get things started
This commit is contained in:
parent
1b7d35e4a7
commit
80734c75b5
|
@ -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 java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.ObjIntConsumer;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.function.ToDoubleFunction;
|
||||
import java.util.regex.Matcher;
|
||||
|
||||
public class Augmentation {
|
||||
public static <T> int getLength(List<T> receiver) {
|
||||
return receiver.size();
|
||||
}
|
||||
|
||||
public static String namedGroup(Matcher receiver, String name) {
|
||||
return receiver.group(name);
|
||||
}
|
||||
|
||||
public static <T> boolean any(Iterable<T> receiver, Predicate<T> predicate) {
|
||||
for (T t : receiver) {
|
||||
if (predicate.test(t)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static <T> int count(Iterable<T> receiver, Predicate<T> predicate) {
|
||||
int count = 0;
|
||||
for (T t : receiver) {
|
||||
if (predicate.test(t)) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
public static <T> Iterable<T> each(Iterable<T> receiver, Consumer<T> consumer) {
|
||||
receiver.forEach(consumer);
|
||||
return receiver;
|
||||
}
|
||||
|
||||
public static <T> Iterable<T> eachWithIndex(Iterable<T> receiver, ObjIntConsumer<T> consumer) {
|
||||
int count = 0;
|
||||
for (T t : receiver) {
|
||||
consumer.accept(t, count++);
|
||||
}
|
||||
return receiver;
|
||||
}
|
||||
|
||||
public static <T> boolean every(Iterable<T> receiver, Predicate<T> predicate) {
|
||||
for (T t : receiver) {
|
||||
if (predicate.test(t) == false) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static <T,U> List<U> findResults(Iterable<T> receiver, Function<T,U> filter) {
|
||||
List<U> list = new ArrayList<>();
|
||||
for (T t: receiver) {
|
||||
U result = filter.apply(t);
|
||||
if (result != null) {
|
||||
list.add(result);
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
public static <T,U> Map<U,List<T>> groupBy(Iterable<T> receiver, Function<T,U> mapper) {
|
||||
Map<U,List<T>> map = new LinkedHashMap<>();
|
||||
for (T t : receiver) {
|
||||
U mapped = mapper.apply(t);
|
||||
List<T> results = map.get(mapped);
|
||||
if (results == null) {
|
||||
results = new ArrayList<>();
|
||||
map.put(mapped, results);
|
||||
}
|
||||
results.add(t);
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
public static <T> String join(Iterable<T> receiver, String separator) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (T t : receiver) {
|
||||
if (sb.length() > 0) {
|
||||
sb.append(separator);
|
||||
}
|
||||
sb.append(t);
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public static <T> double sum(Iterable<T> receiver, ToDoubleFunction<T> function) {
|
||||
double sum = 0;
|
||||
for (T t : receiver) {
|
||||
sum += function.applyAsDouble(t);
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
}
|
|
@ -186,15 +186,17 @@ public final class Definition {
|
|||
public static class Method {
|
||||
public final String name;
|
||||
public final Struct owner;
|
||||
public final boolean augmentation;
|
||||
public final Type rtn;
|
||||
public final List<Type> arguments;
|
||||
public final org.objectweb.asm.commons.Method method;
|
||||
public final int modifiers;
|
||||
public final MethodHandle handle;
|
||||
|
||||
public Method(String name, Struct owner, Type rtn, List<Type> arguments,
|
||||
public Method(String name, Struct owner, boolean augmentation, Type rtn, List<Type> arguments,
|
||||
org.objectweb.asm.commons.Method method, int modifiers, MethodHandle handle) {
|
||||
this.name = name;
|
||||
this.augmentation = augmentation;
|
||||
this.owner = owner;
|
||||
this.rtn = rtn;
|
||||
this.arguments = Collections.unmodifiableList(arguments);
|
||||
|
@ -217,7 +219,15 @@ public final class Definition {
|
|||
// otherwise compute it
|
||||
final Class<?> params[];
|
||||
final Class<?> returnValue;
|
||||
if (Modifier.isStatic(modifiers)) {
|
||||
if (augmentation) {
|
||||
// virtual/interface method disguised as static
|
||||
params = new Class<?>[1 + arguments.size()];
|
||||
params[0] = Augmentation.class;
|
||||
for (int i = 0; i < arguments.size(); i++) {
|
||||
params[i + 1] = arguments.get(i).clazz;
|
||||
}
|
||||
returnValue = rtn.clazz;
|
||||
} else if (Modifier.isStatic(modifiers)) {
|
||||
// static method: straightforward copy
|
||||
params = new Class<?>[arguments.size()];
|
||||
for (int i = 0; i < arguments.size(); i++) {
|
||||
|
@ -242,6 +252,24 @@ public final class Definition {
|
|||
}
|
||||
return MethodType.methodType(returnValue, params);
|
||||
}
|
||||
|
||||
public void write(MethodWriter writer) {
|
||||
final org.objectweb.asm.Type type;
|
||||
if (augmentation) {
|
||||
assert java.lang.reflect.Modifier.isStatic(modifiers);
|
||||
type = org.objectweb.asm.Type.getType(Augmentation.class);
|
||||
} else {
|
||||
type = owner.type;
|
||||
}
|
||||
|
||||
if (java.lang.reflect.Modifier.isStatic(modifiers)) {
|
||||
writer.invokeStatic(type, method);
|
||||
} else if (java.lang.reflect.Modifier.isInterface(owner.clazz.getModifiers())) {
|
||||
writer.invokeInterface(type, method);
|
||||
} else {
|
||||
writer.invokeVirtual(type, method);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static final class Field {
|
||||
|
@ -690,7 +718,7 @@ public final class Definition {
|
|||
" with arguments " + Arrays.toString(classes) + ".");
|
||||
}
|
||||
|
||||
final Method constructor = new Method(name, owner, returnType, Arrays.asList(args), asm, reflect.getModifiers(), handle);
|
||||
final Method constructor = new Method(name, owner, false, returnType, Arrays.asList(args), asm, reflect.getModifiers(), handle);
|
||||
|
||||
owner.constructors.put(methodKey, constructor);
|
||||
}
|
||||
|
@ -734,24 +762,20 @@ public final class Definition {
|
|||
}
|
||||
addConstructorInternal(className, "<init>", args);
|
||||
} else {
|
||||
if (methodName.indexOf('/') >= 0) {
|
||||
String nameAndAlias[] = methodName.split("/");
|
||||
if (nameAndAlias.length != 2) {
|
||||
throw new IllegalArgumentException("Currently only two aliases are allowed!");
|
||||
}
|
||||
addMethodInternal(className, nameAndAlias[0], nameAndAlias[1], rtn, args);
|
||||
if (methodName.indexOf("*") >= 0) {
|
||||
addMethodInternal(className, methodName.substring(0, methodName.length() - 1), true, rtn, args);
|
||||
} else {
|
||||
addMethodInternal(className, methodName, null, rtn, args);
|
||||
addMethodInternal(className, methodName, false, rtn, args);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// field
|
||||
addFieldInternal(className, elements[1], null, rtn);
|
||||
addFieldInternal(className, elements[1], rtn);
|
||||
}
|
||||
}
|
||||
|
||||
private final void addMethodInternal(final String struct, final String name, final String alias,
|
||||
final Type rtn, final Type[] args) {
|
||||
private final void addMethodInternal(String struct, String name, boolean augmentation,
|
||||
Type rtn, Type[] args) {
|
||||
final Struct owner = structsMap.get(struct);
|
||||
|
||||
if (owner == null) {
|
||||
|
@ -777,20 +801,32 @@ public final class Definition {
|
|||
"Duplicate method signature [" + methodKey + "] found within the struct [" + owner.name + "].");
|
||||
}
|
||||
|
||||
final Class<?>[] classes = new Class<?>[args.length];
|
||||
final Class<?> implClass;
|
||||
final Class<?>[] params;
|
||||
|
||||
for (int count = 0; count < classes.length; ++count) {
|
||||
classes[count] = args[count].clazz;
|
||||
if (augmentation == false) {
|
||||
implClass = owner.clazz;
|
||||
params = new Class<?>[args.length];
|
||||
for (int count = 0; count < args.length; ++count) {
|
||||
params[count] = args[count].clazz;
|
||||
}
|
||||
} else {
|
||||
implClass = Augmentation.class;
|
||||
params = new Class<?>[args.length + 1];
|
||||
params[0] = owner.clazz;
|
||||
for (int count = 0; count < args.length; ++count) {
|
||||
params[count+1] = args[count].clazz;
|
||||
}
|
||||
}
|
||||
|
||||
final java.lang.reflect.Method reflect;
|
||||
|
||||
try {
|
||||
reflect = owner.clazz.getMethod(alias == null ? name : alias, classes);
|
||||
} catch (final NoSuchMethodException exception) {
|
||||
throw new IllegalArgumentException("Method [" + (alias == null ? name : alias) +
|
||||
reflect = implClass.getMethod(name, params);
|
||||
} catch (NoSuchMethodException exception) {
|
||||
throw new IllegalArgumentException("Method [" + name +
|
||||
"] not found for class [" + owner.clazz.getName() + "]" +
|
||||
" with arguments " + Arrays.toString(classes) + ".");
|
||||
" with arguments " + Arrays.toString(params) + ".");
|
||||
}
|
||||
|
||||
if (!reflect.getReturnType().equals(rtn.clazz)) {
|
||||
|
@ -805,25 +841,24 @@ public final class Definition {
|
|||
MethodHandle handle;
|
||||
|
||||
try {
|
||||
handle = MethodHandles.publicLookup().in(owner.clazz).unreflect(reflect);
|
||||
handle = MethodHandles.publicLookup().in(implClass).unreflect(reflect);
|
||||
} catch (final IllegalAccessException exception) {
|
||||
throw new IllegalArgumentException("Method [" + (alias == null ? name : alias) + "]" +
|
||||
" not found for class [" + owner.clazz.getName() + "]" +
|
||||
" with arguments " + Arrays.toString(classes) + ".");
|
||||
throw new IllegalArgumentException("Method [" + name + "]" +
|
||||
" not found for class [" + implClass.getName() + "]" +
|
||||
" with arguments " + Arrays.toString(params) + ".");
|
||||
}
|
||||
|
||||
final int modifiers = reflect.getModifiers();
|
||||
final Method method = new Method(name, owner, rtn, Arrays.asList(args), asm, modifiers, handle);
|
||||
final Method method = new Method(name, owner, augmentation, rtn, Arrays.asList(args), asm, modifiers, handle);
|
||||
|
||||
if (java.lang.reflect.Modifier.isStatic(modifiers)) {
|
||||
if (augmentation == false && java.lang.reflect.Modifier.isStatic(modifiers)) {
|
||||
owner.staticMethods.put(methodKey, method);
|
||||
} else {
|
||||
owner.methods.put(methodKey, method);
|
||||
}
|
||||
}
|
||||
|
||||
private final void addFieldInternal(final String struct, final String name, final String alias,
|
||||
final Type type) {
|
||||
private final void addFieldInternal(String struct, String name, Type type) {
|
||||
final Struct owner = structsMap.get(struct);
|
||||
|
||||
if (owner == null) {
|
||||
|
@ -844,9 +879,9 @@ public final class Definition {
|
|||
java.lang.reflect.Field reflect;
|
||||
|
||||
try {
|
||||
reflect = owner.clazz.getField(alias == null ? name : alias);
|
||||
reflect = owner.clazz.getField(name);
|
||||
} catch (final NoSuchFieldException exception) {
|
||||
throw new IllegalArgumentException("Field [" + (alias == null ? name : alias) + "]" +
|
||||
throw new IllegalArgumentException("Field [" + name + "]" +
|
||||
" not found for class [" + owner.clazz.getName() + "].");
|
||||
}
|
||||
|
||||
|
@ -862,7 +897,7 @@ public final class Definition {
|
|||
setter = MethodHandles.publicLookup().unreflectSetter(reflect);
|
||||
}
|
||||
} catch (final IllegalAccessException exception) {
|
||||
throw new IllegalArgumentException("Getter/Setter [" + (alias == null ? name : alias) + "]" +
|
||||
throw new IllegalArgumentException("Getter/Setter [" + name + "]" +
|
||||
" not found for class [" + owner.clazz.getName() + "].");
|
||||
}
|
||||
|
||||
|
@ -875,9 +910,9 @@ public final class Definition {
|
|||
" within the struct [" + owner.name + "] is not final.");
|
||||
}
|
||||
|
||||
owner.staticMembers.put(alias == null ? name : alias, field);
|
||||
owner.staticMembers.put(name, field);
|
||||
} else {
|
||||
owner.members.put(alias == null ? name : alias, field);
|
||||
owner.members.put(name, field);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -915,11 +950,24 @@ public final class Definition {
|
|||
// https://bugs.openjdk.java.net/browse/JDK-8072746
|
||||
} else {
|
||||
try {
|
||||
Class<?> arguments[] = new Class<?>[method.arguments.size()];
|
||||
// TODO: we *have* to remove all these public members and use getter methods to encapsulate!
|
||||
final Class<?> impl;
|
||||
final Class<?> arguments[];
|
||||
if (method.augmentation) {
|
||||
impl = Augmentation.class;
|
||||
arguments = new Class<?>[method.arguments.size() + 1];
|
||||
arguments[0] = method.owner.clazz;
|
||||
for (int i = 0; i < method.arguments.size(); i++) {
|
||||
arguments[i + 1] = method.arguments.get(i).clazz;
|
||||
}
|
||||
} else {
|
||||
impl = owner.clazz;
|
||||
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);
|
||||
}
|
||||
java.lang.reflect.Method m = impl.getMethod(method.method.getName(), arguments);
|
||||
if (m.getReturnType() != method.rtn.clazz) {
|
||||
throw new IllegalStateException("missing covariant override for: " + m + " in " + owner.name);
|
||||
}
|
||||
|
|
|
@ -123,13 +123,7 @@ public final class LCallInvoke extends ALink {
|
|||
argument.write(writer, globals);
|
||||
}
|
||||
|
||||
if (java.lang.reflect.Modifier.isStatic(method.modifiers)) {
|
||||
writer.invokeStatic(method.owner.type, method.method);
|
||||
} else if (java.lang.reflect.Modifier.isInterface(method.owner.clazz.getModifiers())) {
|
||||
writer.invokeInterface(method.owner.type, method.method);
|
||||
} else {
|
||||
writer.invokeVirtual(method.owner.type, method.method);
|
||||
}
|
||||
method.write(writer);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -92,11 +92,7 @@ final class LListShortcut extends ALink {
|
|||
void load(MethodWriter writer, Globals globals) {
|
||||
writer.writeDebugInfo(location);
|
||||
|
||||
if (java.lang.reflect.Modifier.isInterface(getter.owner.clazz.getModifiers())) {
|
||||
writer.invokeInterface(getter.owner.type, getter.method);
|
||||
} else {
|
||||
writer.invokeVirtual(getter.owner.type, getter.method);
|
||||
}
|
||||
getter.write(writer);
|
||||
|
||||
if (!getter.rtn.clazz.equals(getter.handle.type().returnType())) {
|
||||
writer.checkCast(getter.rtn.type);
|
||||
|
@ -107,11 +103,7 @@ final class LListShortcut extends ALink {
|
|||
void store(MethodWriter writer, Globals globals) {
|
||||
writer.writeDebugInfo(location);
|
||||
|
||||
if (java.lang.reflect.Modifier.isInterface(setter.owner.clazz.getModifiers())) {
|
||||
writer.invokeInterface(setter.owner.type, setter.method);
|
||||
} else {
|
||||
writer.invokeVirtual(setter.owner.type, setter.method);
|
||||
}
|
||||
setter.write(writer);
|
||||
|
||||
writer.writePop(setter.rtn.sort.size);
|
||||
}
|
||||
|
|
|
@ -91,11 +91,7 @@ final class LMapShortcut extends ALink {
|
|||
void load(MethodWriter writer, Globals globals) {
|
||||
writer.writeDebugInfo(location);
|
||||
|
||||
if (java.lang.reflect.Modifier.isInterface(getter.owner.clazz.getModifiers())) {
|
||||
writer.invokeInterface(getter.owner.type, getter.method);
|
||||
} else {
|
||||
writer.invokeVirtual(getter.owner.type, getter.method);
|
||||
}
|
||||
getter.write(writer);
|
||||
|
||||
if (!getter.rtn.clazz.equals(getter.handle.type().returnType())) {
|
||||
writer.checkCast(getter.rtn.type);
|
||||
|
@ -106,11 +102,7 @@ final class LMapShortcut extends ALink {
|
|||
void store(MethodWriter writer, Globals globals) {
|
||||
writer.writeDebugInfo(location);
|
||||
|
||||
if (java.lang.reflect.Modifier.isInterface(setter.owner.clazz.getModifiers())) {
|
||||
writer.invokeInterface(setter.owner.type, setter.method);
|
||||
} else {
|
||||
writer.invokeVirtual(setter.owner.type, setter.method);
|
||||
}
|
||||
setter.write(writer);
|
||||
|
||||
writer.writePop(setter.rtn.sort.size);
|
||||
}
|
||||
|
|
|
@ -95,11 +95,7 @@ final class LShortcut extends ALink {
|
|||
void load(MethodWriter writer, Globals globals) {
|
||||
writer.writeDebugInfo(location);
|
||||
|
||||
if (java.lang.reflect.Modifier.isInterface(getter.owner.clazz.getModifiers())) {
|
||||
writer.invokeInterface(getter.owner.type, getter.method);
|
||||
} else {
|
||||
writer.invokeVirtual(getter.owner.type, getter.method);
|
||||
}
|
||||
getter.write(writer);
|
||||
|
||||
if (!getter.rtn.clazz.equals(getter.handle.type().returnType())) {
|
||||
writer.checkCast(getter.rtn.type);
|
||||
|
@ -110,11 +106,7 @@ final class LShortcut extends ALink {
|
|||
void store(MethodWriter writer, Globals globals) {
|
||||
writer.writeDebugInfo(location);
|
||||
|
||||
if (java.lang.reflect.Modifier.isInterface(setter.owner.clazz.getModifiers())) {
|
||||
writer.invokeInterface(setter.owner.type, setter.method);
|
||||
} else {
|
||||
writer.invokeVirtual(setter.owner.type, setter.method);
|
||||
}
|
||||
setter.write(writer);
|
||||
|
||||
writer.writePop(setter.rtn.sort.size);
|
||||
}
|
||||
|
|
|
@ -206,10 +206,8 @@ public class SEach extends AStatement {
|
|||
Type itr = Definition.getType("Iterator");
|
||||
org.objectweb.asm.Type methodType = org.objectweb.asm.Type.getMethodType(itr.type, Definition.DEF_TYPE.type);
|
||||
writer.invokeDefCall("iterator", methodType, DefBootstrap.ITERATOR);
|
||||
} else if (java.lang.reflect.Modifier.isInterface(method.owner.clazz.getModifiers())) {
|
||||
writer.invokeInterface(method.owner.type, method.method);
|
||||
} else {
|
||||
writer.invokeVirtual(method.owner.type, method.method);
|
||||
method.write(writer);
|
||||
}
|
||||
|
||||
writer.visitVarInsn(iterator.type.type.getOpcode(Opcodes.ISTORE), iterator.getSlot());
|
||||
|
|
|
@ -114,7 +114,7 @@ public class SFunction extends AStatement {
|
|||
|
||||
org.objectweb.asm.commons.Method method =
|
||||
new org.objectweb.asm.commons.Method(name, MethodType.methodType(rtnType.clazz, paramClasses).toMethodDescriptorString());
|
||||
this.method = new Method(name, null, rtnType, paramTypes, method, Modifier.STATIC | Modifier.PRIVATE, null);
|
||||
this.method = new Method(name, null, false, rtnType, paramTypes, method, Modifier.STATIC | Modifier.PRIVATE, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -50,6 +50,8 @@ class Iterable -> java.lang.Iterable {
|
|||
void forEach(Consumer)
|
||||
Iterator iterator()
|
||||
Spliterator spliterator()
|
||||
# some adaptations of groovy methods
|
||||
boolean any*(Predicate)
|
||||
}
|
||||
|
||||
# Readable: i/o
|
||||
|
|
|
@ -42,7 +42,7 @@ class Matcher -> java.util.regex.Matcher extends Object {
|
|||
boolean find(int)
|
||||
String group()
|
||||
String group(int)
|
||||
String namedGroup/group(String)
|
||||
String namedGroup*(String)
|
||||
int groupCount()
|
||||
boolean hasAnchoringBounds()
|
||||
boolean hasTransparentBounds()
|
||||
|
|
|
@ -114,8 +114,7 @@ class List -> java.util.List extends Collection,Iterable {
|
|||
def remove(int)
|
||||
void replaceAll(UnaryOperator)
|
||||
def set(int,def)
|
||||
# TODO: wtf?
|
||||
int getLength/size()
|
||||
int getLength*()
|
||||
void sort(Comparator)
|
||||
List subList(int,int)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* 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;
|
||||
|
||||
public class AugmentationTests extends ScriptTestCase {
|
||||
|
||||
@AwaitsFix(bugUrl = "rmuir is working on this")
|
||||
public void testCapturingReference() {
|
||||
assertEquals(1, exec("int foo(Supplier t) { return t.get() }" +
|
||||
"def l = new ArrayList(); l.add(1);" +
|
||||
"return foo(l::getLength);"));
|
||||
}
|
||||
|
||||
|
||||
public void testIterable_Any() {
|
||||
assertEquals(true, exec("List l = new ArrayList(); l.add(1); l.any(x -> x == 1)"));
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue