package nl.uva.se.ql.parser;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import nl.uva.se.ql.ast.Node;
import nl.uva.se.ql.ast.expression.Expression;
import nl.uva.se.ql.ast.expression.arithmetical.Addition;
import nl.uva.se.ql.ast.expression.arithmetical.Divide;
import nl.uva.se.ql.ast.expression.arithmetical.Modulo;
import nl.uva.se.ql.ast.expression.arithmetical.Multiply;
import nl.uva.se.ql.ast.expression.arithmetical.Negative;
import nl.uva.se.ql.ast.expression.arithmetical.Positive;
import nl.uva.se.ql.ast.expression.arithmetical.Power;
import nl.uva.se.ql.ast.expression.arithmetical.Substraction;
import nl.uva.se.ql.ast.expression.literal.BooleanLiteral;
import nl.uva.se.ql.ast.expression.literal.DecimalLiteral;
import nl.uva.se.ql.ast.expression.literal.IntegerLiteral;
import nl.uva.se.ql.ast.expression.literal.StringLiteral;
import nl.uva.se.ql.ast.expression.logical.And;
import nl.uva.se.ql.ast.expression.logical.Equal;
import nl.uva.se.ql.ast.expression.logical.GreaterOrEqual;
import nl.uva.se.ql.ast.expression.logical.GreaterThen;
import nl.uva.se.ql.ast.expression.logical.LessOrEqual;
import nl.uva.se.ql.ast.expression.logical.LessThen;
import nl.uva.se.ql.ast.expression.logical.Not;
import nl.uva.se.ql.ast.expression.logical.NotEqual;
import nl.uva.se.ql.ast.expression.logical.Or;
import nl.uva.se.ql.ast.expression.variable.Reference;
import nl.uva.se.ql.ast.form.Form;
import nl.uva.se.ql.ast.statement.CalculatedQuestion;
import nl.uva.se.ql.ast.statement.Condition;
import nl.uva.se.ql.ast.statement.Question;
import nl.uva.se.ql.ast.statement.Statement;
import nl.uva.se.ql.ast.type.BooleanType;
import nl.uva.se.ql.ast.type.DecimalType;
import nl.uva.se.ql.ast.type.IntegerType;
import nl.uva.se.ql.ast.type.StringType;
import nl.uva.se.ql.ast.type.Type;
import nl.uva.se.ql.ast.type.UndefinedType;
import nl.uva.se.ql.parser.QLParser.ConditionContext;
import nl.uva.se.ql.parser.QLParser.ExpressionContext;
import nl.uva.se.ql.parser.QLParser.FormContext;
import nl.uva.se.ql.parser.QLParser.LiteralContext;
import nl.uva.se.ql.parser.QLParser.QuestionContext;
import nl.uva.se.ql.parser.QLParser.StatementContext;
public class QLVisitorImpl extends QLBaseVisitor<Node> {
@Override
public Node visitForm(FormContext ctx) {
int lineNumber = ctx.start.getLine();
int offset = ctx.start.getCharPositionInLine();
String id = ctx.Identifier().getText();
List<StatementContext> contexts = ctx.statement();
List<Statement> statements = new ArrayList<Statement>();
for (StatementContext context : contexts) {
statements.add((Statement) visitStatement(context));
}
Form form = new Form(id, lineNumber, offset, statements);
return form;
}
@Override
public Node visitQuestion(QuestionContext ctx) {
Type type = getTypeForName((ctx.Type().getText()));
int lineNumber = ctx.start.getLine();
int offset = ctx.start.getCharPositionInLine();
String id = ctx.Identifier().getText();
String question = removeQuotes(ctx.String().getText());
if (type == null) {
throw new IllegalArgumentException("Type " + ctx.Type().getText() + " not supported!");
}
if (ctx.expression() != null) {
return new CalculatedQuestion(lineNumber, offset, id, type,
question, (Expression) visitExpression(ctx.expression()));
}
return new Question(lineNumber, offset, id, type, question);
}
@Override
public Node visitCondition(ConditionContext ctx) {
int lineNumber = ctx.start.getLine();
int offset = ctx.start.getCharPositionInLine();
List<Statement> statements = new ArrayList<Statement>();
for (StatementContext context : ctx.statement()) {
statements.add((Statement) visitStatement(context));
}
return new Condition(lineNumber, offset,
(Expression) visitExpression(ctx.expression()),
statements);
}
@Override
public Node visitStatement(StatementContext ctx) {
if (ctx.question() != null) {
return visitQuestion(ctx.question());
}
return visitCondition(ctx.condition());
}
@Override
public Node visitExpression(ExpressionContext ctx) {
if (ctx.expr != null) {
return visitExpression(ctx.expr);
}
if (ctx.op == null) {
return visitLiteral(ctx.singleLtr);
}
QLOperators operator = QLOperators.getByName(ctx.op.getText());
if (operator == null) {
throw new IllegalArgumentException("Operator " + ctx.op.getText() + " not supported!");
}
int lineNumber = ctx.start.getLine();
int offset = ctx.start.getCharPositionInLine();
if (ctx.singleExpr != null) {
switch (operator) {
case PLUS:
return new Positive(lineNumber, offset, (Expression) visitExpression(ctx.singleExpr));
case MINUS:
return new Negative(lineNumber, offset, (Expression) visitExpression(ctx.singleExpr));
default:
throw new IllegalArgumentException("Unsupported unary operator " + ctx.op.getText());
}
}
switch (operator) {
case AND:
return new And(lineNumber, offset, (Expression) visitExpression(ctx.left),
(Expression) visitExpression(ctx.right));
case DIVIDE:
return new Divide(lineNumber, offset, (Expression) visitExpression(ctx.left),
(Expression) visitExpression(ctx.right));
case EQUAL:
return new Equal(lineNumber, offset, (Expression) visitExpression(ctx.left),
(Expression) visitExpression(ctx.right));
case GREATER_OR_EQUAL:
return new GreaterOrEqual(lineNumber, offset, (Expression) visitExpression(ctx.left),
(Expression) visitExpression(ctx.right));
case GREATER_THAN:
return new GreaterThen(lineNumber, offset, (Expression) visitExpression(ctx.left),
(Expression) visitExpression(ctx.right));
case LESS_OR_EQUAL:
return new LessOrEqual(lineNumber, offset, (Expression) visitExpression(ctx.left),
(Expression) visitExpression(ctx.right));
case LESS_THEN:
return new LessThen(lineNumber, offset, (Expression) visitExpression(ctx.left),
(Expression) visitExpression(ctx.right));
case MINUS:
return new Substraction(lineNumber, offset, (Expression) visitExpression(ctx.left),
(Expression) visitExpression(ctx.right));
case MODULO:
return new Modulo(lineNumber, offset, (Expression) visitExpression(ctx.left),
(Expression) visitExpression(ctx.right));
case MULTIPLY:
return new Multiply(lineNumber, offset, (Expression) visitExpression(ctx.left),
(Expression) visitExpression(ctx.right));
case NOT:
return new Not(lineNumber, offset, (Expression) visitExpression(ctx.singleExpr));
case NOT_EQUAL:
return new NotEqual(lineNumber, offset, (Expression) visitExpression(ctx.left),
(Expression) visitExpression(ctx.right));
case OR:
return new Or(lineNumber, offset, (Expression) visitExpression(ctx.left),
(Expression) visitExpression(ctx.right));
case PLUS:
return new Addition(lineNumber, offset, (Expression) visitExpression(ctx.left),
(Expression) visitExpression(ctx.right));
case POWER:
return new Power(lineNumber, offset, (Expression) visitExpression(ctx.left),
(Expression) visitExpression(ctx.right));
default:
throw new IllegalStateException("No matching Operator");
}
}
@Override
public Node visitLiteral(LiteralContext ctx) {
int lineNumber = ctx.start.getLine();
int offset = ctx.start.getCharPositionInLine();
if (ctx.Boolean() != null) {
return new BooleanLiteral(lineNumber, offset, Boolean.valueOf(ctx.getText()));
}
if (ctx.Decimal() != null) {
BigDecimal decimalValue = new BigDecimal(ctx.getText());
return new DecimalLiteral(lineNumber, offset, decimalValue);
}
if (ctx.Integer() != null) {
return new IntegerLiteral(lineNumber, offset, Integer.valueOf(ctx.getText()));
}
if (ctx.Identifier() != null) {
return new Reference(lineNumber, offset, ctx.getText());
}
return new StringLiteral(lineNumber, offset, removeQuotes(ctx.getText()));
}
public Type getTypeForName(String typeName) {
if (typeName.equalsIgnoreCase("boolean")) {
return new BooleanType();
} else if (typeName.equalsIgnoreCase("integer")) {
return new IntegerType();
} else if (typeName.equalsIgnoreCase("decimal")) {
return new DecimalType();
} else if (typeName.equalsIgnoreCase("string")) {
return new StringType();
}
return new UndefinedType();
}
private String removeQuotes(String question) {
return question.substring(1, question.length()-1);
}
}