.clangd
@@ -1,5 +1,5 @@ CompileFlags: Add: [-Wunused] Add: [-xc++, -Wall] Index: StandardLibrary: No cli/main.cpp
@@ -1,5 +1,4 @@ #include <filesystem> #include <fstream> #include <iostream> #include <unordered_map> @@ -58,6 +57,4 @@ VoidScript voidscript(filename); return voidscript.run(); return 0; } src/!NameSpaceManager.hpp
New file @@ -0,0 +1,144 @@ #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 src/Interpreter/BinaryExpressionNode.hpp
New file @@ -0,0 +1,68 @@ #include <memory> #include <string> #include "ExpressionNode.hpp" namespace Interpreter { class BinaryExpressionNode : public ExpressionNode { std::unique_ptr<ExpressionNode> lhs_; std::unique_ptr<ExpressionNode> rhs_; std::string op_; public: BinaryExpressionNode(std::unique_ptr<ExpressionNode> lhs, std::string op, std::unique_ptr<ExpressionNode> rhs) : lhs_(std::move(lhs)), rhs_(std::move(rhs)), op_(std::move(op)) {} Symbols::Value evaluate(Interpreter & interpreter) const override { auto leftVal = lhs_->evaluate(interpreter); auto rightVal = rhs_->evaluate(interpreter); if (leftVal.getType() != rightVal.getType()) { throw std::runtime_error( "Unsupported types in binary expression: " + Symbols::Variables::TypeToString(leftVal.getType()) + " and " + Symbols::Variables::TypeToString(rightVal.getType()) + " " + toString()); } if (leftVal.getType() == Symbols::Variables::Type::INTEGER && rightVal.getType() == Symbols::Variables::Type::INTEGER) { int l = leftVal.get<int>(); int r = rightVal.get<int>(); if (op_ == "+") { return Symbols::Value(l + r); } if (op_ == "-") { return Symbols::Value(l - r); } if (op_ == "*") { return Symbols::Value(l * r); } if (op_ == "/") { return Symbols::Value(l / r); // TODO: 0 div } throw std::runtime_error("Unknown operator: " + op_); } if (leftVal.getType() == Symbols::Variables::Type::STRING && rightVal.getType() == Symbols::Variables::Type::STRING) { auto l = leftVal.get<std::string>(); auto r = rightVal.get<std::string>(); if (op_ == "+") { return Symbols::Value(l + r); } throw std::runtime_error("Unknown operator: " + op_); } throw std::runtime_error( "Unsupported types in binary expression: " + Symbols::Variables::TypeToString(leftVal.getType()) + " and " + Symbols::Variables::TypeToString(rightVal.getType()) + " " + toString()); } std::string toString() const override { return "(" + lhs_->toString() + " " + op_ + " " + rhs_->toString() + ")"; } }; }; // namespace Interpreter src/Interpreter/DeclareFunctionStatementNode.hpp
New file @@ -0,0 +1,55 @@ #ifndef INTERPRETER_DEFINE_FUNCTION_STATEMENT_NODE_HPP #define INTERPRETER_DEFINE_FUNCTION_STATEMENT_NODE_HPP #include <memory> #include <string> #include <utility> #include "ExpressionNode.hpp" #include "Interpreter.hpp" #include "Interpreter/StatementNode.hpp" #include "Symbols/ParameterContainer.hpp" #include "Symbols/SymbolContainer.hpp" #include "Symbols/SymbolFactory.hpp" namespace Interpreter { class DeclareFunctionStatementNode : public StatementNode { std::string functionName_; Symbols::Variables::Type returnType_; Symbols::FunctionParameterInfo params_; std::unique_ptr<ExpressionNode> expression_; std::string ns; public: DeclareFunctionStatementNode(const std::string & function_name, const std::string & ns, const Symbols::FunctionParameterInfo & params, Symbols::Variables::Type return_type, std::unique_ptr<ExpressionNode> expr, const std::string & file_name, int file_line, size_t line_column) : StatementNode(file_name, file_line, line_column), functionName_(function_name), returnType_(return_type), params_(params), expression_(std::move(expr)), ns(ns) {} 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_)); } const auto func = Symbols::SymbolFactory::createFunction(functionName_, ns, params_, "", returnType_); Symbols::SymbolContainer::instance()->add(func); } std::string toString() const override { return std::string( " FunctioName: " + functionName_ + " return type: " + Symbols::Variables::TypeToString(returnType_) + " params size: " + std::to_string(params_.size())); } }; } // namespace Interpreter #endif // INTERPRETER_DEFINE_FUNCTION_STATEMENT_NODE_HPP src/Interpreter/DeclareVariableStatementNode.hpp
New file @@ -0,0 +1,52 @@ #ifndef INTERPRETER_DEFINE_VARIABLE_STATEMENT_NODE_HPP #define INTERPRETER_DEFINE_VARIABLE_STATEMENT_NODE_HPP #include <memory> #include <string> #include <utility> #include "ExpressionNode.hpp" #include "Interpreter.hpp" #include "Interpreter/StatementNode.hpp" #include "Symbols/SymbolContainer.hpp" #include "Symbols/SymbolFactory.hpp" namespace Interpreter { class DeclareVariableStatementNode : public StatementNode { std::string variableName_; Symbols::Variables::Type variableType_; std::unique_ptr<ExpressionNode> expression_; std::string ns; public: DeclareVariableStatementNode(std::string name, const std::string & ns, Symbols::Variables::Type type, std::unique_ptr<ExpressionNode> expr, const std::string & file_name, int file_line, size_t line_column) : StatementNode(file_name, file_line, line_column), variableName_(std::move(name)), variableType_(type), expression_(std::move(expr)), ns(ns) {} void interpret(Interpreter & interpreter) const override { Symbols::Value value = expression_->evaluate(interpreter); 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_)); } const auto variable = Symbols::SymbolFactory::createVariable(variableName_, value, ns, variableType_); Symbols::SymbolContainer::instance()->add(variable); } std::string toString() const override { return std::string("variable name: " + variableName_ + " type: " + Symbols::Variables::TypeToString(variableType_)); } }; } // namespace Interpreter #endif // INTERPRETER_DEFINE_VARIABLE_STATEMENT_NODE_HPP src/Interpreter/ExpressionBuilder.hpp
New file @@ -0,0 +1,42 @@ #ifndef PARSEREXPRESSION_BUILDER_HPP #define PARSEREXPRESSION_BUILDER_HPP #include <memory> #include <stdexcept> #include "Interpreter/BinaryExpressionNode.hpp" #include "Interpreter/ExpressionNode.hpp" #include "Interpreter/IdentifierExpressionNode.hpp" #include "Interpreter/LiteralExpressionNode.hpp" #include "Interpreter/UnaryExpressionNode.hpp" // <-- új include #include "Parser/ParsedExpression.hpp" namespace Parser { static std::unique_ptr<Interpreter::ExpressionNode> buildExpressionFromParsed( const Parser::ParsedExpressionPtr & expr) { using Kind = Parser::ParsedExpression::Kind; switch (expr->kind) { case Kind::Literal: return std::make_unique<Interpreter::LiteralExpressionNode>(expr->value); case Kind::Variable: return std::make_unique<Interpreter::IdentifierExpressionNode>(expr->name); case Kind::Binary: { auto lhs = buildExpressionFromParsed(expr->lhs); auto rhs = buildExpressionFromParsed(expr->rhs); return std::make_unique<Interpreter::BinaryExpressionNode>(std::move(lhs), expr->op, std::move(rhs)); } case Kind::Unary: { auto operand = buildExpressionFromParsed(expr->rhs); // rhs az operandus return std::make_unique<Interpreter::UnaryExpressionNode>(expr->op, std::move(operand)); } } throw std::runtime_error("Unknown ParsedExpression kind"); } } // namespace Parser #endif // PARSEREXPRESSION_BUILDER_HPP src/Interpreter/ExpressionNode.hpp
@@ -1,16 +1,13 @@ #ifndef INTERPRETER_FUNCTION_EXECUTOR_HPP #define INTERPRETER_FUNCTION_EXECUTOR_HPP namespace Interpreter { struct StatementNode { virtual ~StatementNode() = default; virtual void interpret(class Interpreter & interpreter) const = 0; }; #include "Symbols/Value.hpp" // Kifejezés (csak int literál most) namespace Interpreter { struct ExpressionNode { virtual ~ExpressionNode() = default; virtual int evaluate(class Interpreter & interpreter) const = 0; virtual Symbols::Value evaluate(class Interpreter & interpreter) const = 0; virtual std::string toString() const = 0; }; } // namespace Interpreter src/Interpreter/IdentifierExpressionNode.hpp
New file @@ -0,0 +1,29 @@ #ifndef IDENTIFIER_EXPRESSION_NODE_HPP #define IDENTIFIER_EXPRESSION_NODE_HPP #include "ExpressionNode.hpp" #include "Symbols/SymbolContainer.hpp" #include "Symbols/Value.hpp" namespace Interpreter { class IdentifierExpressionNode : public ExpressionNode { std::string name_; public: explicit IdentifierExpressionNode(std::string name) : name_(std::move(name)) {} Symbols::Value evaluate(Interpreter & /*interpreter*/) const override { const auto ns = Symbols::SymbolContainer::instance()->currentScopeName() + ".variables"; if (Symbols::SymbolContainer::instance()->exists(name_, ns)) { return Symbols::SymbolContainer::instance()->get(ns, name_)->getValue(); } throw std::runtime_error("Variable " + name_ + " does not exist in ns: " + ns); } std::string toString() const override { return name_; } }; } // namespace Interpreter #endif // IDENTIFIER_EXPRESSION_NODE_HPP src/Interpreter/Interpreter.hpp
@@ -1,46 +1,66 @@ #ifndef INTERPRETER_HPP #define INTERPRETER_HPP #include <iostream> #include <memory> #include <utility> #include <vector> #include <stdexcept> #include "Interpreter/Operation.hpp" #include "Interpreter/OperationContainer.hpp" #include "Symbols/SymbolContainer.hpp" namespace Interpreter { class Interpreter { private: std::shared_ptr<Symbols::SymbolContainer> symbol_container_; const OperationContainer & operations_conatiner_; void runOperation(const Operations::Operation & op) { std::cout << "Operation: " << op.toString() << "\n"; void setVariable(const std::string & name, int value) { //symbol_container_->setVariable(name, value); } public: // Constructor takes the populated symbol container from the parser Interpreter(std::shared_ptr<Symbols::SymbolContainer> symbols, const OperationContainer & operations) : symbol_container_(std::move(symbols)), operations_conatiner_(operations) {} void run(const std::vector<Operation> & ops) { for (const auto & op : ops) { switch (op.type) { case OperationType::Assignment: case Operations::Type::Declaration: if (op.statement) { op.statement->interpret(*this); } break; case Operations::Type::FuncDeclaration: { int value = op.expression->evaluate(*this); setVariable(op.targetVariable, value); op.statement->interpret(*this); } break; case Operations::Type::Assignment: { op.statement->interpret(*this); break; } case OperationType::Expression: case Operations::Type::Expression: { op.expression->evaluate(*this); // csak side effect miatt op.statement->interpret(*this); // csak side effect miatt break; } case Operations::Type::FunctionCall: case Operations::Type::Return: case Operations::Type::Loop: case Operations::Type::Break: case Operations::Type::Continue: case Operations::Type::Block: case Operations::Type::Import: case Operations::Type::Error: case Operations::Type::Conditional: // TODO: implementálható később break; default: throw std::runtime_error("Not implemented operation type"); } } public: Interpreter() {} void run() { for (const auto & operation : Operations::Container::instance()->getAll()) { runOperation(*operation); } } }; // class Interpreter src/Interpreter/LiteralExpressionNode.hpp
New file @@ -0,0 +1,25 @@ #ifndef LITERAL_EXPRESSION_NODE_HPP #define LITERAL_EXPRESSION_NODE_HPP #include "ExpressionNode.hpp" #include "Symbols/Value.hpp" namespace Interpreter { class LiteralExpressionNode : public ExpressionNode { Symbols::Value value_; public: explicit LiteralExpressionNode(Symbols::Value value) : value_(std::move(value)) {} Symbols::Value evaluate(class Interpreter & /*interpreter*/) const override { return value_; } const Symbols::Value & value() const { return value_; } // to string std::string toString() const override { return Symbols::Value::to_string(value_); } }; } // namespace Interpreter #endif // LITERAL_EXPRESSION_NODE_HPP src/Interpreter/Operation.hpp
@@ -2,30 +2,68 @@ #define INTERPRETER_OPERATION_HPP #include <cstdint> #include <memory> #include <string> #include <unordered_map> #include "ExpressionNode.hpp" #include "Interpreter/StatementNode.hpp" namespace Interpreter { enum OperationType : std::uint8_t { Assignment, Expression, namespace Operations { enum class Type : std::uint8_t { Assignment, // Variable assignment, e.g., $x = 5 Expression, // Evaluation of an expression (can be evaluated without side effects) FunctionCall, // Call to a function, e.g., print(x) FuncDeclaration, // declaration of new function Return, // return statement Conditional, // if/else structure Loop, // while/for loop Break, // break out of a loop Continue, // continue with the next iteration of a loop Block, // block of statements, e.g. { ... } Declaration, // declaration of new variable (if different from assignment) int $x = 1 Import, // import of another script or module Error, // error or non-interpretable operation (error handling) }; struct Operation { OperationType type; Operation() = default; Operations::Type type; // Általános mezők std::string targetVariable; std::unique_ptr<ExpressionNode> expression; std::string targetName; std::unique_ptr<Interpreter::StatementNode> statement; Operation(OperationType t, std::string var, std::unique_ptr<ExpressionNode> expr) : type(t), targetVariable(std::move(var)), expression(std::move(expr)) {} Operation(Operations::Type t, std::string target_variable, std::unique_ptr<Interpreter::StatementNode> stmt) : type(t), targetName(std::move(target_variable)), statement(std::move(stmt)) {} std::string typeToString() const { std::unordered_map<Operations::Type, std::string> types = { { Operations::Type::Assignment, "Assignment" }, { Operations::Type::Expression, "Expression" }, { Operations::Type::FunctionCall, "FunctionCall" }, { Operations::Type::FuncDeclaration, "FuncDeclaration" }, { Operations::Type::Return, "Return" }, { Operations::Type::Conditional, "Conditional" }, { Operations::Type::Loop, "Loop" }, { Operations::Type::Break, "Break" }, { Operations::Type::Continue, "Continue" }, { Operations::Type::Block, "Block" }, { Operations::Type::Declaration, "Declaration" }, { Operations::Type::Import, "Import" }, { Operations::Type::Error, "Error" } }; auto it = types.find(type); if (it != types.end()) { return it->second; } return "Unknown type"; } }; // namespace Interpreter std::string toString() const { return "Target: " + targetName + " Type: " + this->typeToString() + " Statement: " + statement->toString(); } }; }; // namespace Operations #endif src/Interpreter/OperationContainer.hpp
@@ -1,12 +1,135 @@ #ifndef INTERPRETER_OPERATION_CONTAINER_HPP #define INTERPRETER_OPERATION_CONTAINER_HPP #include <map> #include <string> #include <vector> #include "Interpreter/Operation.hpp" namespace Interpreter { using OperationContainer = std::vector<Operation>; }; // namespace Interpreter namespace Operations { class Container { public: /** * @brief Get the Operations::Container instance. * @return The Operations::Container instance. */ static Operations::Container * instance() { static Operations::Container instance_; return &instance_; } Container() = default; void add(const std::string & ns, Operations::Operation operation) { this->_operations[ns].emplace_back(std::make_shared<Operations::Operation>(std::move(operation))); } /** * @brief Returns the first operation in the namespace. * @param ns Namespace from which to get the operation. * @return The first operation in the namespace. */ std::shared_ptr<Operations::Operation> getFirst(const std::string & ns) { auto it = _operations.find(ns); if (it != _operations.end()) { return it->second.front(); } return nullptr; } /** * @brief Removes the first operation from the namespace. * @param ns Namespace from which to remove the operation. * @return The removed operation. */ std::shared_ptr<Operations::Operation> pullFirst(const std::string & ns) { auto it = _operations.find(ns); if (it != _operations.end()) { auto operation = it->second.front(); it->second.erase(it->second.begin()); return operation; } return nullptr; } /** * @brief Removes the last operation from the namespace. * @param ns Namespace from which to remove the operation. * @return The removed operation. */ std::shared_ptr<Operations::Operation> pullLast(const std::string & ns) { auto it = _operations.find(ns); if (it != _operations.end()) { auto operation = it->second.back(); it->second.pop_back(); return operation; } return nullptr; } /** * @brief Returns the last operation in the namespace. * @param ns Namespace from which to get the operation. * @return The last operation in the namespace. */ std::shared_ptr<Operations::Operation> getLast(const std::string & ns) { auto it = _operations.find(ns); if (it != _operations.end()) { return it->second.back(); } return nullptr; } /** * @brief Returns all operations in the namespace. * @param ns Namespace from which to get the operations. * @return All operations in the namespace. */ std::vector<std::shared_ptr<Operations::Operation>> getAll(const std::string & ns) { auto it = _operations.find(ns); if (it != _operations.end()) { return it->second; } return {}; } /** * @brief Returns all operations from all namespaces * @return All operations in the namespace. */ std::vector<std::shared_ptr<Operations::Operation>> getAll() { std::vector<std::shared_ptr<Operations::Operation>> result; for (const auto & [_, table] : _operations) { result.insert(result.end(), table.begin(), table.end()); } return result; } auto begin() { return _operations.begin(); } auto end() { return _operations.end(); } auto begin() const { return _operations.begin(); } auto end() const { return _operations.end(); } static std::string dump() { std::string result = ""; for (const auto & [_, table] : Operations::Container::instance()->_operations) { result += "Namespace: " + _ + "\n"; for (const auto & operation : table) { result += " Operation: " + operation->toString() + "\n"; } } return result; } private: std::map<std::string, std::vector<std::shared_ptr<Operations::Operation>>> _operations; }; // class Container }; // namespace Operations #endif // INTERPRETER_OPERATION_CONTAINER_HPP src/Interpreter/OperationsFactory.hpp
New file @@ -0,0 +1,59 @@ #ifndef OPERATIONSFACTORY_HPP #define OPERATIONSFACTORY_HPP #include <memory> #include <string> #include "Interpreter/DeclareFunctionStatementNode.hpp" #include "Interpreter/DeclareVariableStatementNode.hpp" #include "Interpreter/ExpressionBuilder.hpp" #include "Interpreter/LiteralExpressionNode.hpp" #include "Interpreter/Operation.hpp" #include "Interpreter/OperationContainer.hpp" #include "Parser/ParsedExpression.hpp" #include "Symbols/ParameterContainer.hpp" #include "Symbols/Value.hpp" namespace Interpreter { class OperationsFactory { public: OperationsFactory() {} static void defineFunction(const std::string & functionName, const Symbols::FunctionParameterInfo & params, const Symbols::Variables::Type & returnType, const std::string & ns, const std::string & fileName, int line, size_t column) { std::unique_ptr<DeclareFunctionStatementNode> stmt = std::make_unique<DeclareFunctionStatementNode>( functionName, ns, params, returnType, nullptr, fileName, line, column); Operations::Container::instance()->add( ns, Operations::Operation{ Operations::Type::FuncDeclaration, functionName, std::move(stmt) }); } static void defineSimpleVariable(const std::string & varName, const Symbols::Value & value, const std::string & ns, const std::string & filename, int line, size_t column) { auto literalExpr = std::make_unique<LiteralExpressionNode>(value); std::unique_ptr<DeclareVariableStatementNode> stmt = std::make_unique<DeclareVariableStatementNode>( varName, ns, value.getType(), std::move(literalExpr), filename, line, column); Operations::Container::instance()->add( ns, Operations::Operation{ Operations::Type::Declaration, varName, std::move(stmt) }); } static void defineVariableWithExpression(const std::string & varName, Symbols::Variables::Type type, const Parser::ParsedExpressionPtr pexpr, const std::string & ns, const std::string & filename, int line, size_t column) { // ParsedExpression → ExpressionNode std::unique_ptr<ExpressionNode> expr = buildExpressionFromParsed(pexpr); std::unique_ptr<DeclareVariableStatementNode> stmt = std::make_unique<DeclareVariableStatementNode>( varName, ns, type, std::move(expr), filename, line, column); Operations::Container::instance()->add( ns, Operations::Operation{Operations::Type::Declaration, varName, std::move(stmt)}); } }; } // namespace Interpreter #endif // OPERATIONSFACTORY_HPP src/Interpreter/StatementNode.hpp
New file @@ -0,0 +1,26 @@ #ifndef STATEMENT_NODE_HPP #define STATEMENT_NODE_HPP #include <string> namespace Interpreter { class StatementNode { public: std::string filename_; int line_; size_t column_; StatementNode(const std::string & file_name, int file_line, size_t line_column) : filename_(file_name), line_(file_line), column_(line_column) {} virtual ~StatementNode() = default; virtual void interpret(class Interpreter & interpreter) const = 0; virtual std::string toString() const = 0; }; }; // namespace Interpreter #endif // STATEMENT_NODE_HPP src/Interpreter/UnaryExpressionNode.hpp
New file @@ -0,0 +1,64 @@ #ifndef UNARY_EXPRESSION_NODE_HPP #define UNARY_EXPRESSION_NODE_HPP #include <memory> #include <string> #include "ExpressionNode.hpp" namespace Interpreter { class UnaryExpressionNode : public ExpressionNode { std::string op_; std::unique_ptr<ExpressionNode> operand_; public: UnaryExpressionNode(std::string op, std::unique_ptr<ExpressionNode> operand) : op_(std::move(op)), operand_(std::move(operand)) {} Symbols::Value evaluate(Interpreter & interpreter) const override { auto value = operand_->evaluate(interpreter); auto type = value.getType(); if (type == Symbols::Variables::Type::INTEGER) { int v = value.get<int>(); if (op_ == "-") { return Symbols::Value(-v); } if (op_ == "+") { return Symbols::Value(+v); } } else if (type == Symbols::Variables::Type::DOUBLE) { double v = value.get<double>(); if (op_ == "-") { return Symbols::Value(-v); } if (op_ == "+") { return Symbols::Value(+v); } } else if (type == Symbols::Variables::Type::FLOAT) { float v = value.get<float>(); if (op_ == "-") { return Symbols::Value(-v); } if (op_ == "+") { return Symbols::Value(+v); } } else if (type == Symbols::Variables::Type::BOOLEAN) { bool v = value.get<bool>(); if (op_ == "!") { return Symbols::Value(!v); } } throw std::runtime_error("Unsupported unary operator '" + op_ + "' for type: " + Symbols::Variables::TypeToString(type)); } std::string toString() const override { return "(" + op_ + operand_->toString() + ")"; } }; } // namespace Interpreter #endif // UNARY_EXPRESSION_NODE_HPP src/Interpreter/VariableExpressionNode.hpp
New file @@ -0,0 +1,36 @@ #ifndef VARIABLEEXPRESSIONNODE_HPP #define VARIABLEEXPRESSIONNODE_HPP #include <memory> #include <string> #include <utility> #include "Interpreter/ExpressionNode.hpp" #include "Interpreter/Interpreter.hpp" #include "Symbols/SymbolContainer.hpp" #include "Symbols/Value.hpp" namespace Interpreter { class VariableExpressionNode : public ExpressionNode { std::string variableName_; std::string ns; public: VariableExpressionNode(std::string varName, std::string ns) : variableName_(std::move(varName)), ns(std::move(ns)) {} Symbols::Value evaluate(Interpreter & interpreter) const override { if (!Symbols::SymbolContainer::instance()->exists(variableName_)) { throw std::runtime_error("Variable not found: " + variableName_); } auto symbol = Symbols::SymbolContainer::instance()->get(ns, variableName_); return symbol->getValue(); } std::string toString() const override { return "$" + variableName_; } }; }; // namespace Interpreter #endif // VARIABLEEXPRESSIONNODE_HPP src/Interpreter/VariableReferenceNode.hpp
New file @@ -0,0 +1,37 @@ #ifndef INTERPRETER_VARIABLE_REFERENCE_NODE_HPP #define INTERPRETER_VARIABLE_REFERENCE_NODE_HPP #include <memory> #include <stdexcept> #include <string> #include "ExpressionNode.hpp" #include "Symbols/SymbolContainer.hpp" #include "Symbols/Value.hpp" #include "Symbols/VariableSymbol.hpp" namespace Interpreter { class VariableReferenceNode : public ExpressionNode { std::string variableName_; std::string namespace_; // pl. "global.variables" public: VariableReferenceNode(const std::string & variableName, const std::string & ns) : variableName_(variableName), namespace_(ns) {} Symbols::Value evaluate(class Interpreter & /*interpreter*/) const override { auto symbol = Symbols::SymbolContainer::instance()->get(namespace_, variableName_); if (!symbol) { throw std::runtime_error("Variable not found: " + variableName_); } auto varSymbol = std::dynamic_pointer_cast<Symbols::VariableSymbol>(symbol); if (!varSymbol) { throw std::runtime_error("Symbol is not a variable: " + variableName_); } return varSymbol->getValue(); } }; }; // namespace Interpreter #endif // INTERPRETER_VARIABLE_REFERENCE_NODE_HPP src/Lexer/Lexer.hpp
@@ -1,14 +1,15 @@ #ifndef LEXER_HPP #define LEXER_HPP #include <algorithm> // std::find_if #include <cctype> // <<< Hozzáadva #include <algorithm> #include <cctype> #include <string> #include <string_view> // <<< Hozzáadva #include <string_view> #include <unordered_map> #include <vector> #include "Token.hpp" // Feltételezzük, hogy ez a fenti Token.hpp #include "Symbols/SymbolContainer.hpp" #include "Token.hpp" namespace Lexer { class Lexer { @@ -32,14 +33,13 @@ column_numbers_[ns] = 1; } void setNamespace(const std::string & ns) { current_namespace_ = ns; } std::vector<Tokens::Token> tokenizeNamespace(const std::string & ns) { if (inputs_.find(ns) == inputs_.end()) { return {}; } setNamespace(ns); Symbols::SymbolContainer::instance()->enter(ns); std::vector<Tokens::Token> tokens; Tokens::Token token; do { @@ -96,7 +96,6 @@ std::unordered_map<std::string, int> column_numbers_; std::string operators_; std::string current_namespace_; std::unordered_map<std::string, Tokens::Type> keywords; // two chars @@ -109,13 +108,41 @@ static const std::vector<std::string> OPERATOR_ARITHMETIC; static const std::vector<std::string> PUNCTUATION; const std::string & input() const { return inputs_.at(current_namespace_); } const std::string & input() const { const auto & ns = Symbols::SymbolContainer::instance()->currentScopeName(); auto it = inputs_.find(ns); if (it != inputs_.end()) { return it->second; } throw std::runtime_error("Input not found in namespace: " + ns); } size_t & pos() { return positions_[current_namespace_]; } size_t & pos() { const auto & ns = Symbols::SymbolContainer::instance()->currentScopeName(); auto it = positions_.find(ns); if (it != positions_.end()) { return it->second; } throw std::runtime_error("Unknown position in namespace: " + ns); } int & line() { return line_numbers_[current_namespace_]; } int & line() { const auto & ns = Symbols::SymbolContainer::instance()->currentScopeName(); auto it = line_numbers_.find(ns); if (it != line_numbers_.end()) { return it->second; } throw std::runtime_error("Unknown line number in namespace: " + ns); } int & col() { return column_numbers_[current_namespace_]; } int & col() { const auto & ns = Symbols::SymbolContainer::instance()->currentScopeName(); auto it = column_numbers_.find(ns); if (it != column_numbers_.end()) { return it->second; } throw std::runtime_error("Unknown column number in namespace: " + ns); } Tokens::Token createToken(Tokens::Type type, size_t start, size_t end, const std::string & value = "") { Tokens::Token token; @@ -134,8 +161,9 @@ // -------------------------------------- char peek(size_t offset = 0) const { const auto & in = inputs_.at(current_namespace_); size_t cp = positions_.at(current_namespace_); const auto & ns = Symbols::SymbolContainer::instance()->currentScopeName(); const auto & in = inputs_.at(ns); size_t cp = positions_.at(ns); if (cp + offset >= in.length()) { return '\0'; } @@ -154,10 +182,9 @@ return c; } bool isAtEnd() const { return positions_.at(current_namespace_) >= inputs_.at(current_namespace_).length(); } bool isComment(const char current_char) const { return (current_char == '/' && peek(1) == '/' || current_char == '#'); bool isAtEnd() const { const auto & ns = Symbols::SymbolContainer::instance()->currentScopeName(); return positions_.at(ns) >= inputs_.at(ns).length(); } void skipWhitespaceAndComments() { src/Lexer/TokenType.hpp
@@ -25,7 +25,7 @@ KEYWORD_DOUBLE, KEYWORD_FLOAT, KEYWORD_BOOLEAN, KEYWORD_FUNCTION, KEYWORD_FUNCTION_DECLARATION, KEYWORD_RETURN, KEYWORD_NULL, UNKNOWN // Ismeretlen karakter/szekvencia @@ -69,7 +69,7 @@ return "KEYWORD_FLOAT"; case Lexer::Tokens::Type::KEYWORD_BOOLEAN: return "KEYWORD_BOOLEAN"; case Lexer::Tokens::Type::KEYWORD_FUNCTION: case Lexer::Tokens::Type::KEYWORD_FUNCTION_DECLARATION: return "KEYWORD_FUNCTION"; case Lexer::Tokens::Type::KEYWORD_RETURN: return "KEYWORD_RETURN"; src/Parser/ParsedExpression.hpp
New file @@ -0,0 +1,66 @@ #ifndef PARSEDEXPRESSION_HPP #define PARSEDEXPRESSION_HPP #include <memory> #include <string> #include "Symbols/Value.hpp" namespace Parser { struct ParsedExpression; using ParsedExpressionPtr = std::unique_ptr<ParsedExpression>; struct ParsedExpression { enum class Kind : std::uint8_t { Literal, Variable, Binary, Unary }; Kind kind; Symbols::Value value; std::string name; // Műveletekhez std::string op; ParsedExpressionPtr lhs; ParsedExpressionPtr rhs; // Konstruktor literálhoz static ParsedExpressionPtr makeLiteral(const Symbols::Value & val) { auto expr = std::make_unique<ParsedExpression>(); expr->kind = Kind::Literal; expr->value = val; return expr; } // Konstruktor változóhoz static ParsedExpressionPtr makeVariable(const std::string & name) { auto expr = std::make_unique<ParsedExpression>(); expr->kind = Kind::Variable; expr->name = name; return expr; } // Konstruktor binárishoz static ParsedExpressionPtr makeBinary(std::string op, ParsedExpressionPtr left, ParsedExpressionPtr right) { auto expr = std::make_unique<ParsedExpression>(); expr->kind = Kind::Binary; expr->op = std::move(op); expr->lhs = std::move(left); expr->rhs = std::move(right); return expr; } // Konstruktor unárishoz static ParsedExpressionPtr makeUnary(std::string op, ParsedExpressionPtr operand) { auto expr = std::make_unique<ParsedExpression>(); expr->kind = Kind::Unary; expr->op = std::move(op); expr->rhs = std::move(operand); return expr; } }; } // namespace Parser #endif // PARSEDEXPRESSION_HPP src/Parser/Parser.cpp
@@ -9,7 +9,7 @@ { "while", Lexer::Tokens::Type::KEYWORD }, { "for", Lexer::Tokens::Type::KEYWORD }, { "return", Lexer::Tokens::Type::KEYWORD_RETURN }, { "function", Lexer::Tokens::Type::KEYWORD_FUNCTION }, { "function", Lexer::Tokens::Type::KEYWORD_FUNCTION_DECLARATION }, // Régebbiek: { "const", Lexer::Tokens::Type::KEYWORD }, { "true", Lexer::Tokens::Type::KEYWORD }, src/Parser/Parser.hpp
@@ -3,17 +3,19 @@ #include <algorithm> #include <memory> #include <sstream> // Hibaüzenetekhez #include <stack> #include <stdexcept> #include <string> #include <vector> // Szükséges header-ök a Lexer és Symbol komponensekből #include "Interpreter/ExpressionBuilder.hpp" #include "Interpreter/OperationsFactory.hpp" #include "Lexer/Token.hpp" #include "Lexer/TokenType.hpp" // Enum és TypeToString #include "Lexer/TokenType.hpp" #include "Parser/ParsedExpression.hpp" #include "Symbols/ParameterContainer.hpp" #include "Symbols/SymbolContainer.hpp" #include "Symbols/SymbolFactory.hpp" #include "Symbols/Value.hpp" // Symbols::Value miatt #include "Symbols/Value.hpp" namespace Parser { @@ -32,11 +34,13 @@ public: Parser() {} void parseProgram(const std::vector<Lexer::Tokens::Token> & tokens, std::string_view input_string) { void parseScript(const std::vector<Lexer::Tokens::Token> & tokens, std::string_view input_string, const std::string & filename) { tokens_ = tokens; input_str_view_ = input_string; current_token_index_ = 0; symbol_container_ = std::make_unique<Symbols::SymbolContainer>(); current_filename_ = filename; try { while (!isAtEnd() && currentToken().type != Lexer::Tokens::Type::END_OF_FILE) { parseStatement(); @@ -52,13 +56,6 @@ } } const std::shared_ptr<Symbols::SymbolContainer> & getSymbolContainer() const { if (!symbol_container_) { throw std::runtime_error("Symbol container is not initialized."); } return symbol_container_; } static const std::unordered_map<std::string, Lexer::Tokens::Type> keywords; static const std::unordered_map<Lexer::Tokens::Type, Symbols::Variables::Type> variable_types; @@ -66,7 +63,7 @@ std::vector<Lexer::Tokens::Token> tokens_; std::string_view input_str_view_; size_t current_token_index_; std::shared_ptr<Symbols::SymbolContainer> symbol_container_; std::string current_filename_; // Token Stream Kezelő és Hibakezelő segédfüggvények (változatlanok) const Lexer::Tokens::Token & currentToken() const { @@ -182,7 +179,7 @@ void parseStatement() { const auto & token_type = currentToken().type; if (token_type == Lexer::Tokens::Type::KEYWORD_FUNCTION) { if (token_type == Lexer::Tokens::Type::KEYWORD_FUNCTION_DECLARATION) { parseFunctionDefinition(); return; } @@ -197,40 +194,33 @@ reportError("Unexpected token at beginning of statement"); } // parseVariableDefinition (SymbolFactory használata már korrekt volt) void parseVariableDefinition() { Symbols::Variables::Type var_type_enum = parseType(); // A típus stringjének tárolása csak a debug kiíráshoz kell //std::string var_type_str = tokens_[current_token_index_ - 1].value; std::cout << "var_name: " << currentToken().lexeme << std::endl; Symbols::Variables::Type var_type = parseType(); Lexer::Tokens::Token id_token = expect(Lexer::Tokens::Type::VARIABLE_IDENTIFIER); std::string var_name = id_token.value; // Levágjuk a '$' jelet, ha a lexer mégis benne hagyta if (!var_name.empty() && var_name[0] == '$') { var_name = var_name.substr(1); } const auto ns = Symbols::SymbolContainer::instance()->currentScopeName(); expect(Lexer::Tokens::Type::OPERATOR_ASSIGNMENT, "="); Symbols::Value initial_value = parseValue(var_type_enum); /* Symbols::Value initial_value = parseValue(var_type); Interpreter::OperationsFactory::defineSimpleVariable(var_name, initial_value, ns, this->current_filename_, id_token.line_number, id_token.column_number); */ auto expr = parseParsedExpression(var_type); Interpreter::OperationsFactory::defineVariableWithExpression( var_name, var_type, std::move(expr), ns, current_filename_, id_token.line_number, id_token.column_number); expect(Lexer::Tokens::Type::PUNCTUATION, ";"); std::string context = "global"; // Globális változó // SymbolFactory használata a létrehozáshoz auto variable_symbol = Symbols::SymbolFactory::createVariable(var_name, initial_value, context, var_type_enum); // Ellenőrzés és definíció az *aktuális* scope-ban (ami itt a globális) if (symbol_container_->exists("variables", var_name)) { reportError("Variable '" + var_name + "' already defined in this scope"); } symbol_container_->define("variables", variable_symbol); // Debugging kiírás (változatlan) // std::cout << "Parsed variable: " << var_type_str << " " << id_token.value << " = ... ;\n"; } // *** MÓDOSÍTOTT parseFunctionDefinition *** void parseFunctionDefinition() { expect(Lexer::Tokens::Type::KEYWORD_FUNCTION); expect(Lexer::Tokens::Type::KEYWORD_FUNCTION_DECLARATION); Lexer::Tokens::Token id_token = expect(Lexer::Tokens::Type::IDENTIFIER); std::string func_name = id_token.value; Symbols::Variables::Type func_return_type = Symbols::Variables::Type::NULL_TYPE; @@ -242,7 +232,6 @@ if (currentToken().type != Lexer::Tokens::Type::PUNCTUATION || currentToken().value != ")") { while (true) { // Paraméter típusa //size_t type_token_index = current_token_index_; // Elmentjük a típus token indexét Symbols::Variables::Type param_type = parseType(); // Ez elfogyasztja a type tokent // Paraméter név ($variable) @@ -275,50 +264,10 @@ } } auto function_symbol = Symbols::SymbolFactory::createFunction(func_name, "global", param_infos, "", func_return_type); if (symbol_container_->exists("functions", func_name)) { reportError("Function '" + func_name + "' already defined in this scope"); } Lexer::Tokens::Token opening_brace = expect(Lexer::Tokens::Type::PUNCTUATION, "{"); symbol_container_->define("functions", function_symbol); // only parse the body if we checked out if not exists the function and created the symbol Symbols::SymbolContainer func_symbols = parseFunctionBody(opening_brace, func_return_type != Symbols::Variables::Type::NULL_TYPE); // create new container for the function std::cout << "Defined function symbol: " << func_name << " in global scope.\n"; // 3. Új scope nyitása a függvény paraméterei (és később lokális változói) számára symbol_container_->enterScope(); //std::cout << "Entered scope for function: " << func_name << "\n"; // 4. Paraméterek definiálása mint változók az *új* (függvény) scope-ban const std::string & param_context = func_name; // Paraméter kontextusa a függvény neve for (const auto & p_info : param_infos) { auto param_symbol = Symbols::SymbolFactory::createVariable(p_info.name, // Név '$' nélkül Symbols::Value(), // Alapértelmezett/üres érték param_context, // Kontextus p_info.type // Típus ); if (symbol_container_->exists("variables", p_info.name)) { reportError("Parameter name '" + p_info.name + "' conflicts with another symbol in function '" + func_name + "'"); } symbol_container_->define("variables", param_symbol); } // 5. Függvény scope elhagyása symbol_container_->leaveScope(); //std::cout << "Left scope for function: " << func_name << "\n"; // Debugging kiírás (változatlan) // std::cout << "Parsed function: " << func_name << " (...) { ... } scope handled.\n"; parseFunctionBody(opening_brace, func_name, func_return_type, param_infos); } // --- Elemzési Segédfüggvények --- @@ -337,118 +286,96 @@ reportError("Expected type keyword (string, int, double, float)"); } // value : STRING_LITERAL | NUMBER // Feldolgozza az értéket a várt típus alapján. Symbols::Value parseValue(Symbols::Variables::Type expected_var_type) { Lexer::Tokens::Token token = currentToken(); /// find if this is a function call if (token.type == Lexer::Tokens::Type::IDENTIFIER && peekToken().lexeme == "(") { for (const auto & symbol_ptr : this->symbol_container_->listNamespace("functions")) { if (auto func_symbol = std::dynamic_pointer_cast<Symbols::FunctionSymbol>(symbol_ptr)) { // TODO: A függvény hívását kellene feldolgozni, a func_symbol-ból kellene lekérni a paramétereket, func_symbol->plainBody() tartalmazza a függvény törzsét // A függvény hívásának feldolgozása std::cout << "Function call: " << token.value << "\n"; while (consumeToken().lexeme != ")") { // Feltételezzük, hogy a függvény hívását a lexer már feldolgozta } return Symbols::Value(""); // TODO: Implementálni a függvény hívását } } } bool is_negative = false; std::cout << "Peek: " << peekToken().lexeme << "\n"; if (token.type == Lexer::Tokens::Type::OPERATOR_ARITHMETIC && peekToken().type == Lexer::Tokens::Type::NUMBER) { is_negative = true; // Előjel kezelése if (token.type == Lexer::Tokens::Type::OPERATOR_ARITHMETIC && (token.lexeme == "-" || token.lexeme == "+") && peekToken().type == Lexer::Tokens::Type::NUMBER) { is_negative = (token.lexeme == "-"); token = peekToken(); consumeToken(); consumeToken(); // előjelet elfogyasztottuk } // STRING típus if (expected_var_type == Symbols::Variables::Type::STRING) { if (token.type == Lexer::Tokens::Type::STRING_LITERAL) { consumeToken(); return Symbols::Value(token.value); // A lexer value-ja már a feldolgozott string return Symbols::Value(token.value); } reportError("Expected string literal value"); } else if (expected_var_type == Symbols::Variables::Type::INTEGER) { if (token.type == Lexer::Tokens::Type::NUMBER) { // Konvertálás int-re, hibakezeléssel try { // TODO: Ellenőrizni, hogy a szám valóban egész-e (nincs benne '.') // Most egyszerűen std::stoi-t használunk. int int_value = std::stoi(token.value); if (is_negative) { int_value = -int_value; } consumeToken(); return Symbols::Value(int_value); } catch (const std::invalid_argument & e) { reportError("Invalid integer literal: " + token.value); } catch (const std::out_of_range & e) { reportError("Integer literal out of range: " + token.value); } } reportError("Expected integer literal value"); } else if (expected_var_type == Symbols::Variables::Type::DOUBLE) { if (token.type == Lexer::Tokens::Type::NUMBER) { // Konvertálás double-re, hibakezeléssel try { double double_value = std::stod(token.value); if (is_negative) { double_value = -double_value; } consumeToken(); return Symbols::Value(double_value); } catch (const std::invalid_argument & e) { reportError("Invalid double literal: " + token.value); } catch (const std::out_of_range & e) { reportError("Double literal out of range: " + token.value); } } reportError("Expected numeric literal value for double"); } else if (expected_var_type == Symbols::Variables::Type::FLOAT) { if (token.type == Lexer::Tokens::Type::NUMBER) { // Konvertálás double-re, hibakezeléssel try { float float_value = std::atof(token.value.data()); if (is_negative) { float_value = -float_value; } // BOOLEAN típus if (expected_var_type == Symbols::Variables::Type::BOOLEAN) { if (token.type == Lexer::Tokens::Type::KEYWORD && (token.value == "true" || token.value == "false")) { consumeToken(); return Symbols::Value(float_value); } catch (const std::invalid_argument & e) { reportError("Invalid float literal: " + token.value); } catch (const std::out_of_range & e) { reportError("Float literal out of range: " + token.value); return Symbols::Value(token.value == "true"); } reportError("Expected boolean literal value (true or false)"); } reportError("Expected numeric literal value for double"); } else if (expected_var_type == Symbols::Variables::Type::BOOLEAN) { if (token.type == Lexer::Tokens::Type::KEYWORD) { // NUMERIC típusok if (expected_var_type == Symbols::Variables::Type::INTEGER || expected_var_type == Symbols::Variables::Type::DOUBLE || expected_var_type == Symbols::Variables::Type::FLOAT) { if (token.type == Lexer::Tokens::Type::NUMBER) { Symbols::Value val = parseNumericLiteral(token.value, is_negative, expected_var_type); consumeToken(); return Symbols::Value(token.value == "true"); // A lexer value-ja már a feldolgozott string return val; } reportError("Expected boolean literal value"); } else { // Más típusok (pl. boolean) itt kezelendők, ha lennének reportError("Expected numeric literal value"); } reportError("Unsupported variable type encountered during value parsing"); } // Should not reach here due to reportError throwing return Symbols::Value(); // Default return to satisfy compiler return Symbols::Value(); // compiler happy } Symbols::SymbolContainer parseFunctionBody(const Lexer::Tokens::Token & opening_brace, bool return_required = false) { Symbols::Value parseNumericLiteral(const std::string & value, bool is_negative, Symbols::Variables::Type type) { try { switch (type) { case Symbols::Variables::Type::INTEGER: { if (value.find('.') != std::string::npos) { throw std::invalid_argument("Floating point value in integer context: " + value); } int v = std::stoi(value); return Symbols::Value(is_negative ? -v : v); } case Symbols::Variables::Type::DOUBLE: { double v = std::stod(value); return Symbols::Value(is_negative ? -v : v); } case Symbols::Variables::Type::FLOAT: { float v = std::stof(value); return Symbols::Value(is_negative ? -v : v); } default: throw std::invalid_argument("Unsupported numeric type"); } } catch (const std::invalid_argument & e) { reportError("Invalid numeric literal: " + value + " (" + e.what() + ")"); } catch (const std::out_of_range & e) { reportError("Numeric literal out of range: " + value + " (" + e.what() + ")"); } return Symbols::Value(); // unreachable } void parseFunctionBody(const Lexer::Tokens::Token & opening_brace, const std::string & function_name, Symbols::Variables::Type return_type, const Symbols::FunctionParameterInfo & params) { size_t braceDepth = 0; int peek = 0; int tokenIndex = current_token_index_; Lexer::Tokens::Token currentToken_; Lexer::Tokens::Token closing_brace; while (tokenIndex < tokens_.size()) { currentToken_ = peekToken(); currentToken_ = peekToken(peek); if (currentToken_.type == Lexer::Tokens::Type::PUNCTUATION) { if (currentToken_.value == "{") { ++braceDepth; @@ -460,6 +387,8 @@ --braceDepth; } } tokenIndex++; peek++; } if (braceDepth != 0) { reportError("Unmatched braces in function body"); @@ -468,65 +397,190 @@ auto startIt = std::find(tokens_.begin(), tokens_.end(), opening_brace); auto endIt = std::find(tokens_.begin(), tokens_.end(), closing_brace); // Ellenőrzés: mindkét token megtalálva és start_token megelőzi az end_token-t if (startIt != tokens_.end() && endIt != tokens_.end() && startIt < endIt) { filtered_tokens = std::vector<Lexer::Tokens::Token>(startIt + 1, endIt); } std::string_view input_string = input_str_view_.substr(opening_brace.end_pos, closing_brace.end_pos); auto parser = Parser(); parser.parseProgram(filtered_tokens, input_string); return *parser.getSymbolContainer(); current_token_index_ = tokenIndex; expect(Lexer::Tokens::Type::PUNCTUATION, "}"); const std::string newns = Symbols::SymbolContainer::instance()->currentScopeName() + "." + function_name; Symbols::SymbolContainer::instance()->create(newns); std::shared_ptr<Parser> parser = std::make_shared<Parser>(); parser->parseScript(filtered_tokens, input_string, this->current_filename_); Symbols::SymbolContainer::instance()->enterPreviousScope(); // create function Interpreter::OperationsFactory::defineFunction( function_name, params, return_type, Symbols::SymbolContainer::instance()->currentScopeName(), this->current_filename_, currentToken_.line_number, currentToken_.column_number); } std::string parseFunctionBodyOld(size_t body_start_pos, bool return_required = false) { std::stringstream body_ss; int brace_level = 1; size_t last_token_end_pos = body_start_pos; bool has_return = false; ParsedExpressionPtr parseParsedExpression(const Symbols::Variables::Type & expected_var_type) { std::stack<std::string> operator_stack; std::vector<ParsedExpressionPtr> output_queue; auto getPrecedence = [](const std::string & op) -> int { if (op == "+" || op == "-") { return 1; } if (op == "*" || op == "/") { return 2; } if (op == "u-" || op == "u+") { return 3; } return 0; }; auto isLeftAssociative = [](const std::string & op) -> bool { return !(op == "u-" || op == "u+"); }; auto applyOperator = [](const std::string & op, ParsedExpressionPtr rhs, ParsedExpressionPtr lhs = nullptr) { if (op == "u-" || op == "u+") { std::string real_op = (op == "u-") ? "-" : "+"; return ParsedExpression::makeUnary(real_op, std::move(rhs)); } else { return ParsedExpression::makeBinary(op, std::move(lhs), std::move(rhs)); } }; auto pushOperand = [&](const Lexer::Tokens::Token & token) { if (token.type == Lexer::Tokens::Type::NUMBER || token.type == Lexer::Tokens::Type::STRING_LITERAL || token.type == Lexer::Tokens::Type::KEYWORD) { output_queue.push_back( ParsedExpression::makeLiteral(Symbols::Value::fromString(token.value, expected_var_type))); } else if (token.type == Lexer::Tokens::Type::VARIABLE_IDENTIFIER) { std::string name = token.value; if (!name.empty() && name[0] == '$') { name = name.substr(1); } output_queue.push_back(ParsedExpression::makeVariable(name)); } else { reportError("Expected literal or variable"); } }; bool expect_unary = true; while (true) { if (isAtEnd()) { reportError("Unexpected end of file inside function body (missing '}')"); } const auto & token = currentToken(); auto token = currentToken(); // Whitespace visszaállítása (ha volt) az 'input_str_view_' alapján if (token.start_pos > last_token_end_pos) { if (last_token_end_pos < input_str_view_.length() && token.start_pos <= input_str_view_.length()) { body_ss << input_str_view_.substr(last_token_end_pos, token.start_pos - last_token_end_pos); if (token.type == Lexer::Tokens::Type::PUNCTUATION && token.lexeme == "(") { operator_stack.push("("); consumeToken(); expect_unary = true; } else if (token.type == Lexer::Tokens::Type::PUNCTUATION && token.lexeme == ")") { consumeToken(); while (!operator_stack.empty() && operator_stack.top() != "(") { std::string op = operator_stack.top(); operator_stack.pop(); if (op == "u-" || op == "u+") { if (output_queue.empty()) { reportError("Missing operand for unary operator"); } auto rhs = std::move(output_queue.back()); output_queue.pop_back(); output_queue.push_back(applyOperator(op, std::move(rhs))); } else { reportError("Invalid position range in body reconstruction"); if (output_queue.size() < 2) { reportError("Malformed expression"); } auto rhs = std::move(output_queue.back()); output_queue.pop_back(); auto lhs = std::move(output_queue.back()); output_queue.pop_back(); output_queue.push_back(applyOperator(op, std::move(rhs), std::move(lhs))); } } if (token.type == Lexer::Tokens::Type::KEYWORD_RETURN) { has_return = true; if (operator_stack.empty() || operator_stack.top() != "(") { reportError("Mismatched parentheses"); } operator_stack.pop(); // remove "(" expect_unary = false; } else if (token.type == Lexer::Tokens::Type::OPERATOR_ARITHMETIC) { std::string op = std::string(token.lexeme); if (expect_unary && (op == "-" || op == "+")) { op = "u" + op; // pl. u- } if (token.type == Lexer::Tokens::Type::PUNCTUATION && token.value == "{") { brace_level++; body_ss << token.lexeme; } else if (token.type == Lexer::Tokens::Type::PUNCTUATION && token.value == "}") { brace_level--; if (brace_level == 0) { consumeToken(); // Záró '}' elfogyasztása while (!operator_stack.empty()) { const std::string & top = operator_stack.top(); if ((isLeftAssociative(op) && getPrecedence(op) <= getPrecedence(top)) || (!isLeftAssociative(op) && getPrecedence(op) < getPrecedence(top))) { operator_stack.pop(); if (top == "u-" || top == "u+") { if (output_queue.empty()) { reportError("Missing operand for unary operator"); } auto rhs = std::move(output_queue.back()); output_queue.pop_back(); output_queue.push_back(applyOperator(top, std::move(rhs))); } else { if (output_queue.size() < 2) { reportError("Malformed expression"); } auto rhs = std::move(output_queue.back()); output_queue.pop_back(); auto lhs = std::move(output_queue.back()); output_queue.pop_back(); output_queue.push_back(applyOperator(top, std::move(rhs), std::move(lhs))); } } else { break; } body_ss << token.lexeme; } else { body_ss << token.lexeme; } last_token_end_pos = token.end_pos; operator_stack.push(op); consumeToken(); expect_unary = true; } else if (token.type == Lexer::Tokens::Type::NUMBER || token.type == Lexer::Tokens::Type::STRING_LITERAL || token.type == Lexer::Tokens::Type::KEYWORD || token.type == Lexer::Tokens::Type::VARIABLE_IDENTIFIER) { pushOperand(token); consumeToken(); expect_unary = false; } else { break; } } if (return_required && !has_return) { return ""; // Kiürítjük az operator stack-et while (!operator_stack.empty()) { std::string op = operator_stack.top(); operator_stack.pop(); if (op == "(" || op == ")") { reportError("Mismatched parentheses"); } return body_ss.str(); if (op == "u-" || op == "u+") { if (output_queue.empty()) { reportError("Missing operand for unary operator"); } auto rhs = std::move(output_queue.back()); output_queue.pop_back(); output_queue.push_back(applyOperator(op, std::move(rhs))); } else { if (output_queue.size() < 2) { reportError("Malformed expression"); } auto rhs = std::move(output_queue.back()); output_queue.pop_back(); auto lhs = std::move(output_queue.back()); output_queue.pop_back(); output_queue.push_back(applyOperator(op, std::move(rhs), std::move(lhs))); } } if (output_queue.size() != 1) { reportError("Expression could not be parsed cleanly"); } return std::move(output_queue.back()); } }; // class Parser src/Symbols/BaseSymbol.hpp
@@ -13,7 +13,7 @@ protected: std::string name_; Value value_; std::string context_; std::string context_; // ns Symbols::Kind kind_; public: @@ -40,6 +40,15 @@ virtual void setValue(const Value & value) { value_ = value; } std::string dump() const { std::string r = "\t\t "+ kindToString(this->kind_) + " name: '" + name_ + "' \n\t\t\tContext: " + context_; r += " \n\t\t\tType: " + Symbols::Variables::TypeToString(value_.getType()); r += " \n\t\t\tValue: '" + Symbols::Value::to_string(value_) + "'"; return r; } // Templated getter template <typename T> T getAs() const { return std::get<T>(value_); } }; src/Symbols/SymbolContainer.hpp
@@ -1,49 +1,139 @@ // SymbolContainer.hpp #ifndef SYMBOL_CONTAINER_HPP #define SYMBOL_CONTAINER_HPP #include <memory> #include <stdexcept> #include <unordered_map> #include "SymbolTable.hpp" #define NSMGR Symbols::SymbolContainer::instance() namespace Symbols { class SymbolContainer { std::shared_ptr<SymbolTable> globalScope_; std::shared_ptr<SymbolTable> currentScope_; std::unordered_map<std::string, std::shared_ptr<SymbolTable>> scopes_; std::string currentScope_ = "global"; std::string previousScope_ = "global"; public: SymbolContainer() { globalScope_ = std::make_shared<SymbolTable>(); currentScope_ = globalScope_; static SymbolContainer * instance() { static SymbolContainer instance_; return &instance_; } void enterScope() { currentScope_ = std::make_shared<SymbolTable>(currentScope_); explicit SymbolContainer(const std::string & default_scope_name = "global") { create(default_scope_name); } // --- Scope management --- void create(const std::string & name) { scopes_[name] = std::make_shared<SymbolTable>(); previousScope_ = currentScope_; currentScope_ = name; } void leaveScope() { if (currentScope_->getParent()) { currentScope_ = currentScope_->getParent(); void enter(const std::string & name) { if (scopes_.contains(name)) { previousScope_ = currentScope_; currentScope_ = name; } else { throw std::runtime_error("Scope does not exist: " + name); } } void define(const std::string& ns, const SymbolPtr& symbol) { currentScope_->define(ns, symbol); void enterPreviousScope() { currentScope_ = previousScope_; } [[nodiscard]] std::string currentScopeName() const { return currentScope_; } std::vector<std::string> getScopeNames() const { std::vector<std::string> result; result.reserve(scopes_.size()); for (const auto & [scopeName, _] : scopes_) { result.push_back(scopeName); } return result; } SymbolPtr resolve(const std::string& ns, const std::string& name) const { return currentScope_->get(ns, name); // --- Symbol operations --- std::string add(const SymbolPtr & symbol) { const std::string ns = getNamespaceForSymbol(symbol); scopes_[currentScope_]->define(ns, symbol); return ns; } bool exists(const std::string& ns, const std::string& name) const { return currentScope_->exists(ns, name); std::vector<std::string> getNameSpaces(const std::string & scopeName) const { std::vector<std::string> result; auto it = scopes_.find(scopeName); if (it != scopes_.end()) { return it->second->listNSs(); } return result; } std::vector<SymbolPtr> listNamespace(const std::string& ns) const { return currentScope_->listAll(ns); std::vector<SymbolPtr> getAll(const std::string & ns = "") const { std::vector<SymbolPtr> result; for (const auto & [_, table] : scopes_) { auto symbols = ns.empty() ? table->listAll() : table->listAll(ns); result.insert(result.end(), symbols.begin(), symbols.end()); } return result; } std::shared_ptr<SymbolTable> getGlobalScope() const { return globalScope_; } std::shared_ptr<SymbolTable> getCurrentScope() const { return currentScope_; } bool exists(const std::string & name, std::string fullNamespace = "") const { if (fullNamespace.empty()) { fullNamespace = currentScope_; } for (const auto & [_, table] : scopes_) { if (table->exists(fullNamespace, name)) { return true; } } return false; } SymbolPtr get(const std::string & fullNamespace, const std::string & name) const { for (const auto & [_, table] : scopes_) { auto sym = table->get(fullNamespace, name); if (sym) { return sym; } } return nullptr; } static std::string dump() { std::string result = ""; std::cout << "\n--- Defined Scopes ---" << '\n'; for (const auto & scope_name : instance()->getScopeNames()) { result += scope_name + '\n'; for (const auto & sname : instance()->getNameSpaces(scope_name)) { result += "\t -" + sname + '\n'; for (const auto & symbol : instance()->getAll(sname)) { result += symbol->dump() + '\n'; } } } return result; } private: std::string getNamespaceForSymbol(const SymbolPtr & symbol) const { std::string base = symbol->context().empty() ? currentScope_ : symbol->context(); switch (symbol->type()) { case Symbols::Kind::Variable: return base + ".variables"; case Symbols::Kind::Function: return base + ".functions"; case Symbols::Kind::Constant: return base + ".constants"; default: return base + ".others"; } } }; } // namespace Symbols src/Symbols/SymbolKind.hpp
@@ -3,6 +3,8 @@ #define SYMBOL_KIND_HPP #include <cstdint> #include <string> #include <unordered_map> namespace Symbols { @@ -13,6 +15,19 @@ // Later: Module, Class, etc.. }; static std::string kindToString(Symbols::Kind kind) { std::unordered_map<Symbols::Kind, std::string> KindToString = { { Symbols::Kind::Variable, "Variable" }, { Symbols::Kind::Constant, "Constant" }, { Symbols::Kind::Function, "Function" }, }; auto it = KindToString.find(kind); if (it != KindToString.end()) { return it->second; } return "Unknown kind: " + std::to_string(static_cast<int>(kind)); } }; // namespace Symbols #endif src/Symbols/SymbolTable.hpp
@@ -1,4 +1,3 @@ // SymbolTable.hpp #ifndef SYMBOL_TABLE_HPP #define SYMBOL_TABLE_HPP @@ -11,11 +10,8 @@ class SymbolTable { NamespaceMap symbols_; std::shared_ptr<SymbolTable> parent_ = nullptr; public: SymbolTable(std::shared_ptr<SymbolTable> parent = nullptr) : parent_(std::move(parent)) {} void define(const std::string & ns, const SymbolPtr & symbol) { symbols_[ns][symbol->name()] = symbol; } bool exists(const std::string & ns, const std::string & name) const { return get(ns, name) != nullptr; } @@ -29,10 +25,6 @@ return it->second; } } // Rekurzívan keresünk a szülő scope-ban if (parent_) { return parent_->get(ns, name); } return nullptr; } @@ -43,12 +35,21 @@ } } std::vector<SymbolPtr> listAll(const std::string & ns) const { std::vector<std::string> listNSs() { std::vector<std::string> result; for (const auto & [ns, _] : symbols_) { result.push_back(ns); } return result; } std::vector<SymbolPtr> listAll(const std::string & prefix = "") const { std::vector<SymbolPtr> result; auto it = symbols_.find(ns); if (it != symbols_.end()) { for (const auto & [_, sym] : it->second) { for (const auto & [ns, map] : symbols_) { if (prefix.empty() || ns.starts_with(prefix)) { for (const auto & [_, sym] : map) { result.push_back(sym); } } } return result; @@ -57,8 +58,6 @@ void clear(const std::string & ns) { symbols_.erase(ns); } void clearAll() { symbols_.clear(); } std::shared_ptr<SymbolTable> getParent() const { return parent_; } }; } // namespace Symbols src/Symbols/Value.hpp
@@ -1,10 +1,13 @@ #ifndef SYMBOL_VALUE_HPP #define SYMBOL_VALUE_HPP #include <algorithm> #include <iostream> #include <stdexcept> #include <string> #include <variant> #include "Symbols/VariableTypes.hpp" namespace Symbols { @@ -14,23 +17,32 @@ Value() = default; Value(int v) : value_(v) {} Value(int v) : value_(v) { type_ = Symbols::Variables::Type::INTEGER; } Value(double v) : value_(v) {} Value(double v) : value_(v) { type_ = Symbols::Variables::Type::DOUBLE; } Value(float v) : value_(v) {} Value(float v) : value_(v) { type_ = Symbols::Variables::Type::FLOAT; } Value(const std::string & v) : value_(v) {} Value(const std::string & v) : value_(v) { type_ = Symbols::Variables::Type::STRING; } Value(const char * v) : value_(std::string(v)) {} Value(const char * v) : value_(std::string(v)) { type_ = Symbols::Variables::Type::STRING; } Value(bool v) : value_(v) {} Value(bool v) : value_(v) { type_ = Symbols::Variables::Type::BOOLEAN; } Value(const std::string & str, bool autoDetectType) { *this = fromString(str, autoDetectType); } const Variant & get() const { return value_; } Symbols::Variables::Type getType() const { return type_; } Variant & get() { return value_; } template <typename T> T get() const { return std::get<T>(value_); } static Symbols::Value makeNull() { auto v = Value("null"); return v; } // operator+ friend Value operator+(const Value & lhs, const Value & rhs) { @@ -68,8 +80,87 @@ static std::string to_string(const Value & val) { return to_string(val.value_); } static Value fromString(const std::string & str, bool autoDetectType) { if (!autoDetectType) { return fromStringToString(str); } std::string trimmed = str; trimmed.erase(0, trimmed.find_first_not_of(" \t\n\r")); trimmed.erase(trimmed.find_last_not_of(" \t\n\r") + 1); // Check bool std::string lower = trimmed; std::transform(lower.begin(), lower.end(), lower.begin(), ::tolower); if (lower == "true" || lower == "false" || lower == "1" || lower == "0") { try { return fromStringToBool(trimmed); } catch (...) { } } // Check int try { size_t idx; int i = std::stoi(trimmed, &idx); if (idx == trimmed.size()) { return fromStringToInt(trimmed); } } catch (...) { } // Check double try { size_t idx; double d = std::stod(trimmed, &idx); if (idx == trimmed.size()) { return fromStringToDouble(trimmed); } } catch (...) { } // Fallback return fromStringToString(str); } static Value fromString(const std::string & str, Symbols::Variables::Type type) { switch (type) { case Symbols::Variables::Type::INTEGER: return fromStringToInt(str); case Symbols::Variables::Type::DOUBLE: return fromStringToDouble(str); case Symbols::Variables::Type::FLOAT: return fromStringToFloat(str); case Symbols::Variables::Type::BOOLEAN: return fromStringToBool(str); case Symbols::Variables::Type::STRING: default: return fromStringToString(str); } } private: Variant value_; Symbols::Variables::Type type_; static Value fromStringToInt(const std::string & str) { return Value(std::stoi(str)); } static Value fromStringToDouble(const std::string & str) { return Value(std::stod(str)); } static Value fromStringToFloat(const std::string & str) { return Value(std::stof(str)); } static Value fromStringToBool(const std::string & str) { std::string s = str; std::transform(s.begin(), s.end(), s.begin(), ::tolower); if (s == "true" || s == "1") { return Value(true); } if (s == "false" || s == "0") { return Value(false); } throw std::invalid_argument("Invalid bool string: " + str); } static Value fromStringToString(const std::string & str) { return Value(str); } }; } // namespace Symbols src/VoidScript.hpp
@@ -5,74 +5,68 @@ #include <fstream> #include <string> #include "Interpreter/Interpreter.hpp" #include "Lexer/Lexer.hpp" #include "Parser/Parser.hpp" class VoidScript { private: std::string file; std::vector<std::string> files; std::shared_ptr<Lexer::Lexer> lexer = nullptr; std::shared_ptr<Parser::Parser> parser = nullptr; std::string file_content; public: VoidScript(const std::string & file) : file(file) { static std::string readFile(const std::string & file) { if (!std::filesystem::exists(file)) { throw std::runtime_error("File " + file + " does not exits"); } lexer = std::make_shared<Lexer::Lexer>(); parser = std::make_shared<Parser::Parser>(); lexer->setKeyWords(Parser::Parser::keywords); // read in the file std::ifstream input(file, std::ios::in); if (!input.is_open()) { throw std::runtime_error("Could not open file " + file); return ""; } file_content = std::string((std::istreambuf_iterator<char>(input)), std::istreambuf_iterator<char>()); std::string content = std::string((std::istreambuf_iterator<char>(input)), std::istreambuf_iterator<char>()); input.close(); return content; } public: VoidScript(const std::string & file) : lexer(std::make_shared<Lexer::Lexer>()), parser(std::make_shared<Parser::Parser>()) { this->files.emplace(this->files.begin(), file); lexer->setKeyWords(Parser::Parser::keywords); } int run() { try { this->lexer->addNamespaceInput(this->file, this->file_content); const auto tokens = this->lexer->tokenizeNamespace(this->file); while (!files.empty()) { std::string file = files.back(); const std::string file_content = readFile(file); files.pop_back(); std::cout << "--- Tokens ---" << '\n'; for (const auto & token : tokens) { if (token.type != Lexer::Tokens::Type::END_OF_FILE) { //token.print(); } } std::cout << "--------------" << '\n'; parser->parseProgram(tokens, this->file_content); const std::shared_ptr<Symbols::SymbolContainer> & symbol_container = parser->getSymbolContainer(); std::string _default_namespace_ = file; std::replace(_default_namespace_.begin(), _default_namespace_.end(), '.', '_'); std::cout << "\n--- Defined Variables ---" << '\n'; for (const auto & symbol_ptr : symbol_container->listNamespace("variables")) { // Itt lehetne a szimbólumokat kiírni vagy tovább feldolgozni // Szükséges lehet dynamic_cast<> a konkrét típushoz (VariableSymbol) if (auto var_symbol = std::dynamic_pointer_cast<Symbols::VariableSymbol>(symbol_ptr)) { std::cout << var_symbol->toString() << '\n'; } } Symbols::SymbolContainer::instance()->create(_default_namespace_); std::cout << "\n--- Defined Functions ---" << '\n'; for (const auto & symbol_ptr : symbol_container->listNamespace("functions")) { if (auto func_symbol = std::dynamic_pointer_cast<Symbols::FunctionSymbol>(symbol_ptr)) { std::cout << "Func Name: " << func_symbol->name() << " return type: " << Symbols::Variables::TypeToString(func_symbol->returnType()) << '\n'; for (const auto & func_param : func_symbol->parameters()) { std::cout << " Param: " << func_param.name << " Type: " << Symbols::Variables::TypeToString(func_param.type) << '\n'; } std::cout << " Context name: " << func_symbol->context() << '\n'; std::cout << " Plain body: " << func_symbol->plainBody() << '\n'; } } const std::string ns = Symbols::SymbolContainer::instance()->currentScopeName(); this->lexer->addNamespaceInput(ns, file_content); const auto tokens = this->lexer->tokenizeNamespace(ns); std::cout << Operations::Container::dump() << "\n"; parser->parseScript(tokens, file_content, file); Interpreter::Interpreter interpreter; interpreter.run(); std::cout << Symbols::SymbolContainer::dump() << "\n"; } // while (!files.empty()) return 0; } catch (const Parser::SyntaxError & e) {