| | |
| | | /** |
| | | * @brief Expression node representing a function call returning a value. |
| | | */ |
| | | class CallExpressionNode : public ExpressionNode { |
| | | std::string functionName_; |
| | | std::vector<std::unique_ptr<ExpressionNode>> args_; |
| | | class CallExpressionNode : public ExpressionNode { |
| | | std::string functionName_; |
| | | std::vector<std::unique_ptr<ExpressionNode>> args_; |
| | | // Source location for error reporting |
| | | std::string filename_; |
| | | int line_; |
| | | size_t column_; |
| | | |
| | | public: |
| | | CallExpressionNode(std::string functionName, |
| | | std::vector<std::unique_ptr<ExpressionNode>> args) : |
| | | functionName_(std::move(functionName)), args_(std::move(args)) {} |
| | | std::vector<std::unique_ptr<ExpressionNode>> args, |
| | | const std::string & filename, |
| | | int line, size_t column) : |
| | | functionName_(std::move(functionName)), args_(std::move(args)), |
| | | filename_(filename), line_(line), column_(column) {} |
| | | |
| | | 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)); |
| | | } |
| | | try { |
| | | // 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); |
| | | } |
| | | // Built-in function |
| | | auto &mgr = Modules::ModuleManager::instance(); |
| | | if (mgr.hasFunction(functionName_)) { |
| | | return mgr.callFunction(functionName_, argValues); |
| | | } |
| | | |
| | | // User-defined function: lookup through scope hierarchy |
| | | SymbolContainer *sc = SymbolContainer::instance(); |
| | | std::string lookupNs = sc->currentScopeName(); |
| | | std::shared_ptr<FunctionSymbol> funcSym; |
| | | // Search for function symbol in current and parent scopes |
| | | while (true) { |
| | | std::string fnSymNs = lookupNs + ".functions"; |
| | | auto sym = sc->get(fnSymNs, functionName_); |
| | | if (sym && sym->getKind() == Kind::Function) { |
| | | funcSym = std::static_pointer_cast<FunctionSymbol>(sym); |
| | | break; |
| | | } |
| | | auto pos = lookupNs.find_last_of('.'); |
| | | if (pos == std::string::npos) { |
| | | break; |
| | | } |
| | | lookupNs = lookupNs.substr(0, pos); |
| | | } |
| | | if (!funcSym) { |
| | | throw std::runtime_error("Function not found: " + functionName_); |
| | | } |
| | | 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 = funcSym->context() + "." + 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; |
| | | // User-defined function: lookup through scope hierarchy |
| | | SymbolContainer *sc = SymbolContainer::instance(); |
| | | std::string lookupNs = sc->currentScopeName(); |
| | | std::shared_ptr<FunctionSymbol> funcSym; |
| | | // Search for function symbol in current and parent scopes |
| | | while (true) { |
| | | std::string fnSymNs = lookupNs + ".functions"; |
| | | auto sym = sc->get(fnSymNs, functionName_); |
| | | if (sym && sym->getKind() == Kind::Function) { |
| | | funcSym = std::static_pointer_cast<FunctionSymbol>(sym); |
| | | break; |
| | | } |
| | | auto pos = lookupNs.find_last_of('.'); |
| | | if (pos == std::string::npos) { |
| | | break; |
| | | } |
| | | lookupNs = lookupNs.substr(0, pos); |
| | | } |
| | | if (!funcSym) { |
| | | throw std::runtime_error("Function not found: " + functionName_); |
| | | } |
| | | 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 = funcSym->context() + "." + 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; |
| | | } catch (const std::exception &e) { |
| | | throw ::Interpreter::Exception(e.what(), filename_, line_, column_); |
| | | } |
| | | // Unreachable: all paths either return or throw |
| | | return Symbols::Value(); |
| | | } |
| | | |
| | | std::string toString() const override { |