From 00240f1ed1aeeae0708a16b2be73b062c4f3bf92 Mon Sep 17 00:00:00 2001 From: PuqiAR Date: Fri, 26 Dec 2025 20:47:57 +0800 Subject: [PATCH] =?UTF-8?q?[Feat]=20=E6=A8=A1=E5=9D=97=E7=B3=BB=E7=BB=9F?= =?UTF-8?q?=E6=94=AF=E6=8C=81=EF=BC=8C=E4=BD=BF=E7=94=A8=20import=20x.x.x?= =?UTF-8?q?=E5=AF=BC=E5=85=A5=20[Fix]=20Context=E5=86=85=E9=83=A8=E8=BE=85?= =?UTF-8?q?=E5=8A=A9=E5=87=BD=E6=95=B0=E4=BF=AE=E6=94=B9,=20getStructName?= =?UTF-8?q?=20....=20[Feat]=20=E5=A2=9E=E5=8A=A0=E5=AD=97=E7=AC=A6?= =?UTF-8?q?=E4=B8=B2=E4=B8=8B=E6=A0=87=E8=8E=B7=E5=8F=96=E6=93=8D=E4=BD=9C?= =?UTF-8?q?=EF=BC=8C=E5=92=8C=E4=BF=AE=E6=94=B9=E5=AD=97=E7=AC=A6=E6=93=8D?= =?UTF-8?q?=E4=BD=9C=EF=BC=8C=E5=AE=9E=E7=8E=B0=E4=BD=BF=E7=94=A8=E4=BA=86?= =?UTF-8?q?=E7=AC=AC=E5=9B=9B=E7=82=B9=E7=9A=84=E5=87=BD=E6=95=B0=20[Impl]?= =?UTF-8?q?=20FString=E6=B7=BB=E5=8A=A0=E6=96=B0=E6=96=B9=E6=B3=95=20getRe?= =?UTF-8?q?alChar,=20realReplace=20[Fun]=20=E5=9C=A8utf8=5Fiterator?= =?UTF-8?q?=E4=B8=AD=E8=BE=B1=E9=AA=82=E4=BA=86C++?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Ast/Statements/ImportSt.hpp | 27 +++ src/Ast/ast.hpp | 1 + src/Ast/astBase.hpp | 5 +- src/Context/context.hpp | 8 +- src/Core/fig_string.hpp | 65 ++++++- src/Core/utf8_iterator.hpp | 16 ++ src/Evaluator/evaluator.cpp | 281 +++++++++++++++++++++++++++++-- src/Evaluator/evaluator.hpp | 14 +- src/Module/Library/std/io/io.fig | 9 + src/Module/Library/std/std.fig | 6 + src/Module/module.hpp | 47 ------ src/Parser/parser.cpp | 49 +++++- src/Parser/parser.hpp | 2 + src/Token/token.hpp | 3 +- src/Utils/utils.hpp | 29 +++- src/Value/LvObject.hpp | 77 ++++++--- src/Value/Type.hpp | 1 + src/Value/module.hpp | 27 +++ src/Value/value.cpp | 2 +- src/Value/value.hpp | 18 +- src/main.cpp | 31 +--- 21 files changed, 578 insertions(+), 140 deletions(-) create mode 100644 src/Ast/Statements/ImportSt.hpp create mode 100644 src/Module/Library/std/io/io.fig create mode 100644 src/Module/Library/std/std.fig delete mode 100644 src/Module/module.hpp create mode 100644 src/Value/module.hpp diff --git a/src/Ast/Statements/ImportSt.hpp b/src/Ast/Statements/ImportSt.hpp new file mode 100644 index 0000000..e0946e9 --- /dev/null +++ b/src/Ast/Statements/ImportSt.hpp @@ -0,0 +1,27 @@ +#pragma once + +#include + +#include + +namespace Fig::Ast +{ + class ImportSt final : public StatementAst + { + public: + std::vector path; + + ImportSt() + { + type = AstType::ImportSt; + } + + ImportSt(std::vector _path) : + path(std::move(_path)) + { + type = AstType::ImportSt; + } + }; + + using Import = std::shared_ptr; +}; \ No newline at end of file diff --git a/src/Ast/ast.hpp b/src/Ast/ast.hpp index fac714b..0a038b4 100644 --- a/src/Ast/ast.hpp +++ b/src/Ast/ast.hpp @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include diff --git a/src/Ast/astBase.hpp b/src/Ast/astBase.hpp index f378e36..4397f77 100644 --- a/src/Ast/astBase.hpp +++ b/src/Ast/astBase.hpp @@ -50,12 +50,15 @@ namespace Fig::Ast ElseSt, ElseIfSt, - VarAssignSt, + // VarAssignSt, WhileSt, ForSt, ReturnSt, BreakSt, ContinueSt, + + PackageSt, + ImportSt, }; // static const std::unordered_map astTypeToString{ diff --git a/src/Context/context.hpp b/src/Context/context.hpp index d72fec2..925d523 100644 --- a/src/Context/context.hpp +++ b/src/Context/context.hpp @@ -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 types, std::unordered_map> vars, std::unordered_map _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 { diff --git a/src/Core/fig_string.hpp b/src/Core/fig_string.hpp index 5391a24..2748812 100644 --- a/src/Core/fig_string.hpp +++ b/src/Core/fig_string.hpp @@ -2,7 +2,6 @@ #include #include - 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(sv.data())); + return FStringView(reinterpret_cast(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 (sv.data())); + return FString(reinterpret_cast(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{}(static_cast(s)); } }; -} \ No newline at end of file +} // namespace std \ No newline at end of file diff --git a/src/Core/utf8_iterator.hpp b/src/Core/utf8_iterator.hpp index 0505e99..3fd503f 100644 --- a/src/Core/utf8_iterator.hpp +++ b/src/Core/utf8_iterator.hpp @@ -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 diff --git a/src/Evaluator/evaluator.cpp b/src/Evaluator/evaluator.cpp index 701364e..5d57ee0 100644 --- a/src/Evaluator/evaluator.cpp +++ b/src/Evaluator/evaluator.cpp @@ -1,11 +1,14 @@ +#include #include #include #include #include #include - #include +#include +#include + 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(); + 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( @@ -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(); ValueType::IntClass indexVal = index->as(); @@ -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::IntClass indexVal = index->as(); + 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(); size_t fnId = fn.id; - const auto &fnNameOpt = ctx->getFunctionName(fnId); + // const auto &fnNameOpt = ctx->getFunctionName(fnId); + // const FString &fnName = (fnNameOpt ? *fnNameOpt : u8""); + + auto fnNameOpt = ctx->getFunctionName(fnId); + if (!fnNameOpt && fn.closureContext) + fnNameOpt = fn.closureContext->getFunctionName(fnId); + const FString &fnName = (fnNameOpt ? *fnNameOpt : u8""); + return evalFunctionCall(fn, fnCall->arg, fnName, ctx); } case AstType::FunctionLiteralExpr: { @@ -722,7 +779,7 @@ namespace Fig } return std::make_shared(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(stmt); + assert(i != nullptr); + return evalImportSt(i, ctx); + } case VarDefSt: { auto varDef = std::dynamic_pointer_cast(stmt); assert(varDef != nullptr); @@ -1067,6 +1129,189 @@ namespace Fig magic_enum::enum_name(stmt->getType())))); } } + + std::filesystem::path Evaluator::resolveModulePath(const std::vector &pathVec) + { + namespace fs = std::filesystem; + + static const std::vector defaultLibraryPath{ + "Library", + "Library/fpm"}; + + std::vector 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(file)), std::istreambuf_iterator()); + file.close(); + + Lexer lexer((FString(source))); + Parser parser(lexer); + std::vector asts; + + std::vector 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( + FString(std::format("", 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 &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( + Module( + modName, + modCtx))); + return StatementResult::normal(); + } + StatementResult Evaluator::Run(std::vector asts) { using Ast::AstType; diff --git a/src/Evaluator/evaluator.hpp b/src/Evaluator/evaluator.hpp index 9e1c6ed..9806dcd 100644 --- a/src/Evaluator/evaluator.hpp +++ b/src/Evaluator/evaluator.hpp @@ -4,6 +4,7 @@ #include #include #include +#include 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 &); + ContextPtr loadModule(const std::filesystem::path &); + + StatementResult evalImportSt(Ast::Import, ContextPtr); + StatementResult Run(std::vector); // Entry - + void printStackTrace(); }; }; // namespace Fig \ No newline at end of file diff --git a/src/Module/Library/std/io/io.fig b/src/Module/Library/std/io/io.fig new file mode 100644 index 0000000..648147d --- /dev/null +++ b/src/Module/Library/std/io/io.fig @@ -0,0 +1,9 @@ +/* +Official Module `std.io` +Library/std/io/io.fig +*/ + +public func print(value) -> Null +{ + __fstdout_print(value); +} \ No newline at end of file diff --git a/src/Module/Library/std/std.fig b/src/Module/Library/std/std.fig new file mode 100644 index 0000000..5c707c1 --- /dev/null +++ b/src/Module/Library/std/std.fig @@ -0,0 +1,6 @@ +/* +Official Module `std` +Library/std/std.fig +*/ + +import io; // link std io \ No newline at end of file diff --git a/src/Module/module.hpp b/src/Module/module.hpp deleted file mode 100644 index 1824d7b..0000000 --- a/src/Module/module.hpp +++ /dev/null @@ -1,47 +0,0 @@ -#pragma once - -#include - -#include -#include -#include - -namespace Fig -{ - // class Module - // { - // public: - // const FString name; - // const FString spec; - // const FString path; - - // std::shared_ptr 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(FString(std::format("", 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(); - // } - // }; -}; \ No newline at end of file diff --git a/src/Parser/parser.cpp b/src/Parser/parser.cpp index de4f15f..4e6019c 100644 --- a/src/Parser/parser.cpp +++ b/src/Parser/parser.cpp @@ -132,7 +132,7 @@ namespace Fig Ast::ValueExpr Parser::__parseValueExpr() { - return makeAst (__parseValue()); + return makeAst(__parseValue()); } Ast::FunctionParameters Parser::__parseFunctionParameters() { @@ -350,7 +350,11 @@ namespace Fig { Ast::Statement stmt; if (isThis(TokenType::EndOfFile)) { return makeAst(); } - 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(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(params, __parseBlockStatement()); } + Ast::Import Parser::__parseImport() + { + next(); // consume `import` + std::vector 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(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; } diff --git a/src/Parser/parser.hpp b/src/Parser/parser.hpp index 146f3dd..4dca735 100644 --- a/src/Parser/parser.hpp +++ b/src/Parser/parser.hpp @@ -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); diff --git a/src/Token/token.hpp b/src/Token/token.hpp index aa61f39..b10abf0 100644 --- a/src/Token/token.hpp +++ b/src/Token/token.hpp @@ -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, // + diff --git a/src/Utils/utils.hpp b/src/Utils/utils.hpp index e5b10f2..fd0d521 100644 --- a/src/Utils/utils.hpp +++ b/src/Utils/utils.hpp @@ -1,5 +1,6 @@ #pragma once -#pragma once + +#include #include #include #include @@ -9,6 +10,32 @@ namespace Fig::Utils { + + inline std::vector splitSource(FString source) + { + UTF8Iterator it(source); + std::vector 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; diff --git a/src/Value/LvObject.hpp b/src/Value/LvObject.hpp index 54e5cbe..f971ea4 100644 --- a/src/Value/LvObject.hpp +++ b/src/Value/LvObject.hpp @@ -12,12 +12,13 @@ namespace Fig { Variable, ListElement, - MapElement + MapElement, + StringElement, } kind; std::shared_ptr 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(); - if (listIndex >= list.size()) + List &list = value->as(); + 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 = value->as(); 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(); + if (numIndex >= string.length()) + throw RuntimeError(FString( + std::format("Index {} out of range {}", numIndex, value->toString().toBasicString()))); + + return std::make_shared(string.getRealChar(numIndex)); + } } void set(const ObjectPtr &v) @@ -87,17 +96,35 @@ namespace Fig } else if (kind == Kind::ListElement) { - List &list = listOrMap->as(); - if (listIndex >= list.size()) + List &list = value->as(); + 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 = value->as(); map[mapIndex] = v; } + else if (kind == Kind::StringElement) + { + FString &string = value->as(); + 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(); + 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; } }; -} \ No newline at end of file +} // namespace Fig \ No newline at end of file diff --git a/src/Value/Type.hpp b/src/Value/Type.hpp index adfa3c0..6622e28 100644 --- a/src/Value/Type.hpp +++ b/src/Value/Type.hpp @@ -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; diff --git a/src/Value/module.hpp b/src/Value/module.hpp new file mode 100644 index 0000000..9689032 --- /dev/null +++ b/src/Value/module.hpp @@ -0,0 +1,27 @@ +#pragma once + +#include + +#include + +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; + } + }; +}; \ No newline at end of file diff --git a/src/Value/value.cpp b/src/Value/value.cpp index f53e14b..b062331 100644 --- a/src/Value/value.cpp +++ b/src/Value/value.cpp @@ -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 \ No newline at end of file diff --git a/src/Value/value.hpp b/src/Value/value.hpp index b230446..16b5992 100644 --- a/src/Value/value.hpp +++ b/src/Value/value.hpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include @@ -58,7 +59,8 @@ namespace Fig StructType, StructInstance, List, - Map>; + Map, + Module>; std::unordered_map, 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) return ValueType::Map; + else if constexpr (std::is_same_v) + return ValueType::Module; + else return ValueType::Any; }, @@ -357,6 +366,12 @@ namespace Fig output += u8"}"; return output; } + if (is()) + { + return FString(std::format( + "", + static_cast(&as()))); + } return FString(u8""); } @@ -576,7 +591,6 @@ namespace Fig using ObjectPtr = std::shared_ptr; using RvObject = ObjectPtr; - inline bool operator==(const ValueKey &l, const ValueKey &r) { return *l.value == *r.value; diff --git a/src/main.cpp b/src/main.cpp index 0249fb6..f0613bc 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -36,36 +36,12 @@ This software is licensed under the MIT License. See LICENSE.txt for details. #include #include #include +#include #include static size_t addressableErrorCount = 0; static size_t unaddressableErrorCount = 0; -std::vector splitSource(FString source) -{ - UTF8Iterator it(source); - std::vector 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 asts; - std::vector sourceLines = splitSource(Fig::FString(source)); + std::vector 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);