[Feat] 模块系统支持,使用 import x.x.x导入

[Fix] Context内部辅助函数修改, getStructName ....
[Feat] 增加字符串下标获取操作,和修改字符操作,实现使用了第四点的函数
[Impl] FString添加新方法 getRealChar, realReplace
[Fun] 在utf8_iterator中辱骂了C++
This commit is contained in:
2025-12-26 20:47:57 +08:00
parent 6e1df63507
commit 00240f1ed1
21 changed files with 578 additions and 140 deletions

View File

@@ -0,0 +1,27 @@
#pragma once
#include <Ast/astBase.hpp>
#include <vector>
namespace Fig::Ast
{
class ImportSt final : public StatementAst
{
public:
std::vector<FString> path;
ImportSt()
{
type = AstType::ImportSt;
}
ImportSt(std::vector<FString> _path) :
path(std::move(_path))
{
type = AstType::ImportSt;
}
};
using Import = std::shared_ptr<ImportSt>;
};

View File

@@ -20,6 +20,7 @@
#include <Ast/Statements/StructDefSt.hpp>
#include <Ast/Statements/IfSt.hpp>
#include <Ast/Statements/ImplementSt.hpp>
#include <Ast/Statements/ImportSt.hpp>
#include <Ast/Statements/FunctionDefSt.hpp>
#include <Ast/Statements/ControlSt.hpp>
#include <Ast/Statements/ExpressionStmt.hpp>

View File

@@ -50,12 +50,15 @@ namespace Fig::Ast
ElseSt,
ElseIfSt,
VarAssignSt,
// VarAssignSt,
WhileSt,
ForSt,
ReturnSt,
BreakSt,
ContinueSt,
PackageSt,
ImportSt,
};
// static const std::unordered_map<AstType, FString> astTypeToString{

View File

@@ -28,9 +28,7 @@ namespace Fig
Context(const Context &) = default;
Context(const FString &name, ContextPtr p = nullptr) :
scopeName(name), parent(p) {}
Context(const FString &name, std::unordered_map<FString, TypeInfo> types, std::unordered_map<FString, std::shared_ptr<VariableSlot>> vars, std::unordered_map<FString, AccessModifier> _ams) :
scopeName(std::move(name)), variables(std::move(vars)) {}
void setParent(ContextPtr _parent)
{
parent = _parent;
@@ -120,7 +118,7 @@ namespace Fig
}
else if (parent != nullptr)
{
parent->set(name, value);
parent->_update(name, value);
}
else
{
@@ -191,7 +189,7 @@ namespace Fig
}
else if (parent)
{
return parent->getFunctionName(id);
return parent->getStructName(id);
}
else
{

View File

@@ -2,7 +2,6 @@
#include <string>
#include <string_view>
namespace Fig
{
// using String = std::u8string;
@@ -12,10 +11,10 @@ namespace Fig
{
public:
using std::u8string_view::u8string_view;
static FStringView fromBasicStringView(std::string_view sv)
{
return FStringView(reinterpret_cast<const char8_t*>(sv.data()));
return FStringView(reinterpret_cast<const char8_t *>(sv.data()));
}
explicit FStringView(std::string_view sv)
@@ -39,7 +38,7 @@ namespace Fig
public:
using std::u8string::u8string;
FString operator+(const FString& x)
FString operator+(const FString &x)
{
return FString(toBasicString() + x.toBasicString());
}
@@ -72,7 +71,7 @@ namespace Fig
static FString fromStringView(FStringView sv)
{
return FString(reinterpret_cast<const char*> (sv.data()));
return FString(reinterpret_cast<const char *>(sv.data()));
}
static FString fromU8String(const std::u8string &str)
@@ -93,6 +92,60 @@ namespace Fig
}
return len;
}
FString getRealChar(size_t index)
{
FString ch;
size_t cnt = 0;
for (size_t i = 0; i < size();)
{
uint8_t cplen = 1;
if ((at(i) & 0xf8) == 0xf0)
cplen = 4;
else if ((at(i) & 0xf0) == 0xe0)
cplen = 3;
else if ((at(i) & 0xe0) == 0xc0)
cplen = 2;
if (i + cplen > size())
cplen = 1;
if (cnt == index)
{
ch += substr(i, cplen);
}
i += cplen;
++ cnt;
}
return ch;
}
void realReplace(size_t index, const FString &src)
{
size_t cnt = 0;
for (size_t i = 0; i < size();)
{
uint8_t cplen = 1;
if ((at(i) & 0xf8) == 0xf0)
cplen = 4;
else if ((at(i) & 0xf0) == 0xe0)
cplen = 3;
else if ((at(i) & 0xe0) == 0xc0)
cplen = 2;
if (i + cplen > size())
cplen = 1;
if (cnt == index)
{
*this = FString(substr(0, i)) + src +
FString(substr(i + cplen));
}
i += cplen;
++cnt;
}
}
};
}; // namespace Fig
@@ -107,4 +160,4 @@ namespace std
return std::hash<std::u8string>{}(static_cast<const std::u8string &>(s));
}
};
}
} // namespace std

