summaryrefslogtreecommitdiff
path: root/typecheck/TypeCheckSimp.java
diff options
context:
space:
mode:
authorbd-912 <bdunahu@colostate.edu>2024-04-26 15:50:38 -0600
committerbd-912 <bdunahu@colostate.edu>2024-04-26 15:50:38 -0600
commit1851f5e76018ec1df3b55dce6cc9a64c9497bf7a (patch)
tree30f629f7b137a494d4202487f4e22df2d9456481 /typecheck/TypeCheckSimp.java
parent012298517078170762112abe2654dc69b2f146e1 (diff)
Rearrange directory structure
Diffstat (limited to 'typecheck/TypeCheckSimp.java')
-rw-r--r--typecheck/TypeCheckSimp.java1097
1 files changed, 1097 insertions, 0 deletions
diff --git a/typecheck/TypeCheckSimp.java b/typecheck/TypeCheckSimp.java
new file mode 100644
index 0000000..99fa187
--- /dev/null
+++ b/typecheck/TypeCheckSimp.java
@@ -0,0 +1,1097 @@
+package typecheck;
+
+import syntaxtree.*;
+import visitor.*;
+import st.*;
+import misc.*;
+import java.util.*;
+
+/**
+ * Provides default methods which visit each node in the tree in depth-first
+ * order. Your visitors may extend this class.
+ */
+public class TypeCheckSimp extends GJDepthFirst<TypeInstance,SymbolTable> {
+
+ private int offset;
+
+ private void printNode(Node n, SymbolTable symt, boolean enter, TypeEnum consensus) {
+ String str = "";
+ for (int i=0; i < this.offset; ++i)
+ str += ".";
+ if (enter)
+ str += "Visiting ";
+ else
+ str += "Leaving ";
+ str += "n.getClass().getSimpleName()";
+ if (!enter) {
+ if (consensus == TypeEnum.ERROR)
+ str += " did not type check.";
+ else
+ str += String.format(" found type %s", consensus);
+ }
+ MinimalLogger.info(str);
+ }
+
+ public TypeInstance visit(NodeList n, SymbolTable symt) {
+ ++this.offset;
+ this.printNode(n, symt, true, null);
+
+ TypeInstance ret = new TypeInstance(null, TypeEnum.CHECK);
+ int _count=0;
+ for ( Enumeration<Node> e = n.elements(); e.hasMoreElements(); ) {
+ TypeInstance node = e.nextElement().accept(this,symt);
+ e.nextElement().accept(this,symt);
+ if (node.getType() == TypeEnum.ERROR)
+ ret = node;
+ _count++;
+ }
+
+ this.printNode(n, symt, false, ret.getType());
+ --this.offset;
+ return ret;
+ }
+
+ public TypeInstance visit(NodeListOptional n, SymbolTable symt) {
+ ++this.offset;
+ this.printNode(n, symt, true, null);
+
+ TypeInstance ret;
+ if ( n.present() ) {
+ ret = new TypeInstance(null, TypeEnum.CHECK);
+ int _count=0;
+ for ( Enumeration<Node> e = n.elements(); e.hasMoreElements(); ) {
+ TypeInstance node = e.nextElement().accept(this,symt);
+ if (node.getType() == TypeEnum.ERROR)
+ ret = node;
+ _count++;
+ }
+ }
+ else
+ ret = new TypeInstance(null, TypeEnum.CHECK);
+
+ this.printNode(n, symt, false, ret.getType());
+ --this.offset;
+ return ret;
+ }
+
+ // FIXME
+ public TypeInstance visit(NodeOptional n, SymbolTable symt) {
+ ++this.offset;
+ this.printNode(n, symt, true, null);
+
+ TypeInstance ret;
+
+ if ( n.present() )
+ ret = n.node.accept(this,symt);
+ else
+ ret = new TypeInstance(null, TypeEnum.CHECK);
+
+ this.printNode(n, symt, false, ret.getType());
+ --this.offset;
+ return ret;
+ }
+
+ public TypeInstance visit(NodeSequence n, SymbolTable symt) {
+ ++this.offset;
+ this.printNode(n, symt, true, null);
+
+ TypeInstance ret = new TypeInstance(null, TypeEnum.CHECK);
+ int _count=0;
+ for ( Enumeration<Node> e = n.elements(); e.hasMoreElements(); ) {
+ TypeInstance node = e.nextElement().accept(this,symt);
+ if (node.getType() == TypeEnum.ERROR)
+ ret = node;
+ _count++;
+ }
+
+ this.printNode(n, symt, false, ret.getType());
+ --this.offset;
+ return ret;
+ }
+
+ public TypeInstance visit(NodeToken n, SymbolTable symt) {
+ // A fixed string token. '⌣'
+ String str = "";
+ for (int i=0; i < this.offset; ++i)
+ str += ".";
+ MinimalLogger.info(String.format("%sLeaving %s => %s",
+ str,
+ n.getClass().getSimpleName(),
+ n.toString()));
+ return null;
+ }
+
+ //
+ // User-generated visitor methods below
+ //
+
+ /**
+ * f0 -> MainClass()
+ * f1 -> ( TypeDeclaration() )*
+ * f2 -> <EOF>
+ */
+ public TypeInstance visit(Goal n, SymbolTable symt) {
+ ++this.offset;
+ this.printNode(n, symt, true, null);
+
+ TypeInstance ret = n.f0.accept(this, symt);
+ n.f1.accept(this, symt);
+ n.f2.accept(this, symt);
+
+ this.printNode(n, symt, false, ret.getType());
+ --this.offset;
+ return ret;
+ }
+
+ /**
+ * f0 -> "class"
+ * f1 -> Identifier()
+ * f2 -> "{"
+ * f3 -> "public"
+ * f4 -> "static"
+ * f5 -> "void"
+ * f6 -> "main"
+ * f7 -> "("
+ * f8 -> "String"
+ * f9 -> "["
+ * f10 -> "]"
+ * f11 -> Identifier()
+ * f12 -> ")"
+ * f13 -> "{"
+ * f14 -> ( VarDeclaration() )*
+ * f15 -> ( Statement() )*
+ * f16 -> "}"
+ * f17 -> "}"
+ */
+ public TypeInstance visit(MainClass n, SymbolTable symt) {
+ ++this.offset;
+ this.printNode(n, symt, true, null);
+
+ n.f0.accept(this, symt);
+ TypeInstance name = n.f1.accept(this, symt);
+ n.f2.accept(this, symt);
+ n.f3.accept(this, symt);
+ n.f4.accept(this, symt);
+ n.f5.accept(this, symt);
+ n.f6.accept(this, symt);
+ n.f7.accept(this, symt);
+ n.f8.accept(this, symt);
+ n.f9.accept(this, symt);
+ n.f10.accept(this, symt);
+ // TypeInstance args = n.f11.accept(this, symt);
+ n.f12.accept(this, symt);
+ n.f13.accept(this, symt);
+ TypeInstance var_dec = n.f14.accept(this, symt);
+ TypeInstance stmt = n.f15.accept(this, symt);
+ n.f16.accept(this, symt);
+ n.f17.accept(this, symt);
+
+ this.printNode(n, symt, false, stmt.getType());
+ --this.offset;
+ return stmt;
+ }
+
+ /**
+ * f0 -> ClassDeclaration()
+ * | ClassExtendsDeclaration()
+ */
+ public TypeInstance visit(TypeDeclaration n, SymbolTable symt) {
+ ++this.offset;
+ this.printNode(n, symt, true, null);
+
+ TypeInstance ret = n.f0.accept(this, symt);
+
+ this.printNode(n, symt, false, ret.getType());
+ --this.offset;
+ return ret;
+ }
+
+ /**
+ * f0 -> "class"
+ * f1 -> Identifier()
+ * f2 -> "{"
+ * f3 -> ( VarDeclaration() )*
+ * f4 -> ( MethodDeclaration() )*
+ * f5 -> "}"
+ */
+ public TypeInstance visit(ClassDeclaration n, SymbolTable symt) {
+ ++this.offset;
+ this.printNode(n, symt, true, null);
+
+ n.f0.accept(this, symt);
+ TypeInstance id = n.f1.accept(this, symt);
+ n.f2.accept(this, symt);
+ TypeInstance vars = n.f3.accept(this, symt);
+ TypeInstance mtds = n.f4.accept(this, symt);
+ n.f5.accept(this, symt);
+ TypeInstance ret = (vars.hasChecked() &&
+ mtds.hasChecked()) ?
+ new TypeInstance(null, TypeEnum.CHECK) :
+ new TypeInstance(null, TypeEnum.ERROR);
+
+ this.printNode(n, symt, false, ret.getType());
+ --this.offset;
+ return ret;
+ }
+
+ /**
+ * f0 -> "class"
+ * f1 -> Identifier()
+ * f2 -> "extends"
+ * f3 -> Identifier()
+ * f4 -> "{"
+ * f5 -> ( VarDeclaration() )*
+ * f6 -> ( MethodDeclaration() )*
+ * f7 -> "}"
+ */
+ public TypeInstance visit(ClassExtendsDeclaration n, SymbolTable symt) {
+ ++this.offset;
+ this.printNode(n, symt, true, null);
+
+ n.f0.accept(this, symt);
+ TypeInstance id = n.f1.accept(this, symt);
+ n.f2.accept(this, symt);
+ TypeInstance ext = n.f3.accept(this, symt);
+ n.f4.accept(this, symt);
+ TypeInstance vars = n.f5.accept(this, symt);
+ TypeInstance mehs = n.f6.accept(this, symt);
+ n.f7.accept(this, symt);
+ TypeInstance ret = (id.getType() == TypeEnum.classname &&
+ vars.hasChecked() &&
+ mehs.hasChecked()) ?
+ new TypeInstance(null, TypeEnum.CHECK) :
+ new TypeInstance(null, TypeEnum.ERROR);
+
+ this.printNode(n, symt, false, ret.getType());
+ --this.offset;
+ return ret;
+ }
+
+ // FIXME (this may be ST-only)
+ /**
+ * f0 -> Type()
+ * f1 -> Identifier()
+ * f2 -> ";"
+ */
+ public TypeInstance visit(VarDeclaration n, SymbolTable symt) {
+ ++this.offset;
+ this.printNode(n, symt, true, null);
+
+ TypeInstance ret = n.f0.accept(this, symt);
+ n.f1.accept(this, symt);
+ n.f2.accept(this, symt);
+
+ this.printNode(n, symt, false, ret.getType());
+ --this.offset;
+ return ret;
+ }
+
+ // FIXME
+ /**
+ * [7.5]: Parameters identifiers are distinct, local vars are distinct,
+ * (vars in scope?), all statements type check
+ *
+ * f0 -> "public"
+ * f1 -> Type()
+ * f2 -> Identifier()
+ * f3 -> "("
+ * f4 -> ( FormalParameterList() )?
+ * f5 -> ")"
+ * f6 -> "{"
+ * f7 -> ( VarDeclaration() )*
+ * f8 -> ( Statement() )*
+ * f9 -> "return"
+ * f10 -> Expression()
+ * f11 -> ";"
+ * f12 -> "}"
+ */
+ public TypeInstance visit(MethodDeclaration n, SymbolTable symt) {
+ ++this.offset;
+ this.printNode(n, symt, true, null);
+
+ MethodInstance self = symt.getMethod(n.f2.f0.tokenImage);
+ n.f0.accept(this, symt);
+ TypeInstance ret_type = n.f1.accept(this, symt);
+ n.f2.accept(this, symt);
+ n.f3.accept(this, symt);
+ n.f4.accept(this, symt);
+ n.f5.accept(this, symt);
+ n.f6.accept(this, symt);
+ n.f7.accept(this, symt);
+ TypeInstance stmt = n.f8.accept(this, symt);
+ n.f9.accept(this, symt);
+ TypeInstance rtrn = n.f10.accept(this, symt);
+ n.f11.accept(this, symt);
+ n.f12.accept(this, symt);
+ TypeInstance ret = (self.getReturn() == rtrn.getType() && // FIXME I am checking that the rtrn matches the method's declared return type. Is this in the document?
+ stmt.hasChecked()) ?
+ new TypeInstance(null, TypeEnum.CHECK) :
+ new TypeInstance(null, TypeEnum.ERROR);
+
+ this.printNode(n, symt, false, ret.getType());
+ --this.offset;
+ return ret;
+ }
+
+ /**
+ * f0 -> FormalParameter()
+ * f1 -> ( FormalParameterRest() )*
+ */
+ public TypeInstance visit(FormalParameterList n, SymbolTable symt) {
+ ++this.offset;
+ this.printNode(n, symt, true, null);
+
+ TypeInstance _ret=null;
+ TypeInstance para1 = n.f0.accept(this, symt);
+ TypeInstance parar = n.f1.accept(this, symt);
+ TypeInstance ret = (para1.hasChecked() &&
+ parar.hasChecked()) ?
+ new TypeInstance(null, TypeEnum.CHECK) :
+ new TypeInstance(null, TypeEnum.ERROR);
+
+ this.printNode(n, symt, false, ret.getType());
+ --this.offset;
+ return ret;
+ }
+
+ /**
+ * f0 -> Type()
+ * f1 -> Identifier()
+ */
+ public TypeInstance visit(FormalParameter n, SymbolTable symt) {
+ ++this.offset;
+ this.printNode(n, symt, true, null);
+
+ TypeInstance ret = n.f0.accept(this, symt);
+ n.f1.accept(this, symt);
+
+ this.printNode(n, symt, false, ret.getType());
+ --this.offset;
+ return ret;
+ }
+
+ /**
+ * f0 -> ","
+ * f1 -> FormalParameter()
+ */
+ public TypeInstance visit(FormalParameterRest n, SymbolTable symt) {
+ ++this.offset;
+ this.printNode(n, symt, true, null);
+
+ n.f0.accept(this, symt);
+ TypeInstance ret = n.f1.accept(this, symt);
+
+ this.printNode(n, symt, false, ret.getType());
+ --this.offset;
+ return ret;
+ }
+
+ /**
+ * f0 -> ArrayType()
+ * | BooleanType()
+ * | IntegerType()
+ * | Identifier()
+ */
+ public TypeInstance visit(Type n, SymbolTable symt) {
+ ++this.offset;
+ this.printNode(n, symt, true, null);
+
+ TypeInstance ret = n.f0.accept(this, symt);
+
+ this.printNode(n, symt, false, ret.getType());
+ --this.offset;
+ return ret;
+ }
+
+ /**
+ * f0 -> "int"
+ * f1 -> "["
+ * f2 -> "]"
+ */
+ public TypeInstance visit(ArrayType n, SymbolTable symt) {
+ ++this.offset;
+ this.printNode(n, symt, true, null);
+
+ TypeInstance ret = new TypeInstance(null, TypeEnum.intarray);
+
+ this.printNode(n, symt, false, ret.getType());
+ --this.offset;
+ return ret;
+ }
+
+ /**
+ * f0 -> "boolean"
+ */
+ public TypeInstance visit(BooleanType n, SymbolTable symt) {
+ ++this.offset;
+ this.printNode(n, symt, true, null);
+
+ TypeInstance ret = new TypeInstance(null, TypeEnum.bool);
+
+ this.printNode(n, symt, false, ret.getType());
+ --this.offset;
+ return ret;
+ }
+
+ /**
+ * f0 -> "int"
+ */
+ public TypeInstance visit(IntegerType n, SymbolTable symt) {
+ ++this.offset;
+ this.printNode(n, symt, true, null);
+
+ TypeInstance ret = new TypeInstance(null, TypeEnum.integer);
+
+ this.printNode(n, symt, false, ret.getType());
+ --this.offset;
+ return ret;
+ }
+
+ /**
+ * f0 -> Block()
+ * | AssignmentStatement()
+ * | ArrayAssignmentStatement()
+ * | IfStatement()
+ * | WhileStatement()
+ * | PrintStatement()
+ */
+ public TypeInstance visit(Statement n, SymbolTable symt) {
+ ++this.offset;
+ this.printNode(n, symt, true, null);
+
+ TypeInstance ret = n.f0.accept(this, symt);
+
+ this.printNode(n, symt, false, ret.getType());
+ --this.offset;
+ return ret;
+ }
+
+ /**
+ * f0 -> "{"
+ * f1 -> ( Statement() )*
+ * f2 -> "}"
+ */
+ public TypeInstance visit(Block n, SymbolTable symt) {
+ ++this.offset;
+ this.printNode(n, symt, true, null);
+
+ n.f0.accept(this, symt);
+ TypeInstance ret = n.f1.accept(this, symt);
+ n.f2.accept(this, symt);
+
+ this.printNode(n, symt, false, ret.getType());
+ --this.offset;
+ return ret;
+ }
+
+ // FIXME FIXME FIXME
+ // Given we only have a few types, what is a subtype of what?
+ /**
+ * [23]: Expression is a subtype of identifier, and e typechecks*
+ *
+ * f0 -> Identifier()
+ * f1 -> "="
+ * f2 -> Expression()
+ * f3 -> ";"
+ */
+ public TypeInstance visit(AssignmentStatement n, SymbolTable symt) {
+ ++this.offset;
+ this.printNode(n, symt, true, null);
+
+ TypeInstance lhs = n.f0.accept(this, symt);
+ n.f1.accept(this, symt);
+ TypeInstance rhs = n.f2.accept(this, symt);
+ n.f3.accept(this, symt);
+ TypeInstance ret = (lhs.sameType(rhs)) ?
+ new TypeInstance(null, TypeEnum.CHECK) :
+ new TypeInstance(null, TypeEnum.ERROR);
+
+ this.printNode(n, symt, false, ret.getType());
+ --this.offset;
+ return ret;
+ }
+
+ // FIXME (this may be done)
+ /**
+ * [24]: Identifier is an integer array, expressions are both integers
+ *
+ * f0 -> Identifier()
+ * f1 -> "["
+ * f2 -> Expression()
+ * f3 -> "]"
+ * f4 -> "="
+ * f5 -> Expression()
+ * f6 -> ";"
+ */
+ public TypeInstance visit(ArrayAssignmentStatement n, SymbolTable symt) {
+ ++this.offset;
+ this.printNode(n, symt, true, null);
+
+ TypeInstance id = n.f0.accept(this, symt);
+ n.f1.accept(this, symt);
+ TypeInstance index = n.f2.accept(this, symt);
+ n.f3.accept(this, symt);
+ n.f4.accept(this, symt);
+ TypeInstance value = n.f5.accept(this, symt);
+ n.f6.accept(this, symt);
+ TypeInstance ret = (id.getType() == TypeEnum.intarray &&
+ index.getType() == TypeEnum.integer &&
+ value.getType() == TypeEnum.integer) ?
+ new TypeInstance(null, TypeEnum.CHECK) :
+ new TypeInstance(null, TypeEnum.ERROR);
+
+ this.printNode(n, symt, false, ret.getType());
+ --this.offset;
+ return ret;
+ }
+
+ /**
+ * DONE [25]: Expression is a bool, both statements type-check
+ *
+ * f0 -> "if"
+ * f1 -> "("
+ * f2 -> Expression()
+ * f3 -> ")"
+ * f4 -> Statement()
+ * f5 -> "else"
+ * f6 -> Statement()
+ */
+ public TypeInstance visit(IfStatement n, SymbolTable symt) {
+ ++this.offset;
+ this.printNode(n, symt, true, null);
+
+ n.f0.accept(this, symt);
+ n.f1.accept(this, symt);
+ TypeInstance expr = n.f2.accept(this, symt);
+ n.f3.accept(this, symt);
+ TypeInstance stmt1 = n.f4.accept(this, symt);
+ n.f5.accept(this, symt);
+ TypeInstance stmt2 = n.f6.accept(this, symt);
+ TypeInstance ret = (expr.getType() == TypeEnum.bool &&
+ stmt1.getType() == stmt2.getType() &&
+ stmt1.hasChecked()) ?
+ new TypeInstance(null, TypeEnum.CHECK) :
+ new TypeInstance(null, TypeEnum.ERROR);
+
+ this.printNode(n, symt, false, ret.getType());
+ --this.offset;
+ return ret;
+
+ }
+
+ /**
+ * DONE [26]: Expression is a bool, statement type-checks
+ *
+ * f0 -> "while"
+ * f1 -> "("
+ * f2 -> Expression()
+ * f3 -> ")"
+ * f4 -> Statement()
+ */
+ public TypeInstance visit(WhileStatement n, SymbolTable symt) {
+ ++this.offset;
+ this.printNode(n, symt, true, null);
+
+ n.f0.accept(this, symt);
+ n.f1.accept(this, symt);
+ TypeInstance expr = n.f2.accept(this, symt);
+ n.f3.accept(this, symt);
+ TypeInstance stmt = n.f4.accept(this, symt);
+ TypeInstance ret = (expr.getType() == TypeEnum.bool &&
+ stmt.hasChecked()) ?
+ new TypeInstance(null, TypeEnum.CHECK) :
+ new TypeInstance(null, TypeEnum.ERROR);
+
+ this.printNode(n, symt, false, ret.getType());
+ --this.offset;
+ return ret;
+ }
+
+ /**
+ * DONE [27]: Expression is an integer
+ *
+ * f0 -> "System.out.println"
+ * f1 -> "("
+ * f2 -> Expression()
+ * f3 -> ")"
+ * f4 -> ";"
+ */
+ public TypeInstance visit(PrintStatement n, SymbolTable symt) {
+ ++this.offset;
+ this.printNode(n, symt, true, null);
+
+ n.f0.accept(this, symt);
+ n.f1.accept(this, symt);
+ TypeInstance ret = n.f2.accept(this, symt);
+ n.f3.accept(this, symt);
+ n.f4.accept(this, symt);
+ ret = (ret.getType() == TypeEnum.integer) ?
+ new TypeInstance(null, TypeEnum.CHECK) :
+ new TypeInstance(null, TypeEnum.ERROR);
+
+ this.printNode(n, symt, false, ret.getType());
+ --this.offset;
+ return ret;
+ }
+
+ /**
+ * f0 -> AndExpression()
+ * | CompareExpression()
+ * | PlusExpression()
+ * | MinusExpression()
+ * | TimesExpression()
+ * | ArrayLookup()
+ * | ArrayLength()
+ * | MessageSend()
+ * | PrimaryExpression()
+ */
+ public TypeInstance visit(Expression n, SymbolTable symt) {
+ ++this.offset;
+ this.printNode(n, symt, true, null);
+
+ TypeInstance ret = n.f0.accept(this, symt);
+
+ this.printNode(n, symt, false, ret.getType());
+ --this.offset;
+ return ret;
+ }
+
+ /**
+ * DONE [28]: If expressions are both booleans, return is a boolean
+ *
+ * f0 -> PrimaryExpression()
+ * f1 -> "&&"
+ * f2 -> PrimaryExpression()
+ */
+ public TypeInstance visit(AndExpression n, SymbolTable symt) {
+ ++this.offset;
+ this.printNode(n, symt, true, null);
+
+ TypeInstance oper1 = n.f0.accept(this, symt);
+ n.f1.accept(this, symt);
+ TypeInstance oper2 = n.f2.accept(this, symt);
+ TypeInstance ret = (oper1.getType() == TypeEnum.bool &&
+ oper2.getType() == TypeEnum.bool) ?
+ new TypeInstance(null, TypeEnum.bool) :
+ new TypeInstance(null, TypeEnum.ERROR);
+
+ this.printNode(n, symt, false, ret.getType());
+ --this.offset;
+ return ret;
+ }
+
+ /**
+ * DONE [29]: If expressions are both integers, return is a boolean
+ *
+ * f0 -> PrimaryExpression()
+ * f1 -> "<"
+ * f2 -> PrimaryExpression()
+ */
+ public TypeInstance visit(CompareExpression n, SymbolTable symt) {
+ ++this.offset;
+ this.printNode(n, symt, true, null);
+
+ TypeInstance oper1 = n.f0.accept(this, symt);
+ n.f1.accept(this, symt);
+ TypeInstance oper2 = n.f2.accept(this, symt);
+ TypeInstance ret = (oper1.getType() == TypeEnum.integer &&
+ oper2.getType() == TypeEnum.integer) ?
+ new TypeInstance(null, TypeEnum.bool) :
+ new TypeInstance(null, TypeEnum.ERROR);
+
+ this.printNode(n, symt, false, ret.getType());
+ --this.offset;
+ return ret;
+ }
+
+ /**
+ * DONE [30]: If expressions are both integers, return is an integer
+ *
+ * f0 -> PrimaryExpression()
+ * f1 -> "+"
+ * f2 -> PrimaryExpression()
+ */
+ public TypeInstance visit(PlusExpression n, SymbolTable symt) {
+ ++this.offset;
+ this.printNode(n, symt, true, null);
+
+ TypeInstance oper1 = n.f0.accept(this, symt);
+ n.f1.accept(this, symt);
+ TypeInstance oper2 = n.f2.accept(this, symt);
+ TypeInstance ret = (oper1.getType() == TypeEnum.integer &&
+ oper2.getType() == TypeEnum.integer) ?
+ new TypeInstance(null, TypeEnum.integer) :
+ new TypeInstance(null, TypeEnum.ERROR);
+
+ this.printNode(n, symt, false, ret.getType());
+ --this.offset;
+ return ret;
+ }
+
+ /**
+ * DONE [31]: If expressions are both integers, return is an integer
+ *
+ * f0 -> PrimaryExpression()
+ * f1 -> "-"
+ * f2 -> PrimaryExpression()
+ */
+ public TypeInstance visit(MinusExpression n, SymbolTable symt) {
+ ++this.offset;
+ this.printNode(n, symt, true, null);
+
+ TypeInstance oper1 = n.f0.accept(this, symt);
+ n.f1.accept(this, symt);
+ TypeInstance oper2 = n.f2.accept(this, symt);
+ TypeInstance ret = (oper1.getType() == TypeEnum.integer &&
+ oper2.getType() == TypeEnum.integer) ?
+ new TypeInstance(null, TypeEnum.integer) :
+ new TypeInstance(null, TypeEnum.ERROR);
+
+ this.printNode(n, symt, false, ret.getType());
+ --this.offset;
+ return ret;
+ }
+
+ /**
+ * DONE [32]: If expressions are both integers, return is an integer
+ *
+ * f0 -> PrimaryExpression()
+ * f1 -> "*"
+ * f2 -> PrimaryExpression()
+ */
+ public TypeInstance visit(TimesExpression n, SymbolTable symt) {
+ ++this.offset;
+ this.printNode(n, symt, true, null);
+
+ TypeInstance oper1 = n.f0.accept(this, symt);
+ n.f1.accept(this, symt);
+ TypeInstance oper2 = n.f2.accept(this, symt);
+ TypeInstance ret = (oper1.getType() == TypeEnum.integer &&
+ oper2.getType() == TypeEnum.integer) ?
+ new TypeInstance(null, TypeEnum.integer) :
+ new TypeInstance(null, TypeEnum.ERROR);
+
+ this.printNode(n, symt, false, ret.getType());
+ --this.offset;
+ return ret;
+ }
+
+ /**
+ * DONE [33]: If expr1 is an integer array and expr2 is an int,
+ * return is an int
+ *
+ * f0 -> PrimaryExpression()
+ * f1 -> "["
+ * f2 -> PrimaryExpression()
+ * f3 -> "]"
+ */
+ public TypeInstance visit(ArrayLookup n, SymbolTable symt) {
+ ++this.offset;
+ this.printNode(n, symt, true, null);
+
+ TypeInstance array = n.f0.accept(this, symt);
+ n.f1.accept(this, symt);
+ TypeInstance index = n.f2.accept(this, symt);
+ n.f3.accept(this, symt);
+ TypeInstance ret = (array.getType() == TypeEnum.intarray &&
+ index.getType() == TypeEnum.integer) ?
+ new TypeInstance(null, TypeEnum.integer) :
+ new TypeInstance(null, TypeEnum.ERROR);
+
+ this.printNode(n, symt, false, ret.getType());
+ --this.offset;
+ return ret;
+ }
+
+ /**
+ * DONE [34]: If expr1 is an integer array, return is an int
+ *
+ * f0 -> PrimaryExpression()
+ * f1 -> "."
+ * f2 -> "length"
+ */
+ public TypeInstance visit(ArrayLength n, SymbolTable symt) {
+ ++this.offset;
+ this.printNode(n, symt, true, null);
+
+ TypeInstance ret = n.f0.accept(this, symt);
+ n.f1.accept(this, symt);
+ n.f2.accept(this, symt);
+ ret = (ret.getType() == TypeEnum.intarray) ? new TypeInstance(null, TypeEnum.integer) :
+ new TypeInstance(null, TypeEnum.ERROR);
+
+ this.printNode(n, symt, false, ret.getType());
+ --this.offset;
+ return ret;
+ }
+
+ // FIXME FIXME FIXME
+ /**
+ * [35]: PrimaryExpr must be a classname, id must be a method name, expressionlist must be correct?
+ *
+ * f0 -> PrimaryExpression()
+ * f1 -> "."
+ * f2 -> Identifier()
+ * f3 -> "("
+ * f4 -> ( ExpressionList() )?
+ * f5 -> ")"
+ */
+ public TypeInstance visit(MessageSend n, SymbolTable symt) {
+ ++this.offset;
+ this.printNode(n, symt, true, null);
+
+ // this MUST be an instance of a class!
+ TypeInstance t = n.f0.accept(this, symt);
+ ClassInstance c = t.getClassInstance();
+ n.f1.accept(this, symt);
+ n.f2.accept(this, symt);
+ MethodInstance m = symt.getMethod(n.f2.f0.tokenImage);
+ n.f3.accept(this, symt);
+ n.f4.accept(this, symt);
+ n.f5.accept(this, symt);
+ --this.offset;
+ return (true) ?
+ new TypeInstance(null, m.getReturn()) :
+ new TypeInstance(null, TypeEnum.ERROR);
+ }
+
+ // FIXME
+ /**
+ * f0 -> Expression()
+ * f1 -> ( ExpressionRest() )*
+ */
+ public TypeInstance visit(ExpressionList n, SymbolTable symt) {
+ ++this.offset;
+ this.printNode(n, symt, true, null);
+
+ TypeInstance expr1 = n.f0.accept(this, symt);
+ TypeInstance exprr = n.f1.accept(this, symt);
+ TypeInstance ret = (expr1.hasChecked() &&
+ exprr.hasChecked()) ?
+ new TypeInstance(null, TypeEnum.CHECK) :
+ new TypeInstance(null, TypeEnum.ERROR);
+
+ this.printNode(n, symt, false, ret.getType());
+ --this.offset;
+ return ret;
+ }
+
+ /**
+ * f0 -> ","
+ * f1 -> Expression()
+ */
+ public TypeInstance visit(ExpressionRest n, SymbolTable symt) {
+ ++this.offset;
+ this.printNode(n, symt, true, null);
+
+ n.f0.accept(this, symt);
+ TypeInstance ret = n.f1.accept(this, symt);
+
+ this.printNode(n, symt, false, ret.getType());
+ --this.offset;
+ return ret;
+ }
+
+ /**
+ * f0 -> IntegerLiteral()
+ * | TrueLiteral()
+ * | FalseLiteral()
+ * | Identifier()
+ * | ThisExpression()
+ * | ArrayAllocationExpression()
+ * | AllocationExpression()
+ * | NotExpression()
+ * | BracketExpression()
+ */
+ public TypeInstance visit(PrimaryExpression n, SymbolTable symt) {
+ ++this.offset;
+ this.printNode(n, symt, true, null);
+
+ TypeInstance ret = n.f0.accept(this, symt);
+
+ this.printNode(n, symt, false, ret.getType());
+ --this.offset;
+ return ret;
+ }
+
+ /**
+ * DONE [36]: return is an int
+ *
+ *
+ * f0 -> <INTEGER_LITERAL>
+ */
+ public TypeInstance visit(IntegerLiteral n, SymbolTable symt) {
+ ++this.offset;
+ this.printNode(n, symt, true, null);
+
+ this.printNode(n, symt, false, TypeEnum.integer);
+ --this.offset;
+ return new TypeInstance(null, TypeEnum.integer);
+ }
+
+ /**
+ * DONE [37]: return is a bool
+ *
+ * f0 -> "true"
+ */
+ public TypeInstance visit(TrueLiteral n, SymbolTable symt) {
+ ++this.offset;
+ this.printNode(n, symt, true, null);
+
+ this.printNode(n, symt, false, TypeEnum.bool);
+ --this.offset;
+ return new TypeInstance(null, TypeEnum.bool);
+ }
+
+ /**
+ * DONE [38]: return is a bool
+ *
+ * f0 -> "false"
+ */
+ public TypeInstance visit(FalseLiteral n, SymbolTable symt) {
+ ++this.offset;
+ this.printNode(n, symt, true, null);
+
+ this.printNode(n, symt, false, TypeEnum.bool);
+ --this.offset;
+ return new TypeInstance(null, TypeEnum.bool);
+ }
+
+ // FIXME
+ /**
+ * [39]: id is a symbol in the current domain, return is id's type
+ *
+ * f0 -> <IDENTIFIER>
+ */
+ public TypeInstance visit(Identifier n, SymbolTable symt) {
+ ++this.offset;
+ this.printNode(n, symt, true, null);
+
+ TypeInstance type;
+ TypeInstance ret;
+ ClassInstance cls;
+ if ((cls = symt.getClass(n.f0.tokenImage)) != null) {
+ // covers "anonymous" instance
+ ret = new TypeInstance(cls.getName(),
+ TypeEnum.classname);
+ ret.addClassInstance(cls);
+ } else {
+ if ((type = symt.getType(n.f0.tokenImage)) != null) {
+ ret = new TypeInstance(type.getName(),
+ type.getType());
+ ret.addClassInstance(type.getClassInstance());
+ } else
+ ret = new TypeInstance(null, TypeEnum.ERROR);
+ }
+
+ this.printNode(n, symt, false, ret.getType());
+ --this.offset;
+ return ret;
+ }
+
+ // FIXME FIXME FIXME
+ /**
+ * [40]: method exists? but where is the token?
+ *
+ * f0 -> "this"
+ */
+ public TypeInstance visit(ThisExpression n, SymbolTable symt) {
+ ++this.offset;
+ this.printNode(n, symt, true, null);
+
+ n.f0.accept(this, symt);
+ TypeInstance ret = new TypeInstance(null, TypeEnum.CHECK);
+
+ this.printNode(n, symt, false, ret.getType());
+ --this.offset;
+ return ret;
+ }
+
+ /**
+ * DONE [41]: if expression is an integer, return is an int array
+ *
+ * f0 -> "new"
+ * f1 -> "int"
+ * f2 -> "["
+ * f3 -> Expression()
+ * f4 -> "]"
+ */
+ public TypeInstance visit(ArrayAllocationExpression n, SymbolTable symt) {
+ ++this.offset;
+ this.printNode(n, symt, true, null);
+
+ n.f0.accept(this, symt);
+ n.f1.accept(this, symt);
+ n.f2.accept(this, symt);
+ TypeInstance ret = n.f3.accept(this, symt);
+ n.f4.accept(this, symt);
+ ret = (ret.getType() == TypeEnum.integer) ? new TypeInstance(null, TypeEnum.intarray) :
+ new TypeInstance(null, TypeEnum.ERROR);
+
+ this.printNode(n, symt, false, ret.getType());
+ --this.offset;
+ return ret;
+ }
+
+ // FIXME
+ /**
+ * [42]:
+ *
+ * f0 -> "new"
+ * f1 -> Identifier()
+ * f2 -> "("
+ * f3 -> ")"
+ */
+ public TypeInstance visit(AllocationExpression n, SymbolTable symt) {
+ ++this.offset;
+ this.printNode(n, symt, true, null);
+
+ n.f0.accept(this, symt);
+ TypeInstance ret = n.f1.accept(this, symt);
+ n.f2.accept(this, symt);
+ n.f3.accept(this, symt);
+
+ this.printNode(n, symt, false, ret.getType());
+ --this.offset;
+ return ret;
+ }
+
+ /**
+ * [43]: if expression is a boolean, return is a boolean
+ *
+ * f0 -> "!"
+ * f1 -> Expression()
+ */
+ public TypeInstance visit(NotExpression n, SymbolTable symt) {
+ ++this.offset;
+ this.printNode(n, symt, true, null);
+
+ n.f0.accept(this, symt);
+ TypeInstance ret = n.f1.accept(this, symt);
+
+ this.printNode(n, symt, false, ret.getType());
+ --this.offset;
+ return (ret.getType() == TypeEnum.bool) ? ret : new TypeInstance(null, TypeEnum.ERROR);
+ }
+
+ /**
+ * [44]: if e is a type, return is that same type
+ *
+ * f0 -> "("
+ * f1 -> Expression()
+ * f2 -> ")"
+ */
+ public TypeInstance visit(BracketExpression n, SymbolTable symt) {
+ ++this.offset;
+ this.printNode(n, symt, true, null);
+
+ n.f0.accept(this, symt);
+ TypeInstance ret = n.f1.accept(this, symt);
+ n.f2.accept(this, symt);
+
+ this.printNode(n, symt, false, ret.getType());
+ --this.offset;
+ return ret;
+ }
+
+}