diff --git a/src/lib/CMakeLists.txt b/src/lib/CMakeLists.txt index cb39c8af..24aeb144 100644 --- a/src/lib/CMakeLists.txt +++ b/src/lib/CMakeLists.txt @@ -83,6 +83,7 @@ add_library(compiler_lib ast/Switch.cpp ast/SwitchCase.cpp ast/ForI.cpp + ast/ForIter.cpp ) target_include_directories(compiler_lib PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} diff --git a/src/lib/ast/AST.h b/src/lib/ast/AST.h index b3751b03..a5b3ff3f 100644 --- a/src/lib/ast/AST.h +++ b/src/lib/ast/AST.h @@ -436,6 +436,26 @@ namespace filc::ast { AbstractExpression *_iteration; std::vector _body; }; + + class ForIter : public AbstractExpression { + public: + ForIter(bool constant, Identifier *identifier, AbstractExpression *array, + const std::vector &body); + + [[nodiscard]] auto isConstant() const -> bool; + + [[nodiscard]] auto getIdentifier() const -> Identifier *; + + [[nodiscard]] auto getArray() const -> AbstractExpression *; + + [[nodiscard]] auto getBody() const -> const std::vector &; + + private: + bool _constant; + Identifier *_identifier; + AbstractExpression *_array; + std::vector _body; + }; } #endif //FILC_AST_H diff --git a/src/lib/ast/AST_decl.h b/src/lib/ast/AST_decl.h index 638ebc42..25c12052 100644 --- a/src/lib/ast/AST_decl.h +++ b/src/lib/ast/AST_decl.h @@ -85,6 +85,8 @@ namespace filc::ast { class SwitchCase; class ForI; + + class ForIter; } #endif //FILC_AST_DECL_H diff --git a/src/lib/ast/ForIter.cpp b/src/lib/ast/ForIter.cpp new file mode 100644 index 00000000..12f3c7e7 --- /dev/null +++ b/src/lib/ast/ForIter.cpp @@ -0,0 +1,46 @@ +/** + * MIT License + * + * Copyright (c) 2023-Present Kevin Traini + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#include "AST.h" + +namespace filc::ast { + ForIter::ForIter(bool constant, filc::ast::Identifier *identifier, filc::ast::AbstractExpression *array, + const std::vector &body) + : AbstractExpression(), _constant(constant), _identifier(identifier), _array(array), _body(body) {} + + auto ForIter::isConstant() const -> bool { + return _constant; + } + + auto ForIter::getIdentifier() const -> Identifier * { + return _identifier; + } + + auto ForIter::getArray() const -> AbstractExpression * { + return _array; + } + + auto ForIter::getBody() const -> const std::vector & { + return _body; + } +} diff --git a/src/lib/grammar/FilParser.g4 b/src/lib/grammar/FilParser.g4 index 7d886639..43e75a5c 100644 --- a/src/lib/grammar/FilParser.g4 +++ b/src/lib/grammar/FilParser.g4 @@ -490,7 +490,9 @@ switch_pattern returns[filc::ast::AbstractExpression *tree] loop returns[filc::ast::AbstractExpression *tree] : fi=for_i { $tree = $fi.tree; - } | for_iter | while_l; + } | fit=for_iter { + $tree = $fit.tree; + } | while_l; for_i returns[filc::ast::ForI *tree] : FOR fic=for_i_condition ib=if_body { @@ -511,11 +513,22 @@ for_i_condition returns[filc::ast::VariableDeclaration *declaration, filc::ast:: $iteration = $e2.tree; })? RPAREN; -for_iter - : FOR for_iter_condition if_body; +for_iter returns[filc::ast::ForIter *tree] + : FOR fic=for_iter_condition ib=if_body { + $tree = new filc::ast::ForIter($fic.constant, $fic.identifier, $fic.array, $ib.tree); + }; -for_iter_condition - : LPAREN (VAL | VAR) IDENTIFIER COLON expression RPAREN; +for_iter_condition returns[bool constant, filc::ast::Identifier *identifier, filc::ast::AbstractExpression *array] +@init { + $constant = true; +} + : LPAREN (VAL | VAR { + $constant = false; + }) i=IDENTIFIER { + $identifier = new filc::ast::Identifier($i); + } COLON e=expression { + $array = $e.tree; + } RPAREN; while_l : WHILE if_condition if_body; diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index b167b6d8..114156d3 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -44,6 +44,7 @@ add_executable(tests unit/ast/SwitchTest.cpp unit/ast/SwitchCaseTest.cpp unit/ast/ForITest.cpp + unit/ast/ForIterTest.cpp ) target_include_directories(tests PUBLIC unit) diff --git a/tests/unit/Fixtures/grammar/for_iter1.fil b/tests/unit/Fixtures/grammar/for_iter1.fil new file mode 100644 index 00000000..9ffbe24f --- /dev/null +++ b/tests/unit/Fixtures/grammar/for_iter1.fil @@ -0,0 +1,5 @@ +module test + +for (val item : my_array) { + &item +} \ No newline at end of file diff --git a/tests/unit/ast/ForIterTest.cpp b/tests/unit/ast/ForIterTest.cpp new file mode 100644 index 00000000..f79e2530 --- /dev/null +++ b/tests/unit/ast/ForIterTest.cpp @@ -0,0 +1,38 @@ +/** + * MIT License + * + * Copyright (c) 2023-Present Kevin Traini + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#include "AST.h" +#include "tools.h" + +TEST(ForIter, constructor) { + filc::ast::ForIter fi1( + true, + new filc::ast::Identifier("item"), + new filc::ast::Identifier("my_array"), + {} + ); + ASSERT_TRUE(fi1.isConstant()); + ASSERT_IDENTIFIER("item", fi1.getIdentifier()); + ASSERT_IDENTIFIER("my_array", fi1.getArray()); + ASSERT_THAT(fi1.getBody(), IsEmpty()); +} \ No newline at end of file diff --git a/tests/unit/grammar/ParserTest.cpp b/tests/unit/grammar/ParserTest.cpp index e9d797d8..c526b2e4 100644 --- a/tests/unit/grammar/ParserTest.cpp +++ b/tests/unit/grammar/ParserTest.cpp @@ -451,3 +451,19 @@ TEST(Parser, ForI) { ASSERT_THAT(expression1_2->getBody(), SizeIs(1)); ASSERT_IDENTIFIER("i", expression1_2->getBody()[0]); } + +TEST(Parser, ForIter) { + filc::grammar::Parser parser1(FIXTURES_PATH "/for_iter1.fil"); + auto *program1 = parser1.getProgram(); + ASSERT_THAT(program1->getExpressions(), SizeIs(1)); + auto *expression1 = static_cast(program1->getExpressions()[0]); + ASSERT_NE(nullptr, expression1); + ASSERT_TRUE(expression1->isConstant()); + ASSERT_IDENTIFIER("item", expression1->getIdentifier()); + ASSERT_IDENTIFIER("my_array", expression1->getArray()); + ASSERT_THAT(expression1->getBody(), SizeIs(1)); + auto *body1 = static_cast(expression1->getBody()[0]); + ASSERT_NE(nullptr, body1); + ASSERT_IDENTIFIER("item", body1->getVariable()); + ASSERT_CLASSIC_OPERATOR(REF, body1->getOperator()); +}