View File

@@ -8,6 +8,22 @@
// fuck
// generate by Qwen3-Coder:
// 2025-12-26
/*
again: C++ fuck you
fuck you
fuck you!
fuck
C++ IS A PIECE OF SHIT
STOP USING C++
unicodeString = "some unicode points";
unicodeString[0] ---> ?????
FUCK YOU C++
*/
namespace Fig
{
class UTF8Char

View File

@@ -1,11 +1,14 @@
#include <Error/errorLog.hpp>
#include <Evaluator/evaluator.hpp>
#include <Evaluator/evaluator_error.hpp>
#include <Module/builtins.hpp>
#include <Context/context.hpp>
#include <Utils/utils.hpp>
#include <Parser/parser.hpp>
#include <filesystem>
#include <fstream>
namespace Fig
{
LvObject Evaluator::evalVarExpr(Ast::VarExpr var, ContextPtr ctx)
@@ -22,6 +25,25 @@ namespace Fig
LvObject base = evalLv(me->base, ctx);
RvObject baseVal = base.get();
const FString &member = me->member;
if (baseVal->getTypeInfo() == ValueType::Module)
{
const Module &mod = baseVal->as<Module>();
if (mod.ctx->contains(member) && mod.ctx->isVariablePublic(member))
{
return LvObject(
mod.ctx->get(member)
);
}
else {
throw EvaluatorError(
u8"VariableNotFoundError",
std::format(
"`{}` has not variable '{}', check if it is public",
baseVal->toString().toBasicString(),
member.toBasicString()),
me->base);
}
}
if (baseVal->hasMemberFunction(member))
{
return LvObject(std::make_shared<VariableSlot>(
@@ -71,10 +93,8 @@ namespace Fig
u8"TypeError",
std::format(
"Type `List` indices must be `Int`, got '{}'",
index->getTypeInfo().toString().toBasicString()
),
ie->index
);
index->getTypeInfo().toString().toBasicString()),
ie->index);
}
List &list = base.get()->as<List>();
ValueType::IntClass indexVal = index->as<ValueType::IntClass>();
@@ -85,21 +105,48 @@ namespace Fig
std::format(
"Index {} out of list `{}` range",
indexVal,
base.get()->toString().toBasicString()
),
ie->index
);
base.get()->toString().toBasicString()),
ie->index);
}
return LvObject(
base.get(),
indexVal
);
indexVal,
LvObject::Kind::ListElement);
}
else if (type == ValueType::Map)
{
return LvObject(
base.get(),
index
index,
LvObject::Kind::MapElement);
}
else if (type == ValueType::String)
{
if (index->getTypeInfo() != ValueType::Int)
{
throw EvaluatorError(
u8"TypeError",
std::format(
"Type `String` indices must be `Int`, got '{}'",
index->getTypeInfo().toString().toBasicString()),
ie->index);
}
FString &string = base.get()->as<ValueType::StringClass>();
ValueType::IntClass indexVal = index->as<ValueType::IntClass>();
if (indexVal >= string.length())
{
throw EvaluatorError(
u8"IndexOutOfRangeError",
std::format(
"Index {} out of string `{}` range",
indexVal,
base.get()->toString().toBasicString()),
ie->index);
}
return LvObject(
base.get(),
indexVal,
LvObject::Kind::StringElement
);
}
else
@@ -111,7 +158,6 @@ namespace Fig
base.declaredType().toString().toBasicString()),
ie->base);
}
}
LvObject Evaluator::evalLv(Ast::Expression exp, ContextPtr ctx)
{
@@ -322,9 +368,13 @@ namespace Fig
Ast::FunctionParameters fnParas = fnStruct.paras;
if (fnArgs.getLength() < fnParas.posParas.size() || fnArgs.getLength() > fnParas.size())
{
throw EvaluatorError(
u8"ArgumentMismatchError",
std::format("Function '{}' expects {} to {} arguments, but {} were provided", fnName.toBasicString(), fnParas.posParas.size(), fnParas.size(), fnArgs.getLength()), fnArgs.argv.back());
throw RuntimeError(FString(
std::format(
"Function '{}' expects {} to {} arguments, but {} were provided",
fnName.toBasicString(),
fnParas.posParas.size(),
fnParas.size(),
fnArgs.getLength())));
}
// positional parameters type check
@@ -484,8 +534,15 @@ namespace Fig
}
const Function &fn = fnObj->as<Function>();
size_t fnId = fn.id;
const auto &fnNameOpt = ctx->getFunctionName(fnId);
// const auto &fnNameOpt = ctx->getFunctionName(fnId);
// const FString &fnName = (fnNameOpt ? *fnNameOpt : u8"<anonymous>");
auto fnNameOpt = ctx->getFunctionName(fnId);
if (!fnNameOpt && fn.closureContext)
fnNameOpt = fn.closureContext->getFunctionName(fnId);
const FString &fnName = (fnNameOpt ? *fnNameOpt : u8"<anonymous>");
return evalFunctionCall(fn, fnCall->arg, fnName, ctx);
}
case AstType::FunctionLiteralExpr: {
@@ -722,7 +779,7 @@ namespace Fig
}
return std::make_shared<Object>(std::move(map));
}
default:
assert(false);
}
@@ -745,6 +802,11 @@ namespace Fig
using enum Ast::AstType;
switch (stmt->getType())
{
case ImportSt: {
auto i = std::dynamic_pointer_cast<Ast::ImportSt>(stmt);
assert(i != nullptr);
return evalImportSt(i, ctx);
}
case VarDefSt: {
auto varDef = std::dynamic_pointer_cast<Ast::VarDefAst>(stmt);
assert(varDef != nullptr);
@@ -1067,6 +1129,189 @@ namespace Fig
magic_enum::enum_name(stmt->getType()))));
}
}
std::filesystem::path Evaluator::resolveModulePath(const std::vector<FString> &pathVec)
{
namespace fs = std::filesystem;
static const std::vector<fs::path> defaultLibraryPath{
"Library",
"Library/fpm"};
std::vector<fs::path> pathToFind(defaultLibraryPath);
pathToFind.insert(
pathToFind.begin(),
fs::path(
this->sourcePath.toBasicString())
.parent_path()); // first search module at the source file path
fs::path path;
/*
Example:
import comp.config;
*/
const FString &modPathStrTop = pathVec.at(0);
fs::path modPath;
bool found = false;
for (auto &parentFolder : pathToFind)
{
modPath = parentFolder / FString(modPathStrTop + u8".fig").toBasicString();
if (fs::exists(modPath))
{
path = modPath;
found = true;
break;
}
else
{
modPath = parentFolder / modPathStrTop.toBasicString();
if (fs::is_directory(modPath)) // comp is a directory
{
modPath = modPath / FString(modPathStrTop + u8".fig").toBasicString();
/*
if module name is a directory, we require [module name].fig at the directory
*/
if (!fs::exists(modPath))
{
throw RuntimeError(FString(
std::format(
"requires module file, {}\\{}",
modPathStrTop.toBasicString(),
FString(modPathStrTop + u8".fig").toBasicString())));
}
found = true;
path = modPath;
break;
}
}
}
if (!found)
throw RuntimeError(
FString(std::format(
"Could not find module `{}`",
modPathStrTop.toBasicString())));
bool found2 = false;
for (size_t i = 1; i < pathVec.size(); ++i) // has next module
{
const FString &next = pathVec.at(i);
modPath = modPath.parent_path(); // get the folder
modPath = modPath / FString(next + u8".fig").toBasicString();
if (fs::exists(modPath))
{
if (i != pathVec.size() - 1)
throw RuntimeError(FString(
std::format(
"expects {} as parent directory and find next module, but got a file",
next.toBasicString())));
// it's the last module
found2 = true;
path = modPath;
break;
}
// `next` is a folder
modPath = modPath.parent_path() / next.toBasicString();
if (!fs::exists(modPath))
throw RuntimeError(FString(
std::format("Could not find module `{}`", next.toBasicString())));
}
if (!found2 && !fs::exists(modPath))
throw RuntimeError(FString(
std::format("Could not find module `{}`", pathVec.end()->toBasicString())));
return path;
}
ContextPtr Evaluator::loadModule(const std::filesystem::path &path)
{
std::ifstream file(path);
assert(file.is_open());
std::string source((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());
file.close();
Lexer lexer((FString(source)));
Parser parser(lexer);
std::vector<Ast::AstBase> asts;
std::vector<FString> sourceLines = Utils::splitSource(FString(source));
try
{
asts = parser.parseAll();
}
catch (const AddressableError &e)
{
ErrorLog::logAddressableError(e, sourcePath, sourceLines);
}
catch (const UnaddressableError &e)
{
ErrorLog::logUnaddressableError(e);
}
catch (const std::exception &e)
{
std::cerr << "uncaught exception of: " << e.what() << '\n';
}
Evaluator evaluator;
evaluator.SetSourcePath(FString(path.string()));
ContextPtr modctx = std::make_shared<Context>(
FString(std::format("<Module at {}>", path.string())),
nullptr);
evaluator.SetGlobalContext(modctx);
evaluator.RegisterBuiltins();
try
{
evaluator.Run(asts);
}
catch (std::exception &e)
{
std::cerr << "load module failed" << '\n';
throw e;
}
return evaluator.global;
}
StatementResult Evaluator::evalImportSt(Ast::Import i, ContextPtr ctx)
{
const std::vector<FString> &pathVec = i->path;
auto path = resolveModulePath(pathVec);
ContextPtr modCtx = loadModule(path);
const FString &modName = pathVec.at(pathVec.size() - 1);
// std::cerr << modName.toBasicString() << '\n'; DEBUG
if (ctx->containsInThisScope(modName))
{
throw EvaluatorError(
u8"RedeclarationError",
std::format(
"{} has already been declared.",
modName.toBasicString()),
i);
}
ctx->def(
modName,
ValueType::Module,
AccessModifier::PublicConst,
std::make_shared<Object>(
Module(
modName,
modCtx)));
return StatementResult::normal();
}
StatementResult Evaluator::Run(std::vector<Ast::AstBase> asts)
{
using Ast::AstType;

View File

@@ -4,6 +4,7 @@
#include <Error/error.hpp>
#include <Module/builtins.hpp>
#include <Value/LvObject.hpp>
#include <filesystem>
namespace Fig
@@ -52,6 +53,12 @@ namespace Fig
private:
ContextPtr global;
public:
FString sourcePath;
void SetSourcePath(const FString &sp)
{
sourcePath = sp;
}
void SetGlobalContext(ContextPtr ctx)
{
@@ -110,8 +117,13 @@ namespace Fig
StatementResult evalBlockStatement(Ast::BlockStatement, ContextPtr); // block
StatementResult evalStatement(Ast::Statement, ContextPtr); // statement
std::filesystem::path resolveModulePath(const std::vector<FString> &);
ContextPtr loadModule(const std::filesystem::path &);
StatementResult evalImportSt(Ast::Import, ContextPtr);
StatementResult Run(std::vector<Ast::AstBase>); // Entry
void printStackTrace();
};
}; // namespace Fig

View File

@@ -0,0 +1,9 @@
/*
Official Module `std.io`
Library/std/io/io.fig
*/
public func print(value) -> Null
{
__fstdout_print(value);
}

View File

@@ -0,0 +1,6 @@
/*
Official Module `std`
Library/std/std.fig
*/
import io; // link std io

View File

@@ -1,47 +0,0 @@
#pragma once
#include <memory>
#include <Core/fig_string.hpp>
#include <Value/value.hpp>
#include <Context/context.hpp>
namespace Fig
{
// class Module
// {
// public:
// const FString name;
// const FString spec;
// const FString path;
// std::shared_ptr<Context> context; // module-level context
// /*
// import module -> automatically create a module context and call function `init` if exists
// all global functions, variables, structs, etc will be stored in module context
// then module context will be linked to the current context
// */
// Module(const FString &moduleName, const FString &moduleSpec, const FString &modulePath) :
// name(moduleName), spec(moduleSpec), path(modulePath)
// {
// context = std::make_shared<Context>(FString(std::format("<Module {}>", name.toBasicString())), nullptr);
// }
// bool hasSymbol(const FString &symbolName)
// {
// return context->contains(symbolName);
// }
// Object getSymbol(const FString &symbolName)
// {
// auto valOpt = context->get(symbolName);
// if (!valOpt.has_value())
// {
// throw RuntimeError(FStringView(std::format("Symbol '{}' not found in module '{}'", symbolName.toBasicString(), name.toBasicString())));
// }
// return valOpt.value();
// }
// };
};

View File

@@ -132,7 +132,7 @@ namespace Fig
Ast::ValueExpr Parser::__parseValueExpr()
{
return makeAst<Ast::ValueExprAst> (__parseValue());
return makeAst<Ast::ValueExprAst>(__parseValue());
}
Ast::FunctionParameters Parser::__parseFunctionParameters()
{
@@ -350,7 +350,11 @@ namespace Fig
{
Ast::Statement stmt;
if (isThis(TokenType::EndOfFile)) { return makeAst<Ast::EofStmt>(); }
if (isThis(TokenType::Public))
else if (isThis(TokenType::Import))
{
stmt = __parseImport();
}
else if (isThis(TokenType::Public))
{
next(); // consume `public`
if (isThis(TokenType::Variable) || isThis(TokenType::Const))
@@ -708,8 +712,7 @@ namespace Fig
{
throwAddressableError<SyntaxError>(FString(
std::format("Expect `,` or `}}` in struct initialization expression, got {}",
currentToken().toString().toBasicString())
));
currentToken().toString().toBasicString())));
}
}
expect(TokenType::RightBrace);
@@ -782,6 +785,33 @@ namespace Fig
return makeAst<Ast::FunctionLiteralExprAst>(params, __parseBlockStatement());
}
Ast::Import Parser::__parseImport()
{
next(); // consume `import`
std::vector<FString> path;
while (true)
{
expect(TokenType::Identifier, u8"package name");
path.push_back(currentToken().getValue());
next(); // consume package name
if (isThis(TokenType::Semicolon))
{
break;
}
else if (isThis(TokenType::Dot))
{
next(); // consume `.`
}
else
{
throw SyntaxError();
}
}
expect(TokenType::Semicolon);
next(); // consume `;`
return makeAst<Ast::ImportSt>(path);
}
Ast::Expression Parser::parseExpression(Precedence bp, TokenType stop, TokenType stop2)
{
Ast::Expression lhs;
@@ -921,10 +951,17 @@ namespace Fig
return output;
}
// TODO: Package/Module Import Support
while (!isEOF())
{
pushNode(__parseStatement());
auto stmt = __parseStatement();
if (!output.empty() && stmt->getType() == Ast::AstType::PackageSt)
{
throw SyntaxError(
u8"Package must be at the beginning of the file",
currentAAI.line,
currentAAI.column);
}
pushNode(stmt);
}
return output;
}

