| src/Interpreter/AssignmentStatementNode.hpp | ●●●●● patch | view | raw | blame | history | |
| src/Interpreter/CallStatementNode.hpp | ●●●●● patch | view | raw | blame | history | |
| src/Interpreter/ConditionalStatementNode.hpp | ●●●●● patch | view | raw | blame | history | |
| src/Interpreter/DeclareFunctionStatementNode.hpp | ●●●●● patch | view | raw | blame | history | |
| src/Interpreter/DeclareVariableStatementNode.hpp | ●●●●● patch | view | raw | blame | history | |
| src/Interpreter/ForStatementNode.hpp | ●●●●● patch | view | raw | blame | history | |
| src/Interpreter/Interpreter.hpp | ●●●●● patch | view | raw | blame | history | |
| src/Parser/Parser.cpp | ●●●●● patch | view | raw | blame | history | |
| src/Parser/Parser.hpp | ●●●●● patch | view | raw | blame | history | |
| test_scripts/object.vs | ●●●●● patch | view | raw | blame | history |
src/Interpreter/AssignmentStatementNode.hpp
@@ -2,6 +2,8 @@ #define INTERPRETER_ASSIGNMENT_STATEMENT_NODE_HPP #include "StatementNode.hpp" // Include for unified runtime Exception #include "Interpreter/Interpreter.hpp" #include "ExpressionNode.hpp" #include "Symbols/SymbolContainer.hpp" #include "Symbols/Value.hpp" @@ -36,9 +38,9 @@ const std::string base_ns = symContainer->currentScopeName(); const std::string var_ns = base_ns + ".variables"; if (!symContainer->exists(targetName_, var_ns)) { throw std::runtime_error("Variable '" + targetName_ + "' does not exist in namespace: " + var_ns + " File: " + filename_ + ", Line: " + std::to_string(line_) + ", Column: " + std::to_string(column_)); throw Exception( "Variable '" + targetName_ + "' does not exist in namespace: " + var_ns, filename_, line_, column_); } auto symbol = symContainer->get(var_ns, targetName_); // Copy current value for potential nested updates @@ -48,20 +50,22 @@ // Simple variable assignment if (propertyPath_.empty()) { // Type check if (newValue.getType() != varValue.getType()) { using namespace Variables; throw std::runtime_error("Type mismatch assigning to variable '" + targetName_ + "': expected '" + TypeToString(varValue.getType()) + "' but got '" + TypeToString(newValue.getType()) + "' File: " + filename_ + ", Line: " + std::to_string(line_) + ", Column: " + std::to_string(column_)); } if (newValue.getType() != varValue.getType()) { using namespace Variables; throw Exception( "Type mismatch assigning to variable '" + targetName_ + "': expected '" + TypeToString(varValue.getType()) + "' but got '" + TypeToString(newValue.getType()) + "'", filename_, line_, column_); } symbol->setValue(newValue); return; } // Nested object property assignment if (varValue.getType() != Variables::Type::OBJECT) { throw std::runtime_error("Attempting to assign property on non-object variable '" + targetName_ + "'"); throw Exception( "Attempting to assign property on non-object variable '" + targetName_ + "'", filename_, line_, column_); } // Traverse into nested maps using ObjectMap = Value::ObjectMap; @@ -71,11 +75,15 @@ const auto & key = propertyPath_[i]; auto it = currMap->find(key); if (it == currMap->end()) { throw std::runtime_error("Property '" + key + "' not found on object '" + targetName_ + "'"); throw Exception( "Property '" + key + "' not found on object '" + targetName_ + "'", filename_, line_, column_); } Value & child = it->second; if (child.getType() != Variables::Type::OBJECT) { throw std::runtime_error("Property '" + key + "' is not an object, cannot assign nested property"); throw Exception( "Property '" + key + "' is not an object, cannot assign nested property", filename_, line_, column_); } currMap = &std::get<ObjectMap>(child.get()); } @@ -83,15 +91,18 @@ const std::string & lastKey = propertyPath_.back(); auto it = currMap->find(lastKey); if (it == currMap->end()) { throw std::runtime_error("Property '" + lastKey + "' not found on object '" + targetName_ + "'"); throw Exception( "Property '" + lastKey + "' not found on object '" + targetName_ + "'", filename_, line_, column_); } // Type check against existing property if (newValue.getType() != it->second.getType()) { using namespace Variables; throw std::runtime_error("Type mismatch for property '" + lastKey + "': expected '" + TypeToString(it->second.getType()) + "' but got '" + TypeToString(newValue.getType()) + "' File: " + filename_ + ", Line: " + std::to_string(line_) + ", Column: " + std::to_string(column_)); throw Exception( "Type mismatch for property '" + lastKey + "': expected '" + TypeToString(it->second.getType()) + "' but got '" + TypeToString(newValue.getType()) + "'", filename_, line_, column_); } // Assign and write back to symbol (*currMap)[lastKey] = newValue; src/Interpreter/CallStatementNode.hpp
@@ -7,6 +7,8 @@ #include "ExpressionNode.hpp" #include "Interpreter/Interpreter.hpp" // Include for unified runtime Exception (inherits BaseException) #include "BaseException.hpp" #include "Interpreter/OperationContainer.hpp" #include "StatementNode.hpp" #include "Symbols/FunctionSymbol.hpp" @@ -54,15 +56,17 @@ 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_); throw Exception("Function not found: " + functionName_, filename_, line_, column_); } 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())); throw Exception( "Function '" + functionName_ + "' expects " + std::to_string(params.size()) + " args, got " + std::to_string(argValues.size()), filename_, line_, column_); } // Enter function scope to bind parameters and execute body src/Interpreter/ConditionalStatementNode.hpp
@@ -4,8 +4,10 @@ #include <vector> #include <memory> #include <string> #include "Interpreter/StatementNode.hpp" #include "Interpreter/ExpressionNode.hpp" #include "Interpreter/StatementNode.hpp" // Include for unified runtime Exception #include "Interpreter/Interpreter.hpp" #include "Interpreter/ExpressionNode.hpp" namespace Interpreter { @@ -36,10 +38,9 @@ bool cond = false; if (val.getType() == Symbols::Variables::Type::BOOLEAN) { cond = val.get<bool>(); } else { throw std::runtime_error("Condition did not evaluate to boolean at " + filename_ + ":" + std::to_string(line_) + "," + std::to_string(column_)); } } else { throw Exception("Condition did not evaluate to boolean", filename_, line_, column_); } // Execute appropriate branch const auto & branch = cond ? thenBranch_ : elseBranch_; for (const auto & stmt : branch) { src/Interpreter/DeclareFunctionStatementNode.hpp
@@ -8,6 +8,8 @@ #include "ExpressionNode.hpp" #include "Interpreter.hpp" #include "Interpreter/StatementNode.hpp" // Include for unified runtime Exception #include "Interpreter/Interpreter.hpp" #include "Symbols/ParameterContainer.hpp" #include "Symbols/SymbolContainer.hpp" #include "Symbols/SymbolFactory.hpp" @@ -37,8 +39,7 @@ void interpret(Interpreter & /*interpreter*/) const override { //Symbols::Value value = expression_->evaluate(interpreter); if (Symbols::SymbolContainer::instance()->exists(functionName_)) { throw std::runtime_error("Function already declared: " + functionName_ + " file: " + filename_ + ", line: " + std::to_string(line_) + ", column: " + std::to_string(column_)); throw Exception("Function already declared: " + functionName_, filename_, line_, column_); } const auto func = Symbols::SymbolFactory::createFunction(functionName_, ns, params_, "", returnType_); Symbols::SymbolContainer::instance()->add(func); src/Interpreter/DeclareVariableStatementNode.hpp
@@ -8,6 +8,8 @@ #include "ExpressionNode.hpp" #include "Interpreter.hpp" #include "Interpreter/StatementNode.hpp" // Include for unified runtime Exception #include "Interpreter/Interpreter.hpp" #include "Symbols/SymbolContainer.hpp" #include "Symbols/SymbolFactory.hpp" @@ -35,18 +37,17 @@ Symbols::Value value = expression_->evaluate(interpreter); // Check for duplicate declaration if (Symbols::SymbolContainer::instance()->exists(variableName_)) { throw std::runtime_error("Variable already declared: " + variableName_ + " File: " + filename_ + ", Line: " + std::to_string(line_) + ", Column: " + std::to_string(column_)); throw Exception("Variable already declared: " + variableName_, filename_, line_, column_); } // Enforce type correctness: the evaluated value must match the declared type if (value.getType() != variableType_) { using namespace Symbols::Variables; std::string expected = TypeToString(variableType_); std::string actual = TypeToString(value.getType()); throw std::runtime_error("Type mismatch for variable '" + variableName_ + "': expected '" + expected + "' but got '" + actual + "' File: " + filename_ + ", Line: " + std::to_string(line_) + ", Column: " + std::to_string(column_)); throw Exception( "Type mismatch for variable '" + variableName_ + "': expected '" + expected + "' but got '" + actual + "'", filename_, line_, column_); } // Create and add the variable symbol const auto variable = Symbols::SymbolFactory::createVariable(variableName_, value, ns, variableType_); src/Interpreter/ForStatementNode.hpp
@@ -5,8 +5,10 @@ #include <memory> #include <string> #include <stdexcept> #include "Interpreter/StatementNode.hpp" #include "Interpreter/ExpressionNode.hpp" #include "Interpreter/StatementNode.hpp" // Include for unified runtime Exception #include "Interpreter/Interpreter.hpp" #include "Interpreter/ExpressionNode.hpp" #include "Symbols/Value.hpp" #include "Symbols/SymbolContainer.hpp" #include "Symbols/SymbolFactory.hpp" @@ -45,8 +47,7 @@ // Evaluate iterable expression auto iterableVal = iterableExpr_->evaluate(interpreter); if (iterableVal.getType() != Variables::Type::OBJECT) { throw std::runtime_error("For-in loop applied to non-object at " + filename_ + ":" + std::to_string(line_) + "," + std::to_string(column_)); throw Exception("For-in loop applied to non-object", filename_, line_, column_); } // Access underlying object map const auto & objMap = std::get<Value::ObjectMap>(iterableVal.get()); src/Interpreter/Interpreter.hpp
@@ -7,6 +7,23 @@ #include "Interpreter/Operation.hpp" #include "Interpreter/OperationContainer.hpp" #include "Symbols/SymbolContainer.hpp" #include "BaseException.hpp" // Exception type for runtime errors, includes file, line, and column context namespace Interpreter { class Exception : public BaseException { public: Exception(const std::string &msg, const std::string &filename, int line, size_t column) { rawMessage_ = msg; context_ = std::string(" in file \"") + filename + "\" at line: " + std::to_string(line) + ", column: " + std::to_string(column); formattedMessage_ = formatMessage(); } std::string formatMessage() const override { return std::string("[Runtime ERROR] >>") + context_ + " << : " + rawMessage_; } }; } // namespace Interpreter namespace Interpreter { src/Parser/Parser.cpp
@@ -1,4 +1,6 @@ #include "Parser/Parser.hpp" // Static filename for unified error reporting in Parser::Exception std::string Parser::Parser::Exception::current_filename_; #include <stack> @@ -781,6 +783,7 @@ void Parser::parseScript(const std::vector<Lexer::Tokens::Token> & tokens, std::string_view input_string, const std::string & filename) { ::Parser::Parser::Exception::current_filename_ = filename; tokens_ = tokens; input_str_view_ = input_string; current_token_index_ = 0; src/Parser/Parser.hpp
@@ -22,11 +22,13 @@ class Exception : public BaseException { public: using BaseException::BaseException; // Filename for error reporting static std::string current_filename_; Exception(const std::string & msg, const std::string & expected, const Lexer::Tokens::Token & token) { rawMessage_ = msg + ": " + token.dump(); context_ = " at line: " + std::to_string(token.line_number) + ", column: " + std::to_string(token.column_number); context_ = " in file \"" + current_filename_ + "\" at line: " + std::to_string(token.line_number) + ", column: " + std::to_string(token.column_number); if (expected.empty() == false) { rawMessage_ += " (expected: " + expected + ")"; } @@ -38,7 +40,8 @@ if (expected.empty() == false) { rawMessage_ += " (expected: " + expected + ")"; } context_ = " at line: " + std::to_string(line) + ", column: " + std::to_string(col); context_ = " in file \"" + current_filename_ + "\" at line: " + std::to_string(line) + ", column: " + std::to_string(col); formattedMessage_ = formatMessage(); } test_scripts/object.vs
@@ -1,6 +1,6 @@ object $person = { string name: "Szoni", string name: "Batman", int age: 37 }; @@ -8,7 +8,7 @@ object $person2 = { string name: "Not Szoni", string name: "Not Batman", int age: 37, object children: { string name: "Child1", @@ -24,9 +24,9 @@ printnl("Person name: ", $person_name); printnl("Child1 old age: ",$person2->children->age); $person2->children->age = $person2->children->age + 2; printnl("Child1 new age: ",$person2->children->age); printnl("Child1 old age: ", $person2->children->age); $person2->children->age = 22; printnl("Child1 new age: ", $person2->children->age); int $age = 10; if ($person2->children->age > 18) {