| src/Interpreter/CallExpressionNode.hpp | ●●●●● patch | view | raw | blame | history | |
| src/Interpreter/ExpressionBuilder.hpp | ●●●●● patch | view | raw | blame | history | |
| src/Parser/ParsedExpression.hpp | ●●●●● patch | view | raw | blame | history | |
| src/Parser/Parser.cpp | ●●●●● patch | view | raw | blame | history | |
| test_scripts/function_test.vs | ●●●●● patch | view | raw | blame | history |
src/Interpreter/CallExpressionNode.hpp
New file @@ -0,0 +1,96 @@ #ifndef INTERPRETER_CALL_EXPRESSION_NODE_HPP #define INTERPRETER_CALL_EXPRESSION_NODE_HPP #include <string> #include <vector> #include <memory> #include "Interpreter/ExpressionNode.hpp" #include "Interpreter/Interpreter.hpp" #include "Interpreter/ReturnException.hpp" #include "Interpreter/OperationContainer.hpp" #include "Interpreter/Operation.hpp" #include "Symbols/SymbolContainer.hpp" #include "Symbols/SymbolFactory.hpp" #include "Symbols/FunctionSymbol.hpp" #include "Symbols/Value.hpp" #include "Modules/ModuleManager.hpp" namespace Interpreter { /** * @brief Expression node representing a function call returning a value. */ class CallExpressionNode : public ExpressionNode { std::string functionName_; std::vector<std::unique_ptr<ExpressionNode>> args_; public: CallExpressionNode(std::string functionName, std::vector<std::unique_ptr<ExpressionNode>> args) : functionName_(std::move(functionName)), args_(std::move(args)) {} Symbols::Value evaluate(Interpreter &interpreter) const override { using namespace Symbols; // Evaluate argument expressions std::vector<Value> argValues; argValues.reserve(args_.size()); for (const auto &expr : args_) { argValues.push_back(expr->evaluate(interpreter)); } // Built-in function auto &mgr = Modules::ModuleManager::instance(); if (mgr.hasFunction(functionName_)) { return mgr.callFunction(functionName_, argValues); } // User-defined function SymbolContainer *sc = Symbols::SymbolContainer::instance(); const std::string currentNs = sc->currentScopeName(); const std::string fnSymNs = currentNs + ".functions"; auto sym = sc->get(fnSymNs, functionName_); if (!sym || sym->getKind() != Kind::Function) { throw std::runtime_error("Function not found: " + functionName_); } auto funcSym = std::static_pointer_cast<FunctionSymbol>(sym); const auto ¶ms = funcSym->parameters(); if (params.size() != argValues.size()) { throw std::runtime_error( "Function '" + functionName_ + "' expects " + std::to_string(params.size()) + " args, got " + std::to_string(argValues.size())); } // Enter function scope and bind parameters const std::string fnOpNs = currentNs + "." + functionName_; sc->enter(fnOpNs); for (size_t i = 0; i < params.size(); ++i) { const auto &p = params[i]; const Value &v = argValues[i]; auto varSym = SymbolFactory::createVariable(p.name, v, fnOpNs); sc->add(varSym); } // Execute function body operations and capture return Symbols::Value returnValue; auto ops = Operations::Container::instance()->getAll(fnOpNs); for (const auto &op : ops) { try { interpreter.runOperation(*op); } catch (const ReturnException &ret) { returnValue = ret.value(); break; } } sc->enterPreviousScope(); return returnValue; } std::string toString() const override { return "CallExpressionNode{ function='" + functionName_ + "', args=" + std::to_string(args_.size()) + " }"; } }; } // namespace Interpreter #endif // INTERPRETER_CALL_EXPRESSION_NODE_HPP src/Interpreter/ExpressionBuilder.hpp
@@ -9,6 +9,7 @@ #include "Interpreter/IdentifierExpressionNode.hpp" #include "Interpreter/LiteralExpressionNode.hpp" #include "Interpreter/UnaryExpressionNode.hpp" // <-- új include #include "Interpreter/CallExpressionNode.hpp" #include "Parser/ParsedExpression.hpp" namespace Parser { @@ -35,6 +36,16 @@ auto operand = buildExpressionFromParsed(expr->rhs); // rhs az operandus return std::make_unique<Interpreter::UnaryExpressionNode>(expr->op, std::move(operand)); } case Kind::Call: { // Build argument expressions std::vector<std::unique_ptr<Interpreter::ExpressionNode>> callArgs; callArgs.reserve(expr->args.size()); for (const auto &arg : expr->args) { callArgs.push_back(buildExpressionFromParsed(arg)); } return std::make_unique<Interpreter::CallExpressionNode>(expr->name, std::move(callArgs)); } } throw std::runtime_error("Unknown ParsedExpression kind"); src/Parser/ParsedExpression.hpp
@@ -3,9 +3,11 @@ #include <memory> #include <string> #include <vector> #include "../Symbols/SymbolContainer.hpp" #include "../Symbols/Value.hpp" #include "../Symbols/FunctionSymbol.hpp" namespace Parser { @@ -14,7 +16,7 @@ using ParsedExpressionPtr = std::unique_ptr<ParsedExpression>; struct ParsedExpression { enum class Kind : std::uint8_t { Literal, Variable, Binary, Unary }; enum class Kind : std::uint8_t { Literal, Variable, Binary, Unary, Call }; Kind kind; @@ -25,6 +27,8 @@ std::string op; ParsedExpressionPtr lhs; ParsedExpressionPtr rhs; // For function call arguments std::vector<ParsedExpressionPtr> args; // Constructor for literal static ParsedExpressionPtr makeLiteral(const Symbols::Value & val) { @@ -60,6 +64,14 @@ expr->rhs = std::move(operand); return expr; } // Constructor for function call static ParsedExpressionPtr makeCall(const std::string &name, std::vector<ParsedExpressionPtr> arguments) { auto expr = std::make_unique<ParsedExpression>(); expr->kind = Kind::Call; expr->name = name; expr->args = std::move(arguments); return expr; } Symbols::Variables::Type getType() const { switch (kind) { @@ -93,6 +105,17 @@ } break; } case Kind::Call: { const std::string ns = Symbols::SymbolContainer::instance()->currentScopeName() + ".functions"; auto symbol = Symbols::SymbolContainer::instance()->get(ns, name); if (!symbol) { throw std::runtime_error("Unknown function: " + name + " in namespace: " + ns); } // FunctionSymbol holds return type auto funcSym = std::static_pointer_cast<Symbols::FunctionSymbol>(symbol); return funcSym->returnType(); } default: throw std::runtime_error("Unknown expression kind"); src/Parser/Parser.cpp
@@ -311,6 +311,30 @@ // Pop the matching "(" operator_stack.pop(); expect_unary = false; } // Function call as expression: identifier followed by '(' else if (token.type == Lexer::Tokens::Type::IDENTIFIER && peekToken().type == Lexer::Tokens::Type::PUNCTUATION && peekToken().value == "(") { // Parse function call std::string func_name = token.value; consumeToken(); // consume function name consumeToken(); // consume '(' std::vector<ParsedExpressionPtr> call_args; // Parse arguments if any if (!(currentToken().type == Lexer::Tokens::Type::PUNCTUATION && currentToken().value == ")")) { while (true) { auto arg_expr = parseParsedExpression(Symbols::Variables::Type::NULL_TYPE); call_args.push_back(std::move(arg_expr)); if (match(Lexer::Tokens::Type::PUNCTUATION, ",")) { continue; } break; } } expect(Lexer::Tokens::Type::PUNCTUATION, ")"); // Create call expression node output_queue.push_back(ParsedExpression::makeCall(func_name, std::move(call_args))); expect_unary = false; } else if (token.type == Lexer::Tokens::Type::OPERATOR_ARITHMETIC) { std::string op = std::string(token.lexeme); test_scripts/function_test.vs
@@ -7,7 +7,6 @@ function test = (int $i) { print("Param: ",$i); int $result = $i + 1; print("The result is: ", $result); } function increment = (int $i) int { @@ -15,7 +14,7 @@ } test(1); int $z = 10; increment($z); int $t = increment(2); print("The result is: ", $t);