Implementation of iterable.
This commit is contained in:
parent
260b0fd40f
commit
b2e648dfde
|
@ -263,11 +263,9 @@ public final class Walker extends PainlessParserBaseVisitor<Object> {
|
||||||
if (ctx.trailer() != null) {
|
if (ctx.trailer() != null) {
|
||||||
SBlock block = (SBlock)visit(ctx.trailer());
|
SBlock block = (SBlock)visit(ctx.trailer());
|
||||||
|
|
||||||
return new SFor(location(ctx),
|
return new SFor(location(ctx), settings.getMaxLoopCounter(), initializer, expression, afterthought, block);
|
||||||
settings.getMaxLoopCounter(), initializer, expression, afterthought, block);
|
|
||||||
} else if (ctx.empty() != null) {
|
} else if (ctx.empty() != null) {
|
||||||
return new SFor(location(ctx),
|
return new SFor(location(ctx), settings.getMaxLoopCounter(), initializer, expression, afterthought, null);
|
||||||
settings.getMaxLoopCounter(), initializer, expression, afterthought, null);
|
|
||||||
} else {
|
} else {
|
||||||
throw location(ctx).createError(new IllegalStateException("Illegal tree structure."));
|
throw location(ctx).createError(new IllegalStateException("Illegal tree structure."));
|
||||||
}
|
}
|
||||||
|
@ -275,12 +273,16 @@ public final class Walker extends PainlessParserBaseVisitor<Object> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object visitEach(EachContext ctx) {
|
public Object visitEach(EachContext ctx) {
|
||||||
|
if (settings.getMaxLoopCounter() > 0) {
|
||||||
|
reserved.usesLoop();
|
||||||
|
}
|
||||||
|
|
||||||
String type = ctx.decltype().getText();
|
String type = ctx.decltype().getText();
|
||||||
String name = ctx.ID().getText();
|
String name = ctx.ID().getText();
|
||||||
AExpression expression = (AExpression)visit(ctx.expression());
|
AExpression expression = (AExpression)visit(ctx.expression());
|
||||||
SBlock block = (SBlock)visit(ctx.trailer());
|
SBlock block = (SBlock)visit(ctx.trailer());
|
||||||
|
|
||||||
return new SEach(location(ctx), type, name, expression, block);
|
return new SEach(location(ctx), settings.getMaxLoopCounter(), type, name, expression, block);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -47,7 +47,7 @@ public final class LBrace extends ALink {
|
||||||
throw createError(new IllegalArgumentException("Illegal array access made without target."));
|
throw createError(new IllegalArgumentException("Illegal array access made without target."));
|
||||||
}
|
}
|
||||||
|
|
||||||
final Sort sort = before.sort;
|
Sort sort = before.sort;
|
||||||
|
|
||||||
if (sort == Sort.ARRAY) {
|
if (sort == Sort.ARRAY) {
|
||||||
index.expected = Definition.INT_TYPE;
|
index.expected = Definition.INT_TYPE;
|
||||||
|
|
|
@ -19,19 +19,40 @@
|
||||||
|
|
||||||
package org.elasticsearch.painless.node;
|
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.Method;
|
||||||
|
import org.elasticsearch.painless.Definition.MethodKey;
|
||||||
|
import org.elasticsearch.painless.Definition.Sort;
|
||||||
|
import org.elasticsearch.painless.Definition.Type;
|
||||||
import org.elasticsearch.painless.Location;
|
import org.elasticsearch.painless.Location;
|
||||||
import org.elasticsearch.painless.MethodWriter;
|
import org.elasticsearch.painless.MethodWriter;
|
||||||
import org.elasticsearch.painless.Variables;
|
import org.elasticsearch.painless.Variables;
|
||||||
|
import org.elasticsearch.painless.Variables.Variable;
|
||||||
|
import org.objectweb.asm.Label;
|
||||||
|
import org.objectweb.asm.Opcodes;
|
||||||
|
|
||||||
public class SEach extends AStatement {
|
public class SEach extends AStatement {
|
||||||
|
|
||||||
|
final int maxLoopCounter;
|
||||||
final String type;
|
final String type;
|
||||||
final String name;
|
final String name;
|
||||||
AExpression expression;
|
AExpression expression;
|
||||||
AStatement block;
|
AStatement block;
|
||||||
|
|
||||||
public SEach(final Location location, final String type, final String name, final AExpression expression, final SBlock block) {
|
Variable variable = null;
|
||||||
|
Variable iterator = null;
|
||||||
|
Method method = null;
|
||||||
|
Method hasNext = null;
|
||||||
|
Method next = null;
|
||||||
|
Cast cast = null;
|
||||||
|
|
||||||
|
public SEach(final Location location, final int maxLoopCounter,
|
||||||
|
final String type, final String name, final AExpression expression, final SBlock block) {
|
||||||
super(location);
|
super(location);
|
||||||
|
|
||||||
|
this.maxLoopCounter = maxLoopCounter;
|
||||||
this.type = type;
|
this.type = type;
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.expression = expression;
|
this.expression = expression;
|
||||||
|
@ -41,11 +62,107 @@ public class SEach extends AStatement {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
AStatement analyze(Variables variables) {
|
AStatement analyze(Variables variables) {
|
||||||
return null;
|
expression.analyze(variables);
|
||||||
|
expression.expected = expression.actual;
|
||||||
|
expression = expression.cast(variables);
|
||||||
|
|
||||||
|
Sort sort = expression.actual.sort;
|
||||||
|
|
||||||
|
if (sort == Sort.ARRAY) {
|
||||||
|
throw location.createError(new UnsupportedOperationException("Cannot execute for each against array type."));
|
||||||
|
} else if (sort == Sort.DEF) {
|
||||||
|
throw location.createError(new UnsupportedOperationException("Cannot execute for each against def type."));
|
||||||
|
} else if (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, false, false);
|
||||||
|
iterator = variables.addVariable(location, itr, "#itr" + location.getOffset(), true, false);
|
||||||
|
|
||||||
|
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.OBJECT) {
|
||||||
|
throw location.createError(new IllegalArgumentException("Method [next] does not return type [Object]."));
|
||||||
|
}
|
||||||
|
|
||||||
|
cast = AnalyzerCaster.getLegalCast(location, Definition.getType("Object"), type, true, true);
|
||||||
|
|
||||||
|
if (block == null) {
|
||||||
|
throw location.createError(new IllegalArgumentException("Extraneous for each loop."));
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
} else {
|
||||||
|
throw location.createError(new IllegalArgumentException("Illegal for each type [" + expression.actual.name + "]."));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
void write(MethodWriter writer) {
|
void write(MethodWriter writer) {
|
||||||
|
expression.write(writer);
|
||||||
|
|
||||||
|
if (java.lang.reflect.Modifier.isInterface(method.owner.clazz.getModifiers())) {
|
||||||
|
writer.invokeInterface(method.owner.type, method.method);
|
||||||
|
} else {
|
||||||
|
writer.invokeVirtual(method.owner.type, method.method);
|
||||||
|
}
|
||||||
|
|
||||||
|
writer.visitVarInsn(iterator.type.type.getOpcode(Opcodes.ISTORE), iterator.slot);
|
||||||
|
|
||||||
|
Label end = new Label();
|
||||||
|
|
||||||
|
writer.visitVarInsn(iterator.type.type.getOpcode(Opcodes.ILOAD), iterator.slot);
|
||||||
|
writer.invokeInterface(hasNext.owner.type, hasNext.method);
|
||||||
|
writer.ifZCmp(MethodWriter.EQ, end);
|
||||||
|
|
||||||
|
writer.visitVarInsn(iterator.type.type.getOpcode(Opcodes.ILOAD), iterator.slot);
|
||||||
|
writer.invokeInterface(next.owner.type, next.method);
|
||||||
|
writer.writeCast(cast);
|
||||||
|
writer.visitVarInsn(variable.type.type.getOpcode(Opcodes.ISTORE), variable.slot);
|
||||||
|
|
||||||
|
block.write(writer);
|
||||||
|
|
||||||
|
writer.mark(end);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,11 +40,11 @@ public final class SFor extends AStatement {
|
||||||
ANode initializer, AExpression condition, AExpression afterthought, SBlock block) {
|
ANode initializer, AExpression condition, AExpression afterthought, SBlock block) {
|
||||||
super(location);
|
super(location);
|
||||||
|
|
||||||
|
this.maxLoopCounter = maxLoopCounter;
|
||||||
this.initializer = initializer;
|
this.initializer = initializer;
|
||||||
this.condition = condition;
|
this.condition = condition;
|
||||||
this.afterthought = afterthought;
|
this.afterthought = afterthought;
|
||||||
this.block = block;
|
this.block = block;
|
||||||
this.maxLoopCounter = maxLoopCounter;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -125,6 +125,11 @@ public class BasicStatementTests extends ScriptTestCase {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testEachStatement() {
|
||||||
|
assertEquals(6, exec("List l = new ArrayList(); l.add(1); l.add(2); l.add(3); int total = 0;" +
|
||||||
|
" for (int x : l) total += x; return x"));
|
||||||
|
}
|
||||||
|
|
||||||
public void testDeclarationStatement() {
|
public void testDeclarationStatement() {
|
||||||
assertEquals((byte)2, exec("byte a = 2; return a;"));
|
assertEquals((byte)2, exec("byte a = 2; return a;"));
|
||||||
assertEquals((short)2, exec("short a = 2; return a;"));
|
assertEquals((short)2, exec("short a = 2; return a;"));
|
||||||
|
|
Loading…
Reference in New Issue