Reverted S-node design change.

This commit is contained in:
Jack Conradson 2016-06-06 17:59:39 -07:00
parent 8db9a971e5
commit 6dace47c1f
21 changed files with 226 additions and 326 deletions

View File

@ -74,7 +74,7 @@ decltype
;
funcref
: ( TYPE | ID ) REF ID
: TYPE REF ID
;
declvar

View File

@ -114,33 +114,11 @@ public abstract class AStatement extends ANode {
/**
* Checks for errors and collects data for the writing phase.
* @return The new child node for the parent node calling this method.
* Possibly returns a different {@link AStatement} node if a type is
* def or if a different specialization is used. Otherwise, returns itself.
*/
abstract AStatement analyze(Variables variables);
abstract void analyze(Variables variables);
/**
* Writes ASM based on the data collected during the analysis phase.
*/
abstract void write(MethodWriter writer);
/**
* Used to copy statement data from one to another during analysis in the case of replacement.
*/
final AStatement copy(AStatement statement) {
lastSource = statement.lastSource;
beginLoop = statement.beginLoop;
inLoop = statement.inLoop;
lastLoop = statement.lastLoop;
methodEscape = statement.methodEscape;
loopEscape = statement.loopEscape;
allEscape = statement.allEscape;
anyContinue = statement.anyContinue;
anyBreak = statement.anyBreak;
loopCounterSlot = statement.loopCounterSlot;
statementCount = statement.statementCount;
return this;
}
}

View File

@ -1,135 +0,0 @@
/*
* Licensed to Elasticsearch under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.elasticsearch.painless.node;
import org.elasticsearch.painless.AnalyzerCaster;
import org.elasticsearch.painless.Definition;
import org.elasticsearch.painless.Definition.Cast;
import org.elasticsearch.painless.Definition.Type;
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.MethodWriter;
import org.elasticsearch.painless.Variables;
import org.elasticsearch.painless.Variables.Variable;
import org.objectweb.asm.Label;
import org.objectweb.asm.Opcodes;
/**
* Represents a for-each loop shortcut for arrays. (Internal only.)
*/
class SArrayEach extends AStatement {
final int maxLoopCounter;
final String type;
final String name;
AExpression expression;
AStatement block;
Variable variable = null;
Variable array = null;
Variable index = null;
Type indexed = null;
Cast cast = null;
public SArrayEach(Location location, int maxLoopCounter, String type, String name, AExpression expression, SBlock block) {
super(location);
this.maxLoopCounter = maxLoopCounter;
this.type = type;
this.name = name;
this.expression = expression;
this.block = block;
}
@Override
AStatement analyze(Variables variables) {
// Note that we do not need to analyze the expression as this must already be done
// in the parent to determine that the for each target type is an array.
final Type type;
try {
type = Definition.getType(this.type);
} catch (IllegalArgumentException exception) {
throw createError(new IllegalArgumentException("Not a type [" + this.type + "]."));
}
variables.incrementScope();
variable = variables.addVariable(location, type, name, true, false);
array = variables.addVariable(location, expression.actual, "#array" + location.getOffset(), true, false);
index = variables.addVariable(location, Definition.INT_TYPE, "#index" + location.getOffset(), true, false);
indexed = Definition.getType(expression.actual.struct, expression.actual.dimensions - 1);
cast = AnalyzerCaster.getLegalCast(location, indexed, type, true, true);
if (block == null) {
throw location.createError(new IllegalArgumentException("Extraneous for each loop."));
}
block.beginLoop = true;
block.inLoop = true;
block = block.analyze(variables);
block.statementCount = Math.max(1, block.statementCount);
if (block.loopEscape && !block.anyContinue) {
throw createError(new IllegalArgumentException("Extraneous for loop."));
}
statementCount = 1;
if (maxLoopCounter > 0) {
loopCounterSlot = variables.getVariable(location, "#loop").slot;
}
variables.decrementScope();
return this;
}
@Override
void write(MethodWriter writer) {
writer.writeStatementOffset(location);
expression.write(writer);
writer.visitVarInsn(array.type.type.getOpcode(Opcodes.ISTORE), array.slot);
writer.push(-1);
writer.visitVarInsn(index.type.type.getOpcode(Opcodes.ISTORE), index.slot);
Label begin = new Label();
Label end = new Label();
writer.mark(begin);
writer.visitIincInsn(index.slot, 1);
writer.visitVarInsn(index.type.type.getOpcode(Opcodes.ILOAD), index.slot);
writer.visitVarInsn(array.type.type.getOpcode(Opcodes.ILOAD), array.slot);
writer.arrayLength();
writer.ifICmp(MethodWriter.GE, end);
writer.visitVarInsn(array.type.type.getOpcode(Opcodes.ILOAD), array.slot);
writer.visitVarInsn(index.type.type.getOpcode(Opcodes.ILOAD), index.slot);
writer.arrayLoad(indexed.type);
writer.writeCast(cast);
writer.visitVarInsn(variable.type.type.getOpcode(Opcodes.ISTORE), variable.slot);
block.write(writer);
writer.goTo(begin);
writer.mark(end);
}
}

