use of org.elasticsearch.painless.FunctionRef in project elasticsearch by elastic.
the class ECapturingFunctionRef method analyze.
@Override
void analyze(Locals variables) {
captured = variables.getVariable(location, variable);
if (expected == null) {
if (captured.type.sort == Definition.Sort.DEF) {
// dynamic implementation
defPointer = "D" + variable + "." + call + ",1";
} else {
// typed implementation
defPointer = "S" + captured.type.name + "." + call + ",1";
}
actual = Definition.getType("String");
} else {
defPointer = null;
// static case
if (captured.type.sort != Definition.Sort.DEF) {
try {
ref = new FunctionRef(expected, captured.type.name, call, 1);
} catch (IllegalArgumentException e) {
throw createError(e);
}
}
actual = expected;
}
}
use of org.elasticsearch.painless.FunctionRef in project elasticsearch by elastic.
the class ELambda method analyze.
@Override
void analyze(Locals locals) {
final Type returnType;
final List<String> actualParamTypeStrs;
Method interfaceMethod;
// inspect the target first, set interface method if we know it.
if (expected == null) {
interfaceMethod = null;
// we don't know anything: treat as def
returnType = Definition.DEF_TYPE;
// don't infer any types
actualParamTypeStrs = paramTypeStrs;
} else {
// we know the method statically, infer return type and any unknown/def types
interfaceMethod = expected.struct.getFunctionalMethod();
if (interfaceMethod == null) {
throw createError(new IllegalArgumentException("Cannot pass lambda to [" + expected.name + "], not a functional interface"));
}
// check arity before we manipulate parameters
if (interfaceMethod.arguments.size() != paramTypeStrs.size())
throw new IllegalArgumentException("Incorrect number of parameters for [" + interfaceMethod.name + "] in [" + expected.clazz + "]");
// for method invocation, its allowed to ignore the return value
if (interfaceMethod.rtn == Definition.VOID_TYPE) {
returnType = Definition.DEF_TYPE;
} else {
returnType = interfaceMethod.rtn;
}
// replace any def types with the actual type (which could still be def)
actualParamTypeStrs = new ArrayList<String>();
for (int i = 0; i < paramTypeStrs.size(); i++) {
String paramType = paramTypeStrs.get(i);
if (paramType.equals(Definition.DEF_TYPE.name)) {
actualParamTypeStrs.add(interfaceMethod.arguments.get(i).name);
} else {
actualParamTypeStrs.add(paramType);
}
}
}
// gather any variables used by the lambda body first.
Set<String> variables = new HashSet<>();
for (AStatement statement : statements) {
statement.extractVariables(variables);
}
// any of those variables defined in our scope need to be captured
captures = new ArrayList<>();
for (String variable : variables) {
if (locals.hasVariable(variable)) {
captures.add(locals.getVariable(location, variable));
}
}
// prepend capture list to lambda's arguments
List<String> paramTypes = new ArrayList<>();
List<String> paramNames = new ArrayList<>();
for (Variable var : captures) {
paramTypes.add(var.type.name);
paramNames.add(var.name);
}
paramTypes.addAll(actualParamTypeStrs);
paramNames.addAll(paramNameStrs);
// desugar lambda body into a synthetic method
desugared = new SFunction(reserved, location, returnType.name, name, paramTypes, paramNames, statements, true);
desugared.generateSignature();
desugared.analyze(Locals.newLambdaScope(locals.getProgramScope(), returnType, desugared.parameters, captures.size(), reserved.getMaxLoopCounter()));
// setup method reference to synthetic method
if (expected == null) {
ref = null;
actual = Definition.getType("String");
defPointer = "Sthis." + name + "," + captures.size();
} else {
defPointer = null;
try {
ref = new FunctionRef(expected, interfaceMethod, desugared.method, captures.size());
} catch (IllegalArgumentException e) {
throw createError(e);
}
actual = expected;
}
}
use of org.elasticsearch.painless.FunctionRef in project elasticsearch by elastic.
the class EFunctionRef method analyze.
@Override
void analyze(Locals locals) {
if (expected == null) {
ref = null;
actual = Definition.getType("String");
defPointer = "S" + type + "." + call + ",0";
} else {
defPointer = null;
try {
if ("this".equals(type)) {
// user's own function
Method interfaceMethod = expected.struct.getFunctionalMethod();
if (interfaceMethod == null) {
throw new IllegalArgumentException("Cannot convert function reference [" + type + "::" + call + "] " + "to [" + expected.name + "], not a functional interface");
}
Method implMethod = locals.getMethod(new MethodKey(call, interfaceMethod.arguments.size()));
if (implMethod == null) {
throw new IllegalArgumentException("Cannot convert function reference [" + type + "::" + call + "] " + "to [" + expected.name + "], function not found");
}
ref = new FunctionRef(expected, interfaceMethod, implMethod, 0);
} else {
// whitelist lookup
ref = new FunctionRef(expected, type, call, 0);
}
} catch (IllegalArgumentException e) {
throw createError(e);
}
actual = expected;
}
}
Aggregations