A simple scripting language in C++
Ferenc Szontágh
2025-04-18 df361ede5e694c41095d7be4eabf86d0ee6a1162
fix function parameter parser
5 files modified
2 files added
120 ■■■■■ changed files
src/Interpreter/OperationsFactory.hpp 19 ●●●●● patch | view | raw | blame | history
src/Interpreter/ReturnException.hpp 19 ●●●●● patch | view | raw | blame | history
src/Interpreter/ReturnStatementNode.hpp 40 ●●●●● patch | view | raw | blame | history
src/Parser/Parser.cpp 22 ●●●●● patch | view | raw | blame | history
src/Parser/Parser.hpp 9 ●●●● patch | view | raw | blame | history
src/Symbols/Value.hpp 4 ●●●● patch | view | raw | blame | history
test_scripts/function_test.vs 7 ●●●● patch | view | raw | blame | history
src/Interpreter/OperationsFactory.hpp
@@ -14,6 +14,7 @@
#include "Parser/ParsedExpression.hpp"
#include "Symbols/ParameterContainer.hpp"
#include "Symbols/Value.hpp"
#include "Interpreter/ReturnStatementNode.hpp"
namespace Interpreter {
@@ -81,6 +82,24 @@
            ns,
            Operations::Operation{Operations::Type::FunctionCall, functionName, std::move(stmt)});
    }
    /**
     * @brief Record a return statement operation inside a function.
     * @param pexpr Parsed expression for return value, or nullptr for void return.
     * @param ns Current namespace (function scope).
     * @param fileName Source filename.
     * @param line Line number of return.
     * @param column Column number of return.
     */
    static void callReturn(const Parser::ParsedExpressionPtr &pexpr,
                           const std::string & ns,
                           const std::string & fileName,
                           int line,
                           size_t column) {
        std::unique_ptr<ExpressionNode> expr = pexpr ? buildExpressionFromParsed(pexpr) : nullptr;
        auto stmt = std::make_unique<ReturnStatementNode>(std::move(expr), fileName, line, column);
        Operations::Container::instance()->add(ns,
            Operations::Operation{Operations::Type::Return, std::string(), std::move(stmt)});
    }
};
}  // namespace Interpreter
src/Interpreter/ReturnException.hpp
New file
@@ -0,0 +1,19 @@
// ReturnException.hpp
#ifndef INTERPRETER_RETURN_EXCEPTION_HPP
#define INTERPRETER_RETURN_EXCEPTION_HPP
#include "Symbols/Value.hpp"
namespace Interpreter {
/**
 * @brief Exception used to unwind the call stack when a return statement is executed.
 */
class ReturnException {
  public:
    explicit ReturnException(const Symbols::Value &value) : value_(value) {}
    const Symbols::Value &value() const { return value_; }
  private:
    Symbols::Value value_;
};
} // namespace Interpreter
#endif // INTERPRETER_RETURN_EXCEPTION_HPP
src/Interpreter/ReturnStatementNode.hpp
New file
@@ -0,0 +1,40 @@
// ReturnStatementNode.hpp
#ifndef INTERPRETER_RETURN_STATEMENT_NODE_HPP
#define INTERPRETER_RETURN_STATEMENT_NODE_HPP
#include <memory>
#include <string>
#include "StatementNode.hpp"
#include "ExpressionNode.hpp"
#include "ReturnException.hpp"
#include "Symbols/Value.hpp"
namespace Interpreter {
/**
 * @brief Statement node representing a return statement inside a function.
 */
class ReturnStatementNode : public StatementNode {
    std::unique_ptr<ExpressionNode> expr_;
  public:
    explicit ReturnStatementNode(std::unique_ptr<ExpressionNode> expr,
                                 const std::string &file_name,
                                 int line,
                                 size_t column) :
        StatementNode(file_name, line, column), expr_(std::move(expr)) {}
    void interpret(Interpreter &interpreter) const override {
        Symbols::Value retVal;
        if (expr_) {
            retVal = expr_->evaluate(interpreter);
        }
        throw ReturnException(retVal);
    }
    std::string toString() const override {
        return std::string("return") + (expr_ ? (" " + expr_->toString()) : std::string());
    }
};
} // namespace Interpreter
#endif // INTERPRETER_RETURN_STATEMENT_NODE_HPP
src/Parser/Parser.cpp
@@ -142,6 +142,28 @@
        id_token.column_number);
}
// Parse a return statement, e.g., return; or return expression;
void Parser::parseReturnStatement() {
    // Consume 'return' keyword
    auto returnToken = expect(Lexer::Tokens::Type::KEYWORD_RETURN);
    // Parse optional expression
    ParsedExpressionPtr expr = nullptr;
    if (!(currentToken().type == Lexer::Tokens::Type::PUNCTUATION && currentToken().value == ";")) {
        expr = parseParsedExpression(Symbols::Variables::Type::NULL_TYPE);
    }
    // Record return operation
    Interpreter::OperationsFactory::callReturn(
        expr,
        Symbols::SymbolContainer::instance()->currentScopeName(),
        this->current_filename_,
        returnToken.line_number,
        returnToken.column_number);
    // Consume terminating semicolon
    expect(Lexer::Tokens::Type::PUNCTUATION, ";");
}
// Continue with numeric literal parsing
//
Symbols::Value Parser::parseNumericLiteral(const std::string & value, bool is_negative, Symbols::Variables::Type type) {
    try {
        switch (type) {
src/Parser/Parser.hpp
@@ -166,12 +166,17 @@
        throw Exception(message, expected, token);
    }
    // parseStatement (unchanged)
    // parseStatement (updated to handle return)
    void parseStatement() {
        const auto & token_type = currentToken().type;
        if (token_type == Lexer::Tokens::Type::KEYWORD_FUNCTION_DECLARATION) {
            parseFunctionDefinition();
            return;
        }
        // Return statement
        if (token_type == Lexer::Tokens::Type::KEYWORD_RETURN) {
            parseReturnStatement();
            return;
        }
@@ -194,6 +199,8 @@
    void parseFunctionDefinition();
    // Parse a top-level function call statement (e.g., foo(arg1, arg2);)
    void parseCallStatement();
    // Parse a return statement (e.g., return; or return expr;)
    void parseReturnStatement();
    // --- Parsing helper functions ---
src/Symbols/Value.hpp
@@ -88,10 +88,10 @@
        trimmed.erase(0, trimmed.find_first_not_of(" \t\n\r"));
        trimmed.erase(trimmed.find_last_not_of(" \t\n\r") + 1);
        // Check bool
        // Check bool literals
        std::string lower = trimmed;
        std::transform(lower.begin(), lower.end(), lower.begin(), ::tolower);
        if (lower == "true" || lower == "false" || lower == "1" || lower == "0") {
        if (lower == "true" || lower == "false") {
            try {
                return fromStringToBool(trimmed);
            } catch (...) {
test_scripts/function_test.vs
@@ -5,7 +5,9 @@
string $variable2 = $variable;
function test = (int $i) {
    print("Param: ",$i);
    int $result = $i + 1;
    print("The result is: ", $result);
}
function increment = (int $i) int {
@@ -13,4 +15,7 @@
}
increment(1);
test(1);
int $t = increment(2);
print("The result is: ", $t);