diff --git a/plugins/lang-plan-a/src/main/antlr/PlanAParser.g4 b/plugins/lang-plan-a/src/main/antlr/PlanAParser.g4 index 1b177a43381..851d924b33f 100644 --- a/plugins/lang-plan-a/src/main/antlr/PlanAParser.g4 +++ b/plugins/lang-plan-a/src/main/antlr/PlanAParser.g4 @@ -34,18 +34,23 @@ statement | CONTINUE SEMICOLON? # continue | BREAK SEMICOLON? # break | RETURN expression SEMICOLON? # return - | TRY block ( CATCH LP ( TYPE ID ) RP block )+ # try + | TRY block trap+ # try | THROW expression SEMICOLON? # throw | expression SEMICOLON? # expr ; block - : LBRACK statement* RBRACK # multiple + : LBRACK statement+ RBRACK # multiple | statement # single ; empty - : SEMICOLON + : emptyscope + | SEMICOLON + ; + +emptyscope + : LBRACK RBRACK ; initializer @@ -69,6 +74,10 @@ declvar : ID ( ASSIGN expression )? ; +trap + : CATCH LP ( TYPE ID ) RP ( block | emptyscope ) + ; + expression : LP expression RP # precedence | ( OCTAL | HEX | INTEGER | DECIMAL ) # numeric diff --git a/plugins/lang-plan-a/src/main/java/org/elasticsearch/plan/a/Adapter.java b/plugins/lang-plan-a/src/main/java/org/elasticsearch/plan/a/Adapter.java deleted file mode 100644 index 9788e63c3d7..00000000000 --- a/plugins/lang-plan-a/src/main/java/org/elasticsearch/plan/a/Adapter.java +++ /dev/null @@ -1,278 +0,0 @@ -/* - * 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. - */ - -package org.elasticsearch.plan.a; - -import org.antlr.v4.runtime.ParserRuleContext; -import org.antlr.v4.runtime.tree.ParseTree; - -import java.util.HashMap; -import java.util.Map; - -import static org.elasticsearch.plan.a.Definition.Cast; -import static org.elasticsearch.plan.a.Definition.Type; -import static org.elasticsearch.plan.a.PlanAParser.ExpressionContext; -import static org.elasticsearch.plan.a.PlanAParser.PrecedenceContext; - -class Adapter { - static class StatementMetadata { - final ParserRuleContext source; - - boolean last; - - boolean allExit; - boolean allReturn; - boolean anyReturn; - boolean allBreak; - boolean anyBreak; - boolean allContinue; - boolean anyContinue; - - private StatementMetadata(final ParserRuleContext source) { - this.source = source; - - last = false; - - allExit = false; - allReturn = false; - anyReturn = false; - allBreak = false; - anyBreak = false; - allContinue = false; - anyContinue = false; - } - } - - static class ExpressionMetadata { - final ParserRuleContext source; - - boolean read; - boolean statement; - - Object preConst; - Object postConst; - boolean isNull; - - Type to; - Type from; - boolean explicit; - boolean typesafe; - - Cast cast; - - private ExpressionMetadata(final ParserRuleContext source) { - this.source = source; - - read = true; - statement = false; - - preConst = null; - postConst = null; - isNull = false; - - to = null; - from = null; - explicit = false; - typesafe = true; - - cast = null; - } - } - - static class ExternalMetadata { - final ParserRuleContext source; - - boolean read; - ParserRuleContext storeExpr; - int token; - boolean pre; - boolean post; - - int scope; - Type current; - boolean statik; - boolean statement; - Object constant; - - private ExternalMetadata(final ParserRuleContext source) { - this.source = source; - - read = false; - storeExpr = null; - token = 0; - pre = false; - post = false; - - scope = 0; - current = null; - statik = false; - statement = false; - constant = null; - } - } - - static class ExtNodeMetadata { - final ParserRuleContext parent; - final ParserRuleContext source; - - Object target; - boolean last; - - Type type; - Type promote; - - Cast castFrom; - Cast castTo; - - private ExtNodeMetadata(final ParserRuleContext parent, final ParserRuleContext source) { - this.parent = parent; - this.source = source; - - target = null; - last = false; - - type = null; - promote = null; - - castFrom = null; - castTo = null; - } - } - - static String error(final ParserRuleContext ctx) { - return "Error [" + ctx.getStart().getLine() + ":" + ctx.getStart().getCharPositionInLine() + "]: "; - } - - final Definition definition; - final String source; - final ParserRuleContext root; - final CompilerSettings settings; - - private final Map statementMetadata; - private final Map expressionMetadata; - private final Map externalMetadata; - private final Map extNodeMetadata; - - Adapter(final Definition definition, final String source, final ParserRuleContext root, final CompilerSettings settings) { - this.definition = definition; - this.source = source; - this.root = root; - this.settings = settings; - - statementMetadata = new HashMap<>(); - expressionMetadata = new HashMap<>(); - externalMetadata = new HashMap<>(); - extNodeMetadata = new HashMap<>(); - } - - StatementMetadata createStatementMetadata(final ParserRuleContext source) { - final StatementMetadata sourcesmd = new StatementMetadata(source); - statementMetadata.put(source, sourcesmd); - - return sourcesmd; - } - - StatementMetadata getStatementMetadata(final ParserRuleContext source) { - final StatementMetadata sourcesmd = statementMetadata.get(source); - - if (sourcesmd == null) { - throw new IllegalStateException(error(source) + "Statement metadata does not exist at" + - " the parse node with text [" + source.getText() + "]."); - } - - return sourcesmd; - } - - ExpressionContext updateExpressionTree(ExpressionContext source) { - if (source instanceof PrecedenceContext) { - final ParserRuleContext parent = source.getParent(); - int index = 0; - - for (final ParseTree child : parent.children) { - if (child == source) { - break; - } - - ++index; - } - - while (source instanceof PrecedenceContext) { - source = ((PrecedenceContext)source).expression(); - } - - parent.children.set(index, source); - } - - return source; - } - - ExpressionMetadata createExpressionMetadata(ParserRuleContext source) { - final ExpressionMetadata sourceemd = new ExpressionMetadata(source); - expressionMetadata.put(source, sourceemd); - - return sourceemd; - } - - ExpressionMetadata getExpressionMetadata(final ParserRuleContext source) { - final ExpressionMetadata sourceemd = expressionMetadata.get(source); - - if (sourceemd == null) { - throw new IllegalStateException(error(source) + "Expression metadata does not exist at" + - " the parse node with text [" + source.getText() + "]."); - } - - return sourceemd; - } - - ExternalMetadata createExternalMetadata(final ParserRuleContext source) { - final ExternalMetadata sourceemd = new ExternalMetadata(source); - externalMetadata.put(source, sourceemd); - - return sourceemd; - } - - ExternalMetadata getExternalMetadata(final ParserRuleContext source) { - final ExternalMetadata sourceemd = externalMetadata.get(source); - - if (sourceemd == null) { - throw new IllegalStateException(error(source) + "External metadata does not exist at" + - " the parse node with text [" + source.getText() + "]."); - } - - return sourceemd; - } - - ExtNodeMetadata createExtNodeMetadata(final ParserRuleContext parent, final ParserRuleContext source) { - final ExtNodeMetadata sourceemd = new ExtNodeMetadata(parent, source); - extNodeMetadata.put(source, sourceemd); - - return sourceemd; - } - - ExtNodeMetadata getExtNodeMetadata(final ParserRuleContext source) { - final ExtNodeMetadata sourceemd = extNodeMetadata.get(source); - - if (sourceemd == null) { - throw new IllegalStateException(error(source) + "External metadata does not exist at" + - " the parse node with text [" + source.getText() + "]."); - } - - return sourceemd; - } -} diff --git a/plugins/lang-plan-a/src/main/java/org/elasticsearch/plan/a/Analyzer.java b/plugins/lang-plan-a/src/main/java/org/elasticsearch/plan/a/Analyzer.java index eb2681cfba8..77769736bf1 100644 --- a/plugins/lang-plan-a/src/main/java/org/elasticsearch/plan/a/Analyzer.java +++ b/plugins/lang-plan-a/src/main/java/org/elasticsearch/plan/a/Analyzer.java @@ -20,6 +20,72 @@ package org.elasticsearch.plan.a; import org.antlr.v4.runtime.ParserRuleContext; +import org.elasticsearch.plan.a.Definition.Cast; +import org.elasticsearch.plan.a.Definition.Constructor; +import org.elasticsearch.plan.a.Definition.Field; +import org.elasticsearch.plan.a.Definition.Method; +import org.elasticsearch.plan.a.Definition.Pair; +import org.elasticsearch.plan.a.Definition.Sort; +import org.elasticsearch.plan.a.Definition.Struct; +import org.elasticsearch.plan.a.Definition.Transform; +import org.elasticsearch.plan.a.Definition.Type; +import org.elasticsearch.plan.a.Metadata.ExpressionMetadata; +import org.elasticsearch.plan.a.Metadata.ExtNodeMetadata; +import org.elasticsearch.plan.a.Metadata.ExternalMetadata; +import org.elasticsearch.plan.a.Metadata.StatementMetadata; +import org.elasticsearch.plan.a.PlanAParser.AfterthoughtContext; +import org.elasticsearch.plan.a.PlanAParser.ArgumentsContext; +import org.elasticsearch.plan.a.PlanAParser.AssignmentContext; +import org.elasticsearch.plan.a.PlanAParser.BinaryContext; +import org.elasticsearch.plan.a.PlanAParser.BlockContext; +import org.elasticsearch.plan.a.PlanAParser.BoolContext; +import org.elasticsearch.plan.a.PlanAParser.BreakContext; +import org.elasticsearch.plan.a.PlanAParser.CastContext; +import org.elasticsearch.plan.a.PlanAParser.CharContext; +import org.elasticsearch.plan.a.PlanAParser.CompContext; +import org.elasticsearch.plan.a.PlanAParser.ConditionalContext; +import org.elasticsearch.plan.a.PlanAParser.ContinueContext; +import org.elasticsearch.plan.a.PlanAParser.DeclContext; +import org.elasticsearch.plan.a.PlanAParser.DeclarationContext; +import org.elasticsearch.plan.a.PlanAParser.DecltypeContext; +import org.elasticsearch.plan.a.PlanAParser.DeclvarContext; +import org.elasticsearch.plan.a.PlanAParser.DoContext; +import org.elasticsearch.plan.a.PlanAParser.EmptyContext; +import org.elasticsearch.plan.a.PlanAParser.ExprContext; +import org.elasticsearch.plan.a.PlanAParser.ExpressionContext; +import org.elasticsearch.plan.a.PlanAParser.ExtbraceContext; +import org.elasticsearch.plan.a.PlanAParser.ExtcallContext; +import org.elasticsearch.plan.a.PlanAParser.ExtcastContext; +import org.elasticsearch.plan.a.PlanAParser.ExtdotContext; +import org.elasticsearch.plan.a.PlanAParser.ExternalContext; +import org.elasticsearch.plan.a.PlanAParser.ExtfieldContext; +import org.elasticsearch.plan.a.PlanAParser.ExtnewContext; +import org.elasticsearch.plan.a.PlanAParser.ExtprecContext; +import org.elasticsearch.plan.a.PlanAParser.ExtstartContext; +import org.elasticsearch.plan.a.PlanAParser.ExtstringContext; +import org.elasticsearch.plan.a.PlanAParser.ExttypeContext; +import org.elasticsearch.plan.a.PlanAParser.ExtvarContext; +import org.elasticsearch.plan.a.PlanAParser.FalseContext; +import org.elasticsearch.plan.a.PlanAParser.ForContext; +import org.elasticsearch.plan.a.PlanAParser.IfContext; +import org.elasticsearch.plan.a.PlanAParser.IncrementContext; +import org.elasticsearch.plan.a.PlanAParser.InitializerContext; +import org.elasticsearch.plan.a.PlanAParser.MultipleContext; +import org.elasticsearch.plan.a.PlanAParser.NullContext; +import org.elasticsearch.plan.a.PlanAParser.NumericContext; +import org.elasticsearch.plan.a.PlanAParser.PostincContext; +import org.elasticsearch.plan.a.PlanAParser.PrecedenceContext; +import org.elasticsearch.plan.a.PlanAParser.PreincContext; +import org.elasticsearch.plan.a.PlanAParser.ReturnContext; +import org.elasticsearch.plan.a.PlanAParser.SingleContext; +import org.elasticsearch.plan.a.PlanAParser.SourceContext; +import org.elasticsearch.plan.a.PlanAParser.StatementContext; +import org.elasticsearch.plan.a.PlanAParser.ThrowContext; +import org.elasticsearch.plan.a.PlanAParser.TrapContext; +import org.elasticsearch.plan.a.PlanAParser.TrueContext; +import org.elasticsearch.plan.a.PlanAParser.TryContext; +import org.elasticsearch.plan.a.PlanAParser.UnaryContext; +import org.elasticsearch.plan.a.PlanAParser.WhileContext; import java.util.ArrayDeque; import java.util.Arrays; @@ -28,81 +94,18 @@ import java.util.Iterator; import java.util.List; import java.util.Map; -import static org.elasticsearch.plan.a.Adapter.ExpressionMetadata; -import static org.elasticsearch.plan.a.Adapter.ExtNodeMetadata; -import static org.elasticsearch.plan.a.Adapter.ExternalMetadata; -import static org.elasticsearch.plan.a.Adapter.StatementMetadata; -import static org.elasticsearch.plan.a.Adapter.error; -import static org.elasticsearch.plan.a.Definition.Cast; -import static org.elasticsearch.plan.a.Definition.Constructor; -import static org.elasticsearch.plan.a.Definition.Field; -import static org.elasticsearch.plan.a.Definition.Method; -import static org.elasticsearch.plan.a.Definition.Pair; -import static org.elasticsearch.plan.a.Definition.Sort; -import static org.elasticsearch.plan.a.Definition.Struct; -import static org.elasticsearch.plan.a.Definition.Transform; -import static org.elasticsearch.plan.a.Definition.Type; +import static org.elasticsearch.plan.a.Metadata.error; import static org.elasticsearch.plan.a.PlanAParser.ADD; -import static org.elasticsearch.plan.a.PlanAParser.AfterthoughtContext; -import static org.elasticsearch.plan.a.PlanAParser.ArgumentsContext; -import static org.elasticsearch.plan.a.PlanAParser.AssignmentContext; import static org.elasticsearch.plan.a.PlanAParser.BWAND; import static org.elasticsearch.plan.a.PlanAParser.BWOR; import static org.elasticsearch.plan.a.PlanAParser.BWXOR; -import static org.elasticsearch.plan.a.PlanAParser.BinaryContext; -import static org.elasticsearch.plan.a.PlanAParser.BlockContext; -import static org.elasticsearch.plan.a.PlanAParser.BoolContext; -import static org.elasticsearch.plan.a.PlanAParser.BreakContext; -import static org.elasticsearch.plan.a.PlanAParser.CastContext; -import static org.elasticsearch.plan.a.PlanAParser.CharContext; -import static org.elasticsearch.plan.a.PlanAParser.CompContext; -import static org.elasticsearch.plan.a.PlanAParser.ConditionalContext; -import static org.elasticsearch.plan.a.PlanAParser.ContinueContext; import static org.elasticsearch.plan.a.PlanAParser.DIV; -import static org.elasticsearch.plan.a.PlanAParser.DeclContext; -import static org.elasticsearch.plan.a.PlanAParser.DeclarationContext; -import static org.elasticsearch.plan.a.PlanAParser.DecltypeContext; -import static org.elasticsearch.plan.a.PlanAParser.DeclvarContext; -import static org.elasticsearch.plan.a.PlanAParser.DoContext; -import static org.elasticsearch.plan.a.PlanAParser.EmptyContext; -import static org.elasticsearch.plan.a.PlanAParser.ExprContext; -import static org.elasticsearch.plan.a.PlanAParser.ExpressionContext; -import static org.elasticsearch.plan.a.PlanAParser.ExtbraceContext; -import static org.elasticsearch.plan.a.PlanAParser.ExtcallContext; -import static org.elasticsearch.plan.a.PlanAParser.ExtcastContext; -import static org.elasticsearch.plan.a.PlanAParser.ExtdotContext; -import static org.elasticsearch.plan.a.PlanAParser.ExternalContext; -import static org.elasticsearch.plan.a.PlanAParser.ExtfieldContext; -import static org.elasticsearch.plan.a.PlanAParser.ExtnewContext; -import static org.elasticsearch.plan.a.PlanAParser.ExtprecContext; -import static org.elasticsearch.plan.a.PlanAParser.ExtstartContext; -import static org.elasticsearch.plan.a.PlanAParser.ExtstringContext; -import static org.elasticsearch.plan.a.PlanAParser.ExttypeContext; -import static org.elasticsearch.plan.a.PlanAParser.ExtvarContext; -import static org.elasticsearch.plan.a.PlanAParser.FalseContext; -import static org.elasticsearch.plan.a.PlanAParser.ForContext; -import static org.elasticsearch.plan.a.PlanAParser.IfContext; -import static org.elasticsearch.plan.a.PlanAParser.IncrementContext; -import static org.elasticsearch.plan.a.PlanAParser.InitializerContext; import static org.elasticsearch.plan.a.PlanAParser.LSH; import static org.elasticsearch.plan.a.PlanAParser.MUL; -import static org.elasticsearch.plan.a.PlanAParser.MultipleContext; -import static org.elasticsearch.plan.a.PlanAParser.NullContext; -import static org.elasticsearch.plan.a.PlanAParser.NumericContext; -import static org.elasticsearch.plan.a.PlanAParser.PostincContext; -import static org.elasticsearch.plan.a.PlanAParser.PrecedenceContext; -import static org.elasticsearch.plan.a.PlanAParser.PreincContext; import static org.elasticsearch.plan.a.PlanAParser.REM; import static org.elasticsearch.plan.a.PlanAParser.RSH; -import static org.elasticsearch.plan.a.PlanAParser.ReturnContext; import static org.elasticsearch.plan.a.PlanAParser.SUB; -import static org.elasticsearch.plan.a.PlanAParser.SingleContext; -import static org.elasticsearch.plan.a.PlanAParser.SourceContext; -import static org.elasticsearch.plan.a.PlanAParser.StatementContext; -import static org.elasticsearch.plan.a.PlanAParser.TrueContext; import static org.elasticsearch.plan.a.PlanAParser.USH; -import static org.elasticsearch.plan.a.PlanAParser.UnaryContext; -import static org.elasticsearch.plan.a.PlanAParser.WhileContext; class Analyzer extends PlanAParserBaseVisitor { private static class Variable { @@ -117,31 +120,30 @@ class Analyzer extends PlanAParserBaseVisitor { } } - static void analyze(final Adapter adapter) { - new Analyzer(adapter); + static void analyze(final Metadata metadata) { + new Analyzer(metadata); } - private final Adapter adapter; + private final Metadata metadata; private final Definition definition; private final CompilerSettings settings; - private final Deque scopes; - private final Deque variables; + private final Deque scopes = new ArrayDeque<>(); + private final Deque variables = new ArrayDeque<>(); - private Analyzer(final Adapter adapter) { - this.adapter = adapter; - definition = adapter.definition; - settings = adapter.settings; - - scopes = new ArrayDeque<>(); - variables = new ArrayDeque<>(); + private Analyzer(final Metadata metadata) { + this.metadata = metadata; + definition = metadata.definition; + settings = metadata.settings; incrementScope(); - addVariable(null, "this", definition.execType); - addVariable(null, "input", definition.smapType); + addVariable(null, "#this", definition.execType); + metadata.inputValueSlot = addVariable(null, "input", definition.smapType).slot; + metadata.scoreValueSlot = addVariable(null, "_score", definition.floatType).slot; + metadata.loopCounterSlot = addVariable(null, "#loop", definition.intType).slot; - adapter.createStatementMetadata(adapter.root); - visit(adapter.root); + metadata.createStatementMetadata(metadata.root); + visit(metadata.root); decrementScope(); } @@ -179,7 +181,7 @@ class Analyzer extends PlanAParserBaseVisitor { throw new IllegalArgumentException("Argument name [" + name + "] already defined within the scope."); } else { throw new IllegalArgumentException( - error(source) + "Variable name [" + name + "] already defined within the scope."); + error(source) + "Variable name [" + name + "] already defined within the scope."); } } @@ -201,34 +203,24 @@ class Analyzer extends PlanAParserBaseVisitor { @Override public Void visitSource(final SourceContext ctx) { - final StatementMetadata sourcesmd = adapter.getStatementMetadata(ctx); + final StatementMetadata sourcesmd = metadata.getStatementMetadata(ctx); final List statectxs = ctx.statement(); final StatementContext lastctx = statectxs.get(statectxs.size() - 1); incrementScope(); for (final StatementContext statectx : statectxs) { - if (sourcesmd.allExit) { + if (sourcesmd.allLast) { throw new IllegalArgumentException(error(statectx) + - "Statement will never be executed because all prior paths exit."); + "Statement will never be executed because all prior paths escape."); } - final StatementMetadata statesmd = adapter.createStatementMetadata(statectx); - statesmd.last = statectx == lastctx; + final StatementMetadata statesmd = metadata.createStatementMetadata(statectx); + statesmd.lastSource = statectx == lastctx; 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; + sourcesmd.methodEscape = statesmd.methodEscape; + sourcesmd.allLast = statesmd.allLast; } decrementScope(); @@ -238,12 +230,10 @@ class Analyzer extends PlanAParserBaseVisitor { @Override public Void visitIf(final IfContext ctx) { - final StatementMetadata ifsmd = adapter.getStatementMetadata(ctx); + final StatementMetadata ifsmd = metadata.getStatementMetadata(ctx); - incrementScope(); - - final ExpressionContext exprctx = adapter.updateExpressionTree(ctx.expression()); - final ExpressionMetadata expremd = adapter.createExpressionMetadata(exprctx); + final ExpressionContext exprctx = metadata.updateExpressionTree(ctx.expression()); + final ExpressionMetadata expremd = metadata.createExpressionMetadata(exprctx); expremd.to = definition.booleanType; visit(exprctx); markCast(expremd); @@ -253,84 +243,85 @@ class Analyzer extends PlanAParserBaseVisitor { } final BlockContext blockctx0 = ctx.block(0); - final StatementMetadata blocksmd0 = adapter.createStatementMetadata(blockctx0); - blocksmd0.last = ifsmd.last; + final StatementMetadata blocksmd0 = metadata.createStatementMetadata(blockctx0); + blocksmd0.lastSource = ifsmd.lastSource; + blocksmd0.inLoop = ifsmd.inLoop; + blocksmd0.lastLoop = ifsmd.lastLoop; + incrementScope(); visit(blockctx0); + decrementScope(); - ifsmd.anyReturn = blocksmd0.anyReturn; - ifsmd.anyBreak = blocksmd0.anyBreak; ifsmd.anyContinue = blocksmd0.anyContinue; + ifsmd.anyBreak = blocksmd0.anyBreak; + + ifsmd.count = blocksmd0.count; if (ctx.ELSE() != null) { final BlockContext blockctx1 = ctx.block(1); - final StatementMetadata blocksmd1 = adapter.createStatementMetadata(blockctx1); - blocksmd1.last = ifsmd.last; + final StatementMetadata blocksmd1 = metadata.createStatementMetadata(blockctx1); + blocksmd1.lastSource = ifsmd.lastSource; + incrementScope(); visit(blockctx1); + decrementScope(); - 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.methodEscape = blocksmd0.methodEscape && blocksmd1.methodEscape; + ifsmd.loopEscape = blocksmd0.loopEscape && blocksmd1.loopEscape; + ifsmd.allLast = blocksmd0.allLast && blocksmd1.allLast; ifsmd.anyContinue |= blocksmd1.anyContinue; - } + ifsmd.anyBreak |= blocksmd1.anyBreak; - decrementScope(); + ifsmd.count = Math.max(ifsmd.count, blocksmd1.count); + } return null; } @Override public Void visitWhile(final WhileContext ctx) { - final StatementMetadata whilesmd = adapter.getStatementMetadata(ctx); + final StatementMetadata whilesmd = metadata.getStatementMetadata(ctx); incrementScope(); - final ExpressionContext exprctx = adapter.updateExpressionTree(ctx.expression()); - final ExpressionMetadata expremd = adapter.createExpressionMetadata(exprctx); + final ExpressionContext exprctx = metadata.updateExpressionTree(ctx.expression()); + final ExpressionMetadata expremd = metadata.createExpressionMetadata(exprctx); expremd.to = definition.booleanType; visit(exprctx); markCast(expremd); - boolean exitrequired = false; + boolean continuous = false; if (expremd.postConst != null) { - boolean constant = (boolean)expremd.postConst; + continuous = (boolean)expremd.postConst; - if (!constant) { + if (!continuous) { throw new IllegalArgumentException(error(ctx) + "The loop will never be executed."); } - exitrequired = true; + if (ctx.empty() != null) { + throw new IllegalArgumentException(error(ctx) + "The loop will never exit."); + } } final BlockContext blockctx = ctx.block(); if (blockctx != null) { - final StatementMetadata blocksmd = adapter.createStatementMetadata(blockctx); + final StatementMetadata blocksmd = metadata.createStatementMetadata(blockctx); + blocksmd.beginLoop = true; + blocksmd.inLoop = true; visit(blockctx); - if (blocksmd.allReturn) { - throw new IllegalArgumentException(error(ctx) + "All paths return so the loop is not necessary."); + if (blocksmd.loopEscape && !blocksmd.anyContinue) { + throw new IllegalArgumentException(error(ctx) + "All paths escape so the loop is not necessary."); } - if (blocksmd.allBreak) { - throw new IllegalArgumentException(error(ctx) + "All paths break so the loop is not necessary."); + if (continuous && !blocksmd.anyBreak) { + whilesmd.methodEscape = true; + whilesmd.allLast = true; } - - 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."); } + whilesmd.count = 1; + decrementScope(); return null; @@ -338,49 +329,41 @@ class Analyzer extends PlanAParserBaseVisitor { @Override public Void visitDo(final DoContext ctx) { - final StatementMetadata dosmd = adapter.getStatementMetadata(ctx); + final StatementMetadata dosmd = metadata.getStatementMetadata(ctx); incrementScope(); final BlockContext blockctx = ctx.block(); - final StatementMetadata blocksmd = adapter.createStatementMetadata(blockctx); + final StatementMetadata blocksmd = metadata.createStatementMetadata(blockctx); + blocksmd.beginLoop = true; + blocksmd.inLoop = true; visit(blockctx); - if (blocksmd.allReturn) { - throw new IllegalArgumentException(error(ctx) + "All paths return so the loop is not necessary."); + if (blocksmd.loopEscape && !blocksmd.anyContinue) { + throw new IllegalArgumentException(error(ctx) + "All paths escape 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.updateExpressionTree(ctx.expression()); - final ExpressionMetadata expremd = adapter.createExpressionMetadata(exprctx); + final ExpressionContext exprctx = metadata.updateExpressionTree(ctx.expression()); + final ExpressionMetadata expremd = metadata.createExpressionMetadata(exprctx); expremd.to = definition.booleanType; visit(exprctx); markCast(expremd); if (expremd.postConst != null) { - final boolean exitrequired = (boolean)expremd.postConst; + final boolean continuous = (boolean)expremd.postConst; - if (exitrequired && !blocksmd.anyReturn && !blocksmd.anyBreak) { - throw new IllegalArgumentException(error(ctx) + "The loop will never exit."); + if (!continuous) { + throw new IllegalArgumentException(error(ctx) + "All paths escape so the loop is not necessary."); } - 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."); + if (!blocksmd.anyBreak) { + dosmd.methodEscape = true; + dosmd.allLast = true; } } + dosmd.count = 1; + decrementScope(); return null; @@ -388,72 +371,68 @@ class Analyzer extends PlanAParserBaseVisitor { @Override public Void visitFor(final ForContext ctx) { - final StatementMetadata forsmd = adapter.getStatementMetadata(ctx); - boolean exitrequired = false; + final StatementMetadata forsmd = metadata.getStatementMetadata(ctx); + boolean continuous = false; incrementScope(); final InitializerContext initctx = ctx.initializer(); if (initctx != null) { - adapter.createStatementMetadata(initctx); + metadata.createStatementMetadata(initctx); visit(initctx); } - final ExpressionContext exprctx = adapter.updateExpressionTree(ctx.expression()); + final ExpressionContext exprctx = metadata.updateExpressionTree(ctx.expression()); if (exprctx != null) { - final ExpressionMetadata expremd = adapter.createExpressionMetadata(exprctx); + final ExpressionMetadata expremd = metadata.createExpressionMetadata(exprctx); expremd.to = definition.booleanType; visit(exprctx); markCast(expremd); if (expremd.postConst != null) { - boolean constant = (boolean)expremd.postConst; + continuous = (boolean)expremd.postConst; - if (!constant) { + if (!continuous) { throw new IllegalArgumentException(error(ctx) + "The loop will never be executed."); } - exitrequired = true; + if (ctx.empty() != null) { + throw new IllegalArgumentException(error(ctx) + "The loop is continuous."); + } } } else { - exitrequired = true; + continuous = true; } final AfterthoughtContext atctx = ctx.afterthought(); if (atctx != null) { - adapter.createStatementMetadata(atctx); + metadata.createStatementMetadata(atctx); visit(atctx); } final BlockContext blockctx = ctx.block(); if (blockctx != null) { - final StatementMetadata blocksmd = adapter.createStatementMetadata(blockctx); + final StatementMetadata blocksmd = metadata.createStatementMetadata(blockctx); + blocksmd.beginLoop = true; + blocksmd.inLoop = true; visit(blockctx); - if (blocksmd.allReturn) { - throw new IllegalArgumentException(error(ctx) + "All paths return so the loop is not necessary."); + if (blocksmd.loopEscape && !blocksmd.anyContinue) { + throw new IllegalArgumentException(error(ctx) + "All paths escape so the loop is not necessary."); } - if (blocksmd.allBreak) { - throw new IllegalArgumentException(error(ctx) + "All paths break so the loop is not necessary."); + if (continuous && !blocksmd.anyBreak) { + forsmd.methodEscape = true; + forsmd.allLast = true; } - - 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."); } + forsmd.count = 1; + decrementScope(); return null; @@ -461,97 +440,185 @@ class Analyzer extends PlanAParserBaseVisitor { @Override public Void visitDecl(final DeclContext ctx) { + final StatementMetadata declsmd = metadata.getStatementMetadata(ctx); + final DeclarationContext declctx = ctx.declaration(); - adapter.createStatementMetadata(declctx); + metadata.createStatementMetadata(declctx); visit(declctx); + declsmd.count = 1; + return null; } @Override public Void visitContinue(final ContinueContext ctx) { - final StatementMetadata continuesmd = adapter.getStatementMetadata(ctx); + final StatementMetadata continuesmd = metadata.getStatementMetadata(ctx); - continuesmd.allExit = true; - continuesmd.allContinue = true; + if (!continuesmd.inLoop) { + throw new IllegalArgumentException(error(ctx) + "Cannot have a continue statement outside of a loop."); + } + + if (continuesmd.lastLoop) { + throw new IllegalArgumentException(error(ctx) + "Unnessary continue statement at the end of a loop."); + } + + continuesmd.allLast = true; continuesmd.anyContinue = true; + continuesmd.count = 1; + return null; } @Override public Void visitBreak(final BreakContext ctx) { - final StatementMetadata breaksmd = adapter.getStatementMetadata(ctx); + final StatementMetadata breaksmd = metadata.getStatementMetadata(ctx); - breaksmd.allExit = true; - breaksmd.allBreak = true; + if (!breaksmd.inLoop) { + throw new IllegalArgumentException(error(ctx) + "Cannot have a break statement outside of a loop."); + } + + breaksmd.loopEscape = true; + breaksmd.allLast = true; breaksmd.anyBreak = true; + breaksmd.count = 1; + return null; } @Override public Void visitReturn(final ReturnContext ctx) { - final StatementMetadata returnsmd = adapter.getStatementMetadata(ctx); + final StatementMetadata returnsmd = metadata.getStatementMetadata(ctx); - final ExpressionContext exprctx = adapter.updateExpressionTree(ctx.expression()); - final ExpressionMetadata expremd = adapter.createExpressionMetadata(exprctx); + final ExpressionContext exprctx = metadata.updateExpressionTree(ctx.expression()); + final ExpressionMetadata expremd = metadata.createExpressionMetadata(exprctx); expremd.to = definition.objectType; visit(exprctx); markCast(expremd); - returnsmd.allExit = true; - returnsmd.allReturn = true; - returnsmd.anyReturn = true; + returnsmd.methodEscape = true; + returnsmd.loopEscape = true; + returnsmd.allLast = true; + + returnsmd.count = 1; + + return null; + } + + @Override + public Void visitTry(final TryContext ctx) { + final StatementMetadata trysmd = metadata.getStatementMetadata(ctx); + + final BlockContext blockctx = ctx.block(); + final StatementMetadata blocksmd = metadata.createStatementMetadata(blockctx); + blocksmd.lastSource = trysmd.lastSource; + blocksmd.inLoop = trysmd.inLoop; + blocksmd.lastLoop = trysmd.lastLoop; + incrementScope(); + visit(blockctx); + decrementScope(); + + trysmd.methodEscape = blocksmd.methodEscape; + trysmd.loopEscape = blocksmd.loopEscape; + trysmd.allLast = blocksmd.allLast; + trysmd.anyContinue = blocksmd.anyContinue; + trysmd.anyBreak = blocksmd.anyBreak; + + int trapcount = 0; + + for (final TrapContext trapctx : ctx.trap()) { + final StatementMetadata trapsmd = metadata.createStatementMetadata(trapctx); + trapsmd.lastSource = trysmd.lastSource; + trapsmd.inLoop = trysmd.inLoop; + trapsmd.lastLoop = trysmd.lastLoop; + incrementScope(); + visit(trapctx); + decrementScope(); + + trysmd.methodEscape &= trapsmd.methodEscape; + trysmd.loopEscape &= trapsmd.loopEscape; + trysmd.allLast &= trapsmd.allLast; + trysmd.anyContinue |= trapsmd.anyContinue; + trysmd.anyBreak |= trapsmd.anyBreak; + + trapcount = Math.max(trapcount, trapsmd.count); + } + + trysmd.count = blocksmd.count + trapcount; + + return null; + } + + @Override + public Void visitThrow(final ThrowContext ctx) { + final StatementMetadata throwsmd = metadata.getStatementMetadata(ctx); + + final ExpressionContext exprctx = metadata.updateExpressionTree(ctx.expression()); + final ExpressionMetadata expremd = metadata.createExpressionMetadata(exprctx); + expremd.to = definition.exceptionType; + visit(exprctx); + markCast(expremd); + + throwsmd.methodEscape = true; + throwsmd.loopEscape = true; + throwsmd.allLast = true; + + throwsmd.count = 1; return null; } @Override public Void visitExpr(final ExprContext ctx) { - final StatementMetadata exprsmd = adapter.getStatementMetadata(ctx); - final ExpressionContext exprctx = adapter.updateExpressionTree(ctx.expression()); - final ExpressionMetadata expremd = adapter.createExpressionMetadata(exprctx); - expremd.read = exprsmd.last; + final StatementMetadata exprsmd = metadata.getStatementMetadata(ctx); + final ExpressionContext exprctx = metadata.updateExpressionTree(ctx.expression()); + final ExpressionMetadata expremd = metadata.createExpressionMetadata(exprctx); + expremd.read = exprsmd.lastSource; visit(exprctx); - if (!expremd.statement && !exprsmd.last) { + if (!expremd.statement && !exprsmd.lastSource) { throw new IllegalArgumentException(error(ctx) + "Not a statement."); } - final boolean rtn = exprsmd.last && expremd.from.sort != Sort.VOID; - exprsmd.allExit = rtn; - exprsmd.allReturn = rtn; - exprsmd.anyReturn = rtn; + final boolean rtn = exprsmd.lastSource && expremd.from.sort != Sort.VOID; + exprsmd.methodEscape = rtn; + exprsmd.loopEscape = rtn; + exprsmd.allLast = rtn; expremd.to = rtn ? definition.objectType : expremd.from; markCast(expremd); + exprsmd.count = 1; + return null; } @Override public Void visitMultiple(final MultipleContext ctx) { - final StatementMetadata multiplesmd = adapter.getStatementMetadata(ctx); + final StatementMetadata multiplesmd = metadata.getStatementMetadata(ctx); final List statectxs = ctx.statement(); final StatementContext lastctx = statectxs.get(statectxs.size() - 1); for (StatementContext statectx : statectxs) { - if (multiplesmd.allExit) { + if (multiplesmd.allLast) { throw new IllegalArgumentException(error(statectx) + - "Statement will never be executed because all prior paths exit."); + "Statement will never be executed because all prior paths escape."); } - final StatementMetadata statesmd = adapter.createStatementMetadata(statectx); - statesmd.last = multiplesmd.last && statectx == lastctx; + final StatementMetadata statesmd = metadata.createStatementMetadata(statectx); + statesmd.lastSource = multiplesmd.lastSource && statectx == lastctx; + statesmd.inLoop = multiplesmd.inLoop; + statesmd.lastLoop = (multiplesmd.beginLoop || multiplesmd.lastLoop) && statectx == lastctx; 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.methodEscape = statesmd.methodEscape; + multiplesmd.loopEscape = statesmd.loopEscape; + multiplesmd.allLast = statesmd.allLast; multiplesmd.anyContinue |= statesmd.anyContinue; + multiplesmd.anyBreak |= statesmd.anyBreak; + + multiplesmd.count += statesmd.count; } return null; @@ -559,20 +626,22 @@ class Analyzer extends PlanAParserBaseVisitor { @Override public Void visitSingle(final SingleContext ctx) { - final StatementMetadata singlesmd = adapter.getStatementMetadata(ctx); + final StatementMetadata singlesmd = metadata.getStatementMetadata(ctx); final StatementContext statectx = ctx.statement(); - final StatementMetadata statesmd = adapter.createStatementMetadata(statectx); - statesmd.last = singlesmd.last; + final StatementMetadata statesmd = metadata.createStatementMetadata(statectx); + statesmd.lastSource = singlesmd.lastSource; + statesmd.inLoop = singlesmd.inLoop; + statesmd.lastLoop = singlesmd.beginLoop || singlesmd.lastLoop; 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.methodEscape = statesmd.methodEscape; + singlesmd.loopEscape = statesmd.loopEscape; + singlesmd.allLast = statesmd.allLast; singlesmd.anyContinue = statesmd.anyContinue; + singlesmd.anyBreak = statesmd.anyBreak; + + singlesmd.count = statesmd.count; return null; } @@ -585,13 +654,13 @@ class Analyzer extends PlanAParserBaseVisitor { @Override public Void visitInitializer(InitializerContext ctx) { final DeclarationContext declctx = ctx.declaration(); - final ExpressionContext exprctx = adapter.updateExpressionTree(ctx.expression()); + final ExpressionContext exprctx = metadata.updateExpressionTree(ctx.expression()); if (declctx != null) { - adapter.createStatementMetadata(declctx); + metadata.createStatementMetadata(declctx); visit(declctx); } else if (exprctx != null) { - final ExpressionMetadata expremd = adapter.createExpressionMetadata(exprctx); + final ExpressionMetadata expremd = metadata.createExpressionMetadata(exprctx); expremd.read = false; visit(exprctx); @@ -600,7 +669,7 @@ class Analyzer extends PlanAParserBaseVisitor { if (!expremd.statement) { throw new IllegalArgumentException(error(exprctx) + - "The intializer of a for loop must be a statement."); + "The intializer of a for loop must be a statement."); } } else { throw new IllegalStateException(error(ctx) + "Unexpected parser state."); @@ -611,10 +680,10 @@ class Analyzer extends PlanAParserBaseVisitor { @Override public Void visitAfterthought(AfterthoughtContext ctx) { - ExpressionContext exprctx = adapter.updateExpressionTree(ctx.expression()); + final ExpressionContext exprctx = metadata.updateExpressionTree(ctx.expression()); if (exprctx != null) { - final ExpressionMetadata expremd = adapter.createExpressionMetadata(exprctx); + final ExpressionMetadata expremd = metadata.createExpressionMetadata(exprctx); expremd.read = false; visit(exprctx); @@ -623,7 +692,7 @@ class Analyzer extends PlanAParserBaseVisitor { if (!expremd.statement) { throw new IllegalArgumentException(error(exprctx) + - "The afterthought of a for loop must be a statement."); + "The afterthought of a for loop must be a statement."); } } @@ -633,11 +702,11 @@ class Analyzer extends PlanAParserBaseVisitor { @Override public Void visitDeclaration(final DeclarationContext ctx) { final DecltypeContext decltypectx = ctx.decltype(); - final ExpressionMetadata decltypeemd = adapter.createExpressionMetadata(decltypectx); + final ExpressionMetadata decltypeemd = metadata.createExpressionMetadata(decltypectx); visit(decltypectx); for (final DeclvarContext declvarctx : ctx.declvar()) { - final ExpressionMetadata declvaremd = adapter.createExpressionMetadata(declvarctx); + final ExpressionMetadata declvaremd = metadata.createExpressionMetadata(declvarctx); declvaremd.to = decltypeemd.from; visit(declvarctx); } @@ -647,7 +716,7 @@ class Analyzer extends PlanAParserBaseVisitor { @Override public Void visitDecltype(final DecltypeContext ctx) { - final ExpressionMetadata decltypeemd = adapter.getExpressionMetadata(ctx); + final ExpressionMetadata decltypeemd = metadata.getExpressionMetadata(ctx); final String name = ctx.getText(); decltypeemd.from = definition.getType(name); @@ -657,15 +726,15 @@ class Analyzer extends PlanAParserBaseVisitor { @Override public Void visitDeclvar(final DeclvarContext ctx) { - final ExpressionMetadata declvaremd = adapter.getExpressionMetadata(ctx); + final ExpressionMetadata declvaremd = metadata.getExpressionMetadata(ctx); final String name = ctx.ID().getText(); declvaremd.postConst = addVariable(ctx, name, declvaremd.to).slot; - final ExpressionContext exprctx = adapter.updateExpressionTree(ctx.expression()); + final ExpressionContext exprctx = metadata.updateExpressionTree(ctx.expression()); if (exprctx != null) { - final ExpressionMetadata expremd = adapter.createExpressionMetadata(exprctx); + final ExpressionMetadata expremd = metadata.createExpressionMetadata(exprctx); expremd.to = declvaremd.to; visit(exprctx); markCast(expremd); @@ -674,6 +743,43 @@ class Analyzer extends PlanAParserBaseVisitor { return null; } + @Override + public Void visitTrap(final TrapContext ctx) { + final StatementMetadata trapsmd = metadata.getStatementMetadata(ctx); + + final String type = ctx.TYPE().getText(); + trapsmd.exception = definition.getType(type); + + try { + trapsmd.exception.clazz.asSubclass(Exception.class); + } catch (final ClassCastException exception) { + throw new IllegalArgumentException(error(ctx) + "Invalid exception type [" + trapsmd.exception.name + "]."); + } + + final String id = ctx.ID().getText(); + trapsmd.slot = addVariable(ctx, id, trapsmd.exception).slot; + + final BlockContext blockctx = ctx.block(); + + if (blockctx != null) { + final StatementMetadata blocksmd = metadata.createStatementMetadata(blockctx); + blocksmd.lastSource = trapsmd.lastSource; + blocksmd.inLoop = trapsmd.inLoop; + blocksmd.lastLoop = trapsmd.lastLoop; + visit(blockctx); + + trapsmd.methodEscape = blocksmd.methodEscape; + trapsmd.loopEscape = blocksmd.loopEscape; + trapsmd.allLast = blocksmd.allLast; + trapsmd.anyContinue = blocksmd.anyContinue; + trapsmd.anyBreak = blocksmd.anyBreak; + } else if (ctx.emptyscope() == null) { + throw new IllegalStateException(error(ctx) + "Unexpected parser state."); + } + + return null; + } + @Override public Void visitPrecedence(final PrecedenceContext ctx) { throw new UnsupportedOperationException(error(ctx) + "Unexpected parser state."); @@ -681,7 +787,7 @@ class Analyzer extends PlanAParserBaseVisitor { @Override public Void visitNumeric(final NumericContext ctx) { - final ExpressionMetadata numericemd = adapter.getExpressionMetadata(ctx); + final ExpressionMetadata numericemd = metadata.getExpressionMetadata(ctx); final boolean negate = ctx.parent instanceof UnaryContext && ((UnaryContext)ctx.parent).SUB() != null; if (ctx.DECIMAL() != null) { @@ -770,7 +876,7 @@ class Analyzer extends PlanAParserBaseVisitor { @Override public Void visitChar(final CharContext ctx) { - final ExpressionMetadata charemd = adapter.getExpressionMetadata(ctx); + final ExpressionMetadata charemd = metadata.getExpressionMetadata(ctx); if (ctx.CHAR() == null) { throw new IllegalStateException(error(ctx) + "Unexpected parser state."); @@ -784,7 +890,7 @@ class Analyzer extends PlanAParserBaseVisitor { @Override public Void visitTrue(final TrueContext ctx) { - final ExpressionMetadata trueemd = adapter.getExpressionMetadata(ctx); + final ExpressionMetadata trueemd = metadata.getExpressionMetadata(ctx); if (ctx.TRUE() == null) { throw new IllegalStateException(error(ctx) + "Unexpected parser state."); @@ -798,7 +904,7 @@ class Analyzer extends PlanAParserBaseVisitor { @Override public Void visitFalse(final FalseContext ctx) { - final ExpressionMetadata falseemd = adapter.getExpressionMetadata(ctx); + final ExpressionMetadata falseemd = metadata.getExpressionMetadata(ctx); if (ctx.FALSE() == null) { throw new IllegalStateException(error(ctx) + "Unexpected parser state."); @@ -812,7 +918,7 @@ class Analyzer extends PlanAParserBaseVisitor { @Override public Void visitNull(final NullContext ctx) { - final ExpressionMetadata nullemd = adapter.getExpressionMetadata(ctx); + final ExpressionMetadata nullemd = metadata.getExpressionMetadata(ctx); if (ctx.NULL() == null) { throw new IllegalStateException(error(ctx) + "Unexpected parser state."); @@ -835,10 +941,10 @@ class Analyzer extends PlanAParserBaseVisitor { @Override public Void visitExternal(final ExternalContext ctx) { - final ExpressionMetadata extemd = adapter.getExpressionMetadata(ctx); + final ExpressionMetadata extemd = metadata.getExpressionMetadata(ctx); final ExtstartContext extstartctx = ctx.extstart(); - final ExternalMetadata extstartemd = adapter.createExternalMetadata(extstartctx); + final ExternalMetadata extstartemd = metadata.createExternalMetadata(extstartctx); extstartemd.read = extemd.read; visit(extstartctx); @@ -852,10 +958,10 @@ class Analyzer extends PlanAParserBaseVisitor { @Override public Void visitPostinc(final PostincContext ctx) { - final ExpressionMetadata postincemd = adapter.getExpressionMetadata(ctx); + final ExpressionMetadata postincemd = metadata.getExpressionMetadata(ctx); final ExtstartContext extstartctx = ctx.extstart(); - final ExternalMetadata extstartemd = adapter.createExternalMetadata(extstartctx); + final ExternalMetadata extstartemd = metadata.createExternalMetadata(extstartctx); extstartemd.read = postincemd.read; extstartemd.storeExpr = ctx.increment(); extstartemd.token = ADD; @@ -871,10 +977,10 @@ class Analyzer extends PlanAParserBaseVisitor { @Override public Void visitPreinc(final PreincContext ctx) { - final ExpressionMetadata preincemd = adapter.getExpressionMetadata(ctx); + final ExpressionMetadata preincemd = metadata.getExpressionMetadata(ctx); final ExtstartContext extstartctx = ctx.extstart(); - final ExternalMetadata extstartemd = adapter.createExternalMetadata(extstartctx); + final ExternalMetadata extstartemd = metadata.createExternalMetadata(extstartctx); extstartemd.read = preincemd.read; extstartemd.storeExpr = ctx.increment(); extstartemd.token = ADD; @@ -890,10 +996,10 @@ class Analyzer extends PlanAParserBaseVisitor { @Override public Void visitUnary(final UnaryContext ctx) { - final ExpressionMetadata unaryemd = adapter.getExpressionMetadata(ctx); + final ExpressionMetadata unaryemd = metadata.getExpressionMetadata(ctx); - final ExpressionContext exprctx = adapter.updateExpressionTree(ctx.expression()); - final ExpressionMetadata expremd = adapter.createExpressionMetadata(exprctx); + final ExpressionContext exprctx = metadata.updateExpressionTree(ctx.expression()); + final ExpressionMetadata expremd = metadata.createExpressionMetadata(exprctx); if (ctx.BOOLNOT() != null) { expremd.to = definition.booleanType; @@ -912,7 +1018,7 @@ class Analyzer extends PlanAParserBaseVisitor { if (promote == null) { throw new ClassCastException("Cannot apply [" + ctx.getChild(0).getText() + "] " + - "operation to type [" + expremd.from.name + "]."); + "operation to type [" + expremd.from.name + "]."); } expremd.to = promote; @@ -981,17 +1087,17 @@ class Analyzer extends PlanAParserBaseVisitor { @Override public Void visitCast(final CastContext ctx) { - final ExpressionMetadata castemd = adapter.getExpressionMetadata(ctx); + final ExpressionMetadata castemd = metadata.getExpressionMetadata(ctx); final DecltypeContext decltypectx = ctx.decltype(); - final ExpressionMetadata decltypemd = adapter.createExpressionMetadata(decltypectx); + final ExpressionMetadata decltypemd = metadata.createExpressionMetadata(decltypectx); visit(decltypectx); final Type type = decltypemd.from; castemd.from = type; - final ExpressionContext exprctx = adapter.updateExpressionTree(ctx.expression()); - final ExpressionMetadata expremd = adapter.createExpressionMetadata(exprctx); + final ExpressionContext exprctx = metadata.updateExpressionTree(ctx.expression()); + final ExpressionMetadata expremd = metadata.createExpressionMetadata(exprctx); expremd.to = type; expremd.explicit = true; visit(exprctx); @@ -1008,26 +1114,26 @@ class Analyzer extends PlanAParserBaseVisitor { @Override public Void visitBinary(final BinaryContext ctx) { - final ExpressionMetadata binaryemd = adapter.getExpressionMetadata(ctx); + final ExpressionMetadata binaryemd = metadata.getExpressionMetadata(ctx); - final ExpressionContext exprctx0 = adapter.updateExpressionTree(ctx.expression(0)); - final ExpressionMetadata expremd0 = adapter.createExpressionMetadata(exprctx0); + final ExpressionContext exprctx0 = metadata.updateExpressionTree(ctx.expression(0)); + final ExpressionMetadata expremd0 = metadata.createExpressionMetadata(exprctx0); visit(exprctx0); - final ExpressionContext exprctx1 = adapter.updateExpressionTree(ctx.expression(1)); - final ExpressionMetadata expremd1 = adapter.createExpressionMetadata(exprctx1); + final ExpressionContext exprctx1 = metadata.updateExpressionTree(ctx.expression(1)); + final ExpressionMetadata expremd1 = metadata.createExpressionMetadata(exprctx1); visit(exprctx1); final boolean decimal = ctx.MUL() != null || ctx.DIV() != null || ctx.REM() != null || ctx.SUB() != null; final boolean add = ctx.ADD() != null; final boolean xor = ctx.BWXOR() != null; final Type promote = add ? promoteAdd(expremd0.from, expremd1.from) : - xor ? promoteXor(expremd0.from, expremd1.from) : - promoteNumeric(expremd0.from, expremd1.from, decimal, true); + xor ? promoteXor(expremd0.from, expremd1.from) : + promoteNumeric(expremd0.from, expremd1.from, decimal, true); if (promote == null) { throw new ClassCastException("Cannot apply [" + ctx.getChild(1).getText() + "] " + - "operation to types [" + expremd0.from.name + "] and [" + expremd1.from.name + "]."); + "operation to types [" + expremd0.from.name + "] and [" + expremd1.from.name + "]."); } final Sort sort = promote.sort; @@ -1234,16 +1340,16 @@ class Analyzer extends PlanAParserBaseVisitor { @Override public Void visitComp(final CompContext ctx) { - final ExpressionMetadata compemd = adapter.getExpressionMetadata(ctx); + final ExpressionMetadata compemd = metadata.getExpressionMetadata(ctx); final boolean equality = ctx.EQ() != null || ctx.NE() != null; final boolean reference = ctx.EQR() != null || ctx.NER() != null; - final ExpressionContext exprctx0 = adapter.updateExpressionTree(ctx.expression(0)); - final ExpressionMetadata expremd0 = adapter.createExpressionMetadata(exprctx0); + final ExpressionContext exprctx0 = metadata.updateExpressionTree(ctx.expression(0)); + final ExpressionMetadata expremd0 = metadata.createExpressionMetadata(exprctx0); visit(exprctx0); - final ExpressionContext exprctx1 = adapter.updateExpressionTree(ctx.expression(1)); - final ExpressionMetadata expremd1 = adapter.createExpressionMetadata(exprctx1); + final ExpressionContext exprctx1 = metadata.updateExpressionTree(ctx.expression(1)); + final ExpressionMetadata expremd1 = metadata.createExpressionMetadata(exprctx1); visit(exprctx1); if (expremd0.isNull && expremd1.isNull) { @@ -1251,12 +1357,12 @@ class Analyzer extends PlanAParserBaseVisitor { } final Type promote = equality ? promoteEquality(expremd0.from, expremd1.from) : - reference ? promoteReference(expremd0.from, expremd1.from) : - promoteNumeric(expremd0.from, expremd1.from, true, true); + reference ? promoteReference(expremd0.from, expremd1.from) : + promoteNumeric(expremd0.from, expremd1.from, true, true); if (promote == null) { throw new ClassCastException("Cannot apply [" + ctx.getChild(1).getText() + "] " + - "operation to types [" + expremd0.from.name + "] and [" + expremd1.from.name + "]."); + "operation to types [" + expremd0.from.name + "] and [" + expremd1.from.name + "]."); } expremd0.to = promote; @@ -1356,16 +1462,16 @@ class Analyzer extends PlanAParserBaseVisitor { @Override public Void visitBool(final BoolContext ctx) { - final ExpressionMetadata boolemd = adapter.getExpressionMetadata(ctx); + final ExpressionMetadata boolemd = metadata.getExpressionMetadata(ctx); - final ExpressionContext exprctx0 = adapter.updateExpressionTree(ctx.expression(0)); - final ExpressionMetadata expremd0 = adapter.createExpressionMetadata(exprctx0); + final ExpressionContext exprctx0 = metadata.updateExpressionTree(ctx.expression(0)); + final ExpressionMetadata expremd0 = metadata.createExpressionMetadata(exprctx0); expremd0.to = definition.booleanType; visit(exprctx0); markCast(expremd0); - final ExpressionContext exprctx1 = adapter.updateExpressionTree(ctx.expression(1)); - final ExpressionMetadata expremd1 = adapter.createExpressionMetadata(exprctx1); + final ExpressionContext exprctx1 = metadata.updateExpressionTree(ctx.expression(1)); + final ExpressionMetadata expremd1 = metadata.createExpressionMetadata(exprctx1); expremd1.to = definition.booleanType; visit(exprctx1); markCast(expremd1); @@ -1388,10 +1494,10 @@ class Analyzer extends PlanAParserBaseVisitor { @Override public Void visitConditional(final ConditionalContext ctx) { - final ExpressionMetadata condemd = adapter.getExpressionMetadata(ctx); + final ExpressionMetadata condemd = metadata.getExpressionMetadata(ctx); - final ExpressionContext exprctx0 = adapter.updateExpressionTree(ctx.expression(0)); - final ExpressionMetadata expremd0 = adapter.createExpressionMetadata(exprctx0); + final ExpressionContext exprctx0 = metadata.updateExpressionTree(ctx.expression(0)); + final ExpressionMetadata expremd0 = metadata.createExpressionMetadata(exprctx0); expremd0.to = definition.booleanType; visit(exprctx0); markCast(expremd0); @@ -1400,14 +1506,14 @@ class Analyzer extends PlanAParserBaseVisitor { throw new IllegalArgumentException(error(ctx) + "Unnecessary conditional statement."); } - final ExpressionContext exprctx1 = adapter.updateExpressionTree(ctx.expression(1)); - final ExpressionMetadata expremd1 = adapter.createExpressionMetadata(exprctx1); + final ExpressionContext exprctx1 = metadata.updateExpressionTree(ctx.expression(1)); + final ExpressionMetadata expremd1 = metadata.createExpressionMetadata(exprctx1); expremd1.to = condemd.to; expremd1.explicit = condemd.explicit; visit(exprctx1); - final ExpressionContext exprctx2 = adapter.updateExpressionTree(ctx.expression(2)); - final ExpressionMetadata expremd2 = adapter.createExpressionMetadata(exprctx2); + final ExpressionContext exprctx2 = metadata.updateExpressionTree(ctx.expression(2)); + final ExpressionMetadata expremd2 = metadata.createExpressionMetadata(exprctx2); expremd2.to = condemd.to; expremd2.explicit = condemd.explicit; visit(exprctx2); @@ -1432,13 +1538,13 @@ class Analyzer extends PlanAParserBaseVisitor { @Override public Void visitAssignment(final AssignmentContext ctx) { - final ExpressionMetadata assignemd = adapter.getExpressionMetadata(ctx); + final ExpressionMetadata assignemd = metadata.getExpressionMetadata(ctx); final ExtstartContext extstartctx = ctx.extstart(); - final ExternalMetadata extstartemd = adapter.createExternalMetadata(extstartctx); + final ExternalMetadata extstartemd = metadata.createExternalMetadata(extstartctx); extstartemd.read = assignemd.read; - extstartemd.storeExpr = adapter.updateExpressionTree(ctx.expression()); + extstartemd.storeExpr = metadata.updateExpressionTree(ctx.expression()); if (ctx.AMUL() != null) { extstartemd.token = MUL; @@ -1483,22 +1589,22 @@ class Analyzer extends PlanAParserBaseVisitor { final ExtstringContext stringctx = ctx.extstring(); if (precctx != null) { - adapter.createExtNodeMetadata(ctx, precctx); + metadata.createExtNodeMetadata(ctx, precctx); visit(precctx); } else if (castctx != null) { - adapter.createExtNodeMetadata(ctx, castctx); + metadata.createExtNodeMetadata(ctx, castctx); visit(castctx); } else if (typectx != null) { - adapter.createExtNodeMetadata(ctx, typectx); + metadata.createExtNodeMetadata(ctx, typectx); visit(typectx); } else if (varctx != null) { - adapter.createExtNodeMetadata(ctx, varctx); + metadata.createExtNodeMetadata(ctx, varctx); visit(varctx); } else if (newctx != null) { - adapter.createExtNodeMetadata(ctx, newctx); + metadata.createExtNodeMetadata(ctx, newctx); visit(newctx); } else if (stringctx != null) { - adapter.createExtNodeMetadata(ctx, stringctx); + metadata.createExtNodeMetadata(ctx, stringctx); visit(stringctx); } else { throw new IllegalStateException(); @@ -1509,9 +1615,9 @@ class Analyzer extends PlanAParserBaseVisitor { @Override public Void visitExtprec(final ExtprecContext ctx) { - final ExtNodeMetadata precenmd = adapter.getExtNodeMetadata(ctx); + final ExtNodeMetadata precenmd = metadata.getExtNodeMetadata(ctx); final ParserRuleContext parent = precenmd.parent; - final ExternalMetadata parentemd = adapter.getExternalMetadata(parent); + final ExternalMetadata parentemd = metadata.getExternalMetadata(parent); final ExtprecContext precctx = ctx.extprec(); final ExtcastContext castctx = ctx.extcast(); @@ -1528,22 +1634,22 @@ class Analyzer extends PlanAParserBaseVisitor { } if (precctx != null) { - adapter.createExtNodeMetadata(parent, precctx); + metadata.createExtNodeMetadata(parent, precctx); visit(precctx); } else if (castctx != null) { - adapter.createExtNodeMetadata(parent, castctx); + metadata.createExtNodeMetadata(parent, castctx); visit(castctx); } else if (typectx != null) { - adapter.createExtNodeMetadata(parent, typectx); + metadata.createExtNodeMetadata(parent, typectx); visit(typectx); } else if (varctx != null) { - adapter.createExtNodeMetadata(parent, varctx); + metadata.createExtNodeMetadata(parent, varctx); visit(varctx); } else if (newctx != null) { - adapter.createExtNodeMetadata(parent, newctx); + metadata.createExtNodeMetadata(parent, newctx); visit(newctx); } else if (stringctx != null) { - adapter.createExtNodeMetadata(ctx, stringctx); + metadata.createExtNodeMetadata(ctx, stringctx); visit(stringctx); } else { throw new IllegalStateException(error(ctx) + "Unexpected parser state."); @@ -1554,12 +1660,12 @@ class Analyzer extends PlanAParserBaseVisitor { if (dotctx != null) { --parentemd.scope; - adapter.createExtNodeMetadata(parent, dotctx); + metadata.createExtNodeMetadata(parent, dotctx); visit(dotctx); } else if (bracectx != null) { --parentemd.scope; - adapter.createExtNodeMetadata(parent, bracectx); + metadata.createExtNodeMetadata(parent, bracectx); visit(bracectx); } @@ -1568,9 +1674,9 @@ class Analyzer extends PlanAParserBaseVisitor { @Override public Void visitExtcast(final ExtcastContext ctx) { - final ExtNodeMetadata castenmd = adapter.getExtNodeMetadata(ctx); + final ExtNodeMetadata castenmd = metadata.getExtNodeMetadata(ctx); final ParserRuleContext parent = castenmd.parent; - final ExternalMetadata parentemd = adapter.getExternalMetadata(parent); + final ExternalMetadata parentemd = metadata.getExternalMetadata(parent); final ExtprecContext precctx = ctx.extprec(); final ExtcastContext castctx = ctx.extcast(); @@ -1580,29 +1686,29 @@ class Analyzer extends PlanAParserBaseVisitor { final ExtstringContext stringctx = ctx.extstring(); if (precctx != null) { - adapter.createExtNodeMetadata(parent, precctx); + metadata.createExtNodeMetadata(parent, precctx); visit(precctx); } else if (castctx != null) { - adapter.createExtNodeMetadata(parent, castctx); + metadata.createExtNodeMetadata(parent, castctx); visit(castctx); } else if (typectx != null) { - adapter.createExtNodeMetadata(parent, typectx); + metadata.createExtNodeMetadata(parent, typectx); visit(typectx); } else if (varctx != null) { - adapter.createExtNodeMetadata(parent, varctx); + metadata.createExtNodeMetadata(parent, varctx); visit(varctx); } else if (newctx != null) { - adapter.createExtNodeMetadata(parent, newctx); + metadata.createExtNodeMetadata(parent, newctx); visit(newctx); } else if (stringctx != null) { - adapter.createExtNodeMetadata(ctx, stringctx); + metadata.createExtNodeMetadata(ctx, stringctx); visit(stringctx); } else { throw new IllegalStateException(error(ctx) + "Unexpected parser state."); } final DecltypeContext declctx = ctx.decltype(); - final ExpressionMetadata declemd = adapter.createExpressionMetadata(declctx); + final ExpressionMetadata declemd = metadata.createExpressionMetadata(declctx); visit(declctx); castenmd.castTo = getLegalCast(ctx, parentemd.current, declemd.from, true); @@ -1615,9 +1721,9 @@ class Analyzer extends PlanAParserBaseVisitor { @Override public Void visitExtbrace(final ExtbraceContext ctx) { - final ExtNodeMetadata braceenmd = adapter.getExtNodeMetadata(ctx); + final ExtNodeMetadata braceenmd = metadata.getExtNodeMetadata(ctx); final ParserRuleContext parent = braceenmd.parent; - final ExternalMetadata parentemd = adapter.getExternalMetadata(parent); + final ExternalMetadata parentemd = metadata.getExternalMetadata(parent); final boolean array = parentemd.current.sort == Sort.ARRAY; final boolean def = parentemd.current.sort == Sort.DEF; @@ -1643,8 +1749,8 @@ class Analyzer extends PlanAParserBaseVisitor { braceenmd.last = parentemd.scope == 0 && dotctx == null && bracectx == null; - final ExpressionContext exprctx = adapter.updateExpressionTree(ctx.expression()); - final ExpressionMetadata expremd = adapter.createExpressionMetadata(exprctx); + final ExpressionContext exprctx = metadata.updateExpressionTree(ctx.expression()); + final ExpressionMetadata expremd = metadata.createExpressionMetadata(exprctx); if (array || def) { expremd.to = array ? definition.intType : definition.objectType; @@ -1653,15 +1759,15 @@ class Analyzer extends PlanAParserBaseVisitor { braceenmd.target = "#brace"; braceenmd.type = def ? definition.defType : - definition.getType(parentemd.current.struct, parentemd.current.type.getDimensions() - 1); + definition.getType(parentemd.current.struct, parentemd.current.type.getDimensions() - 1); analyzeLoadStoreExternal(ctx); parentemd.current = braceenmd.type; if (dotctx != null) { - adapter.createExtNodeMetadata(parent, dotctx); + metadata.createExtNodeMetadata(parent, dotctx); visit(dotctx); } else if (bracectx != null) { - adapter.createExtNodeMetadata(parent, bracectx); + metadata.createExtNodeMetadata(parent, bracectx); visit(bracectx); } } else { @@ -1680,16 +1786,16 @@ class Analyzer extends PlanAParserBaseVisitor { if (getter != null && (getter.rtn.sort == Sort.VOID || getter.arguments.size() != 1)) { throw new IllegalArgumentException(error(ctx) + - "Illegal map get shortcut for type [" + parentemd.current.name + "]."); + "Illegal map get shortcut for type [" + parentemd.current.name + "]."); } if (setter != null && setter.arguments.size() != 2) { throw new IllegalArgumentException(error(ctx) + - "Illegal map set shortcut for type [" + parentemd.current.name + "]."); + "Illegal map set shortcut for type [" + parentemd.current.name + "]."); } if (getter != null && setter != null && (!getter.arguments.get(0).equals(setter.arguments.get(0)) - || !getter.rtn.equals(setter.arguments.get(1)))) { + || !getter.rtn.equals(setter.arguments.get(1)))) { throw new IllegalArgumentException(error(ctx) + "Shortcut argument types must match."); } @@ -1697,21 +1803,21 @@ class Analyzer extends PlanAParserBaseVisitor { settype = setter == null ? null : setter.arguments.get(1); } else if (list) { getter = parentemd.current.struct.methods.get("get"); - setter = parentemd.current.struct.methods.get("add"); + setter = parentemd.current.struct.methods.get("set"); if (getter != null && (getter.rtn.sort == Sort.VOID || getter.arguments.size() != 1 || - getter.arguments.get(0).sort != Sort.INT)) { + getter.arguments.get(0).sort != Sort.INT)) { throw new IllegalArgumentException(error(ctx) + - "Illegal list get shortcut for type [" + parentemd.current.name + "]."); + "Illegal list get shortcut for type [" + parentemd.current.name + "]."); } if (setter != null && (setter.arguments.size() != 2 || setter.arguments.get(0).sort != Sort.INT)) { throw new IllegalArgumentException(error(ctx) + - "Illegal list set shortcut for type [" + parentemd.current.name + "]."); + "Illegal list set shortcut for type [" + parentemd.current.name + "]."); } if (getter != null && setter != null && (!getter.arguments.get(0).equals(setter.arguments.get(0)) - || !getter.rtn.equals(setter.arguments.get(1)))) { + || !getter.rtn.equals(setter.arguments.get(1)))) { throw new IllegalArgumentException(error(ctx) + "Shortcut argument types must match."); } @@ -1735,7 +1841,7 @@ class Analyzer extends PlanAParserBaseVisitor { if (braceenmd.target == null) { throw new IllegalArgumentException(error(ctx) + - "Attempting to address a non-array type [" + parentemd.current.name + "] as an array."); + "Attempting to address a non-array type [" + parentemd.current.name + "] as an array."); } return null; @@ -1743,17 +1849,17 @@ class Analyzer extends PlanAParserBaseVisitor { @Override public Void visitExtdot(final ExtdotContext ctx) { - final ExtNodeMetadata dotemnd = adapter.getExtNodeMetadata(ctx); + final ExtNodeMetadata dotemnd = metadata.getExtNodeMetadata(ctx); final ParserRuleContext parent = dotemnd.parent; final ExtcallContext callctx = ctx.extcall(); final ExtfieldContext fieldctx = ctx.extfield(); if (callctx != null) { - adapter.createExtNodeMetadata(parent, callctx); + metadata.createExtNodeMetadata(parent, callctx); visit(callctx); } else if (fieldctx != null) { - adapter.createExtNodeMetadata(parent, fieldctx); + metadata.createExtNodeMetadata(parent, fieldctx); visit(fieldctx); } @@ -1762,9 +1868,9 @@ class Analyzer extends PlanAParserBaseVisitor { @Override public Void visitExttype(final ExttypeContext ctx) { - final ExtNodeMetadata typeenmd = adapter.getExtNodeMetadata(ctx); + final ExtNodeMetadata typeenmd = metadata.getExtNodeMetadata(ctx); final ParserRuleContext parent = typeenmd.parent; - final ExternalMetadata parentemd = adapter.getExternalMetadata(parent); + final ExternalMetadata parentemd = metadata.getExternalMetadata(parent); if (parentemd.current != null) { throw new IllegalArgumentException(error(ctx) + "Unexpected static type."); @@ -1776,7 +1882,7 @@ class Analyzer extends PlanAParserBaseVisitor { parentemd.statik = true; final ExtdotContext dotctx = ctx.extdot(); - adapter.createExtNodeMetadata(parent, dotctx); + metadata.createExtNodeMetadata(parent, dotctx); visit(dotctx); return null; @@ -1784,9 +1890,9 @@ class Analyzer extends PlanAParserBaseVisitor { @Override public Void visitExtcall(final ExtcallContext ctx) { - final ExtNodeMetadata callenmd = adapter.getExtNodeMetadata(ctx); + final ExtNodeMetadata callenmd = metadata.getExtNodeMetadata(ctx); final ParserRuleContext parent = callenmd.parent; - final ExternalMetadata parentemd = adapter.getExternalMetadata(parent); + final ExternalMetadata parentemd = metadata.getExternalMetadata(parent); final ExtdotContext dotctx = ctx.extdot(); final ExtbraceContext bracectx = ctx.extbrace(); @@ -1811,7 +1917,7 @@ class Analyzer extends PlanAParserBaseVisitor { if (method == null && !def) { throw new IllegalArgumentException( - error(ctx) + "Unknown call [" + name + "] on type [" + struct.name + "]."); + error(ctx) + "Unknown call [" + name + "] on type [" + struct.name + "]."); } else if (method != null) { types = new Type[method.arguments.size()]; method.arguments.toArray(types); @@ -1823,8 +1929,8 @@ class Analyzer extends PlanAParserBaseVisitor { if (size != types.length) { throw new IllegalArgumentException(error(ctx) + "When calling [" + name + "] on type " + - "[" + struct.name + "] expected [" + types.length + "] arguments," + - " but found [" + arguments.size() + "]."); + "[" + struct.name + "] expected [" + types.length + "] arguments," + + " but found [" + arguments.size() + "]."); } } else { types = new Type[arguments.size()]; @@ -1837,8 +1943,8 @@ class Analyzer extends PlanAParserBaseVisitor { } for (int argument = 0; argument < size; ++argument) { - final ExpressionContext exprctx = adapter.updateExpressionTree(arguments.get(argument)); - final ExpressionMetadata expremd = adapter.createExpressionMetadata(exprctx); + final ExpressionContext exprctx = metadata.updateExpressionTree(arguments.get(argument)); + final ExpressionMetadata expremd = metadata.createExpressionMetadata(exprctx); expremd.to = types[argument]; visit(exprctx); markCast(expremd); @@ -1847,10 +1953,10 @@ class Analyzer extends PlanAParserBaseVisitor { parentemd.statik = false; if (dotctx != null) { - adapter.createExtNodeMetadata(parent, dotctx); + metadata.createExtNodeMetadata(parent, dotctx); visit(dotctx); } else if (bracectx != null) { - adapter.createExtNodeMetadata(parent, bracectx); + metadata.createExtNodeMetadata(parent, bracectx); visit(bracectx); } @@ -1859,9 +1965,9 @@ class Analyzer extends PlanAParserBaseVisitor { @Override public Void visitExtvar(final ExtvarContext ctx) { - final ExtNodeMetadata varenmd = adapter.getExtNodeMetadata(ctx); + final ExtNodeMetadata varenmd = metadata.getExtNodeMetadata(ctx); final ParserRuleContext parent = varenmd.parent; - final ExternalMetadata parentemd = adapter.getExternalMetadata(parent); + final ExternalMetadata parentemd = metadata.getExternalMetadata(parent); final String name = ctx.ID().getText(); @@ -1886,10 +1992,10 @@ class Analyzer extends PlanAParserBaseVisitor { parentemd.current = varenmd.type; if (dotctx != null) { - adapter.createExtNodeMetadata(parent, dotctx); + metadata.createExtNodeMetadata(parent, dotctx); visit(dotctx); } else if (bracectx != null) { - adapter.createExtNodeMetadata(parent, bracectx); + metadata.createExtNodeMetadata(parent, bracectx); visit(bracectx); } @@ -1898,9 +2004,9 @@ class Analyzer extends PlanAParserBaseVisitor { @Override public Void visitExtfield(final ExtfieldContext ctx) { - final ExtNodeMetadata memberenmd = adapter.getExtNodeMetadata(ctx); + final ExtNodeMetadata memberenmd = metadata.getExtNodeMetadata(ctx); final ParserRuleContext parent = memberenmd.parent; - final ExternalMetadata parentemd = adapter.getExternalMetadata(parent); + final ExternalMetadata parentemd = metadata.getExternalMetadata(parent); if (ctx.EXTID() == null && ctx.EXTINTEGER() == null) { throw new IllegalArgumentException(error(ctx) + "Unexpected parser state."); @@ -1924,7 +2030,7 @@ class Analyzer extends PlanAParserBaseVisitor { throw new IllegalArgumentException(error(ctx) + "Must read array field [length]."); } else if (store) { throw new IllegalArgumentException( - error(ctx) + "Cannot write to read-only array field [length]."); + error(ctx) + "Cannot write to read-only array field [length]."); } memberenmd.target = "#length"; @@ -1945,7 +2051,7 @@ class Analyzer extends PlanAParserBaseVisitor { if (field != null) { if (store && java.lang.reflect.Modifier.isFinal(field.reflect.getModifiers())) { throw new IllegalArgumentException(error(ctx) + "Cannot write to read-only" + - " field [" + value + "] for type [" + struct.name + "]."); + " field [" + value + "] for type [" + struct.name + "]."); } memberenmd.target = field; @@ -1962,12 +2068,12 @@ class Analyzer extends PlanAParserBaseVisitor { if (getter != null && (getter.rtn.sort == Sort.VOID || !getter.arguments.isEmpty())) { throw new IllegalArgumentException(error(ctx) + - "Illegal get shortcut on field [" + value + "] for type [" + struct.name + "]."); + "Illegal get shortcut on field [" + value + "] for type [" + struct.name + "]."); } if (setter != null && (setter.rtn.sort != Sort.VOID || setter.arguments.size() != 1)) { throw new IllegalArgumentException(error(ctx) + - "Illegal set shortcut on field [" + value + "] for type [" + struct.name + "]."); + "Illegal set shortcut on field [" + value + "] for type [" + struct.name + "]."); } Type settype = setter == null ? null : setter.arguments.get(0); @@ -1983,13 +2089,13 @@ class Analyzer extends PlanAParserBaseVisitor { if (getter != null && (getter.rtn.sort == Sort.VOID || getter.arguments.size() != 1 || getter.arguments.get(0).sort != Sort.STRING)) { throw new IllegalArgumentException(error(ctx) + - "Illegal map get shortcut [" + value + "] for type [" + struct.name + "]."); + "Illegal map get shortcut [" + value + "] for type [" + struct.name + "]."); } if (setter != null && (setter.arguments.size() != 2 || - setter.arguments.get(0).sort != Sort.STRING)) { + setter.arguments.get(0).sort != Sort.STRING)) { throw new IllegalArgumentException(error(ctx) + - "Illegal map set shortcut [" + value + "] for type [" + struct.name + "]."); + "Illegal map set shortcut [" + value + "] for type [" + struct.name + "]."); } if (getter != null && setter != null && !getter.rtn.equals(setter.arguments.get(1))) { @@ -2006,18 +2112,18 @@ class Analyzer extends PlanAParserBaseVisitor { parentemd.current.clazz.asSubclass(List.class); getter = parentemd.current.struct.methods.get("get"); - setter = parentemd.current.struct.methods.get("add"); + setter = parentemd.current.struct.methods.get("set"); if (getter != null && (getter.rtn.sort == Sort.VOID || getter.arguments.size() != 1 || - getter.arguments.get(0).sort != Sort.INT)) { + getter.arguments.get(0).sort != Sort.INT)) { throw new IllegalArgumentException(error(ctx) + - "Illegal list get shortcut [" + value + "] for type [" + struct.name + "]."); + "Illegal list get shortcut [" + value + "] for type [" + struct.name + "]."); } if (setter != null && (setter.rtn.sort != Sort.VOID || setter.arguments.size() != 2 || - setter.arguments.get(0).sort != Sort.INT)) { + setter.arguments.get(0).sort != Sort.INT)) { throw new IllegalArgumentException(error(ctx) + - "Illegal list add shortcut [" + value + "] for type [" + struct.name + "]."); + "Illegal list set shortcut [" + value + "] for type [" + struct.name + "]."); } if (getter != null && setter != null && !getter.rtn.equals(setter.arguments.get(1))) { @@ -2030,7 +2136,7 @@ class Analyzer extends PlanAParserBaseVisitor { constant = Integer.parseInt(value); } catch (NumberFormatException exception) { throw new IllegalArgumentException(error(ctx) + - "Illegal list shortcut value [" + value + "]."); + "Illegal list shortcut value [" + value + "]."); } } catch (ClassCastException exception) { //Do nothing. @@ -2050,17 +2156,17 @@ class Analyzer extends PlanAParserBaseVisitor { if (memberenmd.target == null) { throw new IllegalArgumentException( - error(ctx) + "Unknown field [" + value + "] for type [" + struct.name + "]."); + error(ctx) + "Unknown field [" + value + "] for type [" + struct.name + "]."); } } parentemd.statik = false; if (dotctx != null) { - adapter.createExtNodeMetadata(parent, dotctx); + metadata.createExtNodeMetadata(parent, dotctx); visit(dotctx); } else if (bracectx != null) { - adapter.createExtNodeMetadata(parent, bracectx); + metadata.createExtNodeMetadata(parent, bracectx); visit(bracectx); } @@ -2069,9 +2175,9 @@ class Analyzer extends PlanAParserBaseVisitor { @Override public Void visitExtnew(ExtnewContext ctx) { - final ExtNodeMetadata newenmd = adapter.getExtNodeMetadata(ctx); + final ExtNodeMetadata newenmd = metadata.getExtNodeMetadata(ctx); final ParserRuleContext parent = newenmd.parent; - final ExternalMetadata parentemd = adapter.getExternalMetadata(parent); + final ExternalMetadata parentemd = metadata.getExternalMetadata(parent); final ExtdotContext dotctx = ctx.extdot(); final ExtbraceContext bracectx = ctx.extbrace(); @@ -2129,7 +2235,7 @@ class Analyzer extends PlanAParserBaseVisitor { parentemd.current = newenmd.type; } else { throw new IllegalArgumentException( - error(ctx) + "Unknown new call on type [" + struct.name + "]."); + error(ctx) + "Unknown new call on type [" + struct.name + "]."); } } else { throw new IllegalArgumentException(error(ctx) + "Unknown parser state."); @@ -2137,23 +2243,23 @@ class Analyzer extends PlanAParserBaseVisitor { if (size != types.length) { throw new IllegalArgumentException(error(ctx) + "When calling [" + name + "] on type " + - "[" + struct.name + "] expected [" + types.length + "] arguments," + - " but found [" + arguments.size() + "]."); + "[" + struct.name + "] expected [" + types.length + "] arguments," + + " but found [" + arguments.size() + "]."); } for (int argument = 0; argument < size; ++argument) { - final ExpressionContext exprctx = adapter.updateExpressionTree(arguments.get(argument)); - final ExpressionMetadata expremd = adapter.createExpressionMetadata(exprctx); + final ExpressionContext exprctx = metadata.updateExpressionTree(arguments.get(argument)); + final ExpressionMetadata expremd = metadata.createExpressionMetadata(exprctx); expremd.to = types[argument]; visit(exprctx); markCast(expremd); } if (dotctx != null) { - adapter.createExtNodeMetadata(parent, dotctx); + metadata.createExtNodeMetadata(parent, dotctx); visit(dotctx); } else if (bracectx != null) { - adapter.createExtNodeMetadata(parent, bracectx); + metadata.createExtNodeMetadata(parent, bracectx); visit(bracectx); } @@ -2162,9 +2268,9 @@ class Analyzer extends PlanAParserBaseVisitor { @Override public Void visitExtstring(final ExtstringContext ctx) { - final ExtNodeMetadata memberenmd = adapter.getExtNodeMetadata(ctx); + final ExtNodeMetadata memberenmd = metadata.getExtNodeMetadata(ctx); final ParserRuleContext parent = memberenmd.parent; - final ExternalMetadata parentemd = adapter.getExternalMetadata(parent); + final ExternalMetadata parentemd = metadata.getExternalMetadata(parent); final String string = ctx.STRING().getText(); @@ -2182,7 +2288,7 @@ class Analyzer extends PlanAParserBaseVisitor { throw new IllegalArgumentException(error(ctx) + "Must read String constant [" + string + "]."); } else if (store) { throw new IllegalArgumentException( - error(ctx) + "Cannot write to read-only String constant [" + string + "]."); + error(ctx) + "Cannot write to read-only String constant [" + string + "]."); } memberenmd.target = string; @@ -2194,10 +2300,10 @@ class Analyzer extends PlanAParserBaseVisitor { } if (dotctx != null) { - adapter.createExtNodeMetadata(parent, dotctx); + metadata.createExtNodeMetadata(parent, dotctx); visit(dotctx); } else if (bracectx != null) { - adapter.createExtNodeMetadata(parent, bracectx); + metadata.createExtNodeMetadata(parent, bracectx); visit(bracectx); } @@ -2211,7 +2317,7 @@ class Analyzer extends PlanAParserBaseVisitor { @Override public Void visitIncrement(IncrementContext ctx) { - final ExpressionMetadata incremd = adapter.getExpressionMetadata(ctx); + final ExpressionMetadata incremd = metadata.getExpressionMetadata(ctx); final Sort sort = incremd.to == null ? null : incremd.to.sort; final boolean positive = ctx.INCR() != null; @@ -2242,13 +2348,13 @@ class Analyzer extends PlanAParserBaseVisitor { } private void analyzeLoadStoreExternal(final ParserRuleContext source) { - final ExtNodeMetadata extenmd = adapter.getExtNodeMetadata(source); + final ExtNodeMetadata extenmd = metadata.getExtNodeMetadata(source); final ParserRuleContext parent = extenmd.parent; - final ExternalMetadata parentemd = adapter.getExternalMetadata(parent); + final ExternalMetadata parentemd = metadata.getExternalMetadata(parent); if (extenmd.last && parentemd.storeExpr != null) { final ParserRuleContext store = parentemd.storeExpr; - final ExpressionMetadata storeemd = adapter.createExpressionMetadata(parentemd.storeExpr); + final ExpressionMetadata storeemd = metadata.createExpressionMetadata(parentemd.storeExpr); final int token = parentemd.token; if (token > 0) { @@ -2259,12 +2365,12 @@ class Analyzer extends PlanAParserBaseVisitor { final boolean decimal = token == MUL || token == DIV || token == REM || token == SUB; extenmd.promote = add ? promoteAdd(extenmd.type, storeemd.from) : - xor ? promoteXor(extenmd.type, storeemd.from) : - promoteNumeric(extenmd.type, storeemd.from, decimal, true); + xor ? promoteXor(extenmd.type, storeemd.from) : + promoteNumeric(extenmd.type, storeemd.from, decimal, true); if (extenmd.promote == null) { throw new IllegalArgumentException("Cannot apply compound assignment to " + - " types [" + extenmd.type.name + "] and [" + storeemd.from.name + "]."); + "types [" + extenmd.type.name + "] and [" + storeemd.from.name + "]."); } extenmd.castFrom = getLegalCast(source, extenmd.type, extenmd.promote, false); @@ -2722,7 +2828,7 @@ class Analyzer extends PlanAParserBaseVisitor { from.clazz.asSubclass(to.clazz); return cast; - } catch (ClassCastException cce0) { + } catch (final ClassCastException cce0) { try { if (explicit) { to.clazz.asSubclass(from.clazz); @@ -2730,11 +2836,11 @@ class Analyzer extends PlanAParserBaseVisitor { return cast; } else { throw new ClassCastException( - error(source) + "Cannot cast from [" + from.name + "] to [" + to.name + "]."); - } - } catch (ClassCastException cce1) { - throw new ClassCastException( error(source) + "Cannot cast from [" + from.name + "] to [" + to.name + "]."); + } + } catch (final ClassCastException cce1) { + throw new ClassCastException( + error(source) + "Cannot cast from [" + from.name + "] to [" + to.name + "]."); } } } @@ -2744,7 +2850,7 @@ class Analyzer extends PlanAParserBaseVisitor { if (transform == null) { throw new ClassCastException( - error(source) + "Cannot cast from [" + cast.from.name + "] to [" + cast.to.name + "]."); + error(source) + "Cannot cast from [" + cast.from.name + "] to [" + cast.to.name + "]."); } return transform; @@ -2782,8 +2888,8 @@ class Analyzer extends PlanAParserBaseVisitor { } } else { throw new IllegalStateException(error(source) + "No valid constant cast from " + - "[" + cast.from.clazz.getCanonicalName() + "] to " + - "[" + cast.to.clazz.getCanonicalName() + "]."); + "[" + cast.from.clazz.getCanonicalName() + "] to " + + "[" + cast.to.clazz.getCanonicalName() + "]."); } } } @@ -2800,10 +2906,10 @@ class Analyzer extends PlanAParserBaseVisitor { return jmethod.invoke(object); } } catch (IllegalAccessException | IllegalArgumentException | - java.lang.reflect.InvocationTargetException | NullPointerException | - ExceptionInInitializerError exception) { + java.lang.reflect.InvocationTargetException | NullPointerException | + ExceptionInInitializerError exception) { throw new IllegalStateException(error(source) + "Unable to invoke transform to cast constant from " + - "[" + transform.from.name + "] to [" + transform.to.name + "]."); + "[" + transform.from.name + "] to [" + transform.to.name + "]."); } } @@ -2813,7 +2919,7 @@ class Analyzer extends PlanAParserBaseVisitor { if (sort == Sort.DEF) { return definition.defType; } else if ((sort == Sort.DOUBLE || sort == Sort.DOUBLE_OBJ || sort == Sort.NUMBER) && decimal) { - return primitive ? definition.doubleType : definition.doubleobjType; + return primitive ? definition.doubleType : definition.doubleobjType; } else if ((sort == Sort.FLOAT || sort == Sort.FLOAT_OBJ) && decimal) { return primitive ? definition.floatType : definition.floatobjType; } else if (sort == Sort.LONG || sort == Sort.LONG_OBJ || sort == Sort.NUMBER) { @@ -2835,7 +2941,7 @@ class Analyzer extends PlanAParserBaseVisitor { if (decimal) { if (sort0 == Sort.DOUBLE || sort0 == Sort.DOUBLE_OBJ || sort0 == Sort.NUMBER || - sort1 == Sort.DOUBLE || sort1 == Sort.DOUBLE_OBJ || sort1 == Sort.NUMBER) { + sort1 == Sort.DOUBLE || sort1 == Sort.DOUBLE_OBJ || sort1 == Sort.NUMBER) { return primitive ? definition.doubleType : definition.doubleobjType; } else if (sort0 == Sort.FLOAT || sort0 == Sort.FLOAT_OBJ || sort1 == Sort.FLOAT || sort1 == Sort.FLOAT_OBJ) { return primitive ? definition.floatType : definition.floatobjType; @@ -2843,8 +2949,8 @@ class Analyzer extends PlanAParserBaseVisitor { } if (sort0 == Sort.LONG || sort0 == Sort.LONG_OBJ || sort0 == Sort.NUMBER || - sort1 == Sort.LONG || sort1 == Sort.LONG_OBJ || sort1 == Sort.NUMBER) { - return primitive ? definition.longType : definition.longobjType; + sort1 == Sort.LONG || sort1 == Sort.LONG_OBJ || sort1 == Sort.NUMBER) { + return primitive ? definition.longType : definition.longobjType; } else if (sort0.numeric && sort1.numeric) { return primitive ? definition.intType : definition.intobjType; } @@ -2885,7 +2991,7 @@ class Analyzer extends PlanAParserBaseVisitor { final boolean primitive = sort0.primitive && sort1.primitive; if (sort0.bool && sort1.bool) { - return primitive ? definition.booleanType : definition.byteobjType; + return primitive ? definition.booleanType : definition.booleanobjType; } if (sort0.numeric && sort1.numeric) { diff --git a/plugins/lang-plan-a/src/main/java/org/elasticsearch/plan/a/Compiler.java b/plugins/lang-plan-a/src/main/java/org/elasticsearch/plan/a/Compiler.java index 4d6936a0d72..b6aa5f075ab 100644 --- a/plugins/lang-plan-a/src/main/java/org/elasticsearch/plan/a/Compiler.java +++ b/plugins/lang-plan-a/src/main/java/org/elasticsearch/plan/a/Compiler.java @@ -30,88 +30,87 @@ import java.security.CodeSource; import java.security.SecureClassLoader; import java.security.cert.Certificate; +/** + * The Compiler is the entry point for generating a Plan A script. The compiler will generate an ANTLR + * parse tree based on the source code that is passed in. Two passes will then be run over the parse tree, + * one for analysis using the {@link Analyzer} and another to generate the actual byte code using ASM in + * the {@link Writer}. + */ final class Compiler { + /** + * The default language API to be used with Plan A. The second construction is used + * to finalize all the variables, so there is no mistake of modification afterwards. + */ private static Definition DEFAULT_DEFINITION = new Definition(new Definition()); - /** we define the class with lowest privileges */ + /** + * Define the class with lowest privileges. + */ private static final CodeSource CODESOURCE; + /** + * Setup the code privileges. + */ static { try { + // Setup the code privileges. CODESOURCE = new CodeSource(new URL("file:" + BootstrapInfo.UNTRUSTED_CODEBASE), (Certificate[]) null); } catch (MalformedURLException impossible) { throw new RuntimeException(impossible); } } + /** + * A secure class loader used to define Plan A scripts. + */ static class Loader extends SecureClassLoader { - Loader(ClassLoader parent) { + /** + * @param parent The parent ClassLoader. + */ + Loader(final ClassLoader parent) { super(parent); } - Class define(String name, byte[] bytes) { + /** + * Generates a Class object from the generated byte code. + * @param name The name of the class. + * @param bytes The generated byte code. + * @return A Class object extending {@link Executable}. + */ + Class define(final String name, final byte[] bytes) { return defineClass(name, bytes, 0, bytes.length, CODESOURCE).asSubclass(Executable.class); } } - static Executable compile(Loader loader, final String name, final String source, final Definition custom, CompilerSettings settings) { - long start = System.currentTimeMillis(); - - final Definition definition = custom == null ? DEFAULT_DEFINITION : new Definition(custom); - - //long end = System.currentTimeMillis() - start; - //System.out.println("types: " + end); - //start = System.currentTimeMillis(); - - //final ParserRuleContext root = createParseTree(source, types); - final ANTLRInputStream stream = new ANTLRInputStream(source); - final ErrorHandlingLexer lexer = new ErrorHandlingLexer(stream); - final PlanAParser parser = new PlanAParser(new CommonTokenStream(lexer)); - final ParserErrorStrategy strategy = new ParserErrorStrategy(); - - lexer.removeErrorListeners(); - lexer.setTypes(definition.structs.keySet()); - - //List tokens = lexer.getAllTokens(); - - //for (final Token token : tokens) { - // System.out.println(token.getType() + " " + token.getText()); - //} - - parser.removeErrorListeners(); - parser.setErrorHandler(strategy); - - ParserRuleContext root = parser.source(); - - //end = System.currentTimeMillis() - start; - //System.out.println("tree: " + end); - - final Adapter adapter = new Adapter(definition, source, root, settings); - - start = System.currentTimeMillis(); - - Analyzer.analyze(adapter); - //System.out.println(root.toStringTree(parser)); - - //end = System.currentTimeMillis() - start; - //System.out.println("analyze: " + end); - //start = System.currentTimeMillis(); - - final byte[] bytes = Writer.write(adapter); - - //end = System.currentTimeMillis() - start; - //System.out.println("write: " + end); - //start = System.currentTimeMillis(); - + /** + * Runs the two-pass compiler to generate a Plan A script. + * @param loader The ClassLoader used to define the script. + * @param name The name of the script. + * @param source The source code for the script. + * @param settings The CompilerSettings to be used during the compilation. + * @return An {@link Executable} Plan A script. + */ + static Executable compile(final Loader loader, final String name, final String source, + final Definition custom, final CompilerSettings settings) { + final Definition definition = custom != null ? new Definition(custom) : DEFAULT_DEFINITION; + final ParserRuleContext root = createParseTree(source, definition); + final Metadata metadata = new Metadata(definition, source, root, settings); + Analyzer.analyze(metadata); + final byte[] bytes = Writer.write(metadata); final Executable executable = createExecutable(loader, definition, name, source, bytes); - //end = System.currentTimeMillis() - start; - //System.out.println("create: " + end); - return executable; } - private static ParserRuleContext createParseTree(String source, Definition definition) { + /** + * Generates the ANTLR tree from the given source code. Several methods below, are used + * to ensure that the first error generated by ANTLR will cause the compilation to fail rather than + * use ANTLR's recovery strategies that may be potentially dangerous. + * @param source The source code for the script. + * @param definition The Plan A API. + * @return The root node for the ANTLR parse tree. + */ + private static ParserRuleContext createParseTree(final String source, final Definition definition) { final ANTLRInputStream stream = new ANTLRInputStream(source); final ErrorHandlingLexer lexer = new ErrorHandlingLexer(stream); final PlanAParser parser = new PlanAParser(new CommonTokenStream(lexer)); @@ -119,36 +118,50 @@ final class Compiler { lexer.removeErrorListeners(); lexer.setTypes(definition.structs.keySet()); - parser.removeErrorListeners(); parser.setErrorHandler(strategy); ParserRuleContext root = parser.source(); - // System.out.println(root.toStringTree(parser)); + return root; } - private static Executable createExecutable(Loader loader, Definition definition, String name, String source, byte[] bytes) { + /** + * Generates an {@link Executable} that can run a Plan A script. + * @param loader The {@link Loader} to define the script's class file. + * @param definition The Plan A API. + * @param name The name of the script. + * @param source The source text of the script. + * @param bytes The ASM generated byte code to define the class with. + * @return A Plan A {@link Executable} script. + */ + private static Executable createExecutable(final Loader loader, final Definition definition, + final String name, final String source, final byte[] bytes) { try { - // for debugging: - //try { - // FileOutputStream f = new FileOutputStream(new File("/Users/jdconrad/lang/generated/out.class"), false); - // f.write(bytes); - // f.close(); - //} catch (Exception e) { - // throw new RuntimeException(e); - //} + // Used for debugging. Uncomment this code and add -Dtests.security.manager=false when running to save + // the generated Java class files. The javap tool can then be used to inspect the generated byte code. + + // try { + // FileOutputStream f = new FileOutputStream(new File(""), false); + // f.write(bytes); + // f.close(); + // } catch (Exception e) { + // throw new RuntimeException(e); + // } final Class clazz = loader.define(Writer.CLASS_NAME, bytes); final java.lang.reflect.Constructor constructor = clazz.getConstructor(Definition.class, String.class, String.class); return constructor.newInstance(definition, name, source); - } catch (Exception exception) { + } catch (final Exception exception) { // Catch everything to let the user know this is something caused internally. throw new IllegalStateException( "An internal error occurred attempting to define the script [" + name + "].", exception); } } + /** + * All methods in the compiler should be static. + */ private Compiler() {} } diff --git a/plugins/lang-plan-a/src/main/java/org/elasticsearch/plan/a/CompilerSettings.java b/plugins/lang-plan-a/src/main/java/org/elasticsearch/plan/a/CompilerSettings.java index f66b65d0612..4b5e753e342 100644 --- a/plugins/lang-plan-a/src/main/java/org/elasticsearch/plan/a/CompilerSettings.java +++ b/plugins/lang-plan-a/src/main/java/org/elasticsearch/plan/a/CompilerSettings.java @@ -19,13 +19,30 @@ package org.elasticsearch.plan.a; -/** - * Settings to use when compiling a script +/** + * Settings to use when compiling a script. */ final class CompilerSettings { + /** + * Constant to be used when specifying numeric overflow when compiling a script. + */ + public static final String NUMERIC_OVERFLOW = "numeric_overflow"; + /** + * Constant to be used when specifying the maximum loop counter when compiling a script. + */ + public static final String MAX_LOOP_COUNTER = "max_loop_counter"; + + /** + * Whether or not to allow numeric values to overflow without exception. + */ private boolean numericOverflow = true; + /** + * The maximum number of statements allowed to be run in a loop. + */ + private int maxLoopCounter = 10000; + /** * Returns {@code true} if numeric operations should overflow, {@code false} * if they should signal an exception. @@ -46,4 +63,20 @@ final class CompilerSettings { public void setNumericOverflow(boolean allow) { this.numericOverflow = allow; } + + /** + * Returns the value for the cumulative total number of statements that can be made in all loops + * in a script before an exception is thrown. This attempts to prevent infinite loops. + */ + public int getMaxLoopCounter() { + return maxLoopCounter; + } + + /** + * Set the cumulative total number of statements that can be made in all loops. + * @see #getMaxLoopCounter + */ + public void setMaxLoopCounter(int max) { + this.maxLoopCounter = max; + } } diff --git a/plugins/lang-plan-a/src/main/java/org/elasticsearch/plan/a/Def.java b/plugins/lang-plan-a/src/main/java/org/elasticsearch/plan/a/Def.java index c7a8ce410fd..eb5e0bdd66f 100644 --- a/plugins/lang-plan-a/src/main/java/org/elasticsearch/plan/a/Def.java +++ b/plugins/lang-plan-a/src/main/java/org/elasticsearch/plan/a/Def.java @@ -107,7 +107,7 @@ public class Def { } else if (owner instanceof List) { try { final int index = Integer.parseInt(name); - ((List)owner).add(index, value); + ((List)owner).set(index, value); } catch (NumberFormatException exception) { throw new IllegalArgumentException( "Illegal list shortcut value [" + name + "]."); } @@ -198,7 +198,7 @@ public class Def { "in array class [" + array.getClass().getCanonicalName() + "].", throwable); } } else if (array instanceof List) { - ((List)array).add((int)index, value); + ((List)array).set((int)index, value); } else { throw new IllegalArgumentException("Attempting to address a non-array type " + "[" + array.getClass().getCanonicalName() + "] as an array."); diff --git a/plugins/lang-plan-a/src/main/java/org/elasticsearch/plan/a/Definition.java b/plugins/lang-plan-a/src/main/java/org/elasticsearch/plan/a/Definition.java index 901dd4f8d32..613bdafd8ee 100644 --- a/plugins/lang-plan-a/src/main/java/org/elasticsearch/plan/a/Definition.java +++ b/plugins/lang-plan-a/src/main/java/org/elasticsearch/plan/a/Definition.java @@ -24,10 +24,14 @@ import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collection; import java.util.Collections; import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.Set; class Definition { enum Sort { @@ -351,16 +355,32 @@ class Definition { final Type utilityType; final Type defobjType; + final Type itrType; + final Type oitrType; + final Type sitrType; + + final Type collectionType; + final Type ocollectionType; + final Type scollectionType; + final Type listType; final Type arraylistType; - final Type mapType; - final Type hashmapType; - final Type olistType; final Type oarraylistType; - final Type omapType; - final Type ohashmapType; + final Type slistType; + final Type sarraylistType; + final Type setType; + final Type hashsetType; + final Type osetType; + final Type ohashsetType; + final Type ssetType; + final Type shashsetType; + + final Type mapType; + final Type hashmapType; + final Type oomapType; + final Type oohashmapType; final Type smapType; final Type shashmapType; final Type somapType; @@ -368,6 +388,12 @@ class Definition { final Type execType; + final Type exceptionType; + final Type arithexcepType; + final Type iargexcepType; + final Type istateexceptType; + final Type nfexcepType; + public Definition() { structs = new HashMap<>(); classes = new HashMap<>(); @@ -406,16 +432,32 @@ class Definition { utilityType = getType("Utility"); defobjType = getType("Def"); + itrType = getType("Iterator"); + oitrType = getType("Iterator"); + sitrType = getType("Iterator"); + + collectionType = getType("Collection"); + ocollectionType = getType("Collection"); + scollectionType = getType("Collection"); + listType = getType("List"); arraylistType = getType("ArrayList"); - mapType = getType("Map"); - hashmapType = getType("HashMap"); - olistType = getType("List"); oarraylistType = getType("ArrayList"); - omapType = getType("Map"); - ohashmapType = getType("HashMap"); + slistType = getType("List"); + sarraylistType = getType("ArrayList"); + setType = getType("Set"); + hashsetType = getType("HashSet"); + osetType = getType("Set"); + ohashsetType = getType("HashSet"); + ssetType = getType("Set"); + shashsetType = getType("HashSet"); + + mapType = getType("Map"); + hashmapType = getType("HashMap"); + oomapType = getType("Map"); + oohashmapType = getType("HashMap"); smapType = getType("Map"); shashmapType = getType("HashMap"); somapType = getType("Map"); @@ -423,6 +465,12 @@ class Definition { execType = getType("Executable"); + exceptionType = getType("Exception"); + arithexcepType = getType("ArithmeticException"); + iargexcepType = getType("IllegalArgumentException"); + istateexceptType = getType("IllegalStateException"); + nfexcepType = getType("NumberFormatException"); + addDefaultElements(); copyDefaultStructs(); addDefaultTransforms(); @@ -478,22 +526,44 @@ class Definition { utilityType = definition.utilityType; defobjType = definition.defobjType; + itrType = definition.itrType; + oitrType = definition.oitrType; + sitrType = definition.sitrType; + + collectionType = definition.collectionType; + ocollectionType = definition.ocollectionType; + scollectionType = definition.scollectionType; + listType = definition.listType; arraylistType = definition.arraylistType; - mapType = definition.mapType; - hashmapType = definition.hashmapType; - olistType = definition.olistType; oarraylistType = definition.oarraylistType; - omapType = definition.omapType; - ohashmapType = definition.ohashmapType; + slistType = definition.slistType; + sarraylistType = definition.sarraylistType; + setType = definition.setType; + hashsetType = definition.hashsetType; + osetType = definition.osetType; + ohashsetType = definition.ohashsetType; + ssetType = definition.ssetType; + shashsetType = definition.shashsetType; + + mapType = definition.mapType; + hashmapType = definition.hashmapType; + oomapType = definition.oomapType; + oohashmapType = definition.oohashmapType; smapType = definition.smapType; shashmapType = definition.shashmapType; somapType = definition.somapType; sohashmapType = definition.sohashmapType; execType = definition.execType; + + exceptionType = definition.exceptionType; + arithexcepType = definition.arithexcepType; + iargexcepType = definition.iargexcepType; + istateexceptType = definition.istateexceptType; + nfexcepType = definition.nfexcepType; } private void addDefaultStructs() { @@ -526,22 +596,44 @@ class Definition { addStruct( "Utility" , Utility.class ); addStruct( "Def" , Def.class ); - addStruct( "List" , List.class ); - addStruct( "ArrayList" , ArrayList.class ); - addStruct( "Map" , Map.class ); - addStruct( "HashMap" , HashMap.class ); + addStruct( "Iterator" , Iterator.class ); + addStruct( "Iterator" , Iterator.class ); + addStruct( "Iterator" , Iterator.class ); - addStruct( "List" , List.class ); - addStruct( "ArrayList" , ArrayList.class ); - addStruct( "Map" , Map.class ); - addStruct( "HashMap" , HashMap.class ); + addStruct( "Collection" , Collection.class ); + addStruct( "Collection" , Collection.class ); + addStruct( "Collection" , Collection.class ); - addStruct( "Map" , Map.class ); - addStruct( "HashMap" , HashMap.class ); - addStruct( "Map" , Map.class ); - addStruct( "HashMap" , HashMap.class ); + addStruct( "List" , List.class ); + addStruct( "ArrayList" , ArrayList.class ); + addStruct( "List" , List.class ); + addStruct( "ArrayList" , ArrayList.class ); + addStruct( "List" , List.class ); + addStruct( "ArrayList" , ArrayList.class ); + + addStruct( "Set" , Set.class ); + addStruct( "HashSet" , HashSet.class ); + addStruct( "Set" , Set.class ); + addStruct( "HashSet" , HashSet.class ); + addStruct( "Set" , Set.class ); + addStruct( "HashSet" , HashSet.class ); + + addStruct( "Map" , Map.class ); + addStruct( "HashMap" , HashMap.class ); + addStruct( "Map" , Map.class ); + addStruct( "HashMap" , HashMap.class ); + addStruct( "Map" , Map.class ); + addStruct( "HashMap" , HashMap.class ); + addStruct( "Map" , Map.class ); + addStruct( "HashMap" , HashMap.class ); addStruct( "Executable" , Executable.class ); + + addStruct( "Exception" , Exception.class); + addStruct( "ArithmeticException" , ArithmeticException.class); + addStruct( "IllegalArgumentException" , IllegalArgumentException.class); + addStruct( "IllegalStateException" , IllegalStateException.class); + addStruct( "NumberFormatException" , NumberFormatException.class); } private void addDefaultClasses() { @@ -568,10 +660,16 @@ class Definition { addClass("CharSequence"); addClass("String"); + addClass("Iterator"); + addClass("Collection"); addClass("List"); addClass("ArrayList"); + addClass("Set"); + addClass("HashSet"); addClass("Map"); addClass("HashMap"); + + addClass("Exception"); } private void addDefaultElements() { @@ -587,45 +685,39 @@ class Definition { addMethod("Boolean", "valueOf", null, true, booleanobjType, new Type[] {booleanType}, null, null); addMethod("Boolean", "booleanValue", null, false, booleanType, new Type[] {}, null, null); - addConstructor("Byte", "new", new Type[]{byteType}, null); + addConstructor("Byte", "new", new Type[] {byteType}, null); addMethod("Byte", "valueOf", null, true, byteobjType, new Type[] {byteType}, null, null); - addMethod("Byte", "byteValue", null, false, byteType, new Type[] {}, null, null); addField("Byte", "MIN_VALUE", null, true, byteType, null); addField("Byte", "MAX_VALUE", null, true, byteType, null); - addConstructor("Short", "new", new Type[]{shortType}, null); + addConstructor("Short", "new", new Type[] {shortType}, null); addMethod("Short", "valueOf", null, true, shortobjType, new Type[] {shortType}, null, null); - addMethod("Short", "shortValue", null, false, shortType, new Type[] {}, null, null); addField("Short", "MIN_VALUE", null, true, shortType, null); addField("Short", "MAX_VALUE", null, true, shortType, null); - addConstructor("Character", "new", new Type[]{charType}, null); + addConstructor("Character", "new", new Type[] {charType}, null); addMethod("Character", "valueOf", null, true, charobjType, new Type[] {charType}, null, null); addMethod("Character", "charValue", null, false, charType, new Type[] {}, null, null); addField("Character", "MIN_VALUE", null, true, charType, null); addField("Character", "MAX_VALUE", null, true, charType, null); - addConstructor("Integer", "new", new Type[]{intType}, null); + addConstructor("Integer", "new", new Type[] {intType}, null); addMethod("Integer", "valueOf", null, true, intobjType, new Type[] {intType}, null, null); - addMethod("Integer", "intValue", null, false, intType, new Type[] {}, null, null); addField("Integer", "MIN_VALUE", null, true, intType, null); addField("Integer", "MAX_VALUE", null, true, intType, null); - addConstructor("Long", "new", new Type[]{longType}, null); + addConstructor("Long", "new", new Type[] {longType}, null); addMethod("Long", "valueOf", null, true, longobjType, new Type[] {longType}, null, null); - addMethod("Long", "longValue", null, false, longType, new Type[] {}, null, null); addField("Long", "MIN_VALUE", null, true, longType, null); addField("Long", "MAX_VALUE", null, true, longType, null); - addConstructor("Float", "new", new Type[]{floatType}, null); + addConstructor("Float", "new", new Type[] {floatType}, null); addMethod("Float", "valueOf", null, true, floatobjType, new Type[] {floatType}, null, null); - addMethod("Float", "floatValue", null, false, floatType, new Type[] {}, null, null); addField("Float", "MIN_VALUE", null, true, floatType, null); addField("Float", "MAX_VALUE", null, true, floatType, null); - addConstructor("Double", "new", new Type[]{doubleType}, null); + addConstructor("Double", "new", new Type[] {doubleType}, null); addMethod("Double", "valueOf", null, true, doubleobjType, new Type[] {doubleType}, null, null); - addMethod("Double", "doubleValue", null, false, doubleType, new Type[] {}, null, null); addField("Double", "MIN_VALUE", null, true, doubleType, null); addField("Double", "MAX_VALUE", null, true, doubleType, null); @@ -760,7 +852,44 @@ class Definition { addMethod("Utility", "DoubleToboolean", null, true, booleanType, new Type[] {doubleobjType}, null, null); addMethod("Utility", "DoubleTochar", null, true, charType, new Type[] {doubleobjType}, null, null); - addMethod("Math", "dmax", "max", true, doubleType, new Type[] {doubleType, doubleType}, null, null); + addMethod("Math", "abs", null, true, doubleType, new Type[] {doubleType}, null, null); + addMethod("Math", "fabs", "abs", true, floatType, new Type[] {floatType}, null, null); + addMethod("Math", "labs", "abs", true, longType, new Type[] {longType}, null, null); + addMethod("Math", "iabs", "abs", true, intType, new Type[] {intType}, null, null); + addMethod("Math", "acos", null, true, doubleType, new Type[] {doubleType}, null, null); + addMethod("Math", "asin", null, true, doubleType, new Type[] {doubleType}, null, null); + addMethod("Math", "atan", null, true, doubleType, new Type[] {doubleType}, null, null); + addMethod("Math", "atan2", null, true, doubleType, new Type[] {doubleType, doubleType}, null, null); + addMethod("Math", "cbrt", null, true, doubleType, new Type[] {doubleType}, null, null); + addMethod("Math", "ceil", null, true, doubleType, new Type[] {doubleType}, null, null); + addMethod("Math", "cos", null, true, doubleType, new Type[] {doubleType}, null, null); + addMethod("Math", "cosh", null, true, doubleType, new Type[] {doubleType}, null, null); + addMethod("Math", "exp", null, true, doubleType, new Type[] {doubleType}, null, null); + addMethod("Math", "expm1", null, true, doubleType, new Type[] {doubleType}, null, null); + addMethod("Math", "floor", null, true, doubleType, new Type[] {doubleType}, null, null); + addMethod("Math", "hypot", null, true, doubleType, new Type[] {doubleType, doubleType}, null, null); + addMethod("Math", "log", null, true, doubleType, new Type[] {doubleType}, null, null); + addMethod("Math", "log10", null, true, doubleType, new Type[] {doubleType}, null, null); + addMethod("Math", "log1p", null, true, doubleType, new Type[] {doubleType}, null, null); + addMethod("Math", "max", "max", true, doubleType, new Type[] {doubleType, doubleType}, null, null); + addMethod("Math", "fmax", "max", true, floatType, new Type[] {floatType, floatType}, null, null); + addMethod("Math", "lmax", "max", true, longType, new Type[] {longType, longType}, null, null); + addMethod("Math", "imax", "max", true, intType, new Type[] {intType, intType}, null, null); + addMethod("Math", "min", "min", true, doubleType, new Type[] {doubleType, doubleType}, null, null); + addMethod("Math", "fmin", "min", true, floatType, new Type[] {floatType, floatType}, null, null); + addMethod("Math", "lmin", "min", true, longType, new Type[] {longType, longType}, null, null); + addMethod("Math", "imin", "min", true, intType, new Type[] {intType, intType}, null, null); + addMethod("Math", "pow", null, true, doubleType, new Type[] {doubleType, doubleType}, null, null); + addMethod("Math", "random", null, true, doubleType, new Type[] {}, null, null); + addMethod("Math", "rint", null, true, doubleType, new Type[] {doubleType}, null, null); + addMethod("Math", "round", null, true, longType, new Type[] {doubleType}, null, null); + addMethod("Math", "sin", null, true, doubleType, new Type[] {doubleType}, null, null); + addMethod("Math", "sinh", null, true, doubleType, new Type[] {doubleType}, null, null); + addMethod("Math", "sqrt", null, true, doubleType, new Type[] {doubleType}, null, null); + addMethod("Math", "tan", null, true, doubleType, new Type[] {doubleType}, null, null); + addMethod("Math", "tanh", null, true, doubleType, new Type[] {doubleType}, null, null); + addMethod("Math", "toDegrees", null, true, doubleType, new Type[] {doubleType}, null, null); + addMethod("Math", "toRadians", null, true, doubleType, new Type[] {doubleType}, null, null); addMethod("Def", "DefToboolean", null, true, booleanType, new Type[] {defType}, null, null); addMethod("Def", "DefTobyte", null, true, byteType, new Type[] {defType}, null, null); @@ -779,55 +908,123 @@ class Definition { addMethod("Def", "DefToFloat", null, true, floatobjType, new Type[] {defType}, null, null); addMethod("Def", "DefToDouble", null, true, doubleobjType, new Type[] {defType}, null, null); - addMethod("List", "addLast", "add", false, booleanType, new Type[] {objectType}, null, new Type[] {defType}); - addMethod("List", "add", null, false, voidType, new Type[] {intType, objectType}, null, new Type[] {intType, defType}); + addMethod("Iterator", "hasNext", null, false, booleanType, new Type[] {}, null, null); + addMethod("Iterator", "next", null, false, objectType, new Type[] {}, defType, null); + addMethod("Iterator", "remove", null, false, voidType, new Type[] {}, null, null); + + addMethod("Iterator", "hasNext", null, false, booleanType, new Type[] {}, null, null); + addMethod("Iterator", "next", null, false, objectType, new Type[] {}, null, null); + addMethod("Iterator", "remove", null, false, voidType, new Type[] {}, null, null); + + addMethod("Iterator", "hasNext", null, false, booleanType, new Type[] {}, null, null); + addMethod("Iterator", "next", null, false, objectType, new Type[] {}, stringType, null); + addMethod("Iterator", "remove", null, false, voidType, new Type[] {}, null, null); + + addMethod("Collection", "add", null, false, booleanType, new Type[] {objectType}, null, new Type[] {defType}); + addMethod("Collection", "clear", null, false, voidType, new Type[] {}, null, null); + addMethod("Collection", "contains", null, false, booleanType, new Type[] {objectType}, null, new Type[] {defType}); + addMethod("Collection", "isEmpty", null, false, booleanType, new Type[] {}, null, null); + addMethod("Collection", "iterator", null, false, itrType, new Type[] {}, null, null); + addMethod("Collection", "remove", null, false, booleanType, new Type[] {objectType}, null, new Type[] {defType}); + addMethod("Collection", "size", null, false, intType, new Type[] {}, null, null); + + addMethod("Collection", "add", null, false, booleanType, new Type[] {objectType}, null, null); + addMethod("Collection", "clear", null, false, voidType, new Type[] {}, null, null); + addMethod("Collection", "contains", null, false, booleanType, new Type[] {objectType}, null, null); + addMethod("Collection", "isEmpty", null, false, booleanType, new Type[] {}, null, null); + addMethod("Collection", "iterator", null, false, oitrType, new Type[] {}, null, null); + addMethod("Collection", "remove", null, false, booleanType, new Type[] {objectType}, null, null); + addMethod("Collection", "size", null, false, intType, new Type[] {}, null, null); + + addMethod("Collection", "add", null, false, booleanType, new Type[] {objectType}, null, new Type[] {stringType}); + addMethod("Collection", "clear", null, false, voidType, new Type[] {}, null, null); + addMethod("Collection", "contains", null, false, booleanType, new Type[] {objectType}, null, new Type[] {stringType}); + addMethod("Collection", "isEmpty", null, false, booleanType, new Type[] {}, null, null); + addMethod("Collection", "iterator", null, false, sitrType, new Type[] {}, null, null); + addMethod("Collection", "remove", null, false, booleanType, new Type[] {objectType}, null, new Type[] {stringType}); + addMethod("Collection", "size", null, false, intType, new Type[] {}, null, null); + + addMethod("List", "set", null, false, objectType, new Type[] {intType, objectType}, defType, new Type[] {intType, defType}); addMethod("List", "get", null, false, objectType, new Type[] {intType}, defType, null); addMethod("List", "remove", null, false, objectType, new Type[] {intType}, defType, null); - addMethod("List", "size", null, false, intType, new Type[] {}, null, null); - addMethod("List", "isEmpty", null, false, booleanType, new Type[] {}, null, null); addConstructor("ArrayList", "new", new Type[] {}, null); + addMethod("List", "set", null, false, objectType, new Type[] {intType, objectType}, null, null); + addMethod("List", "get", null, false, objectType, new Type[] {intType}, null, null); + addMethod("List", "remove", null, false, objectType, new Type[] {intType}, null, null); + + addConstructor("ArrayList", "new", new Type[] {}, null); + + addMethod("List", "set", null, false, objectType, new Type[] {intType, objectType}, stringType, new Type[] {intType, stringType}); + addMethod("List", "get", null, false, objectType, new Type[] {intType}, stringType, null); + addMethod("List", "remove", null, false, objectType, new Type[] {intType}, stringType, null); + + addConstructor("ArrayList", "new", new Type[] {}, null); + + addConstructor("HashSet", "new", new Type[] {}, null); + + addConstructor("HashSet", "new", new Type[] {}, null); + + addConstructor("HashSet", "new", new Type[] {}, null); + addMethod("Map", "put", null, false, objectType, new Type[] {objectType, objectType}, defType, new Type[] {defType, defType}); addMethod("Map", "get", null, false, objectType, new Type[] {objectType}, defType, new Type[] {defType}); addMethod("Map", "remove", null, false, objectType, new Type[] {objectType}, null, null); - addMethod("Map", "size", null, false, intType, new Type[] {}, null, null); addMethod("Map", "isEmpty", null, false, booleanType, new Type[] {}, null, null); + addMethod("Map", "size", null, false, intType, new Type[] {}, null, null); + addMethod("Map", "containsKey", null, false, booleanType, new Type[] {objectType}, null, new Type[] {defType}); + addMethod("Map", "containsValue", null, false, booleanType, new Type[] {objectType}, null, new Type[] {defType}); + addMethod("Map", "keySet", null, false, osetType, new Type[] {}, setType, null); + addMethod("Map", "values", null, false, ocollectionType, new Type[] {}, collectionType, null); addConstructor("HashMap", "new", new Type[] {}, null); - addMethod("Map", "put", null, false, objectType, new Type[] {objectType, objectType}, defType, new Type[] {stringType, defType}); - addMethod("Map", "get", null, false, objectType, new Type[] {objectType}, defType, new Type[] {stringType}); - addMethod("Map", "remove", null, false, objectType, new Type[] {objectType}, defType, new Type[] {stringType}); - addMethod("Map", "size", null, false, intType, new Type[] {}, null, null); - addMethod("Map", "isEmpty", null, false, booleanType, new Type[] {}, null, null); - - addConstructor("HashMap", "new", new Type[] {}, null); - - addMethod("List", "addLast", "add", false, booleanType, new Type[] {objectType}, null, null); - addMethod("List", "add", null, false, voidType, new Type[] {intType, objectType}, null, null); - addMethod("List", "get", null, false, objectType, new Type[] {intType}, null, null); - addMethod("List", "remove", null, false, objectType, new Type[] {intType}, null, null); - addMethod("List", "size", null, false, intType, new Type[] {}, null, null); - addMethod("List", "isEmpty", null, false, booleanType, new Type[] {}, null, null); - - addConstructor("ArrayList", "new", new Type[] {}, null); - addMethod("Map", "put", null, false, objectType, new Type[] {objectType, objectType}, null, null); addMethod("Map", "get", null, false, objectType, new Type[] {objectType}, null, null); addMethod("Map", "remove", null, false, objectType, new Type[] {objectType}, null, null); - addMethod("Map", "size", null, false, intType, new Type[] {}, null, null); addMethod("Map", "isEmpty", null, false, booleanType, new Type[] {}, null, null); + addMethod("Map", "size", null, false, intType, new Type[] {}, null, null); + addMethod("Map", "containsKey", null, false, booleanType, new Type[] {objectType}, null, null); + addMethod("Map", "containsValue", null, false, booleanType, new Type[] {objectType}, null, null); + addMethod("Map", "keySet", null, false, osetType, new Type[] {}, null, null); + addMethod("Map", "values", null, false, ocollectionType, new Type[] {}, null, null); addConstructor("HashMap", "new", new Type[] {}, null); + addMethod("Map", "put", null, false, objectType, new Type[] {objectType, objectType}, defType, new Type[] {stringType, defType}); + addMethod("Map", "get", null, false, objectType, new Type[] {objectType}, defType, new Type[] {stringType}); + addMethod("Map", "remove", null, false, objectType, new Type[] {objectType}, defType, new Type[] {stringType}); + addMethod("Map", "isEmpty", null, false, booleanType, new Type[] {}, null, null); + addMethod("Map", "size", null, false, intType, new Type[] {}, null, null); + addMethod("Map", "containsKey", null, false, booleanType, new Type[] {objectType}, null, new Type[] {stringType}); + addMethod("Map", "containsValue", null, false, booleanType, new Type[] {objectType}, null, new Type[] {defType}); + addMethod("Map", "keySet", null, false, osetType, new Type[] {}, ssetType, null); + addMethod("Map", "values", null, false, ocollectionType, new Type[] {}, collectionType, null); + + addConstructor("HashMap", "new", new Type[] {}, null); + addMethod("Map", "put", null, false, objectType, new Type[] {objectType, objectType}, null, new Type[] {stringType, objectType}); addMethod("Map", "get", null, false, objectType, new Type[] {objectType}, null, new Type[] {stringType}); addMethod("Map", "remove", null, false, objectType, new Type[] {objectType}, null, new Type[] {stringType}); - addMethod("Map", "size", null, false, intType, new Type[] {}, null, null); addMethod("Map", "isEmpty", null, false, booleanType, new Type[] {}, null, null); + addMethod("Map", "size", null, false, intType, new Type[] {}, null, null); + addMethod("Map", "containsKey", null, false, booleanType, new Type[] {objectType}, null, new Type[] {stringType}); + addMethod("Map", "containsValue", null, false, booleanType, new Type[] {objectType}, null, null); + addMethod("Map", "keySet", null, false, osetType, new Type[] {}, ssetType, null); + addMethod("Map", "values", null, false, ocollectionType, new Type[] {}, null, null); addConstructor("HashMap", "new", new Type[] {}, null); + + addMethod("Exception", "getMessage", null, false, stringType, new Type[] {}, null, null); + + addConstructor("ArithmeticException", "new", new Type[] {stringType}, null); + + addConstructor("IllegalArgumentException", "new", new Type[] {stringType}, null); + + addConstructor("IllegalStateException", "new", new Type[] {stringType}, null); + + addConstructor("NumberFormatException", "new", new Type[] {stringType}, null); } private void copyDefaultStructs() { @@ -845,21 +1042,36 @@ class Definition { copyStruct("CharSequence", "Object"); copyStruct("String", "CharSequence", "Object"); - copyStruct("List", "Object"); - copyStruct("ArrayList", "List", "Object"); + copyStruct("List", "Collection", "Object"); + copyStruct("ArrayList", "List", "Collection", "Object"); + copyStruct("List", "Collection", "Object"); + copyStruct("ArrayList", "List", "Collection", "Object"); + copyStruct("List", "Collection", "Object"); + copyStruct("ArrayList", "List", "Collection", "Object"); + + copyStruct("Set", "Collection", "Object"); + copyStruct("HashSet", "Set", "Collection", "Object"); + copyStruct("Set", "Collection", "Object"); + copyStruct("HashSet", "Set", "Collection", "Object"); + copyStruct("Set", "Collection", "Object"); + copyStruct("HashSet", "Set", "Collection", "Object"); + copyStruct("Map", "Object"); copyStruct("HashMap", "Map", "Object"); - copyStruct("Map", "Object"); - copyStruct("HashMap", "Map", "Object"); - - copyStruct("List", "Object"); - copyStruct("ArrayList", "List", "Object"); copyStruct("Map", "Object"); copyStruct("HashMap", "Map", "Object"); + copyStruct("Map", "Object"); + copyStruct("HashMap", "Map", "Object"); copyStruct("Map", "Object"); copyStruct("HashMap", "Map", "Object"); copyStruct("Executable", "Object"); + + copyStruct("Exception", "Object"); + copyStruct("ArithmeticException", "Exception", "Object"); + copyStruct("IllegalArgumentException", "Exception", "Object"); + copyStruct("IllegalStateException", "Exception", "Object"); + copyStruct("NumberFormatException", "Exception", "Object"); } private void addDefaultTransforms() { @@ -1162,41 +1374,155 @@ class Definition { addBound(stringType, charseqType, charseqType); + addBound(oitrType, itrType, itrType); + addBound(oitrType, sitrType, itrType); + addBound(sitrType, itrType, itrType); + + addBound(ocollectionType, collectionType, collectionType); + addBound(scollectionType, collectionType, collectionType); + addBound(scollectionType, ocollectionType, ocollectionType); + addBound(listType, collectionType, collectionType); + addBound(listType, ocollectionType, collectionType); + addBound(listType, scollectionType, collectionType); + addBound(arraylistType, collectionType, collectionType); + addBound(arraylistType, ocollectionType, collectionType); + addBound(arraylistType, scollectionType, collectionType); addBound(arraylistType, listType, listType); + addBound(olistType, collectionType, collectionType); + addBound(olistType, ocollectionType, ocollectionType); + addBound(olistType, scollectionType, ocollectionType); addBound(olistType, listType, listType); addBound(olistType, arraylistType, listType); + addBound(oarraylistType, collectionType, collectionType); + addBound(oarraylistType, ocollectionType, ocollectionType); + addBound(oarraylistType, scollectionType, ocollectionType); addBound(oarraylistType, listType, listType); - addBound(oarraylistType, olistType, olistType); addBound(oarraylistType, arraylistType, arraylistType); + addBound(oarraylistType, olistType, olistType); + addBound(slistType, collectionType, collectionType); + addBound(slistType, ocollectionType, ocollectionType); + addBound(slistType, scollectionType, scollectionType); + addBound(slistType, listType, listType); + addBound(slistType, arraylistType, listType); + addBound(slistType, olistType, olistType); + addBound(slistType, oarraylistType, olistType); + addBound(sarraylistType, collectionType, collectionType); + addBound(sarraylistType, ocollectionType, ocollectionType); + addBound(sarraylistType, scollectionType, scollectionType); + addBound(sarraylistType, listType, listType); + addBound(sarraylistType, arraylistType, arraylistType); + addBound(sarraylistType, olistType, olistType); + addBound(sarraylistType, oarraylistType, oarraylistType); + addBound(sarraylistType, slistType, slistType); + addBound(setType, collectionType, collectionType); + addBound(setType, ocollectionType, collectionType); + addBound(setType, scollectionType, collectionType); + addBound(setType, listType, collectionType); + addBound(setType, arraylistType, collectionType); + addBound(setType, olistType, collectionType); + addBound(setType, oarraylistType, collectionType); + addBound(setType, slistType, collectionType); + addBound(setType, sarraylistType, collectionType); + addBound(hashsetType, collectionType, collectionType); + addBound(hashsetType, ocollectionType, collectionType); + addBound(hashsetType, scollectionType, collectionType); + addBound(hashsetType, listType, collectionType); + addBound(hashsetType, arraylistType, collectionType); + addBound(hashsetType, olistType, collectionType); + addBound(hashsetType, oarraylistType, collectionType); + addBound(hashsetType, slistType, collectionType); + addBound(hashsetType, sarraylistType, collectionType); + addBound(hashsetType, setType, setType); + addBound(osetType, collectionType, collectionType); + addBound(osetType, ocollectionType, ocollectionType); + addBound(osetType, scollectionType, ocollectionType); + addBound(osetType, listType, collectionType); + addBound(osetType, arraylistType, collectionType); + addBound(osetType, olistType, ocollectionType); + addBound(osetType, oarraylistType, ocollectionType); + addBound(osetType, slistType, ocollectionType); + addBound(osetType, sarraylistType, ocollectionType); + addBound(osetType, setType, setType); + addBound(osetType, hashsetType, setType); + addBound(ohashsetType, collectionType, collectionType); + addBound(ohashsetType, ocollectionType, ocollectionType); + addBound(ohashsetType, scollectionType, ocollectionType); + addBound(ohashsetType, listType, collectionType); + addBound(ohashsetType, arraylistType, collectionType); + addBound(ohashsetType, olistType, ocollectionType); + addBound(ohashsetType, oarraylistType, ocollectionType); + addBound(ohashsetType, slistType, ocollectionType); + addBound(ohashsetType, sarraylistType, ocollectionType); + addBound(ohashsetType, setType, setType); + addBound(ohashsetType, hashsetType, hashsetType); + addBound(ohashsetType, osetType, osetType); + addBound(ssetType, collectionType, collectionType); + addBound(ssetType, ocollectionType, ocollectionType); + addBound(ssetType, scollectionType, scollectionType); + addBound(ssetType, listType, collectionType); + addBound(ssetType, arraylistType, collectionType); + addBound(ssetType, olistType, ocollectionType); + addBound(ssetType, oarraylistType, ocollectionType); + addBound(ssetType, slistType, scollectionType); + addBound(ssetType, sarraylistType, scollectionType); + addBound(ssetType, setType, setType); + addBound(ssetType, hashsetType, setType); + addBound(ssetType, osetType, osetType); + addBound(ssetType, ohashsetType, osetType); + addBound(shashsetType, collectionType, collectionType); + addBound(shashsetType, ocollectionType, ocollectionType); + addBound(shashsetType, scollectionType, scollectionType); + addBound(shashsetType, listType, collectionType); + addBound(shashsetType, arraylistType, collectionType); + addBound(shashsetType, olistType, ocollectionType); + addBound(shashsetType, oarraylistType, ocollectionType); + addBound(shashsetType, slistType, scollectionType); + addBound(shashsetType, sarraylistType, scollectionType); + addBound(shashsetType, setType, setType); + addBound(shashsetType, hashsetType, hashsetType); + addBound(shashsetType, osetType, osetType); + addBound(shashsetType, ohashsetType, hashsetType); + addBound(shashsetType, ssetType, ssetType); addBound(hashmapType, mapType, mapType); - addBound(omapType, mapType, mapType); - addBound(omapType, hashmapType, mapType); - addBound(ohashmapType, mapType, mapType); - addBound(ohashmapType, hashmapType, hashmapType); - addBound(ohashmapType, omapType, omapType); + addBound(oomapType, mapType, mapType); + addBound(oomapType, hashmapType, mapType); + addBound(oohashmapType, mapType, mapType); + addBound(oohashmapType, hashmapType, hashmapType); + addBound(oohashmapType, oomapType, oomapType); addBound(smapType, mapType, mapType); addBound(smapType, hashmapType, mapType); - addBound(smapType, omapType, omapType); - addBound(smapType, ohashmapType, omapType); + addBound(smapType, oomapType, oomapType); + addBound(smapType, oohashmapType, oomapType); addBound(shashmapType, mapType, mapType); addBound(shashmapType, hashmapType, hashmapType); - addBound(shashmapType, omapType, omapType); - addBound(shashmapType, ohashmapType, ohashmapType); + addBound(shashmapType, oomapType, oomapType); + addBound(shashmapType, oohashmapType, oohashmapType); addBound(shashmapType, smapType, smapType); addBound(somapType, mapType, mapType); addBound(somapType, hashmapType, mapType); - addBound(somapType, omapType, omapType); - addBound(somapType, ohashmapType, omapType); + addBound(somapType, oomapType, oomapType); + addBound(somapType, oohashmapType, oomapType); addBound(somapType, smapType, smapType); addBound(somapType, shashmapType, smapType); addBound(sohashmapType, mapType, mapType); addBound(sohashmapType, hashmapType, hashmapType); - addBound(sohashmapType, omapType, omapType); - addBound(sohashmapType, ohashmapType, ohashmapType); + addBound(sohashmapType, oomapType, oomapType); + addBound(sohashmapType, oohashmapType, oohashmapType); addBound(sohashmapType, smapType, smapType); addBound(sohashmapType, shashmapType, shashmapType); addBound(sohashmapType, somapType, somapType); + + addBound(arithexcepType, exceptionType, exceptionType); + addBound(iargexcepType, exceptionType, exceptionType); + addBound(istateexceptType, exceptionType, exceptionType); + addBound(nfexcepType, exceptionType, exceptionType); + addBound(arithexcepType, iargexcepType, exceptionType); + addBound(arithexcepType, istateexceptType, exceptionType); + addBound(arithexcepType, nfexcepType, exceptionType); + addBound(iargexcepType, istateexceptType, exceptionType); + addBound(iargexcepType, nfexcepType, exceptionType); + addBound(istateexceptType, nfexcepType, exceptionType); } public final void addStruct(final String name, final Class clazz) { @@ -1232,27 +1558,27 @@ class Definition { if (owner == null) { throw new IllegalArgumentException( - "Owner struct [" + struct + "] not defined for constructor [" + name + "]."); + "Owner struct [" + struct + "] not defined for constructor [" + name + "]."); } if (!name.matches("^[_a-zA-Z][_a-zA-Z0-9]*$")) { throw new IllegalArgumentException( - "Invalid constructor name [" + name + "] with the struct [" + owner.name + "]."); + "Invalid constructor name [" + name + "] with the struct [" + owner.name + "]."); } if (owner.constructors.containsKey(name)) { throw new IllegalArgumentException( - "Duplicate constructor name [" + name + "] found within the struct [" + owner.name + "]."); + "Duplicate constructor name [" + name + "] found within the struct [" + owner.name + "]."); } if (owner.statics.containsKey(name)) { throw new IllegalArgumentException("Constructors and functions may not have the same name" + - " [" + name + "] within the same struct [" + owner.name + "]."); + " [" + name + "] within the same struct [" + owner.name + "]."); } if (owner.methods.containsKey(name)) { throw new IllegalArgumentException("Constructors and methods may not have the same name" + - " [" + name + "] within the same struct [" + owner.name + "]."); + " [" + name + "] within the same struct [" + owner.name + "]."); } final Class[] classes = new Class[args.length]; @@ -1263,8 +1589,8 @@ class Definition { genargs[count].clazz.asSubclass(args[count].clazz); } catch (ClassCastException exception) { throw new ClassCastException("Generic argument [" + genargs[count].name + "]" + - " is not a sub class of [" + args[count].name + "] in the constructor" + - " [" + name + " ] from the struct [" + owner.name + "]."); + " is not a sub class of [" + args[count].name + "] in the constructor" + + " [" + name + " ] from the struct [" + owner.name + "]."); } } @@ -1277,12 +1603,12 @@ class Definition { reflect = owner.clazz.getConstructor(classes); } catch (NoSuchMethodException exception) { throw new IllegalArgumentException("Constructor [" + name + "] not found for class" + - " [" + owner.clazz.getName() + "] with arguments " + Arrays.toString(classes) + "."); + " [" + owner.clazz.getName() + "] with arguments " + Arrays.toString(classes) + "."); } final org.objectweb.asm.commons.Method asm = org.objectweb.asm.commons.Method.getMethod(reflect); final Constructor constructor = - new Constructor(name, owner, Arrays.asList(genargs != null ? genargs : args), asm, reflect); + new Constructor(name, owner, Arrays.asList(genargs != null ? genargs : args), asm, reflect); owner.constructors.put(name, constructor); } @@ -1293,37 +1619,37 @@ class Definition { if (owner == null) { throw new IllegalArgumentException("Owner struct [" + struct + "] not defined" + - " for " + (statik ? "function" : "method") + " [" + name + "]."); + " for " + (statik ? "function" : "method") + " [" + name + "]."); } if (!name.matches("^[_a-zA-Z][_a-zA-Z0-9]*$")) { throw new IllegalArgumentException("Invalid " + (statik ? "function" : "method") + - " name [" + name + "] with the struct [" + owner.name + "]."); + " name [" + name + "] with the struct [" + owner.name + "]."); } if (owner.constructors.containsKey(name)) { throw new IllegalArgumentException("Constructors and " + (statik ? "functions" : "methods") + - " may not have the same name [" + name + "] within the same struct" + - " [" + owner.name + "]."); + " may not have the same name [" + name + "] within the same struct" + + " [" + owner.name + "]."); } if (owner.statics.containsKey(name)) { if (statik) { throw new IllegalArgumentException( - "Duplicate function name [" + name + "] found within the struct [" + owner.name + "]."); + "Duplicate function name [" + name + "] found within the struct [" + owner.name + "]."); } else { throw new IllegalArgumentException("Functions and methods may not have the same name" + - " [" + name + "] within the same struct [" + owner.name + "]."); + " [" + name + "] within the same struct [" + owner.name + "]."); } } if (owner.methods.containsKey(name)) { if (statik) { throw new IllegalArgumentException("Functions and methods may not have the same name" + - " [" + name + "] within the same struct [" + owner.name + "]."); + " [" + name + "] within the same struct [" + owner.name + "]."); } else { throw new IllegalArgumentException("Duplicate method name [" + name + "]" + - " found within the struct [" + owner.name + "]."); + " found within the struct [" + owner.name + "]."); } } @@ -1332,15 +1658,15 @@ class Definition { genrtn.clazz.asSubclass(rtn.clazz); } catch (ClassCastException exception) { throw new ClassCastException("Generic return [" + genrtn.clazz.getCanonicalName() + "]" + - " is not a sub class of [" + rtn.clazz.getCanonicalName() + "] in the method" + - " [" + name + " ] from the struct [" + owner.name + "]."); + " is not a sub class of [" + rtn.clazz.getCanonicalName() + "] in the method" + + " [" + name + " ] from the struct [" + owner.name + "]."); } } if (genargs != null && genargs.length != args.length) { throw new IllegalArgumentException("Generic arguments arity [" + genargs.length + "] is not the same as " + - (statik ? "function" : "method") + " [" + name + "] arguments arity" + - " [" + args.length + "] within the struct [" + owner.name + "]."); + (statik ? "function" : "method") + " [" + name + "] arguments arity" + + " [" + args.length + "] within the struct [" + owner.name + "]."); } final Class[] classes = new Class[args.length]; @@ -1351,8 +1677,8 @@ class Definition { genargs[count].clazz.asSubclass(args[count].clazz); } catch (ClassCastException exception) { throw new ClassCastException("Generic argument [" + genargs[count].name + "] is not a sub class" + - " of [" + args[count].name + "] in the " + (statik ? "function" : "method") + - " [" + name + " ] from the struct [" + owner.name + "]."); + " of [" + args[count].name + "] in the " + (statik ? "function" : "method") + + " [" + name + " ] from the struct [" + owner.name + "]."); } } @@ -1365,15 +1691,15 @@ class Definition { reflect = owner.clazz.getMethod(alias == null ? name : alias, classes); } catch (NoSuchMethodException exception) { throw new IllegalArgumentException((statik ? "Function" : "Method") + - " [" + (alias == null ? name : alias) + "] not found for class [" + owner.clazz.getName() + "]" + - " with arguments " + Arrays.toString(classes) + "."); + " [" + (alias == null ? name : alias) + "] not found for class [" + owner.clazz.getName() + "]" + + " with arguments " + Arrays.toString(classes) + "."); } if (!reflect.getReturnType().equals(rtn.clazz)) { throw new IllegalArgumentException("Specified return type class [" + rtn.clazz + "]" + - " does not match the found return type class [" + reflect.getReturnType() + "] for the " + - (statik ? "function" : "method") + " [" + name + "]" + - " within the struct [" + owner.name + "]."); + " does not match the found return type class [" + reflect.getReturnType() + "] for the " + + (statik ? "function" : "method") + " [" + name + "]" + + " within the struct [" + owner.name + "]."); } final org.objectweb.asm.commons.Method asm = org.objectweb.asm.commons.Method.getMethod(reflect); @@ -1383,32 +1709,32 @@ class Definition { try { if (statik) { handle = MethodHandles.publicLookup().in(owner.clazz).findStatic( - owner.clazz, alias == null ? name : alias, MethodType.methodType(rtn.clazz, classes)); + owner.clazz, alias == null ? name : alias, MethodType.methodType(rtn.clazz, classes)); } else { handle = MethodHandles.publicLookup().in(owner.clazz).findVirtual( - owner.clazz, alias == null ? name : alias, MethodType.methodType(rtn.clazz, classes)); + owner.clazz, alias == null ? name : alias, MethodType.methodType(rtn.clazz, classes)); } } catch (NoSuchMethodException | IllegalAccessException exception) { throw new IllegalArgumentException("Method [" + (alias == null ? name : alias) + "]" + - " not found for class [" + owner.clazz.getName() + "]" + - " with arguments " + Arrays.toString(classes) + "."); + " not found for class [" + owner.clazz.getName() + "]" + + " with arguments " + Arrays.toString(classes) + "."); } final Method method = new Method(name, owner, genrtn != null ? genrtn : rtn, - Arrays.asList(genargs != null ? genargs : args), asm, reflect, handle); + Arrays.asList(genargs != null ? genargs : args), asm, reflect, handle); final int modifiers = reflect.getModifiers(); if (statik) { if (!java.lang.reflect.Modifier.isStatic(modifiers)) { throw new IllegalArgumentException("Function [" + name + "]" + - " within the struct [" + owner.name + "] is not linked to a static Java method."); + " within the struct [" + owner.name + "] is not linked to a static Java method."); } owner.functions.put(name, method); } else { if (java.lang.reflect.Modifier.isStatic(modifiers)) { throw new IllegalArgumentException("Method [" + name + "]" + - " within the struct [" + owner.name + "] is not linked to a non-static Java method."); + " within the struct [" + owner.name + "] is not linked to a non-static Java method."); } owner.methods.put(name, method); @@ -1421,31 +1747,31 @@ class Definition { if (owner == null) { throw new IllegalArgumentException("Owner struct [" + struct + "] not defined for " + - (statik ? "static" : "member") + " [" + name + "]."); + (statik ? "static" : "member") + " [" + name + "]."); } if (!name.matches("^[_a-zA-Z][_a-zA-Z0-9]*$")) { throw new IllegalArgumentException("Invalid " + (statik ? "static" : "member") + - " name [" + name + "] with the struct [" + owner.name + "]."); + " name [" + name + "] with the struct [" + owner.name + "]."); } if (owner.statics.containsKey(name)) { if (statik) { throw new IllegalArgumentException("Duplicate static name [" + name + "]" + - " found within the struct [" + owner.name + "]."); + " found within the struct [" + owner.name + "]."); } else { throw new IllegalArgumentException("Statics and members may not have the same name " + - "[" + name + "] within the same struct [" + owner.name + "]."); + "[" + name + "] within the same struct [" + owner.name + "]."); } } if (owner.members.containsKey(name)) { if (statik) { throw new IllegalArgumentException("Statics and members may not have the same name " + - "[" + name + "] within the same struct [" + owner.name + "]."); + "[" + name + "] within the same struct [" + owner.name + "]."); } else { throw new IllegalArgumentException("Duplicate member name [" + name + "]" + - " found within the struct [" + owner.name + "]."); + " found within the struct [" + owner.name + "]."); } } @@ -1454,8 +1780,8 @@ class Definition { generic.clazz.asSubclass(type.clazz); } catch (ClassCastException exception) { throw new ClassCastException("Generic type [" + generic.clazz.getCanonicalName() + "]" + - " is not a sub class of [" + type.clazz.getCanonicalName() + "] for the field" + - " [" + name + " ] from the struct [" + owner.name + "]."); + " is not a sub class of [" + type.clazz.getCanonicalName() + "] for the field" + + " [" + name + " ] from the struct [" + owner.name + "]."); } } @@ -1465,7 +1791,7 @@ class Definition { reflect = owner.clazz.getField(alias == null ? name : alias); } catch (NoSuchFieldException exception) { throw new IllegalArgumentException("Field [" + (alias == null ? name : alias) + "]" + - " not found for class [" + owner.clazz.getName() + "]."); + " not found for class [" + owner.clazz.getName() + "]."); } MethodHandle getter = null; @@ -1474,13 +1800,13 @@ class Definition { try { if (!statik) { getter = MethodHandles.publicLookup().in(owner.clazz).findGetter( - owner.clazz, alias == null ? name : alias, type.clazz); + owner.clazz, alias == null ? name : alias, type.clazz); setter = MethodHandles.publicLookup().in(owner.clazz).findSetter( - owner.clazz, alias == null ? name : alias, type.clazz); + owner.clazz, alias == null ? name : alias, type.clazz); } } catch (NoSuchFieldException | IllegalAccessException exception) { throw new IllegalArgumentException("Getter/Setter [" + (alias == null ? name : alias) + "]" + - " not found for class [" + owner.clazz.getName() + "]."); + " not found for class [" + owner.clazz.getName() + "]."); } final Field field = new Field(name, owner, generic == null ? type : generic, type, reflect, getter, setter); @@ -1493,14 +1819,14 @@ class Definition { if (!java.lang.reflect.Modifier.isFinal(modifiers)) { throw new IllegalArgumentException("Static [" + name + "]" + - " within the struct [" + owner.name + "] is not linked to static Java field."); + " within the struct [" + owner.name + "] is not linked to static Java field."); } owner.statics.put(alias == null ? name : alias, field); } else { if (java.lang.reflect.Modifier.isStatic(modifiers)) { throw new IllegalArgumentException("Member [" + name + "]" + - " within the struct [" + owner.name + "] is not linked to non-static Java field."); + " within the struct [" + owner.name + "] is not linked to non-static Java field."); } owner.members.put(alias == null ? name : alias, field); @@ -1519,18 +1845,18 @@ class Definition { if (struct == null) { throw new IllegalArgumentException("Child struct [" + children[count] + "]" + - " not defined for copy to owner struct [" + owner.name + "]."); + " not defined for copy to owner struct [" + owner.name + "]."); } try { owner.clazz.asSubclass(child.clazz); } catch (ClassCastException exception) { throw new ClassCastException("Child struct [" + child.name + "]" + - " is not a super type of owner struct [" + owner.name + "] in copy."); + " is not a super type of owner struct [" + owner.name + "] in copy."); } final boolean object = child.clazz.equals(Object.class) && - java.lang.reflect.Modifier.isInterface(owner.clazz.getModifiers()); + java.lang.reflect.Modifier.isInterface(owner.clazz.getModifiers()); for (final Method method : child.methods.values()) { if (owner.methods.get(method.name) == null) { @@ -1543,22 +1869,22 @@ class Definition { reflect = clazz.getMethod(method.method.getName(), method.reflect.getParameterTypes()); } catch (NoSuchMethodException exception) { throw new IllegalArgumentException("Method [" + method.method.getName() + "] not found for" + - " class [" + owner.clazz.getName() + "] with arguments " + - Arrays.toString(method.reflect.getParameterTypes()) + "."); + " class [" + owner.clazz.getName() + "] with arguments " + + Arrays.toString(method.reflect.getParameterTypes()) + "."); } try { handle = MethodHandles.publicLookup().in(owner.clazz).findVirtual( - owner.clazz, method.method.getName(), - MethodType.methodType(method.reflect.getReturnType(), method.reflect.getParameterTypes())); + owner.clazz, method.method.getName(), + MethodType.methodType(method.reflect.getReturnType(), method.reflect.getParameterTypes())); } catch (NoSuchMethodException | IllegalAccessException exception) { throw new IllegalArgumentException("Method [" + method.method.getName() + "] not found for" + - " class [" + owner.clazz.getName() + "] with arguments " + - Arrays.toString(method.reflect.getParameterTypes()) + "."); + " class [" + owner.clazz.getName() + "] with arguments " + + Arrays.toString(method.reflect.getParameterTypes()) + "."); } owner.methods.put(method.name, - new Method(method.name, owner, method.rtn, method.arguments, method.method, reflect, handle)); + new Method(method.name, owner, method.rtn, method.arguments, method.method, reflect, handle)); } } @@ -1572,21 +1898,21 @@ class Definition { reflect = owner.clazz.getField(field.reflect.getName()); } catch (NoSuchFieldException exception) { throw new IllegalArgumentException("Field [" + field.reflect.getName() + "]" + - " not found for class [" + owner.clazz.getName() + "]."); + " not found for class [" + owner.clazz.getName() + "]."); } try { getter = MethodHandles.publicLookup().in(owner.clazz).findGetter( - owner.clazz, field.name, field.type.clazz); + owner.clazz, field.name, field.type.clazz); setter = MethodHandles.publicLookup().in(owner.clazz).findSetter( - owner.clazz, field.name, field.type.clazz); + owner.clazz, field.name, field.type.clazz); } catch (NoSuchFieldException | IllegalAccessException exception) { throw new IllegalArgumentException("Getter/Setter [" + field.name + "]" + - " not found for class [" + owner.clazz.getName() + "]."); + " not found for class [" + owner.clazz.getName() + "]."); } owner.members.put(field.name, - new Field(field.name, owner, field.type, field.generic, reflect, getter, setter)); + new Field(field.name, owner, field.type, field.generic, reflect, getter, setter)); } } } @@ -1598,19 +1924,19 @@ class Definition { if (owner == null) { throw new IllegalArgumentException("Owner struct [" + struct + "] not defined for" + - " transform with cast type from [" + from.name + "] and cast type to [" + to.name + "]."); + " transform with cast type from [" + from.name + "] and cast type to [" + to.name + "]."); } if (from.equals(to)) { throw new IllegalArgumentException("Transform with owner struct [" + owner.name + "] cannot" + - " have cast type from [" + from.name + "] be the same as cast type to [" + to.name + "]."); + " have cast type from [" + from.name + "] be the same as cast type to [" + to.name + "]."); } final Cast cast = new Cast(from, to); if (transforms.containsKey(cast)) { throw new IllegalArgumentException("Transform with owner struct [" + owner.name + "]" + - " and cast type from [" + from.name + "] to cast type to [" + to.name + "] already defined."); + " and cast type from [" + from.name + "] to cast type to [" + to.name + "] already defined."); } Method method; @@ -1622,14 +1948,14 @@ class Definition { if (method == null) { throw new IllegalArgumentException("Transform with owner struct [" + owner.name + "]" + - " and cast type from [" + from.name + "] to cast type to [" + to.name + - "] using a function [" + name + "] that is not defined."); + " and cast type from [" + from.name + "] to cast type to [" + to.name + + "] using a function [" + name + "] that is not defined."); } if (method.arguments.size() != 1) { throw new IllegalArgumentException("Transform with owner struct [" + owner.name + "]" + - " and cast type from [" + from.name + "] to cast type to [" + to.name + - "] using function [" + name + "] does not have a single type argument."); + " and cast type from [" + from.name + "] to cast type to [" + to.name + + "] using function [" + name + "] does not have a single type argument."); } Type argument = method.arguments.get(0); @@ -1642,8 +1968,8 @@ class Definition { upcast = argument; } catch (ClassCastException cce1) { throw new ClassCastException("Transform with owner struct [" + owner.name + "]" + - " and cast type from [" + from.name + "] to cast type to [" + to.name + "] using" + - " function [" + name + "] cannot cast from type to the function input argument type."); + " and cast type from [" + from.name + "] to cast type to [" + to.name + "] using" + + " function [" + name + "] cannot cast from type to the function input argument type."); } } @@ -1657,8 +1983,8 @@ class Definition { downcast = to; } catch (ClassCastException cce1) { throw new ClassCastException("Transform with owner struct [" + owner.name + "]" + - " and cast type from [" + from.name + "] to cast type to [" + to.name + "] using" + - " function [" + name + "] cannot cast to type to the function return argument type."); + " and cast type from [" + from.name + "] to cast type to [" + to.name + "] using" + + " function [" + name + "] cannot cast to type to the function return argument type."); } } } else { @@ -1666,14 +1992,14 @@ class Definition { if (method == null) { throw new IllegalArgumentException("Transform with owner struct [" + owner.name + "]" + - " and cast type from [" + from.name + "] to cast type to [" + to.name + - "] using a method [" + name + "] that is not defined."); + " and cast type from [" + from.name + "] to cast type to [" + to.name + + "] using a method [" + name + "] that is not defined."); } if (!method.arguments.isEmpty()) { throw new IllegalArgumentException("Transform with owner struct [" + owner.name + "]" + - " and cast type from [" + from.name + "] to cast type to [" + to.name + - "] using method [" + name + "] does not have a single type argument."); + " and cast type from [" + from.name + "] to cast type to [" + to.name + + "] using method [" + name + "] does not have a single type argument."); } try { @@ -1684,8 +2010,8 @@ class Definition { upcast = getType(owner.name); } catch (ClassCastException cce1) { throw new ClassCastException("Transform with owner struct [" + owner.name + "]" + - " and cast type from [" + from.name + "] to cast type to [" + to.name + "] using" + - " method [" + name + "] cannot cast from type to the method input argument type."); + " and cast type from [" + from.name + "] to cast type to [" + to.name + "] using" + + " method [" + name + "] cannot cast from type to the method input argument type."); } } @@ -1699,8 +2025,8 @@ class Definition { downcast = to; } catch (ClassCastException cce1) { throw new ClassCastException("Transform with owner struct [" + owner.name + "]" + - " and cast type from [" + from.name + "] to cast type to [" + to.name + "]" + - " using method [" + name + "] cannot cast to type to the method return argument type."); + " and cast type from [" + from.name + "] to cast type to [" + to.name + "]" + + " using method [" + name + "] cannot cast to type to the method return argument type."); } } } @@ -1715,12 +2041,12 @@ class Definition { if (bounds.containsKey(pair0)) { throw new IllegalArgumentException( - "Bound already defined for types [" + type0.name + "] and [" + type1.name + "]."); + "Bound already defined for types [" + type0.name + "] and [" + type1.name + "]."); } if (bounds.containsKey(pair1)) { throw new IllegalArgumentException( - "Bound already defined for types [" + type1.name + "] and [" + type0.name + "]."); + "Bound already defined for types [" + type1.name + "] and [" + type0.name + "]."); } bounds.put(pair0, bound); @@ -1763,7 +2089,7 @@ class Definition { clazz = Class.forName(type.getInternalName().replace('/', '.')); } catch (ClassNotFoundException exception) { throw new IllegalArgumentException("The class [" + type.getInternalName() + "]" + - " could not be found to create type [" + name + "]."); + " could not be found to create type [" + name + "]."); } sort = Sort.ARRAY; diff --git a/plugins/lang-plan-a/src/main/java/org/elasticsearch/plan/a/ErrorHandlingLexer.java b/plugins/lang-plan-a/src/main/java/org/elasticsearch/plan/a/ErrorHandlingLexer.java index 4963815f470..768b0aea2ec 100644 --- a/plugins/lang-plan-a/src/main/java/org/elasticsearch/plan/a/ErrorHandlingLexer.java +++ b/plugins/lang-plan-a/src/main/java/org/elasticsearch/plan/a/ErrorHandlingLexer.java @@ -1,5 +1,3 @@ -package org.elasticsearch.plan.a; - /* * Licensed to Elasticsearch under one or more contributor * license agreements. See the NOTICE file distributed with @@ -19,6 +17,8 @@ package org.elasticsearch.plan.a; * under the License. */ +package org.elasticsearch.plan.a; + import org.antlr.v4.runtime.CharStream; import org.antlr.v4.runtime.LexerNoViableAltException; import org.antlr.v4.runtime.misc.Interval; diff --git a/plugins/lang-plan-a/src/main/java/org/elasticsearch/plan/a/Metadata.java b/plugins/lang-plan-a/src/main/java/org/elasticsearch/plan/a/Metadata.java new file mode 100644 index 00000000000..221b951497f --- /dev/null +++ b/plugins/lang-plan-a/src/main/java/org/elasticsearch/plan/a/Metadata.java @@ -0,0 +1,619 @@ +/* + * 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. + */ + +package org.elasticsearch.plan.a; + +import org.antlr.v4.runtime.ParserRuleContext; +import org.antlr.v4.runtime.tree.ParseTree; +import org.elasticsearch.plan.a.Definition.Cast; +import org.elasticsearch.plan.a.Definition.Type; +import org.elasticsearch.plan.a.PlanAParser.ExpressionContext; +import org.elasticsearch.plan.a.PlanAParser.PrecedenceContext; + +import java.util.HashMap; +import java.util.Map; + +/** + * Metadata is a wrapper for all the data that is collected by the {@link Analyzer}. Each node in the ANTLR parse tree + * will have one of the types of metadata to store information used either in a different node by the analyzer + * or by the {@link Writer} during byte code generation. Metadata also contains several objects passed into the + * {@link Analyzer} and {@link Writer} used during compilation including the {@link Definition}, the source code, + * the root of the ANTLR parse tree, and the {@link CompilerSettings}. + */ +class Metadata { + + /** + * StatementMetadata is used to store metadata mostly about + * control flow for ANTLR nodes related to if/else, do, while, for, etc. + */ + static class StatementMetadata { + /** + * The source variable is the ANTLR node used to generate this metadata. + */ + final ParserRuleContext source; + + /** + * The lastSource variable will be set to true when the final statement from the root ANTLR node is about + * to be visited. This is used to determine whether or not the auto-return feature is allowed to be used, + * and if a null return value needs to be generated automatically since a return value is always required. + */ + boolean lastSource = false; + + /** + * The beginLoop variable will be set to true whenever a loop node is initially visited including inner + * loops. This will not be propagated down the parse tree afterwards, though. This is used to determine + * whether or not inLoop should be set further down the tree. Note that inLoop alone is not enough + * information to determine whether we are in the last statement of a loop because we may inside of + * multiple loops, so this variable is necessary. + */ + boolean beginLoop = false; + + /** + * The inLoop variable is set to true when inside a loop. This will be propagated down the parse tree. This + * is used to determine whether or not continue and break statements are legal. + */ + boolean inLoop = false; + + /** + * The lastLoop variable is set to true when the final statement of a loop is reached. This will be + * propagated down the parse tree until another loop is reached and then will not be propagated further for + * the current loop. This is used to determine whether or not a continue statement is superfluous. + */ + boolean lastLoop = false; + + /** + * The methodEscape variable is set to true when a statement would cause the method to potentially exit. This + * includes return, throw, and continuous loop statements. Note that a catch statement may possibly + * reset this to false after a throw statement. This will be propagated up the tree as far as necessary. + * This is used by the {@link Writer} to ensure that superfluous statements aren't unnecessarily written + * into generated bytecode. + */ + boolean methodEscape = false; + + /** + * The loopEscape variable is set to true when a loop is going to be exited. This may be caused by a number of + * different statements including continue, break, return, etc. This will only be propagated as far as the + * loop node. This is used to ensure that in certain case an infinite loop will be caught at + * compile-time rather than run-time. + */ + boolean loopEscape = false; + + /** + * The allLast variable is set whenever a final statement in a block is reached. This includes the end of loop, + * if, else, etc. This will be only propagated to the top of the block statement ANTLR node. + * This is used to ensure that there are no unreachable statements within the script. + */ + boolean allLast = false; + + /** + * The anyContinue will be set to true when a continue statement is visited. This will be propagated to the + * loop node it's within. This is used to ensure that in certain case an infinite loop will be caught at + * compile-time rather than run-time. + */ + boolean anyContinue = false; + + /** + * The anyBreak will be set to true when a break statement is visited. This will be propagated to the + * loop node it's within. This is used to in conjunction with methodEscape to ensure there are no unreachable + * statements within the script. + */ + boolean anyBreak = false; + + /** + * The count variable is used as a rudimentary count of statements within a loop. This will be used in + * the {@link Writer} to keep a count of statements that have been executed at run-time to ensure that a loop + * will exit if it runs too long. + */ + int count = 0; + + /** + * The exception variable is used to store the exception type when a throw node is visited. This is used by + * the {@link Writer} to write the correct type of exception in the generated byte code. + */ + Type exception = null; + + /** + * The slot variable is used to store the place on the stack of where a thrown exception will be stored to. + * This is used by the {@link Writer}. + */ + int slot = -1; + + /** + * Constructor. + * @param source The associated ANTLR node. + */ + private StatementMetadata(final ParserRuleContext source) { + this.source = source; + } + } + + /** + * ExpressionMetadata is used to store metadata mostly about constants and casting + * for ANTLR nodes related to mathematical operations. + */ + static class ExpressionMetadata { + /** + * The source variable is the ANTLR node used to generate this metadata. + */ + final ParserRuleContext source; + + /** + * The read variable is used to determine whether or not the value of an expression will be read from. + * This is set to false when the expression is the left-hand side of an assignment that is not chained or + * when a method call is made alone. This will propagate down the tree as far as necessary. + * The {@link Writer} uses this to determine when a value may need to be popped from the stack + * such as when a method call returns a value that is never read. + */ + boolean read = true; + + /** + * The statement variable is set true when an expression is a complete meaning that there is some sort + * of effect on a variable or a method call is made. This will propagate up the tree as far as necessary. + * This prevents statements that have no effect on the output of a script from being executed. + */ + boolean statement = false; + + /** + * The preConst variable is set to a non-null value when a constant statement is made in a script. This is + * used to track the constant value prior to any casts being made on an ANTLR node. + */ + Object preConst = null; + + /** + * The postConst variable is set to a non-null value when a cast is made on a node where a preConst variable + * has already been set when the cast would leave the constant as a non-object value except in the case of a + * String. This will be propagated up the tree and used to simplify constants when possible such as making + * the value of 2*2 be 4 in the * node, so that the {@link Writer} only has to push a 4 onto the stack. + */ + Object postConst = null; + + /** + * The isNull variable is set to true when a null constant statement is made in the script. This allows the + * {@link Writer} to potentially shortcut certain comparison operations. + */ + boolean isNull = false; + + /** + * The to variable is used to track what an ANTLR node's value should be cast to. This is set on every ANTLR + * node in the tree, and used by the {@link Writer} to make a run-time cast if necessary in the byte code. + * This is also used by the {@link Analyzer} to determine if a cast is legal. + */ + Type to = null; + + /** + * The from variable is used to track what an ANTLR node's value should be cast from. This is set on every + * ANTLR node in the tree independent of other nodes. This is used by the {@link Analyzer} to determine if a + * cast is legal. + */ + Type from = null; + + /** + * The explicit variable is set to true when a cast is explicitly made in the script. This tracks whether + * or not a cast is a legal up cast. + */ + boolean explicit = false; + + /** + * The typesafe variable is set to true when a dynamic type is used as part of an expression. This propagates + * up the tree to the top of the expression. This allows for implicit up casts throughout the expression and + * is used by the {@link Analyzer}. + */ + boolean typesafe = true; + + /** + * This is set to the combination of the to and from variables at the end of each node visit in the + * {@link Analyzer}. This is set on every ANTLR node in the tree independent of other nodes, and is + * used by {@link Writer} to make a run-time cast if necessary in the byte code. + */ + Cast cast = null; + + /** + * Constructor. + * @param source The associated ANTLR node. + */ + private ExpressionMetadata(final ParserRuleContext source) { + this.source = source; + } + } + + /** + * ExternalMetadata is used to store metadata about the overall state of a variable/method chain such as + * '(int)x.get(3)' where each piece of that chain is broken into it's indiviual pieces and stored in + * {@link ExtNodeMetadata}. + */ + static class ExternalMetadata { + /** + * The source variable is the ANTLR node used to generate this metadata. + */ + final ParserRuleContext source; + + /** + * The read variable is set to true when the value of a variable/method chain is going to be read from. + * This is used by the {@link Analyzer} to determine if this variable/method chain will be in a standalone + * statement. + */ + boolean read = false; + + /** + * The storeExpr variable is set to the right-hand side of an assignment in the variable/method chain if + * necessary. This is used by the {@link Analyzer} to set the proper metadata for a read versus a write, + * and is used by the {@link Writer} to determine if a bytecode operation should be a load or a store. + */ + ParserRuleContext storeExpr = null; + + /** + * The token variable is set to a constant value of the operator type (+, -, etc.) when a compound assignment + * is being visited. This is also used by the increment and decrement operators. This is used by both the + * {@link Analyzer} and {@link Writer} to correctly handle the compound assignment. + */ + int token = 0; + + /** + * The pre variable is set to true when pre-increment or pre-decrement is visited. This is used by both the + * {@link Analyzer} and {@link Writer} to correctly handle any reads of the variable/method chain that are + * necessary. + */ + boolean pre = false; + + /** + * The post variable is set to true when post-increment or post-decrement is visited. This is used by both the + * {@link Analyzer} and {@link Writer} to correctly handle any reads of the variable/method chain that are + * necessary. + */ + boolean post = false; + + /** + * The scope variable is incremented and decremented when a precedence node is visited as part of a + * variable/method chain. This is used by the {@link Analyzer} to determine when the final piece of the + * variable/method chain has been reached. + */ + int scope = 0; + + /** + * The current variable is set to whatever the current type is within the visited node of the variable/method + * chain. This changes as the nodes for the variable/method are walked through. This is used by the + * {@link Analyzer} to make decisions about whether or not a cast is legal, and what methods are available + * for that specific type. + */ + Type current = null; + + /** + * The statik variable is set to true when a variable/method chain begins with static type. This is used by + * the {@link Analyzer} to determine what methods/members are available for that specific type. + */ + boolean statik = false; + + /** + * The statement variable is set to true when a variable/method chain can be standalone statement. This is + * used by the {@link Analyzer} to error out if there a variable/method chain that is not a statement. + */ + boolean statement = false; + + /** + * The constant variable is set when a String constant is part of the variable/method chain. String is a + * special case because methods/members need to be able to be called on a String constant, so this can't be + * only as part of {@link ExpressionMetadata}. This is used by the {@link Writer} to write out the String + * constant in the byte code. + */ + Object constant = null; + + /** + * Constructor. + * @param source The associated ANTLR node. + */ + private ExternalMetadata(final ParserRuleContext source) { + this.source = source; + } + } + + static class ExtNodeMetadata { + /** + * The parent variable is top-level ANTLR node of the variable/method chain. This is used to retrieve the + * ExternalMetadata for the variable/method chain this ExtNodeMetadata is a piece of. + */ + final ParserRuleContext parent; + + /** + * The source variable is the ANTLR node used to generate this metadata. + */ + final ParserRuleContext source; + + /** + * The target variable is set to a value based on the type of ANTLR node that is visited. This is used by + * {@link Writer} to determine whether a cast, store, load, or method call should be written in byte code + * depending on what the target variable is. + */ + Object target = null; + + /** + * The last variable is set to true when the last ANTLR node of the variable/method chain is visted. This is + * used by the {@link Writer} in conjuction with the storeExpr variable to determine whether or not a store + * needs to be written as opposed to a load. + */ + boolean last = false; + + /** + * The type variable is set to the type that a visited node ends with. This is used by both the + * {@link Analyzer} and {@link Writer} to make decisions about compound assignments, String constants, and + * shortcuts. + */ + Type type = null; + + /** + * The promote variable is set to the type of a promotion within a compound assignment. Compound assignments + * may require promotion between the left-hand side variable and right-hand side value. This is used by the + * {@link Writer} to make the correct decision about the byte code operation. + */ + Type promote = null; + + /** + * The castFrom variable is set during a compound assignment. This is used by the {@link Writer} to + * cast the values to the promoted type during a compound assignment. + */ + Cast castFrom = null; + + /** + * The castTo variable is set during an explicit cast in a variable/method chain or during a compound + * assignment. This is used by the {@link Writer} to either do an explicit cast, or cast the values + * from the promoted type back to the original type during a compound assignment. + */ + Cast castTo = null; + + /** + * Constructor. + * @param parent The top-level ANTLR node for the variable/method chain. + * @param source The associated ANTLR node. + */ + private ExtNodeMetadata(final ParserRuleContext parent, final ParserRuleContext source) { + this.parent = parent; + this.source = source; + } + } + + /** + * A utility method to output consistent error messages. + * @param ctx The ANTLR node the error occurred in. + * @return The error message with tacked on line number and character position. + */ + static String error(final ParserRuleContext ctx) { + return "Error [" + ctx.getStart().getLine() + ":" + ctx.getStart().getCharPositionInLine() + "]: "; + } + + /** + * Acts as both the Plan A API and white-list for what types and methods are allowed. + */ + final Definition definition; + + /** + * The original text of the input script. This is used to write out the source code into + * the byte code file for debugging purposes. + */ + final String source; + + /** + * Toot node of the ANTLR tree for the Plan A script. + */ + final ParserRuleContext root; + + /** + * Used to determine certain compile-time constraints such as whether or not numeric overflow is allowed + * and how many statements are allowed before a loop will throw an exception. + */ + final CompilerSettings settings; + + /** + * Used to determine what slot the input variable is stored in. This is used in the {@link Writer} whenever + * the input variable is accessed. + */ + int inputValueSlot = -1; + + /** + * Used to determine what slot the score variable is stored in. This is used in the {@link Writer} whenever + * the score variable is accessed. + */ + int scoreValueSlot = -1; + + /** + * Used to determine what slot the loopCounter variable is stored in. This is used n the {@link Writer} whenever + * the loop variable is accessed. + */ + int loopCounterSlot = -1; + + /** + * Maps the relevant ANTLR node to its metadata. + */ + private final Map statementMetadata = new HashMap<>(); + + /** + * Maps the relevant ANTLR node to its metadata. + */ + private final Map expressionMetadata = new HashMap<>(); + + /** + * Maps the relevant ANTLR node to its metadata. + */ + private final Map externalMetadata = new HashMap<>(); + + /** + * Maps the relevant ANTLR node to its metadata. + */ + private final Map extNodeMetadata = new HashMap<>(); + + /** + * Constructor. + * @param definition The Plan A definition. + * @param source The source text for the script. + * @param root The root ANTLR node. + * @param settings The compile-time settings. + */ + Metadata(final Definition definition, final String source, final ParserRuleContext root, final CompilerSettings settings) { + this.definition = definition; + this.source = source; + this.root = root; + this.settings = settings; + } + + /** + * Creates a new StatementMetadata and stores it in the statementMetadata map. + * @param source The ANTLR node for this metadata. + * @return The new StatementMetadata. + */ + StatementMetadata createStatementMetadata(final ParserRuleContext source) { + final StatementMetadata sourcesmd = new StatementMetadata(source); + statementMetadata.put(source, sourcesmd); + + return sourcesmd; + } + + /** + * Retrieves StatementMetadata from the statementMetadata map. + * @param source The ANTLR node for this metadata. + * @return The retrieved StatementMetadata. + */ + StatementMetadata getStatementMetadata(final ParserRuleContext source) { + final StatementMetadata sourcesmd = statementMetadata.get(source); + + if (sourcesmd == null) { + throw new IllegalStateException(error(source) + "Statement metadata does not exist at" + + " the parse node with text [" + source.getText() + "]."); + } + + return sourcesmd; + } + + /** + * The ANTLR parse tree is modified in one single case; a parent node needs to check a child node to see if it's + * a precedence node, and if so, it must be removed from the tree permanently. Once the ANTLR tree is built, + * precedence nodes are no longer necessary to maintain the correct ordering of the tree, so they only + * add a level of indirection where complicated decisions about metadata passing would have to be made. This + * method removes the need for those decisions. + * @param source The child ANTLR node to check for precedence. + * @return The updated child ANTLR node. + */ + ExpressionContext updateExpressionTree(ExpressionContext source) { + // Check to see if the ANTLR node is a precedence node. + if (source instanceof PrecedenceContext) { + final ParserRuleContext parent = source.getParent(); + int index = 0; + + // Mark the index of the source node within the list of child nodes from the parent. + for (final ParseTree child : parent.children) { + if (child == source) { + break; + } + + ++index; + } + + // If there are multiple precedence nodes in a row, remove them all. + while (source instanceof PrecedenceContext) { + source = ((PrecedenceContext)source).expression(); + } + + // Update the parent node with the child of the precedence node. + parent.children.set(index, source); + } + + return source; + } + + /** + * Creates a new ExpressionMetadata and stores it in the expressionMetadata map. + * @param source The ANTLR node for this metadata. + * @return The new ExpressionMetadata. + */ + ExpressionMetadata createExpressionMetadata(ParserRuleContext source) { + final ExpressionMetadata sourceemd = new ExpressionMetadata(source); + expressionMetadata.put(source, sourceemd); + + return sourceemd; + } + + /** + * Retrieves ExpressionMetadata from the expressionMetadata map. + * @param source The ANTLR node for this metadata. + * @return The retrieved ExpressionMetadata. + */ + ExpressionMetadata getExpressionMetadata(final ParserRuleContext source) { + final ExpressionMetadata sourceemd = expressionMetadata.get(source); + + if (sourceemd == null) { + throw new IllegalStateException(error(source) + "Expression metadata does not exist at" + + " the parse node with text [" + source.getText() + "]."); + } + + return sourceemd; + } + + /** + * Creates a new ExternalMetadata and stores it in the externalMetadata map. + * @param source The ANTLR node for this metadata. + * @return The new ExternalMetadata. + */ + ExternalMetadata createExternalMetadata(final ParserRuleContext source) { + final ExternalMetadata sourceemd = new ExternalMetadata(source); + externalMetadata.put(source, sourceemd); + + return sourceemd; + } + + /** + * Retrieves ExternalMetadata from the externalMetadata map. + * @param source The ANTLR node for this metadata. + * @return The retrieved ExternalMetadata. + */ + ExternalMetadata getExternalMetadata(final ParserRuleContext source) { + final ExternalMetadata sourceemd = externalMetadata.get(source); + + if (sourceemd == null) { + throw new IllegalStateException(error(source) + "External metadata does not exist at" + + " the parse node with text [" + source.getText() + "]."); + } + + return sourceemd; + } + + /** + * Creates a new ExtNodeMetadata and stores it in the extNodeMetadata map. + * @param source The ANTLR node for this metadata. + * @return The new ExtNodeMetadata. + */ + ExtNodeMetadata createExtNodeMetadata(final ParserRuleContext parent, final ParserRuleContext source) { + final ExtNodeMetadata sourceemd = new ExtNodeMetadata(parent, source); + extNodeMetadata.put(source, sourceemd); + + return sourceemd; + } + + /** + * Retrieves ExtNodeMetadata from the extNodeMetadata map. + * @param source The ANTLR node for this metadata. + * @return The retrieved ExtNodeMetadata. + */ + ExtNodeMetadata getExtNodeMetadata(final ParserRuleContext source) { + final ExtNodeMetadata sourceemd = extNodeMetadata.get(source); + + if (sourceemd == null) { + throw new IllegalStateException(error(source) + "External metadata does not exist at" + + " the parse node with text [" + source.getText() + "]."); + } + + return sourceemd; + } +} diff --git a/plugins/lang-plan-a/src/main/java/org/elasticsearch/plan/a/PlanAError.java b/plugins/lang-plan-a/src/main/java/org/elasticsearch/plan/a/PlanAError.java new file mode 100644 index 00000000000..dea3c2021a8 --- /dev/null +++ b/plugins/lang-plan-a/src/main/java/org/elasticsearch/plan/a/PlanAError.java @@ -0,0 +1,37 @@ +/* + * 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. + */ + +package org.elasticsearch.plan.a; + +/** + * The PlanAError class is used to throw internal errors caused by Plan A scripts that cannot be + * caught using a standard {@link Exception}. This prevents the user from catching this specific error + * (as Exceptions are available in the Plan A API, but Errors are not,) and possibly continuing to do + * something hazardous. The alternative was extending {@link Throwable}, but that seemed worse than using + * an {@link Error} in this case. + */ +public class PlanAError extends Error { + /** + * Constructor. + * @param message The error message. + */ + public PlanAError(final String message) { + super(message); + } +} diff --git a/plugins/lang-plan-a/src/main/java/org/elasticsearch/plan/a/PlanAParser.java b/plugins/lang-plan-a/src/main/java/org/elasticsearch/plan/a/PlanAParser.java index da9943385c0..e7de571ef2e 100644 --- a/plugins/lang-plan-a/src/main/java/org/elasticsearch/plan/a/PlanAParser.java +++ b/plugins/lang-plan-a/src/main/java/org/elasticsearch/plan/a/PlanAParser.java @@ -40,17 +40,17 @@ class PlanAParser extends Parser { STRING=68, CHAR=69, TRUE=70, FALSE=71, NULL=72, TYPE=73, ID=74, EXTINTEGER=75, EXTID=76; public static final int - RULE_source = 0, RULE_statement = 1, RULE_block = 2, RULE_empty = 3, RULE_initializer = 4, - RULE_afterthought = 5, RULE_declaration = 6, RULE_decltype = 7, RULE_declvar = 8, - RULE_expression = 9, RULE_extstart = 10, RULE_extprec = 11, RULE_extcast = 12, - RULE_extbrace = 13, RULE_extdot = 14, RULE_exttype = 15, RULE_extcall = 16, - RULE_extvar = 17, RULE_extfield = 18, RULE_extnew = 19, RULE_extstring = 20, - RULE_arguments = 21, RULE_increment = 22; + RULE_source = 0, RULE_statement = 1, RULE_block = 2, RULE_empty = 3, RULE_emptyscope = 4, + RULE_initializer = 5, RULE_afterthought = 6, RULE_declaration = 7, RULE_decltype = 8, + RULE_declvar = 9, RULE_trap = 10, RULE_expression = 11, RULE_extstart = 12, + RULE_extprec = 13, RULE_extcast = 14, RULE_extbrace = 15, RULE_extdot = 16, + RULE_exttype = 17, RULE_extcall = 18, RULE_extvar = 19, RULE_extfield = 20, + RULE_extnew = 21, RULE_extstring = 22, RULE_arguments = 23, RULE_increment = 24; public static final String[] ruleNames = { - "source", "statement", "block", "empty", "initializer", "afterthought", - "declaration", "decltype", "declvar", "expression", "extstart", "extprec", - "extcast", "extbrace", "extdot", "exttype", "extcall", "extvar", "extfield", - "extnew", "extstring", "arguments", "increment" + "source", "statement", "block", "empty", "emptyscope", "initializer", + "afterthought", "declaration", "decltype", "declvar", "trap", "expression", + "extstart", "extprec", "extcast", "extbrace", "extdot", "exttype", "extcall", + "extvar", "extfield", "extnew", "extstring", "arguments", "increment" }; private static final String[] _LITERAL_NAMES = { @@ -149,21 +149,21 @@ class PlanAParser extends Parser { try { enterOuterAlt(_localctx, 1); { - setState(47); + setState(51); _errHandler.sync(this); _la = _input.LA(1); do { { { - setState(46); + setState(50); statement(); } } - setState(49); + setState(53); _errHandler.sync(this); _la = _input.LA(1); } while ( (((_la) & ~0x3f) == 0 && ((1L << _la) & ((1L << LP) | (1L << IF) | (1L << WHILE) | (1L << DO) | (1L << FOR) | (1L << CONTINUE) | (1L << BREAK) | (1L << RETURN) | (1L << NEW) | (1L << TRY) | (1L << THROW) | (1L << BOOLNOT) | (1L << BWNOT) | (1L << ADD) | (1L << SUB) | (1L << INCR) | (1L << DECR))) != 0) || ((((_la - 64)) & ~0x3f) == 0 && ((1L << (_la - 64)) & ((1L << (OCTAL - 64)) | (1L << (HEX - 64)) | (1L << (INTEGER - 64)) | (1L << (DECIMAL - 64)) | (1L << (STRING - 64)) | (1L << (CHAR - 64)) | (1L << (TRUE - 64)) | (1L << (FALSE - 64)) | (1L << (NULL - 64)) | (1L << (TYPE - 64)) | (1L << (ID - 64)))) != 0) ); - setState(51); + setState(55); match(EOF); } } @@ -266,31 +266,14 @@ class PlanAParser extends Parser { } public static class TryContext extends StatementContext { public TerminalNode TRY() { return getToken(PlanAParser.TRY, 0); } - public List block() { - return getRuleContexts(BlockContext.class); + public BlockContext block() { + return getRuleContext(BlockContext.class,0); } - public BlockContext block(int i) { - return getRuleContext(BlockContext.class,i); + public List trap() { + return getRuleContexts(TrapContext.class); } - public List CATCH() { return getTokens(PlanAParser.CATCH); } - public TerminalNode CATCH(int i) { - return getToken(PlanAParser.CATCH, i); - } - public List LP() { return getTokens(PlanAParser.LP); } - public TerminalNode LP(int i) { - return getToken(PlanAParser.LP, i); - } - public List RP() { return getTokens(PlanAParser.RP); } - public TerminalNode RP(int i) { - return getToken(PlanAParser.RP, i); - } - public List TYPE() { return getTokens(PlanAParser.TYPE); } - public TerminalNode TYPE(int i) { - return getToken(PlanAParser.TYPE, i); - } - public List ID() { return getTokens(PlanAParser.ID); } - public TerminalNode ID(int i) { - return getToken(PlanAParser.ID, i); + public TrapContext trap(int i) { + return getRuleContext(TrapContext.class,i); } public TryContext(StatementContext ctx) { copyFrom(ctx); } @Override @@ -391,29 +374,29 @@ class PlanAParser extends Parser { int _la; try { int _alt; - setState(136); + setState(134); switch ( getInterpreter().adaptivePredict(_input,15,_ctx) ) { case 1: _localctx = new IfContext(_localctx); enterOuterAlt(_localctx, 1); { - setState(53); - match(IF); - setState(54); - match(LP); - setState(55); - expression(0); - setState(56); - match(RP); setState(57); - block(); + match(IF); + setState(58); + match(LP); + setState(59); + expression(0); setState(60); + match(RP); + setState(61); + block(); + setState(64); switch ( getInterpreter().adaptivePredict(_input,1,_ctx) ) { case 1: { - setState(58); + setState(62); match(ELSE); - setState(59); + setState(63); block(); } break; @@ -424,58 +407,28 @@ class PlanAParser extends Parser { _localctx = new WhileContext(_localctx); enterOuterAlt(_localctx, 2); { - setState(62); + setState(66); match(WHILE); - setState(63); + setState(67); match(LP); - setState(64); - expression(0); - setState(65); - match(RP); setState(68); - switch (_input.LA(1)) { - case LBRACK: - case LP: - case IF: - case WHILE: - case DO: - case FOR: - case CONTINUE: - case BREAK: - case RETURN: - case NEW: - case TRY: - case THROW: - case BOOLNOT: - case BWNOT: - case ADD: - case SUB: - case INCR: - case DECR: - case OCTAL: - case HEX: - case INTEGER: - case DECIMAL: - case STRING: - case CHAR: - case TRUE: - case FALSE: - case NULL: - case TYPE: - case ID: + expression(0); + setState(69); + match(RP); + setState(72); + switch ( getInterpreter().adaptivePredict(_input,2,_ctx) ) { + case 1: { - setState(66); + setState(70); block(); } break; - case SEMICOLON: + case 2: { - setState(67); + setState(71); empty(); } break; - default: - throw new NoViableAltException(this); } } break; @@ -483,23 +436,23 @@ class PlanAParser extends Parser { _localctx = new DoContext(_localctx); enterOuterAlt(_localctx, 3); { - setState(70); - match(DO); - setState(71); - block(); - setState(72); - match(WHILE); - setState(73); - match(LP); setState(74); - expression(0); + match(DO); setState(75); - match(RP); + block(); + setState(76); + match(WHILE); setState(77); + match(LP); + setState(78); + expression(0); + setState(79); + match(RP); + setState(81); _la = _input.LA(1); if (_la==SEMICOLON) { { - setState(76); + setState(80); match(SEMICOLON); } } @@ -510,27 +463,16 @@ class PlanAParser extends Parser { _localctx = new ForContext(_localctx); enterOuterAlt(_localctx, 4); { - setState(79); + setState(83); match(FOR); - setState(80); - match(LP); - setState(82); - _la = _input.LA(1); - if ((((_la) & ~0x3f) == 0 && ((1L << _la) & ((1L << LP) | (1L << NEW) | (1L << BOOLNOT) | (1L << BWNOT) | (1L << ADD) | (1L << SUB) | (1L << INCR) | (1L << DECR))) != 0) || ((((_la - 64)) & ~0x3f) == 0 && ((1L << (_la - 64)) & ((1L << (OCTAL - 64)) | (1L << (HEX - 64)) | (1L << (INTEGER - 64)) | (1L << (DECIMAL - 64)) | (1L << (STRING - 64)) | (1L << (CHAR - 64)) | (1L << (TRUE - 64)) | (1L << (FALSE - 64)) | (1L << (NULL - 64)) | (1L << (TYPE - 64)) | (1L << (ID - 64)))) != 0)) { - { - setState(81); - initializer(); - } - } - setState(84); - match(SEMICOLON); + match(LP); setState(86); _la = _input.LA(1); if ((((_la) & ~0x3f) == 0 && ((1L << _la) & ((1L << LP) | (1L << NEW) | (1L << BOOLNOT) | (1L << BWNOT) | (1L << ADD) | (1L << SUB) | (1L << INCR) | (1L << DECR))) != 0) || ((((_la - 64)) & ~0x3f) == 0 && ((1L << (_la - 64)) & ((1L << (OCTAL - 64)) | (1L << (HEX - 64)) | (1L << (INTEGER - 64)) | (1L << (DECIMAL - 64)) | (1L << (STRING - 64)) | (1L << (CHAR - 64)) | (1L << (TRUE - 64)) | (1L << (FALSE - 64)) | (1L << (NULL - 64)) | (1L << (TYPE - 64)) | (1L << (ID - 64)))) != 0)) { { setState(85); - expression(0); + initializer(); } } @@ -541,56 +483,37 @@ class PlanAParser extends Parser { if ((((_la) & ~0x3f) == 0 && ((1L << _la) & ((1L << LP) | (1L << NEW) | (1L << BOOLNOT) | (1L << BWNOT) | (1L << ADD) | (1L << SUB) | (1L << INCR) | (1L << DECR))) != 0) || ((((_la - 64)) & ~0x3f) == 0 && ((1L << (_la - 64)) & ((1L << (OCTAL - 64)) | (1L << (HEX - 64)) | (1L << (INTEGER - 64)) | (1L << (DECIMAL - 64)) | (1L << (STRING - 64)) | (1L << (CHAR - 64)) | (1L << (TRUE - 64)) | (1L << (FALSE - 64)) | (1L << (NULL - 64)) | (1L << (TYPE - 64)) | (1L << (ID - 64)))) != 0)) { { setState(89); - afterthought(); + expression(0); } } setState(92); - match(RP); - setState(95); - switch (_input.LA(1)) { - case LBRACK: - case LP: - case IF: - case WHILE: - case DO: - case FOR: - case CONTINUE: - case BREAK: - case RETURN: - case NEW: - case TRY: - case THROW: - case BOOLNOT: - case BWNOT: - case ADD: - case SUB: - case INCR: - case DECR: - case OCTAL: - case HEX: - case INTEGER: - case DECIMAL: - case STRING: - case CHAR: - case TRUE: - case FALSE: - case NULL: - case TYPE: - case ID: + match(SEMICOLON); + setState(94); + _la = _input.LA(1); + if ((((_la) & ~0x3f) == 0 && ((1L << _la) & ((1L << LP) | (1L << NEW) | (1L << BOOLNOT) | (1L << BWNOT) | (1L << ADD) | (1L << SUB) | (1L << INCR) | (1L << DECR))) != 0) || ((((_la - 64)) & ~0x3f) == 0 && ((1L << (_la - 64)) & ((1L << (OCTAL - 64)) | (1L << (HEX - 64)) | (1L << (INTEGER - 64)) | (1L << (DECIMAL - 64)) | (1L << (STRING - 64)) | (1L << (CHAR - 64)) | (1L << (TRUE - 64)) | (1L << (FALSE - 64)) | (1L << (NULL - 64)) | (1L << (TYPE - 64)) | (1L << (ID - 64)))) != 0)) { { setState(93); + afterthought(); + } + } + + setState(96); + match(RP); + setState(99); + switch ( getInterpreter().adaptivePredict(_input,7,_ctx) ) { + case 1: + { + setState(97); block(); } break; - case SEMICOLON: + case 2: { - setState(94); + setState(98); empty(); } break; - default: - throw new NoViableAltException(this); } } break; @@ -598,25 +521,8 @@ class PlanAParser extends Parser { _localctx = new DeclContext(_localctx); enterOuterAlt(_localctx, 5); { - setState(97); - declaration(); - setState(99); - _la = _input.LA(1); - if (_la==SEMICOLON) { - { - setState(98); - match(SEMICOLON); - } - } - - } - break; - case 6: - _localctx = new ContinueContext(_localctx); - enterOuterAlt(_localctx, 6); - { setState(101); - match(CONTINUE); + declaration(); setState(103); _la = _input.LA(1); if (_la==SEMICOLON) { @@ -628,12 +534,12 @@ class PlanAParser extends Parser { } break; - case 7: - _localctx = new BreakContext(_localctx); - enterOuterAlt(_localctx, 7); + case 6: + _localctx = new ContinueContext(_localctx); + enterOuterAlt(_localctx, 6); { setState(105); - match(BREAK); + match(CONTINUE); setState(107); _la = _input.LA(1); if (_la==SEMICOLON) { @@ -643,21 +549,38 @@ class PlanAParser extends Parser { } } + } + break; + case 7: + _localctx = new BreakContext(_localctx); + enterOuterAlt(_localctx, 7); + { + setState(109); + match(BREAK); + setState(111); + _la = _input.LA(1); + if (_la==SEMICOLON) { + { + setState(110); + match(SEMICOLON); + } + } + } break; case 8: _localctx = new ReturnContext(_localctx); enterOuterAlt(_localctx, 8); { - setState(109); + setState(113); match(RETURN); - setState(110); + setState(114); expression(0); - setState(112); + setState(116); _la = _input.LA(1); if (_la==SEMICOLON) { { - setState(111); + setState(115); match(SEMICOLON); } } @@ -668,11 +591,11 @@ class PlanAParser extends Parser { _localctx = new TryContext(_localctx); enterOuterAlt(_localctx, 9); { - setState(114); + setState(118); match(TRY); - setState(115); + setState(119); block(); - setState(123); + setState(121); _errHandler.sync(this); _alt = 1; do { @@ -680,27 +603,15 @@ class PlanAParser extends Parser { case 1: { { - setState(116); - match(CATCH); - setState(117); - match(LP); - { - setState(118); - match(TYPE); - setState(119); - match(ID); - } - setState(121); - match(RP); - setState(122); - block(); + setState(120); + trap(); } } break; default: throw new NoViableAltException(this); } - setState(125); + setState(123); _errHandler.sync(this); _alt = getInterpreter().adaptivePredict(_input,12,_ctx); } while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ); @@ -710,15 +621,15 @@ class PlanAParser extends Parser { _localctx = new ThrowContext(_localctx); enterOuterAlt(_localctx, 10); { - setState(127); + setState(125); match(THROW); - setState(128); + setState(126); expression(0); - setState(130); + setState(128); _la = _input.LA(1); if (_la==SEMICOLON) { { - setState(129); + setState(127); match(SEMICOLON); } } @@ -729,13 +640,13 @@ class PlanAParser extends Parser { _localctx = new ExprContext(_localctx); enterOuterAlt(_localctx, 11); { - setState(132); + setState(130); expression(0); - setState(134); + setState(132); _la = _input.LA(1); if (_la==SEMICOLON) { { - setState(133); + setState(131); match(SEMICOLON); } } @@ -799,29 +710,29 @@ class PlanAParser extends Parser { enterRule(_localctx, 4, RULE_block); int _la; try { - setState(147); + setState(145); switch (_input.LA(1)) { case LBRACK: _localctx = new MultipleContext(_localctx); enterOuterAlt(_localctx, 1); { - setState(138); + setState(136); match(LBRACK); - setState(142); + setState(138); _errHandler.sync(this); _la = _input.LA(1); - while ((((_la) & ~0x3f) == 0 && ((1L << _la) & ((1L << LP) | (1L << IF) | (1L << WHILE) | (1L << DO) | (1L << FOR) | (1L << CONTINUE) | (1L << BREAK) | (1L << RETURN) | (1L << NEW) | (1L << TRY) | (1L << THROW) | (1L << BOOLNOT) | (1L << BWNOT) | (1L << ADD) | (1L << SUB) | (1L << INCR) | (1L << DECR))) != 0) || ((((_la - 64)) & ~0x3f) == 0 && ((1L << (_la - 64)) & ((1L << (OCTAL - 64)) | (1L << (HEX - 64)) | (1L << (INTEGER - 64)) | (1L << (DECIMAL - 64)) | (1L << (STRING - 64)) | (1L << (CHAR - 64)) | (1L << (TRUE - 64)) | (1L << (FALSE - 64)) | (1L << (NULL - 64)) | (1L << (TYPE - 64)) | (1L << (ID - 64)))) != 0)) { + do { { { - setState(139); + setState(137); statement(); } } - setState(144); + setState(140); _errHandler.sync(this); _la = _input.LA(1); - } - setState(145); + } while ( (((_la) & ~0x3f) == 0 && ((1L << _la) & ((1L << LP) | (1L << IF) | (1L << WHILE) | (1L << DO) | (1L << FOR) | (1L << CONTINUE) | (1L << BREAK) | (1L << RETURN) | (1L << NEW) | (1L << TRY) | (1L << THROW) | (1L << BOOLNOT) | (1L << BWNOT) | (1L << ADD) | (1L << SUB) | (1L << INCR) | (1L << DECR))) != 0) || ((((_la - 64)) & ~0x3f) == 0 && ((1L << (_la - 64)) & ((1L << (OCTAL - 64)) | (1L << (HEX - 64)) | (1L << (INTEGER - 64)) | (1L << (DECIMAL - 64)) | (1L << (STRING - 64)) | (1L << (CHAR - 64)) | (1L << (TRUE - 64)) | (1L << (FALSE - 64)) | (1L << (NULL - 64)) | (1L << (TYPE - 64)) | (1L << (ID - 64)))) != 0) ); + setState(142); match(RBRACK); } break; @@ -856,7 +767,7 @@ class PlanAParser extends Parser { _localctx = new SingleContext(_localctx); enterOuterAlt(_localctx, 2); { - setState(146); + setState(144); statement(); } break; @@ -876,6 +787,9 @@ class PlanAParser extends Parser { } public static class EmptyContext extends ParserRuleContext { + public EmptyscopeContext emptyscope() { + return getRuleContext(EmptyscopeContext.class,0); + } public TerminalNode SEMICOLON() { return getToken(PlanAParser.SEMICOLON, 0); } public EmptyContext(ParserRuleContext parent, int invokingState) { super(parent, invokingState); @@ -891,11 +805,62 @@ class PlanAParser extends Parser { public final EmptyContext empty() throws RecognitionException { EmptyContext _localctx = new EmptyContext(_ctx, getState()); enterRule(_localctx, 6, RULE_empty); + try { + setState(149); + switch (_input.LA(1)) { + case LBRACK: + enterOuterAlt(_localctx, 1); + { + setState(147); + emptyscope(); + } + break; + case SEMICOLON: + enterOuterAlt(_localctx, 2); + { + setState(148); + match(SEMICOLON); + } + break; + default: + throw new NoViableAltException(this); + } + } + catch (RecognitionException re) { + _localctx.exception = re; + _errHandler.reportError(this, re); + _errHandler.recover(this, re); + } + finally { + exitRule(); + } + return _localctx; + } + + public static class EmptyscopeContext extends ParserRuleContext { + public TerminalNode LBRACK() { return getToken(PlanAParser.LBRACK, 0); } + public TerminalNode RBRACK() { return getToken(PlanAParser.RBRACK, 0); } + public EmptyscopeContext(ParserRuleContext parent, int invokingState) { + super(parent, invokingState); + } + @Override public int getRuleIndex() { return RULE_emptyscope; } + @Override + public T accept(ParseTreeVisitor visitor) { + if ( visitor instanceof PlanAParserVisitor ) return ((PlanAParserVisitor)visitor).visitEmptyscope(this); + else return visitor.visitChildren(this); + } + } + + public final EmptyscopeContext emptyscope() throws RecognitionException { + EmptyscopeContext _localctx = new EmptyscopeContext(_ctx, getState()); + enterRule(_localctx, 8, RULE_emptyscope); try { enterOuterAlt(_localctx, 1); { - setState(149); - match(SEMICOLON); + setState(151); + match(LBRACK); + setState(152); + match(RBRACK); } } catch (RecognitionException re) { @@ -929,21 +894,21 @@ class PlanAParser extends Parser { public final InitializerContext initializer() throws RecognitionException { InitializerContext _localctx = new InitializerContext(_ctx, getState()); - enterRule(_localctx, 8, RULE_initializer); + enterRule(_localctx, 10, RULE_initializer); try { - setState(153); - switch ( getInterpreter().adaptivePredict(_input,18,_ctx) ) { + setState(156); + switch ( getInterpreter().adaptivePredict(_input,19,_ctx) ) { case 1: enterOuterAlt(_localctx, 1); { - setState(151); + setState(154); declaration(); } break; case 2: enterOuterAlt(_localctx, 2); { - setState(152); + setState(155); expression(0); } break; @@ -977,11 +942,11 @@ class PlanAParser extends Parser { public final AfterthoughtContext afterthought() throws RecognitionException { AfterthoughtContext _localctx = new AfterthoughtContext(_ctx, getState()); - enterRule(_localctx, 10, RULE_afterthought); + enterRule(_localctx, 12, RULE_afterthought); try { enterOuterAlt(_localctx, 1); { - setState(155); + setState(158); expression(0); } } @@ -1023,28 +988,28 @@ class PlanAParser extends Parser { public final DeclarationContext declaration() throws RecognitionException { DeclarationContext _localctx = new DeclarationContext(_ctx, getState()); - enterRule(_localctx, 12, RULE_declaration); + enterRule(_localctx, 14, RULE_declaration); int _la; try { enterOuterAlt(_localctx, 1); { - setState(157); + setState(160); decltype(); - setState(158); + setState(161); declvar(); - setState(163); + setState(166); _errHandler.sync(this); _la = _input.LA(1); while (_la==COMMA) { { { - setState(159); + setState(162); match(COMMA); - setState(160); + setState(163); declvar(); } } - setState(165); + setState(168); _errHandler.sync(this); _la = _input.LA(1); } @@ -1084,26 +1049,26 @@ class PlanAParser extends Parser { public final DecltypeContext decltype() throws RecognitionException { DecltypeContext _localctx = new DecltypeContext(_ctx, getState()); - enterRule(_localctx, 14, RULE_decltype); + enterRule(_localctx, 16, RULE_decltype); int _la; try { enterOuterAlt(_localctx, 1); { - setState(166); + setState(169); match(TYPE); - setState(171); + setState(174); _errHandler.sync(this); _la = _input.LA(1); while (_la==LBRACE) { { { - setState(167); + setState(170); match(LBRACE); - setState(168); + setState(171); match(RBRACE); } } - setState(173); + setState(176); _errHandler.sync(this); _la = _input.LA(1); } @@ -1139,20 +1104,20 @@ class PlanAParser extends Parser { public final DeclvarContext declvar() throws RecognitionException { DeclvarContext _localctx = new DeclvarContext(_ctx, getState()); - enterRule(_localctx, 16, RULE_declvar); + enterRule(_localctx, 18, RULE_declvar); int _la; try { enterOuterAlt(_localctx, 1); { - setState(174); - match(ID); setState(177); + match(ID); + setState(180); _la = _input.LA(1); if (_la==ASSIGN) { { - setState(175); + setState(178); match(ASSIGN); - setState(176); + setState(179); expression(0); } } @@ -1170,6 +1135,75 @@ class PlanAParser extends Parser { return _localctx; } + public static class TrapContext extends ParserRuleContext { + public TerminalNode CATCH() { return getToken(PlanAParser.CATCH, 0); } + public TerminalNode LP() { return getToken(PlanAParser.LP, 0); } + public TerminalNode RP() { return getToken(PlanAParser.RP, 0); } + public TerminalNode TYPE() { return getToken(PlanAParser.TYPE, 0); } + public TerminalNode ID() { return getToken(PlanAParser.ID, 0); } + public BlockContext block() { + return getRuleContext(BlockContext.class,0); + } + public EmptyscopeContext emptyscope() { + return getRuleContext(EmptyscopeContext.class,0); + } + public TrapContext(ParserRuleContext parent, int invokingState) { + super(parent, invokingState); + } + @Override public int getRuleIndex() { return RULE_trap; } + @Override + public T accept(ParseTreeVisitor visitor) { + if ( visitor instanceof PlanAParserVisitor ) return ((PlanAParserVisitor)visitor).visitTrap(this); + else return visitor.visitChildren(this); + } + } + + public final TrapContext trap() throws RecognitionException { + TrapContext _localctx = new TrapContext(_ctx, getState()); + enterRule(_localctx, 20, RULE_trap); + try { + enterOuterAlt(_localctx, 1); + { + setState(182); + match(CATCH); + setState(183); + match(LP); + { + setState(184); + match(TYPE); + setState(185); + match(ID); + } + setState(187); + match(RP); + setState(190); + switch ( getInterpreter().adaptivePredict(_input,23,_ctx) ) { + case 1: + { + setState(188); + block(); + } + break; + case 2: + { + setState(189); + emptyscope(); + } + break; + } + } + } + catch (RecognitionException re) { + _localctx.exception = re; + _errHandler.reportError(this, re); + _errHandler.recover(this, re); + } + finally { + exitRule(); + } + return _localctx; + } + public static class ExpressionContext extends ParserRuleContext { public ExpressionContext(ParserRuleContext parent, int invokingState) { super(parent, invokingState); @@ -1427,29 +1461,29 @@ class PlanAParser extends Parser { int _parentState = getState(); ExpressionContext _localctx = new ExpressionContext(_ctx, _parentState); ExpressionContext _prevctx = _localctx; - int _startState = 18; - enterRecursionRule(_localctx, 18, RULE_expression, _p); + int _startState = 22; + enterRecursionRule(_localctx, 22, RULE_expression, _p); int _la; try { int _alt; enterOuterAlt(_localctx, 1); { - setState(207); - switch ( getInterpreter().adaptivePredict(_input,22,_ctx) ) { + setState(220); + switch ( getInterpreter().adaptivePredict(_input,24,_ctx) ) { case 1: { _localctx = new UnaryContext(_localctx); _ctx = _localctx; _prevctx = _localctx; - setState(180); + setState(193); _la = _input.LA(1); if ( !((((_la) & ~0x3f) == 0 && ((1L << _la) & ((1L << BOOLNOT) | (1L << BWNOT) | (1L << ADD) | (1L << SUB))) != 0)) ) { _errHandler.recoverInline(this); } else { consume(); } - setState(181); + setState(194); expression(14); } break; @@ -1458,13 +1492,13 @@ class PlanAParser extends Parser { _localctx = new CastContext(_localctx); _ctx = _localctx; _prevctx = _localctx; - setState(182); + setState(195); match(LP); - setState(183); + setState(196); decltype(); - setState(184); + setState(197); match(RP); - setState(185); + setState(198); expression(13); } break; @@ -1473,16 +1507,16 @@ class PlanAParser extends Parser { _localctx = new AssignmentContext(_localctx); _ctx = _localctx; _prevctx = _localctx; - setState(187); + setState(200); extstart(); - setState(188); + setState(201); _la = _input.LA(1); if ( !((((_la) & ~0x3f) == 0 && ((1L << _la) & ((1L << ASSIGN) | (1L << AADD) | (1L << ASUB) | (1L << AMUL) | (1L << ADIV) | (1L << AREM) | (1L << AAND) | (1L << AXOR) | (1L << AOR) | (1L << ALSH) | (1L << ARSH) | (1L << AUSH))) != 0)) ) { _errHandler.recoverInline(this); } else { consume(); } - setState(189); + setState(202); expression(1); } break; @@ -1491,11 +1525,11 @@ class PlanAParser extends Parser { _localctx = new PrecedenceContext(_localctx); _ctx = _localctx; _prevctx = _localctx; - setState(191); + setState(204); match(LP); - setState(192); + setState(205); expression(0); - setState(193); + setState(206); match(RP); } break; @@ -1504,7 +1538,7 @@ class PlanAParser extends Parser { _localctx = new NumericContext(_localctx); _ctx = _localctx; _prevctx = _localctx; - setState(195); + setState(208); _la = _input.LA(1); if ( !(((((_la - 64)) & ~0x3f) == 0 && ((1L << (_la - 64)) & ((1L << (OCTAL - 64)) | (1L << (HEX - 64)) | (1L << (INTEGER - 64)) | (1L << (DECIMAL - 64)))) != 0)) ) { _errHandler.recoverInline(this); @@ -1518,7 +1552,7 @@ class PlanAParser extends Parser { _localctx = new CharContext(_localctx); _ctx = _localctx; _prevctx = _localctx; - setState(196); + setState(209); match(CHAR); } break; @@ -1527,7 +1561,7 @@ class PlanAParser extends Parser { _localctx = new TrueContext(_localctx); _ctx = _localctx; _prevctx = _localctx; - setState(197); + setState(210); match(TRUE); } break; @@ -1536,7 +1570,7 @@ class PlanAParser extends Parser { _localctx = new FalseContext(_localctx); _ctx = _localctx; _prevctx = _localctx; - setState(198); + setState(211); match(FALSE); } break; @@ -1545,7 +1579,7 @@ class PlanAParser extends Parser { _localctx = new NullContext(_localctx); _ctx = _localctx; _prevctx = _localctx; - setState(199); + setState(212); match(NULL); } break; @@ -1554,9 +1588,9 @@ class PlanAParser extends Parser { _localctx = new PostincContext(_localctx); _ctx = _localctx; _prevctx = _localctx; - setState(200); + setState(213); extstart(); - setState(201); + setState(214); increment(); } break; @@ -1565,9 +1599,9 @@ class PlanAParser extends Parser { _localctx = new PreincContext(_localctx); _ctx = _localctx; _prevctx = _localctx; - setState(203); + setState(216); increment(); - setState(204); + setState(217); extstart(); } break; @@ -1576,36 +1610,36 @@ class PlanAParser extends Parser { _localctx = new ExternalContext(_localctx); _ctx = _localctx; _prevctx = _localctx; - setState(206); + setState(219); extstart(); } break; } _ctx.stop = _input.LT(-1); - setState(247); + setState(260); _errHandler.sync(this); - _alt = getInterpreter().adaptivePredict(_input,24,_ctx); + _alt = getInterpreter().adaptivePredict(_input,26,_ctx); while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) { if ( _alt==1 ) { if ( _parseListeners!=null ) triggerExitRuleEvent(); _prevctx = _localctx; { - setState(245); - switch ( getInterpreter().adaptivePredict(_input,23,_ctx) ) { + setState(258); + switch ( getInterpreter().adaptivePredict(_input,25,_ctx) ) { case 1: { _localctx = new BinaryContext(new ExpressionContext(_parentctx, _parentState)); pushNewRecursionContext(_localctx, _startState, RULE_expression); - setState(209); + setState(222); if (!(precpred(_ctx, 12))) throw new FailedPredicateException(this, "precpred(_ctx, 12)"); - setState(210); + setState(223); _la = _input.LA(1); if ( !((((_la) & ~0x3f) == 0 && ((1L << _la) & ((1L << MUL) | (1L << DIV) | (1L << REM))) != 0)) ) { _errHandler.recoverInline(this); } else { consume(); } - setState(211); + setState(224); expression(13); } break; @@ -1613,16 +1647,16 @@ class PlanAParser extends Parser { { _localctx = new BinaryContext(new ExpressionContext(_parentctx, _parentState)); pushNewRecursionContext(_localctx, _startState, RULE_expression); - setState(212); + setState(225); if (!(precpred(_ctx, 11))) throw new FailedPredicateException(this, "precpred(_ctx, 11)"); - setState(213); + setState(226); _la = _input.LA(1); if ( !(_la==ADD || _la==SUB) ) { _errHandler.recoverInline(this); } else { consume(); } - setState(214); + setState(227); expression(12); } break; @@ -1630,16 +1664,16 @@ class PlanAParser extends Parser { { _localctx = new BinaryContext(new ExpressionContext(_parentctx, _parentState)); pushNewRecursionContext(_localctx, _startState, RULE_expression); - setState(215); + setState(228); if (!(precpred(_ctx, 10))) throw new FailedPredicateException(this, "precpred(_ctx, 10)"); - setState(216); + setState(229); _la = _input.LA(1); if ( !((((_la) & ~0x3f) == 0 && ((1L << _la) & ((1L << LSH) | (1L << RSH) | (1L << USH))) != 0)) ) { _errHandler.recoverInline(this); } else { consume(); } - setState(217); + setState(230); expression(11); } break; @@ -1647,16 +1681,16 @@ class PlanAParser extends Parser { { _localctx = new CompContext(new ExpressionContext(_parentctx, _parentState)); pushNewRecursionContext(_localctx, _startState, RULE_expression); - setState(218); + setState(231); if (!(precpred(_ctx, 9))) throw new FailedPredicateException(this, "precpred(_ctx, 9)"); - setState(219); + setState(232); _la = _input.LA(1); if ( !((((_la) & ~0x3f) == 0 && ((1L << _la) & ((1L << LT) | (1L << LTE) | (1L << GT) | (1L << GTE))) != 0)) ) { _errHandler.recoverInline(this); } else { consume(); } - setState(220); + setState(233); expression(10); } break; @@ -1664,16 +1698,16 @@ class PlanAParser extends Parser { { _localctx = new CompContext(new ExpressionContext(_parentctx, _parentState)); pushNewRecursionContext(_localctx, _startState, RULE_expression); - setState(221); + setState(234); if (!(precpred(_ctx, 8))) throw new FailedPredicateException(this, "precpred(_ctx, 8)"); - setState(222); + setState(235); _la = _input.LA(1); if ( !((((_la) & ~0x3f) == 0 && ((1L << _la) & ((1L << EQ) | (1L << EQR) | (1L << NE) | (1L << NER))) != 0)) ) { _errHandler.recoverInline(this); } else { consume(); } - setState(223); + setState(236); expression(9); } break; @@ -1681,11 +1715,11 @@ class PlanAParser extends Parser { { _localctx = new BinaryContext(new ExpressionContext(_parentctx, _parentState)); pushNewRecursionContext(_localctx, _startState, RULE_expression); - setState(224); + setState(237); if (!(precpred(_ctx, 7))) throw new FailedPredicateException(this, "precpred(_ctx, 7)"); - setState(225); + setState(238); match(BWAND); - setState(226); + setState(239); expression(8); } break; @@ -1693,11 +1727,11 @@ class PlanAParser extends Parser { { _localctx = new BinaryContext(new ExpressionContext(_parentctx, _parentState)); pushNewRecursionContext(_localctx, _startState, RULE_expression); - setState(227); + setState(240); if (!(precpred(_ctx, 6))) throw new FailedPredicateException(this, "precpred(_ctx, 6)"); - setState(228); + setState(241); match(BWXOR); - setState(229); + setState(242); expression(7); } break; @@ -1705,11 +1739,11 @@ class PlanAParser extends Parser { { _localctx = new BinaryContext(new ExpressionContext(_parentctx, _parentState)); pushNewRecursionContext(_localctx, _startState, RULE_expression); - setState(230); + setState(243); if (!(precpred(_ctx, 5))) throw new FailedPredicateException(this, "precpred(_ctx, 5)"); - setState(231); + setState(244); match(BWOR); - setState(232); + setState(245); expression(6); } break; @@ -1717,11 +1751,11 @@ class PlanAParser extends Parser { { _localctx = new BoolContext(new ExpressionContext(_parentctx, _parentState)); pushNewRecursionContext(_localctx, _startState, RULE_expression); - setState(233); + setState(246); if (!(precpred(_ctx, 4))) throw new FailedPredicateException(this, "precpred(_ctx, 4)"); - setState(234); + setState(247); match(BOOLAND); - setState(235); + setState(248); expression(5); } break; @@ -1729,11 +1763,11 @@ class PlanAParser extends Parser { { _localctx = new BoolContext(new ExpressionContext(_parentctx, _parentState)); pushNewRecursionContext(_localctx, _startState, RULE_expression); - setState(236); + setState(249); if (!(precpred(_ctx, 3))) throw new FailedPredicateException(this, "precpred(_ctx, 3)"); - setState(237); + setState(250); match(BOOLOR); - setState(238); + setState(251); expression(4); } break; @@ -1741,24 +1775,24 @@ class PlanAParser extends Parser { { _localctx = new ConditionalContext(new ExpressionContext(_parentctx, _parentState)); pushNewRecursionContext(_localctx, _startState, RULE_expression); - setState(239); + setState(252); if (!(precpred(_ctx, 2))) throw new FailedPredicateException(this, "precpred(_ctx, 2)"); - setState(240); + setState(253); match(COND); - setState(241); + setState(254); expression(0); - setState(242); + setState(255); match(COLON); - setState(243); + setState(256); expression(2); } break; } } } - setState(249); + setState(262); _errHandler.sync(this); - _alt = getInterpreter().adaptivePredict(_input,24,_ctx); + _alt = getInterpreter().adaptivePredict(_input,26,_ctx); } } } @@ -1805,49 +1839,49 @@ class PlanAParser extends Parser { public final ExtstartContext extstart() throws RecognitionException { ExtstartContext _localctx = new ExtstartContext(_ctx, getState()); - enterRule(_localctx, 20, RULE_extstart); + enterRule(_localctx, 24, RULE_extstart); try { - setState(256); - switch ( getInterpreter().adaptivePredict(_input,25,_ctx) ) { + setState(269); + switch ( getInterpreter().adaptivePredict(_input,27,_ctx) ) { case 1: enterOuterAlt(_localctx, 1); { - setState(250); + setState(263); extprec(); } break; case 2: enterOuterAlt(_localctx, 2); { - setState(251); + setState(264); extcast(); } break; case 3: enterOuterAlt(_localctx, 3); { - setState(252); + setState(265); exttype(); } break; case 4: enterOuterAlt(_localctx, 4); { - setState(253); + setState(266); extvar(); } break; case 5: enterOuterAlt(_localctx, 5); { - setState(254); + setState(267); extnew(); } break; case 6: enterOuterAlt(_localctx, 6); { - setState(255); + setState(268); extstring(); } break; @@ -1904,64 +1938,64 @@ class PlanAParser extends Parser { public final ExtprecContext extprec() throws RecognitionException { ExtprecContext _localctx = new ExtprecContext(_ctx, getState()); - enterRule(_localctx, 22, RULE_extprec); + enterRule(_localctx, 26, RULE_extprec); try { enterOuterAlt(_localctx, 1); { - setState(258); + setState(271); match(LP); - setState(265); - switch ( getInterpreter().adaptivePredict(_input,26,_ctx) ) { + setState(278); + switch ( getInterpreter().adaptivePredict(_input,28,_ctx) ) { case 1: { - setState(259); + setState(272); extprec(); } break; case 2: { - setState(260); + setState(273); extcast(); } break; case 3: { - setState(261); + setState(274); exttype(); } break; case 4: { - setState(262); + setState(275); extvar(); } break; case 5: { - setState(263); + setState(276); extnew(); } break; case 6: { - setState(264); + setState(277); extstring(); } break; } - setState(267); + setState(280); match(RP); - setState(270); - switch ( getInterpreter().adaptivePredict(_input,27,_ctx) ) { + setState(283); + switch ( getInterpreter().adaptivePredict(_input,29,_ctx) ) { case 1: { - setState(268); + setState(281); extdot(); } break; case 2: { - setState(269); + setState(282); extbrace(); } break; @@ -2016,51 +2050,51 @@ class PlanAParser extends Parser { public final ExtcastContext extcast() throws RecognitionException { ExtcastContext _localctx = new ExtcastContext(_ctx, getState()); - enterRule(_localctx, 24, RULE_extcast); + enterRule(_localctx, 28, RULE_extcast); try { enterOuterAlt(_localctx, 1); { - setState(272); + setState(285); match(LP); - setState(273); + setState(286); decltype(); - setState(274); + setState(287); match(RP); - setState(281); - switch ( getInterpreter().adaptivePredict(_input,28,_ctx) ) { + setState(294); + switch ( getInterpreter().adaptivePredict(_input,30,_ctx) ) { case 1: { - setState(275); + setState(288); extprec(); } break; case 2: { - setState(276); + setState(289); extcast(); } break; case 3: { - setState(277); + setState(290); exttype(); } break; case 4: { - setState(278); + setState(291); extvar(); } break; case 5: { - setState(279); + setState(292); extnew(); } break; case 6: { - setState(280); + setState(293); extstring(); } break; @@ -2103,27 +2137,27 @@ class PlanAParser extends Parser { public final ExtbraceContext extbrace() throws RecognitionException { ExtbraceContext _localctx = new ExtbraceContext(_ctx, getState()); - enterRule(_localctx, 26, RULE_extbrace); + enterRule(_localctx, 30, RULE_extbrace); try { enterOuterAlt(_localctx, 1); { - setState(283); + setState(296); match(LBRACE); - setState(284); + setState(297); expression(0); - setState(285); + setState(298); match(RBRACE); - setState(288); - switch ( getInterpreter().adaptivePredict(_input,29,_ctx) ) { + setState(301); + switch ( getInterpreter().adaptivePredict(_input,31,_ctx) ) { case 1: { - setState(286); + setState(299); extdot(); } break; case 2: { - setState(287); + setState(300); extbrace(); } break; @@ -2162,23 +2196,23 @@ class PlanAParser extends Parser { public final ExtdotContext extdot() throws RecognitionException { ExtdotContext _localctx = new ExtdotContext(_ctx, getState()); - enterRule(_localctx, 28, RULE_extdot); + enterRule(_localctx, 32, RULE_extdot); try { enterOuterAlt(_localctx, 1); { - setState(290); + setState(303); match(DOT); - setState(293); - switch ( getInterpreter().adaptivePredict(_input,30,_ctx) ) { + setState(306); + switch ( getInterpreter().adaptivePredict(_input,32,_ctx) ) { case 1: { - setState(291); + setState(304); extcall(); } break; case 2: { - setState(292); + setState(305); extfield(); } break; @@ -2214,13 +2248,13 @@ class PlanAParser extends Parser { public final ExttypeContext exttype() throws RecognitionException { ExttypeContext _localctx = new ExttypeContext(_ctx, getState()); - enterRule(_localctx, 30, RULE_exttype); + enterRule(_localctx, 34, RULE_exttype); try { enterOuterAlt(_localctx, 1); { - setState(295); + setState(308); match(TYPE); - setState(296); + setState(309); extdot(); } } @@ -2259,25 +2293,25 @@ class PlanAParser extends Parser { public final ExtcallContext extcall() throws RecognitionException { ExtcallContext _localctx = new ExtcallContext(_ctx, getState()); - enterRule(_localctx, 32, RULE_extcall); + enterRule(_localctx, 36, RULE_extcall); try { enterOuterAlt(_localctx, 1); { - setState(298); + setState(311); match(EXTID); - setState(299); + setState(312); arguments(); - setState(302); - switch ( getInterpreter().adaptivePredict(_input,31,_ctx) ) { + setState(315); + switch ( getInterpreter().adaptivePredict(_input,33,_ctx) ) { case 1: { - setState(300); + setState(313); extdot(); } break; case 2: { - setState(301); + setState(314); extbrace(); } break; @@ -2316,23 +2350,23 @@ class PlanAParser extends Parser { public final ExtvarContext extvar() throws RecognitionException { ExtvarContext _localctx = new ExtvarContext(_ctx, getState()); - enterRule(_localctx, 34, RULE_extvar); + enterRule(_localctx, 38, RULE_extvar); try { enterOuterAlt(_localctx, 1); { - setState(304); + setState(317); match(ID); - setState(307); - switch ( getInterpreter().adaptivePredict(_input,32,_ctx) ) { + setState(320); + switch ( getInterpreter().adaptivePredict(_input,34,_ctx) ) { case 1: { - setState(305); + setState(318); extdot(); } break; case 2: { - setState(306); + setState(319); extbrace(); } break; @@ -2372,29 +2406,29 @@ class PlanAParser extends Parser { public final ExtfieldContext extfield() throws RecognitionException { ExtfieldContext _localctx = new ExtfieldContext(_ctx, getState()); - enterRule(_localctx, 36, RULE_extfield); + enterRule(_localctx, 40, RULE_extfield); int _la; try { enterOuterAlt(_localctx, 1); { - setState(309); + setState(322); _la = _input.LA(1); if ( !(_la==EXTINTEGER || _la==EXTID) ) { _errHandler.recoverInline(this); } else { consume(); } - setState(312); - switch ( getInterpreter().adaptivePredict(_input,33,_ctx) ) { + setState(325); + switch ( getInterpreter().adaptivePredict(_input,35,_ctx) ) { case 1: { - setState(310); + setState(323); extdot(); } break; case 2: { - setState(311); + setState(324); extbrace(); } break; @@ -2451,33 +2485,33 @@ class PlanAParser extends Parser { public final ExtnewContext extnew() throws RecognitionException { ExtnewContext _localctx = new ExtnewContext(_ctx, getState()); - enterRule(_localctx, 38, RULE_extnew); + enterRule(_localctx, 42, RULE_extnew); try { int _alt; enterOuterAlt(_localctx, 1); { - setState(314); + setState(327); match(NEW); - setState(315); + setState(328); match(TYPE); - setState(332); + setState(345); switch (_input.LA(1)) { case LP: { { - setState(316); + setState(329); arguments(); - setState(319); - switch ( getInterpreter().adaptivePredict(_input,34,_ctx) ) { + setState(332); + switch ( getInterpreter().adaptivePredict(_input,36,_ctx) ) { case 1: { - setState(317); + setState(330); extdot(); } break; case 2: { - setState(318); + setState(331); extbrace(); } break; @@ -2488,7 +2522,7 @@ class PlanAParser extends Parser { case LBRACE: { { - setState(325); + setState(338); _errHandler.sync(this); _alt = 1; do { @@ -2496,11 +2530,11 @@ class PlanAParser extends Parser { case 1: { { - setState(321); + setState(334); match(LBRACE); - setState(322); + setState(335); expression(0); - setState(323); + setState(336); match(RBRACE); } } @@ -2508,15 +2542,15 @@ class PlanAParser extends Parser { default: throw new NoViableAltException(this); } - setState(327); + setState(340); _errHandler.sync(this); - _alt = getInterpreter().adaptivePredict(_input,35,_ctx); + _alt = getInterpreter().adaptivePredict(_input,37,_ctx); } while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ); - setState(330); - switch ( getInterpreter().adaptivePredict(_input,36,_ctx) ) { + setState(343); + switch ( getInterpreter().adaptivePredict(_input,38,_ctx) ) { case 1: { - setState(329); + setState(342); extdot(); } break; @@ -2561,23 +2595,23 @@ class PlanAParser extends Parser { public final ExtstringContext extstring() throws RecognitionException { ExtstringContext _localctx = new ExtstringContext(_ctx, getState()); - enterRule(_localctx, 40, RULE_extstring); + enterRule(_localctx, 44, RULE_extstring); try { enterOuterAlt(_localctx, 1); { - setState(334); + setState(347); match(STRING); - setState(337); - switch ( getInterpreter().adaptivePredict(_input,38,_ctx) ) { + setState(350); + switch ( getInterpreter().adaptivePredict(_input,40,_ctx) ) { case 1: { - setState(335); + setState(348); extdot(); } break; case 2: { - setState(336); + setState(349); extbrace(); } break; @@ -2621,40 +2655,40 @@ class PlanAParser extends Parser { public final ArgumentsContext arguments() throws RecognitionException { ArgumentsContext _localctx = new ArgumentsContext(_ctx, getState()); - enterRule(_localctx, 42, RULE_arguments); + enterRule(_localctx, 46, RULE_arguments); int _la; try { enterOuterAlt(_localctx, 1); { { - setState(339); + setState(352); match(LP); - setState(348); + setState(361); _la = _input.LA(1); if ((((_la) & ~0x3f) == 0 && ((1L << _la) & ((1L << LP) | (1L << NEW) | (1L << BOOLNOT) | (1L << BWNOT) | (1L << ADD) | (1L << SUB) | (1L << INCR) | (1L << DECR))) != 0) || ((((_la - 64)) & ~0x3f) == 0 && ((1L << (_la - 64)) & ((1L << (OCTAL - 64)) | (1L << (HEX - 64)) | (1L << (INTEGER - 64)) | (1L << (DECIMAL - 64)) | (1L << (STRING - 64)) | (1L << (CHAR - 64)) | (1L << (TRUE - 64)) | (1L << (FALSE - 64)) | (1L << (NULL - 64)) | (1L << (TYPE - 64)) | (1L << (ID - 64)))) != 0)) { { - setState(340); + setState(353); expression(0); - setState(345); + setState(358); _errHandler.sync(this); _la = _input.LA(1); while (_la==COMMA) { { { - setState(341); + setState(354); match(COMMA); - setState(342); + setState(355); expression(0); } } - setState(347); + setState(360); _errHandler.sync(this); _la = _input.LA(1); } } } - setState(350); + setState(363); match(RP); } } @@ -2686,12 +2720,12 @@ class PlanAParser extends Parser { public final IncrementContext increment() throws RecognitionException { IncrementContext _localctx = new IncrementContext(_ctx, getState()); - enterRule(_localctx, 44, RULE_increment); + enterRule(_localctx, 48, RULE_increment); int _la; try { enterOuterAlt(_localctx, 1); { - setState(352); + setState(365); _la = _input.LA(1); if ( !(_la==INCR || _la==DECR) ) { _errHandler.recoverInline(this); @@ -2713,7 +2747,7 @@ class PlanAParser extends Parser { public boolean sempred(RuleContext _localctx, int ruleIndex, int predIndex) { switch (ruleIndex) { - case 9: + case 11: return expression_sempred((ExpressionContext)_localctx, predIndex); } return true; @@ -2747,144 +2781,148 @@ class PlanAParser extends Parser { } public static final String _serializedATN = - "\3\u0430\ud6d1\u8206\uad2d\u4417\uaef1\u8d80\uaadd\3N\u0165\4\2\t\2\4"+ + "\3\u0430\ud6d1\u8206\uad2d\u4417\uaef1\u8d80\uaadd\3N\u0172\4\2\t\2\4"+ "\3\t\3\4\4\t\4\4\5\t\5\4\6\t\6\4\7\t\7\4\b\t\b\4\t\t\t\4\n\t\n\4\13\t"+ "\13\4\f\t\f\4\r\t\r\4\16\t\16\4\17\t\17\4\20\t\20\4\21\t\21\4\22\t\22"+ - "\4\23\t\23\4\24\t\24\4\25\t\25\4\26\t\26\4\27\t\27\4\30\t\30\3\2\6\2\62"+ - "\n\2\r\2\16\2\63\3\2\3\2\3\3\3\3\3\3\3\3\3\3\3\3\3\3\5\3?\n\3\3\3\3\3"+ - "\3\3\3\3\3\3\3\3\5\3G\n\3\3\3\3\3\3\3\3\3\3\3\3\3\3\3\5\3P\n\3\3\3\3\3"+ - "\3\3\5\3U\n\3\3\3\3\3\5\3Y\n\3\3\3\3\3\5\3]\n\3\3\3\3\3\3\3\5\3b\n\3\3"+ - "\3\3\3\5\3f\n\3\3\3\3\3\5\3j\n\3\3\3\3\3\5\3n\n\3\3\3\3\3\3\3\5\3s\n\3"+ - "\3\3\3\3\3\3\3\3\3\3\3\3\3\3\3\3\3\3\6\3~\n\3\r\3\16\3\177\3\3\3\3\3\3"+ - "\5\3\u0085\n\3\3\3\3\3\5\3\u0089\n\3\5\3\u008b\n\3\3\4\3\4\7\4\u008f\n"+ - "\4\f\4\16\4\u0092\13\4\3\4\3\4\5\4\u0096\n\4\3\5\3\5\3\6\3\6\5\6\u009c"+ - "\n\6\3\7\3\7\3\b\3\b\3\b\3\b\7\b\u00a4\n\b\f\b\16\b\u00a7\13\b\3\t\3\t"+ - "\3\t\7\t\u00ac\n\t\f\t\16\t\u00af\13\t\3\n\3\n\3\n\5\n\u00b4\n\n\3\13"+ - "\3\13\3\13\3\13\3\13\3\13\3\13\3\13\3\13\3\13\3\13\3\13\3\13\3\13\3\13"+ - "\3\13\3\13\3\13\3\13\3\13\3\13\3\13\3\13\3\13\3\13\3\13\3\13\3\13\5\13"+ - "\u00d2\n\13\3\13\3\13\3\13\3\13\3\13\3\13\3\13\3\13\3\13\3\13\3\13\3\13"+ - "\3\13\3\13\3\13\3\13\3\13\3\13\3\13\3\13\3\13\3\13\3\13\3\13\3\13\3\13"+ - "\3\13\3\13\3\13\3\13\3\13\3\13\3\13\3\13\3\13\3\13\7\13\u00f8\n\13\f\13"+ - "\16\13\u00fb\13\13\3\f\3\f\3\f\3\f\3\f\3\f\5\f\u0103\n\f\3\r\3\r\3\r\3"+ - "\r\3\r\3\r\3\r\5\r\u010c\n\r\3\r\3\r\3\r\5\r\u0111\n\r\3\16\3\16\3\16"+ - "\3\16\3\16\3\16\3\16\3\16\3\16\5\16\u011c\n\16\3\17\3\17\3\17\3\17\3\17"+ - "\5\17\u0123\n\17\3\20\3\20\3\20\5\20\u0128\n\20\3\21\3\21\3\21\3\22\3"+ - "\22\3\22\3\22\5\22\u0131\n\22\3\23\3\23\3\23\5\23\u0136\n\23\3\24\3\24"+ - "\3\24\5\24\u013b\n\24\3\25\3\25\3\25\3\25\3\25\5\25\u0142\n\25\3\25\3"+ - "\25\3\25\3\25\6\25\u0148\n\25\r\25\16\25\u0149\3\25\5\25\u014d\n\25\5"+ - "\25\u014f\n\25\3\26\3\26\3\26\5\26\u0154\n\26\3\27\3\27\3\27\3\27\7\27"+ - "\u015a\n\27\f\27\16\27\u015d\13\27\5\27\u015f\n\27\3\27\3\27\3\30\3\30"+ - "\3\30\2\3\24\31\2\4\6\b\n\f\16\20\22\24\26\30\32\34\36 \"$&(*,.\2\f\4"+ - "\2\32\33\37 \3\2\65@\3\2BE\3\2\34\36\3\2\37 \3\2!#\3\2$\'\3\2(+\3\2MN"+ - "\3\2\63\64\u01a5\2\61\3\2\2\2\4\u008a\3\2\2\2\6\u0095\3\2\2\2\b\u0097"+ - "\3\2\2\2\n\u009b\3\2\2\2\f\u009d\3\2\2\2\16\u009f\3\2\2\2\20\u00a8\3\2"+ - "\2\2\22\u00b0\3\2\2\2\24\u00d1\3\2\2\2\26\u0102\3\2\2\2\30\u0104\3\2\2"+ - "\2\32\u0112\3\2\2\2\34\u011d\3\2\2\2\36\u0124\3\2\2\2 \u0129\3\2\2\2\""+ - "\u012c\3\2\2\2$\u0132\3\2\2\2&\u0137\3\2\2\2(\u013c\3\2\2\2*\u0150\3\2"+ - "\2\2,\u0155\3\2\2\2.\u0162\3\2\2\2\60\62\5\4\3\2\61\60\3\2\2\2\62\63\3"+ - "\2\2\2\63\61\3\2\2\2\63\64\3\2\2\2\64\65\3\2\2\2\65\66\7\2\2\3\66\3\3"+ - "\2\2\2\678\7\16\2\289\7\t\2\29:\5\24\13\2:;\7\n\2\2;>\5\6\4\2<=\7\17\2"+ - "\2=?\5\6\4\2><\3\2\2\2>?\3\2\2\2?\u008b\3\2\2\2@A\7\20\2\2AB\7\t\2\2B"+ - "C\5\24\13\2CF\7\n\2\2DG\5\6\4\2EG\5\b\5\2FD\3\2\2\2FE\3\2\2\2G\u008b\3"+ - "\2\2\2HI\7\21\2\2IJ\5\6\4\2JK\7\20\2\2KL\7\t\2\2LM\5\24\13\2MO\7\n\2\2"+ - "NP\7\r\2\2ON\3\2\2\2OP\3\2\2\2P\u008b\3\2\2\2QR\7\22\2\2RT\7\t\2\2SU\5"+ - "\n\6\2TS\3\2\2\2TU\3\2\2\2UV\3\2\2\2VX\7\r\2\2WY\5\24\13\2XW\3\2\2\2X"+ - "Y\3\2\2\2YZ\3\2\2\2Z\\\7\r\2\2[]\5\f\7\2\\[\3\2\2\2\\]\3\2\2\2]^\3\2\2"+ - "\2^a\7\n\2\2_b\5\6\4\2`b\5\b\5\2a_\3\2\2\2a`\3\2\2\2b\u008b\3\2\2\2ce"+ - "\5\16\b\2df\7\r\2\2ed\3\2\2\2ef\3\2\2\2f\u008b\3\2\2\2gi\7\23\2\2hj\7"+ - "\r\2\2ih\3\2\2\2ij\3\2\2\2j\u008b\3\2\2\2km\7\24\2\2ln\7\r\2\2ml\3\2\2"+ - "\2mn\3\2\2\2n\u008b\3\2\2\2op\7\25\2\2pr\5\24\13\2qs\7\r\2\2rq\3\2\2\2"+ - "rs\3\2\2\2s\u008b\3\2\2\2tu\7\27\2\2u}\5\6\4\2vw\7\30\2\2wx\7\t\2\2xy"+ - "\7K\2\2yz\7L\2\2z{\3\2\2\2{|\7\n\2\2|~\5\6\4\2}v\3\2\2\2~\177\3\2\2\2"+ - "\177}\3\2\2\2\177\u0080\3\2\2\2\u0080\u008b\3\2\2\2\u0081\u0082\7\31\2"+ - "\2\u0082\u0084\5\24\13\2\u0083\u0085\7\r\2\2\u0084\u0083\3\2\2\2\u0084"+ - "\u0085\3\2\2\2\u0085\u008b\3\2\2\2\u0086\u0088\5\24\13\2\u0087\u0089\7"+ - "\r\2\2\u0088\u0087\3\2\2\2\u0088\u0089\3\2\2\2\u0089\u008b\3\2\2\2\u008a"+ - "\67\3\2\2\2\u008a@\3\2\2\2\u008aH\3\2\2\2\u008aQ\3\2\2\2\u008ac\3\2\2"+ - "\2\u008ag\3\2\2\2\u008ak\3\2\2\2\u008ao\3\2\2\2\u008at\3\2\2\2\u008a\u0081"+ - "\3\2\2\2\u008a\u0086\3\2\2\2\u008b\5\3\2\2\2\u008c\u0090\7\5\2\2\u008d"+ - "\u008f\5\4\3\2\u008e\u008d\3\2\2\2\u008f\u0092\3\2\2\2\u0090\u008e\3\2"+ - "\2\2\u0090\u0091\3\2\2\2\u0091\u0093\3\2\2\2\u0092\u0090\3\2\2\2\u0093"+ - "\u0096\7\6\2\2\u0094\u0096\5\4\3\2\u0095\u008c\3\2\2\2\u0095\u0094\3\2"+ - "\2\2\u0096\7\3\2\2\2\u0097\u0098\7\r\2\2\u0098\t\3\2\2\2\u0099\u009c\5"+ - "\16\b\2\u009a\u009c\5\24\13\2\u009b\u0099\3\2\2\2\u009b\u009a\3\2\2\2"+ - "\u009c\13\3\2\2\2\u009d\u009e\5\24\13\2\u009e\r\3\2\2\2\u009f\u00a0\5"+ - "\20\t\2\u00a0\u00a5\5\22\n\2\u00a1\u00a2\7\f\2\2\u00a2\u00a4\5\22\n\2"+ - "\u00a3\u00a1\3\2\2\2\u00a4\u00a7\3\2\2\2\u00a5\u00a3\3\2\2\2\u00a5\u00a6"+ - "\3\2\2\2\u00a6\17\3\2\2\2\u00a7\u00a5\3\2\2\2\u00a8\u00ad\7K\2\2\u00a9"+ - "\u00aa\7\7\2\2\u00aa\u00ac\7\b\2\2\u00ab\u00a9\3\2\2\2\u00ac\u00af\3\2"+ - "\2\2\u00ad\u00ab\3\2\2\2\u00ad\u00ae\3\2\2\2\u00ae\21\3\2\2\2\u00af\u00ad"+ - "\3\2\2\2\u00b0\u00b3\7L\2\2\u00b1\u00b2\7\65\2\2\u00b2\u00b4\5\24\13\2"+ - "\u00b3\u00b1\3\2\2\2\u00b3\u00b4\3\2\2\2\u00b4\23\3\2\2\2\u00b5\u00b6"+ - "\b\13\1\2\u00b6\u00b7\t\2\2\2\u00b7\u00d2\5\24\13\20\u00b8\u00b9\7\t\2"+ - "\2\u00b9\u00ba\5\20\t\2\u00ba\u00bb\7\n\2\2\u00bb\u00bc\5\24\13\17\u00bc"+ - "\u00d2\3\2\2\2\u00bd\u00be\5\26\f\2\u00be\u00bf\t\3\2\2\u00bf\u00c0\5"+ - "\24\13\3\u00c0\u00d2\3\2\2\2\u00c1\u00c2\7\t\2\2\u00c2\u00c3\5\24\13\2"+ - "\u00c3\u00c4\7\n\2\2\u00c4\u00d2\3\2\2\2\u00c5\u00d2\t\4\2\2\u00c6\u00d2"+ - "\7G\2\2\u00c7\u00d2\7H\2\2\u00c8\u00d2\7I\2\2\u00c9\u00d2\7J\2\2\u00ca"+ - "\u00cb\5\26\f\2\u00cb\u00cc\5.\30\2\u00cc\u00d2\3\2\2\2\u00cd\u00ce\5"+ - ".\30\2\u00ce\u00cf\5\26\f\2\u00cf\u00d2\3\2\2\2\u00d0\u00d2\5\26\f\2\u00d1"+ - "\u00b5\3\2\2\2\u00d1\u00b8\3\2\2\2\u00d1\u00bd\3\2\2\2\u00d1\u00c1\3\2"+ - "\2\2\u00d1\u00c5\3\2\2\2\u00d1\u00c6\3\2\2\2\u00d1\u00c7\3\2\2\2\u00d1"+ - "\u00c8\3\2\2\2\u00d1\u00c9\3\2\2\2\u00d1\u00ca\3\2\2\2\u00d1\u00cd\3\2"+ - "\2\2\u00d1\u00d0\3\2\2\2\u00d2\u00f9\3\2\2\2\u00d3\u00d4\f\16\2\2\u00d4"+ - "\u00d5\t\5\2\2\u00d5\u00f8\5\24\13\17\u00d6\u00d7\f\r\2\2\u00d7\u00d8"+ - "\t\6\2\2\u00d8\u00f8\5\24\13\16\u00d9\u00da\f\f\2\2\u00da\u00db\t\7\2"+ - "\2\u00db\u00f8\5\24\13\r\u00dc\u00dd\f\13\2\2\u00dd\u00de\t\b\2\2\u00de"+ - "\u00f8\5\24\13\f\u00df\u00e0\f\n\2\2\u00e0\u00e1\t\t\2\2\u00e1\u00f8\5"+ - "\24\13\13\u00e2\u00e3\f\t\2\2\u00e3\u00e4\7,\2\2\u00e4\u00f8\5\24\13\n"+ - "\u00e5\u00e6\f\b\2\2\u00e6\u00e7\7-\2\2\u00e7\u00f8\5\24\13\t\u00e8\u00e9"+ - "\f\7\2\2\u00e9\u00ea\7.\2\2\u00ea\u00f8\5\24\13\b\u00eb\u00ec\f\6\2\2"+ - "\u00ec\u00ed\7/\2\2\u00ed\u00f8\5\24\13\7\u00ee\u00ef\f\5\2\2\u00ef\u00f0"+ - "\7\60\2\2\u00f0\u00f8\5\24\13\6\u00f1\u00f2\f\4\2\2\u00f2\u00f3\7\61\2"+ - "\2\u00f3\u00f4\5\24\13\2\u00f4\u00f5\7\62\2\2\u00f5\u00f6\5\24\13\4\u00f6"+ - "\u00f8\3\2\2\2\u00f7\u00d3\3\2\2\2\u00f7\u00d6\3\2\2\2\u00f7\u00d9\3\2"+ - "\2\2\u00f7\u00dc\3\2\2\2\u00f7\u00df\3\2\2\2\u00f7\u00e2\3\2\2\2\u00f7"+ - "\u00e5\3\2\2\2\u00f7\u00e8\3\2\2\2\u00f7\u00eb\3\2\2\2\u00f7\u00ee\3\2"+ - "\2\2\u00f7\u00f1\3\2\2\2\u00f8\u00fb\3\2\2\2\u00f9\u00f7\3\2\2\2\u00f9"+ - "\u00fa\3\2\2\2\u00fa\25\3\2\2\2\u00fb\u00f9\3\2\2\2\u00fc\u0103\5\30\r"+ - "\2\u00fd\u0103\5\32\16\2\u00fe\u0103\5 \21\2\u00ff\u0103\5$\23\2\u0100"+ - "\u0103\5(\25\2\u0101\u0103\5*\26\2\u0102\u00fc\3\2\2\2\u0102\u00fd\3\2"+ - "\2\2\u0102\u00fe\3\2\2\2\u0102\u00ff\3\2\2\2\u0102\u0100\3\2\2\2\u0102"+ - "\u0101\3\2\2\2\u0103\27\3\2\2\2\u0104\u010b\7\t\2\2\u0105\u010c\5\30\r"+ - "\2\u0106\u010c\5\32\16\2\u0107\u010c\5 \21\2\u0108\u010c\5$\23\2\u0109"+ - "\u010c\5(\25\2\u010a\u010c\5*\26\2\u010b\u0105\3\2\2\2\u010b\u0106\3\2"+ - "\2\2\u010b\u0107\3\2\2\2\u010b\u0108\3\2\2\2\u010b\u0109\3\2\2\2\u010b"+ - "\u010a\3\2\2\2\u010c\u010d\3\2\2\2\u010d\u0110\7\n\2\2\u010e\u0111\5\36"+ - "\20\2\u010f\u0111\5\34\17\2\u0110\u010e\3\2\2\2\u0110\u010f\3\2\2\2\u0110"+ - "\u0111\3\2\2\2\u0111\31\3\2\2\2\u0112\u0113\7\t\2\2\u0113\u0114\5\20\t"+ - "\2\u0114\u011b\7\n\2\2\u0115\u011c\5\30\r\2\u0116\u011c\5\32\16\2\u0117"+ - "\u011c\5 \21\2\u0118\u011c\5$\23\2\u0119\u011c\5(\25\2\u011a\u011c\5*"+ - "\26\2\u011b\u0115\3\2\2\2\u011b\u0116\3\2\2\2\u011b\u0117\3\2\2\2\u011b"+ - "\u0118\3\2\2\2\u011b\u0119\3\2\2\2\u011b\u011a\3\2\2\2\u011c\33\3\2\2"+ - "\2\u011d\u011e\7\7\2\2\u011e\u011f\5\24\13\2\u011f\u0122\7\b\2\2\u0120"+ - "\u0123\5\36\20\2\u0121\u0123\5\34\17\2\u0122\u0120\3\2\2\2\u0122\u0121"+ - "\3\2\2\2\u0122\u0123\3\2\2\2\u0123\35\3\2\2\2\u0124\u0127\7\13\2\2\u0125"+ - "\u0128\5\"\22\2\u0126\u0128\5&\24\2\u0127\u0125\3\2\2\2\u0127\u0126\3"+ - "\2\2\2\u0128\37\3\2\2\2\u0129\u012a\7K\2\2\u012a\u012b\5\36\20\2\u012b"+ - "!\3\2\2\2\u012c\u012d\7N\2\2\u012d\u0130\5,\27\2\u012e\u0131\5\36\20\2"+ - "\u012f\u0131\5\34\17\2\u0130\u012e\3\2\2\2\u0130\u012f\3\2\2\2\u0130\u0131"+ - "\3\2\2\2\u0131#\3\2\2\2\u0132\u0135\7L\2\2\u0133\u0136\5\36\20\2\u0134"+ - "\u0136\5\34\17\2\u0135\u0133\3\2\2\2\u0135\u0134\3\2\2\2\u0135\u0136\3"+ - "\2\2\2\u0136%\3\2\2\2\u0137\u013a\t\n\2\2\u0138\u013b\5\36\20\2\u0139"+ - "\u013b\5\34\17\2\u013a\u0138\3\2\2\2\u013a\u0139\3\2\2\2\u013a\u013b\3"+ - "\2\2\2\u013b\'\3\2\2\2\u013c\u013d\7\26\2\2\u013d\u014e\7K\2\2\u013e\u0141"+ - "\5,\27\2\u013f\u0142\5\36\20\2\u0140\u0142\5\34\17\2\u0141\u013f\3\2\2"+ - "\2\u0141\u0140\3\2\2\2\u0141\u0142\3\2\2\2\u0142\u014f\3\2\2\2\u0143\u0144"+ - "\7\7\2\2\u0144\u0145\5\24\13\2\u0145\u0146\7\b\2\2\u0146\u0148\3\2\2\2"+ - "\u0147\u0143\3\2\2\2\u0148\u0149\3\2\2\2\u0149\u0147\3\2\2\2\u0149\u014a"+ - "\3\2\2\2\u014a\u014c\3\2\2\2\u014b\u014d\5\36\20\2\u014c\u014b\3\2\2\2"+ - "\u014c\u014d\3\2\2\2\u014d\u014f\3\2\2\2\u014e\u013e\3\2\2\2\u014e\u0147"+ - "\3\2\2\2\u014f)\3\2\2\2\u0150\u0153\7F\2\2\u0151\u0154\5\36\20\2\u0152"+ - "\u0154\5\34\17\2\u0153\u0151\3\2\2\2\u0153\u0152\3\2\2\2\u0153\u0154\3"+ - "\2\2\2\u0154+\3\2\2\2\u0155\u015e\7\t\2\2\u0156\u015b\5\24\13\2\u0157"+ - "\u0158\7\f\2\2\u0158\u015a\5\24\13\2\u0159\u0157\3\2\2\2\u015a\u015d\3"+ - "\2\2\2\u015b\u0159\3\2\2\2\u015b\u015c\3\2\2\2\u015c\u015f\3\2\2\2\u015d"+ - "\u015b\3\2\2\2\u015e\u0156\3\2\2\2\u015e\u015f\3\2\2\2\u015f\u0160\3\2"+ - "\2\2\u0160\u0161\7\n\2\2\u0161-\3\2\2\2\u0162\u0163\t\13\2\2\u0163/\3"+ - "\2\2\2+\63>FOTX\\aeimr\177\u0084\u0088\u008a\u0090\u0095\u009b\u00a5\u00ad"+ - "\u00b3\u00d1\u00f7\u00f9\u0102\u010b\u0110\u011b\u0122\u0127\u0130\u0135"+ - "\u013a\u0141\u0149\u014c\u014e\u0153\u015b\u015e"; + "\4\23\t\23\4\24\t\24\4\25\t\25\4\26\t\26\4\27\t\27\4\30\t\30\4\31\t\31"+ + "\4\32\t\32\3\2\6\2\66\n\2\r\2\16\2\67\3\2\3\2\3\3\3\3\3\3\3\3\3\3\3\3"+ + "\3\3\5\3C\n\3\3\3\3\3\3\3\3\3\3\3\3\3\5\3K\n\3\3\3\3\3\3\3\3\3\3\3\3\3"+ + "\3\3\5\3T\n\3\3\3\3\3\3\3\5\3Y\n\3\3\3\3\3\5\3]\n\3\3\3\3\3\5\3a\n\3\3"+ + "\3\3\3\3\3\5\3f\n\3\3\3\3\3\5\3j\n\3\3\3\3\3\5\3n\n\3\3\3\3\3\5\3r\n\3"+ + "\3\3\3\3\3\3\5\3w\n\3\3\3\3\3\3\3\6\3|\n\3\r\3\16\3}\3\3\3\3\3\3\5\3\u0083"+ + "\n\3\3\3\3\3\5\3\u0087\n\3\5\3\u0089\n\3\3\4\3\4\6\4\u008d\n\4\r\4\16"+ + "\4\u008e\3\4\3\4\3\4\5\4\u0094\n\4\3\5\3\5\5\5\u0098\n\5\3\6\3\6\3\6\3"+ + "\7\3\7\5\7\u009f\n\7\3\b\3\b\3\t\3\t\3\t\3\t\7\t\u00a7\n\t\f\t\16\t\u00aa"+ + "\13\t\3\n\3\n\3\n\7\n\u00af\n\n\f\n\16\n\u00b2\13\n\3\13\3\13\3\13\5\13"+ + "\u00b7\n\13\3\f\3\f\3\f\3\f\3\f\3\f\3\f\3\f\5\f\u00c1\n\f\3\r\3\r\3\r"+ + "\3\r\3\r\3\r\3\r\3\r\3\r\3\r\3\r\3\r\3\r\3\r\3\r\3\r\3\r\3\r\3\r\3\r\3"+ + "\r\3\r\3\r\3\r\3\r\3\r\3\r\3\r\5\r\u00df\n\r\3\r\3\r\3\r\3\r\3\r\3\r\3"+ + "\r\3\r\3\r\3\r\3\r\3\r\3\r\3\r\3\r\3\r\3\r\3\r\3\r\3\r\3\r\3\r\3\r\3\r"+ + "\3\r\3\r\3\r\3\r\3\r\3\r\3\r\3\r\3\r\3\r\3\r\3\r\7\r\u0105\n\r\f\r\16"+ + "\r\u0108\13\r\3\16\3\16\3\16\3\16\3\16\3\16\5\16\u0110\n\16\3\17\3\17"+ + "\3\17\3\17\3\17\3\17\3\17\5\17\u0119\n\17\3\17\3\17\3\17\5\17\u011e\n"+ + "\17\3\20\3\20\3\20\3\20\3\20\3\20\3\20\3\20\3\20\5\20\u0129\n\20\3\21"+ + "\3\21\3\21\3\21\3\21\5\21\u0130\n\21\3\22\3\22\3\22\5\22\u0135\n\22\3"+ + "\23\3\23\3\23\3\24\3\24\3\24\3\24\5\24\u013e\n\24\3\25\3\25\3\25\5\25"+ + "\u0143\n\25\3\26\3\26\3\26\5\26\u0148\n\26\3\27\3\27\3\27\3\27\3\27\5"+ + "\27\u014f\n\27\3\27\3\27\3\27\3\27\6\27\u0155\n\27\r\27\16\27\u0156\3"+ + "\27\5\27\u015a\n\27\5\27\u015c\n\27\3\30\3\30\3\30\5\30\u0161\n\30\3\31"+ + "\3\31\3\31\3\31\7\31\u0167\n\31\f\31\16\31\u016a\13\31\5\31\u016c\n\31"+ + "\3\31\3\31\3\32\3\32\3\32\2\3\30\33\2\4\6\b\n\f\16\20\22\24\26\30\32\34"+ + "\36 \"$&(*,.\60\62\2\f\4\2\32\33\37 \3\2\65@\3\2BE\3\2\34\36\3\2\37 \3"+ + "\2!#\3\2$\'\3\2(+\3\2MN\3\2\63\64\u01b2\2\65\3\2\2\2\4\u0088\3\2\2\2\6"+ + "\u0093\3\2\2\2\b\u0097\3\2\2\2\n\u0099\3\2\2\2\f\u009e\3\2\2\2\16\u00a0"+ + "\3\2\2\2\20\u00a2\3\2\2\2\22\u00ab\3\2\2\2\24\u00b3\3\2\2\2\26\u00b8\3"+ + "\2\2\2\30\u00de\3\2\2\2\32\u010f\3\2\2\2\34\u0111\3\2\2\2\36\u011f\3\2"+ + "\2\2 \u012a\3\2\2\2\"\u0131\3\2\2\2$\u0136\3\2\2\2&\u0139\3\2\2\2(\u013f"+ + "\3\2\2\2*\u0144\3\2\2\2,\u0149\3\2\2\2.\u015d\3\2\2\2\60\u0162\3\2\2\2"+ + "\62\u016f\3\2\2\2\64\66\5\4\3\2\65\64\3\2\2\2\66\67\3\2\2\2\67\65\3\2"+ + "\2\2\678\3\2\2\289\3\2\2\29:\7\2\2\3:\3\3\2\2\2;<\7\16\2\2<=\7\t\2\2="+ + ">\5\30\r\2>?\7\n\2\2?B\5\6\4\2@A\7\17\2\2AC\5\6\4\2B@\3\2\2\2BC\3\2\2"+ + "\2C\u0089\3\2\2\2DE\7\20\2\2EF\7\t\2\2FG\5\30\r\2GJ\7\n\2\2HK\5\6\4\2"+ + "IK\5\b\5\2JH\3\2\2\2JI\3\2\2\2K\u0089\3\2\2\2LM\7\21\2\2MN\5\6\4\2NO\7"+ + "\20\2\2OP\7\t\2\2PQ\5\30\r\2QS\7\n\2\2RT\7\r\2\2SR\3\2\2\2ST\3\2\2\2T"+ + "\u0089\3\2\2\2UV\7\22\2\2VX\7\t\2\2WY\5\f\7\2XW\3\2\2\2XY\3\2\2\2YZ\3"+ + "\2\2\2Z\\\7\r\2\2[]\5\30\r\2\\[\3\2\2\2\\]\3\2\2\2]^\3\2\2\2^`\7\r\2\2"+ + "_a\5\16\b\2`_\3\2\2\2`a\3\2\2\2ab\3\2\2\2be\7\n\2\2cf\5\6\4\2df\5\b\5"+ + "\2ec\3\2\2\2ed\3\2\2\2f\u0089\3\2\2\2gi\5\20\t\2hj\7\r\2\2ih\3\2\2\2i"+ + "j\3\2\2\2j\u0089\3\2\2\2km\7\23\2\2ln\7\r\2\2ml\3\2\2\2mn\3\2\2\2n\u0089"+ + "\3\2\2\2oq\7\24\2\2pr\7\r\2\2qp\3\2\2\2qr\3\2\2\2r\u0089\3\2\2\2st\7\25"+ + "\2\2tv\5\30\r\2uw\7\r\2\2vu\3\2\2\2vw\3\2\2\2w\u0089\3\2\2\2xy\7\27\2"+ + "\2y{\5\6\4\2z|\5\26\f\2{z\3\2\2\2|}\3\2\2\2}{\3\2\2\2}~\3\2\2\2~\u0089"+ + "\3\2\2\2\177\u0080\7\31\2\2\u0080\u0082\5\30\r\2\u0081\u0083\7\r\2\2\u0082"+ + "\u0081\3\2\2\2\u0082\u0083\3\2\2\2\u0083\u0089\3\2\2\2\u0084\u0086\5\30"+ + "\r\2\u0085\u0087\7\r\2\2\u0086\u0085\3\2\2\2\u0086\u0087\3\2\2\2\u0087"+ + "\u0089\3\2\2\2\u0088;\3\2\2\2\u0088D\3\2\2\2\u0088L\3\2\2\2\u0088U\3\2"+ + "\2\2\u0088g\3\2\2\2\u0088k\3\2\2\2\u0088o\3\2\2\2\u0088s\3\2\2\2\u0088"+ + "x\3\2\2\2\u0088\177\3\2\2\2\u0088\u0084\3\2\2\2\u0089\5\3\2\2\2\u008a"+ + "\u008c\7\5\2\2\u008b\u008d\5\4\3\2\u008c\u008b\3\2\2\2\u008d\u008e\3\2"+ + "\2\2\u008e\u008c\3\2\2\2\u008e\u008f\3\2\2\2\u008f\u0090\3\2\2\2\u0090"+ + "\u0091\7\6\2\2\u0091\u0094\3\2\2\2\u0092\u0094\5\4\3\2\u0093\u008a\3\2"+ + "\2\2\u0093\u0092\3\2\2\2\u0094\7\3\2\2\2\u0095\u0098\5\n\6\2\u0096\u0098"+ + "\7\r\2\2\u0097\u0095\3\2\2\2\u0097\u0096\3\2\2\2\u0098\t\3\2\2\2\u0099"+ + "\u009a\7\5\2\2\u009a\u009b\7\6\2\2\u009b\13\3\2\2\2\u009c\u009f\5\20\t"+ + "\2\u009d\u009f\5\30\r\2\u009e\u009c\3\2\2\2\u009e\u009d\3\2\2\2\u009f"+ + "\r\3\2\2\2\u00a0\u00a1\5\30\r\2\u00a1\17\3\2\2\2\u00a2\u00a3\5\22\n\2"+ + "\u00a3\u00a8\5\24\13\2\u00a4\u00a5\7\f\2\2\u00a5\u00a7\5\24\13\2\u00a6"+ + "\u00a4\3\2\2\2\u00a7\u00aa\3\2\2\2\u00a8\u00a6\3\2\2\2\u00a8\u00a9\3\2"+ + "\2\2\u00a9\21\3\2\2\2\u00aa\u00a8\3\2\2\2\u00ab\u00b0\7K\2\2\u00ac\u00ad"+ + "\7\7\2\2\u00ad\u00af\7\b\2\2\u00ae\u00ac\3\2\2\2\u00af\u00b2\3\2\2\2\u00b0"+ + "\u00ae\3\2\2\2\u00b0\u00b1\3\2\2\2\u00b1\23\3\2\2\2\u00b2\u00b0\3\2\2"+ + "\2\u00b3\u00b6\7L\2\2\u00b4\u00b5\7\65\2\2\u00b5\u00b7\5\30\r\2\u00b6"+ + "\u00b4\3\2\2\2\u00b6\u00b7\3\2\2\2\u00b7\25\3\2\2\2\u00b8\u00b9\7\30\2"+ + "\2\u00b9\u00ba\7\t\2\2\u00ba\u00bb\7K\2\2\u00bb\u00bc\7L\2\2\u00bc\u00bd"+ + "\3\2\2\2\u00bd\u00c0\7\n\2\2\u00be\u00c1\5\6\4\2\u00bf\u00c1\5\n\6\2\u00c0"+ + "\u00be\3\2\2\2\u00c0\u00bf\3\2\2\2\u00c1\27\3\2\2\2\u00c2\u00c3\b\r\1"+ + "\2\u00c3\u00c4\t\2\2\2\u00c4\u00df\5\30\r\20\u00c5\u00c6\7\t\2\2\u00c6"+ + "\u00c7\5\22\n\2\u00c7\u00c8\7\n\2\2\u00c8\u00c9\5\30\r\17\u00c9\u00df"+ + "\3\2\2\2\u00ca\u00cb\5\32\16\2\u00cb\u00cc\t\3\2\2\u00cc\u00cd\5\30\r"+ + "\3\u00cd\u00df\3\2\2\2\u00ce\u00cf\7\t\2\2\u00cf\u00d0\5\30\r\2\u00d0"+ + "\u00d1\7\n\2\2\u00d1\u00df\3\2\2\2\u00d2\u00df\t\4\2\2\u00d3\u00df\7G"+ + "\2\2\u00d4\u00df\7H\2\2\u00d5\u00df\7I\2\2\u00d6\u00df\7J\2\2\u00d7\u00d8"+ + "\5\32\16\2\u00d8\u00d9\5\62\32\2\u00d9\u00df\3\2\2\2\u00da\u00db\5\62"+ + "\32\2\u00db\u00dc\5\32\16\2\u00dc\u00df\3\2\2\2\u00dd\u00df\5\32\16\2"+ + "\u00de\u00c2\3\2\2\2\u00de\u00c5\3\2\2\2\u00de\u00ca\3\2\2\2\u00de\u00ce"+ + "\3\2\2\2\u00de\u00d2\3\2\2\2\u00de\u00d3\3\2\2\2\u00de\u00d4\3\2\2\2\u00de"+ + "\u00d5\3\2\2\2\u00de\u00d6\3\2\2\2\u00de\u00d7\3\2\2\2\u00de\u00da\3\2"+ + "\2\2\u00de\u00dd\3\2\2\2\u00df\u0106\3\2\2\2\u00e0\u00e1\f\16\2\2\u00e1"+ + "\u00e2\t\5\2\2\u00e2\u0105\5\30\r\17\u00e3\u00e4\f\r\2\2\u00e4\u00e5\t"+ + "\6\2\2\u00e5\u0105\5\30\r\16\u00e6\u00e7\f\f\2\2\u00e7\u00e8\t\7\2\2\u00e8"+ + "\u0105\5\30\r\r\u00e9\u00ea\f\13\2\2\u00ea\u00eb\t\b\2\2\u00eb\u0105\5"+ + "\30\r\f\u00ec\u00ed\f\n\2\2\u00ed\u00ee\t\t\2\2\u00ee\u0105\5\30\r\13"+ + "\u00ef\u00f0\f\t\2\2\u00f0\u00f1\7,\2\2\u00f1\u0105\5\30\r\n\u00f2\u00f3"+ + "\f\b\2\2\u00f3\u00f4\7-\2\2\u00f4\u0105\5\30\r\t\u00f5\u00f6\f\7\2\2\u00f6"+ + "\u00f7\7.\2\2\u00f7\u0105\5\30\r\b\u00f8\u00f9\f\6\2\2\u00f9\u00fa\7/"+ + "\2\2\u00fa\u0105\5\30\r\7\u00fb\u00fc\f\5\2\2\u00fc\u00fd\7\60\2\2\u00fd"+ + "\u0105\5\30\r\6\u00fe\u00ff\f\4\2\2\u00ff\u0100\7\61\2\2\u0100\u0101\5"+ + "\30\r\2\u0101\u0102\7\62\2\2\u0102\u0103\5\30\r\4\u0103\u0105\3\2\2\2"+ + "\u0104\u00e0\3\2\2\2\u0104\u00e3\3\2\2\2\u0104\u00e6\3\2\2\2\u0104\u00e9"+ + "\3\2\2\2\u0104\u00ec\3\2\2\2\u0104\u00ef\3\2\2\2\u0104\u00f2\3\2\2\2\u0104"+ + "\u00f5\3\2\2\2\u0104\u00f8\3\2\2\2\u0104\u00fb\3\2\2\2\u0104\u00fe\3\2"+ + "\2\2\u0105\u0108\3\2\2\2\u0106\u0104\3\2\2\2\u0106\u0107\3\2\2\2\u0107"+ + "\31\3\2\2\2\u0108\u0106\3\2\2\2\u0109\u0110\5\34\17\2\u010a\u0110\5\36"+ + "\20\2\u010b\u0110\5$\23\2\u010c\u0110\5(\25\2\u010d\u0110\5,\27\2\u010e"+ + "\u0110\5.\30\2\u010f\u0109\3\2\2\2\u010f\u010a\3\2\2\2\u010f\u010b\3\2"+ + "\2\2\u010f\u010c\3\2\2\2\u010f\u010d\3\2\2\2\u010f\u010e\3\2\2\2\u0110"+ + "\33\3\2\2\2\u0111\u0118\7\t\2\2\u0112\u0119\5\34\17\2\u0113\u0119\5\36"+ + "\20\2\u0114\u0119\5$\23\2\u0115\u0119\5(\25\2\u0116\u0119\5,\27\2\u0117"+ + "\u0119\5.\30\2\u0118\u0112\3\2\2\2\u0118\u0113\3\2\2\2\u0118\u0114\3\2"+ + "\2\2\u0118\u0115\3\2\2\2\u0118\u0116\3\2\2\2\u0118\u0117\3\2\2\2\u0119"+ + "\u011a\3\2\2\2\u011a\u011d\7\n\2\2\u011b\u011e\5\"\22\2\u011c\u011e\5"+ + " \21\2\u011d\u011b\3\2\2\2\u011d\u011c\3\2\2\2\u011d\u011e\3\2\2\2\u011e"+ + "\35\3\2\2\2\u011f\u0120\7\t\2\2\u0120\u0121\5\22\n\2\u0121\u0128\7\n\2"+ + "\2\u0122\u0129\5\34\17\2\u0123\u0129\5\36\20\2\u0124\u0129\5$\23\2\u0125"+ + "\u0129\5(\25\2\u0126\u0129\5,\27\2\u0127\u0129\5.\30\2\u0128\u0122\3\2"+ + "\2\2\u0128\u0123\3\2\2\2\u0128\u0124\3\2\2\2\u0128\u0125\3\2\2\2\u0128"+ + "\u0126\3\2\2\2\u0128\u0127\3\2\2\2\u0129\37\3\2\2\2\u012a\u012b\7\7\2"+ + "\2\u012b\u012c\5\30\r\2\u012c\u012f\7\b\2\2\u012d\u0130\5\"\22\2\u012e"+ + "\u0130\5 \21\2\u012f\u012d\3\2\2\2\u012f\u012e\3\2\2\2\u012f\u0130\3\2"+ + "\2\2\u0130!\3\2\2\2\u0131\u0134\7\13\2\2\u0132\u0135\5&\24\2\u0133\u0135"+ + "\5*\26\2\u0134\u0132\3\2\2\2\u0134\u0133\3\2\2\2\u0135#\3\2\2\2\u0136"+ + "\u0137\7K\2\2\u0137\u0138\5\"\22\2\u0138%\3\2\2\2\u0139\u013a\7N\2\2\u013a"+ + "\u013d\5\60\31\2\u013b\u013e\5\"\22\2\u013c\u013e\5 \21\2\u013d\u013b"+ + "\3\2\2\2\u013d\u013c\3\2\2\2\u013d\u013e\3\2\2\2\u013e\'\3\2\2\2\u013f"+ + "\u0142\7L\2\2\u0140\u0143\5\"\22\2\u0141\u0143\5 \21\2\u0142\u0140\3\2"+ + "\2\2\u0142\u0141\3\2\2\2\u0142\u0143\3\2\2\2\u0143)\3\2\2\2\u0144\u0147"+ + "\t\n\2\2\u0145\u0148\5\"\22\2\u0146\u0148\5 \21\2\u0147\u0145\3\2\2\2"+ + "\u0147\u0146\3\2\2\2\u0147\u0148\3\2\2\2\u0148+\3\2\2\2\u0149\u014a\7"+ + "\26\2\2\u014a\u015b\7K\2\2\u014b\u014e\5\60\31\2\u014c\u014f\5\"\22\2"+ + "\u014d\u014f\5 \21\2\u014e\u014c\3\2\2\2\u014e\u014d\3\2\2\2\u014e\u014f"+ + "\3\2\2\2\u014f\u015c\3\2\2\2\u0150\u0151\7\7\2\2\u0151\u0152\5\30\r\2"+ + "\u0152\u0153\7\b\2\2\u0153\u0155\3\2\2\2\u0154\u0150\3\2\2\2\u0155\u0156"+ + "\3\2\2\2\u0156\u0154\3\2\2\2\u0156\u0157\3\2\2\2\u0157\u0159\3\2\2\2\u0158"+ + "\u015a\5\"\22\2\u0159\u0158\3\2\2\2\u0159\u015a\3\2\2\2\u015a\u015c\3"+ + "\2\2\2\u015b\u014b\3\2\2\2\u015b\u0154\3\2\2\2\u015c-\3\2\2\2\u015d\u0160"+ + "\7F\2\2\u015e\u0161\5\"\22\2\u015f\u0161\5 \21\2\u0160\u015e\3\2\2\2\u0160"+ + "\u015f\3\2\2\2\u0160\u0161\3\2\2\2\u0161/\3\2\2\2\u0162\u016b\7\t\2\2"+ + "\u0163\u0168\5\30\r\2\u0164\u0165\7\f\2\2\u0165\u0167\5\30\r\2\u0166\u0164"+ + "\3\2\2\2\u0167\u016a\3\2\2\2\u0168\u0166\3\2\2\2\u0168\u0169\3\2\2\2\u0169"+ + "\u016c\3\2\2\2\u016a\u0168\3\2\2\2\u016b\u0163\3\2\2\2\u016b\u016c\3\2"+ + "\2\2\u016c\u016d\3\2\2\2\u016d\u016e\7\n\2\2\u016e\61\3\2\2\2\u016f\u0170"+ + "\t\13\2\2\u0170\63\3\2\2\2-\67BJSX\\`eimqv}\u0082\u0086\u0088\u008e\u0093"+ + "\u0097\u009e\u00a8\u00b0\u00b6\u00c0\u00de\u0104\u0106\u010f\u0118\u011d"+ + "\u0128\u012f\u0134\u013d\u0142\u0147\u014e\u0156\u0159\u015b\u0160\u0168"+ + "\u016b"; public static final ATN _ATN = new ATNDeserializer().deserialize(_serializedATN.toCharArray()); static { diff --git a/plugins/lang-plan-a/src/main/java/org/elasticsearch/plan/a/PlanAParserBaseVisitor.java b/plugins/lang-plan-a/src/main/java/org/elasticsearch/plan/a/PlanAParserBaseVisitor.java index d731b57676b..7997b57ae6b 100644 --- a/plugins/lang-plan-a/src/main/java/org/elasticsearch/plan/a/PlanAParserBaseVisitor.java +++ b/plugins/lang-plan-a/src/main/java/org/elasticsearch/plan/a/PlanAParserBaseVisitor.java @@ -116,6 +116,13 @@ class PlanAParserBaseVisitor extends AbstractParseTreeVisitor implements P * {@link #visitChildren} on {@code ctx}.

*/ @Override public T visitEmpty(PlanAParser.EmptyContext ctx) { return visitChildren(ctx); } + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public T visitEmptyscope(PlanAParser.EmptyscopeContext ctx) { return visitChildren(ctx); } /** * {@inheritDoc} * @@ -151,6 +158,13 @@ class PlanAParserBaseVisitor extends AbstractParseTreeVisitor implements P * {@link #visitChildren} on {@code ctx}.

*/ @Override public T visitDeclvar(PlanAParser.DeclvarContext ctx) { return visitChildren(ctx); } + /** + * {@inheritDoc} + * + *

The default implementation returns the result of calling + * {@link #visitChildren} on {@code ctx}.

+ */ + @Override public T visitTrap(PlanAParser.TrapContext ctx) { return visitChildren(ctx); } /** * {@inheritDoc} * diff --git a/plugins/lang-plan-a/src/main/java/org/elasticsearch/plan/a/PlanAParserVisitor.java b/plugins/lang-plan-a/src/main/java/org/elasticsearch/plan/a/PlanAParserVisitor.java index 7470f3b6ad5..326a62555e7 100644 --- a/plugins/lang-plan-a/src/main/java/org/elasticsearch/plan/a/PlanAParserVisitor.java +++ b/plugins/lang-plan-a/src/main/java/org/elasticsearch/plan/a/PlanAParserVisitor.java @@ -113,6 +113,12 @@ interface PlanAParserVisitor extends ParseTreeVisitor { * @return the visitor result */ T visitEmpty(PlanAParser.EmptyContext ctx); + /** + * Visit a parse tree produced by {@link PlanAParser#emptyscope}. + * @param ctx the parse tree + * @return the visitor result + */ + T visitEmptyscope(PlanAParser.EmptyscopeContext ctx); /** * Visit a parse tree produced by {@link PlanAParser#initializer}. * @param ctx the parse tree @@ -143,6 +149,12 @@ interface PlanAParserVisitor extends ParseTreeVisitor { * @return the visitor result */ T visitDeclvar(PlanAParser.DeclvarContext ctx); + /** + * Visit a parse tree produced by {@link PlanAParser#trap}. + * @param ctx the parse tree + * @return the visitor result + */ + T visitTrap(PlanAParser.TrapContext ctx); /** * Visit a parse tree produced by the {@code comp} * labeled alternative in {@link PlanAParser#expression}. diff --git a/plugins/lang-plan-a/src/main/java/org/elasticsearch/plan/a/PlanAPlugin.java b/plugins/lang-plan-a/src/main/java/org/elasticsearch/plan/a/PlanAPlugin.java index c893cd38324..d87c9a9e1c4 100644 --- a/plugins/lang-plan-a/src/main/java/org/elasticsearch/plan/a/PlanAPlugin.java +++ b/plugins/lang-plan-a/src/main/java/org/elasticsearch/plan/a/PlanAPlugin.java @@ -34,7 +34,7 @@ public final class PlanAPlugin extends Plugin { return "Plan A scripting language for Elasticsearch"; } - public void onModule(ScriptModule module) { + public void onModule(final ScriptModule module) { module.addScriptEngine(PlanAScriptEngineService.class); } } diff --git a/plugins/lang-plan-a/src/main/java/org/elasticsearch/plan/a/PlanAScriptEngineService.java b/plugins/lang-plan-a/src/main/java/org/elasticsearch/plan/a/PlanAScriptEngineService.java index 69736f311e6..858bf21021c 100644 --- a/plugins/lang-plan-a/src/main/java/org/elasticsearch/plan/a/PlanAScriptEngineService.java +++ b/plugins/lang-plan-a/src/main/java/org/elasticsearch/plan/a/PlanAScriptEngineService.java @@ -40,117 +40,199 @@ import java.security.ProtectionDomain; import java.util.HashMap; import java.util.Map; +/** + * Implementation of a ScriptEngine for the Plan A language. + */ public class PlanAScriptEngineService extends AbstractComponent implements ScriptEngineService { + /** + * Standard name of the Plan A language. + */ public static final String NAME = "plan-a"; - // default settings, used unless otherwise specified + + /** + * Default compiler settings to be used. + */ private static final CompilerSettings DEFAULT_COMPILER_SETTINGS = new CompilerSettings(); - public static final String NUMERIC_OVERFLOW = "numeric_overflow"; + /** + * Permissions context used during compilation. + */ + private static final AccessControlContext COMPILATION_CONTEXT; - // TODO: how should custom definitions be specified? + /** + * Setup the allowed permissions. + */ + static { + final Permissions none = new Permissions(); + none.setReadOnly(); + COMPILATION_CONTEXT = new AccessControlContext(new ProtectionDomain[] { + new ProtectionDomain(null, none) + }); + } + + /** + * Used only for testing. + */ private Definition definition = null; + /** + * Used only for testing. + */ + void setDefinition(final Definition definition) { + this.definition = definition; + } + + /** + * Constructor. + * @param settings The settings to initialize the engine with. + */ @Inject - public PlanAScriptEngineService(Settings settings) { + public PlanAScriptEngineService(final Settings settings) { super(settings); } - public void setDefinition(final Definition definition) { - this.definition = new Definition(definition); - } - + /** + * Get the type name(s) for the language. + * @return Always contains only the single name of the language. + */ @Override public String[] types() { return new String[] { NAME }; } + /** + * Get the extension(s) for the language. + * @return Always contains only the single extension of the language. + */ @Override public String[] extensions() { return new String[] { NAME }; } + /** + * Whether or not the engine is secure. + * @return Always true as the engine should be secure at runtime. + */ @Override public boolean sandboxed() { return true; } - // context used during compilation - private static final AccessControlContext COMPILATION_CONTEXT; - static { - Permissions none = new Permissions(); - none.setReadOnly(); - COMPILATION_CONTEXT = new AccessControlContext(new ProtectionDomain[] { - new ProtectionDomain(null, none) - }); - } - + /** + * Compiles a Plan A script with the specified parameters. + * @param script The code to be compiled. + * @param params The params used to modify the compiler settings on a per script basis. + * @return Compiled script object represented by an {@link Executable}. + */ @Override - public Object compile(String script, Map params) { + public Object compile(final String script, final Map params) { final CompilerSettings compilerSettings; + if (params.isEmpty()) { + // Use the default settings. compilerSettings = DEFAULT_COMPILER_SETTINGS; } else { - // custom settings + // Use custom settings specified by params. compilerSettings = new CompilerSettings(); - Map clone = new HashMap<>(params); - String value = clone.remove(NUMERIC_OVERFLOW); + Map copy = new HashMap<>(params); + String value = copy.remove(CompilerSettings.NUMERIC_OVERFLOW); + if (value != null) { - // TODO: can we get a real boolean parser in here? compilerSettings.setNumericOverflow(Boolean.parseBoolean(value)); } - if (!clone.isEmpty()) { - throw new IllegalArgumentException("Unrecognized compile-time parameter(s): " + clone); + + value = copy.remove(CompilerSettings.MAX_LOOP_COUNTER); + + if (value != null) { + compilerSettings.setMaxLoopCounter(Integer.parseInt(value)); + } + + if (!copy.isEmpty()) { + throw new IllegalArgumentException("Unrecognized compile-time parameter(s): " + copy); } } - // check we ourselves are not being called by unprivileged code - SecurityManager sm = System.getSecurityManager(); + + // Check we ourselves are not being called by unprivileged code. + final SecurityManager sm = System.getSecurityManager(); + if (sm != null) { sm.checkPermission(new SpecialPermission()); } - // create our loader (which loads compiled code with no permissions) - Compiler.Loader loader = AccessController.doPrivileged(new PrivilegedAction() { + + // Create our loader (which loads compiled code with no permissions). + final Compiler.Loader loader = AccessController.doPrivileged(new PrivilegedAction() { @Override public Compiler.Loader run() { return new Compiler.Loader(getClass().getClassLoader()); } }); - // drop all permissions to actually compile the code itself + + // Drop all permissions to actually compile the code itself. return AccessController.doPrivileged(new PrivilegedAction() { @Override public Executable run() { - return Compiler.compile(loader, "something", script, definition, compilerSettings); + return Compiler.compile(loader, "unknown", script, definition, compilerSettings); } }, COMPILATION_CONTEXT); } + /** + * Retrieve an {@link ExecutableScript} for later use. + * @param compiledScript A previously compiled script. + * @param vars The variables to be used in the script. + * @return An {@link ExecutableScript} with the currently specified variables. + */ @Override - public ExecutableScript executable(CompiledScript compiledScript, Map vars) { - return new ScriptImpl((Executable) compiledScript.compiled(), vars, null); + public ExecutableScript executable(final CompiledScript compiledScript, final Map vars) { + return new ScriptImpl((Executable)compiledScript.compiled(), vars, null); } + /** + * Retrieve a {@link SearchScript} for later use. + * @param compiledScript A previously compiled script. + * @param lookup The object that ultimately allows access to search fields. + * @param vars The variables to be used in the script. + * @return An {@link SearchScript} with the currently specified variables. + */ @Override - public SearchScript search(CompiledScript compiledScript, SearchLookup lookup, Map vars) { + public SearchScript search(final CompiledScript compiledScript, final SearchLookup lookup, final Map vars) { return new SearchScript() { + /** + * Get the search script that will have access to search field values. + * @param context The LeafReaderContext to be used. + * @return A script that will have the search fields from the current context available for use. + */ @Override - public LeafSearchScript getLeafSearchScript(LeafReaderContext context) throws IOException { - return new ScriptImpl((Executable) compiledScript.compiled(), vars, lookup.getLeafSearchLookup(context)); + public LeafSearchScript getLeafSearchScript(final LeafReaderContext context) throws IOException { + return new ScriptImpl((Executable)compiledScript.compiled(), vars, lookup.getLeafSearchLookup(context)); } + /** + * Whether or not the score is needed. + * @return Always true as it's assumed score is needed. + */ @Override public boolean needsScores() { - return true; // TODO: maybe even do these different and more like expressions. + return true; } }; } + /** + * Action taken when a script is removed from the cache. + * @param script The removed script. + */ @Override - public void scriptRemoved(CompiledScript script) { - // nothing to do + public void scriptRemoved(final CompiledScript script) { + // Nothing to do. } + /** + * Action taken when the engine is closed. + */ @Override public void close() throws IOException { - // nothing to do + // Nothing to do. } } diff --git a/plugins/lang-plan-a/src/main/java/org/elasticsearch/plan/a/ScriptImpl.java b/plugins/lang-plan-a/src/main/java/org/elasticsearch/plan/a/ScriptImpl.java index 3910cdc96f7..33fdce36d47 100644 --- a/plugins/lang-plan-a/src/main/java/org/elasticsearch/plan/a/ScriptImpl.java +++ b/plugins/lang-plan-a/src/main/java/org/elasticsearch/plan/a/ScriptImpl.java @@ -28,67 +28,128 @@ import org.elasticsearch.search.lookup.LeafSearchLookup; import java.util.HashMap; import java.util.Map; +/** + * ScriptImpl can be used as either an {@link ExecutableScript} or a {@link LeafSearchScript} + * to run a previously compiled Plan A script. + */ final class ScriptImpl implements ExecutableScript, LeafSearchScript { - final Executable executable; - final Map variables; - final LeafSearchLookup lookup; - - ScriptImpl(Executable executable, Map vars, LeafSearchLookup lookup) { + /** + * The Plan A Executable script that can be run. + */ + private final Executable executable; + + /** + * A map that can be used to access input parameters at run-time. + */ + private final Map variables; + + /** + * The lookup is used to access search field values at run-time. + */ + private final LeafSearchLookup lookup; + + /** + * Creates a ScriptImpl for the a previously compiled Plan A script. + * @param executable The previously compiled Plan A script. + * @param vars The initial variables to run the script with. + * @param lookup The lookup to allow search fields to be available if this is run as a search script. + */ + ScriptImpl(final Executable executable, final Map vars, final LeafSearchLookup lookup) { this.executable = executable; this.lookup = lookup; this.variables = new HashMap<>(); + if (vars != null) { variables.putAll(vars); } + if (lookup != null) { variables.putAll(lookup.asMap()); } } - + + /** + * Set a variable for the script to be run against. + * @param name The variable name. + * @param value The variable value. + */ @Override - public void setNextVar(String name, Object value) { + public void setNextVar(final String name, final Object value) { variables.put(name, value); } - + + /** + * Run the script. + * @return The script result. + */ @Override public Object run() { return executable.execute(variables); } - - @Override - public float runAsFloat() { - return ((Number) run()).floatValue(); - } - - @Override - public long runAsLong() { - return ((Number) run()).longValue(); - } + /** + * Run the script. + * @return The script result as a double. + */ @Override public double runAsDouble() { - return ((Number) run()).doubleValue(); + return ((Number)run()).doubleValue(); } - + + /** + * Run the script. + * @return The script result as a float. + */ @Override - public Object unwrap(Object value) { + public float runAsFloat() { + return ((Number)run()).floatValue(); + } + + /** + * Run the script. + * @return The script result as a long. + */ + @Override + public long runAsLong() { + return ((Number)run()).longValue(); + } + + /** + * This method has no effect in Plan A. + * @param value The value to unwrap. + * @return The value passed in. + */ + @Override + public Object unwrap(final Object value) { return value; } + /** + * Sets the scorer to be accessible within a script. + * @param scorer The scorer used for a search. + */ @Override - public void setScorer(Scorer scorer) { - variables.put("_score", new ScoreAccessor(scorer)); + public void setScorer(final Scorer scorer) { + variables.put("#score", new ScoreAccessor(scorer)); } + /** + * Sets the current document. + * @param doc The current document. + */ @Override - public void setDocument(int doc) { + public void setDocument(final int doc) { if (lookup != null) { lookup.setDocument(doc); } } + /** + * Sets the current source. + * @param source The current source. + */ @Override - public void setSource(Map source) { + public void setSource(final Map source) { if (lookup != null) { lookup.source().setSource(source); } diff --git a/plugins/lang-plan-a/src/main/java/org/elasticsearch/plan/a/Utility.java b/plugins/lang-plan-a/src/main/java/org/elasticsearch/plan/a/Utility.java index c31bcb91f10..f132d1edf2f 100644 --- a/plugins/lang-plan-a/src/main/java/org/elasticsearch/plan/a/Utility.java +++ b/plugins/lang-plan-a/src/main/java/org/elasticsearch/plan/a/Utility.java @@ -1,5 +1,3 @@ -package org.elasticsearch.plan.a; - /* * Licensed to Elasticsearch under one or more contributor * license agreements. See the NOTICE file distributed with @@ -19,6 +17,8 @@ package org.elasticsearch.plan.a; * under the License. */ +package org.elasticsearch.plan.a; + public class Utility { public static boolean NumberToboolean(final Number value) { return value.longValue() != 0; diff --git a/plugins/lang-plan-a/src/main/java/org/elasticsearch/plan/a/Writer.java b/plugins/lang-plan-a/src/main/java/org/elasticsearch/plan/a/Writer.java index 4f3361576c4..34b5b535afa 100644 --- a/plugins/lang-plan-a/src/main/java/org/elasticsearch/plan/a/Writer.java +++ b/plugins/lang-plan-a/src/main/java/org/elasticsearch/plan/a/Writer.java @@ -21,6 +21,7 @@ package org.elasticsearch.plan.a; import org.antlr.v4.runtime.ParserRuleContext; import org.antlr.v4.runtime.tree.ParseTree; +import org.elasticsearch.script.ScoreAccessor; import org.objectweb.asm.ClassWriter; import org.objectweb.asm.Label; import org.objectweb.asm.Opcodes; @@ -34,11 +35,6 @@ import java.util.List; import java.util.Map; import java.util.Set; -import static org.elasticsearch.plan.a.Adapter.ExpressionMetadata; -import static org.elasticsearch.plan.a.Adapter.ExtNodeMetadata; -import static org.elasticsearch.plan.a.Adapter.ExternalMetadata; -import static org.elasticsearch.plan.a.Adapter.StatementMetadata; -import static org.elasticsearch.plan.a.Adapter.error; import static org.elasticsearch.plan.a.Definition.Cast; import static org.elasticsearch.plan.a.Definition.Constructor; import static org.elasticsearch.plan.a.Definition.Field; @@ -46,6 +42,11 @@ import static org.elasticsearch.plan.a.Definition.Method; import static org.elasticsearch.plan.a.Definition.Sort; import static org.elasticsearch.plan.a.Definition.Transform; import static org.elasticsearch.plan.a.Definition.Type; +import static org.elasticsearch.plan.a.Metadata.ExpressionMetadata; +import static org.elasticsearch.plan.a.Metadata.ExtNodeMetadata; +import static org.elasticsearch.plan.a.Metadata.ExternalMetadata; +import static org.elasticsearch.plan.a.Metadata.StatementMetadata; +import static org.elasticsearch.plan.a.Metadata.error; import static org.elasticsearch.plan.a.PlanAParser.ADD; import static org.elasticsearch.plan.a.PlanAParser.AfterthoughtContext; import static org.elasticsearch.plan.a.PlanAParser.ArgumentsContext; @@ -69,6 +70,7 @@ import static org.elasticsearch.plan.a.PlanAParser.DecltypeContext; import static org.elasticsearch.plan.a.PlanAParser.DeclvarContext; import static org.elasticsearch.plan.a.PlanAParser.DoContext; import static org.elasticsearch.plan.a.PlanAParser.EmptyContext; +import static org.elasticsearch.plan.a.PlanAParser.EmptyscopeContext; import static org.elasticsearch.plan.a.PlanAParser.ExprContext; import static org.elasticsearch.plan.a.PlanAParser.ExpressionContext; import static org.elasticsearch.plan.a.PlanAParser.ExtbraceContext; @@ -103,7 +105,10 @@ import static org.elasticsearch.plan.a.PlanAParser.SUB; import static org.elasticsearch.plan.a.PlanAParser.SingleContext; import static org.elasticsearch.plan.a.PlanAParser.SourceContext; import static org.elasticsearch.plan.a.PlanAParser.StatementContext; +import static org.elasticsearch.plan.a.PlanAParser.ThrowContext; +import static org.elasticsearch.plan.a.PlanAParser.TrapContext; import static org.elasticsearch.plan.a.PlanAParser.TrueContext; +import static org.elasticsearch.plan.a.PlanAParser.TryContext; import static org.elasticsearch.plan.a.PlanAParser.USH; import static org.elasticsearch.plan.a.PlanAParser.UnaryContext; import static org.elasticsearch.plan.a.PlanAParser.WhileContext; @@ -112,18 +117,13 @@ class Writer extends PlanAParserBaseVisitor { private static class Branch { final ParserRuleContext source; - Label begin; - Label end; - Label tru; - Label fals; + Label begin = null; + Label end = null; + Label tru = null; + Label fals = null; private Branch(final ParserRuleContext source) { this.source = source; - - begin = null; - end = null; - tru = null; - fals = null; } } @@ -131,200 +131,206 @@ class Writer extends PlanAParserBaseVisitor { final static String CLASS_NAME = BASE_CLASS_NAME + "$CompiledPlanAExecutable"; private final static org.objectweb.asm.Type BASE_CLASS_TYPE = org.objectweb.asm.Type.getType(Executable.class); private final static org.objectweb.asm.Type CLASS_TYPE = - org.objectweb.asm.Type.getType("L" + CLASS_NAME.replace(".", "/") + ";"); + org.objectweb.asm.Type.getType("L" + CLASS_NAME.replace(".", "/") + ";"); + + private final static org.objectweb.asm.Type PLAN_A_ERROR_TYPE = org.objectweb.asm.Type.getType(PlanAError.class); private final static org.objectweb.asm.commons.Method CONSTRUCTOR = org.objectweb.asm.commons.Method.getMethod( - "void (org.elasticsearch.plan.a.Definition, java.lang.String, java.lang.String)"); + "void (org.elasticsearch.plan.a.Definition, java.lang.String, java.lang.String)"); private final static org.objectweb.asm.commons.Method EXECUTE = org.objectweb.asm.commons.Method.getMethod( - "java.lang.Object execute(java.util.Map)"); + "java.lang.Object execute(java.util.Map)"); private final static String SIGNATURE = "(Ljava/util/Map;)Ljava/lang/Object;"; private final static org.objectweb.asm.Type DEFINITION_TYPE = org.objectweb.asm.Type.getType(Definition.class); + private final static org.objectweb.asm.Type MAP_TYPE = org.objectweb.asm.Type.getType(Map.class); + private final static org.objectweb.asm.commons.Method MAP_GET = + org.objectweb.asm.commons.Method.getMethod("Object get(Object)"); + + private final static org.objectweb.asm.Type SCORE_ACCESSOR_TYPE = org.objectweb.asm.Type.getType(ScoreAccessor.class); + private final static org.objectweb.asm.commons.Method SCORE_ACCESSOR_FLOAT = + org.objectweb.asm.commons.Method.getMethod("float floatValue()"); + private final static org.objectweb.asm.commons.Method DEF_METHOD_CALL = org.objectweb.asm.commons.Method.getMethod( - "java.lang.Object methodCall(java.lang.Object, java.lang.String, " + + "java.lang.Object methodCall(java.lang.Object, java.lang.String, " + "org.elasticsearch.plan.a.Definition, java.lang.Object[], boolean[])"); private final static org.objectweb.asm.commons.Method DEF_ARRAY_STORE = org.objectweb.asm.commons.Method.getMethod( - "void arrayStore(java.lang.Object, java.lang.Object, java.lang.Object, " + + "void arrayStore(java.lang.Object, java.lang.Object, java.lang.Object, " + "org.elasticsearch.plan.a.Definition, boolean, boolean)"); private final static org.objectweb.asm.commons.Method DEF_ARRAY_LOAD = org.objectweb.asm.commons.Method.getMethod( - "java.lang.Object arrayLoad(java.lang.Object, java.lang.Object, " + + "java.lang.Object arrayLoad(java.lang.Object, java.lang.Object, " + "org.elasticsearch.plan.a.Definition, boolean)"); private final static org.objectweb.asm.commons.Method DEF_FIELD_STORE = org.objectweb.asm.commons.Method.getMethod( - "void fieldStore(java.lang.Object, java.lang.Object, java.lang.String, " + + "void fieldStore(java.lang.Object, java.lang.Object, java.lang.String, " + "org.elasticsearch.plan.a.Definition, boolean)"); private final static org.objectweb.asm.commons.Method DEF_FIELD_LOAD = org.objectweb.asm.commons.Method.getMethod( - "java.lang.Object fieldLoad(java.lang.Object, java.lang.String, org.elasticsearch.plan.a.Definition)"); + "java.lang.Object fieldLoad(java.lang.Object, java.lang.String, org.elasticsearch.plan.a.Definition)"); private final static org.objectweb.asm.commons.Method DEF_NOT_CALL = org.objectweb.asm.commons.Method.getMethod( - "java.lang.Object not(java.lang.Object)"); + "java.lang.Object not(java.lang.Object)"); private final static org.objectweb.asm.commons.Method DEF_NEG_CALL = org.objectweb.asm.commons.Method.getMethod( - "java.lang.Object neg(java.lang.Object)"); + "java.lang.Object neg(java.lang.Object)"); private final static org.objectweb.asm.commons.Method DEF_MUL_CALL = org.objectweb.asm.commons.Method.getMethod( - "java.lang.Object mul(java.lang.Object, java.lang.Object)"); + "java.lang.Object mul(java.lang.Object, java.lang.Object)"); private final static org.objectweb.asm.commons.Method DEF_DIV_CALL = org.objectweb.asm.commons.Method.getMethod( - "java.lang.Object div(java.lang.Object, java.lang.Object)"); + "java.lang.Object div(java.lang.Object, java.lang.Object)"); private final static org.objectweb.asm.commons.Method DEF_REM_CALL = org.objectweb.asm.commons.Method.getMethod( - "java.lang.Object rem(java.lang.Object, java.lang.Object)"); + "java.lang.Object rem(java.lang.Object, java.lang.Object)"); private final static org.objectweb.asm.commons.Method DEF_ADD_CALL = org.objectweb.asm.commons.Method.getMethod( - "java.lang.Object add(java.lang.Object, java.lang.Object)"); + "java.lang.Object add(java.lang.Object, java.lang.Object)"); private final static org.objectweb.asm.commons.Method DEF_SUB_CALL = org.objectweb.asm.commons.Method.getMethod( - "java.lang.Object sub(java.lang.Object, java.lang.Object)"); + "java.lang.Object sub(java.lang.Object, java.lang.Object)"); private final static org.objectweb.asm.commons.Method DEF_LSH_CALL = org.objectweb.asm.commons.Method.getMethod( - "java.lang.Object lsh(java.lang.Object, java.lang.Object)"); + "java.lang.Object lsh(java.lang.Object, java.lang.Object)"); private final static org.objectweb.asm.commons.Method DEF_RSH_CALL = org.objectweb.asm.commons.Method.getMethod( - "java.lang.Object rsh(java.lang.Object, java.lang.Object)"); + "java.lang.Object rsh(java.lang.Object, java.lang.Object)"); private final static org.objectweb.asm.commons.Method DEF_USH_CALL = org.objectweb.asm.commons.Method.getMethod( - "java.lang.Object ush(java.lang.Object, java.lang.Object)"); + "java.lang.Object ush(java.lang.Object, java.lang.Object)"); private final static org.objectweb.asm.commons.Method DEF_AND_CALL = org.objectweb.asm.commons.Method.getMethod( - "java.lang.Object and(java.lang.Object, java.lang.Object)"); + "java.lang.Object and(java.lang.Object, java.lang.Object)"); private final static org.objectweb.asm.commons.Method DEF_XOR_CALL = org.objectweb.asm.commons.Method.getMethod( - "java.lang.Object xor(java.lang.Object, java.lang.Object)"); + "java.lang.Object xor(java.lang.Object, java.lang.Object)"); private final static org.objectweb.asm.commons.Method DEF_OR_CALL = org.objectweb.asm.commons.Method.getMethod( - "java.lang.Object or(java.lang.Object, java.lang.Object)"); + "java.lang.Object or(java.lang.Object, java.lang.Object)"); private final static org.objectweb.asm.commons.Method DEF_EQ_CALL = org.objectweb.asm.commons.Method.getMethod( - "boolean eq(java.lang.Object, java.lang.Object)"); + "boolean eq(java.lang.Object, java.lang.Object)"); private final static org.objectweb.asm.commons.Method DEF_LT_CALL = org.objectweb.asm.commons.Method.getMethod( - "boolean lt(java.lang.Object, java.lang.Object)"); + "boolean lt(java.lang.Object, java.lang.Object)"); private final static org.objectweb.asm.commons.Method DEF_LTE_CALL = org.objectweb.asm.commons.Method.getMethod( - "boolean lte(java.lang.Object, java.lang.Object)"); + "boolean lte(java.lang.Object, java.lang.Object)"); private final static org.objectweb.asm.commons.Method DEF_GT_CALL = org.objectweb.asm.commons.Method.getMethod( - "boolean gt(java.lang.Object, java.lang.Object)"); + "boolean gt(java.lang.Object, java.lang.Object)"); private final static org.objectweb.asm.commons.Method DEF_GTE_CALL = org.objectweb.asm.commons.Method.getMethod( - "boolean gte(java.lang.Object, java.lang.Object)"); + "boolean gte(java.lang.Object, java.lang.Object)"); private final static org.objectweb.asm.Type STRINGBUILDER_TYPE = org.objectweb.asm.Type.getType(StringBuilder.class); private final static org.objectweb.asm.commons.Method STRINGBUILDER_CONSTRUCTOR = - org.objectweb.asm.commons.Method.getMethod("void ()"); + org.objectweb.asm.commons.Method.getMethod("void ()"); private final static org.objectweb.asm.commons.Method STRINGBUILDER_APPEND_BOOLEAN = - org.objectweb.asm.commons.Method.getMethod("java.lang.StringBuilder append(boolean)"); + org.objectweb.asm.commons.Method.getMethod("java.lang.StringBuilder append(boolean)"); private final static org.objectweb.asm.commons.Method STRINGBUILDER_APPEND_CHAR = - org.objectweb.asm.commons.Method.getMethod("java.lang.StringBuilder append(char)"); + org.objectweb.asm.commons.Method.getMethod("java.lang.StringBuilder append(char)"); private final static org.objectweb.asm.commons.Method STRINGBUILDER_APPEND_INT = - org.objectweb.asm.commons.Method.getMethod("java.lang.StringBuilder append(int)"); + org.objectweb.asm.commons.Method.getMethod("java.lang.StringBuilder append(int)"); private final static org.objectweb.asm.commons.Method STRINGBUILDER_APPEND_LONG = - org.objectweb.asm.commons.Method.getMethod("java.lang.StringBuilder append(long)"); + org.objectweb.asm.commons.Method.getMethod("java.lang.StringBuilder append(long)"); private final static org.objectweb.asm.commons.Method STRINGBUILDER_APPEND_FLOAT = - org.objectweb.asm.commons.Method.getMethod("java.lang.StringBuilder append(float)"); + org.objectweb.asm.commons.Method.getMethod("java.lang.StringBuilder append(float)"); private final static org.objectweb.asm.commons.Method STRINGBUILDER_APPEND_DOUBLE = - org.objectweb.asm.commons.Method.getMethod("java.lang.StringBuilder append(double)"); + org.objectweb.asm.commons.Method.getMethod("java.lang.StringBuilder append(double)"); private final static org.objectweb.asm.commons.Method STRINGBUILDER_APPEND_STRING = - org.objectweb.asm.commons.Method.getMethod("java.lang.StringBuilder append(java.lang.String)"); + org.objectweb.asm.commons.Method.getMethod("java.lang.StringBuilder append(java.lang.String)"); private final static org.objectweb.asm.commons.Method STRINGBUILDER_APPEND_OBJECT = - org.objectweb.asm.commons.Method.getMethod("java.lang.StringBuilder append(java.lang.Object)"); + org.objectweb.asm.commons.Method.getMethod("java.lang.StringBuilder append(java.lang.Object)"); private final static org.objectweb.asm.commons.Method STRINGBUILDER_TOSTRING = - org.objectweb.asm.commons.Method.getMethod("java.lang.String toString()"); + org.objectweb.asm.commons.Method.getMethod("java.lang.String toString()"); private final static org.objectweb.asm.commons.Method TOINTEXACT_LONG = - org.objectweb.asm.commons.Method.getMethod("int toIntExact(long)"); + org.objectweb.asm.commons.Method.getMethod("int toIntExact(long)"); private final static org.objectweb.asm.commons.Method NEGATEEXACT_INT = - org.objectweb.asm.commons.Method.getMethod("int negateExact(int)"); + org.objectweb.asm.commons.Method.getMethod("int negateExact(int)"); private final static org.objectweb.asm.commons.Method NEGATEEXACT_LONG = - org.objectweb.asm.commons.Method.getMethod("long negateExact(long)"); + org.objectweb.asm.commons.Method.getMethod("long negateExact(long)"); private final static org.objectweb.asm.commons.Method MULEXACT_INT = - org.objectweb.asm.commons.Method.getMethod("int multiplyExact(int, int)"); + org.objectweb.asm.commons.Method.getMethod("int multiplyExact(int, int)"); private final static org.objectweb.asm.commons.Method MULEXACT_LONG = - org.objectweb.asm.commons.Method.getMethod("long multiplyExact(long, long)"); + org.objectweb.asm.commons.Method.getMethod("long multiplyExact(long, long)"); private final static org.objectweb.asm.commons.Method ADDEXACT_INT = - org.objectweb.asm.commons.Method.getMethod("int addExact(int, int)"); + org.objectweb.asm.commons.Method.getMethod("int addExact(int, int)"); private final static org.objectweb.asm.commons.Method ADDEXACT_LONG = - org.objectweb.asm.commons.Method.getMethod("long addExact(long, long)"); + org.objectweb.asm.commons.Method.getMethod("long addExact(long, long)"); private final static org.objectweb.asm.commons.Method SUBEXACT_INT = - org.objectweb.asm.commons.Method.getMethod("int subtractExact(int, int)"); + org.objectweb.asm.commons.Method.getMethod("int subtractExact(int, int)"); private final static org.objectweb.asm.commons.Method SUBEXACT_LONG = - org.objectweb.asm.commons.Method.getMethod("long subtractExact(long, long)"); + org.objectweb.asm.commons.Method.getMethod("long subtractExact(long, long)"); private final static org.objectweb.asm.commons.Method CHECKEQUALS = - org.objectweb.asm.commons.Method.getMethod("boolean checkEquals(java.lang.Object, java.lang.Object)"); + org.objectweb.asm.commons.Method.getMethod("boolean checkEquals(java.lang.Object, java.lang.Object)"); private final static org.objectweb.asm.commons.Method TOBYTEEXACT_INT = - org.objectweb.asm.commons.Method.getMethod("byte toByteExact(int)"); + org.objectweb.asm.commons.Method.getMethod("byte toByteExact(int)"); private final static org.objectweb.asm.commons.Method TOBYTEEXACT_LONG = - org.objectweb.asm.commons.Method.getMethod("byte toByteExact(long)"); + org.objectweb.asm.commons.Method.getMethod("byte toByteExact(long)"); private final static org.objectweb.asm.commons.Method TOBYTEWOOVERFLOW_FLOAT = - org.objectweb.asm.commons.Method.getMethod("byte toByteWithoutOverflow(float)"); + org.objectweb.asm.commons.Method.getMethod("byte toByteWithoutOverflow(float)"); private final static org.objectweb.asm.commons.Method TOBYTEWOOVERFLOW_DOUBLE = - org.objectweb.asm.commons.Method.getMethod("byte toByteWithoutOverflow(double)"); + org.objectweb.asm.commons.Method.getMethod("byte toByteWithoutOverflow(double)"); private final static org.objectweb.asm.commons.Method TOSHORTEXACT_INT = - org.objectweb.asm.commons.Method.getMethod("short toShortExact(int)"); + org.objectweb.asm.commons.Method.getMethod("short toShortExact(int)"); private final static org.objectweb.asm.commons.Method TOSHORTEXACT_LONG = - org.objectweb.asm.commons.Method.getMethod("short toShortExact(long)"); + org.objectweb.asm.commons.Method.getMethod("short toShortExact(long)"); private final static org.objectweb.asm.commons.Method TOSHORTWOOVERFLOW_FLOAT = - org.objectweb.asm.commons.Method.getMethod("short toShortWithoutOverflow(float)"); + org.objectweb.asm.commons.Method.getMethod("short toShortWithoutOverflow(float)"); private final static org.objectweb.asm.commons.Method TOSHORTWOOVERFLOW_DOUBLE = - org.objectweb.asm.commons.Method.getMethod("short toShortWithoutOverflow(double)"); + org.objectweb.asm.commons.Method.getMethod("short toShortWithoutOverflow(double)"); private final static org.objectweb.asm.commons.Method TOCHAREXACT_INT = - org.objectweb.asm.commons.Method.getMethod("char toCharExact(int)"); + org.objectweb.asm.commons.Method.getMethod("char toCharExact(int)"); private final static org.objectweb.asm.commons.Method TOCHAREXACT_LONG = - org.objectweb.asm.commons.Method.getMethod("char toCharExact(long)"); + org.objectweb.asm.commons.Method.getMethod("char toCharExact(long)"); private final static org.objectweb.asm.commons.Method TOCHARWOOVERFLOW_FLOAT = - org.objectweb.asm.commons.Method.getMethod("char toCharWithoutOverflow(float)"); + org.objectweb.asm.commons.Method.getMethod("char toCharWithoutOverflow(float)"); private final static org.objectweb.asm.commons.Method TOCHARWOOVERFLOW_DOUBLE = - org.objectweb.asm.commons.Method.getMethod("char toCharWithoutOverflow(double)"); + org.objectweb.asm.commons.Method.getMethod("char toCharWithoutOverflow(double)"); private final static org.objectweb.asm.commons.Method TOINTWOOVERFLOW_FLOAT = - org.objectweb.asm.commons.Method.getMethod("int toIntWithoutOverflow(float)"); + org.objectweb.asm.commons.Method.getMethod("int toIntWithoutOverflow(float)"); private final static org.objectweb.asm.commons.Method TOINTWOOVERFLOW_DOUBLE = - org.objectweb.asm.commons.Method.getMethod("int toIntWithoutOverflow(double)"); + org.objectweb.asm.commons.Method.getMethod("int toIntWithoutOverflow(double)"); private final static org.objectweb.asm.commons.Method TOLONGWOOVERFLOW_FLOAT = - org.objectweb.asm.commons.Method.getMethod("long toLongExactWithoutOverflow(float)"); + org.objectweb.asm.commons.Method.getMethod("long toLongExactWithoutOverflow(float)"); private final static org.objectweb.asm.commons.Method TOLONGWOOVERFLOW_DOUBLE = - org.objectweb.asm.commons.Method.getMethod("long toLongExactWithoutOverflow(double)"); + org.objectweb.asm.commons.Method.getMethod("long toLongExactWithoutOverflow(double)"); private final static org.objectweb.asm.commons.Method TOFLOATWOOVERFLOW_DOUBLE = - org.objectweb.asm.commons.Method.getMethod("float toFloatWithoutOverflow(double)"); + org.objectweb.asm.commons.Method.getMethod("float toFloatWithoutOverflow(double)"); private final static org.objectweb.asm.commons.Method MULWOOVERLOW_FLOAT = - org.objectweb.asm.commons.Method.getMethod("float multiplyWithoutOverflow(float, float)"); + org.objectweb.asm.commons.Method.getMethod("float multiplyWithoutOverflow(float, float)"); private final static org.objectweb.asm.commons.Method MULWOOVERLOW_DOUBLE = - org.objectweb.asm.commons.Method.getMethod("double multiplyWithoutOverflow(double, double)"); + org.objectweb.asm.commons.Method.getMethod("double multiplyWithoutOverflow(double, double)"); private final static org.objectweb.asm.commons.Method DIVWOOVERLOW_INT = - org.objectweb.asm.commons.Method.getMethod("int divideWithoutOverflow(int, int)"); + org.objectweb.asm.commons.Method.getMethod("int divideWithoutOverflow(int, int)"); private final static org.objectweb.asm.commons.Method DIVWOOVERLOW_LONG = - org.objectweb.asm.commons.Method.getMethod("long divideWithoutOverflow(long, long)"); + org.objectweb.asm.commons.Method.getMethod("long divideWithoutOverflow(long, long)"); private final static org.objectweb.asm.commons.Method DIVWOOVERLOW_FLOAT = - org.objectweb.asm.commons.Method.getMethod("float divideWithoutOverflow(float, float)"); + org.objectweb.asm.commons.Method.getMethod("float divideWithoutOverflow(float, float)"); private final static org.objectweb.asm.commons.Method DIVWOOVERLOW_DOUBLE = - org.objectweb.asm.commons.Method.getMethod("double divideWithoutOverflow(double, double)"); + org.objectweb.asm.commons.Method.getMethod("double divideWithoutOverflow(double, double)"); private final static org.objectweb.asm.commons.Method REMWOOVERLOW_FLOAT = - org.objectweb.asm.commons.Method.getMethod("float remainderWithoutOverflow(float, float)"); + org.objectweb.asm.commons.Method.getMethod("float remainderWithoutOverflow(float, float)"); private final static org.objectweb.asm.commons.Method REMWOOVERLOW_DOUBLE = - org.objectweb.asm.commons.Method.getMethod("double remainderWithoutOverflow(double, double)"); + org.objectweb.asm.commons.Method.getMethod("double remainderWithoutOverflow(double, double)"); private final static org.objectweb.asm.commons.Method ADDWOOVERLOW_FLOAT = - org.objectweb.asm.commons.Method.getMethod("float addWithoutOverflow(float, float)"); + org.objectweb.asm.commons.Method.getMethod("float addWithoutOverflow(float, float)"); private final static org.objectweb.asm.commons.Method ADDWOOVERLOW_DOUBLE = - org.objectweb.asm.commons.Method.getMethod("double addWithoutOverflow(double, double)"); + org.objectweb.asm.commons.Method.getMethod("double addWithoutOverflow(double, double)"); private final static org.objectweb.asm.commons.Method SUBWOOVERLOW_FLOAT = - org.objectweb.asm.commons.Method.getMethod("float subtractWithoutOverflow(float, float)"); + org.objectweb.asm.commons.Method.getMethod("float subtractWithoutOverflow(float, float)"); private final static org.objectweb.asm.commons.Method SUBWOOVERLOW_DOUBLE = - org.objectweb.asm.commons.Method.getMethod("double subtractWithoutOverflow(double, double)"); + org.objectweb.asm.commons.Method.getMethod("double subtractWithoutOverflow(double, double)"); - static byte[] write(Adapter adapter) { - Writer writer = new Writer(adapter); + static byte[] write(Metadata metadata) { + Writer writer = new Writer(metadata); return writer.getBytes(); } - private final Adapter adapter; + private final Metadata metadata; private final Definition definition; private final ParseTree root; private final String source; private final CompilerSettings settings; - private final Map branches; - private final Deque jumps; - private final Set strings; + private final Map branches = new HashMap<>(); + private final Deque jumps = new ArrayDeque<>(); + private final Set strings = new HashSet<>(); private ClassWriter writer; private GeneratorAdapter execute; - private Writer(final Adapter adapter) { - this.adapter = adapter; - definition = adapter.definition; - root = adapter.root; - source = adapter.source; - settings = adapter.settings; - - branches = new HashMap<>(); - jumps = new ArrayDeque<>(); - strings = new HashSet<>(); + private Writer(final Metadata metadata) { + this.metadata = metadata; + definition = metadata.definition; + root = metadata.root; + source = metadata.source; + settings = metadata.settings; writeBegin(); writeConstructor(); @@ -377,19 +383,39 @@ class Writer extends PlanAParserBaseVisitor { private void writeExecute() { final int access = Opcodes.ACC_PUBLIC | Opcodes.ACC_SYNTHETIC; execute = new GeneratorAdapter(access, EXECUTE, SIGNATURE, null, writer); + + final Label fals = new Label(); + final Label end = new Label(); + execute.visitVarInsn(Opcodes.ALOAD, metadata.inputValueSlot); + execute.push("#score"); + execute.invokeInterface(MAP_TYPE, MAP_GET); + execute.dup(); + execute.ifNull(fals); + execute.checkCast(SCORE_ACCESSOR_TYPE); + execute.invokeVirtual(SCORE_ACCESSOR_TYPE, SCORE_ACCESSOR_FLOAT); + execute.goTo(end); + execute.mark(fals); + execute.pop(); + execute.push(0F); + execute.mark(end); + execute.visitVarInsn(Opcodes.FSTORE, metadata.scoreValueSlot); + + execute.push(settings.getMaxLoopCounter()); + execute.visitVarInsn(Opcodes.ISTORE, metadata.loopCounterSlot); + visit(root); execute.endMethod(); } @Override public Void visitSource(final SourceContext ctx) { - final StatementMetadata sourcesmd = adapter.getStatementMetadata(ctx); + final StatementMetadata sourcesmd = metadata.getStatementMetadata(ctx); for (final StatementContext sctx : ctx.statement()) { visit(sctx); } - if (!sourcesmd.allReturn) { + if (!sourcesmd.methodEscape) { execute.visitInsn(Opcodes.ACONST_NULL); execute.returnValue(); } @@ -408,11 +434,11 @@ class Writer extends PlanAParserBaseVisitor { visit(exprctx); final BlockContext blockctx0 = ctx.block(0); - final StatementMetadata blockmd0 = adapter.getStatementMetadata(blockctx0); + final StatementMetadata blockmd0 = metadata.getStatementMetadata(blockctx0); visit(blockctx0); if (els) { - if (!blockmd0.allExit) { + if (!blockmd0.allLast) { execute.goTo(branch.end); } @@ -438,15 +464,20 @@ class Writer extends PlanAParserBaseVisitor { visit(exprctx); final BlockContext blockctx = ctx.block(); - boolean allexit = false; + boolean allLast = false; if (blockctx != null) { - StatementMetadata blocksmd = adapter.getStatementMetadata(blockctx); - allexit = blocksmd.allExit; + final StatementMetadata blocksmd = metadata.getStatementMetadata(blockctx); + allLast = blocksmd.allLast; + writeLoopCounter(blocksmd.count > 0 ? blocksmd.count : 1); visit(blockctx); + } else if (ctx.empty() != null) { + writeLoopCounter(1); + } else { + throw new IllegalStateException(error(ctx) + "Unexpected writer state."); } - if (!allexit) { + if (!allLast) { execute.goTo(branch.begin); } @@ -460,23 +491,21 @@ class Writer extends PlanAParserBaseVisitor { public Void visitDo(final DoContext ctx) { final ExpressionContext exprctx = ctx.expression(); final Branch branch = markBranch(ctx, exprctx); + Label start = new Label(); branch.begin = new Label(); branch.end = new Label(); branch.fals = branch.end; + final BlockContext blockctx = ctx.block(); + final StatementMetadata blocksmd = metadata.getStatementMetadata(blockctx); + jumps.push(branch); + execute.mark(start); + visit(blockctx); execute.mark(branch.begin); - - final BlockContext bctx = ctx.block(); - final StatementMetadata blocksmd = adapter.getStatementMetadata(bctx); - visit(bctx); - visit(exprctx); - - if (!blocksmd.allExit) { - execute.goTo(branch.begin); - } - + writeLoopCounter(blocksmd.count > 0 ? blocksmd.count : 1); + execute.goTo(start); execute.mark(branch.end); jumps.pop(); @@ -506,12 +535,24 @@ class Writer extends PlanAParserBaseVisitor { } final BlockContext blockctx = ctx.block(); - boolean allexit = false; + boolean allLast = false; if (blockctx != null) { - StatementMetadata blocksmd = adapter.getStatementMetadata(blockctx); - allexit = blocksmd.allExit; + StatementMetadata blocksmd = metadata.getStatementMetadata(blockctx); + allLast = blocksmd.allLast; + + int count = blocksmd.count > 0 ? blocksmd.count : 1; + + if (atctx != null) { + ++count; + } + + writeLoopCounter(count); visit(blockctx); + } else if (ctx.empty() != null) { + writeLoopCounter(1); + } else { + throw new IllegalStateException(error(ctx) + "Unexpected writer state."); } if (atctx != null) { @@ -519,7 +560,7 @@ class Writer extends PlanAParserBaseVisitor { visit(atctx); } - if (atctx != null || !allexit) { + if (atctx != null || !allLast) { execute.goTo(start); } @@ -560,14 +601,56 @@ class Writer extends PlanAParserBaseVisitor { return null; } + @Override + public Void visitTry(final TryContext ctx) { + final TrapContext[] trapctxs = new TrapContext[ctx.trap().size()]; + ctx.trap().toArray(trapctxs); + final Branch branch = markBranch(ctx, trapctxs); + + Label end = new Label(); + branch.begin = new Label(); + branch.end = new Label(); + branch.tru = trapctxs.length > 1 ? end : null; + + execute.mark(branch.begin); + + final BlockContext blockctx = ctx.block(); + final StatementMetadata blocksmd = metadata.getStatementMetadata(blockctx); + visit(blockctx); + + if (!blocksmd.allLast) { + execute.goTo(end); + } + + execute.mark(branch.end); + + for (final TrapContext trapctx : trapctxs) { + visit(trapctx); + } + + if (!blocksmd.allLast || trapctxs.length > 1) { + execute.mark(end); + } + + return null; + } + + @Override + public Void visitThrow(final ThrowContext ctx) { + visit(ctx.expression()); + execute.throwException(); + + return null; + } + @Override public Void visitExpr(final ExprContext ctx) { - final StatementMetadata exprsmd = adapter.getStatementMetadata(ctx); + final StatementMetadata exprsmd = metadata.getStatementMetadata(ctx); final ExpressionContext exprctx = ctx.expression(); - final ExpressionMetadata expremd = adapter.getExpressionMetadata(exprctx); + final ExpressionMetadata expremd = metadata.getExpressionMetadata(exprctx); visit(exprctx); - if (exprsmd.allReturn) { + if (exprsmd.methodEscape) { execute.returnValue(); } else { writePop(expremd.to.type.getSize()); @@ -605,7 +688,9 @@ class Writer extends PlanAParserBaseVisitor { if (declctx != null) { visit(declctx); } else if (exprctx != null) { + final ExpressionMetadata expremd = metadata.getExpressionMetadata(exprctx); visit(exprctx); + writePop(expremd.to.type.getSize()); } else { throw new IllegalStateException(error(ctx) + "Unexpected writer state."); } @@ -615,7 +700,10 @@ class Writer extends PlanAParserBaseVisitor { @Override public Void visitAfterthought(AfterthoughtContext ctx) { + final ExpressionContext exprctx = ctx.expression(); + final ExpressionMetadata expremd = metadata.getExpressionMetadata(exprctx); visit(ctx.expression()); + writePop(expremd.to.type.getSize()); return null; } @@ -636,7 +724,7 @@ class Writer extends PlanAParserBaseVisitor { @Override public Void visitDeclvar(final DeclvarContext ctx) { - final ExpressionMetadata declvaremd = adapter.getExpressionMetadata(ctx); + final ExpressionMetadata declvaremd = metadata.getExpressionMetadata(ctx); final org.objectweb.asm.Type type = declvaremd.to.type; final Sort sort = declvaremd.to.sort; final int slot = (int)declvaremd.postConst; @@ -666,6 +754,34 @@ class Writer extends PlanAParserBaseVisitor { return null; } + @Override + public Void visitTrap(final TrapContext ctx) { + final StatementMetadata trapsmd = metadata.getStatementMetadata(ctx); + + final Branch branch = getBranch(ctx); + final Label jump = new Label(); + + final BlockContext blockctx = ctx.block(); + final EmptyscopeContext emptyctx = ctx.emptyscope(); + + execute.mark(jump); + writeLoadStoreVariable(ctx, true, trapsmd.exception, trapsmd.slot); + + if (blockctx != null) { + visit(ctx.block()); + } else if (emptyctx == null) { + throw new IllegalStateException(error(ctx) + "Unexpected writer state."); + } + + execute.visitTryCatchBlock(branch.begin, branch.end, jump, trapsmd.exception.type.getInternalName()); + + if (branch.tru != null && !trapsmd.allLast) { + execute.goTo(branch.tru); + } + + return null; + } + @Override public Void visitPrecedence(final PrecedenceContext ctx) { throw new UnsupportedOperationException(error(ctx) + "Unexpected writer state."); @@ -673,7 +789,7 @@ class Writer extends PlanAParserBaseVisitor { @Override public Void visitNumeric(final NumericContext ctx) { - final ExpressionMetadata numericemd = adapter.getExpressionMetadata(ctx); + final ExpressionMetadata numericemd = metadata.getExpressionMetadata(ctx); final Object postConst = numericemd.postConst; if (postConst == null) { @@ -690,7 +806,7 @@ class Writer extends PlanAParserBaseVisitor { @Override public Void visitChar(final CharContext ctx) { - final ExpressionMetadata charemd = adapter.getExpressionMetadata(ctx); + final ExpressionMetadata charemd = metadata.getExpressionMetadata(ctx); final Object postConst = charemd.postConst; if (postConst == null) { @@ -707,7 +823,7 @@ class Writer extends PlanAParserBaseVisitor { @Override public Void visitTrue(final TrueContext ctx) { - final ExpressionMetadata trueemd = adapter.getExpressionMetadata(ctx); + final ExpressionMetadata trueemd = metadata.getExpressionMetadata(ctx); final Object postConst = trueemd.postConst; final Branch branch = getBranch(ctx); @@ -727,7 +843,7 @@ class Writer extends PlanAParserBaseVisitor { @Override public Void visitFalse(final FalseContext ctx) { - final ExpressionMetadata falseemd = adapter.getExpressionMetadata(ctx); + final ExpressionMetadata falseemd = metadata.getExpressionMetadata(ctx); final Object postConst = falseemd.postConst; final Branch branch = getBranch(ctx); @@ -747,7 +863,7 @@ class Writer extends PlanAParserBaseVisitor { @Override public Void visitNull(final NullContext ctx) { - final ExpressionMetadata nullemd = adapter.getExpressionMetadata(ctx); + final ExpressionMetadata nullemd = metadata.getExpressionMetadata(ctx); execute.visitInsn(Opcodes.ACONST_NULL); checkWriteCast(nullemd); @@ -758,7 +874,7 @@ class Writer extends PlanAParserBaseVisitor { @Override public Void visitExternal(final ExternalContext ctx) { - final ExpressionMetadata expremd = adapter.getExpressionMetadata(ctx); + final ExpressionMetadata expremd = metadata.getExpressionMetadata(ctx); visit(ctx.extstart()); checkWriteCast(expremd); checkWriteBranch(ctx); @@ -769,7 +885,7 @@ class Writer extends PlanAParserBaseVisitor { @Override public Void visitPostinc(final PostincContext ctx) { - final ExpressionMetadata expremd = adapter.getExpressionMetadata(ctx); + final ExpressionMetadata expremd = metadata.getExpressionMetadata(ctx); visit(ctx.extstart()); checkWriteCast(expremd); checkWriteBranch(ctx); @@ -779,7 +895,7 @@ class Writer extends PlanAParserBaseVisitor { @Override public Void visitPreinc(final PreincContext ctx) { - final ExpressionMetadata expremd = adapter.getExpressionMetadata(ctx); + final ExpressionMetadata expremd = metadata.getExpressionMetadata(ctx); visit(ctx.extstart()); checkWriteCast(expremd); checkWriteBranch(ctx); @@ -789,7 +905,7 @@ class Writer extends PlanAParserBaseVisitor { @Override public Void visitUnary(final UnaryContext ctx) { - final ExpressionMetadata unaryemd = adapter.getExpressionMetadata(ctx); + final ExpressionMetadata unaryemd = metadata.getExpressionMetadata(ctx); final Object postConst = unaryemd.postConst; final Object preConst = unaryemd.preConst; final Branch branch = getBranch(ctx); @@ -891,7 +1007,7 @@ class Writer extends PlanAParserBaseVisitor { @Override public Void visitCast(final CastContext ctx) { - final ExpressionMetadata castemd = adapter.getExpressionMetadata(ctx); + final ExpressionMetadata castemd = metadata.getExpressionMetadata(ctx); final Object postConst = castemd.postConst; if (postConst == null) { @@ -908,7 +1024,7 @@ class Writer extends PlanAParserBaseVisitor { @Override public Void visitBinary(final BinaryContext ctx) { - final ExpressionMetadata binaryemd = adapter.getExpressionMetadata(ctx); + final ExpressionMetadata binaryemd = metadata.getExpressionMetadata(ctx); final Object postConst = binaryemd.postConst; final Object preConst = binaryemd.preConst; final Branch branch = getBranch(ctx); @@ -930,7 +1046,7 @@ class Writer extends PlanAParserBaseVisitor { } final ExpressionContext exprctx0 = ctx.expression(0); - final ExpressionMetadata expremd0 = adapter.getExpressionMetadata(exprctx0); + final ExpressionMetadata expremd0 = metadata.getExpressionMetadata(exprctx0); strings.add(exprctx0); visit(exprctx0); @@ -940,7 +1056,7 @@ class Writer extends PlanAParserBaseVisitor { } final ExpressionContext exprctx1 = ctx.expression(1); - final ExpressionMetadata expremd1 = adapter.getExpressionMetadata(exprctx1); + final ExpressionMetadata expremd1 = metadata.getExpressionMetadata(exprctx1); strings.add(exprctx1); visit(exprctx1); @@ -990,7 +1106,7 @@ class Writer extends PlanAParserBaseVisitor { @Override public Void visitComp(final CompContext ctx) { - final ExpressionMetadata compemd = adapter.getExpressionMetadata(ctx); + final ExpressionMetadata compemd = metadata.getExpressionMetadata(ctx); final Object postConst = compemd.postConst; final Object preConst = compemd.preConst; final Branch branch = getBranch(ctx); @@ -1014,10 +1130,10 @@ class Writer extends PlanAParserBaseVisitor { } } else { final ExpressionContext exprctx0 = ctx.expression(0); - final ExpressionMetadata expremd0 = adapter.getExpressionMetadata(exprctx0); + final ExpressionMetadata expremd0 = metadata.getExpressionMetadata(exprctx0); final ExpressionContext exprctx1 = ctx.expression(1); - final ExpressionMetadata expremd1 = adapter.getExpressionMetadata(exprctx1); + final ExpressionMetadata expremd1 = metadata.getExpressionMetadata(exprctx1); final org.objectweb.asm.Type type = expremd1.to.type; final Sort sort1 = expremd1.to.sort; @@ -1033,9 +1149,9 @@ class Writer extends PlanAParserBaseVisitor { final Label end = new Label(); final boolean eq = (ctx.EQ() != null || ctx.EQR() != null) && (tru || !fals) || - (ctx.NE() != null || ctx.NER() != null) && fals; + (ctx.NE() != null || ctx.NER() != null) && fals; final boolean ne = (ctx.NE() != null || ctx.NER() != null) && (tru || !fals) || - (ctx.EQ() != null || ctx.EQR() != null) && fals; + (ctx.EQ() != null || ctx.EQR() != null) && fals; final boolean lt = ctx.LT() != null && (tru || !fals) || ctx.GTE() != null && fals; final boolean lte = ctx.LTE() != null && (tru || !fals) || ctx.GT() != null && fals; final boolean gt = ctx.GT() != null && (tru || !fals) || ctx.LTE() != null && fals; @@ -1156,7 +1272,7 @@ class Writer extends PlanAParserBaseVisitor { @Override public Void visitBool(final BoolContext ctx) { - final ExpressionMetadata boolemd = adapter.getExpressionMetadata(ctx); + final ExpressionMetadata boolemd = metadata.getExpressionMetadata(ctx); final Object postConst = boolemd.postConst; final Object preConst = boolemd.preConst; final Branch branch = getBranch(ctx); @@ -1255,7 +1371,7 @@ class Writer extends PlanAParserBaseVisitor { @Override public Void visitConditional(final ConditionalContext ctx) { - final ExpressionMetadata condemd = adapter.getExpressionMetadata(ctx); + final ExpressionMetadata condemd = metadata.getExpressionMetadata(ctx); final Branch branch = getBranch(ctx); final ExpressionContext expr0 = ctx.expression(0); @@ -1286,7 +1402,7 @@ class Writer extends PlanAParserBaseVisitor { @Override public Void visitAssignment(final AssignmentContext ctx) { - final ExpressionMetadata expremd = adapter.getExpressionMetadata(ctx); + final ExpressionMetadata expremd = metadata.getExpressionMetadata(ctx); visit(ctx.extstart()); checkWriteCast(expremd); checkWriteBranch(ctx); @@ -1296,10 +1412,10 @@ class Writer extends PlanAParserBaseVisitor { @Override public Void visitExtstart(ExtstartContext ctx) { - final ExternalMetadata startemd = adapter.getExternalMetadata(ctx); + final ExternalMetadata startemd = metadata.getExternalMetadata(ctx); if (startemd.token == ADD) { - final ExpressionMetadata storeemd = adapter.getExpressionMetadata(startemd.storeExpr); + final ExpressionMetadata storeemd = metadata.getExpressionMetadata(startemd.storeExpr); if (startemd.current.sort == Sort.STRING || storeemd.from.sort == Sort.STRING) { writeNewStrings(); @@ -1372,7 +1488,7 @@ class Writer extends PlanAParserBaseVisitor { @Override public Void visitExtcast(final ExtcastContext ctx) { - ExtNodeMetadata castenmd = adapter.getExtNodeMetadata(ctx); + ExtNodeMetadata castenmd = metadata.getExtNodeMetadata(ctx); final ExtprecContext precctx = ctx.extprec(); final ExtcastContext castctx = ctx.extcast(); @@ -1404,7 +1520,7 @@ class Writer extends PlanAParserBaseVisitor { @Override public Void visitExtbrace(final ExtbraceContext ctx) { - final ExpressionContext exprctx = adapter.updateExpressionTree(ctx.expression()); + final ExpressionContext exprctx = metadata.updateExpressionTree(ctx.expression()); visit(exprctx); writeLoadStoreExternal(ctx); @@ -1508,7 +1624,7 @@ class Writer extends PlanAParserBaseVisitor { @Override public Void visitExtstring(ExtstringContext ctx) { - final ExtNodeMetadata stringenmd = adapter.getExtNodeMetadata(ctx); + final ExtNodeMetadata stringenmd = metadata.getExtNodeMetadata(ctx); writeConstant(ctx, stringenmd.target); @@ -1531,7 +1647,7 @@ class Writer extends PlanAParserBaseVisitor { @Override public Void visitIncrement(IncrementContext ctx) { - final ExpressionMetadata incremd = adapter.getExpressionMetadata(ctx); + final ExpressionMetadata incremd = metadata.getExpressionMetadata(ctx); final Object postConst = incremd.postConst; if (postConst == null) { @@ -1546,6 +1662,18 @@ class Writer extends PlanAParserBaseVisitor { return null; } + private void writeLoopCounter(final int count) { + final Label end = new Label(); + + execute.iinc(metadata.loopCounterSlot, -count); + execute.visitVarInsn(Opcodes.ILOAD, metadata.loopCounterSlot); + execute.push(0); + execute.ifICmp(GeneratorAdapter.GT, end); + execute.throwException(PLAN_A_ERROR_TYPE, + "The maximum number of statements that can be executed in a loop has been reached."); + execute.mark(end); + } + private void writeConstant(final ParserRuleContext source, final Object constant) { if (constant instanceof Number) { writeNumeric(source, constant); @@ -1618,12 +1746,12 @@ class Writer extends PlanAParserBaseVisitor { private void writeBinaryInstruction(final ParserRuleContext source, final Type type, final int token) { final Sort sort = type.sort; final boolean exact = !settings.getNumericOverflow() && - ((sort == Sort.INT || sort == Sort.LONG) && + ((sort == Sort.INT || sort == Sort.LONG) && (token == MUL || token == DIV || token == ADD || token == SUB) || (sort == Sort.FLOAT || sort == Sort.DOUBLE) && - (token == MUL || token == DIV || token == REM || token == ADD || token == SUB)); + (token == MUL || token == DIV || token == REM || token == ADD || token == SUB)); - // if its a 64-bit shift, fixup the last argument to truncate to 32-bits + // if its a 64-bit shift, fixup the lastSource argument to truncate to 32-bits // note unlike java, this means we still do binary promotion of shifts, // but it keeps things simple -- this check works because we promote shifts. if (sort == Sort.LONG && (token == LSH || token == USH || token == RSH)) { @@ -1683,7 +1811,7 @@ class Writer extends PlanAParserBaseVisitor { } } else { if ((sort == Sort.FLOAT || sort == Sort.DOUBLE) && - (token == LSH || token == USH || token == RSH || token == BWAND || token == BWXOR || token == BWOR)) { + (token == LSH || token == USH || token == RSH || token == BWAND || token == BWXOR || token == BWOR)) { throw new IllegalStateException(error(source) + "Unexpected writer state."); } @@ -1731,122 +1859,122 @@ class Writer extends PlanAParserBaseVisitor { * @return true if an instruction is written, false otherwise */ private boolean writeExactInstruction(final Sort osort, final Sort psort) { - if (psort == Sort.DOUBLE) { - if (osort == Sort.FLOAT) { - execute.invokeStatic(definition.utilityType.type, TOFLOATWOOVERFLOW_DOUBLE); - } else if (osort == Sort.FLOAT_OBJ) { - execute.invokeStatic(definition.utilityType.type, TOFLOATWOOVERFLOW_DOUBLE); - execute.checkCast(definition.floatobjType.type); - } else if (osort == Sort.LONG) { - execute.invokeStatic(definition.utilityType.type, TOLONGWOOVERFLOW_DOUBLE); - } else if (osort == Sort.LONG_OBJ) { - execute.invokeStatic(definition.utilityType.type, TOLONGWOOVERFLOW_DOUBLE); - execute.checkCast(definition.longobjType.type); - } else if (osort == Sort.INT) { - execute.invokeStatic(definition.utilityType.type, TOINTWOOVERFLOW_DOUBLE); - } else if (osort == Sort.INT_OBJ) { - execute.invokeStatic(definition.utilityType.type, TOINTWOOVERFLOW_DOUBLE); - execute.checkCast(definition.intobjType.type); - } else if (osort == Sort.CHAR) { - execute.invokeStatic(definition.utilityType.type, TOCHARWOOVERFLOW_DOUBLE); - } else if (osort == Sort.CHAR_OBJ) { - execute.invokeStatic(definition.utilityType.type, TOCHARWOOVERFLOW_DOUBLE); - execute.checkCast(definition.charobjType.type); - } else if (osort == Sort.SHORT) { - execute.invokeStatic(definition.utilityType.type, TOSHORTWOOVERFLOW_DOUBLE); - } else if (osort == Sort.SHORT_OBJ) { - execute.invokeStatic(definition.utilityType.type, TOSHORTWOOVERFLOW_DOUBLE); - execute.checkCast(definition.shortobjType.type); - } else if (osort == Sort.BYTE) { - execute.invokeStatic(definition.utilityType.type, TOBYTEWOOVERFLOW_DOUBLE); - } else if (osort == Sort.BYTE_OBJ) { - execute.invokeStatic(definition.utilityType.type, TOBYTEWOOVERFLOW_DOUBLE); - execute.checkCast(definition.byteobjType.type); - } else { - return false; - } - } else if (psort == Sort.FLOAT) { - if (osort == Sort.LONG) { - execute.invokeStatic(definition.utilityType.type, TOLONGWOOVERFLOW_FLOAT); - } else if (osort == Sort.LONG_OBJ) { - execute.invokeStatic(definition.utilityType.type, TOLONGWOOVERFLOW_FLOAT); - execute.checkCast(definition.longobjType.type); - } else if (osort == Sort.INT) { - execute.invokeStatic(definition.utilityType.type, TOINTWOOVERFLOW_FLOAT); - } else if (osort == Sort.INT_OBJ) { - execute.invokeStatic(definition.utilityType.type, TOINTWOOVERFLOW_FLOAT); - execute.checkCast(definition.intobjType.type); - } else if (osort == Sort.CHAR) { - execute.invokeStatic(definition.utilityType.type, TOCHARWOOVERFLOW_FLOAT); - } else if (osort == Sort.CHAR_OBJ) { - execute.invokeStatic(definition.utilityType.type, TOCHARWOOVERFLOW_FLOAT); - execute.checkCast(definition.charobjType.type); - } else if (osort == Sort.SHORT) { - execute.invokeStatic(definition.utilityType.type, TOSHORTWOOVERFLOW_FLOAT); - } else if (osort == Sort.SHORT_OBJ) { - execute.invokeStatic(definition.utilityType.type, TOSHORTWOOVERFLOW_FLOAT); - execute.checkCast(definition.shortobjType.type); - } else if (osort == Sort.BYTE) { - execute.invokeStatic(definition.utilityType.type, TOBYTEWOOVERFLOW_FLOAT); - } else if (osort == Sort.BYTE_OBJ) { - execute.invokeStatic(definition.utilityType.type, TOBYTEWOOVERFLOW_FLOAT); - execute.checkCast(definition.byteobjType.type); - } else { - return false; - } - } else if (psort == Sort.LONG) { - if (osort == Sort.INT) { - execute.invokeStatic(definition.mathType.type, TOINTEXACT_LONG); - } else if (osort == Sort.INT_OBJ) { - execute.invokeStatic(definition.mathType.type, TOINTEXACT_LONG); - execute.checkCast(definition.intobjType.type); - } else if (osort == Sort.CHAR) { - execute.invokeStatic(definition.utilityType.type, TOCHAREXACT_LONG); - } else if (osort == Sort.CHAR_OBJ) { - execute.invokeStatic(definition.utilityType.type, TOCHAREXACT_LONG); - execute.checkCast(definition.charobjType.type); - } else if (osort == Sort.SHORT) { - execute.invokeStatic(definition.utilityType.type, TOSHORTEXACT_LONG); - } else if (osort == Sort.SHORT_OBJ) { - execute.invokeStatic(definition.utilityType.type, TOSHORTEXACT_LONG); - execute.checkCast(definition.shortobjType.type); - } else if (osort == Sort.BYTE) { - execute.invokeStatic(definition.utilityType.type, TOBYTEEXACT_LONG); - } else if (osort == Sort.BYTE_OBJ) { - execute.invokeStatic(definition.utilityType.type, TOBYTEEXACT_LONG); - execute.checkCast(definition.byteobjType.type); - } else { - return false; - } - } else if (psort == Sort.INT) { - if (osort == Sort.CHAR) { - execute.invokeStatic(definition.utilityType.type, TOCHAREXACT_INT); - } else if (osort == Sort.CHAR_OBJ) { - execute.invokeStatic(definition.utilityType.type, TOCHAREXACT_INT); - execute.checkCast(definition.charobjType.type); - } else if (osort == Sort.SHORT) { - execute.invokeStatic(definition.utilityType.type, TOSHORTEXACT_INT); - } else if (osort == Sort.SHORT_OBJ) { - execute.invokeStatic(definition.utilityType.type, TOSHORTEXACT_INT); - execute.checkCast(definition.shortobjType.type); - } else if (osort == Sort.BYTE) { - execute.invokeStatic(definition.utilityType.type, TOBYTEEXACT_INT); - } else if (osort == Sort.BYTE_OBJ) { - execute.invokeStatic(definition.utilityType.type, TOBYTEEXACT_INT); - execute.checkCast(definition.byteobjType.type); - } else { - return false; - } + if (psort == Sort.DOUBLE) { + if (osort == Sort.FLOAT) { + execute.invokeStatic(definition.utilityType.type, TOFLOATWOOVERFLOW_DOUBLE); + } else if (osort == Sort.FLOAT_OBJ) { + execute.invokeStatic(definition.utilityType.type, TOFLOATWOOVERFLOW_DOUBLE); + execute.checkCast(definition.floatobjType.type); + } else if (osort == Sort.LONG) { + execute.invokeStatic(definition.utilityType.type, TOLONGWOOVERFLOW_DOUBLE); + } else if (osort == Sort.LONG_OBJ) { + execute.invokeStatic(definition.utilityType.type, TOLONGWOOVERFLOW_DOUBLE); + execute.checkCast(definition.longobjType.type); + } else if (osort == Sort.INT) { + execute.invokeStatic(definition.utilityType.type, TOINTWOOVERFLOW_DOUBLE); + } else if (osort == Sort.INT_OBJ) { + execute.invokeStatic(definition.utilityType.type, TOINTWOOVERFLOW_DOUBLE); + execute.checkCast(definition.intobjType.type); + } else if (osort == Sort.CHAR) { + execute.invokeStatic(definition.utilityType.type, TOCHARWOOVERFLOW_DOUBLE); + } else if (osort == Sort.CHAR_OBJ) { + execute.invokeStatic(definition.utilityType.type, TOCHARWOOVERFLOW_DOUBLE); + execute.checkCast(definition.charobjType.type); + } else if (osort == Sort.SHORT) { + execute.invokeStatic(definition.utilityType.type, TOSHORTWOOVERFLOW_DOUBLE); + } else if (osort == Sort.SHORT_OBJ) { + execute.invokeStatic(definition.utilityType.type, TOSHORTWOOVERFLOW_DOUBLE); + execute.checkCast(definition.shortobjType.type); + } else if (osort == Sort.BYTE) { + execute.invokeStatic(definition.utilityType.type, TOBYTEWOOVERFLOW_DOUBLE); + } else if (osort == Sort.BYTE_OBJ) { + execute.invokeStatic(definition.utilityType.type, TOBYTEWOOVERFLOW_DOUBLE); + execute.checkCast(definition.byteobjType.type); } else { return false; } + } else if (psort == Sort.FLOAT) { + if (osort == Sort.LONG) { + execute.invokeStatic(definition.utilityType.type, TOLONGWOOVERFLOW_FLOAT); + } else if (osort == Sort.LONG_OBJ) { + execute.invokeStatic(definition.utilityType.type, TOLONGWOOVERFLOW_FLOAT); + execute.checkCast(definition.longobjType.type); + } else if (osort == Sort.INT) { + execute.invokeStatic(definition.utilityType.type, TOINTWOOVERFLOW_FLOAT); + } else if (osort == Sort.INT_OBJ) { + execute.invokeStatic(definition.utilityType.type, TOINTWOOVERFLOW_FLOAT); + execute.checkCast(definition.intobjType.type); + } else if (osort == Sort.CHAR) { + execute.invokeStatic(definition.utilityType.type, TOCHARWOOVERFLOW_FLOAT); + } else if (osort == Sort.CHAR_OBJ) { + execute.invokeStatic(definition.utilityType.type, TOCHARWOOVERFLOW_FLOAT); + execute.checkCast(definition.charobjType.type); + } else if (osort == Sort.SHORT) { + execute.invokeStatic(definition.utilityType.type, TOSHORTWOOVERFLOW_FLOAT); + } else if (osort == Sort.SHORT_OBJ) { + execute.invokeStatic(definition.utilityType.type, TOSHORTWOOVERFLOW_FLOAT); + execute.checkCast(definition.shortobjType.type); + } else if (osort == Sort.BYTE) { + execute.invokeStatic(definition.utilityType.type, TOBYTEWOOVERFLOW_FLOAT); + } else if (osort == Sort.BYTE_OBJ) { + execute.invokeStatic(definition.utilityType.type, TOBYTEWOOVERFLOW_FLOAT); + execute.checkCast(definition.byteobjType.type); + } else { + return false; + } + } else if (psort == Sort.LONG) { + if (osort == Sort.INT) { + execute.invokeStatic(definition.mathType.type, TOINTEXACT_LONG); + } else if (osort == Sort.INT_OBJ) { + execute.invokeStatic(definition.mathType.type, TOINTEXACT_LONG); + execute.checkCast(definition.intobjType.type); + } else if (osort == Sort.CHAR) { + execute.invokeStatic(definition.utilityType.type, TOCHAREXACT_LONG); + } else if (osort == Sort.CHAR_OBJ) { + execute.invokeStatic(definition.utilityType.type, TOCHAREXACT_LONG); + execute.checkCast(definition.charobjType.type); + } else if (osort == Sort.SHORT) { + execute.invokeStatic(definition.utilityType.type, TOSHORTEXACT_LONG); + } else if (osort == Sort.SHORT_OBJ) { + execute.invokeStatic(definition.utilityType.type, TOSHORTEXACT_LONG); + execute.checkCast(definition.shortobjType.type); + } else if (osort == Sort.BYTE) { + execute.invokeStatic(definition.utilityType.type, TOBYTEEXACT_LONG); + } else if (osort == Sort.BYTE_OBJ) { + execute.invokeStatic(definition.utilityType.type, TOBYTEEXACT_LONG); + execute.checkCast(definition.byteobjType.type); + } else { + return false; + } + } else if (psort == Sort.INT) { + if (osort == Sort.CHAR) { + execute.invokeStatic(definition.utilityType.type, TOCHAREXACT_INT); + } else if (osort == Sort.CHAR_OBJ) { + execute.invokeStatic(definition.utilityType.type, TOCHAREXACT_INT); + execute.checkCast(definition.charobjType.type); + } else if (osort == Sort.SHORT) { + execute.invokeStatic(definition.utilityType.type, TOSHORTEXACT_INT); + } else if (osort == Sort.SHORT_OBJ) { + execute.invokeStatic(definition.utilityType.type, TOSHORTEXACT_INT); + execute.checkCast(definition.shortobjType.type); + } else if (osort == Sort.BYTE) { + execute.invokeStatic(definition.utilityType.type, TOBYTEEXACT_INT); + } else if (osort == Sort.BYTE_OBJ) { + execute.invokeStatic(definition.utilityType.type, TOBYTEEXACT_INT); + execute.checkCast(definition.byteobjType.type); + } else { + return false; + } + } else { + return false; + } return true; } private void writeLoadStoreExternal(final ParserRuleContext source) { - final ExtNodeMetadata sourceenmd = adapter.getExtNodeMetadata(source); - final ExternalMetadata parentemd = adapter.getExternalMetadata(sourceenmd.parent); + final ExtNodeMetadata sourceenmd = metadata.getExtNodeMetadata(source); + final ExternalMetadata parentemd = metadata.getExternalMetadata(sourceenmd.parent); final boolean length = "#length".equals(sourceenmd.target); final boolean array = "#brace".equals(sourceenmd.target); @@ -1868,7 +1996,7 @@ class Writer extends PlanAParserBaseVisitor { if (length) { execute.arrayLength(); } else if (sourceenmd.last && parentemd.storeExpr != null) { - final ExpressionMetadata expremd = adapter.getExpressionMetadata(parentemd.storeExpr); + final ExpressionMetadata expremd = metadata.getExpressionMetadata(parentemd.storeExpr); final boolean cat = strings.contains(parentemd.storeExpr); if (cat) { @@ -1934,7 +2062,7 @@ class Writer extends PlanAParserBaseVisitor { boolean exact = false; if (!settings.getNumericOverflow() && expremd.typesafe && sourceenmd.type.sort != Sort.DEF && - (token == MUL || token == DIV || token == REM || token == ADD || token == SUB)) { + (token == MUL || token == DIV || token == REM || token == ADD || token == SUB)) { exact = writeExactInstruction(sourceenmd.type.sort, sourceenmd.promote.sort); } @@ -1973,7 +2101,7 @@ class Writer extends PlanAParserBaseVisitor { final boolean store, final boolean variable, final boolean field, final boolean name, final boolean array, final boolean shortcut) { - final ExtNodeMetadata sourceemd = adapter.getExtNodeMetadata(source); + final ExtNodeMetadata sourceemd = metadata.getExtNodeMetadata(source); if (variable) { writeLoadStoreVariable(source, store, sourceemd.type, (int)sourceemd.target); @@ -2030,9 +2158,9 @@ class Writer extends PlanAParserBaseVisitor { private void writeLoadStoreField(final ParserRuleContext source, final boolean store, final String name) { if (store) { - final ExtNodeMetadata sourceemd = adapter.getExtNodeMetadata(source); - final ExternalMetadata parentemd = adapter.getExternalMetadata(sourceemd.parent); - final ExpressionMetadata expremd = adapter.getExpressionMetadata(parentemd.storeExpr); + final ExtNodeMetadata sourceemd = metadata.getExtNodeMetadata(source); + final ExternalMetadata parentemd = metadata.getExternalMetadata(sourceemd.parent); + final ExpressionMetadata expremd = metadata.getExpressionMetadata(parentemd.storeExpr); execute.push(name); execute.loadThis(); @@ -2054,12 +2182,12 @@ class Writer extends PlanAParserBaseVisitor { if (type.sort == Sort.DEF) { final ExtbraceContext bracectx = (ExtbraceContext)source; - final ExpressionMetadata expremd0 = adapter.getExpressionMetadata(bracectx.expression()); + final ExpressionMetadata expremd0 = metadata.getExpressionMetadata(bracectx.expression()); if (store) { - final ExtNodeMetadata braceenmd = adapter.getExtNodeMetadata(bracectx); - final ExternalMetadata parentemd = adapter.getExternalMetadata(braceenmd.parent); - final ExpressionMetadata expremd1 = adapter.getExpressionMetadata(parentemd.storeExpr); + final ExtNodeMetadata braceenmd = metadata.getExtNodeMetadata(bracectx); + final ExternalMetadata parentemd = metadata.getExternalMetadata(braceenmd.parent); + final ExpressionMetadata expremd1 = metadata.getExpressionMetadata(parentemd.storeExpr); execute.loadThis(); execute.getField(CLASS_TYPE, "definition", DEFINITION_TYPE); @@ -2118,8 +2246,8 @@ class Writer extends PlanAParserBaseVisitor { } private void writeNewExternal(final ExtnewContext source) { - final ExtNodeMetadata sourceenmd = adapter.getExtNodeMetadata(source); - final ExternalMetadata parentemd = adapter.getExternalMetadata(sourceenmd.parent); + final ExtNodeMetadata sourceenmd = metadata.getExtNodeMetadata(source); + final ExternalMetadata parentemd = metadata.getExternalMetadata(sourceenmd.parent); final boolean makearray = "#makearray".equals(sourceenmd.target); final boolean constructor = sourceenmd.target instanceof Constructor; @@ -2155,7 +2283,7 @@ class Writer extends PlanAParserBaseVisitor { } private void writeCallExternal(final ExtcallContext source) { - final ExtNodeMetadata sourceenmd = adapter.getExtNodeMetadata(source); + final ExtNodeMetadata sourceenmd = metadata.getExtNodeMetadata(source); final boolean method = sourceenmd.target instanceof Method; final boolean def = sourceenmd.target instanceof String; @@ -2205,7 +2333,7 @@ class Writer extends PlanAParserBaseVisitor { for (int argument = 0; argument < arguments.size(); ++argument) { execute.dup(); execute.push(argument); - execute.push(adapter.getExpressionMetadata(arguments.get(argument)).typesafe); + execute.push(metadata.getExpressionMetadata(arguments.get(argument)).typesafe); execute.arrayStore(definition.booleanType.type); } diff --git a/plugins/lang-plan-a/src/test/java/org/elasticsearch/plan/a/BasicAPITests.java b/plugins/lang-plan-a/src/test/java/org/elasticsearch/plan/a/BasicAPITests.java new file mode 100644 index 00000000000..d81c4029a79 --- /dev/null +++ b/plugins/lang-plan-a/src/test/java/org/elasticsearch/plan/a/BasicAPITests.java @@ -0,0 +1,52 @@ +/* + * 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. + */ + +package org.elasticsearch.plan.a; + +public class BasicAPITests extends ScriptTestCase { + + public void testListIterator() { + assertEquals(3, exec("List x = new ArrayList(); x.add(2); x.add(3); x.add(-2); Iterator y = x.iterator(); " + + "int total = 0; while (y.hasNext()) total += y.next(); return total;")); + assertEquals(3, exec("List x = new ArrayList(); x.add(2); x.add(3); x.add(-2); Iterator y = x.iterator(); " + + "int total = 0; while (y.hasNext()) total += (int)y.next(); return total;")); + assertEquals("abc", exec("List x = new ArrayList(); x.add(\"a\"); x.add(\"b\"); x.add(\"c\"); " + + "Iterator y = x.iterator(); String total = \"\"; while (y.hasNext()) total += y.next(); return total;")); + assertEquals(3, exec("def x = new ArrayList(); x.add(2); x.add(3); x.add(-2); def y = x.iterator(); " + + "def total = 0; while (y.hasNext()) total += y.next(); return total;")); + } + + public void testSetIterator() { + assertEquals(3, exec("Set x = new HashSet(); x.add(2); x.add(3); x.add(-2); Iterator y = x.iterator(); " + + "int total = 0; while (y.hasNext()) total += y.next(); return total;")); + assertEquals(3, exec("Set x = new HashSet(); x.add(2); x.add(3); x.add(-2); Iterator y = x.iterator(); " + + "int total = 0; while (y.hasNext()) total += (int)y.next(); return total;")); + assertEquals("abc", exec("Set x = new HashSet(); x.add(\"a\"); x.add(\"b\"); x.add(\"c\"); " + + "Iterator y = x.iterator(); String total = \"\"; while (y.hasNext()) total += y.next(); return total;")); + assertEquals(3, exec("def x = new HashSet(); x.add(2); x.add(3); x.add(-2); def y = x.iterator(); " + + "def total = 0; while (y.hasNext()) total += (int)y.next(); return total;")); + } + + public void testMapIterator() { + assertEquals(3, exec("Map x = new HashMap(); x.put(2, 2); x.put(3, 3); x.put(-2, -2); Iterator y = x.keySet().iterator(); " + + "int total = 0; while (y.hasNext()) total += (int)y.next(); return total;")); + assertEquals(3, exec("Map x = new HashMap(); x.put(2, 2); x.put(3, 3); x.put(-2, -2); Iterator y = x.values().iterator(); " + + "int total = 0; while (y.hasNext()) total += (int)y.next(); return total;")); + } +} diff --git a/plugins/lang-plan-a/src/test/java/org/elasticsearch/plan/a/FloatOverflowDisabledTests.java b/plugins/lang-plan-a/src/test/java/org/elasticsearch/plan/a/FloatOverflowDisabledTests.java index 4603a669df2..2f8966d581f 100644 --- a/plugins/lang-plan-a/src/test/java/org/elasticsearch/plan/a/FloatOverflowDisabledTests.java +++ b/plugins/lang-plan-a/src/test/java/org/elasticsearch/plan/a/FloatOverflowDisabledTests.java @@ -24,14 +24,14 @@ import java.util.Map; /** Tests floating point overflow with numeric overflow disabled */ public class FloatOverflowDisabledTests extends ScriptTestCase { - + /** wire overflow to false for all tests */ @Override public Object exec(String script, Map vars) { - return exec(script, vars, Collections.singletonMap(PlanAScriptEngineService.NUMERIC_OVERFLOW, "false")); + return exec(script, vars, Collections.singletonMap(CompilerSettings.NUMERIC_OVERFLOW, "false")); } - public void testAssignmentAdditionOverflow() { + public void testAssignmentAdditionOverflow() { // float try { exec("float x = 3.4028234663852886E38f; x += 3.4028234663852886E38f; return x;"); @@ -41,7 +41,7 @@ public class FloatOverflowDisabledTests extends ScriptTestCase { exec("float x = -3.4028234663852886E38f; x += -3.4028234663852886E38f; return x;"); fail("didn't hit expected exception"); } catch (ArithmeticException expected) {} - + // double try { exec("double x = 1.7976931348623157E308; x += 1.7976931348623157E308; return x;"); @@ -52,8 +52,8 @@ public class FloatOverflowDisabledTests extends ScriptTestCase { fail("didn't hit expected exception"); } catch (ArithmeticException expected) {} } - - public void testAssignmentSubtractionOverflow() { + + public void testAssignmentSubtractionOverflow() { // float try { exec("float x = 3.4028234663852886E38f; x -= -3.4028234663852886E38f; return x;"); @@ -63,7 +63,7 @@ public class FloatOverflowDisabledTests extends ScriptTestCase { exec("float x = -3.4028234663852886E38f; x -= 3.4028234663852886E38f; return x;"); fail("didn't hit expected exception"); } catch (ArithmeticException expected) {} - + // double try { exec("double x = 1.7976931348623157E308; x -= -1.7976931348623157E308; return x;"); @@ -74,7 +74,7 @@ public class FloatOverflowDisabledTests extends ScriptTestCase { fail("didn't hit expected exception"); } catch (ArithmeticException expected) {} } - + public void testAssignmentMultiplicationOverflow() { // float try { @@ -85,7 +85,7 @@ public class FloatOverflowDisabledTests extends ScriptTestCase { exec("float x = 3.4028234663852886E38f; x *= -3.4028234663852886E38f; return x;"); fail("didn't hit expected exception"); } catch (ArithmeticException expected) {} - + // double try { exec("double x = 1.7976931348623157E308; x *= 1.7976931348623157E308; return x;"); @@ -96,7 +96,7 @@ public class FloatOverflowDisabledTests extends ScriptTestCase { fail("didn't hit expected exception"); } catch (ArithmeticException expected) {} } - + public void testAssignmentDivisionOverflow() { // float try { @@ -111,7 +111,7 @@ public class FloatOverflowDisabledTests extends ScriptTestCase { exec("float x = 1.0f; x /= 0.0f; return x;"); fail("didn't hit expected exception"); } catch (ArithmeticException expected) {} - + // double try { exec("double x = 1.7976931348623157E308; x /= 4.9E-324; return x;"); @@ -137,7 +137,7 @@ public class FloatOverflowDisabledTests extends ScriptTestCase { fail("didn't hit expected exception"); } catch (ArithmeticException expected) {} } - + public void testAdditionConst() throws Exception { try { exec("return 3.4028234663852886E38f + 3.4028234663852886E38f;"); @@ -148,7 +148,7 @@ public class FloatOverflowDisabledTests extends ScriptTestCase { fail("didn't hit expected exception"); } catch (ArithmeticException expected) {} } - + public void testSubtraction() throws Exception { try { exec("float x = -3.4028234663852886E38f; float y = 3.4028234663852886E38f; return x - y;"); @@ -159,7 +159,7 @@ public class FloatOverflowDisabledTests extends ScriptTestCase { fail("didn't hit expected exception"); } catch (ArithmeticException expected) {} } - + public void testSubtractionConst() throws Exception { try { exec("return -3.4028234663852886E38f - 3.4028234663852886E38f;"); @@ -170,7 +170,7 @@ public class FloatOverflowDisabledTests extends ScriptTestCase { fail("didn't hit expected exception"); } catch (ArithmeticException expected) {} } - + public void testMultiplication() throws Exception { try { exec("float x = 3.4028234663852886E38f; float y = 3.4028234663852886E38f; return x * y;"); @@ -181,7 +181,7 @@ public class FloatOverflowDisabledTests extends ScriptTestCase { fail("didn't hit expected exception"); } catch (ArithmeticException expected) {} } - + public void testMultiplicationConst() throws Exception { try { exec("return 3.4028234663852886E38f * 3.4028234663852886E38f;"); @@ -211,7 +211,7 @@ public class FloatOverflowDisabledTests extends ScriptTestCase { fail("didn't hit expected exception"); } catch (ArithmeticException expected) {} } - + public void testDivisionConst() throws Exception { try { exec("return 3.4028234663852886E38f / 1.401298464324817E-45f;"); @@ -230,7 +230,7 @@ public class FloatOverflowDisabledTests extends ScriptTestCase { fail("didn't hit expected exception"); } catch (ArithmeticException expected) {} } - + public void testDivisionNaN() throws Exception { // float division, constant division, and assignment try { @@ -245,7 +245,7 @@ public class FloatOverflowDisabledTests extends ScriptTestCase { exec("float x = 0f; x /= 0f; return x;"); fail("didn't hit expected exception"); } catch (ArithmeticException expected) {} - + // double division, constant division, and assignment try { exec("double x = 0.0; double y = 0.0; return x / y;"); @@ -260,7 +260,7 @@ public class FloatOverflowDisabledTests extends ScriptTestCase { fail("didn't hit expected exception"); } catch (ArithmeticException expected) {} } - + public void testRemainderNaN() throws Exception { // float division, constant division, and assignment try { @@ -275,7 +275,7 @@ public class FloatOverflowDisabledTests extends ScriptTestCase { exec("float x = 1f; x %= 0f; return x;"); fail("didn't hit expected exception"); } catch (ArithmeticException expected) {} - + // double division, constant division, and assignment try { exec("double x = 1.0; double y = 0.0; return x % y;"); diff --git a/plugins/lang-plan-a/src/test/java/org/elasticsearch/plan/a/FloatOverflowEnabledTests.java b/plugins/lang-plan-a/src/test/java/org/elasticsearch/plan/a/FloatOverflowEnabledTests.java index 02a738de71e..c858e211faa 100644 --- a/plugins/lang-plan-a/src/test/java/org/elasticsearch/plan/a/FloatOverflowEnabledTests.java +++ b/plugins/lang-plan-a/src/test/java/org/elasticsearch/plan/a/FloatOverflowEnabledTests.java @@ -24,49 +24,49 @@ import java.util.Map; /** Tests floating point overflow with numeric overflow enabled */ public class FloatOverflowEnabledTests extends ScriptTestCase { - + /** wire overflow to true for all tests */ @Override public Object exec(String script, Map vars) { - return exec(script, vars, Collections.singletonMap(PlanAScriptEngineService.NUMERIC_OVERFLOW, "true")); + return exec(script, vars, Collections.singletonMap(CompilerSettings.NUMERIC_OVERFLOW, "true")); } - public void testAssignmentAdditionOverflow() { + public void testAssignmentAdditionOverflow() { // float assertEquals(Float.POSITIVE_INFINITY, exec("float x = 3.4028234663852886E38f; x += 3.4028234663852886E38f; return x;")); assertEquals(Float.NEGATIVE_INFINITY, exec("float x = -3.4028234663852886E38f; x += -3.4028234663852886E38f; return x;")); - + // double assertEquals(Double.POSITIVE_INFINITY, exec("double x = 1.7976931348623157E308; x += 1.7976931348623157E308; return x;")); assertEquals(Double.NEGATIVE_INFINITY, exec("double x = -1.7976931348623157E308; x += -1.7976931348623157E308; return x;")); } - - public void testAssignmentSubtractionOverflow() { + + public void testAssignmentSubtractionOverflow() { // float assertEquals(Float.POSITIVE_INFINITY, exec("float x = 3.4028234663852886E38f; x -= -3.4028234663852886E38f; return x;")); assertEquals(Float.NEGATIVE_INFINITY, exec("float x = -3.4028234663852886E38f; x -= 3.4028234663852886E38f; return x;")); - + // double assertEquals(Double.POSITIVE_INFINITY, exec("double x = 1.7976931348623157E308; x -= -1.7976931348623157E308; return x;")); assertEquals(Double.NEGATIVE_INFINITY, exec("double x = -1.7976931348623157E308; x -= 1.7976931348623157E308; return x;")); } - + public void testAssignmentMultiplicationOverflow() { // float assertEquals(Float.POSITIVE_INFINITY, exec("float x = 3.4028234663852886E38f; x *= 3.4028234663852886E38f; return x;")); assertEquals(Float.NEGATIVE_INFINITY, exec("float x = 3.4028234663852886E38f; x *= -3.4028234663852886E38f; return x;")); - + // double assertEquals(Double.POSITIVE_INFINITY, exec("double x = 1.7976931348623157E308; x *= 1.7976931348623157E308; return x;")); assertEquals(Double.NEGATIVE_INFINITY, exec("double x = 1.7976931348623157E308; x *= -1.7976931348623157E308; return x;")); } - + public void testAssignmentDivisionOverflow() { // float assertEquals(Float.POSITIVE_INFINITY, exec("float x = 3.4028234663852886E38f; x /= 1.401298464324817E-45f; return x;")); assertEquals(Float.NEGATIVE_INFINITY, exec("float x = 3.4028234663852886E38f; x /= -1.401298464324817E-45f; return x;")); assertEquals(Float.POSITIVE_INFINITY, exec("float x = 1.0f; x /= 0.0f; return x;")); - + // double assertEquals(Double.POSITIVE_INFINITY, exec("double x = 1.7976931348623157E308; x /= 4.9E-324; return x;")); assertEquals(Double.NEGATIVE_INFINITY, exec("double x = 1.7976931348623157E308; x /= -4.9E-324; return x;")); @@ -74,32 +74,32 @@ public class FloatOverflowEnabledTests extends ScriptTestCase { } public void testAddition() throws Exception { - assertEquals(Float.POSITIVE_INFINITY, exec("float x = 3.4028234663852886E38f; float y = 3.4028234663852886E38f; return x + y;")); + assertEquals(Float.POSITIVE_INFINITY, exec("float x = 3.4028234663852886E38f; float y = 3.4028234663852886E38f; return x + y;")); assertEquals(Double.POSITIVE_INFINITY, exec("double x = 1.7976931348623157E308; double y = 1.7976931348623157E308; return x + y;")); } - + public void testAdditionConst() throws Exception { - assertEquals(Float.POSITIVE_INFINITY, exec("return 3.4028234663852886E38f + 3.4028234663852886E38f;")); + assertEquals(Float.POSITIVE_INFINITY, exec("return 3.4028234663852886E38f + 3.4028234663852886E38f;")); assertEquals(Double.POSITIVE_INFINITY, exec("return 1.7976931348623157E308 + 1.7976931348623157E308;")); } - + public void testSubtraction() throws Exception { - assertEquals(Float.NEGATIVE_INFINITY, exec("float x = -3.4028234663852886E38f; float y = 3.4028234663852886E38f; return x - y;")); + assertEquals(Float.NEGATIVE_INFINITY, exec("float x = -3.4028234663852886E38f; float y = 3.4028234663852886E38f; return x - y;")); assertEquals(Double.NEGATIVE_INFINITY, exec("double x = -1.7976931348623157E308; double y = 1.7976931348623157E308; return x - y;")); } - + public void testSubtractionConst() throws Exception { - assertEquals(Float.NEGATIVE_INFINITY, exec("return -3.4028234663852886E38f - 3.4028234663852886E38f;")); + assertEquals(Float.NEGATIVE_INFINITY, exec("return -3.4028234663852886E38f - 3.4028234663852886E38f;")); assertEquals(Double.NEGATIVE_INFINITY, exec("return -1.7976931348623157E308 - 1.7976931348623157E308;")); } - + public void testMultiplication() throws Exception { - assertEquals(Float.POSITIVE_INFINITY, exec("float x = 3.4028234663852886E38f; float y = 3.4028234663852886E38f; return x * y;")); + assertEquals(Float.POSITIVE_INFINITY, exec("float x = 3.4028234663852886E38f; float y = 3.4028234663852886E38f; return x * y;")); assertEquals(Double.POSITIVE_INFINITY, exec("double x = 1.7976931348623157E308; double y = 1.7976931348623157E308; return x * y;")); } - + public void testMultiplicationConst() throws Exception { - assertEquals(Float.POSITIVE_INFINITY, exec("return 3.4028234663852886E38f * 3.4028234663852886E38f;")); + assertEquals(Float.POSITIVE_INFINITY, exec("return 3.4028234663852886E38f * 3.4028234663852886E38f;")); assertEquals(Double.POSITIVE_INFINITY, exec("return 1.7976931348623157E308 * 1.7976931348623157E308;")); } @@ -109,32 +109,32 @@ public class FloatOverflowEnabledTests extends ScriptTestCase { assertEquals(Double.POSITIVE_INFINITY, exec("double x = 1.7976931348623157E308; double y = 4.9E-324; return x / y;")); assertEquals(Double.POSITIVE_INFINITY, exec("double x = 1.0; double y = 0.0; return x / y;")); } - + public void testDivisionConst() throws Exception { assertEquals(Float.POSITIVE_INFINITY, exec("return 3.4028234663852886E38f / 1.401298464324817E-45f;")); assertEquals(Float.POSITIVE_INFINITY, exec("return 1.0f / 0.0f;")); assertEquals(Double.POSITIVE_INFINITY, exec("return 1.7976931348623157E308 / 4.9E-324;")); assertEquals(Double.POSITIVE_INFINITY, exec("return 1.0 / 0.0;")); } - + public void testDivisionNaN() throws Exception { // float division, constant division, and assignment assertTrue(Float.isNaN((Float) exec("float x = 0f; float y = 0f; return x / y;"))); assertTrue(Float.isNaN((Float) exec("return 0f / 0f;"))); assertTrue(Float.isNaN((Float) exec("float x = 0f; x /= 0f; return x;"))); - + // double division, constant division, and assignment assertTrue(Double.isNaN((Double) exec("double x = 0.0; double y = 0.0; return x / y;"))); assertTrue(Double.isNaN((Double) exec("return 0.0 / 0.0;"))); assertTrue(Double.isNaN((Double) exec("double x = 0.0; x /= 0.0; return x;"))); } - + public void testRemainderNaN() throws Exception { // float division, constant division, and assignment assertTrue(Float.isNaN((Float) exec("float x = 1f; float y = 0f; return x % y;"))); assertTrue(Float.isNaN((Float) exec("return 1f % 0f;"))); assertTrue(Float.isNaN((Float) exec("float x = 1f; x %= 0f; return x;"))); - + // double division, constant division, and assignment assertTrue(Double.isNaN((Double) exec("double x = 1.0; double y = 0.0; return x % y;"))); assertTrue(Double.isNaN((Double) exec("return 1.0 % 0.0;"))); diff --git a/plugins/lang-plan-a/src/test/java/org/elasticsearch/plan/a/IntegerOverflowDisabledTests.java b/plugins/lang-plan-a/src/test/java/org/elasticsearch/plan/a/IntegerOverflowDisabledTests.java index dbffb11f0d0..86b4f46a765 100644 --- a/plugins/lang-plan-a/src/test/java/org/elasticsearch/plan/a/IntegerOverflowDisabledTests.java +++ b/plugins/lang-plan-a/src/test/java/org/elasticsearch/plan/a/IntegerOverflowDisabledTests.java @@ -24,11 +24,11 @@ import java.util.Map; /** Tests integer overflow with numeric overflow disabled */ public class IntegerOverflowDisabledTests extends ScriptTestCase { - + /** wire overflow to true for all tests */ @Override public Object exec(String script, Map vars) { - return exec(script, vars, Collections.singletonMap(PlanAScriptEngineService.NUMERIC_OVERFLOW, "false")); + return exec(script, vars, Collections.singletonMap(CompilerSettings.NUMERIC_OVERFLOW, "false")); } public void testAssignmentAdditionOverflow() { @@ -42,7 +42,7 @@ public class IntegerOverflowDisabledTests extends ScriptTestCase { exec("byte x = 0; x += -129; return x;"); fail("did not get expected exception"); } catch (ArithmeticException expected) {} - + // short try { exec("short x = 0; x += 32768; return x;"); @@ -53,7 +53,7 @@ public class IntegerOverflowDisabledTests extends ScriptTestCase { exec("byte x = 0; x += -32769; return x;"); fail("did not get expected exception"); } catch (ArithmeticException expected) {} - + // char try { exec("char x = 0; x += 65536; return x;"); @@ -64,7 +64,7 @@ public class IntegerOverflowDisabledTests extends ScriptTestCase { exec("char x = 0; x += -65536; return x;"); fail("did not get expected exception"); } catch (ArithmeticException expected) {} - + // int try { exec("int x = 1; x += 2147483647; return x;"); @@ -75,7 +75,7 @@ public class IntegerOverflowDisabledTests extends ScriptTestCase { exec("int x = -2; x += -2147483647; return x;"); fail("did not get expected exception"); } catch (ArithmeticException expected) {} - + // long try { exec("long x = 1; x += 9223372036854775807L; return x;"); @@ -87,7 +87,7 @@ public class IntegerOverflowDisabledTests extends ScriptTestCase { fail("did not get expected exception"); } catch (ArithmeticException expected) {} } - + public void testAssignmentSubtractionOverflow() { // byte try { @@ -99,7 +99,7 @@ public class IntegerOverflowDisabledTests extends ScriptTestCase { exec("byte x = 0; x -= 129; return x;"); fail("did not get expected exception"); } catch (ArithmeticException expected) {} - + // short try { exec("short x = 0; x -= -32768; return x;"); @@ -110,7 +110,7 @@ public class IntegerOverflowDisabledTests extends ScriptTestCase { exec("byte x = 0; x -= 32769; return x;"); fail("did not get expected exception"); } catch (ArithmeticException expected) {} - + // char try { exec("char x = 0; x -= -65536; return x;"); @@ -121,7 +121,7 @@ public class IntegerOverflowDisabledTests extends ScriptTestCase { exec("char x = 0; x -= 65536; return x;"); fail("did not get expected exception"); } catch (ArithmeticException expected) {} - + // int try { exec("int x = 1; x -= -2147483647; return x;"); @@ -132,7 +132,7 @@ public class IntegerOverflowDisabledTests extends ScriptTestCase { exec("int x = -2; x -= 2147483647; return x;"); fail("did not get expected exception"); } catch (ArithmeticException expected) {} - + // long try { exec("long x = 1; x -= -9223372036854775807L; return x;"); @@ -144,7 +144,7 @@ public class IntegerOverflowDisabledTests extends ScriptTestCase { fail("did not get expected exception"); } catch (ArithmeticException expected) {} } - + public void testAssignmentMultiplicationOverflow() { // byte try { @@ -156,7 +156,7 @@ public class IntegerOverflowDisabledTests extends ScriptTestCase { exec("byte x = 2; x *= -128; return x;"); fail("did not get expected exception"); } catch (ArithmeticException expected) {} - + // char try { exec("char x = 2; x *= 65536; return x;"); @@ -167,7 +167,7 @@ public class IntegerOverflowDisabledTests extends ScriptTestCase { exec("char x = 2; x *= -65536; return x;"); fail("did not get expected exception"); } catch (ArithmeticException expected) {} - + // int try { exec("int x = 2; x *= 2147483647; return x;"); @@ -178,7 +178,7 @@ public class IntegerOverflowDisabledTests extends ScriptTestCase { exec("int x = 2; x *= -2147483647; return x;"); fail("did not get expected exception"); } catch (ArithmeticException expected) {} - + // long try { exec("long x = 2; x *= 9223372036854775807L; return x;"); @@ -190,7 +190,7 @@ public class IntegerOverflowDisabledTests extends ScriptTestCase { fail("did not get expected exception"); } catch (ArithmeticException expected) {} } - + public void testAssignmentDivisionOverflow() { // byte try { @@ -203,108 +203,108 @@ public class IntegerOverflowDisabledTests extends ScriptTestCase { exec("short x = (short) -32768; x /= -1; return x;"); fail("should have hit exception"); } catch (ArithmeticException expected) {} - + // cannot happen for char: unsigned - + // int try { exec("int x = -2147483647 - 1; x /= -1; return x;"); fail("should have hit exception"); } catch (ArithmeticException expected) {} - + // long try { exec("long x = -9223372036854775807L - 1L; x /=-1L; return x;"); fail("should have hit exception"); } catch (ArithmeticException expected) {} } - + public void testIncrementOverFlow() throws Exception { // byte try { exec("byte x = 127; ++x; return x;"); fail("did not get expected exception"); } catch (ArithmeticException expected) {} - + try { exec("byte x = 127; x++; return x;"); fail("did not get expected exception"); } catch (ArithmeticException expected) {} - + try { exec("byte x = (byte) -128; --x; return x;"); fail("did not get expected exception"); } catch (ArithmeticException expected) {} - + try { exec("byte x = (byte) -128; x--; return x;"); fail("did not get expected exception"); } catch (ArithmeticException expected) {} - + // short try { exec("short x = 32767; ++x; return x;"); fail("did not get expected exception"); } catch (ArithmeticException expected) {} - + try { exec("short x = 32767; x++; return x;"); fail("did not get expected exception"); } catch (ArithmeticException expected) {} - + try { exec("short x = (short) -32768; --x; return x;"); fail("did not get expected exception"); } catch (ArithmeticException expected) {} - + try { exec("short x = (short) -32768; x--; return x;"); } catch (ArithmeticException expected) {} - + // char try { exec("char x = 65535; ++x; return x;"); } catch (ArithmeticException expected) {} - + try { exec("char x = 65535; x++; return x;"); } catch (ArithmeticException expected) {} - + try { exec("char x = (char) 0; --x; return x;"); } catch (ArithmeticException expected) {} - + try { exec("char x = (char) 0; x--; return x;"); } catch (ArithmeticException expected) {} - + // int try { exec("int x = 2147483647; ++x; return x;"); fail("did not get expected exception"); } catch (ArithmeticException expected) {} - + try { exec("int x = 2147483647; x++; return x;"); fail("did not get expected exception"); } catch (ArithmeticException expected) {} - + try { exec("int x = (int) -2147483648L; --x; return x;"); fail("did not get expected exception"); } catch (ArithmeticException expected) {} - + try { exec("int x = (int) -2147483648L; x--; return x;"); fail("did not get expected exception"); } catch (ArithmeticException expected) {} - + // long try { exec("long x = 9223372036854775807L; ++x; return x;"); fail("did not get expected exception"); } catch (ArithmeticException expected) {} - + try { exec("long x = 9223372036854775807L; x++; return x;"); fail("did not get expected exception"); @@ -320,68 +320,68 @@ public class IntegerOverflowDisabledTests extends ScriptTestCase { fail("did not get expected exception"); } catch (ArithmeticException expected) {} } - + public void testAddition() throws Exception { try { exec("int x = 2147483647; int y = 2147483647; return x + y;"); fail("should have hit exception"); } catch (ArithmeticException expected) {} - + try { exec("long x = 9223372036854775807L; long y = 9223372036854775807L; return x + y;"); fail("should have hit exception"); } catch (ArithmeticException expected) {} } - + public void testAdditionConst() throws Exception { try { exec("return 2147483647 + 2147483647;"); fail("should have hit exception"); } catch (ArithmeticException expected) {} - + try { exec("return 9223372036854775807L + 9223372036854775807L;"); fail("should have hit exception"); } catch (ArithmeticException expected) {} } - - + + public void testSubtraction() throws Exception { try { exec("int x = -10; int y = 2147483647; return x - y;"); fail("should have hit exception"); } catch (ArithmeticException expected) {} - + try { exec("long x = -10L; long y = 9223372036854775807L; return x - y;"); fail("should have hit exception"); } catch (ArithmeticException expected) {} } - + public void testSubtractionConst() throws Exception { try { exec("return -10 - 2147483647;"); fail("should have hit exception"); } catch (ArithmeticException expected) {} - + try { exec("return -10L - 9223372036854775807L;"); fail("should have hit exception"); } catch (ArithmeticException expected) {} } - + public void testMultiplication() throws Exception { try { exec("int x = 2147483647; int y = 2147483647; return x * y;"); fail("should have hit exception"); } catch (ArithmeticException expected) {} - + try { exec("long x = 9223372036854775807L; long y = 9223372036854775807L; return x * y;"); fail("should have hit exception"); } catch (ArithmeticException expected) {} } - + public void testMultiplicationConst() throws Exception { try { exec("return 2147483647 * 2147483647;"); @@ -399,13 +399,13 @@ public class IntegerOverflowDisabledTests extends ScriptTestCase { exec("int x = -2147483647 - 1; int y = -1; return x / y;"); fail("should have hit exception"); } catch (ArithmeticException expected) {} - + try { exec("long x = -9223372036854775808L; long y = -1L; return x / y;"); fail("should have hit exception"); } catch (ArithmeticException expected) {} } - + public void testDivisionConst() throws Exception { try { exec("return (-2147483648) / -1;"); @@ -417,25 +417,25 @@ public class IntegerOverflowDisabledTests extends ScriptTestCase { fail("should have hit exception"); } catch (ArithmeticException expected) {} } - + public void testNegationOverflow() throws Exception { try { exec("int x = -2147483648; x = -x; return x;"); fail("did not get expected exception"); } catch (ArithmeticException expected) {} - + try { exec("long x = -9223372036854775808L; x = -x; return x;"); fail("did not get expected exception"); } catch (ArithmeticException expected) {} } - + public void testNegationOverflowConst() throws Exception { try { exec("int x = -(-2147483648); return x;"); fail("did not get expected exception"); } catch (ArithmeticException expected) {} - + try { exec("long x = -(-9223372036854775808L); return x;"); fail("did not get expected exception"); diff --git a/plugins/lang-plan-a/src/test/java/org/elasticsearch/plan/a/IntegerOverflowEnabledTests.java b/plugins/lang-plan-a/src/test/java/org/elasticsearch/plan/a/IntegerOverflowEnabledTests.java index cdab0e89fe6..ab5f82fd6d2 100644 --- a/plugins/lang-plan-a/src/test/java/org/elasticsearch/plan/a/IntegerOverflowEnabledTests.java +++ b/plugins/lang-plan-a/src/test/java/org/elasticsearch/plan/a/IntegerOverflowEnabledTests.java @@ -24,148 +24,148 @@ import java.util.Map; /** Tests integer overflow with numeric overflow enabled */ public class IntegerOverflowEnabledTests extends ScriptTestCase { - + /** wire overflow to true for all tests */ @Override public Object exec(String script, Map vars) { - return exec(script, vars, Collections.singletonMap(PlanAScriptEngineService.NUMERIC_OVERFLOW, "true")); + return exec(script, vars, Collections.singletonMap(CompilerSettings.NUMERIC_OVERFLOW, "true")); } public void testAssignmentAdditionOverflow() { // byte assertEquals((byte)(0 + 128), exec("byte x = 0; x += 128; return x;")); assertEquals((byte)(0 + -129), exec("byte x = 0; x += -129; return x;")); - + // short assertEquals((short)(0 + 32768), exec("short x = 0; x += 32768; return x;")); assertEquals((short)(0 + -32769), exec("short x = 0; x += -32769; return x;")); - + // char assertEquals((char)(0 + 65536), exec("char x = 0; x += 65536; return x;")); assertEquals((char)(0 + -65536), exec("char x = 0; x += -65536; return x;")); - + // int assertEquals(1 + 2147483647, exec("int x = 1; x += 2147483647; return x;")); assertEquals(-2 + -2147483647, exec("int x = -2; x += -2147483647; return x;")); - + // long assertEquals(1L + 9223372036854775807L, exec("long x = 1; x += 9223372036854775807L; return x;")); assertEquals(-2L + -9223372036854775807L, exec("long x = -2; x += -9223372036854775807L; return x;")); } - + public void testAssignmentSubtractionOverflow() { // byte assertEquals((byte)(0 - -128), exec("byte x = 0; x -= -128; return x;")); assertEquals((byte)(0 - 129), exec("byte x = 0; x -= 129; return x;")); - + // short assertEquals((short)(0 - -32768), exec("short x = 0; x -= -32768; return x;")); assertEquals((short)(0 - 32769), exec("short x = 0; x -= 32769; return x;")); - + // char assertEquals((char)(0 - -65536), exec("char x = 0; x -= -65536; return x;")); assertEquals((char)(0 - 65536), exec("char x = 0; x -= 65536; return x;")); - + // int assertEquals(1 - -2147483647, exec("int x = 1; x -= -2147483647; return x;")); assertEquals(-2 - 2147483647, exec("int x = -2; x -= 2147483647; return x;")); - + // long assertEquals(1L - -9223372036854775807L, exec("long x = 1; x -= -9223372036854775807L; return x;")); assertEquals(-2L - 9223372036854775807L, exec("long x = -2; x -= 9223372036854775807L; return x;")); } - + public void testAssignmentMultiplicationOverflow() { // byte assertEquals((byte) (2 * 128), exec("byte x = 2; x *= 128; return x;")); assertEquals((byte) (2 * -128), exec("byte x = 2; x *= -128; return x;")); - + // char assertEquals((char) (2 * 65536), exec("char x = 2; x *= 65536; return x;")); assertEquals((char) (2 * -65536), exec("char x = 2; x *= -65536; return x;")); - + // int assertEquals(2 * 2147483647, exec("int x = 2; x *= 2147483647; return x;")); assertEquals(2 * -2147483647, exec("int x = 2; x *= -2147483647; return x;")); - + // long assertEquals(2L * 9223372036854775807L, exec("long x = 2; x *= 9223372036854775807L; return x;")); assertEquals(2L * -9223372036854775807L, exec("long x = 2; x *= -9223372036854775807L; return x;")); } - + public void testAssignmentDivisionOverflow() { // byte assertEquals((byte) (-128 / -1), exec("byte x = (byte) -128; x /= -1; return x;")); // short assertEquals((short) (-32768 / -1), exec("short x = (short) -32768; x /= -1; return x;")); - + // cannot happen for char: unsigned - + // int assertEquals((-2147483647 - 1) / -1, exec("int x = -2147483647 - 1; x /= -1; return x;")); - + // long assertEquals((-9223372036854775807L - 1L) / -1L, exec("long x = -9223372036854775807L - 1L; x /=-1L; return x;")); } - + public void testIncrementOverFlow() throws Exception { // byte assertEquals((byte) 128, exec("byte x = 127; ++x; return x;")); assertEquals((byte) 128, exec("byte x = 127; x++; return x;")); assertEquals((byte) -129, exec("byte x = (byte) -128; --x; return x;")); assertEquals((byte) -129, exec("byte x = (byte) -128; x--; return x;")); - + // short assertEquals((short) 32768, exec("short x = 32767; ++x; return x;")); assertEquals((short) 32768, exec("short x = 32767; x++; return x;")); assertEquals((short) -32769, exec("short x = (short) -32768; --x; return x;")); assertEquals((short) -32769, exec("short x = (short) -32768; x--; return x;")); - + // char assertEquals((char) 65536, exec("char x = 65535; ++x; return x;")); assertEquals((char) 65536, exec("char x = 65535; x++; return x;")); assertEquals((char) -1, exec("char x = (char) 0; --x; return x;")); assertEquals((char) -1, exec("char x = (char) 0; x--; return x;")); - + // int - assertEquals(2147483647 + 1, exec("int x = 2147483647; ++x; return x;")); + assertEquals(2147483647 + 1, exec("int x = 2147483647; ++x; return x;")); assertEquals(2147483647 + 1, exec("int x = 2147483647; x++; return x;")); - assertEquals(-2147483648 - 1, exec("int x = (int) -2147483648L; --x; return x;")); + assertEquals(-2147483648 - 1, exec("int x = (int) -2147483648L; --x; return x;")); assertEquals(-2147483648 - 1, exec("int x = (int) -2147483648L; x--; return x;")); - + // long - assertEquals(9223372036854775807L + 1L, exec("long x = 9223372036854775807L; ++x; return x;")); + assertEquals(9223372036854775807L + 1L, exec("long x = 9223372036854775807L; ++x; return x;")); assertEquals(9223372036854775807L + 1L, exec("long x = 9223372036854775807L; x++; return x;")); assertEquals(-9223372036854775807L - 1L - 1L, exec("long x = -9223372036854775807L - 1L; --x; return x;")); assertEquals(-9223372036854775807L - 1L - 1L, exec("long x = -9223372036854775807L - 1L; x--; return x;")); } - + public void testAddition() throws Exception { - assertEquals(2147483647 + 2147483647, exec("int x = 2147483647; int y = 2147483647; return x + y;")); + assertEquals(2147483647 + 2147483647, exec("int x = 2147483647; int y = 2147483647; return x + y;")); assertEquals(9223372036854775807L + 9223372036854775807L, exec("long x = 9223372036854775807L; long y = 9223372036854775807L; return x + y;")); } - + public void testAdditionConst() throws Exception { - assertEquals(2147483647 + 2147483647, exec("return 2147483647 + 2147483647;")); + assertEquals(2147483647 + 2147483647, exec("return 2147483647 + 2147483647;")); assertEquals(9223372036854775807L + 9223372036854775807L, exec("return 9223372036854775807L + 9223372036854775807L;")); } - + public void testSubtraction() throws Exception { - assertEquals(-10 - 2147483647, exec("int x = -10; int y = 2147483647; return x - y;")); + assertEquals(-10 - 2147483647, exec("int x = -10; int y = 2147483647; return x - y;")); assertEquals(-10L - 9223372036854775807L, exec("long x = -10L; long y = 9223372036854775807L; return x - y;")); } - + public void testSubtractionConst() throws Exception { - assertEquals(-10 - 2147483647, exec("return -10 - 2147483647;")); + assertEquals(-10 - 2147483647, exec("return -10 - 2147483647;")); assertEquals(-10L - 9223372036854775807L, exec("return -10L - 9223372036854775807L;")); } - + public void testMultiplication() throws Exception { - assertEquals(2147483647 * 2147483647, exec("int x = 2147483647; int y = 2147483647; return x * y;")); + assertEquals(2147483647 * 2147483647, exec("int x = 2147483647; int y = 2147483647; return x * y;")); assertEquals(9223372036854775807L * 9223372036854775807L, exec("long x = 9223372036854775807L; long y = 9223372036854775807L; return x * y;")); } - + public void testMultiplicationConst() throws Exception { assertEquals(2147483647 * 2147483647, exec("return 2147483647 * 2147483647;")); assertEquals(9223372036854775807L * 9223372036854775807L, exec("return 9223372036854775807L * 9223372036854775807L;")); @@ -175,17 +175,17 @@ public class IntegerOverflowEnabledTests extends ScriptTestCase { assertEquals((-2147483647 - 1) / -1, exec("int x = -2147483648; int y = -1; return x / y;")); assertEquals((-9223372036854775807L - 1L) / -1L, exec("long x = -9223372036854775808L; long y = -1L; return x / y;")); } - + public void testDivisionConst() throws Exception { assertEquals((-2147483647 - 1) / -1, exec("return (-2147483648) / -1;")); assertEquals((-9223372036854775807L - 1L) / -1L, exec("return (-9223372036854775808L) / -1L;")); } - + public void testNegationOverflow() throws Exception { assertEquals(-(-2147483647 - 1), exec("int x = -2147483648; x = -x; return x;")); assertEquals(-(-9223372036854775807L - 1L), exec("long x = -9223372036854775808L; x = -x; return x;")); } - + public void testNegationOverflowConst() throws Exception { assertEquals(-(-2147483647 - 1), exec("int x = -(-2147483648); return x;")); assertEquals(-(-9223372036854775807L - 1L), exec("long x = -(-9223372036854775808L); return x;")); diff --git a/plugins/lang-plan-a/src/test/java/org/elasticsearch/plan/a/ScriptTestCase.java b/plugins/lang-plan-a/src/test/java/org/elasticsearch/plan/a/ScriptTestCase.java index 5b4948036f3..8ff87bd2a0d 100644 --- a/plugins/lang-plan-a/src/test/java/org/elasticsearch/plan/a/ScriptTestCase.java +++ b/plugins/lang-plan-a/src/test/java/org/elasticsearch/plan/a/ScriptTestCase.java @@ -48,7 +48,7 @@ public abstract class ScriptTestCase extends ESTestCase { /** Compiles and returns the result of {@code script} with access to {@code vars} */ public Object exec(String script, Map vars) { - return exec(script, vars, Collections.singletonMap(PlanAScriptEngineService.NUMERIC_OVERFLOW, Boolean.toString(random().nextBoolean()))); + return exec(script, vars, Collections.singletonMap(CompilerSettings.NUMERIC_OVERFLOW, Boolean.toString(random().nextBoolean()))); } /** Compiles and returns the result of {@code script} with access to {@code vars} and compile-time parameters */ diff --git a/plugins/lang-plan-a/src/test/java/org/elasticsearch/plan/a/WhenThingsGoWrongTests.java b/plugins/lang-plan-a/src/test/java/org/elasticsearch/plan/a/WhenThingsGoWrongTests.java index 277778e7e76..e4dbce83122 100644 --- a/plugins/lang-plan-a/src/test/java/org/elasticsearch/plan/a/WhenThingsGoWrongTests.java +++ b/plugins/lang-plan-a/src/test/java/org/elasticsearch/plan/a/WhenThingsGoWrongTests.java @@ -19,6 +19,7 @@ package org.elasticsearch.plan.a; +import java.text.ParseException; import java.util.Collections; public class WhenThingsGoWrongTests extends ScriptTestCase { @@ -40,7 +41,7 @@ public class WhenThingsGoWrongTests extends ScriptTestCase { fail("should have hit cce"); } catch (ClassCastException expected) {} } - + public void testBogusParameter() { try { exec("return 5;", null, Collections.singletonMap("bogusParameterKey", "bogusParameterValue")); @@ -49,4 +50,83 @@ public class WhenThingsGoWrongTests extends ScriptTestCase { assertTrue(expected.getMessage().contains("Unrecognized compile-time parameter")); } } + + public void testInfiniteLoops() { + try { + exec("boolean x = true; while (x) {}"); + fail("should have hit PlanAError"); + } catch (PlanAError expected) { + assertTrue(expected.getMessage().contains( + "The maximum number of statements that can be executed in a loop has been reached.")); + } + + try { + exec("while (true) {int y = 5}"); + fail("should have hit PlanAError"); + } catch (PlanAError expected) { + assertTrue(expected.getMessage().contains( + "The maximum number of statements that can be executed in a loop has been reached.")); + } + + try { + exec("while (true) { boolean x = true; while (x) {} }"); + fail("should have hit PlanAError"); + } catch (PlanAError expected) { + assertTrue(expected.getMessage().contains( + "The maximum number of statements that can be executed in a loop has been reached.")); + } + + try { + exec("while (true) { boolean x = false; while (x) {} }"); + fail("should have hit PlanAError"); + } catch (PlanAError expected) { + assertTrue(expected.getMessage().contains( + "The maximum number of statements that can be executed in a loop has been reached.")); + } + + try { + exec("boolean x = true; for (;x;) {}"); + fail("should have hit PlanAError"); + } catch (PlanAError expected) { + assertTrue(expected.getMessage().contains( + "The maximum number of statements that can be executed in a loop has been reached.")); + } + + try { + exec("for (;;) {int x = 5}"); + fail("should have hit PlanAError"); + } catch (PlanAError expected) { + assertTrue(expected.getMessage().contains( + "The maximum number of statements that can be executed in a loop has been reached.")); + } + + try { + exec("def x = true; do {int y = 5;} while (x)"); + fail("should have hit PlanAError"); + } catch (PlanAError expected) { + assertTrue(expected.getMessage().contains( + "The maximum number of statements that can be executed in a loop has been reached.")); + } + + try { + exec("try { int x } catch (PlanAError error) {}"); + fail("should have hit ParseException"); + } catch (RuntimeException expected) { + assertTrue(expected.getMessage().contains( + "unexpected token ['PlanAError'] was expecting one of [TYPE].")); + } + + } + + public void testLoopLimits() { + exec("for (int x = 0; x < 9999; ++x) {}"); + + try { + exec("for (int x = 0; x < 10000; ++x) {}"); + fail("should have hit PlanAError"); + } catch (PlanAError expected) { + assertTrue(expected.getMessage().contains( + "The maximum number of statements that can be executed in a loop has been reached.")); + } + } }