View File

@@ -325,6 +325,8 @@ namespace Fig
Ast::Expression __parseTupleOrParenExpr(); // entry: current is `(`
Ast::FunctionLiteralExpr __parseFunctionLiteralExpr(); // entry: current is Token::LParen after Token::Function
Ast::Import __parseImport(); // entry: current is Token::Import
Ast::Statement __parseStatement(); // entry: (idk)
Ast::Expression parseExpression(Precedence, TokenType = TokenType::Semicolon, TokenType = TokenType::Semicolon);

View File

@@ -18,6 +18,7 @@ namespace Fig
Identifier,
/* Keywords */
Package, // package
And, // and
Or, // or
Not, // not
@@ -48,7 +49,7 @@ namespace Fig
LiteralNumber, // number (int,float...)
LiteralString, // FString
LiteralBool, // bool (true/false)
LiteralNull, // null (Null的唯一实例)
LiteralNull, // null (Null unique instance)
/* Punct */
Plus, // +

View File

@@ -1,5 +1,6 @@
#pragma once
#pragma once
#include <Lexer/lexer.hpp>
#include <Core/fig_string.hpp>
#include <string>
#include <locale>
@@ -9,6 +10,32 @@
namespace Fig::Utils
{
inline std::vector<FString> splitSource(FString source)
{
UTF8Iterator it(source);
std::vector<FString> lines;
FString currentLine;
while (!it.isEnd())
{
UTF8Char c = *it;
if (c == U'\n')
{
lines.push_back(currentLine);
currentLine = FString(u8"");
}
else
{
currentLine += c.getString();
}
++it;
}
if (!currentLine.empty())
{
lines.push_back(currentLine);
}
return lines;
}
inline std::u32string utf8ToUtf32(const FString &s)
{
std::u32string result;

View File

@@ -12,12 +12,13 @@ namespace Fig
{
Variable,
ListElement,
MapElement
MapElement,
StringElement,
} kind;
std::shared_ptr<VariableSlot> slot;
ObjectPtr listOrMap = nullptr;
size_t listIndex;
ObjectPtr value = nullptr;
size_t numIndex;
ObjectPtr mapIndex;
@@ -26,20 +27,18 @@ namespace Fig
{
kind = Kind::Variable;
}
LvObject(ObjectPtr _v, size_t _index) :
listOrMap(_v), listIndex(_index)
LvObject(ObjectPtr _v, size_t _index, Kind _kind) :
value(_v), numIndex(_index)
{
assert(_v->getTypeInfo() == ValueType::List);
kind = Kind::ListElement;
kind = _kind;
}
LvObject(ObjectPtr _v, ObjectPtr _index) :
listOrMap(_v), mapIndex(_index)
LvObject(ObjectPtr _v, ObjectPtr _index, Kind _kind) :
value(_v), mapIndex(_index)
{
assert(_v->getTypeInfo() == ValueType::Map);
kind = Kind::MapElement;
kind = _kind;
}
const ObjectPtr &get() const
ObjectPtr get() const
{
if (kind == Kind::Variable)
{
@@ -48,20 +47,30 @@ namespace Fig
}
else if (kind == Kind::ListElement)
{
List &list = listOrMap->as<List>();
if (listIndex >= list.size())
List &list = value->as<List>();
if (numIndex >= list.size())
throw RuntimeError(FString(
std::format("Index {} out of range", listIndex)));
return list.at(listIndex);
std::format("Index {} out of range {}", numIndex, value->toString().toBasicString())));
return list.at(numIndex);
}
else // map
else if (kind == Kind::MapElement) // map
{
Map &map = listOrMap->as<Map>();
Map &map = value->as<Map>();
if (!map.contains(mapIndex))
throw RuntimeError(FString(
std::format("Key {} not found", mapIndex->toString().toBasicString())));
return map.at(mapIndex);
}
else
{
// string
FString &string = value->as<ValueType::StringClass>();
if (numIndex >= string.length())
throw RuntimeError(FString(
std::format("Index {} out of range {}", numIndex, value->toString().toBasicString())));
return std::make_shared<Object>(string.getRealChar(numIndex));
}
}
void set(const ObjectPtr &v)
@@ -87,17 +96,35 @@ namespace Fig
}
else if (kind == Kind::ListElement)
{
List &list = listOrMap->as<List>();
if (listIndex >= list.size())
List &list = value->as<List>();
if (numIndex >= list.size())
throw RuntimeError(FString(
std::format("Index {} out of range", listIndex)));
list[listIndex] = v;
std::format("Index {} out of range", numIndex)));
list[numIndex] = v;
}
else // map
else if (kind == Kind::MapElement) // map
{
Map &map = listOrMap->as<Map>();
Map &map = value->as<Map>();
map[mapIndex] = v;
}
else if (kind == Kind::StringElement)
{
FString &string = value->as<ValueType::StringClass>();
if (numIndex >= string.length())
throw RuntimeError(FString(
std::format("Index {} out of range {}", numIndex, value->toString().toBasicString())));
if (v->getTypeInfo() != ValueType::String)
throw RuntimeError(FString(
std::format("Could not assign {} to sub string", v->toString().toBasicString())
));
const FString &strReplace = v->as<ValueType::StringClass>();
if (strReplace.length() > 1)
throw RuntimeError(FString(
std::format("Could not assign {} to sub string, expects length 1", v->toString().toBasicString())
));
string.realReplace(numIndex, strReplace);
}
}
FString name() const { return resolve(slot)->name; }
@@ -111,4 +138,4 @@ namespace Fig
return s;
}
};
}
} // namespace Fig

