From a9cf3d6b0ec265b5f980fe276e23570568b8ba62 Mon Sep 17 00:00:00 2001 From: steambird1 Date: Fri, 7 Nov 2025 14:45:21 +0800 Subject: [PATCH 1/6] Bug fixes --- interpreter/parse_factor.cpp | 13 +++++++++++-- interpreter/parse_stmt.cpp | 1 + interpreter/parser.cpp | 9 ++++++++- 3 files changed, 20 insertions(+), 3 deletions(-) diff --git a/interpreter/parse_factor.cpp b/interpreter/parse_factor.cpp index aaf2fbdb..f52aff10 100644 --- a/interpreter/parse_factor.cpp +++ b/interpreter/parse_factor.cpp @@ -32,6 +32,7 @@ std::unique_ptr Parser::parse_a_token() { } skip_token("{"); + std::cerr << "[Debug output] pipe process begin\n"; auto stmt = parse_block(true); skip_token("}"); return std::make_unique("", std::move(params),std::move(stmt)); @@ -56,14 +57,22 @@ std::unique_ptr Parser::parse_a_token() { if (tok.type == LexerTokenType::LBrace) { std::vector>> init_vec{}; while (curr_token().type != LexerTokenType::RBrace) { - auto key = skip_token().text; + //auto key = skip_token().text; + std::string key = ""; + do { + key = skip_token().text; + } while (key == "\n" || key == "\t" || key == " " || key == ";" || key == "\r" || key == ""); + if (key == "}") { + break; + } + std::cerr << "[Debug output] member assignment: key: " << key << std::endl; skip_token("="); auto val = parse_expression(); if (curr_token().type == LexerTokenType::Comma) skip_token(","); if (curr_token().type == LexerTokenType::Semicolon) skip_token(";"); init_vec.emplace_back(std::move(key), std::move(val)); } - skip_token("}"); + if (curr_token().type == LexerTokenType::RBrace) skip_token("}"); return std::make_unique(std::move(init_vec)); } if (tok.type == LexerTokenType::LBracket) { diff --git a/interpreter/parse_stmt.cpp b/interpreter/parse_stmt.cpp index 0df5d3c3..739bccc0 100644 --- a/interpreter/parse_stmt.cpp +++ b/interpreter/parse_stmt.cpp @@ -3,6 +3,7 @@ std::unique_ptr Parser::parse_block(bool is_global) { std::vector> stmts; while (curr_token().type != LexerTokenType::RBrace) { + std::cerr << "[Debug output] block is going through statements\n"; stmts.emplace_back(parse_stmt()); if (curr_token().type == LexerTokenType::Semicolon) skip_token(";"); } diff --git a/interpreter/parser.cpp b/interpreter/parser.cpp index 292d9eae..f21efdbe 100644 --- a/interpreter/parser.cpp +++ b/interpreter/parser.cpp @@ -18,6 +18,7 @@ Token Parser::skip_token(const std::string& want_skip) { if (curr_tok_idx_ < tokens_.size()) { auto& tok = tokens_[curr_tok_idx_]; if (!want_skip.empty() and tok.text != want_skip) { + std::cerr << "[Parser] Errinfo: "; std::cerr << ConClr::RED << "There should be '" << want_skip << "' , but you given '" << tok.text << "'" << ConClr::RESET << std::endl; @@ -34,6 +35,7 @@ Token Parser::curr_token() const { auto& tok = tokens_[curr_tok_idx_]; return tok; } + std::cerr << "[Debug output] token fetch got EOF\n"; return {LexerTokenType::EndOfFile, "", 0, 0}; } @@ -84,6 +86,9 @@ std::vector> Parser::parse_program() { } std::unique_ptr Parser::parse_stmt() { + while (curr_tok_idx_ < tokens_.size() && curr_token().type == LexerTokenType::EndOfLine) { + skip_token(); + } auto tok = curr_token(); if (tok.type == LexerTokenType::If) { @@ -135,7 +140,7 @@ std::unique_ptr Parser::parse_stmt() { skip_token("loop"); // Disallow empty immediate '{' to remove infinite-loop syntax if (curr_token().text == "{") { - std::cerr << "SyntaxError: infinite 'loop { }' is not supported; use 'loop { ... }'" << std::endl; + std::cerr << "SyntaxError: infinite 'loop { }' is no longer supported; use 'loop { ... }'" << std::endl; throw StdLibException("invalid loop syntax: infinite loop removed"); } auto count_expr = parse_expression(); @@ -182,6 +187,7 @@ std::unique_ptr Parser::parse_stmt() { and tokens_[curr_tok_idx_ + 1].type == LexerTokenType::Assign ) { const auto name = skip_token().text; + std::cerr << "[Debug output] regarded as assignment\n"; skip_token("="); auto expr = parse_expression(); skip_end_of_ln(); @@ -189,6 +195,7 @@ std::unique_ptr Parser::parse_stmt() { } auto expr = parse_expression(); if (expr != nullptr and curr_token().text == "=") { + std::cerr << "[Debug output] regarded as member assignment\n"; if (dynamic_cast(expr.get())) { skip_token("="); auto value = parse_expression(); From 1a279dcb532ee8598d3e388ff3408ea4b2675d1d Mon Sep 17 00:00:00 2001 From: steambird1 Date: Fri, 7 Nov 2025 14:46:06 +0800 Subject: [PATCH 2/6] Debug output removal --- interpreter/parse_factor.cpp | 2 -- interpreter/parse_stmt.cpp | 1 - interpreter/parser.cpp | 3 --- 3 files changed, 6 deletions(-) diff --git a/interpreter/parse_factor.cpp b/interpreter/parse_factor.cpp index f52aff10..6065513d 100644 --- a/interpreter/parse_factor.cpp +++ b/interpreter/parse_factor.cpp @@ -32,7 +32,6 @@ std::unique_ptr Parser::parse_a_token() { } skip_token("{"); - std::cerr << "[Debug output] pipe process begin\n"; auto stmt = parse_block(true); skip_token("}"); return std::make_unique("", std::move(params),std::move(stmt)); @@ -65,7 +64,6 @@ std::unique_ptr Parser::parse_a_token() { if (key == "}") { break; } - std::cerr << "[Debug output] member assignment: key: " << key << std::endl; skip_token("="); auto val = parse_expression(); if (curr_token().type == LexerTokenType::Comma) skip_token(","); diff --git a/interpreter/parse_stmt.cpp b/interpreter/parse_stmt.cpp index 739bccc0..0df5d3c3 100644 --- a/interpreter/parse_stmt.cpp +++ b/interpreter/parse_stmt.cpp @@ -3,7 +3,6 @@ std::unique_ptr Parser::parse_block(bool is_global) { std::vector> stmts; while (curr_token().type != LexerTokenType::RBrace) { - std::cerr << "[Debug output] block is going through statements\n"; stmts.emplace_back(parse_stmt()); if (curr_token().type == LexerTokenType::Semicolon) skip_token(";"); } diff --git a/interpreter/parser.cpp b/interpreter/parser.cpp index f21efdbe..0a88d4b3 100644 --- a/interpreter/parser.cpp +++ b/interpreter/parser.cpp @@ -35,7 +35,6 @@ Token Parser::curr_token() const { auto& tok = tokens_[curr_tok_idx_]; return tok; } - std::cerr << "[Debug output] token fetch got EOF\n"; return {LexerTokenType::EndOfFile, "", 0, 0}; } @@ -187,7 +186,6 @@ std::unique_ptr Parser::parse_stmt() { and tokens_[curr_tok_idx_ + 1].type == LexerTokenType::Assign ) { const auto name = skip_token().text; - std::cerr << "[Debug output] regarded as assignment\n"; skip_token("="); auto expr = parse_expression(); skip_end_of_ln(); @@ -195,7 +193,6 @@ std::unique_ptr Parser::parse_stmt() { } auto expr = parse_expression(); if (expr != nullptr and curr_token().text == "=") { - std::cerr << "[Debug output] regarded as member assignment\n"; if (dynamic_cast(expr.get())) { skip_token("="); auto value = parse_expression(); From 57ba515b7a90384a9f8aa1eea3bcf4fe30914c39 Mon Sep 17 00:00:00 2001 From: steambird1 Date: Fri, 7 Nov 2025 17:17:34 +0800 Subject: [PATCH 3/6] Handling EOLs --- interpreter/eval.cpp | 9 +++++++++ interpreter/interpreter.cpp | 3 +++ interpreter/lexer.cpp | 2 ++ interpreter/lexer.hpp | 2 ++ interpreter/parse_expr.cpp | 13 +++++++++++-- interpreter/parse_factor.cpp | 1 + interpreter/parse_stmt.cpp | 19 +++++++++++++++++-- interpreter/parser.cpp | 9 ++++++++- 8 files changed, 53 insertions(+), 5 deletions(-) diff --git a/interpreter/eval.cpp b/interpreter/eval.cpp index 1cc6d0b8..b149c86f 100644 --- a/interpreter/eval.cpp +++ b/interpreter/eval.cpp @@ -111,6 +111,7 @@ Value HANDLE_BINARYEXPR_ADD(Value* l, Value* r) { Value HANDLE_BINARYEXPR_STR_ADD_STR(Value* l, Value* r) { std::string ls = l->to_string(); std::string rs = r->to_string(); + /* try { // Try to parse both strings as CAS expressions and combine them symbolically LaminaCAS::Parser pl(ls); @@ -257,6 +258,8 @@ Value HANDLE_BINARYEXPR_STR_ADD_STR(Value* l, Value* r) { } catch (...) { // parsing failed for one or both strings; fall back to normal concatenation } + */ + return Value(ls + rs); } Value Interpreter::eval_LiteralExpr(const LiteralExpr* node) { @@ -805,6 +808,12 @@ Value Interpreter::eval_BinaryExpr(const BinaryExpr* bin) { } } + if (bin->op == "and" || bin->op == "or") { + bool lb = l.as_bool(), rb = r.as_bool(); + if (bin->op == "and") return lb and rb; + else if (bin->op == "or") return lb or rb; + } + L_ERR("Unknown binary operator '" + bin->op + "'"); return {}; } diff --git a/interpreter/interpreter.cpp b/interpreter/interpreter.cpp index 9855741d..ad3ad29c 100644 --- a/interpreter/interpreter.cpp +++ b/interpreter/interpreter.cpp @@ -95,6 +95,9 @@ void Interpreter::set_global_variable(const std::string& name, const Value& val) } Value Interpreter::execute(const std::unique_ptr& node) { + + std::cerr << "[Debug output] call of execute in interpreter!\n"; + if (!node) { return LAMINA_NULL; } diff --git a/interpreter/lexer.cpp b/interpreter/lexer.cpp index 23758f93..630d3665 100644 --- a/interpreter/lexer.cpp +++ b/interpreter/lexer.cpp @@ -30,6 +30,8 @@ void registerKeywords() { keywords["null"] = LexerTokenType::Null; keywords["do"] = LexerTokenType::Lambda; keywords["loop"] = LexerTokenType::Loop; + keywords["and"] = LexerTokenType::LogicalAnd; + keywords["or"] = LexerTokenType::LogicalOr; keywords_registered = true; } diff --git a/interpreter/lexer.hpp b/interpreter/lexer.hpp index 1c10e091..dad2769a 100644 --- a/interpreter/lexer.hpp +++ b/interpreter/lexer.hpp @@ -67,6 +67,8 @@ enum class LexerTokenType { Pipe, // | FatArrow, // => ThinArrow, // -> + LogicalAnd, + LogicalOr, EndOfFile, EndOfLine, Unknown diff --git a/interpreter/parse_expr.cpp b/interpreter/parse_expr.cpp index 6a226816..e7668691 100644 --- a/interpreter/parse_expr.cpp +++ b/interpreter/parse_expr.cpp @@ -3,8 +3,17 @@ #include "parser.hpp" std::unique_ptr Parser::parse_expression() { - // ToDo: add op support 'and' 'or' 'not in' 'in' - return parse_comparison(); + // ToDo: add op support 'not in' 'in' + auto node = parse_comparison(); + while (curr_token().type == LexerTokenType::LogicalAnd + or curr_token().type == LexerTokenType::LogicalOr + ) { + auto tok = curr_token(); + auto op = skip_token().text; + auto right = parse_comparison(); + node = std::make_unique(std::move(op), std::move(node), std::move(right)); + } + return node; } std::unique_ptr Parser::parse_comparison() { diff --git a/interpreter/parse_factor.cpp b/interpreter/parse_factor.cpp index 6065513d..e1265092 100644 --- a/interpreter/parse_factor.cpp +++ b/interpreter/parse_factor.cpp @@ -33,6 +33,7 @@ std::unique_ptr Parser::parse_a_token() { skip_token("{"); auto stmt = parse_block(true); + std::cerr << "[Debug output] lambda processor end!\n"; skip_token("}"); return std::make_unique("", std::move(params),std::move(stmt)); } diff --git a/interpreter/parse_stmt.cpp b/interpreter/parse_stmt.cpp index 0df5d3c3..06ba535a 100644 --- a/interpreter/parse_stmt.cpp +++ b/interpreter/parse_stmt.cpp @@ -1,10 +1,25 @@ #include "lexer.hpp" #include "parser.hpp" std::unique_ptr Parser::parse_block(bool is_global) { + // Is this boolean parameter really useful??? std::vector> stmts; while (curr_token().type != LexerTokenType::RBrace) { - stmts.emplace_back(parse_stmt()); - if (curr_token().type == LexerTokenType::Semicolon) skip_token(";"); + std::cerr << "[Debug output] parse through blocks! Current: " << curr_token().text << std::endl; + auto pres = parse_stmt(); + if (pres) + stmts.push_back(move(pres)); + else std::cerr << "[Debug output] resolved empty statement!\n"; + std::cerr << "[Debug output] statement parser end\n"; + // I think we should sooner or later make this an independent function: + bool flag = false; + do { + flag = false; + while (curr_token().type == LexerTokenType::Semicolon + or curr_token().type == LexerTokenType::EndOfLine) { + skip_token(); // Maybe shall be forced? + flag = true; + } + } while (flag); } return std::make_unique(std::move(stmts)); } diff --git a/interpreter/parser.cpp b/interpreter/parser.cpp index 0a88d4b3..56f5ebf7 100644 --- a/interpreter/parser.cpp +++ b/interpreter/parser.cpp @@ -79,17 +79,24 @@ std::vector> Parser::parse_program() { s != nullptr ) { stmts.push_back(std::move(s)); + std::cerr << "[Debug output] end of program statement processor!\n"; } } + std::cerr << "[Debug output] finished parser.\n"; return stmts; } std::unique_ptr Parser::parse_stmt() { + // A little bit weird, but ok for current use while (curr_tok_idx_ < tokens_.size() && curr_token().type == LexerTokenType::EndOfLine) { skip_token(); } auto tok = curr_token(); - + if (tok.type == LexerTokenType::EndOfFile || tok.type == LexerTokenType::Semicolon) { + std::cerr << "[Debug output] !!! Semicolon/EOF appeared at the beginning of statement parser !!!\n"; + return nullptr; + } + std::cerr << "[Debug output] in token: " << tok.text << std::endl; if (tok.type == LexerTokenType::If) { skip_token("if"); return parse_if(); From 89bf854a10ad85f34250bc72e5f0c227e53711fb Mon Sep 17 00:00:00 2001 From: steambird1 Date: Fri, 7 Nov 2025 17:18:14 +0800 Subject: [PATCH 4/6] Remove debug outputs --- interpreter/interpreter.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interpreter/interpreter.cpp b/interpreter/interpreter.cpp index ad3ad29c..bfe2a269 100644 --- a/interpreter/interpreter.cpp +++ b/interpreter/interpreter.cpp @@ -96,7 +96,7 @@ void Interpreter::set_global_variable(const std::string& name, const Value& val) Value Interpreter::execute(const std::unique_ptr& node) { - std::cerr << "[Debug output] call of execute in interpreter!\n"; + //std::cerr << "[Debug output] call of execute in interpreter!\n"; if (!node) { return LAMINA_NULL; From 971a462952ce1839f1ed9e2ef8044264821c41c4 Mon Sep 17 00:00:00 2001 From: steambird1 Date: Fri, 7 Nov 2025 17:18:29 +0800 Subject: [PATCH 5/6] Remove debug outputs --- interpreter/parse_factor.cpp | 2 +- interpreter/parse_stmt.cpp | 6 +++--- interpreter/parser.cpp | 8 ++++---- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/interpreter/parse_factor.cpp b/interpreter/parse_factor.cpp index e1265092..587199ba 100644 --- a/interpreter/parse_factor.cpp +++ b/interpreter/parse_factor.cpp @@ -33,7 +33,7 @@ std::unique_ptr Parser::parse_a_token() { skip_token("{"); auto stmt = parse_block(true); - std::cerr << "[Debug output] lambda processor end!\n"; + //std::cerr << "[Debug output] lambda processor end!\n"; skip_token("}"); return std::make_unique("", std::move(params),std::move(stmt)); } diff --git a/interpreter/parse_stmt.cpp b/interpreter/parse_stmt.cpp index 06ba535a..d0c979fd 100644 --- a/interpreter/parse_stmt.cpp +++ b/interpreter/parse_stmt.cpp @@ -4,12 +4,12 @@ std::unique_ptr Parser::parse_block(bool is_global) { // Is this boolean parameter really useful??? std::vector> stmts; while (curr_token().type != LexerTokenType::RBrace) { - std::cerr << "[Debug output] parse through blocks! Current: " << curr_token().text << std::endl; + //std::cerr << "[Debug output] parse through blocks! Current: " << curr_token().text << std::endl; auto pres = parse_stmt(); if (pres) stmts.push_back(move(pres)); - else std::cerr << "[Debug output] resolved empty statement!\n"; - std::cerr << "[Debug output] statement parser end\n"; + //else std::cerr << "[Debug output] resolved empty statement!\n"; + //std::cerr << "[Debug output] statement parser end\n"; // I think we should sooner or later make this an independent function: bool flag = false; do { diff --git a/interpreter/parser.cpp b/interpreter/parser.cpp index 56f5ebf7..37d89aa2 100644 --- a/interpreter/parser.cpp +++ b/interpreter/parser.cpp @@ -79,10 +79,10 @@ std::vector> Parser::parse_program() { s != nullptr ) { stmts.push_back(std::move(s)); - std::cerr << "[Debug output] end of program statement processor!\n"; + //std::cerr << "[Debug output] end of program statement processor!\n"; } } - std::cerr << "[Debug output] finished parser.\n"; + //std::cerr << "[Debug output] finished parser.\n"; return stmts; } @@ -93,10 +93,10 @@ std::unique_ptr Parser::parse_stmt() { } auto tok = curr_token(); if (tok.type == LexerTokenType::EndOfFile || tok.type == LexerTokenType::Semicolon) { - std::cerr << "[Debug output] !!! Semicolon/EOF appeared at the beginning of statement parser !!!\n"; + //std::cerr << "[Debug output] !!! Semicolon/EOF appeared at the beginning of statement parser !!!\n"; return nullptr; } - std::cerr << "[Debug output] in token: " << tok.text << std::endl; + //std::cerr << "[Debug output] in token: " << tok.text << std::endl; if (tok.type == LexerTokenType::If) { skip_token("if"); return parse_if(); From ff7976eb1aea743e9775c0348a76bd163e23b67f Mon Sep 17 00:00:00 2001 From: steambird1 Date: Sat, 8 Nov 2025 11:09:01 +0800 Subject: [PATCH 6/6] To-some-degree cherry pick --- extensions/standard/array.cpp | 73 ++++++++++++++++++++++++++++ extensions/standard/standard.hpp | 13 +++++ interpreter/eval.cpp | 75 ++++++++++++++++++++++++++-- interpreter/interpreter.cpp | 81 +++++++++++++++++++++---------- interpreter/interpreter.hpp | 5 +- interpreter/lamina_api/lamina.hpp | 14 ++++-- interpreter/lamina_api/value.hpp | 71 ++++++++++++++++++++++++++- interpreter/lexer.cpp | 1 + interpreter/lexer.hpp | 1 + interpreter/parse_expr.cpp | 7 ++- interpreter/parser.cpp | 11 ++--- 11 files changed, 306 insertions(+), 46 deletions(-) diff --git a/extensions/standard/array.cpp b/extensions/standard/array.cpp index 54f5420d..e7ef51f0 100644 --- a/extensions/standard/array.cpp +++ b/extensions/standard/array.cpp @@ -187,3 +187,76 @@ Value replace(const std::vector& args) { arr = result; return arr; } + + +// 拼接给定的所有列表 +Value concat(const std::vector& args) { + std::vector result; + for (const auto &i : args) { + if (!i.is_array()) { + L_ERR("Given parameter(s) have no-array element"); + return LAMINA_NULL; + } + for (const auto &j : std::get >(i.data)) { + result.push_back(j); + } + } + return Value(result); +} + +// 列表切片 +Value slice(const std::vector& args) { + check_cpp_function_argv_x(args, 3, 4); + if (!args[0].is_array()) { + L_ERR("slice() requires a list"); + return LAMINA_NULL; + } + std::vector val = std::get >(args[0].data); + std::vector result; + int begin = (int) args[1].as_number(), end = (int) args[2].as_number(), step = 1; + if (end < begin) step = -1; + if (args.size() >= 4) { + step = (int) args[3].as_number(); + } + for (int i = begin; i != end; i += step) { + int it = (i >= 0) ? i : (int(val.size()) + i); + if (it < 0 || it >= val.size()) { + break; + } + result.push_back(val[it]); + } + return Value(result); +} + +// 排序给定的列表,第二个参数表示比较器 +Value _sort(const std::vector& args) { + check_cpp_function_argv_x(args, 1, 2); + if (!args[0].is_array()) { + L_ERR("sort() requires a list"); + return LAMINA_NULL; + } + std::vector val = std::get >(args[0].data); + for (auto &i : val) { + if (!i.is_comparable()) { + L_ERR("Array has uncomparable object"); + return args[0]; // A failure, not an error. + } + } + std::function comparer; + if (args.size() >= 2) { + if (!args[1].is_lambda()) { + L_ERR("Comparer must be a lambda/function"); + return LAMINA_NULL; + } + const auto func = std::get>(args[1].data); + comparer = [&func](const Value &a, const Value &b) -> bool { + return Interpreter::call_function(func.get(), {a, b}).as_bool(); + }; + } else { + comparer = [](const Value &a, const Value &b) -> bool { + return a < b; + }; + } + sort(val.begin(), val.end(), comparer); + return Value(val); +} \ No newline at end of file diff --git a/extensions/standard/standard.hpp b/extensions/standard/standard.hpp index 69188c3a..a30f14af 100644 --- a/extensions/standard/standard.hpp +++ b/extensions/standard/standard.hpp @@ -150,6 +150,15 @@ Value map(const std::vector& args); // 替换内容:需3个参数(原字符串/容器、目标值、替换值),替换所有匹配的目标值并返回新结果 Value replace(const std::vector& args); +// 拼接给定的所有列表 +Value concat(const std::vector& args); + +// 切片,可以为 [a:b] 或 [a:b:c] +Value slice(const std::vector& args); + +// 排序给定的列表,第二个参数表示比较器 +Value _sort(const std::vector& args); + // 变量表 Value vars(const std::vector& args); @@ -298,6 +307,10 @@ inline std::unordered_map register_builtins = LAMINA_FUNC("find", find), LAMINA_FUNC("map", map), LAMINA_FUNC("replace", replace), + + LAMINA_FUNC("concat", concat), + LAMINA_FUNC("slice", slice), + LAMINA_FUNC("sort", _sort), // CAS数学模块:封装符号计算相关的解析、化简、求导等功能 LAMINA_MODULE("cas", LAMINA_VERSION, { diff --git a/interpreter/eval.cpp b/interpreter/eval.cpp index b149c86f..10955755 100644 --- a/interpreter/eval.cpp +++ b/interpreter/eval.cpp @@ -74,7 +74,7 @@ Value HANDLE_BINARYEXPR_ADD(Value* l, Value* r) { return Value(l->to_string() + r->to_string()); } else if (ltype & VALUE_IS_ARRAY && rtype & VALUE_IS_ARRAY) { // Vector addition - return l->vector_add(r); + return l->vector_add(*r); // 只要有一方是 Irrational 或 Symbolic,优先生成符号表达式 } else if (((ltype & VALUE_IS_IRRATIONAL) || (ltype & VALUE_IS_SYMBOLIC) || (rtype & VALUE_IS_IRRATIONAL) || (rtype & VALUE_IS_SYMBOLIC)) && (ltype & VALUE_IS_NUMERIC) && (rtype & VALUE_IS_NUMERIC)) { std::shared_ptr leftExpr = GET_SYMBOLICEXPR(l, ltype); @@ -340,11 +340,13 @@ Value Interpreter::eval_CallExpr(const CallExpr* call) { return {}; } // User function - return Interpreter::call_function(func.get(), args, self); + return Interpreter::call_function(func.get(), args, self, left.in_module ? Value(left.in_module) : LAMINA_NULL); } if (std::holds_alternative>(left.data)) { push_frame("", " "); + push_scope(); + set_module_as(left.in_module ? Value(left.in_module) : LAMINA_NULL); Value result; std::shared_ptr func; @@ -353,9 +355,11 @@ Value Interpreter::eval_CallExpr(const CallExpr* call) { result = func->function(args); } catch (...) { pop_frame(); + pop_scope(); throw; } pop_frame(); + pop_scope(); return result; } @@ -363,7 +367,7 @@ Value Interpreter::eval_CallExpr(const CallExpr* call) { return {}; } -Value Interpreter::call_function(const LambdaDeclExpr* func, const std::vector& args, Value self) { +Value Interpreter::call_function(const LambdaDeclExpr* func, const std::vector& args, Value self, Value module) { if (func == nullptr) { std::cerr << "Error: Function at '" << func << "' is null" << std::endl; return Value(""); @@ -372,6 +376,7 @@ Value Interpreter::call_function(const LambdaDeclExpr* func, const std::vectorname, "