From acb1c33ab258dc14dcc51b405b44cc5923b34324 Mon Sep 17 00:00:00 2001
From: Ferenc Szontágh <szf@fsociety.hu>
Date: Fri, 18 Apr 2025 08:52:16 +0000
Subject: [PATCH] add function call

---
 src/Parser/Parser.cpp                 |    9 +
 /dev/null                             |  144 ------------------------
 src/Interpreter/CallStatementNode.hpp |   90 +++++++++++++++
 src/Symbols/SymbolFactory.hpp         |    5 
 src/Interpreter/OperationsFactory.hpp |   18 ++
 src/Lexer/Operators.hpp               |   12 +
 test_scripts/test2.vs                 |    8 
 src/Interpreter/Interpreter.hpp       |   33 +++--
 8 files changed, 150 insertions(+), 169 deletions(-)

diff --git "a/src/\041NameSpaceManager.hpp" "b/src/\041NameSpaceManager.hpp"
deleted file mode 100644
index fa249e9..0000000
--- "a/src/\041NameSpaceManager.hpp"
+++ /dev/null
@@ -1,144 +0,0 @@
-#ifndef NAMESPACE_MANAGER_H
-#define NAMESPACE_MANAGER_H
-#include <functional>
-#include <map>
-#include <memory>
-#include <sstream>
-#include <string>
-#include <vector>
-
-class Namespace {
-  public:
-    Namespace(const std::string & name = "", Namespace * parent = nullptr) : name_(name), parent_(parent) {}
-
-    /**
-    * @brief Add a child namespace to the current namespace.
-    * @param name Name of the child namespace.
-    */
-    Namespace * addChild(const std::string & name) {
-        auto it = children_.find(name);
-        if (it == children_.end()) {
-            children_[name] = std::make_unique<Namespace>(name, this);
-        }
-        return children_[name].get();
-    }
-
-    /**
-    * @brief Get the child namespace by name.
-    * @param name Name of the child namespace.
-    * @return The child namespace
-    */
-    Namespace * getChild(const std::string & name) const {
-        auto it = children_.find(name);
-        return it != children_.end() ? it->second.get() : nullptr;
-    }
-
-    /**
-    * @brief Get the child namespace by name.
-    * @param name Name of the child namespace.
-    * @return The child namespace
-    */
-    Namespace * getOrCreate(const std::string & fullName) {
-        auto        parts   = split(fullName, '.');
-        Namespace * current = this;
-        for (const auto & part : parts) {
-            current = current->addChild(part);
-        }
-        return current;
-    }
-
-    /**
-    * @brief Get the parent namespace.
-    * @return The parent namespace.
-    */
-    Namespace * getParent() const { return parent_; }
-
-    std::string toString() const {
-        if (!parent_ || name_.empty()) {
-            return name_;
-        }
-        return parent_->toString() + "." + name_;
-    }
-
-    void traverse(const std::function<void(const Namespace &)>& visitor) const {
-        visitor(*this);
-        for (const auto & [_, child] : children_) {
-            child->traverse(visitor);
-        }
-    }
-
-    const std::string & getName() const { return name_; }
-
-  private:
-    std::string                                       name_;
-    Namespace *                                       parent_;
-    std::map<std::string, std::unique_ptr<Namespace>> children_;
-
-    static std::vector<std::string> split(const std::string & str, char delimiter) {
-        std::stringstream        ss(str);
-        std::string              part;
-        std::vector<std::string> result;
-        while (std::getline(ss, part, delimiter)) {
-            result.push_back(part);
-        }
-        return result;
-    }
-};
-
-class NamespaceManager {
-  public:
-    static NamespaceManager & instance() {
-        static NamespaceManager instance_;
-        return instance_;
-    }
-
-    /**
-     * @brief Constructor for NamespaceManager.
-     * @param name Name of the namespace.
-     * @param parent Parent namespace.
-     */
-    NamespaceManager() : root_(""), currentNamespace_(&root_) {}
-
-    /**
-    * @brief Get or create a namespace by full name.
-    * @param fullName Full name of the namespace.
-    * @return The namespace object.
-    */
-    Namespace * getOrCreate(const std::string & fullName) { return root_.getOrCreate(fullName); }
-
-    /**
-    * @brief Set the current namespace.
-    * @param fullName Full name of the namespace.
-    */
-    void setCurrent(const std::string & fullName) {
-        Namespace * ns = root_.getOrCreate(fullName);
-        if (ns) {
-            currentNamespace_ = ns;
-        } else {
-            currentNamespace_ = &root_;  // fallback
-        }
-    }
-
-    /**
-    * @brief Get the current namespace.
-    * @return The current namespace object.
-    */
-    Namespace * getCurrent() const { return currentNamespace_; }
-
-    /**
-    * @brief Reset the current namespace.
-    */
-    void resetCurrent() { currentNamespace_ = &root_; }
-
-    /**
-    * @brief Traverse the namespace tree.
-    * @param visitor A function to visit each namespace.
-    */
-    void traverse(const std::function<void(const Namespace &)>& visitor) const { root_.traverse(visitor); }
-
-  private:
-    Namespace   root_;
-    Namespace * currentNamespace_;
-};
-
-#endif  // NAMESPACE_MANAGER_H
diff --git a/src/Interpreter/CallStatementNode.hpp b/src/Interpreter/CallStatementNode.hpp
new file mode 100644
index 0000000..ccd85a1
--- /dev/null
+++ b/src/Interpreter/CallStatementNode.hpp
@@ -0,0 +1,90 @@
+#ifndef INTERPRETER_CALL_STATEMENT_NODE_HPP
+#define INTERPRETER_CALL_STATEMENT_NODE_HPP
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "ExpressionNode.hpp"
+#include "Interpreter/Interpreter.hpp"
+#include "Interpreter/OperationContainer.hpp"
+#include "StatementNode.hpp"
+#include "Symbols/FunctionSymbol.hpp"
+#include "Symbols/SymbolContainer.hpp"
+#include "Symbols/SymbolFactory.hpp"
+#include "Symbols/Value.hpp"
+
+namespace Interpreter {
+
+/**
+ * @brief Statement node representing a function call with argument expressions.
+ */
+class CallStatementNode : public StatementNode {
+    std::string                                  functionName_;
+    std::vector<std::unique_ptr<ExpressionNode>> args_;
+
+  public:
+    CallStatementNode(const std::string & functionName, std::vector<std::unique_ptr<ExpressionNode>> args,
+                      const std::string & file_name, int file_line, size_t column) :
+        StatementNode(file_name, file_line, column),
+        functionName_(functionName),
+        args_(std::move(args)) {}
+
+    void interpret(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));
+        }
+
+        // Lookup function symbol in functions namespace
+        SymbolContainer * sc        = 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);
+
+        // Check parameter count
+        const auto & params = 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 to bind parameters and execute body
+        const std::string fnOpNs = currentNs + "." + functionName_;
+        sc->enter(fnOpNs);
+        // Bind parameters as local variables
+        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
+        auto ops = Operations::Container::instance()->getAll(fnOpNs);
+        auto it  = ops.begin();
+        for (; it != ops.end(); ++it) {
+            interpreter.runOperation(*(*it));
+        }
+        // Exit function scope
+        sc->enterPreviousScope();
+    }
+
+    std::string toString() const override {
+        return "CallStatementNode{ functionName='" + functionName_ + "', " +
+               "args=" + std::to_string(args_.size()) + " " + "filename='" + filename_ + "', " +
+               "line=" + std::to_string(line_) + ", " + "column=" + std::to_string(column_) + "}";
+    };
+};
+
+}  // namespace Interpreter
+
+// namespace Interpreter
+#endif  // INTERPRETER_CALL_STATEMENT_NODE_HPP
diff --git a/src/Interpreter/Interpreter.hpp b/src/Interpreter/Interpreter.hpp
index b8e2ce8..fe1dfb7 100644
--- a/src/Interpreter/Interpreter.hpp
+++ b/src/Interpreter/Interpreter.hpp
@@ -12,6 +12,22 @@
 
 class Interpreter {
   private:
+
+
+  public:
+    Interpreter() {}
+
+    /**
+     * @brief Execute all operations in the current namespace (e.g., file-level or function-level).
+     */
+    void run() {
+        // Determine namespace to execute
+        const std::string ns = Symbols::SymbolContainer::instance()->currentScopeName();
+        for (const auto & operation : Operations::Container::instance()->getAll(ns)) {
+            runOperation(*operation);
+        }
+    }
+
     void runOperation(const Operations::Operation & op) {
         std::cout << "Operation: " << op.toString() << "\n";
 
@@ -39,13 +55,11 @@
                     break;
                 }
 
-            case Operations::Type::FunctionCall: {
-                // Check that the called function is defined in the symbol table
-                if (!Symbols::SymbolContainer::instance()->exists(op.targetName)) {
-                    throw std::runtime_error("Function not declared: " + op.targetName);
+            case Operations::Type::FunctionCall:
+                if (op.statement) {
+                    op.statement->interpret(*this);
                 }
                 break;
-            }
             case Operations::Type::Return:
             case Operations::Type::Loop:
             case Operations::Type::Break:
@@ -58,15 +72,6 @@
                 break;
             default:
                 throw std::runtime_error("Not implemented operation type");
-        }
-    }
-
-  public:
-    Interpreter() {}
-
-    void run() {
-        for (const auto & operation : Operations::Container::instance()->getAll()) {
-            runOperation(*operation);
         }
     }
 