View File

@@ -67,6 +67,7 @@ namespace Fig
extern const TypeInfo StructInstance;
extern const TypeInfo List;
extern const TypeInfo Map;
extern const TypeInfo Module;
// extern const TypeInfo Tuple;
using IntClass = int64_t;

27
src/Value/module.hpp Normal file
View File

@@ -0,0 +1,27 @@
#pragma once
#include <Core/fig_string.hpp>
#include <Context/context_forward.hpp>
namespace Fig
{
struct Module
{
FString name;
ContextPtr ctx;
Module() = default;
Module(FString n, ContextPtr c) :
name(std::move(n)),
ctx(std::move(c))
{
}
bool operator==(const Module &o) const noexcept
{
return name == o.name;
}
};
};

View File

@@ -80,5 +80,5 @@ namespace Fig
const TypeInfo ValueType::StructInstance(FString(u8"StructInstance"), true); // id: 9
const TypeInfo ValueType::List(FString(u8"List"), true); // id: 10
const TypeInfo ValueType::Map(FString(u8"Map"), true); // id: 11
// const TypeInfo ValueType::Tuple(FString(u8"Tuple"), true); // id: 12
const TypeInfo ValueType::Module(FString(u8"Module"), true); // id: 12
} // namespace Fig

View File

@@ -4,6 +4,7 @@
#include <Value/structInstance.hpp>
#include <Value/Type.hpp>
#include <Value/valueError.hpp>
#include <Value/module.hpp>
#include <variant>
#include <cmath>
@@ -58,7 +59,8 @@ namespace Fig
StructType,
StructInstance,
List,
Map>;
Map,
Module>;
std::unordered_map<TypeInfo,
std::unordered_map<FString,
@@ -134,6 +136,7 @@ namespace Fig
map.contains(index));
}},
}},
{ValueType::Module, {}}
};
std::unordered_map<TypeInfo, std::unordered_map<FString, int>, TypeInfoHash> memberTypeFunctionsParas{
{ValueType::Null, {}},
@@ -151,6 +154,7 @@ namespace Fig
{u8"get", 1},
{u8"contains", 1},
}},
{ValueType::Module, {}}
};
bool hasMemberFunction(const FString &name) const
@@ -190,6 +194,8 @@ namespace Fig
data(l) {}
Object(const Map &m) :
data(m) {}
Object(const Module &m) :
data(m) {}
Object(const Object &) = default;
Object(Object &&) noexcept = default;
@@ -283,6 +289,9 @@ namespace Fig
else if constexpr (std::is_same_v<T, Map>)
return ValueType::Map;
else if constexpr (std::is_same_v<T, Module>)
return ValueType::Module;
else
return ValueType::Any;
},
@@ -357,6 +366,12 @@ namespace Fig
output += u8"}";
return output;
}
if (is<Module>())
{
return FString(std::format(
"<Module at {:p}>",
static_cast<const void *>(&as<Module>())));
}
return FString(u8"<error>");
}
@@ -576,7 +591,6 @@ namespace Fig
using ObjectPtr = std::shared_ptr<Object>;
using RvObject = ObjectPtr;
inline bool operator==(const ValueKey &l, const ValueKey &r)
{
return *l.value == *r.value;

View File

@@ -36,36 +36,12 @@ This software is licensed under the MIT License. See LICENSE.txt for details.
#include <Parser/parser.hpp>
#include <Evaluator/evaluator.hpp>
#include <Utils/AstPrinter.hpp>
#include <Utils/utils.hpp>
#include <Error/errorLog.hpp>
static size_t addressableErrorCount = 0;
static size_t unaddressableErrorCount = 0;
std::vector<FString> splitSource(FString source)
{
UTF8Iterator it(source);
std::vector<FString> lines;
FString currentLine;
while (!it.isEnd())
{
UTF8Char c = *it;
if (c == U'\n')
{
lines.push_back(currentLine);
currentLine = FString(u8"");
}
else
{
currentLine += c.getString();
}
++it;
}
if (!currentLine.empty())
{
lines.push_back(currentLine);
}
return lines;
}
int main(int argc, char **argv)
{
@@ -119,7 +95,7 @@ int main(int argc, char **argv)
Fig::Parser parser(lexer);
std::vector<Fig::Ast::AstBase> asts;
std::vector<FString> sourceLines = splitSource(Fig::FString(source));
std::vector<FString> sourceLines = Fig::Utils::splitSource(Fig::FString(source));
try
{
@@ -151,8 +127,11 @@ int main(int argc, char **argv)
// }
Fig::Evaluator evaluator;
evaluator.SetSourcePath(sourcePath);
evaluator.CreateGlobalContext();
evaluator.RegisterBuiltins();
try
{
evaluator.Run(asts);