package org.elasticsearch.plan.a;
/*
* Licensed to Elasticsearch under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import static org.elasticsearch.plan.a.Adapter.*;
import static org.elasticsearch.plan.a.Caster.*;
import static org.elasticsearch.plan.a.Default.*;
import static org.elasticsearch.plan.a.Definition.*;
import static org.elasticsearch.plan.a.PlanAParser.*;
class Analyzer extends PlanABaseVisitor<Void> {
static void analyze(final Adapter adapter) {
new Analyzer(adapter);
}
private final Adapter adapter;
private final Definition definition;
private final Standard standard;
private final Caster caster;
private Analyzer(final Adapter adapter) {
this.adapter = adapter;
definition = adapter.definition;
standard = adapter.standard;
caster = adapter.caster;
adapter.createStatementMetadata(adapter.root);
visit(adapter.root);
}
@Override
public Void visitSource(final SourceContext ctx) {
final StatementMetadata sourcesmd = adapter.getStatementMetadata(ctx);
adapter.incrementScope();
for (final StatementContext statectx : ctx.statement()) {
if (sourcesmd.allExit) {
throw new IllegalArgumentException(error(statectx) +
"Statement will never be executed because all prior paths exit.");
}
final StatementMetadata statesmd = adapter.createStatementMetadata(statectx);
visit(statectx);
if (statesmd.anyContinue) {
throw new IllegalArgumentException(error(statectx) +
"Cannot have a continue statement outside of a loop.");
}
if (statesmd.anyBreak) {
throw new IllegalArgumentException(error(statectx) +
"Cannot have a break statement outside of a loop.");
}
sourcesmd.allExit = statesmd.allExit;
sourcesmd.allReturn = statesmd.allReturn;
}
adapter.decrementScope();
return null;
}
@Override
public Void visitIf(final IfContext ctx) {
final StatementMetadata ifsmd = adapter.getStatementMetadata(ctx);
adapter.incrementScope();
final ExpressionContext exprctx = adapter.getExpressionContext(ctx.expression());
final ExpressionMetadata expremd = adapter.createExpressionMetadata(exprctx);
expremd.to = standard.boolType;
visit(exprctx);
if (expremd.postConst != null) {
throw new IllegalArgumentException(error(ctx) + "If statement is not necessary.");
}
final BlockContext blockctx0 = ctx.block(0);
final StatementMetadata blocksmd0 = adapter.createStatementMetadata(blockctx0);
visit(blockctx0);
ifsmd.anyReturn = blocksmd0.anyReturn;
ifsmd.anyBreak = blocksmd0.anyBreak;
ifsmd.anyContinue = blocksmd0.anyContinue;
if (ctx.ELSE() != null) {
final BlockContext blockctx1 = ctx.block(1);
final StatementMetadata blocksmd1 = adapter.createStatementMetadata(blockctx1);
visit(blockctx1);
ifsmd.allExit = blocksmd0.allExit && blocksmd1.allExit;
ifsmd.allReturn = blocksmd0.allReturn && blocksmd1.allReturn;
ifsmd.anyReturn |= blocksmd1.anyReturn;
ifsmd.allBreak = blocksmd0.allBreak && blocksmd1.allBreak;
ifsmd.anyBreak |= blocksmd1.anyBreak;
ifsmd.allContinue = blocksmd0.allContinue && blocksmd1.allContinue;
ifsmd.anyContinue |= blocksmd1.anyContinue;
}
adapter.decrementScope();
return null;
}
@Override
public Void visitWhile(final WhileContext ctx) {
final StatementMetadata whilesmd = adapter.getStatementMetadata(ctx);
adapter.incrementScope();
final ExpressionContext exprctx = adapter.getExpressionContext(ctx.expression());
final ExpressionMetadata expremd = adapter.createExpressionMetadata(exprctx);
expremd.to = standard.boolType;
visit(exprctx);
boolean exitrequired = false;
if (expremd.postConst != null) {
boolean constant = (boolean)expremd.postConst;
if (!constant) {
throw new IllegalArgumentException(error(ctx) + "The loop will never be executed.");
}
exitrequired = true;
}
final BlockContext blockctx = ctx.block();
if (blockctx != null) {
final StatementMetadata blocksmd = adapter.createStatementMetadata(blockctx);
visit(blockctx);
if (blocksmd.allReturn) {
throw new IllegalArgumentException(error(ctx) + "All paths return so the loop is not necessary.");
}
if (blocksmd.allBreak) {
throw new IllegalArgumentException(error(ctx) + "All paths break so the loop is not necessary.");
}
if (exitrequired && !blocksmd.anyReturn && !blocksmd.anyBreak) {
throw new IllegalArgumentException(error(ctx) + "The loop will never exit.");
}
if (exitrequired && blocksmd.anyReturn && !blocksmd.anyBreak) {
whilesmd.allExit = true;
whilesmd.allReturn = true;
}
} else if (exitrequired) {
throw new IllegalArgumentException(error(ctx) + "The loop will never exit.");
}
adapter.decrementScope();
return null;
}
@Override
public Void visitDo(final DoContext ctx) {
final StatementMetadata dosmd = adapter.getStatementMetadata(ctx);
adapter.incrementScope();
final BlockContext blockctx = ctx.block();
final StatementMetadata blocksmd = adapter.createStatementMetadata(blockctx);
visit(blockctx);
if (blocksmd.allReturn) {
throw new IllegalArgumentException(error(ctx) + "All paths return so the loop is not necessary.");
}
if (blocksmd.allBreak) {
throw new IllegalArgumentException(error(ctx) + "All paths break so the loop is not necessary.");
}
if (blocksmd.allContinue) {
throw new IllegalArgumentException(error(ctx) + "The loop will never exit.");
}
final ExpressionContext exprctx = adapter.getExpressionContext(ctx.expression());
final ExpressionMetadata expremd = adapter.createExpressionMetadata(exprctx);
expremd.to = standard.boolType;
visit(exprctx);
if (expremd.postConst != null) {
final boolean exitrequired = (boolean)expremd.postConst;
if (exitrequired && !blocksmd.anyReturn && !blocksmd.anyBreak) {
throw new IllegalArgumentException(error(ctx) + "The loop will never exit.");
}
if (exitrequired && blocksmd.anyReturn && !blocksmd.anyBreak) {
dosmd.allExit = true;
dosmd.allReturn = true;
}
if (!exitrequired && !blocksmd.anyContinue) {
throw new IllegalArgumentException(error(ctx) + "All paths exit so the loop is not necessary.");
}
}
adapter.decrementScope();
return null;
}
@Override
public Void visitFor(final ForContext ctx) {
final StatementMetadata forsmd = adapter.getStatementMetadata(ctx);
boolean exitrequired = false;
adapter.incrementScope();
final DeclarationContext declctx = ctx.declaration();
if (declctx != null) {
adapter.createStatementMetadata(declctx);
visit(declctx);
}
final ExpressionContext exprctx0 = adapter.getExpressionContext(ctx.expression(0));
if (exprctx0 != null) {
final ExpressionMetadata expremd0 = adapter.createExpressionMetadata(exprctx0);
expremd0.to = standard.boolType;
visit(exprctx0);
if (expremd0.postConst != null) {
boolean constant = (boolean)expremd0.postConst;
if (!constant) {
throw new IllegalArgumentException(error(ctx) + "The loop will never be executed.");
}
exitrequired = true;
}
} else {
exitrequired = true;
}
final ExpressionContext exprctx1 = adapter.getExpressionContext(ctx.expression(1));
if (exprctx1 != null) {
final ExpressionMetadata expremd1 = adapter.createExpressionMetadata(exprctx1);
expremd1.to = standard.voidType;
try {
visit(exprctx1);
} catch (ClassCastException exception) {
expremd1.statement = false;
}
if (!expremd1.statement) {
throw new IllegalArgumentException(error(exprctx1) +
"The afterthought of a for loop must be a statement.");
}
}
final BlockContext blockctx = ctx.block();
if (blockctx != null) {
final StatementMetadata blocksmd = adapter.createStatementMetadata(blockctx);
visit(blockctx);
if (blocksmd.allReturn) {
throw new IllegalArgumentException(error(ctx) + "All paths return so the loop is not necessary.");
}
if (blocksmd.allBreak) {
throw new IllegalArgumentException(error(ctx) + "All paths break so the loop is not necessary.");
}
if (exitrequired && !blocksmd.anyReturn && !blocksmd.anyBreak) {
throw new IllegalArgumentException(error(ctx) + "The loop will never exit.");
}
if (exitrequired && blocksmd.anyReturn && !blocksmd.anyBreak) {
forsmd.allExit = true;
forsmd.allReturn = true;
}
} else if (exitrequired) {
throw new IllegalArgumentException(error(ctx) + "The loop will never exit.");
}
adapter.decrementScope();
return null;
}
@Override
public Void visitDecl(final DeclContext ctx) {
final DeclarationContext declctx = ctx.declaration();
adapter.createStatementMetadata(declctx);
visit(declctx);
return null;
}
@Override
public Void visitContinue(final ContinueContext ctx) {
final StatementMetadata continuesmd = adapter.getStatementMetadata(ctx);
continuesmd.allExit = true;
continuesmd.allContinue = true;
continuesmd.anyContinue = true;
return null;
}
@Override
public Void visitBreak(final BreakContext ctx) {
final StatementMetadata breaksmd = adapter.getStatementMetadata(ctx);
breaksmd.allExit = true;
breaksmd.allBreak = true;
breaksmd.anyBreak = true;
return null;
}
@Override
public Void visitReturn(final ReturnContext ctx) {
final StatementMetadata returnsmd = adapter.getStatementMetadata(ctx);
final ExpressionContext exprctx = adapter.getExpressionContext(ctx.expression());
final ExpressionMetadata expremd = adapter.createExpressionMetadata(exprctx);
expremd.to = standard.objectType;
visit(exprctx);
returnsmd.allExit = true;
returnsmd.allReturn = true;
returnsmd.anyReturn = true;
return null;
}
@Override
public Void visitExpr(final ExprContext ctx) {
final ExpressionContext exprctx = adapter.getExpressionContext(ctx.expression());
final ExpressionMetadata expremd = adapter.createExpressionMetadata(exprctx);
expremd.to = standard.voidType;
try {
visit(exprctx);
} catch (ClassCastException exception) {
expremd.statement = false;
}
if (!expremd.statement) {
throw new IllegalArgumentException(error(ctx) + "Not a statement.");
}
return null;
}
@Override
public Void visitMultiple(final MultipleContext ctx) {
final StatementMetadata multiplesmd = adapter.getStatementMetadata(ctx);
for (StatementContext statectx : ctx.statement()) {
if (multiplesmd.allExit) {
throw new IllegalArgumentException(error(statectx) +
"Statement will never be executed because all prior paths exit.");
}
final StatementMetadata statesmd = adapter.createStatementMetadata(statectx);
visit(statectx);
multiplesmd.allExit = statesmd.allExit;
multiplesmd.allReturn = statesmd.allReturn && !statesmd.anyBreak && !statesmd.anyContinue;
multiplesmd.anyReturn |= statesmd.anyReturn;
multiplesmd.allBreak = !statesmd.anyReturn && statesmd.allBreak && !statesmd.anyContinue;
multiplesmd.anyBreak |= statesmd.anyBreak;
multiplesmd.allContinue = !statesmd.anyReturn && !statesmd.anyBreak && statesmd.allContinue;
multiplesmd.anyContinue |= statesmd.anyContinue;
}
return null;
}
@Override
public Void visitSingle(final SingleContext ctx) {
final StatementMetadata singlesmd = adapter.getStatementMetadata(ctx);
final StatementContext statectx = ctx.statement();
final StatementMetadata statesmd = adapter.createStatementMetadata(statectx);
visit(statectx);
singlesmd.allExit = statesmd.allExit;
singlesmd.allReturn = statesmd.allReturn;
singlesmd.anyReturn = statesmd.anyReturn;
singlesmd.allBreak = statesmd.allBreak;
singlesmd.anyBreak = statesmd.anyBreak;
singlesmd.allContinue = statesmd.allContinue;
singlesmd.anyContinue = statesmd.anyContinue;
return null;
}
@Override
public Void visitEmpty(final EmptyContext ctx) {
throw new UnsupportedOperationException(error(ctx) + "Unexpected parser state.");
}
@Override
public Void visitDeclaration(final DeclarationContext ctx) {
final DecltypeContext decltypectx = ctx.decltype();
final ExpressionMetadata decltypeemd = adapter.createExpressionMetadata(decltypectx);
visit(decltypectx);
for (final DeclvarContext declvarctx : ctx.declvar()) {
final ExpressionMetadata declvaremd = adapter.createExpressionMetadata(declvarctx);
declvaremd.to = decltypeemd.from;
visit(declvarctx);
}
return null;
}
@Override
public Void visitDecltype(final DecltypeContext ctx) {
final ExpressionMetadata decltypeemd = adapter.getExpressionMetadata(ctx);
final String pnamestr = ctx.getText();
decltypeemd.from = getTypeFromCanonicalName(definition, pnamestr);
return null;
}
@Override
public Void visitDeclvar(final DeclvarContext ctx) {
final ExpressionMetadata declvaremd = adapter.getExpressionMetadata(ctx);
final String name = ctx.ID().getText();
declvaremd.postConst = adapter.addVariable(ctx, name, declvaremd.to);
final ExpressionContext exprctx = adapter.getExpressionContext(ctx.expression());
if (exprctx != null) {
final ExpressionMetadata expremd = adapter.createExpressionMetadata(exprctx);
expremd.to = declvaremd.to;
visit(exprctx);
}
return null;
}
@Override
public Void visitPrecedence(final PrecedenceContext ctx) {
throw new UnsupportedOperationException(error(ctx) + "Unexpected parser state.");
}
@Override
public Void visitNumeric(final NumericContext ctx) {
final ExpressionMetadata numericemd = adapter.getExpressionMetadata(ctx);
if (ctx.DECIMAL() != null) {
final String svalue = ctx.DECIMAL().getText();
if (svalue.endsWith("f") || svalue.endsWith("F")) {
try {
numericemd.from = standard.floatType;
numericemd.preConst = Float.parseFloat(svalue.substring(0, svalue.length() - 1));
} catch (NumberFormatException exception) {
throw new IllegalArgumentException(error(ctx) + "Invalid float constant.");
}
} else {
try {
numericemd.from = standard.doubleType;
numericemd.preConst = Double.parseDouble(svalue);
} catch (NumberFormatException exception) {
throw new IllegalArgumentException(error(ctx) + "Invalid double constant.");
}
}
} else {
String svalue;
int radix;
if (ctx.OCTAL() != null) {
svalue = ctx.OCTAL().getText();
radix = 8;
} else if (ctx.INTEGER() != null) {
svalue = ctx.INTEGER().getText();
radix = 10;
} else if (ctx.HEX() != null) {
svalue = ctx.HEX().getText();
radix = 16;
} else {
throw new IllegalStateException(error(ctx) + "Unexpected parser state.");
}
if (svalue.endsWith("l") || svalue.endsWith("L")) {
try {
numericemd.from = standard.longType;
numericemd.preConst = Long.parseLong(svalue.substring(0, svalue.length() - 1), radix);
} catch (NumberFormatException exception) {
throw new IllegalArgumentException(error(ctx) + "Invalid long constant.");
}
} else {
try {
final Type type = numericemd.to;
final TypeMetadata tmd = type == null ? TypeMetadata.INT : type.metadata;
final int value = Integer.parseInt(svalue, radix);
if (tmd == TypeMetadata.BYTE && value >= Byte.MIN_VALUE && value <= Byte.MAX_VALUE) {
numericemd.from = standard.byteType;
numericemd.preConst = (byte)value;
} else if (tmd == TypeMetadata.CHAR && value >= Character.MIN_VALUE && value <= Character.MAX_VALUE) {
numericemd.from = standard.charType;
numericemd.preConst = (char)value;
} else if (tmd == TypeMetadata.SHORT && value >= Short.MIN_VALUE && value <= Short.MAX_VALUE) {
numericemd.from = standard.shortType;
numericemd.preConst = (short)value;
} else {
numericemd.from = standard.intType;
numericemd.preConst = value;
}
} catch (NumberFormatException exception) {
throw new IllegalArgumentException(error(ctx) + "Invalid int constant.");
}
}
}
caster.markCast(numericemd);
return null;
}
@Override
public Void visitString(final StringContext ctx) {
final ExpressionMetadata stringemd = adapter.getExpressionMetadata(ctx);
if (ctx.STRING() == null) {
throw new IllegalStateException(error(ctx) + "Unexpected parser state.");
}
final int length = ctx.STRING().getText().length();
stringemd.preConst = ctx.STRING().getText().substring(1, length - 1);
stringemd.from = standard.stringType;
caster.markCast(stringemd);
return null;
}
@Override
public Void visitChar(final CharContext ctx) {
final ExpressionMetadata charemd = adapter.getExpressionMetadata(ctx);
if (ctx.CHAR() == null) {
throw new IllegalStateException(error(ctx) + "Unexpected parser state.");
}
if (ctx.CHAR().getText().length() != 3) {
throw new IllegalStateException(error(ctx) + "Invalid character constant.");
}
charemd.preConst = ctx.CHAR().getText().charAt(1);
charemd.from = standard.charType;
caster.markCast(charemd);
return null;
}
@Override
public Void visitTrue(final TrueContext ctx) {
final ExpressionMetadata trueemd = adapter.getExpressionMetadata(ctx);
if (ctx.TRUE() == null) {
throw new IllegalStateException(error(ctx) + "Unexpected parser state.");
}
trueemd.preConst = true;
trueemd.from = standard.boolType;
caster.markCast(trueemd);
return null;
}
@Override
public Void visitFalse(final FalseContext ctx) {
final ExpressionMetadata falseemd = adapter.getExpressionMetadata(ctx);
if (ctx.FALSE() == null) {
throw new IllegalStateException(error(ctx) + "Unexpected parser state.");
}
falseemd.preConst = false;
falseemd.from = standard.boolType;
caster.markCast(falseemd);
return null;
}
@Override
public Void visitNull(final NullContext ctx) {
final ExpressionMetadata nullemd = adapter.getExpressionMetadata(ctx);
if (ctx.NULL() == null) {
throw new IllegalStateException(error(ctx) + "Unexpected parser state.");
}
nullemd.isNull = true;
if (nullemd.to != null && nullemd.to.metadata.object) {
nullemd.from = nullemd.to;
} else {
nullemd.from = standard.objectType;
}
caster.markCast(nullemd);
return null;
}
@Override
public Void visitCat(CatContext ctx) {
ExpressionMetadata catemd = adapter.getExpressionMetadata(ctx);
final ExpressionContext exprctx0 = adapter.getExpressionContext(ctx.expression(0));
final ExpressionMetadata expremd0 = adapter.createExpressionMetadata(exprctx0);
expremd0.promotion = caster.concat;
visit(exprctx0);
expremd0.to = expremd0.from;
caster.markCast(expremd0);
final ExpressionContext exprctx1 = adapter.getExpressionContext(ctx.expression(1));
final ExpressionMetadata expremd1 = adapter.createExpressionMetadata(exprctx1);
expremd1.promotion = caster.concat;
visit(exprctx1);
expremd1.to = expremd1.from;
caster.markCast(expremd1);
if (expremd0.postConst != null && expremd1.postConst != null) {
catemd.postConst = expremd0.postConst.toString() + expremd1.postConst.toString();
}
catemd.from = standard.stringType;
caster.markCast(catemd);
return null;
}
@Override
public Void visitExt(final ExtContext ctx) {
External external = new External(adapter, this);
external.ext(ctx);
adapter.putExternal(ctx, external);
return null;
}
@Override
public Void visitPostinc(final PostincContext ctx) {
External external = new External(adapter, this);
external.postinc(ctx);
adapter.putExternal(ctx, external);
return null;
}
@Override
public Void visitPreinc(final PreincContext ctx) {
External external = new External(adapter, this);
external.preinc(ctx);
adapter.putExternal(ctx, external);
return null;
}
@Override
public Void visitUnary(final UnaryContext ctx) {
final ExpressionMetadata unaryemd = adapter.getExpressionMetadata(ctx);
final ExpressionContext exprctx = adapter.getExpressionContext(ctx.expression());
final ExpressionMetadata expremd = adapter.createExpressionMetadata(exprctx);
if (ctx.BOOLNOT() != null) {
expremd.to = standard.boolType;
visit(exprctx);
if (expremd.postConst != null) {
unaryemd.preConst = !(boolean)expremd.postConst;
}
unaryemd.from = standard.boolType;
} else if (ctx.BWNOT() != null || ctx.ADD() != null || ctx.SUB() != null) {
final Promotion promotion = ctx.BWNOT() != null ? caster.numeric : caster.decimal;
expremd.promotion = promotion;
visit(exprctx);
final Type promote = caster.getTypePromotion(ctx, expremd.from, null, promotion);
expremd.to = promote;
caster.markCast(expremd);
if (expremd.postConst != null) {
final TypeMetadata tmd = promote.metadata;
if (ctx.BWNOT() != null) {
if (tmd == TypeMetadata.INT) {
unaryemd.preConst = ~(int)expremd.postConst;
} else if (tmd == TypeMetadata.LONG) {
unaryemd.preConst = ~(long)expremd.postConst;
} else {
throw new IllegalStateException(error(ctx) + "Unexpected parser state.");
}
} else if (ctx.SUB() != null) {
if (tmd == TypeMetadata.INT) {
unaryemd.preConst = -(int)expremd.postConst;
} else if (tmd == TypeMetadata.LONG) {
unaryemd.preConst = -(long)expremd.postConst;
} else if (tmd == TypeMetadata.FLOAT) {
unaryemd.preConst = -(float)expremd.postConst;
} else if (tmd == TypeMetadata.DOUBLE) {
unaryemd.preConst = -(double)expremd.postConst;
} else {
throw new IllegalStateException(error(ctx) + "Unexpected parser state.");
}
} else if (ctx.ADD() != null) {
if (tmd == TypeMetadata.INT) {
unaryemd.preConst = +(int)expremd.postConst;
} else if (tmd == TypeMetadata.LONG) {
unaryemd.preConst = +(long)expremd.postConst;
} else if (tmd == TypeMetadata.FLOAT) {
unaryemd.preConst = +(float)expremd.postConst;
} else if (tmd == TypeMetadata.DOUBLE) {
unaryemd.preConst = +(double)expremd.postConst;
} else {
throw new IllegalStateException(error(ctx) + "Unexpected parser state.");
}
} else {
throw new IllegalStateException(error(ctx) + "Unexpected parser state.");
}
}
unaryemd.from = promote;
} else {
throw new IllegalStateException(error(ctx) + "Unexpected parser state.");
}
caster.markCast(unaryemd);
return null;
}
@Override
public Void visitCast(final CastContext ctx) {
final ExpressionMetadata castemd = adapter.getExpressionMetadata(ctx);
final DecltypeContext decltypectx = ctx.decltype();
final ExpressionMetadata decltypemd = adapter.createExpressionMetadata(decltypectx);
visit(decltypectx);
final Type type = decltypemd.from;
castemd.from = type;
final ExpressionContext exprctx = adapter.getExpressionContext(ctx.expression());
final ExpressionMetadata expremd = adapter.createExpressionMetadata(exprctx);
expremd.to = type;
expremd.explicit = true;
visit(exprctx);
if (expremd.postConst != null) {
castemd.preConst = expremd.postConst;
}
caster.markCast(castemd);
return null;
}
@Override
public Void visitBinary(final BinaryContext ctx) {
final ExpressionMetadata binaryemd = adapter.getExpressionMetadata(ctx);
Promotion promotion;
if (ctx.ADD() != null || ctx.SUB() != null || ctx.DIV() != null || ctx.MUL() != null || ctx.REM() != null) {
promotion = caster.decimal;
} else {
promotion = caster.numeric;
}
final ExpressionContext exprctx0 = adapter.getExpressionContext(ctx.expression(0));
final ExpressionMetadata expremd0 = adapter.createExpressionMetadata(exprctx0);
expremd0.promotion = promotion;
visit(exprctx0);
final ExpressionContext exprctx1 = adapter.getExpressionContext(ctx.expression(1));
final ExpressionMetadata expremd1 = adapter.createExpressionMetadata(exprctx1);
expremd1.promotion = promotion;
visit(exprctx1);
final Type promote = caster.getTypePromotion(ctx, expremd0.from, expremd1.from, promotion);
expremd0.to = promote;
caster.markCast(expremd0);
expremd1.to = promote;
caster.markCast(expremd1);
if (expremd0.postConst != null && expremd1.postConst != null) {
final TypeMetadata tmd = promote.metadata;
if (ctx.MUL() != null) {
if (tmd == TypeMetadata.INT) {
binaryemd.preConst = (int)expremd0.postConst * (int)expremd1.postConst;
} else if (tmd == TypeMetadata.LONG) {
binaryemd.preConst = (long)expremd0.postConst * (long)expremd1.postConst;
} else if (tmd == TypeMetadata.FLOAT) {
binaryemd.preConst = (float)expremd0.postConst * (float)expremd1.postConst;
} else if (tmd == TypeMetadata.DOUBLE) {
binaryemd.preConst = (double)expremd0.postConst * (double)expremd1.postConst;
} else {
throw new IllegalStateException(error(ctx) + "Unexpected parser state.");
}
} else if (ctx.DIV() != null) {
if (tmd == TypeMetadata.INT) {
binaryemd.preConst = (int)expremd0.postConst / (int)expremd1.postConst;
} else if (tmd == TypeMetadata.LONG) {
binaryemd.preConst = (long)expremd0.postConst / (long)expremd1.postConst;
} else if (tmd == TypeMetadata.FLOAT) {
binaryemd.preConst = (float)expremd0.postConst / (float)expremd1.postConst;
} else if (tmd == TypeMetadata.DOUBLE) {
binaryemd.preConst = (double)expremd0.postConst / (double)expremd1.postConst;
} else {
throw new IllegalStateException(error(ctx) + "Unexpected parser state.");
}
} else if (ctx.REM() != null) {
if (tmd == TypeMetadata.INT) {
binaryemd.preConst = (int)expremd0.postConst % (int)expremd1.postConst;
} else if (tmd == TypeMetadata.LONG) {
binaryemd.preConst = (long)expremd0.postConst % (long)expremd1.postConst;
} else if (tmd == TypeMetadata.FLOAT) {
binaryemd.preConst = (float)expremd0.postConst % (float)expremd1.postConst;
} else if (tmd == TypeMetadata.DOUBLE) {
binaryemd.preConst = (double)expremd0.postConst % (double)expremd1.postConst;
} else {
throw new IllegalStateException(error(ctx) + "Unexpected parser state.");
}
} else if (ctx.ADD() != null) {
if (tmd == TypeMetadata.INT) {
binaryemd.preConst = (int)expremd0.postConst + (int)expremd1.postConst;
} else if (tmd == TypeMetadata.LONG) {
binaryemd.preConst = (long)expremd0.postConst + (long)expremd1.postConst;
} else if (tmd == TypeMetadata.FLOAT) {
binaryemd.preConst = (float)expremd0.postConst + (float)expremd1.postConst;
} else if (tmd == TypeMetadata.DOUBLE) {
binaryemd.preConst = (double)expremd0.postConst + (double)expremd1.postConst;
} else {
throw new IllegalStateException(error(ctx) + "Unexpected parser state.");
}
} else if (ctx.SUB() != null) {
if (tmd == TypeMetadata.INT) {
binaryemd.preConst = (int)expremd0.postConst - (int)expremd1.postConst;
} else if (tmd == TypeMetadata.LONG) {
binaryemd.preConst = (long)expremd0.postConst - (long)expremd1.postConst;
} else if (tmd == TypeMetadata.FLOAT) {
binaryemd.preConst = (float)expremd0.postConst - (float)expremd1.postConst;
} else if (tmd == TypeMetadata.DOUBLE) {
binaryemd.preConst = (double)expremd0.postConst - (double)expremd1.postConst;
} else {
throw new IllegalStateException(error(ctx) + "Unexpected parser state.");
}
} else if (ctx.LSH() != null) {
if (tmd == TypeMetadata.INT) {
binaryemd.preConst = (int)expremd0.postConst << (int)expremd1.postConst;
} else if (tmd == TypeMetadata.LONG) {
binaryemd.preConst = (long)expremd0.postConst << (long)expremd1.postConst;
} else {
throw new IllegalStateException(error(ctx) + "Unexpected parser state.");
}
} else if (ctx.RSH() != null) {
if (tmd == TypeMetadata.INT) {
binaryemd.preConst = (int)expremd0.postConst >> (int)expremd1.postConst;
} else if (tmd == TypeMetadata.LONG) {
binaryemd.preConst = (long)expremd0.postConst >> (long)expremd1.postConst;
} else {
throw new IllegalStateException(error(ctx) + "Unexpected parser state.");
}
} else if (ctx.USH() != null) {
if (tmd == TypeMetadata.INT) {
binaryemd.preConst = (int)expremd0.postConst >>> (int)expremd1.postConst;
} else if (tmd == TypeMetadata.LONG) {
binaryemd.preConst = (long)expremd0.postConst >>> (long)expremd1.postConst;
} else {
throw new IllegalStateException(error(ctx) + "Unexpected parser state.");
}
} else if (ctx.BWAND() != null) {
if (tmd == TypeMetadata.INT) {
binaryemd.preConst = (int)expremd0.postConst & (int)expremd1.postConst;
} else if (tmd == TypeMetadata.LONG) {
binaryemd.preConst = (long)expremd0.postConst & (long)expremd1.postConst;
} else {
throw new IllegalStateException(error(ctx) + "Unexpected parser state.");
}
} else if (ctx.BWXOR() != null) {
if (tmd == TypeMetadata.INT) {
binaryemd.preConst = (int)expremd0.postConst ^ (int)expremd1.postConst;
} else if (tmd == TypeMetadata.LONG) {
binaryemd.preConst = (long)expremd0.postConst ^ (long)expremd1.postConst;
} else {
throw new IllegalStateException(error(ctx) + "Unexpected parser state.");
}
} else if (ctx.BWOR() != null) {
if (tmd == TypeMetadata.INT) {
binaryemd.preConst = (int)expremd0.postConst | (int)expremd1.postConst;
} else if (tmd == TypeMetadata.LONG) {
binaryemd.preConst = (long)expremd0.postConst | (long)expremd1.postConst;
} else {
throw new IllegalStateException(error(ctx) + "Unexpected parser state.");
}
} else {
throw new IllegalStateException(error(ctx) + "Unexpected parser state.");
}
}
binaryemd.from = promote;
caster.markCast(binaryemd);
return null;
}
@Override
public Void visitComp(final CompContext ctx) {
final ExpressionMetadata compemd = adapter.getExpressionMetadata(ctx);
final Promotion promotion =
ctx.EQ() != null || ctx.EQR() != null || ctx.NE() != null || ctx.NER() != null ?
caster.equality : caster.decimal;
final ExpressionContext exprctx0 = adapter.getExpressionContext(ctx.expression(0));
final ExpressionMetadata expremd0 = adapter.createExpressionMetadata(exprctx0);
expremd0.promotion = promotion;
visit(exprctx0);
final ExpressionContext exprctx1 = adapter.getExpressionContext(ctx.expression(1));
final ExpressionMetadata expremd1 = adapter.createExpressionMetadata(exprctx1);
expremd1.promotion = promotion;
visit(exprctx1);
final Type promote = caster.getTypePromotion(ctx, expremd0.from, expremd1.from, promotion);
if (expremd0.isNull && expremd1.isNull) {
throw new IllegalArgumentException(error(ctx) + "Unnecessary comparison of null constants.");
}
expremd0.to = promote;
caster.markCast(expremd0);
expremd1.to = promote;
caster.markCast(expremd1);
if (expremd0.postConst != null && expremd1.postConst != null) {
final TypeMetadata metadata = promote.metadata;
if (ctx.EQ() != null || ctx.EQR() != null) {
if (metadata == TypeMetadata.BOOL) {
compemd.preConst = (boolean)expremd0.postConst == (boolean)expremd1.postConst;
} else if (metadata == TypeMetadata.INT) {
compemd.preConst = (int)expremd0.postConst == (int)expremd1.postConst;
} else if (metadata == TypeMetadata.LONG) {
compemd.preConst = (long)expremd0.postConst == (long)expremd1.postConst;
} else if (metadata == TypeMetadata.FLOAT) {
compemd.preConst = (float)expremd0.postConst == (float)expremd1.postConst;
} else if (metadata == TypeMetadata.DOUBLE) {
compemd.preConst = (double)expremd0.postConst == (double)expremd1.postConst;
} else {
if (ctx.EQ() != null && !expremd0.isNull && !expremd1.isNull) {
compemd.preConst = expremd0.postConst.equals(expremd1.postConst);
} else if (ctx.EQR() != null) {
compemd.preConst = expremd0.postConst == expremd1.postConst;
}
}
} else if (ctx.NE() != null || ctx.NER() != null) {
if (metadata == TypeMetadata.BOOL) {
compemd.preConst = (boolean)expremd0.postConst != (boolean)expremd1.postConst;
} else if (metadata == TypeMetadata.INT) {
compemd.preConst = (int)expremd0.postConst != (int)expremd1.postConst;
} else if (metadata == TypeMetadata.LONG) {
compemd.preConst = (long)expremd0.postConst != (long)expremd1.postConst;
} else if (metadata == TypeMetadata.FLOAT) {
compemd.preConst = (float)expremd0.postConst != (float)expremd1.postConst;
} else if (metadata == TypeMetadata.DOUBLE) {
compemd.preConst = (double)expremd0.postConst != (double)expremd1.postConst;
} else {
if (ctx.NE() != null && !expremd0.isNull && !expremd1.isNull) {
compemd.preConst = expremd0.postConst.equals(expremd1.postConst);
} else if (ctx.NER() != null) {
compemd.preConst = expremd0.postConst == expremd1.postConst;
}
}
} else if (ctx.GTE() != null) {
if (metadata == TypeMetadata.INT) {
compemd.preConst = (int)expremd0.postConst >= (int)expremd1.postConst;
} else if (metadata == TypeMetadata.LONG) {
compemd.preConst = (long)expremd0.postConst >= (long)expremd1.postConst;
} else if (metadata == TypeMetadata.FLOAT) {
compemd.preConst = (float)expremd0.postConst >= (float)expremd1.postConst;
} else if (metadata == TypeMetadata.DOUBLE) {
compemd.preConst = (double)expremd0.postConst >= (double)expremd1.postConst;
}
} else if (ctx.GT() != null) {
if (metadata == TypeMetadata.INT) {
compemd.preConst = (int)expremd0.postConst > (int)expremd1.postConst;
} else if (metadata == TypeMetadata.LONG) {
compemd.preConst = (long)expremd0.postConst > (long)expremd1.postConst;
} else if (metadata == TypeMetadata.FLOAT) {
compemd.preConst = (float)expremd0.postConst > (float)expremd1.postConst;
} else if (metadata == TypeMetadata.DOUBLE) {
compemd.preConst = (double)expremd0.postConst > (double)expremd1.postConst;
}
} else if (ctx.LTE() != null) {
if (metadata == TypeMetadata.INT) {
compemd.preConst = (int)expremd0.postConst <= (int)expremd1.postConst;
} else if (metadata == TypeMetadata.LONG) {
compemd.preConst = (long)expremd0.postConst <= (long)expremd1.postConst;
} else if (metadata == TypeMetadata.FLOAT) {
compemd.preConst = (float)expremd0.postConst <= (float)expremd1.postConst;
} else if (metadata == TypeMetadata.DOUBLE) {
compemd.preConst = (double)expremd0.postConst <= (double)expremd1.postConst;
}
} else if (ctx.LT() != null) {
if (metadata == TypeMetadata.INT) {
compemd.preConst = (int)expremd0.postConst < (int)expremd1.postConst;
} else if (metadata == TypeMetadata.LONG) {
compemd.preConst = (long)expremd0.postConst < (long)expremd1.postConst;
} else if (metadata == TypeMetadata.FLOAT) {
compemd.preConst = (float)expremd0.postConst < (float)expremd1.postConst;
} else if (metadata == TypeMetadata.DOUBLE) {
compemd.preConst = (double)expremd0.postConst < (double)expremd1.postConst;
}
} else {
throw new IllegalStateException(error(ctx) + "Unexpected parser state.");
}
}
compemd.from = standard.boolType;
caster.markCast(compemd);
return null;
}
@Override
public Void visitBool(final BoolContext ctx) {
final ExpressionMetadata boolemd = adapter.getExpressionMetadata(ctx);
final ExpressionContext exprctx0 = adapter.getExpressionContext(ctx.expression(0));
final ExpressionMetadata expremd0 = adapter.createExpressionMetadata(exprctx0);
expremd0.to = standard.boolType;
visit(exprctx0);
final ExpressionContext exprctx1 = adapter.getExpressionContext(ctx.expression(1));
final ExpressionMetadata expremd1 = adapter.createExpressionMetadata(exprctx1);
expremd1.to = standard.boolType;
visit(exprctx1);
if (expremd0.postConst != null && expremd1.postConst != null) {
if (ctx.BOOLAND() != null) {
boolemd.preConst = (boolean)expremd0.postConst && (boolean)expremd1.postConst;
} else if (ctx.BOOLOR() != null) {
boolemd.preConst = (boolean)expremd0.postConst || (boolean)expremd1.postConst;
} else {
throw new IllegalStateException(error(ctx) + "Unexpected parser state.");
}
}
boolemd.from = standard.boolType;
caster.markCast(boolemd);
return null;
}
@Override
public Void visitConditional(final ConditionalContext ctx) {
final ExpressionMetadata condemd = adapter.getExpressionMetadata(ctx);
final ExpressionContext exprctx0 = adapter.getExpressionContext(ctx.expression(0));
final ExpressionMetadata expremd0 = adapter.createExpressionMetadata(exprctx0);
expremd0.to = standard.boolType;
visit(exprctx0);
if (expremd0.postConst != null) {
throw new IllegalArgumentException(error(ctx) + "Unnecessary conditional statement.");
}
final ExpressionContext exprctx1 = adapter.getExpressionContext(ctx.expression(1));
final ExpressionMetadata expremd1 = adapter.createExpressionMetadata(exprctx1);
expremd1.to = condemd.to;
expremd1.promotion = condemd.promotion;
visit(exprctx1);
final ExpressionContext exprctx2 = adapter.getExpressionContext(ctx.expression(2));
final ExpressionMetadata expremd2 = adapter.createExpressionMetadata(exprctx2);
expremd2.to = condemd.to;
expremd2.promotion = condemd.promotion;
visit(exprctx2);
if (condemd.to != null) {
condemd.from = condemd.to;
} else if (condemd.promotion != null) {
final Type promote = caster.getTypePromotion(ctx, expremd1.from, expremd2.from, condemd.promotion);
expremd0.to = promote;
caster.markCast(expremd1);
expremd1.to = promote;
caster.markCast(expremd2);
condemd.from = promote;
} else {
throw new IllegalStateException(error(ctx) + "No cast or promotion specified.");
}
caster.markCast(condemd);
return null;
}
@Override
public Void visitAssignment(final AssignmentContext ctx) {
External external = new External(adapter, this);
external.assignment(ctx);
adapter.putExternal(ctx, external);
return null;
}
@Override
public Void visitExtstart(final ExtstartContext ctx) {
throw new UnsupportedOperationException(error(ctx) + "Unexpected parser state.");
}
@Override
public Void visitExtprec(final ExtprecContext ctx) {
throw new UnsupportedOperationException(error(ctx) + "Unexpected parser state.");
}
@Override
public Void visitExtcast(final ExtcastContext ctx) {
throw new UnsupportedOperationException(error(ctx) + "Unexpected parser state.");
}
@Override
public Void visitExtbrace(final ExtbraceContext ctx) {
throw new UnsupportedOperationException(error(ctx) + "Unexpected parser state.");
}
@Override
public Void visitExtdot(final ExtdotContext ctx) {
throw new UnsupportedOperationException(error(ctx) + "Unexpected parser state.");
}
@Override
public Void visitExttype(final ExttypeContext ctx) {
throw new UnsupportedOperationException(error(ctx) + "Unexpected parser state.");
}
@Override
public Void visitExtcall(final ExtcallContext ctx) {
throw new UnsupportedOperationException(error(ctx) + "Unexpected parser state.");
}
@Override
public Void visitExtmember(final ExtmemberContext ctx) {
throw new UnsupportedOperationException(error(ctx) + "Unexpected parser state.");
}
@Override
public Void visitArguments(final ArgumentsContext ctx) {
throw new UnsupportedOperationException(error(ctx) + "Unexpected parser state.");
}
@Override
public Void visitIncrement(IncrementContext ctx) {
final ExpressionMetadata incremd = adapter.getExpressionMetadata(ctx);
final TypeMetadata metadata = incremd.to == null ? null : incremd.to.metadata;
final boolean positive = ctx.INCR() != null;
if (incremd.to == null) {
incremd.preConst = positive ? 1 : -1;
incremd.from = standard.intType;
} else {
switch (metadata) {
case LONG:
incremd.preConst = positive ? 1L : -1L;
incremd.from = standard.longType;
case FLOAT:
incremd.preConst = positive ? 1.0F : -1.0F;
incremd.from = standard.floatType;
case DOUBLE:
incremd.preConst = positive ? 1.0 : -1.0;
incremd.from = standard.doubleType;
default:
incremd.preConst = positive ? 1 : -1;
incremd.from = standard.intType;
}
}
caster.markCast(incremd);
return null;
}
}