Cleaned up SEach node.
This commit is contained in:
parent
231268c89d
commit
b3804c47f7
|
@ -30,6 +30,7 @@ import java.lang.invoke.CallSite;
|
||||||
import java.lang.invoke.MethodHandles;
|
import java.lang.invoke.MethodHandles;
|
||||||
import java.lang.invoke.MethodType;
|
import java.lang.invoke.MethodType;
|
||||||
import java.util.BitSet;
|
import java.util.BitSet;
|
||||||
|
import java.util.Iterator;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -56,6 +57,10 @@ public final class WriterConstants {
|
||||||
public final static Type MAP_TYPE = Type.getType(Map.class);
|
public final static Type MAP_TYPE = Type.getType(Map.class);
|
||||||
public final static Method MAP_GET = getAsmMethod(Object.class, "get", Object.class);
|
public final static Method MAP_GET = getAsmMethod(Object.class, "get", Object.class);
|
||||||
|
|
||||||
|
public final static Type ITERATOR_TYPE = Type.getType(Iterator.class);
|
||||||
|
public final static Method ITERATOR_HASNEXT = getAsmMethod(boolean.class, "hasNext");
|
||||||
|
public final static Method ITERATOR_NEXT = getAsmMethod(Object.class, "next");
|
||||||
|
|
||||||
public final static Type UTILITY_TYPE = Type.getType(Utility.class);
|
public final static Type UTILITY_TYPE = Type.getType(Utility.class);
|
||||||
public final static Method STRING_TO_CHAR = getAsmMethod(char.class, "StringTochar", String.class);
|
public final static Method STRING_TO_CHAR = getAsmMethod(char.class, "StringTochar", String.class);
|
||||||
public final static Method CHAR_TO_STRING = getAsmMethod(String.class, "charToString", char.class);
|
public final static Method CHAR_TO_STRING = getAsmMethod(String.class, "charToString", char.class);
|
||||||
|
|
|
@ -35,6 +35,9 @@ import org.objectweb.asm.Label;
|
||||||
import org.objectweb.asm.Opcodes;
|
import org.objectweb.asm.Opcodes;
|
||||||
|
|
||||||
import static org.elasticsearch.painless.WriterConstants.DEF_BOOTSTRAP_HANDLE;
|
import static org.elasticsearch.painless.WriterConstants.DEF_BOOTSTRAP_HANDLE;
|
||||||
|
import static org.elasticsearch.painless.WriterConstants.ITERATOR_HASNEXT;
|
||||||
|
import static org.elasticsearch.painless.WriterConstants.ITERATOR_NEXT;
|
||||||
|
import static org.elasticsearch.painless.WriterConstants.ITERATOR_TYPE;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a for-each loop shortcut for iterables. Defers to other S-nodes for non-iterable types.
|
* Represents a for-each loop shortcut for iterables. Defers to other S-nodes for non-iterable types.
|
||||||
|
@ -59,8 +62,6 @@ public class SEach extends AStatement {
|
||||||
// Members for the iterable case.
|
// Members for the iterable case.
|
||||||
Variable iterator = null;
|
Variable iterator = null;
|
||||||
Method method = null;
|
Method method = null;
|
||||||
Method hasNext = null;
|
|
||||||
Method next = null;
|
|
||||||
|
|
||||||
public SEach(Location location, int maxLoopCounter, String type, String name, AExpression expression, SBlock block) {
|
public SEach(Location location, int maxLoopCounter, String type, String name, AExpression expression, SBlock block) {
|
||||||
super(location);
|
super(location);
|
||||||
|
@ -78,16 +79,6 @@ public class SEach extends AStatement {
|
||||||
expression.expected = expression.actual;
|
expression.expected = expression.actual;
|
||||||
expression = expression.cast(variables);
|
expression = expression.cast(variables);
|
||||||
|
|
||||||
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;
|
final Type type;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -99,10 +90,14 @@ public class SEach extends AStatement {
|
||||||
variables.incrementScope();
|
variables.incrementScope();
|
||||||
|
|
||||||
variable = variables.addVariable(location, type, name, true, false);
|
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);
|
if (expression.actual.sort == Sort.ARRAY) {
|
||||||
indexed = Definition.getType(expression.actual.struct, expression.actual.dimensions - 1);
|
analyzeArray(variables, type);
|
||||||
cast = AnalyzerCaster.getLegalCast(location, indexed, type, true, true);
|
} else if (expression.actual.sort == Sort.DEF || Iterable.class.isAssignableFrom(expression.actual.clazz)) {
|
||||||
|
analyzeIterable(variables, type);
|
||||||
|
} else {
|
||||||
|
throw location.createError(new IllegalArgumentException("Illegal for each type [" + expression.actual.name + "]."));
|
||||||
|
}
|
||||||
|
|
||||||
if (block == null) {
|
if (block == null) {
|
||||||
throw location.createError(new IllegalArgumentException("Extraneous for each loop."));
|
throw location.createError(new IllegalArgumentException("Extraneous for each loop."));
|
||||||
|
@ -126,24 +121,19 @@ public class SEach extends AStatement {
|
||||||
variables.decrementScope();
|
variables.decrementScope();
|
||||||
}
|
}
|
||||||
|
|
||||||
void analyzeIterable(Variables variables) {
|
void analyzeArray(Variables variables, Type type) {
|
||||||
final Type type;
|
// 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.
|
||||||
try {
|
array = variables.addVariable(location, expression.actual, "#array" + location.getOffset(), true, false);
|
||||||
type = Definition.getType(this.type);
|
index = variables.addVariable(location, Definition.INT_TYPE, "#index" + location.getOffset(), true, false);
|
||||||
} catch (IllegalArgumentException exception) {
|
indexed = Definition.getType(expression.actual.struct, expression.actual.dimensions - 1);
|
||||||
throw createError(new IllegalArgumentException("Not a type [" + this.type + "]."));
|
cast = AnalyzerCaster.getLegalCast(location, indexed, type, true, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
variables.incrementScope();
|
|
||||||
|
|
||||||
Type itr = Definition.getType("Iterator");
|
|
||||||
|
|
||||||
variable = variables.addVariable(location, type, name, true, false);
|
|
||||||
|
|
||||||
|
void analyzeIterable(Variables variables, Type type) {
|
||||||
// We must store the iterator as a variable for securing a slot on the stack, and
|
// 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.
|
// 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);
|
iterator = variables.addVariable(location, Definition.getType("Iterator"), "#itr" + location.getOffset(), true, false);
|
||||||
|
|
||||||
if (expression.actual.sort == Sort.DEF) {
|
if (expression.actual.sort == Sort.DEF) {
|
||||||
method = null;
|
method = null;
|
||||||
|
@ -156,48 +146,13 @@ public class SEach extends AStatement {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
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
|
@Override
|
||||||
void write(MethodWriter writer) {
|
void write(MethodWriter writer) {
|
||||||
|
writer.writeStatementOffset(location);
|
||||||
|
|
||||||
if (array != null) {
|
if (array != null) {
|
||||||
writeArray(writer);
|
writeArray(writer);
|
||||||
} else if (iterator != null) {
|
} else if (iterator != null) {
|
||||||
|
@ -208,8 +163,6 @@ public class SEach extends AStatement {
|
||||||
}
|
}
|
||||||
|
|
||||||
void writeArray(MethodWriter writer) {
|
void writeArray(MethodWriter writer) {
|
||||||
writer.writeStatementOffset(location);
|
|
||||||
|
|
||||||
expression.write(writer);
|
expression.write(writer);
|
||||||
writer.visitVarInsn(array.type.type.getOpcode(Opcodes.ISTORE), array.slot);
|
writer.visitVarInsn(array.type.type.getOpcode(Opcodes.ISTORE), array.slot);
|
||||||
writer.push(-1);
|
writer.push(-1);
|
||||||
|
@ -239,8 +192,6 @@ public class SEach extends AStatement {
|
||||||
}
|
}
|
||||||
|
|
||||||
void writeIterable(MethodWriter writer) {
|
void writeIterable(MethodWriter writer) {
|
||||||
writer.writeStatementOffset(location);
|
|
||||||
|
|
||||||
expression.write(writer);
|
expression.write(writer);
|
||||||
|
|
||||||
if (method == null) {
|
if (method == null) {
|
||||||
|
@ -261,11 +212,11 @@ public class SEach extends AStatement {
|
||||||
writer.mark(begin);
|
writer.mark(begin);
|
||||||
|
|
||||||
writer.visitVarInsn(iterator.type.type.getOpcode(Opcodes.ILOAD), iterator.slot);
|
writer.visitVarInsn(iterator.type.type.getOpcode(Opcodes.ILOAD), iterator.slot);
|
||||||
writer.invokeInterface(hasNext.owner.type, hasNext.method);
|
writer.invokeInterface(ITERATOR_TYPE, ITERATOR_HASNEXT);
|
||||||
writer.ifZCmp(MethodWriter.EQ, end);
|
writer.ifZCmp(MethodWriter.EQ, end);
|
||||||
|
|
||||||
writer.visitVarInsn(iterator.type.type.getOpcode(Opcodes.ILOAD), iterator.slot);
|
writer.visitVarInsn(iterator.type.type.getOpcode(Opcodes.ILOAD), iterator.slot);
|
||||||
writer.invokeInterface(next.owner.type, next.method);
|
writer.invokeInterface(ITERATOR_TYPE, ITERATOR_NEXT);
|
||||||
writer.writeCast(cast);
|
writer.writeCast(cast);
|
||||||
writer.visitVarInsn(variable.type.type.getOpcode(Opcodes.ISTORE), variable.slot);
|
writer.visitVarInsn(variable.type.type.getOpcode(Opcodes.ISTORE), variable.slot);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue