mirror of
https://github.com/honeymoose/OpenSearch.git
synced 2025-03-01 00:19:11 +00:00
Painless: modify grammar to allow more statement delimiters (#29566)
This allows the grammar to determine when and what delimiters statements will use by splitting up the statements into regular statements and delimited statements, those that do not require a delimiter versus those that do. This allows consumers of the statements to determine what delimiters the statements will use so that in certain cases semicolons are not necessary like when there's a closing right bracket. This change removes the need for semicolon insertion in the lexer, simplifying the existing lexer quite a bit. It also ensures that there isn't a need to track semicolons being inserted into places that aren't necessary such as array initializers.
This commit is contained in:
parent
3e7fccddaf
commit
da9a6899ff
@ -22,7 +22,7 @@ parser grammar PainlessParser;
|
|||||||
options { tokenVocab=PainlessLexer; }
|
options { tokenVocab=PainlessLexer; }
|
||||||
|
|
||||||
source
|
source
|
||||||
: function* statement* EOF
|
: function* statement* dstatement? EOF
|
||||||
;
|
;
|
||||||
|
|
||||||
function
|
function
|
||||||
@ -33,23 +33,31 @@ parameters
|
|||||||
: LP ( decltype ID ( COMMA decltype ID )* )? RP
|
: LP ( decltype ID ( COMMA decltype ID )* )? RP
|
||||||
;
|
;
|
||||||
|
|
||||||
|
statement
|
||||||
|
: rstatement
|
||||||
|
| dstatement SEMICOLON
|
||||||
|
;
|
||||||
|
|
||||||
// Note we use a predicate on the if/else case here to prevent the
|
// Note we use a predicate on the if/else case here to prevent the
|
||||||
// "dangling-else" ambiguity by forcing the 'else' token to be consumed
|
// "dangling-else" ambiguity by forcing the 'else' token to be consumed
|
||||||
// as soon as one is found. See (https://en.wikipedia.org/wiki/Dangling_else).
|
// as soon as one is found. See (https://en.wikipedia.org/wiki/Dangling_else).
|
||||||
statement
|
rstatement
|
||||||
: IF LP expression RP trailer ( ELSE trailer | { _input.LA(1) != ELSE }? ) # if
|
: IF LP expression RP trailer ( ELSE trailer | { _input.LA(1) != ELSE }? ) # if
|
||||||
| WHILE LP expression RP ( trailer | empty ) # while
|
| WHILE LP expression RP ( trailer | empty ) # while
|
||||||
| DO block WHILE LP expression RP delimiter # do
|
|
||||||
| FOR LP initializer? SEMICOLON expression? SEMICOLON afterthought? RP ( trailer | empty ) # for
|
| FOR LP initializer? SEMICOLON expression? SEMICOLON afterthought? RP ( trailer | empty ) # for
|
||||||
| FOR LP decltype ID COLON expression RP trailer # each
|
| FOR LP decltype ID COLON expression RP trailer # each
|
||||||
| FOR LP ID IN expression RP trailer # ineach
|
| FOR LP ID IN expression RP trailer # ineach
|
||||||
| declaration delimiter # decl
|
|
||||||
| CONTINUE delimiter # continue
|
|
||||||
| BREAK delimiter # break
|
|
||||||
| RETURN expression delimiter # return
|
|
||||||
| TRY block trap+ # try
|
| TRY block trap+ # try
|
||||||
| THROW expression delimiter # throw
|
;
|
||||||
| expression delimiter # expr
|
|
||||||
|
dstatement
|
||||||
|
: DO block WHILE LP expression RP # do
|
||||||
|
| declaration # decl
|
||||||
|
| CONTINUE # continue
|
||||||
|
| BREAK # break
|
||||||
|
| RETURN expression # return
|
||||||
|
| THROW expression # throw
|
||||||
|
| expression # expr
|
||||||
;
|
;
|
||||||
|
|
||||||
trailer
|
trailer
|
||||||
@ -58,7 +66,7 @@ trailer
|
|||||||
;
|
;
|
||||||
|
|
||||||
block
|
block
|
||||||
: LBRACK statement* RBRACK
|
: LBRACK statement* dstatement? RBRACK
|
||||||
;
|
;
|
||||||
|
|
||||||
empty
|
empty
|
||||||
@ -90,11 +98,6 @@ trap
|
|||||||
: CATCH LP TYPE ID RP block
|
: CATCH LP TYPE ID RP block
|
||||||
;
|
;
|
||||||
|
|
||||||
delimiter
|
|
||||||
: SEMICOLON
|
|
||||||
| EOF
|
|
||||||
;
|
|
||||||
|
|
||||||
expression
|
expression
|
||||||
: unary # single
|
: unary # single
|
||||||
| expression ( MUL | DIV | REM ) expression # binary
|
| expression ( MUL | DIV | REM ) expression # binary
|
||||||
@ -169,8 +172,8 @@ braceaccess
|
|||||||
;
|
;
|
||||||
|
|
||||||
arrayinitializer
|
arrayinitializer
|
||||||
: NEW TYPE ( LBRACE expression RBRACE )+ ( postdot postfix* )? # newstandardarray
|
: NEW TYPE ( LBRACE expression RBRACE )+ ( postdot postfix* )? # newstandardarray
|
||||||
| NEW TYPE LBRACE RBRACE LBRACK ( expression ( COMMA expression )* )? SEMICOLON? RBRACK postfix* # newinitializedarray
|
| NEW TYPE LBRACE RBRACE LBRACK ( expression ( COMMA expression )* )? RBRACK postfix* # newinitializedarray
|
||||||
;
|
;
|
||||||
|
|
||||||
listinitializer
|
listinitializer
|
||||||
@ -206,10 +209,8 @@ lamtype
|
|||||||
;
|
;
|
||||||
|
|
||||||
funcref
|
funcref
|
||||||
: TYPE REF ID # classfuncref // reference to a static or instance method,
|
: TYPE REF ID # classfuncref
|
||||||
// e.g. ArrayList::size or Integer::compare
|
| decltype REF NEW # constructorfuncref
|
||||||
| decltype REF NEW # constructorfuncref // reference to a constructor, e.g. ArrayList::new
|
| ID REF ID # capturingfuncref
|
||||||
| ID REF ID # capturingfuncref // reference to an instance method, e.g. object::toString
|
| THIS REF ID # localfuncref
|
||||||
// currently limited to capture of a simple variable (id).
|
|
||||||
| THIS REF ID # localfuncref // reference to a local function, e.g. this::myfunc
|
|
||||||
;
|
;
|
||||||
|
@ -44,8 +44,7 @@ final class EnhancedPainlessLexer extends PainlessLexer {
|
|||||||
private final String sourceName;
|
private final String sourceName;
|
||||||
private final Definition definition;
|
private final Definition definition;
|
||||||
|
|
||||||
private Token stashedNext = null;
|
private Token current = null;
|
||||||
private Token previous = null;
|
|
||||||
|
|
||||||
EnhancedPainlessLexer(CharStream charStream, String sourceName, Definition definition) {
|
EnhancedPainlessLexer(CharStream charStream, String sourceName, Definition definition) {
|
||||||
super(charStream);
|
super(charStream);
|
||||||
@ -53,27 +52,10 @@ final class EnhancedPainlessLexer extends PainlessLexer {
|
|||||||
this.definition = definition;
|
this.definition = definition;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Token getPreviousToken() {
|
|
||||||
return previous;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Token nextToken() {
|
public Token nextToken() {
|
||||||
if (stashedNext != null) {
|
current = super.nextToken();
|
||||||
previous = stashedNext;
|
return current;
|
||||||
stashedNext = null;
|
|
||||||
return previous;
|
|
||||||
}
|
|
||||||
Token next = super.nextToken();
|
|
||||||
if (insertSemicolon(previous, next)) {
|
|
||||||
stashedNext = next;
|
|
||||||
previous = _factory.create(new Pair<TokenSource, CharStream>(this, _input), PainlessLexer.SEMICOLON, ";",
|
|
||||||
Lexer.DEFAULT_TOKEN_CHANNEL, next.getStartIndex(), next.getStopIndex(), next.getLine(), next.getCharPositionInLine());
|
|
||||||
return previous;
|
|
||||||
} else {
|
|
||||||
previous = next;
|
|
||||||
return next;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -101,7 +83,7 @@ final class EnhancedPainlessLexer extends PainlessLexer {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean slashIsRegex() {
|
protected boolean slashIsRegex() {
|
||||||
Token lastToken = getPreviousToken();
|
Token lastToken = current;
|
||||||
if (lastToken == null) {
|
if (lastToken == null) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -120,18 +102,4 @@ final class EnhancedPainlessLexer extends PainlessLexer {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean insertSemicolon(Token previous, Token next) {
|
|
||||||
if (previous == null || next.getType() != PainlessLexer.RBRACK) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
switch (previous.getType()) {
|
|
||||||
case PainlessLexer.RBRACK: // };} would be weird!
|
|
||||||
case PainlessLexer.SEMICOLON: // already have a semicolon, no need to add one
|
|
||||||
case PainlessLexer.LBRACK: // empty blocks don't need a semicolon
|
|
||||||
return false;
|
|
||||||
default:
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -32,6 +32,13 @@ class PainlessParserBaseVisitor<T> extends AbstractParseTreeVisitor<T> implement
|
|||||||
* {@link #visitChildren} on {@code ctx}.</p>
|
* {@link #visitChildren} on {@code ctx}.</p>
|
||||||
*/
|
*/
|
||||||
@Override public T visitParameters(PainlessParser.ParametersContext ctx) { return visitChildren(ctx); }
|
@Override public T visitParameters(PainlessParser.ParametersContext ctx) { return visitChildren(ctx); }
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* <p>The default implementation returns the result of calling
|
||||||
|
* {@link #visitChildren} on {@code ctx}.</p>
|
||||||
|
*/
|
||||||
|
@Override public T visitStatement(PainlessParser.StatementContext ctx) { return visitChildren(ctx); }
|
||||||
/**
|
/**
|
||||||
* {@inheritDoc}
|
* {@inheritDoc}
|
||||||
*
|
*
|
||||||
@ -46,13 +53,6 @@ class PainlessParserBaseVisitor<T> extends AbstractParseTreeVisitor<T> implement
|
|||||||
* {@link #visitChildren} on {@code ctx}.</p>
|
* {@link #visitChildren} on {@code ctx}.</p>
|
||||||
*/
|
*/
|
||||||
@Override public T visitWhile(PainlessParser.WhileContext ctx) { return visitChildren(ctx); }
|
@Override public T visitWhile(PainlessParser.WhileContext ctx) { return visitChildren(ctx); }
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*
|
|
||||||
* <p>The default implementation returns the result of calling
|
|
||||||
* {@link #visitChildren} on {@code ctx}.</p>
|
|
||||||
*/
|
|
||||||
@Override public T visitDo(PainlessParser.DoContext ctx) { return visitChildren(ctx); }
|
|
||||||
/**
|
/**
|
||||||
* {@inheritDoc}
|
* {@inheritDoc}
|
||||||
*
|
*
|
||||||
@ -74,6 +74,20 @@ class PainlessParserBaseVisitor<T> extends AbstractParseTreeVisitor<T> implement
|
|||||||
* {@link #visitChildren} on {@code ctx}.</p>
|
* {@link #visitChildren} on {@code ctx}.</p>
|
||||||
*/
|
*/
|
||||||
@Override public T visitIneach(PainlessParser.IneachContext ctx) { return visitChildren(ctx); }
|
@Override public T visitIneach(PainlessParser.IneachContext ctx) { return visitChildren(ctx); }
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* <p>The default implementation returns the result of calling
|
||||||
|
* {@link #visitChildren} on {@code ctx}.</p>
|
||||||
|
*/
|
||||||
|
@Override public T visitTry(PainlessParser.TryContext ctx) { return visitChildren(ctx); }
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* <p>The default implementation returns the result of calling
|
||||||
|
* {@link #visitChildren} on {@code ctx}.</p>
|
||||||
|
*/
|
||||||
|
@Override public T visitDo(PainlessParser.DoContext ctx) { return visitChildren(ctx); }
|
||||||
/**
|
/**
|
||||||
* {@inheritDoc}
|
* {@inheritDoc}
|
||||||
*
|
*
|
||||||
@ -102,13 +116,6 @@ class PainlessParserBaseVisitor<T> extends AbstractParseTreeVisitor<T> implement
|
|||||||
* {@link #visitChildren} on {@code ctx}.</p>
|
* {@link #visitChildren} on {@code ctx}.</p>
|
||||||
*/
|
*/
|
||||||
@Override public T visitReturn(PainlessParser.ReturnContext ctx) { return visitChildren(ctx); }
|
@Override public T visitReturn(PainlessParser.ReturnContext ctx) { return visitChildren(ctx); }
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*
|
|
||||||
* <p>The default implementation returns the result of calling
|
|
||||||
* {@link #visitChildren} on {@code ctx}.</p>
|
|
||||||
*/
|
|
||||||
@Override public T visitTry(PainlessParser.TryContext ctx) { return visitChildren(ctx); }
|
|
||||||
/**
|
/**
|
||||||
* {@inheritDoc}
|
* {@inheritDoc}
|
||||||
*
|
*
|
||||||
@ -186,13 +193,6 @@ class PainlessParserBaseVisitor<T> extends AbstractParseTreeVisitor<T> implement
|
|||||||
* {@link #visitChildren} on {@code ctx}.</p>
|
* {@link #visitChildren} on {@code ctx}.</p>
|
||||||
*/
|
*/
|
||||||
@Override public T visitTrap(PainlessParser.TrapContext ctx) { return visitChildren(ctx); }
|
@Override public T visitTrap(PainlessParser.TrapContext ctx) { return visitChildren(ctx); }
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*
|
|
||||||
* <p>The default implementation returns the result of calling
|
|
||||||
* {@link #visitChildren} on {@code ctx}.</p>
|
|
||||||
*/
|
|
||||||
@Override public T visitDelimiter(PainlessParser.DelimiterContext ctx) { return visitChildren(ctx); }
|
|
||||||
/**
|
/**
|
||||||
* {@inheritDoc}
|
* {@inheritDoc}
|
||||||
*
|
*
|
||||||
|
@ -28,93 +28,99 @@ interface PainlessParserVisitor<T> extends ParseTreeVisitor<T> {
|
|||||||
* @return the visitor result
|
* @return the visitor result
|
||||||
*/
|
*/
|
||||||
T visitParameters(PainlessParser.ParametersContext ctx);
|
T visitParameters(PainlessParser.ParametersContext ctx);
|
||||||
|
/**
|
||||||
|
* Visit a parse tree produced by {@link PainlessParser#statement}.
|
||||||
|
* @param ctx the parse tree
|
||||||
|
* @return the visitor result
|
||||||
|
*/
|
||||||
|
T visitStatement(PainlessParser.StatementContext ctx);
|
||||||
/**
|
/**
|
||||||
* Visit a parse tree produced by the {@code if}
|
* Visit a parse tree produced by the {@code if}
|
||||||
* labeled alternative in {@link PainlessParser#statement}.
|
* labeled alternative in {@link PainlessParser#rstatement}.
|
||||||
* @param ctx the parse tree
|
* @param ctx the parse tree
|
||||||
* @return the visitor result
|
* @return the visitor result
|
||||||
*/
|
*/
|
||||||
T visitIf(PainlessParser.IfContext ctx);
|
T visitIf(PainlessParser.IfContext ctx);
|
||||||
/**
|
/**
|
||||||
* Visit a parse tree produced by the {@code while}
|
* Visit a parse tree produced by the {@code while}
|
||||||
* labeled alternative in {@link PainlessParser#statement}.
|
* labeled alternative in {@link PainlessParser#rstatement}.
|
||||||
* @param ctx the parse tree
|
* @param ctx the parse tree
|
||||||
* @return the visitor result
|
* @return the visitor result
|
||||||
*/
|
*/
|
||||||
T visitWhile(PainlessParser.WhileContext ctx);
|
T visitWhile(PainlessParser.WhileContext ctx);
|
||||||
/**
|
|
||||||
* Visit a parse tree produced by the {@code do}
|
|
||||||
* labeled alternative in {@link PainlessParser#statement}.
|
|
||||||
* @param ctx the parse tree
|
|
||||||
* @return the visitor result
|
|
||||||
*/
|
|
||||||
T visitDo(PainlessParser.DoContext ctx);
|
|
||||||
/**
|
/**
|
||||||
* Visit a parse tree produced by the {@code for}
|
* Visit a parse tree produced by the {@code for}
|
||||||
* labeled alternative in {@link PainlessParser#statement}.
|
* labeled alternative in {@link PainlessParser#rstatement}.
|
||||||
* @param ctx the parse tree
|
* @param ctx the parse tree
|
||||||
* @return the visitor result
|
* @return the visitor result
|
||||||
*/
|
*/
|
||||||
T visitFor(PainlessParser.ForContext ctx);
|
T visitFor(PainlessParser.ForContext ctx);
|
||||||
/**
|
/**
|
||||||
* Visit a parse tree produced by the {@code each}
|
* Visit a parse tree produced by the {@code each}
|
||||||
* labeled alternative in {@link PainlessParser#statement}.
|
* labeled alternative in {@link PainlessParser#rstatement}.
|
||||||
* @param ctx the parse tree
|
* @param ctx the parse tree
|
||||||
* @return the visitor result
|
* @return the visitor result
|
||||||
*/
|
*/
|
||||||
T visitEach(PainlessParser.EachContext ctx);
|
T visitEach(PainlessParser.EachContext ctx);
|
||||||
/**
|
/**
|
||||||
* Visit a parse tree produced by the {@code ineach}
|
* Visit a parse tree produced by the {@code ineach}
|
||||||
* labeled alternative in {@link PainlessParser#statement}.
|
* labeled alternative in {@link PainlessParser#rstatement}.
|
||||||
* @param ctx the parse tree
|
* @param ctx the parse tree
|
||||||
* @return the visitor result
|
* @return the visitor result
|
||||||
*/
|
*/
|
||||||
T visitIneach(PainlessParser.IneachContext ctx);
|
T visitIneach(PainlessParser.IneachContext ctx);
|
||||||
|
/**
|
||||||
|
* Visit a parse tree produced by the {@code try}
|
||||||
|
* labeled alternative in {@link PainlessParser#rstatement}.
|
||||||
|
* @param ctx the parse tree
|
||||||
|
* @return the visitor result
|
||||||
|
*/
|
||||||
|
T visitTry(PainlessParser.TryContext ctx);
|
||||||
|
/**
|
||||||
|
* Visit a parse tree produced by the {@code do}
|
||||||
|
* labeled alternative in {@link PainlessParser#dstatement}.
|
||||||
|
* @param ctx the parse tree
|
||||||
|
* @return the visitor result
|
||||||
|
*/
|
||||||
|
T visitDo(PainlessParser.DoContext ctx);
|
||||||
/**
|
/**
|
||||||
* Visit a parse tree produced by the {@code decl}
|
* Visit a parse tree produced by the {@code decl}
|
||||||
* labeled alternative in {@link PainlessParser#statement}.
|
* labeled alternative in {@link PainlessParser#dstatement}.
|
||||||
* @param ctx the parse tree
|
* @param ctx the parse tree
|
||||||
* @return the visitor result
|
* @return the visitor result
|
||||||
*/
|
*/
|
||||||
T visitDecl(PainlessParser.DeclContext ctx);
|
T visitDecl(PainlessParser.DeclContext ctx);
|
||||||
/**
|
/**
|
||||||
* Visit a parse tree produced by the {@code continue}
|
* Visit a parse tree produced by the {@code continue}
|
||||||
* labeled alternative in {@link PainlessParser#statement}.
|
* labeled alternative in {@link PainlessParser#dstatement}.
|
||||||
* @param ctx the parse tree
|
* @param ctx the parse tree
|
||||||
* @return the visitor result
|
* @return the visitor result
|
||||||
*/
|
*/
|
||||||
T visitContinue(PainlessParser.ContinueContext ctx);
|
T visitContinue(PainlessParser.ContinueContext ctx);
|
||||||
/**
|
/**
|
||||||
* Visit a parse tree produced by the {@code break}
|
* Visit a parse tree produced by the {@code break}
|
||||||
* labeled alternative in {@link PainlessParser#statement}.
|
* labeled alternative in {@link PainlessParser#dstatement}.
|
||||||
* @param ctx the parse tree
|
* @param ctx the parse tree
|
||||||
* @return the visitor result
|
* @return the visitor result
|
||||||
*/
|
*/
|
||||||
T visitBreak(PainlessParser.BreakContext ctx);
|
T visitBreak(PainlessParser.BreakContext ctx);
|
||||||
/**
|
/**
|
||||||
* Visit a parse tree produced by the {@code return}
|
* Visit a parse tree produced by the {@code return}
|
||||||
* labeled alternative in {@link PainlessParser#statement}.
|
* labeled alternative in {@link PainlessParser#dstatement}.
|
||||||
* @param ctx the parse tree
|
* @param ctx the parse tree
|
||||||
* @return the visitor result
|
* @return the visitor result
|
||||||
*/
|
*/
|
||||||
T visitReturn(PainlessParser.ReturnContext ctx);
|
T visitReturn(PainlessParser.ReturnContext ctx);
|
||||||
/**
|
|
||||||
* Visit a parse tree produced by the {@code try}
|
|
||||||
* labeled alternative in {@link PainlessParser#statement}.
|
|
||||||
* @param ctx the parse tree
|
|
||||||
* @return the visitor result
|
|
||||||
*/
|
|
||||||
T visitTry(PainlessParser.TryContext ctx);
|
|
||||||
/**
|
/**
|
||||||
* Visit a parse tree produced by the {@code throw}
|
* Visit a parse tree produced by the {@code throw}
|
||||||
* labeled alternative in {@link PainlessParser#statement}.
|
* labeled alternative in {@link PainlessParser#dstatement}.
|
||||||
* @param ctx the parse tree
|
* @param ctx the parse tree
|
||||||
* @return the visitor result
|
* @return the visitor result
|
||||||
*/
|
*/
|
||||||
T visitThrow(PainlessParser.ThrowContext ctx);
|
T visitThrow(PainlessParser.ThrowContext ctx);
|
||||||
/**
|
/**
|
||||||
* Visit a parse tree produced by the {@code expr}
|
* Visit a parse tree produced by the {@code expr}
|
||||||
* labeled alternative in {@link PainlessParser#statement}.
|
* labeled alternative in {@link PainlessParser#dstatement}.
|
||||||
* @param ctx the parse tree
|
* @param ctx the parse tree
|
||||||
* @return the visitor result
|
* @return the visitor result
|
||||||
*/
|
*/
|
||||||
@ -173,12 +179,6 @@ interface PainlessParserVisitor<T> extends ParseTreeVisitor<T> {
|
|||||||
* @return the visitor result
|
* @return the visitor result
|
||||||
*/
|
*/
|
||||||
T visitTrap(PainlessParser.TrapContext ctx);
|
T visitTrap(PainlessParser.TrapContext ctx);
|
||||||
/**
|
|
||||||
* Visit a parse tree produced by {@link PainlessParser#delimiter}.
|
|
||||||
* @param ctx the parse tree
|
|
||||||
* @return the visitor result
|
|
||||||
*/
|
|
||||||
T visitDelimiter(PainlessParser.DelimiterContext ctx);
|
|
||||||
/**
|
/**
|
||||||
* Visit a parse tree produced by the {@code single}
|
* Visit a parse tree produced by the {@code single}
|
||||||
* labeled alternative in {@link PainlessParser#expression}.
|
* labeled alternative in {@link PainlessParser#expression}.
|
||||||
|
@ -56,7 +56,6 @@ import org.elasticsearch.painless.antlr.PainlessParser.DeclContext;
|
|||||||
import org.elasticsearch.painless.antlr.PainlessParser.DeclarationContext;
|
import org.elasticsearch.painless.antlr.PainlessParser.DeclarationContext;
|
||||||
import org.elasticsearch.painless.antlr.PainlessParser.DecltypeContext;
|
import org.elasticsearch.painless.antlr.PainlessParser.DecltypeContext;
|
||||||
import org.elasticsearch.painless.antlr.PainlessParser.DeclvarContext;
|
import org.elasticsearch.painless.antlr.PainlessParser.DeclvarContext;
|
||||||
import org.elasticsearch.painless.antlr.PainlessParser.DelimiterContext;
|
|
||||||
import org.elasticsearch.painless.antlr.PainlessParser.DoContext;
|
import org.elasticsearch.painless.antlr.PainlessParser.DoContext;
|
||||||
import org.elasticsearch.painless.antlr.PainlessParser.DynamicContext;
|
import org.elasticsearch.painless.antlr.PainlessParser.DynamicContext;
|
||||||
import org.elasticsearch.painless.antlr.PainlessParser.EachContext;
|
import org.elasticsearch.painless.antlr.PainlessParser.EachContext;
|
||||||
@ -264,6 +263,10 @@ public final class Walker extends PainlessParserBaseVisitor<ANode> {
|
|||||||
statements.add((AStatement)visit(statement));
|
statements.add((AStatement)visit(statement));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ctx.dstatement() != null) {
|
||||||
|
statements.add((AStatement)visit(ctx.dstatement()));
|
||||||
|
}
|
||||||
|
|
||||||
return new SSource(scriptClassInfo, settings, sourceName, sourceText, debugStream, (MainMethodReserved)reserved.pop(),
|
return new SSource(scriptClassInfo, settings, sourceName, sourceText, debugStream, (MainMethodReserved)reserved.pop(),
|
||||||
location(ctx), functions, globals, statements);
|
location(ctx), functions, globals, statements);
|
||||||
}
|
}
|
||||||
@ -290,6 +293,10 @@ public final class Walker extends PainlessParserBaseVisitor<ANode> {
|
|||||||
statements.add((AStatement)visit(statement));
|
statements.add((AStatement)visit(statement));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ctx.block().dstatement() != null) {
|
||||||
|
statements.add((AStatement)visit(ctx.block().dstatement()));
|
||||||
|
}
|
||||||
|
|
||||||
return new SFunction((FunctionReserved)reserved.pop(), location(ctx), rtnType, name,
|
return new SFunction((FunctionReserved)reserved.pop(), location(ctx), rtnType, name,
|
||||||
paramTypes, paramNames, statements, false);
|
paramTypes, paramNames, statements, false);
|
||||||
}
|
}
|
||||||
@ -299,6 +306,17 @@ public final class Walker extends PainlessParserBaseVisitor<ANode> {
|
|||||||
throw location(ctx).createError(new IllegalStateException("Illegal tree structure."));
|
throw location(ctx).createError(new IllegalStateException("Illegal tree structure."));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ANode visitStatement(StatementContext ctx) {
|
||||||
|
if (ctx.rstatement() != null) {
|
||||||
|
return visit(ctx.rstatement());
|
||||||
|
} else if (ctx.dstatement() != null) {
|
||||||
|
return visit(ctx.dstatement());
|
||||||
|
} else {
|
||||||
|
throw location(ctx).createError(new IllegalStateException("Illegal tree structure."));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ANode visitIf(IfContext ctx) {
|
public ANode visitIf(IfContext ctx) {
|
||||||
AExpression expression = (AExpression)visit(ctx.expression());
|
AExpression expression = (AExpression)visit(ctx.expression());
|
||||||
@ -446,7 +464,7 @@ public final class Walker extends PainlessParserBaseVisitor<ANode> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ANode visitBlock(BlockContext ctx) {
|
public ANode visitBlock(BlockContext ctx) {
|
||||||
if (ctx.statement().isEmpty()) {
|
if (ctx.statement().isEmpty() && ctx.dstatement() == null) {
|
||||||
return null;
|
return null;
|
||||||
} else {
|
} else {
|
||||||
List<AStatement> statements = new ArrayList<>();
|
List<AStatement> statements = new ArrayList<>();
|
||||||
@ -455,6 +473,10 @@ public final class Walker extends PainlessParserBaseVisitor<ANode> {
|
|||||||
statements.add((AStatement)visit(statement));
|
statements.add((AStatement)visit(statement));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ctx.dstatement() != null) {
|
||||||
|
statements.add((AStatement)visit(ctx.dstatement()));
|
||||||
|
}
|
||||||
|
|
||||||
return new SBlock(location(ctx), statements);
|
return new SBlock(location(ctx), statements);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -514,11 +536,6 @@ public final class Walker extends PainlessParserBaseVisitor<ANode> {
|
|||||||
return new SCatch(location(ctx), type, name, block);
|
return new SCatch(location(ctx), type, name, block);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public ANode visitDelimiter(DelimiterContext ctx) {
|
|
||||||
throw location(ctx).createError(new IllegalStateException("Illegal tree structure."));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ANode visitSingle(SingleContext ctx) {
|
public ANode visitSingle(SingleContext ctx) {
|
||||||
return visit(ctx.unary());
|
return visit(ctx.unary());
|
||||||
@ -1074,6 +1091,10 @@ public final class Walker extends PainlessParserBaseVisitor<ANode> {
|
|||||||
for (StatementContext statement : ctx.block().statement()) {
|
for (StatementContext statement : ctx.block().statement()) {
|
||||||
statements.add((AStatement)visit(statement));
|
statements.add((AStatement)visit(statement));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ctx.block().dstatement() != null) {
|
||||||
|
statements.add((AStatement)visit(ctx.block().dstatement()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FunctionReserved lambdaReserved = (FunctionReserved)reserved.pop();
|
FunctionReserved lambdaReserved = (FunctionReserved)reserved.pop();
|
||||||
|
@ -278,6 +278,6 @@ public class RegexTests extends ScriptTestCase {
|
|||||||
IllegalArgumentException e = expectScriptThrows(IllegalArgumentException.class, () -> {
|
IllegalArgumentException e = expectScriptThrows(IllegalArgumentException.class, () -> {
|
||||||
exec("/asdf/b", false); // Not picky so we get a non-assertion error
|
exec("/asdf/b", false); // Not picky so we get a non-assertion error
|
||||||
});
|
});
|
||||||
assertEquals("unexpected token ['b'] was expecting one of [{<EOF>, ';'}].", e.getMessage());
|
assertEquals("invalid sequence of tokens near ['b'].", e.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -256,7 +256,7 @@ public class WhenThingsGoWrongTests extends ScriptTestCase {
|
|||||||
// We don't want PICKY here so we get the normal error message
|
// We don't want PICKY here so we get the normal error message
|
||||||
exec("def i = 1} return 1", emptyMap(), emptyMap(), null, false);
|
exec("def i = 1} return 1", emptyMap(), emptyMap(), null, false);
|
||||||
});
|
});
|
||||||
assertEquals("unexpected token ['}'] was expecting one of [<EOF>].", e.getMessage());
|
assertEquals("invalid sequence of tokens near ['}'].", e.getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testBadBoxingCast() {
|
public void testBadBoxingCast() {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user