diff --git a/modules/lang-painless/src/main/antlr/PainlessParser.g4 b/modules/lang-painless/src/main/antlr/PainlessParser.g4
index 31b6a9445ea..2e22cd21a2e 100644
--- a/modules/lang-painless/src/main/antlr/PainlessParser.g4
+++ b/modules/lang-painless/src/main/antlr/PainlessParser.g4
@@ -83,6 +83,7 @@ decltype
funcref
: TYPE REF ( ID | NEW )
+ | ID REF ID
;
declvar
diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/Def.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/Def.java
index 1edaddea2c1..e60cbef79cf 100644
--- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/Def.java
+++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/Def.java
@@ -212,6 +212,8 @@ public final class Def {
* until it finds a matching whitelisted method. If one is not found, it throws an exception.
* Otherwise it returns a handle to the matching method.
*
+ * @param lookup caller's lookup
+ * @param callSiteType callsite's type
* @param receiverClass Class of the object to invoke the method on.
* @param name Name of the method.
* @param args args passed to callsite
@@ -220,31 +222,103 @@ public final class Def {
* @throws LambdaConversionException if a method reference cannot be converted to an functional interface
* @throws IllegalArgumentException if no matching whitelisted method was found.
*/
- static MethodHandle lookupMethod(Lookup lookup, Class> receiverClass, String name,
- Object args[], long recipe) throws LambdaConversionException {
- Method method = lookupMethodInternal(receiverClass, name, args.length - 1);
+ static MethodHandle lookupMethod(Lookup lookup, MethodType callSiteType,
+ Class> receiverClass, String name, Object args[], long recipe) throws LambdaConversionException {
+ // simple case: no lambdas
+ if (recipe == 0) {
+ return lookupMethodInternal(receiverClass, name, args.length - 1).handle;
+ }
+
+ // otherwise: first we have to compute the "real" arity. This is because we have extra arguments:
+ // e.g. f(a, g(x), b, h(y), i()) looks like f(a, g, x, b, h, y, i).
+ int arity = args.length - 1;
+ for (int i = 0; i < args.length; i++) {
+ if ((recipe & (1L << (i - 1))) != 0) {
+ String signature = (String) args[i];
+ int numCaptures = Integer.parseInt(signature.substring(signature.indexOf(',')+1));
+ arity -= numCaptures;
+ }
+ }
+
+ // lookup the method with the proper arity, then we know everything (e.g. interface types of parameters).
+ // based on these we can finally link any remaining lambdas that were deferred.
+ Method method = lookupMethodInternal(receiverClass, name, arity);
MethodHandle handle = method.handle;
- if (recipe != 0) {
- MethodHandle filters[] = new MethodHandle[args.length];
- for (int i = 0; i < args.length; i++) {
- // its a functional reference, replace the argument with an impl
- if ((recipe & (1L << (i - 1))) != 0) {
- filters[i] = lookupReference(lookup, method.arguments.get(i - 1), (String) args[i]);
+ int replaced = 0;
+ for (int i = 1; i < args.length; i++) {
+ // its a functional reference, replace the argument with an impl
+ if ((recipe & (1L << (i - 1))) != 0) {
+ // decode signature of form 'type.call,2'
+ String signature = (String) args[i];
+ int separator = signature.indexOf('.');
+ int separator2 = signature.indexOf(',');
+ String type = signature.substring(1, separator);
+ String call = signature.substring(separator+1, separator2);
+ int numCaptures = Integer.parseInt(signature.substring(separator2+1));
+ Class> captures[] = new Class>[numCaptures];
+ for (int capture = 0; capture < captures.length; capture++) {
+ captures[capture] = callSiteType.parameterType(i + 1 + capture);
}
+ MethodHandle filter;
+ Definition.Type interfaceType = method.arguments.get(i - 1 - replaced);
+ if (signature.charAt(0) == 'S') {
+ // the implementation is strongly typed, now that we know the interface type,
+ // we have everything.
+ filter = lookupReferenceInternal(lookup,
+ interfaceType,
+ type,
+ call,
+ captures);
+ } else if (signature.charAt(0) == 'D') {
+ // the interface type is now known, but we need to get the implementation.
+ // this is dynamically based on the receiver type (and cached separately, underneath
+ // this cache). It won't blow up since we never nest here (just references)
+ MethodType nestedType = MethodType.methodType(interfaceType.clazz, captures);
+ CallSite nested = DefBootstrap.bootstrap(lookup,
+ call,
+ nestedType,
+ DefBootstrap.REFERENCE,
+ interfaceType.name);
+ filter = nested.dynamicInvoker();
+ } else {
+ throw new AssertionError();
+ }
+ // the filter now ignores the signature (placeholder) on the stack
+ filter = MethodHandles.dropArguments(filter, 0, String.class);
+ handle = MethodHandles.collectArguments(handle, i, filter);
+ i += numCaptures;
+ replaced += numCaptures;
}
- handle = MethodHandles.filterArguments(handle, 0, filters);
}
return handle;
}
+ /**
+ * Returns an implementation of interfaceClass that calls receiverClass.name
+ *
+ * This is just like LambdaMetaFactory, only with a dynamic type. The interface type is known,
+ * so we simply need to lookup the matching implementation method based on receiver type.
+ */
+ static MethodHandle lookupReference(Lookup lookup, String interfaceClass,
+ Class> receiverClass, String name) throws LambdaConversionException {
+ Definition.Type interfaceType = Definition.getType(interfaceClass);
+ Method interfaceMethod = interfaceType.struct.getFunctionalMethod();
+ if (interfaceMethod == null) {
+ throw new IllegalArgumentException("Class [" + interfaceClass + "] is not a functional interface");
+ }
+ int arity = interfaceMethod.arguments.size();
+ Method implMethod = lookupMethodInternal(receiverClass, name, arity);
+ return lookupReferenceInternal(lookup, interfaceType, implMethod.owner.name, implMethod.name, receiverClass);
+ }
+
/** Returns a method handle to an implementation of clazz, given method reference signature
* @throws LambdaConversionException if a method reference cannot be converted to an functional interface
*/
- private static MethodHandle lookupReference(Lookup lookup, Definition.Type clazz, String signature) throws LambdaConversionException {
- int separator = signature.indexOf('.');
- FunctionRef ref = new FunctionRef(clazz, signature.substring(0, separator), signature.substring(separator+1));
+ private static MethodHandle lookupReferenceInternal(Lookup lookup, Definition.Type clazz, String type,
+ String call, Class>... captures) throws LambdaConversionException {
+ FunctionRef ref = new FunctionRef(clazz, type, call, captures);
final CallSite callSite;
if (ref.needsBridges()) {
callSite = LambdaMetafactory.altMetafactory(lookup,
@@ -265,9 +339,7 @@ public final class Def {
ref.samMethodType,
0);
}
- // we could actually invoke and cache here (in non-capturing cases), but this is not a speedup.
- MethodHandle factory = callSite.dynamicInvoker().asType(MethodType.methodType(clazz.clazz));
- return MethodHandles.dropArguments(factory, 0, Object.class);
+ return callSite.dynamicInvoker().asType(MethodType.methodType(clazz.clazz, captures));
}
diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/DefBootstrap.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/DefBootstrap.java
index 5dc773672a7..040008c0d62 100644
--- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/DefBootstrap.java
+++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/DefBootstrap.java
@@ -60,6 +60,8 @@ public final class DefBootstrap {
public static final int ARRAY_STORE = 4;
/** static bootstrap parameter indicating a dynamic iteration, e.g. for (x : y) */
public static final int ITERATOR = 5;
+ /** static bootstrap parameter indicating a dynamic method reference, e.g. foo::bar */
+ public static final int REFERENCE = 6;
/**
* CallSite that implements the polymorphic inlining cache (PIC).
@@ -71,17 +73,15 @@ public final class DefBootstrap {
private final Lookup lookup;
private final String name;
private final int flavor;
- private final long recipe;
+ private final Object[] args;
int depth; // pkg-protected for testing
- PIC(Lookup lookup, String name, MethodType type, int flavor, long recipe) {
+ PIC(Lookup lookup, String name, MethodType type, int flavor, Object[] args) {
super(type);
this.lookup = lookup;
this.name = name;
this.flavor = flavor;
- this.recipe = recipe;
- assert recipe == 0 || flavor == METHOD_CALL;
- assert Long.bitCount(recipe) <= type.parameterCount();
+ this.args = args;
final MethodHandle fallback = FALLBACK.bindTo(this)
.asCollector(Object[].class, type.parameterCount())
@@ -101,10 +101,10 @@ public final class DefBootstrap {
/**
* Does a slow lookup against the whitelist.
*/
- private MethodHandle lookup(int flavor, Class> clazz, String name, Object[] args, long recipe) throws Throwable {
+ private MethodHandle lookup(int flavor, Class> clazz, String name, Object[] args) throws Throwable {
switch(flavor) {
case METHOD_CALL:
- return Def.lookupMethod(lookup, clazz, name, args, recipe);
+ return Def.lookupMethod(lookup, type(), clazz, name, args, (Long) this.args[0]);
case LOAD:
return Def.lookupGetter(clazz, name);
case STORE:
@@ -115,6 +115,8 @@ public final class DefBootstrap {
return Def.lookupArrayStore(clazz);
case ITERATOR:
return Def.lookupIterator(clazz);
+ case REFERENCE:
+ return Def.lookupReference(lookup, (String) this.args[0], clazz, name);
default: throw new AssertionError();
}
}
@@ -128,7 +130,7 @@ public final class DefBootstrap {
final MethodType type = type();
final Object receiver = args[0];
final Class> receiverClass = receiver.getClass();
- final MethodHandle target = lookup(flavor, receiverClass, name, args, recipe).asType(type);
+ final MethodHandle target = lookup(flavor, receiverClass, name, args).asType(type);
if (depth >= MAX_DEPTH) {
// revert to a vtable call
@@ -170,8 +172,36 @@ public final class DefBootstrap {
*
* see https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-6.html#jvms-6.5.invokedynamic
*/
- public static CallSite bootstrap(Lookup lookup, String name, MethodType type, int flavor, long recipe) {
- return new PIC(lookup, name, type, flavor, recipe);
+ public static CallSite bootstrap(Lookup lookup, String name, MethodType type, int flavor, Object... args) {
+ // validate arguments
+ switch(flavor) {
+ case METHOD_CALL:
+ if (args.length != 1) {
+ throw new BootstrapMethodError("Invalid number of parameters for method call");
+ }
+ if (args[0] instanceof Long == false) {
+ throw new BootstrapMethodError("Illegal parameter for method call: " + args[0]);
+ }
+ long recipe = (Long) args[0];
+ if (Long.bitCount(recipe) > type.parameterCount()) {
+ throw new BootstrapMethodError("Illegal recipe for method call: too many bits");
+ }
+ break;
+ case REFERENCE:
+ if (args.length != 1) {
+ throw new BootstrapMethodError("Invalid number of parameters for reference call");
+ }
+ if (args[0] instanceof String == false) {
+ throw new BootstrapMethodError("Illegal parameter for reference call: " + args[0]);
+ }
+ break;
+ default:
+ if (args.length > 0) {
+ throw new BootstrapMethodError("Illegal static bootstrap parameters for flavor: " + flavor);
+ }
+ break;
+ }
+ return new PIC(lookup, name, type, flavor, args);
}
}
diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/Definition.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/Definition.java
index a8d4a803361..8a91bd7d7fd 100644
--- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/Definition.java
+++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/Definition.java
@@ -890,8 +890,7 @@ public final class Definition {
throw new AssertionError(e);
}
}
- owner.methods.put(methodKey,
- new Method(method.name, owner, method.rtn, method.arguments, method.method, method.modifiers, method.handle));
+ owner.methods.put(methodKey, method);
}
}
diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/FeatureTest.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/FeatureTest.java
index bef83daaad3..603023e61fe 100644
--- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/FeatureTest.java
+++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/FeatureTest.java
@@ -1,5 +1,7 @@
package org.elasticsearch.painless;
+import java.util.function.Function;
+
/*
* Licensed to Elasticsearch under one or more contributor
* license agreements. See the NOTICE file distributed with
@@ -63,4 +65,9 @@ public class FeatureTest {
public static boolean overloadedStatic(boolean whatToReturn) {
return whatToReturn;
}
+
+ /** method taking two functions! */
+ public Object twoFunctionsOfX(Function f, Function g) {
+ return f.apply(g.apply(x));
+ }
}
diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/FunctionRef.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/FunctionRef.java
index 03b6cc604c9..fb0175cc97e 100644
--- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/FunctionRef.java
+++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/FunctionRef.java
@@ -53,8 +53,9 @@ public class FunctionRef {
* @param expected interface type to implement.
* @param type the left hand side of a method reference expression
* @param call the right hand side of a method reference expression
+ * @param captures captured arguments
*/
- public FunctionRef(Definition.Type expected, String type, String call) {
+ public FunctionRef(Definition.Type expected, String type, String call, Class>... captures) {
boolean isCtorReference = "new".equals(call);
// check its really a functional interface
// for e.g. Comparable
@@ -66,7 +67,7 @@ public class FunctionRef {
// e.g. compareTo
invokedName = method.name;
// e.g. (Object)Comparator
- invokedType = MethodType.methodType(expected.clazz);
+ invokedType = MethodType.methodType(expected.clazz, captures);
// e.g. (Object,Object)int
interfaceMethodType = method.handle.type().dropParameterTypes(0, 1);
// lookup requested method
@@ -80,7 +81,15 @@ public class FunctionRef {
Definition.Method staticImpl = struct.staticMethods.get(new Definition.MethodKey(call, method.arguments.size()));
if (staticImpl == null) {
// otherwise a virtual impl
- impl = struct.methods.get(new Definition.MethodKey(call, method.arguments.size()-1));
+ final int arity;
+ if (captures.length > 0) {
+ // receiver captured
+ arity = method.arguments.size();
+ } else {
+ // receiver passed
+ arity = method.arguments.size() - 1;
+ }
+ impl = struct.methods.get(new Definition.MethodKey(call, arity));
} else {
impl = staticImpl;
}
@@ -98,12 +107,19 @@ public class FunctionRef {
} else {
tag = Opcodes.H_INVOKEVIRTUAL;
}
- implMethodASM = new Handle(tag, struct.type.getInternalName(), impl.name, impl.method.getDescriptor());
+ if (impl.owner.clazz.isInterface()) {
+ implMethodASM = new Handle(tag, struct.type.getInternalName(), impl.name, impl.method.getDescriptor());
+ } else {
+ implMethodASM = new Handle(tag, impl.owner.type.getInternalName(), impl.name, impl.method.getDescriptor());
+ }
implMethod = impl.handle;
if (isCtorReference) {
samMethodType = MethodType.methodType(interfaceMethodType.returnType(), impl.handle.type().parameterArray());
} else if (Modifier.isStatic(impl.modifiers)) {
samMethodType = impl.handle.type();
+ } else if (captures.length > 0) {
+ // drop the receiver, we capture it
+ samMethodType = impl.handle.type().dropParameterTypes(0, 1);
} else {
// ensure the receiver type is exact and not a superclass type
samMethodType = impl.handle.type().changeParameterType(0, struct.clazz);
diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/MethodWriter.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/MethodWriter.java
index 923c2e3f1e8..641a5582ab8 100644
--- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/MethodWriter.java
+++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/MethodWriter.java
@@ -22,7 +22,6 @@ package org.elasticsearch.painless;
import org.elasticsearch.painless.Definition.Cast;
import org.elasticsearch.painless.Definition.Sort;
import org.elasticsearch.painless.Definition.Type;
-import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.Label;
import org.objectweb.asm.Opcodes;
diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ScriptImpl.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ScriptImpl.java
index 8fdc48e19ba..b303089b339 100644
--- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/ScriptImpl.java
+++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/ScriptImpl.java
@@ -119,7 +119,7 @@ final class ScriptImpl implements ExecutableScript, LeafSearchScript {
public Object run() {
try {
return executable.execute(variables, scorer, doc, aggregationValue);
- } catch (PainlessError | BootstrapMethodError | Exception t) {
+ } catch (PainlessError | BootstrapMethodError | IllegalAccessError | Exception t) {
throw convertToScriptException(t);
}
}
diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/WriterConstants.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/WriterConstants.java
index 03879a0a3a0..4ec835b02c5 100644
--- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/WriterConstants.java
+++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/WriterConstants.java
@@ -68,7 +68,7 @@ public final class WriterConstants {
/** dynamic callsite bootstrap signature */
public final static MethodType DEF_BOOTSTRAP_TYPE =
- MethodType.methodType(CallSite.class, MethodHandles.Lookup.class, String.class, MethodType.class, int.class, long.class);
+ MethodType.methodType(CallSite.class, MethodHandles.Lookup.class, String.class, MethodType.class, int.class, Object[].class);
public final static Handle DEF_BOOTSTRAP_HANDLE =
new Handle(Opcodes.H_INVOKESTATIC, Type.getInternalName(DefBootstrap.class),
"bootstrap", DEF_BOOTSTRAP_TYPE.toMethodDescriptorString());
diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/antlr/PainlessParser.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/antlr/PainlessParser.java
index acaf00a5765..5eca024e812 100644
--- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/antlr/PainlessParser.java
+++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/antlr/PainlessParser.java
@@ -1181,7 +1181,10 @@ class PainlessParser extends Parser {
public static class FuncrefContext extends ParserRuleContext {
public TerminalNode TYPE() { return getToken(PainlessParser.TYPE, 0); }
public TerminalNode REF() { return getToken(PainlessParser.REF, 0); }
- public TerminalNode ID() { return getToken(PainlessParser.ID, 0); }
+ public List ID() { return getTokens(PainlessParser.ID); }
+ public TerminalNode ID(int i) {
+ return getToken(PainlessParser.ID, i);
+ }
public TerminalNode NEW() { return getToken(PainlessParser.NEW, 0); }
public FuncrefContext(ParserRuleContext parent, int invokingState) {
super(parent, invokingState);
@@ -1199,19 +1202,37 @@ class PainlessParser extends Parser {
enterRule(_localctx, 22, RULE_funcref);
int _la;
try {
- enterOuterAlt(_localctx, 1);
- {
- setState(201);
- match(TYPE);
- setState(202);
- match(REF);
- setState(203);
- _la = _input.LA(1);
- if ( !(_la==NEW || _la==ID) ) {
- _errHandler.recoverInline(this);
- } else {
- consume();
- }
+ setState(207);
+ switch (_input.LA(1)) {
+ case TYPE:
+ enterOuterAlt(_localctx, 1);
+ {
+ setState(201);
+ match(TYPE);
+ setState(202);
+ match(REF);
+ setState(203);
+ _la = _input.LA(1);
+ if ( !(_la==NEW || _la==ID) ) {
+ _errHandler.recoverInline(this);
+ } else {
+ consume();
+ }
+ }
+ break;
+ case ID:
+ enterOuterAlt(_localctx, 2);
+ {
+ setState(204);
+ match(ID);
+ setState(205);
+ match(REF);
+ setState(206);
+ match(ID);
+ }
+ break;
+ default:
+ throw new NoViableAltException(this);
}
}
catch (RecognitionException re) {
@@ -1249,15 +1270,15 @@ class PainlessParser extends Parser {
try {
enterOuterAlt(_localctx, 1);
{
- setState(205);
+ setState(209);
match(ID);
- setState(208);
+ setState(212);
_la = _input.LA(1);
if (_la==ASSIGN) {
{
- setState(206);
+ setState(210);
match(ASSIGN);
- setState(207);
+ setState(211);
expression(0);
}
}
@@ -1301,17 +1322,17 @@ class PainlessParser extends Parser {
try {
enterOuterAlt(_localctx, 1);
{
- setState(210);
- match(CATCH);
- setState(211);
- match(LP);
- setState(212);
- match(TYPE);
- setState(213);
- match(ID);
setState(214);
- match(RP);
+ match(CATCH);
setState(215);
+ match(LP);
+ setState(216);
+ match(TYPE);
+ setState(217);
+ match(ID);
+ setState(218);
+ match(RP);
+ setState(219);
block();
}
}
@@ -1347,7 +1368,7 @@ class PainlessParser extends Parser {
try {
enterOuterAlt(_localctx, 1);
{
- setState(217);
+ setState(221);
_la = _input.LA(1);
if ( !(_la==EOF || _la==SEMICOLON) ) {
_errHandler.recoverInline(this);
@@ -1516,24 +1537,24 @@ class PainlessParser extends Parser {
int _alt;
enterOuterAlt(_localctx, 1);
{
- setState(228);
- switch ( getInterpreter().adaptivePredict(_input,18,_ctx) ) {
+ setState(232);
+ switch ( getInterpreter().adaptivePredict(_input,19,_ctx) ) {
case 1:
{
_localctx = new AssignmentContext(_localctx);
_ctx = _localctx;
_prevctx = _localctx;
- setState(220);
+ setState(224);
chain(true);
- setState(221);
+ setState(225);
_la = _input.LA(1);
if ( !((((_la) & ~0x3f) == 0 && ((1L << _la) & ((1L << ASSIGN) | (1L << AADD) | (1L << ASUB) | (1L << AMUL) | (1L << ADIV) | (1L << AREM) | (1L << AAND) | (1L << AXOR) | (1L << AOR) | (1L << ALSH) | (1L << ARSH) | (1L << AUSH))) != 0)) ) {
_errHandler.recoverInline(this);
} else {
consume();
}
- setState(222);
+ setState(226);
expression(1);
((AssignmentContext)_localctx).s = false;
}
@@ -1543,37 +1564,37 @@ class PainlessParser extends Parser {
_localctx = new SingleContext(_localctx);
_ctx = _localctx;
_prevctx = _localctx;
- setState(225);
+ setState(229);
((SingleContext)_localctx).u = unary(false);
((SingleContext)_localctx).s = ((SingleContext)_localctx).u.s;
}
break;
}
_ctx.stop = _input.LT(-1);
- setState(289);
+ setState(293);
_errHandler.sync(this);
- _alt = getInterpreter().adaptivePredict(_input,20,_ctx);
+ _alt = getInterpreter().adaptivePredict(_input,21,_ctx);
while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) {
if ( _alt==1 ) {
if ( _parseListeners!=null ) triggerExitRuleEvent();
_prevctx = _localctx;
{
- setState(287);
- switch ( getInterpreter().adaptivePredict(_input,19,_ctx) ) {
+ setState(291);
+ switch ( getInterpreter().adaptivePredict(_input,20,_ctx) ) {
case 1:
{
_localctx = new BinaryContext(new ExpressionContext(_parentctx, _parentState));
pushNewRecursionContext(_localctx, _startState, RULE_expression);
- setState(230);
+ setState(234);
if (!(precpred(_ctx, 12))) throw new FailedPredicateException(this, "precpred(_ctx, 12)");
- setState(231);
+ setState(235);
_la = _input.LA(1);
if ( !((((_la) & ~0x3f) == 0 && ((1L << _la) & ((1L << MUL) | (1L << DIV) | (1L << REM))) != 0)) ) {
_errHandler.recoverInline(this);
} else {
consume();
}
- setState(232);
+ setState(236);
expression(13);
((BinaryContext)_localctx).s = false;
}
@@ -1582,16 +1603,16 @@ class PainlessParser extends Parser {
{
_localctx = new BinaryContext(new ExpressionContext(_parentctx, _parentState));
pushNewRecursionContext(_localctx, _startState, RULE_expression);
- setState(235);
+ setState(239);
if (!(precpred(_ctx, 11))) throw new FailedPredicateException(this, "precpred(_ctx, 11)");
- setState(236);
+ setState(240);
_la = _input.LA(1);
if ( !(_la==ADD || _la==SUB) ) {
_errHandler.recoverInline(this);
} else {
consume();
}
- setState(237);
+ setState(241);
expression(12);
((BinaryContext)_localctx).s = false;
}
@@ -1600,16 +1621,16 @@ class PainlessParser extends Parser {
{
_localctx = new BinaryContext(new ExpressionContext(_parentctx, _parentState));
pushNewRecursionContext(_localctx, _startState, RULE_expression);
- setState(240);
+ setState(244);
if (!(precpred(_ctx, 10))) throw new FailedPredicateException(this, "precpred(_ctx, 10)");
- setState(241);
+ setState(245);
_la = _input.LA(1);
if ( !((((_la) & ~0x3f) == 0 && ((1L << _la) & ((1L << LSH) | (1L << RSH) | (1L << USH))) != 0)) ) {
_errHandler.recoverInline(this);
} else {
consume();
}
- setState(242);
+ setState(246);
expression(11);
((BinaryContext)_localctx).s = false;
}
@@ -1618,16 +1639,16 @@ class PainlessParser extends Parser {
{
_localctx = new CompContext(new ExpressionContext(_parentctx, _parentState));
pushNewRecursionContext(_localctx, _startState, RULE_expression);
- setState(245);
+ setState(249);
if (!(precpred(_ctx, 9))) throw new FailedPredicateException(this, "precpred(_ctx, 9)");
- setState(246);
+ setState(250);
_la = _input.LA(1);
if ( !((((_la) & ~0x3f) == 0 && ((1L << _la) & ((1L << LT) | (1L << LTE) | (1L << GT) | (1L << GTE))) != 0)) ) {
_errHandler.recoverInline(this);
} else {
consume();
}
- setState(247);
+ setState(251);
expression(10);
((CompContext)_localctx).s = false;
}
@@ -1636,16 +1657,16 @@ class PainlessParser extends Parser {
{
_localctx = new CompContext(new ExpressionContext(_parentctx, _parentState));
pushNewRecursionContext(_localctx, _startState, RULE_expression);
- setState(250);
+ setState(254);
if (!(precpred(_ctx, 8))) throw new FailedPredicateException(this, "precpred(_ctx, 8)");
- setState(251);
+ setState(255);
_la = _input.LA(1);
if ( !((((_la) & ~0x3f) == 0 && ((1L << _la) & ((1L << EQ) | (1L << EQR) | (1L << NE) | (1L << NER))) != 0)) ) {
_errHandler.recoverInline(this);
} else {
consume();
}
- setState(252);
+ setState(256);
expression(9);
((CompContext)_localctx).s = false;
}
@@ -1654,11 +1675,11 @@ class PainlessParser extends Parser {
{
_localctx = new BinaryContext(new ExpressionContext(_parentctx, _parentState));
pushNewRecursionContext(_localctx, _startState, RULE_expression);
- setState(255);
+ setState(259);
if (!(precpred(_ctx, 7))) throw new FailedPredicateException(this, "precpred(_ctx, 7)");
- setState(256);
+ setState(260);
match(BWAND);
- setState(257);
+ setState(261);
expression(8);
((BinaryContext)_localctx).s = false;
}
@@ -1667,11 +1688,11 @@ class PainlessParser extends Parser {
{
_localctx = new BinaryContext(new ExpressionContext(_parentctx, _parentState));
pushNewRecursionContext(_localctx, _startState, RULE_expression);
- setState(260);
+ setState(264);
if (!(precpred(_ctx, 6))) throw new FailedPredicateException(this, "precpred(_ctx, 6)");
- setState(261);
+ setState(265);
match(XOR);
- setState(262);
+ setState(266);
expression(7);
((BinaryContext)_localctx).s = false;
}
@@ -1680,11 +1701,11 @@ class PainlessParser extends Parser {
{
_localctx = new BinaryContext(new ExpressionContext(_parentctx, _parentState));
pushNewRecursionContext(_localctx, _startState, RULE_expression);
- setState(265);
+ setState(269);
if (!(precpred(_ctx, 5))) throw new FailedPredicateException(this, "precpred(_ctx, 5)");
- setState(266);
+ setState(270);
match(BWOR);
- setState(267);
+ setState(271);
expression(6);
((BinaryContext)_localctx).s = false;
}
@@ -1693,11 +1714,11 @@ class PainlessParser extends Parser {
{
_localctx = new BoolContext(new ExpressionContext(_parentctx, _parentState));
pushNewRecursionContext(_localctx, _startState, RULE_expression);
- setState(270);
+ setState(274);
if (!(precpred(_ctx, 4))) throw new FailedPredicateException(this, "precpred(_ctx, 4)");
- setState(271);
+ setState(275);
match(BOOLAND);
- setState(272);
+ setState(276);
expression(5);
((BoolContext)_localctx).s = false;
}
@@ -1706,11 +1727,11 @@ class PainlessParser extends Parser {
{
_localctx = new BoolContext(new ExpressionContext(_parentctx, _parentState));
pushNewRecursionContext(_localctx, _startState, RULE_expression);
- setState(275);
+ setState(279);
if (!(precpred(_ctx, 3))) throw new FailedPredicateException(this, "precpred(_ctx, 3)");
- setState(276);
+ setState(280);
match(BOOLOR);
- setState(277);
+ setState(281);
expression(4);
((BoolContext)_localctx).s = false;
}
@@ -1719,15 +1740,15 @@ class PainlessParser extends Parser {
{
_localctx = new ConditionalContext(new ExpressionContext(_parentctx, _parentState));
pushNewRecursionContext(_localctx, _startState, RULE_expression);
- setState(280);
- if (!(precpred(_ctx, 2))) throw new FailedPredicateException(this, "precpred(_ctx, 2)");
- setState(281);
- match(COND);
- setState(282);
- ((ConditionalContext)_localctx).e0 = expression(0);
- setState(283);
- match(COLON);
setState(284);
+ if (!(precpred(_ctx, 2))) throw new FailedPredicateException(this, "precpred(_ctx, 2)");
+ setState(285);
+ match(COND);
+ setState(286);
+ ((ConditionalContext)_localctx).e0 = expression(0);
+ setState(287);
+ match(COLON);
+ setState(288);
((ConditionalContext)_localctx).e1 = expression(2);
((ConditionalContext)_localctx).s = ((ConditionalContext)_localctx).e0.s && ((ConditionalContext)_localctx).e1.s;
}
@@ -1735,9 +1756,9 @@ class PainlessParser extends Parser {
}
}
}
- setState(291);
+ setState(295);
_errHandler.sync(this);
- _alt = getInterpreter().adaptivePredict(_input,20,_ctx);
+ _alt = getInterpreter().adaptivePredict(_input,21,_ctx);
}
}
}
@@ -1882,22 +1903,22 @@ class PainlessParser extends Parser {
enterRule(_localctx, 32, RULE_unary);
int _la;
try {
- setState(321);
- switch ( getInterpreter().adaptivePredict(_input,21,_ctx) ) {
+ setState(325);
+ switch ( getInterpreter().adaptivePredict(_input,22,_ctx) ) {
case 1:
_localctx = new PreContext(_localctx);
enterOuterAlt(_localctx, 1);
{
- setState(292);
+ setState(296);
if (!( !_localctx.c )) throw new FailedPredicateException(this, " !$c ");
- setState(293);
+ setState(297);
_la = _input.LA(1);
if ( !(_la==INCR || _la==DECR) ) {
_errHandler.recoverInline(this);
} else {
consume();
}
- setState(294);
+ setState(298);
chain(true);
}
break;
@@ -1905,11 +1926,11 @@ class PainlessParser extends Parser {
_localctx = new PostContext(_localctx);
enterOuterAlt(_localctx, 2);
{
- setState(295);
+ setState(299);
if (!( !_localctx.c )) throw new FailedPredicateException(this, " !$c ");
- setState(296);
+ setState(300);
chain(true);
- setState(297);
+ setState(301);
_la = _input.LA(1);
if ( !(_la==INCR || _la==DECR) ) {
_errHandler.recoverInline(this);
@@ -1922,9 +1943,9 @@ class PainlessParser extends Parser {
_localctx = new ReadContext(_localctx);
enterOuterAlt(_localctx, 3);
{
- setState(299);
+ setState(303);
if (!( !_localctx.c )) throw new FailedPredicateException(this, " !$c ");
- setState(300);
+ setState(304);
chain(false);
}
break;
@@ -1932,9 +1953,9 @@ class PainlessParser extends Parser {
_localctx = new NumericContext(_localctx);
enterOuterAlt(_localctx, 4);
{
- setState(301);
+ setState(305);
if (!( !_localctx.c )) throw new FailedPredicateException(this, " !$c ");
- setState(302);
+ setState(306);
_la = _input.LA(1);
if ( !(((((_la - 64)) & ~0x3f) == 0 && ((1L << (_la - 64)) & ((1L << (OCTAL - 64)) | (1L << (HEX - 64)) | (1L << (INTEGER - 64)) | (1L << (DECIMAL - 64)))) != 0)) ) {
_errHandler.recoverInline(this);
@@ -1948,9 +1969,9 @@ class PainlessParser extends Parser {
_localctx = new TrueContext(_localctx);
enterOuterAlt(_localctx, 5);
{
- setState(304);
+ setState(308);
if (!( !_localctx.c )) throw new FailedPredicateException(this, " !$c ");
- setState(305);
+ setState(309);
match(TRUE);
((TrueContext)_localctx).s = false;
}
@@ -1959,9 +1980,9 @@ class PainlessParser extends Parser {
_localctx = new FalseContext(_localctx);
enterOuterAlt(_localctx, 6);
{
- setState(307);
+ setState(311);
if (!( !_localctx.c )) throw new FailedPredicateException(this, " !$c ");
- setState(308);
+ setState(312);
match(FALSE);
((FalseContext)_localctx).s = false;
}
@@ -1970,9 +1991,9 @@ class PainlessParser extends Parser {
_localctx = new NullContext(_localctx);
enterOuterAlt(_localctx, 7);
{
- setState(310);
+ setState(314);
if (!( !_localctx.c )) throw new FailedPredicateException(this, " !$c ");
- setState(311);
+ setState(315);
match(NULL);
((NullContext)_localctx).s = false;
}
@@ -1981,16 +2002,16 @@ class PainlessParser extends Parser {
_localctx = new OperatorContext(_localctx);
enterOuterAlt(_localctx, 8);
{
- setState(313);
+ setState(317);
if (!( !_localctx.c )) throw new FailedPredicateException(this, " !$c ");
- setState(314);
+ setState(318);
_la = _input.LA(1);
if ( !((((_la) & ~0x3f) == 0 && ((1L << _la) & ((1L << BOOLNOT) | (1L << BWNOT) | (1L << ADD) | (1L << SUB))) != 0)) ) {
_errHandler.recoverInline(this);
} else {
consume();
}
- setState(315);
+ setState(319);
unary(false);
}
break;
@@ -1998,13 +2019,13 @@ class PainlessParser extends Parser {
_localctx = new CastContext(_localctx);
enterOuterAlt(_localctx, 9);
{
- setState(316);
+ setState(320);
match(LP);
- setState(317);
+ setState(321);
decltype();
- setState(318);
+ setState(322);
match(RP);
- setState(319);
+ setState(323);
unary(_localctx.c);
}
break;
@@ -2113,29 +2134,29 @@ class PainlessParser extends Parser {
enterRule(_localctx, 34, RULE_chain);
try {
int _alt;
- setState(357);
- switch ( getInterpreter().adaptivePredict(_input,27,_ctx) ) {
+ setState(361);
+ switch ( getInterpreter().adaptivePredict(_input,28,_ctx) ) {
case 1:
_localctx = new DynamicContext(_localctx);
enterOuterAlt(_localctx, 1);
{
- setState(323);
- ((DynamicContext)_localctx).p = primary(_localctx.c);
setState(327);
+ ((DynamicContext)_localctx).p = primary(_localctx.c);
+ setState(331);
_errHandler.sync(this);
- _alt = getInterpreter().adaptivePredict(_input,22,_ctx);
+ _alt = getInterpreter().adaptivePredict(_input,23,_ctx);
while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) {
if ( _alt==1 ) {
{
{
- setState(324);
+ setState(328);
secondary(((DynamicContext)_localctx).p.s);
}
}
}
- setState(329);
+ setState(333);
_errHandler.sync(this);
- _alt = getInterpreter().adaptivePredict(_input,22,_ctx);
+ _alt = getInterpreter().adaptivePredict(_input,23,_ctx);
}
}
break;
@@ -2143,25 +2164,25 @@ class PainlessParser extends Parser {
_localctx = new StaticContext(_localctx);
enterOuterAlt(_localctx, 2);
{
- setState(330);
+ setState(334);
decltype();
- setState(331);
- dot();
setState(335);
+ dot();
+ setState(339);
_errHandler.sync(this);
- _alt = getInterpreter().adaptivePredict(_input,23,_ctx);
+ _alt = getInterpreter().adaptivePredict(_input,24,_ctx);
while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) {
if ( _alt==1 ) {
{
{
- setState(332);
+ setState(336);
secondary(true);
}
}
}
- setState(337);
+ setState(341);
_errHandler.sync(this);
- _alt = getInterpreter().adaptivePredict(_input,23,_ctx);
+ _alt = getInterpreter().adaptivePredict(_input,24,_ctx);
}
}
break;
@@ -2169,11 +2190,11 @@ class PainlessParser extends Parser {
_localctx = new NewarrayContext(_localctx);
enterOuterAlt(_localctx, 3);
{
- setState(338);
+ setState(342);
match(NEW);
- setState(339);
+ setState(343);
match(TYPE);
- setState(344);
+ setState(348);
_errHandler.sync(this);
_alt = 1;
do {
@@ -2181,11 +2202,11 @@ class PainlessParser extends Parser {
case 1:
{
{
- setState(340);
+ setState(344);
match(LBRACE);
- setState(341);
+ setState(345);
expression(0);
- setState(342);
+ setState(346);
match(RBRACE);
}
}
@@ -2193,31 +2214,31 @@ class PainlessParser extends Parser {
default:
throw new NoViableAltException(this);
}
- setState(346);
- _errHandler.sync(this);
- _alt = getInterpreter().adaptivePredict(_input,24,_ctx);
- } while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER );
- setState(355);
- switch ( getInterpreter().adaptivePredict(_input,26,_ctx) ) {
- case 1:
- {
- setState(348);
- dot();
- setState(352);
+ setState(350);
_errHandler.sync(this);
_alt = getInterpreter().adaptivePredict(_input,25,_ctx);
+ } while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER );
+ setState(359);
+ switch ( getInterpreter().adaptivePredict(_input,27,_ctx) ) {
+ case 1:
+ {
+ setState(352);
+ dot();
+ setState(356);
+ _errHandler.sync(this);
+ _alt = getInterpreter().adaptivePredict(_input,26,_ctx);
while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) {
if ( _alt==1 ) {
{
{
- setState(349);
+ setState(353);
secondary(true);
}
}
}
- setState(354);
+ setState(358);
_errHandler.sync(this);
- _alt = getInterpreter().adaptivePredict(_input,25,_ctx);
+ _alt = getInterpreter().adaptivePredict(_input,26,_ctx);
}
}
break;
@@ -2329,19 +2350,19 @@ class PainlessParser extends Parser {
PrimaryContext _localctx = new PrimaryContext(_ctx, getState(), c);
enterRule(_localctx, 36, RULE_primary);
try {
- setState(377);
- switch ( getInterpreter().adaptivePredict(_input,28,_ctx) ) {
+ setState(381);
+ switch ( getInterpreter().adaptivePredict(_input,29,_ctx) ) {
case 1:
_localctx = new ExprprecContext(_localctx);
enterOuterAlt(_localctx, 1);
{
- setState(359);
+ setState(363);
if (!( !_localctx.c )) throw new FailedPredicateException(this, " !$c ");
- setState(360);
+ setState(364);
match(LP);
- setState(361);
+ setState(365);
((ExprprecContext)_localctx).e = expression(0);
- setState(362);
+ setState(366);
match(RP);
((ExprprecContext)_localctx).s = ((ExprprecContext)_localctx).e.s;
}
@@ -2350,13 +2371,13 @@ class PainlessParser extends Parser {
_localctx = new ChainprecContext(_localctx);
enterOuterAlt(_localctx, 2);
{
- setState(365);
+ setState(369);
if (!( _localctx.c )) throw new FailedPredicateException(this, " $c ");
- setState(366);
+ setState(370);
match(LP);
- setState(367);
+ setState(371);
unary(true);
- setState(368);
+ setState(372);
match(RP);
}
break;
@@ -2364,7 +2385,7 @@ class PainlessParser extends Parser {
_localctx = new StringContext(_localctx);
enterOuterAlt(_localctx, 3);
{
- setState(370);
+ setState(374);
match(STRING);
}
break;
@@ -2372,7 +2393,7 @@ class PainlessParser extends Parser {
_localctx = new VariableContext(_localctx);
enterOuterAlt(_localctx, 4);
{
- setState(371);
+ setState(375);
match(ID);
}
break;
@@ -2380,9 +2401,9 @@ class PainlessParser extends Parser {
_localctx = new CalllocalContext(_localctx);
enterOuterAlt(_localctx, 5);
{
- setState(372);
+ setState(376);
match(ID);
- setState(373);
+ setState(377);
arguments();
}
break;
@@ -2390,11 +2411,11 @@ class PainlessParser extends Parser {
_localctx = new NewobjectContext(_localctx);
enterOuterAlt(_localctx, 6);
{
- setState(374);
+ setState(378);
match(NEW);
- setState(375);
+ setState(379);
match(TYPE);
- setState(376);
+ setState(380);
arguments();
}
break;
@@ -2436,23 +2457,23 @@ class PainlessParser extends Parser {
SecondaryContext _localctx = new SecondaryContext(_ctx, getState(), s);
enterRule(_localctx, 38, RULE_secondary);
try {
- setState(383);
- switch ( getInterpreter().adaptivePredict(_input,29,_ctx) ) {
+ setState(387);
+ switch ( getInterpreter().adaptivePredict(_input,30,_ctx) ) {
case 1:
enterOuterAlt(_localctx, 1);
{
- setState(379);
+ setState(383);
if (!( _localctx.s )) throw new FailedPredicateException(this, " $s ");
- setState(380);
+ setState(384);
dot();
}
break;
case 2:
enterOuterAlt(_localctx, 2);
{
- setState(381);
+ setState(385);
if (!( _localctx.s )) throw new FailedPredicateException(this, " $s ");
- setState(382);
+ setState(386);
brace();
}
break;
@@ -2510,17 +2531,17 @@ class PainlessParser extends Parser {
enterRule(_localctx, 40, RULE_dot);
int _la;
try {
- setState(390);
- switch ( getInterpreter().adaptivePredict(_input,30,_ctx) ) {
+ setState(394);
+ switch ( getInterpreter().adaptivePredict(_input,31,_ctx) ) {
case 1:
_localctx = new CallinvokeContext(_localctx);
enterOuterAlt(_localctx, 1);
{
- setState(385);
+ setState(389);
match(DOT);
- setState(386);
+ setState(390);
match(DOTID);
- setState(387);
+ setState(391);
arguments();
}
break;
@@ -2528,9 +2549,9 @@ class PainlessParser extends Parser {
_localctx = new FieldaccessContext(_localctx);
enterOuterAlt(_localctx, 2);
{
- setState(388);
+ setState(392);
match(DOT);
- setState(389);
+ setState(393);
_la = _input.LA(1);
if ( !(_la==DOTINTEGER || _la==DOTID) ) {
_errHandler.recoverInline(this);
@@ -2584,11 +2605,11 @@ class PainlessParser extends Parser {
_localctx = new BraceaccessContext(_localctx);
enterOuterAlt(_localctx, 1);
{
- setState(392);
+ setState(396);
match(LBRACE);
- setState(393);
+ setState(397);
expression(0);
- setState(394);
+ setState(398);
match(RBRACE);
}
}
@@ -2635,34 +2656,34 @@ class PainlessParser extends Parser {
enterOuterAlt(_localctx, 1);
{
{
- setState(396);
+ setState(400);
match(LP);
- setState(405);
- switch ( getInterpreter().adaptivePredict(_input,32,_ctx) ) {
+ setState(409);
+ switch ( getInterpreter().adaptivePredict(_input,33,_ctx) ) {
case 1:
{
- setState(397);
+ setState(401);
argument();
- setState(402);
+ setState(406);
_errHandler.sync(this);
_la = _input.LA(1);
while (_la==COMMA) {
{
{
- setState(398);
+ setState(402);
match(COMMA);
- setState(399);
+ setState(403);
argument();
}
}
- setState(404);
+ setState(408);
_errHandler.sync(this);
_la = _input.LA(1);
}
}
break;
}
- setState(407);
+ setState(411);
match(RP);
}
}
@@ -2700,19 +2721,19 @@ class PainlessParser extends Parser {
ArgumentContext _localctx = new ArgumentContext(_ctx, getState());
enterRule(_localctx, 46, RULE_argument);
try {
- setState(411);
- switch ( getInterpreter().adaptivePredict(_input,33,_ctx) ) {
+ setState(415);
+ switch ( getInterpreter().adaptivePredict(_input,34,_ctx) ) {
case 1:
enterOuterAlt(_localctx, 1);
{
- setState(409);
+ setState(413);
expression(0);
}
break;
case 2:
enterOuterAlt(_localctx, 2);
{
- setState(410);
+ setState(414);
funcref();
}
break;
@@ -2819,7 +2840,7 @@ class PainlessParser extends Parser {
}
public static final String _serializedATN =
- "\3\u0430\ud6d1\u8206\uad2d\u4417\uaef1\u8d80\uaadd\3M\u01a0\4\2\t\2\4"+
+ "\3\u0430\ud6d1\u8206\uad2d\u4417\uaef1\u8d80\uaadd\3M\u01a4\4\2\t\2\4"+
"\3\t\3\4\4\t\4\4\5\t\5\4\6\t\6\4\7\t\7\4\b\t\b\4\t\t\t\4\n\t\n\4\13\t"+
"\13\4\f\t\f\4\r\t\r\4\16\t\16\4\17\t\17\4\20\t\20\4\21\t\21\4\22\t\22"+
"\4\23\t\23\4\24\t\24\4\25\t\25\4\26\t\26\4\27\t\27\4\30\t\30\4\31\t\31"+
@@ -2833,144 +2854,146 @@ class PainlessParser extends Parser {
"\5\3\5\5\5\u00a4\n\5\3\6\3\6\5\6\u00a8\n\6\3\7\3\7\7\7\u00ac\n\7\f\7\16"+
"\7\u00af\13\7\3\7\3\7\3\b\3\b\3\t\3\t\5\t\u00b7\n\t\3\n\3\n\3\13\3\13"+
"\3\13\3\13\7\13\u00bf\n\13\f\13\16\13\u00c2\13\13\3\f\3\f\3\f\7\f\u00c7"+
- "\n\f\f\f\16\f\u00ca\13\f\3\r\3\r\3\r\3\r\3\16\3\16\3\16\5\16\u00d3\n\16"+
- "\3\17\3\17\3\17\3\17\3\17\3\17\3\17\3\20\3\20\3\21\3\21\3\21\3\21\3\21"+
- "\3\21\3\21\3\21\3\21\5\21\u00e7\n\21\3\21\3\21\3\21\3\21\3\21\3\21\3\21"+
+ "\n\f\f\f\16\f\u00ca\13\f\3\r\3\r\3\r\3\r\3\r\3\r\5\r\u00d2\n\r\3\16\3"+
+ "\16\3\16\5\16\u00d7\n\16\3\17\3\17\3\17\3\17\3\17\3\17\3\17\3\20\3\20"+
+ "\3\21\3\21\3\21\3\21\3\21\3\21\3\21\3\21\3\21\5\21\u00eb\n\21\3\21\3\21"+
"\3\21\3\21\3\21\3\21\3\21\3\21\3\21\3\21\3\21\3\21\3\21\3\21\3\21\3\21"+
"\3\21\3\21\3\21\3\21\3\21\3\21\3\21\3\21\3\21\3\21\3\21\3\21\3\21\3\21"+
"\3\21\3\21\3\21\3\21\3\21\3\21\3\21\3\21\3\21\3\21\3\21\3\21\3\21\3\21"+
- "\3\21\3\21\3\21\3\21\3\21\3\21\3\21\3\21\7\21\u0122\n\21\f\21\16\21\u0125"+
- "\13\21\3\22\3\22\3\22\3\22\3\22\3\22\3\22\3\22\3\22\3\22\3\22\3\22\3\22"+
+ "\3\21\3\21\3\21\3\21\3\21\3\21\3\21\3\21\3\21\3\21\3\21\3\21\3\21\7\21"+
+ "\u0126\n\21\f\21\16\21\u0129\13\21\3\22\3\22\3\22\3\22\3\22\3\22\3\22"+
"\3\22\3\22\3\22\3\22\3\22\3\22\3\22\3\22\3\22\3\22\3\22\3\22\3\22\3\22"+
- "\3\22\3\22\5\22\u0144\n\22\3\23\3\23\7\23\u0148\n\23\f\23\16\23\u014b"+
- "\13\23\3\23\3\23\3\23\7\23\u0150\n\23\f\23\16\23\u0153\13\23\3\23\3\23"+
- "\3\23\3\23\3\23\3\23\6\23\u015b\n\23\r\23\16\23\u015c\3\23\3\23\7\23\u0161"+
- "\n\23\f\23\16\23\u0164\13\23\5\23\u0166\n\23\5\23\u0168\n\23\3\24\3\24"+
- "\3\24\3\24\3\24\3\24\3\24\3\24\3\24\3\24\3\24\3\24\3\24\3\24\3\24\3\24"+
- "\3\24\3\24\5\24\u017c\n\24\3\25\3\25\3\25\3\25\5\25\u0182\n\25\3\26\3"+
- "\26\3\26\3\26\3\26\5\26\u0189\n\26\3\27\3\27\3\27\3\27\3\30\3\30\3\30"+
- "\3\30\7\30\u0193\n\30\f\30\16\30\u0196\13\30\5\30\u0198\n\30\3\30\3\30"+
- "\3\31\3\31\5\31\u019e\n\31\3\31\2\3 \32\2\4\6\b\n\f\16\20\22\24\26\30"+
- "\32\34\36 \"$&(*,.\60\2\16\4\2\26\26KK\3\3\r\r\3\2\66A\3\2\34\36\3\2\37"+
- " \3\2!#\3\2$\'\3\2(+\3\2\64\65\3\2BE\4\2\32\33\37 \3\2LM\u01c8\2\65\3"+
- "\2\2\2\4@\3\2\2\2\6E\3\2\2\2\b\u00a3\3\2\2\2\n\u00a7\3\2\2\2\f\u00a9\3"+
- "\2\2\2\16\u00b2\3\2\2\2\20\u00b6\3\2\2\2\22\u00b8\3\2\2\2\24\u00ba\3\2"+
- "\2\2\26\u00c3\3\2\2\2\30\u00cb\3\2\2\2\32\u00cf\3\2\2\2\34\u00d4\3\2\2"+
- "\2\36\u00db\3\2\2\2 \u00e6\3\2\2\2\"\u0143\3\2\2\2$\u0167\3\2\2\2&\u017b"+
- "\3\2\2\2(\u0181\3\2\2\2*\u0188\3\2\2\2,\u018a\3\2\2\2.\u018e\3\2\2\2\60"+
- "\u019d\3\2\2\2\62\64\5\4\3\2\63\62\3\2\2\2\64\67\3\2\2\2\65\63\3\2\2\2"+
- "\65\66\3\2\2\2\66;\3\2\2\2\67\65\3\2\2\28:\5\b\5\298\3\2\2\2:=\3\2\2\2"+
- ";9\3\2\2\2;<\3\2\2\2<>\3\2\2\2=;\3\2\2\2>?\7\2\2\3?\3\3\2\2\2@A\5\26\f"+
- "\2AB\7K\2\2BC\5\6\4\2CD\5\f\7\2D\5\3\2\2\2EQ\7\t\2\2FG\5\26\f\2GN\7K\2"+
- "\2HI\7\f\2\2IJ\5\26\f\2JK\7K\2\2KM\3\2\2\2LH\3\2\2\2MP\3\2\2\2NL\3\2\2"+
- "\2NO\3\2\2\2OR\3\2\2\2PN\3\2\2\2QF\3\2\2\2QR\3\2\2\2RS\3\2\2\2ST\7\n\2"+
- "\2T\7\3\2\2\2UV\7\16\2\2VW\7\t\2\2WX\5 \21\2XY\7\n\2\2Y]\5\n\6\2Z[\7\17"+
- "\2\2[^\5\n\6\2\\^\6\5\2\2]Z\3\2\2\2]\\\3\2\2\2^\u00a4\3\2\2\2_`\7\20\2"+
- "\2`a\7\t\2\2ab\5 \21\2be\7\n\2\2cf\5\n\6\2df\5\16\b\2ec\3\2\2\2ed\3\2"+
- "\2\2f\u00a4\3\2\2\2gh\7\21\2\2hi\5\f\7\2ij\7\20\2\2jk\7\t\2\2kl\5 \21"+
- "\2lm\7\n\2\2mn\5\36\20\2n\u00a4\3\2\2\2op\7\22\2\2pr\7\t\2\2qs\5\20\t"+
- "\2rq\3\2\2\2rs\3\2\2\2st\3\2\2\2tv\7\r\2\2uw\5 \21\2vu\3\2\2\2vw\3\2\2"+
- "\2wx\3\2\2\2xz\7\r\2\2y{\5\22\n\2zy\3\2\2\2z{\3\2\2\2{|\3\2\2\2|\177\7"+
- "\n\2\2}\u0080\5\n\6\2~\u0080\5\16\b\2\177}\3\2\2\2\177~\3\2\2\2\u0080"+
- "\u00a4\3\2\2\2\u0081\u0082\7\22\2\2\u0082\u0083\7\t\2\2\u0083\u0084\5"+
- "\26\f\2\u0084\u0085\7K\2\2\u0085\u0086\7\62\2\2\u0086\u0087\5 \21\2\u0087"+
- "\u0088\7\n\2\2\u0088\u0089\5\n\6\2\u0089\u00a4\3\2\2\2\u008a\u008b\5\24"+
- "\13\2\u008b\u008c\5\36\20\2\u008c\u00a4\3\2\2\2\u008d\u008e\7\23\2\2\u008e"+
- "\u00a4\5\36\20\2\u008f\u0090\7\24\2\2\u0090\u00a4\5\36\20\2\u0091\u0092"+
- "\7\25\2\2\u0092\u0093\5 \21\2\u0093\u0094\5\36\20\2\u0094\u00a4\3\2\2"+
- "\2\u0095\u0096\7\27\2\2\u0096\u0098\5\f\7\2\u0097\u0099\5\34\17\2\u0098"+
- "\u0097\3\2\2\2\u0099\u009a\3\2\2\2\u009a\u0098\3\2\2\2\u009a\u009b\3\2"+
- "\2\2\u009b\u00a4\3\2\2\2\u009c\u009d\7\31\2\2\u009d\u009e\5 \21\2\u009e"+
- "\u009f\5\36\20\2\u009f\u00a4\3\2\2\2\u00a0\u00a1\5 \21\2\u00a1\u00a2\5"+
- "\36\20\2\u00a2\u00a4\3\2\2\2\u00a3U\3\2\2\2\u00a3_\3\2\2\2\u00a3g\3\2"+
- "\2\2\u00a3o\3\2\2\2\u00a3\u0081\3\2\2\2\u00a3\u008a\3\2\2\2\u00a3\u008d"+
- "\3\2\2\2\u00a3\u008f\3\2\2\2\u00a3\u0091\3\2\2\2\u00a3\u0095\3\2\2\2\u00a3"+
- "\u009c\3\2\2\2\u00a3\u00a0\3\2\2\2\u00a4\t\3\2\2\2\u00a5\u00a8\5\f\7\2"+
- "\u00a6\u00a8\5\b\5\2\u00a7\u00a5\3\2\2\2\u00a7\u00a6\3\2\2\2\u00a8\13"+
- "\3\2\2\2\u00a9\u00ad\7\5\2\2\u00aa\u00ac\5\b\5\2\u00ab\u00aa\3\2\2\2\u00ac"+
- "\u00af\3\2\2\2\u00ad\u00ab\3\2\2\2\u00ad\u00ae\3\2\2\2\u00ae\u00b0\3\2"+
- "\2\2\u00af\u00ad\3\2\2\2\u00b0\u00b1\7\6\2\2\u00b1\r\3\2\2\2\u00b2\u00b3"+
- "\7\r\2\2\u00b3\17\3\2\2\2\u00b4\u00b7\5\24\13\2\u00b5\u00b7\5 \21\2\u00b6"+
- "\u00b4\3\2\2\2\u00b6\u00b5\3\2\2\2\u00b7\21\3\2\2\2\u00b8\u00b9\5 \21"+
- "\2\u00b9\23\3\2\2\2\u00ba\u00bb\5\26\f\2\u00bb\u00c0\5\32\16\2\u00bc\u00bd"+
- "\7\f\2\2\u00bd\u00bf\5\32\16\2\u00be\u00bc\3\2\2\2\u00bf\u00c2\3\2\2\2"+
- "\u00c0\u00be\3\2\2\2\u00c0\u00c1\3\2\2\2\u00c1\25\3\2\2\2\u00c2\u00c0"+
- "\3\2\2\2\u00c3\u00c8\7J\2\2\u00c4\u00c5\7\7\2\2\u00c5\u00c7\7\b\2\2\u00c6"+
- "\u00c4\3\2\2\2\u00c7\u00ca\3\2\2\2\u00c8\u00c6\3\2\2\2\u00c8\u00c9\3\2"+
- "\2\2\u00c9\27\3\2\2\2\u00ca\u00c8\3\2\2\2\u00cb\u00cc\7J\2\2\u00cc\u00cd"+
- "\7\63\2\2\u00cd\u00ce\t\2\2\2\u00ce\31\3\2\2\2\u00cf\u00d2\7K\2\2\u00d0"+
- "\u00d1\7\66\2\2\u00d1\u00d3\5 \21\2\u00d2\u00d0\3\2\2\2\u00d2\u00d3\3"+
- "\2\2\2\u00d3\33\3\2\2\2\u00d4\u00d5\7\30\2\2\u00d5\u00d6\7\t\2\2\u00d6"+
- "\u00d7\7J\2\2\u00d7\u00d8\7K\2\2\u00d8\u00d9\7\n\2\2\u00d9\u00da\5\f\7"+
- "\2\u00da\35\3\2\2\2\u00db\u00dc\t\3\2\2\u00dc\37\3\2\2\2\u00dd\u00de\b"+
- "\21\1\2\u00de\u00df\5$\23\2\u00df\u00e0\t\4\2\2\u00e0\u00e1\5 \21\3\u00e1"+
- "\u00e2\b\21\1\2\u00e2\u00e7\3\2\2\2\u00e3\u00e4\5\"\22\2\u00e4\u00e5\b"+
- "\21\1\2\u00e5\u00e7\3\2\2\2\u00e6\u00dd\3\2\2\2\u00e6\u00e3\3\2\2\2\u00e7"+
- "\u0123\3\2\2\2\u00e8\u00e9\f\16\2\2\u00e9\u00ea\t\5\2\2\u00ea\u00eb\5"+
- " \21\17\u00eb\u00ec\b\21\1\2\u00ec\u0122\3\2\2\2\u00ed\u00ee\f\r\2\2\u00ee"+
- "\u00ef\t\6\2\2\u00ef\u00f0\5 \21\16\u00f0\u00f1\b\21\1\2\u00f1\u0122\3"+
- "\2\2\2\u00f2\u00f3\f\f\2\2\u00f3\u00f4\t\7\2\2\u00f4\u00f5\5 \21\r\u00f5"+
- "\u00f6\b\21\1\2\u00f6\u0122\3\2\2\2\u00f7\u00f8\f\13\2\2\u00f8\u00f9\t"+
- "\b\2\2\u00f9\u00fa\5 \21\f\u00fa\u00fb\b\21\1\2\u00fb\u0122\3\2\2\2\u00fc"+
- "\u00fd\f\n\2\2\u00fd\u00fe\t\t\2\2\u00fe\u00ff\5 \21\13\u00ff\u0100\b"+
- "\21\1\2\u0100\u0122\3\2\2\2\u0101\u0102\f\t\2\2\u0102\u0103\7,\2\2\u0103"+
- "\u0104\5 \21\n\u0104\u0105\b\21\1\2\u0105\u0122\3\2\2\2\u0106\u0107\f"+
- "\b\2\2\u0107\u0108\7-\2\2\u0108\u0109\5 \21\t\u0109\u010a\b\21\1\2\u010a"+
- "\u0122\3\2\2\2\u010b\u010c\f\7\2\2\u010c\u010d\7.\2\2\u010d\u010e\5 \21"+
- "\b\u010e\u010f\b\21\1\2\u010f\u0122\3\2\2\2\u0110\u0111\f\6\2\2\u0111"+
- "\u0112\7/\2\2\u0112\u0113\5 \21\7\u0113\u0114\b\21\1\2\u0114\u0122\3\2"+
- "\2\2\u0115\u0116\f\5\2\2\u0116\u0117\7\60\2\2\u0117\u0118\5 \21\6\u0118"+
- "\u0119\b\21\1\2\u0119\u0122\3\2\2\2\u011a\u011b\f\4\2\2\u011b\u011c\7"+
- "\61\2\2\u011c\u011d\5 \21\2\u011d\u011e\7\62\2\2\u011e\u011f\5 \21\4\u011f"+
- "\u0120\b\21\1\2\u0120\u0122\3\2\2\2\u0121\u00e8\3\2\2\2\u0121\u00ed\3"+
- "\2\2\2\u0121\u00f2\3\2\2\2\u0121\u00f7\3\2\2\2\u0121\u00fc\3\2\2\2\u0121"+
- "\u0101\3\2\2\2\u0121\u0106\3\2\2\2\u0121\u010b\3\2\2\2\u0121\u0110\3\2"+
- "\2\2\u0121\u0115\3\2\2\2\u0121\u011a\3\2\2\2\u0122\u0125\3\2\2\2\u0123"+
- "\u0121\3\2\2\2\u0123\u0124\3\2\2\2\u0124!\3\2\2\2\u0125\u0123\3\2\2\2"+
- "\u0126\u0127\6\22\16\3\u0127\u0128\t\n\2\2\u0128\u0144\5$\23\2\u0129\u012a"+
- "\6\22\17\3\u012a\u012b\5$\23\2\u012b\u012c\t\n\2\2\u012c\u0144\3\2\2\2"+
- "\u012d\u012e\6\22\20\3\u012e\u0144\5$\23\2\u012f\u0130\6\22\21\3\u0130"+
- "\u0131\t\13\2\2\u0131\u0144\b\22\1\2\u0132\u0133\6\22\22\3\u0133\u0134"+
- "\7G\2\2\u0134\u0144\b\22\1\2\u0135\u0136\6\22\23\3\u0136\u0137\7H\2\2"+
- "\u0137\u0144\b\22\1\2\u0138\u0139\6\22\24\3\u0139\u013a\7I\2\2\u013a\u0144"+
- "\b\22\1\2\u013b\u013c\6\22\25\3\u013c\u013d\t\f\2\2\u013d\u0144\5\"\22"+
- "\2\u013e\u013f\7\t\2\2\u013f\u0140\5\26\f\2\u0140\u0141\7\n\2\2\u0141"+
- "\u0142\5\"\22\2\u0142\u0144\3\2\2\2\u0143\u0126\3\2\2\2\u0143\u0129\3"+
- "\2\2\2\u0143\u012d\3\2\2\2\u0143\u012f\3\2\2\2\u0143\u0132\3\2\2\2\u0143"+
- "\u0135\3\2\2\2\u0143\u0138\3\2\2\2\u0143\u013b\3\2\2\2\u0143\u013e\3\2"+
- "\2\2\u0144#\3\2\2\2\u0145\u0149\5&\24\2\u0146\u0148\5(\25\2\u0147\u0146"+
- "\3\2\2\2\u0148\u014b\3\2\2\2\u0149\u0147\3\2\2\2\u0149\u014a\3\2\2\2\u014a"+
- "\u0168\3\2\2\2\u014b\u0149\3\2\2\2\u014c\u014d\5\26\f\2\u014d\u0151\5"+
- "*\26\2\u014e\u0150\5(\25\2\u014f\u014e\3\2\2\2\u0150\u0153\3\2\2\2\u0151"+
- "\u014f\3\2\2\2\u0151\u0152\3\2\2\2\u0152\u0168\3\2\2\2\u0153\u0151\3\2"+
- "\2\2\u0154\u0155\7\26\2\2\u0155\u015a\7J\2\2\u0156\u0157\7\7\2\2\u0157"+
- "\u0158\5 \21\2\u0158\u0159\7\b\2\2\u0159\u015b\3\2\2\2\u015a\u0156\3\2"+
- "\2\2\u015b\u015c\3\2\2\2\u015c\u015a\3\2\2\2\u015c\u015d\3\2\2\2\u015d"+
- "\u0165\3\2\2\2\u015e\u0162\5*\26\2\u015f\u0161\5(\25\2\u0160\u015f\3\2"+
- "\2\2\u0161\u0164\3\2\2\2\u0162\u0160\3\2\2\2\u0162\u0163\3\2\2\2\u0163"+
- "\u0166\3\2\2\2\u0164\u0162\3\2\2\2\u0165\u015e\3\2\2\2\u0165\u0166\3\2"+
- "\2\2\u0166\u0168\3\2\2\2\u0167\u0145\3\2\2\2\u0167\u014c\3\2\2\2\u0167"+
- "\u0154\3\2\2\2\u0168%\3\2\2\2\u0169\u016a\6\24\26\3\u016a\u016b\7\t\2"+
- "\2\u016b\u016c\5 \21\2\u016c\u016d\7\n\2\2\u016d\u016e\b\24\1\2\u016e"+
- "\u017c\3\2\2\2\u016f\u0170\6\24\27\3\u0170\u0171\7\t\2\2\u0171\u0172\5"+
- "\"\22\2\u0172\u0173\7\n\2\2\u0173\u017c\3\2\2\2\u0174\u017c\7F\2\2\u0175"+
- "\u017c\7K\2\2\u0176\u0177\7K\2\2\u0177\u017c\5.\30\2\u0178\u0179\7\26"+
- "\2\2\u0179\u017a\7J\2\2\u017a\u017c\5.\30\2\u017b\u0169\3\2\2\2\u017b"+
- "\u016f\3\2\2\2\u017b\u0174\3\2\2\2\u017b\u0175\3\2\2\2\u017b\u0176\3\2"+
- "\2\2\u017b\u0178\3\2\2\2\u017c\'\3\2\2\2\u017d\u017e\6\25\30\3\u017e\u0182"+
- "\5*\26\2\u017f\u0180\6\25\31\3\u0180\u0182\5,\27\2\u0181\u017d\3\2\2\2"+
- "\u0181\u017f\3\2\2\2\u0182)\3\2\2\2\u0183\u0184\7\13\2\2\u0184\u0185\7"+
- "M\2\2\u0185\u0189\5.\30\2\u0186\u0187\7\13\2\2\u0187\u0189\t\r\2\2\u0188"+
- "\u0183\3\2\2\2\u0188\u0186\3\2\2\2\u0189+\3\2\2\2\u018a\u018b\7\7\2\2"+
- "\u018b\u018c\5 \21\2\u018c\u018d\7\b\2\2\u018d-\3\2\2\2\u018e\u0197\7"+
- "\t\2\2\u018f\u0194\5\60\31\2\u0190\u0191\7\f\2\2\u0191\u0193\5\60\31\2"+
- "\u0192\u0190\3\2\2\2\u0193\u0196\3\2\2\2\u0194\u0192\3\2\2\2\u0194\u0195"+
- "\3\2\2\2\u0195\u0198\3\2\2\2\u0196\u0194\3\2\2\2\u0197\u018f\3\2\2\2\u0197"+
- "\u0198\3\2\2\2\u0198\u0199\3\2\2\2\u0199\u019a\7\n\2\2\u019a/\3\2\2\2"+
- "\u019b\u019e\5 \21\2\u019c\u019e\5\30\r\2\u019d\u019b\3\2\2\2\u019d\u019c"+
- "\3\2\2\2\u019e\61\3\2\2\2$\65;NQ]ervz\177\u009a\u00a3\u00a7\u00ad\u00b6"+
- "\u00c0\u00c8\u00d2\u00e6\u0121\u0123\u0143\u0149\u0151\u015c\u0162\u0165"+
- "\u0167\u017b\u0181\u0188\u0194\u0197\u019d";
+ "\3\22\3\22\3\22\3\22\3\22\3\22\3\22\3\22\5\22\u0148\n\22\3\23\3\23\7\23"+
+ "\u014c\n\23\f\23\16\23\u014f\13\23\3\23\3\23\3\23\7\23\u0154\n\23\f\23"+
+ "\16\23\u0157\13\23\3\23\3\23\3\23\3\23\3\23\3\23\6\23\u015f\n\23\r\23"+
+ "\16\23\u0160\3\23\3\23\7\23\u0165\n\23\f\23\16\23\u0168\13\23\5\23\u016a"+
+ "\n\23\5\23\u016c\n\23\3\24\3\24\3\24\3\24\3\24\3\24\3\24\3\24\3\24\3\24"+
+ "\3\24\3\24\3\24\3\24\3\24\3\24\3\24\3\24\5\24\u0180\n\24\3\25\3\25\3\25"+
+ "\3\25\5\25\u0186\n\25\3\26\3\26\3\26\3\26\3\26\5\26\u018d\n\26\3\27\3"+
+ "\27\3\27\3\27\3\30\3\30\3\30\3\30\7\30\u0197\n\30\f\30\16\30\u019a\13"+
+ "\30\5\30\u019c\n\30\3\30\3\30\3\31\3\31\5\31\u01a2\n\31\3\31\2\3 \32\2"+
+ "\4\6\b\n\f\16\20\22\24\26\30\32\34\36 \"$&(*,.\60\2\16\4\2\26\26KK\3\3"+
+ "\r\r\3\2\66A\3\2\34\36\3\2\37 \3\2!#\3\2$\'\3\2(+\3\2\64\65\3\2BE\4\2"+
+ "\32\33\37 \3\2LM\u01cd\2\65\3\2\2\2\4@\3\2\2\2\6E\3\2\2\2\b\u00a3\3\2"+
+ "\2\2\n\u00a7\3\2\2\2\f\u00a9\3\2\2\2\16\u00b2\3\2\2\2\20\u00b6\3\2\2\2"+
+ "\22\u00b8\3\2\2\2\24\u00ba\3\2\2\2\26\u00c3\3\2\2\2\30\u00d1\3\2\2\2\32"+
+ "\u00d3\3\2\2\2\34\u00d8\3\2\2\2\36\u00df\3\2\2\2 \u00ea\3\2\2\2\"\u0147"+
+ "\3\2\2\2$\u016b\3\2\2\2&\u017f\3\2\2\2(\u0185\3\2\2\2*\u018c\3\2\2\2,"+
+ "\u018e\3\2\2\2.\u0192\3\2\2\2\60\u01a1\3\2\2\2\62\64\5\4\3\2\63\62\3\2"+
+ "\2\2\64\67\3\2\2\2\65\63\3\2\2\2\65\66\3\2\2\2\66;\3\2\2\2\67\65\3\2\2"+
+ "\28:\5\b\5\298\3\2\2\2:=\3\2\2\2;9\3\2\2\2;<\3\2\2\2<>\3\2\2\2=;\3\2\2"+
+ "\2>?\7\2\2\3?\3\3\2\2\2@A\5\26\f\2AB\7K\2\2BC\5\6\4\2CD\5\f\7\2D\5\3\2"+
+ "\2\2EQ\7\t\2\2FG\5\26\f\2GN\7K\2\2HI\7\f\2\2IJ\5\26\f\2JK\7K\2\2KM\3\2"+
+ "\2\2LH\3\2\2\2MP\3\2\2\2NL\3\2\2\2NO\3\2\2\2OR\3\2\2\2PN\3\2\2\2QF\3\2"+
+ "\2\2QR\3\2\2\2RS\3\2\2\2ST\7\n\2\2T\7\3\2\2\2UV\7\16\2\2VW\7\t\2\2WX\5"+
+ " \21\2XY\7\n\2\2Y]\5\n\6\2Z[\7\17\2\2[^\5\n\6\2\\^\6\5\2\2]Z\3\2\2\2]"+
+ "\\\3\2\2\2^\u00a4\3\2\2\2_`\7\20\2\2`a\7\t\2\2ab\5 \21\2be\7\n\2\2cf\5"+
+ "\n\6\2df\5\16\b\2ec\3\2\2\2ed\3\2\2\2f\u00a4\3\2\2\2gh\7\21\2\2hi\5\f"+
+ "\7\2ij\7\20\2\2jk\7\t\2\2kl\5 \21\2lm\7\n\2\2mn\5\36\20\2n\u00a4\3\2\2"+
+ "\2op\7\22\2\2pr\7\t\2\2qs\5\20\t\2rq\3\2\2\2rs\3\2\2\2st\3\2\2\2tv\7\r"+
+ "\2\2uw\5 \21\2vu\3\2\2\2vw\3\2\2\2wx\3\2\2\2xz\7\r\2\2y{\5\22\n\2zy\3"+
+ "\2\2\2z{\3\2\2\2{|\3\2\2\2|\177\7\n\2\2}\u0080\5\n\6\2~\u0080\5\16\b\2"+
+ "\177}\3\2\2\2\177~\3\2\2\2\u0080\u00a4\3\2\2\2\u0081\u0082\7\22\2\2\u0082"+
+ "\u0083\7\t\2\2\u0083\u0084\5\26\f\2\u0084\u0085\7K\2\2\u0085\u0086\7\62"+
+ "\2\2\u0086\u0087\5 \21\2\u0087\u0088\7\n\2\2\u0088\u0089\5\n\6\2\u0089"+
+ "\u00a4\3\2\2\2\u008a\u008b\5\24\13\2\u008b\u008c\5\36\20\2\u008c\u00a4"+
+ "\3\2\2\2\u008d\u008e\7\23\2\2\u008e\u00a4\5\36\20\2\u008f\u0090\7\24\2"+
+ "\2\u0090\u00a4\5\36\20\2\u0091\u0092\7\25\2\2\u0092\u0093\5 \21\2\u0093"+
+ "\u0094\5\36\20\2\u0094\u00a4\3\2\2\2\u0095\u0096\7\27\2\2\u0096\u0098"+
+ "\5\f\7\2\u0097\u0099\5\34\17\2\u0098\u0097\3\2\2\2\u0099\u009a\3\2\2\2"+
+ "\u009a\u0098\3\2\2\2\u009a\u009b\3\2\2\2\u009b\u00a4\3\2\2\2\u009c\u009d"+
+ "\7\31\2\2\u009d\u009e\5 \21\2\u009e\u009f\5\36\20\2\u009f\u00a4\3\2\2"+
+ "\2\u00a0\u00a1\5 \21\2\u00a1\u00a2\5\36\20\2\u00a2\u00a4\3\2\2\2\u00a3"+
+ "U\3\2\2\2\u00a3_\3\2\2\2\u00a3g\3\2\2\2\u00a3o\3\2\2\2\u00a3\u0081\3\2"+
+ "\2\2\u00a3\u008a\3\2\2\2\u00a3\u008d\3\2\2\2\u00a3\u008f\3\2\2\2\u00a3"+
+ "\u0091\3\2\2\2\u00a3\u0095\3\2\2\2\u00a3\u009c\3\2\2\2\u00a3\u00a0\3\2"+
+ "\2\2\u00a4\t\3\2\2\2\u00a5\u00a8\5\f\7\2\u00a6\u00a8\5\b\5\2\u00a7\u00a5"+
+ "\3\2\2\2\u00a7\u00a6\3\2\2\2\u00a8\13\3\2\2\2\u00a9\u00ad\7\5\2\2\u00aa"+
+ "\u00ac\5\b\5\2\u00ab\u00aa\3\2\2\2\u00ac\u00af\3\2\2\2\u00ad\u00ab\3\2"+
+ "\2\2\u00ad\u00ae\3\2\2\2\u00ae\u00b0\3\2\2\2\u00af\u00ad\3\2\2\2\u00b0"+
+ "\u00b1\7\6\2\2\u00b1\r\3\2\2\2\u00b2\u00b3\7\r\2\2\u00b3\17\3\2\2\2\u00b4"+
+ "\u00b7\5\24\13\2\u00b5\u00b7\5 \21\2\u00b6\u00b4\3\2\2\2\u00b6\u00b5\3"+
+ "\2\2\2\u00b7\21\3\2\2\2\u00b8\u00b9\5 \21\2\u00b9\23\3\2\2\2\u00ba\u00bb"+
+ "\5\26\f\2\u00bb\u00c0\5\32\16\2\u00bc\u00bd\7\f\2\2\u00bd\u00bf\5\32\16"+
+ "\2\u00be\u00bc\3\2\2\2\u00bf\u00c2\3\2\2\2\u00c0\u00be\3\2\2\2\u00c0\u00c1"+
+ "\3\2\2\2\u00c1\25\3\2\2\2\u00c2\u00c0\3\2\2\2\u00c3\u00c8\7J\2\2\u00c4"+
+ "\u00c5\7\7\2\2\u00c5\u00c7\7\b\2\2\u00c6\u00c4\3\2\2\2\u00c7\u00ca\3\2"+
+ "\2\2\u00c8\u00c6\3\2\2\2\u00c8\u00c9\3\2\2\2\u00c9\27\3\2\2\2\u00ca\u00c8"+
+ "\3\2\2\2\u00cb\u00cc\7J\2\2\u00cc\u00cd\7\63\2\2\u00cd\u00d2\t\2\2\2\u00ce"+
+ "\u00cf\7K\2\2\u00cf\u00d0\7\63\2\2\u00d0\u00d2\7K\2\2\u00d1\u00cb\3\2"+
+ "\2\2\u00d1\u00ce\3\2\2\2\u00d2\31\3\2\2\2\u00d3\u00d6\7K\2\2\u00d4\u00d5"+
+ "\7\66\2\2\u00d5\u00d7\5 \21\2\u00d6\u00d4\3\2\2\2\u00d6\u00d7\3\2\2\2"+
+ "\u00d7\33\3\2\2\2\u00d8\u00d9\7\30\2\2\u00d9\u00da\7\t\2\2\u00da\u00db"+
+ "\7J\2\2\u00db\u00dc\7K\2\2\u00dc\u00dd\7\n\2\2\u00dd\u00de\5\f\7\2\u00de"+
+ "\35\3\2\2\2\u00df\u00e0\t\3\2\2\u00e0\37\3\2\2\2\u00e1\u00e2\b\21\1\2"+
+ "\u00e2\u00e3\5$\23\2\u00e3\u00e4\t\4\2\2\u00e4\u00e5\5 \21\3\u00e5\u00e6"+
+ "\b\21\1\2\u00e6\u00eb\3\2\2\2\u00e7\u00e8\5\"\22\2\u00e8\u00e9\b\21\1"+
+ "\2\u00e9\u00eb\3\2\2\2\u00ea\u00e1\3\2\2\2\u00ea\u00e7\3\2\2\2\u00eb\u0127"+
+ "\3\2\2\2\u00ec\u00ed\f\16\2\2\u00ed\u00ee\t\5\2\2\u00ee\u00ef\5 \21\17"+
+ "\u00ef\u00f0\b\21\1\2\u00f0\u0126\3\2\2\2\u00f1\u00f2\f\r\2\2\u00f2\u00f3"+
+ "\t\6\2\2\u00f3\u00f4\5 \21\16\u00f4\u00f5\b\21\1\2\u00f5\u0126\3\2\2\2"+
+ "\u00f6\u00f7\f\f\2\2\u00f7\u00f8\t\7\2\2\u00f8\u00f9\5 \21\r\u00f9\u00fa"+
+ "\b\21\1\2\u00fa\u0126\3\2\2\2\u00fb\u00fc\f\13\2\2\u00fc\u00fd\t\b\2\2"+
+ "\u00fd\u00fe\5 \21\f\u00fe\u00ff\b\21\1\2\u00ff\u0126\3\2\2\2\u0100\u0101"+
+ "\f\n\2\2\u0101\u0102\t\t\2\2\u0102\u0103\5 \21\13\u0103\u0104\b\21\1\2"+
+ "\u0104\u0126\3\2\2\2\u0105\u0106\f\t\2\2\u0106\u0107\7,\2\2\u0107\u0108"+
+ "\5 \21\n\u0108\u0109\b\21\1\2\u0109\u0126\3\2\2\2\u010a\u010b\f\b\2\2"+
+ "\u010b\u010c\7-\2\2\u010c\u010d\5 \21\t\u010d\u010e\b\21\1\2\u010e\u0126"+
+ "\3\2\2\2\u010f\u0110\f\7\2\2\u0110\u0111\7.\2\2\u0111\u0112\5 \21\b\u0112"+
+ "\u0113\b\21\1\2\u0113\u0126\3\2\2\2\u0114\u0115\f\6\2\2\u0115\u0116\7"+
+ "/\2\2\u0116\u0117\5 \21\7\u0117\u0118\b\21\1\2\u0118\u0126\3\2\2\2\u0119"+
+ "\u011a\f\5\2\2\u011a\u011b\7\60\2\2\u011b\u011c\5 \21\6\u011c\u011d\b"+
+ "\21\1\2\u011d\u0126\3\2\2\2\u011e\u011f\f\4\2\2\u011f\u0120\7\61\2\2\u0120"+
+ "\u0121\5 \21\2\u0121\u0122\7\62\2\2\u0122\u0123\5 \21\4\u0123\u0124\b"+
+ "\21\1\2\u0124\u0126\3\2\2\2\u0125\u00ec\3\2\2\2\u0125\u00f1\3\2\2\2\u0125"+
+ "\u00f6\3\2\2\2\u0125\u00fb\3\2\2\2\u0125\u0100\3\2\2\2\u0125\u0105\3\2"+
+ "\2\2\u0125\u010a\3\2\2\2\u0125\u010f\3\2\2\2\u0125\u0114\3\2\2\2\u0125"+
+ "\u0119\3\2\2\2\u0125\u011e\3\2\2\2\u0126\u0129\3\2\2\2\u0127\u0125\3\2"+
+ "\2\2\u0127\u0128\3\2\2\2\u0128!\3\2\2\2\u0129\u0127\3\2\2\2\u012a\u012b"+
+ "\6\22\16\3\u012b\u012c\t\n\2\2\u012c\u0148\5$\23\2\u012d\u012e\6\22\17"+
+ "\3\u012e\u012f\5$\23\2\u012f\u0130\t\n\2\2\u0130\u0148\3\2\2\2\u0131\u0132"+
+ "\6\22\20\3\u0132\u0148\5$\23\2\u0133\u0134\6\22\21\3\u0134\u0135\t\13"+
+ "\2\2\u0135\u0148\b\22\1\2\u0136\u0137\6\22\22\3\u0137\u0138\7G\2\2\u0138"+
+ "\u0148\b\22\1\2\u0139\u013a\6\22\23\3\u013a\u013b\7H\2\2\u013b\u0148\b"+
+ "\22\1\2\u013c\u013d\6\22\24\3\u013d\u013e\7I\2\2\u013e\u0148\b\22\1\2"+
+ "\u013f\u0140\6\22\25\3\u0140\u0141\t\f\2\2\u0141\u0148\5\"\22\2\u0142"+
+ "\u0143\7\t\2\2\u0143\u0144\5\26\f\2\u0144\u0145\7\n\2\2\u0145\u0146\5"+
+ "\"\22\2\u0146\u0148\3\2\2\2\u0147\u012a\3\2\2\2\u0147\u012d\3\2\2\2\u0147"+
+ "\u0131\3\2\2\2\u0147\u0133\3\2\2\2\u0147\u0136\3\2\2\2\u0147\u0139\3\2"+
+ "\2\2\u0147\u013c\3\2\2\2\u0147\u013f\3\2\2\2\u0147\u0142\3\2\2\2\u0148"+
+ "#\3\2\2\2\u0149\u014d\5&\24\2\u014a\u014c\5(\25\2\u014b\u014a\3\2\2\2"+
+ "\u014c\u014f\3\2\2\2\u014d\u014b\3\2\2\2\u014d\u014e\3\2\2\2\u014e\u016c"+
+ "\3\2\2\2\u014f\u014d\3\2\2\2\u0150\u0151\5\26\f\2\u0151\u0155\5*\26\2"+
+ "\u0152\u0154\5(\25\2\u0153\u0152\3\2\2\2\u0154\u0157\3\2\2\2\u0155\u0153"+
+ "\3\2\2\2\u0155\u0156\3\2\2\2\u0156\u016c\3\2\2\2\u0157\u0155\3\2\2\2\u0158"+
+ "\u0159\7\26\2\2\u0159\u015e\7J\2\2\u015a\u015b\7\7\2\2\u015b\u015c\5 "+
+ "\21\2\u015c\u015d\7\b\2\2\u015d\u015f\3\2\2\2\u015e\u015a\3\2\2\2\u015f"+
+ "\u0160\3\2\2\2\u0160\u015e\3\2\2\2\u0160\u0161\3\2\2\2\u0161\u0169\3\2"+
+ "\2\2\u0162\u0166\5*\26\2\u0163\u0165\5(\25\2\u0164\u0163\3\2\2\2\u0165"+
+ "\u0168\3\2\2\2\u0166\u0164\3\2\2\2\u0166\u0167\3\2\2\2\u0167\u016a\3\2"+
+ "\2\2\u0168\u0166\3\2\2\2\u0169\u0162\3\2\2\2\u0169\u016a\3\2\2\2\u016a"+
+ "\u016c\3\2\2\2\u016b\u0149\3\2\2\2\u016b\u0150\3\2\2\2\u016b\u0158\3\2"+
+ "\2\2\u016c%\3\2\2\2\u016d\u016e\6\24\26\3\u016e\u016f\7\t\2\2\u016f\u0170"+
+ "\5 \21\2\u0170\u0171\7\n\2\2\u0171\u0172\b\24\1\2\u0172\u0180\3\2\2\2"+
+ "\u0173\u0174\6\24\27\3\u0174\u0175\7\t\2\2\u0175\u0176\5\"\22\2\u0176"+
+ "\u0177\7\n\2\2\u0177\u0180\3\2\2\2\u0178\u0180\7F\2\2\u0179\u0180\7K\2"+
+ "\2\u017a\u017b\7K\2\2\u017b\u0180\5.\30\2\u017c\u017d\7\26\2\2\u017d\u017e"+
+ "\7J\2\2\u017e\u0180\5.\30\2\u017f\u016d\3\2\2\2\u017f\u0173\3\2\2\2\u017f"+
+ "\u0178\3\2\2\2\u017f\u0179\3\2\2\2\u017f\u017a\3\2\2\2\u017f\u017c\3\2"+
+ "\2\2\u0180\'\3\2\2\2\u0181\u0182\6\25\30\3\u0182\u0186\5*\26\2\u0183\u0184"+
+ "\6\25\31\3\u0184\u0186\5,\27\2\u0185\u0181\3\2\2\2\u0185\u0183\3\2\2\2"+
+ "\u0186)\3\2\2\2\u0187\u0188\7\13\2\2\u0188\u0189\7M\2\2\u0189\u018d\5"+
+ ".\30\2\u018a\u018b\7\13\2\2\u018b\u018d\t\r\2\2\u018c\u0187\3\2\2\2\u018c"+
+ "\u018a\3\2\2\2\u018d+\3\2\2\2\u018e\u018f\7\7\2\2\u018f\u0190\5 \21\2"+
+ "\u0190\u0191\7\b\2\2\u0191-\3\2\2\2\u0192\u019b\7\t\2\2\u0193\u0198\5"+
+ "\60\31\2\u0194\u0195\7\f\2\2\u0195\u0197\5\60\31\2\u0196\u0194\3\2\2\2"+
+ "\u0197\u019a\3\2\2\2\u0198\u0196\3\2\2\2\u0198\u0199\3\2\2\2\u0199\u019c"+
+ "\3\2\2\2\u019a\u0198\3\2\2\2\u019b\u0193\3\2\2\2\u019b\u019c\3\2\2\2\u019c"+
+ "\u019d\3\2\2\2\u019d\u019e\7\n\2\2\u019e/\3\2\2\2\u019f\u01a2\5 \21\2"+
+ "\u01a0\u01a2\5\30\r\2\u01a1\u019f\3\2\2\2\u01a1\u01a0\3\2\2\2\u01a2\61"+
+ "\3\2\2\2%\65;NQ]ervz\177\u009a\u00a3\u00a7\u00ad\u00b6\u00c0\u00c8\u00d1"+
+ "\u00d6\u00ea\u0125\u0127\u0147\u014d\u0155\u0160\u0166\u0169\u016b\u017f"+
+ "\u0185\u018c\u0198\u019b\u01a1";
public static final ATN _ATN =
new ATNDeserializer().deserialize(_serializedATN.toCharArray());
static {
diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/antlr/Walker.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/antlr/Walker.java
index c1fe02f9388..aa474f14c81 100644
--- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/antlr/Walker.java
+++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/antlr/Walker.java
@@ -100,6 +100,7 @@ import org.elasticsearch.painless.node.AStatement;
import org.elasticsearch.painless.node.EBinary;
import org.elasticsearch.painless.node.EBool;
import org.elasticsearch.painless.node.EBoolean;
+import org.elasticsearch.painless.node.ECapturingFunctionRef;
import org.elasticsearch.painless.node.EChain;
import org.elasticsearch.painless.node.EComp;
import org.elasticsearch.painless.node.EConditional;
@@ -447,15 +448,19 @@ public final class Walker extends PainlessParserBaseVisitor {
@Override
public Object visitFuncref(FuncrefContext ctx) {
- final String methodText;
- if (ctx.ID() != null) {
- methodText = ctx.ID().getText();
- } else if (ctx.NEW() != null ){
- methodText = ctx.NEW().getText();
+ if (ctx.TYPE() != null) {
+ // non-capturing Type::method or Type::new
+ final String methodText;
+ if (ctx.NEW() != null) {
+ methodText = ctx.NEW().getText();
+ } else {
+ methodText = ctx.ID(0).getText();
+ }
+ return new EFunctionRef(location(ctx), ctx.TYPE().getText(), methodText);
} else {
- throw location(ctx).createError(new IllegalStateException("Illegal tree structure."));
+ // capturing object::method
+ return new ECapturingFunctionRef(location(ctx), ctx.ID(0).getText(), ctx.ID(1).getText());
}
- return new EFunctionRef(location(ctx), ctx.TYPE().getText(), methodText);
}
@Override
diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ECapturingFunctionRef.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ECapturingFunctionRef.java
new file mode 100644
index 00000000000..3e35602a3a2
--- /dev/null
+++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ECapturingFunctionRef.java
@@ -0,0 +1,119 @@
+/*
+ * 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.DefBootstrap;
+import org.elasticsearch.painless.Definition;
+import org.elasticsearch.painless.FunctionRef;
+import org.elasticsearch.painless.Location;
+import org.elasticsearch.painless.MethodWriter;
+import org.elasticsearch.painless.Locals;
+import org.elasticsearch.painless.Locals.Variable;
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.Type;
+
+import static org.elasticsearch.painless.WriterConstants.DEF_BOOTSTRAP_HANDLE;
+import static org.elasticsearch.painless.WriterConstants.LAMBDA_BOOTSTRAP_HANDLE;
+
+import java.lang.invoke.LambdaMetafactory;
+
+/**
+ * Represents a capturing function reference.
+ */
+public class ECapturingFunctionRef extends AExpression {
+ public final String type;
+ public final String call;
+
+ private FunctionRef ref;
+ Variable captured;
+ private boolean defInterface;
+
+ public ECapturingFunctionRef(Location location, String type, String call) {
+ super(location);
+
+ this.type = type;
+ this.call = call;
+ }
+
+ @Override
+ void analyze(Locals variables) {
+ captured = variables.getVariable(location, type);
+ if (expected == null) {
+ defInterface = true;
+ actual = Definition.getType("String");
+ } else {
+ defInterface = false;
+ // static case
+ if (captured.type.sort != Definition.Sort.DEF) {
+ try {
+ ref = new FunctionRef(expected, captured.type.name, call, captured.type.clazz);
+ } catch (IllegalArgumentException e) {
+ throw createError(e);
+ }
+ }
+ actual = expected;
+ }
+ }
+
+ @Override
+ void write(MethodWriter writer) {
+ writer.writeDebugInfo(location);
+ if (defInterface && captured.type.sort == Definition.Sort.DEF) {
+ // dynamic interface, dynamic implementation
+ writer.push("D" + type + "." + call + ",1");
+ writer.visitVarInsn(captured.type.type.getOpcode(Opcodes.ILOAD), captured.slot);
+ } else if (defInterface) {
+ // dynamic interface, typed implementation
+ writer.push("S" + captured.type.name + "." + call + ",1");
+ writer.visitVarInsn(captured.type.type.getOpcode(Opcodes.ILOAD), captured.slot);
+ } else if (ref == null) {
+ // typed interface, dynamic implementation
+ writer.visitVarInsn(captured.type.type.getOpcode(Opcodes.ILOAD), captured.slot);
+ String descriptor = Type.getMethodType(expected.type, captured.type.type).getDescriptor();
+ writer.invokeDynamic(call, descriptor, DEF_BOOTSTRAP_HANDLE, (Object)DefBootstrap.REFERENCE, expected.name);
+ } else {
+ // typed interface, typed implementation
+ writer.visitVarInsn(captured.type.type.getOpcode(Opcodes.ILOAD), captured.slot);
+ // convert MethodTypes to asm Type for the constant pool.
+ String invokedType = ref.invokedType.toMethodDescriptorString();
+ Type samMethodType = Type.getMethodType(ref.samMethodType.toMethodDescriptorString());
+ Type interfaceType = Type.getMethodType(ref.interfaceMethodType.toMethodDescriptorString());
+ if (ref.needsBridges()) {
+ writer.invokeDynamic(ref.invokedName,
+ invokedType,
+ LAMBDA_BOOTSTRAP_HANDLE,
+ samMethodType,
+ ref.implMethodASM,
+ samMethodType,
+ LambdaMetafactory.FLAG_BRIDGES,
+ 1,
+ interfaceType);
+ } else {
+ writer.invokeDynamic(ref.invokedName,
+ invokedType,
+ LAMBDA_BOOTSTRAP_HANDLE,
+ samMethodType,
+ ref.implMethodASM,
+ samMethodType,
+ 0);
+ }
+ }
+ }
+}
diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EFunctionRef.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EFunctionRef.java
index ec45f89868a..9d96809bf25 100644
--- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EFunctionRef.java
+++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EFunctionRef.java
@@ -64,7 +64,7 @@ public class EFunctionRef extends AExpression {
@Override
void write(MethodWriter writer) {
if (ref == null) {
- writer.push(type + "." + call);
+ writer.push("S" + type + "." + call + ",0");
} else {
writer.writeDebugInfo(location);
// convert MethodTypes to asm Type for the constant pool.
diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/LDefArray.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/LDefArray.java
index 524f62eea15..dc8890e5122 100644
--- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/LDefArray.java
+++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/LDefArray.java
@@ -62,7 +62,7 @@ final class LDefArray extends ALink implements IDefLink {
writer.writeDebugInfo(location);
String desc = Type.getMethodDescriptor(after.type, Definition.DEF_TYPE.type, index.actual.type);
- writer.invokeDynamic("arrayLoad", desc, DEF_BOOTSTRAP_HANDLE, (Object)DefBootstrap.ARRAY_LOAD, 0);
+ writer.invokeDynamic("arrayLoad", desc, DEF_BOOTSTRAP_HANDLE, (Object)DefBootstrap.ARRAY_LOAD);
}
@Override
@@ -70,6 +70,6 @@ final class LDefArray extends ALink implements IDefLink {
writer.writeDebugInfo(location);
String desc = Type.getMethodDescriptor(Definition.VOID_TYPE.type, Definition.DEF_TYPE.type, index.actual.type, after.type);
- writer.invokeDynamic("arrayStore", desc, DEF_BOOTSTRAP_HANDLE, (Object)DefBootstrap.ARRAY_STORE, 0);
+ writer.invokeDynamic("arrayStore", desc, DEF_BOOTSTRAP_HANDLE, (Object)DefBootstrap.ARRAY_STORE);
}
}
diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/LDefCall.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/LDefCall.java
index 871bd2273db..554144c2999 100644
--- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/LDefCall.java
+++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/LDefCall.java
@@ -55,11 +55,15 @@ final class LDefCall extends ALink implements IDefLink {
}
recipe = 0;
+ int totalCaptures = 0;
for (int argument = 0; argument < arguments.size(); ++argument) {
AExpression expression = arguments.get(argument);
if (expression instanceof EFunctionRef) {
- recipe |= (1L << argument); // mark argument as deferred reference
+ recipe |= (1L << (argument + totalCaptures)); // mark argument as deferred reference
+ } else if (expression instanceof ECapturingFunctionRef) {
+ recipe |= (1L << (argument + totalCaptures)); // mark argument as deferred reference
+ totalCaptures++;
}
expression.internal = true;
expression.analyze(locals);
@@ -90,6 +94,10 @@ final class LDefCall extends ALink implements IDefLink {
for (AExpression argument : arguments) {
signature.append(argument.actual.type.getDescriptor());
+ if (argument instanceof ECapturingFunctionRef) {
+ ECapturingFunctionRef capturingRef = (ECapturingFunctionRef) argument;
+ signature.append(capturingRef.captured.type.type.getDescriptor());
+ }
argument.write(writer);
}
diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/LDefField.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/LDefField.java
index 861dfe0df53..91ee8e0f03d 100644
--- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/LDefField.java
+++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/LDefField.java
@@ -59,7 +59,7 @@ final class LDefField extends ALink implements IDefLink {
writer.writeDebugInfo(location);
String desc = Type.getMethodDescriptor(after.type, Definition.DEF_TYPE.type);
- writer.invokeDynamic(value, desc, DEF_BOOTSTRAP_HANDLE, (Object)DefBootstrap.LOAD, 0);
+ writer.invokeDynamic(value, desc, DEF_BOOTSTRAP_HANDLE, (Object)DefBootstrap.LOAD);
}
@Override
@@ -67,6 +67,6 @@ final class LDefField extends ALink implements IDefLink {
writer.writeDebugInfo(location);
String desc = Type.getMethodDescriptor(Definition.VOID_TYPE.type, Definition.DEF_TYPE.type, after.type);
- writer.invokeDynamic(value, desc, DEF_BOOTSTRAP_HANDLE, (Object)DefBootstrap.STORE, 0);
+ writer.invokeDynamic(value, desc, DEF_BOOTSTRAP_HANDLE, (Object)DefBootstrap.STORE);
}
}
diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SEach.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SEach.java
index b42bd1aff5a..a6156324873 100644
--- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SEach.java
+++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SEach.java
@@ -195,7 +195,7 @@ public class SEach extends AStatement {
if (method == null) {
Type itr = Definition.getType("Iterator");
String desc = org.objectweb.asm.Type.getMethodDescriptor(itr.type, Definition.DEF_TYPE.type);
- writer.invokeDynamic("iterator", desc, DEF_BOOTSTRAP_HANDLE, (Object)DefBootstrap.ITERATOR, (Object)0);
+ writer.invokeDynamic("iterator", desc, DEF_BOOTSTRAP_HANDLE, (Object)DefBootstrap.ITERATOR);
} else if (java.lang.reflect.Modifier.isInterface(method.owner.clazz.getModifiers())) {
writer.invokeInterface(method.owner.type, method.method);
} else {
diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/package-info.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/package-info.java
index 8ab69366f24..d98e5f68bcf 100644
--- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/package-info.java
+++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/package-info.java
@@ -35,6 +35,7 @@
* {@link org.elasticsearch.painless.node.EBinary} - Represents a binary math expression.
* {@link org.elasticsearch.painless.node.EBool} - Represents a boolean expression.
* {@link org.elasticsearch.painless.node.EBoolean} - Represents a boolean constant.
+ * {@link org.elasticsearch.painless.node.ECapturingFunctionRef} - Represents a function reference (capturing).
* {@link org.elasticsearch.painless.node.ECast} - Represents an implicit cast in most cases. (Internal only.)
* {@link org.elasticsearch.painless.node.EChain} - Represents the entirety of a variable/method chain for read/write operations.
* {@link org.elasticsearch.painless.node.EComp} - Represents a comparison expression.
@@ -42,7 +43,7 @@
* {@link org.elasticsearch.painless.node.EConstant} - Represents a constant. (Internal only.)
* {@link org.elasticsearch.painless.node.EDecimal} - Represents a decimal constant.
* {@link org.elasticsearch.painless.node.EExplicit} - Represents an explicit cast.
- * {@link org.elasticsearch.painless.node.EFunctionRef} - Represents a function reference.
+ * {@link org.elasticsearch.painless.node.EFunctionRef} - Represents a function reference (non-capturing).
* {@link org.elasticsearch.painless.node.ENull} - Represents a null constant.
* {@link org.elasticsearch.painless.node.ENumeric} - Represents a non-decimal numeric constant.
* {@link org.elasticsearch.painless.node.EUnary} - Represents a unary math expression.
diff --git a/modules/lang-painless/src/main/resources/org/elasticsearch/painless/org.elasticsearch.txt b/modules/lang-painless/src/main/resources/org/elasticsearch/painless/org.elasticsearch.txt
index 7fff9ac0aa4..308f2661ebc 100644
--- a/modules/lang-painless/src/main/resources/org/elasticsearch/painless/org.elasticsearch.txt
+++ b/modules/lang-painless/src/main/resources/org/elasticsearch/painless/org.elasticsearch.txt
@@ -125,4 +125,5 @@ class org.elasticsearch.painless.FeatureTest -> org.elasticsearch.painless.Featu
void setY(int)
boolean overloadedStatic()
boolean overloadedStatic(boolean)
+ Object twoFunctionsOfX(Function,Function)
}
diff --git a/modules/lang-painless/src/test/java/org/elasticsearch/painless/DefBootstrapTests.java b/modules/lang-painless/src/test/java/org/elasticsearch/painless/DefBootstrapTests.java
index 7a55844a224..4330c613e14 100644
--- a/modules/lang-painless/src/test/java/org/elasticsearch/painless/DefBootstrapTests.java
+++ b/modules/lang-painless/src/test/java/org/elasticsearch/painless/DefBootstrapTests.java
@@ -33,7 +33,7 @@ public class DefBootstrapTests extends ESTestCase {
CallSite site = DefBootstrap.bootstrap(MethodHandles.publicLookup(),
"toString",
MethodType.methodType(String.class, Object.class),
- DefBootstrap.METHOD_CALL, 0);
+ DefBootstrap.METHOD_CALL, 0L);
MethodHandle handle = site.dynamicInvoker();
assertDepthEquals(site, 0);
@@ -50,7 +50,7 @@ public class DefBootstrapTests extends ESTestCase {
CallSite site = DefBootstrap.bootstrap(MethodHandles.publicLookup(),
"toString",
MethodType.methodType(String.class, Object.class),
- DefBootstrap.METHOD_CALL, 0);
+ DefBootstrap.METHOD_CALL, 0L);
MethodHandle handle = site.dynamicInvoker();
assertDepthEquals(site, 0);
@@ -72,7 +72,7 @@ public class DefBootstrapTests extends ESTestCase {
CallSite site = DefBootstrap.bootstrap(MethodHandles.publicLookup(),
"toString",
MethodType.methodType(String.class, Object.class),
- DefBootstrap.METHOD_CALL, 0);
+ DefBootstrap.METHOD_CALL, 0L);
MethodHandle handle = site.dynamicInvoker();
assertDepthEquals(site, 0);
diff --git a/modules/lang-painless/src/test/java/org/elasticsearch/painless/FunctionRefTests.java b/modules/lang-painless/src/test/java/org/elasticsearch/painless/FunctionRefTests.java
index 12265f161ab..d3055ac228b 100644
--- a/modules/lang-painless/src/test/java/org/elasticsearch/painless/FunctionRefTests.java
+++ b/modules/lang-painless/src/test/java/org/elasticsearch/painless/FunctionRefTests.java
@@ -19,6 +19,8 @@
package org.elasticsearch.painless;
+import java.util.Comparator;
+
public class FunctionRefTests extends ScriptTestCase {
public void testStaticMethodReference() {
@@ -39,12 +41,12 @@ public class FunctionRefTests extends ScriptTestCase {
public void testCtorMethodReference() {
assertEquals(3.0D,
- exec("List l = new ArrayList(); l.add(1.0); l.add(2.0); " +
- "DoubleStream doubleStream = l.stream().mapToDouble(Double::doubleValue);" +
- "DoubleSummaryStatistics stats = doubleStream.collect(DoubleSummaryStatistics::new, " +
- "DoubleSummaryStatistics::accept, " +
- "DoubleSummaryStatistics::combine); " +
- "return stats.getSum()"));
+ exec("List l = new ArrayList(); l.add(1.0); l.add(2.0); " +
+ "DoubleStream doubleStream = l.stream().mapToDouble(Double::doubleValue);" +
+ "DoubleSummaryStatistics stats = doubleStream.collect(DoubleSummaryStatistics::new, " +
+ "DoubleSummaryStatistics::accept, " +
+ "DoubleSummaryStatistics::combine); " +
+ "return stats.getSum()"));
}
public void testCtorMethodReferenceDef() {
@@ -56,6 +58,58 @@ public class FunctionRefTests extends ScriptTestCase {
"DoubleSummaryStatistics::combine); " +
"return stats.getSum()"));
}
+
+ public void testCapturingMethodReference() {
+ 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);"));
+ }
+
+ public void testCapturingMethodReferenceDefImpl() {
+ assertEquals("5", exec("def x = Integer.valueOf(5); return Optional.empty().orElseGet(x::toString);"));
+ assertEquals("[]", exec("def l = new ArrayList(); return Optional.empty().orElseGet(l::toString);"));
+ }
+
+ public void testCapturingMethodReferenceDefInterface() {
+ assertEquals("5", exec("Integer x = Integer.valueOf(5); def opt = Optional.empty(); return opt.orElseGet(x::toString);"));
+ assertEquals("[]", exec("List l = new ArrayList(); def opt = Optional.empty(); return opt.orElseGet(l::toString);"));
+ }
+
+ public void testCapturingMethodReferenceDefEverywhere() {
+ assertEquals("5", exec("def x = Integer.valueOf(5); def opt = Optional.empty(); return opt.orElseGet(x::toString);"));
+ assertEquals("[]", exec("def l = new ArrayList(); def opt = Optional.empty(); return opt.orElseGet(l::toString);"));
+ }
+
+ public void testCapturingMethodReferenceMultipleLambdas() {
+ assertEquals("testingcdefg", exec(
+ "String x = 'testing';" +
+ "String y = 'abcdefg';" +
+ "org.elasticsearch.painless.FeatureTest test = new org.elasticsearch.painless.FeatureTest(2,3);" +
+ "return test.twoFunctionsOfX(x::concat, y::substring);"));
+ }
+
+ public void testCapturingMethodReferenceMultipleLambdasDefImpls() {
+ assertEquals("testingcdefg", exec(
+ "def x = 'testing';" +
+ "def y = 'abcdefg';" +
+ "org.elasticsearch.painless.FeatureTest test = new org.elasticsearch.painless.FeatureTest(2,3);" +
+ "return test.twoFunctionsOfX(x::concat, y::substring);"));
+ }
+
+ public void testCapturingMethodReferenceMultipleLambdasDefInterface() {
+ assertEquals("testingcdefg", exec(
+ "String x = 'testing';" +
+ "String y = 'abcdefg';" +
+ "def test = new org.elasticsearch.painless.FeatureTest(2,3);" +
+ "return test.twoFunctionsOfX(x::concat, y::substring);"));
+ }
+
+ public void testCapturingMethodReferenceMultipleLambdasDefEverywhere() {
+ assertEquals("testingcdefg", exec(
+ "def x = 'testing';" +
+ "def y = 'abcdefg';" +
+ "def test = new org.elasticsearch.painless.FeatureTest(2,3);" +
+ "return test.twoFunctionsOfX(x::concat, y::substring);"));
+ }
public void testMethodMissing() {
IllegalArgumentException expected = expectScriptThrows(IllegalArgumentException.class, () -> {