diff --git a/modules/lang-painless/src/main/antlr/PainlessParser.g4 b/modules/lang-painless/src/main/antlr/PainlessParser.g4 index 5125e7b29a6..0abab56dad2 100644 --- a/modules/lang-painless/src/main/antlr/PainlessParser.g4 +++ b/modules/lang-painless/src/main/antlr/PainlessParser.g4 @@ -73,7 +73,7 @@ decltype ; funcref - : TYPE REF ID + : TYPE REF ( ID | NEW ) ; 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 bd8e09f504b..60c42e2af55 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 @@ -22,6 +22,9 @@ package org.elasticsearch.painless; import org.elasticsearch.painless.Definition.Method; import org.elasticsearch.painless.Definition.RuntimeClass; +import java.lang.invoke.CallSite; +import java.lang.invoke.LambdaConversionException; +import java.lang.invoke.LambdaMetafactory; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodHandles.Lookup; @@ -123,7 +126,52 @@ public final class Def { } /** - * Looks up handle for a dynamic method call. + * Looks up method entry for a dynamic method call. + *

+ * A dynamic method call for variable {@code x} of type {@code def} looks like: + * {@code x.method(args...)} + *

+ * This method traverses {@code recieverClass}'s class hierarchy (including interfaces) + * until it finds a matching whitelisted method. If one is not found, it throws an exception. + * Otherwise it returns the matching method. + *

+ * @param receiverClass Class of the object to invoke the method on. + * @param name Name of the method. + * @param arity arity of method + * @return matching method to invoke. never returns null. + * @throws IllegalArgumentException if no matching whitelisted method was found. + */ + static Method lookupMethodInternal(Class receiverClass, String name, int arity) { + Definition.MethodKey key = new Definition.MethodKey(name, arity); + // check whitelist for matching method + for (Class clazz = receiverClass; clazz != null; clazz = clazz.getSuperclass()) { + RuntimeClass struct = Definition.getRuntimeClass(clazz); + + if (struct != null) { + Method method = struct.methods.get(key); + if (method != null) { + return method; + } + } + + for (Class iface : clazz.getInterfaces()) { + struct = Definition.getRuntimeClass(iface); + + if (struct != null) { + Method method = struct.methods.get(key); + if (method != null) { + return method; + } + } + } + } + + throw new IllegalArgumentException("Unable to find dynamic method [" + name + "] with [" + arity + "] arguments " + + "for class [" + receiverClass.getCanonicalName() + "]."); + } + + /** + * Looks up handle for a dynamic method call, with lambda replacement *

* A dynamic method call for variable {@code x} of type {@code def} looks like: * {@code x.method(args...)} @@ -134,41 +182,72 @@ public final class Def { *

* @param receiverClass Class of the object to invoke the method on. * @param name Name of the method. - * @param type Callsite signature. Need not match exactly, except the number of parameters. + * @param args args passed to callsite + * @param recipe bitset marking functional parameters * @return pointer to matching method to invoke. never returns null. * @throws IllegalArgumentException if no matching whitelisted method was found. */ - static MethodHandle lookupMethod(Class receiverClass, String name, MethodType type) { - // we don't consider receiver an argument/counting towards arity - type = type.dropParameterTypes(0, 1); - Definition.MethodKey key = new Definition.MethodKey(name, type.parameterCount()); - // check whitelist for matching method - for (Class clazz = receiverClass; clazz != null; clazz = clazz.getSuperclass()) { - RuntimeClass struct = Definition.getRuntimeClass(clazz); + static MethodHandle lookupMethod(Class receiverClass, String name, Object args[], long recipe) { + Method method = lookupMethodInternal(receiverClass, name, args.length - 1); + MethodHandle handle = method.handle; + MethodHandle filters[] = new MethodHandle[args.length]; - if (struct != null) { - Method method = struct.methods.get(key); - if (method != null) { - return method.handle; - } - } - - for (final Class iface : clazz.getInterfaces()) { - struct = Definition.getRuntimeClass(iface); - - if (struct != null) { - Method method = struct.methods.get(key); - if (method != null) { - return method.handle; - } + if (recipe != 0) { + 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(method.arguments.get(i - 1).clazz, (String) args[i]); } } } - - // no matching methods in whitelist found - throw new IllegalArgumentException("Unable to find dynamic method [" + name + "] with signature [" + type + "] " + - "for class [" + receiverClass.getCanonicalName() + "]."); - } + handle = MethodHandles.filterArguments(handle, 0, filters); + + return handle; + } + + /** Returns a method handle to an implementation of clazz, given method reference signature */ + private static MethodHandle lookupReference(Class clazz, String signature) { + int separator = signature.indexOf('.'); + FunctionRef ref = new FunctionRef(clazz, signature.substring(0, separator), signature.substring(separator+1)); + MethodHandles.Lookup lookup = MethodHandles.lookup(); // XXX: no lookuping needed, we should pass this from DefBootstrap! + final CallSite callSite; + // XXX: clean all this up to use handles in FunctionRef, deal with ASM in EFunctionRef differently + MethodType invokedType = MethodType.fromMethodDescriptorString(ref.invokedType.getDescriptor(), Def.class.getClassLoader()); + MethodType samMethodType = MethodType.fromMethodDescriptorString(ref.samMethodType.getDescriptor(), Def.class.getClassLoader()); + MethodType interfaceType = MethodType.fromMethodDescriptorString(ref.interfaceType.getDescriptor(), Def.class.getClassLoader()); + try { + if (ref.interfaceType.equals(ref.samMethodType)) { + callSite = LambdaMetafactory.altMetafactory(lookup, + ref.invokedName, + invokedType, + samMethodType, + ref.implMethodHandle, + samMethodType, + 0); + } else { + callSite = LambdaMetafactory.altMetafactory(lookup, + ref.invokedName, + invokedType, + samMethodType, + ref.implMethodHandle, + samMethodType, + LambdaMetafactory.FLAG_BRIDGES, + 1, + interfaceType); + } + } catch (LambdaConversionException e) { + throw new RuntimeException(e); + } + try { + // create an implementation of the interface (instance) + Object instance = callSite.dynamicInvoker().asType(MethodType.methodType(clazz)).invoke(); + // bind this instance as a constant replacement for the parameter + return MethodHandles.dropArguments(MethodHandles.constant(clazz, instance), 0, Object.class); + } catch (Throwable e) { + throw new RuntimeException(e); + } + } + /** * Looks up handle for a dynamic field getter (field load) 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 40b9cc6cbe8..4c30891dd2d 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 @@ -66,12 +66,16 @@ public final class DefBootstrap { private final String name; private final int flavor; + private final long recipe; int depth; // pkg-protected for testing - PIC(String name, MethodType type, int flavor) { + PIC(String name, MethodType type, int flavor, long recipe) { super(type); this.name = name; this.flavor = flavor; + this.recipe = recipe; + assert recipe == 0 || flavor == METHOD_CALL; + assert Long.bitCount(flavor) <= type.parameterCount(); final MethodHandle fallback = FALLBACK.bindTo(this) .asCollector(Object[].class, type.parameterCount()) @@ -91,10 +95,10 @@ public final class DefBootstrap { /** * Does a slow lookup against the whitelist. */ - private static MethodHandle lookup(int flavor, Class clazz, String name, MethodType type) { + private static MethodHandle lookup(int flavor, Class clazz, String name, Object[] args, long recipe) { switch(flavor) { case METHOD_CALL: - return Def.lookupMethod(clazz, name, type); + return Def.lookupMethod(clazz, name, args, recipe); case LOAD: return Def.lookupGetter(clazz, name); case STORE: @@ -115,7 +119,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, type).asType(type); + final MethodHandle target = lookup(flavor, receiverClass, name, args, recipe).asType(type); if (depth >= MAX_DEPTH) { // revert to a vtable call @@ -157,8 +161,8 @@ 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) { - return new PIC(name, type, flavor); + public static CallSite bootstrap(Lookup lookup, String name, MethodType type, int flavor, long recipe) { + return new PIC(name, type, flavor, recipe); } } 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 50ee4649074..061ef0d95d7 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 @@ -24,6 +24,7 @@ import java.io.InputStreamReader; import java.io.LineNumberReader; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; +import java.lang.reflect.Modifier; import java.nio.charset.StandardCharsets; import java.util.Arrays; import java.util.Collections; @@ -31,6 +32,8 @@ import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.PrimitiveIterator; +import java.util.Spliterator; /** * The entire API for Painless. Also used as a whitelist for checking for legal @@ -171,21 +174,6 @@ public final class Definition { } } - public static final class Constructor { - public final String name; - public final Struct owner; - public final List arguments; - public final org.objectweb.asm.commons.Method method; - - private Constructor(String name, Struct owner, List arguments, - org.objectweb.asm.commons.Method method) { - this.name = name; - this.owner = owner; - this.arguments = Collections.unmodifiableList(arguments); - this.method = method; - } - } - public static class Method { public final String name; public final Struct owner; @@ -287,7 +275,7 @@ public final class Definition { public final Class clazz; public final org.objectweb.asm.Type type; - public final Map constructors; + public final Map constructors; public final Map staticMethods; public final Map methods; @@ -439,6 +427,18 @@ public final class Definition { for (Map.Entry> clazz : hierarchy.entrySet()) { copyStruct(clazz.getKey(), clazz.getValue()); } + // if someone declares an interface type, its still an Object + for (Map.Entry clazz : structsMap.entrySet()) { + String name = clazz.getKey(); + Class javaPeer = clazz.getValue().clazz; + if (javaPeer.isInterface()) { + copyStruct(name, Collections.singletonList("Object")); + } else if (name.equals("def") == false && name.equals("Object") == false && javaPeer.isPrimitive() == false) { + // but otherwise, unless its a primitive type, it really should + assert hierarchy.get(name) != null : "class '" + name + "' does not extend Object!"; + assert hierarchy.get(name).contains("Object") : "class '" + name + "' does not extend Object!"; + } + } // precompute runtime classes for (Struct struct : structsMap.values()) { addRuntimeClass(struct); @@ -573,7 +573,7 @@ public final class Definition { "Owner struct [" + struct + "] not defined for constructor [" + name + "]."); } - if (!name.matches("^[_a-zA-Z][_a-zA-Z0-9]*$")) { + if (!name.matches("")) { throw new IllegalArgumentException( "Invalid constructor name [" + name + "] with the struct [" + owner.name + "]."); } @@ -611,7 +611,18 @@ public final class Definition { } final org.objectweb.asm.commons.Method asm = org.objectweb.asm.commons.Method.getMethod(reflect); - final Constructor constructor = new Constructor(name, owner, Arrays.asList(args), asm); + final Type returnType = getTypeInternal("void"); + final MethodHandle handle; + + try { + handle = MethodHandles.publicLookup().in(owner.clazz).unreflectConstructor(reflect); + } catch (final IllegalAccessException exception) { + throw new IllegalArgumentException("Constructor " + + " not found for class [" + owner.clazz.getName() + "]" + + " with arguments " + Arrays.toString(classes) + "."); + } + + final Method constructor = new Method(name, owner, returnType, Arrays.asList(args), asm, reflect.getModifiers(), handle); owner.constructors.put(methodKey, constructor); } @@ -653,7 +664,7 @@ public final class Definition { if (!elements[0].equals(className)) { throw new IllegalArgumentException("Constructors must return their own type"); } - addConstructorInternal(className, "new", args); + addConstructorInternal(className, "", args); } else { if (methodName.indexOf('/') >= 0) { String nameAndAlias[] = methodName.split("/"); @@ -720,7 +731,7 @@ public final class Definition { " method [" + name + "]" + " within the struct [" + owner.name + "]."); } - + final org.objectweb.asm.commons.Method asm = org.objectweb.asm.commons.Method.getMethod(reflect); MethodHandle handle; @@ -821,11 +832,37 @@ public final class Definition { throw new ClassCastException("Child struct [" + child.name + "]" + " is not a super type of owner struct [" + owner.name + "] in copy."); } - + for (Map.Entry kvPair : child.methods.entrySet()) { MethodKey methodKey = kvPair.getKey(); Method method = kvPair.getValue(); if (owner.methods.get(methodKey) == null) { + // sanity check, look for missing covariant/generic override + if (owner.clazz.isInterface() && child.clazz == Object.class) { + // ok + } else if (child.clazz == Spliterator.OfPrimitive.class || child.clazz == PrimitiveIterator.class) { + // ok, we rely on generics erasure for these (its guaranteed in the javadocs though!!!!) + } else { + try { + Class arguments[] = new Class[method.arguments.size()]; + for (int i = 0; i < method.arguments.size(); i++) { + arguments[i] = method.arguments.get(i).clazz; + } + java.lang.reflect.Method m = owner.clazz.getMethod(method.method.getName(), arguments); + if (m.getReturnType() != method.rtn.clazz) { + throw new IllegalStateException("missing covariant override for: " + m + " in " + owner.name); + } + if (m.isBridge() && !Modifier.isVolatile(method.modifiers)) { + // its a bridge in the destination, but not in the source, but it might still be ok, check generics: + java.lang.reflect.Method source = child.clazz.getMethod(method.method.getName(), arguments); + if (!Arrays.equals(source.getGenericParameterTypes(), source.getParameterTypes())) { + throw new IllegalStateException("missing generic override for: " + m + " in " + owner.name); + } + } + } catch (ReflectiveOperationException e) { + throw new AssertionError(e); + } + } owner.methods.put(methodKey, new Method(method.name, owner, method.rtn, method.arguments, method.method, method.modifiers, method.handle)); } 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 new file mode 100644 index 00000000000..5b121d3a31a --- /dev/null +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/FunctionRef.java @@ -0,0 +1,126 @@ +/* + * 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; + +import org.objectweb.asm.Handle; +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.Type; + +import java.lang.invoke.MethodHandle; +import java.lang.reflect.Modifier; +import java.util.HashSet; +import java.util.Set; + +/** + * computes "everything you need" to call LambdaMetaFactory, given an expected interface, + * and reference class + method name + */ +public class FunctionRef { + // XXX: this is a mess, because of ASM versus MethodHandle types + // clean all this up, move reflection out of here into definition, etc etc + public final String invokedName; + public final Type invokedType; + public final Handle implMethod; + public final Type samMethodType; + public final Type interfaceType; + + public final MethodHandle implMethodHandle; + + public FunctionRef(Class expected, String type, String call) { + boolean isCtorReference = "new".equals(call); + // check its really a functional interface + // for e.g. Comparable + java.lang.reflect.Method method = getFunctionalMethod(type, call, expected); + // e.g. compareTo + invokedName = method.getName(); + // e.g. (Object)Comparator + invokedType = Type.getMethodType(Type.getType(expected)); + // e.g. (Object,Object)int + interfaceType = Type.getMethodType(Type.getMethodDescriptor(method)); + // lookup requested method + Definition.Struct struct = Definition.getType(type).struct; + final Definition.Method impl; + // ctor ref + if (isCtorReference) { + impl = struct.constructors.get(new Definition.MethodKey("", method.getParameterCount())); + } else { + // look for a static impl first + Definition.Method staticImpl = struct.staticMethods.get(new Definition.MethodKey(call, method.getParameterCount())); + if (staticImpl == null) { + // otherwise a virtual impl + impl = struct.methods.get(new Definition.MethodKey(call, method.getParameterCount()-1)); + } else { + impl = staticImpl; + } + } + if (impl == null) { + throw new IllegalArgumentException("Unknown reference [" + type + "::" + call + "] matching " + + "[" + expected + "]"); + } + + final int tag; + if (isCtorReference) { + tag = Opcodes.H_NEWINVOKESPECIAL; + } else if (Modifier.isStatic(impl.modifiers)) { + tag = Opcodes.H_INVOKESTATIC; + } else { + tag = Opcodes.H_INVOKEVIRTUAL; + } + implMethod = new Handle(tag, struct.type.getInternalName(), impl.name, impl.method.getDescriptor()); + implMethodHandle = impl.handle; + if (isCtorReference) { + samMethodType = Type.getMethodType(interfaceType.getReturnType(), impl.method.getArgumentTypes()); + } else if (Modifier.isStatic(impl.modifiers)) { + samMethodType = Type.getMethodType(impl.method.getReturnType(), impl.method.getArgumentTypes()); + } else { + Type[] argTypes = impl.method.getArgumentTypes(); + Type[] params = new Type[argTypes.length + 1]; + System.arraycopy(argTypes, 0, params, 1, argTypes.length); + params[0] = struct.type; + samMethodType = Type.getMethodType(impl.method.getReturnType(), params); + } + } + + static final Set OBJECT_METHODS = new HashSet<>(); + static { + for (java.lang.reflect.Method m : Object.class.getMethods()) { + OBJECT_METHODS.add(new Definition.MethodKey(m.getName(), m.getParameterCount())); + } + } + + // TODO: move all this crap out, to Definition to compute up front + java.lang.reflect.Method getFunctionalMethod(String type, String call, Class clazz) { + if (!clazz.isInterface()) { + throw new IllegalArgumentException("Cannot convert function reference [" + + type + "::" + call + "] to [" + clazz + "]"); + } + for (java.lang.reflect.Method m : clazz.getMethods()) { + if (m.isDefault()) { + continue; + } + if (OBJECT_METHODS.contains(new Definition.MethodKey(m.getName(), m.getParameterCount()))) { + continue; + } + return m; + } + throw new IllegalArgumentException("Cannot convert function reference [" + + type + "::" + call + "] to [" + clazz + "]"); + } +} diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/PainlessScriptEngineService.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/PainlessScriptEngineService.java index 4971c08b086..0d8d9fa4a8b 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/PainlessScriptEngineService.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/PainlessScriptEngineService.java @@ -40,7 +40,6 @@ import java.security.Permissions; import java.security.PrivilegedAction; import java.security.ProtectionDomain; import java.util.ArrayList; -import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; 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 380b6c2bf21..52388a5942e 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 | Exception t) { + } catch (PainlessError | BootstrapMethodError | 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 a4804cde434..1e10446e7b4 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 @@ -27,6 +27,8 @@ import org.objectweb.asm.Type; import org.objectweb.asm.commons.Method; import java.lang.invoke.CallSite; +import java.lang.invoke.LambdaMetafactory; +import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; import java.util.BitSet; @@ -62,7 +64,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); + MethodType.methodType(CallSite.class, MethodHandles.Lookup.class, String.class, MethodType.class, int.class, long.class); public final static Handle DEF_BOOTSTRAP_HANDLE = new Handle(Opcodes.H_INVOKESTATIC, Type.getInternalName(DefBootstrap.class), "bootstrap", DEF_BOOTSTRAP_TYPE.toMethodDescriptorString()); @@ -101,7 +103,15 @@ public final class WriterConstants { public final static Method DEF_LTE_CALL = getAsmMethod(boolean.class, "lte", Object.class, Object.class); public final static Method DEF_GT_CALL = getAsmMethod(boolean.class, "gt" , Object.class, Object.class); public final static Method DEF_GTE_CALL = getAsmMethod(boolean.class, "gte", Object.class, Object.class); - + + /** invokedynamic bootstrap for lambda expression/method references */ + public final static MethodType LAMBDA_BOOTSTRAP_TYPE = + MethodType.methodType(CallSite.class, MethodHandles.Lookup.class, String.class, + MethodType.class, Object[].class); + public final static Handle LAMBDA_BOOTSTRAP_HANDLE = + new Handle(Opcodes.H_INVOKESTATIC, Type.getInternalName(LambdaMetafactory.class), + "altMetafactory", LAMBDA_BOOTSTRAP_TYPE.toMethodDescriptorString()); + /** dynamic invokedynamic bootstrap for indy string concats (Java 9+) */ public final static Handle INDY_STRING_CONCAT_BOOTSTRAP_HANDLE; static { 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 98eb16732fd..a0903de5574 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 @@ -986,6 +986,7 @@ class PainlessParser extends Parser { 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 TerminalNode NEW() { return getToken(PainlessParser.NEW, 0); } public FuncrefContext(ParserRuleContext parent, int invokingState) { super(parent, invokingState); } @@ -1000,6 +1001,7 @@ class PainlessParser extends Parser { public final FuncrefContext funcref() throws RecognitionException { FuncrefContext _localctx = new FuncrefContext(_ctx, getState()); enterRule(_localctx, 18, RULE_funcref); + int _la; try { enterOuterAlt(_localctx, 1); { @@ -1008,7 +1010,12 @@ class PainlessParser extends Parser { setState(162); match(REF); setState(163); - match(ID); + _la = _input.LA(1); + if ( !(_la==NEW || _la==ID) ) { + _errHandler.recoverInline(this); + } else { + consume(); + } } } catch (RecognitionException re) { @@ -2623,112 +2630,112 @@ class PainlessParser extends Parser { "\24\3\24\3\24\3\24\3\24\5\24\u015f\n\24\3\25\3\25\3\25\3\25\3\26\3\26"+ "\3\26\3\26\7\26\u0169\n\26\f\26\16\26\u016c\13\26\5\26\u016e\n\26\3\26"+ "\3\26\3\27\3\27\5\27\u0174\n\27\3\27\2\3\34\30\2\4\6\b\n\f\16\20\22\24"+ - "\26\30\32\34\36 \"$&(*,\2\r\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\u019b\2\61\3\2\2\2\4{"+ - "\3\2\2\2\6\177\3\2\2\2\b\u0081\3\2\2\2\n\u008a\3\2\2\2\f\u008e\3\2\2\2"+ - "\16\u0090\3\2\2\2\20\u0092\3\2\2\2\22\u009b\3\2\2\2\24\u00a3\3\2\2\2\26"+ - "\u00a7\3\2\2\2\30\u00ac\3\2\2\2\32\u00b3\3\2\2\2\34\u00be\3\2\2\2\36\u011b"+ - "\3\2\2\2 \u013f\3\2\2\2\"\u0151\3\2\2\2$\u0157\3\2\2\2&\u015e\3\2\2\2"+ - "(\u0160\3\2\2\2*\u0164\3\2\2\2,\u0173\3\2\2\2.\60\5\4\3\2/.\3\2\2\2\60"+ - "\63\3\2\2\2\61/\3\2\2\2\61\62\3\2\2\2\62\64\3\2\2\2\63\61\3\2\2\2\64\65"+ - "\7\2\2\3\65\3\3\2\2\2\66\67\7\16\2\2\678\7\t\2\289\5\34\17\29:\7\n\2\2"+ - ":>\5\6\4\2;<\7\17\2\2;\3\2\2\2>=\3\2\2\2?|\3\2\2"+ - "\2@A\7\20\2\2AB\7\t\2\2BC\5\34\17\2CF\7\n\2\2DG\5\6\4\2EG\5\n\6\2FD\3"+ - "\2\2\2FE\3\2\2\2G|\3\2\2\2HI\7\21\2\2IJ\5\b\5\2JK\7\20\2\2KL\7\t\2\2L"+ - "M\5\34\17\2MN\7\n\2\2NO\5\32\16\2O|\3\2\2\2PQ\7\22\2\2QS\7\t\2\2RT\5\f"+ - "\7\2SR\3\2\2\2ST\3\2\2\2TU\3\2\2\2UW\7\r\2\2VX\5\34\17\2WV\3\2\2\2WX\3"+ - "\2\2\2XY\3\2\2\2Y[\7\r\2\2Z\\\5\16\b\2[Z\3\2\2\2[\\\3\2\2\2\\]\3\2\2\2"+ - "]`\7\n\2\2^a\5\6\4\2_a\5\n\6\2`^\3\2\2\2`_\3\2\2\2a|\3\2\2\2bc\5\20\t"+ - "\2cd\5\32\16\2d|\3\2\2\2ef\7\23\2\2f|\5\32\16\2gh\7\24\2\2h|\5\32\16\2"+ - "ij\7\25\2\2jk\5\34\17\2kl\5\32\16\2l|\3\2\2\2mn\7\27\2\2np\5\b\5\2oq\5"+ - "\30\r\2po\3\2\2\2qr\3\2\2\2rp\3\2\2\2rs\3\2\2\2s|\3\2\2\2tu\7\31\2\2u"+ - "v\5\34\17\2vw\5\32\16\2w|\3\2\2\2xy\5\34\17\2yz\5\32\16\2z|\3\2\2\2{\66"+ - "\3\2\2\2{@\3\2\2\2{H\3\2\2\2{P\3\2\2\2{b\3\2\2\2{e\3\2\2\2{g\3\2\2\2{"+ - "i\3\2\2\2{m\3\2\2\2{t\3\2\2\2{x\3\2\2\2|\5\3\2\2\2}\u0080\5\b\5\2~\u0080"+ - "\5\4\3\2\177}\3\2\2\2\177~\3\2\2\2\u0080\7\3\2\2\2\u0081\u0085\7\5\2\2"+ - "\u0082\u0084\5\4\3\2\u0083\u0082\3\2\2\2\u0084\u0087\3\2\2\2\u0085\u0083"+ - "\3\2\2\2\u0085\u0086\3\2\2\2\u0086\u0088\3\2\2\2\u0087\u0085\3\2\2\2\u0088"+ - "\u0089\7\6\2\2\u0089\t\3\2\2\2\u008a\u008b\7\r\2\2\u008b\13\3\2\2\2\u008c"+ - "\u008f\5\20\t\2\u008d\u008f\5\34\17\2\u008e\u008c\3\2\2\2\u008e\u008d"+ - "\3\2\2\2\u008f\r\3\2\2\2\u0090\u0091\5\34\17\2\u0091\17\3\2\2\2\u0092"+ - "\u0093\5\22\n\2\u0093\u0098\5\26\f\2\u0094\u0095\7\f\2\2\u0095\u0097\5"+ - "\26\f\2\u0096\u0094\3\2\2\2\u0097\u009a\3\2\2\2\u0098\u0096\3\2\2\2\u0098"+ - "\u0099\3\2\2\2\u0099\21\3\2\2\2\u009a\u0098\3\2\2\2\u009b\u00a0\7J\2\2"+ - "\u009c\u009d\7\7\2\2\u009d\u009f\7\b\2\2\u009e\u009c\3\2\2\2\u009f\u00a2"+ - "\3\2\2\2\u00a0\u009e\3\2\2\2\u00a0\u00a1\3\2\2\2\u00a1\23\3\2\2\2\u00a2"+ - "\u00a0\3\2\2\2\u00a3\u00a4\7J\2\2\u00a4\u00a5\7\63\2\2\u00a5\u00a6\7K"+ - "\2\2\u00a6\25\3\2\2\2\u00a7\u00aa\7K\2\2\u00a8\u00a9\7\66\2\2\u00a9\u00ab"+ - "\5\34\17\2\u00aa\u00a8\3\2\2\2\u00aa\u00ab\3\2\2\2\u00ab\27\3\2\2\2\u00ac"+ - "\u00ad\7\30\2\2\u00ad\u00ae\7\t\2\2\u00ae\u00af\7J\2\2\u00af\u00b0\7K"+ - "\2\2\u00b0\u00b1\7\n\2\2\u00b1\u00b2\5\b\5\2\u00b2\31\3\2\2\2\u00b3\u00b4"+ - "\t\2\2\2\u00b4\33\3\2\2\2\u00b5\u00b6\b\17\1\2\u00b6\u00b7\5 \21\2\u00b7"+ - "\u00b8\t\3\2\2\u00b8\u00b9\5\34\17\3\u00b9\u00ba\b\17\1\2\u00ba\u00bf"+ - "\3\2\2\2\u00bb\u00bc\5\36\20\2\u00bc\u00bd\b\17\1\2\u00bd\u00bf\3\2\2"+ - "\2\u00be\u00b5\3\2\2\2\u00be\u00bb\3\2\2\2\u00bf\u00fb\3\2\2\2\u00c0\u00c1"+ - "\f\16\2\2\u00c1\u00c2\t\4\2\2\u00c2\u00c3\5\34\17\17\u00c3\u00c4\b\17"+ - "\1\2\u00c4\u00fa\3\2\2\2\u00c5\u00c6\f\r\2\2\u00c6\u00c7\t\5\2\2\u00c7"+ - "\u00c8\5\34\17\16\u00c8\u00c9\b\17\1\2\u00c9\u00fa\3\2\2\2\u00ca\u00cb"+ - "\f\f\2\2\u00cb\u00cc\t\6\2\2\u00cc\u00cd\5\34\17\r\u00cd\u00ce\b\17\1"+ - "\2\u00ce\u00fa\3\2\2\2\u00cf\u00d0\f\13\2\2\u00d0\u00d1\t\7\2\2\u00d1"+ - "\u00d2\5\34\17\f\u00d2\u00d3\b\17\1\2\u00d3\u00fa\3\2\2\2\u00d4\u00d5"+ - "\f\n\2\2\u00d5\u00d6\t\b\2\2\u00d6\u00d7\5\34\17\13\u00d7\u00d8\b\17\1"+ - "\2\u00d8\u00fa\3\2\2\2\u00d9\u00da\f\t\2\2\u00da\u00db\7,\2\2\u00db\u00dc"+ - "\5\34\17\n\u00dc\u00dd\b\17\1\2\u00dd\u00fa\3\2\2\2\u00de\u00df\f\b\2"+ - "\2\u00df\u00e0\7-\2\2\u00e0\u00e1\5\34\17\t\u00e1\u00e2\b\17\1\2\u00e2"+ - "\u00fa\3\2\2\2\u00e3\u00e4\f\7\2\2\u00e4\u00e5\7.\2\2\u00e5\u00e6\5\34"+ - "\17\b\u00e6\u00e7\b\17\1\2\u00e7\u00fa\3\2\2\2\u00e8\u00e9\f\6\2\2\u00e9"+ - "\u00ea\7/\2\2\u00ea\u00eb\5\34\17\7\u00eb\u00ec\b\17\1\2\u00ec\u00fa\3"+ - "\2\2\2\u00ed\u00ee\f\5\2\2\u00ee\u00ef\7\60\2\2\u00ef\u00f0\5\34\17\6"+ - "\u00f0\u00f1\b\17\1\2\u00f1\u00fa\3\2\2\2\u00f2\u00f3\f\4\2\2\u00f3\u00f4"+ - "\7\61\2\2\u00f4\u00f5\5\34\17\2\u00f5\u00f6\7\62\2\2\u00f6\u00f7\5\34"+ - "\17\4\u00f7\u00f8\b\17\1\2\u00f8\u00fa\3\2\2\2\u00f9\u00c0\3\2\2\2\u00f9"+ - "\u00c5\3\2\2\2\u00f9\u00ca\3\2\2\2\u00f9\u00cf\3\2\2\2\u00f9\u00d4\3\2"+ - "\2\2\u00f9\u00d9\3\2\2\2\u00f9\u00de\3\2\2\2\u00f9\u00e3\3\2\2\2\u00f9"+ - "\u00e8\3\2\2\2\u00f9\u00ed\3\2\2\2\u00f9\u00f2\3\2\2\2\u00fa\u00fd\3\2"+ - "\2\2\u00fb\u00f9\3\2\2\2\u00fb\u00fc\3\2\2\2\u00fc\35\3\2\2\2\u00fd\u00fb"+ - "\3\2\2\2\u00fe\u00ff\6\20\16\3\u00ff\u0100\t\t\2\2\u0100\u011c\5 \21\2"+ - "\u0101\u0102\6\20\17\3\u0102\u0103\5 \21\2\u0103\u0104\t\t\2\2\u0104\u011c"+ - "\3\2\2\2\u0105\u0106\6\20\20\3\u0106\u011c\5 \21\2\u0107\u0108\6\20\21"+ - "\3\u0108\u0109\t\n\2\2\u0109\u011c\b\20\1\2\u010a\u010b\6\20\22\3\u010b"+ - "\u010c\7G\2\2\u010c\u011c\b\20\1\2\u010d\u010e\6\20\23\3\u010e\u010f\7"+ - "H\2\2\u010f\u011c\b\20\1\2\u0110\u0111\6\20\24\3\u0111\u0112\7I\2\2\u0112"+ - "\u011c\b\20\1\2\u0113\u0114\6\20\25\3\u0114\u0115\t\13\2\2\u0115\u011c"+ - "\5\36\20\2\u0116\u0117\7\t\2\2\u0117\u0118\5\22\n\2\u0118\u0119\7\n\2"+ - "\2\u0119\u011a\5\36\20\2\u011a\u011c\3\2\2\2\u011b\u00fe\3\2\2\2\u011b"+ - "\u0101\3\2\2\2\u011b\u0105\3\2\2\2\u011b\u0107\3\2\2\2\u011b\u010a\3\2"+ - "\2\2\u011b\u010d\3\2\2\2\u011b\u0110\3\2\2\2\u011b\u0113\3\2\2\2\u011b"+ - "\u0116\3\2\2\2\u011c\37\3\2\2\2\u011d\u0121\5\"\22\2\u011e\u0120\5$\23"+ - "\2\u011f\u011e\3\2\2\2\u0120\u0123\3\2\2\2\u0121\u011f\3\2\2\2\u0121\u0122"+ - "\3\2\2\2\u0122\u0140\3\2\2\2\u0123\u0121\3\2\2\2\u0124\u0125\5\22\n\2"+ - "\u0125\u0129\5&\24\2\u0126\u0128\5$\23\2\u0127\u0126\3\2\2\2\u0128\u012b"+ - "\3\2\2\2\u0129\u0127\3\2\2\2\u0129\u012a\3\2\2\2\u012a\u0140\3\2\2\2\u012b"+ - "\u0129\3\2\2\2\u012c\u012d\7\26\2\2\u012d\u0132\7J\2\2\u012e\u012f\7\7"+ - "\2\2\u012f\u0130\5\34\17\2\u0130\u0131\7\b\2\2\u0131\u0133\3\2\2\2\u0132"+ - "\u012e\3\2\2\2\u0133\u0134\3\2\2\2\u0134\u0132\3\2\2\2\u0134\u0135\3\2"+ - "\2\2\u0135\u013d\3\2\2\2\u0136\u013a\5&\24\2\u0137\u0139\5$\23\2\u0138"+ - "\u0137\3\2\2\2\u0139\u013c\3\2\2\2\u013a\u0138\3\2\2\2\u013a\u013b\3\2"+ - "\2\2\u013b\u013e\3\2\2\2\u013c\u013a\3\2\2\2\u013d\u0136\3\2\2\2\u013d"+ - "\u013e\3\2\2\2\u013e\u0140\3\2\2\2\u013f\u011d\3\2\2\2\u013f\u0124\3\2"+ - "\2\2\u013f\u012c\3\2\2\2\u0140!\3\2\2\2\u0141\u0142\6\22\26\3\u0142\u0143"+ - "\7\t\2\2\u0143\u0144\5\34\17\2\u0144\u0145\7\n\2\2\u0145\u0146\b\22\1"+ - "\2\u0146\u0152\3\2\2\2\u0147\u0148\6\22\27\3\u0148\u0149\7\t\2\2\u0149"+ - "\u014a\5\36\20\2\u014a\u014b\7\n\2\2\u014b\u0152\3\2\2\2\u014c\u0152\7"+ - "F\2\2\u014d\u0152\7K\2\2\u014e\u014f\7\26\2\2\u014f\u0150\7J\2\2\u0150"+ - "\u0152\5*\26\2\u0151\u0141\3\2\2\2\u0151\u0147\3\2\2\2\u0151\u014c\3\2"+ - "\2\2\u0151\u014d\3\2\2\2\u0151\u014e\3\2\2\2\u0152#\3\2\2\2\u0153\u0154"+ - "\6\23\30\3\u0154\u0158\5&\24\2\u0155\u0156\6\23\31\3\u0156\u0158\5(\25"+ - "\2\u0157\u0153\3\2\2\2\u0157\u0155\3\2\2\2\u0158%\3\2\2\2\u0159\u015a"+ - "\7\13\2\2\u015a\u015b\7M\2\2\u015b\u015f\5*\26\2\u015c\u015d\7\13\2\2"+ - "\u015d\u015f\t\f\2\2\u015e\u0159\3\2\2\2\u015e\u015c\3\2\2\2\u015f\'\3"+ - "\2\2\2\u0160\u0161\7\7\2\2\u0161\u0162\5\34\17\2\u0162\u0163\7\b\2\2\u0163"+ - ")\3\2\2\2\u0164\u016d\7\t\2\2\u0165\u016a\5,\27\2\u0166\u0167\7\f\2\2"+ - "\u0167\u0169\5,\27\2\u0168\u0166\3\2\2\2\u0169\u016c\3\2\2\2\u016a\u0168"+ - "\3\2\2\2\u016a\u016b\3\2\2\2\u016b\u016e\3\2\2\2\u016c\u016a\3\2\2\2\u016d"+ - "\u0165\3\2\2\2\u016d\u016e\3\2\2\2\u016e\u016f\3\2\2\2\u016f\u0170\7\n"+ - "\2\2\u0170+\3\2\2\2\u0171\u0174\5\34\17\2\u0172\u0174\5\24\13\2\u0173"+ - "\u0171\3\2\2\2\u0173\u0172\3\2\2\2\u0174-\3\2\2\2!\61>FSW[`r{\177\u0085"+ - "\u008e\u0098\u00a0\u00aa\u00be\u00f9\u00fb\u011b\u0121\u0129\u0134\u013a"+ - "\u013d\u013f\u0151\u0157\u015e\u016a\u016d\u0173"; + "\26\30\32\34\36 \"$&(*,\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\u019b\2\61"+ + "\3\2\2\2\4{\3\2\2\2\6\177\3\2\2\2\b\u0081\3\2\2\2\n\u008a\3\2\2\2\f\u008e"+ + "\3\2\2\2\16\u0090\3\2\2\2\20\u0092\3\2\2\2\22\u009b\3\2\2\2\24\u00a3\3"+ + "\2\2\2\26\u00a7\3\2\2\2\30\u00ac\3\2\2\2\32\u00b3\3\2\2\2\34\u00be\3\2"+ + "\2\2\36\u011b\3\2\2\2 \u013f\3\2\2\2\"\u0151\3\2\2\2$\u0157\3\2\2\2&\u015e"+ + "\3\2\2\2(\u0160\3\2\2\2*\u0164\3\2\2\2,\u0173\3\2\2\2.\60\5\4\3\2/.\3"+ + "\2\2\2\60\63\3\2\2\2\61/\3\2\2\2\61\62\3\2\2\2\62\64\3\2\2\2\63\61\3\2"+ + "\2\2\64\65\7\2\2\3\65\3\3\2\2\2\66\67\7\16\2\2\678\7\t\2\289\5\34\17\2"+ + "9:\7\n\2\2:>\5\6\4\2;<\7\17\2\2;\3\2\2\2>=\3\2\2"+ + "\2?|\3\2\2\2@A\7\20\2\2AB\7\t\2\2BC\5\34\17\2CF\7\n\2\2DG\5\6\4\2EG\5"+ + "\n\6\2FD\3\2\2\2FE\3\2\2\2G|\3\2\2\2HI\7\21\2\2IJ\5\b\5\2JK\7\20\2\2K"+ + "L\7\t\2\2LM\5\34\17\2MN\7\n\2\2NO\5\32\16\2O|\3\2\2\2PQ\7\22\2\2QS\7\t"+ + "\2\2RT\5\f\7\2SR\3\2\2\2ST\3\2\2\2TU\3\2\2\2UW\7\r\2\2VX\5\34\17\2WV\3"+ + "\2\2\2WX\3\2\2\2XY\3\2\2\2Y[\7\r\2\2Z\\\5\16\b\2[Z\3\2\2\2[\\\3\2\2\2"+ + "\\]\3\2\2\2]`\7\n\2\2^a\5\6\4\2_a\5\n\6\2`^\3\2\2\2`_\3\2\2\2a|\3\2\2"+ + "\2bc\5\20\t\2cd\5\32\16\2d|\3\2\2\2ef\7\23\2\2f|\5\32\16\2gh\7\24\2\2"+ + "h|\5\32\16\2ij\7\25\2\2jk\5\34\17\2kl\5\32\16\2l|\3\2\2\2mn\7\27\2\2n"+ + "p\5\b\5\2oq\5\30\r\2po\3\2\2\2qr\3\2\2\2rp\3\2\2\2rs\3\2\2\2s|\3\2\2\2"+ + "tu\7\31\2\2uv\5\34\17\2vw\5\32\16\2w|\3\2\2\2xy\5\34\17\2yz\5\32\16\2"+ + "z|\3\2\2\2{\66\3\2\2\2{@\3\2\2\2{H\3\2\2\2{P\3\2\2\2{b\3\2\2\2{e\3\2\2"+ + "\2{g\3\2\2\2{i\3\2\2\2{m\3\2\2\2{t\3\2\2\2{x\3\2\2\2|\5\3\2\2\2}\u0080"+ + "\5\b\5\2~\u0080\5\4\3\2\177}\3\2\2\2\177~\3\2\2\2\u0080\7\3\2\2\2\u0081"+ + "\u0085\7\5\2\2\u0082\u0084\5\4\3\2\u0083\u0082\3\2\2\2\u0084\u0087\3\2"+ + "\2\2\u0085\u0083\3\2\2\2\u0085\u0086\3\2\2\2\u0086\u0088\3\2\2\2\u0087"+ + "\u0085\3\2\2\2\u0088\u0089\7\6\2\2\u0089\t\3\2\2\2\u008a\u008b\7\r\2\2"+ + "\u008b\13\3\2\2\2\u008c\u008f\5\20\t\2\u008d\u008f\5\34\17\2\u008e\u008c"+ + "\3\2\2\2\u008e\u008d\3\2\2\2\u008f\r\3\2\2\2\u0090\u0091\5\34\17\2\u0091"+ + "\17\3\2\2\2\u0092\u0093\5\22\n\2\u0093\u0098\5\26\f\2\u0094\u0095\7\f"+ + "\2\2\u0095\u0097\5\26\f\2\u0096\u0094\3\2\2\2\u0097\u009a\3\2\2\2\u0098"+ + "\u0096\3\2\2\2\u0098\u0099\3\2\2\2\u0099\21\3\2\2\2\u009a\u0098\3\2\2"+ + "\2\u009b\u00a0\7J\2\2\u009c\u009d\7\7\2\2\u009d\u009f\7\b\2\2\u009e\u009c"+ + "\3\2\2\2\u009f\u00a2\3\2\2\2\u00a0\u009e\3\2\2\2\u00a0\u00a1\3\2\2\2\u00a1"+ + "\23\3\2\2\2\u00a2\u00a0\3\2\2\2\u00a3\u00a4\7J\2\2\u00a4\u00a5\7\63\2"+ + "\2\u00a5\u00a6\t\2\2\2\u00a6\25\3\2\2\2\u00a7\u00aa\7K\2\2\u00a8\u00a9"+ + "\7\66\2\2\u00a9\u00ab\5\34\17\2\u00aa\u00a8\3\2\2\2\u00aa\u00ab\3\2\2"+ + "\2\u00ab\27\3\2\2\2\u00ac\u00ad\7\30\2\2\u00ad\u00ae\7\t\2\2\u00ae\u00af"+ + "\7J\2\2\u00af\u00b0\7K\2\2\u00b0\u00b1\7\n\2\2\u00b1\u00b2\5\b\5\2\u00b2"+ + "\31\3\2\2\2\u00b3\u00b4\t\3\2\2\u00b4\33\3\2\2\2\u00b5\u00b6\b\17\1\2"+ + "\u00b6\u00b7\5 \21\2\u00b7\u00b8\t\4\2\2\u00b8\u00b9\5\34\17\3\u00b9\u00ba"+ + "\b\17\1\2\u00ba\u00bf\3\2\2\2\u00bb\u00bc\5\36\20\2\u00bc\u00bd\b\17\1"+ + "\2\u00bd\u00bf\3\2\2\2\u00be\u00b5\3\2\2\2\u00be\u00bb\3\2\2\2\u00bf\u00fb"+ + "\3\2\2\2\u00c0\u00c1\f\16\2\2\u00c1\u00c2\t\5\2\2\u00c2\u00c3\5\34\17"+ + "\17\u00c3\u00c4\b\17\1\2\u00c4\u00fa\3\2\2\2\u00c5\u00c6\f\r\2\2\u00c6"+ + "\u00c7\t\6\2\2\u00c7\u00c8\5\34\17\16\u00c8\u00c9\b\17\1\2\u00c9\u00fa"+ + "\3\2\2\2\u00ca\u00cb\f\f\2\2\u00cb\u00cc\t\7\2\2\u00cc\u00cd\5\34\17\r"+ + "\u00cd\u00ce\b\17\1\2\u00ce\u00fa\3\2\2\2\u00cf\u00d0\f\13\2\2\u00d0\u00d1"+ + "\t\b\2\2\u00d1\u00d2\5\34\17\f\u00d2\u00d3\b\17\1\2\u00d3\u00fa\3\2\2"+ + "\2\u00d4\u00d5\f\n\2\2\u00d5\u00d6\t\t\2\2\u00d6\u00d7\5\34\17\13\u00d7"+ + "\u00d8\b\17\1\2\u00d8\u00fa\3\2\2\2\u00d9\u00da\f\t\2\2\u00da\u00db\7"+ + ",\2\2\u00db\u00dc\5\34\17\n\u00dc\u00dd\b\17\1\2\u00dd\u00fa\3\2\2\2\u00de"+ + "\u00df\f\b\2\2\u00df\u00e0\7-\2\2\u00e0\u00e1\5\34\17\t\u00e1\u00e2\b"+ + "\17\1\2\u00e2\u00fa\3\2\2\2\u00e3\u00e4\f\7\2\2\u00e4\u00e5\7.\2\2\u00e5"+ + "\u00e6\5\34\17\b\u00e6\u00e7\b\17\1\2\u00e7\u00fa\3\2\2\2\u00e8\u00e9"+ + "\f\6\2\2\u00e9\u00ea\7/\2\2\u00ea\u00eb\5\34\17\7\u00eb\u00ec\b\17\1\2"+ + "\u00ec\u00fa\3\2\2\2\u00ed\u00ee\f\5\2\2\u00ee\u00ef\7\60\2\2\u00ef\u00f0"+ + "\5\34\17\6\u00f0\u00f1\b\17\1\2\u00f1\u00fa\3\2\2\2\u00f2\u00f3\f\4\2"+ + "\2\u00f3\u00f4\7\61\2\2\u00f4\u00f5\5\34\17\2\u00f5\u00f6\7\62\2\2\u00f6"+ + "\u00f7\5\34\17\4\u00f7\u00f8\b\17\1\2\u00f8\u00fa\3\2\2\2\u00f9\u00c0"+ + "\3\2\2\2\u00f9\u00c5\3\2\2\2\u00f9\u00ca\3\2\2\2\u00f9\u00cf\3\2\2\2\u00f9"+ + "\u00d4\3\2\2\2\u00f9\u00d9\3\2\2\2\u00f9\u00de\3\2\2\2\u00f9\u00e3\3\2"+ + "\2\2\u00f9\u00e8\3\2\2\2\u00f9\u00ed\3\2\2\2\u00f9\u00f2\3\2\2\2\u00fa"+ + "\u00fd\3\2\2\2\u00fb\u00f9\3\2\2\2\u00fb\u00fc\3\2\2\2\u00fc\35\3\2\2"+ + "\2\u00fd\u00fb\3\2\2\2\u00fe\u00ff\6\20\16\3\u00ff\u0100\t\n\2\2\u0100"+ + "\u011c\5 \21\2\u0101\u0102\6\20\17\3\u0102\u0103\5 \21\2\u0103\u0104\t"+ + "\n\2\2\u0104\u011c\3\2\2\2\u0105\u0106\6\20\20\3\u0106\u011c\5 \21\2\u0107"+ + "\u0108\6\20\21\3\u0108\u0109\t\13\2\2\u0109\u011c\b\20\1\2\u010a\u010b"+ + "\6\20\22\3\u010b\u010c\7G\2\2\u010c\u011c\b\20\1\2\u010d\u010e\6\20\23"+ + "\3\u010e\u010f\7H\2\2\u010f\u011c\b\20\1\2\u0110\u0111\6\20\24\3\u0111"+ + "\u0112\7I\2\2\u0112\u011c\b\20\1\2\u0113\u0114\6\20\25\3\u0114\u0115\t"+ + "\f\2\2\u0115\u011c\5\36\20\2\u0116\u0117\7\t\2\2\u0117\u0118\5\22\n\2"+ + "\u0118\u0119\7\n\2\2\u0119\u011a\5\36\20\2\u011a\u011c\3\2\2\2\u011b\u00fe"+ + "\3\2\2\2\u011b\u0101\3\2\2\2\u011b\u0105\3\2\2\2\u011b\u0107\3\2\2\2\u011b"+ + "\u010a\3\2\2\2\u011b\u010d\3\2\2\2\u011b\u0110\3\2\2\2\u011b\u0113\3\2"+ + "\2\2\u011b\u0116\3\2\2\2\u011c\37\3\2\2\2\u011d\u0121\5\"\22\2\u011e\u0120"+ + "\5$\23\2\u011f\u011e\3\2\2\2\u0120\u0123\3\2\2\2\u0121\u011f\3\2\2\2\u0121"+ + "\u0122\3\2\2\2\u0122\u0140\3\2\2\2\u0123\u0121\3\2\2\2\u0124\u0125\5\22"+ + "\n\2\u0125\u0129\5&\24\2\u0126\u0128\5$\23\2\u0127\u0126\3\2\2\2\u0128"+ + "\u012b\3\2\2\2\u0129\u0127\3\2\2\2\u0129\u012a\3\2\2\2\u012a\u0140\3\2"+ + "\2\2\u012b\u0129\3\2\2\2\u012c\u012d\7\26\2\2\u012d\u0132\7J\2\2\u012e"+ + "\u012f\7\7\2\2\u012f\u0130\5\34\17\2\u0130\u0131\7\b\2\2\u0131\u0133\3"+ + "\2\2\2\u0132\u012e\3\2\2\2\u0133\u0134\3\2\2\2\u0134\u0132\3\2\2\2\u0134"+ + "\u0135\3\2\2\2\u0135\u013d\3\2\2\2\u0136\u013a\5&\24\2\u0137\u0139\5$"+ + "\23\2\u0138\u0137\3\2\2\2\u0139\u013c\3\2\2\2\u013a\u0138\3\2\2\2\u013a"+ + "\u013b\3\2\2\2\u013b\u013e\3\2\2\2\u013c\u013a\3\2\2\2\u013d\u0136\3\2"+ + "\2\2\u013d\u013e\3\2\2\2\u013e\u0140\3\2\2\2\u013f\u011d\3\2\2\2\u013f"+ + "\u0124\3\2\2\2\u013f\u012c\3\2\2\2\u0140!\3\2\2\2\u0141\u0142\6\22\26"+ + "\3\u0142\u0143\7\t\2\2\u0143\u0144\5\34\17\2\u0144\u0145\7\n\2\2\u0145"+ + "\u0146\b\22\1\2\u0146\u0152\3\2\2\2\u0147\u0148\6\22\27\3\u0148\u0149"+ + "\7\t\2\2\u0149\u014a\5\36\20\2\u014a\u014b\7\n\2\2\u014b\u0152\3\2\2\2"+ + "\u014c\u0152\7F\2\2\u014d\u0152\7K\2\2\u014e\u014f\7\26\2\2\u014f\u0150"+ + "\7J\2\2\u0150\u0152\5*\26\2\u0151\u0141\3\2\2\2\u0151\u0147\3\2\2\2\u0151"+ + "\u014c\3\2\2\2\u0151\u014d\3\2\2\2\u0151\u014e\3\2\2\2\u0152#\3\2\2\2"+ + "\u0153\u0154\6\23\30\3\u0154\u0158\5&\24\2\u0155\u0156\6\23\31\3\u0156"+ + "\u0158\5(\25\2\u0157\u0153\3\2\2\2\u0157\u0155\3\2\2\2\u0158%\3\2\2\2"+ + "\u0159\u015a\7\13\2\2\u015a\u015b\7M\2\2\u015b\u015f\5*\26\2\u015c\u015d"+ + "\7\13\2\2\u015d\u015f\t\r\2\2\u015e\u0159\3\2\2\2\u015e\u015c\3\2\2\2"+ + "\u015f\'\3\2\2\2\u0160\u0161\7\7\2\2\u0161\u0162\5\34\17\2\u0162\u0163"+ + "\7\b\2\2\u0163)\3\2\2\2\u0164\u016d\7\t\2\2\u0165\u016a\5,\27\2\u0166"+ + "\u0167\7\f\2\2\u0167\u0169\5,\27\2\u0168\u0166\3\2\2\2\u0169\u016c\3\2"+ + "\2\2\u016a\u0168\3\2\2\2\u016a\u016b\3\2\2\2\u016b\u016e\3\2\2\2\u016c"+ + "\u016a\3\2\2\2\u016d\u0165\3\2\2\2\u016d\u016e\3\2\2\2\u016e\u016f\3\2"+ + "\2\2\u016f\u0170\7\n\2\2\u0170+\3\2\2\2\u0171\u0174\5\34\17\2\u0172\u0174"+ + "\5\24\13\2\u0173\u0171\3\2\2\2\u0173\u0172\3\2\2\2\u0174-\3\2\2\2!\61"+ + ">FSW[`r{\177\u0085\u008e\u0098\u00a0\u00aa\u00be\u00f9\u00fb\u011b\u0121"+ + "\u0129\u0134\u013a\u013d\u013f\u0151\u0157\u015e\u016a\u016d\u0173"; 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 0f155ceb4c1..66d854fd220 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 @@ -391,7 +391,15 @@ public final class Walker extends PainlessParserBaseVisitor { @Override public Object visitFuncref(FuncrefContext ctx) { - return new EFunctionRef(location(ctx), ctx.TYPE().getText(), ctx.ID().getText()); + final String methodText; + if (ctx.ID() != null) { + methodText = ctx.ID().getText(); + } else if (ctx.NEW() != null ){ + methodText = ctx.NEW().getText(); + } else { + throw location(ctx).createError(new IllegalStateException("Illegal tree structure.")); + } + return new EFunctionRef(location(ctx), ctx.TYPE().getText(), methodText); } @Override 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 ec2bd6f7e47..dd050a549ea 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 @@ -19,16 +19,24 @@ package org.elasticsearch.painless.node; +import org.elasticsearch.painless.Definition; +import org.elasticsearch.painless.FunctionRef; import org.elasticsearch.painless.Location; import org.elasticsearch.painless.MethodWriter; import org.elasticsearch.painless.Variables; +import static org.elasticsearch.painless.WriterConstants.LAMBDA_BOOTSTRAP_HANDLE; + +import java.lang.invoke.LambdaMetafactory; + /** * Represents a function reference. */ public class EFunctionRef extends AExpression { - public String type; - public String call; + public final String type; + public final String call; + + private FunctionRef ref; public EFunctionRef(Location location, String type, String call) { super(location); @@ -39,12 +47,35 @@ public class EFunctionRef extends AExpression { @Override void analyze(Variables variables) { - throw createError(new UnsupportedOperationException("Function references [" + type + "::" + call + - "] are not currently supported.")); + if (expected == null) { + ref = null; + actual = Definition.getType("String"); + } else { + try { + ref = new FunctionRef(expected.clazz, type, call); + } catch (IllegalArgumentException e) { + throw createError(e); + } + actual = expected; + } } @Override void write(MethodWriter writer) { - throw createError(new IllegalStateException("Illegal tree structure.")); + if (ref == null) { + writer.push(type + "." + call); + } else { + writer.writeDebugInfo(location); + // currently if the interface differs, we ask for a bridge, but maybe we should do smarter checking? + // either way, stuff will fail if its wrong :) + if (ref.interfaceType.equals(ref.samMethodType)) { + writer.invokeDynamic(ref.invokedName, ref.invokedType.getDescriptor(), LAMBDA_BOOTSTRAP_HANDLE, + ref.samMethodType, ref.implMethod, ref.samMethodType, 0); + } else { + writer.invokeDynamic(ref.invokedName, ref.invokedType.getDescriptor(), LAMBDA_BOOTSTRAP_HANDLE, + ref.samMethodType, ref.implMethod, ref.samMethodType, + LambdaMetafactory.FLAG_BRIDGES, 1, ref.interfaceType); + } + } } } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/LCall.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/LCall.java index f7e91790108..7696e775ab6 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/LCall.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/LCall.java @@ -82,7 +82,7 @@ public final class LCall extends ALink { } throw createError(new IllegalArgumentException("Unknown call [" + name + "] with [" + arguments.size() + - "] arguments on type [" + struct.name + "].")); + "] arguments on type [" + struct.name + "].")); } @Override 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 5fb2ff870ef..b51d7612297 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 @@ -61,13 +61,13 @@ final class LDefArray extends ALink implements IDefLink { void load(MethodWriter writer) { 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); + writer.invokeDynamic("arrayLoad", desc, DEF_BOOTSTRAP_HANDLE, (Object)DefBootstrap.ARRAY_LOAD, 0); } @Override void store(MethodWriter writer) { 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); + writer.invokeDynamic("arrayStore", desc, DEF_BOOTSTRAP_HANDLE, (Object)DefBootstrap.ARRAY_STORE, 0); } } 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 3b07d367eba..2bd31999ed2 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 @@ -36,6 +36,7 @@ final class LDefCall extends ALink implements IDefLink { final String name; final List arguments; + long recipe; LDefCall(Location location, String name, List arguments) { super(location, -1); @@ -46,9 +47,20 @@ final class LDefCall extends ALink implements IDefLink { @Override ALink analyze(Variables variables) { + if (arguments.size() > 63) { + // technically, the limitation is just methods with > 63 params, containing method references. + // this is because we are lazy and use a long as a bitset. we can always change to a "string" if need be. + // but NEED NOT BE. nothing with this many parameters is in the whitelist and we do not support varargs. + throw new UnsupportedOperationException("methods with > 63 arguments are currently not supported"); + } + + recipe = 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 + } expression.internal = true; expression.analyze(variables); expression.expected = expression.actual; @@ -84,7 +96,7 @@ final class LDefCall extends ALink implements IDefLink { // return value signature.append(after.type.getDescriptor()); - writer.invokeDynamic(name, signature.toString(), DEF_BOOTSTRAP_HANDLE, (Object)DefBootstrap.METHOD_CALL); + writer.invokeDynamic(name, signature.toString(), DEF_BOOTSTRAP_HANDLE, (Object)DefBootstrap.METHOD_CALL, recipe); } @Override 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 2b32d75d89c..c9e94ce887e 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 @@ -58,13 +58,13 @@ final class LDefField extends ALink implements IDefLink { void load(MethodWriter writer) { writer.writeDebugInfo(location); String desc = Type.getMethodDescriptor(after.type, Definition.DEF_TYPE.type); - writer.invokeDynamic(value, desc, DEF_BOOTSTRAP_HANDLE, (Object)DefBootstrap.LOAD); + writer.invokeDynamic(value, desc, DEF_BOOTSTRAP_HANDLE, (Object)DefBootstrap.LOAD, 0); } @Override void store(MethodWriter writer) { 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); + writer.invokeDynamic(value, desc, DEF_BOOTSTRAP_HANDLE, (Object)DefBootstrap.STORE, 0); } } diff --git a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/LNewObj.java b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/LNewObj.java index a27aa25754d..2f80b254350 100644 --- a/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/LNewObj.java +++ b/modules/lang-painless/src/main/java/org/elasticsearch/painless/node/LNewObj.java @@ -21,7 +21,7 @@ package org.elasticsearch.painless.node; import org.elasticsearch.painless.Definition; import org.elasticsearch.painless.Location; -import org.elasticsearch.painless.Definition.Constructor; +import org.elasticsearch.painless.Definition.Method; import org.elasticsearch.painless.Definition.Struct; import org.elasticsearch.painless.Definition.Type; import org.elasticsearch.painless.Variables; @@ -37,7 +37,7 @@ public final class LNewObj extends ALink { final String type; final List arguments; - Constructor constructor; + Method constructor; public LNewObj(Location location, String type, List arguments) { super(location, -1); @@ -63,7 +63,7 @@ public final class LNewObj extends ALink { } Struct struct = type.struct; - constructor = struct.constructors.get(new Definition.MethodKey("new", arguments.size())); + constructor = struct.constructors.get(new Definition.MethodKey("", arguments.size())); if (constructor != null) { Type[] types = new Type[constructor.arguments.size()]; diff --git a/modules/lang-painless/src/main/resources/org/elasticsearch/painless/java.lang.txt b/modules/lang-painless/src/main/resources/org/elasticsearch/painless/java.lang.txt index 755c8d44c0f..ec1a46e633f 100644 --- a/modules/lang-painless/src/main/resources/org/elasticsearch/painless/java.lang.txt +++ b/modules/lang-painless/src/main/resources/org/elasticsearch/painless/java.lang.txt @@ -63,6 +63,7 @@ class Boolean -> java.lang.Boolean extends Comparable,Object { Boolean FALSE boolean booleanValue() int compare(boolean,boolean) + int compareTo(Boolean) int hashCode(boolean) boolean logicalAnd(boolean,boolean) boolean logicalOr(boolean,boolean) @@ -78,6 +79,7 @@ class Byte -> java.lang.Byte extends Number,Comparable,Object { byte MIN_VALUE int SIZE int compare(byte,byte) + int compareTo(Byte) Byte decode(String) int hashCode(byte) byte parseByte(String) @@ -163,6 +165,7 @@ class Character -> java.lang.Character extends Comparable,Object { int codePointBefore(CharSequence,int) int codePointCount(CharSequence,int,int) int compare(char,char) + int compareTo(Character) int digit(int,int) char forDigit(int,int) byte getDirectionality(int) @@ -454,6 +457,7 @@ class Double -> java.lang.Double extends Number,Comparable,Object { double POSITIVE_INFINITY int SIZE int compare(double,double) + int compareTo(Double) long doubleToLongBits(double) long doubleToRawLongBits(double) int hashCode(double) @@ -473,6 +477,7 @@ class Double -> java.lang.Double extends Number,Comparable,Object { } class Enum -> java.lang.Enum extends Comparable,Object { + int compareTo(Enum) String name(); int ordinal(); } @@ -489,6 +494,7 @@ class Float -> java.lang.Float extends Number,Comparable,Object { float POSITIVE_INFINITY int SIZE int compare(float,float) + int compareTo(Float) int floatToIntBits(float) int floatToRawIntBits(float) int hashCode(float) @@ -516,6 +522,7 @@ class Integer -> java.lang.Integer extends Number,Comparable,Object { int SIZE int bitCount(int) int compare(int,int) + int compareTo(Integer) int compareUnsigned(int,int) Integer decode(String) int divideUnsigned(int,int) @@ -555,6 +562,7 @@ class Long -> java.lang.Long extends Number,Comparable,Object { int SIZE int bitCount(long) int compare(long,long) + int compareTo(Long) int compareUnsigned(long,long) Long decode(String) long divideUnsigned(long,long) @@ -587,7 +595,7 @@ class Long -> java.lang.Long extends Number,Comparable,Object { Long valueOf(String,int) } -class Math -> java.lang.Math { +class Math -> java.lang.Math extends Object { double E double PI double abs(double) @@ -658,6 +666,7 @@ class Short -> java.lang.Short extends Number,Comparable,Object { short MIN_VALUE int SIZE int compare(short,short) + int compareTo(Short) Short decode(String) int hashCode(short) short parseShort(String) @@ -679,7 +688,7 @@ class StackTraceElement -> java.lang.StackTraceElement extends Object { boolean isNativeMethod() } -class StrictMath -> java.lang.StrictMath { +class StrictMath -> java.lang.StrictMath extends Object { double E double PI double abs(double) @@ -726,6 +735,7 @@ class String -> java.lang.String extends CharSequence,Comparable,Object { int codePointAt(int) int codePointBefore(int) int codePointCount(int,int) + int compareTo(String) int compareToIgnoreCase(String) String concat(String) boolean contains(CharSequence) diff --git a/modules/lang-painless/src/main/resources/org/elasticsearch/painless/java.math.txt b/modules/lang-painless/src/main/resources/org/elasticsearch/painless/java.math.txt index 42680f8a428..e3d13a0959c 100644 --- a/modules/lang-painless/src/main/resources/org/elasticsearch/painless/java.math.txt +++ b/modules/lang-painless/src/main/resources/org/elasticsearch/painless/java.math.txt @@ -35,6 +35,7 @@ class BigDecimal -> java.math.BigDecimal extends Number,Comparable,Object { BigDecimal add(BigDecimal) BigDecimal add(BigDecimal,MathContext) byte byteValueExact() + int compareTo(BigDecimal) BigDecimal divide(BigDecimal) BigDecimal divide(BigDecimal,MathContext) BigDecimal[] divideAndRemainder(BigDecimal) @@ -90,6 +91,7 @@ class BigInteger -> java.math.BigInteger extends Number,Comparable,Object { int bitLength() byte byteValueExact() BigInteger clearBit(int) + int compareTo(BigInteger) BigInteger divide(BigInteger) BigInteger[] divideAndRemainder(BigInteger) BigInteger flipBit(int) diff --git a/modules/lang-painless/src/main/resources/org/elasticsearch/painless/java.text.txt b/modules/lang-painless/src/main/resources/org/elasticsearch/painless/java.text.txt index eac725cfb94..2e93b14ab3d 100644 --- a/modules/lang-painless/src/main/resources/org/elasticsearch/painless/java.text.txt +++ b/modules/lang-painless/src/main/resources/org/elasticsearch/painless/java.text.txt @@ -149,6 +149,7 @@ class CollationElementIterator -> java.text.CollationElementIterator extends Obj } class CollationKey -> java.text.CollationKey extends Comparable,Object { + int compareTo(CollationKey) String getSourceString() byte[] toByteArray() } diff --git a/modules/lang-painless/src/main/resources/org/elasticsearch/painless/java.time.chrono.txt b/modules/lang-painless/src/main/resources/org/elasticsearch/painless/java.time.chrono.txt index 8dd0478605e..7374efea04b 100644 --- a/modules/lang-painless/src/main/resources/org/elasticsearch/painless/java.time.chrono.txt +++ b/modules/lang-painless/src/main/resources/org/elasticsearch/painless/java.time.chrono.txt @@ -24,8 +24,9 @@ #### Interfaces -class ChronoLocalDate -> java.time.chrono.ChronoLocalDate extends Comparable,Temporal,TemporalAccessor,TemporalAdjuster { +class ChronoLocalDate -> java.time.chrono.ChronoLocalDate extends Temporal,TemporalAccessor,TemporalAdjuster,Comparable { ChronoLocalDateTime atTime(LocalTime) + int compareTo(ChronoLocalDate) boolean equals(Object) String format(DateTimeFormatter) ChronoLocalDate from(TemporalAccessor) @@ -50,8 +51,9 @@ class ChronoLocalDate -> java.time.chrono.ChronoLocalDate extends Comparable,Tem ChronoLocalDate with(TemporalField,long) } -class ChronoLocalDateTime -> java.time.chrono.ChronoLocalDateTime extends Comparable,Temporal,TemporalAccessor,TemporalAdjuster { +class ChronoLocalDateTime -> java.time.chrono.ChronoLocalDateTime extends Temporal,TemporalAccessor,TemporalAdjuster,Comparable { ChronoZonedDateTime atZone(ZoneId) + int compareTo(ChronoLocalDateTime) boolean equals(Object) String format(DateTimeFormatter) ChronoLocalDateTime from(TemporalAccessor) @@ -75,6 +77,7 @@ class ChronoLocalDateTime -> java.time.chrono.ChronoLocalDateTime extends Compar } class Chronology -> java.time.chrono.Chronology extends Comparable { + int compareTo(Chronology) ChronoLocalDate date(TemporalAccessor) ChronoLocalDate date(Era,int,int,int) ChronoLocalDate date(int,int,int) @@ -121,7 +124,8 @@ class ChronoPeriod -> java.time.chrono.ChronoPeriod extends TemporalAmount { String toString() } -class ChronoZonedDateTime -> java.time.chrono.ChronoZonedDateTime extends Comparable,Temporal,TemporalAccessor { +class ChronoZonedDateTime -> java.time.chrono.ChronoZonedDateTime extends Temporal,TemporalAccessor,Comparable { + int compareTo(ChronoZonedDateTime) boolean equals(Object) String format(DateTimeFormatter) ChronoZonedDateTime from(TemporalAccessor) @@ -158,10 +162,10 @@ class Era -> java.time.chrono.Era extends TemporalAccessor,TemporalAdjuster { #### Classes -class AbstractChronology -> java.time.chrono.Chronology extends Comparable,Chronology,Object { +class AbstractChronology -> java.time.chrono.Chronology extends Chronology,Comparable,Object { } -class HijrahChronology -> java.time.chrono.HijrahChronology extends AbstractChronology,Comparable,Chronology,Object { +class HijrahChronology -> java.time.chrono.HijrahChronology extends AbstractChronology,Chronology,Comparable,Object { HijrahChronology INSTANCE HijrahDate date(TemporalAccessor) HijrahDate date(int,int,int) @@ -172,25 +176,26 @@ class HijrahChronology -> java.time.chrono.HijrahChronology extends AbstractChro HijrahDate dateYearDay(int,int) HijrahDate dateYearDay(Era,int,int) HijrahEra eraOf(int) + HijrahDate resolveDate(Map,ResolverStyle) } -class HijrahDate -> java.time.chrono.HijrahDate extends Comparable,ChronoLocalDate,Temporal,TemporalAccessor,TemporalAdjuster,Object { - HijrahDate now() - HijrahDate now(ZoneId) - HijrahDate of(int,int,int) +class HijrahDate -> java.time.chrono.HijrahDate extends ChronoLocalDate,Temporal,TemporalAccessor,TemporalAdjuster,Comparable,Object { HijrahDate from(TemporalAccessor) HijrahChronology getChronology() HijrahEra getEra() + HijrahDate minus(TemporalAmount) + HijrahDate minus(long,TemporalUnit) + HijrahDate now() + HijrahDate now(ZoneId) + HijrahDate of(int,int,int) + HijrahDate plus(TemporalAmount) + HijrahDate plus(long,TemporalUnit) HijrahDate with(TemporalField,long) HijrahDate with(TemporalAdjuster) HijrahDate withVariant(HijrahChronology) - HijrahDate plus(TemporalAmount) - HijrahDate minus(TemporalAmount) - HijrahDate plus(long,TemporalUnit) - HijrahDate minus(long,TemporalUnit) } -class IsoChronology -> java.time.chrono.IsoChronology extends AbstractChronology,Comparable,Chronology,Object { +class IsoChronology -> java.time.chrono.IsoChronology extends AbstractChronology,Chronology,Comparable,Object { IsoChronology INSTANCE LocalDate date(TemporalAccessor) LocalDate date(int,int,int) @@ -201,9 +206,14 @@ class IsoChronology -> java.time.chrono.IsoChronology extends AbstractChronology LocalDate dateYearDay(int,int) LocalDate dateYearDay(Era,int,int) IsoEra eraOf(int) + LocalDateTime localDateTime(TemporalAccessor) + Period period(int,int,int) + LocalDate resolveDate(Map,ResolverStyle) + ZonedDateTime zonedDateTime(TemporalAccessor) + ZonedDateTime zonedDateTime(Instant,ZoneId) } -class JapaneseChronology -> java.time.chrono.JapaneseChronology extends AbstractChronology,Comparable,Chronology,Object { +class JapaneseChronology -> java.time.chrono.JapaneseChronology extends AbstractChronology,Chronology,Comparable,Object { JapaneseChronology INSTANCE JapaneseDate date(TemporalAccessor) JapaneseDate date(int,int,int) @@ -214,9 +224,10 @@ class JapaneseChronology -> java.time.chrono.JapaneseChronology extends Abstract JapaneseDate dateYearDay(int,int) JapaneseDate dateYearDay(Era,int,int) JapaneseEra eraOf(int) + JapaneseDate resolveDate(Map,ResolverStyle) } -class JapaneseDate -> java.time.chrono.JapaneseDate extends Comparable,ChronoLocalDate,Temporal,TemporalAccessor,TemporalAdjuster,Object { +class JapaneseDate -> java.time.chrono.JapaneseDate extends ChronoLocalDate,Temporal,TemporalAccessor,TemporalAdjuster,Comparable,Object { JapaneseDate now() JapaneseDate now(ZoneId) JapaneseDate of(int,int,int) @@ -242,7 +253,7 @@ class JapaneseEra -> java.time.chrono.JapaneseEra extends Era,TemporalAccessor,T JapaneseEra[] values() } -class MinguoChronology -> java.time.chrono.MinguoChronology extends AbstractChronology,Comparable,Chronology,Object { +class MinguoChronology -> java.time.chrono.MinguoChronology extends AbstractChronology,Chronology,Comparable,Object { MinguoChronology INSTANCE MinguoDate date(TemporalAccessor) MinguoDate date(int,int,int) @@ -253,9 +264,10 @@ class MinguoChronology -> java.time.chrono.MinguoChronology extends AbstractChro MinguoDate dateYearDay(int,int) MinguoDate dateYearDay(Era,int,int) MinguoEra eraOf(int) + MinguoDate resolveDate(Map,ResolverStyle) } -class MinguoDate -> java.time.chrono.MinguoDate extends Comparable,ChronoLocalDate,Temporal,TemporalAccessor,TemporalAdjuster,Object { +class MinguoDate -> java.time.chrono.MinguoDate extends ChronoLocalDate,Temporal,TemporalAccessor,TemporalAdjuster,Comparable,Object { MinguoDate now() MinguoDate now(ZoneId) MinguoDate of(int,int,int) @@ -270,7 +282,7 @@ class MinguoDate -> java.time.chrono.MinguoDate extends Comparable,ChronoLocalDa MinguoDate minus(long,TemporalUnit) } -class ThaiBuddhistChronology -> java.time.chrono.ThaiBuddhistChronology extends AbstractChronology,Comparable,Chronology,Object { +class ThaiBuddhistChronology -> java.time.chrono.ThaiBuddhistChronology extends AbstractChronology,Chronology,Comparable,Object { ThaiBuddhistChronology INSTANCE ThaiBuddhistDate date(TemporalAccessor) ThaiBuddhistDate date(int,int,int) @@ -281,9 +293,10 @@ class ThaiBuddhistChronology -> java.time.chrono.ThaiBuddhistChronology extends ThaiBuddhistDate dateYearDay(int,int) ThaiBuddhistDate dateYearDay(Era,int,int) ThaiBuddhistEra eraOf(int) + ThaiBuddhistDate resolveDate(Map,ResolverStyle) } -class ThaiBuddhistDate -> java.time.chrono.ThaiBuddhistDate extends Comparable,ChronoLocalDate,Temporal,TemporalAccessor,TemporalAdjuster,Object { +class ThaiBuddhistDate -> java.time.chrono.ThaiBuddhistDate extends ChronoLocalDate,Temporal,TemporalAccessor,TemporalAdjuster,Comparable,Object { ThaiBuddhistDate now() ThaiBuddhistDate now(ZoneId) ThaiBuddhistDate of(int,int,int) diff --git a/modules/lang-painless/src/main/resources/org/elasticsearch/painless/java.time.txt b/modules/lang-painless/src/main/resources/org/elasticsearch/painless/java.time.txt index 1b7d19a6c9c..4481004fdf6 100644 --- a/modules/lang-painless/src/main/resources/org/elasticsearch/painless/java.time.txt +++ b/modules/lang-painless/src/main/resources/org/elasticsearch/painless/java.time.txt @@ -43,6 +43,7 @@ class Duration -> java.time.Duration extends Comparable,TemporalAmount,Object { Duration ZERO Duration abs() Duration between(Temporal,Temporal) + int compareTo(Duration) Duration dividedBy(long) Duration from(TemporalAmount) int getNano() @@ -91,6 +92,7 @@ class Instant -> java.time.Instant extends Comparable,Temporal,TemporalAccessor, Instant MIN OffsetDateTime atOffset(ZoneOffset) ZonedDateTime atZone(ZoneId) + int compareTo(Instant) Instant from(TemporalAccessor) long getEpochSecond() int getNano() @@ -118,7 +120,7 @@ class Instant -> java.time.Instant extends Comparable,Temporal,TemporalAccessor, Instant with(TemporalField,long) } -class LocalDate -> java.time.LocalDate extends Comparable,ChronoLocalDate,Temporal,TemporalAccessor,TemporalAdjuster,Object { +class LocalDate -> java.time.LocalDate extends ChronoLocalDate,Temporal,TemporalAccessor,TemporalAdjuster,Comparable,Object { LocalDate MAX LocalDate MIN LocalDateTime atStartOfDay() @@ -154,6 +156,7 @@ class LocalDate -> java.time.LocalDate extends Comparable,ChronoLocalDate,Tempor LocalDate plusMonths(long) LocalDate plusWeeks(long) LocalDate plusDays(long) + Period until(ChronoLocalDate) LocalDate with(TemporalAdjuster) LocalDate with(TemporalField,long) LocalDate withDayOfMonth(int) @@ -162,7 +165,7 @@ class LocalDate -> java.time.LocalDate extends Comparable,ChronoLocalDate,Tempor LocalDate withYear(int) } -class LocalDateTime -> java.time.LocalDateTime extends Comparable,ChronoLocalDateTime,Temporal,TemporalAccessor,TemporalAdjuster,Object { +class LocalDateTime -> java.time.LocalDateTime extends ChronoLocalDateTime,Temporal,TemporalAccessor,TemporalAdjuster,Comparable,Object { LocalDateTime MIN LocalDateTime MAX OffsetDateTime atOffset(ZoneOffset) @@ -208,6 +211,7 @@ class LocalDateTime -> java.time.LocalDateTime extends Comparable,ChronoLocalDat LocalDateTime plusSeconds(long) LocalDateTime plusWeeks(long) LocalDateTime plusYears(long) + LocalDate toLocalDate() LocalDateTime truncatedTo(TemporalUnit) LocalDateTime with(TemporalAdjuster) LocalDateTime with(TemporalField,long) @@ -220,13 +224,14 @@ class LocalDateTime -> java.time.LocalDateTime extends Comparable,ChronoLocalDat LocalDateTime withYear(int) } -class LocalTime -> java.time.LocalTime extends Comparable,Temporal,TemporalAccessor,TemporalAdjuster,Object { +class LocalTime -> java.time.LocalTime extends Temporal,TemporalAccessor,TemporalAdjuster,Comparable,Object { LocalTime MAX LocalTime MIDNIGHT LocalTime MIN LocalTime NOON LocalDateTime atDate(LocalDate) OffsetTime atOffset(ZoneOffset) + int compareTo(LocalTime) String format(DateTimeFormatter) LocalTime from(TemporalAccessor) int getHour() @@ -267,8 +272,9 @@ class LocalTime -> java.time.LocalTime extends Comparable,Temporal,TemporalAcces LocalTime withSecond(int) } -class MonthDay -> java.time.MonthDay extends Comparable,TemporalAccessor,TemporalAdjuster,Object { +class MonthDay -> java.time.MonthDay extends TemporalAccessor,TemporalAdjuster,Comparable,Object { LocalDate atYear(int) + int compareTo(MonthDay) String format(DateTimeFormatter) MonthDay from(TemporalAccessor) int getMonthValue() @@ -287,11 +293,12 @@ class MonthDay -> java.time.MonthDay extends Comparable,TemporalAccessor,Tempora MonthDay withMonth(int) } -class OffsetDateTime -> java.time.OffsetDateTime extends Comparable,Temporal,TemporalAccessor,TemporalAdjuster,Object { +class OffsetDateTime -> java.time.OffsetDateTime extends Temporal,TemporalAccessor,TemporalAdjuster,Comparable,Object { OffsetDateTime MAX OffsetDateTime MIN ZonedDateTime atZoneSameInstant(ZoneId) ZonedDateTime atZoneSimilarLocal(ZoneId) + int compareTo(OffsetDateTime) String format(DateTimeFormatter) OffsetDateTime from(TemporalAccessor) int getDayOfMonth() @@ -359,9 +366,10 @@ class OffsetDateTime -> java.time.OffsetDateTime extends Comparable,Temporal,Tem OffsetDateTime withOffsetSameInstant(ZoneOffset) } -class OffsetTime -> java.time.OffsetTime extends Comparable,Temporal,TemporalAccessor,TemporalAdjuster,Object { +class OffsetTime -> java.time.OffsetTime extends Temporal,TemporalAccessor,TemporalAdjuster,Comparable,Object { OffsetTime MAX OffsetTime MIN + int compareTo(OffsetTime) String format(DateTimeFormatter) OffsetTime from(TemporalAccessor) int getHour() @@ -434,12 +442,13 @@ class Period -> java.time.Period extends ChronoPeriod,TemporalAmount,Object { Period withYears(int) } -class Year -> java.time.Year extends Comparable,Temporal,TemporalAccessor,TemporalAdjuster,Object { +class Year -> java.time.Year extends Temporal,TemporalAccessor,TemporalAdjuster,Comparable,Object { int MAX_VALUE int MIN_VALUE LocalDate atDay(int) YearMonth atMonth(int) LocalDate atMonthDay(MonthDay) + int compareTo(Year) String format(DateTimeFormatter) Year from(TemporalAccessor) int getValue() @@ -463,9 +472,10 @@ class Year -> java.time.Year extends Comparable,Temporal,TemporalAccessor,Tempor Year with(TemporalField,long) } -class YearMonth -> java.time.YearMonth extends Comparable,Temporal,TemporalAccessor,TemporalAdjuster,Object { +class YearMonth -> java.time.YearMonth extends Temporal,TemporalAccessor,TemporalAdjuster,Comparable,Object { LocalDate atDay(int) LocalDate atEndOfMonth() + int compareTo(YearMonth) String format(DateTimeFormatter) YearMonth from(TemporalAccessor) Month getMonth() @@ -496,7 +506,7 @@ class YearMonth -> java.time.YearMonth extends Comparable,Temporal,TemporalAcces YearMonth withMonth(int) } -class ZonedDateTime -> java.time.ZonedDateTime extends Comparable,ChronoZonedDateTime,Temporal,TemporalAccessor,Object { +class ZonedDateTime -> java.time.ZonedDateTime extends ChronoZonedDateTime,Temporal,TemporalAccessor,Comparable,Object { int getDayOfMonth() DayOfWeek getDayOfWeek() int getDayOfYear() @@ -589,7 +599,7 @@ class ZoneOffset -> java.time.ZoneOffset extends ZoneId,Object { #### Enums -class DayOfWeek -> java.time.DayOfWeek extends Enum,Comparable,TemporalAccessor,TemporalAdjuster,Object { +class DayOfWeek -> java.time.DayOfWeek extends Enum,TemporalAccessor,TemporalAdjuster,Comparable,Object { DayOfWeek FRIDAY DayOfWeek MONDAY DayOfWeek SATURDAY @@ -607,7 +617,7 @@ class DayOfWeek -> java.time.DayOfWeek extends Enum,Comparable,TemporalAccessor, DayOfWeek[] values() } -class Month -> java.time.Month extends Enum,Comparable,TemporalAccessor,TemporalAdjuster,Object { +class Month -> java.time.Month extends Enum,TemporalAccessor,TemporalAdjuster,Comparable,Object { Month APRIL Month AUGUST Month DECEMBER diff --git a/modules/lang-painless/src/main/resources/org/elasticsearch/painless/java.time.zone.txt b/modules/lang-painless/src/main/resources/org/elasticsearch/painless/java.time.zone.txt index 036e2a734f9..d9d1cce5c10 100644 --- a/modules/lang-painless/src/main/resources/org/elasticsearch/painless/java.time.zone.txt +++ b/modules/lang-painless/src/main/resources/org/elasticsearch/painless/java.time.zone.txt @@ -25,6 +25,7 @@ #### Classes class ZoneOffsetTransition -> java.time.zone.ZoneOffsetTransition extends Comparable,Object { + int compareTo(ZoneOffsetTransition) LocalDateTime getDateTimeAfter() LocalDateTime getDateTimeBefore() Duration getDuration() diff --git a/modules/lang-painless/src/main/resources/org/elasticsearch/painless/java.util.txt b/modules/lang-painless/src/main/resources/org/elasticsearch/painless/java.util.txt index 5e240d0d45a..cccbf60f1a3 100644 --- a/modules/lang-painless/src/main/resources/org/elasticsearch/painless/java.util.txt +++ b/modules/lang-painless/src/main/resources/org/elasticsearch/painless/java.util.txt @@ -454,6 +454,7 @@ class Calendar -> java.util.Calendar extends Comparable,Object { void clear() void clear(int) def clone() + int compareTo(Calendar) int get(int) int getActualMaximum(int) int getActualMinimum(int) @@ -584,6 +585,7 @@ class Date -> java.util.Date extends Comparable,Object { boolean after(Date) boolean before(Date) def clone() + int compareTo(Date) Date from(Instant) long getTime() void setTime(long) @@ -999,6 +1001,7 @@ class TreeSet -> java.util.TreeSet extends AbstractSet,NavigableSet,SortedSet,Se class UUID -> java.util.UUID extends Comparable,Object { UUID (long,long) + int compareTo(UUID) int clockSequence() UUID fromString(String) long getLeastSignificantBits() @@ -1054,101 +1057,101 @@ class Locale.FilteringMode -> java.util.Locale$FilteringMode extends Enum,Compar #### Exceptions -class ConcurrentModificationException -> java.util.ConcurrentModificationException extends RuntimeException,Exception { +class ConcurrentModificationException -> java.util.ConcurrentModificationException extends RuntimeException,Exception,Object { ConcurrentModificationException () ConcurrentModificationException (String) } -class DuplicateFormatFlagsException -> java.util.DuplicateFormatFlagsException extends IllegalFormatException,IllegalArgumentException,RuntimeException,Exception { +class DuplicateFormatFlagsException -> java.util.DuplicateFormatFlagsException extends IllegalFormatException,IllegalArgumentException,RuntimeException,Exception,Object { DuplicateFormatFlagsException (String) String getFlags() } -class EmptyStackException -> java.util.EmptyStackException extends RuntimeException,Exception { +class EmptyStackException -> java.util.EmptyStackException extends RuntimeException,Exception,Object { EmptyStackException () } -class FormatFlagsConversionMismatchException -> java.util.FormatFlagsConversionMismatchException extends IllegalFormatException,IllegalArgumentException,RuntimeException,Exception { +class FormatFlagsConversionMismatchException -> java.util.FormatFlagsConversionMismatchException extends IllegalFormatException,IllegalArgumentException,RuntimeException,Exception,Object { FormatFlagsConversionMismatchException (String,char) char getConversion() String getFlags() } -class FormatterClosedException -> java.util.FormatterClosedException extends IllegalStateException,RuntimeException,Exception { +class FormatterClosedException -> java.util.FormatterClosedException extends IllegalStateException,RuntimeException,Exception,Object { FormatterClosedException () } -class IllegalFormatCodePointException -> java.util.IllegalFormatCodePointException extends IllegalFormatException,IllegalArgumentException,RuntimeException,Exception { +class IllegalFormatCodePointException -> java.util.IllegalFormatCodePointException extends IllegalFormatException,IllegalArgumentException,RuntimeException,Exception,Object { IllegalFormatCodePointException (int) int getCodePoint() } -class IllegalFormatConversionException -> java.util.IllegalFormatConversionException extends IllegalFormatException,IllegalArgumentException,RuntimeException,Exception { +class IllegalFormatConversionException -> java.util.IllegalFormatConversionException extends IllegalFormatException,IllegalArgumentException,RuntimeException,Exception,Object { char getConversion() } -class IllegalFormatException -> java.util.IllegalFormatException extends IllegalArgumentException,RuntimeException,Exception { +class IllegalFormatException -> java.util.IllegalFormatException extends IllegalArgumentException,RuntimeException,Exception,Object { } -class IllegalFormatFlagsException -> java.util.IllegalFormatFlagsException extends IllegalFormatException,IllegalArgumentException,RuntimeException,Exception { +class IllegalFormatFlagsException -> java.util.IllegalFormatFlagsException extends IllegalFormatException,IllegalArgumentException,RuntimeException,Exception,Object { IllegalFormatFlagsException (String) String getFlags() } -class IllegalFormatPrecisionException -> java.util.IllegalFormatPrecisionException extends IllegalFormatException,IllegalArgumentException,RuntimeException,Exception { +class IllegalFormatPrecisionException -> java.util.IllegalFormatPrecisionException extends IllegalFormatException,IllegalArgumentException,RuntimeException,Exception,Object { IllegalFormatPrecisionException (int) int getPrecision() } -class IllegalFormatWidthException -> java.util.IllegalFormatWidthException extends IllegalFormatException,IllegalArgumentException,RuntimeException,Exception { +class IllegalFormatWidthException -> java.util.IllegalFormatWidthException extends IllegalFormatException,IllegalArgumentException,RuntimeException,Exception,Object { IllegalFormatWidthException (int) int getWidth() } -class IllformedLocaleException -> java.util.IllformedLocaleException extends RuntimeException,Exception { +class IllformedLocaleException -> java.util.IllformedLocaleException extends RuntimeException,Exception,Object { IllformedLocaleException () IllformedLocaleException (String) IllformedLocaleException (String,int) int getErrorIndex() } -class InputMismatchException -> java.util.InputMismatchException extends NoSuchElementException,RuntimeException,Exception { +class InputMismatchException -> java.util.InputMismatchException extends NoSuchElementException,RuntimeException,Exception,Object { InputMismatchException () InputMismatchException (String) } -class MissingFormatArgumentException -> java.util.MissingFormatArgumentException extends IllegalFormatException,IllegalArgumentException,RuntimeException,Exception { +class MissingFormatArgumentException -> java.util.MissingFormatArgumentException extends IllegalFormatException,IllegalArgumentException,RuntimeException,Exception,Object { MissingFormatArgumentException (String) String getFormatSpecifier() } -class MissingFormatWidthException -> java.util.MissingFormatWidthException extends IllegalFormatException,IllegalArgumentException,RuntimeException,Exception { +class MissingFormatWidthException -> java.util.MissingFormatWidthException extends IllegalFormatException,IllegalArgumentException,RuntimeException,Exception,Object { MissingFormatWidthException (String) String getFormatSpecifier() } -class MissingResourceException -> java.util.MissingResourceException extends RuntimeException,Exception { +class MissingResourceException -> java.util.MissingResourceException extends RuntimeException,Exception,Object { MissingResourceException (String,String,String) String getClassName() String getKey() } -class NoSuchElementException -> java.util.NoSuchElementException extends RuntimeException,Exception { +class NoSuchElementException -> java.util.NoSuchElementException extends RuntimeException,Exception,Object { NoSuchElementException () NoSuchElementException (String) } -class TooManyListenersException -> java.util.TooManyListenersException extends Exception { +class TooManyListenersException -> java.util.TooManyListenersException extends Exception,Object { TooManyListenersException () TooManyListenersException (String) } -class UnknownFormatConversionException -> java.util.UnknownFormatConversionException extends IllegalFormatException,IllegalArgumentException,RuntimeException,Exception { +class UnknownFormatConversionException -> java.util.UnknownFormatConversionException extends IllegalFormatException,IllegalArgumentException,RuntimeException,Exception,Object { UnknownFormatConversionException (String) String getConversion() } -class UnknownFormatFlagsException -> java.util.UnknownFormatFlagsException extends IllegalFormatException,IllegalArgumentException,RuntimeException,Exception { +class UnknownFormatFlagsException -> java.util.UnknownFormatFlagsException extends IllegalFormatException,IllegalArgumentException,RuntimeException,Exception,Object { UnknownFormatFlagsException (String) String getFlags() } 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 8627de26d26..7fff9ac0aa4 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 @@ -65,22 +65,26 @@ class org.elasticsearch.common.geo.GeoPoint -> org.elasticsearch.common.geo.GeoP } class org.elasticsearch.index.fielddata.ScriptDocValues.Strings -> org.elasticsearch.index.fielddata.ScriptDocValues$Strings extends List,Collection,Iterable,Object { + String get(int) String getValue() List getValues() } class org.elasticsearch.index.fielddata.ScriptDocValues.Longs -> org.elasticsearch.index.fielddata.ScriptDocValues$Longs extends List,Collection,Iterable,Object { + Long get(int) long getValue() List getValues() org.joda.time.ReadableDateTime getDate() } class org.elasticsearch.index.fielddata.ScriptDocValues.Doubles -> org.elasticsearch.index.fielddata.ScriptDocValues$Doubles extends List,Collection,Iterable,Object { + Double get(int) double getValue() List getValues() } class org.elasticsearch.index.fielddata.ScriptDocValues.GeoPoints -> org.elasticsearch.index.fielddata.ScriptDocValues$GeoPoints extends List,Collection,Iterable,Object { + org.elasticsearch.common.geo.GeoPoint get(int) org.elasticsearch.common.geo.GeoPoint getValue() List getValues() double getLat() diff --git a/modules/lang-painless/src/test/java/org/elasticsearch/painless/BasicAPITests.java b/modules/lang-painless/src/test/java/org/elasticsearch/painless/BasicAPITests.java index 46609a76173..885ce060aaa 100644 --- a/modules/lang-painless/src/test/java/org/elasticsearch/painless/BasicAPITests.java +++ b/modules/lang-painless/src/test/java/org/elasticsearch/painless/BasicAPITests.java @@ -19,7 +19,6 @@ package org.elasticsearch.painless; -import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.Map; @@ -111,7 +110,13 @@ public class BasicAPITests extends ScriptTestCase { assertBytecodeExists("def x = 1D", "INVOKESTATIC java/lang/Double.valueOf (D)Ljava/lang/Double;"); } - void testStream() { - assertEquals(11, exec("params.list.stream().sum()", Collections.singletonMap("list", Arrays.asList(1,2,3,5)))); + public void testInterfaceDefaultMethods() { + assertEquals(1, exec("Map map = new HashMap(); return map.getOrDefault(5,1);")); + assertEquals(1, exec("def map = new HashMap(); return map.getOrDefault(5,1);")); + } + + public void testInterfacesHaveObject() { + assertEquals("{}", exec("Map map = new HashMap(); return map.toString();")); + assertEquals("{}", exec("def map = new HashMap(); return map.toString();")); } } 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 4469279c8be..7a55844a224 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); + DefBootstrap.METHOD_CALL, 0); 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); + DefBootstrap.METHOD_CALL, 0); 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); + DefBootstrap.METHOD_CALL, 0); 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 20c48fe87d6..12265f161ab 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 @@ -20,11 +20,60 @@ package org.elasticsearch.painless; public class FunctionRefTests extends ScriptTestCase { - public void testUnsupported() { - expectScriptThrows(UnsupportedOperationException.class, () -> { - exec("DoubleStream.Builder builder = DoubleStream.builder();" + - "builder.add(2.0); builder.add(1.0); builder.add(3.0);" + - "builder.build().reduce(Double::unsupported);"); + + public void testStaticMethodReference() { + assertEquals(1, exec("List l = new ArrayList(); l.add(2); l.add(1); l.sort(Integer::compare); return l.get(0);")); + } + + public void testStaticMethodReferenceDef() { + assertEquals(1, exec("def l = new ArrayList(); l.add(2); l.add(1); l.sort(Integer::compare); return l.get(0);")); + } + + public void testVirtualMethodReference() { + assertEquals(2, exec("List l = new ArrayList(); l.add(1); l.add(1); return l.stream().mapToInt(Integer::intValue).sum();")); + } + + public void testVirtualMethodReferenceDef() { + assertEquals(2, exec("def l = new ArrayList(); l.add(1); l.add(1); return l.stream().mapToInt(Integer::intValue).sum();")); + } + + 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()")); + } + + public void testCtorMethodReferenceDef() { + assertEquals(3.0D, + exec("def l = new ArrayList(); l.add(1.0); l.add(2.0); " + + "def doubleStream = l.stream().mapToDouble(Double::doubleValue);" + + "def stats = doubleStream.collect(DoubleSummaryStatistics::new, " + + "DoubleSummaryStatistics::accept, " + + "DoubleSummaryStatistics::combine); " + + "return stats.getSum()")); + } + + public void testMethodMissing() { + IllegalArgumentException expected = expectScriptThrows(IllegalArgumentException.class, () -> { + exec("List l = new ArrayList(); l.add(2); l.add(1); l.sort(Integer::bogus); return l.get(0);"); + }); + assertTrue(expected.getMessage().contains("Unknown reference")); + } + + public void testNotFunctionalInterface() { + IllegalArgumentException expected = expectScriptThrows(IllegalArgumentException.class, () -> { + exec("List l = new ArrayList(); l.add(2); l.add(1); l.add(Integer::bogus); return l.get(0);"); + }); + assertTrue(expected.getMessage().contains("Cannot convert function reference")); + } + + public void testIncompatible() { + expectScriptThrows(BootstrapMethodError.class, () -> { + exec("List l = new ArrayList(); l.add(2); l.add(1); l.sort(String::startsWith); return l.get(0);"); }); } } diff --git a/modules/lang-painless/src/test/java/org/elasticsearch/painless/OverloadTests.java b/modules/lang-painless/src/test/java/org/elasticsearch/painless/OverloadTests.java index ba095c05a9d..fce827e686c 100644 --- a/modules/lang-painless/src/test/java/org/elasticsearch/painless/OverloadTests.java +++ b/modules/lang-painless/src/test/java/org/elasticsearch/painless/OverloadTests.java @@ -37,7 +37,7 @@ public class OverloadTests extends ScriptTestCase { IllegalArgumentException expected = expectScriptThrows(IllegalArgumentException.class, () -> { exec("def x = 'abc123abc'; return x.indexOf('c', 3, 'bogus');"); }); - assertTrue(expected.getMessage().contains("dynamic method [indexOf] with signature [(String,int,String)")); + assertTrue(expected.getMessage().contains("dynamic method [indexOf]")); } public void testConstructor() {