diff --git a/Alunos.txt b/Alunos.txt new file mode 100644 index 0000000..3190ce8 --- /dev/null +++ b/Alunos.txt @@ -0,0 +1,2 @@ +Marcos Vinicius Oliveira Souza +João Pedro Lonczynski \ No newline at end of file diff --git a/doc/eplan-compiler.tex b/doc/eplan-compiler.tex index 33119f5..0e71f42 100644 --- a/doc/eplan-compiler.tex +++ b/doc/eplan-compiler.tex @@ -1526,7 +1526,7 @@ \section{Análise semântica} % \begin{pygmented}[] % // declarações % Dec(Loc loc) // classe abstrata -% VarDec(Loc loc, Symbol name, Symbol type, Exp init) +% VarDec(Loc loc, Symbol name, Symbol type, Exp body) % // variáveis % Var(Loc loc) // classe abstrata diff --git a/src/main/cup/parser.cup b/src/main/cup/parser.cup index e076a7e..72e7725 100644 --- a/src/main/cup/parser.cup +++ b/src/main/cup/parser.cup @@ -51,21 +51,34 @@ terminal LET, IN; terminal ASSIGN; terminal IF, THEN, ELSE; terminal TYPE; - -non terminal Exp program; -non terminal Exp exp; -non terminal List exps, expsRest; -non terminal List expseq, expseqRest; -non terminal DecVar decvar; -non terminal DecType dectype; +terminal EQT, NEQ, LT, LE, GT, GE; +terminal WHILE, DO, BREAK; +terminal FUNCTION; +terminal LBRACK, RBRACK, AT; +terminal LBRACE, RBRACE; +terminal DOT; + +non terminal Exp program; +non terminal Exp exp; +non terminal List exps, expsRest; +non terminal List expseq, expseqRest; +non terminal DecVar decvar; +non terminal DecType dectype; +non terminal DecFunction decfunc; non terminal List dectypes; -non terminal List decs; -non terminal List decs_beg_with_variable, decs_beg_with_type; -non terminal Var var; -non terminal Ty ty; +non terminal List decs; +non terminal List decs_beg_with_variable, decs_beg_with_type, decs_beg_with_func; +non terminal Var var; +non terminal Ty ty; +non terminal Parameter parameter; +non terminal List parameters, parametersRest; +non terminal List decfuncs; +non terminal ParameterWithExp parameterexp; +non terminal List parameterexps, parameterexpsRest; precedence left OR; precedence left AND; +precedence nonassoc EQT, NEQ, LT, LE, GT, GE; precedence left PLUS, MINUS; precedence left TIMES, DIV; precedence left UMINUS; @@ -78,23 +91,33 @@ program ::= ; exp ::= - exp:x PLUS exp:y {: RESULT = new ExpBinOp(loc(xxleft,yxright), ExpBinOp.Op.PLUS, x, y); :} -| exp:x MINUS exp:y {: RESULT = new ExpBinOp(loc(xxleft,yxright), ExpBinOp.Op.MINUS, x, y); :} -| exp:x TIMES exp:y {: RESULT = new ExpBinOp(loc(xxleft,yxright), ExpBinOp.Op.TIMES, x, y); :} -| exp:x DIV exp:y {: RESULT = new ExpBinOp(loc(xxleft,yxright), ExpBinOp.Op.DIV, x, y); :} -| exp:x AND exp:y {: RESULT = new ExpBinOp(loc(xxleft,yxright), ExpBinOp.Op.AND, x, y); :} -| exp:x OR exp:y {: RESULT = new ExpBinOp(loc(xxleft,yxright), ExpBinOp.Op.OR, x, y); :} -| LITINT:x {: RESULT = new ExpInt(loc(xxleft,xxright), x); :} -| LITREAL:x {: RESULT = new ExpReal(loc(xxleft,xxright), x); :} -| LITBOOL:x {: RESULT = new ExpBool(loc(xxleft,xxright), x); :} -| MINUS:m exp:x {: RESULT = new ExpNegate(loc(mxleft,xxright), x); :} %prec UMINUS -| ID:f LPAREN exps:x RPAREN:r {: RESULT = new ExpCall(loc(fxleft,rxright), f, x); :} -| var:v {: RESULT = new ExpVar(loc(vxleft,vxright), v); :} -| var:v ASSIGN exp:e {: RESULT = new ExpAssign(loc(vxleft,exright), v, e); :} -| 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); :} -| IF:i exp:t THEN exp:a ELSE exp:b {: RESULT = new ExpIf(loc(ixleft,bxright), t, a, b); :} -| IF:i exp:t THEN exp:a {: RESULT = new ExpIf(loc(ixleft,axright), t, a, null); :} + exp:x PLUS exp:y {: RESULT = new ExpBinOp(loc(xxleft,yxright), ExpBinOp.Op.PLUS, x, y); :} +| exp:x MINUS exp:y {: RESULT = new ExpBinOp(loc(xxleft,yxright), ExpBinOp.Op.MINUS, x, y); :} +| exp:x TIMES exp:y {: RESULT = new ExpBinOp(loc(xxleft,yxright), ExpBinOp.Op.TIMES, x, y); :} +| exp:x DIV exp:y {: RESULT = new ExpBinOp(loc(xxleft,yxright), ExpBinOp.Op.DIV, x, y); :} +| exp:x AND exp:y {: RESULT = new ExpBinOp(loc(xxleft,yxright), ExpBinOp.Op.AND, x, y); :} +| exp:x OR exp:y {: RESULT = new ExpBinOp(loc(xxleft,yxright), ExpBinOp.Op.OR, x, y); :} +| exp:x EQT exp:y {: RESULT = new ExpBinOp(loc(xxleft,yxright), ExpBinOp.Op.EQT, x, y); :} +| exp:x NEQ exp:y {: RESULT = new ExpBinOp(loc(xxleft,yxright), ExpBinOp.Op.NEQ, x, y); :} +| exp:x LT exp:y {: RESULT = new ExpBinOp(loc(xxleft,yxright), ExpBinOp.Op.LT, x, y); :} +| exp:x LE exp:y {: RESULT = new ExpBinOp(loc(xxleft,yxright), ExpBinOp.Op.LE, x, y); :} +| exp:x GT exp:y {: RESULT = new ExpBinOp(loc(xxleft,yxright), ExpBinOp.Op.GT, x, y); :} +| exp:x GE exp:y {: RESULT = new ExpBinOp(loc(xxleft,yxright), ExpBinOp.Op.GE, x, y); :} +| LITINT:x {: RESULT = new ExpInt(loc(xxleft,xxright), x); :} +| LITREAL:x {: RESULT = new ExpReal(loc(xxleft,xxright), x); :} +| LITBOOL:x {: RESULT = new ExpBool(loc(xxleft,xxright), x); :} +| MINUS:m exp:x {: RESULT = new ExpNegate(loc(mxleft,xxright), x); :} %prec UMINUS +| ID:f LPAREN exps:x RPAREN:r {: RESULT = new ExpCall(loc(fxleft,rxright), f, x); :} +| var:v {: RESULT = new ExpVar(loc(vxleft,vxright), v); :} +| var:v ASSIGN exp:e {: RESULT = new ExpAssign(loc(vxleft,exright), v, e); :} +| 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); :} +| IF:i exp:t THEN exp:a ELSE exp:b {: RESULT = new ExpIf(loc(ixleft,bxright), t, a, b); :} +| IF:i exp:t THEN exp:a {: RESULT = new ExpIf(loc(ixleft,axright), t, a, null); :} +| WHILE:w exp:t DO exp:b {: RESULT = new ExpWhile(loc(wxleft,bxright), t, b); :} +| BREAK:b {: RESULT = new ExpBreak(loc(bxleft,bxright)); :} +| AT:a ID:id LBRACK exps:e RBRACK:r {: RESULT = new ExpArray(loc(axleft,rxright),id,e); :} +| AT:a ID:id LBRACE parameterexps:f RBRACE:r{: RESULT = new ExpRecord(loc(axleft,rxright),id,f); :} ; exps ::= @@ -134,23 +157,74 @@ dectypes ::= decs ::= decs_beg_with_variable:ds {: RESULT = ds; :} | decs_beg_with_type:ds {: RESULT = ds; :} +| decs_beg_with_func:ds {: RESULT = ds; :} ; decs_beg_with_variable ::= decvar:d {: RESULT = List.of(d); :} | decvar:d decs_beg_with_variable:ds {: RESULT = ds.prepend(d); :} | decvar:d decs_beg_with_type:ds {: RESULT = ds.prepend(d); :} +| decvar:d decs_beg_with_func:ds {: RESULT = ds.prepend(d); :} ; decs_beg_with_type ::= dectypes:dt {: RESULT = List.of(new DecTypeMutual(loc(dtxleft,dtxright), dt)); :} | dectypes:dt decs_beg_with_variable:ds {: RESULT = ds.prepend(new DecTypeMutual(loc(dtxleft,dtxright), dt)); :} +| dectypes:dt decs_beg_with_func:ds {: RESULT = ds.prepend(new DecTypeMutual(loc(dtxleft,dtxright), dt)); :} ; var ::= - ID:v {: RESULT = new VarSimple(loc(vxleft,vxright), v); :} + ID:v {: RESULT = new VarSimple(loc(vxleft,vxright), v); :} +| var:x LBRACK exp:e RBRACK:r {: RESULT = new VarSubscript(loc(xxleft,rxright), x, e); :} +| var:x DOT ID:id {: RESULT = new VarField(loc(xxleft,idxright), x, id); :} ; ty ::= - ID:id {: RESULT = new TyName(loc(idxleft,idxright), id); :} + ID:id {: RESULT = new TyName(loc(idxleft,idxright), id); :} +| LBRACK:l ID:id RBRACK:r {: RESULT = new TyArray(loc(idxleft,idxright), id); :} +| LBRACE:l parameters:p RBRACE:r {: RESULT = new TyRecord(loc(lxleft,rxright), p); :} +; + +parameter ::= + ID:n COLON ID:t {: RESULT = new Parameter(loc(nxleft,txright),n,t); :} +; + +parameters ::= + /* empty */ {: RESULT = List.empty(); :} +| parameter:p parametersRest:ps {: RESULT = ps.prepend(p); :} +; + +parametersRest ::= + /* empty */ {: RESULT = List.empty(); :} +| COMMA parameter:p parametersRest:ps {: RESULT = ps.prepend(p); :} +; + +parameterexp ::= + ID:n EQ exp:e {: RESULT = new ParameterWithExp(loc(nxleft,exright),n,e); :} ; + +parameterexps ::= + /* empty */ {: RESULT = List.empty(); :} +| parameterexp:p parameterexpsRest:ps {: RESULT = ps.prepend(p); :} +; + +parameterexpsRest ::= + /* empty */ {: RESULT = List.empty(); :} +| COMMA parameterexp:p parameterexpsRest:ps {: RESULT = ps.prepend(p); :} +; + +decfunc ::= + FUNCTION:f ID:n LPAREN parameters:p RPAREN COLON ID:t EQ exp:b {: RESULT = new DecFunction(loc(fxleft,bxright),n,p,t,b); :} +| FUNCTION:f ID:n LPAREN parameters:p RPAREN EQ exp:b {: RESULT = new DecFunction(loc(fxleft,bxright),n,p,null,b); :} +; + +decfuncs ::= + decfunc:d {: RESULT = List.of(d); :} +| decfunc:d decfuncs:ds {: RESULT = ds.prepend(d); :} +; + +decs_beg_with_func ::= + decfuncs:d {: RESULT = List.of(new DecFunctionMutual(loc(dxleft,dxright), d)); :} +| decfuncs:d decs_beg_with_variable:ds {: RESULT = ds.prepend(new DecFunctionMutual(loc(dxleft,dxright), d)); :} +| decfuncs:d decs_beg_with_type:ds {: RESULT = ds.prepend(new DecFunctionMutual(loc(dxleft,dxright), d)); :} +; \ No newline at end of file diff --git a/src/main/java/absyn/Dec.java b/src/main/java/absyn/Dec.java index f29bb85..f2860ee 100644 --- a/src/main/java/absyn/Dec.java +++ b/src/main/java/absyn/Dec.java @@ -11,6 +11,6 @@ public Dec(Loc loc) { } // Do semantic analysis of the declaraction - public abstract void semantic(Env env); + public abstract Type semantic(Env env); } diff --git a/src/main/java/absyn/DecFunction.java b/src/main/java/absyn/DecFunction.java new file mode 100644 index 0000000..d362faf --- /dev/null +++ b/src/main/java/absyn/DecFunction.java @@ -0,0 +1,33 @@ +package absyn; + +import env.Env; +import javaslang.collection.List; +import javaslang.collection.Tree; +import parse.Loc; +import types.Type; + +public class DecFunction extends AST { + + public final String name; + public final List parameters; + public final String typeName; + public final Exp body; + + public DecFunction(Loc loc, String name, List parameters, String typeName, Exp body) { + super(loc); + this.name = name; + this.parameters = parameters; + this.typeName = typeName; + this.body = body; + } + + @Override + public Tree.Node toTree() { + return Tree.of("DecFunction: " + name, + Tree.of("Parameters", parameters.map(Parameter::toTree)), + Tree.of(typeName == null ? "" : typeName), + body.toTree() + ); + } + +} diff --git a/src/main/java/absyn/DecFunctionMutual.java b/src/main/java/absyn/DecFunctionMutual.java new file mode 100644 index 0000000..f3e7ff1 --- /dev/null +++ b/src/main/java/absyn/DecFunctionMutual.java @@ -0,0 +1,62 @@ +package absyn; + +import env.Env; +import javaslang.collection.List; +import javaslang.collection.Tree; +import parse.Loc; +import semantic.SemanticHelper; +import types.FUNCTION; +import types.Type; +import types.UNIT; + + +public class DecFunctionMutual extends Dec { + + public final List decs; + + public DecFunctionMutual(Loc loc, List decs) { + super(loc); + this.decs = decs; + } + + @Override + public Tree.Node toTree() { + return Tree.of("DecFunctionMutual", decs.map(DecFunction::toTree)); + } + + @Override + public Type semantic(Env env) { + for (DecFunction d : decs) { + List t_params = d.parameters.map(p -> p.semantic(env)); + + Type t_result = UNIT.T; + if (d.typeName != null) { + t_result = env.tenv.get(d.typeName); + if (t_result == null) { + throw SemanticHelper.undefined(d.loc, "type", d.name); + } + } + + env.venv.put(d.name, new FUNCTION(t_result, t_params)); + } + for (DecFunction d : decs) { + env.venv.beginScope(); + + FUNCTION func = (FUNCTION) env.venv.get(d.name); + List t_params = func.formals; + List parameters = d.parameters; + + while (!parameters.isEmpty()) { + env.venv.put(parameters.head().name, t_params.head()); + parameters = parameters.tail(); + t_params = t_params.tail(); + } + + Type t_body = d.body.semantic(env); + if (!t_body.is(func.result)) + throw SemanticHelper.functionTypeMismatch(d.loc, func.result, t_body); + env.venv.endScope(); + } + return null; + } +} diff --git a/src/main/java/absyn/DecTypeMutual.java b/src/main/java/absyn/DecTypeMutual.java index 3d0ba5f..0bc3a76 100644 --- a/src/main/java/absyn/DecTypeMutual.java +++ b/src/main/java/absyn/DecTypeMutual.java @@ -1,28 +1,39 @@ package absyn; import env.Env; +import error.CompilerError; import javaslang.collection.List; import javaslang.collection.Tree; import parse.Loc; -import semantic.SemanticHelper; +import types.NAME; import types.Type; -public class DecTypeMutual extends Dec { - public final List decs; +public class DecTypeMutual extends Dec { - public DecTypeMutual(Loc loc, List decs) { - super(loc); - this.decs = decs; - } + public final List decs; - @Override - public Tree.Node toTree() { - return Tree.of("DecTypeMutual", decs.map(DecType::toTree)); - } + public DecTypeMutual(Loc loc, List decs) { + super(loc); + this.decs = decs; + } - @Override - public void semantic(Env env) { + @Override + public Tree.Node toTree() { + return Tree.of("DecTypeMutual", decs.map(DecType::toTree)); + } - } + @Override + public Type semantic(Env env) { + for (DecType d : decs) + env.tenv.put(d.name, new NAME(d.name)); + for (DecType d : decs){ + Type t = d.ty.semantic(env); + Type tname = env.tenv.get(d.name); + if (!(tname instanceof NAME)) + throw new CompilerError("bug!!!!!!"); + ((NAME) tname).binding = t; + } + return null; + } } diff --git a/src/main/java/absyn/DecVar.java b/src/main/java/absyn/DecVar.java index aff4870..f869ca9 100644 --- a/src/main/java/absyn/DecVar.java +++ b/src/main/java/absyn/DecVar.java @@ -30,7 +30,7 @@ public Tree.Node toTree() { } @Override - public void semantic(Env env) { + public Type semantic(Env env) { Type t_init = init.semantic(env); Type t_var = t_init; if (typeName != null) { @@ -42,5 +42,6 @@ public void semantic(Env env) { t_var = t_typeName; } env.venv.put(name, t_var); + return t_init; } } diff --git a/src/main/java/absyn/ExpArray.java b/src/main/java/absyn/ExpArray.java new file mode 100644 index 0000000..e28cd68 --- /dev/null +++ b/src/main/java/absyn/ExpArray.java @@ -0,0 +1,49 @@ +package absyn; + +import env.Env; +import javaslang.collection.List; +import javaslang.collection.Tree; +import parse.Loc; +import semantic.SemanticHelper; +import types.ARRAY; +import types.Type; + +public class ExpArray extends Exp{ + + public final String typeName; + public final List elements; + + public ExpArray(Loc loc, String typeName, List elements) { + super(loc); + this.typeName = typeName; + this.elements = elements; + } + + @Override + public Tree.Node toTree() { + return Tree.of("ExpArray",Tree.of(typeName),Tree.of("Elements", elements.map(Exp::toTree))); + } + + @Override + protected Type semantic_(Env env) { + Type t_typeName = env.tenv.get(typeName); + Type t_test = t_typeName; + if (t_typeName == null) + throw SemanticHelper.undefined(loc,"type",typeName); + else{ + t_typeName = t_typeName.actual(); + if (!(t_typeName instanceof ARRAY)) + throw SemanticHelper.arrayMismatch(loc,t_typeName); + } + + Type t_elements = ((ARRAY) t_typeName).typeName; + + for (Exp e: elements) { + Type t_aux = e.semantic(env); + if (!t_aux.is(t_elements)) + throw SemanticHelper.typeMismatch(loc,t_aux,t_elements); + } + + return t_test; + } +} diff --git a/src/main/java/absyn/ExpBinOp.java b/src/main/java/absyn/ExpBinOp.java index dce0d7d..cd11956 100644 --- a/src/main/java/absyn/ExpBinOp.java +++ b/src/main/java/absyn/ExpBinOp.java @@ -14,61 +14,85 @@ public class ExpBinOp extends Exp { - public enum Op { - PLUS, MINUS, TIMES, DIV, - AND, OR - } - - public final Op op; - public final Exp left; - public final Exp right; - - public ExpBinOp(Loc loc, Op op, Exp left, Exp right) { - super(loc); - this.op = op; - this.left = left; - this.right = right; - } - - @Override - public Tree.Node toTree() { - return Tree.of(annotateType("ExpBinOp: " + op), left.toTree(), right.toTree()); - } - - @Override - protected Type semantic_(Env env) { - final Type t_left = left.semantic(env); - final Type t_right = right.semantic(env); - - switch (op) { - case PLUS: - case MINUS: - case TIMES: - case DIV: - if (!t_left.is(INT.T, REAL.T)) - throw typeMismatch(left.loc, t_left, INT.T, REAL.T); - - if (!t_right.is(INT.T, REAL.T)) - throw typeMismatch(right.loc, t_right, INT.T, REAL.T); - - if (t_left.is(REAL.T) || t_right.is(REAL.T)) - return REAL.T; - - return INT.T; - - case AND: - case OR: - if (!t_left.is(BOOL.T)) - throw typeMismatch(left.loc, t_left, BOOL.T); - - if (!t_right.is(BOOL.T)) - throw typeMismatch(right.loc, t_right, BOOL.T); - - return BOOL.T; - - default: - throw fatal("unexpected invalid operator: %s", op); - } - } + public enum Op { + PLUS, MINUS, TIMES, DIV, + AND, OR, EQT, NEQ, LT, LE, GT, GE + } + + public final Op op; + public final Exp left; + public final Exp right; + + public ExpBinOp(Loc loc, Op op, Exp left, Exp right) { + super(loc); + this.op = op; + this.left = left; + this.right = right; + } + + @Override + public Tree.Node toTree() { + return Tree.of(annotateType("ExpBinOp: " + op), left.toTree(), right.toTree()); + } + + @Override + protected Type semantic_(Env env) { + final Type t_left = left.semantic(env); + final Type t_right = right.semantic(env); + + switch (op) { + case PLUS: + case MINUS: + case TIMES: + case DIV: + if (!t_left.is(INT.T, REAL.T)) + throw typeMismatch(left.loc, t_left, INT.T, REAL.T); + + if (!t_right.is(INT.T, REAL.T)) + throw typeMismatch(right.loc, t_right, INT.T, REAL.T); + + if (t_left.is(REAL.T) || t_right.is(REAL.T)) + return REAL.T; + + return INT.T; + + case AND: + case OR: + if (!t_left.is(BOOL.T)) + throw typeMismatch(left.loc, t_left, BOOL.T); + + if (!t_right.is(BOOL.T)) + throw typeMismatch(right.loc, t_right, BOOL.T); + + return BOOL.T; + + case EQT: + case NEQ: + if (!t_left.is(BOOL.T, INT.T, REAL.T)) + throw typeMismatch(left.loc, t_left, BOOL.T, INT.T, REAL.T); + + if (!t_right.is(t_left)) { + if (t_right.is(INT.T) || t_right.is(REAL.T)) + return BOOL.T; + + throw typeMismatch(right.loc, t_right, t_left); + } + return BOOL.T; + case LT: + case LE: + case GT: + case GE: + if (!t_left.is(INT.T, REAL.T)) + throw typeMismatch(left.loc, t_left, INT.T, REAL.T); + + if (!t_right.is(INT.T, REAL.T)) + throw typeMismatch(right.loc, t_right, INT.T, REAL.T); + + return BOOL.T; + + default: + throw fatal("unexpected invalid operator: %s", op); + } + } } diff --git a/src/main/java/absyn/ExpBreak.java b/src/main/java/absyn/ExpBreak.java new file mode 100644 index 0000000..b35fcc1 --- /dev/null +++ b/src/main/java/absyn/ExpBreak.java @@ -0,0 +1,31 @@ +package absyn; + +import env.Env; +import javaslang.collection.Tree; +import parse.Loc; +import types.BOOL; +import types.Type; +import types.UNIT; + +import static semantic.SemanticHelper.breakOutWhile; +import static semantic.SemanticHelper.typeMismatch; + +public class ExpBreak extends Exp { + + public ExpBreak(Loc loc) { + super(loc); + } + + @Override + public Tree.Node toTree() { + return Tree.of(annotateType("ExpBreak")); + } + + @Override + protected Type semantic_(Env env) { + if (env.isWhile == false) + throw breakOutWhile(loc); + return UNIT.T; + } + +} diff --git a/src/main/java/absyn/ExpRecord.java b/src/main/java/absyn/ExpRecord.java new file mode 100644 index 0000000..37c43ba --- /dev/null +++ b/src/main/java/absyn/ExpRecord.java @@ -0,0 +1,66 @@ +package absyn; + +import env.Env; +import javaslang.collection.List; +import javaslang.collection.Tree; +import javaslang.control.Option; +import parse.Loc; +import semantic.SemanticHelper; +import types.RECORD; +import types.Type; + +public class ExpRecord extends Exp{ + + public final String typeName; + public final List elements; + + public ExpRecord(Loc loc, String typeName, List elements) { + super(loc); + this.typeName = typeName; + this.elements = elements; + } + + @Override + public Tree.Node toTree() { + return Tree.of("ExpRecord",Tree.of(typeName),Tree.of("Elements", elements.map(ParameterWithExp::toTree))); + } + + @Override + protected Type semantic_(Env env) { + Type t_typeName = env.tenv.get(typeName); + if (t_typeName == null) + throw SemanticHelper.undefined(loc,"type",typeName); + else { + t_typeName = t_typeName.actual(); + if (!(t_typeName instanceof RECORD)) + throw SemanticHelper.recordMismatch(loc,t_typeName); + } + + List t_parameters = ((RECORD) t_typeName).elements; + //Lista para verificar a duplicidade entre variaveis + List verify = List.empty(); + + for (ParameterWithExp parameterWithExp: elements ) { + Type t_parameterWithExp = parameterWithExp.semantic_(env); + + if (verify.contains(parameterWithExp.name)) + throw SemanticHelper.duplicatedParameter(loc,parameterWithExp.name); + else{ + Option t_p = t_parameters.find(p -> p.name == parameterWithExp.name); + if (t_p.isEmpty()) + throw SemanticHelper.unknownRecordParameter(loc,parameterWithExp.name); + else{ + Type t_aux = t_p.get().semantic_(env); + if (!t_parameterWithExp.is(t_aux)) + throw SemanticHelper.recordTypeMismatch(loc, parameterWithExp.name, t_parameterWithExp, t_aux); + t_parameters = t_parameters.remove(t_p.get()); + } + verify = verify.prepend(parameterWithExp.name); + } + } + if (! t_parameters.isEmpty()) + throw SemanticHelper.missingParametersRecord(loc, t_parameters.map(p -> p.name)); + + return t_typeName; + } +} diff --git a/src/main/java/absyn/ExpWhile.java b/src/main/java/absyn/ExpWhile.java new file mode 100644 index 0000000..c4d9a0b --- /dev/null +++ b/src/main/java/absyn/ExpWhile.java @@ -0,0 +1,43 @@ +package absyn; + +import env.Env; +import javaslang.collection.Tree; +import parse.Loc; +import types.BOOL; +import types.Type; +import types.UNIT; + +import static semantic.SemanticHelper.typeMismatch; + +public class ExpWhile extends Exp { + + public final Exp test; + public final Exp body; + + + public ExpWhile(Loc loc, Exp test, Exp body) { + super(loc); + this.test = test; + this.body = body; + } + + @Override + public Tree.Node toTree() { + return Tree.of(annotateType("ExpWhile: "), test.toTree(), body.toTree()); + } + + @Override + protected Type semantic_(Env env) { + //Verificando a expressão teste + final Type t_test = test.semantic(env); + if (!t_test.is(BOOL.T)) + throw typeMismatch(test.loc, t_test, BOOL.T); + boolean localIsWhile = env.isWhile; + env.isWhile = true; + body.semantic(env); + env.isWhile = localIsWhile; + + return UNIT.T; + } + +} diff --git a/src/main/java/absyn/Parameter.java b/src/main/java/absyn/Parameter.java new file mode 100644 index 0000000..b6971d0 --- /dev/null +++ b/src/main/java/absyn/Parameter.java @@ -0,0 +1,37 @@ +package absyn; + +import env.Env; +import javaslang.collection.Tree; +import parse.Loc; +import semantic.SemanticHelper; +import types.Type; + +public class Parameter extends Exp { + + public final String name; + public final String typeName; + + public Parameter(Loc loc, String name, String typeName) { + super(loc); + this.name = name; + this.typeName = typeName; + } + + @Override + public Tree.Node toTree() { + return Tree.of("Parameter", Tree.of(name), Tree.of(typeName)); + } + + @Override + protected Type semantic_(Env env) { + Type t_type = env.tenv.get(typeName); + if (t_type == null) + throw SemanticHelper.undefined(loc, "type", typeName); + return t_type; + } + + @Override + public String toString() { + return name + " : " + typeName; + } +} diff --git a/src/main/java/absyn/ParameterWithExp.java b/src/main/java/absyn/ParameterWithExp.java new file mode 100644 index 0000000..5b89836 --- /dev/null +++ b/src/main/java/absyn/ParameterWithExp.java @@ -0,0 +1,29 @@ +package absyn; + +import env.Env; +import javaslang.collection.Tree; +import parse.Loc; +import semantic.SemanticHelper; +import types.Type; + +public class ParameterWithExp extends Exp { + + public final String name; + public final Exp body; + + public ParameterWithExp(Loc loc, String name, Exp body) { + super(loc); + this.name = name; + this.body = body; + } + + @Override + public Tree.Node toTree() { + return Tree.of("Parameter", Tree.of(name), body.toTree()); + } + + @Override + protected Type semantic_(Env env) { + return body.semantic(env); + } +} diff --git a/src/main/java/absyn/Ty.java b/src/main/java/absyn/Ty.java index 7da3412..937f2f5 100644 --- a/src/main/java/absyn/Ty.java +++ b/src/main/java/absyn/Ty.java @@ -2,6 +2,7 @@ import env.Env; import parse.Loc; +import types.Type; public abstract class Ty extends AST { @@ -10,6 +11,6 @@ public Ty(Loc loc) { } // Do semantic analysis of the declaraction - public abstract void semantic(Env env); + public abstract Type semantic(Env env); } diff --git a/src/main/java/absyn/TyArray.java b/src/main/java/absyn/TyArray.java new file mode 100644 index 0000000..3ba0d07 --- /dev/null +++ b/src/main/java/absyn/TyArray.java @@ -0,0 +1,35 @@ +package absyn; + +import env.Env; +import javaslang.collection.Tree; +import parse.Loc; +import types.ARRAY; +import types.Type; + +import static semantic.SemanticHelper.undefined; + +public class TyArray extends Ty { + + public final String name; + + public TyArray(Loc loc, String name) { + super(loc); + this.name = name; + } + + @Override + public Tree.Node toTree() { + return Tree.of("TyArray: " + name); + } + + @Override + public Type semantic(Env env) { + Type t = env.tenv.get(name); + if (t == null) + throw undefined(loc, "type", name); + + return new ARRAY(t); + } + + +} diff --git a/src/main/java/absyn/TyName.java b/src/main/java/absyn/TyName.java index 8ed2469..3410c6b 100644 --- a/src/main/java/absyn/TyName.java +++ b/src/main/java/absyn/TyName.java @@ -3,6 +3,9 @@ import env.Env; import javaslang.collection.Tree; import parse.Loc; +import types.Type; + +import static semantic.SemanticHelper.undefined; public class TyName extends Ty { @@ -14,8 +17,11 @@ public TyName(Loc loc, String name) { } @Override - public void semantic(Env env) { - + public Type semantic(Env env) { + Type t = env.tenv.get(name); + if (t == null) + throw undefined(loc,"type",name); + return t; } @Override diff --git a/src/main/java/absyn/TyRecord.java b/src/main/java/absyn/TyRecord.java new file mode 100644 index 0000000..2407f03 --- /dev/null +++ b/src/main/java/absyn/TyRecord.java @@ -0,0 +1,34 @@ +package absyn; + +import env.Env; +import javaslang.collection.List; +import javaslang.collection.Tree; +import parse.Loc; +import types.ARRAY; +import types.RECORD; +import types.Type; + +import static semantic.SemanticHelper.undefined; + +public class TyRecord extends Ty { + + public final List elements; + + public TyRecord(Loc loc, List elements) { + super(loc); + this.elements = elements; + } + + @Override + public Tree.Node toTree() { + return Tree.of("TyRecord: ",elements.map(Parameter::toTree)); + } + + @Override + public Type semantic(Env env) { + List t_elements = elements.map(parameter -> parameter.semantic_(env)); + return new RECORD(elements); + } + + +} diff --git a/src/main/java/absyn/VarField.java b/src/main/java/absyn/VarField.java new file mode 100644 index 0000000..8ff59a4 --- /dev/null +++ b/src/main/java/absyn/VarField.java @@ -0,0 +1,49 @@ +package absyn; + +import env.Env; +import javaslang.collection.List; +import javaslang.collection.Tree; +import javaslang.control.Option; +import parse.Loc; +import semantic.SemanticHelper; +import types.INT; +import types.RECORD; +import types.Type; + +public class VarField extends Var { + + public final Var base; + public final String field; + + public VarField(Loc loc, Var base, String field) { + super(loc); + this.base = base; + this.field = field; + } + + @Override + public Tree.Node toTree() { + return Tree.of(annotateType("VarSubscript: "), + base.toTree(), + Tree.of(field)); + } + + @Override + protected Type semantic_(Env env) { + Type t_base = base.semantic(env); + + t_base = t_base.actual(); + if (!(t_base instanceof RECORD)) + throw SemanticHelper.recordMismatch(loc, t_base); + + List t_bodyParams = ((RECORD) t_base).elements; + Option t_p = t_bodyParams.find(p -> p.name == field); + if (t_p.isEmpty()) + throw SemanticHelper.unknownRecordParameter(loc, field); + + Type t_aux = t_p.get().semantic_(env); + //t_aux = t_aux.actual(); + return t_aux; + } + +} diff --git a/src/main/java/absyn/VarSubscript.java b/src/main/java/absyn/VarSubscript.java new file mode 100644 index 0000000..1a4627e --- /dev/null +++ b/src/main/java/absyn/VarSubscript.java @@ -0,0 +1,46 @@ +package absyn; + +import env.Env; +import javaslang.collection.Tree; +import parse.Loc; +import semantic.SemanticHelper; +import types.ARRAY; +import types.INT; +import types.Type; + +public class VarSubscript extends Var { + + public final Var base; + public final Exp indice; + + public VarSubscript(Loc loc, Var base, Exp indice) { + super(loc); + this.base = base; + this.indice = indice; + } + + @Override + public Tree.Node toTree() { + return Tree.of(annotateType("VarSubscript: "), + base.toTree(), + indice.toTree()); + } + + @Override + protected Type semantic_(Env env) { + Type t_init = indice.semantic(env); + if (!t_init.is(INT.T)) + throw SemanticHelper.typeMismatch(indice.loc,t_init, INT.T); + + Type t_base = base.semantic(env); + + t_base = t_base.actual(); + if (!(t_base instanceof ARRAY)) + throw SemanticHelper.arrayMismatch(loc,t_base); + + t_base = ((ARRAY)t_base).typeName; + + return t_base; + } + +} diff --git a/src/main/java/env/Env.java b/src/main/java/env/Env.java index dcb3547..7d6b921 100644 --- a/src/main/java/env/Env.java +++ b/src/main/java/env/Env.java @@ -4,38 +4,41 @@ public class Env { - public Table tenv; - public Table venv; - - public Env() { - tenv = new Table(); - put(tenv, "unit", UNIT.T); - put(tenv, "int", INT.T); - put(tenv, "real", REAL.T); - put(tenv, "bool", BOOL.T); - - venv = new Table(); - put(venv, "print_int", new FUNCTION(UNIT.T, INT.T)); - put(venv, "print_real", new FUNCTION(UNIT.T, REAL.T)); - put(venv, "print_unit", new FUNCTION(UNIT.T, UNIT.T)); - put(venv, "print_bool", new FUNCTION(UNIT.T, BOOL.T)); - put(venv, "round", new FUNCTION(INT.T, REAL.T)); - put(venv, "ceil", new FUNCTION(INT.T, REAL.T)); - put(venv, "floor", new FUNCTION(INT.T, REAL.T)); - put(venv, "real", new FUNCTION(REAL.T, INT.T)); - put(venv, "not", new FUNCTION(BOOL.T, BOOL.T)); - } - - @Override - public String toString() { - return "Env{" + - "tenv=" + tenv + - ", venv=" + venv + - '}'; - } - - private static void put(Table table, String name, E value) { - table.put(name.intern(), value); - } + public Table tenv; + public Table venv; + public boolean isWhile; + + public Env() { + isWhile = false; + + tenv = new Table(); + put(tenv, "unit", UNIT.T); + put(tenv, "int", INT.T); + put(tenv, "real", REAL.T); + put(tenv, "bool", BOOL.T); + + venv = new Table(); + put(venv, "print_int", new FUNCTION(UNIT.T, INT.T)); + put(venv, "print_real", new FUNCTION(UNIT.T, REAL.T)); + put(venv, "print_unit", new FUNCTION(UNIT.T, UNIT.T)); + put(venv, "print_bool", new FUNCTION(UNIT.T, BOOL.T)); + put(venv, "round", new FUNCTION(INT.T, REAL.T)); + put(venv, "ceil", new FUNCTION(INT.T, REAL.T)); + put(venv, "floor", new FUNCTION(INT.T, REAL.T)); + put(venv, "real", new FUNCTION(REAL.T, INT.T)); + put(venv, "not", new FUNCTION(BOOL.T, BOOL.T)); + } + + @Override + public String toString() { + return "Env{" + + "tenv=" + tenv + + ", venv=" + venv + + '}'; + } + + private static void put(Table table, String name, E value) { + table.put(name.intern(), value); + } } diff --git a/src/main/java/semantic/SemanticHelper.java b/src/main/java/semantic/SemanticHelper.java index 7009f97..c4f80ab 100644 --- a/src/main/java/semantic/SemanticHelper.java +++ b/src/main/java/semantic/SemanticHelper.java @@ -2,39 +2,90 @@ import error.CompilerError; +import javaslang.collection.List; import parse.Loc; import types.Type; public interface SemanticHelper { - static CompilerError typeMismatch(Loc loc, Type found, Type... expected) { - final StringBuilder builder = new StringBuilder(); - final int n = expected.length; - if (n > 0) { - builder.append(expected[0]); - if (n > 1) { - for (int i = 1; i < n - 2; i++) - builder.append(", ").append(expected[i]); - builder.append(" or ").append(expected[n - 1]); - } - } - return new CompilerError(loc, "type mismatch: found %s but expected %s", found, builder); - } - - static CompilerError undefined(Loc loc, String category, String name) { - return new CompilerError(loc, "undefined %s '%s'", category, name); - } - - static CompilerError notAFunction(Loc loc, String name) { - return new CompilerError(loc, "'%s' is not a function", name); - } - - static CompilerError tooFewArguments(Loc loc, String name) { - return new CompilerError(loc, "too few arguments in call to '%s'", name); - } - - static CompilerError tooMuchArguments(Loc loc, String name) { - return new CompilerError(loc, "too much arguments in call to '%s'", name); - } + static CompilerError typeMismatch(Loc loc, Type found, Type... expected) { + final StringBuilder builder = new StringBuilder(); + final int n = expected.length; + if (n > 0) { + builder.append(expected[0]); + if (n > 1) { + for (int i = 1; i < n - 2; i++) + builder.append(", ").append(expected[i]); + builder.append(" or ").append(expected[n - 1]); + } + } + return new CompilerError(loc, "type mismatch: found %s but expected %s", found, builder); + } + static CompilerError undefined(Loc loc, String category, String name) { + return new CompilerError(loc, "undefined %s '%s'", category, name); + } + + static CompilerError notAFunction(Loc loc, String name) { + return new CompilerError(loc, "'%s' is not a function", name); + } + + static CompilerError tooFewArguments(Loc loc, String name) { + return new CompilerError(loc, "too few arguments in call to '%s'", name); + } + + static CompilerError tooMuchArguments(Loc loc, String name) { + return new CompilerError(loc, "too much arguments in call to '%s'", name); + } + + static CompilerError breakOutWhile(Loc loc) { + return new CompilerError(loc, "break ins't in loop."); + } + + static CompilerError functionTypeMismatch(Loc loc, Type result, Type found) { + return new CompilerError(loc, "function type mismatch: found %s in body but expected %s", found, result); + } + + static CompilerError arrayMismatch(Loc loc, Type found) { + return new CompilerError(loc, "type mismatch: found %s but expected array type", found); + } + + static CompilerError recordMismatch(Loc loc, Type found) { + return new CompilerError(loc, "type mismatch: found %s but expected record type", found); + } + + static CompilerError duplicatedParameter(Loc loc, String parameter) { + return new CompilerError(loc, "parameter %s is duplicated", parameter); + } + + static CompilerError unknownRecordParameter(Loc loc, String parameter) { + return new CompilerError(loc, "record parameter %s is unknown", parameter); + } + + static CompilerError recordTypeMismatch(Loc loc, String name, Type found, Type... expected) { + final StringBuilder builder = new StringBuilder(); + final int n = expected.length; + if (n > 0) { + builder.append(expected[0]); + if (n > 1) { + for (int i = 1; i < n - 2; i++) + builder.append(", ").append(expected[i]); + builder.append(" or ").append(expected[n - 1]); + } + } + return new CompilerError(loc, "type mismatch in record parameter %s: found %s but expected %S", name, found, builder); + } + + static CompilerError missingParametersRecord(Loc loc, List list) { + final StringBuilder builder = new StringBuilder(); + final int n = list.size(); + if (n > 0) { + builder.append(list.get()); + if (n > 1) { + for (int i = 1; i < n; i++) + builder.append(", ").append(list.get(i)); + } + } + return new CompilerError(loc, "missing parameters %s in record", builder); + } } diff --git a/src/main/java/types/ARRAY.java b/src/main/java/types/ARRAY.java new file mode 100644 index 0000000..02aa19e --- /dev/null +++ b/src/main/java/types/ARRAY.java @@ -0,0 +1,15 @@ +package types; + +public class ARRAY extends Type { + + public final Type typeName; + + public ARRAY(Type typeName) { + this.typeName = typeName; + } + + @Override + public String toString() { + return "Array of "+ typeName; + } +} diff --git a/src/main/java/types/NAME.java b/src/main/java/types/NAME.java new file mode 100644 index 0000000..a9d4165 --- /dev/null +++ b/src/main/java/types/NAME.java @@ -0,0 +1,32 @@ +package types; + +import javaslang.collection.Tree; + +public class NAME extends Type { + public final String name; + public Type binding; + + public NAME(String name) { + this.name = name; + } + + @Override + public Tree.Node toTree() { + return Tree.of("NAME: " + name); + } + + @Override + public boolean is(Type type) { + return actual().is(type); + } + + @Override + public Type actual() { + return binding.actual(); + } + + @Override + public String toString() { + return name; + } +} diff --git a/src/main/java/types/RECORD.java b/src/main/java/types/RECORD.java new file mode 100644 index 0000000..ddc979f --- /dev/null +++ b/src/main/java/types/RECORD.java @@ -0,0 +1,19 @@ +package types; + +import absyn.Parameter; +import javaslang.collection.List; +import javaslang.collection.Tree; + +public class RECORD extends Type { + + public final List elements; + + public RECORD(List elements) { + this.elements = elements; + } + + @Override + public Tree.Node toTree() { + return Tree.of("RECORD", elements.map(Parameter::toTree)); + } +} diff --git a/src/main/java/types/Type.java b/src/main/java/types/Type.java index 0abb24f..aea4373 100644 --- a/src/main/java/types/Type.java +++ b/src/main/java/types/Type.java @@ -9,25 +9,29 @@ public abstract class Type implements ToTree { - @Override - public Node toTree() { - return Tree.of(toString()); - } + @Override + public Node toTree() { + return Tree.of(toString()); + } - @Override - public String toString() { - return ToStringBuilder.reflectionToString(this, ToStringStyle.SHORT_PREFIX_STYLE); - } + @Override + public String toString() { + return ToStringBuilder.reflectionToString(this, ToStringStyle.SHORT_PREFIX_STYLE); + } - // Verify if this type can be coerced to the given type. In - // general one type can be coerced to another type if and only if the - // types are the same. - public boolean is(Type type) { - return type == this; - } + public Type actual(){ + return this; + } - // Verify if this type can be coerced to any of the given types. - public boolean is(Type... types) { - return List.of(types).exists(t -> this.is(t)); - } + // Verify if this type can be coerced to the given type. In + // general one type can be coerced to another type if and only if the + // types are the same. + public boolean is(Type type) { + return type.actual() == this; + } + + // Verify if this type can be coerced to any of the given types. + public boolean is(Type... types) { + return List.of(types).exists(t -> this.is(t)); + } } diff --git a/src/main/jflex/lexer.jflex b/src/main/jflex/lexer.jflex index 395a079..3b07801 100644 --- a/src/main/jflex/lexer.jflex +++ b/src/main/jflex/lexer.jflex @@ -84,6 +84,10 @@ in { return tok(IN); } if { return tok(IF); } then { return tok(THEN); } else { return tok(ELSE); } +while { return tok(WHILE); } +do { return tok(DO); } +break { return tok(BREAK); } +function { return tok(FUNCTION); } {id} { return tok(ID, yytext().intern()); } @@ -93,12 +97,26 @@ else { return tok(ELSE); } "/" { return tok(DIV); } "&&" { return tok(AND); } "||" { return tok(OR); } + "(" { return tok(LPAREN); } ")" { return tok(RPAREN); } +"[" { return tok(LBRACK); } +"]" { return tok(RBRACK); } +"{" { return tok(LBRACE); } +"}" { return tok(RBRACE); } + "," { return tok(COMMA); } ";" { return tok(SEMICOLON); } ":" { return tok(COLON); } +"." { return tok(DOT); } "=" { return tok(EQ); } ":=" { return tok(ASSIGN); } +"==" { return tok(EQT); } +"!=" { return tok(NEQ); } +"<" { return tok(LT); } +"<=" { return tok(LE); } +">" { return tok(GT); } +">=" { return tok(GE); } +"@" { return tok(AT); } . { 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 9b17199..0c33ab4 100644 --- a/src/test/java/Test/SemantTest.java +++ b/src/test/java/Test/SemantTest.java @@ -113,4 +113,103 @@ public void testIf() throws Exception { "error.CompilerError: 1/14-1/17 type mismatch: found real but expected unit"); } + @Test + public void testBooleanArguments() throws Exception { + trun("2 == 2", BOOL.T); + trun("2 > 2", BOOL.T); + trun("2 < 2", BOOL.T); + trun("2 >= 2", BOOL.T); + trun("2 <= 2", BOOL.T); + trun("2 != 2", BOOL.T); + erun("2 => 2", "error.CompilerError: 1/3-1/4 Syntax error at '='"); + erun("2 =< 2", "error.CompilerError: 1/3-1/4 Syntax error at '='"); + erun("2 =! 2", "error.CompilerError: 1/3-1/4 Syntax error at '='"); + erun("2 == test", "error.CompilerError: 1/6-1/10 undefined variable 'test'"); + } + + @Test + public void testWhile() throws Exception { + trun("while true do 1", UNIT.T); + trun("while false do 1", UNIT.T); + trun("while 2 == 2 do 1", UNIT.T); + trun("while 2 > 2 do print_int(2)", UNIT.T); + trun("while 2 > 2 do let var x = 2 in x", UNIT.T); + trun("let var x = 2 var y = 2 in while x > y do print_int(x)", UNIT.T); + erun("while 2 do 1", "error.CompilerError: 1/7-1/8 type mismatch: found int but expected bool"); + erun("while print_int(2) do print_int(2)", "error.CompilerError: 1/7-1/19 type mismatch: found unit but expected bool"); + } + + @Test + public void testBreak() throws Exception { + trun("while true do break", UNIT.T); + trun("while true do let var x = 2 in break", UNIT.T); + erun("let var x = 2 in break", "error.CompilerError: 1/18-1/23 break ins't in loop."); + erun("break", "error.CompilerError: 1/1-1/6 break ins't in loop."); + erun("while true do let var x = 2 break in break", "error.CompilerError: 1/29-1/34 Syntax error at 'break'"); + } + + @Test + public void testFunction() throws Exception { + trun("let function teste(x:int):int = x in teste(2)", INT.T); + trun("let function teste(x:real):real = x in teste(2.2)", REAL.T); + trun("let function teste(x:bool):bool = x in teste(true)", BOOL.T); + trun("let function teste(x:unit):unit = x in teste(())", UNIT.T); + trun("let function teste(x:unit, y:unit):unit = x in teste((),())", UNIT.T); + trun("let function teste(x:int, y:int):int = x in teste(2 , 2)", INT.T); + trun("let function teste(x:real, y:real):real = x in teste(2.2 , 2.2)", REAL.T); + erun("let function teste(x:int):int = x in teste(2.2)", "error.CompilerError: 1/44-1/47 type mismatch: found real but expected int"); + erun("let function teste(x:int):real = x in teste(2)", "error.CompilerError: 1/5-1/35 function type mismatch: found int in body but expected real"); + erun("let function teste(x:real):int = x in teste(2)", "error.CompilerError: 1/5-1/35 function type mismatch: found real in body but expected int"); + erun("let function teste(x:int):int = x in teste(())", "error.CompilerError: 1/44-1/46 type mismatch: found unit but expected int"); + erun("let function teste(x:unit):unit = x in teste()", "error.CompilerError: 1/40-1/47 too few arguments in call to 'teste'"); + erun("let function teste(x:unit):unit = x in teste(2)", "error.CompilerError: 1/46-1/47 type mismatch: found int but expected unit"); + erun("let function teste(x:unit):int = x in teste(2)", "error.CompilerError: 1/5-1/35 function type mismatch: found unit in body but expected int"); + erun("let function teste(x:unit):int = x in teste(2.2)", "error.CompilerError: 1/5-1/35 function type mismatch: found unit in body but expected int"); + erun("let function teste(x:real):real = x in teste(2)", "error.CompilerError: 1/46-1/47 type mismatch: found int but expected real"); + erun("let function teste(x:real):real = x in teste(())", "error.CompilerError: 1/46-1/48 type mismatch: found unit but expected real"); + erun("let function teste(x:real):unit = x in teste(())", "error.CompilerError: 1/5-1/36 function type mismatch: found real in body but expected unit"); + erun("let function teste(x:unit):real = x in teste(())", "error.CompilerError: 1/5-1/36 function type mismatch: found unit in body but expected real"); + erun("let function teste(x:unit):real = x in teste(2.2)", "error.CompilerError: 1/5-1/36 function type mismatch: found unit in body but expected real"); + erun("let function teste(x:real, y:real):int = x in teste(2.2, 2.2)", "error.CompilerError: 1/5-1/43 function type mismatch: found real in body but expected int"); + erun("let function teste(x:real, y:real):real = x in teste(2.2, 2)", "error.CompilerError: 1/59-1/60 type mismatch: found int but expected real"); + erun("let function teste(x:real, y:real):real = x in teste(2, 2)", "error.CompilerError: 1/54-1/55 type mismatch: found int but expected real"); + erun("let function teste(x:unit, y:real):real = x in teste((), 2)", "error.CompilerError: 1/5-1/44 function type mismatch: found unit in body but expected real"); + } + + @Test + public void testArray() throws Exception { + trun("let type t1 = [int] var a1:t1 = @t1[10,20,30] in print_int(a1[2])", UNIT.T); + trun("let type t = [int] var v:t = @t[10,20,30] var x:int = v[1] var y:int = v[x] in x", INT.T); + trun("let type t = [int] var v:t = @t[10,20,30] var x :int= v[2+3] in 2", INT.T); + trun("let type t = [int] var v:t = @t[10,20,30] var x :int= v[2+3] in x", INT.T); + trun("let type t = [int] var v:t = @t[10,20] var x:int = v[2] in x", INT.T); + trun("let type t = [real] var v:t = @t[10.0,20.0] var x:real = v[2] in x", REAL.T); + trun("let type t = [unit] var v:t = @t[()] var x:unit = v[2] in x", UNIT.T); + trun("let type t1 = [int] type t2 = [t1] var a1 = @t2 [@t1[10,20], @t1[30]] in (a1[1][0]:=18; print_int(a1[1][0]))", UNIT.T); + erun("let var a1 = 2.3 var x = a[1] in print_int(x)", "error.CompilerError: 1/26-1/27 undefined variable 'a'"); + erun("let type t1 = [int] var a1 = @int[10,20,30] in print_int(a1)", "error.CompilerError: 1/30-1/44 type mismatch: found int but expected array type"); + erun("let type t1 = [abobrinha] var a1:t1 = @t1[10,20,30] in print_int(a1)", "error.CompilerError: 1/16-1/25 undefined type 'abobrinha'"); + erun("let type t = [int] var v:t = @t[10,20,30] var x = b[1] in x", "error.CompilerError: 1/51-1/52 undefined variable 'b'"); + erun("let type t1 = [int] var a1 = @t2[10,20,30] in print_int(a1[2])", "error.CompilerError: 1/30-1/43 undefined type 't2'"); + erun("let type t = [unit] var v:t = @t[(),1] var x:unit = v[2] in x", "error.CompilerError: 1/31-1/39 type mismatch: found int but expected unit"); + erun("let type t = [real] var v:t = @t[10.0,20.0] var x:int = v[2] in x", "error.CompilerError: 1/57-1/61 type mismatch: found real but expected int"); + erun("let type t = [real] var v:t = @t[10.0,20.0] var x:real = v[2.0] in x", "error.CompilerError: 1/60-1/63 type mismatch: found real but expected int"); + erun("let type t = [int] var v:t = @t[10,20,()] var x :int= v[2+3] in 2", "error.CompilerError: 1/30-1/42 type mismatch: found unit but expected int"); + erun("let type t = [int] var v:t = @t[10,20,30] var x:int = v[y] var y:int = v[1] in x", "error.CompilerError: 1/57-1/58 undefined variable 'y'"); + } + + @Test + public void testRegisters() throws Exception { + trun("let type t1 = [int] type t2 = {x:int, y:t1} var k = @t2{x=10, y=@t1[10,20,30]} in k.y[1]", INT.T); + trun("let type ponto = {x:real, y:int} var p:ponto = @ponto{x=2.3,y=8} var x : int = p.y in x", INT.T); + trun("let type ponto = {x:real, y:real} var p:ponto = @ponto{x=2.3,y=0.8} var x : real = p.x in 2", INT.T); + trun("let type ponto = {x:real, y:real} var p:ponto = @ponto{x=2.3,y=0.8} var x : real = p.x in x", REAL.T); + trun("let type ponto = {x:int, y:int} var p:ponto = @ponto{x=2,y=0} var x : int = p.x in 2", INT.T); + trun("let type ponto = {x:unit, y:unit} var p:ponto = @ponto{x=(),y=()} var x : unit = p.x in 2", INT.T); + trun("let type ponto = {x:unit, y:unit} var p:ponto = @ponto{x=(),y=()} var x : unit = p.x in ()", UNIT.T); + trun("let type ponto = {x:unit, y:unit} var p:ponto = @ponto{x=(),y=()} var x : unit = p.x in x", UNIT.T); + erun("let type ponto = {x:int, y:int} var p:ponto = @ponto{x=2,y=0} var x : real = p.x in 2", "error.CompilerError: 1/78-1/81 type mismatch: found int but expected real"); + erun("let type ponto = {x:real, y:real} var p:ponto = @ponto{x=2.3,y=0.8} var x : int = p.x in ()", "error.CompilerError: 1/83-1/86 type mismatch: found real but expected int"); + erun("let type ponto = {x:real, y:int} var p:ponto = @ponto{x=2.3,y=8} var x : real = p.y in x", "error.CompilerError: 1/81-1/84 type mismatch: found int but expected real"); + } }