private boolean checkCurriedOnClosed(Object curried, int position) { if (position != 1 || !isClosedOnFreeVar()) return false; checkClosedType(curried); closed = curried; freeVarsNumber--; return true; }
void curryParam(Object curried, int position) throws IllegalArgumentException { if (checkCurriedOnClosed(curried, position)) return; if (curriedVars == null) { curriedVars = new Object[freeVarsNumber]; curriedVarsFlags = new boolean[freeVarsNumber]; } if (!findVarToBeCurried(curried, position)) throw new IllegalArgumentException("Trying to curry this closure on an already bound or unexisting variable"); }
/** * Curry this closure by fixing one of its free variable to a given value. * @param curriedClosure The closure resulting from this curry operation * @param curried The value to which the free variable should be curry * @param position The 1-based position of the variable to which apply the curry operation * @return A Closure having a free variable less than this one since one of them has been fixed to the given value * @throws IllegalArgumentException if this closure doesn't have a free variable in the specified position */ <T extends AbstractClosure> T curry(T curriedClosure, Object curried, int position) throws IllegalArgumentException { cloneClosureForCurry(curriedClosure); curriedClosure.curryParam(curried, position); return curriedClosure; }
/** * Invokes this closure once for each passed set of variables. * Each iterable is used as a different set of variables with which this closure is invoked * @param vars The variables used to invoke this closure once for each set of variables * @return A list of Object containing the results of each closure invocation * @throws WrongClosureInvocationException if the number of the passed variables doesn't correspond to one * with which this closure has been defined */ List<?> closeAll(Iterable<?>... vars) throws WrongClosureInvocationException { List<Object> results = new ArrayList<Object>(); int length = vars.length; Iterator<?>[] iterators = new Iterator<?>[length]; for (int i = 0; i < length; i++) { iterators[i] = vars[i].iterator(); } while (true) { Object[] varSet = new Object[length]; if (buildParams(length, iterators, varSet)) break; results.add(closeOne(varSet)); } return results; }
public Object invoke(Object proxy, Method method, Object[] args) throws InvocationTargetException, IllegalAccessException { if (registered) return method.invoke(proxy, args); registered = true; closure.bindInvocation(method, args); DelayedClosure.call(); Class<?> returnType = method.getReturnType(); if (returnType == Void.TYPE) { closure.closeUnhandledInvocations(); return null; } return createProxyClosure(closure, returnType); } }
/** * Invokes this closure once by applying the given set of variables to it. * @param vars The set of variables used to invoke this closure once * @return The result of the closure invocation * @throws WrongClosureInvocationException if the number of the passed variables doesn't correspond to one * with which this closure has been defined */ Object closeOne(Object... vars) throws WrongClosureInvocationException { if (invokables.isEmpty()) { unhandeledInvocations.add(vars); return null; } List<Object[]> boundParams = bindParams(vars); Object result = isClosedOnFreeVar() ? vars[0] : closed; Iterator<Object[]> argsIterator = boundParams != null ? boundParams.iterator() : null; for (Invokable invokable : invokables) { result = invokable.invoke(result, argsIterator != null ? argsIterator.next() : null); } return result; }
private List<Object[]> bindParams(Object... vars) throws WrongClosureInvocationException { if (checkParams(vars)) return null; int varCounter = isClosedOnFreeVar() ? 1 : 0; int curriedParamCounter = 0; List<Object[]> boundParams = new ArrayList<Object[]>();
/** * Defines the method invoked by this closure. * @param closedObject The object on which the closure has to be invoked. It can be a fixed object or a Class. * In this last case, if the method is not static, it is treated as it was an * unbound argument defined through the {@link ch.lambdaj.Lambda#var(Class)} method * @param methodName The name of the method invoked by this closure or {@link AbstractClosure#CONSTRUCTOR} * if you want to call a constructor * @param args The arguments used to invoke this closure. They can be a mixed of fixed value and * unbound one defined through the {@link ch.lambdaj.Lambda#var(Class)} method * @return The closure itself */ protected AbstractClosure of(Object closedObject, String methodName, Object ... args) { Class<?> closedClass = closedObject instanceof Class<?> ? (Class<?>)closedObject : closedObject.getClass(); Invokable invokable = methodName.equals(CONSTRUCTOR) ? new InvokableConstructor(findConstructor(closedClass, args)) : new InvokableMethod(findMethod(closedClass, methodName, args)); bindInvocation(invokable, args); setClosed(invokable.isStatic() ? null : closedObject); return this; }
/** * {@inheritDoc} */ public T exec(Object ... args) { return (T)closure.closeOne(args); } }
void bindInvocation(Method method, Object[] args) { if (!method.isAccessible()) method.setAccessible(true); bindInvocation(new InvokableMethod(method),args); }
public Object invoke(Object proxy, Method method, Object[] args) throws WrongClosureInvocationException { return closeOne(args); } }
private boolean checkParams(Object... vars) { if (vars == null || vars.length == 0) { if (freeVarsNumber != 0) throw new WrongClosureInvocationException("Closure invoked without vars instead of the expected " + freeVarsNumber); if (curriedVars == null && argsList == null) return true; } if (freeVarsNumber != vars.length) throw new WrongClosureInvocationException("Closure invoked with " + vars.length + " vars instead of the expected " + freeVarsNumber); if (isClosedOnFreeVar()) checkClosedType(vars[0]); return false; }
/** * Invokes this closure once for each passed variable. * It is then assumed that this closure has been defined with exactly one free variable * @param vars The set of variables used to invoke this closure once for each variable * @return A list of Object containing the results of each closure invocation * @throws WrongClosureInvocationException if this closure hasn't been defined with exactly one free variable */ List<?> closeAll(Object... vars) throws WrongClosureInvocationException { List<Object> results = new ArrayList<Object>(); for (Object var : vars) { results.add(closeOne(var)); } return results; }
void closeUnhandledInvocations() { for (Object[] vars : unhandeledInvocations) { closeOne(vars); } unhandeledInvocations.clear(); }