add array ctor refs

This commit is contained in:
Robert Muir 2016-06-12 12:53:37 -04:00
parent 5be9211761
commit faee2323ab
7 changed files with 61 additions and 9 deletions

View File

@ -209,7 +209,7 @@ classFuncref
// reference to a constructor, e.g. ArrayList::new // reference to a constructor, e.g. ArrayList::new
// currently limited to simple non-array types // currently limited to simple non-array types
constructorFuncref constructorFuncref
: TYPE REF NEW : decltype REF NEW
; ;
// reference to an instance method, e.g. object::toString // reference to an instance method, e.g. object::toString

View File

@ -2969,7 +2969,9 @@ class PainlessParser extends Parser {
} }
public static class ConstructorFuncrefContext extends ParserRuleContext { public static class ConstructorFuncrefContext extends ParserRuleContext {
public TerminalNode TYPE() { return getToken(PainlessParser.TYPE, 0); } public DecltypeContext decltype() {
return getRuleContext(DecltypeContext.class,0);
}
public TerminalNode REF() { return getToken(PainlessParser.REF, 0); } public TerminalNode REF() { return getToken(PainlessParser.REF, 0); }
public TerminalNode NEW() { return getToken(PainlessParser.NEW, 0); } public TerminalNode NEW() { return getToken(PainlessParser.NEW, 0); }
public ConstructorFuncrefContext(ParserRuleContext parent, int invokingState) { public ConstructorFuncrefContext(ParserRuleContext parent, int invokingState) {
@ -2990,7 +2992,7 @@ class PainlessParser extends Parser {
enterOuterAlt(_localctx, 1); enterOuterAlt(_localctx, 1);
{ {
setState(460); setState(460);
match(TYPE); decltype();
setState(461); setState(461);
match(REF); match(REF);
setState(462); setState(462);
@ -3350,7 +3352,7 @@ class PainlessParser extends Parser {
"\u01c4\u01c9\5\66\34\2\u01c5\u01c9\58\35\2\u01c6\u01c9\5:\36\2\u01c7\u01c9"+ "\u01c4\u01c9\5\66\34\2\u01c5\u01c9\58\35\2\u01c6\u01c9\5:\36\2\u01c7\u01c9"+
"\5<\37\2\u01c8\u01c4\3\2\2\2\u01c8\u01c5\3\2\2\2\u01c8\u01c6\3\2\2\2\u01c8"+ "\5<\37\2\u01c8\u01c4\3\2\2\2\u01c8\u01c5\3\2\2\2\u01c8\u01c6\3\2\2\2\u01c8"+
"\u01c7\3\2\2\2\u01c9\65\3\2\2\2\u01ca\u01cb\7L\2\2\u01cb\u01cc\7\64\2"+ "\u01c7\3\2\2\2\u01c9\65\3\2\2\2\u01ca\u01cb\7L\2\2\u01cb\u01cc\7\64\2"+
"\2\u01cc\u01cd\7M\2\2\u01cd\67\3\2\2\2\u01ce\u01cf\7L\2\2\u01cf\u01d0"+ "\2\u01cc\u01cd\7M\2\2\u01cd\67\3\2\2\2\u01ce\u01cf\5\26\f\2\u01cf\u01d0"+
"\7\64\2\2\u01d0\u01d1\7\26\2\2\u01d19\3\2\2\2\u01d2\u01d3\7M\2\2\u01d3"+ "\7\64\2\2\u01d0\u01d1\7\26\2\2\u01d19\3\2\2\2\u01d2\u01d3\7M\2\2\u01d3"+
"\u01d4\7\64\2\2\u01d4\u01d5\7M\2\2\u01d5;\3\2\2\2\u01d6\u01d7\7\32\2\2"+ "\u01d4\7\64\2\2\u01d4\u01d5\7M\2\2\u01d5;\3\2\2\2\u01d6\u01d7\7\32\2\2"+
"\u01d7\u01d8\7\64\2\2\u01d8\u01d9\7M\2\2\u01d9=\3\2\2\2*AGZ]iq~\u0082"+ "\u01d7\u01d8\7\64\2\2\u01d8\u01d9\7M\2\2\u01d9=\3\2\2\2*AGZ]iq~\u0082"+

View File

@ -148,6 +148,7 @@ import org.elasticsearch.painless.node.SWhile;
import java.util.ArrayDeque; import java.util.ArrayDeque;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.Deque; import java.util.Deque;
import java.util.List; import java.util.List;
@ -166,6 +167,7 @@ public final class Walker extends PainlessParserBaseVisitor<Object> {
private final String sourceText; private final String sourceText;
private final Deque<Reserved> reserved = new ArrayDeque<>(); private final Deque<Reserved> reserved = new ArrayDeque<>();
private final List<SFunction> synthetic = new ArrayList<>();
private Walker(String sourceName, String sourceText, CompilerSettings settings) { private Walker(String sourceName, String sourceText, CompilerSettings settings) {
this.settings = settings; this.settings = settings;
@ -230,6 +232,8 @@ public final class Walker extends PainlessParserBaseVisitor<Object> {
statements.add((AStatement)visit(statement)); statements.add((AStatement)visit(statement));
} }
functions.addAll(synthetic);
return new SSource(sourceName, sourceText, (ExecuteReserved)reserved.pop(), location(ctx), functions, statements); return new SSource(sourceName, sourceText, (ExecuteReserved)reserved.pop(), location(ctx), functions, statements);
} }
@ -255,7 +259,7 @@ public final class Walker extends PainlessParserBaseVisitor<Object> {
statements.add((AStatement)visit(statement)); statements.add((AStatement)visit(statement));
} }
return new SFunction((FunctionReserved)reserved.pop(), location(ctx), rtnType, name, paramTypes, paramNames, statements); return new SFunction((FunctionReserved)reserved.pop(), location(ctx), rtnType, name, paramTypes, paramNames, statements, false);
} }
@Override @Override
@ -974,7 +978,22 @@ public final class Walker extends PainlessParserBaseVisitor<Object> {
@Override @Override
public Object visitConstructorFuncref(ConstructorFuncrefContext ctx) { public Object visitConstructorFuncref(ConstructorFuncrefContext ctx) {
return new EFunctionRef(location(ctx), ctx.TYPE().getText(), ctx.NEW().getText()); if (!ctx.decltype().LBRACE().isEmpty()) {
// array constructors are special: we need to make a synthetic method
// taking integer as argument and returning a new instance, and return a ref to that.
Location location = location(ctx);
String arrayType = ctx.decltype().getText();
SReturn code = new SReturn(location,
new EChain(location,
new LNewArray(location, arrayType, Arrays.asList(
new EChain(location,
new LVariable(location, "size"))))));
String name = "lambda$" + synthetic.size();
synthetic.add(new SFunction(new FunctionReserved(), location, arrayType, name,
Arrays.asList("int"), Arrays.asList("size"), Arrays.asList(code), true));
return new EFunctionRef(location(ctx), "this", name);
}
return new EFunctionRef(location(ctx), ctx.decltype().getText(), ctx.NEW().getText());
} }
@Override @Override

View File

@ -29,6 +29,7 @@ import org.elasticsearch.painless.Operation;
import org.elasticsearch.painless.Locals; import org.elasticsearch.painless.Locals;
import org.elasticsearch.painless.MethodWriter; import org.elasticsearch.painless.MethodWriter;
import java.util.Arrays;
import java.util.List; import java.util.List;
/** /**
@ -47,6 +48,11 @@ public final class EChain extends AExpression {
Cast there = null; Cast there = null;
Cast back = null; Cast back = null;
/** Creates a new simple EChain */
public EChain(Location location, ALink link) {
this(location, Arrays.asList(link), false, false, null, null);
}
public EChain(Location location, List<ALink> links, public EChain(Location location, List<ALink> links,
boolean pre, boolean post, Operation operation, AExpression expression) { boolean pre, boolean post, Operation operation, AExpression expression) {
super(location); super(location);

View File

@ -50,6 +50,7 @@ public class SFunction extends AStatement {
final List<String> paramTypeStrs; final List<String> paramTypeStrs;
final List<String> paramNameStrs; final List<String> paramNameStrs;
final List<AStatement> statements; final List<AStatement> statements;
final boolean synthetic;
Type rtnType = null; Type rtnType = null;
List<Parameter> parameters = new ArrayList<>(); List<Parameter> parameters = new ArrayList<>();
@ -58,7 +59,8 @@ public class SFunction extends AStatement {
Locals locals = null; Locals locals = null;
public SFunction(FunctionReserved reserved, Location location, public SFunction(FunctionReserved reserved, Location location,
String rtnType, String name, List<String> paramTypes, List<String> paramNames, List<AStatement> statements) { String rtnType, String name, List<String> paramTypes,
List<String> paramNames, List<AStatement> statements, boolean synthetic) {
super(location); super(location);
this.reserved = reserved; this.reserved = reserved;
@ -67,6 +69,7 @@ public class SFunction extends AStatement {
this.paramTypeStrs = Collections.unmodifiableList(paramTypes); this.paramTypeStrs = Collections.unmodifiableList(paramTypes);
this.paramNameStrs = Collections.unmodifiableList(paramNames); this.paramNameStrs = Collections.unmodifiableList(paramNames);
this.statements = Collections.unmodifiableList(statements); this.statements = Collections.unmodifiableList(statements);
this.synthetic = synthetic;
} }
void generate() { void generate() {
@ -138,7 +141,11 @@ public class SFunction extends AStatement {
/** Writes the function to given ClassWriter. */ /** Writes the function to given ClassWriter. */
void write (ClassWriter writer, BitSet statements) { void write (ClassWriter writer, BitSet statements) {
final MethodWriter function = new MethodWriter(Opcodes.ACC_PRIVATE | Opcodes.ACC_STATIC, method.method, writer, statements); int access = Opcodes.ACC_PRIVATE | Opcodes.ACC_STATIC;
if (synthetic) {
access |= Opcodes.ACC_SYNTHETIC;
}
final MethodWriter function = new MethodWriter(access, method.method, writer, statements);
write(function); write(function);
function.endMethod(); function.endMethod();
} }

View File

@ -70,6 +70,10 @@ public class ArrayTests extends ScriptTestCase {
assertEquals(1, exec("int x; def y = new def[1]; x = y[0] = 1; return x;")); assertEquals(1, exec("int x; def y = new def[1]; x = y[0] = 1; return x;"));
} }
public void testArrayVariable() {
assertEquals(1, exec("int x = 1; int[] y = new int[x]; return y.length"));
}
public void testForLoop() { public void testForLoop() {
assertEquals(999*1000/2, exec("def a = new int[1000]; for (int x = 0; x < a.length; x++) { a[x] = x; } "+ assertEquals(999*1000/2, exec("def a = new int[1000]; for (int x = 0; x < a.length; x++) { a[x] = x; } "+
"int total = 0; for (int x = 0; x < a.length; x++) { total += a[x]; } return total;")); "int total = 0; for (int x = 0; x < a.length; x++) { total += a[x]; } return total;"));

View File

@ -57,6 +57,20 @@ public class FunctionRefTests extends ScriptTestCase {
"return stats.getSum()")); "return stats.getSum()"));
} }
public void testArrayCtorMethodRef() {
assertEquals(1.0D,
exec("List l = new ArrayList(); l.add(1.0); l.add(2.0); " +
"def[] array = l.stream().toArray(Double[]::new);" +
"return array[0];"));
}
public void testArrayCtorMethodRefDef() {
assertEquals(1.0D,
exec("def l = new ArrayList(); l.add(1.0); l.add(2.0); " +
"def[] array = l.stream().toArray(Double[]::new);" +
"return array[0];"));
}
public void testCapturingMethodReference() { public void testCapturingMethodReference() {
assertEquals("5", exec("Integer x = Integer.valueOf(5); return Optional.empty().orElseGet(x::toString);")); assertEquals("5", exec("Integer x = Integer.valueOf(5); return Optional.empty().orElseGet(x::toString);"));
assertEquals("[]", exec("List l = new ArrayList(); return Optional.empty().orElseGet(l::toString);")); assertEquals("[]", exec("List l = new ArrayList(); return Optional.empty().orElseGet(l::toString);"));