diff --git a/src/main/cup/parser.cup b/src/main/cup/parser.cup index ef83e71..3815c68 100644 --- a/src/main/cup/parser.cup +++ b/src/main/cup/parser.cup @@ -48,6 +48,8 @@ terminal LPAREN, RPAREN; terminal COMMA, SEMICOLON; terminal VAR, EQ, COLON; terminal LET, IN; +terminal ASSIGN; +terminal IF, THEN, ELSE; non terminal Exp program; non terminal Exp exp; @@ -84,6 +86,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:x {: RESULT = new ExpAssign(loc(vxleft,xxright), v, x); :} +/*| IF:i exp:cond THEN exp:e1 {: RESULT = new ExpIf(loc(ixleft,e2xright), cond, e1); :}*/ +| IF:i exp:cond THEN exp:e1 ELSE exp:e2 {: RESULT = new ExpIf(loc(ixleft,e2xright), cond, 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..3ebf4fa --- /dev/null +++ b/src/main/java/absyn/ExpAssign.java @@ -0,0 +1,38 @@ +package absyn; + +import env.Env; +import javaslang.collection.Tree; +import parse.Loc; +import types.INT; +import types.Type; + +import static error.ErrorHelper.*; +import static semantic.SemanticHelper.*; +import static semantic.SemanticHelper.typeMismatch; + +public class ExpAssign extends Exp { + + public final Var var; + public final Exp value; + + public ExpAssign(Loc loc, Var var, Exp value) { + super(loc); + this.var = var; + this.value = value; + } + + @Override + public Tree.Node toTree() { + return Tree.of(annotateType("ExpAssign"), var.toTree(), value.toTree()); + } + + @Override + protected Type semantic_(Env env) { + Type t1 = var.semantic(env); + Type t2 = value.semantic(env); + if(t1.is(t2)) + return t1; + else + throw typeMismatch(value.loc, t2, t1); + } +} diff --git a/src/main/java/absyn/ExpIf.java b/src/main/java/absyn/ExpIf.java new file mode 100644 index 0000000..766e159 --- /dev/null +++ b/src/main/java/absyn/ExpIf.java @@ -0,0 +1,62 @@ +package absyn; + +import env.Env; +import javaslang.collection.List; +import javaslang.collection.Tree; +import parse.Loc; +import types.BOOL; +import types.INT; +import types.Type; +import types.UNIT; + +import static semantic.SemanticHelper.typeMismatch; + +public class ExpIf extends Exp { + + public final Exp condition; + public final Exp expTrue; + public final Exp expFalse; + + public ExpIf(Loc loc, Exp condition, Exp expTrue, Exp expFalse) { + super(loc); + this.condition = condition; + this.expTrue = expTrue; + this.expFalse = expFalse; + } + + public ExpIf(Loc loc, Exp condition, Exp expTrue) { + super(loc); + this.condition = condition; + this.expTrue = expTrue; + this.expFalse = null; + } + + @Override + public Tree.Node toTree() { + List> children = List.of(condition.toTree()); + children = children.append(expTrue.toTree()); + if (expFalse != null) + children = children.append(expFalse.toTree()); + return Tree.of(annotateType("ExpIf"), children); + } + + @Override + protected Type semantic_(Env env) { + Type tCondition = condition.semantic(env); + if(tCondition.is(BOOL.T)){ + Type tExp1 = expTrue.semantic(env); + if(expFalse == null){ + if(!tExp1.is(UNIT.T)){ + throw typeMismatch(expTrue.loc, tExp1, UNIT.T); + } + } + Type tExp2 = expFalse.semantic(env); + if(tExp2.is(tExp1)) + return tExp1; + else + throw typeMismatch(expFalse.loc, tExp2, tExp1); + } + else + throw typeMismatch(condition.loc, tCondition, BOOL.T); + } +} diff --git a/src/main/jflex/lexer.jflex b/src/main/jflex/lexer.jflex index 0e40df5..f9d7dac 100644 --- a/src/main/jflex/lexer.jflex +++ b/src/main/jflex/lexer.jflex @@ -80,6 +80,10 @@ 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 +99,8 @@ 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..0a63188 100644 --- a/src/test/java/Test/SemantTest.java +++ b/src/test/java/Test/SemantTest.java @@ -89,4 +89,21 @@ public void testSimpleVariableAndLet() throws Exception { "error.CompilerError: 1/33-1/34 undefined variable 'x'"); } + @Test + public void testExpressionOfAssign() throws IOException { + trun("let var a : int = 10 in a := 5", INT.T); + trun("let var a = 100.8 in a := 5 * 43.56", REAL.T); + erun("let var a = 10 in a := 5 * 43.56", "error.CompilerError: 1/24-1/33 type mismatch: found real but expected int"); + trun("let var a = false in a := true || false", BOOL.T); + erun("let var a = 10 in a := true", "error.CompilerError: 1/24-1/28 type mismatch: found bool but expected int"); + } + + @Test + public void testExpressionIf() throws IOException { + trun("if false then () else ()", UNIT.T); + trun("if true then 57*3.14 else 10.4", REAL.T); + trun("if true || false then true else false", BOOL.T); + erun("if 4.234 then true else false", "error.CompilerError: 1/4-1/9 type mismatch: found real but expected bool"); + erun("if false then 57*3.14 else false", "error.CompilerError: 1/28-1/33 type mismatch: found bool but expected real"); + } }