diff --git a/src/Interpreter/OperationsFactory.hpp b/src/Interpreter/OperationsFactory.hpp
index 2dc39af..2034a72 100644
--- a/src/Interpreter/OperationsFactory.hpp
+++ b/src/Interpreter/OperationsFactory.hpp
@@ -8,6 +8,7 @@
 #include "Interpreter/DeclareVariableStatementNode.hpp"
 #include "Interpreter/ExpressionBuilder.hpp"
 #include "Interpreter/LiteralExpressionNode.hpp"
+#include "Interpreter/CallStatementNode.hpp"
 #include "Interpreter/Operation.hpp"
 #include "Interpreter/OperationContainer.hpp"
 #include "Parser/ParsedExpression.hpp"
@@ -54,22 +55,31 @@
                                           }
     
     /**
-     * @brief Record a function call operation for later detection.
+     * @brief Record a function call operation with argument expressions.
      * @param functionName Name of the function being called.
-     * @param ns Current namespace scope.
+     * @param parsedArgs Vector of parsed argument expressions.
+     * @param ns Current namespace scope for operations.
      * @param fileName Source filename.
      * @param line Line number of call.
      * @param column Column number of call.
      */
     static void callFunction(const std::string & functionName,
+                             std::vector<Parser::ParsedExpressionPtr> &&parsedArgs,
                              const std::string & ns,
                              const std::string & fileName,
                              int line,
                              size_t column) {
-        // No associated StatementNode; this is for detection only
+        // Build argument ExpressionNode list
+        std::vector<std::unique_ptr<ExpressionNode>> exprs;
+        exprs.reserve(parsedArgs.size());
+        for (auto &pexpr : parsedArgs) {
+            exprs.push_back(buildExpressionFromParsed(pexpr));
+        }
+        // Create call statement node
+        auto stmt = std::make_unique<CallStatementNode>(functionName, std::move(exprs), fileName, line, column);
         Operations::Container::instance()->add(
             ns,
-            Operations::Operation{Operations::Type::FunctionCall, functionName, nullptr});
+            Operations::Operation{Operations::Type::FunctionCall, functionName, std::move(stmt)});
     }
 };
 
