package com.klq.ast;
import com.klq.ast.impl.ANode;
import com.klq.ast.impl.Location;
import com.klq.ast.impl.Type;
import com.klq.ast.impl.stmt.*;
import com.klq.ast.impl.expr.AExpression;
import com.klq.ast.impl.expr.ExpressionUtil;
import com.klq.ast.impl.expr.bool.*;
import com.klq.ast.impl.expr.literal.DateNode;
import com.klq.ast.impl.expr.IdentifierNode;
import com.klq.ast.impl.expr.literal.NumberNode;
import com.klq.ast.impl.expr.literal.StringNode;
import com.klq.ast.impl.expr.math.AddNode;
import com.klq.ast.impl.expr.math.DivideNode;
import com.klq.ast.impl.expr.math.MultiplyNode;
import com.klq.ast.impl.expr.math.SubtractNode;
import com.klq.ast.impl.value.DateValue;
import com.klq.parser.KLQBaseVisitor;
import com.klq.parser.KLQParser;
import org.antlr.v4.runtime.ParserRuleContext;
import org.antlr.v4.runtime.Token;
import java.io.File;
import java.math.BigDecimal;
import java.util.ArrayList;
/**
* Created by juriaan on 16-2-15.
*/
public class ParseTreeConverter extends KLQBaseVisitor<ANode> {
private File file;
public ParseTreeConverter(File file) {
this.file = file;
}
/*==================================================================================================================
Statements
==================================================================================================================*/
@Override
public ANode visitQuestionnaire(KLQParser.QuestionnaireContext ctx) {
QuestionnaireNode ast = new QuestionnaireNode(formatLocation(ctx));
for(KLQParser.QuestionContext question : ctx.question()){
ast.getChildren().add((AStatementNode) visit(question));
}
return ast;
}
@Override
public ANode visitUncondQuestion(KLQParser.UncondQuestionContext ctx) {
QuestionNode questionNode;
IdentifierNode id = new IdentifierNode(ctx.id.getText());
Type type = Type.getEnum(ctx.type.getText());
if(ctx.expr() == null){
questionNode = new QuestionNode(id, type, stripQuotes(ctx.text.getText()), formatLocation(ctx));
} else {
AExpression computedAnswer = (AExpression) visit(ctx.expr());
questionNode = new ComputedQuestionNode(id, type, stripQuotes(ctx.text.getText()), computedAnswer, formatLocation(ctx));
}
return questionNode;
}
@Override
public ANode visitCondQuestion(KLQParser.CondQuestionContext ctx) {
AExpression condition = (AExpression) visit(ctx.expr());
ArrayList<AStatementNode> body = new ArrayList<AStatementNode>();
for(KLQParser.QuestionContext question : ctx.question()){
body.add((AStatementNode) visit(question));
}
return new ConditionalNode(condition, body, formatLocation(ctx));
}
/*==================================================================================================================
Primitives
==================================================================================================================*/
@Override
public ANode visitDate(KLQParser.DateContext ctx) {
String dateString = ctx.Date().getText();
DateValue date = (DateValue) ExpressionUtil.createTerminalFromString(Type.DATE, dateString);
DateNode dateNode = new DateNode(date.getValue(), formatLocation(ctx));
return dateNode;
}
@Override
public ANode visitNumber(KLQParser.NumberContext ctx) {
BigDecimal value = new BigDecimal(Double.valueOf(ctx.Number().getText()));
NumberNode numberNode = new NumberNode(value, formatLocation(ctx));
return numberNode;
}
@Override
public ANode visitString(KLQParser.StringContext ctx) {
StringNode stringNode = new StringNode(stripQuotes(ctx.String().getText()), formatLocation(ctx));
return stringNode;
}
/*==================================================================================================================
Expressions
==================================================================================================================*/
@Override
public ANode visitId(KLQParser.IdContext ctx) {
return new IdentifierNode(ctx.QuestionId().getText(), formatLocation(ctx));
}
@Override
public ANode visitAddSub(KLQParser.AddSubContext ctx) {
AExpression leftChild = (AExpression)(visit(ctx.expr(0)));
AExpression rightChild = (AExpression)(visit(ctx.expr(1)));
ANode node;
if(ctx.operator.getType() == KLQParser.ADD) {
node = new AddNode(leftChild, rightChild, formatLocation(ctx));
}
else{
node = new SubtractNode(leftChild, rightChild, formatLocation(ctx));
}
return node;
}
@Override
public ANode visitMulDiv(KLQParser.MulDivContext ctx) {
AExpression leftChild = (AExpression)(visit(ctx.expr(0)));
AExpression rightChild = (AExpression)(visit(ctx.expr(1)));
ANode node;
if(ctx.operator.getType() == KLQParser.MUL) {
node = new MultiplyNode(leftChild, rightChild, formatLocation(ctx));
}
else{
node = new DivideNode(leftChild, rightChild, formatLocation(ctx));
}
return node;
}
@Override
public ANode visitComparators(KLQParser.ComparatorsContext ctx) {
AExpression leftChild = (AExpression)(visit(ctx.expr(0)));
AExpression rightChild = (AExpression)(visit(ctx.expr(1)));
switch(ctx.operator.getType()){
case KLQParser.GT: return new GreaterThanNode(leftChild, rightChild, formatLocation(ctx));
case KLQParser.GE: return new GreaterEqualsNode(leftChild, rightChild, formatLocation(ctx));
case KLQParser.LT: return new LessThanNode(leftChild, rightChild, formatLocation(ctx));
case KLQParser.LE: return new LessEqualsNode(leftChild, rightChild, formatLocation(ctx));
case KLQParser.EQ: return new EqualsNode(leftChild, rightChild, formatLocation(ctx));
case KLQParser.NEQ: return new NotEqualsNode(leftChild, rightChild, formatLocation(ctx));
default: return null;
}
}
@Override
public ANode visitOr(KLQParser.OrContext ctx) {
AExpression leftChild = (AExpression)(visit(ctx.expr(0)));
AExpression rightChild = (AExpression)(visit(ctx.expr(1)));
return new OrNode(leftChild, rightChild, formatLocation(ctx));
}
@Override
public ANode visitAnd(KLQParser.AndContext ctx) {
AExpression leftChild = (AExpression)(visit(ctx.expr(0)));
AExpression rightChild = (AExpression)(visit(ctx.expr(1)));
return new AndNode(leftChild, rightChild, formatLocation(ctx));
}
@Override
public ANode visitParens(KLQParser.ParensContext ctx) {
return visit(ctx.expr());
}
private String stripQuotes(String s) {
if ( s==null || s.charAt(0)!='"' ) return s;
return s.substring(1, s.length() - 1);
}
private Location formatLocation(ParserRuleContext ctx){
Token tokenStart = ctx.getStart();
Token tokenEnd = ctx.getStop();
return new Location(file.getName(),
tokenStart.getStartIndex(),
tokenStart.getStopIndex() - tokenStart.getStartIndex(),
tokenStart.getLine(),
tokenStart.getCharPositionInLine(),
tokenEnd.getLine(),
tokenEnd.getCharPositionInLine());
}
}