blob: 65ea3984d18d2c85f23c4959c04b2bef6126f845 [file] [log] [blame]
/*********************************************************************
* Copyright (c) 2018 The University of York.
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
**********************************************************************/
package org.eclipse.epsilon.eol.function;
import java.util.Iterator;
import java.util.List;
import org.eclipse.epsilon.common.module.ModuleElement;
import org.eclipse.epsilon.eol.dom.Expression;
import org.eclipse.epsilon.eol.dom.Parameter;
import org.eclipse.epsilon.eol.exceptions.EolIllegalOperationException;
import org.eclipse.epsilon.eol.exceptions.EolIllegalReturnException;
import org.eclipse.epsilon.eol.exceptions.EolRuntimeException;
import org.eclipse.epsilon.eol.execute.context.FrameStack;
import org.eclipse.epsilon.eol.execute.context.FrameType;
import org.eclipse.epsilon.eol.execute.context.IEolContext;
/**
* Utility class for converting EOL lambdas to Java lambdas.
*
* @author Sina Madani
* @since 1.6
*/
public class LambdaFactory {
public static Object resolveFor(Class<?> clazz, List<Parameter> iteratorParams, Expression lambdaExpr,
ModuleElement ast, IEolContext context) throws EolIllegalOperationException {
return resolveFor(clazz.getSimpleName(), iteratorParams, lambdaExpr, ast, context);
}
/**
* Validation of parameters is assumed to have already been performed in DynamicOperation or by the caller.
* @param methodName
* @param iteratorParams
* @param lambdaExprs
* @param context
* @return
* @throws EolIllegalOperationException
*/
public static Object resolveFor(String methodName, List<Parameter> iteratorParams, Expression lambdaExpr,
ModuleElement ast, IEolContext context) throws EolIllegalOperationException {
methodName = methodName.toLowerCase().replace("checkedeol", "");
if (methodName.startsWith("get")) {
methodName = methodName.substring(3);
}
switch (methodName) {
case "runnable":// case "statement":
return (CheckedEolRunnable) () -> executeExpression(context, lambdaExpr, null, lambdaExpr, iteratorParams);
case "consumer":// case "setter":
return (CheckedEolConsumer<?>) t -> executeExpression(context, ast, null, lambdaExpr, iteratorParams, t);
case "supplier":// case "getter":
return (CheckedEolSupplier<?>) () -> executeExpression(context, ast, null, lambdaExpr, iteratorParams);
case "function":// case "func": case "fun": case "mapper":
return (CheckedEolFunction<?, ?>) t -> executeExpression(context, ast, null, lambdaExpr, iteratorParams, t);
case "predicate":// case "filter":
return (CheckedEolPredicate<?>) t -> executeExpression(context, ast, Boolean.class, lambdaExpr, iteratorParams, t);
case "unary": case "unaryoperator":// case "uoperator": case "unaryop":
return (CheckedEolUnaryOperator<?>) t -> executeExpression(context, ast, t != null ? t.getClass() : null, lambdaExpr, iteratorParams, t);
case "biconsumer":// case "binaryconsumer": case "bisetter": case "binarysetter":
return (CheckedEolBiConsumer<?, ?>) (t, u) -> executeExpression(context, ast, null, lambdaExpr, iteratorParams, t, u);
case "bifunction":// case "bifunc": case "bifun": case "binaryfunction": case "binaryfunc": case "binaryfun": case "bimappper": case "binarymapper":
return (CheckedEolBiFunction<?, ?, ?>) (t, u) -> executeExpression(context, ast, null, lambdaExpr, iteratorParams, t, u);
case "bipredicate":// case "binarypredicate": case "bifilter": case "binaryfilter":
return (CheckedEolBiPredicate<?, ?>) (t, u) -> executeExpression(context, ast, Boolean.class, lambdaExpr, iteratorParams, t, u);
case "binaryoperator":// case "bioperator": case "binary": case "binaryop":
return (CheckedEolBinaryOperator<?>) (t, u) -> executeExpression(context, ast, t != null ? t.getClass() : null, lambdaExpr, iteratorParams, t, u);
default:
throw new EolIllegalOperationException(LambdaFactory.class, methodName, ast, context.getPrettyPrinterManager());
}
}
@SuppressWarnings("unchecked")
public static <R> R executeExpression(IEolContext context, ModuleElement ast,
Class<R> expectedReturnType, Expression expression, List<Parameter> params,
Object... paramValues) throws EolRuntimeException {
assert params.size() == paramValues.length;
FrameStack scope = context.getFrameStack();
scope.enterLocal(FrameType.UNPROTECTED, expression);
Iterator<Parameter> paramsIter = params.iterator();
for (Object value : paramValues) {
String name = paramsIter.next().getName();
scope.put(name, value);
}
Object result = context.getExecutorFactory().execute(expression, context);
scope.leaveLocal(expression);
// Use try-catch for slightly better performance. If it goes wrong we end up creating an
// exception anyway so no benefit of using if/else. Most of the time the try should succeed.
try {//(expectedReturnType == null || result == null || expectedReturnType.isInstance(result))
return (R) result;
}
catch (ClassCastException ccx) {
throw new EolIllegalReturnException(expectedReturnType.getName(), result, ast, context);
}
}
}