diff --git a/src/Lexer/Operators.hpp b/src/Lexer/Operators.hpp
index 690efe5..6725b99 100644
--- a/src/Lexer/Operators.hpp
+++ b/src/Lexer/Operators.hpp
@@ -59,8 +59,16 @@
                                       std::vector<Parser::ParsedExpressionPtr> & output_queue) {
     if (token.type == Tokens::Type::NUMBER || token.type == Tokens::Type::STRING_LITERAL ||
         token.type == Tokens::Type::KEYWORD) {
-        output_queue.push_back(
-            Parser::ParsedExpression::makeLiteral(Symbols::Value::fromString(token.value, expected_var_type)));
+        // Parse literal: use expected type if provided, otherwise auto-detect
+        if (expected_var_type == Symbols::Variables::Type::NULL_TYPE) {
+            output_queue.push_back(
+                Parser::ParsedExpression::makeLiteral(
+                    Symbols::Value::fromString(token.value, /*autoDetectType*/ true)));
+        } else {
+            output_queue.push_back(
+                Parser::ParsedExpression::makeLiteral(
+                    Symbols::Value::fromString(token.value, expected_var_type)));
+        }
         return true;
     }
     if (token.type == Tokens::Type::VARIABLE_IDENTIFIER) {
diff --git a/src/Parser/Parser.cpp b/src/Parser/Parser.cpp
index b59b193..3e2bde8 100644
--- a/src/Parser/Parser.cpp
+++ b/src/Parser/Parser.cpp
@@ -133,8 +133,13 @@
     expect(Lexer::Tokens::Type::PUNCTUATION, ")");
     expect(Lexer::Tokens::Type::PUNCTUATION, ";");
     // Record the function call operation
-    Interpreter::OperationsFactory::callFunction(func_name, Symbols::SymbolContainer::instance()->currentScopeName(),
-                                                 this->current_filename_, id_token.line_number, id_token.column_number);
+    Interpreter::OperationsFactory::callFunction(
+        func_name,
+        std::move(args),
+        Symbols::SymbolContainer::instance()->currentScopeName(),
+        this->current_filename_,
+        id_token.line_number,
+        id_token.column_number);
 }
 
 Symbols::Value Parser::parseNumericLiteral(const std::string & value, bool is_negative, Symbols::Variables::Type type) {
diff --git a/src/Symbols/SymbolFactory.hpp b/src/Symbols/SymbolFactory.hpp
index 5b7a168..dd9007f 100644
--- a/src/Symbols/SymbolFactory.hpp
+++ b/src/Symbols/SymbolFactory.hpp
@@ -14,6 +14,11 @@
 class SymbolFactory {
   public:
     static std::shared_ptr<Symbol> createVariable(const std::string & name, const Symbols::Value & value,
+                                                  const std::string & context) {
+        return std::make_shared<VariableSymbol>(name, value, context, value.getType());
+    }
+
+    static std::shared_ptr<Symbol> createVariable(const std::string & name, const Symbols::Value & value,
                                                   const std::string & context, Variables::Type type) {
         return std::make_shared<VariableSymbol>(name, value, context, type);
     }
diff --git a/test_scripts/test2.vs b/test_scripts/test2.vs
index ab60178..bb9d822 100644
--- a/test_scripts/test2.vs
+++ b/test_scripts/test2.vs
@@ -4,7 +4,9 @@
 
 string $variable2 = $variable;
 
-print("$double: ", $double, "\n");
-print("$variable2: ", $variable2, "\n");
-print("$variable: ", $variable, "\n");
+function test = (int $i) {
+    int $result = $i + 1;
+}
 
+
+test(5);
\ No newline at end of file

--
Gitblit v1.9.3