From ba9a9199d01b0fdd4bf9a54914f8058bf71f30c5 Mon Sep 17 00:00:00 2001
From: Ferenc Szontágh <szf@fsociety.hu>
Date: Thu, 17 Apr 2025 16:03:01 +0000
Subject: [PATCH] unary and binary operations
---
src/Interpreter/ExpressionBuilder.hpp | 42 +
src/Interpreter/VariableReferenceNode.hpp | 37 +
src/Interpreter/BinaryExpressionNode.hpp | 68 ++
src/Interpreter/OperationsFactory.hpp | 59 +
src/Interpreter/IdentifierExpressionNode.hpp | 29
src/Symbols/SymbolKind.hpp | 17
.clangd | 2
src/Symbols/Value.hpp | 105 ++
src/Symbols/BaseSymbol.hpp | 11
src/VoidScript.hpp | 82 +-
src/Parser/ParsedExpression.hpp | 66 ++
src/Interpreter/OperationContainer.hpp | 129 +++
src/!NameSpaceManager.hpp | 144 ++++
src/Interpreter/Operation.hpp | 68 +
src/Parser/Parser.cpp | 2
src/Lexer/Lexer.hpp | 65 +
src/Interpreter/UnaryExpressionNode.hpp | 64 +
src/Parser/Parser.hpp | 484 ++++++++------
src/Interpreter/LiteralExpressionNode.hpp | 25
src/Interpreter/ExpressionNode.hpp | 13
src/Interpreter/Interpreter.hpp | 74 +
cli/main.cpp | 3
src/Interpreter/DeclareFunctionStatementNode.hpp | 55 +
src/Lexer/TokenType.hpp | 4
src/Symbols/SymbolTable.hpp | 31
src/Symbols/SymbolContainer.hpp | 136 +++
src/Interpreter/DeclareVariableStatementNode.hpp | 52 +
src/Interpreter/StatementNode.hpp | 26
src/Interpreter/VariableExpressionNode.hpp | 36 +
29 files changed, 1,543 insertions(+), 386 deletions(-)
diff --git a/.clangd b/.clangd
index 1843e4d..a267584 100644
--- a/.clangd
+++ b/.clangd
@@ -1,5 +1,5 @@
CompileFlags:
- Add: [-Wunused]
+ Add: [-xc++, -Wall]
Index:
StandardLibrary: No
\ No newline at end of file
diff --git a/cli/main.cpp b/cli/main.cpp
index ca6c810..65dca3a 100644
--- a/cli/main.cpp
+++ b/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;
}
diff --git "a/src/\041NameSpaceManager.hpp" "b/src/\041NameSpaceManager.hpp"
new file mode 100644
index 0000000..fa249e9
--- /dev/null
+++ "b/src/\041NameSpaceManager.hpp"
@@ -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
diff --git a/src/Interpreter/BinaryExpressionNode.hpp b/src/Interpreter/BinaryExpressionNode.hpp
new file mode 100644
index 0000000..f741d3f
--- /dev/null
+++ b/src/Interpreter/BinaryExpressionNode.hpp
@@ -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
diff --git a/src/Interpreter/DeclareFunctionStatementNode.hpp b/src/Interpreter/DeclareFunctionStatementNode.hpp
new file mode 100644
index 0000000..bb3eea7
--- /dev/null
+++ b/src/Interpreter/DeclareFunctionStatementNode.hpp
@@ -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
diff --git a/src/Interpreter/DeclareVariableStatementNode.hpp b/src/Interpreter/DeclareVariableStatementNode.hpp
new file mode 100644
index 0000000..875c87b
--- /dev/null
+++ b/src/Interpreter/DeclareVariableStatementNode.hpp
@@ -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
diff --git a/src/Interpreter/ExpressionBuilder.hpp b/src/Interpreter/ExpressionBuilder.hpp
new file mode 100644
index 0000000..32b2e9b
--- /dev/null
+++ b/src/Interpreter/ExpressionBuilder.hpp
@@ -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
diff --git a/src/Interpreter/ExpressionNode.hpp b/src/Interpreter/ExpressionNode.hpp
index b3853e3..a969015 100644
--- a/src/Interpreter/ExpressionNode.hpp
+++ b/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 ~ExpressionNode() = default;
+ virtual Symbols::Value evaluate(class Interpreter & interpreter) const = 0;
+ virtual std::string toString() const = 0;
};
} // namespace Interpreter
diff --git a/src/Interpreter/IdentifierExpressionNode.hpp b/src/Interpreter/IdentifierExpressionNode.hpp
new file mode 100644
index 0000000..c610f77
--- /dev/null
+++ b/src/Interpreter/IdentifierExpressionNode.hpp
@@ -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
diff --git a/src/Interpreter/Interpreter.hpp b/src/Interpreter/Interpreter.hpp
index 84d725b..cb617c8 100644
--- a/src/Interpreter/Interpreter.hpp
+++ b/src/Interpreter/Interpreter.hpp
@@ -1,45 +1,65 @@
#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);
+ switch (op.type) {
+ case Operations::Type::Declaration:
+ if (op.statement) {
+ op.statement->interpret(*this);
+ }
+ break;
+ case Operations::Type::FuncDeclaration:
+ {
+ op.statement->interpret(*this);
+ }
+ break;
+
+ case Operations::Type::Assignment:
+ {
+ op.statement->interpret(*this);
+ break;
+ }
+
+ case Operations::Type::Expression:
+ {
+ 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:
- // 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) {}
+ Interpreter() {}
- void run(const std::vector<Operation> & ops) {
- for (const auto & op : ops) {
- switch (op.type) {
- case OperationType::Assignment:
- {
- int value = op.expression->evaluate(*this);
- setVariable(op.targetVariable, value);
- break;
- }
-
- case OperationType::Expression:
- {
- op.expression->evaluate(*this); // csak side effect miatt
- break;
- }
- }
+ void run() {
+ for (const auto & operation : Operations::Container::instance()->getAll()) {
+ runOperation(*operation);
}
}
diff --git a/src/Interpreter/LiteralExpressionNode.hpp b/src/Interpreter/LiteralExpressionNode.hpp
new file mode 100644
index 0000000..efe7c0a
--- /dev/null
+++ b/src/Interpreter/LiteralExpressionNode.hpp
@@ -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
diff --git a/src/Interpreter/Operation.hpp b/src/Interpreter/Operation.hpp
index ecbae0b..8804075 100644
--- a/src/Interpreter/Operation.hpp
+++ b/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";
+ }
+
+ std::string toString() const {
+ return "Target: " + targetName + " Type: " + this->typeToString() + " Statement: " + statement->toString();
+ }
};
-
-
-}; // namespace Interpreter
+}; // namespace Operations
#endif
diff --git a/src/Interpreter/OperationContainer.hpp b/src/Interpreter/OperationContainer.hpp
index 62b5c1d..20f9e2c 100644
--- a/src/Interpreter/OperationContainer.hpp
+++ b/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
diff --git a/src/Interpreter/OperationsFactory.hpp b/src/Interpreter/OperationsFactory.hpp
new file mode 100644
index 0000000..5adbaf7
--- /dev/null
+++ b/src/Interpreter/OperationsFactory.hpp
@@ -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
diff --git a/src/Interpreter/StatementNode.hpp b/src/Interpreter/StatementNode.hpp
new file mode 100644
index 0000000..ce070a8
--- /dev/null
+++ b/src/Interpreter/StatementNode.hpp
@@ -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
diff --git a/src/Interpreter/UnaryExpressionNode.hpp b/src/Interpreter/UnaryExpressionNode.hpp
new file mode 100644
index 0000000..e3abde1
--- /dev/null
+++ b/src/Interpreter/UnaryExpressionNode.hpp
@@ -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
diff --git a/src/Interpreter/VariableExpressionNode.hpp b/src/Interpreter/VariableExpressionNode.hpp
new file mode 100644
index 0000000..6171fc3
--- /dev/null
+++ b/src/Interpreter/VariableExpressionNode.hpp
@@ -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
diff --git a/src/Interpreter/VariableReferenceNode.hpp b/src/Interpreter/VariableReferenceNode.hpp
new file mode 100644
index 0000000..2906570
--- /dev/null
+++ b/src/Interpreter/VariableReferenceNode.hpp
@@ -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
diff --git a/src/Lexer/Lexer.hpp b/src/Lexer/Lexer.hpp
index 737ec1d..4bd0ecf 100644
--- a/src/Lexer/Lexer.hpp
+++ b/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 {
@@ -73,7 +73,7 @@
if (isalpha(c) || c == '_') {
return matchIdentifierOrKeyword(start);
}
- if (isdigit(c) || (isdigit(c) && peek(1) == '.')|| (c == '.' && isdigit(peek(1)))) {
+ if (isdigit(c) || (isdigit(c) && peek(1) == '.') || (c == '.' && isdigit(peek(1)))) {
return matchNumber(start);
}
if (c == '"' || c == '\'') {
@@ -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() {
diff --git a/src/Lexer/TokenType.hpp b/src/Lexer/TokenType.hpp
index 2dd49ca..e29ba04 100644
--- a/src/Lexer/TokenType.hpp
+++ b/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";
diff --git a/src/Parser/ParsedExpression.hpp b/src/Parser/ParsedExpression.hpp
new file mode 100644
index 0000000..3f74478
--- /dev/null
+++ b/src/Parser/ParsedExpression.hpp
@@ -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
diff --git a/src/Parser/Parser.cpp b/src/Parser/Parser.cpp
index fbd0e73..3c5af2b 100644
--- a/src/Parser/Parser.cpp
+++ b/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 },
diff --git a/src/Parser/Parser.hpp b/src/Parser/Parser.hpp
index b40397e..41a7545 100644
--- a/src/Parser/Parser.hpp
+++ b/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,21 +56,14 @@
}
}
- 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;
private:
- 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::vector<Lexer::Tokens::Token> tokens_;
+ std::string_view input_str_view_;
+ size_t current_token_index_;
+ 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();
+ Lexer::Tokens::Token token = currentToken();
+ bool is_negative = false;
- /// 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;
- }
- 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);
- }
- }
- reportError("Expected numeric literal value for double");
- } else if (expected_var_type == Symbols::Variables::Type::BOOLEAN) {
- if (token.type == Lexer::Tokens::Type::KEYWORD) {
- consumeToken();
- return Symbols::Value(token.value == "true"); // A lexer value-ja már a feldolgozott string
- }
- reportError("Expected boolean literal value");
- } else {
- // Más típusok (pl. boolean) itt kezelendők, ha lennének
- reportError("Unsupported variable type encountered during value parsing");
}
- // Should not reach here due to reportError throwing
- return Symbols::Value(); // Default return to satisfy compiler
+
+ // 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(token.value == "true");
+ }
+ reportError("Expected boolean literal value (true or false)");
+ }
+
+ // 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 val;
+ }
+
+ reportError("Expected numeric literal value");
+ }
+
+ reportError("Unsupported variable type encountered during value parsing");
+ 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);
- } else {
- reportError("Invalid position range in body reconstruction");
+ 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 {
+ 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 (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
- break;
+ if (operator_stack.empty() || operator_stack.top() != "(") {
+ reportError("Mismatched parentheses");
}
- body_ss << token.lexeme;
+ 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-
+ }
+
+ 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;
+ }
+ }
+
+ 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 {
- body_ss << token.lexeme;
+ break;
+ }
+ }
+
+ // 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");
}
- last_token_end_pos = token.end_pos;
- consumeToken();
+ 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 (return_required && !has_return) {
- return "";
+ if (output_queue.size() != 1) {
+ reportError("Expression could not be parsed cleanly");
}
- return body_ss.str();
+ return std::move(output_queue.back());
}
}; // class Parser
diff --git a/src/Symbols/BaseSymbol.hpp b/src/Symbols/BaseSymbol.hpp
index 2d3cdb2..604463c 100644
--- a/src/Symbols/BaseSymbol.hpp
+++ b/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_); }
};
diff --git a/src/Symbols/SymbolContainer.hpp b/src/Symbols/SymbolContainer.hpp
index 1985c50..c0bb814 100644
--- a/src/Symbols/SymbolContainer.hpp
+++ b/src/Symbols/SymbolContainer.hpp
@@ -1,51 +1,141 @@
-// 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_;
+ public:
+ 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
+} // namespace Symbols
#endif
diff --git a/src/Symbols/SymbolKind.hpp b/src/Symbols/SymbolKind.hpp
index 5f9c8e8..8b4c5bf 100644
--- a/src/Symbols/SymbolKind.hpp
+++ b/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..
};
-}; // namespace Symbols
+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
diff --git a/src/Symbols/SymbolTable.hpp b/src/Symbols/SymbolTable.hpp
index 0c4c7da..f774f8d 100644
--- a/src/Symbols/SymbolTable.hpp
+++ b/src/Symbols/SymbolTable.hpp
@@ -1,4 +1,3 @@
-// SymbolTable.hpp
#ifndef SYMBOL_TABLE_HPP
#define SYMBOL_TABLE_HPP
@@ -10,12 +9,9 @@
namespace Symbols {
class SymbolTable {
- NamespaceMap symbols_;
- std::shared_ptr<SymbolTable> parent_ = nullptr;
+ NamespaceMap symbols_;
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) {
- result.push_back(sym);
+ 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
diff --git a/src/Symbols/Value.hpp b/src/Symbols/Value.hpp
index 4c52b04..a0ff38b 100644
--- a/src/Symbols/Value.hpp
+++ b/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_;
+ 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
diff --git a/src/VoidScript.hpp b/src/VoidScript.hpp
index d1188b5..4f0aed4 100644
--- a/src/VoidScript.hpp
+++ b/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) {
--
Gitblit v1.9.3