From 824b333603ea5fbc12439e12802c675a5623286a Mon Sep 17 00:00:00 2001 From: Borja Lorente Date: Thu, 4 May 2017 00:22:16 +0200 Subject: [PATCH] Finish integration --- examples/Conditionals.grace | 11 ++ examples/Loops.grace | 11 ++ grammars/GraceLexer.g4 | 7 ++ grammars/GraceLexer.tokens | 104 ++++++++++-------- grammars/GraceParser.g4 | 26 ++++- .../src/core/parser/NaylangParserVisitor.cpp | 58 ++++++++++ .../src/core/parser/NaylangParserVisitor.h | 7 ++ .../core/parser/NaylangParserVisitor_test.cpp | 39 +++++++ 8 files changed, 214 insertions(+), 49 deletions(-) create mode 100644 examples/Conditionals.grace create mode 100644 examples/Loops.grace diff --git a/examples/Conditionals.grace b/examples/Conditionals.grace new file mode 100644 index 0000000..82ef142 --- /dev/null +++ b/examples/Conditionals.grace @@ -0,0 +1,11 @@ +var x := 0; +if (x < 1) { + x := 4; +} + +var y := 3; +if (y < 1) { + y := 4; +} else { + y := 6; +} \ No newline at end of file diff --git a/examples/Loops.grace b/examples/Loops.grace new file mode 100644 index 0000000..9b792e8 --- /dev/null +++ b/examples/Loops.grace @@ -0,0 +1,11 @@ +var x := 4; +var i := 0; +var j := 0; +while {i < 5} { + while {j < 5} { + x := x + 1; + j := j + 1; + } + j := 0; + i := i + 1; +} \ No newline at end of file diff --git a/grammars/GraceLexer.g4 b/grammars/GraceLexer.g4 index 428d5ac..3e8d783 100644 --- a/grammars/GraceLexer.g4 +++ b/grammars/GraceLexer.g4 @@ -51,6 +51,9 @@ VAR: 'var '; DEF: 'def '; PREFIX: 'prefix'; OBJECT: 'object'; +IF: 'if'; +ELSE: 'else'; +WHILE: 'while'; COMMA: ','; DOT: '.'; @@ -73,6 +76,10 @@ DIV: '/'; MOD: '%'; POW: '^'; EQUAL: '='; +LESS: '<'; +LESS_EQUAL: '<='; +GREATER: '>'; +GREATER_EQUAL: '>='; TRUE: 'true'; FALSE: 'false'; diff --git a/grammars/GraceLexer.tokens b/grammars/GraceLexer.tokens index 74398b0..a5f1d9e 100644 --- a/grammars/GraceLexer.tokens +++ b/grammars/GraceLexer.tokens @@ -8,54 +8,68 @@ VAR=7 DEF=8 PREFIX=9 OBJECT=10 -COMMA=11 -DOT=12 -DELIMITER=13 -QUOTE=14 -EXCLAMATION=15 -RIGHT_ARROW=16 -OPEN_PAREN=17 -CLOSE_PAREN=18 -OPEN_BRACE=19 -CLOSE_BRACE=20 -OPEN_BRACKET=21 -CLOSE_BRACKET=22 -CONCAT=23 -PLUS=24 -MINUS=25 -MUL=26 -DIV=27 -MOD=28 -POW=29 -EQUAL=30 -TRUE=31 -FALSE=32 -ID=33 +IF=11 +ELSE=12 +WHILE=13 +COMMA=14 +DOT=15 +DELIMITER=16 +QUOTE=17 +EXCLAMATION=18 +RIGHT_ARROW=19 +OPEN_PAREN=20 +CLOSE_PAREN=21 +OPEN_BRACE=22 +CLOSE_BRACE=23 +OPEN_BRACKET=24 +CLOSE_BRACKET=25 +CONCAT=26 +PLUS=27 +MINUS=28 +MUL=29 +DIV=30 +MOD=31 +POW=32 +EQUAL=33 +LESS=34 +LESS_EQUAL=35 +GREATER=36 +GREATER_EQUAL=37 +TRUE=38 +FALSE=39 +ID=40 'method '=5 ':='=6 'var '=7 'def '=8 'prefix'=9 'object'=10 -','=11 -'.'=12 -';'=13 -'"'=14 -'!'=15 -'->'=16 -'('=17 -')'=18 -'{'=19 -'}'=20 -'['=21 -']'=22 -'++'=23 -'+'=24 -'-'=25 -'*'=26 -'/'=27 -'%'=28 -'^'=29 -'='=30 -'true'=31 -'false'=32 +'if'=11 +'else'=12 +'while'=13 +','=14 +'.'=15 +';'=16 +'"'=17 +'!'=18 +'->'=19 +'('=20 +')'=21 +'{'=22 +'}'=23 +'['=24 +']'=25 +'++'=26 +'+'=27 +'-'=28 +'*'=29 +'/'=30 +'%'=31 +'^'=32 +'='=33 +'<'=34 +'<='=35 +'>'=36 +'>='=37 +'true'=38 +'false'=39 diff --git a/grammars/GraceParser.g4 b/grammars/GraceParser.g4 index 17bc65d..24a9882 100644 --- a/grammars/GraceParser.g4 +++ b/grammars/GraceParser.g4 @@ -70,13 +70,22 @@ void doAfter() {} * Parser Rules */ program: (statement)*; -statement: expression DELIMITER | declaration | assignment; //| control; +statement: expression DELIMITER | declaration | assignment | control; assignment : field=identifier VAR_ASSIGN val=expression DELIMITER #SelfAssign | scope=explicitRequest DOT field=identifier VAR_ASSIGN val=expression DELIMITER #ExplAssign | scope=implicitRequest DOT field=identifier VAR_ASSIGN val=expression DELIMITER #ImplAssign ; +control : ifThen + | ifThenElse + | whileNode + ; + +ifThen : IF OPEN_PAREN cond=expression CLOSE_PAREN thn=methodBody; +ifThenElse : IF OPEN_PAREN cond=expression CLOSE_PAREN thn=methodBody ELSE els=methodBody; +whileNode : WHILE OPEN_BRACE cond=expression CLOSE_BRACE body=methodBody; + declaration : variableDeclaration | constantDeclaration | methodDeclaration @@ -97,7 +106,7 @@ formalParameterList: formalParameter (COMMA formalParameter)*; formalParameter: identifier; methodBody: OPEN_BRACE methodBodyLine* CLOSE_BRACE; -methodBodyLine: variableDeclaration | constantDeclaration | expression DELIMITER; //| control; +methodBodyLine: variableDeclaration | constantDeclaration | expression DELIMITER | control | assignment; // Using left-recursion and implicit operator precendence. ANTLR 4 Reference, page 70 expression : rec=expression op=(MUL | DIV) param=expression #MulDivExp @@ -105,7 +114,7 @@ expression : rec=expression op=(MUL | DIV) param=expression #MulDivExp | explicitRequest #ExplicitReqExp | implicitRequest #ImplicitReqExp | prefix_op rec=expression #PrefixExp - | rec=expression infix_op param=expression #InficExp + | rec=expression infix_op param=expression #InfixExp | value #ValueExp ; @@ -144,5 +153,14 @@ number: INT; boolean: TRUE | FALSE; string: QUOTE content=.*? QUOTE; prefix_op: MINUS | EXCLAMATION; -infix_op: MOD | POW | CONCAT; +infix_op: MOD + | POW + | CONCAT + | LESS + | LESS_EQUAL + | GREATER + | GREATER_EQUAL + | EQUAL EQUAL + | EXCLAMATION EQUAL + ; diff --git a/interpreter/src/core/parser/NaylangParserVisitor.cpp b/interpreter/src/core/parser/NaylangParserVisitor.cpp index bfdd730..b1fedef 100644 --- a/interpreter/src/core/parser/NaylangParserVisitor.cpp +++ b/interpreter/src/core/parser/NaylangParserVisitor.cpp @@ -82,6 +82,24 @@ antlrcpp::Any NaylangParserVisitor::visitPrefixExp(GraceParser::PrefixExpContext return 0; } +antlrcpp::Any NaylangParserVisitor::visitInfixExp(GraceParser::InfixExpContext *ctx) { + ctx->infix_op()->accept(this); + auto opname = popPartialStr(); + ctx->rec->accept(this); + auto rec = popPartialExp(); + ctx->param->accept(this); + auto param = popPartialExp(); + std::vector params{param}; + auto req = make_node(opname, rec, params, getLine(ctx), getCol(ctx)); + pushPartialExp(req); + return 0; +} + +antlrcpp::Any NaylangParserVisitor::visitInfix_op(GraceParser::Infix_opContext *ctx) { + pushPartialStr(ctx->getText() + "(_)"); + return 0; +} + antlrcpp::Any NaylangParserVisitor::visitNumber(GraceParser::NumberContext *ctx) { int lastLine = ctx->stop->getLine(); @@ -422,4 +440,44 @@ antlrcpp::Any NaylangParserVisitor::visitExplAssign(GraceParser::ExplAssignConte pushPartialStat(assign); return 0; } + +antlrcpp::Any NaylangParserVisitor::visitIfThen(GraceParser::IfThenContext *ctx) { + ctx->cond->accept(this); + auto cond = popPartialExp(); + + ctx->thn->accept(this); + auto bodyLength = ctx->thn->methodBodyLine().size(); + auto body = popPartialStats(bodyLength); + + pushPartialStat(make_node(cond, body)); + return 0; +} + +antlrcpp::Any NaylangParserVisitor::visitIfThenElse(GraceParser::IfThenElseContext *ctx) { + ctx->cond->accept(this); + auto cond = popPartialExp(); + + ctx->thn->accept(this); + auto thenLength = ctx->thn->methodBodyLine().size(); + auto thenBlock = popPartialStats(thenLength); + + ctx->els->accept(this); + auto elsLen = ctx->els->methodBodyLine().size(); + auto elseBlock = popPartialStats(elsLen); + + pushPartialStat(make_node(cond, thenBlock, elseBlock)); + return 0; +} + +antlrcpp::Any NaylangParserVisitor::visitWhileNode(GraceParser::WhileNodeContext *ctx) { + ctx->cond->accept(this); + auto cond = popPartialExp(); + + ctx->body->accept(this); + auto bodyLength = ctx->body->methodBodyLine().size(); + auto body = popPartialStats(bodyLength); + + pushPartialStat(make_node(cond, body)); + return 0; +} } \ No newline at end of file diff --git a/interpreter/src/core/parser/NaylangParserVisitor.h b/interpreter/src/core/parser/NaylangParserVisitor.h index 6e07089..1dc3a92 100644 --- a/interpreter/src/core/parser/NaylangParserVisitor.h +++ b/interpreter/src/core/parser/NaylangParserVisitor.h @@ -33,9 +33,16 @@ class NaylangParserVisitor : public GraceParserBaseVisitor { antlrcpp::Any visitImplAssign(GraceParser::ImplAssignContext *ctx) override; antlrcpp::Any visitExplAssign(GraceParser::ExplAssignContext *ctx) override; + antlrcpp::Any visitIfThen(GraceParser::IfThenContext *ctx) override; + antlrcpp::Any visitIfThenElse(GraceParser::IfThenElseContext *ctx) override; + antlrcpp::Any visitWhileNode(GraceParser::WhileNodeContext *ctx) override; + antlrcpp::Any visitPrefixExp(GraceParser::PrefixExpContext *ctx) override; antlrcpp::Any visitPrefix_op(GraceParser::Prefix_opContext *ctx) override; + antlrcpp::Any visitInfixExp(GraceParser::InfixExpContext *ctx) override; + antlrcpp::Any visitInfix_op(GraceParser::Infix_opContext *ctx) override; + antlrcpp::Any visitNumber(GraceParser::NumberContext *ctx) override; antlrcpp::Any visitString(GraceParser::StringContext *ctx) override; antlrcpp::Any visitBoolean(GraceParser::BooleanContext *ctx) override; diff --git a/tests/src/core/parser/NaylangParserVisitor_test.cpp b/tests/src/core/parser/NaylangParserVisitor_test.cpp index e4fdf1b..5f99cda 100644 --- a/tests/src/core/parser/NaylangParserVisitor_test.cpp +++ b/tests/src/core/parser/NaylangParserVisitor_test.cpp @@ -340,6 +340,45 @@ TEST_CASE("Assignment", "[Naylang Parser Visitor]") { } } +TEST_CASE("Control Structures") { + SECTION("IfThen") { + auto AST = translate("if (6 < 5) {5;}"); + auto it = static_cast(*(AST[0])); + auto cond = static_cast(*it.condition()); + auto rec = static_cast(*cond.receiver()); + auto param = static_cast(*cond.params()[0]); + auto five = static_cast(*it.thenPart()[0]); + REQUIRE(it.thenPart().size() == 1); + REQUIRE(cond.identifier() == "<(_)"); + REQUIRE(rec.value() == 6.0); + REQUIRE(param.value() == 5.0); + REQUIRE(five.value() == 5.0); + } + + SECTION("IfThenElse") { + auto AST = translate("if (true) {\n 5;\n } else {\n 6;\n }\n"); + auto ite = static_cast(*(AST[0])); + auto tr = static_cast(*ite.condition()); + auto five = static_cast(*ite.thenPart()[0]); + auto six = static_cast(*ite.elsePart()[0]); + REQUIRE(ite.thenPart().size() == 1); + REQUIRE(ite.elsePart().size() == 1); + REQUIRE(tr.value()); + REQUIRE(five.value() == 5.0); + REQUIRE(six.value() == 6.0); + } + + SECTION("While") { + auto AST = translate("while {true} {\n 5;\n }\n"); + auto wh = static_cast(*(AST[0])); + auto tr = static_cast(*wh.condition()); + auto five = static_cast(*wh.body()[0]); + REQUIRE(wh.body().size() == 1); + REQUIRE(tr.value()); + REQUIRE(five.value() == 5.0); + } +} + GraceAST translate(std::string line) { ANTLRInputStream stream(line); GraceLexer lexer(&stream);