View File

@ -23,6 +23,7 @@ import org.elasticsearch.painless.Variables;
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.MethodWriter;
import java.util.Collections;
import java.util.List;
/**
@ -35,27 +36,29 @@ public final class SBlock extends AStatement {
public SBlock(Location location, List<AStatement> statements) {
super(location);
this.statements = statements;
this.statements = Collections.unmodifiableList(statements);
}
@Override
AStatement analyze(Variables variables) {
void analyze(Variables variables) {
if (statements == null || statements.isEmpty()) {
throw createError(new IllegalArgumentException("A block must contain at least one statement."));
}
for (int index = 0; index < statements.size(); ++index) {
AStatement last = statements.get(statements.size() - 1);
for (AStatement statement : statements) {
// Note that we do not need to check after the last statement because
// there is no statement that can be unreachable after the last.
if (allEscape) {
throw createError(new IllegalArgumentException("Unreachable statement."));
}
AStatement statement = statements.get(index);
statement.inLoop = inLoop;
statement.lastSource = lastSource && index == statements.size() - 1;
statement.lastLoop = (beginLoop || lastLoop) && index == statements.size() - 1;
statement.lastSource = lastSource && statement == last;
statement.lastLoop = (beginLoop || lastLoop) && statement == last;
statements.set(index, statement.analyze(variables));
statement.analyze(variables);
methodEscape = statement.methodEscape;
loopEscape = statement.loopEscape;
@ -64,8 +67,6 @@ public final class SBlock extends AStatement {
anyBreak |= statement.anyBreak;
statementCount += statement.statementCount;
}
return this;
}
@Override

View File

@ -33,7 +33,7 @@ public final class SBreak extends AStatement {
}
@Override
AStatement analyze(Variables variables) {
void analyze(Variables variables) {
if (!inLoop) {
throw createError(new IllegalArgumentException("Break statement outside of a loop."));
}
@ -42,8 +42,6 @@ public final class SBreak extends AStatement {
allEscape = true;
anyBreak = true;
statementCount = 1;
return this;
}
@Override

View File

@ -35,7 +35,7 @@ public final class SCatch extends AStatement {
final String type;
final String name;
AStatement block;
final SBlock block;
Variable variable;
@ -52,7 +52,7 @@ public final class SCatch extends AStatement {
}
@Override
AStatement analyze(Variables variables) {
void analyze(Variables variables) {
final Type type;
try {
@ -72,7 +72,7 @@ public final class SCatch extends AStatement {
block.inLoop = inLoop;
block.lastLoop = lastLoop;
block = block.analyze(variables);
block.analyze(variables);
methodEscape = block.methodEscape;
loopEscape = block.loopEscape;
@ -81,8 +81,6 @@ public final class SCatch extends AStatement {
anyBreak = block.anyBreak;
statementCount = block.statementCount;
}
return this;
}
@Override

View File

@ -33,7 +33,7 @@ public final class SContinue extends AStatement {
}
@Override
AStatement analyze(Variables variables) {
void analyze(Variables variables) {
if (!inLoop) {
throw createError(new IllegalArgumentException("Continue statement outside of a loop."));
}
@ -45,8 +45,6 @@ public final class SContinue extends AStatement {
allEscape = true;
anyContinue = true;
statementCount = 1;
return this;
}
@Override

View File

@ -23,6 +23,7 @@ import org.elasticsearch.painless.Variables;
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.MethodWriter;
import java.util.Collections;
import java.util.List;
/**
@ -35,20 +36,16 @@ public final class SDeclBlock extends AStatement {
public SDeclBlock(Location location, List<SDeclaration> declarations) {
super(location);
this.declarations = declarations;
this.declarations = Collections.unmodifiableList(declarations);
}
@Override
AStatement analyze(Variables variables) {
for (int index = 0; index < declarations.size(); ++index) {
AStatement declaration = declarations.get(index);
declarations.set(index, (SDeclaration)declaration.analyze(variables));
void analyze(Variables variables) {
for (SDeclaration declaration : declarations) {
declaration.analyze(variables);
}
statementCount = declarations.size();
return this;
}
@Override

View File

@ -47,7 +47,7 @@ public final class SDeclaration extends AStatement {
}
@Override
AStatement analyze(Variables variables) {
void analyze(Variables variables) {
final Type type;
try {
@ -63,8 +63,6 @@ public final class SDeclaration extends AStatement {
}
variable = variables.addVariable(location, type, name, false, false);
return this;
}
@Override

View File

@ -31,7 +31,7 @@ import org.elasticsearch.painless.MethodWriter;
public final class SDo extends AStatement {
final int maxLoopCounter;
AStatement block;
final SBlock block;
AExpression condition;
public SDo(Location location, int maxLoopCounter, SBlock block, AExpression condition) {
@ -43,7 +43,7 @@ public final class SDo extends AStatement {
}
@Override
AStatement analyze(Variables variables) {
void analyze(Variables variables) {
variables.incrementScope();
if (block == null) {
@ -53,7 +53,7 @@ public final class SDo extends AStatement {
block.beginLoop = true;
block.inLoop = true;
block = block.analyze(variables);
block.analyze(variables);
if (block.loopEscape && !block.anyContinue) {
throw createError(new IllegalArgumentException("Extraneous do while loop."));
@ -83,8 +83,6 @@ public final class SDo extends AStatement {
}
variables.decrementScope();
return this;
}
@Override

View File

@ -45,14 +45,22 @@ public class SEach extends AStatement {
final String type;
final String name;
AExpression expression;
AStatement block;
final SBlock block;
// Members for all cases.
Variable variable = null;
Cast cast = null;
// Members for the array case.
Variable array = null;
Variable index = null;
Type indexed = null;
// Members for the iterable case.
Variable iterator = null;
Method method = null;
Method hasNext = null;
Method next = null;
Cast cast = null;
public SEach(Location location, int maxLoopCounter, String type, String name, AExpression expression, SBlock block) {
super(location);
@ -65,92 +73,172 @@ public class SEach extends AStatement {
}
@Override
AStatement analyze(Variables variables) {
void analyze(Variables variables) {
expression.analyze(variables);
expression.expected = expression.actual;
expression = expression.cast(variables);
Sort sort = expression.actual.sort;
if (sort == Sort.ARRAY) {
return new SArrayEach(location, maxLoopCounter, type, name, expression, (SBlock)block).copy(this).analyze(variables);
} else if (sort == Sort.DEF || Iterable.class.isAssignableFrom(expression.actual.clazz)) {
final Type type;
try {
type = Definition.getType(this.type);
} catch (IllegalArgumentException exception) {
throw createError(new IllegalArgumentException("Not a type [" + this.type + "]."));
}
variables.incrementScope();
Type itr = Definition.getType("Iterator");
variable = variables.addVariable(location, type, name, true, false);
// 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 = variables.addVariable(location, itr, "#itr" + location.getOffset(), true, false);
if (sort == Sort.DEF) {
method = null;
} else {
method = expression.actual.struct.methods.get(new MethodKey("iterator", 0));
if (method == null) {
throw location.createError(new IllegalArgumentException(
"Unable to create iterator for the type [" + expression.actual.name + "]."));
}
}
hasNext = itr.struct.methods.get(new MethodKey("hasNext", 0));
if (hasNext == null) {
throw location.createError(new IllegalArgumentException("Method [hasNext] does not exist for type [Iterator]."));
} else if (hasNext.rtn.sort != Sort.BOOL) {
throw location.createError(new IllegalArgumentException("Method [hasNext] does not return type [boolean]."));
}
next = itr.struct.methods.get(new MethodKey("next", 0));
if (next == null) {
throw location.createError(new IllegalArgumentException("Method [next] does not exist for type [Iterator]."));
} else if (next.rtn.sort != Sort.DEF) {
throw location.createError(new IllegalArgumentException("Method [next] does not return type [def]."));
}
cast = AnalyzerCaster.getLegalCast(location, Definition.DEF_TYPE, type, true, true);
if (block == null) {
throw location.createError(new IllegalArgumentException("Extraneous for each loop."));
}
block.beginLoop = true;
block.inLoop = true;
block = block.analyze(variables);
block.statementCount = Math.max(1, block.statementCount);
if (block.loopEscape && !block.anyContinue) {
throw createError(new IllegalArgumentException("Extraneous for loop."));
}
statementCount = 1;
if (maxLoopCounter > 0) {
loopCounterSlot = variables.getVariable(location, "#loop").slot;
}
variables.decrementScope();
return this;
if (expression.actual.sort == Sort.ARRAY) {
analyzeArray(variables);
} else if (expression.actual.sort == Sort.DEF || Iterable.class.isAssignableFrom(expression.actual.clazz)) {
analyzeIterable(variables);
} else {
throw location.createError(new IllegalArgumentException("Illegal for each type [" + expression.actual.name + "]."));
}
}
void analyzeArray(Variables variables) {
final Type type;
try {
type = Definition.getType(this.type);
} catch (IllegalArgumentException exception) {
throw createError(new IllegalArgumentException("Not a type [" + this.type + "]."));
}
variables.incrementScope();
variable = variables.addVariable(location, type, name, true, false);
array = variables.addVariable(location, expression.actual, "#array" + location.getOffset(), true, false);
index = variables.addVariable(location, Definition.INT_TYPE, "#index" + location.getOffset(), true, false);
indexed = Definition.getType(expression.actual.struct, expression.actual.dimensions - 1);
cast = AnalyzerCaster.getLegalCast(location, indexed, type, true, true);
if (block == null) {
throw location.createError(new IllegalArgumentException("Extraneous for each loop."));
}
block.beginLoop = true;
block.inLoop = true;
block.analyze(variables);
block.statementCount = Math.max(1, block.statementCount);
if (block.loopEscape && !block.anyContinue) {
throw createError(new IllegalArgumentException("Extraneous for loop."));
}
statementCount = 1;
if (maxLoopCounter > 0) {
loopCounterSlot = variables.getVariable(location, "#loop").slot;
}
variables.decrementScope();
}
void analyzeIterable(Variables variables) {
final Type type;
try {
type = Definition.getType(this.type);
} catch (IllegalArgumentException exception) {
throw createError(new IllegalArgumentException("Not a type [" + this.type + "]."));
}
variables.incrementScope();
Type itr = Definition.getType("Iterator");
variable = variables.addVariable(location, type, name, true, false);
// 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 = variables.addVariable(location, itr, "#itr" + location.getOffset(), true, false);
if (expression.actual.sort == Sort.DEF) {
method = null;
} else {
method = expression.actual.struct.methods.get(new MethodKey("iterator", 0));
if (method == null) {
throw location.createError(new IllegalArgumentException(
"Unable to create iterator for the type [" + expression.actual.name + "]."));
}
}
hasNext = itr.struct.methods.get(new MethodKey("hasNext", 0));
if (hasNext == null) {
throw location.createError(new IllegalArgumentException("Method [hasNext] does not exist for type [Iterator]."));
} else if (hasNext.rtn.sort != Sort.BOOL) {
throw location.createError(new IllegalArgumentException("Method [hasNext] does not return type [boolean]."));
}
next = itr.struct.methods.get(new MethodKey("next", 0));
if (next == null) {
throw location.createError(new IllegalArgumentException("Method [next] does not exist for type [Iterator]."));
} else if (next.rtn.sort != Sort.DEF) {
throw location.createError(new IllegalArgumentException("Method [next] does not return type [def]."));
}
cast = AnalyzerCaster.getLegalCast(location, Definition.DEF_TYPE, type, true, true);
if (block == null) {
throw location.createError(new IllegalArgumentException("Extraneous for each loop."));
}
block.beginLoop = true;
block.inLoop = true;
block.analyze(variables);
block.statementCount = Math.max(1, block.statementCount);
if (block.loopEscape && !block.anyContinue) {
throw createError(new IllegalArgumentException("Extraneous for loop."));
}
statementCount = 1;
if (maxLoopCounter > 0) {
loopCounterSlot = variables.getVariable(location, "#loop").slot;
}
variables.decrementScope();
}
@Override
void write(MethodWriter writer) {
if (array != null) {
writeArray(writer);
} else if (iterator != null) {
writeIterable(writer);
} else {
throw location.createError(new IllegalStateException("Illegal tree structure."));
}
}
void writeArray(MethodWriter writer) {
writer.writeStatementOffset(location);
expression.write(writer);
writer.visitVarInsn(array.type.type.getOpcode(Opcodes.ISTORE), array.slot);
writer.push(-1);
writer.visitVarInsn(index.type.type.getOpcode(Opcodes.ISTORE), index.slot);
Label begin = new Label();
Label end = new Label();
writer.mark(begin);
writer.visitIincInsn(index.slot, 1);
writer.visitVarInsn(index.type.type.getOpcode(Opcodes.ILOAD), index.slot);
writer.visitVarInsn(array.type.type.getOpcode(Opcodes.ILOAD), array.slot);
writer.arrayLength();
writer.ifICmp(MethodWriter.GE, end);
writer.visitVarInsn(array.type.type.getOpcode(Opcodes.ILOAD), array.slot);
writer.visitVarInsn(index.type.type.getOpcode(Opcodes.ILOAD), index.slot);
writer.arrayLoad(indexed.type);
writer.writeCast(cast);
writer.visitVarInsn(variable.type.type.getOpcode(Opcodes.ISTORE), variable.slot);
block.write(writer);
writer.goTo(begin);
writer.mark(end);
}
void writeIterable(MethodWriter writer) {
writer.writeStatementOffset(location);
expression.write(writer);

View File

@ -39,7 +39,7 @@ public final class SExpression extends AStatement {
}
@Override
AStatement analyze(Variables variables) {
void analyze(Variables variables) {
expression.read = lastSource;
expression.analyze(variables);
@ -57,8 +57,6 @@ public final class SExpression extends AStatement {
loopEscape = rtn;
allEscape = rtn;
statementCount = 1;
return this;
}
@Override

View File

@ -34,7 +34,7 @@ public final class SFor extends AStatement {
ANode initializer;
AExpression condition;
AExpression afterthought;
AStatement block;
final SBlock block;
public SFor(Location location, int maxLoopCounter,
ANode initializer, AExpression condition, AExpression afterthought, SBlock block) {
@ -48,14 +48,14 @@ public final class SFor extends AStatement {
}
@Override
AStatement analyze(Variables variables) {
void analyze(Variables variables) {
variables.incrementScope();
boolean continuous = false;
if (initializer != null) {
if (initializer instanceof AStatement) {
initializer = ((AStatement)initializer).analyze(variables);
((AStatement)initializer).analyze(variables);
} else if (initializer instanceof AExpression) {
AExpression initializer = (AExpression)this.initializer;
@ -103,7 +103,7 @@ public final class SFor extends AStatement {
block.beginLoop = true;
block.inLoop = true;
block = block.analyze(variables);
block.analyze(variables);
if (block.loopEscape && !block.anyContinue) {
throw createError(new IllegalArgumentException("Extraneous for loop."));
@ -124,8 +124,6 @@ public final class SFor extends AStatement {
}
variables.decrementScope();
return this;
}
@Override

View File

@ -31,7 +31,7 @@ import org.elasticsearch.painless.MethodWriter;
public final class SIf extends AStatement {
AExpression condition;
AStatement ifblock;
final SBlock ifblock;
public SIf(Location location, AExpression condition, SBlock ifblock) {
super(location);
@ -41,7 +41,7 @@ public final class SIf extends AStatement {
}
@Override
AStatement analyze(Variables variables) {
void analyze(Variables variables) {
condition.expected = Definition.BOOLEAN_TYPE;
condition.analyze(variables);
condition = condition.cast(variables);
@ -59,14 +59,12 @@ public final class SIf extends AStatement {
ifblock.lastLoop = lastLoop;
variables.incrementScope();
ifblock = ifblock.analyze(variables);
ifblock.analyze(variables);
variables.decrementScope();
anyContinue = ifblock.anyContinue;
anyBreak = ifblock.anyBreak;
statementCount = ifblock.statementCount;
return this;
}
@Override

View File

@ -31,8 +31,8 @@ import org.elasticsearch.painless.MethodWriter;
public final class SIfElse extends AStatement {
AExpression condition;
AStatement ifblock;
AStatement elseblock;
final SBlock ifblock;
final SBlock elseblock;
public SIfElse(Location location, AExpression condition, SBlock ifblock, SBlock elseblock) {
super(location);
@ -43,7 +43,7 @@ public final class SIfElse extends AStatement {
}
@Override
AStatement analyze(Variables variables) {
void analyze(Variables variables) {
condition.expected = Definition.BOOLEAN_TYPE;
condition.analyze(variables);
condition = condition.cast(variables);
@ -61,7 +61,7 @@ public final class SIfElse extends AStatement {
ifblock.lastLoop = lastLoop;
variables.incrementScope();
ifblock = ifblock.analyze(variables);
ifblock.analyze(variables);
variables.decrementScope();
anyContinue = ifblock.anyContinue;
@ -77,7 +77,7 @@ public final class SIfElse extends AStatement {
elseblock.lastLoop = lastLoop;
variables.incrementScope();
elseblock = elseblock.analyze(variables);
elseblock.analyze(variables);
variables.decrementScope();
methodEscape = ifblock.methodEscape && elseblock.methodEscape;
@ -86,8 +86,6 @@ public final class SIfElse extends AStatement {
anyContinue |= elseblock.anyContinue;
anyBreak |= elseblock.anyBreak;
statementCount = Math.max(ifblock.statementCount, elseblock.statementCount);
return this;
}
@Override

View File

@ -38,7 +38,7 @@ public final class SReturn extends AStatement {
}
@Override
AStatement analyze(Variables variables) {
void analyze(Variables variables) {
expression.expected = Definition.OBJECT_TYPE;
expression.internal = true;
expression.analyze(variables);
@ -49,8 +49,6 @@ public final class SReturn extends AStatement {
allEscape = true;
statementCount = 1;
return this;
}
@Override

View File

@ -24,6 +24,7 @@ import org.objectweb.asm.Opcodes;
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.MethodWriter;
import java.util.Collections;
import java.util.List;
/**
@ -36,36 +37,35 @@ public final class SSource extends AStatement {
public SSource(Location location, List<AStatement> statements) {
super(location);
this.statements = statements;
this.statements = Collections.unmodifiableList(statements);
}
@Override
public AStatement analyze(Variables variables) {
public void analyze(Variables variables) {
if (statements == null || statements.isEmpty()) {
throw createError(new IllegalArgumentException("Cannot generate an empty script."));
}
variables.incrementScope();
for (int index = 0; index < statements.size(); ++index) {
AStatement statement = statements.get(index);
AStatement last = statements.get(statements.size() - 1);
for (AStatement statement : statements) {
// Note that we do not need to check after the last statement because
// there is no statement that can be unreachable after the last.
if (allEscape) {
throw createError(new IllegalArgumentException("Unreachable statement."));
}
statement.lastSource = index == statements.size() - 1;
statements.set(index, statement.analyze(variables));
statement.lastSource = statement == last;
statement.analyze(variables);
methodEscape = statement.methodEscape;
allEscape = statement.allEscape;
}
variables.decrementScope();
return this;
}
@Override

View File

@ -38,7 +38,7 @@ public final class SThrow extends AStatement {
}
@Override
AStatement analyze(Variables variables) {
void analyze(Variables variables) {
expression.expected = Definition.EXCEPTION_TYPE;
expression.analyze(variables);
expression = expression.cast(variables);
@ -47,8 +47,6 @@ public final class SThrow extends AStatement {
loopEscape = true;
allEscape = true;
statementCount = 1;
return this;
}
@Override

View File

@ -24,6 +24,7 @@ import org.objectweb.asm.Label;
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.MethodWriter;
import java.util.Collections;
import java.util.List;
/**
@ -31,18 +32,18 @@ import java.util.List;
*/
public final class STry extends AStatement {
AStatement block;
final SBlock block;
final List<SCatch> catches;
public STry(Location location, SBlock block, List<SCatch> catches) {
super(location);
this.block = block;
this.catches = catches;
this.catches = Collections.unmodifiableList(catches);
}
@Override
AStatement analyze(Variables variables) {
void analyze(Variables variables) {
if (block == null) {
throw createError(new IllegalArgumentException("Extraneous try statement."));
}
@ -52,7 +53,7 @@ public final class STry extends AStatement {
block.lastLoop = lastLoop;
variables.incrementScope();
block = block.analyze(variables);
block.analyze(variables);
variables.decrementScope();
methodEscape = block.methodEscape;
@ -63,15 +64,13 @@ public final class STry extends AStatement {
int statementCount = 0;
for (int index = 0; index < catches.size(); ++index) {
SCatch catc = catches.get(index);
for (SCatch catc : catches) {
catc.lastSource = lastSource;
catc.inLoop = inLoop;
catc.lastLoop = lastLoop;
variables.incrementScope();
catches.set(index, (SCatch)catc.analyze(variables));
catc.analyze(variables);
variables.decrementScope();
methodEscape &= catc.methodEscape;
@ -84,8 +83,6 @@ public final class STry extends AStatement {
}
this.statementCount = block.statementCount + statementCount;
return this;
}
@Override

View File

@ -32,7 +32,7 @@ public final class SWhile extends AStatement {
final int maxLoopCounter;
AExpression condition;
AStatement block;
final SBlock block;
public SWhile(Location location, int maxLoopCounter, AExpression condition, SBlock block) {
super(location);
@ -43,7 +43,7 @@ public final class SWhile extends AStatement {
}
@Override
AStatement analyze(Variables variables) {
void analyze(Variables variables) {
variables.incrementScope();
condition.expected = Definition.BOOLEAN_TYPE;
@ -68,7 +68,7 @@ public final class SWhile extends AStatement {
block.beginLoop = true;
block.inLoop = true;
block = block.analyze(variables);
block.analyze(variables);
if (block.loopEscape && !block.anyContinue) {
throw createError(new IllegalArgumentException("Extraneous while loop."));
@ -89,8 +89,6 @@ public final class SWhile extends AStatement {
}
variables.decrementScope();
return this;
}
@Override

View File

@ -63,7 +63,6 @@
* {@link org.elasticsearch.painless.node.LStatic} - Represents a static type target.
* {@link org.elasticsearch.painless.node.LString} - Represents a string constant.
* {@link org.elasticsearch.painless.node.LVariable} - Represents a variable load/store.
* {@link org.elasticsearch.painless.node.SArrayEach} - Represents a for each loop shortcut for arrays. (Internal only.)
* {@link org.elasticsearch.painless.node.SBlock} - Represents a set of statements as a branch of control-flow.
* {@link org.elasticsearch.painless.node.SBreak} - Represents a break statement.
* {@link org.elasticsearch.painless.node.SCatch} - Represents a catch block as part of a try-catch block.
@ -92,8 +91,7 @@
* <p>
* Generally, statement nodes have member data that evaluate legal control-flow during the analysis phase.
* The typical order for statement nodes is for each node to call analyze on it's children during the analysis phase
* and write on it's children during the writing phase. Upon analysis completion, a statement will return either
* itself or another statement node depending on if a shortcut or def type was found.
* and write on it's children during the writing phase.
* <p>
* Generally, expression nodes have member data that evaluate static types. The typical order for an expression node
* during the analysis phase looks like the following: