From 3895272a7f238c9aef0b584bd3b10b900445245d Mon Sep 17 00:00:00 2001
From: Ferenc Szontágh <szf@fsociety.hu>
Date: Tue, 15 Apr 2025 19:45:02 +0000
Subject: [PATCH] refactored
---
src/Lexer/Token.hpp | 37 +
src/Symbols/SymbolFactory.hpp | 24
CMakeLists.txt | 6
src/Symbols/ConstantSymbol.hpp | 0
src/Symbols/SymbolKind.hpp | 0
src/Symbols/SymbolTypes.hpp | 0
src/Symbols/ValueContainer.hpp | 12
src/Symbols/Value.hpp | 77 ++
src/Symbols/BaseSymbol.hpp | 4
src/VoidScript.hpp | 89 +++
src/Interpreter/OperationContainer.hpp | 12
src/Interpreter/Operation.hpp | 31 +
src/Parser/Parser.cpp | 37 +
src/Symbols/VariableTypes.hpp | 48 +
src/Lexer/Lexer.hpp | 316 +++++++++++
src/Parser/Parser.hpp | 536 +++++++++++++++++++
src/Lexer/Lexer.cpp | 14
src/Interpreter/ExpressionNode.hpp | 17
src/Interpreter/Interpreter.hpp | 49 +
src/Builtins/BaseFunction.hpp | 0
cli/main.cpp | 25
/dev/null | 120 ----
src/Symbols/FunctionSymbol.hpp | 41 +
src/Symbols/ParameterContainer.hpp | 17
src/Symbols/VariableSymbol.hpp | 45 +
src/Lexer/TokenType.hpp | 87 +++
src/Symbols/SymbolTable.hpp | 1
src/Symbols/SymbolContainer.hpp | 0
28 files changed, 1,492 insertions(+), 153 deletions(-)
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 013b4c9..b9e1780 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -113,13 +113,13 @@
configure_file("test_scripts/test1.vs" "test_scripts/test1.vs" @ONLY)
configure_file("test_scripts/test2.vs" "test_scripts/test2.vs" @ONLY)
-include_directories(${CMAKE_BINARY_DIR}/include ${CMAKE_SOURCE_DIR}/src ${CMAKE_SOURCE_DIR}/include)
+include_directories(${CMAKE_BINARY_DIR}/include ${CMAKE_SOURCE_DIR}/src)
# LIBRARY TARGET
add_library(voidscript
- src/ScriptInterpreter.cpp
- src/Lexer.cpp
+ src/Parser/Parser.cpp
+ src/Lexer/Lexer.cpp
)
install(TARGETS voidscript DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT "lib")
diff --git a/cli/main.cpp b/cli/main.cpp
index a20c2bc..ca6c810 100644
--- a/cli/main.cpp
+++ b/cli/main.cpp
@@ -1,9 +1,10 @@
#include <filesystem>
#include <fstream>
+#include <iostream>
+#include <unordered_map>
-#include "Builtins/PrintModule.hpp"
-#include "Builtins/SleepModule.hpp"
-#include "ScriptInterpreter.hpp"
+#include "options.h"
+#include "VoidScript.hpp"
const std::unordered_map<std::string, std::string> params = {
{ "--help", "Print this help message" },
@@ -55,22 +56,8 @@
const std::string filename = std::filesystem::canonical(file).string();
- try {
- std::ifstream input(filename);
- if (!input.is_open()) {
- std::cerr << "Error: Could not open file " << filename << "\n";
- return 1;
- }
-
- std::string content((std::istreambuf_iterator<char>(input)), std::istreambuf_iterator<char>());
- ScriptInterpreter interp;
- interp.registerModule("print", std::make_shared<PrintFunction>());
- interp.registerModule("sleep", std::make_shared<SleepFunction>());
- interp.executeScript(content, filename, "DEFAULT", false);
- } catch (const std::exception & e) {
- std::cerr << "Parser error: " << e.what() << "\n";
- return 1;
- }
+ VoidScript voidscript(filename);
+ return voidscript.run();
return 0;
}
diff --git a/include/FunctionSymbol.hpp b/include/FunctionSymbol.hpp
deleted file mode 100644
index 97c23f8..0000000
--- a/include/FunctionSymbol.hpp
+++ /dev/null
@@ -1,31 +0,0 @@
-// FunctionSymbol.hpp
-#ifndef FUNCTION_SYMBOL_HPP
-#define FUNCTION_SYMBOL_HPP
-
-#include <vector>
-
-#include "BaseSymbol.hpp"
-
-namespace Symbols {
-using ValueContainer = std::vector<Symbols::Value>;
-
-class FunctionSymbol : public Symbol {
- std::vector<Symbols::Value> parameters_;
- Symbols::Value returnType_;
- std::string plainBody_;
-
- public:
- FunctionSymbol(const std::string & name, const std::string & context, const ValueContainer & parameters,
- const std::string & plainbody = "") :
- Symbol(name, {}, context, Symbols::Kind::Function),
- parameters_(parameters),
- plainBody_(plainbody) {}
-
- Symbols::Kind kind() const override { return Symbols::Kind::Function; }
-
- const ValueContainer & parameters() const { return parameters_; }
-};
-
-} // namespace Symbols
-
-#endif
diff --git a/include/VariableSymbol.hpp b/include/VariableSymbol.hpp
deleted file mode 100644
index 652565e..0000000
--- a/include/VariableSymbol.hpp
+++ /dev/null
@@ -1,20 +0,0 @@
-// VariableSymbol.hpp
-#ifndef VARIABLE_SYMBOL_HPP
-#define VARIABLE_SYMBOL_HPP
-
-#include "BaseSymbol.hpp"
-
-namespace Symbols {
-
-class VariableSymbol : public Symbol {
- public:
- VariableSymbol(const std::string & name, const Symbols::Value & value, const std::string & context,
- Symbols::Kind type) :
- Symbol(name, value, context, type) {}
-
- Symbols::Kind kind() const override { return Symbols::Kind::Variable; }
-};
-
-} // namespace Symbols
-
-#endif
diff --git a/include/VariableTypes.hpp b/include/VariableTypes.hpp
deleted file mode 100644
index 8ac087d..0000000
--- a/include/VariableTypes.hpp
+++ /dev/null
@@ -1,46 +0,0 @@
-#ifndef VARIABLE_TYPES_HPP
-#define VARIABLE_TYPES_HPP
-
-#include <cstdint>
-#include <string>
-#include <unordered_map>
-
-namespace Symbols::Variables {
-
-enum class Type : std::uint8_t { VT_INT, VT_DOUBLE, VT_STRING, VT_BOOLEAN, VT_NULL, VT_UNDEFINED };
-
-const std::unordered_map<std::string, Type> StringToTypeMap = {
- { "int", Type::VT_INT },
- { "double", Type::VT_DOUBLE },
- { "string", Type::VT_STRING },
- { "bool", Type::VT_BOOLEAN },
- { "boolean", Type::VT_BOOLEAN },
- { "null", Type::VT_NULL },
-
- { "undefined", Type::VT_UNDEFINED },
-};
-const std::unordered_map<Type, std::string> StypeToStringMap = {
- { Type::VT_INT, "int" },
- { Type::VT_DOUBLE, "double" },
- { Type::VT_STRING, "string" },
- { Type::VT_BOOLEAN, "bool" },
- { Type::VT_NULL, "null" },
- { Type::VT_UNDEFINED, "undeffined" },
-};
-
-inline static std::string TypeToString(Type type) {
- if (StypeToStringMap.find(type) != StypeToStringMap.end()) {
- return StypeToStringMap.at(type);
- }
- return "null";
-};
-
-inline static Type StringToType(const std::string & type) {
- if (StringToTypeMap.find(type) != StringToTypeMap.end()) {
- return StringToTypeMap.at(type);
- }
- return Type::VT_NULL;
-};
-
-}; // namespace Symbols
-#endif // VARIABLE_TYPES_HPP
diff --git a/include/BaseFunction.hpp b/src/Builtins/BaseFunction.hpp
similarity index 100%
rename from include/BaseFunction.hpp
rename to src/Builtins/BaseFunction.hpp
diff --git a/src/Interpreter/ExpressionNode.hpp b/src/Interpreter/ExpressionNode.hpp
new file mode 100644
index 0000000..b3853e3
--- /dev/null
+++ b/src/Interpreter/ExpressionNode.hpp
@@ -0,0 +1,17 @@
+#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;
+};
+
+// Kifejezés (csak int literál most)
+struct ExpressionNode {
+ virtual ~ExpressionNode() = default;
+ virtual int evaluate(class Interpreter & interpreter) const = 0;
+};
+
+} // namespace Interpreter
+#endif // INTERPRETER_FUNCTION_EXECUTOR_HPP
diff --git a/src/Interpreter/Interpreter.hpp b/src/Interpreter/Interpreter.hpp
new file mode 100644
index 0000000..84d725b
--- /dev/null
+++ b/src/Interpreter/Interpreter.hpp
@@ -0,0 +1,49 @@
+#ifndef INTERPRETER_HPP
+#define INTERPRETER_HPP
+#include <memory>
+#include <utility>
+#include <vector>
+
+#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 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:
+ {
+ int value = op.expression->evaluate(*this);
+ setVariable(op.targetVariable, value);
+ break;
+ }
+
+ case OperationType::Expression:
+ {
+ op.expression->evaluate(*this); // csak side effect miatt
+ break;
+ }
+ }
+ }
+ }
+
+}; // class Interpreter
+
+} // namespace Interpreter
+#endif // INTERPRETER_HPP
diff --git a/src/Interpreter/Operation.hpp b/src/Interpreter/Operation.hpp
new file mode 100644
index 0000000..ecbae0b
--- /dev/null
+++ b/src/Interpreter/Operation.hpp
@@ -0,0 +1,31 @@
+#ifndef INTERPRETER_OPERATION_HPP
+#define INTERPRETER_OPERATION_HPP
+
+#include <cstdint>
+
+#include <memory>
+#include <string>
+
+#include "ExpressionNode.hpp"
+
+namespace Interpreter {
+enum OperationType : std::uint8_t {
+ Assignment,
+ Expression,
+
+};
+
+struct Operation {
+ OperationType type;
+
+ // Általános mezők
+ std::string targetVariable;
+ std::unique_ptr<ExpressionNode> expression;
+
+ Operation(OperationType t, std::string var, std::unique_ptr<ExpressionNode> expr)
+ : type(t), targetVariable(std::move(var)), expression(std::move(expr)) {}
+};
+
+
+}; // namespace Interpreter
+#endif
diff --git a/src/Interpreter/OperationContainer.hpp b/src/Interpreter/OperationContainer.hpp
new file mode 100644
index 0000000..62b5c1d
--- /dev/null
+++ b/src/Interpreter/OperationContainer.hpp
@@ -0,0 +1,12 @@
+#ifndef INTERPRETER_OPERATION_CONTAINER_HPP
+#define INTERPRETER_OPERATION_CONTAINER_HPP
+
+#include <vector>
+
+#include "Interpreter/Operation.hpp"
+
+namespace Interpreter {
+using OperationContainer = std::vector<Operation>;
+}; // namespace Interpreter
+
+#endif // INTERPRETER_OPERATION_CONTAINER_HPP
diff --git a/src/Lexer.cpp b/src/Lexer.cpp
deleted file mode 100644
index 362e4b8..0000000
--- a/src/Lexer.cpp
+++ /dev/null
@@ -1,352 +0,0 @@
-#include "Lexer.hpp"
-
-#include <cctype>
-
-#include "options.h"
-
-Lexer::Lexer(const std::string & source, const std::string & filename) :
- src(source),
- pos(0),
- filename(filename),
- lineNumber(1),
- colNumber(1),
- charNumber(0) {}
-
-/**
- * Peek at the current character without advancing the lexer's position.
- *
- * @return The current character, or '\0' if at the end of the source.
- */
-char Lexer::peek() const {
- return pos < src.size() ? src[pos] : '\0';
-}
-
-char Lexer::advance() {
- if (pos >= src.size()) {
- return '\0';
- }
- char c = src[pos++];
- if (c == '\n') {
- this->lineNumber++;
- this->colNumber = 1;
- } else {
- this->colNumber++;
- }
- this->charNumber++;
- return c;
-}
-
-bool Lexer::isAtEnd() const {
- return pos >= src.size();
-}
-
-Tokens::Token Lexer::createToken(Tokens::Type type, const std::string & lexeme) const {
- size_t startChar = charNumber - lexeme.length();
- return {
- type, lexeme, filename, lineNumber, colNumber - lexeme.length(), { startChar, charNumber }
- };
-}
-
-Tokens::Token Lexer::createSingleCharToken(Tokens::Type type, const std::string & lexeme) {
- size_t startCol = colNumber;
- size_t startChar = charNumber;
- advance();
- return {
- type, lexeme, filename, lineNumber, startCol, { startChar, charNumber }
- };
-}
-
-Tokens::Token Lexer::createUnknownToken(const std::string & lexeme) const {
- size_t startChar = charNumber - lexeme.length();
- return {
- Tokens::Type::Unknown, lexeme, filename, lineNumber, colNumber - lexeme.length(), { startChar, charNumber }
- };
-}
-
-Tokens::Token Lexer::stringToken() {
- std::string result;
- size_t startChar = charNumber;
- size_t startCol = colNumber;
- advance(); // Skip opening quote
- while (!isAtEnd() && peek() != '"') {
- result += advance();
- }
- if (isAtEnd() || peek() != '"') {
- return {
- Tokens::Type::Unknown, "Unterminated string", filename, lineNumber, startCol, { startChar, pos }
- };
- }
- advance(); // Skip closing quote
- return {
- Tokens::Type::StringLiteral, result, filename, lineNumber, startCol, { startChar, pos }
- };
-}
-
-Tokens::Token Lexer::numberToken() {
- std::string result;
- std::string found;
- Tokens::Type type = Tokens::Type::Unknown;
- bool decimalPointSeen = false;
- size_t startChar = charNumber;
- size_t startCol = colNumber;
-
- while (std::isdigit(peek()) || peek() == '.') {
- if (peek() == '.') {
- if (decimalPointSeen) {
- return {
- Tokens::Type::Unknown, "Invalid number format", filename, lineNumber, startCol, { startChar, pos }
- };
- }
- decimalPointSeen = true;
- }
- found.append(1, advance());
- }
-
- if (!found.empty()) {
- if (found.find('.') == std::string::npos) {
- if (is_number<int>(found)) {
- result = found;
- type = Tokens::Type::IntLiteral;
- } else {
- return {
- Tokens::Type::Unknown, "Invalid integer", filename, lineNumber, startCol, { startChar, pos }
- };
- }
- } else {
- if (is_number<double>(found)) {
- result = found;
- type = Tokens::Type::DoubleLiteral;
- } else {
- return {
- Tokens::Type::Unknown, "Invalid double", filename, lineNumber, startCol, { startChar, pos }
- };
- }
- }
- } else {
- return {
- Tokens::Type::Unknown, "Expected number", filename, lineNumber, startCol, { startChar, pos }
- };
- }
-
- return {
- type, result, filename, lineNumber, startCol, { startChar, pos }
- };
-}
-
-Tokens::Token Lexer::identifierToken() {
- std::string result;
- size_t startChar = charNumber;
- size_t startCol = colNumber;
- while (isalnum(peek()) || peek() == '_') {
- result += advance();
- }
- return {
- Tokens::Type::Identifier, result, filename, lineNumber, startCol, { startChar, pos }
- };
-}
-
-Tokens::Token Lexer::variableToken() {
- size_t startChar = charNumber;
- size_t startCol = colNumber;
- advance(); // Skip $
- std::string varName;
- if (isalpha(peek()) || peek() == '_') {
- varName += advance();
- while (isalnum(peek()) || peek() == '_') {
- varName += advance();
- }
- return {
- Tokens::Type::Variable, varName, filename, lineNumber, startCol, { startChar, pos }
- };
- }
- return {
- Tokens::Type::Unknown, "$ followed by invalid character", filename, lineNumber, startCol, { startChar, pos }
- };
-}
-
-Tokens::Token Lexer::commentToken() {
- size_t startChar = charNumber;
- size_t startCol = colNumber;
- advance(); // Skip #
- std::string commentText;
- while (!isAtEnd() && peek() != '\n') {
- commentText += advance();
- }
- return {
- Tokens::Type::Comment, commentText, filename, lineNumber, startCol, { startChar, pos }
- };
-}
-
-Tokens::Token Lexer::keywordOrIdentifierToken() {
- std::string lexeme;
- while (isalpha(peek())) {
- lexeme += advance();
- }
- if (lexeme == IDENTIFIER_FUNCTION) {
- return this->functionDeclarationToken();
- }
-
- if (lexeme == IDENTIFIER_RETURN) {
- return createToken(Tokens::Type::Return, lexeme);
- }
- if (lexeme == IDENTIFIER_IF) {
- return createToken(Tokens::Type::ParserIfStatement, lexeme);
- }
-
- if (peek() == '(') { // Function call
- return createToken(Tokens::Type::FunctionCall, lexeme);
- }
-
- auto it = Variables::StringToTypeMap.find(lexeme);
- if (it != Variables::StringToTypeMap.end()) {
- const auto & type = it->second;
- while (isspace(peek())) {
- advance();
- }
-
- if (peek() == IDENTIFIER_VARIABLE) {
- return this->variableDeclarationToken(type);
- }
- return createToken(Tokens::Type::Identifier, lexeme);
- }
- return createToken(Tokens::Type::Identifier, lexeme);
-}
-
-Tokens::Token Lexer::functionDeclarationToken() {
- advance(); // Skip function
- std::string functionName;
- if (isalpha(peek()) || peek() == '_') {
- functionName += advance();
- while (isalnum(peek()) || peek() == '_') {
- functionName += advance();
- }
- return createToken(Tokens::Type::FunctionDeclaration, functionName);
- }
- return createUnknownToken("function followed by invalid character");
-}
-
-Tokens::Token Lexer::variableDeclarationToken(Variables::Type type) {
- advance(); // Skip $
- std::string varName;
- if (isalpha(peek()) || peek() == '_') {
- varName += advance();
- while (isalnum(peek()) || peek() == '_') {
- varName += advance();
- }
- for (auto it = Variables::StringToTypeMap.begin(); it != Variables::StringToTypeMap.end(); ++it) {
- if (it->second == type) {
- return createToken(getTokenTypeFromValueDeclaration(it->second), varName);
- }
- }
- return createUnknownToken("Invalid variable type in declaration");
- }
- return createUnknownToken("$ followed by invalid character in declaration");
-}
-
-bool Lexer::matchSequence(const std::string & sequence, bool caseSensitive) const {
- if (this->pos + sequence.size() > src.size()) {
- return false;
- }
- for (size_t i = 0; i < sequence.size(); ++i) {
- char srcChar = src[this->pos + i];
- char seqChar = sequence[i];
- if (!caseSensitive) {
- srcChar = std::tolower(static_cast<unsigned char>(srcChar));
- seqChar = std::tolower(static_cast<unsigned char>(seqChar));
- }
- if (srcChar != seqChar) {
- return false;
- }
- }
- return true;
-}
-
-void Lexer::matchAndConsume(const std::string & sequence, bool caseSensitive) {
- if (matchSequence(sequence, caseSensitive)) {
- for (size_t i = 0; i < sequence.length(); ++i) {
- advance();
- }
- }
-}
-
-std::vector<Tokens::Token> Lexer::tokenize() {
- std::vector<Tokens::Token> tokens;
- tokens.reserve(src.size() / 4);
-
- while (pos < src.size()) {
- char c = src[pos];
-
- if (isspace(c)) {
- advance();
- continue;
- }
- if (c == '\n') {
- tokens.push_back(createSingleCharToken(Tokens::Type::EndOfLine, "\n"));
- continue;
- }
- if (c == IDENTIFIER_COMMENT) {
- tokens.push_back(commentToken());
- advance(); // Skip newline after comment
- continue;
- }
- if (matchSequence(PARSER_OPEN_TAG)) {
- matchAndConsume(PARSER_OPEN_TAG);
- tokens.push_back(createToken(Tokens::Type::ParserOpenTag, PARSER_OPEN_TAG));
- continue;
- }
- if (matchSequence(PARSER_CLOSE_TAG)) {
- matchAndConsume(PARSER_CLOSE_TAG);
- tokens.push_back(createToken(Tokens::Type::ParserCloseTag, PARSER_CLOSE_TAG));
- continue;
- }
- switch (c) {
- case 'a' ... 'z':
- case 'A' ... 'Z':
- tokens.push_back(keywordOrIdentifierToken());
- break;
- case IDENTIFIER_VARIABLE:
- tokens.push_back(variableToken());
- break;
- case '0' ... '9':
- tokens.push_back(numberToken());
- break;
- case '"':
- case '\'':
- tokens.push_back(stringToken());
- break;
- case '(':
- tokens.push_back(createSingleCharToken(Tokens::Type::LeftParenthesis, "("));
- break;
- case ')':
- tokens.push_back(createSingleCharToken(Tokens::Type::RightParenthesis, ")"));
- break;
- case ',':
- tokens.push_back(createSingleCharToken(Tokens::Type::Comma, ","));
- break;
- case ';':
- tokens.push_back(createSingleCharToken(Tokens::Type::Semicolon, ";"));
- break;
- case '=':
- tokens.push_back(createSingleCharToken(Tokens::Type::Equals, "="));
- break;
- case '+':
- tokens.push_back(createSingleCharToken(Tokens::Type::Plus, "+"));
- break;
- case '{':
- tokens.push_back(createSingleCharToken(Tokens::Type::LeftCurlyBracket, "{"));
- break;
- case '}':
- tokens.push_back(createSingleCharToken(Tokens::Type::RightCurlyBracket, "}"));
- break;
- default:
- tokens.push_back(createUnknownToken(std::string(1, c)));
- advance();
- break;
- }
- }
-
- tokens.push_back({
- Tokens::Type::EndOfFile, "", filename, lineNumber, colNumber, { charNumber, charNumber }
- });
- return tokens;
-}
diff --git a/src/Lexer.hpp b/src/Lexer.hpp
deleted file mode 100644
index 7274e47..0000000
--- a/src/Lexer.hpp
+++ /dev/null
@@ -1,77 +0,0 @@
-#ifndef LEXER_HPP
-#define LEXER_HPP
-
-#include <algorithm>
-#include <istream>
-#include <sstream>
-#include <vector>
-
-#include "StringHelpers.hpp"
-#include "Token.hpp"
-#include "VariableTypes.hpp"
-
-class Lexer {
- public:
- Lexer(const std::string & source, const std::string & filename);
- std::vector<Token> tokenize();
-
- private:
- const std::string & src;
- const std::string & filename;
- size_t pos;
- int lineNumber = 1;
- size_t colNumber = 1;
- size_t charNumber = 1;
-
- char peek() const;
- char advance();
- bool isAtEnd() const;
-
- Token string();
- Token number();
- Token identifier();
- Token variable();
- Token comment();
- Token keywordOrIdentifier();
- Token boolean();
- Token singleCharToken(TokenType type, const std::string & lexeme);
- bool matchSequence(const std::string & sequence, bool caseSensitive = true) const;
- Token variableDeclaration(Variables::Type type);
- void matchAndConsume(const std::string & sequence, bool caseSensitive = true);
-
- // create token methods
- Token createToken(TokenType type, const std::string & lexeme) const;
- Token createSingleCharToken(TokenType type, const std::string & lexeme);
- Token createUnknownToken(const std::string & lexeme) const;
- Token createErrorToken(const std::string & lexeme) const;
- Token stringToken();
- Token numberToken();
- Token identifierToken();
- Token variableToken();
- Token commentToken();
- Token keywordOrIdentifierToken();
- Token functionDeclarationToken();
- Token variableDeclarationToken(Variables::Type type);
-
- // validate number types from string
- template <typename Numeric> static bool is_number(const std::string & s) {
- Numeric n;
- return ((std::istringstream(s) >> n >> std::ws).eof());
- }
-
- bool matchSequence(const std::string & sequence, bool caseSensitive = true) {
- if (caseSensitive) {
- return src.substr(pos, sequence.length()) == sequence;
- }
-
- std::string srcSubstr = src.substr(pos, sequence.length());
- std::string seqLower = sequence;
-
- StringHelpers::strtolower(srcSubstr);
- StringHelpers::strtolower(seqLower);
-
- return srcSubstr == seqLower;
- }
-};
-
-#endif // LEXER_HPP
diff --git a/src/Lexer/Lexer.cpp b/src/Lexer/Lexer.cpp
new file mode 100644
index 0000000..6f6cc35
--- /dev/null
+++ b/src/Lexer/Lexer.cpp
@@ -0,0 +1,14 @@
+#include "Lexer/Lexer.hpp"
+
+namespace Lexer {
+const std::vector<std::string> Lexer::Lexer::OPERATOR_RELATIONAL = { "==", "!=", "<", ">", "<=", ">=" };
+const std::vector<std::string> Lexer::Lexer::OPERATOR_INCREMENT = { "++", "--" };
+const std::vector<std::string> Lexer::Lexer::OPERATOR_ASSIGNMENT = { "=", "+=", "-=", "*=", "/=", "%=" };
+const std::vector<std::string> Lexer::Lexer::OPERATOR_LOGICAL = { "&&", "||" };
+
+const std::vector<std::string> Lexer::Lexer::OPERATOR_ARITHMETIC = { "+", "-", "*", "/", "%" };
+const std::vector<std::string> Lexer::Lexer::PUNCTUATION = { "(", ")", "{", "}", "[", "]", ",", ";" };
+
+
+
+}; // namespace Lexer
diff --git a/src/Lexer/Lexer.hpp b/src/Lexer/Lexer.hpp
new file mode 100644
index 0000000..737ec1d
--- /dev/null
+++ b/src/Lexer/Lexer.hpp
@@ -0,0 +1,316 @@
+#ifndef LEXER_HPP
+#define LEXER_HPP
+
+#include <algorithm> // std::find_if
+#include <cctype> // <<< Hozzáadva
+#include <string>
+#include <string_view> // <<< Hozzáadva
+#include <unordered_map>
+#include <vector>
+
+#include "Token.hpp" // Feltételezzük, hogy ez a fenti Token.hpp
+
+namespace Lexer {
+class Lexer {
+ public:
+ Lexer() {
+ for (const auto & vecRef :
+ { std::cref(OPERATOR_ARITHMETIC), std::cref(OPERATOR_RELATIONAL), std::cref(OPERATOR_INCREMENT),
+ std::cref(OPERATOR_ASSIGNMENT), std::cref(OPERATOR_LOGICAL), std::cref(PUNCTUATION) }) {
+ for (const auto & str : vecRef.get()) {
+ operators_ += str;
+ }
+ }
+
+ operators_ += "$";
+ }
+
+ void addNamespaceInput(const std::string & ns, const std::string & input) {
+ inputs_[ns] = input;
+ positions_[ns] = 0;
+ line_numbers_[ns] = 1;
+ 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);
+ std::vector<Tokens::Token> tokens;
+ Tokens::Token token;
+ do {
+ token = nextToken();
+ tokens.push_back(token);
+ } while (token.type != Tokens::Type::END_OF_FILE);
+
+ tokens_[ns] = tokens;
+ return tokens;
+ }
+
+ std::vector<Tokens::Token> getTokens(const std::string & ns) const {
+ auto it = tokens_.find(ns);
+ if (it != tokens_.end()) {
+ return it->second;
+ }
+ return {};
+ }
+
+ void setKeyWords(const std::unordered_map<std::string, Tokens::Type> & new_keywords) { keywords = new_keywords; }
+
+ Tokens::Token nextToken() {
+ skipWhitespaceAndComments();
+ size_t start = pos();
+
+ if (isAtEnd()) {
+ return createToken(Tokens::Type::END_OF_FILE, start, start);
+ }
+
+ char c = peek();
+ if (isalpha(c) || c == '_') {
+ return matchIdentifierOrKeyword(start);
+ }
+ if (isdigit(c) || (isdigit(c) && peek(1) == '.')|| (c == '.' && isdigit(peek(1)))) {
+ return matchNumber(start);
+ }
+ if (c == '"' || c == '\'') {
+ return matchStringLiteral(start);
+ }
+ if (operators_.find(c) != std::string_view::npos) {
+ return matchOperatorOrPunctuation(start);
+ }
+
+ advance();
+ return createToken(Tokens::Type::UNKNOWN, start, pos());
+ }
+
+
+ private:
+ std::unordered_map<std::string, std::string> inputs_;
+ std::unordered_map<std::string, std::vector<Tokens::Token>> tokens_;
+ std::unordered_map<std::string, size_t> positions_;
+ std::unordered_map<std::string, int> line_numbers_;
+ 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
+ static const std::vector<std::string> OPERATOR_RELATIONAL;
+ static const std::vector<std::string> OPERATOR_INCREMENT;
+ static const std::vector<std::string> OPERATOR_ASSIGNMENT;
+ static const std::vector<std::string> OPERATOR_LOGICAL;
+
+ // one char
+ 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_); }
+
+ size_t & pos() { return positions_[current_namespace_]; }
+
+ int & line() { return line_numbers_[current_namespace_]; }
+
+ int & col() { return column_numbers_[current_namespace_]; }
+
+ Tokens::Token createToken(Tokens::Type type, size_t start, size_t end, const std::string & value = "") {
+ Tokens::Token token;
+ token.type = type;
+ token.start_pos = start;
+ token.end_pos = end;
+ token.line_number = line();
+ token.column_number = col();
+ if (start <= end && end <= input().length()) {
+ token.lexeme = std::string_view(input()).substr(start, end - start);
+ token.value = value.empty() ? std::string(token.lexeme) : value;
+ }
+ return token;
+ }
+
+ // --------------------------------------
+
+ char peek(size_t offset = 0) const {
+ const auto & in = inputs_.at(current_namespace_);
+ size_t cp = positions_.at(current_namespace_);
+ if (cp + offset >= in.length()) {
+ return '\0';
+ }
+ return in[cp + offset];
+ }
+
+ char advance() {
+ char c = peek();
+ pos()++;
+ if (c == '\n') {
+ line()++;
+ col() = 1;
+ } else {
+ col()++;
+ }
+ 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 == '#');
+ }
+
+ void skipWhitespaceAndComments() {
+ while (!isAtEnd()) {
+ char c = peek();
+ if (isspace(c)) {
+ advance();
+ } else if ((c == '/' && peek(1) == '/') || c == '#') {
+ while (!isAtEnd() && peek() != '\n') {
+ advance();
+ }
+ } else {
+ break;
+ }
+ }
+ }
+
+ Tokens::Token matchIdentifierOrKeyword(size_t start_pos, Tokens::Type type = Tokens::Type::IDENTIFIER) {
+ while (!isAtEnd() && (isalnum(peek()) || peek() == '_')) {
+ advance();
+ }
+ size_t end = pos();
+ std::string value = input().substr(start_pos, end - start_pos);
+ if (value.empty()) {
+ return createToken(Tokens::Type::UNKNOWN, start_pos, end);
+ }
+
+ if (type == Tokens::Type::IDENTIFIER) {
+ auto it = keywords.find(value);
+ if (it != keywords.end()) {
+ return createToken(it->second, start_pos, end);
+ }
+ }
+ return createToken(type, start_pos, end);
+ }
+
+ Tokens::Token matchNumber(size_t start_pos) {
+ bool has_dot = false;
+
+ while (!isAtEnd()) {
+ if (isdigit(peek())) {
+ advance();
+ } else if (!has_dot && peek() == '.' && isdigit(peek(1))) {
+ has_dot = true;
+ advance(); // a pont
+ advance(); // az első számjegy a pont után
+ } else {
+ break;
+ }
+ }
+
+ size_t end = pos();
+ return createToken(Tokens::Type::NUMBER, start_pos, end);
+ }
+
+ Tokens::Token matchStringLiteral(size_t start_pos) {
+ char opening_quote = peek();
+ advance(); // Skip opening quote
+ std::string value;
+ bool unterminated = false;
+
+ while (!isAtEnd()) {
+ char c = peek();
+ if (c == opening_quote) {
+ advance();
+ break;
+ }
+ if (c == '\\') {
+ advance();
+ char e = advance();
+ switch (e) {
+ case 'n':
+ value += '\n';
+ break;
+ case 't':
+ value += '\t';
+ break;
+ case '"':
+ value += opening_quote;
+ break;
+ case '\\':
+ value += '\\';
+ break;
+ default:
+ value += e;
+ break;
+ }
+ } else {
+ value += advance();
+ }
+ }
+
+ size_t end = pos();
+ if (unterminated) {
+ return createToken(Tokens::Type::UNKNOWN, start_pos, end, input().substr(start_pos, end - start_pos));
+ }
+ return createToken(Tokens::Type::STRING_LITERAL, start_pos, end, value);
+ }
+
+ Tokens::Token matchOperatorOrPunctuation(size_t start_pos) {
+ char first_char = advance(); // Első karakter elfogyasztása
+
+ if (!isAtEnd()) {
+ char second_char = peek(0); // Következő karakter megnézése
+ std::string two_chars_str{ first_char, second_char };
+
+ const std::vector<std::pair<const std::vector<std::string> *, Tokens::Type>> two_char_op_types = {
+ { &OPERATOR_RELATIONAL, Tokens::Type::OPERATOR_RELATIONAL },
+ { &OPERATOR_INCREMENT, Tokens::Type::OPERATOR_INCREMENT },
+ { &OPERATOR_ASSIGNMENT, Tokens::Type::OPERATOR_ASSIGNMENT },
+ { &OPERATOR_LOGICAL, Tokens::Type::OPERATOR_LOGICAL }
+ };
+
+ for (const auto & [vec_ptr, type] : two_char_op_types) {
+ if (matchFromVector(*vec_ptr, two_chars_str)) {
+ advance(); // Második karakter elfogyasztása
+ size_t end_pos = pos();
+ return createToken(type, start_pos, end_pos);
+ }
+ }
+ }
+
+ // Egykarakteres operátor vagy írásjel
+ std::string single_char_str(1, first_char);
+
+ if (single_char_str == "$") {
+ if (isalpha(peek(0)) || peek(0) == '_') {
+ return matchIdentifierOrKeyword(start_pos, Tokens::Type::VARIABLE_IDENTIFIER);
+ }
+ }
+
+ const std::vector<std::pair<const std::vector<std::string> *, Tokens::Type>> one_char_op_types = {
+ { &OPERATOR_ARITHMETIC, Tokens::Type::OPERATOR_ARITHMETIC },
+ { &OPERATOR_ASSIGNMENT, Tokens::Type::OPERATOR_ASSIGNMENT }, // "=" itt van!
+ { &PUNCTUATION, Tokens::Type::PUNCTUATION }
+ };
+
+ for (const auto & [vec_ptr, type] : one_char_op_types) {
+ if (matchFromVector(*vec_ptr, single_char_str)) {
+ size_t end_pos = pos();
+ return createToken(type, start_pos, end_pos);
+ }
+ }
+
+ size_t end_pos = pos();
+ return createToken(Tokens::Type::UNKNOWN, start_pos, end_pos);
+ }
+
+ static bool matchFromVector(const std::vector<std::string> & vec, const std::string & value) {
+ return std::find(vec.begin(), vec.end(), value) != vec.end();
+ }
+
+}; // class Lexer
+
+}; // namespace Lexer
+#endif // LEXER_HPP
diff --git a/src/Lexer/Token.hpp b/src/Lexer/Token.hpp
new file mode 100644
index 0000000..ac2ac9f
--- /dev/null
+++ b/src/Lexer/Token.hpp
@@ -0,0 +1,37 @@
+#ifndef TOKEN_HPP
+#define TOKEN_HPP
+
+#include <iostream>
+#include <string> // <<< Hozzáadva
+#include <string_view> // <<< Hozzáadva
+
+#include "Lexer/TokenType.hpp" // Feltételezzük, hogy ez definiálja Type-ot és TypeToString-ot
+
+namespace Lexer::Tokens {
+
+struct Token {
+ Lexer::Tokens::Type type;
+ std::string value; // A token feldolgozott értéke
+ std::string_view lexeme; // A nyers szövegrész az eredeti stringből
+ size_t start_pos; // Kezdő index
+ size_t end_pos; // Vég index (exclusive)
+ int line_number;
+ int column_number;
+
+ // Módosított print metódus a lexeme kiírásával
+ void print() const {
+ std::cout << "Token { Type: " << Lexer::Tokens::TypeToString(type) << ", Value: \"" << value << "\""
+ << ", Pos: [" << start_pos << ", " << end_pos
+ << ")"
+ // Lexeme kiírása (stringgé konvertálva a biztonság kedvéért, ha pl. null lenne)
+ << ", Lexeme: \"" << std::string(lexeme) << "\""
+ << " }" << '\n';
+ }
+};
+
+inline bool operator==(const Token & lhs, const Token & rhs) {
+ return lhs.type == rhs.type && lhs.value == rhs.value && lhs.start_pos == rhs.start_pos &&
+ lhs.end_pos == rhs.end_pos;
+}
+}; // namespace Lexer::Tokens
+#endif // TOKEN_HPP
diff --git a/src/Lexer/TokenType.hpp b/src/Lexer/TokenType.hpp
new file mode 100644
index 0000000..2dd49ca
--- /dev/null
+++ b/src/Lexer/TokenType.hpp
@@ -0,0 +1,87 @@
+#ifndef TOKEN_TYPE_HPP
+#define TOKEN_TYPE_HPP
+
+#include <cstdint>
+#include <string>
+
+namespace Lexer::Tokens {
+
+enum class Type : std::uint8_t {
+ IDENTIFIER, // Pl. változónév: myVar
+ VARIABLE_IDENTIFIER, // Pl. $
+ KEYWORD, // Pl. if, else, while
+ NUMBER, // Pl. 123, 42
+ STRING_LITERAL, // Pl. "hello world"
+ OPERATOR_RELATIONAL, // Pl. +, -, *, /, =, ==, <, >
+ OPERATOR_LOGICAL, // Pl. &&, ||
+ OPERATOR_ASSIGNMENT, // Pl. +=, -=, *=, /=
+ OPERATOR_INCREMENT, // Pl. ++, --
+ OPERATOR_ARITHMETIC, // Pl. +, -, *, /
+ PUNCTUATION, // Pl. (, ), {, }, ;, ,
+ COMMENT, // Általában kihagyjuk
+ END_OF_FILE, // A string végét jelzi
+ KEYWORD_STRING,
+ KEYWORD_INT,
+ KEYWORD_DOUBLE,
+ KEYWORD_FLOAT,
+ KEYWORD_BOOLEAN,
+ KEYWORD_FUNCTION,
+ KEYWORD_RETURN,
+ KEYWORD_NULL,
+ UNKNOWN // Ismeretlen karakter/szekvencia
+};
+
+inline std::string TypeToString(Lexer::Tokens::Type type) {
+ switch (type) {
+ case Lexer::Tokens::Type::IDENTIFIER:
+ return "IDENTIFIER";
+ case Lexer::Tokens::Type::VARIABLE_IDENTIFIER:
+ return "VARIABLE_IDENTIFIER";
+ case Lexer::Tokens::Type::KEYWORD:
+ return "KEYWORD";
+ case Lexer::Tokens::Type::NUMBER:
+ return "NUMBER";
+ case Lexer::Tokens::Type::STRING_LITERAL:
+ return "STRING_LITERAL";
+ case Lexer::Tokens::Type::OPERATOR_RELATIONAL:
+ return "OPERATOR_RELATIONAL";
+ case Lexer::Tokens::Type::OPERATOR_LOGICAL:
+ return "OPERATOR_LOGICAL";
+ case Lexer::Tokens::Type::OPERATOR_ASSIGNMENT:
+ return "OPERATOR_ASSIGNMENT";
+ case Lexer::Tokens::Type::OPERATOR_INCREMENT:
+ return "OPERATOR_INCREMENT";
+ case Lexer::Tokens::Type::OPERATOR_ARITHMETIC:
+ return "OPERATOR_ARITHMETIC";
+ case Lexer::Tokens::Type::PUNCTUATION:
+ return "PUNCTUATION";
+ case Lexer::Tokens::Type::COMMENT:
+ return "COMMENT";
+ case Lexer::Tokens::Type::END_OF_FILE:
+ return "END_OF_FILE";
+ case Lexer::Tokens::Type::KEYWORD_STRING:
+ return "KEYWORD_STRING";
+ case Lexer::Tokens::Type::KEYWORD_INT:
+ return "KEYWORD_INT";
+ case Lexer::Tokens::Type::KEYWORD_DOUBLE:
+ return "KEYWORD_DOUBLE";
+ case Lexer::Tokens::Type::KEYWORD_FLOAT:
+ return "KEYWORD_FLOAT";
+ case Lexer::Tokens::Type::KEYWORD_BOOLEAN:
+ return "KEYWORD_BOOLEAN";
+ case Lexer::Tokens::Type::KEYWORD_FUNCTION:
+ return "KEYWORD_FUNCTION";
+ case Lexer::Tokens::Type::KEYWORD_RETURN:
+ return "KEYWORD_RETURN";
+ case Lexer::Tokens::Type::KEYWORD_NULL:
+ return "KEYWORD_NULL";
+ case Lexer::Tokens::Type::UNKNOWN:
+ return "UNKNOWN";
+ default:
+ return "INVALID_TYPE";
+ }
+}
+
+}; // namespace Lexer::Tokens
+
+#endif // TOKEN_TYPE_HPP
diff --git a/src/Parser/Parser.cpp b/src/Parser/Parser.cpp
new file mode 100644
index 0000000..fbd0e73
--- /dev/null
+++ b/src/Parser/Parser.cpp
@@ -0,0 +1,37 @@
+#include "Parser/Parser.hpp"
+
+// Más szükséges include-ok, ha kellenek
+namespace Parser {
+
+const std::unordered_map<std::string, Lexer::Tokens::Type> Parser::keywords = {
+ { "if", Lexer::Tokens::Type::KEYWORD },
+ { "else", Lexer::Tokens::Type::KEYWORD },
+ { "while", Lexer::Tokens::Type::KEYWORD },
+ { "for", Lexer::Tokens::Type::KEYWORD },
+ { "return", Lexer::Tokens::Type::KEYWORD_RETURN },
+ { "function", Lexer::Tokens::Type::KEYWORD_FUNCTION },
+ // Régebbiek:
+ { "const", Lexer::Tokens::Type::KEYWORD },
+ { "true", Lexer::Tokens::Type::KEYWORD },
+ { "false", Lexer::Tokens::Type::KEYWORD },
+ // változó típusok
+ { "null", Lexer::Tokens::Type::KEYWORD_NULL },
+ { "int", Lexer::Tokens::Type::KEYWORD_INT },
+ { "double", Lexer::Tokens::Type::KEYWORD_DOUBLE },
+ { "float", Lexer::Tokens::Type::KEYWORD_FLOAT },
+ { "string", Lexer::Tokens::Type::KEYWORD_STRING },
+ { "boolean", Lexer::Tokens::Type::KEYWORD_BOOLEAN },
+ { "bool", Lexer::Tokens::Type::KEYWORD_BOOLEAN },
+ // ... egyéb kulcsszavak ...
+};
+
+const std::unordered_map<Lexer::Tokens::Type, Symbols::Variables::Type> Parser::variable_types = {
+ { Lexer::Tokens::Type::KEYWORD_INT, Symbols::Variables::Type::INTEGER },
+ { Lexer::Tokens::Type::KEYWORD_DOUBLE, Symbols::Variables::Type::DOUBLE },
+ { Lexer::Tokens::Type::KEYWORD_FLOAT, Symbols::Variables::Type::FLOAT },
+ { Lexer::Tokens::Type::KEYWORD_STRING, Symbols::Variables::Type::STRING },
+ { Lexer::Tokens::Type::KEYWORD_NULL, Symbols::Variables::Type::NULL_TYPE },
+ { Lexer::Tokens::Type::KEYWORD_BOOLEAN, Symbols::Variables::Type::BOOLEAN },
+};
+
+} // namespace Parser
diff --git a/src/Parser/Parser.hpp b/src/Parser/Parser.hpp
new file mode 100644
index 0000000..b40397e
--- /dev/null
+++ b/src/Parser/Parser.hpp
@@ -0,0 +1,536 @@
+#ifndef PARSER_HPP
+#define PARSER_HPP
+
+#include <algorithm>
+#include <memory>
+#include <sstream> // Hibaüzenetekhez
+#include <stdexcept>
+#include <string>
+#include <vector>
+
+// Szükséges header-ök a Lexer és Symbol komponensekből
+#include "Lexer/Token.hpp"
+#include "Lexer/TokenType.hpp" // Enum és TypeToString
+#include "Symbols/SymbolContainer.hpp"
+#include "Symbols/SymbolFactory.hpp"
+#include "Symbols/Value.hpp" // Symbols::Value miatt
+
+namespace Parser {
+
+class SyntaxError : public std::runtime_error {
+ public:
+ SyntaxError(const std::string & message, const int line, const int col) :
+ std::runtime_error(message + " at line " + std::to_string(line) + ", column " + std::to_string(col)) {}
+
+ SyntaxError(const std::string & message, const Lexer::Tokens::Token & token) :
+ SyntaxError(
+ message + " (found token: '" + token.value + "' type: " + Lexer::Tokens::TypeToString(token.type) + ")",
+ token.line_number, token.column_number) {}
+};
+
+class Parser {
+ public:
+ Parser() {}
+
+ void parseProgram(const std::vector<Lexer::Tokens::Token> & tokens, std::string_view input_string) {
+ tokens_ = tokens;
+ input_str_view_ = input_string;
+ current_token_index_ = 0;
+ symbol_container_ = std::make_unique<Symbols::SymbolContainer>();
+ try {
+ while (!isAtEnd() && currentToken().type != Lexer::Tokens::Type::END_OF_FILE) {
+ parseStatement();
+ }
+ if (!isAtEnd() && currentToken().type != Lexer::Tokens::Type::END_OF_FILE) {
+ reportError("Unexpected tokens after program end");
+ }
+ } catch (const SyntaxError & e) {
+ std::cerr << "Syntax Error: " << e.what() << '\n';
+ } catch (const std::exception & e) {
+ std::cerr << "Error during parsing: " << e.what() << '\n';
+ throw;
+ }
+ }
+
+ 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_;
+
+ // Token Stream Kezelő és Hibakezelő segédfüggvények (változatlanok)
+ const Lexer::Tokens::Token & currentToken() const {
+ if (isAtEnd()) {
+ // Technikailag itt már nem kellene lennünk, ha a parseProgram ciklus jól van megírva
+ // De biztonsági ellenőrzésként jó lehet
+ if (!tokens_.empty() && tokens_.back().type == Lexer::Tokens::Type::END_OF_FILE) {
+ return tokens_.back(); // Visszaadjuk az EOF tokent
+ }
+ throw std::runtime_error("Unexpected end of token stream reached.");
+ }
+ return tokens_[current_token_index_];
+ }
+
+ // Előre néz a token stream-ben
+ const Lexer::Tokens::Token & peekToken(size_t offset = 1) const {
+ if (current_token_index_ + offset >= tokens_.size()) {
+ // EOF vagy azon túl vagyunk, adjuk vissza az utolsó tokent (ami EOF kell legyen)
+ if (!tokens_.empty()) {
+ return tokens_.back();
+ }
+ throw std::runtime_error("Cannot peek beyond end of token stream.");
+ }
+ return tokens_[current_token_index_ + offset];
+ }
+
+ // Elfogyasztja (lépteti az indexet) az aktuális tokent és visszaadja azt
+ Lexer::Tokens::Token consumeToken() {
+ if (isAtEnd()) {
+ throw std::runtime_error("Cannot consume token at end of stream.");
+ }
+ return tokens_[current_token_index_++];
+ }
+
+ // Ellenőrzi, hogy az aktuális token típusa megegyezik-e a várttal.
+ // Ha igen, elfogyasztja és true-t ad vissza. Ha nem, false-t ad vissza.
+ bool match(Lexer::Tokens::Type expected_type) {
+ if (isAtEnd()) {
+ return false;
+ }
+ if (currentToken().type == expected_type) {
+ consumeToken();
+ return true;
+ }
+ return false;
+ }
+
+ // Ellenőrzi, hogy az aktuális token típusa és értéke megegyezik-e a várttal.
+ // Csak OPERATOR és PUNCTUATION esetén érdemes használni az érték ellenőrzést.
+ bool match(Lexer::Tokens::Type expected_type, const std::string & expected_value) {
+ if (isAtEnd()) {
+ return false;
+ }
+ const auto & token = currentToken();
+ if (token.type == expected_type && token.value == expected_value) {
+ consumeToken();
+ return true;
+ }
+ return false;
+ }
+
+ Lexer::Tokens::Token expect(Lexer::Tokens::Type expected_type) {
+ if (isAtEnd()) {
+ reportError("Unexpected end of file, expected token type: " + Lexer::Tokens::TypeToString(expected_type));
+ }
+ const auto & token = currentToken();
+ if (token.type == expected_type) {
+ return consumeToken();
+ }
+ reportError("Expected token type " + Lexer::Tokens::TypeToString(expected_type));
+ // A reportError dob, ez a return sosem fut le, de a fordító kedvéért kellhet:
+ return token; // Vagy dobjon a reportError
+ }
+
+ // Mint az expect, de az értékét is ellenőrzi.
+ Lexer::Tokens::Token expect(Lexer::Tokens::Type expected_type, const std::string & expected_value) {
+ if (isAtEnd()) {
+ reportError("Unexpected end of file, expected token: " + Lexer::Tokens::TypeToString(expected_type) +
+ " with value '" + expected_value + "'");
+ }
+ const auto & token = currentToken();
+ if (token.type == expected_type && token.value == expected_value) {
+ return consumeToken();
+ }
+ reportError("Expected token " + Lexer::Tokens::TypeToString(expected_type) + " with value '" + expected_value +
+ "'");
+ return token; // reportError dob
+ }
+
+ // Ellenőrzi, hogy a releváns tokenek végére értünk-e (az EOF előtti utolsó tokenen vagyunk-e)
+ bool isAtEnd() const {
+ // Akkor vagyunk a végén, ha az index a tokenek méretével egyenlő,
+ // vagy ha már csak az EOF token van hátra (ha az a lista utolsó eleme).
+ return current_token_index_ >= tokens_.size() ||
+ (current_token_index_ == tokens_.size() - 1 && tokens_.back().type == Lexer::Tokens::Type::END_OF_FILE);
+ }
+
+ // --- Hibakezelés ---
+ // Hiba jelentése és kivétel dobása
+ [[noreturn]] void reportError(const std::string & message) {
+ // Használjuk az aktuális token pozícióját, ha még nem értünk a végére
+ if (current_token_index_ < tokens_.size()) {
+ throw SyntaxError(message, tokens_[current_token_index_]);
+ } // Ha már a végén vagyunk, az utolsó ismert pozíciót használjuk
+ int line = tokens_.empty() ? 0 : tokens_.back().line_number;
+ int col = tokens_.empty() ? 0 : tokens_.back().column_number;
+ throw SyntaxError(message, line, col);
+ }
+
+ // --- Elemzési Módszerek (Moduláris részek) ---
+
+ // parseStatement (változatlan)
+ void parseStatement() {
+ const auto & token_type = currentToken().type;
+
+ if (token_type == Lexer::Tokens::Type::KEYWORD_FUNCTION) {
+ parseFunctionDefinition();
+ return;
+ }
+
+ for (const auto & _type : Parser::Parser::variable_types) {
+ if (token_type == _type.first) {
+ parseVariableDefinition();
+ return;
+ }
+ }
+
+ 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;
+ 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);
+ }
+
+ expect(Lexer::Tokens::Type::OPERATOR_ASSIGNMENT, "=");
+ Symbols::Value initial_value = parseValue(var_type_enum);
+ 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);
+ 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;
+ expect(Lexer::Tokens::Type::OPERATOR_ASSIGNMENT, "=");
+ expect(Lexer::Tokens::Type::PUNCTUATION, "(");
+
+ Symbols::FunctionParameterInfo param_infos;
+
+ 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)
+ Lexer::Tokens::Token param_id_token = expect(Lexer::Tokens::Type::VARIABLE_IDENTIFIER);
+ std::string param_name = param_id_token.value;
+ if (!param_name.empty() && param_name[0] == '$') { // '$' eltávolítása
+ param_name = param_name.substr(1);
+ }
+
+ param_infos.push_back({ param_name, param_type });
+
+ // Vessző vagy zárójel következik?
+ if (match(Lexer::Tokens::Type::PUNCTUATION, ",")) {
+ continue;
+ }
+ if (currentToken().type == Lexer::Tokens::Type::PUNCTUATION && currentToken().value == ")") {
+ break; // Lista vége
+ }
+ reportError("Expected ',' or ')' in parameter list");
+ }
+ }
+ // Most a ')' következik
+ expect(Lexer::Tokens::Type::PUNCTUATION, ")");
+
+ // check if we have a option return type: function name() type { ... }
+ for (const auto & _type : Parser::variable_types) {
+ if (match(_type.first)) {
+ func_return_type = _type.second;
+ break;
+ }
+ }
+
+ 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";
+ }
+
+ // --- Elemzési Segédfüggvények ---
+
+ // type : KEYWORD_STRING | KEYWORD_INT | KEYWORD_DOUBLE
+ // Visszaadja a megfelelő Symbols::Variables::Type enum értéket és elfogyasztja a tokent.
+ Symbols::Variables::Type parseType() {
+ const auto & token = currentToken();
+ for (const auto & _type : Parser::variable_types) {
+ if (token.type == _type.first) {
+ consumeToken();
+ return _type.second;
+ }
+ }
+
+ 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;
+ token = peekToken();
+ consumeToken();
+ }
+
+ 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
+ }
+ 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
+ }
+
+ Symbols::SymbolContainer parseFunctionBody(const Lexer::Tokens::Token & opening_brace,
+ bool return_required = false) {
+ size_t braceDepth = 0;
+ int tokenIndex = current_token_index_;
+ Lexer::Tokens::Token currentToken_;
+ Lexer::Tokens::Token closing_brace;
+
+ while (tokenIndex < tokens_.size()) {
+ currentToken_ = peekToken();
+
+ if (currentToken_.type == Lexer::Tokens::Type::PUNCTUATION) {
+ if (currentToken_.value == "{") {
+ ++braceDepth;
+ } else if (currentToken_.value == "}") {
+ if (braceDepth == 0) {
+ closing_brace = currentToken_;
+ break;
+ }
+ --braceDepth;
+ }
+ }
+ }
+ if (braceDepth != 0) {
+ reportError("Unmatched braces in function body");
+ }
+ std::vector<Lexer::Tokens::Token> filtered_tokens;
+ 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();
+ }
+
+ 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;
+
+ while (true) {
+ if (isAtEnd()) {
+ reportError("Unexpected end of file inside function body (missing '}')");
+ }
+ const 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::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;
+ }
+ body_ss << token.lexeme;
+ } else {
+ body_ss << token.lexeme;
+ }
+
+ last_token_end_pos = token.end_pos;
+ consumeToken();
+ }
+
+ if (return_required && !has_return) {
+ return "";
+ }
+
+ return body_ss.str();
+ }
+
+}; // class Parser
+
+} // namespace Parser
+
+#endif // PARSER_HPP
diff --git a/src/ScriptException.hpp b/src/ScriptException.hpp
deleted file mode 100644
index d1f88c2..0000000
--- a/src/ScriptException.hpp
+++ /dev/null
@@ -1,148 +0,0 @@
-#ifndef SCRIPTEXCEPTION_HPP
-#define SCRIPTEXCEPTION_HPP
-
-#include <stdexcept>
-#include <string>
-
-#include "options.h"
-#include "Token.hpp"
-
-enum class ScriptErrorType : std::uint8_t {
- UnexpectedToken,
- UndefinedVariable,
- UndefinedFunction,
- VariableTypeMismatch,
- VariableRedefinition,
- Custom
-};
-
-class ScriptException : public std::runtime_error {
- public:
- ScriptException(ScriptErrorType type, const std::string & message, const std::string & file = "", int line = 0,
- const Token & token = Token()) :
- std::runtime_error(message),
- type_(type),
- file_(file),
- line_(line),
- token_(token),
- fullMessage_(formatMessage(message)) {}
-
- const char * what() const noexcept override { return fullMessage_.c_str(); }
-
- ScriptErrorType type() const { return type_; }
-
- const std::string & file() const { return file_; }
-
- int line() const { return line_; }
-
- const Token & token() const { return token_; }
-
- static ScriptException makeUnexpectedEndOfFileError(const Token & token, const std::string & file = "",
- int line = 0) {
- std::string msg = "unexpected end of file";
- if (!token.lexeme.empty()) {
- msg += " near '" + token.lexeme + "'";
- }
- return ScriptException(ScriptErrorType::UnexpectedToken, msg, file, line, token);
- }
-
- static ScriptException makeUnexpectedTokenError(const Token & token, const std::string & expected = "",
- const std::string & file = "", int line = 0) {
- std::string msg = "unexpected token: '" + token.lexeme + "'";
-
-#if DEBUG_BUILD == 1
- msg.append(" token type: " + tokenTypeNames.at(token.type));
-#endif
-
- if (!expected.empty()) {
- msg += ", expected " + expected;
- }
- return ScriptException(ScriptErrorType::UnexpectedToken, msg, file, line, token);
- }
-
- static ScriptException makeUndefinedVariableError(const std::string & name, const Token & token,
- const std::string & file = "", int line = 0) {
- std::string msg = "undefined variable: '$" + name + "'";
- return ScriptException(ScriptErrorType::UndefinedVariable, msg, file, line, token);
- }
-
- static ScriptException makeUndefinedFunctionError(const std::string & name, const Token & token,
- const std::string & file = "", int line = 0) {
- std::string msg = "undefined function: '" + name + "'";
-#if DEBUG_BUILD == 1
- msg.append(", type: " + getTokenTypeAsString(token.type));
-#endif
- return ScriptException(ScriptErrorType::UndefinedFunction, msg, file, line, token);
- }
-
- static ScriptException makeVariableRedefinitionError(const std::string & name, const Token & token,
- const std::string & file = "", int line = 0) {
- std::string msg = "variable already defined: '" + name + "'";
- return ScriptException(ScriptErrorType::VariableRedefinition, msg, file, line, token);
- }
-
- static ScriptException makeVariableTypeMismatchError(const std::string & targetVar, const std::string & targetType,
- const std::string & sourceVar, const std::string & sourceType,
- const Token & token, const std::string & file = "",
- int line = 0) {
- std::string msg = "variable type mismatch: '$" + targetVar + "' declared type: '" + targetType + "'";
- if (!sourceVar.empty()) {
- msg += ", source variable: '" + sourceVar + "'";
- }
- if (!sourceType.empty()) {
- msg += ", assigned type: '" + sourceType + "'";
- }
- return ScriptException(ScriptErrorType::VariableTypeMismatch, msg, file, line, token);
- }
-
- static ScriptException makeFunctionRedefinitionError(const std::string & name, const Token & token,
- const std::string & file = "", int line = 0) {
- std::string msg = "variable already defined: '" + name + "'";
- return ScriptException(ScriptErrorType::VariableRedefinition, msg, file, line, token);
- }
-
- static ScriptException makeFunctionInvalidArgumentError(const std::string & functionName,
- const std::string & argName, const Token & token,
- const std::string & file = "", int line = 0) {
- std::string msg = "invalid argument for function '" + functionName + "': '" + argName + "'";
- return ScriptException(ScriptErrorType::Custom, msg, file, line, token);
- }
-
- static ScriptException makeFunctionArgumentCountMismatchError(const std::string & functionName,
- const size_t & expected, size_t actual,
- const Token & token, const std::string & file = "",
- int line = 0) {
- std::string msg = "invalid argument count for function '" + functionName + "', expected " +
- std::to_string(expected) + ", got " + std::to_string(actual);
- return ScriptException(ScriptErrorType::Custom, msg, file, line, token);
- }
-
- static ScriptException makeFunctionBodyEmptyError(const std::string & functionName, const Token & token,
- const std::string & file = "", int line = 0) {
- std::string msg = "function '" + functionName + "' has no body";
- return ScriptException(ScriptErrorType::Custom, msg, file, line, token);
- }
-
- private:
- ScriptErrorType type_;
- std::string file_;
- int line_;
- Token token_;
- std::string fullMessage_;
-
- std::string formatMessage(const std::string & base) const {
- std::string formatted = base;
- if (!token_.file.empty()) {
- formatted += " in file: " + token_.file + ":" + std::to_string(token_.lineNumber) + ":" +
- std::to_string(token_.columnNumber);
- }
-#if DEBUG_BUILD == 1
- if (!file_.empty()) {
- formatted = file_ + ":" + std::to_string(line_) + "\n" + formatted;
- }
-#endif
- return formatted;
- }
-};
-
-#endif // SCRIPTEXCEPTION_HPP
diff --git a/src/ScriptExceptionMacros.h b/src/ScriptExceptionMacros.h
deleted file mode 100644
index d0263ed..0000000
--- a/src/ScriptExceptionMacros.h
+++ /dev/null
@@ -1,55 +0,0 @@
-#ifndef SCRIPT_EXCEPTION_MACROS_H
-#define SCRIPT_EXCEPTION_MACROS_H
-
-#include "ScriptException.hpp"
-
-//
-// Purpose of macros: unified exception handling with extended error information (source file and line number)
-//
-#define THROW_UNEXPECTED_END_OF_FILE_ERROR(token) \
- throw ScriptException::makeUnexpectedEndOfFileError(token, __FILE__, __LINE__)
-
-// Invalid token type - expected different type
-#define THROW_UNEXPECTED_TOKEN_ERROR(token, expected) \
- throw ScriptException::makeUnexpectedTokenError(token, expected, __FILE__, __LINE__)
-
-#define THROW_UNEXPECTED_TOKEN_ERROR_HELPER(token, expected, file, line) \
- throw ScriptException::makeUnexpectedTokenError(token, expected, file, line)
-
-// Accessing unknown (undefined) variable
-#define THROW_UNDEFINED_VARIABLE_ERROR(name, token) \
- throw ScriptException::makeUndefinedVariableError(name, token, __FILE__, __LINE__)
-
-#define THROW_UNDEFINED_VARIABLE_ERROR_HELPER(name, token, file, line) \
- throw ScriptException::makeUndefinedVariableError(name, token, file, line)
-
-// Unknown (undefined) function call
-#define THROW_UNDEFINED_FUNCTION_ERROR(name, token) \
- throw ScriptException::makeUndefinedFunctionError(name, token, __FILE__, __LINE__)
-
-// Variable type mismatch - e.g. string instead of number
-#define THROW_VARIABLE_TYPE_MISSMATCH_ERROR(target_variable_name, target_variable_type, source_variable_name, \
- source_variable_type, token) \
- throw ScriptException::makeVariableTypeMismatchError(target_variable_name, target_variable_type, \
- source_variable_name, source_variable_type, token, __FILE__, \
- __LINE__)
-
-// Redefining a variable with the same name is not allowed
-#define THROW_VARIABLE_REDEFINITION_ERROR(name, token) \
- throw ScriptException::makeVariableRedefinitionError(name, token, __FILE__, __LINE__)
-
-#define THROW_FUNCTION_REDEFINITION_ERROR(name, token) \
- throw ScriptException::makeFunctionRedefinitionError(name, token, __FILE__, __LINE__)
-
-// Invalid or incorrect function argument
-#define THROW_INVALID_FUNCTION_ARGUMENT_ERROR(functionName, argName, token) \
- throw ScriptException::makeFunctionInvalidArgumentError(functionName, argName, token, __FILE__, __LINE__)
-
-#define THROW_FUNCTION_ARG_COUNT_MISMATCH_ERROR(functionName, expected, actual, token) \
- throw ScriptException::makeFunctionArgumentCountMismatchError(functionName, expected, actual, token, __FILE__, \
- __LINE__)
-
-#define THROW_FUNCTION_BODY_EMPTY(funcName, token) \
- throw ScriptException::makeFunctionBodyEmptyError(funcName, token, __FILE__, __LINE__)
-
-#endif // SCRIPT_EXCEPTION_MACROS_H
diff --git a/src/ScriptInterpreter.cpp b/src/ScriptInterpreter.cpp
deleted file mode 100644
index 8af8d43..0000000
--- a/src/ScriptInterpreter.cpp
+++ /dev/null
@@ -1,379 +0,0 @@
-#include "ScriptInterpreter.hpp"
-
-#include <iostream>
-#include <stdexcept>
-#include <unordered_map>
-#include <utility>
-
-#include "Lexer.hpp"
-#include "ScriptExceptionMacros.h"
-#include "Value.hpp"
-
-void ScriptInterpreter::registerModule(const std::string & name, std::shared_ptr<BaseFunction> fn) {
- functionObjects[name] = std::move(fn);
-}
-
-Value ScriptInterpreter::evaluateExpression(const Token & token) const {
- switch (token.type) {
- case TokenType::StringLiteral:
- return Value::fromString(token);
-
- case TokenType::IntLiteral:
- try {
- return Value::fromInt(token);
- } catch (const std::invalid_argument & e) {
- throw std::runtime_error("Invalid integer literal: " + token.lexeme);
- } catch (const std::out_of_range & e) {
- throw std::runtime_error("Integer literal out of range: " + token.lexeme);
- }
-
- case TokenType::DoubleLiteral:
- try {
- return Value::fromDouble(token);
- } catch (const std::invalid_argument & e) {
- throw std::runtime_error("Invalid double literal: " + token.lexeme);
- } catch (const std::out_of_range & e) {
- throw std::runtime_error("Double literal out of range: " + token.lexeme);
- }
-
- case TokenType::BooleanLiteral:
- case TokenType::Identifier:
- {
- return Value::fromBoolean(token);
- }
-
- case TokenType::Variable:
- return this->getVariable(token, this->contextPrefix, __FILE__, __LINE__);
-
- default:
- THROW_UNEXPECTED_TOKEN_ERROR(token, "string, integer, double, or variable");
- }
-
- return Value();
-}
-
-std::vector<Value> ScriptInterpreter::parseFunctionArguments(const std::vector<Token> & tokens,
- std::size_t & index) const {
- std::vector<Value> args;
- size_t current_index = index;
-
- if (current_index >= tokens.size() || tokens[current_index].type != TokenType::LeftParenthesis) {
- THROW_UNEXPECTED_TOKEN_ERROR(tokens[current_index], tokenTypeNames.at(TokenType::LeftParenthesis));
- }
- current_index++; // Skip '('
-
- while (current_index < tokens.size() && tokens[current_index].type != TokenType::RightParenthesis) {
- args.push_back(evaluateExpression(tokens[current_index]));
- current_index++;
- if (current_index < tokens.size() && tokens[current_index].type == TokenType::Comma) {
- current_index++; // Skip ','
- if (current_index >= tokens.size() || tokens[current_index].type == TokenType::RightParenthesis) {
- THROW_UNEXPECTED_TOKEN_ERROR(tokens[current_index], "expression after comma");
- }
- } else if (tokens[current_index].type != TokenType::RightParenthesis && current_index < tokens.size()) {
- THROW_UNEXPECTED_TOKEN_ERROR(tokens[current_index], "',' or ')'");
- }
- }
-
- if (current_index >= tokens.size() || tokens[current_index].type != TokenType::RightParenthesis) {
- THROW_UNEXPECTED_TOKEN_ERROR(tokens[current_index], "')'");
- }
- current_index++; // Skip ')'
- index = current_index;
-
- return args;
-}
-
-void ScriptInterpreter::handleBooleanDeclaration(const std::vector<Token> & tokens, size_t & i) {
- if (tokens.size() <= i || tokens[i].type != TokenType::Identifier) {
- THROW_UNEXPECTED_TOKEN_ERROR(tokens[i], "variable name");
- }
-
- const Token & varToken = tokens[i++];
- if (i >= tokens.size()) {
- THROW_UNEXPECTED_TOKEN_ERROR(tokens[i + 1], "semicolon or assignment after variable name");
- }
-
- if (tokens[i].type == TokenType::Semicolon) {
- auto val = Value::fromBoolean(tokens[i]);
- this->setVariable(varToken.lexeme, val, this->contextPrefix, true);
- i++;
- } else if (tokens[i].type == TokenType::Equal) {
- i++;
- if (i >= tokens.size()) {
- //throw InterpreterException("Expected value after assignment.", tokens[i - 1]);
- THROW_UNEXPECTED_TOKEN_ERROR(tokens[i - 1], "value after assignment");
- }
-
- auto value = evaluateExpression(tokens[i]);
- if (value.type != Variables::Type::VT_BOOLEAN) {
- THROW_VARIABLE_TYPE_MISSMATCH_ERROR(varToken.lexeme, Variables::TypeToString(Variables::Type::VT_BOOLEAN),
- tokens[i].lexeme, value.TypeToString(), tokens[i]);
- }
- this->setVariable(varToken.lexeme, value, this->contextPrefix, true);
- i++;
- EXPECT_SEMICOLON(tokens, i, "after bool declaration");
- } else {
- EXPECT_SEMICOLON(tokens, i, "after bool declaration");
- }
-}
-
-void ScriptInterpreter::handleStringDeclaration(const std::vector<Token> & tokens, std::size_t & i) {
- const auto & varToken = tokens[i];
-
- i++; // Skip variable name
- if (i < tokens.size() && tokens[i].type == TokenType::Equals) {
- i++; // Skip '='
-
- if (i < tokens.size() && tokens[i].type == TokenType::Variable) {
- const auto variable = this->getVariable(tokens[i], this->contextPrefix, __FILE__, __LINE__);
-
- if (variable.type != Variables::Type::VT_STRING) {
- THROW_VARIABLE_TYPE_MISSMATCH_ERROR(varToken.lexeme,
- Variables::TypeToString(Variables::Type::VT_STRING),
- tokens[i].lexeme, variable.TypeToString(), tokens[i]);
- }
- auto value = variable;
- this->setVariable(varToken.lexeme, value, this->contextPrefix, true);
- i++; // Skip variable name
- EXPECT_SEMICOLON(tokens, i, "after string variable declaration");
-
- } else if (i < tokens.size() && tokens[i].type == TokenType::StringLiteral) {
- auto value = Value::fromString(tokens[i]);
- this->setVariable(varToken.lexeme, value, this->contextPrefix, true);
- i++; // Skip string literal
- EXPECT_SEMICOLON(tokens, i, "after string declaration");
- } else {
- THROW_UNEXPECTED_TOKEN_ERROR(tokens[i], "string literal after '='");
- }
- } else {
- THROW_UNEXPECTED_TOKEN_ERROR(tokens[i], "= after string declaration");
- }
-}
-
-void ScriptInterpreter::handleNumberDeclaration(const std::vector<Token> & tokens, std::size_t & i, TokenType type) {
- const auto & varToken = tokens[i];
-
- i++; // Skip variable name
- if (i < tokens.size() && tokens[i].type == TokenType::Equals) {
- i++; // Skip '='
- if (i < tokens.size()) {
- if (type == TokenType::IntDeclaration && tokens[i].type == TokenType::IntLiteral) {
- try {
- auto value = Value::fromInt(tokens[i]);
- this->setVariable(varToken.lexeme, value, this->contextPrefix, true);
- i++; // Skip int literal
- } catch (const std::invalid_argument & e) {
- throw std::runtime_error("Invalid integer literal in declaration: " + tokens[i].lexeme);
- } catch (const std::out_of_range & e) {
- throw std::runtime_error("Integer literal out of range in declaration: " + tokens[i].lexeme);
- }
- } else if (type == TokenType::DoubleDeclaration && tokens[i].type == TokenType::DoubleLiteral) {
- try {
- auto value = Value::fromDouble(tokens[i]);
- this->setVariable(varToken.lexeme, value, this->contextPrefix, true);
- i++; // Skip double literal
- } catch (const std::invalid_argument & e) {
- throw std::runtime_error("Invalid double literal in declaration: " + tokens[i].lexeme);
- } catch (const std::out_of_range & e) {
- throw std::runtime_error("Double literal out of range in declaration: " + tokens[i].lexeme);
- }
- } else {
- const std::string expectedType = type == TokenType::IntDeclaration ? "int" : "double";
- THROW_VARIABLE_TYPE_MISSMATCH_ERROR(varToken.lexeme, expectedType, "",
- getVariableTypeFromTokenTypeAsString(tokens[i].type), tokens[i]);
- }
- EXPECT_SEMICOLON(tokens, i, "after variable declaration");
- } else {
- THROW_UNEXPECTED_TOKEN_ERROR(tokens[i - 1], "literal after '='");
- }
- } else {
- THROW_UNEXPECTED_TOKEN_ERROR(tokens[i], "= after variable declaration, variable name: " + varToken.lexeme);
- }
-}
-
-void ScriptInterpreter::handleFunctionDeclaration(const std::vector<Token> & tokens, std::size_t & i) {
- const auto & funcToken = tokens[i];
-
- i++; // skip funct name
-
- if (i < tokens.size() && tokens[i].type != TokenType::Equals) {
- THROW_UNEXPECTED_TOKEN_ERROR(tokens[i], "= after function declaration");
- }
- i++; // skip '='
-
- if (this->functionBodies.find(funcToken.lexeme) != this->functionBodies.end()) {
- THROW_FUNCTION_REDEFINITION_ERROR(funcToken.lexeme, tokens[i]);
- }
-
- if (i < tokens.size() && tokens[i].type != TokenType::LeftParenthesis) {
- THROW_UNEXPECTED_TOKEN_ERROR(tokens[i - 1], "");
- }
- i++;
- // parse arg definitions
- const std::string context_name = this->getContextName(funcToken.lexeme);
- const auto args = ScriptInterpreterHelpers::parseFunctionDeclarationArguments(tokens, i, __FILE__, __LINE__);
- for (const auto & arg : args) {
- auto value = arg;
- this->setVariable(arg.GetToken().lexeme, value, context_name, true);
- }
-
- size_t start;
- size_t end;
- ScriptInterpreterHelpers::getFunctionBody(tokens, i, start, end);
-
- const std::string function_body = StringHelpers::extractSubstring(this->source, start, end);
- if (function_body.empty()) {
- std::cout << this->source << '\n';
- THROW_FUNCTION_BODY_EMPTY(funcToken.lexeme, tokens[i - 1]);
- }
- this->functionBodies[funcToken.lexeme] = function_body;
- // recheck the close curly brace
- if (i >= tokens.size() || tokens[i].type != TokenType::RightCurlyBracket) {
- THROW_UNEXPECTED_TOKEN_ERROR(tokens[i], "}");
- }
- i++;
-}
-
-void ScriptInterpreter::handleFunctionCall(const std::vector<Token> & tokens, std::size_t & i) {
- const auto & functiontoken = tokens[i];
-
- i++; // skip funct name
- if (i < tokens.size() && tokens[i].type != TokenType::LeftParenthesis) {
- THROW_UNEXPECTED_TOKEN_ERROR(tokens[i - 1], "");
- }
-
- std::vector<Value> args = parseFunctionArguments(tokens, i);
-
- auto it1 = functionObjects.find(functiontoken.lexeme);
- if (it1 != functionObjects.end()) {
- it1->second->call(args);
- } else {
- auto it2 = functionBodies.find(functiontoken.lexeme);
- if (it2 == functionBodies.end()) {
- THROW_UNDEFINED_FUNCTION_ERROR(functiontoken.lexeme, tokens[i]);
- }
-
- if (args.size() > 0) {
- auto varList = this->getcontextVariables(this->getContextName(functiontoken.lexeme));
- if (varList.size() != args.size()) {
- THROW_FUNCTION_ARG_COUNT_MISMATCH_ERROR(functiontoken.lexeme, varList.size(), args.size(), tokens[i]);
- }
- size_t counter = 0;
- for (auto & var : varList) {
- this->setVariable(var.first, args[counter], var.second.context, false, true);
- counter++;
- }
- }
-
- this->executeScript(it2->second, this->filename, functiontoken.lexeme, true);
- }
-
- //i++;
-
- EXPECT_SEMICOLON(tokens, i, "after function call");
-}
-
-void ScriptInterpreter::handleVariableReference(const std::vector<Token> & tokens, std::size_t & i) {
- const auto & varToken = tokens[i];
- i++; // Skip variable token to avoid infinite loop
- if (i < tokens.size() && tokens[i].type == TokenType::Equals) {
- i++; // Skip '='
- if (i < tokens.size()) {
- const auto variable = this->getVariable(varToken, this->contextPrefix, __FILE__, __LINE__);
- auto value = evaluateExpression(tokens[i]);
- this->setVariable(varToken.lexeme, value, this->contextPrefix, false);
- i++; // Skip value
- EXPECT_SEMICOLON(tokens, i, "after variable assignment");
- } else {
- THROW_UNEXPECTED_TOKEN_ERROR(tokens[i - 1], "value after '='");
- }
- } else {
- THROW_UNEXPECTED_TOKEN_ERROR(tokens[i - 1], "'=' for assignment");
- }
-}
-
-void ScriptInterpreter::executeScript(const std::string & source, const std::string & filename,
- const std::string & _namespace, bool ignore_tags) {
- std::string oldContext;
- std::string oldSource;
-
- this->filename = filename;
- if (!this->source.empty()) {
- oldSource = this->source;
- }
- this->source = source;
-
- if (!this->contextPrefix.empty()) {
- oldContext = this->contextPrefix;
- }
- this->contextPrefix = this->getContextName(_namespace);
- Lexer lexer(source, filename);
- auto tokens = lexer.tokenize();
-
- bool insideScript = false;
-
- for (std::size_t i = 0; i < tokens.size();) {
- const auto & token = tokens[i];
-
- if (token.type == TokenType::EndOfFile) {
- break;
- }
-
- if (token.type == TokenType::ParserOpenTag) {
- insideScript = true;
- i++; // Skip the open tag
- continue;
- }
-
- if (token.type == TokenType::ParserCloseTag) {
- insideScript = false;
- i++; // Skip the close tag
- continue;
- }
-
- if (insideScript == false && ignore_tags == false) {
- //std::cout << token.lexeme;
- i++;
- continue;
- }
-
- switch (token.type) {
- case TokenType::StringDeclaration:
- handleStringDeclaration(tokens, i);
- break;
- case TokenType::BooleanDeclaration:
- handleBooleanDeclaration(tokens, i);
- break;
- case TokenType::FunctionDeclaration:
- handleFunctionDeclaration(tokens, i);
- break;
- case TokenType::IntDeclaration:
- case TokenType::DoubleDeclaration:
- handleNumberDeclaration(tokens, i, token.type);
- break;
- case TokenType::FunctionCall:
- handleFunctionCall(tokens, i);
- break;
- case TokenType::Variable:
- handleVariableReference(tokens, i);
- break;
- case TokenType::Comment:
- handleComment(i);
- break;
- case TokenType::Semicolon:
- handleSemicolon(i);
- break;
- default:
- THROW_UNEXPECTED_TOKEN_ERROR(token, "");
- }
- }
- if (!oldContext.empty()) {
- this->contextPrefix = oldContext;
- oldContext.clear();
- }
- if (!oldSource.empty()) {
- this->source = oldSource;
- oldSource.clear();
- }
-}
diff --git a/src/ScriptInterpreter.hpp b/src/ScriptInterpreter.hpp
deleted file mode 100644
index b8077bd..0000000
--- a/src/ScriptInterpreter.hpp
+++ /dev/null
@@ -1,140 +0,0 @@
-#ifndef SSCRIPTINTERPRETER_HPP
-#define SSCRIPTINTERPRETER_HPP
-#include <functional>
-#include <map>
-#include <memory>
-#include <string>
-#include <unordered_map>
-#include <vector>
-
-#include "BaseFunction.hpp"
-#include "Token.hpp"
-#include "Value.hpp"
-
-using FunctionValidator =
- std::function<void(const std::vector<Token> &, size_t &, const std::unordered_map<std::string, Value> &)>;
-using VariableContext = std::map<std::string, Value>;
-
-class ScriptInterpreter {
- public:
- void registerModule(const std::string & name, std::shared_ptr<BaseFunction> fn);
- void executeScript(const std::string & source, const std::string & filename,
- const std::string & _namespace = "DEFAULT", bool ignore_tags = false);
-
- private:
- std::unordered_map<std::string, FunctionValidator> functionValidators;
- std::unordered_map<std::string, std::shared_ptr<BaseFunction>> functionObjects;
- // store the current script's variables
- std::unordered_map<std::string, VariableContext> variables;
- // store the current script's function arguments
- std::unordered_map<std::string, std::vector<Value>> functionParameters;
- std::unordered_map<std::string, std::string> functionBodies;
- std::string filename;
- std::string source;
- std::string contextPrefix;
-
- [[nodiscard]] std::vector<Value> parseFunctionArguments(const std::vector<Token> & tokens,
- std::size_t & index) const;
- [[nodiscard]] Value evaluateExpression(const Token & token) const;
-
- // type handlers
- void setVariable(const std::string & name, Value & value, const std::string & context = "default",
- bool exception_if_exists = false, bool exception_if_not_exists = false) {
- if (exception_if_exists && variables[context].find(name) != variables[context].end()) {
- THROW_VARIABLE_REDEFINITION_ERROR(name, value.token);
- }
- if (exception_if_not_exists && variables[context].find(name) == variables[context].end()) {
- THROW_UNDEFINED_VARIABLE_ERROR(name, value.token);
- }
- value.name = name;
- value.context = context;
- this->variables[context][name] = value;
- }
-
- [[nodiscard]] Value getVariable(const std::string & name, const std::string & context = "default") const {
- for (auto it = variables.begin(); it != variables.end(); ++it) {
- if (it->first == context) {
- const auto & innerMap = it->second.find(name);
- if (innerMap != it->second.end()) {
- return it->second.at(name);
- }
- }
- }
- throw std::runtime_error("Variable not found: " + name);
- };
-
- [[nodiscard]] Value getVariable(const Token & token, const std::string & context = "default",
- const std::string & file = __FILE__, const int & line = __LINE__) const {
- for (auto it = variables.begin(); it != variables.end(); ++it) {
- if (it->first == context) {
- const auto & innerMap = it->second.find(token.lexeme);
- if (innerMap != it->second.end()) {
- return it->second.at(token.lexeme);
- }
- }
- }
- THROW_UNDEFINED_VARIABLE_ERROR_HELPER(token.lexeme, token, file, line);
- };
-
- [[nodiscard]] std::map<std::string, Value> getcontextVariables(const std::string & context) const {
- auto it = variables.find(context);
- if (it != variables.end()) {
- return it->second;
- }
- throw std::runtime_error("Context not found: " + context);
- }
-
- /**
- * Checks if a variable exists within the specified context.
- *
- * @param name The name of the variable to check.
- * @param context The context in which to search for the variable (defaults to "default").
- * @param file The source file where the check is performed (for error reporting).
- * @param line The line number where the check is performed (for error reporting).
- * @return True if the variable exists in the specified context.
- * @throws Throws an undefined variable error if the variable is not found.
- */
- [[nodiscard]] bool variableExists(const std::string & name, const std::string & context = "default",
- const std::string & file = __FILE__, const int & line = __LINE__) const {
- for (auto it = variables.begin(); it != variables.end(); ++it) {
- if (it->first == context) {
- const auto & innerMap = it->second.find(name);
- if (innerMap != it->second.end()) {
- return true;
- }
- }
- }
- THROW_UNDEFINED_VARIABLE_ERROR_HELPER(name, Token(TokenType::Variable, name, name, 0, 0), file, line);
- }
-
- /**
- * Checks if a variable exists within the specified context using a Token.
- *
- * @param token The token representing the variable to check.
- * @param context The context in which to search for the variable (defaults to "default").
- * @param file The source file where the check is performed (for error reporting).
- * @param line The line number where the check is performed (for error reporting).
- * @return True if the variable exists in the specified context.
- * @throws Throws an undefined variable error if the variable is not found.
- */
- [[nodiscard]] bool variableExists(const Token & token, const std::string & context = "default",
- const std::string & file = __FILE__, const int & line = __LINE__) const {
- return this->variableExists(token.lexeme, context, file, line);
- }
-
- void handleFunctionCall(const std::vector<Token> & tokens, std::size_t & i);
- void handleVariableReference(const std::vector<Token> & tokens, std::size_t & i);
-
- static void handleComment(std::size_t & i) { i++; }
-
- static void handleSemicolon(std::size_t & i) { i++; };
-
- void handleStringDeclaration(const std::vector<Token> & tokens, std::size_t & i);
- void handleBooleanDeclaration(const std::vector<Token> & tokens, std::size_t & i);
- void handleNumberDeclaration(const std::vector<Token> & tokens, std::size_t & i, TokenType type);
- void handleFunctionDeclaration(const std::vector<Token> & tokens, std::size_t & i);
-
- std::string getContextName(const std::string & suffix) const { return this->filename + "::" + suffix; }
-};
-
-#endif // SSCRIPTINTERPRETER_HPP
diff --git a/src/ScriptInterpreterHelpers.hpp b/src/ScriptInterpreterHelpers.hpp
deleted file mode 100644
index a8567fc..0000000
--- a/src/ScriptInterpreterHelpers.hpp
+++ /dev/null
@@ -1,98 +0,0 @@
-#ifndef SCRIPTINTERPRETERHELPERS_HPP
-#define SCRIPTINTERPRETERHELPERS_HPP
-
-#include <algorithm>
-#include <vector>
-
-#include "ScriptExceptionMacros.h"
-#include "Token.hpp"
-#include "Value.hpp"
-
-#define EXPECT_SEMICOLON(tokens, i, message) \
- ScriptInterpreterHelpers::expectSemicolon(tokens, i, message, __FILE__, __LINE__)
-
-namespace ScriptInterpreterHelpers {
-
-
-
-static void expectSemicolon(const std::vector<Token> & tokens, std::size_t & i, const std::string & message,
- const std::string & file = __FILE__, int line = __LINE__) {
- if (i >= tokens.size() || tokens[i].type != TokenType::Semicolon) {
- THROW_UNEXPECTED_TOKEN_ERROR_HELPER(tokens[i - 1], "; " + message, file, line);
- }
- i++; // Skip ';'
-}
-
-[[nodiscard]] static std::vector<Value> parseFunctionDeclarationArguments(const std::vector<Token> & tokens,
- std::size_t & i,
- const std::string & file = __FILE__,
- int line = __LINE__) {
- std::vector<Value> arguments;
-
- // check the arguments types
- if (tokens[i].type != TokenType::StringDeclaration && tokens[i].type != TokenType::BooleanDeclaration &&
- tokens[i].type != TokenType::IntDeclaration && tokens[i].type != TokenType::DoubleDeclaration &&
- tokens[i].type != TokenType::RightParenthesis) {
- THROW_UNEXPECTED_TOKEN_ERROR_HELPER(tokens[i], "variable declaration: 'type $" + tokens[i].lexeme + "'", file,
- line);
- }
- if (tokens[i].type != TokenType::RightParenthesis) {
- const auto parameter_type = getVariableTypeFromTokenTypeDeclaration(tokens[i].type);
- if (parameter_type == Variables::Type::VT_NOT_DEFINED) {
- THROW_UNEXPECTED_TOKEN_ERROR_HELPER(tokens[i], "valid type identifier", file, line);
- }
-
- // if (parameter_type == Variables::Type::VT_FUNCTION) {
- // THROW_UNEXPECTED_TOKEN_ERROR_HELPER(tokens[i], "valid type identifier", file, line);
- // }
-
- if (parameter_type == Variables::Type::VT_NULL) {
- THROW_UNEXPECTED_TOKEN_ERROR_HELPER(tokens[i], "valid type identifier", file, line);
- }
-
- Value val;
- val.type = parameter_type;
- val.token = tokens[i];
-
- arguments.emplace_back(std::move(val));
- i++; // Skip variable declaration
- }
-
- if (tokens[i].type != TokenType::RightParenthesis) {
- THROW_UNEXPECTED_TOKEN_ERROR_HELPER(tokens[i], ") - Only one argument is allowed", file, line);
- }
- i++; // Skip ')'
-
- return arguments;
-}
-
-static void getFunctionBody(const std::vector<Token> & tokens, std::size_t & i, std::size_t & start,
- std::size_t & end) {
- start = tokens[i].pos.end;
- if (i >= tokens.size() || tokens[i].type != TokenType::LeftCurlyBracket) {
- THROW_UNEXPECTED_TOKEN_ERROR(tokens[i], "{");
- }
- i++; // Skip '{'
-
- while (i < tokens.size() && tokens[i].type != TokenType::RightCurlyBracket) {
- if (tokens[i].type == TokenType::EndOfLine) {
- i++;
- continue;
- }
- if (tokens[i].type == TokenType::EndOfFile) {
- THROW_UNEXPECTED_END_OF_FILE_ERROR(tokens[i]);
- break;
- }
- i++;
- }
- end = tokens[i].pos.start - 1;
-
- if (i >= tokens.size() || tokens[i].type != TokenType::RightCurlyBracket) {
- THROW_UNEXPECTED_TOKEN_ERROR(tokens[i], "}");
- }
-};
-
-
-}; // namespace ScriptInterpreterHelpers
-
-#endif // SCRIPTINTERPRETERHELPERS_HPP
diff --git a/src/StringHelpers.hpp b/src/StringHelpers.hpp
deleted file mode 100644
index 937959f..0000000
--- a/src/StringHelpers.hpp
+++ /dev/null
@@ -1,20 +0,0 @@
-#ifndef STRINGHELPERS_HPP
-#define STRINGHELPERS_HPP
-#include <algorithm>
-#include <string>
-
-namespace StringHelpers {
-
-static std::string extractSubstring(const std::string & str, const size_t & start, const size_t & end) {
- if (start >= 0 && start < str.length() && end >= start && end < str.length()) {
- return str.substr(start, end - start + 1);
- }
- return "";
-}
-
-static void strtolower(std::string & data) {
- std::transform(data.begin(), data.end(), data.begin(), [](unsigned char c) { return std::tolower(c); });
-}
-
-}; // namespace StringHelpers
-#endif // STRINGHELPERS_HPP
diff --git a/include/BaseSymbol.hpp b/src/Symbols/BaseSymbol.hpp
similarity index 92%
rename from include/BaseSymbol.hpp
rename to src/Symbols/BaseSymbol.hpp
index b326e4b..2d3cdb2 100644
--- a/include/BaseSymbol.hpp
+++ b/src/Symbols/BaseSymbol.hpp
@@ -3,13 +3,11 @@
#define BASE_SYMBOL_HPP
#include <string>
-#include <variant>
#include "SymbolKind.hpp"
+#include "Value.hpp"
namespace Symbols {
-
-using Value = std::variant<int, double, std::string, bool>;
class Symbol {
protected:
diff --git a/include/ConstantSymbol.hpp b/src/Symbols/ConstantSymbol.hpp
similarity index 100%
rename from include/ConstantSymbol.hpp
rename to src/Symbols/ConstantSymbol.hpp
diff --git a/src/Symbols/FunctionSymbol.hpp b/src/Symbols/FunctionSymbol.hpp
new file mode 100644
index 0000000..255b0af
--- /dev/null
+++ b/src/Symbols/FunctionSymbol.hpp
@@ -0,0 +1,41 @@
+// FunctionSymbol.hpp
+#ifndef FUNCTION_SYMBOL_HPP
+#define FUNCTION_SYMBOL_HPP
+
+#include <vector>
+
+#include "BaseSymbol.hpp"
+#include "Lexer/Token.hpp"
+#include "Symbols/ParameterContainer.hpp"
+#include "Symbols/VariableTypes.hpp"
+
+namespace Symbols {
+
+class FunctionSymbol : public Symbol {
+ // store the variables name and type
+ FunctionParameterInfo parameters_;
+ Symbols::Variables::Type returnType_;
+ std::string plainBody_;
+ std::vector<Lexer::Tokens::Token> tokens_;
+
+ public:
+ FunctionSymbol(const std::string & name, const std::string & context, const FunctionParameterInfo & parameters,
+ const std::string & plainbody = "",
+ Symbols::Variables::Type returnType = Symbols::Variables::Type::NULL_TYPE) :
+ Symbol(name, {}, context, Symbols::Kind::Function),
+ parameters_(parameters),
+ plainBody_(plainbody),
+ returnType_(returnType) {}
+
+ Symbols::Kind kind() const override { return Symbols::Kind::Function; }
+
+ Symbols::Variables::Type returnType() const { return returnType_; }
+
+ const FunctionParameterInfo & parameters() const { return parameters_; }
+
+ const std::string & plainBody() const { return plainBody_; }
+};
+
+} // namespace Symbols
+
+#endif
diff --git a/src/Symbols/ParameterContainer.hpp b/src/Symbols/ParameterContainer.hpp
new file mode 100644
index 0000000..65f05f7
--- /dev/null
+++ b/src/Symbols/ParameterContainer.hpp
@@ -0,0 +1,17 @@
+#ifndef SYMBOLS_PARAMETER_CONTAINER_HPP
+#define SYMBOLS_PARAMETER_CONTAINER_HPP
+
+#include <string>
+#include <vector>
+
+#include "Symbols/VariableTypes.hpp"
+
+namespace Symbols {
+struct functionParameterType {
+ std::string name;
+ Symbols::Variables::Type type;
+};
+
+using FunctionParameterInfo = std::vector<Symbols::functionParameterType>;
+} // namespace Symbols
+#endif
diff --git a/include/SymbolContainer.hpp b/src/Symbols/SymbolContainer.hpp
similarity index 100%
rename from include/SymbolContainer.hpp
rename to src/Symbols/SymbolContainer.hpp
diff --git a/include/SymbolFactory.hpp b/src/Symbols/SymbolFactory.hpp
similarity index 70%
rename from include/SymbolFactory.hpp
rename to src/Symbols/SymbolFactory.hpp
index da37e15..5b7a168 100644
--- a/include/SymbolFactory.hpp
+++ b/src/Symbols/SymbolFactory.hpp
@@ -24,32 +24,42 @@
}
static std::shared_ptr<Symbol> createFunction(const std::string & name, const std::string & context,
- const Symbols::ValueContainer & parameters = {}) {
+ const Symbols::FunctionParameterInfo & parameters = {}) {
return std::make_shared<FunctionSymbol>(name, context, parameters);
}
static std::shared_ptr<Symbol> createFunction(const std::string & name, const std::string & context,
- const Symbols::ValueContainer & parameters,
- const std::string & plainBody) {
+ const Symbols::FunctionParameterInfo & parameters,
+ const std::string & plainBody) {
return std::make_shared<FunctionSymbol>(name, context, parameters, plainBody);
+ }
+
+ static std::shared_ptr<Symbol> createFunction(const std::string & name, const std::string & context,
+ const Symbols::FunctionParameterInfo & parameters,
+ const std::string & plainBody, Symbols::Variables::Type returnType) {
+ return std::make_shared<FunctionSymbol>(name, context, parameters, plainBody, returnType);
}
// Overloadok
static std::shared_ptr<Symbol> createVariable(const std::string & name, int value, const std::string & context) {
- return createVariable(name, Symbols::Value(value), context, Symbols::Variables::Type::VT_INT);
+ return createVariable(name, Symbols::Value(value), context, Symbols::Variables::Type::INTEGER);
}
static std::shared_ptr<Symbol> createVariable(const std::string & name, double value, const std::string & context) {
- return createVariable(name, Symbols::Value(value), context, Symbols::Variables::Type::VT_DOUBLE);
+ return createVariable(name, Symbols::Value(value), context, Symbols::Variables::Type::DOUBLE);
+ }
+
+ static std::shared_ptr<Symbol> createVariable(const std::string & name, float value, const std::string & context) {
+ return createVariable(name, Symbols::Value(value), context, Symbols::Variables::Type::FLOAT);
}
static std::shared_ptr<Symbol> createVariable(const std::string & name, const std::string & value,
const std::string & context) {
- return createVariable(name, Symbols::Value(value), context, Symbols::Variables::Type::VT_STRING);
+ return createVariable(name, Symbols::Value(value), context, Symbols::Variables::Type::STRING);
}
static std::shared_ptr<Symbol> createVariable(const std::string & name, bool value, const std::string & context) {
- return createVariable(name, Symbols::Value(value), context, Symbols::Variables::Type::VT_BOOLEAN);
+ return createVariable(name, Symbols::Value(value), context, Symbols::Variables::Type::BOOLEAN);
}
};
diff --git a/include/SymbolKind.hpp b/src/Symbols/SymbolKind.hpp
similarity index 100%
rename from include/SymbolKind.hpp
rename to src/Symbols/SymbolKind.hpp
diff --git a/include/SymbolTable.hpp b/src/Symbols/SymbolTable.hpp
similarity index 98%
rename from include/SymbolTable.hpp
rename to src/Symbols/SymbolTable.hpp
index db23889..0c4c7da 100644
--- a/include/SymbolTable.hpp
+++ b/src/Symbols/SymbolTable.hpp
@@ -3,7 +3,6 @@
#define SYMBOL_TABLE_HPP
#include <memory>
-#include <optional>
#include <vector>
#include "SymbolTypes.hpp"
diff --git a/include/SymbolTypes.hpp b/src/Symbols/SymbolTypes.hpp
similarity index 100%
rename from include/SymbolTypes.hpp
rename to src/Symbols/SymbolTypes.hpp
diff --git a/src/Symbols/Value.hpp b/src/Symbols/Value.hpp
new file mode 100644
index 0000000..4c52b04
--- /dev/null
+++ b/src/Symbols/Value.hpp
@@ -0,0 +1,77 @@
+#ifndef SYMBOL_VALUE_HPP
+#define SYMBOL_VALUE_HPP
+
+#include <iostream>
+#include <stdexcept>
+#include <string>
+#include <variant>
+
+namespace Symbols {
+
+class Value {
+ public:
+ using Variant = std::variant<int, double, float, std::string, bool>;
+
+ Value() = default;
+
+ Value(int v) : value_(v) {}
+
+ Value(double v) : value_(v) {}
+
+ Value(float v) : value_(v) {}
+
+ Value(const std::string & v) : value_(v) {}
+
+ Value(const char * v) : value_(std::string(v)) {}
+
+ Value(bool v) : value_(v) {}
+
+ const Variant & get() const { return value_; }
+
+ Variant & get() { return value_; }
+
+ template <typename T> T get() const { return std::get<T>(value_); }
+
+ // operator+
+ friend Value operator+(const Value & lhs, const Value & rhs) {
+ return std::visit(
+ [](auto && a, auto && b) -> Value {
+ using A = std::decay_t<decltype(a)>;
+ using B = std::decay_t<decltype(b)>;
+ if constexpr ((std::is_arithmetic_v<A> && std::is_arithmetic_v<B>) ) {
+ return Value{ a + b };
+ } else {
+ throw std::runtime_error("Invalid types for operator+");
+ }
+ },
+ lhs.value_, rhs.value_);
+ }
+
+ // operator==
+ friend bool operator==(const Value & lhs, const Value & rhs) { return lhs.value_ == rhs.value_; }
+
+ // to_string helper (needed for string + int, etc.)
+ static std::string to_string(const Variant & v) {
+ return std::visit(
+ [](auto && val) -> std::string {
+ using T = std::decay_t<decltype(val)>;
+ if constexpr (std::is_same_v<T, bool>) {
+ return val ? "true" : "false";
+ } else if constexpr (std::is_same_v<T, std::string>) {
+ return val;
+ } else {
+ return std::to_string(val);
+ }
+ },
+ v);
+ }
+
+ static std::string to_string(const Value & val) { return to_string(val.value_); }
+
+ private:
+ Variant value_;
+};
+
+} // namespace Symbols
+
+#endif // SYMBOL_VALUE_HPP
diff --git a/src/Symbols/ValueContainer.hpp b/src/Symbols/ValueContainer.hpp
new file mode 100644
index 0000000..fbc6fed
--- /dev/null
+++ b/src/Symbols/ValueContainer.hpp
@@ -0,0 +1,12 @@
+#ifndef SYMBOLS_VALUE_CONTAINER_HPP
+#define SYMBOLS_VALUE_CONTAINER_HPP
+
+#include <vector>
+
+#include "Symbols/Value.hpp"
+
+namespace Symbols {
+using ValueContainer = std::vector<Symbols::Value>;
+}; // namespace Symbols
+
+#endif // SYMBOLS_VALUE_CONTAINER_HPP
diff --git a/src/Symbols/VariableSymbol.hpp b/src/Symbols/VariableSymbol.hpp
new file mode 100644
index 0000000..325b920
--- /dev/null
+++ b/src/Symbols/VariableSymbol.hpp
@@ -0,0 +1,45 @@
+// VariableSymbol.hpp
+#ifndef VARIABLE_SYMBOL_HPP
+#define VARIABLE_SYMBOL_HPP
+
+#include "BaseSymbol.hpp"
+#include "Symbols/VariableTypes.hpp"
+
+namespace Symbols {
+
+class VariableSymbol : public Symbol {
+ protected:
+ Symbols::Variables::Type type_;
+ public:
+ VariableSymbol(const std::string & name, const Symbols::Value & value, const std::string & context,
+ Variables::Type type) :
+ Symbol(name, value, context, Symbols::Kind::Variable),
+ type_(type) {}
+
+ Symbols::Kind kind() const override { return Symbols::Kind::Variable; }
+
+ Variables::Type type() const { return type_; }
+
+ std::string toString() const {
+ std::string r = "VariableSymbol: " + name_ + " Type: " + Symbols::Variables::TypeToString(type_);
+ if (type_ == Symbols::Variables::Type::INTEGER) {
+ r += " Value: " + std::to_string(value_.get<int>());
+ } else if (type_ == Symbols::Variables::Type::DOUBLE) {
+ r += " Value: " + std::to_string(value_.get<double>());
+ } else if (type_ == Symbols::Variables::Type::FLOAT) {
+ r += " Value: " + std::to_string(value_.get<float>());
+ } else if (type_ == Symbols::Variables::Type::STRING) {
+ r += " Value: " + value_.get<std::string>();
+ } else if (type_ == Symbols::Variables::Type::BOOLEAN) {
+ r += " Value: " + std::to_string(value_.get<bool>());
+ } else if (type_ == Symbols::Variables::Type::NULL_TYPE) {
+ r += " Value: null";
+ }
+
+ return r;
+ }
+};
+
+} // namespace Symbols
+
+#endif
diff --git a/src/Symbols/VariableTypes.hpp b/src/Symbols/VariableTypes.hpp
new file mode 100644
index 0000000..99c4802
--- /dev/null
+++ b/src/Symbols/VariableTypes.hpp
@@ -0,0 +1,48 @@
+#ifndef VARIABLE_TYPES_HPP
+#define VARIABLE_TYPES_HPP
+
+#include <cstdint>
+#include <string>
+#include <unordered_map>
+
+namespace Symbols::Variables {
+
+enum class Type : std::uint8_t { INTEGER, DOUBLE, FLOAT, STRING, BOOLEAN, NULL_TYPE, UNDEFINED_TYPE };
+
+const std::unordered_map<std::string, Type> StringToTypeMap = {
+ { "int", Type::INTEGER },
+ { "double", Type::DOUBLE },
+ { "float", Type::FLOAT },
+ { "string", Type::STRING },
+ { "bool", Type::BOOLEAN },
+ { "boolean", Type::BOOLEAN },
+ { "null", Type::NULL_TYPE },
+
+ { "undefined", Type::UNDEFINED_TYPE },
+};
+const std::unordered_map<Type, std::string> StypeToStringMap = {
+ { Type::INTEGER, "int" },
+ { Type::DOUBLE, "double" },
+ { Type::FLOAT, "float" },
+ { Type::STRING, "string" },
+ { Type::BOOLEAN, "bool" },
+ { Type::NULL_TYPE, "null" },
+ { Type::UNDEFINED_TYPE, "undeffined" },
+};
+
+inline static std::string TypeToString(Symbols::Variables::Type type) {
+ if (StypeToStringMap.find(type) != StypeToStringMap.end()) {
+ return StypeToStringMap.at(type);
+ }
+ return "null";
+};
+
+inline static Type StringToType(const std::string & type) {
+ if (StringToTypeMap.find(type) != StringToTypeMap.end()) {
+ return StringToTypeMap.at(type);
+ }
+ return Type::NULL_TYPE;
+};
+
+}; // namespace Symbols::Variables
+#endif // VARIABLE_TYPES_HPP
diff --git a/src/Token.hpp b/src/Token.hpp
deleted file mode 100644
index 564356a..0000000
--- a/src/Token.hpp
+++ /dev/null
@@ -1,120 +0,0 @@
-#ifndef TOKEN_HPP
-#define TOKEN_HPP
-#include <cstdint>
-#include <string>
-#include <unordered_map>
-
-namespace Tokens {
-enum class Type : std::uint8_t {
- ParserOpenTag,
- ParserCloseTag,
- ParserIfStatement, // if
- FileClose,
- Identifier,
- StringLiteral,
- IntLiteral,
- DoubleLiteral,
- BooleanLiteral,
- LeftParenthesis, // (
- RightParenthesis, // )
- Comma, // ,
- Semicolon, // ;
- Variable, // $variable
- VariableSign, // $ variable start sign
- StringDeclaration, // string $variable
- IntDeclaration, // int $variable
- DoubleDeclaration, // double $variable
- BooleanDeclaration, // bool $variable
- FunctionDeclaration, // function fn_name
- FunctionCall, // fn_name(args)
- Return, // return
- Equals, // =
- Plus, // +
- Minus, // -
- Multiply, // *
- Divide, // /
- Modulo, // %
- GreaterThan, // >
- LessThan, // <
- GreaterThanOrEqual, // >=
- LessThanOrEqual, // <=
- NotEqual, // !=
- Equal, // ==
- Not, // !
- And, // &&
- Or, // ||
- LeftBracket, // [
- RightBracket, // ]
- LeftCurlyBracket, // {
- RightCurlyBracket, // }
- EndOfFile, // \0
- EndOfLine, // \n
- Comment, // #
- Unknown // Unknown
-};
-
-const static std::unordered_map<Tokens::Type, std::string> tokenTypeNames = {
- { Tokens::Type::ParserOpenTag, "ParserOpenTag" },
- { Tokens::Type::ParserCloseTag, "ParserCloseTag" },
- { Tokens::Type::ParserIfStatement, "ParserIfStatement" },
- { Tokens::Type::FileClose, "FileClose" },
- { Tokens::Type::Identifier, "Identifier" },
- { Tokens::Type::StringLiteral, "StringLiteral" },
- { Tokens::Type::IntLiteral, "IntLiteral" },
- { Tokens::Type::DoubleLiteral, "DoubleLiteral" },
- { Tokens::Type::BooleanLiteral, "BooleanLiteral" },
- { Tokens::Type::LeftParenthesis, "LeftParenthesis" },
- { Tokens::Type::RightParenthesis, "RightParenthesis" },
- { Tokens::Type::Comma, "Comma" },
- { Tokens::Type::Semicolon, "Semicolon" },
- { Tokens::Type::Variable, "Variable" },
- { Tokens::Type::VariableSign, "VariableSign" },
- { Tokens::Type::StringDeclaration, "StringDeclaration" },
- { Tokens::Type::IntDeclaration, "IntDeclaration" },
- { Tokens::Type::DoubleDeclaration, "DoubleDeclaration" },
- { Tokens::Type::BooleanDeclaration, "BooleanDeclaration" },
- { Tokens::Type::FunctionDeclaration, "FunctionDeclaration" },
- { Tokens::Type::FunctionCall, "FunctionCall" },
- { Tokens::Type::Return, "Return" },
- { Tokens::Type::Equals, "Equals" },
- { Tokens::Type::Plus, "Plus" },
- { Tokens::Type::Minus, "Minus" },
- { Tokens::Type::Multiply, "Multiply" },
- { Tokens::Type::Divide, "Divide" },
- { Tokens::Type::Modulo, "Modulo" },
- { Tokens::Type::GreaterThan, "GreaterThan" },
- { Tokens::Type::LessThan, "LessThan" },
- { Tokens::Type::GreaterThanOrEqual, "GreaterThanOrEqual" },
- { Tokens::Type::LessThanOrEqual, "LessThanOrEqual" },
- { Tokens::Type::NotEqual, "NotEqual" },
- { Tokens::Type::Equal, "Equal" },
- { Tokens::Type::Not, "Not" },
- { Tokens::Type::And, "And" },
- { Tokens::Type::Or, "Or" },
- { Tokens::Type::LeftBracket, "LeftBracket" },
- { Tokens::Type::RightBracket, "RightBracket" },
- { Tokens::Type::LeftCurlyBracket, "LeftCurlyBracket" },
- { Tokens::Type::RightCurlyBracket, "RightCurlyBracket" },
- { Tokens::Type::EndOfFile, "EndOfFile" },
- { Tokens::Type::EndOfLine, "EndOfLine" },
- { Tokens::Type::Comment, "Comment" },
- { Tokens::Type::Unknown, "Unknown" }
-};
-
-struct TokenPos {
- size_t start;
- size_t end;
-};
-
-struct Token {
- Tokens::Type type;
- std::string lexeme;
- std::string file;
- int lineNumber;
- size_t columnNumber;
- TokenPos pos;
-
- [[nodiscard]] std::string getTokenName() const { return tokenTypeNames.at(type); }
-};
-} // namespace Tokens
-#endif // TOKEN_HPP
diff --git a/src/VoidScript.hpp b/src/VoidScript.hpp
new file mode 100644
index 0000000..d1188b5
--- /dev/null
+++ b/src/VoidScript.hpp
@@ -0,0 +1,89 @@
+#ifndef VOIDSCRIPT_HPP
+#define VOIDSCRIPT_HPP
+
+#include <filesystem>
+#include <fstream>
+#include <string>
+
+#include "Lexer/Lexer.hpp"
+#include "Parser/Parser.hpp"
+
+class VoidScript {
+ private:
+ std::string file;
+ 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) {
+ 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);
+ }
+ file_content = std::string((std::istreambuf_iterator<char>(input)), std::istreambuf_iterator<char>());
+ input.close();
+ }
+
+ int run() {
+ try {
+ this->lexer->addNamespaceInput(this->file, this->file_content);
+ const auto tokens = this->lexer->tokenizeNamespace(this->file);
+
+ 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::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';
+ }
+ }
+
+ 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';
+ }
+ }
+
+ return 0;
+ } catch (const Parser::SyntaxError & e) {
+ std::cerr << "Syntax Error during parsing: " << e.what() << '\n';
+ return 1;
+ } catch (const std::exception & e) {
+ std::cerr << "An error occurred: " << e.what() << '\n';
+ return 1;
+ }
+ return 1;
+ }
+}; // class VoidScript
+
+#endif // VOIDSCRIPT_HPP
--
Gitblit v1.9.3