| | |
| | | #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" |
| | |
| | | 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 |
| | |
| | | // Type check |
| | | if (newValue.getType() != varValue.getType()) { |
| | | using namespace Variables; |
| | | throw std::runtime_error("Type mismatch assigning to variable '" + targetName_ + |
| | | throw Exception( |
| | | "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_)); |
| | | "' 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; |
| | |
| | | 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()); |
| | | } |
| | |
| | | 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 '" + |
| | | throw Exception( |
| | | "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_)); |
| | | TypeToString(newValue.getType()) + "'", |
| | | filename_, line_, column_); |
| | | } |
| | | // Assign and write back to symbol |
| | | (*currMap)[lastKey] = newValue; |
| | |
| | | |
| | | #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" |
| | |
| | | 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 |
| | |
| | | #include <memory> |
| | | #include <string> |
| | | #include "Interpreter/StatementNode.hpp" |
| | | // Include for unified runtime Exception |
| | | #include "Interpreter/Interpreter.hpp" |
| | | #include "Interpreter/ExpressionNode.hpp" |
| | | |
| | | namespace Interpreter { |
| | |
| | | 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_)); |
| | | throw Exception("Condition did not evaluate to boolean", filename_, line_, column_); |
| | | } |
| | | // Execute appropriate branch |
| | | const auto & branch = cond ? thenBranch_ : elseBranch_; |
| | |
| | | #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" |
| | |
| | | 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); |
| | |
| | | #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" |
| | | |
| | |
| | | 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_); |
| | |
| | | #include <string> |
| | | #include <stdexcept> |
| | | #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" |
| | |
| | | // 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()); |
| | |
| | | #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 { |
| | | |
| | |
| | | #include "Parser/Parser.hpp" |
| | | // Static filename for unified error reporting in Parser::Exception |
| | | std::string Parser::Parser::Exception::current_filename_; |
| | | |
| | | #include <stack> |
| | | |
| | |
| | | |
| | | 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; |
| | |
| | | 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 + ")"; |
| | | } |
| | |
| | | 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(); |
| | | } |
| | | |
| | |
| | | |
| | | object $person = { |
| | | string name: "Szoni", |
| | | string name: "Batman", |
| | | int age: 37 |
| | | }; |
| | | |
| | |
| | | |
| | | |
| | | object $person2 = { |
| | | string name: "Not Szoni", |
| | | string name: "Not Batman", |
| | | int age: 37, |
| | | object children: { |
| | | string name: "Child1", |
| | |
| | | |
| | | |
| | | printnl("Child1 old age: ",$person2->children->age); |
| | | $person2->children->age = $person2->children->age + 2; |
| | | $person2->children->age = 22; |
| | | printnl("Child1 new age: ",$person2->children->age); |
| | | |
| | | int $age = 10; |