package cd.frontend.parser; import cd.frontend.parser.JavaliParser.*; import cd.ir.Ast; import cd.ir.Ast.*; import cd.ir.Ast.BinaryOp.BOp; import cd.ir.Ast.UnaryOp.UOp; import org.antlr.v4.runtime.tree.ParseTree; import org.antlr.v4.runtime.tree.TerminalNode; import java.util.ArrayList; import java.util.List; public final class JavaliAstVisitor extends JavaliBaseVisitor { public List classDecls = new ArrayList<>(); @Override public Ast visitUnit(UnitContext ctx) { for (ClassDeclContext classDeclContext : ctx.classDecl()) classDecls.add((ClassDecl) visit(classDeclContext)); return new Seq(new ArrayList<>(classDecls)); } @Override public Ast visitClassDecl(ClassDeclContext ctx) { String name = ctx.Ident(0).getText(); String superClass = "Object"; // Common superclass if (ctx.Ident().size() == 2) superClass = ctx.Ident(1).getText(); Seq members = (Seq) visit(ctx.memberList()); return new ClassDecl(name, superClass, members.children()); } @Override public Ast visitMemberList(MemberListContext ctx) { if (ctx.children == null) { return new Seq(new ArrayList<>()); } List list = new ArrayList<>(ctx.children.size()); for (ParseTree parseTree : ctx.children) { if (parseTree instanceof VarDeclContext) { Seq seqVars = (Seq) visit(parseTree); list.addAll(seqVars.children()); } else { assert parseTree instanceof MethodDeclContext; list.add(visit(parseTree)); } } return new Seq(list); } @Override public Ast visitVarDecl(VarDeclContext ctx) { List list = new ArrayList<>(ctx.Ident().size()); String type = ctx.type().getText(); for (TerminalNode n : ctx.Ident()) list.add(new VarDecl(type, n.getText())); return new Seq(list); } @Override public Ast visitMethodDecl(MethodDeclContext ctx) { List argumentTypes = new ArrayList<>(); List argumentNames = new ArrayList<>(); if (ctx.formalParamList() != null) { Seq paramList = (Seq) visit(ctx.formalParamList()); for (Ast ast : paramList.children()) { VarDecl var = (VarDecl) ast; argumentNames.add(var.name); argumentTypes.add(var.type); } } List decls = new ArrayList<>(ctx.varDecl().size()); for (VarDeclContext varDecl : ctx.varDecl()) { Seq declarationSeq = (Seq) visit(varDecl); decls.addAll(declarationSeq.children()); } List stmts = new ArrayList<>(ctx.stmt().size()); for (StmtContext s : ctx.stmt()) stmts.add(visit(s)); return new MethodDecl( ctx.type() == null ? "void" : ctx.type().getText(), ctx.Ident().getText(), argumentTypes, argumentNames, new Seq(decls), new Seq(stmts) ); } @Override public Ast visitFormalParamList(FormalParamListContext ctx) { List list = new ArrayList<>(ctx.type().size()); for (int i = 0; i < ctx.type().size(); i++) { String type = ctx.type(i).getText(); String name = ctx.Ident(i).getText(); list.add(new VarDecl(type, name)); } return new Seq(list); } @Override public Ast visitStmt(StmtContext ctx) { return visit(ctx.children.get(0)); } @Override public Ast visitStmtBlock(StmtBlockContext ctx) { List list = new ArrayList<>(ctx.stmt().size()); for (StmtContext stmtContext : ctx.stmt()) list.add(visit(stmtContext)); return new Seq(list); } @Override public Ast visitLocalMethodCallStmt(LocalMethodCallStmtContext ctx) { return new MethodCall(new MethodCallExpr( new ThisRef(), ctx.Ident().getText(), getParams(ctx.actualParamList()) )); } @Override public Ast visitObjectMethodCallStmt(ObjectMethodCallStmtContext ctx) { return new MethodCall(new MethodCallExpr( (Expr) visit(ctx.identAccess()), ctx.Ident().getText(), getParams(ctx.actualParamList()) )); } @Override public Ast visitAssignmentStmt(AssignmentStmtContext ctx) { Expr left = (Expr) visit(ctx.children.get(0)); Expr right = (Expr) visit(ctx.children.get(2)); return new Assign(left, right); } @Override public Ast visitWrite(WriteContext ctx) { return new BuiltInWrite((Expr) visit(ctx.expr())); } @Override public Ast visitWriteLn(WriteLnContext ctx) { return new BuiltInWriteln(); } @Override public Ast visitIfStmt(IfStmtContext ctx) { Expr condition = (Expr) visit(ctx.expr()); Ast then = visit(ctx.stmtBlock(0)); Ast otherwise = new Nop(); if (ctx.stmtBlock().size() == 2) otherwise = visit(ctx.stmtBlock(1)); return new IfElse(condition, then, otherwise); } @Override public Ast visitWhileStmt(WhileStmtContext ctx) { Expr condition = (Expr) visit(ctx.expr()); Ast body = visit(ctx.stmtBlock()); return new WhileLoop(condition, body); } @Override public Ast visitReturnStmt(ReturnStmtContext ctx) { if (ctx.expr() != null) return new ReturnStmt((Expr) visit(ctx.expr())); else return new ReturnStmt(null); } @Override public Ast visitNewObject(NewObjectContext ctx) { return new NewObject(ctx.Ident().getText()); } @Override public Ast visitNewObjectArray(NewObjectArrayContext ctx) { String type = ctx.Ident().getText(); Expr size = (Expr) visit(ctx.expr()); return new NewArray(type + "[]", size); } @Override public Ast visitNewPrimitiveArray(NewPrimitiveArrayContext ctx) { String type = ctx.primitiveType().getText(); Expr size = (Expr) visit(ctx.expr()); return new NewArray(type + "[]", size); } @Override public Ast visitReadExpr(ReadExprContext ctx) { return new BuiltInRead(); } @Override public Ast visitActualParamList(ActualParamListContext ctx) { List list = new ArrayList<>(ctx.expr().size()); for (ExprContext exprContext : ctx.expr()) list.add(visit(exprContext)); return new Seq(list); } @Override public Ast visitAccessThis(AccessThisContext ctx) { return new ThisRef(); } @Override public Ast visitAccessLocalField(AccessLocalFieldContext ctx) { return new Var(ctx.Ident().getText()); } @Override public Ast visitAccessObjectField(AccessObjectFieldContext ctx) { Expr arg = (Expr) visit(ctx.identAccess()); String fieldName = ctx.Ident().getText(); return new Field(arg, fieldName); } @Override public Ast visitAccessLocalMethod(AccessLocalMethodContext ctx) { return new MethodCallExpr( new ThisRef(), ctx.Ident().getText(), getParams(ctx.actualParamList()) ); } @Override public Ast visitAccessArray(AccessArrayContext ctx) { Expr array = (Expr) visit(ctx.identAccess()); Expr index = (Expr) visit(ctx.expr()); return new Index(array, index); } @Override public Ast visitAccessObjectMethod(AccessObjectMethodContext ctx) { return new MethodCallExpr( (Expr) visit(ctx.identAccess()), ctx.Ident().getText(), getParams(ctx.actualParamList()) ); } @Override public Ast visitExprBinary(ExprBinaryContext ctx) { Expr left = (Expr) visit(ctx.expr(0)); Expr right = (Expr) visit(ctx.expr(1)); String op = ctx.getChild(1).getText(); for (BOp bop : BOp.values()) if (bop.repr.equals(op)) return new BinaryOp(left, bop, right); throw new RuntimeException("BOp enum is inconsistent with grammar"); } @Override public Ast visitExprCast(ExprCastContext ctx) { Expr arg = (Expr) visit(ctx.expr()); String typeName = ctx.referenceType().getText(); return new Cast(arg, typeName); } @Override public Ast visitExprParentheses(ExprParenthesesContext ctx) { return visit(ctx.expr()); } @Override public Ast visitExprUnary(ExprUnaryContext ctx) { Expr expr = (Expr) visit(ctx.expr()); String op = ctx.getChild(0).getText(); for (UOp uop : UOp.values()) if (uop.repr.equals(op)) return new UnaryOp(uop, expr); throw new RuntimeException("UOp enum is inconsistent with grammar"); } @Override public Ast visitExprConstant(ExprConstantContext ctx) { return visit(ctx.literal()); } @Override public Ast visitNullLiteral(NullLiteralContext ctx) { return new NullConst(); } @Override public Ast visitBoolLiteral(BoolLiteralContext ctx) { return new BooleanConst(ctx.Boolean().getText().equals("true")); } @Override public Ast visitIntLiteral(IntLiteralContext ctx) { try { return new IntConst(Integer.decode(ctx.Integer().getText())); } catch (NumberFormatException exception) { throw new ParseFailure(ctx.start.getLine(), "Value not in 32bit signed int range"); } } @Override public Ast visitExprIdentAccess(ExprIdentAccessContext ctx) { return visit(ctx.identAccess()); } /** * Obtain the parameters for a method call * @param paramListContext Formal parameter list from the ANTRL tree * @return List of parameters for the method call */ private List getParams(ActualParamListContext paramListContext) { List paramList = new ArrayList<>(); if (paramListContext != null) { Seq paramSeq = (Seq) visit(paramListContext); for (Ast ast : paramSeq.children()) paramList.add((Expr) ast); } return paramList; } }