From 01b989197bfa4d5edfc776c81e071f368b79573c Mon Sep 17 00:00:00 2001 From: Borja Lorente Date: Wed, 3 May 2017 23:43:21 +0200 Subject: [PATCH] Implement While, ITE, IT evaluation --- .../src/core/model/ast/control/IfThen.cpp | 6 +-- .../src/core/model/ast/control/IfThen.h | 14 +++---- .../src/core/model/ast/control/IfThenElse.cpp | 14 +++---- .../src/core/model/ast/control/IfThenElse.h | 16 ++++---- .../src/core/model/ast/control/While.cpp | 8 ++-- .../src/core/model/ast/control/While.h | 12 +++--- .../model/evaluators/ExecutionEvaluator.cpp | 37 ++++++++++++++++- .../model/evaluators/ExecutionEvaluator.h | 6 ++- .../model/execution/objects/GraceNumber.cpp | 4 ++ .../model/ast/control/IfThenElse_test.cpp | 10 ++--- .../core/model/ast/control/IfThen_test.cpp | 5 +-- .../core/model/ast/control/WhileLoop_test.cpp | 11 ++--- .../evaluators/ExecutionEvaluator_test.cpp | 41 ++++++++++++++++++- 13 files changed, 130 insertions(+), 54 deletions(-) diff --git a/interpreter/src/core/model/ast/control/IfThen.cpp b/interpreter/src/core/model/ast/control/IfThen.cpp index 85bae9e..c275064 100644 --- a/interpreter/src/core/model/ast/control/IfThen.cpp +++ b/interpreter/src/core/model/ast/control/IfThen.cpp @@ -6,10 +6,10 @@ #include "IfThen.h" namespace naylang { -IfThen::IfThen(ExpressionPtr condition, BlockPtr thenExp, int line, int col) : +IfThen::IfThen(ExpressionPtr condition, std::vector thenExp, int line, int col) : _condition{condition}, _then{thenExp}, IfThen::Statement(line, col) {} -IfThen::IfThen(ExpressionPtr condition, BlockPtr thenExp) : +IfThen::IfThen(ExpressionPtr condition, std::vector thenExp) : IfThen(condition, thenExp, -1, -1) {} void IfThen::accept(Evaluator &evaluator) { @@ -20,7 +20,7 @@ ExpressionPtr IfThen::condition() const { return _condition; } -BlockPtr IfThen::thenExpression() const { +const std::vector &IfThen::thenPart() const { return _then; } } \ No newline at end of file diff --git a/interpreter/src/core/model/ast/control/IfThen.h b/interpreter/src/core/model/ast/control/IfThen.h index 8fef5eb..0494a23 100644 --- a/interpreter/src/core/model/ast/control/IfThen.h +++ b/interpreter/src/core/model/ast/control/IfThen.h @@ -3,8 +3,8 @@ // Distributed under the GPLv3 license. // -#ifndef NAYLANG_IFTHENELSE_H -#define NAYLANG_IFTHENELSE_H +#ifndef NAYLANG_IFTHEN_H +#define NAYLANG_IFTHEN_H #include #include @@ -14,24 +14,24 @@ namespace naylang { class IfThen : public Statement { ExpressionPtr _condition; - BlockPtr _then; + std::vector _then; public: IfThen( ExpressionPtr condition, - BlockPtr thenExp, + std::vector thenExp, int line, int col); IfThen( ExpressionPtr condition, - BlockPtr thenExp); + std::vector thenExp); virtual void accept(Evaluator &evaluator); ExpressionPtr condition() const; - BlockPtr thenExpression() const; + const std::vector &thenPart() const; }; } -#endif //NAYLANG_IFTHENELSE_H +#endif //NAYLANG_IFTHEN_H diff --git a/interpreter/src/core/model/ast/control/IfThenElse.cpp b/interpreter/src/core/model/ast/control/IfThenElse.cpp index 4c51791..1b4c072 100644 --- a/interpreter/src/core/model/ast/control/IfThenElse.cpp +++ b/interpreter/src/core/model/ast/control/IfThenElse.cpp @@ -8,15 +8,15 @@ namespace naylang { IfThenElse::IfThenElse( ExpressionPtr condition, - BlockPtr thenExp, - BlockPtr elseExp) : + std::vector thenExp, + std::vector elseExp) : IfThenElse(condition, thenExp, elseExp, -1, -1) {} -IfThenElse::IfThenElse(ExpressionPtr condition, BlockPtr thenExp, BlockPtr elseExp, int line, int col) : +IfThenElse::IfThenElse(ExpressionPtr condition, std::vector thenExp, std::vector elseExp, int line, int col) : IfThenElse::Statement(line, col) { _condition = std::move(condition); - _then = std::move(thenExp); - _else = std::move(elseExp); + _then = thenExp; + _else = elseExp; } void IfThenElse::accept(Evaluator &evaluator) { @@ -27,11 +27,11 @@ ExpressionPtr IfThenElse::condition() const { return _condition; } -BlockPtr IfThenElse::thenExpression() const { +const std::vector &IfThenElse::thenPart() const { return _then; } -BlockPtr IfThenElse::elseExpression() const { +const std::vector &IfThenElse::elsePart() const { return _else; } diff --git a/interpreter/src/core/model/ast/control/IfThenElse.h b/interpreter/src/core/model/ast/control/IfThenElse.h index ca386c2..3009248 100644 --- a/interpreter/src/core/model/ast/control/IfThenElse.h +++ b/interpreter/src/core/model/ast/control/IfThenElse.h @@ -14,25 +14,25 @@ namespace naylang { class IfThenElse : public Statement { ExpressionPtr _condition; - BlockPtr _then; - BlockPtr _else; + std::vector _then; + std::vector _else; public: IfThenElse( ExpressionPtr condition, - BlockPtr thenExp, - BlockPtr elseExp, + std::vector thenExp, + std::vector elseExp, int line, int col); IfThenElse( ExpressionPtr condition, - BlockPtr thenExp, - BlockPtr elseExp); + std::vector thenExp, + std::vector elseExp); virtual void accept(Evaluator &evaluator); ExpressionPtr condition() const; - BlockPtr thenExpression() const; - BlockPtr elseExpression() const; + const std::vector &thenPart() const; + const std::vector &elsePart() const; }; } diff --git a/interpreter/src/core/model/ast/control/While.cpp b/interpreter/src/core/model/ast/control/While.cpp index 10e5f7b..d8bc89e 100644 --- a/interpreter/src/core/model/ast/control/While.cpp +++ b/interpreter/src/core/model/ast/control/While.cpp @@ -10,21 +10,21 @@ namespace naylang { -While::While(BlockPtr condition, BlockPtr body, int line, int col) : +While::While(ExpressionPtr condition, const std::vector &body, int line, int col) : _condition{condition}, _body{body}, While::Statement(line, col) {} -While::While(BlockPtr condition, BlockPtr body) : + While::While(ExpressionPtr condition, const std::vector &body) : While(condition, body, -1, -1) {} void While::accept(Evaluator &evaluator) { evaluator.evaluate(*this); } -const std::shared_ptr &While::condition() const { +ExpressionPtr While::condition() const { return _condition; } -const std::shared_ptr &While::body() const { +const std::vector &While::body() const { return _body; } } \ No newline at end of file diff --git a/interpreter/src/core/model/ast/control/While.h b/interpreter/src/core/model/ast/control/While.h index bc66998..78984e1 100644 --- a/interpreter/src/core/model/ast/control/While.h +++ b/interpreter/src/core/model/ast/control/While.h @@ -15,17 +15,17 @@ namespace naylang { class While : public Statement { - BlockPtr _condition; - BlockPtr _body; + ExpressionPtr _condition; + std::vector _body; public: - While(BlockPtr condition, BlockPtr body, int line, int col); - While(BlockPtr condition, BlockPtr body); + While(ExpressionPtr condition, const std::vector &body, int line, int col); + While(ExpressionPtr condition, const std::vector &body); void accept(Evaluator &evaluator) override; - const std::shared_ptr &condition() const; - const std::shared_ptr &body() const; + ExpressionPtr condition() const; + const std::vector &body() const; }; } // end namespace naylang diff --git a/interpreter/src/core/model/evaluators/ExecutionEvaluator.cpp b/interpreter/src/core/model/evaluators/ExecutionEvaluator.cpp index 44c74d9..46d46c8 100644 --- a/interpreter/src/core/model/evaluators/ExecutionEvaluator.cpp +++ b/interpreter/src/core/model/evaluators/ExecutionEvaluator.cpp @@ -205,7 +205,42 @@ void ExecutionEvaluator::evaluate(Assignment &expression) { _currentScope = _partial; _currentScope->setField(expression.field(), val); - _currentScope = oldScope; } + +void ExecutionEvaluator::evaluate(IfThen &expression) { + expression.condition()->accept(*this); + auto cond = _partial->asBoolean().value(); + if (cond) { + for (auto exp : expression.thenPart()) { + exp->accept(*this); + } + } +} + +void ExecutionEvaluator::evaluate(IfThenElse &expression) { + expression.condition()->accept(*this); + auto cond = _partial->asBoolean().value(); + if (cond) { + for (auto exp : expression.thenPart()) { + exp->accept(*this); + } + } else { + for (auto exp : expression.elsePart()) { + exp->accept(*this); + } + } +} + +void ExecutionEvaluator::evaluate(While &expression) { + expression.condition()->accept(*this); + auto cond = _partial->asBoolean().value(); + while (cond) { + for (auto exp : expression.body()) { + exp->accept(*this); + } + expression.condition()->accept(*this); + cond = _partial->asBoolean().value(); + } +} } \ No newline at end of file diff --git a/interpreter/src/core/model/evaluators/ExecutionEvaluator.h b/interpreter/src/core/model/evaluators/ExecutionEvaluator.h index 215ef64..5c41750 100644 --- a/interpreter/src/core/model/evaluators/ExecutionEvaluator.h +++ b/interpreter/src/core/model/evaluators/ExecutionEvaluator.h @@ -53,7 +53,11 @@ class ExecutionEvaluator : public Evaluator { virtual void evaluate(Block &expression) override; virtual void evaluate(ObjectConstructor &expression) override; virtual void evaluate(VariableDeclaration &expression) override; - void evaluate(Assignment &expression) override; + virtual void evaluate(Assignment &expression) override; + void evaluate(IfThen &expression) override; + void evaluate(IfThenElse &expression) override; + + void evaluate(While &expression) override; // Debug Methods void setDebugState(DebugState state); diff --git a/interpreter/src/core/model/execution/objects/GraceNumber.cpp b/interpreter/src/core/model/execution/objects/GraceNumber.cpp index dc52aef..86ba9a2 100644 --- a/interpreter/src/core/model/execution/objects/GraceNumber.cpp +++ b/interpreter/src/core/model/execution/objects/GraceNumber.cpp @@ -21,6 +21,10 @@ void GraceNumber::addDefaultMethods() { _nativeMethods["prefix!"] = make_native(); _nativeMethods["==(_)"] = make_native(); _nativeMethods["!=(_)"] = make_native(); + _nativeMethods["<(_)"] = make_native(); + _nativeMethods["<=(_)"] = make_native(); + _nativeMethods[">(_)"] = make_native(); + _nativeMethods[">=(_)"] = make_native(); _nativeMethods["+(_)"] = make_native(); _nativeMethods["-(_)"] = make_native(); _nativeMethods["*(_)"] = make_native(); diff --git a/tests/src/core/model/ast/control/IfThenElse_test.cpp b/tests/src/core/model/ast/control/IfThenElse_test.cpp index 6549381..7177951 100644 --- a/tests/src/core/model/ast/control/IfThenElse_test.cpp +++ b/tests/src/core/model/ast/control/IfThenElse_test.cpp @@ -16,10 +16,8 @@ TEST_CASE("If Then Else Expressions", "[Control]") { auto tru = make_node(true); auto five = make_node(5.0); auto six = make_node(6.0); - auto thenBlock = make_node(); - thenBlock->addStatement(five); - auto elseBlock = make_node(); - elseBlock->addStatement(six); + std::vector thenBlock{five}; + std::vector elseBlock{six}; SECTION("ITE Expressions take a condition expression and two consequence blocks") { REQUIRE_NOTHROW(IfThenElse ite(tru, thenBlock, elseBlock);); @@ -28,7 +26,7 @@ TEST_CASE("If Then Else Expressions", "[Control]") { SECTION("ITE Expressions can return either of their fields") { IfThenElse ite(tru, thenBlock, elseBlock); REQUIRE(ite.condition() == tru); - REQUIRE(ite.thenExpression() == thenBlock); - REQUIRE(ite.elseExpression() == elseBlock); + REQUIRE(ite.thenPart() == thenBlock); + REQUIRE(ite.elsePart() == elseBlock); } } \ No newline at end of file diff --git a/tests/src/core/model/ast/control/IfThen_test.cpp b/tests/src/core/model/ast/control/IfThen_test.cpp index 3d8722d..7f25871 100644 --- a/tests/src/core/model/ast/control/IfThen_test.cpp +++ b/tests/src/core/model/ast/control/IfThen_test.cpp @@ -16,8 +16,7 @@ TEST_CASE("If Then Expressions", "[Control]") { auto tru = make_node(true); auto five = make_node(5.0); auto six = make_node(6.0); - auto thenBlock = make_node(); - thenBlock->addStatement(five); + std::vector thenBlock{five}; SECTION("IThen Expressions take a condition expression and a then block") { REQUIRE_NOTHROW(IfThen it(tru, thenBlock);); @@ -26,6 +25,6 @@ TEST_CASE("If Then Expressions", "[Control]") { SECTION("ITE Expressions can return either of their fields") { IfThen it(tru, thenBlock); REQUIRE(it.condition() == tru); - REQUIRE(it.thenExpression() == thenBlock); + REQUIRE(it.thenPart() == thenBlock); } } \ No newline at end of file diff --git a/tests/src/core/model/ast/control/WhileLoop_test.cpp b/tests/src/core/model/ast/control/WhileLoop_test.cpp index 658527d..063e21a 100644 --- a/tests/src/core/model/ast/control/WhileLoop_test.cpp +++ b/tests/src/core/model/ast/control/WhileLoop_test.cpp @@ -15,20 +15,17 @@ using namespace naylang; TEST_CASE("While Loop", "[Control]") { auto tru = make_node(true); - auto truBlock = make_node(); - truBlock->addStatement(tru); auto five = make_node(5.0); - auto fiveBlock = make_node(); - fiveBlock->addStatement(five); + std::vector fiveBlock{five}; SECTION("A while loop accepts a condition block and a body block") { - REQUIRE_NOTHROW(While loop(truBlock, fiveBlock);); + REQUIRE_NOTHROW(While loop(tru, fiveBlock);); } SECTION("A while loop can return it's condition and body") { - While loop(truBlock, fiveBlock); - REQUIRE(loop.condition() == truBlock); + While loop(tru, fiveBlock); + REQUIRE(loop.condition() == tru); REQUIRE(loop.body() == fiveBlock); } } diff --git a/tests/src/core/model/evaluators/ExecutionEvaluator_test.cpp b/tests/src/core/model/evaluators/ExecutionEvaluator_test.cpp index 29cf098..3518ccd 100644 --- a/tests/src/core/model/evaluators/ExecutionEvaluator_test.cpp +++ b/tests/src/core/model/evaluators/ExecutionEvaluator_test.cpp @@ -30,6 +30,8 @@ TEST_CASE("Execution Evaluator", "[Evaluators]") { auto ctruConstDecl = make_node("ctru", trueLiteral); auto five = make_node(5.0); auto six = make_node(6.0); + auto zero = make_node(0.0); + auto twentyTwo = make_node(22.0); auto hiStr = make_node("Hi"); SECTION("An execution evaluator has a partial GraceObject") { @@ -125,7 +127,44 @@ TEST_CASE("Execution Evaluator", "[Evaluators]") { REQUIRE(eval.partial()->hasField("x")); } - SECTION("Evaluating an AssignmentNode places the value into the field of the receiver") { + SECTION("IfThen & IfThenElse") { + ExecutionEvaluator eval; + + auto five = make_node(5.0); + auto six = make_node(6.0); + std::vector thenBlock{five}; + std::vector elseBlock{six}; + + IfThenElse ite(falseLiteral, thenBlock, elseBlock); + ite.accept(eval); + REQUIRE(eval.partial()->asNumber().value() == 6.0); + + IfThen it(trueLiteral, thenBlock); + it.accept(eval); + REQUIRE(eval.partial()->asNumber().value() == 5.0); + } + + SECTION("While loop") { + ExecutionEvaluator eval; + + auto xDeclToZero = make_node("x", zero); + xDeclToZero->accept(eval); + + std::vector addParams{five}; + auto addFive = make_node("+(_)", xRef, addParams); + auto assign = make_node("x", addFive); + std::vector whileBody{assign}; + std::vector lessThanParams{twentyTwo}; + auto whileCond = make_node("<(_)", xRef, lessThanParams); + + While wh(whileCond, whileBody); + wh.accept(eval); + + xRef->accept(eval); + REQUIRE(eval.partial()->asNumber().value() == 25.0); + } + + SECTION("Evaluating an Assignment places the value into the field of the receiver") { SECTION("Number assignment") { ExecutionEvaluator eval; xDec->accept(eval);