From 03c17b3574250eb12a024b42f50912b489bdce30 Mon Sep 17 00:00:00 2001 From: marcelnoehre Date: Sun, 1 Dec 2024 15:16:14 +0100 Subject: [PATCH 01/10] store arrays --- include/interpreter/storage.hpp | 15 ++++++++++++++- .../expressions/literal_expression.cpp | 8 ++++++++ src/interpreter/storage.cpp | 1 + 3 files changed, 23 insertions(+), 1 deletion(-) diff --git a/include/interpreter/storage.hpp b/include/interpreter/storage.hpp index 9895fe2..03ad321 100644 --- a/include/interpreter/storage.hpp +++ b/include/interpreter/storage.hpp @@ -11,7 +11,18 @@ class Storage { public: enum class WrapperType { VALUE, VARIABLE, CONSTANT }; - enum DataType { INTEGER, DOUBLE, BOOLEAN, CHAR, STRING, HEXCODE, _NULL }; + enum DataType { + INTEGER, + DOUBLE, + BOOLEAN, + CHAR, + STRING, + HEXCODE, + ARRAY, + _NULL + }; + + struct DataWrapper; union Data { int _int; @@ -19,6 +30,7 @@ class Storage { bool _bool; char _char; std::string *_string; + std::vector *_array; Data(); Data(int value); @@ -26,6 +38,7 @@ class Storage { Data(bool value); Data(char value); Data(std::string *value); + Data(std::vector *value); ~Data(); }; diff --git a/src/interpreter/expressions/literal_expression.cpp b/src/interpreter/expressions/literal_expression.cpp index dbc3193..beb5fb7 100644 --- a/src/interpreter/expressions/literal_expression.cpp +++ b/src/interpreter/expressions/literal_expression.cpp @@ -11,6 +11,14 @@ Storage::DataWrapper LiteralExpression::execute() { throw std::logic_error("Variable not declared."); } return storage[keyIndex]->getEntry(expr->identifier.value); + } else if (auto expr = dynamic_cast(expressionNode)) { + std::vector elements; + for (const auto &element : expr->elements) { + elements.push_back(Expression(element.get(), storage).execute()); + } + return Storage::DataWrapper( + Storage::WrapperType::VALUE, Storage::DataType::ARRAY, + new std::vector(elements)); } else if (auto expr = dynamic_cast(expressionNode)) { return Storage::DataWrapper(Storage::WrapperType::VALUE, Storage::DataType::INTEGER, expr->value); diff --git a/src/interpreter/storage.cpp b/src/interpreter/storage.cpp index 733dec9..6979ef7 100644 --- a/src/interpreter/storage.cpp +++ b/src/interpreter/storage.cpp @@ -6,6 +6,7 @@ Storage::Data::Data(double value) : _double(value) {} Storage::Data::Data(bool value) : _bool(value) {} Storage::Data::Data(char value) : _char(value) {} Storage::Data::Data(std::string *value) : _string(value) {} +Storage::Data::Data(std::vector *value) : _array(value) {} Storage::Data::~Data() {} Storage::DataWrapper::DataWrapper() From 02bc2646ccf8267ccb4f1a60a54ac23e26894a60 Mon Sep 17 00:00:00 2001 From: marcelnoehre Date: Sun, 1 Dec 2024 15:16:19 +0100 Subject: [PATCH 02/10] log arrays --- .../interpreter/statements/log_statement.hpp | 2 +- src/interpreter/statements/log_statement.cpp | 62 +++++++++++-------- 2 files changed, 36 insertions(+), 28 deletions(-) diff --git a/include/interpreter/statements/log_statement.hpp b/include/interpreter/statements/log_statement.hpp index 080e490..73e95f1 100644 --- a/include/interpreter/statements/log_statement.hpp +++ b/include/interpreter/statements/log_statement.hpp @@ -13,7 +13,7 @@ class LogStatement { private: LogStmt *logNode; std::vector> storage; - std::string getPrintableValue(); + std::string getPrintableValue(Storage::DataWrapper value); void hexToRGB(const std::string &hex, int &r, int &g, int &b); }; diff --git a/src/interpreter/statements/log_statement.cpp b/src/interpreter/statements/log_statement.cpp index 73edf07..eb53d48 100644 --- a/src/interpreter/statements/log_statement.cpp +++ b/src/interpreter/statements/log_statement.cpp @@ -8,10 +8,17 @@ void LogStatement::execute() { if (logNode->logType.tag != Token::TypeTag::LOG) { throw std::logic_error("Expected log token."); } + if (!logNode->message) { + return; + } + + std::string printableValue = getPrintableValue( + Expression(dynamic_cast(logNode->message.get()), storage) + .execute()); switch (logNode->logType.type.logToken) { case LogToken::BASIC: - std::cout << getPrintableValue() << std::endl; + std::cout << printableValue << std::endl; break; case LogToken::COLORED: @@ -19,18 +26,18 @@ void LogStatement::execute() { if (auto *hexCode = dynamic_cast(logNode->color.get())) { hexToRGB(hexCode->value, r, g, b); std::cout << "\033[38;2;" << r << ";" << g << ";" << b << "m" - << getPrintableValue() << "\033[0m" << std::endl; + << printableValue << "\033[0m" << std::endl; } else { throw std::invalid_argument("Expected hex code for colored log message."); } break; case LogToken::WARN: - std::cout << "\033[33m" << getPrintableValue() << "\033[0m" << std::endl; + std::cout << "\033[33m" << printableValue << "\033[0m" << std::endl; break; case LogToken::ERROR: - std::cout << "\033[31m" << getPrintableValue() << "\033[0m" << std::endl; + std::cout << "\033[31m" << printableValue << "\033[0m" << std::endl; break; default: @@ -38,30 +45,31 @@ void LogStatement::execute() { } } -std::string LogStatement::getPrintableValue() { - if (logNode->message) { - Storage::DataWrapper value = - Expression(dynamic_cast(logNode->message.get()), storage) - .execute(); - switch (value.dataType) { - case Storage::DataType::INTEGER: - return std::to_string(value.data._int); - case Storage::DataType::DOUBLE: - return std::to_string(value.data._double); - case Storage::DataType::BOOLEAN: - return value.data._bool ? "true" : "false"; - case Storage::DataType::CHAR: - return std::string(1, value.data._char); - case Storage::DataType::STRING: - case Storage::DataType::HEXCODE: - return *(value.data._string); - case Storage::DataType::_NULL: - return "null"; - default: - throw std::invalid_argument("Unknown data type!"); +std::string LogStatement::getPrintableValue(Storage::DataWrapper value) { + std::string result = ""; + switch (value.dataType) { + case Storage::DataType::INTEGER: + return std::to_string(value.data._int); + case Storage::DataType::DOUBLE: + return std::to_string(value.data._double); + case Storage::DataType::BOOLEAN: + return value.data._bool ? "true" : "false"; + case Storage::DataType::CHAR: + return std::string(1, value.data._char); + case Storage::DataType::STRING: + case Storage::DataType::HEXCODE: + return *(value.data._string); + case Storage::DataType::ARRAY: + result = "["; + for (const auto &element : *(value.data._array)) { + result += getPrintableValue(element) + + (&element != &value.data._array->back() ? ", " : ""); } - } else { - throw std::invalid_argument("No log message provided."); + return result + "]"; + case Storage::DataType::_NULL: + return "null"; + default: + throw std::invalid_argument("Unknown data type!"); } } From d5eab40b29cd3388e960b4da3abff61136f1bae1 Mon Sep 17 00:00:00 2001 From: marcelnoehre Date: Tue, 3 Dec 2024 17:28:34 +0100 Subject: [PATCH 03/10] store object literals --- include/interpreter/storage.hpp | 3 +++ src/interpreter/expressions/literal_expression.cpp | 8 ++++++++ src/interpreter/storage.cpp | 1 + 3 files changed, 12 insertions(+) diff --git a/include/interpreter/storage.hpp b/include/interpreter/storage.hpp index 03ad321..044a1b7 100644 --- a/include/interpreter/storage.hpp +++ b/include/interpreter/storage.hpp @@ -19,6 +19,7 @@ class Storage { STRING, HEXCODE, ARRAY, + OBJECT, _NULL }; @@ -31,6 +32,7 @@ class Storage { char _char; std::string *_string; std::vector *_array; + std::unordered_map *_object; Data(); Data(int value); @@ -39,6 +41,7 @@ class Storage { Data(char value); Data(std::string *value); Data(std::vector *value); + Data(std::unordered_map *value); ~Data(); }; diff --git a/src/interpreter/expressions/literal_expression.cpp b/src/interpreter/expressions/literal_expression.cpp index beb5fb7..b6fe87a 100644 --- a/src/interpreter/expressions/literal_expression.cpp +++ b/src/interpreter/expressions/literal_expression.cpp @@ -19,6 +19,14 @@ Storage::DataWrapper LiteralExpression::execute() { return Storage::DataWrapper( Storage::WrapperType::VALUE, Storage::DataType::ARRAY, new std::vector(elements)); + } else if (auto expr = dynamic_cast (expressionNode)) { + std::unordered_map elements; + for (const auto &property : expr->properties) { + elements[property.get()->key.value] = Expression(property.get()->value.get(), storage).execute(); + } + return Storage::DataWrapper( + Storage::WrapperType::VALUE, Storage::DataType::OBJECT, + new std::unordered_map(elements)); } else if (auto expr = dynamic_cast(expressionNode)) { return Storage::DataWrapper(Storage::WrapperType::VALUE, Storage::DataType::INTEGER, expr->value); diff --git a/src/interpreter/storage.cpp b/src/interpreter/storage.cpp index 6979ef7..809afae 100644 --- a/src/interpreter/storage.cpp +++ b/src/interpreter/storage.cpp @@ -7,6 +7,7 @@ Storage::Data::Data(bool value) : _bool(value) {} Storage::Data::Data(char value) : _char(value) {} Storage::Data::Data(std::string *value) : _string(value) {} Storage::Data::Data(std::vector *value) : _array(value) {} +Storage::Data::Data(std::unordered_map *value) : _object(value) {} Storage::Data::~Data() {} Storage::DataWrapper::DataWrapper() From abc9dd24d0da1e65f43fb00eab4599de073ec6bb Mon Sep 17 00:00:00 2001 From: marcelnoehre Date: Tue, 3 Dec 2024 17:37:31 +0100 Subject: [PATCH 04/10] log object literals --- src/interpreter/statements/log_statement.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/interpreter/statements/log_statement.cpp b/src/interpreter/statements/log_statement.cpp index eb53d48..d292afa 100644 --- a/src/interpreter/statements/log_statement.cpp +++ b/src/interpreter/statements/log_statement.cpp @@ -66,6 +66,13 @@ std::string LogStatement::getPrintableValue(Storage::DataWrapper value) { (&element != &value.data._array->back() ? ", " : ""); } return result + "]"; + case Storage::DataType::OBJECT: + result = "{"; + for (auto it = value.data._object->begin(); it != value.data._object->end(); ++it) { + result += it->first + ": " + getPrintableValue(it->second) + + (std::next(it) != value.data._object->end() ? ", " : ""); + } + return result + "}"; case Storage::DataType::_NULL: return "null"; default: From df0d0d8fc9bb6b002413a49a4c0f9df88f676667 Mon Sep 17 00:00:00 2001 From: marcelnoehre Date: Tue, 3 Dec 2024 17:44:21 +0100 Subject: [PATCH 05/10] remove chained storage instances after usage --- src/interpreter/statements/conditional_statement.cpp | 1 + src/interpreter/statements/loop_statement.cpp | 11 +++++++---- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/interpreter/statements/conditional_statement.cpp b/src/interpreter/statements/conditional_statement.cpp index 5bd7368..c6ff159 100644 --- a/src/interpreter/statements/conditional_statement.cpp +++ b/src/interpreter/statements/conditional_statement.cpp @@ -29,4 +29,5 @@ void ConditionalStatement::execute() { Statement(stmt.get(), storage).execute(); } } + storage.pop_back(); } diff --git a/src/interpreter/statements/loop_statement.cpp b/src/interpreter/statements/loop_statement.cpp index 7905b5f..2c9f7b2 100644 --- a/src/interpreter/statements/loop_statement.cpp +++ b/src/interpreter/statements/loop_statement.cpp @@ -36,21 +36,23 @@ void LoopStatement::execute() { void LoopStatement::executeWhileLoop() { auto whileLoop = std::get(loopNode); - storage.push_back(std::make_shared()); while (checkTrueishness(whileLoop->condition, storage)) { + storage.push_back(std::make_shared()); for (const auto &stmt : whileLoop->body) { Statement(stmt.get(), storage).execute(); } + storage.pop_back(); } } void LoopStatement::executeDoWhileLoop() { auto doWhileLoop = std::get(loopNode); - storage.push_back(std::make_shared()); do { + storage.push_back(std::make_shared()); for (const auto &stmt : doWhileLoop->body) { Statement(stmt.get(), storage).execute(); } + storage.pop_back(); } while (checkTrueishness(doWhileLoop->condition, storage)); } @@ -60,21 +62,22 @@ void LoopStatement::executeForLoop() { forLoop->iterator ? Statement(forLoop->iterator.get(), storage).execute() : void(); while (checkTrueishness(forLoop->condition, storage)) { + storage.push_back(std::make_shared()); for (const auto &stmt : forLoop->body) { Statement(stmt.get(), storage).execute(); } if (forLoop->increment) { Statement(forLoop->increment.get(), storage).execute(); } + storage.pop_back(); } + storage.pop_back(); } void LoopStatement::executeForInLoop() { auto forInLoop = std::get(loopNode); - storage.push_back(std::make_shared()); } void LoopStatement::executeForOfLoop() { auto forOfLoop = std::get(loopNode); - storage.push_back(std::make_shared()); } From cfee2765ee48fb8fc95b4e739c3fc43e97c90c1c Mon Sep 17 00:00:00 2001 From: marcelnoehre Date: Tue, 3 Dec 2024 17:53:33 +0100 Subject: [PATCH 06/10] apply clang format --- include/interpreter/statements/loop_statement.hpp | 2 +- src/interpreter/expressions/literal_expression.cpp | 5 +++-- src/interpreter/statements/log_statement.cpp | 3 ++- src/interpreter/statements/loop_statement.cpp | 8 ++++---- src/interpreter/storage.cpp | 3 ++- 5 files changed, 12 insertions(+), 9 deletions(-) diff --git a/include/interpreter/statements/loop_statement.hpp b/include/interpreter/statements/loop_statement.hpp index 08d30d8..fbb5fd3 100644 --- a/include/interpreter/statements/loop_statement.hpp +++ b/include/interpreter/statements/loop_statement.hpp @@ -31,8 +31,8 @@ class LoopStatement { void executeWhileLoop(); void executeDoWhileLoop(); void executeForLoop(); - void executeForInLoop(); void executeForOfLoop(); + void executeForInLoop(); }; #endif // LOOP_STATEMENT_HPP \ No newline at end of file diff --git a/src/interpreter/expressions/literal_expression.cpp b/src/interpreter/expressions/literal_expression.cpp index b6fe87a..7fe270b 100644 --- a/src/interpreter/expressions/literal_expression.cpp +++ b/src/interpreter/expressions/literal_expression.cpp @@ -19,10 +19,11 @@ Storage::DataWrapper LiteralExpression::execute() { return Storage::DataWrapper( Storage::WrapperType::VALUE, Storage::DataType::ARRAY, new std::vector(elements)); - } else if (auto expr = dynamic_cast (expressionNode)) { + } else if (auto expr = dynamic_cast(expressionNode)) { std::unordered_map elements; for (const auto &property : expr->properties) { - elements[property.get()->key.value] = Expression(property.get()->value.get(), storage).execute(); + elements[property.get()->key.value] = + Expression(property.get()->value.get(), storage).execute(); } return Storage::DataWrapper( Storage::WrapperType::VALUE, Storage::DataType::OBJECT, diff --git a/src/interpreter/statements/log_statement.cpp b/src/interpreter/statements/log_statement.cpp index d292afa..969677a 100644 --- a/src/interpreter/statements/log_statement.cpp +++ b/src/interpreter/statements/log_statement.cpp @@ -68,7 +68,8 @@ std::string LogStatement::getPrintableValue(Storage::DataWrapper value) { return result + "]"; case Storage::DataType::OBJECT: result = "{"; - for (auto it = value.data._object->begin(); it != value.data._object->end(); ++it) { + for (auto it = value.data._object->begin(); it != value.data._object->end(); + ++it) { result += it->first + ": " + getPrintableValue(it->second) + (std::next(it) != value.data._object->end() ? ", " : ""); } diff --git a/src/interpreter/statements/loop_statement.cpp b/src/interpreter/statements/loop_statement.cpp index 2c9f7b2..ebe86b6 100644 --- a/src/interpreter/statements/loop_statement.cpp +++ b/src/interpreter/statements/loop_statement.cpp @@ -74,10 +74,10 @@ void LoopStatement::executeForLoop() { storage.pop_back(); } -void LoopStatement::executeForInLoop() { - auto forInLoop = std::get(loopNode); -} - void LoopStatement::executeForOfLoop() { auto forOfLoop = std::get(loopNode); } + +void LoopStatement::executeForInLoop() { + auto forInLoop = std::get(loopNode); +} diff --git a/src/interpreter/storage.cpp b/src/interpreter/storage.cpp index 809afae..6ce9f52 100644 --- a/src/interpreter/storage.cpp +++ b/src/interpreter/storage.cpp @@ -7,7 +7,8 @@ Storage::Data::Data(bool value) : _bool(value) {} Storage::Data::Data(char value) : _char(value) {} Storage::Data::Data(std::string *value) : _string(value) {} Storage::Data::Data(std::vector *value) : _array(value) {} -Storage::Data::Data(std::unordered_map *value) : _object(value) {} +Storage::Data::Data(std::unordered_map *value) + : _object(value) {} Storage::Data::~Data() {} Storage::DataWrapper::DataWrapper() From 1002d5774e06676061308b909eab2ee332b04d33 Mon Sep 17 00:00:00 2001 From: marcelnoehre Date: Tue, 3 Dec 2024 19:00:44 +0100 Subject: [PATCH 07/10] for of loop --- include/interpreter/storage.hpp | 1 + .../statements/declaration_statement.cpp | 17 +++++++++-------- src/interpreter/statements/loop_statement.cpp | 16 ++++++++++++++++ src/interpreter/storage.cpp | 7 +++++++ 4 files changed, 33 insertions(+), 8 deletions(-) diff --git a/include/interpreter/storage.hpp b/include/interpreter/storage.hpp index 044a1b7..611179e 100644 --- a/include/interpreter/storage.hpp +++ b/include/interpreter/storage.hpp @@ -66,6 +66,7 @@ class Storage { bool exists(const std::string &name) const; bool functionExists(const std::string &name) const; DataWrapper &getEntry(const std::string &name); + std::string getSingleKey(); void storeFunction(const std::string &name, std::shared_ptr function); diff --git a/src/interpreter/statements/declaration_statement.cpp b/src/interpreter/statements/declaration_statement.cpp index e2e4543..52f4fc9 100644 --- a/src/interpreter/statements/declaration_statement.cpp +++ b/src/interpreter/statements/declaration_statement.cpp @@ -21,15 +21,16 @@ void DeclarationStatement::execute() { void DeclarationStatement::executeVarDeclaration() { auto varDeclaration = std::get(declarationNode); for (const auto &declaration : varDeclaration->declarations) { - if (declaration.second) { - if (storageKeyIndex(storage, declaration.first.value) != -1) { - throw std::logic_error("Variable already declared."); - } - storage.back()->setValue( - declaration.first.value, - Expression(static_cast(declaration.second.get()), storage) - .execute()); + if (storageKeyIndex(storage, declaration.first.value) != -1) { + throw std::logic_error("Variable already declared."); } + Storage::DataWrapper value = + declaration.second == nullptr + ? Storage::DataWrapper(Storage::WrapperType::VALUE, + Storage::DataType::_NULL, 0) + : Expression(static_cast(declaration.second.get()), storage) + .execute(); + storage.back()->setValue(declaration.first.value, value); } } diff --git a/src/interpreter/statements/loop_statement.cpp b/src/interpreter/statements/loop_statement.cpp index ebe86b6..cb31fe2 100644 --- a/src/interpreter/statements/loop_statement.cpp +++ b/src/interpreter/statements/loop_statement.cpp @@ -76,6 +76,22 @@ void LoopStatement::executeForLoop() { void LoopStatement::executeForOfLoop() { auto forOfLoop = std::get(loopNode); + storage.push_back(std::make_shared()); + Statement(forOfLoop->iterator.get(), storage).execute(); + Storage::DataWrapper iterable = + Expression(forOfLoop->iterable.get(), storage).execute(); + if (iterable.dataType != Storage::DataType::ARRAY) { + throw std::runtime_error("Iterable is not an array!"); + } + std::string key = storage.back()->getSingleKey(); + for (const auto &data : *iterable.data._array) { + storage.back()->updateValue(key, data); + storage.push_back(std::make_shared()); + for (const auto &stmt : forOfLoop->body) { + Statement(stmt.get(), storage).execute(); + } + storage.pop_back(); + } } void LoopStatement::executeForInLoop() { diff --git a/src/interpreter/storage.cpp b/src/interpreter/storage.cpp index 6ce9f52..8c821f8 100644 --- a/src/interpreter/storage.cpp +++ b/src/interpreter/storage.cpp @@ -108,6 +108,13 @@ Storage::DataWrapper &Storage::getEntry(const std::string &name) { throw std::invalid_argument("Undefined identifier: " + name); } +std::string Storage::getSingleKey() { + if (storage.size() == 1) { + return storage.begin()->first; + } + throw std::invalid_argument("Expected a single identifier!"); +} + void Storage::storeFunction(const std::string &name, std::shared_ptr function) { if (functions.find(name) != functions.end()) { From 03774eb314913dd9576a052c3dbaa18674bd70d9 Mon Sep 17 00:00:00 2001 From: marcelnoehre Date: Tue, 3 Dec 2024 19:29:09 +0100 Subject: [PATCH 08/10] for in loop --- .../statements/declaration_statement.hpp | 3 ++- include/interpreter/storage.hpp | 1 - .../statements/declaration_statement.cpp | 9 +++++++- src/interpreter/statements/loop_statement.cpp | 23 ++++++++++++++++--- src/interpreter/storage.cpp | 7 ------ 5 files changed, 30 insertions(+), 13 deletions(-) diff --git a/include/interpreter/statements/declaration_statement.hpp b/include/interpreter/statements/declaration_statement.hpp index 33a68f6..c533173 100644 --- a/include/interpreter/statements/declaration_statement.hpp +++ b/include/interpreter/statements/declaration_statement.hpp @@ -14,12 +14,13 @@ class DeclarationStatement { DeclarationStatement(VarDeclaration *declarationNode, std::vector> storage); void execute(); + std::vector declareLoopVariables(); private: std::variant declarationNode; std::vector> storage; - void executeVarDeclaration(); + std::vector executeVarDeclaration(); void executeFunctionDeclaration(); }; diff --git a/include/interpreter/storage.hpp b/include/interpreter/storage.hpp index 611179e..044a1b7 100644 --- a/include/interpreter/storage.hpp +++ b/include/interpreter/storage.hpp @@ -66,7 +66,6 @@ class Storage { bool exists(const std::string &name) const; bool functionExists(const std::string &name) const; DataWrapper &getEntry(const std::string &name); - std::string getSingleKey(); void storeFunction(const std::string &name, std::shared_ptr function); diff --git a/src/interpreter/statements/declaration_statement.cpp b/src/interpreter/statements/declaration_statement.cpp index 52f4fc9..8b34919 100644 --- a/src/interpreter/statements/declaration_statement.cpp +++ b/src/interpreter/statements/declaration_statement.cpp @@ -18,8 +18,13 @@ void DeclarationStatement::execute() { } } -void DeclarationStatement::executeVarDeclaration() { +std::vector DeclarationStatement::declareLoopVariables() { + return executeVarDeclaration(); +} + +std::vector DeclarationStatement::executeVarDeclaration() { auto varDeclaration = std::get(declarationNode); + std::vector declaredVariables = {}; for (const auto &declaration : varDeclaration->declarations) { if (storageKeyIndex(storage, declaration.first.value) != -1) { throw std::logic_error("Variable already declared."); @@ -31,7 +36,9 @@ void DeclarationStatement::executeVarDeclaration() { : Expression(static_cast(declaration.second.get()), storage) .execute(); storage.back()->setValue(declaration.first.value, value); + declaredVariables.push_back(declaration.first.value); } + return declaredVariables; } void DeclarationStatement::executeFunctionDeclaration() { diff --git a/src/interpreter/statements/loop_statement.cpp b/src/interpreter/statements/loop_statement.cpp index cb31fe2..d02d213 100644 --- a/src/interpreter/statements/loop_statement.cpp +++ b/src/interpreter/statements/loop_statement.cpp @@ -77,15 +77,14 @@ void LoopStatement::executeForLoop() { void LoopStatement::executeForOfLoop() { auto forOfLoop = std::get(loopNode); storage.push_back(std::make_shared()); - Statement(forOfLoop->iterator.get(), storage).execute(); + std::vector keys = DeclarationStatement(dynamic_cast(forOfLoop->iterator.get()), storage).declareLoopVariables(); Storage::DataWrapper iterable = Expression(forOfLoop->iterable.get(), storage).execute(); if (iterable.dataType != Storage::DataType::ARRAY) { throw std::runtime_error("Iterable is not an array!"); } - std::string key = storage.back()->getSingleKey(); for (const auto &data : *iterable.data._array) { - storage.back()->updateValue(key, data); + storage.back()->updateValue(keys.front(), data); storage.push_back(std::make_shared()); for (const auto &stmt : forOfLoop->body) { Statement(stmt.get(), storage).execute(); @@ -96,4 +95,22 @@ void LoopStatement::executeForOfLoop() { void LoopStatement::executeForInLoop() { auto forInLoop = std::get(loopNode); + storage.push_back(std::make_shared()); + std::vector keys = DeclarationStatement(dynamic_cast(forInLoop->iterator.get()), storage).declareLoopVariables(); + Storage::DataWrapper iterable = + Expression(forInLoop->iterable.get(), storage).execute(); + if (iterable.dataType != Storage::DataType::OBJECT) { + throw std::runtime_error("Iterable is not an object!"); + } + for (const auto &data : *iterable.data._object) { + storage.back()->updateValue(keys.front(), Storage::DataWrapper(Storage::WrapperType::VALUE, Storage::DataType::STRING, new std::string(data.first))); + if (keys.size() > 1) { + storage.back()->updateValue(keys.at(1), data.second); + } + storage.push_back(std::make_shared()); + for (const auto &stmt : forInLoop->body) { + Statement(stmt.get(), storage).execute(); + } + storage.pop_back(); + } } diff --git a/src/interpreter/storage.cpp b/src/interpreter/storage.cpp index 8c821f8..6ce9f52 100644 --- a/src/interpreter/storage.cpp +++ b/src/interpreter/storage.cpp @@ -108,13 +108,6 @@ Storage::DataWrapper &Storage::getEntry(const std::string &name) { throw std::invalid_argument("Undefined identifier: " + name); } -std::string Storage::getSingleKey() { - if (storage.size() == 1) { - return storage.begin()->first; - } - throw std::invalid_argument("Expected a single identifier!"); -} - void Storage::storeFunction(const std::string &name, std::shared_ptr function) { if (functions.find(name) != functions.end()) { From 682282e41061d004af31853090f7bb3188492975 Mon Sep 17 00:00:00 2001 From: marcelnoehre Date: Tue, 3 Dec 2024 19:33:01 +0100 Subject: [PATCH 09/10] track objects property order --- include/interpreter/storage.hpp | 5 +++-- src/interpreter/expressions/literal_expression.cpp | 4 ++-- src/interpreter/storage.cpp | 3 +-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/include/interpreter/storage.hpp b/include/interpreter/storage.hpp index 044a1b7..1110ee0 100644 --- a/include/interpreter/storage.hpp +++ b/include/interpreter/storage.hpp @@ -7,6 +7,7 @@ #include #include #include +#include class Storage { public: @@ -32,7 +33,7 @@ class Storage { char _char; std::string *_string; std::vector *_array; - std::unordered_map *_object; + std::map *_object; Data(); Data(int value); @@ -41,7 +42,7 @@ class Storage { Data(char value); Data(std::string *value); Data(std::vector *value); - Data(std::unordered_map *value); + Data(std::map *value); ~Data(); }; diff --git a/src/interpreter/expressions/literal_expression.cpp b/src/interpreter/expressions/literal_expression.cpp index 7fe270b..0cb4454 100644 --- a/src/interpreter/expressions/literal_expression.cpp +++ b/src/interpreter/expressions/literal_expression.cpp @@ -20,14 +20,14 @@ Storage::DataWrapper LiteralExpression::execute() { Storage::WrapperType::VALUE, Storage::DataType::ARRAY, new std::vector(elements)); } else if (auto expr = dynamic_cast(expressionNode)) { - std::unordered_map elements; + std::map elements; for (const auto &property : expr->properties) { elements[property.get()->key.value] = Expression(property.get()->value.get(), storage).execute(); } return Storage::DataWrapper( Storage::WrapperType::VALUE, Storage::DataType::OBJECT, - new std::unordered_map(elements)); + new std::map(elements)); } else if (auto expr = dynamic_cast(expressionNode)) { return Storage::DataWrapper(Storage::WrapperType::VALUE, Storage::DataType::INTEGER, expr->value); diff --git a/src/interpreter/storage.cpp b/src/interpreter/storage.cpp index 6ce9f52..51873d0 100644 --- a/src/interpreter/storage.cpp +++ b/src/interpreter/storage.cpp @@ -7,8 +7,7 @@ Storage::Data::Data(bool value) : _bool(value) {} Storage::Data::Data(char value) : _char(value) {} Storage::Data::Data(std::string *value) : _string(value) {} Storage::Data::Data(std::vector *value) : _array(value) {} -Storage::Data::Data(std::unordered_map *value) - : _object(value) {} +Storage::Data::Data(std::map *value) : _object(value) {} Storage::Data::~Data() {} Storage::DataWrapper::DataWrapper() From 6677a5a9a140c512a3620c1a5bc17f4c638eb1b2 Mon Sep 17 00:00:00 2001 From: marcelnoehre Date: Wed, 4 Dec 2024 12:20:34 +0100 Subject: [PATCH 10/10] member expressions --- .../interpreter/expressions/expression.hpp | 1 + .../expressions/member_expression.hpp | 19 ++++++++++ include/interpreter/storage.hpp | 2 +- src/interpreter/expressions/expression.cpp | 3 ++ .../expressions/member_expression.cpp | 35 +++++++++++++++++++ src/interpreter/statements/loop_statement.cpp | 15 ++++++-- src/interpreter/storage.cpp | 3 +- 7 files changed, 73 insertions(+), 5 deletions(-) create mode 100644 include/interpreter/expressions/member_expression.hpp create mode 100644 src/interpreter/expressions/member_expression.cpp diff --git a/include/interpreter/expressions/expression.hpp b/include/interpreter/expressions/expression.hpp index 6f5e31c..e6ce1a8 100644 --- a/include/interpreter/expressions/expression.hpp +++ b/include/interpreter/expressions/expression.hpp @@ -7,6 +7,7 @@ #include "interpreter/expressions/assignment_expression.hpp" #include "interpreter/expressions/binary_expression.hpp" #include "interpreter/expressions/literal_expression.hpp" +#include "interpreter/expressions/member_expression.hpp" #include "interpreter/expressions/unary_expression.hpp" class Expression { diff --git a/include/interpreter/expressions/member_expression.hpp b/include/interpreter/expressions/member_expression.hpp new file mode 100644 index 0000000..aaed7df --- /dev/null +++ b/include/interpreter/expressions/member_expression.hpp @@ -0,0 +1,19 @@ +#ifndef MEMBER_EXPRESSION_HPP +#define MEMBER_EXPRESSION_HPP + +#include "interpreter/expressions/expression.hpp" +#include "interpreter/storage.hpp" +#include "parser/ast_nodes.hpp" + +class MemberExpression { +public: + MemberExpression(MemberExpr *expressionNode, + std::vector> storage); + Storage::DataWrapper execute(); + +private: + MemberExpr *expressionNode; + std::vector> storage; +}; + +#endif // MEMBER_EXPRESSION_HPP \ No newline at end of file diff --git a/include/interpreter/storage.hpp b/include/interpreter/storage.hpp index 1110ee0..774ab88 100644 --- a/include/interpreter/storage.hpp +++ b/include/interpreter/storage.hpp @@ -3,11 +3,11 @@ #include "parser/ast_nodes.hpp" #include +#include #include #include #include #include -#include class Storage { public: diff --git a/src/interpreter/expressions/expression.cpp b/src/interpreter/expressions/expression.cpp index 291712d..5584be9 100644 --- a/src/interpreter/expressions/expression.cpp +++ b/src/interpreter/expressions/expression.cpp @@ -17,6 +17,9 @@ Storage::DataWrapper Expression::execute() { case NodeType::UnaryExpr: return UnaryExpression(dynamic_cast(exprNode), storage) .execute(); + case NodeType::MemberExpr: + return MemberExpression(dynamic_cast(exprNode), storage) + .execute(); default: return LiteralExpression(exprNode, storage).execute(); } diff --git a/src/interpreter/expressions/member_expression.cpp b/src/interpreter/expressions/member_expression.cpp new file mode 100644 index 0000000..1457b35 --- /dev/null +++ b/src/interpreter/expressions/member_expression.cpp @@ -0,0 +1,35 @@ +#include "interpreter/expressions/member_expression.hpp" + +MemberExpression::MemberExpression( + MemberExpr *expressionNode, std::vector> storage) + : expressionNode(expressionNode), storage(std::move(storage)) {} + +Storage::DataWrapper MemberExpression::execute() { + Storage::DataWrapper object = + Expression(dynamic_cast(expressionNode->object.get()), storage) + .execute(); + if (object.dataType != Storage::DataType::OBJECT) { + throw std::logic_error("Object expected!"); + } + std::string property = ""; + if (expressionNode->computed) { + Storage::DataWrapper propertyStr = + Expression(dynamic_cast(expressionNode->property.get()), + storage) + .execute(); + if (propertyStr.dataType != Storage::DataType::STRING) { + throw std::logic_error("Property name must be a string!"); + } + property = *propertyStr.data._string; + } else { + if (expressionNode->property->kind != NodeType::Identifier) { + throw std::logic_error("Property name must be an identifier!"); + } + property = dynamic_cast(expressionNode->property.get()) + ->identifier.value; + } + if (object.data._object->find(property) == object.data._object->end()) { + throw std::logic_error("Property not found!"); + } + return object.data._object->at(property); +} \ No newline at end of file diff --git a/src/interpreter/statements/loop_statement.cpp b/src/interpreter/statements/loop_statement.cpp index d02d213..d54c5d6 100644 --- a/src/interpreter/statements/loop_statement.cpp +++ b/src/interpreter/statements/loop_statement.cpp @@ -77,7 +77,10 @@ void LoopStatement::executeForLoop() { void LoopStatement::executeForOfLoop() { auto forOfLoop = std::get(loopNode); storage.push_back(std::make_shared()); - std::vector keys = DeclarationStatement(dynamic_cast(forOfLoop->iterator.get()), storage).declareLoopVariables(); + std::vector keys = + DeclarationStatement( + dynamic_cast(forOfLoop->iterator.get()), storage) + .declareLoopVariables(); Storage::DataWrapper iterable = Expression(forOfLoop->iterable.get(), storage).execute(); if (iterable.dataType != Storage::DataType::ARRAY) { @@ -96,14 +99,20 @@ void LoopStatement::executeForOfLoop() { void LoopStatement::executeForInLoop() { auto forInLoop = std::get(loopNode); storage.push_back(std::make_shared()); - std::vector keys = DeclarationStatement(dynamic_cast(forInLoop->iterator.get()), storage).declareLoopVariables(); + std::vector keys = + DeclarationStatement( + dynamic_cast(forInLoop->iterator.get()), storage) + .declareLoopVariables(); Storage::DataWrapper iterable = Expression(forInLoop->iterable.get(), storage).execute(); if (iterable.dataType != Storage::DataType::OBJECT) { throw std::runtime_error("Iterable is not an object!"); } for (const auto &data : *iterable.data._object) { - storage.back()->updateValue(keys.front(), Storage::DataWrapper(Storage::WrapperType::VALUE, Storage::DataType::STRING, new std::string(data.first))); + storage.back()->updateValue( + keys.front(), Storage::DataWrapper(Storage::WrapperType::VALUE, + Storage::DataType::STRING, + new std::string(data.first))); if (keys.size() > 1) { storage.back()->updateValue(keys.at(1), data.second); } diff --git a/src/interpreter/storage.cpp b/src/interpreter/storage.cpp index 51873d0..7b6cd79 100644 --- a/src/interpreter/storage.cpp +++ b/src/interpreter/storage.cpp @@ -7,7 +7,8 @@ Storage::Data::Data(bool value) : _bool(value) {} Storage::Data::Data(char value) : _char(value) {} Storage::Data::Data(std::string *value) : _string(value) {} Storage::Data::Data(std::vector *value) : _array(value) {} -Storage::Data::Data(std::map *value) : _object(value) {} +Storage::Data::Data(std::map *value) + : _object(value) {} Storage::Data::~Data() {} Storage::DataWrapper::DataWrapper()