package ql.ast;
import java.math.BigDecimal;
import java.util.Iterator;
import org.antlr.v4.runtime.misc.NotNull;
import ql.ast.expression.IExpression;
import ql.ast.expression.Id;
import ql.ast.expression.ParenthesesExpression;
import ql.ast.expression.arithmetic.Add;
import ql.ast.expression.arithmetic.Divide;
import ql.ast.expression.arithmetic.Multiply;
import ql.ast.expression.arithmetic.Remainder;
import ql.ast.expression.arithmetic.Subtract;
import ql.ast.expression.arithmetic.UnaryMinus;
import ql.ast.expression.arithmetic.UnaryPlus;
import ql.ast.expression.comparison.Equal;
import ql.ast.expression.comparison.GreaterThan;
import ql.ast.expression.comparison.GreaterThanEqual;
import ql.ast.expression.comparison.LessThan;
import ql.ast.expression.comparison.LessThanEqual;
import ql.ast.expression.comparison.NotEqual;
import ql.ast.expression.literal.BooleanLiteral;
import ql.ast.expression.literal.DecimalLiteral;
import ql.ast.expression.literal.IEnumElement;
import ql.ast.expression.literal.IntegerLiteral;
import ql.ast.expression.literal.NumberLiteral;
import ql.ast.expression.literal.StringLiteral;
import ql.ast.expression.logical.LogicalAnd;
import ql.ast.expression.logical.LogicalOr;
import ql.ast.expression.logical.Not;
import ql.ast.expression_value.BooleanValue;
import ql.ast.statement.Assignment;
import ql.ast.statement.Block;
import ql.ast.statement.ComputedAssignment;
import ql.ast.statement.IStatement;
import ql.ast.statement.IfStatement;
import ql.ast.statement.StatementList;
import ql.ast.type.BooleanType;
import ql.ast.type.DateType;
import ql.ast.type.DecimalType;
import ql.ast.type.EnumType;
import ql.ast.type.IntegerType;
import ql.ast.type.MoneyType;
import ql.ast.type.RangeType;
import ql.ast.type.StringType;
import ql.ast.type.Type;
import ql.ast.visitor_elements.IElement;
import antlr4_ql.QLBaseVisitor;
import antlr4_ql.QLParser;
import antlr4_ql.QLParser.IfStatementContext;
/**
* @author orosu
*/
public class AstBuilderVisitor extends QLBaseVisitor<IElement>
{
public AstBuilderVisitor()
{
}
@Override
public QuestionnaireList visitForms(@NotNull QLParser.FormsContext ctx)
{
QuestionnaireList questionnaireList = new QuestionnaireList();
for (QLParser.FormContext formContext: ctx.form()) {
questionnaireList.add(this.visitForm(formContext));
}
return questionnaireList;
}
@Override
public Questionnaire visitForm(@NotNull QLParser.FormContext ctx)
{
return new Questionnaire(ctx.ID().getText(), visitBlock(ctx.block()));
}
@Override
public Block visitBlock(@NotNull QLParser.BlockContext ctx)
{
StatementList statementList = new StatementList();
for(QLParser.StatementContext statementContext: ctx.statement()) {
statementList.add((IStatement) statementContext.accept(this));
}
return new Block(statementList);
}
@Override
public BooleanType visitBooleanType(@NotNull QLParser.BooleanTypeContext ctx)
{
return new BooleanType();
}
@Override
public IntegerType visitIntegerType(@NotNull QLParser.IntegerTypeContext ctx)
{
return new IntegerType();
}
@Override
public DecimalType visitDecimalType(@NotNull QLParser.DecimalTypeContext ctx)
{
return new DecimalType();
}
@Override
public MoneyType visitMoneyType(@NotNull QLParser.MoneyTypeContext ctx)
{
return new MoneyType();
}
@Override
public DateType visitDateType(@NotNull QLParser.DateTypeContext ctx)
{
return new DateType();
}
@Override
public StringType visitStringType(@NotNull QLParser.StringTypeContext ctx)
{
return new StringType();
}
@Override
public EnumType visitEnumType(@NotNull QLParser.EnumTypeContext ctx)
{
return (EnumType) ctx.enumTypeP().accept(this);
}
@Override
public EnumType visitStringEnum(@NotNull QLParser.StringEnumContext ctx)
{
EnumType enumType = new EnumType();
String value = ctx.STRING().getText();
enumType.addElement(new StringLiteral(value.substring(1, value.length()-1)));
// Check if there are other elements
if (ctx.enumTypeP() == null) {
return enumType;
}
return this._visitEnumTypeTail(enumType, (EnumType) ctx.enumTypeP().accept(this));
}
@Override
public EnumType visitNumberEnum(@NotNull QLParser.NumberEnumContext ctx)
{
EnumType enumType = new EnumType();
enumType.addElement((NumberLiteral) ctx.numberLiteralP().accept(this));
// Check if there are other elements
if (ctx.enumTypeP() == null) {
return enumType;
}
return this._visitEnumTypeTail(enumType, (EnumType) ctx.enumTypeP().accept(this));
}
@Override
public RangeType visitIntegerRangeType(@NotNull QLParser.IntegerRangeTypeContext ctx)
{
return new RangeType(
new IntegerLiteral(Integer.parseInt(ctx.INT(0).getText())),
new IntegerLiteral(Integer.parseInt(ctx.INT(1).getText()))
);
}
@Override
public Assignment visitAssignment(@NotNull QLParser.AssignmentContext ctx)
{
return new Assignment(
ctx.ID().getText(),
ctx.STRING().getText().substring(1, ctx.STRING().getText().length()-1),
(Type) ctx.type().accept(this)
);
}
@Override
public ComputedAssignment visitComputedAssignment(@NotNull QLParser.ComputedAssignmentContext ctx)
{
return new ComputedAssignment(
ctx.ID().getText(),
ctx.STRING().getText().substring(1, ctx.STRING().getText().length()-1),
(Type) ctx.type().accept(this),
(IExpression) ctx.expression().accept(this)
);
}
@Override
public IfStatement visitIfStatement(@NotNull IfStatementContext ctx)
{
return new IfStatement(
(IExpression) ctx.expression().accept(this),
visitBlock(ctx.block()),
new Block(new StatementList())
);
}
@Override
public IfStatement visitIfElseStatement(@NotNull QLParser.IfElseStatementContext ctx)
{
return new IfStatement(
(IExpression) ctx.expression().accept(this),
visitBlock(ctx.block(0)),
visitBlock(ctx.block(1))
);
}
@Override
public UnaryPlus visitUnaryPlus(@NotNull QLParser.UnaryPlusContext ctx)
{
return new UnaryPlus((IExpression) ctx.expression().accept(this));
}
@Override
public UnaryMinus visitUnaryMinus(@NotNull QLParser.UnaryMinusContext ctx)
{
return new UnaryMinus((IExpression) ctx.expression().accept(this));
}
@Override
public Not visitNot(@NotNull QLParser.NotContext ctx)
{
return new Not((IExpression) ctx.expression().accept(this));
}
@Override
public Multiply visitMultiply(@NotNull QLParser.MultiplyContext ctx)
{
return new Multiply(
(IExpression) ctx.expression(0).accept(this),
(IExpression) ctx.expression(1).accept(this)
);
}
@Override
public Divide visitDivide(@NotNull QLParser.DivideContext ctx)
{
return new Divide(
(IExpression) ctx.expression(0).accept(this),
(IExpression) ctx.expression(1).accept(this)
);
}
@Override
public Remainder visitRemainder(@NotNull QLParser.RemainderContext ctx)
{
return new Remainder(
(IExpression) ctx.expression(0).accept(this),
(IExpression) ctx.expression(1).accept(this)
);
}
@Override
public Add visitAdd(@NotNull QLParser.AddContext ctx)
{
return new Add(
(IExpression) ctx.expression(0).accept(this),
(IExpression) ctx.expression(1).accept(this)
);
}
@Override
public Subtract visitSubtract(@NotNull QLParser.SubtractContext ctx)
{
return new Subtract(
(IExpression) ctx.expression(0).accept(this),
(IExpression) ctx.expression(1).accept(this)
);
}
@Override
public LessThan visitLessThan(@NotNull QLParser.LessThanContext ctx)
{
return new LessThan(
(IExpression) ctx.expression(0).accept(this),
(IExpression) ctx.expression(1).accept(this)
);
}
@Override
public GreaterThan visitGreaterThan(@NotNull QLParser.GreaterThanContext ctx)
{
return new GreaterThan(
(IExpression) ctx.expression(0).accept(this),
(IExpression) ctx.expression(1).accept(this)
);
}
@Override
public LessThanEqual visitLessThanEqual(@NotNull QLParser.LessThanEqualContext ctx)
{
return new LessThanEqual(
(IExpression) ctx.expression(0).accept(this),
(IExpression) ctx.expression(1).accept(this)
);
}
@Override
public GreaterThanEqual visitGreaterThanEqual(@NotNull QLParser.GreaterThanEqualContext ctx)
{
return new GreaterThanEqual(
(IExpression) ctx.expression(0).accept(this),
(IExpression) ctx.expression(1).accept(this)
);
}
@Override
public Equal visitEqual(@NotNull QLParser.EqualContext ctx)
{
return new Equal(
(IExpression) ctx.expression(0).accept(this),
(IExpression) ctx.expression(1).accept(this)
);
}
@Override
public NotEqual visitNotEqual(@NotNull QLParser.NotEqualContext ctx)
{
return new NotEqual(
(IExpression) ctx.expression(0).accept(this),
(IExpression) ctx.expression(1).accept(this)
);
}
@Override
public LogicalAnd visitLogicalAnd(@NotNull QLParser.LogicalAndContext ctx)
{
return new LogicalAnd(
(IExpression) ctx.expression(0).accept(this),
(IExpression) ctx.expression(1).accept(this)
);
}
@Override
public LogicalOr visitLogicalOr(@NotNull QLParser.LogicalOrContext ctx)
{
return new LogicalOr(
(IExpression) ctx.expression(0).accept(this),
(IExpression) ctx.expression(1).accept(this)
);
}
@Override
public BooleanLiteral visitBooleanLiteral(@NotNull QLParser.BooleanLiteralContext ctx)
{
BooleanValue booleanValue = (BooleanValue) ctx.booleanLiteralP().accept(this);
return new BooleanLiteral(booleanValue.getValue());
}
@Override
public BooleanValue visitTrue(@NotNull QLParser.TrueContext ctx)
{
return new BooleanValue(true);
}
@Override
public BooleanValue visitFalse(@NotNull QLParser.FalseContext ctx)
{
return new BooleanValue(false);
}
@Override
public Id visitId(@NotNull QLParser.IdContext ctx)
{
return new Id(ctx.ID().getText());
}
@Override
public NumberLiteral visitNumberLiteral(@NotNull QLParser.NumberLiteralContext ctx)
{
return (NumberLiteral) ctx.numberLiteralP().accept(this);
}
@Override
public DecimalLiteral visitDecimal(@NotNull QLParser.DecimalContext ctx)
{
return new DecimalLiteral(new BigDecimal(ctx.getText()));
}
@Override
public IntegerLiteral visitInteger(@NotNull QLParser.IntegerContext ctx)
{
return new IntegerLiteral(Integer.parseInt(ctx.getText()));
}
@Override
public StringLiteral visitString(@NotNull QLParser.StringContext ctx)
{
return new StringLiteral(ctx.getText().substring(1, ctx.getText().length()-1));
}
@Override
public ParenthesesExpression visitParentheses(@NotNull QLParser.ParenthesesContext ctx)
{
return new ParenthesesExpression((IExpression) ctx.expression().accept(this));
}
private EnumType _visitEnumTypeTail(EnumType enumType, EnumType otherEnumType)
{
Iterator<IEnumElement> elementsIterator = otherEnumType.getElementsIterator();
while (elementsIterator.hasNext()) {
enumType.addElement(elementsIterator.next());
}
return enumType;
}
}