Add a ScriptRoot to consolidate global data necessary for multiple passes (#47532)

This PR is to get plumbing in for a ScriptRoot class that will consolidate 
several pieces of state required by potentially multiple passes including 
PainlessLookup, CompilerSettings, FunctionTable, the root class node, and a 
synthetic counter. It's possible more may be added to this as we move 
forward and slowly make the the nodes have less mutable state.
This commit is contained in:
Jack Conradson 2019-10-04 08:36:44 -07:00
parent 9b3e5409c1
commit e3aab1295e
69 changed files with 520 additions and 479 deletions

View File

@ -20,7 +20,6 @@
package org.elasticsearch.painless;
import org.elasticsearch.painless.ScriptClassInfo.MethodArgument;
import org.elasticsearch.painless.lookup.PainlessLookup;
import org.elasticsearch.painless.lookup.PainlessLookupUtility;
import java.util.Arrays;
@ -38,19 +37,6 @@ import static org.elasticsearch.painless.lookup.PainlessLookupUtility.typeToJava
* Tracks user defined variables across compilation phases.
*/
public final class Locals {
private int syntheticCounter = 0;
/**
* Returns a unique identifier for generating the name of a synthetic method.
*/
public String getNextSyntheticName() {
Locals locals = this;
while (locals.getParent() != null) {
locals = locals.getParent();
}
return "lambda$" + locals.syntheticCounter++;
}
/** Reserved word: loop counter */
public static final String LOOP = "#loop";
@ -64,9 +50,7 @@ public final class Locals {
/** Creates a new local variable scope (e.g. loop) inside the current scope */
public static Locals newLocalScope(Locals currentScope) {
Locals locals = new Locals(currentScope);
return locals;
return new Locals(currentScope);
}
/**
@ -76,7 +60,7 @@ public final class Locals {
*/
public static Locals newLambdaScope(Locals programScope, String name, Class<?> returnType, List<Parameter> parameters,
int captureCount, int maxLoopCounter) {
Locals locals = new Locals(programScope, programScope.painlessLookup, programScope.baseClass, returnType, KEYWORDS);
Locals locals = new Locals(programScope, returnType, KEYWORDS);
List<Class<?>> typeParameters = parameters.stream().map(parameter -> typeToJavaType(parameter.clazz)).collect(Collectors.toList());
for (int i = 0; i < parameters.size(); i++) {
Parameter parameter = parameters.get(i);
@ -96,7 +80,7 @@ public final class Locals {
/** Creates a new function scope inside the current scope */
public static Locals newFunctionScope(Locals programScope, Class<?> returnType, List<Parameter> parameters, int maxLoopCounter) {
Locals locals = new Locals(programScope, programScope.painlessLookup, programScope.baseClass, returnType, KEYWORDS);
Locals locals = new Locals(programScope, returnType, KEYWORDS);
for (Parameter parameter : parameters) {
locals.addVariable(parameter.location, parameter.clazz, parameter.name, false);
}
@ -109,8 +93,7 @@ public final class Locals {
/** Creates a new main method scope */
public static Locals newMainMethodScope(ScriptClassInfo scriptClassInfo, Locals programScope, int maxLoopCounter) {
Locals locals = new Locals(programScope, programScope.painlessLookup,
scriptClassInfo.getBaseClass(), scriptClassInfo.getExecuteMethodReturnType(), KEYWORDS);
Locals locals = new Locals(programScope, scriptClassInfo.getExecuteMethodReturnType(), KEYWORDS);
// This reference. Internal use only.
locals.defineVariable(null, Object.class, THIS, true);
@ -127,8 +110,8 @@ public final class Locals {
}
/** Creates a new program scope as the root of all scopes */
public static Locals newProgramScope(ScriptClassInfo scriptClassInfo, PainlessLookup painlessLookup) {
return new Locals(null, painlessLookup, scriptClassInfo.getBaseClass(), null, null);
public static Locals newProgramScope() {
return new Locals(null, null, null);
}
/** Checks if a variable exists or not, in this scope or any parents. */
@ -180,22 +163,8 @@ public final class Locals {
return locals;
}
/** Whitelist against which this script is being compiled. */
public PainlessLookup getPainlessLookup() {
return painlessLookup;
}
/** Base class for the compiled script. */
public Class<?> getBaseClass() {
return baseClass;
}
///// private impl
/** Whitelist against which this script is being compiled. */
private final PainlessLookup painlessLookup;
/** Base class for the compiled script. */
private final Class<?> baseClass;
// parent scope
private final Locals parent;
// return type of this scope
@ -211,16 +180,14 @@ public final class Locals {
* Create a new Locals
*/
private Locals(Locals parent) {
this(parent, parent.painlessLookup, parent.baseClass, parent.returnType, parent.keywords);
this(parent, parent.returnType, parent.keywords);
}
/**
* Create a new Locals with specified return type
*/
private Locals(Locals parent, PainlessLookup painlessLookup, Class<?> baseClass, Class<?> returnType, Set<String> keywords) {
private Locals(Locals parent, Class<?> returnType, Set<String> keywords) {
this.parent = parent;
this.painlessLookup = painlessLookup;
this.baseClass = baseClass;
this.returnType = returnType;
this.keywords = keywords;
if (parent == null) {

View File

@ -0,0 +1,75 @@
/*
* 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 org.elasticsearch.painless.lookup.PainlessLookup;
import org.elasticsearch.painless.node.SClass;
import org.elasticsearch.painless.symbol.FunctionTable;
import java.util.Objects;
/**
* Stores information for use across the entirety of compilation.
*/
public class ScriptRoot {
protected final PainlessLookup painlessLookup;
protected final CompilerSettings compilerSettings;
protected final ScriptClassInfo scriptClassInfo;
protected final SClass classNode;
protected final FunctionTable functionTable = new FunctionTable();
protected int syntheticCounter = 0;
public ScriptRoot(PainlessLookup painlessLookup, CompilerSettings compilerSettings, ScriptClassInfo scriptClassInfo, SClass classRoot) {
this.painlessLookup = Objects.requireNonNull(painlessLookup);
this.compilerSettings = Objects.requireNonNull(compilerSettings);
this.scriptClassInfo = Objects.requireNonNull(scriptClassInfo);
this.classNode = Objects.requireNonNull(classRoot);
}
public PainlessLookup getPainlessLookup() {
return painlessLookup;
}
public CompilerSettings getCompilerSettings() {
return compilerSettings;
}
public ScriptClassInfo getScriptClassInfo() {
return scriptClassInfo;
}
public SClass getClassNode() {
return classNode;
}
public FunctionTable getFunctionTable() {
return functionTable;
}
/**
* Returns a unique identifier for generating the name of a synthetic value.
*/
public String getNextSyntheticName(String prefix) {
return prefix + "$synthetic$" + syntheticCounter++;
}
}

View File

@ -24,7 +24,7 @@ import org.elasticsearch.painless.Locals;
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.lookup.PainlessCast;
import org.elasticsearch.painless.lookup.PainlessLookupUtility;
import org.elasticsearch.painless.symbol.FunctionTable;
import org.elasticsearch.painless.ScriptRoot;
import java.util.Objects;
@ -118,7 +118,7 @@ public abstract class AExpression extends ANode {
* nodes with the constant variable set to a non-null value with {@link EConstant}.
* @return The new child node for the parent node calling this method.
*/
AExpression cast(FunctionTable functions, Locals locals) {
AExpression cast(ScriptRoot scriptRoot, Locals locals) {
PainlessCast cast = AnalyzerCaster.getLegalCast(location, actual, expected, explicit, internal);
if (cast == null) {
@ -136,7 +136,7 @@ public abstract class AExpression extends ANode {
// will already be the same.
EConstant econstant = new EConstant(location, constant);
econstant.analyze(functions, locals);
econstant.analyze(scriptRoot, locals);
if (!expected.equals(econstant.actual)) {
throw createError(new IllegalStateException("Illegal tree structure."));
@ -170,7 +170,7 @@ public abstract class AExpression extends ANode {
constant = AnalyzerCaster.constCast(location, constant, cast);
EConstant econstant = new EConstant(location, constant);
econstant.analyze(functions, locals);
econstant.analyze(scriptRoot, locals);
if (!expected.equals(econstant.actual)) {
throw createError(new IllegalStateException("Illegal tree structure."));
@ -201,7 +201,7 @@ public abstract class AExpression extends ANode {
// the EConstant will already be the same.
EConstant econstant = new EConstant(location, constant);
econstant.analyze(functions, locals);
econstant.analyze(scriptRoot, locals);
if (!actual.equals(econstant.actual)) {
throw createError(new IllegalStateException("Illegal tree structure."));

View File

@ -25,7 +25,7 @@ import org.elasticsearch.painless.Globals;
import org.elasticsearch.painless.Locals;
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.MethodWriter;
import org.elasticsearch.painless.symbol.FunctionTable;
import org.elasticsearch.painless.ScriptRoot;
import java.util.ArrayList;
import java.util.Arrays;
@ -72,7 +72,7 @@ public abstract class ANode {
/**
* Checks for errors and collects data for the writing phase.
*/
abstract void analyze(FunctionTable functions, Locals locals);
abstract void analyze(ScriptRoot scriptRoot, Locals locals);
/**
* Writes ASM based on the data collected during the analysis phase.

View File

@ -31,7 +31,7 @@ import org.elasticsearch.painless.MethodWriter;
import org.elasticsearch.painless.Operation;
import org.elasticsearch.painless.lookup.PainlessCast;
import org.elasticsearch.painless.lookup.def;
import org.elasticsearch.painless.symbol.FunctionTable;
import org.elasticsearch.painless.ScriptRoot;
import java.util.ArrayList;
import java.util.List;
@ -84,26 +84,26 @@ public final class EAssignment extends AExpression {
}
@Override
void analyze(FunctionTable functions, Locals locals) {
analyzeLHS(functions, locals);
void analyze(ScriptRoot scriptRoot, Locals locals) {
analyzeLHS(scriptRoot, locals);
analyzeIncrDecr();
if (operation != null) {
analyzeCompound(functions, locals);
analyzeCompound(scriptRoot, locals);
} else if (rhs != null) {
analyzeSimple(functions, locals);
analyzeSimple(scriptRoot, locals);
} else {
throw new IllegalStateException("Illegal tree structure.");
}
}
private void analyzeLHS(FunctionTable functions, Locals locals) {
private void analyzeLHS(ScriptRoot scriptRoot, Locals locals) {
if (lhs instanceof AStoreable) {
AStoreable lhs = (AStoreable)this.lhs;
lhs.read = read;
lhs.write = true;
lhs.analyze(functions, locals);
lhs.analyze(scriptRoot, locals);
} else {
throw new IllegalArgumentException("Left-hand side cannot be assigned a value.");
}
@ -147,9 +147,8 @@ public final class EAssignment extends AExpression {
}
}
private void analyzeCompound(FunctionTable functions, Locals locals) {
rhs.analyze(functions, locals);
private void analyzeCompound(ScriptRoot scriptRoot, Locals locals) {
rhs.analyze(scriptRoot, locals);
boolean shift = false;
if (operation == Operation.MUL) {
@ -211,7 +210,7 @@ public final class EAssignment extends AExpression {
rhs.expected = promote;
}
rhs = rhs.cast(functions, locals);
rhs = rhs.cast(scriptRoot, locals);
there = AnalyzerCaster.getLegalCast(location, lhs.actual, promote, false, false);
back = AnalyzerCaster.getLegalCast(location, promote, lhs.actual, true, false);
@ -220,12 +219,12 @@ public final class EAssignment extends AExpression {
this.actual = read ? lhs.actual : void.class;
}
private void analyzeSimple(FunctionTable functions, Locals locals) {
private void analyzeSimple(ScriptRoot scriptRoot, Locals locals) {
AStoreable lhs = (AStoreable)this.lhs;
// If the lhs node is a def optimized node we update the actual type to remove the need for a cast.
if (lhs.isDefOptimized()) {
rhs.analyze(functions, locals);
rhs.analyze(scriptRoot, locals);
if (rhs.actual == void.class) {
throw createError(new IllegalArgumentException("Right-hand side cannot be a [void] type for assignment."));
@ -236,10 +235,10 @@ public final class EAssignment extends AExpression {
// Otherwise, we must adapt the rhs type to the lhs type with a cast.
} else {
rhs.expected = lhs.actual;
rhs.analyze(functions, locals);
rhs.analyze(scriptRoot, locals);
}
rhs = rhs.cast(functions, locals);
rhs = rhs.cast(scriptRoot, locals);
this.statement = true;
this.actual = read ? lhs.actual : void.class;

View File

@ -31,7 +31,7 @@ import org.elasticsearch.painless.Operation;
import org.elasticsearch.painless.WriterConstants;
import org.elasticsearch.painless.lookup.PainlessLookupUtility;
import org.elasticsearch.painless.lookup.def;
import org.elasticsearch.painless.symbol.FunctionTable;
import org.elasticsearch.painless.ScriptRoot;
import java.util.Objects;
import java.util.Set;
@ -73,43 +73,43 @@ public final class EBinary extends AExpression {
}
@Override
void analyze(FunctionTable functions, Locals locals) {
void analyze(ScriptRoot scriptRoot, Locals locals) {
originallyExplicit = explicit;
if (operation == Operation.MUL) {
analyzeMul(functions, locals);
analyzeMul(scriptRoot, locals);
} else if (operation == Operation.DIV) {
analyzeDiv(functions, locals);
analyzeDiv(scriptRoot, locals);
} else if (operation == Operation.REM) {
analyzeRem(functions, locals);
analyzeRem(scriptRoot, locals);
} else if (operation == Operation.ADD) {
analyzeAdd(functions, locals);
analyzeAdd(scriptRoot, locals);
} else if (operation == Operation.SUB) {
analyzeSub(functions, locals);
analyzeSub(scriptRoot, locals);
} else if (operation == Operation.FIND) {
analyzeRegexOp(functions, locals);
analyzeRegexOp(scriptRoot, locals);
} else if (operation == Operation.MATCH) {
analyzeRegexOp(functions, locals);
analyzeRegexOp(scriptRoot, locals);
} else if (operation == Operation.LSH) {
analyzeLSH(functions, locals);
analyzeLSH(scriptRoot, locals);
} else if (operation == Operation.RSH) {
analyzeRSH(functions, locals);
analyzeRSH(scriptRoot, locals);
} else if (operation == Operation.USH) {
analyzeUSH(functions, locals);
analyzeUSH(scriptRoot, locals);
} else if (operation == Operation.BWAND) {
analyzeBWAnd(functions, locals);
analyzeBWAnd(scriptRoot, locals);
} else if (operation == Operation.XOR) {
analyzeXor(functions, locals);
analyzeXor(scriptRoot, locals);
} else if (operation == Operation.BWOR) {
analyzeBWOr(functions, locals);
analyzeBWOr(scriptRoot, locals);
} else {
throw createError(new IllegalStateException("Illegal tree structure."));
}
}
private void analyzeMul(FunctionTable functions, Locals variables) {
left.analyze(functions, variables);
right.analyze(functions, variables);
private void analyzeMul(ScriptRoot scriptRoot, Locals variables) {
left.analyze(scriptRoot, variables);
right.analyze(scriptRoot, variables);
promote = AnalyzerCaster.promoteNumeric(left.actual, right.actual, true);
@ -132,8 +132,8 @@ public final class EBinary extends AExpression {
right.expected = promote;
}
left = left.cast(functions, variables);
right = right.cast(functions, variables);
left = left.cast(scriptRoot, variables);
right = right.cast(scriptRoot, variables);
if (left.constant != null && right.constant != null) {
if (promote == int.class) {
@ -150,9 +150,9 @@ public final class EBinary extends AExpression {
}
}
private void analyzeDiv(FunctionTable functions, Locals variables) {
left.analyze(functions, variables);
right.analyze(functions, variables);
private void analyzeDiv(ScriptRoot scriptRoot, Locals variables) {
left.analyze(scriptRoot, variables);
right.analyze(scriptRoot, variables);
promote = AnalyzerCaster.promoteNumeric(left.actual, right.actual, true);
@ -176,8 +176,8 @@ public final class EBinary extends AExpression {
right.expected = promote;
}
left = left.cast(functions, variables);
right = right.cast(functions, variables);
left = left.cast(scriptRoot, variables);
right = right.cast(scriptRoot, variables);
if (left.constant != null && right.constant != null) {
try {
@ -198,9 +198,9 @@ public final class EBinary extends AExpression {
}
}
private void analyzeRem(FunctionTable functions, Locals variables) {
left.analyze(functions, variables);
right.analyze(functions, variables);
private void analyzeRem(ScriptRoot scriptRoot, Locals variables) {
left.analyze(scriptRoot, variables);
right.analyze(scriptRoot, variables);
promote = AnalyzerCaster.promoteNumeric(left.actual, right.actual, true);
@ -224,8 +224,8 @@ public final class EBinary extends AExpression {
right.expected = promote;
}
left = left.cast(functions, variables);
right = right.cast(functions, variables);
left = left.cast(scriptRoot, variables);
right = right.cast(scriptRoot, variables);
if (left.constant != null && right.constant != null) {
try {
@ -246,9 +246,9 @@ public final class EBinary extends AExpression {
}
}
private void analyzeAdd(FunctionTable functions, Locals variables) {
left.analyze(functions, variables);
right.analyze(functions, variables);
private void analyzeAdd(ScriptRoot scriptRoot, Locals variables) {
left.analyze(scriptRoot, variables);
right.analyze(scriptRoot, variables);
promote = AnalyzerCaster.promoteAdd(left.actual, right.actual);
@ -284,8 +284,8 @@ public final class EBinary extends AExpression {
right.expected = promote;
}
left = left.cast(functions, variables);
right = right.cast(functions, variables);
left = left.cast(scriptRoot, variables);
right = right.cast(scriptRoot, variables);
if (left.constant != null && right.constant != null) {
if (promote == int.class) {
@ -305,9 +305,9 @@ public final class EBinary extends AExpression {
}
private void analyzeSub(FunctionTable functions, Locals variables) {
left.analyze(functions, variables);
right.analyze(functions, variables);
private void analyzeSub(ScriptRoot scriptRoot, Locals variables) {
left.analyze(scriptRoot, variables);
right.analyze(scriptRoot, variables);
promote = AnalyzerCaster.promoteNumeric(left.actual, right.actual, true);
@ -331,8 +331,8 @@ public final class EBinary extends AExpression {
right.expected = promote;
}
left = left.cast(functions, variables);
right = right.cast(functions, variables);
left = left.cast(scriptRoot, variables);
right = right.cast(scriptRoot, variables);
if (left.constant != null && right.constant != null) {
if (promote == int.class) {
@ -349,23 +349,23 @@ public final class EBinary extends AExpression {
}
}
private void analyzeRegexOp(FunctionTable functions, Locals variables) {
left.analyze(functions, variables);
right.analyze(functions, variables);
private void analyzeRegexOp(ScriptRoot scriptRoot, Locals variables) {
left.analyze(scriptRoot, variables);
right.analyze(scriptRoot, variables);
left.expected = String.class;
right.expected = Pattern.class;
left = left.cast(functions, variables);
right = right.cast(functions, variables);
left = left.cast(scriptRoot, variables);
right = right.cast(scriptRoot, variables);
promote = boolean.class;
actual = boolean.class;
}
private void analyzeLSH(FunctionTable functions, Locals variables) {
left.analyze(functions, variables);
right.analyze(functions, variables);
private void analyzeLSH(ScriptRoot scriptRoot, Locals variables) {
left.analyze(scriptRoot, variables);
right.analyze(scriptRoot, variables);
Class<?> lhspromote = AnalyzerCaster.promoteNumeric(left.actual, false);
Class<?> rhspromote = AnalyzerCaster.promoteNumeric(right.actual, false);
@ -397,8 +397,8 @@ public final class EBinary extends AExpression {
}
}
left = left.cast(functions, variables);
right = right.cast(functions, variables);
left = left.cast(scriptRoot, variables);
right = right.cast(scriptRoot, variables);
if (left.constant != null && right.constant != null) {
if (promote == int.class) {
@ -411,9 +411,9 @@ public final class EBinary extends AExpression {
}
}
private void analyzeRSH(FunctionTable functions, Locals variables) {
left.analyze(functions, variables);
right.analyze(functions, variables);
private void analyzeRSH(ScriptRoot scriptRoot, Locals variables) {
left.analyze(scriptRoot, variables);
right.analyze(scriptRoot, variables);
Class<?> lhspromote = AnalyzerCaster.promoteNumeric(left.actual, false);
Class<?> rhspromote = AnalyzerCaster.promoteNumeric(right.actual, false);
@ -445,8 +445,8 @@ public final class EBinary extends AExpression {
}
}
left = left.cast(functions, variables);
right = right.cast(functions, variables);
left = left.cast(scriptRoot, variables);
right = right.cast(scriptRoot, variables);
if (left.constant != null && right.constant != null) {
if (promote == int.class) {
@ -459,9 +459,9 @@ public final class EBinary extends AExpression {
}
}
private void analyzeUSH(FunctionTable functions, Locals variables) {
left.analyze(functions, variables);
right.analyze(functions, variables);
private void analyzeUSH(ScriptRoot scriptRoot, Locals variables) {
left.analyze(scriptRoot, variables);
right.analyze(scriptRoot, variables);
Class<?> lhspromote = AnalyzerCaster.promoteNumeric(left.actual, false);
Class<?> rhspromote = AnalyzerCaster.promoteNumeric(right.actual, false);
@ -493,8 +493,8 @@ public final class EBinary extends AExpression {
}
}
left = left.cast(functions, variables);
right = right.cast(functions, variables);
left = left.cast(scriptRoot, variables);
right = right.cast(scriptRoot, variables);
if (left.constant != null && right.constant != null) {
if (promote == int.class) {
@ -507,9 +507,9 @@ public final class EBinary extends AExpression {
}
}
private void analyzeBWAnd(FunctionTable functions, Locals variables) {
left.analyze(functions, variables);
right.analyze(functions, variables);
private void analyzeBWAnd(ScriptRoot scriptRoot, Locals variables) {
left.analyze(scriptRoot, variables);
right.analyze(scriptRoot, variables);
promote = AnalyzerCaster.promoteNumeric(left.actual, right.actual, false);
@ -533,8 +533,8 @@ public final class EBinary extends AExpression {
right.expected = promote;
}
left = left.cast(functions, variables);
right = right.cast(functions, variables);
left = left.cast(scriptRoot, variables);
right = right.cast(scriptRoot, variables);
if (left.constant != null && right.constant != null) {
if (promote == int.class) {
@ -547,9 +547,9 @@ public final class EBinary extends AExpression {
}
}
private void analyzeXor(FunctionTable functions, Locals variables) {
left.analyze(functions, variables);
right.analyze(functions, variables);
private void analyzeXor(ScriptRoot scriptRoot, Locals variables) {
left.analyze(scriptRoot, variables);
right.analyze(scriptRoot, variables);
promote = AnalyzerCaster.promoteXor(left.actual, right.actual);
@ -572,8 +572,8 @@ public final class EBinary extends AExpression {
right.expected = promote;
}
left = left.cast(functions, variables);
right = right.cast(functions, variables);
left = left.cast(scriptRoot, variables);
right = right.cast(scriptRoot, variables);
if (left.constant != null && right.constant != null) {
if (promote == boolean.class) {
@ -588,9 +588,9 @@ public final class EBinary extends AExpression {
}
}
private void analyzeBWOr(FunctionTable functions, Locals variables) {
left.analyze(functions, variables);
right.analyze(functions, variables);
private void analyzeBWOr(ScriptRoot scriptRoot, Locals variables) {
left.analyze(scriptRoot, variables);
right.analyze(scriptRoot, variables);
promote = AnalyzerCaster.promoteNumeric(left.actual, right.actual, false);
@ -613,8 +613,8 @@ public final class EBinary extends AExpression {
right.expected = promote;
}
left = left.cast(functions, variables);
right = right.cast(functions, variables);
left = left.cast(scriptRoot, variables);
right = right.cast(scriptRoot, variables);
if (left.constant != null && right.constant != null) {
if (promote == int.class) {

View File

@ -26,7 +26,7 @@ import org.elasticsearch.painless.Locals;
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.MethodWriter;
import org.elasticsearch.painless.Operation;
import org.elasticsearch.painless.symbol.FunctionTable;
import org.elasticsearch.painless.ScriptRoot;
import org.objectweb.asm.Label;
import org.objectweb.asm.Opcodes;
@ -63,14 +63,14 @@ public final class EBool extends AExpression {
}
@Override
void analyze(FunctionTable functions, Locals locals) {
void analyze(ScriptRoot scriptRoot, Locals locals) {
left.expected = boolean.class;
left.analyze(functions, locals);
left = left.cast(functions, locals);
left.analyze(scriptRoot, locals);
left = left.cast(scriptRoot, locals);
right.expected = boolean.class;
right.analyze(functions, locals);
right = right.cast(functions, locals);
right.analyze(scriptRoot, locals);
right = right.cast(scriptRoot, locals);
if (left.constant != null && right.constant != null) {
if (operation == Operation.AND) {

View File

@ -25,7 +25,7 @@ import org.elasticsearch.painless.Globals;
import org.elasticsearch.painless.Locals;
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.MethodWriter;
import org.elasticsearch.painless.symbol.FunctionTable;
import org.elasticsearch.painless.ScriptRoot;
import java.util.Set;
@ -51,7 +51,7 @@ public final class EBoolean extends AExpression {
}
@Override
void analyze(FunctionTable functions, Locals locals) {
void analyze(ScriptRoot scriptRoot, Locals locals) {
if (!read) {
throw createError(new IllegalArgumentException("Must read from constant [" + constant + "]."));
}

View File

@ -28,6 +28,7 @@ import org.elasticsearch.painless.MethodWriter;
import org.elasticsearch.painless.lookup.PainlessClassBinding;
import org.elasticsearch.painless.lookup.PainlessInstanceBinding;
import org.elasticsearch.painless.lookup.PainlessMethod;
import org.elasticsearch.painless.ScriptRoot;
import org.elasticsearch.painless.symbol.FunctionTable;
import org.objectweb.asm.Label;
import org.objectweb.asm.Type;
@ -76,8 +77,8 @@ public final class ECallLocal extends AExpression {
}
@Override
void analyze(FunctionTable functions, Locals locals) {
localFunction = functions.getFunction(name, arguments.size());
void analyze(ScriptRoot scriptRoot, Locals locals) {
localFunction = scriptRoot.getFunctionTable().getFunction(name, arguments.size());
// user cannot call internal functions, reset to null if an internal function is found
if (localFunction != null && localFunction.isInternal()) {
@ -85,14 +86,14 @@ public final class ECallLocal extends AExpression {
}
if (localFunction == null) {
importedMethod = locals.getPainlessLookup().lookupImportedPainlessMethod(name, arguments.size());
importedMethod = scriptRoot.getPainlessLookup().lookupImportedPainlessMethod(name, arguments.size());
if (importedMethod == null) {
classBinding = locals.getPainlessLookup().lookupPainlessClassBinding(name, arguments.size());
classBinding = scriptRoot.getPainlessLookup().lookupPainlessClassBinding(name, arguments.size());
// check to see if this class binding requires an implicit this reference
if (classBinding != null && classBinding.typeParameters.isEmpty() == false &&
classBinding.typeParameters.get(0) == locals.getBaseClass()) {
classBinding.typeParameters.get(0) == scriptRoot.getScriptClassInfo().getBaseClass()) {
classBinding = null;
}
@ -103,11 +104,11 @@ public final class ECallLocal extends AExpression {
// will likely involve adding a class instance binding where any instance can have a class binding
// as part of its API. However, the situation at run-time is difficult and will modifications that
// are a substantial change if even possible to do.
classBinding = locals.getPainlessLookup().lookupPainlessClassBinding(name, arguments.size() + 1);
classBinding = scriptRoot.getPainlessLookup().lookupPainlessClassBinding(name, arguments.size() + 1);
if (classBinding != null) {
if (classBinding.typeParameters.isEmpty() == false &&
classBinding.typeParameters.get(0) == locals.getBaseClass()) {
classBinding.typeParameters.get(0) == scriptRoot.getScriptClassInfo().getBaseClass()) {
classBindingOffset = 1;
} else {
classBinding = null;
@ -115,7 +116,7 @@ public final class ECallLocal extends AExpression {
}
if (classBinding == null) {
instanceBinding = locals.getPainlessLookup().lookupPainlessInstanceBinding(name, arguments.size());
instanceBinding = scriptRoot.getPainlessLookup().lookupPainlessInstanceBinding(name, arguments.size());
if (instanceBinding == null) {
throw createError(new IllegalArgumentException(
@ -152,8 +153,8 @@ public final class ECallLocal extends AExpression {
expression.expected = typeParameters.get(argument + classBindingOffset);
expression.internal = true;
expression.analyze(functions, locals);
arguments.set(argument, expression.cast(functions, locals));
expression.analyze(scriptRoot, locals);
arguments.set(argument, expression.cast(scriptRoot, locals));
}
statement = true;

View File

@ -30,7 +30,7 @@ import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.MethodWriter;
import org.elasticsearch.painless.lookup.PainlessLookupUtility;
import org.elasticsearch.painless.lookup.def;
import org.elasticsearch.painless.symbol.FunctionTable;
import org.elasticsearch.painless.ScriptRoot;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
@ -66,7 +66,7 @@ public final class ECapturingFunctionRef extends AExpression implements ILambda
}
@Override
void analyze(FunctionTable functions, Locals locals) {
void analyze(ScriptRoot scriptRoot, Locals locals) {
captured = locals.getVariable(location, variable);
if (expected == null) {
if (captured.clazz == def.class) {
@ -81,7 +81,7 @@ public final class ECapturingFunctionRef extends AExpression implements ILambda
defPointer = null;
// static case
if (captured.clazz != def.class) {
ref = FunctionRef.create(locals.getPainlessLookup(), functions, location,
ref = FunctionRef.create(scriptRoot.getPainlessLookup(), scriptRoot.getFunctionTable(), location,
expected, PainlessLookupUtility.typeToCanonicalTypeName(captured.clazz), call, 1);
}
actual = expected;

View File

@ -27,7 +27,7 @@ import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.MethodWriter;
import org.elasticsearch.painless.lookup.PainlessCast;
import org.elasticsearch.painless.lookup.PainlessLookupUtility;
import org.elasticsearch.painless.symbol.FunctionTable;
import org.elasticsearch.painless.ScriptRoot;
import java.util.Objects;
import java.util.Set;
@ -58,7 +58,7 @@ final class ECast extends AExpression {
}
@Override
void analyze(FunctionTable functions, Locals locals) {
void analyze(ScriptRoot scriptRoot, Locals locals) {
throw createError(new IllegalStateException("Illegal tree structure."));
}

View File

@ -30,7 +30,7 @@ import org.elasticsearch.painless.MethodWriter;
import org.elasticsearch.painless.Operation;
import org.elasticsearch.painless.lookup.PainlessLookupUtility;
import org.elasticsearch.painless.lookup.def;
import org.elasticsearch.painless.symbol.FunctionTable;
import org.elasticsearch.painless.ScriptRoot;
import org.objectweb.asm.Label;
import org.objectweb.asm.Type;
@ -72,31 +72,31 @@ public final class EComp extends AExpression {
}
@Override
void analyze(FunctionTable functions, Locals locals) {
void analyze(ScriptRoot scriptRoot, Locals locals) {
if (operation == Operation.EQ) {
analyzeEq(functions, locals);
analyzeEq(scriptRoot, locals);
} else if (operation == Operation.EQR) {
analyzeEqR(functions, locals);
analyzeEqR(scriptRoot, locals);
} else if (operation == Operation.NE) {
analyzeNE(functions, locals);
analyzeNE(scriptRoot, locals);
} else if (operation == Operation.NER) {
analyzeNER(functions, locals);
analyzeNER(scriptRoot, locals);
} else if (operation == Operation.GTE) {
analyzeGTE(functions, locals);
analyzeGTE(scriptRoot, locals);
} else if (operation == Operation.GT) {
analyzeGT(functions, locals);
analyzeGT(scriptRoot, locals);
} else if (operation == Operation.LTE) {
analyzeLTE(functions, locals);
analyzeLTE(scriptRoot, locals);
} else if (operation == Operation.LT) {
analyzeLT(functions, locals);
analyzeLT(scriptRoot, locals);
} else {
throw createError(new IllegalStateException("Illegal tree structure."));
}
}
private void analyzeEq(FunctionTable functions, Locals variables) {
left.analyze(functions, variables);
right.analyze(functions, variables);
private void analyzeEq(ScriptRoot scriptRoot, Locals variables) {
left.analyze(scriptRoot, variables);
right.analyze(scriptRoot, variables);
promotedType = AnalyzerCaster.promoteEquality(left.actual, right.actual);
@ -114,8 +114,8 @@ public final class EComp extends AExpression {
right.expected = promotedType;
}
left = left.cast(functions, variables);
right = right.cast(functions, variables);
left = left.cast(scriptRoot, variables);
right = right.cast(scriptRoot, variables);
if (left.isNull && right.isNull) {
throw createError(new IllegalArgumentException("Extraneous comparison of null constants."));
@ -144,9 +144,9 @@ public final class EComp extends AExpression {
actual = boolean.class;
}
private void analyzeEqR(FunctionTable functions, Locals variables) {
left.analyze(functions, variables);
right.analyze(functions, variables);
private void analyzeEqR(ScriptRoot scriptRoot, Locals variables) {
left.analyze(scriptRoot, variables);
right.analyze(scriptRoot, variables);
promotedType = AnalyzerCaster.promoteEquality(left.actual, right.actual);
@ -159,8 +159,8 @@ public final class EComp extends AExpression {
left.expected = promotedType;
right.expected = promotedType;
left = left.cast(functions, variables);
right = right.cast(functions, variables);
left = left.cast(scriptRoot, variables);
right = right.cast(scriptRoot, variables);
if (left.isNull && right.isNull) {
throw createError(new IllegalArgumentException("Extraneous comparison of null constants."));
@ -185,9 +185,9 @@ public final class EComp extends AExpression {
actual = boolean.class;
}
private void analyzeNE(FunctionTable functions, Locals variables) {
left.analyze(functions, variables);
right.analyze(functions, variables);
private void analyzeNE(ScriptRoot scriptRoot, Locals variables) {
left.analyze(scriptRoot, variables);
right.analyze(scriptRoot, variables);
promotedType = AnalyzerCaster.promoteEquality(left.actual, right.actual);
@ -205,8 +205,8 @@ public final class EComp extends AExpression {
right.expected = promotedType;
}
left = left.cast(functions, variables);
right = right.cast(functions, variables);
left = left.cast(scriptRoot, variables);
right = right.cast(scriptRoot, variables);
if (left.isNull && right.isNull) {
throw createError(new IllegalArgumentException("Extraneous comparison of null constants."));
@ -235,9 +235,9 @@ public final class EComp extends AExpression {
actual = boolean.class;
}
private void analyzeNER(FunctionTable functions, Locals variables) {
left.analyze(functions, variables);
right.analyze(functions, variables);
private void analyzeNER(ScriptRoot scriptRoot, Locals variables) {
left.analyze(scriptRoot, variables);
right.analyze(scriptRoot, variables);
promotedType = AnalyzerCaster.promoteEquality(left.actual, right.actual);
@ -250,8 +250,8 @@ public final class EComp extends AExpression {
left.expected = promotedType;
right.expected = promotedType;
left = left.cast(functions, variables);
right = right.cast(functions, variables);
left = left.cast(scriptRoot, variables);
right = right.cast(scriptRoot, variables);
if (left.isNull && right.isNull) {
throw createError(new IllegalArgumentException("Extraneous comparison of null constants."));
@ -276,9 +276,9 @@ public final class EComp extends AExpression {
actual = boolean.class;
}
private void analyzeGTE(FunctionTable functions, Locals variables) {
left.analyze(functions, variables);
right.analyze(functions, variables);
private void analyzeGTE(ScriptRoot scriptRoot, Locals variables) {
left.analyze(scriptRoot, variables);
right.analyze(scriptRoot, variables);
promotedType = AnalyzerCaster.promoteNumeric(left.actual, right.actual, true);
@ -296,8 +296,8 @@ public final class EComp extends AExpression {
right.expected = promotedType;
}
left = left.cast(functions, variables);
right = right.cast(functions, variables);
left = left.cast(scriptRoot, variables);
right = right.cast(scriptRoot, variables);
if (left.constant != null && right.constant != null) {
if (promotedType == int.class) {
@ -316,9 +316,9 @@ public final class EComp extends AExpression {
actual = boolean.class;
}
private void analyzeGT(FunctionTable functions, Locals variables) {
left.analyze(functions, variables);
right.analyze(functions, variables);
private void analyzeGT(ScriptRoot scriptRoot, Locals variables) {
left.analyze(scriptRoot, variables);
right.analyze(scriptRoot, variables);
promotedType = AnalyzerCaster.promoteNumeric(left.actual, right.actual, true);
@ -336,8 +336,8 @@ public final class EComp extends AExpression {
right.expected = promotedType;
}
left = left.cast(functions, variables);
right = right.cast(functions, variables);
left = left.cast(scriptRoot, variables);
right = right.cast(scriptRoot, variables);
if (left.constant != null && right.constant != null) {
if (promotedType == int.class) {
@ -356,9 +356,9 @@ public final class EComp extends AExpression {
actual = boolean.class;
}
private void analyzeLTE(FunctionTable functions, Locals variables) {
left.analyze(functions, variables);
right.analyze(functions, variables);
private void analyzeLTE(ScriptRoot scriptRoot, Locals variables) {
left.analyze(scriptRoot, variables);
right.analyze(scriptRoot, variables);
promotedType = AnalyzerCaster.promoteNumeric(left.actual, right.actual, true);
@ -376,8 +376,8 @@ public final class EComp extends AExpression {
right.expected = promotedType;
}
left = left.cast(functions, variables);
right = right.cast(functions, variables);
left = left.cast(scriptRoot, variables);
right = right.cast(scriptRoot, variables);
if (left.constant != null && right.constant != null) {
if (promotedType == int.class) {
@ -396,9 +396,9 @@ public final class EComp extends AExpression {
actual = boolean.class;
}
private void analyzeLT(FunctionTable functions, Locals variables) {
left.analyze(functions, variables);
right.analyze(functions, variables);
private void analyzeLT(ScriptRoot scriptRoot, Locals variables) {
left.analyze(scriptRoot, variables);
right.analyze(scriptRoot, variables);
promotedType = AnalyzerCaster.promoteNumeric(left.actual, right.actual, true);
@ -416,8 +416,8 @@ public final class EComp extends AExpression {
right.expected = promotedType;
}
left = left.cast(functions, variables);
right = right.cast(functions, variables);
left = left.cast(scriptRoot, variables);
right = right.cast(scriptRoot, variables);
if (left.constant != null && right.constant != null) {
if (promotedType == int.class) {

View File

@ -26,7 +26,7 @@ import org.elasticsearch.painless.Globals;
import org.elasticsearch.painless.Locals;
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.MethodWriter;
import org.elasticsearch.painless.symbol.FunctionTable;
import org.elasticsearch.painless.ScriptRoot;
import org.objectweb.asm.Label;
import org.objectweb.asm.Opcodes;
@ -65,10 +65,10 @@ public final class EConditional extends AExpression {
}
@Override
void analyze(FunctionTable functions, Locals locals) {
void analyze(ScriptRoot scriptRoot, Locals locals) {
condition.expected = boolean.class;
condition.analyze(functions, locals);
condition = condition.cast(functions, locals);
condition.analyze(scriptRoot, locals);
condition = condition.cast(scriptRoot, locals);
if (condition.constant != null) {
throw createError(new IllegalArgumentException("Extraneous conditional statement."));
@ -82,8 +82,8 @@ public final class EConditional extends AExpression {
right.internal = internal;
actual = expected;
left.analyze(functions, locals);
right.analyze(functions, locals);
left.analyze(scriptRoot, locals);
right.analyze(scriptRoot, locals);
if (expected == null) {
Class<?> promote = AnalyzerCaster.promoteConditional(left.actual, right.actual, left.constant, right.constant);
@ -93,8 +93,8 @@ public final class EConditional extends AExpression {
actual = promote;
}
left = left.cast(functions, locals);
right = right.cast(functions, locals);
left = left.cast(scriptRoot, locals);
right = right.cast(scriptRoot, locals);
}
@Override

View File

@ -25,7 +25,7 @@ import org.elasticsearch.painless.Globals;
import org.elasticsearch.painless.Locals;
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.MethodWriter;
import org.elasticsearch.painless.symbol.FunctionTable;
import org.elasticsearch.painless.ScriptRoot;
import java.util.Set;
@ -52,7 +52,7 @@ final class EConstant extends AExpression {
}
@Override
void analyze(FunctionTable functions, Locals locals) {
void analyze(ScriptRoot scriptRoot, Locals locals) {
if (constant instanceof String) {
actual = String.class;
} else if (constant instanceof Double) {

View File

@ -25,7 +25,7 @@ import org.elasticsearch.painless.Globals;
import org.elasticsearch.painless.Locals;
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.MethodWriter;
import org.elasticsearch.painless.symbol.FunctionTable;
import org.elasticsearch.painless.ScriptRoot;
import java.util.Objects;
import java.util.Set;
@ -54,7 +54,7 @@ public final class EDecimal extends AExpression {
}
@Override
void analyze(FunctionTable functions, Locals locals) {
void analyze(ScriptRoot scriptRoot, Locals locals) {
if (!read) {
throw createError(new IllegalArgumentException("Must read from constant [" + value + "]."));
}

View File

@ -26,7 +26,7 @@ import org.elasticsearch.painless.Globals;
import org.elasticsearch.painless.Locals;
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.MethodWriter;
import org.elasticsearch.painless.symbol.FunctionTable;
import org.elasticsearch.painless.ScriptRoot;
import org.objectweb.asm.Label;
import java.util.Set;
@ -61,7 +61,7 @@ public class EElvis extends AExpression {
}
@Override
void analyze(FunctionTable functions, Locals locals) {
void analyze(ScriptRoot scriptRoot, Locals locals) {
if (expected != null && expected.isPrimitive()) {
throw createError(new IllegalArgumentException("Elvis operator cannot return primitives"));
}
@ -72,8 +72,8 @@ public class EElvis extends AExpression {
rhs.explicit = explicit;
rhs.internal = internal;
actual = expected;
lhs.analyze(functions, locals);
rhs.analyze(functions, locals);
lhs.analyze(scriptRoot, locals);
rhs.analyze(scriptRoot, locals);
if (lhs.isNull) {
throw createError(new IllegalArgumentException("Extraneous elvis operator. LHS is null."));
@ -96,8 +96,8 @@ public class EElvis extends AExpression {
actual = promote;
}
lhs = lhs.cast(functions, locals);
rhs = rhs.cast(functions, locals);
lhs = lhs.cast(scriptRoot, locals);
rhs = rhs.cast(scriptRoot, locals);
}
@Override

View File

@ -25,7 +25,7 @@ import org.elasticsearch.painless.Globals;
import org.elasticsearch.painless.Locals;
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.MethodWriter;
import org.elasticsearch.painless.symbol.FunctionTable;
import org.elasticsearch.painless.ScriptRoot;
import java.util.Objects;
import java.util.Set;
@ -56,8 +56,8 @@ public final class EExplicit extends AExpression {
}
@Override
void analyze(FunctionTable functions, Locals locals) {
actual = locals.getPainlessLookup().canonicalTypeNameToType(type);
void analyze(ScriptRoot scriptRoot, Locals locals) {
actual = scriptRoot.getPainlessLookup().canonicalTypeNameToType(type);
if (actual == null) {
throw createError(new IllegalArgumentException("Not a type [" + type + "]."));
@ -65,8 +65,8 @@ public final class EExplicit extends AExpression {
child.expected = actual;
child.explicit = true;
child.analyze(functions, locals);
child = child.cast(functions, locals);
child.analyze(scriptRoot, locals);
child = child.cast(scriptRoot, locals);
}
@Override
@ -74,12 +74,12 @@ public final class EExplicit extends AExpression {
throw createError(new IllegalStateException("Illegal tree structure."));
}
AExpression cast(FunctionTable functions, Locals locals) {
AExpression cast(ScriptRoot scriptRoot, Locals locals) {
child.expected = expected;
child.explicit = explicit;
child.internal = internal;
return child.cast(functions, locals);
return child.cast(scriptRoot, locals);
}
@Override

View File

@ -26,7 +26,7 @@ import org.elasticsearch.painless.Globals;
import org.elasticsearch.painless.Locals;
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.MethodWriter;
import org.elasticsearch.painless.symbol.FunctionTable;
import org.elasticsearch.painless.ScriptRoot;
import org.objectweb.asm.Type;
import java.util.Objects;
@ -60,14 +60,14 @@ public final class EFunctionRef extends AExpression implements ILambda {
}
@Override
void analyze(FunctionTable functions, Locals locals) {
void analyze(ScriptRoot scriptRoot, Locals locals) {
if (expected == null) {
ref = null;
actual = String.class;
defPointer = "S" + type + "." + call + ",0";
} else {
defPointer = null;
ref = FunctionRef.create(locals.getPainlessLookup(), functions, location, expected, type, call, 0);
ref = FunctionRef.create(scriptRoot.getPainlessLookup(), scriptRoot.getFunctionTable(), location, expected, type, call, 0);
actual = expected;
}
}

View File

@ -26,7 +26,7 @@ import org.elasticsearch.painless.Locals;
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.MethodWriter;
import org.elasticsearch.painless.lookup.PainlessLookupUtility;
import org.elasticsearch.painless.symbol.FunctionTable;
import org.elasticsearch.painless.ScriptRoot;
import java.util.Objects;
import java.util.Set;
@ -61,10 +61,9 @@ public final class EInstanceof extends AExpression {
}
@Override
void analyze(FunctionTable functions, Locals locals) {
void analyze(ScriptRoot scriptRoot, Locals locals) {
// ensure the specified type is part of the definition
Class<?> clazz = locals.getPainlessLookup().canonicalTypeNameToType(this.type);
Class<?> clazz = scriptRoot.getPainlessLookup().canonicalTypeNameToType(this.type);
if (clazz == null) {
throw createError(new IllegalArgumentException("Not a type [" + this.type + "]."));
@ -75,9 +74,9 @@ public final class EInstanceof extends AExpression {
PainlessLookupUtility.typeToJavaType(clazz);
// analyze and cast the expression
expression.analyze(functions, locals);
expression.analyze(scriptRoot, locals);
expression.expected = expression.actual;
expression = expression.cast(functions, locals);
expression = expression.cast(scriptRoot, locals);
// record if the expression returns a primitive
primitiveExpression = expression.actual.isPrimitive();

View File

@ -30,7 +30,7 @@ import org.elasticsearch.painless.MethodWriter;
import org.elasticsearch.painless.lookup.PainlessLookupUtility;
import org.elasticsearch.painless.lookup.PainlessMethod;
import org.elasticsearch.painless.lookup.def;
import org.elasticsearch.painless.symbol.FunctionTable;
import org.elasticsearch.painless.ScriptRoot;
import org.objectweb.asm.Opcodes;
import java.util.ArrayList;
@ -111,7 +111,7 @@ public final class ELambda extends AExpression implements ILambda {
}
@Override
void analyze(FunctionTable functions, Locals locals) {
void analyze(ScriptRoot scriptRoot, Locals locals) {
Class<?> returnType;
List<String> actualParamTypeStrs;
PainlessMethod interfaceMethod;
@ -132,7 +132,7 @@ public final class ELambda extends AExpression implements ILambda {
} else {
// we know the method statically, infer return type and any unknown/def types
interfaceMethod = locals.getPainlessLookup().lookupFunctionalInterfacePainlessMethod(expected);
interfaceMethod = scriptRoot.getPainlessLookup().lookupFunctionalInterfacePainlessMethod(expected);
if (interfaceMethod == null) {
throw createError(new IllegalArgumentException("Cannot pass lambda to " +
"[" + PainlessLookupUtility.typeToCanonicalTypeName(expected) + "], not a functional interface"));
@ -176,14 +176,15 @@ public final class ELambda extends AExpression implements ILambda {
paramNames.addAll(paramNameStrs);
// desugar lambda body into a synthetic method
String name = locals.getNextSyntheticName();
desugared = new SFunction(location, PainlessLookupUtility.typeToCanonicalTypeName(returnType), name, paramTypes, paramNames,
String name = scriptRoot.getNextSyntheticName("lambda");
desugared = new SFunction(
location, PainlessLookupUtility.typeToCanonicalTypeName(returnType), name, paramTypes, paramNames,
new SBlock(location, statements), true);
desugared.storeSettings(settings);
desugared.generateSignature(locals.getPainlessLookup());
desugared.analyze(functions, Locals.newLambdaScope(locals.getProgramScope(), desugared.name, returnType,
desugared.generateSignature(scriptRoot.getPainlessLookup());
desugared.analyze(scriptRoot, Locals.newLambdaScope(locals.getProgramScope(), desugared.name, returnType,
desugared.parameters, captures.size(), settings.getMaxLoopCounter()));
functions.addFunction(desugared.name, desugared.returnType, desugared.typeParameters, true);
scriptRoot.getFunctionTable().addFunction(desugared.name, desugared.returnType, desugared.typeParameters, true);
// setup method reference to synthetic method
if (expected == null) {
@ -192,8 +193,8 @@ public final class ELambda extends AExpression implements ILambda {
defPointer = "Sthis." + name + "," + captures.size();
} else {
defPointer = null;
ref = FunctionRef.create(
locals.getPainlessLookup(), functions, location, expected, "this", desugared.name, captures.size());
ref = FunctionRef.create(scriptRoot.getPainlessLookup(), scriptRoot.getFunctionTable(),
location, expected, "this", desugared.name, captures.size());
actual = expected;
}
}

View File

@ -28,7 +28,7 @@ import org.elasticsearch.painless.MethodWriter;
import org.elasticsearch.painless.lookup.PainlessConstructor;
import org.elasticsearch.painless.lookup.PainlessMethod;
import org.elasticsearch.painless.lookup.def;
import org.elasticsearch.painless.symbol.FunctionTable;
import org.elasticsearch.painless.ScriptRoot;
import org.objectweb.asm.Type;
import org.objectweb.asm.commons.Method;
@ -68,21 +68,21 @@ public final class EListInit extends AExpression {
}
@Override
void analyze(FunctionTable functions, Locals locals) {
void analyze(ScriptRoot scriptRoot, Locals locals) {
if (!read) {
throw createError(new IllegalArgumentException("Must read from list initializer."));
}
actual = ArrayList.class;
constructor = locals.getPainlessLookup().lookupPainlessConstructor(actual, 0);
constructor = scriptRoot.getPainlessLookup().lookupPainlessConstructor(actual, 0);
if (constructor == null) {
throw createError(new IllegalArgumentException(
"constructor [" + typeToCanonicalTypeName(actual) + ", <init>/0] not found"));
}
method = locals.getPainlessLookup().lookupPainlessMethod(actual, false, "add", 1);
method = scriptRoot.getPainlessLookup().lookupPainlessMethod(actual, false, "add", 1);
if (method == null) {
throw createError(new IllegalArgumentException("method [" + typeToCanonicalTypeName(actual) + ", add/1] not found"));
@ -93,8 +93,8 @@ public final class EListInit extends AExpression {
expression.expected = def.class;
expression.internal = true;
expression.analyze(functions, locals);
values.set(index, expression.cast(functions, locals));
expression.analyze(scriptRoot, locals);
values.set(index, expression.cast(scriptRoot, locals));
}
}

View File

@ -28,7 +28,7 @@ import org.elasticsearch.painless.MethodWriter;
import org.elasticsearch.painless.lookup.PainlessConstructor;
import org.elasticsearch.painless.lookup.PainlessMethod;
import org.elasticsearch.painless.lookup.def;
import org.elasticsearch.painless.symbol.FunctionTable;
import org.elasticsearch.painless.ScriptRoot;
import org.objectweb.asm.Type;
import org.objectweb.asm.commons.Method;
@ -78,21 +78,21 @@ public final class EMapInit extends AExpression {
}
@Override
void analyze(FunctionTable functions, Locals locals) {
void analyze(ScriptRoot scriptRoot, Locals locals) {
if (!read) {
throw createError(new IllegalArgumentException("Must read from map initializer."));
}
actual = HashMap.class;
constructor = locals.getPainlessLookup().lookupPainlessConstructor(actual, 0);
constructor = scriptRoot.getPainlessLookup().lookupPainlessConstructor(actual, 0);
if (constructor == null) {
throw createError(new IllegalArgumentException(
"constructor [" + typeToCanonicalTypeName(actual) + ", <init>/0] not found"));
}
method = locals.getPainlessLookup().lookupPainlessMethod(actual, false, "put", 2);
method = scriptRoot.getPainlessLookup().lookupPainlessMethod(actual, false, "put", 2);
if (method == null) {
throw createError(new IllegalArgumentException("method [" + typeToCanonicalTypeName(actual) + ", put/2] not found"));
@ -107,8 +107,8 @@ public final class EMapInit extends AExpression {
expression.expected = def.class;
expression.internal = true;
expression.analyze(functions, locals);
keys.set(index, expression.cast(functions, locals));
expression.analyze(scriptRoot, locals);
keys.set(index, expression.cast(scriptRoot, locals));
}
for (int index = 0; index < values.size(); ++index) {
@ -116,8 +116,8 @@ public final class EMapInit extends AExpression {
expression.expected = def.class;
expression.internal = true;
expression.analyze(functions, locals);
values.set(index, expression.cast(functions, locals));
expression.analyze(scriptRoot, locals);
values.set(index, expression.cast(scriptRoot, locals));
}
}

View File

@ -25,7 +25,7 @@ import org.elasticsearch.painless.Globals;
import org.elasticsearch.painless.Locals;
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.MethodWriter;
import org.elasticsearch.painless.symbol.FunctionTable;
import org.elasticsearch.painless.ScriptRoot;
import java.util.List;
import java.util.Objects;
@ -63,12 +63,12 @@ public final class ENewArray extends AExpression {
}
@Override
void analyze(FunctionTable functions, Locals locals) {
void analyze(ScriptRoot scriptRoot, Locals locals) {
if (!read) {
throw createError(new IllegalArgumentException("A newly created array must be read from."));
}
Class<?> clazz = locals.getPainlessLookup().canonicalTypeNameToType(this.type);
Class<?> clazz = scriptRoot.getPainlessLookup().canonicalTypeNameToType(this.type);
if (clazz == null) {
throw createError(new IllegalArgumentException("Not a type [" + this.type + "]."));
@ -79,8 +79,8 @@ public final class ENewArray extends AExpression {
expression.expected = initialize ? clazz.getComponentType() : int.class;
expression.internal = true;
expression.analyze(functions, locals);
arguments.set(argument, expression.cast(functions, locals));
expression.analyze(scriptRoot, locals);
arguments.set(argument, expression.cast(scriptRoot, locals));
}
actual = clazz;

View File

@ -26,7 +26,7 @@ import org.elasticsearch.painless.Globals;
import org.elasticsearch.painless.Locals;
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.MethodWriter;
import org.elasticsearch.painless.symbol.FunctionTable;
import org.elasticsearch.painless.ScriptRoot;
import org.objectweb.asm.Type;
import java.util.Arrays;
@ -63,17 +63,18 @@ public final class ENewArrayFunctionRef extends AExpression implements ILambda {
}
@Override
void analyze(FunctionTable functions, Locals locals) {
void analyze(ScriptRoot scriptRoot, Locals locals) {
SReturn code = new SReturn(location, new ENewArray(location, type, Arrays.asList(new EVariable(location, "size")), false));
function = new SFunction(location, type, locals.getNextSyntheticName(),
function = new SFunction(
location, type, scriptRoot.getNextSyntheticName("newarray"),
Collections.singletonList("int"), Collections.singletonList("size"),
new SBlock(location, Collections.singletonList(code)), true);
function.storeSettings(settings);
function.generateSignature(locals.getPainlessLookup());
function.generateSignature(scriptRoot.getPainlessLookup());
function.extractVariables(null);
function.analyze(functions, Locals.newLambdaScope(locals.getProgramScope(), function.name, function.returnType,
function.analyze(scriptRoot, Locals.newLambdaScope(locals.getProgramScope(), function.name, function.returnType,
function.parameters, 0, settings.getMaxLoopCounter()));
functions.addFunction(function.name, function.returnType, function.typeParameters, true);
scriptRoot.getFunctionTable().addFunction(function.name, function.returnType, function.typeParameters, true);
if (expected == null) {
ref = null;
@ -81,7 +82,8 @@ public final class ENewArrayFunctionRef extends AExpression implements ILambda {
defPointer = "Sthis." + function.name + ",0";
} else {
defPointer = null;
ref = FunctionRef.create(locals.getPainlessLookup(), functions, location, expected, "this", function.name, 0);
ref = FunctionRef.create(scriptRoot.getPainlessLookup(), scriptRoot.getFunctionTable(),
location, expected, "this", function.name, 0);
actual = expected;
}
}

View File

@ -27,7 +27,7 @@ import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.MethodWriter;
import org.elasticsearch.painless.lookup.PainlessConstructor;
import org.elasticsearch.painless.lookup.PainlessLookupUtility;
import org.elasticsearch.painless.symbol.FunctionTable;
import org.elasticsearch.painless.ScriptRoot;
import org.objectweb.asm.Type;
import org.objectweb.asm.commons.Method;
@ -69,14 +69,14 @@ public final class ENewObj extends AExpression {
}
@Override
void analyze(FunctionTable functions, Locals locals) {
actual = locals.getPainlessLookup().canonicalTypeNameToType(this.type);
void analyze(ScriptRoot scriptRoot, Locals locals) {
actual = scriptRoot.getPainlessLookup().canonicalTypeNameToType(this.type);
if (actual == null) {
throw createError(new IllegalArgumentException("Not a type [" + this.type + "]."));
}
constructor = locals.getPainlessLookup().lookupPainlessConstructor(actual, arguments.size());
constructor = scriptRoot.getPainlessLookup().lookupPainlessConstructor(actual, arguments.size());
if (constructor == null) {
throw createError(new IllegalArgumentException(
@ -97,8 +97,8 @@ public final class ENewObj extends AExpression {
expression.expected = types[argument];
expression.internal = true;
expression.analyze(functions, locals);
arguments.set(argument, expression.cast(functions, locals));
expression.analyze(scriptRoot, locals);
arguments.set(argument, expression.cast(scriptRoot, locals));
}
statement = true;

View File

@ -26,7 +26,7 @@ import org.elasticsearch.painless.Locals;
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.MethodWriter;
import org.elasticsearch.painless.lookup.PainlessLookupUtility;
import org.elasticsearch.painless.symbol.FunctionTable;
import org.elasticsearch.painless.ScriptRoot;
import org.objectweb.asm.Opcodes;
import java.util.Set;
@ -51,7 +51,7 @@ public final class ENull extends AExpression {
}
@Override
void analyze(FunctionTable functions, Locals locals) {
void analyze(ScriptRoot scriptRoot, Locals locals) {
if (!read) {
throw createError(new IllegalArgumentException("Must read from null constant."));
}

View File

@ -25,7 +25,7 @@ import org.elasticsearch.painless.Globals;
import org.elasticsearch.painless.Locals;
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.MethodWriter;
import org.elasticsearch.painless.symbol.FunctionTable;
import org.elasticsearch.painless.ScriptRoot;
import java.util.Objects;
import java.util.Set;
@ -56,7 +56,7 @@ public final class ENumeric extends AExpression {
}
@Override
void analyze(FunctionTable functions, Locals locals) {
void analyze(ScriptRoot scriptRoot, Locals locals) {
if (!read) {
throw createError(new IllegalArgumentException("Must read from constant [" + value + "]."));
}

View File

@ -27,7 +27,7 @@ import org.elasticsearch.painless.Locals;
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.MethodWriter;
import org.elasticsearch.painless.WriterConstants;
import org.elasticsearch.painless.symbol.FunctionTable;
import org.elasticsearch.painless.ScriptRoot;
import java.util.Set;
import java.util.regex.Pattern;
@ -69,7 +69,7 @@ public final class ERegex extends AExpression {
}
@Override
void analyze(FunctionTable functions, Locals locals) {
void analyze(ScriptRoot scriptRoot, Locals locals) {
if (false == settings.areRegexesEnabled()) {
throw createError(new IllegalStateException("Regexes are disabled. Set [script.painless.regex.enabled] to [true] "
+ "in elasticsearch.yaml to allow them. Be careful though, regexes break out of Painless's protection against deep "

View File

@ -25,7 +25,7 @@ import org.elasticsearch.painless.Globals;
import org.elasticsearch.painless.Locals;
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.MethodWriter;
import org.elasticsearch.painless.symbol.FunctionTable;
import org.elasticsearch.painless.ScriptRoot;
import java.util.Objects;
import java.util.Set;
@ -54,8 +54,8 @@ public final class EStatic extends AExpression {
}
@Override
void analyze(FunctionTable functions, Locals locals) {
actual = locals.getPainlessLookup().canonicalTypeNameToType(type);
void analyze(ScriptRoot scriptRoot, Locals locals) {
actual = scriptRoot.getPainlessLookup().canonicalTypeNameToType(type);
if (actual == null) {
throw createError(new IllegalArgumentException("Not a type [" + type + "]."));

View File

@ -25,7 +25,7 @@ import org.elasticsearch.painless.Globals;
import org.elasticsearch.painless.Locals;
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.MethodWriter;
import org.elasticsearch.painless.symbol.FunctionTable;
import org.elasticsearch.painless.ScriptRoot;
import java.util.Objects;
import java.util.Set;
@ -52,7 +52,7 @@ public final class EString extends AExpression {
}
@Override
void analyze(FunctionTable functions, Locals locals) {
void analyze(ScriptRoot scriptRoot, Locals locals) {
if (!read) {
throw createError(new IllegalArgumentException("Must read from constant [" + constant + "]."));
}

View File

@ -30,7 +30,7 @@ import org.elasticsearch.painless.MethodWriter;
import org.elasticsearch.painless.Operation;
import org.elasticsearch.painless.lookup.PainlessLookupUtility;
import org.elasticsearch.painless.lookup.def;
import org.elasticsearch.painless.symbol.FunctionTable;
import org.elasticsearch.painless.ScriptRoot;
import org.objectweb.asm.Label;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
@ -67,26 +67,26 @@ public final class EUnary extends AExpression {
}
@Override
void analyze(FunctionTable functions, Locals locals) {
void analyze(ScriptRoot scriptRoot, Locals locals) {
originallyExplicit = explicit;
if (operation == Operation.NOT) {
analyzeNot(functions, locals);
analyzeNot(scriptRoot, locals);
} else if (operation == Operation.BWNOT) {
analyzeBWNot(functions, locals);
analyzeBWNot(scriptRoot, locals);
} else if (operation == Operation.ADD) {
analyzerAdd(functions, locals);
analyzerAdd(scriptRoot, locals);
} else if (operation == Operation.SUB) {
analyzerSub(functions, locals);
analyzerSub(scriptRoot, locals);
} else {
throw createError(new IllegalStateException("Illegal tree structure."));
}
}
void analyzeNot(FunctionTable functions, Locals variables) {
void analyzeNot(ScriptRoot scriptRoot, Locals variables) {
child.expected = boolean.class;
child.analyze(functions, variables);
child = child.cast(functions, variables);
child.analyze(scriptRoot, variables);
child = child.cast(scriptRoot, variables);
if (child.constant != null) {
constant = !(boolean)child.constant;
@ -95,8 +95,8 @@ public final class EUnary extends AExpression {
actual = boolean.class;
}
void analyzeBWNot(FunctionTable functions, Locals variables) {
child.analyze(functions, variables);
void analyzeBWNot(ScriptRoot scriptRoot, Locals variables) {
child.analyze(scriptRoot, variables);
promote = AnalyzerCaster.promoteNumeric(child.actual, false);
@ -106,7 +106,7 @@ public final class EUnary extends AExpression {
}
child.expected = promote;
child = child.cast(functions, variables);
child = child.cast(scriptRoot, variables);
if (child.constant != null) {
if (promote == int.class) {
@ -125,8 +125,8 @@ public final class EUnary extends AExpression {
}
}
void analyzerAdd(FunctionTable functions, Locals variables) {
child.analyze(functions, variables);
void analyzerAdd(ScriptRoot scriptRoot, Locals variables) {
child.analyze(scriptRoot, variables);
promote = AnalyzerCaster.promoteNumeric(child.actual, true);
@ -136,7 +136,7 @@ public final class EUnary extends AExpression {
}
child.expected = promote;
child = child.cast(functions, variables);
child = child.cast(scriptRoot, variables);
if (child.constant != null) {
if (promote == int.class) {
@ -159,8 +159,8 @@ public final class EUnary extends AExpression {
}
}
void analyzerSub(FunctionTable functions, Locals variables) {
child.analyze(functions, variables);
void analyzerSub(ScriptRoot scriptRoot, Locals variables) {
child.analyze(scriptRoot, variables);
promote = AnalyzerCaster.promoteNumeric(child.actual, true);
@ -170,7 +170,7 @@ public final class EUnary extends AExpression {
}
child.expected = promote;
child = child.cast(functions, variables);
child = child.cast(scriptRoot, variables);
if (child.constant != null) {
if (promote == int.class) {

View File

@ -26,7 +26,7 @@ import org.elasticsearch.painless.Locals;
import org.elasticsearch.painless.Locals.Variable;
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.MethodWriter;
import org.elasticsearch.painless.symbol.FunctionTable;
import org.elasticsearch.painless.ScriptRoot;
import org.objectweb.asm.Opcodes;
import java.util.Objects;
@ -58,7 +58,7 @@ public final class EVariable extends AStoreable {
}
@Override
void analyze(FunctionTable functions, Locals locals) {
void analyze(ScriptRoot scriptRoot, Locals locals) {
variable = locals.getVariable(location, name);
if (write && variable.readonly) {

View File

@ -27,7 +27,7 @@ import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.MethodWriter;
import org.elasticsearch.painless.lookup.PainlessLookupUtility;
import org.elasticsearch.painless.lookup.def;
import org.elasticsearch.painless.symbol.FunctionTable;
import org.elasticsearch.painless.ScriptRoot;
import java.util.List;
import java.util.Map;
@ -62,10 +62,10 @@ public final class PBrace extends AStoreable {
}
@Override
void analyze(FunctionTable functions, Locals locals) {
prefix.analyze(functions, locals);
void analyze(ScriptRoot scriptRoot, Locals locals) {
prefix.analyze(scriptRoot, locals);
prefix.expected = prefix.actual;
prefix = prefix.cast(functions, locals);
prefix = prefix.cast(scriptRoot, locals);
if (prefix.actual.isArray()) {
sub = new PSubBrace(location, prefix.actual, index);
@ -84,7 +84,7 @@ public final class PBrace extends AStoreable {
sub.read = read;
sub.expected = expected;
sub.explicit = explicit;
sub.analyze(functions, locals);
sub.analyze(scriptRoot, locals);
actual = sub.actual;
}

View File

@ -27,7 +27,7 @@ import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.MethodWriter;
import org.elasticsearch.painless.lookup.PainlessMethod;
import org.elasticsearch.painless.lookup.def;
import org.elasticsearch.painless.symbol.FunctionTable;
import org.elasticsearch.painless.ScriptRoot;
import java.util.List;
import java.util.Objects;
@ -73,16 +73,16 @@ public final class PCallInvoke extends AExpression {
}
@Override
void analyze(FunctionTable functions, Locals locals) {
prefix.analyze(functions, locals);
void analyze(ScriptRoot scriptRoot, Locals locals) {
prefix.analyze(scriptRoot, locals);
prefix.expected = prefix.actual;
prefix = prefix.cast(functions, locals);
prefix = prefix.cast(scriptRoot, locals);
if (prefix.actual == def.class) {
sub = new PSubDefCall(location, name, arguments);
} else {
PainlessMethod method =
locals.getPainlessLookup().lookupPainlessMethod(prefix.actual, prefix instanceof EStatic, name, arguments.size());
scriptRoot.getPainlessLookup().lookupPainlessMethod(prefix.actual, prefix instanceof EStatic, name, arguments.size());
if (method == null) {
throw createError(new IllegalArgumentException(
@ -98,7 +98,7 @@ public final class PCallInvoke extends AExpression {
sub.expected = expected;
sub.explicit = explicit;
sub.analyze(functions, locals);
sub.analyze(scriptRoot, locals);
actual = sub.actual;
statement = true;

View File

@ -29,7 +29,7 @@ import org.elasticsearch.painless.lookup.PainlessField;
import org.elasticsearch.painless.lookup.PainlessLookupUtility;
import org.elasticsearch.painless.lookup.PainlessMethod;
import org.elasticsearch.painless.lookup.def;
import org.elasticsearch.painless.symbol.FunctionTable;
import org.elasticsearch.painless.ScriptRoot;
import java.util.List;
import java.util.Map;
@ -66,38 +66,38 @@ public final class PField extends AStoreable {
}
@Override
void analyze(FunctionTable functions, Locals locals) {
prefix.analyze(functions, locals);
void analyze(ScriptRoot scriptRoot, Locals locals) {
prefix.analyze(scriptRoot, locals);
prefix.expected = prefix.actual;
prefix = prefix.cast(functions, locals);
prefix = prefix.cast(scriptRoot, locals);
if (prefix.actual.isArray()) {
sub = new PSubArrayLength(location, PainlessLookupUtility.typeToCanonicalTypeName(prefix.actual), value);
} else if (prefix.actual == def.class) {
sub = new PSubDefField(location, value);
} else {
PainlessField field = locals.getPainlessLookup().lookupPainlessField(prefix.actual, prefix instanceof EStatic, value);
PainlessField field = scriptRoot.getPainlessLookup().lookupPainlessField(prefix.actual, prefix instanceof EStatic, value);
if (field == null) {
PainlessMethod getter;
PainlessMethod setter;
getter = locals.getPainlessLookup().lookupPainlessMethod(prefix.actual, false,
getter = scriptRoot.getPainlessLookup().lookupPainlessMethod(prefix.actual, false,
"get" + Character.toUpperCase(value.charAt(0)) + value.substring(1), 0);
if (getter == null) {
getter = locals.getPainlessLookup().lookupPainlessMethod(prefix.actual, false,
getter = scriptRoot.getPainlessLookup().lookupPainlessMethod(prefix.actual, false,
"is" + Character.toUpperCase(value.charAt(0)) + value.substring(1), 0);
}
setter = locals.getPainlessLookup().lookupPainlessMethod(prefix.actual, false,
setter = scriptRoot.getPainlessLookup().lookupPainlessMethod(prefix.actual, false,
"set" + Character.toUpperCase(value.charAt(0)) + value.substring(1), 0);
if (getter != null || setter != null) {
sub = new PSubShortcut(location, value, PainlessLookupUtility.typeToCanonicalTypeName(prefix.actual), getter, setter);
} else {
EConstant index = new EConstant(location, value);
index.analyze(functions, locals);
index.analyze(scriptRoot, locals);
if (Map.class.isAssignableFrom(prefix.actual)) {
sub = new PSubMapShortcut(location, prefix.actual, index);
@ -125,7 +125,7 @@ public final class PField extends AStoreable {
sub.read = read;
sub.expected = expected;
sub.explicit = explicit;
sub.analyze(functions, locals);
sub.analyze(scriptRoot, locals);
actual = sub.actual;
}

View File

@ -25,7 +25,7 @@ import org.elasticsearch.painless.Globals;
import org.elasticsearch.painless.Locals;
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.MethodWriter;
import org.elasticsearch.painless.symbol.FunctionTable;
import org.elasticsearch.painless.ScriptRoot;
import java.util.Objects;
import java.util.Set;
@ -56,7 +56,7 @@ final class PSubArrayLength extends AStoreable {
}
@Override
void analyze(FunctionTable functions, Locals locals) {
void analyze(ScriptRoot scriptRoot, Locals locals) {
if ("length".equals(value)) {
if (write) {
throw createError(new IllegalArgumentException("Cannot write to read-only field [length] for an array."));

View File

@ -25,7 +25,7 @@ import org.elasticsearch.painless.Globals;
import org.elasticsearch.painless.Locals;
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.MethodWriter;
import org.elasticsearch.painless.symbol.FunctionTable;
import org.elasticsearch.painless.ScriptRoot;
import java.util.Objects;
import java.util.Set;
@ -56,10 +56,10 @@ final class PSubBrace extends AStoreable {
}
@Override
void analyze(FunctionTable functions, Locals locals) {
void analyze(ScriptRoot scriptRoot, Locals locals) {
index.expected = int.class;
index.analyze(functions, locals);
index = index.cast(functions, locals);
index.analyze(scriptRoot, locals);
index = index.cast(scriptRoot, locals);
actual = clazz.getComponentType();
}

View File

@ -26,7 +26,7 @@ import org.elasticsearch.painless.Locals;
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.MethodWriter;
import org.elasticsearch.painless.lookup.PainlessMethod;
import org.elasticsearch.painless.symbol.FunctionTable;
import org.elasticsearch.painless.ScriptRoot;
import java.util.List;
import java.util.Objects;
@ -60,14 +60,14 @@ final class PSubCallInvoke extends AExpression {
}
@Override
void analyze(FunctionTable functions, Locals locals) {
void analyze(ScriptRoot scriptRoot, Locals locals) {
for (int argument = 0; argument < arguments.size(); ++argument) {
AExpression expression = arguments.get(argument);
expression.expected = method.typeParameters.get(argument);
expression.internal = true;
expression.analyze(functions, locals);
arguments.set(argument, expression.cast(functions, locals));
expression.analyze(scriptRoot, locals);
arguments.set(argument, expression.cast(scriptRoot, locals));
}
statement = true;

View File

@ -27,7 +27,7 @@ import org.elasticsearch.painless.Locals;
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.MethodWriter;
import org.elasticsearch.painless.lookup.def;
import org.elasticsearch.painless.symbol.FunctionTable;
import org.elasticsearch.painless.ScriptRoot;
import org.objectweb.asm.Type;
import java.time.ZonedDateTime;
@ -57,10 +57,10 @@ final class PSubDefArray extends AStoreable {
}
@Override
void analyze(FunctionTable functions, Locals locals) {
index.analyze(functions, locals);
void analyze(ScriptRoot scriptRoot, Locals locals) {
index.analyze(scriptRoot, locals);
index.expected = index.actual;
index = index.cast(functions, locals);
index = index.cast(scriptRoot, locals);
// TODO: remove ZonedDateTime exception when JodaCompatibleDateTime is removed
actual = expected == null || expected == ZonedDateTime.class || explicit ? def.class : expected;

View File

@ -27,7 +27,7 @@ import org.elasticsearch.painless.Locals;
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.MethodWriter;
import org.elasticsearch.painless.lookup.def;
import org.elasticsearch.painless.symbol.FunctionTable;
import org.elasticsearch.painless.ScriptRoot;
import org.objectweb.asm.Type;
import java.time.ZonedDateTime;
@ -66,7 +66,7 @@ final class PSubDefCall extends AExpression {
}
@Override
void analyze(FunctionTable functions, Locals locals) {
void analyze(ScriptRoot scriptRoot, Locals locals) {
recipe = new StringBuilder();
int totalCaptures = 0;
@ -74,7 +74,7 @@ final class PSubDefCall extends AExpression {
AExpression expression = arguments.get(argument);
expression.internal = true;
expression.analyze(functions, locals);
expression.analyze(scriptRoot, locals);
if (expression instanceof ILambda) {
ILambda lambda = (ILambda) expression;
@ -90,7 +90,7 @@ final class PSubDefCall extends AExpression {
}
expression.expected = expression.actual;
arguments.set(argument, expression.cast(functions, locals));
arguments.set(argument, expression.cast(scriptRoot, locals));
}
// TODO: remove ZonedDateTime exception when JodaCompatibleDateTime is removed

View File

@ -27,7 +27,7 @@ import org.elasticsearch.painless.Locals;
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.MethodWriter;
import org.elasticsearch.painless.lookup.def;
import org.elasticsearch.painless.symbol.FunctionTable;
import org.elasticsearch.painless.ScriptRoot;
import java.time.ZonedDateTime;
import java.util.Objects;
@ -57,7 +57,7 @@ final class PSubDefField extends AStoreable {
}
@Override
void analyze(FunctionTable functions, Locals locals) {
void analyze(ScriptRoot scriptRoot, Locals locals) {
// TODO: remove ZonedDateTime exception when JodaCompatibleDateTime is removed
actual = expected == null || expected == ZonedDateTime.class || explicit ? def.class : expected;
}

View File

@ -27,7 +27,7 @@ import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.MethodWriter;
import org.elasticsearch.painless.lookup.PainlessField;
import org.elasticsearch.painless.lookup.PainlessLookupUtility;
import org.elasticsearch.painless.symbol.FunctionTable;
import org.elasticsearch.painless.ScriptRoot;
import org.objectweb.asm.Type;
import java.lang.reflect.Modifier;
@ -58,7 +58,7 @@ final class PSubField extends AStoreable {
}
@Override
void analyze(FunctionTable functions, Locals locals) {
void analyze(ScriptRoot scriptRoot, Locals locals) {
if (write && Modifier.isFinal(field.javaField.getModifiers())) {
throw createError(new IllegalArgumentException("Cannot write to read-only field [" + field.javaField.getName() + "] " +
"for type [" + PainlessLookupUtility.typeToCanonicalTypeName(field.javaField.getDeclaringClass()) + "]."));

View File

@ -28,7 +28,7 @@ import org.elasticsearch.painless.MethodWriter;
import org.elasticsearch.painless.WriterConstants;
import org.elasticsearch.painless.lookup.PainlessLookupUtility;
import org.elasticsearch.painless.lookup.PainlessMethod;
import org.elasticsearch.painless.symbol.FunctionTable;
import org.elasticsearch.painless.ScriptRoot;
import java.util.Objects;
import java.util.Set;
@ -62,11 +62,11 @@ final class PSubListShortcut extends AStoreable {
}
@Override
void analyze(FunctionTable functions, Locals locals) {
void analyze(ScriptRoot scriptRoot, Locals locals) {
String canonicalClassName = PainlessLookupUtility.typeToCanonicalTypeName(targetClass);
getter = locals.getPainlessLookup().lookupPainlessMethod(targetClass, false, "get", 1);
setter = locals.getPainlessLookup().lookupPainlessMethod(targetClass, false, "set", 2);
getter = scriptRoot.getPainlessLookup().lookupPainlessMethod(targetClass, false, "get", 1);
setter = scriptRoot.getPainlessLookup().lookupPainlessMethod(targetClass, false, "set", 2);
if (getter != null && (getter.returnType == void.class || getter.typeParameters.size() != 1 ||
getter.typeParameters.get(0) != int.class)) {
@ -84,8 +84,8 @@ final class PSubListShortcut extends AStoreable {
if ((read || write) && (!read || getter != null) && (!write || setter != null)) {
index.expected = int.class;
index.analyze(functions, locals);
index = index.cast(functions, locals);
index.analyze(scriptRoot, locals);
index = index.cast(scriptRoot, locals);
actual = setter != null ? setter.typeParameters.get(1) : getter.returnType;
} else {

View File

@ -27,7 +27,7 @@ import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.MethodWriter;
import org.elasticsearch.painless.lookup.PainlessLookupUtility;
import org.elasticsearch.painless.lookup.PainlessMethod;
import org.elasticsearch.painless.symbol.FunctionTable;
import org.elasticsearch.painless.ScriptRoot;
import java.util.Objects;
import java.util.Set;
@ -61,11 +61,11 @@ final class PSubMapShortcut extends AStoreable {
}
@Override
void analyze(FunctionTable functions, Locals locals) {
void analyze(ScriptRoot scriptRoot, Locals locals) {
String canonicalClassName = PainlessLookupUtility.typeToCanonicalTypeName(targetClass);
getter = locals.getPainlessLookup().lookupPainlessMethod(targetClass, false, "get", 1);
setter = locals.getPainlessLookup().lookupPainlessMethod(targetClass, false, "put", 2);
getter = scriptRoot.getPainlessLookup().lookupPainlessMethod(targetClass, false, "get", 1);
setter = scriptRoot.getPainlessLookup().lookupPainlessMethod(targetClass, false, "put", 2);
if (getter != null && (getter.returnType == void.class || getter.typeParameters.size() != 1)) {
throw createError(new IllegalArgumentException("Illegal map get shortcut for type [" + canonicalClassName + "]."));
@ -82,8 +82,8 @@ final class PSubMapShortcut extends AStoreable {
if ((read || write) && (!read || getter != null) && (!write || setter != null)) {
index.expected = setter != null ? setter.typeParameters.get(0) : getter.typeParameters.get(0);
index.analyze(functions, locals);
index = index.cast(functions, locals);
index.analyze(scriptRoot, locals);
index = index.cast(scriptRoot, locals);
actual = setter != null ? setter.typeParameters.get(1) : getter.returnType;
} else {

View File

@ -25,7 +25,7 @@ import org.elasticsearch.painless.Globals;
import org.elasticsearch.painless.Locals;
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.MethodWriter;
import org.elasticsearch.painless.symbol.FunctionTable;
import org.elasticsearch.painless.ScriptRoot;
import org.objectweb.asm.Label;
import java.util.Set;
@ -57,8 +57,8 @@ public class PSubNullSafeCallInvoke extends AExpression {
}
@Override
void analyze(FunctionTable functions, Locals locals) {
guarded.analyze(functions, locals);
void analyze(ScriptRoot scriptRoot, Locals locals) {
guarded.analyze(scriptRoot, locals);
actual = guarded.actual;
if (actual.isPrimitive()) {
throw new IllegalArgumentException("Result of null safe operator must be nullable");

View File

@ -25,7 +25,7 @@ import org.elasticsearch.painless.Globals;
import org.elasticsearch.painless.Locals;
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.MethodWriter;
import org.elasticsearch.painless.symbol.FunctionTable;
import org.elasticsearch.painless.ScriptRoot;
import org.objectweb.asm.Label;
import java.util.Set;
@ -52,12 +52,12 @@ public class PSubNullSafeField extends AStoreable {
}
@Override
void analyze(FunctionTable functions, Locals locals) {
void analyze(ScriptRoot scriptRoot, Locals locals) {
if (write) {
throw createError(new IllegalArgumentException("Can't write to null safe reference"));
}
guarded.read = read;
guarded.analyze(functions, locals);
guarded.analyze(scriptRoot, locals);
actual = guarded.actual;
if (actual.isPrimitive()) {
throw new IllegalArgumentException("Result of null safe operator must be nullable");

View File

@ -26,7 +26,7 @@ import org.elasticsearch.painless.Locals;
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.MethodWriter;
import org.elasticsearch.painless.lookup.PainlessMethod;
import org.elasticsearch.painless.symbol.FunctionTable;
import org.elasticsearch.painless.ScriptRoot;
import java.util.Set;
@ -60,7 +60,7 @@ final class PSubShortcut extends AStoreable {
}
@Override
void analyze(FunctionTable functions, Locals locals) {
void analyze(ScriptRoot scriptRoot, Locals locals) {
if (getter != null && (getter.returnType == void.class || !getter.typeParameters.isEmpty())) {
throw createError(new IllegalArgumentException(
"Illegal get shortcut on field [" + value + "] for type [" + type + "]."));

View File

@ -25,7 +25,7 @@ import org.elasticsearch.painless.Globals;
import org.elasticsearch.painless.Locals;
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.MethodWriter;
import org.elasticsearch.painless.symbol.FunctionTable;
import org.elasticsearch.painless.ScriptRoot;
import java.util.Collections;
import java.util.List;
@ -61,7 +61,7 @@ public final class SBlock extends AStatement {
}
@Override
void analyze(FunctionTable functions, Locals locals) {
void analyze(ScriptRoot scriptRoot, Locals locals) {
if (statements == null || statements.isEmpty()) {
throw createError(new IllegalArgumentException("A block must contain at least one statement."));
}
@ -78,8 +78,7 @@ public final class SBlock extends AStatement {
statement.inLoop = inLoop;
statement.lastSource = lastSource && statement == last;
statement.lastLoop = (beginLoop || lastLoop) && statement == last;
statement.analyze(functions, locals);
statement.analyze(scriptRoot, locals);
methodEscape = statement.methodEscape;
loopEscape = statement.loopEscape;

View File

@ -25,7 +25,7 @@ import org.elasticsearch.painless.Globals;
import org.elasticsearch.painless.Locals;
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.MethodWriter;
import org.elasticsearch.painless.symbol.FunctionTable;
import org.elasticsearch.painless.ScriptRoot;
import java.util.Set;
@ -49,7 +49,7 @@ public final class SBreak extends AStatement {
}
@Override
void analyze(FunctionTable functions, Locals locals) {
void analyze(ScriptRoot scriptRoot, Locals locals) {
if (!inLoop) {
throw createError(new IllegalArgumentException("Break statement outside of a loop."));
}

View File

@ -26,7 +26,7 @@ import org.elasticsearch.painless.Locals;
import org.elasticsearch.painless.Locals.Variable;
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.MethodWriter;
import org.elasticsearch.painless.symbol.FunctionTable;
import org.elasticsearch.painless.ScriptRoot;
import org.objectweb.asm.Label;
import org.objectweb.asm.Opcodes;
@ -73,8 +73,8 @@ public final class SCatch extends AStatement {
}
@Override
void analyze(FunctionTable functions, Locals locals) {
Class<?> clazz = locals.getPainlessLookup().canonicalTypeNameToType(this.type);
void analyze(ScriptRoot scriptRoot, Locals locals) {
Class<?> clazz = scriptRoot.getPainlessLookup().canonicalTypeNameToType(this.type);
if (clazz == null) {
throw createError(new IllegalArgumentException("Not a type [" + this.type + "]."));
@ -90,8 +90,7 @@ public final class SCatch extends AStatement {
block.lastSource = lastSource;
block.inLoop = inLoop;
block.lastLoop = lastLoop;
block.analyze(functions, locals);
block.analyze(scriptRoot, locals);
methodEscape = block.methodEscape;
loopEscape = block.loopEscape;

View File

@ -30,6 +30,7 @@ import org.elasticsearch.painless.MethodWriter;
import org.elasticsearch.painless.ScriptClassInfo;
import org.elasticsearch.painless.WriterConstants;
import org.elasticsearch.painless.lookup.PainlessLookup;
import org.elasticsearch.painless.ScriptRoot;
import org.elasticsearch.painless.symbol.FunctionTable;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.Label;
@ -87,7 +88,7 @@ public final class SClass extends AStatement {
private CompilerSettings settings;
private FunctionTable table;
private ScriptRoot table;
private Locals mainMethod;
private final Set<String> extractedVariables;
private final List<org.objectweb.asm.commons.Method> getMethods;
@ -134,30 +135,30 @@ public final class SClass extends AStatement {
}
public void analyze(PainlessLookup painlessLookup) {
table = new FunctionTable();
table = new ScriptRoot(painlessLookup, settings, scriptClassInfo, this);
for (SFunction function : functions) {
function.generateSignature(painlessLookup);
String key = FunctionTable.buildLocalFunctionKey(function.name, function.parameters.size());
if (table.getFunction(key) != null) {
throw createError(new IllegalArgumentException("function [" + key + "] already defined"));
if (table.getFunctionTable().getFunction(key) != null) {
throw createError(new IllegalArgumentException("Illegal duplicate functions [" + key + "]."));
}
table.addFunction(function.name, function.returnType, function.typeParameters, false);
table.getFunctionTable().addFunction(function.name, function.returnType, function.typeParameters, false);
}
Locals locals = Locals.newProgramScope(scriptClassInfo, painlessLookup);
Locals locals = Locals.newProgramScope();
analyze(table, locals);
}
@Override
void analyze(FunctionTable functions, Locals program) {
void analyze(ScriptRoot scriptRoot, Locals program) {
for (SFunction function : this.functions) {
Locals functionLocals =
Locals.newFunctionScope(program, function.returnType, function.parameters, settings.getMaxLoopCounter());
function.analyze(functions, functionLocals);
function.analyze(scriptRoot, functionLocals);
}
if (statements == null || statements.isEmpty()) {
@ -188,8 +189,7 @@ public final class SClass extends AStatement {
}
statement.lastSource = statement == last;
statement.analyze(functions, mainMethod);
statement.analyze(scriptRoot, mainMethod);
methodEscape = statement.methodEscape;
allEscape = statement.allEscape;
@ -348,7 +348,7 @@ public final class SClass extends AStatement {
bytes = classWriter.getClassBytes();
Map<String, Object> statics = new HashMap<>();
statics.put("$FUNCTIONS", table);
statics.put("$FUNCTIONS", table.getFunctionTable());
for (Map.Entry<Object, String> instanceBinding : globals.getInstanceBindings().entrySet()) {
statics.put(instanceBinding.getValue(), instanceBinding.getKey());

View File

@ -25,7 +25,7 @@ import org.elasticsearch.painless.Globals;
import org.elasticsearch.painless.Locals;
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.MethodWriter;
import org.elasticsearch.painless.symbol.FunctionTable;
import org.elasticsearch.painless.ScriptRoot;
import java.util.Set;
@ -49,7 +49,7 @@ public final class SContinue extends AStatement {
}
@Override
void analyze(FunctionTable functions, Locals locals) {
void analyze(ScriptRoot scriptRoot, Locals locals) {
if (!inLoop) {
throw createError(new IllegalArgumentException("Continue statement outside of a loop."));
}

View File

@ -25,7 +25,7 @@ import org.elasticsearch.painless.Globals;
import org.elasticsearch.painless.Locals;
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.MethodWriter;
import org.elasticsearch.painless.symbol.FunctionTable;
import org.elasticsearch.painless.ScriptRoot;
import java.util.Collections;
import java.util.List;
@ -61,9 +61,9 @@ public final class SDeclBlock extends AStatement {
}
@Override
void analyze(FunctionTable functions, Locals locals) {
void analyze(ScriptRoot scriptRoot, Locals locals) {
for (SDeclaration declaration : declarations) {
declaration.analyze(functions, locals);
declaration.analyze(scriptRoot, locals);
}
statementCount = declarations.size();

View File

@ -26,7 +26,7 @@ import org.elasticsearch.painless.Locals;
import org.elasticsearch.painless.Locals.Variable;
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.MethodWriter;
import org.elasticsearch.painless.symbol.FunctionTable;
import org.elasticsearch.painless.ScriptRoot;
import org.objectweb.asm.Opcodes;
import java.util.Objects;
@ -68,8 +68,8 @@ public final class SDeclaration extends AStatement {
}
@Override
void analyze(FunctionTable functions, Locals locals) {
Class<?> clazz = locals.getPainlessLookup().canonicalTypeNameToType(this.type);
void analyze(ScriptRoot scriptRoot, Locals locals) {
Class<?> clazz = scriptRoot.getPainlessLookup().canonicalTypeNameToType(this.type);
if (clazz == null) {
throw createError(new IllegalArgumentException("Not a type [" + this.type + "]."));
@ -77,8 +77,8 @@ public final class SDeclaration extends AStatement {
if (expression != null) {
expression.expected = clazz;
expression.analyze(functions, locals);
expression = expression.cast(functions, locals);
expression.analyze(scriptRoot, locals);
expression = expression.cast(scriptRoot, locals);
}
variable = locals.addVariable(location, clazz, name, false);

View File

@ -25,7 +25,7 @@ import org.elasticsearch.painless.Globals;
import org.elasticsearch.painless.Locals;
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.MethodWriter;
import org.elasticsearch.painless.symbol.FunctionTable;
import org.elasticsearch.painless.ScriptRoot;
import org.objectweb.asm.Label;
import org.objectweb.asm.Opcodes;
@ -68,7 +68,7 @@ public final class SDo extends AStatement {
}
@Override
void analyze(FunctionTable functions, Locals locals) {
void analyze(ScriptRoot scriptRoot, Locals locals) {
locals = Locals.newLocalScope(locals);
if (block == null) {
@ -77,16 +77,15 @@ public final class SDo extends AStatement {
block.beginLoop = true;
block.inLoop = true;
block.analyze(functions, locals);
block.analyze(scriptRoot, locals);
if (block.loopEscape && !block.anyContinue) {
throw createError(new IllegalArgumentException("Extraneous do while loop."));
}
condition.expected = boolean.class;
condition.analyze(functions, locals);
condition = condition.cast(functions, locals);
condition.analyze(scriptRoot, locals);
condition = condition.cast(scriptRoot, locals);
if (condition.constant != null) {
continuous = (boolean)condition.constant;

View File

@ -28,7 +28,7 @@ import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.MethodWriter;
import org.elasticsearch.painless.lookup.PainlessLookupUtility;
import org.elasticsearch.painless.lookup.def;
import org.elasticsearch.painless.symbol.FunctionTable;
import org.elasticsearch.painless.ScriptRoot;
import java.util.Objects;
import java.util.Set;
@ -75,12 +75,12 @@ public class SEach extends AStatement {
}
@Override
void analyze(FunctionTable functions, Locals locals) {
expression.analyze(functions, locals);
void analyze(ScriptRoot scriptRoot, Locals locals) {
expression.analyze(scriptRoot, locals);
expression.expected = expression.actual;
expression = expression.cast(functions, locals);
expression = expression.cast(scriptRoot, locals);
Class<?> clazz = locals.getPainlessLookup().canonicalTypeNameToType(this.type);
Class<?> clazz = scriptRoot.getPainlessLookup().canonicalTypeNameToType(this.type);
if (clazz == null) {
throw createError(new IllegalArgumentException("Not a type [" + this.type + "]."));
@ -98,7 +98,7 @@ public class SEach extends AStatement {
"[" + PainlessLookupUtility.typeToCanonicalTypeName(expression.actual) + "]."));
}
sub.analyze(functions, locals);
sub.analyze(scriptRoot, locals);
if (block == null) {
throw createError(new IllegalArgumentException("Extraneous for each loop."));
@ -106,7 +106,7 @@ public class SEach extends AStatement {
block.beginLoop = true;
block.inLoop = true;
block.analyze(functions, locals);
block.analyze(scriptRoot, locals);
block.statementCount = Math.max(1, block.statementCount);
if (block.loopEscape && !block.anyContinue) {

View File

@ -25,7 +25,7 @@ import org.elasticsearch.painless.Globals;
import org.elasticsearch.painless.Locals;
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.MethodWriter;
import org.elasticsearch.painless.symbol.FunctionTable;
import org.elasticsearch.painless.ScriptRoot;
import java.util.Objects;
import java.util.Set;
@ -54,12 +54,12 @@ public final class SExpression extends AStatement {
}
@Override
void analyze(FunctionTable functions, Locals locals) {
void analyze(ScriptRoot scriptRoot, Locals locals) {
Class<?> rtnType = locals.getReturnType();
boolean isVoid = rtnType == void.class;
expression.read = lastSource && !isVoid;
expression.analyze(functions, locals);
expression.analyze(scriptRoot, locals);
if (!lastSource && !expression.statement) {
throw createError(new IllegalArgumentException("Not a statement."));
@ -69,7 +69,7 @@ public final class SExpression extends AStatement {
expression.expected = rtn ? rtnType : expression.actual;
expression.internal = rtn;
expression = expression.cast(functions, locals);
expression = expression.cast(scriptRoot, locals);
methodEscape = rtn;
loopEscape = rtn;

View File

@ -25,7 +25,7 @@ import org.elasticsearch.painless.Globals;
import org.elasticsearch.painless.Locals;
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.MethodWriter;
import org.elasticsearch.painless.symbol.FunctionTable;
import org.elasticsearch.painless.ScriptRoot;
import org.objectweb.asm.Label;
import org.objectweb.asm.Opcodes;
@ -94,24 +94,24 @@ public final class SFor extends AStatement {
}
@Override
void analyze(FunctionTable functions, Locals locals) {
void analyze(ScriptRoot scriptRoot, Locals locals) {
locals = Locals.newLocalScope(locals);
if (initializer != null) {
if (initializer instanceof SDeclBlock) {
initializer.analyze(functions, locals);
initializer.analyze(scriptRoot, locals);
} else if (initializer instanceof AExpression) {
AExpression initializer = (AExpression)this.initializer;
initializer.read = false;
initializer.analyze(functions, locals);
initializer.analyze(scriptRoot, locals);
if (!initializer.statement) {
throw createError(new IllegalArgumentException("Not a statement."));
}
initializer.expected = initializer.actual;
this.initializer = initializer.cast(functions, locals);
this.initializer = initializer.cast(scriptRoot, locals);
} else {
throw createError(new IllegalStateException("Illegal tree structure."));
}
@ -119,8 +119,8 @@ public final class SFor extends AStatement {
if (condition != null) {
condition.expected = boolean.class;
condition.analyze(functions, locals);
condition = condition.cast(functions, locals);
condition.analyze(scriptRoot, locals);
condition = condition.cast(scriptRoot, locals);
if (condition.constant != null) {
continuous = (boolean)condition.constant;
@ -139,21 +139,21 @@ public final class SFor extends AStatement {
if (afterthought != null) {
afterthought.read = false;
afterthought.analyze(functions, locals);
afterthought.analyze(scriptRoot, locals);
if (!afterthought.statement) {
throw createError(new IllegalArgumentException("Not a statement."));
}
afterthought.expected = afterthought.actual;
afterthought = afterthought.cast(functions, locals);
afterthought = afterthought.cast(scriptRoot, locals);
}
if (block != null) {
block.beginLoop = true;
block.inLoop = true;
block.analyze(functions, locals);
block.analyze(scriptRoot, locals);
if (block.loopEscape && !block.anyContinue) {
throw createError(new IllegalArgumentException("Extraneous for loop."));

View File

@ -29,7 +29,7 @@ import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.MethodWriter;
import org.elasticsearch.painless.lookup.PainlessLookup;
import org.elasticsearch.painless.lookup.PainlessLookupUtility;
import org.elasticsearch.painless.symbol.FunctionTable;
import org.elasticsearch.painless.ScriptRoot;
import org.objectweb.asm.Opcodes;
import java.lang.invoke.MethodType;
@ -127,7 +127,7 @@ public final class SFunction extends AStatement {
}
@Override
void analyze(FunctionTable functions, Locals locals) {
void analyze(ScriptRoot scriptRoot, Locals locals) {
if (block.statements.isEmpty()) {
throw createError(new IllegalArgumentException("Cannot generate an empty function [" + name + "]."));
}
@ -135,7 +135,7 @@ public final class SFunction extends AStatement {
locals = Locals.newLocalScope(locals);
block.lastSource = true;
block.analyze(functions, locals);
block.analyze(scriptRoot, locals);
methodEscape = block.methodEscape;
if (!methodEscape && returnType != void.class) {

View File

@ -25,7 +25,7 @@ import org.elasticsearch.painless.Globals;
import org.elasticsearch.painless.Locals;
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.MethodWriter;
import org.elasticsearch.painless.symbol.FunctionTable;
import org.elasticsearch.painless.ScriptRoot;
import org.objectweb.asm.Label;
import org.objectweb.asm.Opcodes;
@ -66,10 +66,10 @@ public final class SIf extends AStatement {
}
@Override
void analyze(FunctionTable functions, Locals locals) {
void analyze(ScriptRoot scriptRoot, Locals locals) {
condition.expected = boolean.class;
condition.analyze(functions, locals);
condition = condition.cast(functions, locals);
condition.analyze(scriptRoot, locals);
condition = condition.cast(scriptRoot, locals);
if (condition.constant != null) {
throw createError(new IllegalArgumentException("Extraneous if statement."));
@ -83,7 +83,7 @@ public final class SIf extends AStatement {
ifblock.inLoop = inLoop;
ifblock.lastLoop = lastLoop;
ifblock.analyze(functions, Locals.newLocalScope(locals));
ifblock.analyze(scriptRoot, Locals.newLocalScope(locals));
anyContinue = ifblock.anyContinue;
anyBreak = ifblock.anyBreak;

View File

@ -25,7 +25,7 @@ import org.elasticsearch.painless.Globals;
import org.elasticsearch.painless.Locals;
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.MethodWriter;
import org.elasticsearch.painless.symbol.FunctionTable;
import org.elasticsearch.painless.ScriptRoot;
import org.objectweb.asm.Label;
import org.objectweb.asm.Opcodes;
@ -79,10 +79,10 @@ public final class SIfElse extends AStatement {
}
@Override
void analyze(FunctionTable functions, Locals locals) {
void analyze(ScriptRoot scriptRoot, Locals locals) {
condition.expected = boolean.class;
condition.analyze(functions, locals);
condition = condition.cast(functions, locals);
condition.analyze(scriptRoot, locals);
condition = condition.cast(scriptRoot, locals);
if (condition.constant != null) {
throw createError(new IllegalArgumentException("Extraneous if statement."));
@ -96,7 +96,7 @@ public final class SIfElse extends AStatement {
ifblock.inLoop = inLoop;
ifblock.lastLoop = lastLoop;
ifblock.analyze(functions, Locals.newLocalScope(locals));
ifblock.analyze(scriptRoot, Locals.newLocalScope(locals));
anyContinue = ifblock.anyContinue;
anyBreak = ifblock.anyBreak;
@ -110,7 +110,7 @@ public final class SIfElse extends AStatement {
elseblock.inLoop = inLoop;
elseblock.lastLoop = lastLoop;
elseblock.analyze(functions, Locals.newLocalScope(locals));
elseblock.analyze(scriptRoot, Locals.newLocalScope(locals));
methodEscape = ifblock.methodEscape && elseblock.methodEscape;
loopEscape = ifblock.loopEscape && elseblock.loopEscape;

View File

@ -26,7 +26,7 @@ import org.elasticsearch.painless.Locals;
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.MethodWriter;
import org.elasticsearch.painless.lookup.PainlessLookupUtility;
import org.elasticsearch.painless.symbol.FunctionTable;
import org.elasticsearch.painless.ScriptRoot;
import java.util.Set;
@ -58,7 +58,7 @@ public final class SReturn extends AStatement {
}
@Override
void analyze(FunctionTable functions, Locals locals) {
void analyze(ScriptRoot scriptRoot, Locals locals) {
if (expression == null) {
if (locals.getReturnType() != void.class) {
throw location.createError(new ClassCastException("Cannot cast from " +
@ -68,8 +68,8 @@ public final class SReturn extends AStatement {
} else {
expression.expected = locals.getReturnType();
expression.internal = true;
expression.analyze(functions, locals);
expression = expression.cast(functions, locals);
expression.analyze(scriptRoot, locals);
expression = expression.cast(scriptRoot, locals);
}
methodEscape = true;

View File

@ -29,7 +29,7 @@ import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.MethodWriter;
import org.elasticsearch.painless.lookup.PainlessCast;
import org.elasticsearch.painless.lookup.PainlessLookupUtility;
import org.elasticsearch.painless.symbol.FunctionTable;
import org.elasticsearch.painless.ScriptRoot;
import org.objectweb.asm.Label;
import org.objectweb.asm.Opcodes;
@ -68,7 +68,7 @@ final class SSubEachArray extends AStatement {
}
@Override
void analyze(FunctionTable functions, Locals locals) {
void analyze(ScriptRoot scriptRoot, Locals locals) {
// We must store the array and index as variables for securing slots on the stack, and
// also add the location offset to make the names unique in case of nested for each loops.
array = locals.addVariable(location, expression.actual, "#array" + location.getOffset(), true);

View File

@ -32,7 +32,7 @@ import org.elasticsearch.painless.lookup.PainlessCast;
import org.elasticsearch.painless.lookup.PainlessLookupUtility;
import org.elasticsearch.painless.lookup.PainlessMethod;
import org.elasticsearch.painless.lookup.def;
import org.elasticsearch.painless.symbol.FunctionTable;
import org.elasticsearch.painless.ScriptRoot;
import org.objectweb.asm.Label;
import org.objectweb.asm.Opcodes;
@ -77,7 +77,7 @@ final class SSubEachIterable extends AStatement {
}
@Override
void analyze(FunctionTable functions, Locals locals) {
void analyze(ScriptRoot scriptRoot, Locals locals) {
// We must store the iterator as a variable for securing a slot on the stack, and
// also add the location offset to make the name unique in case of nested for each loops.
iterator = locals.addVariable(location, Iterator.class, "#itr" + location.getOffset(), true);
@ -85,7 +85,7 @@ final class SSubEachIterable extends AStatement {
if (expression.actual == def.class) {
method = null;
} else {
method = locals.getPainlessLookup().lookupPainlessMethod(expression.actual, false, "iterator", 0);
method = scriptRoot.getPainlessLookup().lookupPainlessMethod(expression.actual, false, "iterator", 0);
if (method == null) {
throw createError(new IllegalArgumentException(

View File

@ -25,7 +25,7 @@ import org.elasticsearch.painless.Globals;
import org.elasticsearch.painless.Locals;
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.MethodWriter;
import org.elasticsearch.painless.symbol.FunctionTable;
import org.elasticsearch.painless.ScriptRoot;
import java.util.Objects;
import java.util.Set;
@ -54,10 +54,10 @@ public final class SThrow extends AStatement {
}
@Override
void analyze(FunctionTable functions, Locals locals) {
void analyze(ScriptRoot scriptRoot, Locals locals) {
expression.expected = Exception.class;
expression.analyze(functions, locals);
expression = expression.cast(functions, locals);
expression.analyze(scriptRoot, locals);
expression = expression.cast(scriptRoot, locals);
methodEscape = true;
loopEscape = true;

View File

@ -25,7 +25,7 @@ import org.elasticsearch.painless.Globals;
import org.elasticsearch.painless.Locals;
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.MethodWriter;
import org.elasticsearch.painless.symbol.FunctionTable;
import org.elasticsearch.painless.ScriptRoot;
import org.objectweb.asm.Label;
import java.util.Collections;
@ -71,7 +71,7 @@ public final class STry extends AStatement {
}
@Override
void analyze(FunctionTable functions, Locals locals) {
void analyze(ScriptRoot scriptRoot, Locals locals) {
if (block == null) {
throw createError(new IllegalArgumentException("Extraneous try statement."));
}
@ -80,7 +80,7 @@ public final class STry extends AStatement {
block.inLoop = inLoop;
block.lastLoop = lastLoop;
block.analyze(functions, Locals.newLocalScope(locals));
block.analyze(scriptRoot, Locals.newLocalScope(locals));
methodEscape = block.methodEscape;
loopEscape = block.loopEscape;
@ -95,7 +95,7 @@ public final class STry extends AStatement {
catc.inLoop = inLoop;
catc.lastLoop = lastLoop;
catc.analyze(functions, Locals.newLocalScope(locals));
catc.analyze(scriptRoot, Locals.newLocalScope(locals));
methodEscape &= catc.methodEscape;
loopEscape &= catc.loopEscape;

View File

@ -25,7 +25,7 @@ import org.elasticsearch.painless.Globals;
import org.elasticsearch.painless.Locals;
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.MethodWriter;
import org.elasticsearch.painless.symbol.FunctionTable;
import org.elasticsearch.painless.ScriptRoot;
import org.objectweb.asm.Label;
import org.objectweb.asm.Opcodes;
@ -67,12 +67,12 @@ public final class SWhile extends AStatement {
}
@Override
void analyze(FunctionTable functions, Locals locals) {
void analyze(ScriptRoot scriptRoot, Locals locals) {
locals = Locals.newLocalScope(locals);
condition.expected = boolean.class;
condition.analyze(functions, locals);
condition = condition.cast(functions, locals);
condition.analyze(scriptRoot, locals);
condition = condition.cast(scriptRoot, locals);
if (condition.constant != null) {
continuous = (boolean)condition.constant;
@ -90,7 +90,7 @@ public final class SWhile extends AStatement {
block.beginLoop = true;
block.inLoop = true;
block.analyze(functions, locals);
block.analyze(scriptRoot, locals);
if (block.loopEscape && !block.anyContinue) {
throw createError(new IllegalArgumentException("Extraneous while loop."));

View File

@ -459,11 +459,11 @@ public class DefOptimizationTests extends ScriptTestCase {
public void testLambdaReturnType() {
assertBytecodeExists("List l = new ArrayList(); l.removeIf(x -> x < 10)",
"synthetic lambda$0(Ljava/lang/Object;)Z");
"synthetic lambda$synthetic$0(Ljava/lang/Object;)Z");
}
public void testLambdaArguments() {
assertBytecodeExists("List l = new ArrayList(); l.stream().mapToDouble(Double::valueOf).map(x -> x + 1)",
"synthetic lambda$0(D)D");
"synthetic lambda$synthetic$0(D)D");
}
}

View File

@ -70,7 +70,7 @@ public class FunctionTests extends ScriptTestCase {
Exception expected = expectScriptThrows(IllegalArgumentException.class, () -> {
exec("void test(int x) {x = 2;} void test(def y) {y = 3;} test()");
});
assertThat(expected.getMessage(), containsString("already defined"));
assertThat(expected.getMessage(), containsString("Illegal duplicate functions"));
}
public void testBadCastFromMethod() {