diff --git a/inc/ast/visitors/EvalVisitor.hpp b/inc/ast/visitors/EvalVisitor.hpp index 73a2287..f08a4c2 100644 --- a/inc/ast/visitors/EvalVisitor.hpp +++ b/inc/ast/visitors/EvalVisitor.hpp @@ -77,7 +77,6 @@ namespace ast private: std::ostream &_output; runtime::Object _expressionResult; - runtime::State::ptr _globalState; runtime::State::ptr _localState; const runtime::Object &evaluate(const ast::ExpressionNode::ptr &expr); diff --git a/input.txt b/input.txt index cabb1e4..fc0a12c 100644 --- a/input.txt +++ b/input.txt @@ -32,15 +32,29 @@ else if (i == 0) else print("i is smaller than 0"); -for (int i = 0; i < 5 && i < 10; i = i + 1) +for (int i = 0; i < 5 && i < 10; i = i + 1) { print(i); +} -fnc print_str(s string) { +fnc print_str(str s) { print(s); } fnc div(int n, int m) int { + fnc print_int() { + print(42); + } + print_int(); return n / m; } -int r = div(4, 2); \ No newline at end of file +int r = div(4, 2); + +print_str("yo"); + +{ + fnc foo() { + print("foo"); + } + foo(); +} diff --git a/src/ast/visitors/EvalVisitor.cpp b/src/ast/visitors/EvalVisitor.cpp index d02d62e..ee6851d 100644 --- a/src/ast/visitors/EvalVisitor.cpp +++ b/src/ast/visitors/EvalVisitor.cpp @@ -202,8 +202,7 @@ void ast::EvalVisitor::clearState() noexcept ast::EvalVisitor::EvalVisitor(std::ostream &output) : _output(output), _expressionResult(), - _globalState(runtime::State::create()), - _localState(runtime::State::create(this->_globalState)) + _localState(runtime::State::create()) {} void ast::EvalVisitor::visit(ast::WhileNode &node) @@ -283,8 +282,7 @@ void ast::EvalVisitor::visit(ast::FunctionNode &node) { runtime::Object object(node); - // Add function object to global state, so it can be called from anywhere, including functions - this->_globalState->set(node.getIdentifier(), object); + this->_localState->set(node.getIdentifier(), object); } void ast::EvalVisitor::visit(ast::CallNode &node) @@ -305,7 +303,7 @@ void ast::EvalVisitor::visit(ast::CallNode &node) // Create a new state for the function. // function's state takes global state as parent state, so declared functions can be called from the current function // but variables of the current state cannot be references from current function. - auto state = runtime::State::create(this->_globalState); + auto state = runtime::State::create(this->_localState); for (std::size_t i = 0; i < params.size(); i++) { auto evaluatedParam = this->evaluate(params[i]); diff --git a/tst/evaluator/statements_test.cpp b/tst/evaluator/statements_test.cpp index 5ab9a8c..008da0a 100644 --- a/tst/evaluator/statements_test.cpp +++ b/tst/evaluator/statements_test.cpp @@ -374,7 +374,7 @@ TEST(StatementTest, Functions) .expectedOutput = "8\n" }, StatementTest{ - .description = "3. Declared function scope should not have access to outer variables", + .description = "3. Declared function scope should have access to outer variables", .program = "{ " " int n = 0; " " fnc f() { " @@ -382,7 +382,7 @@ TEST(StatementTest, Functions) " } " " f(); " "} ", - .shouldThrow = true + .expectedOutput = "0\n" }, StatementTest{ .description = "4. Calling a function from a function", @@ -526,6 +526,62 @@ TEST(StatementTest, Functions) "2\n" "4\n" "256\n" + }, + StatementTest{ + .description = "17. Function defined in function", + .program = + "{ " + " fnc div(int n, int m) int { " + " fnc print_int() { " + " print(42); " + " } " + " print_int(); " + " return n / m; " + " } " + " div(4, 2); " + "} ", + .expectedOutput = "42\n" + }, + StatementTest{ + .description = "18. Function in block", + .program = + "{ " + " { " + " fnc foo() { " + " print(\"foo\"); " + " } " + " foo(); " + " } " + "} ", + .expectedOutput = "foo\n" + }, + StatementTest{ + .description = "19. Function called outside of scope #1", + .program = + "{ " + " fnc div(int n, int m) int { " + " fnc print_int() { " + " print(42); " + " } " + " return n / m; " + " } " + " div(4, 2); " + " print_int(); " + "} ", + .shouldThrow = true + }, + StatementTest{ + .description = "20. Function called outside of scope #2", + .program = + "{ " + " { " + " fnc foo() { " + " print(\"foo\"); " + " } " + " } " + " foo(); " + "} ", + .shouldThrow = true } };