From 878257c8cc16f41304f4c4457d3a819c163ecc82 Mon Sep 17 00:00:00 2001 From: Breno Keller Date: Mon, 13 Mar 2017 17:59:35 -0300 Subject: [PATCH] =?UTF-8?q?adicionado=20atribui=C3=A7=C3=A3o=20de=20variav?= =?UTF-8?q?eis=20e=20if=20then=20else?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 1 + src/main/cup/parser.cup | 7 +- src/main/java/absyn/ExpAssign.java | 37 +++++++ src/main/java/absyn/ExpIf.java | 60 +++++++++++ src/main/jflex/lexer.jflex | 4 + src/test/java/Test/SemantTest.java | 154 +++++++++++++++++------------ 6 files changed, 196 insertions(+), 67 deletions(-) create mode 100644 src/main/java/absyn/ExpAssign.java create mode 100644 src/main/java/absyn/ExpIf.java diff --git a/pom.xml b/pom.xml index a16fbbb..19184a3 100644 --- a/pom.xml +++ b/pom.xml @@ -95,6 +95,7 @@ Parser SymbolConstants true + 1 true diff --git a/src/main/cup/parser.cup b/src/main/cup/parser.cup index ef83e71..78e48fb 100644 --- a/src/main/cup/parser.cup +++ b/src/main/cup/parser.cup @@ -45,9 +45,9 @@ terminal String ID; terminal PLUS, MINUS, TIMES, DIV, UMINUS; terminal AND, OR; terminal LPAREN, RPAREN; -terminal COMMA, SEMICOLON; +terminal COMMA, SEMICOLON, ASSIGN; terminal VAR, EQ, COLON; -terminal LET, IN; +terminal LET, IN, IF, THEN, ELSE; non terminal Exp program; non terminal Exp exp; @@ -84,6 +84,9 @@ exp ::= | var:v {: RESULT = new ExpVar(loc(vxleft,vxright), v); :} | LET:l decs:ds IN exp:b {: RESULT = new ExpLet(loc(lxleft,bxright), ds, b); :} | LPAREN:l expseq:es RPAREN:r {: RESULT = new ExpSeq(loc(lxleft,rxright), es); :} +| var:v ASSIGN exp:e {: RESULT = new ExpAssign(loc(vxleft,exright), v, e);:} +| IF:i exp:t THEN exp:e1 {: RESULT = new ExpIf(loc(ixleft,e1xright), t, e1, null);:} +| IF:i exp:t THEN exp:e1 ELSE exp:e2 {: RESULT = new ExpIf(loc(ixleft,e2xright), t, e1, e2);:} ; exps ::= diff --git a/src/main/java/absyn/ExpAssign.java b/src/main/java/absyn/ExpAssign.java new file mode 100644 index 0000000..f1f780e --- /dev/null +++ b/src/main/java/absyn/ExpAssign.java @@ -0,0 +1,37 @@ +package absyn; + +import env.Env; +import javaslang.collection.Tree; +import parse.Loc; +import types.Type; + +import static semantic.SemanticHelper.typeMismatch; + +public class ExpAssign extends Exp { + + public final Var variable; + public final Exp exp; + + public ExpAssign(Loc loc, Var variable, Exp exp) { + super(loc); + this.variable = variable; + this.exp = exp; + } + + @Override + public Tree.Node toTree() { + return Tree.of(annotateType("ExpAssign"), + variable.toTree(), + exp.toTree()); + } + + @Override + protected Type semantic_(Env env) { + Type t_var = variable.semantic(env); + Type t_exp = exp.semantic_(env); + if (!t_exp.is(t_var)) { + throw typeMismatch(exp.loc, t_exp, t_var); + } + return t_var; + } +} diff --git a/src/main/java/absyn/ExpIf.java b/src/main/java/absyn/ExpIf.java new file mode 100644 index 0000000..ce1a321 --- /dev/null +++ b/src/main/java/absyn/ExpIf.java @@ -0,0 +1,60 @@ +package absyn; + +import env.Env; +import javaslang.collection.List; +import javaslang.collection.Tree; +import parse.Loc; +import types.BOOL; +import types.Type; +import types.UNIT; + +import static semantic.SemanticHelper.typeMismatch; + +public class ExpIf extends Exp { + + public final Exp test; + public final Exp e1; + public final Exp e2; + + public ExpIf(Loc loc, Exp test, Exp e1, Exp e2) { + super(loc); + this.test = test; + this.e1 = e1; + this.e2 = e2; + } + + @Override + public Tree.Node toTree() { + List> children = List.of(test.toTree()); + children = children.append(e1.toTree()); + if (e2 != null) + children = children.append(e2.toTree()); + return Tree.of("ExpIf", children); + } + + @Override + protected Type semantic_(Env env) { + Type t_test = test.semantic(env); + if (!t_test.is(BOOL.T)) { + throw typeMismatch(test.loc, t_test, BOOL.T); + } + + Type t_e1 = e1.semantic(env); + if (e2 != null) { + Type t_e2 = e2.semantic(env); + if (!t_e1.is(t_e2)) { + if (!t_e2.is(t_e1)) { + throw typeMismatch(e2.loc, t_e2, t_e1); + } else { + return t_e2; + } + } + return t_e1; + } else { + if (!t_e1.is(UNIT.T)) { + throw typeMismatch(e1.loc, t_e1, UNIT.T); + } + return t_e1; + } + } +} diff --git a/src/main/jflex/lexer.jflex b/src/main/jflex/lexer.jflex index 0e40df5..4f7e0f0 100644 --- a/src/main/jflex/lexer.jflex +++ b/src/main/jflex/lexer.jflex @@ -80,6 +80,9 @@ id = [a-zA-Z][a-zA-Z0-9_]* var { return tok(VAR); } let { return tok(LET); } in { return tok(IN); } +if { return tok(IF); } +then { return tok(THEN); } +else { return tok(ELSE); } {id} { return tok(ID, yytext().intern()); } @@ -95,5 +98,6 @@ in { return tok(IN); } ";" { return tok(SEMICOLON); } ":" { return tok(COLON); } "=" { return tok(EQ); } +":=" { return tok(ASSIGN); } . { throw error(Loc.loc(locLeft()), "unexpected char '%s'", yytext()); } diff --git a/src/test/java/Test/SemantTest.java b/src/test/java/Test/SemantTest.java index dd734fe..24c3a83 100644 --- a/src/test/java/Test/SemantTest.java +++ b/src/test/java/Test/SemantTest.java @@ -16,77 +16,101 @@ public class SemantTest { - private Type runSemantic(String input) throws Exception { - Lexer lexer = new Lexer(new StringReader(input), "unknown"); - Parser parser = new Parser(lexer); - Symbol program = parser.parse(); - Exp parseTree = (Exp) program.value; - return parseTree.semantic(new Env()); - } + private Type runSemantic(String input) throws Exception { + Lexer lexer = new Lexer(new StringReader(input), "unknown"); + Parser parser = new Parser(lexer); + Symbol program = parser.parse(); + Exp parseTree = (Exp) program.value; + return parseTree.semantic(new Env()); + } - private void trun(String input, Type type) { - try { - softly.assertThat(runSemantic(input)) - .as("%s", input) - .isEqualTo(type); - } - catch (Exception e) { - e.printStackTrace(); - } - } + private void trun(String input, Type type) { + try { + softly.assertThat(runSemantic(input)) + .as("%s", input) + .isEqualTo(type); + } catch (Exception e) { + e.printStackTrace(); + } + } - private void erun(String input, String message) throws IOException { - softly.assertThatThrownBy(() -> runSemantic(input)) - .as("%s", input) - .isInstanceOf(CompilerError.class) - .hasToString(message); - } + private void erun(String input, String message) throws IOException { + softly.assertThatThrownBy(() -> runSemantic(input)) + .as("%s", input) + .isInstanceOf(CompilerError.class) + .hasToString(message); + } - @Rule - public final JUnitSoftAssertions softly = new JUnitSoftAssertions(); + @Rule + public final JUnitSoftAssertions softly = new JUnitSoftAssertions(); - @Test - public void testLiterals() throws Exception { - trun("true", BOOL.T); - trun("123", INT.T); - trun("12.34", REAL.T); - } + @Test + public void testLiterals() throws Exception { + trun("true", BOOL.T); + trun("123", INT.T); + trun("12.34", REAL.T); + } - @Test - public void testFunctionCall() throws Exception { - erun("fat(9)", - "error.CompilerError: 1/1-1/7 undefined function 'fat'"); - erun("fat(g(), h())", - "error.CompilerError: 1/5-1/8 undefined function 'g'"); - trun("print_int(123)", - UNIT.T); - erun("print_int(true)", - "error.CompilerError: 1/11-1/15 type mismatch: found bool but expected int"); - erun("print_int(123, true, f())", - "error.CompilerError: 1/22-1/25 undefined function 'f'"); - erun("print_int()", - "error.CompilerError: 1/1-1/12 too few arguments in call to 'print_int'"); - } + @Test + public void testFunctionCall() throws Exception { + erun("fat(9)", + "error.CompilerError: 1/1-1/7 undefined function 'fat'"); + erun("fat(g(), h())", + "error.CompilerError: 1/5-1/8 undefined function 'g'"); + trun("print_int(123)", + UNIT.T); + erun("print_int(true)", + "error.CompilerError: 1/11-1/15 type mismatch: found bool but expected int"); + erun("print_int(123, true, f())", + "error.CompilerError: 1/22-1/25 undefined function 'f'"); + erun("print_int()", + "error.CompilerError: 1/1-1/12 too few arguments in call to 'print_int'"); + } - @Test - public void testSequence() throws Exception { - trun("()", UNIT.T); - trun("(true)", BOOL.T); - trun("(print_int(23); 2.3)", REAL.T); - } + @Test + public void testSequence() throws Exception { + trun("()", UNIT.T); + trun("(true)", BOOL.T); + trun("(print_int(23); 2.3)", REAL.T); + } - @Test - public void testSimpleVariableAndLet() throws Exception { - erun("x", - "error.CompilerError: 1/1-1/2 undefined variable 'x'"); - trun("let var x: int = 10 in x", - INT.T); - trun("let var x = 0.56 in x", - REAL.T); - erun("let var x: int = 3.4 in x", - "error.CompilerError: 1/18-1/21 type mismatch: found real but expected int"); - erun("(let var x = 5 in print_int(x); x)", - "error.CompilerError: 1/33-1/34 undefined variable 'x'"); - } + @Test + public void testSimpleVariableAndLet() throws Exception { + erun("x", + "error.CompilerError: 1/1-1/2 undefined variable 'x'"); + trun("let var x: int = 10 in x", + INT.T); + trun("let var x = 0.56 in x", + REAL.T); + erun("let var x: int = 3.4 in x", + "error.CompilerError: 1/18-1/21 type mismatch: found real but expected int"); + erun("(let var x = 5 in print_int(x); x)", + "error.CompilerError: 1/33-1/34 undefined variable 'x'"); + } + @Test + public void testExpAssign() throws Exception { + trun("let var x = 5.2 in x:=6.6", REAL.T); + trun("let var x = 5 var y = 4 in x := 2*y", INT.T); + trun("let var x = 5.2 var y = 4.3 in x := 2*y", REAL.T); + trun("let var x = false in x := true", BOOL.T); + trun("let var x = 5 in x:=2*x", INT.T); + erun("let var x = 5.2 in z := x", + "error.CompilerError: 1/20-1/21 undefined variable 'z'"); + erun("let var x = 5.2 in x:=true", + "error.CompilerError: 1/23-1/27 type mismatch: found bool but expected real"); + } + + @Test + public void testExpIf() throws Exception { + trun("if true then print_int(4)", UNIT.T); + trun("if false then 4/4 else 3/2", INT.T); + trun("if not(true && false) then print_int(5) else print_real(4.3)", UNIT.T); + erun("if false then true else 3/2", + "error.CompilerError: 1/25-1/28 type mismatch: found int but expected bool"); + erun("if true then 4*5", + "error.CompilerError: 1/14-1/17 type mismatch: found int but expected unit"); + erun("if 2+2 then print_int(4)", + "error.CompilerError: 1/4-1/7 type mismatch: found int but expected bool"); + } }