package net.iplantevin.ql.ast.astbuilder;
import net.iplantevin.ql.antlr.QLBaseVisitor;
import net.iplantevin.ql.antlr.QLParser;
import net.iplantevin.ql.ast.ASTNode;
import net.iplantevin.ql.ast.LineInfo;
import net.iplantevin.ql.ast.expressions.Expression;
import net.iplantevin.ql.ast.expressions.Par;
import net.iplantevin.ql.ast.expressions.literals.Bool;
import net.iplantevin.ql.ast.expressions.literals.ID;
import net.iplantevin.ql.ast.expressions.literals.Int;
import net.iplantevin.ql.ast.expressions.literals.Str;
import net.iplantevin.ql.ast.expressions.operators.Add;
import net.iplantevin.ql.ast.expressions.operators.And;
import net.iplantevin.ql.ast.expressions.operators.Binary;
import net.iplantevin.ql.ast.expressions.operators.Div;
import net.iplantevin.ql.ast.expressions.operators.EQ;
import net.iplantevin.ql.ast.expressions.operators.GEQ;
import net.iplantevin.ql.ast.expressions.operators.GT;
import net.iplantevin.ql.ast.expressions.operators.LEQ;
import net.iplantevin.ql.ast.expressions.operators.LT;
import net.iplantevin.ql.ast.expressions.operators.Mul;
import net.iplantevin.ql.ast.expressions.operators.NEQ;
import net.iplantevin.ql.ast.expressions.operators.Neg;
import net.iplantevin.ql.ast.expressions.operators.Not;
import net.iplantevin.ql.ast.expressions.operators.Or;
import net.iplantevin.ql.ast.expressions.operators.Pos;
import net.iplantevin.ql.ast.expressions.operators.Sub;
import net.iplantevin.ql.ast.expressions.operators.Unary;
import net.iplantevin.ql.ast.form.Form;
import net.iplantevin.ql.ast.form.FormCollection;
import net.iplantevin.ql.ast.statements.Block;
import net.iplantevin.ql.ast.statements.Computation;
import net.iplantevin.ql.ast.statements.If;
import net.iplantevin.ql.ast.statements.IfElse;
import net.iplantevin.ql.ast.statements.Question;
import net.iplantevin.ql.ast.statements.Statement;
import net.iplantevin.ql.ast.types.BooleanType;
import net.iplantevin.ql.ast.types.IntegerType;
import net.iplantevin.ql.ast.types.StringType;
import net.iplantevin.ql.ast.types.Type;
import org.antlr.v4.runtime.misc.NotNull;
import java.util.ArrayList;
/**
* Visitor that creates an custom AST from the antlr tree.
*
* @author Ivan
*/
public class ASTBuilderVisitor extends QLBaseVisitor<ASTNode> {
/**
*
*/
private void dieWithOperatorError() {
System.err.println("No matching operator found!");
System.exit(1);
}
/**
*
*/
@Override
public FormCollection visitForms(@NotNull QLParser.FormsContext ctx) {
ArrayList<Form> forms = new ArrayList<Form>();
for (QLParser.FormContext formCtx : ctx.form()) {
forms.add((Form) formCtx.accept(this));
}
return new FormCollection(forms, new LineInfo(ctx));
}
/**
*
*/
@Override
public Form visitForm(@NotNull QLParser.FormContext ctx) {
String name = ctx.ID().getText();
Block body = (Block) ctx.block().accept(this);
return new Form(name, body, new LineInfo(ctx));
}
/**
*
*/
@Override
public Block visitBlock(@NotNull QLParser.BlockContext ctx) {
ArrayList<Statement> statements = new ArrayList<Statement>();
for (QLParser.StatContext statCtx : ctx.stat()) {
statements.add((Statement) statCtx.accept(this));
}
return new Block(statements, new LineInfo(ctx));
}
/**
*
*/
@Override
public IfElse visitIfElse(@NotNull QLParser.IfElseContext ctx) {
Expression condition = (Expression) ctx.expr().accept(this);
Statement body = (Statement) ctx.stat().get(0).accept(this);
Statement elseBody = (Statement) ctx.stat().get(1).accept(this);
return new IfElse(condition, body, elseBody, new LineInfo(ctx));
}
/**
*
*/
@Override
public If visitIf(@NotNull QLParser.IfContext ctx) {
Expression condition = (Expression) ctx.expr().accept(this);
Statement body = (Statement) ctx.stat().accept(this);
return new If(condition, body, new LineInfo(ctx));
}
/**
*
*/
@Override
public Block visitBlockStat(@NotNull QLParser.BlockStatContext ctx) {
return (Block) ctx.block().accept(this);
}
/**
*
*/
@Override
public Computation visitComputation(@NotNull QLParser.ComputationContext ctx) {
Type type = ((Expression) ctx.type().accept(this)).getType(null);
LineInfo lineInfo = new LineInfo(ctx.ID().getSymbol().getLine(),
ctx.ID().getSymbol().getCharPositionInLine());
ID name = new ID(ctx.ID().getText(), lineInfo);
lineInfo = new LineInfo(ctx.STR().getSymbol().getLine(),
ctx.STR().getSymbol().getCharPositionInLine());
Str label = new Str(ctx.STR().getText(), lineInfo);
Expression expression = (Expression) ctx.expr().accept(this);
return new Computation(name, label, type, expression, new LineInfo(ctx));
}
/**
*
*/
@Override
public Question visitQuestion(@NotNull QLParser.QuestionContext ctx) {
Type type = ((Expression) ctx.type().accept(this)).getType(null);
LineInfo lineInfo = new LineInfo(ctx.ID().getSymbol().getLine(),
ctx.ID().getSymbol().getCharPositionInLine());
ID name = new ID(ctx.ID().getText(), lineInfo);
lineInfo = new LineInfo(ctx.STR().getSymbol().getLine(),
ctx.STR().getSymbol().getCharPositionInLine());
Str label = new Str(ctx.STR().getText(), lineInfo);
return new Question(name, label, type, new LineInfo(ctx));
}
/**
*
*/
@Override
public Bool visitBoolType(@NotNull QLParser.BoolTypeContext ctx) {
return new Bool(true, null);
}
/**
*
*/
@Override
public Int visitIntType(@NotNull QLParser.IntTypeContext ctx) {
return new Int(0, null);
}
/**
*
*/
@Override
public Str visitStrType(@NotNull QLParser.StrTypeContext ctx) {
return new Str(" ", null);
}
/**
*
*/
@Override
public Bool visitTrue(@NotNull QLParser.TrueContext ctx) {
return new Bool(true, new LineInfo(ctx));
}
/**
*
*/
@Override
public Bool visitFalse(@NotNull QLParser.FalseContext ctx) {
return new Bool(false, new LineInfo(ctx));
}
/**
*
*/
@Override
public Unary visitUnary(@NotNull QLParser.UnaryContext ctx) {
Expression expression = (Expression) ctx.expr().accept(this);
switch (ctx.op.getType()) {
case QLParser.ADD:
return new Pos(expression, new LineInfo(ctx.ADD()));
case QLParser.SUB:
return new Neg(expression, new LineInfo(ctx.SUB()));
case QLParser.NOT:
return new Not(expression, new LineInfo(ctx.NOT()));
}
dieWithOperatorError();
return null;
}
/**
* Note: also division.
*/
@Override
public Binary visitMultiplication(@NotNull QLParser.MultiplicationContext ctx) {
Expression leftExpr = (Expression) ctx.expr().get(0).accept(this);
Expression rightExpr = (Expression) ctx.expr().get(1).accept(this);
switch (ctx.op.getType()) {
case QLParser.MUL:
return new Mul(leftExpr, rightExpr, new LineInfo(ctx.MUL()));
case QLParser.DIV:
return new Div(leftExpr, rightExpr, new LineInfo(ctx.DIV()));
}
dieWithOperatorError();
return null;
}
/**
* Note: also subtraction.
*/
@Override
public Binary visitAddition(@NotNull QLParser.AdditionContext ctx) {
Expression leftExpr = (Expression) ctx.expr().get(0).accept(this);
Expression rightExpr = (Expression) ctx.expr().get(1).accept(this);
switch (ctx.op.getType()) {
case QLParser.ADD:
return new Add(leftExpr, rightExpr, new LineInfo(ctx.ADD()));
case QLParser.SUB:
return new Sub(leftExpr, rightExpr, new LineInfo(ctx.SUB()));
}
dieWithOperatorError();
return null;
}
/**
* Note: all relational operators!
*/
@Override
public Binary visitRelational(@NotNull QLParser.RelationalContext ctx) {
Expression leftExpr = (Expression) ctx.expr().get(0).accept(this);
Expression rightExpr = (Expression) ctx.expr().get(1).accept(this);
switch (ctx.op.getType()) {
case QLParser.LT:
return new LT(leftExpr, rightExpr, new LineInfo(ctx.LT()));
case QLParser.GT:
return new GT(leftExpr, rightExpr, new LineInfo(ctx.GT()));
case QLParser.LEQ:
return new LEQ(leftExpr, rightExpr, new LineInfo(ctx.LEQ()));
case QLParser.GEQ:
return new GEQ(leftExpr, rightExpr, new LineInfo(ctx.GEQ()));
}
dieWithOperatorError();
return null;
}
/**
* Note: also NEQ.
*/
@Override
public Binary visitEquality(@NotNull QLParser.EqualityContext ctx) {
Expression leftExpr = (Expression) ctx.expr().get(0).accept(this);
Expression rightExpr = (Expression) ctx.expr().get(1).accept(this);
switch (ctx.op.getType()) {
case QLParser.EQ:
return new EQ(leftExpr, rightExpr, new LineInfo(ctx.EQ()));
case QLParser.NEQ:
return new NEQ(leftExpr, rightExpr, new LineInfo(ctx.NEQ()));
}
dieWithOperatorError();
return null;
}
/**
*
*/
@Override
public And visitLogicalAnd(@NotNull QLParser.LogicalAndContext ctx) {
Expression leftExpr = (Expression) ctx.expr().get(0).accept(this);
Expression rightExpr = (Expression) ctx.expr().get(1).accept(this);
return new And(leftExpr, rightExpr, new LineInfo(ctx.AND()));
}
/**
*
*/
@Override
public Or visitLogicalOr(@NotNull QLParser.LogicalOrContext ctx) {
Expression leftExpr = (Expression) ctx.expr().get(0).accept(this);
Expression rightExpr = (Expression) ctx.expr().get(1).accept(this);
return new Or(leftExpr, rightExpr, new LineInfo(ctx.OR()));
}
/**
*
*/
@Override
public Bool visitBoolean(@NotNull QLParser.BooleanContext ctx) {
return (Bool) ctx.bool().accept(this);
}
/**
*
*/
@Override
public ID visitIdentifier(@NotNull QLParser.IdentifierContext ctx) {
return new ID(ctx.ID().getText(), new LineInfo(ctx));
}
/**
*
*/
@Override
public Int visitInteger(@NotNull QLParser.IntegerContext ctx) {
String stringValue = ctx.INT().getText();
return new Int(Integer.valueOf(stringValue), new LineInfo(ctx));
}
/**
*
*/
@Override
public Str visitString(@NotNull QLParser.StringContext ctx) {
return new Str(ctx.STR().getText(), new LineInfo(ctx));
}
/**
*
*/
@Override
public Par visitParantheses(@NotNull QLParser.ParanthesesContext ctx) {
return new Par((Expression) ctx.expr().accept(this), new LineInfo(ctx));
}
}