6 files modified
1 files renamed
11 files added
2 files deleted
| | |
| | | set(ARCHITECTURE "amd64") |
| | | elseif(CMAKE_SIZEOF_VOID_P EQUAL 4) |
| | | set(ARCHITECTURE "i386") |
| | | else() |
| | | message(STATUS "Célarchitektúra: Nem meghatározható (CMAKE_SIZEOF_VOID_P: ${CMAKE_SIZEOF_VOID_P})") |
| | | endif() |
| | | endif() |
| | | |
| | |
| | | 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 src) |
| | | include_directories(${CMAKE_BINARY_DIR}/include ${CMAKE_SOURCE_DIR}/src ${CMAKE_SOURCE_DIR}/include) |
| | | |
| | | |
| | | # LIBRARY TARGET |
| | | add_library(voidscript |
| File was renamed from src/BaseFunction.hpp |
| | |
| | | #define SCRIPT_FUNCTION_HPP |
| | | |
| | | #include <functional> |
| | | #include <stdexcept> |
| | | #include <unordered_map> |
| | | #include <utility> |
| | | #include <vector> |
| New file |
| | |
| | | // BaseSymbol.hpp |
| | | #ifndef BASE_SYMBOL_HPP |
| | | #define BASE_SYMBOL_HPP |
| | | |
| | | #include <string> |
| | | #include <variant> |
| | | |
| | | #include "SymbolKind.hpp" |
| | | |
| | | namespace Symbols { |
| | | |
| | | using Value = std::variant<int, double, std::string, bool>; |
| | | |
| | | class Symbol { |
| | | protected: |
| | | std::string name_; |
| | | Value value_; |
| | | std::string context_; |
| | | Symbols::Kind kind_; |
| | | |
| | | public: |
| | | Symbol(const std::string & name, const Value & value, const std::string & context, Symbols::Kind type) : |
| | | name_(name), |
| | | value_(value), |
| | | context_(context), |
| | | kind_(type) {} |
| | | |
| | | virtual ~Symbol() = default; |
| | | |
| | | // Polimorf azonosító |
| | | virtual Symbols::Kind kind() const = 0; |
| | | |
| | | // Getterek |
| | | const std::string & name() const { return name_; } |
| | | |
| | | const std::string & context() const { return context_; } |
| | | |
| | | Symbols::Kind type() const { return kind_; } |
| | | |
| | | // Virtuális getter/setter a value-hoz |
| | | virtual const Value & getValue() const { return value_; } |
| | | |
| | | virtual void setValue(const Value & value) { value_ = value; } |
| | | |
| | | // Templated getter |
| | | template <typename T> T getAs() const { return std::get<T>(value_); } |
| | | }; |
| | | |
| | | } // namespace Symbols |
| | | |
| | | #endif |
| New file |
| | |
| | | // ConstantSymbol.hpp |
| | | #ifndef CONSTANT_SYMBOL_HPP |
| | | #define CONSTANT_SYMBOL_HPP |
| | | |
| | | #include <stdexcept> |
| | | |
| | | #include "BaseSymbol.hpp" |
| | | #include "VariableTypes.hpp" |
| | | |
| | | namespace Symbols { |
| | | |
| | | class ConstantSymbol : public Symbol { |
| | | protected: |
| | | Symbols::Variables::Type _vartype; |
| | | public: |
| | | ConstantSymbol(const std::string & name, const Symbols::Value & value, const std::string & context) : |
| | | Symbol(name, value, context, Symbols::Kind::Constant) {} |
| | | |
| | | Symbols::Kind kind() const override { return Symbols::Kind::Constant; } |
| | | |
| | | void setValue(const Symbols::Value & /*value*/) override { |
| | | throw std::logic_error("Cannot modify a constant symbol"); |
| | | } |
| | | }; |
| | | |
| | | } // namespace Symbols |
| | | |
| | | #endif |
| New file |
| | |
| | | // 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 |
| New file |
| | |
| | | // SymbolContainer.hpp |
| | | #ifndef SYMBOL_CONTAINER_HPP |
| | | #define SYMBOL_CONTAINER_HPP |
| | | |
| | | #include "SymbolTable.hpp" |
| | | |
| | | namespace Symbols { |
| | | |
| | | class SymbolContainer { |
| | | std::shared_ptr<SymbolTable> globalScope_; |
| | | std::shared_ptr<SymbolTable> currentScope_; |
| | | |
| | | public: |
| | | SymbolContainer() { |
| | | globalScope_ = std::make_shared<SymbolTable>(); |
| | | currentScope_ = globalScope_; |
| | | } |
| | | |
| | | void enterScope() { |
| | | currentScope_ = std::make_shared<SymbolTable>(currentScope_); |
| | | } |
| | | |
| | | void leaveScope() { |
| | | if (currentScope_->getParent()) { |
| | | currentScope_ = currentScope_->getParent(); |
| | | } |
| | | } |
| | | |
| | | void define(const std::string& ns, const SymbolPtr& symbol) { |
| | | currentScope_->define(ns, symbol); |
| | | } |
| | | |
| | | SymbolPtr resolve(const std::string& ns, const std::string& name) const { |
| | | return currentScope_->get(ns, name); |
| | | } |
| | | |
| | | bool exists(const std::string& ns, const std::string& name) const { |
| | | return currentScope_->exists(ns, name); |
| | | } |
| | | |
| | | std::vector<SymbolPtr> listNamespace(const std::string& ns) const { |
| | | return currentScope_->listAll(ns); |
| | | } |
| | | |
| | | std::shared_ptr<SymbolTable> getGlobalScope() const { return globalScope_; } |
| | | std::shared_ptr<SymbolTable> getCurrentScope() const { return currentScope_; } |
| | | }; |
| | | |
| | | } // namespace Symbols |
| | | |
| | | #endif |
| New file |
| | |
| | | // SymbolFactory.hpp |
| | | #ifndef SYMBOL_FACTORY_HPP |
| | | #define SYMBOL_FACTORY_HPP |
| | | |
| | | #include <memory> |
| | | #include <string> |
| | | |
| | | #include "ConstantSymbol.hpp" |
| | | #include "FunctionSymbol.hpp" |
| | | #include "VariableSymbol.hpp" |
| | | |
| | | namespace Symbols { |
| | | |
| | | class SymbolFactory { |
| | | public: |
| | | static std::shared_ptr<Symbol> createVariable(const std::string & name, const Symbols::Value & value, |
| | | const std::string & context, Variables::Type type) { |
| | | return std::make_shared<VariableSymbol>(name, value, context, type); |
| | | } |
| | | |
| | | static std::shared_ptr<Symbol> createConstant(const std::string & name, const Symbols::Value & value, |
| | | const std::string & context) { |
| | | return std::make_shared<ConstantSymbol>(name, value, context); |
| | | } |
| | | |
| | | static std::shared_ptr<Symbol> createFunction(const std::string & name, const std::string & context, |
| | | const Symbols::ValueContainer & 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) { |
| | | return std::make_shared<FunctionSymbol>(name, context, parameters, plainBody); |
| | | } |
| | | |
| | | // 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); |
| | | } |
| | | |
| | | 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); |
| | | } |
| | | |
| | | 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); |
| | | } |
| | | |
| | | 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); |
| | | } |
| | | }; |
| | | |
| | | } // namespace Symbols |
| | | |
| | | #endif |
| New file |
| | |
| | | // SymbolKind.hpp |
| | | #ifndef SYMBOL_KIND_HPP |
| | | #define SYMBOL_KIND_HPP |
| | | |
| | | #include <cstdint> |
| | | |
| | | namespace Symbols { |
| | | |
| | | enum class Kind : std::uint8_t { |
| | | Variable, |
| | | Constant, |
| | | Function |
| | | // Later: Module, Class, etc.. |
| | | }; |
| | | |
| | | }; // namespace Symbols |
| | | |
| | | #endif |
| New file |
| | |
| | | // SymbolTable.hpp |
| | | #ifndef SYMBOL_TABLE_HPP |
| | | #define SYMBOL_TABLE_HPP |
| | | |
| | | #include <memory> |
| | | #include <optional> |
| | | #include <vector> |
| | | |
| | | #include "SymbolTypes.hpp" |
| | | |
| | | namespace Symbols { |
| | | |
| | | class SymbolTable { |
| | | NamespaceMap symbols_; |
| | | std::shared_ptr<SymbolTable> parent_ = nullptr; |
| | | |
| | | public: |
| | | SymbolTable(std::shared_ptr<SymbolTable> parent = nullptr) : parent_(std::move(parent)) {} |
| | | |
| | | void define(const std::string & ns, const SymbolPtr & symbol) { symbols_[ns][symbol->name()] = symbol; } |
| | | |
| | | bool exists(const std::string & ns, const std::string & name) const { return get(ns, name) != nullptr; } |
| | | |
| | | SymbolPtr get(const std::string & ns, const std::string & name) const { |
| | | auto itNs = symbols_.find(ns); |
| | | if (itNs != symbols_.end()) { |
| | | const auto & map = itNs->second; |
| | | auto it = map.find(name); |
| | | if (it != map.end()) { |
| | | return it->second; |
| | | } |
| | | } |
| | | // Rekurzívan keresünk a szülő scope-ban |
| | | if (parent_) { |
| | | return parent_->get(ns, name); |
| | | } |
| | | return nullptr; |
| | | } |
| | | |
| | | void remove(const std::string & ns, const std::string & name) { |
| | | auto itNs = symbols_.find(ns); |
| | | if (itNs != symbols_.end()) { |
| | | itNs->second.erase(name); |
| | | } |
| | | } |
| | | |
| | | std::vector<SymbolPtr> listAll(const std::string & ns) const { |
| | | std::vector<SymbolPtr> result; |
| | | auto it = symbols_.find(ns); |
| | | if (it != symbols_.end()) { |
| | | for (const auto & [_, sym] : it->second) { |
| | | result.push_back(sym); |
| | | } |
| | | } |
| | | return result; |
| | | } |
| | | |
| | | void clear(const std::string & ns) { symbols_.erase(ns); } |
| | | |
| | | void clearAll() { symbols_.clear(); } |
| | | |
| | | std::shared_ptr<SymbolTable> getParent() const { return parent_; } |
| | | }; |
| | | |
| | | } // namespace Symbols |
| | | |
| | | #endif |
| New file |
| | |
| | | // SymbolTypes.hpp |
| | | #ifndef SYMBOL_TYPES_HPP |
| | | #define SYMBOL_TYPES_HPP |
| | | |
| | | #include <memory> |
| | | #include <string> |
| | | #include <unordered_map> |
| | | |
| | | #include "BaseSymbol.hpp" |
| | | |
| | | namespace Symbols { |
| | | |
| | | |
| | | using SymbolPtr = std::shared_ptr<Symbol>; |
| | | |
| | | // Namespace -> név -> szimbólum |
| | | using SymbolMap = std::unordered_map<std::string, SymbolPtr>; |
| | | using NamespaceMap = std::unordered_map<std::string, SymbolMap>; |
| | | |
| | | } // namespace Symbols |
| | | |
| | | #endif |
| New file |
| | |
| | | // 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 |
| New file |
| | |
| | | #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 |
| | |
| | | return pos >= src.size(); |
| | | } |
| | | |
| | | Token Lexer::createToken(TokenType type, const std::string & lexeme) const { |
| | | 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 } |
| | | }; |
| | | } |
| | | |
| | | Token Lexer::createSingleCharToken(TokenType type, const std::string & lexeme) { |
| | | Tokens::Token Lexer::createSingleCharToken(Tokens::Type type, const std::string & lexeme) { |
| | | size_t startCol = colNumber; |
| | | size_t startChar = charNumber; |
| | | advance(); |
| | |
| | | }; |
| | | } |
| | | |
| | | Token Lexer::createUnknownToken(const std::string & lexeme) const { |
| | | Tokens::Token Lexer::createUnknownToken(const std::string & lexeme) const { |
| | | size_t startChar = charNumber - lexeme.length(); |
| | | return { |
| | | TokenType::Unknown, lexeme, filename, lineNumber, colNumber - lexeme.length(), { startChar, charNumber } |
| | | Tokens::Type::Unknown, lexeme, filename, lineNumber, colNumber - lexeme.length(), { startChar, charNumber } |
| | | }; |
| | | } |
| | | |
| | | Token Lexer::stringToken() { |
| | | Tokens::Token Lexer::stringToken() { |
| | | std::string result; |
| | | size_t startChar = charNumber; |
| | | size_t startCol = colNumber; |
| | |
| | | } |
| | | if (isAtEnd() || peek() != '"') { |
| | | return { |
| | | TokenType::Unknown, "Unterminated string", filename, lineNumber, startCol, { startChar, pos } |
| | | Tokens::Type::Unknown, "Unterminated string", filename, lineNumber, startCol, { startChar, pos } |
| | | }; |
| | | } |
| | | advance(); // Skip closing quote |
| | | return { |
| | | TokenType::StringLiteral, result, filename, lineNumber, startCol, { startChar, pos } |
| | | Tokens::Type::StringLiteral, result, filename, lineNumber, startCol, { startChar, pos } |
| | | }; |
| | | } |
| | | |
| | | Token Lexer::numberToken() { |
| | | Tokens::Token Lexer::numberToken() { |
| | | std::string result; |
| | | std::string found; |
| | | TokenType type = TokenType::Unknown; |
| | | Tokens::Type type = Tokens::Type::Unknown; |
| | | bool decimalPointSeen = false; |
| | | size_t startChar = charNumber; |
| | | size_t startCol = colNumber; |
| | |
| | | if (peek() == '.') { |
| | | if (decimalPointSeen) { |
| | | return { |
| | | TokenType::Unknown, "Invalid number format", filename, lineNumber, startCol, { startChar, pos } |
| | | Tokens::Type::Unknown, "Invalid number format", filename, lineNumber, startCol, { startChar, pos } |
| | | }; |
| | | } |
| | | decimalPointSeen = true; |
| | |
| | | if (found.find('.') == std::string::npos) { |
| | | if (is_number<int>(found)) { |
| | | result = found; |
| | | type = TokenType::IntLiteral; |
| | | type = Tokens::Type::IntLiteral; |
| | | } else { |
| | | return { |
| | | TokenType::Unknown, "Invalid integer", filename, lineNumber, startCol, { startChar, pos } |
| | | Tokens::Type::Unknown, "Invalid integer", filename, lineNumber, startCol, { startChar, pos } |
| | | }; |
| | | } |
| | | } else { |
| | | if (is_number<double>(found)) { |
| | | result = found; |
| | | type = TokenType::DoubleLiteral; |
| | | type = Tokens::Type::DoubleLiteral; |
| | | } else { |
| | | return { |
| | | TokenType::Unknown, "Invalid double", filename, lineNumber, startCol, { startChar, pos } |
| | | Tokens::Type::Unknown, "Invalid double", filename, lineNumber, startCol, { startChar, pos } |
| | | }; |
| | | } |
| | | } |
| | | } else { |
| | | return { |
| | | TokenType::Unknown, "Expected number", filename, lineNumber, startCol, { startChar, pos } |
| | | Tokens::Type::Unknown, "Expected number", filename, lineNumber, startCol, { startChar, pos } |
| | | }; |
| | | } |
| | | |
| | |
| | | }; |
| | | } |
| | | |
| | | Token Lexer::identifierToken() { |
| | | Tokens::Token Lexer::identifierToken() { |
| | | std::string result; |
| | | size_t startChar = charNumber; |
| | | size_t startCol = colNumber; |
| | |
| | | result += advance(); |
| | | } |
| | | return { |
| | | TokenType::Identifier, result, filename, lineNumber, startCol, { startChar, pos } |
| | | Tokens::Type::Identifier, result, filename, lineNumber, startCol, { startChar, pos } |
| | | }; |
| | | } |
| | | |
| | | Token Lexer::variableToken() { |
| | | Tokens::Token Lexer::variableToken() { |
| | | size_t startChar = charNumber; |
| | | size_t startCol = colNumber; |
| | | advance(); // Skip $ |
| | |
| | | varName += advance(); |
| | | } |
| | | return { |
| | | TokenType::Variable, varName, filename, lineNumber, startCol, { startChar, pos } |
| | | Tokens::Type::Variable, varName, filename, lineNumber, startCol, { startChar, pos } |
| | | }; |
| | | } |
| | | return { |
| | | TokenType::Unknown, "$ followed by invalid character", filename, lineNumber, startCol, { startChar, pos } |
| | | Tokens::Type::Unknown, "$ followed by invalid character", filename, lineNumber, startCol, { startChar, pos } |
| | | }; |
| | | } |
| | | |
| | | Token Lexer::commentToken() { |
| | | Tokens::Token Lexer::commentToken() { |
| | | size_t startChar = charNumber; |
| | | size_t startCol = colNumber; |
| | | advance(); // Skip # |
| | |
| | | commentText += advance(); |
| | | } |
| | | return { |
| | | TokenType::Comment, commentText, filename, lineNumber, startCol, { startChar, pos } |
| | | Tokens::Type::Comment, commentText, filename, lineNumber, startCol, { startChar, pos } |
| | | }; |
| | | } |
| | | |
| | | Token Lexer::keywordOrIdentifierToken() { |
| | | Tokens::Token Lexer::keywordOrIdentifierToken() { |
| | | std::string lexeme; |
| | | while (isalpha(peek())) { |
| | | lexeme += advance(); |
| | |
| | | } |
| | | |
| | | if (lexeme == IDENTIFIER_RETURN) { |
| | | return createToken(TokenType::Return, lexeme); |
| | | return createToken(Tokens::Type::Return, lexeme); |
| | | } |
| | | if (lexeme == IDENTIFIER_IF) { |
| | | return createToken(TokenType::ParserIfStatement, lexeme); |
| | | return createToken(Tokens::Type::ParserIfStatement, lexeme); |
| | | } |
| | | |
| | | if (peek() == '(') { // Function call |
| | | return createToken(TokenType::FunctionCall, lexeme); |
| | | return createToken(Tokens::Type::FunctionCall, lexeme); |
| | | } |
| | | |
| | | auto it = Variables::StringToTypeMap.find(lexeme); |
| | |
| | | if (peek() == IDENTIFIER_VARIABLE) { |
| | | return this->variableDeclarationToken(type); |
| | | } |
| | | return createToken(TokenType::Identifier, lexeme); |
| | | return createToken(Tokens::Type::Identifier, lexeme); |
| | | } |
| | | return createToken(TokenType::Identifier, lexeme); |
| | | return createToken(Tokens::Type::Identifier, lexeme); |
| | | } |
| | | |
| | | Token Lexer::functionDeclarationToken() { |
| | | Tokens::Token Lexer::functionDeclarationToken() { |
| | | advance(); // Skip function |
| | | std::string functionName; |
| | | if (isalpha(peek()) || peek() == '_') { |
| | |
| | | while (isalnum(peek()) || peek() == '_') { |
| | | functionName += advance(); |
| | | } |
| | | return createToken(TokenType::FunctionDeclaration, functionName); |
| | | return createToken(Tokens::Type::FunctionDeclaration, functionName); |
| | | } |
| | | return createUnknownToken("function followed by invalid character"); |
| | | } |
| | | |
| | | Token Lexer::variableDeclarationToken(Variables::Type type) { |
| | | Tokens::Token Lexer::variableDeclarationToken(Variables::Type type) { |
| | | advance(); // Skip $ |
| | | std::string varName; |
| | | if (isalpha(peek()) || peek() == '_') { |
| | |
| | | } |
| | | } |
| | | |
| | | std::vector<Token> Lexer::tokenize() { |
| | | std::vector<Token> tokens; |
| | | std::vector<Tokens::Token> Lexer::tokenize() { |
| | | std::vector<Tokens::Token> tokens; |
| | | tokens.reserve(src.size() / 4); |
| | | |
| | | while (pos < src.size()) { |
| | |
| | | continue; |
| | | } |
| | | if (c == '\n') { |
| | | tokens.push_back(createSingleCharToken(TokenType::EndOfLine, "\n")); |
| | | tokens.push_back(createSingleCharToken(Tokens::Type::EndOfLine, "\n")); |
| | | continue; |
| | | } |
| | | if (c == IDENTIFIER_COMMENT) { |
| | |
| | | } |
| | | if (matchSequence(PARSER_OPEN_TAG)) { |
| | | matchAndConsume(PARSER_OPEN_TAG); |
| | | tokens.push_back(createToken(TokenType::ParserOpenTag, 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(TokenType::ParserCloseTag, PARSER_CLOSE_TAG)); |
| | | tokens.push_back(createToken(Tokens::Type::ParserCloseTag, PARSER_CLOSE_TAG)); |
| | | continue; |
| | | } |
| | | switch (c) { |
| | |
| | | tokens.push_back(stringToken()); |
| | | break; |
| | | case '(': |
| | | tokens.push_back(createSingleCharToken(TokenType::LeftParenthesis, "(")); |
| | | tokens.push_back(createSingleCharToken(Tokens::Type::LeftParenthesis, "(")); |
| | | break; |
| | | case ')': |
| | | tokens.push_back(createSingleCharToken(TokenType::RightParenthesis, ")")); |
| | | tokens.push_back(createSingleCharToken(Tokens::Type::RightParenthesis, ")")); |
| | | break; |
| | | case ',': |
| | | tokens.push_back(createSingleCharToken(TokenType::Comma, ",")); |
| | | tokens.push_back(createSingleCharToken(Tokens::Type::Comma, ",")); |
| | | break; |
| | | case ';': |
| | | tokens.push_back(createSingleCharToken(TokenType::Semicolon, ";")); |
| | | tokens.push_back(createSingleCharToken(Tokens::Type::Semicolon, ";")); |
| | | break; |
| | | case '=': |
| | | tokens.push_back(createSingleCharToken(TokenType::Equals, "=")); |
| | | tokens.push_back(createSingleCharToken(Tokens::Type::Equals, "=")); |
| | | break; |
| | | case '+': |
| | | tokens.push_back(createSingleCharToken(TokenType::Plus, "+")); |
| | | tokens.push_back(createSingleCharToken(Tokens::Type::Plus, "+")); |
| | | break; |
| | | case '{': |
| | | tokens.push_back(createSingleCharToken(TokenType::LeftCurlyBracket, "{")); |
| | | tokens.push_back(createSingleCharToken(Tokens::Type::LeftCurlyBracket, "{")); |
| | | break; |
| | | case '}': |
| | | tokens.push_back(createSingleCharToken(TokenType::RightCurlyBracket, "}")); |
| | | tokens.push_back(createSingleCharToken(Tokens::Type::RightCurlyBracket, "}")); |
| | | break; |
| | | default: |
| | | tokens.push_back(createUnknownToken(std::string(1, c))); |
| | |
| | | } |
| | | |
| | | tokens.push_back({ |
| | | TokenType::EndOfFile, "", filename, lineNumber, colNumber, { charNumber, charNumber } |
| | | Tokens::Type::EndOfFile, "", filename, lineNumber, colNumber, { charNumber, charNumber } |
| | | }); |
| | | return tokens; |
| | | } |
| | |
| | | #include <sstream> |
| | | #include <vector> |
| | | |
| | | #include "StringHelpers.hpp" |
| | | #include "Token.hpp" |
| | | #include "VariableTypes.hpp" |
| | | |
| | |
| | | std::string srcSubstr = src.substr(pos, sequence.length()); |
| | | std::string seqLower = sequence; |
| | | |
| | | std::transform(srcSubstr.begin(), srcSubstr.end(), srcSubstr.begin(), |
| | | [](unsigned char c) { return std::tolower(c); }); |
| | | |
| | | std::transform(seqLower.begin(), seqLower.end(), seqLower.begin(), |
| | | [](unsigned char c) { return std::tolower(c); }); |
| | | StringHelpers::strtolower(srcSubstr); |
| | | StringHelpers::strtolower(seqLower); |
| | | |
| | | return srcSubstr == seqLower; |
| | | } |
| | |
| | | } |
| | | |
| | | Value ScriptInterpreter::evaluateExpression(const Token & token) const { |
| | | if (token.type == TokenType::StringLiteral) { |
| | | switch (token.type) { |
| | | case TokenType::StringLiteral: |
| | | return Value::fromString(token); |
| | | } |
| | | if (token.type == TokenType::IntLiteral) { |
| | | |
| | | case TokenType::IntLiteral: |
| | | try { |
| | | return Value::fromInt(token); |
| | | } catch (const std::invalid_argument & e) { |
| | |
| | | } catch (const std::out_of_range & e) { |
| | | throw std::runtime_error("Integer literal out of range: " + token.lexeme); |
| | | } |
| | | } |
| | | if (token.type == TokenType::DoubleLiteral) { |
| | | |
| | | case TokenType::DoubleLiteral: |
| | | try { |
| | | return Value::fromDouble(token); |
| | | } catch (const std::invalid_argument & e) { |
| | |
| | | } 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); |
| | | } |
| | | if (token.type == TokenType::BooleanLiteral || token.type == TokenType::Identifier) { |
| | | std::string lowered = token.lexeme; |
| | | std::transform(lowered.begin(), lowered.end(), lowered.begin(), |
| | | [](unsigned char c) { return std::tolower(c); }); |
| | | return Value::fromBoolean(token, (lowered == "true" ? true : false)); |
| | | } |
| | | if (token.type == TokenType::Variable) { |
| | | |
| | | case TokenType::Variable: |
| | | return this->getVariable(token, this->contextPrefix, __FILE__, __LINE__); |
| | | } |
| | | |
| | | default: |
| | | THROW_UNEXPECTED_TOKEN_ERROR(token, "string, integer, double, or variable"); |
| | | } |
| | | |
| | | return Value(); |
| | | } |
| | |
| | | return args; |
| | | } |
| | | |
| | | void ScriptInterpreter::handleBooleanDeclaration(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) { |
| | | auto variable = this->getVariable(tokens[i], this->contextPrefix, __FILE__, __LINE__); |
| | | |
| | | if (variable.type != Variables::Type::VT_BOOLEAN) { |
| | | THROW_VARIABLE_TYPE_MISSMATCH_ERROR(varToken.lexeme, |
| | | Variables::TypeToString(Variables::Type::VT_BOOLEAN), |
| | | tokens[i].lexeme, variable.TypeToString(), tokens[i]); |
| | | 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"); |
| | | } |
| | | this->setVariable(varToken.lexeme, variable, this->contextPrefix, true); |
| | | i++; // Skip variable name |
| | | EXPECT_SEMICOLON(tokens, i, "after bool variable declaration"); |
| | | |
| | | } else if (i < tokens.size() && |
| | | (tokens[i].type == TokenType::Identifier || tokens[i].type == TokenType::StringLiteral)) { |
| | | std::string lowered = tokens[i].lexeme; |
| | | std::transform(lowered.begin(), lowered.end(), lowered.begin(), |
| | | [](unsigned char c) { return std::tolower(c); }); |
| | | const Token & varToken = tokens[i++]; |
| | | if (i >= tokens.size()) { |
| | | THROW_UNEXPECTED_TOKEN_ERROR(tokens[i + 1], "semicolon or assignment after variable name"); |
| | | } |
| | | |
| | | if (lowered == "true") { |
| | | auto value = Value::fromBoolean(tokens[i], true); |
| | | this->setVariable(varToken.lexeme, value, this->contextPrefix, true); |
| | | } else if (lowered == "false") { |
| | | auto value = Value::fromBoolean(tokens[i], false); |
| | | this->setVariable(varToken.lexeme, value, this->contextPrefix, true); |
| | | } else { |
| | | THROW_UNEXPECTED_TOKEN_ERROR(tokens[i], "true or false after '='"); |
| | | 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"); |
| | | } |
| | | i++; // Skip boolean literal |
| | | EXPECT_SEMICOLON(tokens, i, "after bool declaration"); |
| | | } else if (i < tokens.size() && tokens[i].type == TokenType::IntLiteral) { |
| | | const auto test = std::stoi(tokens[i].lexeme); |
| | | if (test == 0) { |
| | | auto value = Value::fromBoolean(tokens[i], false); |
| | | this->setVariable(varToken.lexeme, value, this->contextPrefix, true); |
| | | } else if (test > 0) { |
| | | auto value = Value::fromBoolean(tokens[i], false); |
| | | this->setVariable(varToken.lexeme, value, this->contextPrefix, true); |
| | | } else { |
| | | THROW_UNEXPECTED_TOKEN_ERROR(tokens[i], "bool literal after '='"); |
| | | |
| | | 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 { |
| | | THROW_UNEXPECTED_TOKEN_ERROR(tokens[i], "bool literal after '='"); |
| | | EXPECT_SEMICOLON(tokens, i, "after bool declaration"); |
| | | } |
| | | |
| | | } else { |
| | | THROW_UNEXPECTED_TOKEN_ERROR(tokens[i], "= after bool declaration"); |
| | | } |
| | | }; |
| | | |
| | | void ScriptInterpreter::handleStringDeclaration(const std::vector<Token> & tokens, std::size_t & i) { |
| | | const auto & varToken = tokens[i]; |
| | |
| | | size_t end; |
| | | ScriptInterpreterHelpers::getFunctionBody(tokens, i, start, end); |
| | | |
| | | const std::string function_body = ScriptInterpreterHelpers::extractSubstring(this->source, 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]); |
| | |
| | | #ifndef SCRIPTINTERPRETERHELPERS_HPP |
| | | #define SCRIPTINTERPRETERHELPERS_HPP |
| | | |
| | | #include <iostream> |
| | | #include <ostream> |
| | | #include <algorithm> |
| | | #include <vector> |
| | | |
| | | #include "ScriptExceptionMacros.h" |
| | |
| | | |
| | | namespace ScriptInterpreterHelpers { |
| | | |
| | | 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 expectSemicolon(const std::vector<Token> & tokens, std::size_t & i, const std::string & message, |
| | | const std::string & file = __FILE__, int line = __LINE__) { |
| | |
| | | } |
| | | }; |
| | | |
| | | |
| | | }; // namespace ScriptInterpreterHelpers |
| | | |
| | | #endif // SCRIPTINTERPRETERHELPERS_HPP |
| New file |
| | |
| | | #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 |
| | |
| | | #ifndef TOKEN_HPP |
| | | #define TOKEN_HPP |
| | | #include <cstdint> |
| | | #include <iostream> |
| | | #include <string> |
| | | #include <unordered_map> |
| | | |
| | | #include "VariableTypes.hpp" |
| | | |
| | | enum class TokenType : std::uint8_t { |
| | | namespace Tokens { |
| | | enum class Type : std::uint8_t { |
| | | ParserOpenTag, |
| | | ParserCloseTag, |
| | | ParserIfStatement, // if |
| | |
| | | Unknown // Unknown |
| | | }; |
| | | |
| | | const static std::unordered_map<TokenType, std::string> tokenTypeNames = { |
| | | { TokenType::ParserOpenTag, "ParserOpenTag" }, |
| | | { TokenType::ParserCloseTag, "ParserCloseTag" }, |
| | | { TokenType::ParserIfStatement, "ParserIfStatement" }, |
| | | { TokenType::FileClose, "FileClose" }, |
| | | { TokenType::Identifier, "Identifier" }, |
| | | { TokenType::StringLiteral, "StringLiteral" }, |
| | | { TokenType::IntLiteral, "IntLiteral" }, |
| | | { TokenType::DoubleLiteral, "DoubleLiteral" }, |
| | | { TokenType::BooleanLiteral, "BooleanLiteral" }, |
| | | { TokenType::LeftParenthesis, "LeftParenthesis" }, |
| | | { TokenType::RightParenthesis, "RightParenthesis" }, |
| | | { TokenType::Comma, "Comma" }, |
| | | { TokenType::Semicolon, "Semicolon" }, |
| | | { TokenType::Variable, "Variable" }, |
| | | { TokenType::VariableSign, "VariableSign" }, |
| | | { TokenType::StringDeclaration, "StringDeclaration" }, |
| | | { TokenType::IntDeclaration, "IntDeclaration" }, |
| | | { TokenType::DoubleDeclaration, "DoubleDeclaration" }, |
| | | { TokenType::BooleanDeclaration, "BooleanDeclaration" }, |
| | | { TokenType::FunctionDeclaration, "FunctionDeclaration" }, |
| | | { TokenType::FunctionCall, "FunctionCall" }, |
| | | { TokenType::Return, "Return" }, |
| | | { TokenType::Equals, "Equals" }, |
| | | { TokenType::Plus, "Plus" }, |
| | | { TokenType::Minus, "Minus" }, |
| | | { TokenType::Multiply, "Multiply" }, |
| | | { TokenType::Divide, "Divide" }, |
| | | { TokenType::Modulo, "Modulo" }, |
| | | { TokenType::GreaterThan, "GreaterThan" }, |
| | | { TokenType::LessThan, "LessThan" }, |
| | | { TokenType::GreaterThanOrEqual, "GreaterThanOrEqual" }, |
| | | { TokenType::LessThanOrEqual, "LessThanOrEqual" }, |
| | | { TokenType::NotEqual, "NotEqual" }, |
| | | { TokenType::Equal, "Equal" }, |
| | | { TokenType::Not, "Not" }, |
| | | { TokenType::And, "And" }, |
| | | { TokenType::Or, "Or" }, |
| | | { TokenType::LeftBracket, "LeftBracket" }, |
| | | { TokenType::RightBracket, "RightBracket" }, |
| | | { TokenType::LeftCurlyBracket, "LeftCurlyBracket" }, |
| | | { TokenType::RightCurlyBracket, "RightCurlyBracket" }, |
| | | { TokenType::EndOfFile, "EndOfFile" }, |
| | | { TokenType::EndOfLine, "EndOfLine" }, |
| | | { TokenType::Comment, "Comment" }, |
| | | { TokenType::Unknown, "Unknown" } |
| | | }; |
| | | |
| | | [[nodiscard]] static inline std::string getTokenTypeAsString(TokenType type) { |
| | | auto it = tokenTypeNames.find(type); |
| | | if (it != tokenTypeNames.end()) { |
| | | return it->second; |
| | | } |
| | | return "Unknown"; |
| | | //throw std::runtime_error("Unknown token type"); |
| | | }; |
| | | |
| | | static const std::unordered_map<TokenType, Variables::Type> tokenTypeToVariableType = { |
| | | { TokenType::StringLiteral, Variables::Type::VT_STRING }, |
| | | { TokenType::IntLiteral, Variables::Type::VT_INT }, |
| | | { TokenType::DoubleLiteral, Variables::Type::VT_DOUBLE }, |
| | | { TokenType::BooleanLiteral, Variables::Type::VT_BOOLEAN } |
| | | }; |
| | | |
| | | static const std::unordered_map<Variables::Type, TokenType> variableTypeToTokenType = { |
| | | { Variables::Type::VT_STRING, TokenType::StringLiteral }, |
| | | { Variables::Type::VT_INT, TokenType::IntLiteral }, |
| | | { Variables::Type::VT_DOUBLE, TokenType::DoubleLiteral }, |
| | | { Variables::Type::VT_BOOLEAN, TokenType::BooleanLiteral } |
| | | }; |
| | | |
| | | [[nodiscard]] static inline Variables::Type getVariableTypeFromTokenType(TokenType type) { |
| | | auto it = tokenTypeToVariableType.find(type); |
| | | if (it != tokenTypeToVariableType.end()) { |
| | | return it->second; |
| | | } |
| | | |
| | | return Variables::Type::VT_NOT_DEFINED; |
| | | } |
| | | |
| | | [[nodiscard]] static inline std::string getVariableTypeFromTokenTypeAsString(TokenType type) { |
| | | return Variables::TypeToString(getVariableTypeFromTokenType(type)); |
| | | } |
| | | |
| | | [[nodiscard]] static inline TokenType getTokenTypeFromVariableType(Variables::Type type) { |
| | | auto it = variableTypeToTokenType.find(type); |
| | | if (it != variableTypeToTokenType.end()) { |
| | | return it->second; |
| | | } |
| | | return TokenType::Unknown; |
| | | }; |
| | | |
| | | [[nodiscard]] static inline TokenType getTokenTypeFromValueDeclaration(const Variables::Type & declaration) { |
| | | if (declaration == Variables::Type::VT_STRING) { |
| | | return TokenType::StringDeclaration; |
| | | } |
| | | if (declaration == Variables::Type::VT_INT) { |
| | | return TokenType::IntDeclaration; |
| | | } |
| | | if (declaration == Variables::Type::VT_DOUBLE) { |
| | | return TokenType::DoubleDeclaration; |
| | | } |
| | | if (declaration == Variables::Type::VT_BOOLEAN) { |
| | | return TokenType::BooleanDeclaration; |
| | | } |
| | | // if (declaration == Variables::Type::VT_FUNCTION) { |
| | | // return TokenType::FunctionDeclaration; |
| | | // } |
| | | std::cout << "Unknown variable type: " << Variables::TypeToString(declaration) << "\n"; |
| | | return TokenType::Unknown; |
| | | } |
| | | |
| | | [[nodiscard]] static inline Variables::Type getVariableTypeFromTokenTypeDeclaration(const TokenType & type) { |
| | | if (type == TokenType::StringDeclaration) { |
| | | return Variables::Type::VT_STRING; |
| | | } |
| | | if (type == TokenType::IntDeclaration) { |
| | | return Variables::Type::VT_INT; |
| | | } |
| | | if (type == TokenType::DoubleDeclaration) { |
| | | return Variables::Type::VT_DOUBLE; |
| | | } |
| | | if (type == TokenType::BooleanDeclaration) { |
| | | return Variables::Type::VT_BOOLEAN; |
| | | } |
| | | //if (type == TokenType::FunctionDeclaration) { |
| | | // return Variables::Type::VT_FUNCTION; |
| | | //} |
| | | return Variables::Type::VT_NULL; |
| | | 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 { |
| | |
| | | }; |
| | | |
| | | struct Token { |
| | | TokenType type; |
| | | Tokens::Type type; |
| | | std::string lexeme; |
| | | std::string file; |
| | | int lineNumber; |
| | | size_t columnNumber; |
| | | TokenPos pos; |
| | | Variables::Type variableType = Variables::Type::VT_NULL; |
| | | |
| | | [[nodiscard]] std::string getTypeName() const { return tokenTypeNames.at(type); } |
| | | |
| | | [[nodiscard]] std::string getVariableTypeName() const { return Variables::TypeToString(variableType); } |
| | | [[nodiscard]] std::string getTokenName() const { return tokenTypeNames.at(type); } |
| | | }; |
| | | |
| | | } // namespace Tokens |
| | | #endif // TOKEN_HPP |