commit
ea206237e3
|
@ -126,21 +126,23 @@ expression returns [boolean s = true]
|
|||
// processing a variable/method chain. This prevents the chain
|
||||
// from being applied to rules where it wouldn't be allowed.
|
||||
unary[boolean c] returns [boolean s = true]
|
||||
: { !$c }? ( INCR | DECR ) chain[true] # pre
|
||||
| { !$c }? chain[true] (INCR | DECR ) # post
|
||||
| { !$c }? chain[false] # read
|
||||
| { !$c }? ( OCTAL | HEX | INTEGER | DECIMAL ) { $s = false; } # numeric
|
||||
| { !$c }? TRUE { $s = false; } # true
|
||||
| { !$c }? FALSE { $s = false; } # false
|
||||
| { !$c }? NULL { $s = false; } # null
|
||||
| { !$c }? ( BOOLNOT | BWNOT | ADD | SUB ) unary[false] # operator
|
||||
| LP decltype RP unary[$c] # cast
|
||||
: { !$c }? ( INCR | DECR ) chain[true] # pre
|
||||
| { !$c }? chain[true] (INCR | DECR ) # post
|
||||
| { !$c }? chain[false] # read
|
||||
| { !$c }? ( OCTAL | HEX | INTEGER | DECIMAL ) { $s = false; } # numeric
|
||||
| { !$c }? TRUE { $s = false; } # true
|
||||
| { !$c }? FALSE { $s = false; } # false
|
||||
| { !$c }? NULL { $s = false; } # null
|
||||
| { !$c }? listinitializer { $s = false; } # listinit
|
||||
| { !$c }? mapinitializer { $s = false; } # mapinit
|
||||
| { !$c }? ( BOOLNOT | BWNOT | ADD | SUB ) unary[false] # operator
|
||||
| LP decltype RP unary[$c] # cast
|
||||
;
|
||||
|
||||
chain[boolean c]
|
||||
: p = primary[$c] secondary[$p.s]* # dynamic
|
||||
| decltype dot secondary[true]* # static
|
||||
| NEW TYPE (LBRACE expression RBRACE)+ (dot secondary[true]*)? # newarray
|
||||
: p = primary[$c] secondary[$p.s]* # dynamic
|
||||
| decltype dot secondary[true]* # static
|
||||
| arrayinitializer # newarray
|
||||
;
|
||||
|
||||
primary[boolean c] returns [boolean s = true]
|
||||
|
@ -213,3 +215,22 @@ capturingFuncref
|
|||
localFuncref
|
||||
: THIS REF ID
|
||||
;
|
||||
|
||||
arrayinitializer
|
||||
: NEW TYPE (LBRACE expression RBRACE)+ (dot secondary[true]*)? # newstandardarray
|
||||
| NEW TYPE LBRACE RBRACE LBRACK ( expression ( COMMA expression )* )? SEMICOLON? RBRACK # newinitializedarray
|
||||
;
|
||||
|
||||
listinitializer
|
||||
: LBRACE expression ( COMMA expression)* RBRACE
|
||||
| LBRACE RBRACE
|
||||
;
|
||||
|
||||
mapinitializer
|
||||
: LBRACE maptoken ( COMMA maptoken )* RBRACE
|
||||
| LBRACE COLON RBRACE
|
||||
;
|
||||
|
||||
maptoken
|
||||
: expression COLON expression
|
||||
;
|
File diff suppressed because it is too large
Load Diff
|
@ -277,6 +277,20 @@ class PainlessParserBaseVisitor<T> extends AbstractParseTreeVisitor<T> implement
|
|||
* {@link #visitChildren} on {@code ctx}.</p>
|
||||
*/
|
||||
@Override public T visitNull(PainlessParser.NullContext ctx) { return visitChildren(ctx); }
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* <p>The default implementation returns the result of calling
|
||||
* {@link #visitChildren} on {@code ctx}.</p>
|
||||
*/
|
||||
@Override public T visitListinit(PainlessParser.ListinitContext ctx) { return visitChildren(ctx); }
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* <p>The default implementation returns the result of calling
|
||||
* {@link #visitChildren} on {@code ctx}.</p>
|
||||
*/
|
||||
@Override public T visitMapinit(PainlessParser.MapinitContext ctx) { return visitChildren(ctx); }
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
|
@ -452,4 +466,39 @@ class PainlessParserBaseVisitor<T> extends AbstractParseTreeVisitor<T> implement
|
|||
* {@link #visitChildren} on {@code ctx}.</p>
|
||||
*/
|
||||
@Override public T visitLocalFuncref(PainlessParser.LocalFuncrefContext ctx) { return visitChildren(ctx); }
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* <p>The default implementation returns the result of calling
|
||||
* {@link #visitChildren} on {@code ctx}.</p>
|
||||
*/
|
||||
@Override public T visitNewstandardarray(PainlessParser.NewstandardarrayContext ctx) { return visitChildren(ctx); }
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* <p>The default implementation returns the result of calling
|
||||
* {@link #visitChildren} on {@code ctx}.</p>
|
||||
*/
|
||||
@Override public T visitNewinitializedarray(PainlessParser.NewinitializedarrayContext ctx) { return visitChildren(ctx); }
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* <p>The default implementation returns the result of calling
|
||||
* {@link #visitChildren} on {@code ctx}.</p>
|
||||
*/
|
||||
@Override public T visitListinitializer(PainlessParser.ListinitializerContext ctx) { return visitChildren(ctx); }
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* <p>The default implementation returns the result of calling
|
||||
* {@link #visitChildren} on {@code ctx}.</p>
|
||||
*/
|
||||
@Override public T visitMapinitializer(PainlessParser.MapinitializerContext ctx) { return visitChildren(ctx); }
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* <p>The default implementation returns the result of calling
|
||||
* {@link #visitChildren} on {@code ctx}.</p>
|
||||
*/
|
||||
@Override public T visitMaptoken(PainlessParser.MaptokenContext ctx) { return visitChildren(ctx); }
|
||||
}
|
||||
|
|
|
@ -263,6 +263,20 @@ interface PainlessParserVisitor<T> extends ParseTreeVisitor<T> {
|
|||
* @return the visitor result
|
||||
*/
|
||||
T visitNull(PainlessParser.NullContext ctx);
|
||||
/**
|
||||
* Visit a parse tree produced by the {@code listinit}
|
||||
* labeled alternative in {@link PainlessParser#unary}.
|
||||
* @param ctx the parse tree
|
||||
* @return the visitor result
|
||||
*/
|
||||
T visitListinit(PainlessParser.ListinitContext ctx);
|
||||
/**
|
||||
* Visit a parse tree produced by the {@code mapinit}
|
||||
* labeled alternative in {@link PainlessParser#unary}.
|
||||
* @param ctx the parse tree
|
||||
* @return the visitor result
|
||||
*/
|
||||
T visitMapinit(PainlessParser.MapinitContext ctx);
|
||||
/**
|
||||
* Visit a parse tree produced by the {@code operator}
|
||||
* labeled alternative in {@link PainlessParser#unary}.
|
||||
|
@ -428,4 +442,36 @@ interface PainlessParserVisitor<T> extends ParseTreeVisitor<T> {
|
|||
* @return the visitor result
|
||||
*/
|
||||
T visitLocalFuncref(PainlessParser.LocalFuncrefContext ctx);
|
||||
/**
|
||||
* Visit a parse tree produced by the {@code newstandardarray}
|
||||
* labeled alternative in {@link PainlessParser#arrayinitializer}.
|
||||
* @param ctx the parse tree
|
||||
* @return the visitor result
|
||||
*/
|
||||
T visitNewstandardarray(PainlessParser.NewstandardarrayContext ctx);
|
||||
/**
|
||||
* Visit a parse tree produced by the {@code newinitializedarray}
|
||||
* labeled alternative in {@link PainlessParser#arrayinitializer}.
|
||||
* @param ctx the parse tree
|
||||
* @return the visitor result
|
||||
*/
|
||||
T visitNewinitializedarray(PainlessParser.NewinitializedarrayContext ctx);
|
||||
/**
|
||||
* Visit a parse tree produced by {@link PainlessParser#listinitializer}.
|
||||
* @param ctx the parse tree
|
||||
* @return the visitor result
|
||||
*/
|
||||
T visitListinitializer(PainlessParser.ListinitializerContext ctx);
|
||||
/**
|
||||
* Visit a parse tree produced by {@link PainlessParser#mapinitializer}.
|
||||
* @param ctx the parse tree
|
||||
* @return the visitor result
|
||||
*/
|
||||
T visitMapinitializer(PainlessParser.MapinitializerContext ctx);
|
||||
/**
|
||||
* Visit a parse tree produced by {@link PainlessParser#maptoken}.
|
||||
* @param ctx the parse tree
|
||||
* @return the visitor result
|
||||
*/
|
||||
T visitMaptoken(PainlessParser.MaptokenContext ctx);
|
||||
}
|
||||
|
|
|
@ -30,6 +30,15 @@ import org.antlr.v4.runtime.atn.PredictionMode;
|
|||
import org.antlr.v4.runtime.tree.TerminalNode;
|
||||
import org.elasticsearch.painless.CompilerSettings;
|
||||
import org.elasticsearch.painless.Globals;
|
||||
import org.elasticsearch.painless.antlr.PainlessParser.ListinitContext;
|
||||
import org.elasticsearch.painless.antlr.PainlessParser.ListinitializerContext;
|
||||
import org.elasticsearch.painless.antlr.PainlessParser.MapinitContext;
|
||||
import org.elasticsearch.painless.antlr.PainlessParser.MapinitializerContext;
|
||||
import org.elasticsearch.painless.antlr.PainlessParser.MaptokenContext;
|
||||
import org.elasticsearch.painless.antlr.PainlessParser.NewinitializedarrayContext;
|
||||
import org.elasticsearch.painless.antlr.PainlessParser.NewstandardarrayContext;
|
||||
import org.elasticsearch.painless.node.EListInit;
|
||||
import org.elasticsearch.painless.node.EMapInit;
|
||||
import org.elasticsearch.painless.node.SFunction.Reserved;
|
||||
import org.elasticsearch.painless.node.SSource.MainMethodReserved;
|
||||
import org.elasticsearch.painless.node.SFunction.FunctionReserved;
|
||||
|
@ -241,7 +250,7 @@ public final class Walker extends PainlessParserBaseVisitor<Object> {
|
|||
statements.add((AStatement)visit(statement));
|
||||
}
|
||||
|
||||
return new SSource(settings, sourceName, sourceText, debugStream, (MainMethodReserved)reserved.pop(),
|
||||
return new SSource(settings, sourceName, sourceText, debugStream, (MainMethodReserved)reserved.pop(),
|
||||
location(ctx), functions, globals, statements);
|
||||
}
|
||||
|
||||
|
@ -267,7 +276,7 @@ public final class Walker extends PainlessParserBaseVisitor<Object> {
|
|||
statements.add((AStatement)visit(statement));
|
||||
}
|
||||
|
||||
return new SFunction((FunctionReserved)reserved.pop(), location(ctx), rtnType, name,
|
||||
return new SFunction((FunctionReserved)reserved.pop(), location(ctx), rtnType, name,
|
||||
paramTypes, paramNames, statements, false);
|
||||
}
|
||||
|
||||
|
@ -720,6 +729,16 @@ public final class Walker extends PainlessParserBaseVisitor<Object> {
|
|||
return new ENull(location(ctx));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visitListinit(ListinitContext ctx) {
|
||||
return visit(ctx.listinitializer());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visitMapinit(MapinitContext ctx) {
|
||||
return visit(ctx.mapinitializer());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visitOperator(OperatorContext ctx) {
|
||||
if (ctx.SUB() != null && ctx.unary() instanceof NumericContext) {
|
||||
|
@ -797,27 +816,7 @@ public final class Walker extends PainlessParserBaseVisitor<Object> {
|
|||
|
||||
@Override
|
||||
public Object visitNewarray(NewarrayContext ctx) {
|
||||
String type = ctx.TYPE().getText();
|
||||
List<AExpression> expressions = new ArrayList<>();
|
||||
|
||||
for (ExpressionContext expression : ctx.expression()) {
|
||||
expressions.add((AExpression)visitExpression(expression));
|
||||
}
|
||||
|
||||
List<ALink> links = new ArrayList<>();
|
||||
links.add(new LNewArray(location(ctx), type, expressions));
|
||||
|
||||
if (ctx.dot() != null) {
|
||||
links.add((ALink)visit(ctx.dot()));
|
||||
|
||||
for (SecondaryContext secondary : ctx.secondary()) {
|
||||
links.add((ALink)visit(secondary));
|
||||
}
|
||||
} else if (!ctx.secondary().isEmpty()) {
|
||||
throw location(ctx).createError(new IllegalStateException("Illegal tree structure."));
|
||||
}
|
||||
|
||||
return links;
|
||||
return visit(ctx.arrayinitializer());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -978,9 +977,9 @@ public final class Walker extends PainlessParserBaseVisitor<Object> {
|
|||
statements.add((AStatement)visit(statement));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
String name = nextLambda();
|
||||
return new ELambda(name, (FunctionReserved)reserved.pop(), location(ctx),
|
||||
return new ELambda(name, (FunctionReserved)reserved.pop(), location(ctx),
|
||||
paramTypes, paramNames, statements);
|
||||
}
|
||||
|
||||
|
@ -1016,13 +1015,13 @@ public final class Walker extends PainlessParserBaseVisitor<Object> {
|
|||
// taking integer as argument and returning a new instance, and return a ref to that.
|
||||
Location location = location(ctx);
|
||||
String arrayType = ctx.decltype().getText();
|
||||
SReturn code = new SReturn(location,
|
||||
SReturn code = new SReturn(location,
|
||||
new EChain(location,
|
||||
new LNewArray(location, arrayType, Arrays.asList(
|
||||
new EChain(location,
|
||||
new LVariable(location, "size"))))));
|
||||
new EChain(location,
|
||||
new LVariable(location, "size"))), false)));
|
||||
String name = nextLambda();
|
||||
globals.addSyntheticMethod(new SFunction(new FunctionReserved(), location, arrayType, name,
|
||||
globals.addSyntheticMethod(new SFunction(new FunctionReserved(), location, arrayType, name,
|
||||
Arrays.asList("int"), Arrays.asList("size"), Arrays.asList(code), true));
|
||||
return new EFunctionRef(location(ctx), "this", name);
|
||||
}
|
||||
|
@ -1038,7 +1037,76 @@ public final class Walker extends PainlessParserBaseVisitor<Object> {
|
|||
public Object visitLocalFuncref(LocalFuncrefContext ctx) {
|
||||
return new EFunctionRef(location(ctx), ctx.THIS().getText(), ctx.ID().getText());
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Object visitNewstandardarray(NewstandardarrayContext ctx) {
|
||||
String type = ctx.TYPE().getText();
|
||||
List<AExpression> expressions = new ArrayList<>();
|
||||
|
||||
for (ExpressionContext expression : ctx.expression()) {
|
||||
expressions.add((AExpression)visitExpression(expression));
|
||||
}
|
||||
|
||||
List<ALink> links = new ArrayList<>();
|
||||
links.add(new LNewArray(location(ctx), type, expressions, false));
|
||||
|
||||
if (ctx.dot() != null) {
|
||||
links.add((ALink)visit(ctx.dot()));
|
||||
|
||||
for (SecondaryContext secondary : ctx.secondary()) {
|
||||
links.add((ALink)visit(secondary));
|
||||
}
|
||||
} else if (!ctx.secondary().isEmpty()) {
|
||||
throw location(ctx).createError(new IllegalStateException("Illegal tree structure."));
|
||||
}
|
||||
|
||||
return links;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visitNewinitializedarray(NewinitializedarrayContext ctx) {
|
||||
String type = ctx.TYPE().getText();
|
||||
List<AExpression> expressions = new ArrayList<>();
|
||||
|
||||
for (ExpressionContext expression : ctx.expression()) {
|
||||
expressions.add((AExpression)visitExpression(expression));
|
||||
}
|
||||
|
||||
List<ALink> links = new ArrayList<>();
|
||||
links.add(new LNewArray(location(ctx), type, expressions, true));
|
||||
|
||||
return links;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visitListinitializer(ListinitializerContext ctx) {
|
||||
List<AExpression> values = new ArrayList<>();
|
||||
|
||||
for (ExpressionContext expression : ctx.expression()) {
|
||||
values.add((AExpression)visitExpression(expression));
|
||||
}
|
||||
|
||||
return new EListInit(location(ctx), values);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visitMapinitializer(MapinitializerContext ctx) {
|
||||
List<AExpression> keys = new ArrayList<>();
|
||||
List<AExpression> values = new ArrayList<>();
|
||||
|
||||
for (MaptokenContext maptoken : ctx.maptoken()) {
|
||||
keys.add((AExpression)visitExpression(maptoken.expression(0)));
|
||||
values.add((AExpression)visitExpression(maptoken.expression(1)));
|
||||
}
|
||||
|
||||
return new EMapInit(location(ctx), keys, values);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visitMaptoken(MaptokenContext ctx) {
|
||||
throw location(ctx).createError(new IllegalStateException("Illegal tree structure."));
|
||||
}
|
||||
|
||||
/** Returns name of next lambda */
|
||||
private String nextLambda() {
|
||||
return "lambda$" + syntheticCounter++;
|
||||
|
|
|
@ -0,0 +1,100 @@
|
|||
/*
|
||||
* 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.painless.node;
|
||||
|
||||
import org.elasticsearch.painless.Definition;
|
||||
import org.elasticsearch.painless.Definition.Method;
|
||||
import org.elasticsearch.painless.Definition.MethodKey;
|
||||
import org.elasticsearch.painless.Globals;
|
||||
import org.elasticsearch.painless.Locals;
|
||||
import org.elasticsearch.painless.Location;
|
||||
import org.elasticsearch.painless.MethodWriter;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Represents a list initialization shortcut.
|
||||
*/
|
||||
public class EListInit extends AExpression {
|
||||
final List<AExpression> values;
|
||||
|
||||
Method constructor = null;
|
||||
Method method = null;
|
||||
|
||||
public EListInit(Location location, List<AExpression> values) {
|
||||
super(location);
|
||||
|
||||
this.values = values;
|
||||
}
|
||||
|
||||
@Override
|
||||
void extractVariables(Set<String> variables) {
|
||||
for (AExpression value : values) {
|
||||
value.extractVariables(variables);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
void analyze(Locals locals) {
|
||||
try {
|
||||
actual = Definition.getType("ArrayList");
|
||||
} catch (IllegalArgumentException exception) {
|
||||
throw createError(new IllegalStateException("Illegal tree structure."));
|
||||
}
|
||||
|
||||
constructor = actual.struct.constructors.get(new MethodKey("<init>", 0));
|
||||
|
||||
if (constructor == null) {
|
||||
throw createError(new IllegalStateException("Illegal tree structure."));
|
||||
}
|
||||
|
||||
method = actual.struct.methods.get(new MethodKey("add", 1));
|
||||
|
||||
if (method == null) {
|
||||
throw createError(new IllegalStateException("Illegal tree structure."));
|
||||
}
|
||||
|
||||
for (int index = 0; index < values.size(); ++index) {
|
||||
AExpression expression = values.get(index);
|
||||
|
||||
expression.expected = Definition.DEF_TYPE;
|
||||
expression.internal = true;
|
||||
expression.analyze(locals);
|
||||
values.set(index, expression.cast(locals));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
void write(MethodWriter writer, Globals globals) {
|
||||
writer.writeDebugInfo(location);
|
||||
|
||||
writer.newInstance(actual.type);
|
||||
writer.dup();
|
||||
writer.invokeConstructor(constructor.owner.type, constructor.method);
|
||||
|
||||
for (AExpression value : values) {
|
||||
writer.dup();
|
||||
value.write(writer, globals);
|
||||
method.write(writer);
|
||||
writer.pop();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,123 @@
|
|||
/*
|
||||
* 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.painless.node;
|
||||
|
||||
import org.elasticsearch.painless.Definition;
|
||||
import org.elasticsearch.painless.Definition.Method;
|
||||
import org.elasticsearch.painless.Definition.MethodKey;
|
||||
import org.elasticsearch.painless.Globals;
|
||||
import org.elasticsearch.painless.Locals;
|
||||
import org.elasticsearch.painless.Location;
|
||||
import org.elasticsearch.painless.MethodWriter;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Represents a map initialization shortcut.
|
||||
*/
|
||||
public class EMapInit extends AExpression {
|
||||
final List<AExpression> keys;
|
||||
final List<AExpression> values;
|
||||
|
||||
Method constructor = null;
|
||||
Method method = null;
|
||||
|
||||
public EMapInit(Location location, List<AExpression> keys, List<AExpression> values) {
|
||||
super(location);
|
||||
|
||||
this.keys = keys;
|
||||
this.values = values;
|
||||
}
|
||||
|
||||
@Override
|
||||
void extractVariables(Set<String> variables) {
|
||||
for (AExpression key : keys) {
|
||||
key.extractVariables(variables);
|
||||
}
|
||||
|
||||
for (AExpression value : values) {
|
||||
value.extractVariables(variables);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
void analyze(Locals locals) {
|
||||
try {
|
||||
actual = Definition.getType("HashMap");
|
||||
} catch (IllegalArgumentException exception) {
|
||||
throw createError(new IllegalStateException("Illegal tree structure."));
|
||||
}
|
||||
|
||||
constructor = actual.struct.constructors.get(new MethodKey("<init>", 0));
|
||||
|
||||
if (constructor == null) {
|
||||
throw createError(new IllegalStateException("Illegal tree structure."));
|
||||
}
|
||||
|
||||
method = actual.struct.methods.get(new MethodKey("put", 2));
|
||||
|
||||
if (method == null) {
|
||||
throw createError(new IllegalStateException("Illegal tree structure."));
|
||||
}
|
||||
|
||||
if (keys.size() != values.size()) {
|
||||
throw createError(new IllegalStateException("Illegal tree structure."));
|
||||
}
|
||||
|
||||
for (int index = 0; index < keys.size(); ++index) {
|
||||
AExpression expression = keys.get(index);
|
||||
|
||||
expression.expected = Definition.DEF_TYPE;
|
||||
expression.internal = true;
|
||||
expression.analyze(locals);
|
||||
keys.set(index, expression.cast(locals));
|
||||
}
|
||||
|
||||
for (int index = 0; index < values.size(); ++index) {
|
||||
AExpression expression = values.get(index);
|
||||
|
||||
expression.expected = Definition.DEF_TYPE;
|
||||
expression.internal = true;
|
||||
expression.analyze(locals);
|
||||
values.set(index, expression.cast(locals));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
void write(MethodWriter writer, Globals globals) {
|
||||
writer.writeDebugInfo(location);
|
||||
|
||||
writer.newInstance(actual.type);
|
||||
writer.dup();
|
||||
writer.invokeConstructor(constructor.owner.type, constructor.method);
|
||||
|
||||
for (int index = 0; index < keys.size(); ++index) {
|
||||
AExpression key = keys.get(index);
|
||||
AExpression value = values.get(index);
|
||||
|
||||
writer.dup();
|
||||
key.write(writer, globals);
|
||||
value.write(writer, globals);
|
||||
method.write(writer);
|
||||
writer.pop();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -37,14 +37,16 @@ public final class LNewArray extends ALink {
|
|||
|
||||
final String type;
|
||||
final List<AExpression> arguments;
|
||||
final boolean initialize;
|
||||
|
||||
public LNewArray(Location location, String type, List<AExpression> arguments) {
|
||||
public LNewArray(Location location, String type, List<AExpression> arguments, boolean initialize) {
|
||||
super(location, -1);
|
||||
|
||||
this.type = Objects.requireNonNull(type);
|
||||
this.arguments = Objects.requireNonNull(arguments);
|
||||
this.initialize = initialize;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
void extractVariables(Set<String> variables) {
|
||||
for (AExpression argument : arguments) {
|
||||
|
@ -73,12 +75,13 @@ public final class LNewArray extends ALink {
|
|||
for (int argument = 0; argument < arguments.size(); ++argument) {
|
||||
AExpression expression = arguments.get(argument);
|
||||
|
||||
expression.expected = Definition.INT_TYPE;
|
||||
expression.expected = initialize ? Definition.getType(type.struct, 0) : Definition.INT_TYPE;
|
||||
expression.internal = true;
|
||||
expression.analyze(locals);
|
||||
arguments.set(argument, expression.cast(locals));
|
||||
}
|
||||
|
||||
after = Definition.getType(type.struct, arguments.size());
|
||||
after = Definition.getType(type.struct, initialize ? 1 : arguments.size());
|
||||
|
||||
return this;
|
||||
}
|
||||
|
@ -92,14 +95,28 @@ public final class LNewArray extends ALink {
|
|||
void load(MethodWriter writer, Globals globals) {
|
||||
writer.writeDebugInfo(location);
|
||||
|
||||
for (AExpression argument : arguments) {
|
||||
argument.write(writer, globals);
|
||||
}
|
||||
|
||||
if (arguments.size() > 1) {
|
||||
writer.visitMultiANewArrayInsn(after.type.getDescriptor(), after.type.getDimensions());
|
||||
} else {
|
||||
if (initialize) {
|
||||
writer.push(arguments.size());
|
||||
writer.newArray(Definition.getType(after.struct, 0).type);
|
||||
|
||||
for (int index = 0; index < arguments.size(); ++index) {
|
||||
AExpression argument = arguments.get(index);
|
||||
|
||||
writer.dup();
|
||||
writer.push(index);
|
||||
argument.write(writer, globals);
|
||||
writer.arrayStore(Definition.getType(after.struct, 0).type);
|
||||
}
|
||||
} else {
|
||||
for (AExpression argument : arguments) {
|
||||
argument.write(writer, globals);
|
||||
}
|
||||
|
||||
if (arguments.size() > 1) {
|
||||
writer.visitMultiANewArrayInsn(after.type.getDescriptor(), after.type.getDimensions());
|
||||
} else {
|
||||
writer.newArray(Definition.getType(after.struct, 0).type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -44,6 +44,8 @@
|
|||
* {@link org.elasticsearch.painless.node.EDecimal} - Represents a decimal constant.
|
||||
* {@link org.elasticsearch.painless.node.EExplicit} - Represents an explicit cast.
|
||||
* {@link org.elasticsearch.painless.node.EFunctionRef} - Represents a function reference (non-capturing).
|
||||
* {@link org.elasticsearch.painless.node.EListInit} - Represents a list initialization shortcut.
|
||||
* {@link org.elasticsearch.painless.node.EMapInit} - Represents a map initializiation shortcut.
|
||||
* {@link org.elasticsearch.painless.node.ENull} - Represents a null constant.
|
||||
* {@link org.elasticsearch.painless.node.ENumeric} - Represents a non-decimal numeric constant.
|
||||
* {@link org.elasticsearch.painless.node.EUnary} - Represents a unary math expression.
|
||||
|
|
|
@ -0,0 +1,146 @@
|
|||
/*
|
||||
* 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.painless;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class InitializerTests extends ScriptTestCase {
|
||||
|
||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||
public void testArrayInitializers() {
|
||||
int[] ints = (int[])exec("new int[] {}");
|
||||
|
||||
assertEquals(0, ints.length);
|
||||
|
||||
ints = (int[])exec("new int[] {5, 7, -1, 14}");
|
||||
|
||||
assertEquals(4, ints.length);
|
||||
assertEquals(5, ints[0]);
|
||||
assertEquals(7, ints[1]);
|
||||
assertEquals(-1, ints[2]);
|
||||
assertEquals(14, ints[3]);
|
||||
|
||||
ints = (int[])exec("int y = 2; int z = 3; int[] x = new int[] {y*z, y + z, y - z, y, z}; return x;");
|
||||
|
||||
assertEquals(5, ints.length);
|
||||
assertEquals(6, ints[0]);
|
||||
assertEquals(5, ints[1]);
|
||||
assertEquals(-1, ints[2]);
|
||||
assertEquals(2, ints[3]);
|
||||
assertEquals(3, ints[4]);
|
||||
|
||||
Object[] objects = (Object[])exec("int y = 2; List z = new ArrayList(); String s = 'aaa';" +
|
||||
"Object[] x = new Object[] {y, z, 1 + s, s + 'aaa'}; return x;");
|
||||
|
||||
assertEquals(4, objects.length);
|
||||
assertEquals(new Integer(2), objects[0]);
|
||||
assertEquals(new ArrayList(), objects[1]);
|
||||
assertEquals("1aaa", objects[2]);
|
||||
assertEquals("aaaaaa", objects[3]);
|
||||
}
|
||||
|
||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||
public void testListInitializers() {
|
||||
List list = (List)exec("[]");
|
||||
|
||||
assertEquals(0, list.size());
|
||||
|
||||
list = (List)exec("[5, 7, -1, 14]");
|
||||
|
||||
assertEquals(4, list.size());
|
||||
assertEquals(5, list.get(0));
|
||||
assertEquals(7, list.get(1));
|
||||
assertEquals(-1, list.get(2));
|
||||
assertEquals(14, list.get(3));
|
||||
|
||||
list = (List)exec("int y = 2; int z = 3; def x = [y*z, y + z, y - z, y, z]; return x;");
|
||||
|
||||
assertEquals(5, list.size());
|
||||
assertEquals(6, list.get(0));
|
||||
assertEquals(5, list.get(1));
|
||||
assertEquals(-1, list.get(2));
|
||||
assertEquals(2, list.get(3));
|
||||
assertEquals(3, list.get(4));
|
||||
|
||||
list = (List)exec("int y = 2; List z = new ArrayList(); String s = 'aaa'; List x = [y, z, 1 + s, s + 'aaa']; return x;");
|
||||
|
||||
assertEquals(4, list.size());
|
||||
assertEquals(new Integer(2), list.get(0));
|
||||
assertEquals(new ArrayList(), list.get(1));
|
||||
assertEquals("1aaa", list.get(2));
|
||||
assertEquals("aaaaaa", list.get(3));
|
||||
}
|
||||
|
||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||
public void testMapInitializers() {
|
||||
Map map = (Map)exec("[:]");
|
||||
|
||||
assertEquals(0, map.size());
|
||||
|
||||
map = (Map)exec("[5 : 7, -1 : 14]");
|
||||
|
||||
assertEquals(2, map.size());
|
||||
assertEquals(new Integer(7), map.get(5));
|
||||
assertEquals(new Integer(14), map.get(-1));
|
||||
|
||||
map = (Map)exec("int y = 2; int z = 3; Map x = [y*z : y + z, y - z : y, z : z]; return x;");
|
||||
|
||||
assertEquals(3, map.size());
|
||||
assertEquals(new Integer(5), map.get(6));
|
||||
assertEquals(new Integer(2), map.get(-1));
|
||||
assertEquals(new Integer(3), map.get(3));
|
||||
|
||||
map = (Map)exec("int y = 2; List z = new ArrayList(); String s = 'aaa';" +
|
||||
"def x = [y : z, 1 + s : s + 'aaa']; return x;");
|
||||
|
||||
assertEquals(2, map.size());
|
||||
assertEquals(new ArrayList(), map.get(2));
|
||||
assertEquals("aaaaaa", map.get("1aaa"));
|
||||
}
|
||||
|
||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||
public void testCrazyInitializer() {
|
||||
Map map = (Map)exec("int y = 2; int z = 3; Map x = [y*z : y + z, 's' : [y, [y : [[z], [], [:]]]], z : [z, 9]]; return x;");
|
||||
|
||||
List list0 = new ArrayList();
|
||||
list0.add(3);
|
||||
List list1 = new ArrayList();
|
||||
list1.add(list0);
|
||||
list1.add(new ArrayList());
|
||||
list1.add(new HashMap());
|
||||
Map map0 = new HashMap();
|
||||
map0.put(2, list1);
|
||||
List list2 = new ArrayList();
|
||||
list2.add(2);
|
||||
list2.add(map0);
|
||||
|
||||
List list3 = new ArrayList();
|
||||
list3.add(3);
|
||||
list3.add(9);
|
||||
|
||||
assertEquals(3, map.size());
|
||||
assertEquals(new Integer(5), map.get(6));
|
||||
assertEquals(list2, map.get("s"));
|
||||
assertEquals(list3, map.get(3));
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue