package cn.liutils.ripple; import cn.liutils.ripple.RippleException.RippleRuntimeException; /** * A wrapped function object compiled from script. * @author acaly * */ public final class ScriptFunction { private Path path; private IFunction[] internalFunc; ScriptFunction(ScriptProgram program, Path path) { this.path = path; this.internalFunc = new IFunction[0]; } void merge(IFunction newFunc, int sizeArg) { // At this point of time, the thread may also hold a lock on the program object. // As the program is always locked before a function, no deadlocks. synchronized (this) { if (internalFunc.length <= sizeArg) { IFunction[] newFuncArray = new IFunction[sizeArg + 1]; for (int i = 0; i < internalFunc.length; ++i) { newFuncArray[i] = internalFunc[i]; } newFuncArray[sizeArg] = newFunc; internalFunc = newFuncArray; } else if (internalFunc[sizeArg] == null) { internalFunc[sizeArg] = newFunc; } else { throw new RippleRuntimeException("Function overloading fails. Argument number " + sizeArg); } } } private IFunction getOverload(int sizeArg) { synchronized (this) { if (sizeArg >= internalFunc.length || internalFunc[sizeArg] == null) { throw new RippleRuntimeException("Function overload not found. Argument number " + sizeArg); } return internalFunc[sizeArg]; } } public Object callObject(Object... args) { IFunction f = getOverload(args.length); int frameCount = ScriptStacktrace.pushFrame(path.path); try { Object ret = f.call(args); ScriptStacktrace.popFrame(); return ret; } catch (RippleRuntimeException e) { ScriptStacktrace.adjustFrame(frameCount); throw e; } catch (Throwable t) { ScriptStacktrace.adjustFrame(frameCount); throw new RippleRuntimeException(t); } } public int callInteger(Object... args) { return Calculation.castInt(callObject(args)); } public float callFloat(Object ...args) { return (float) callDouble(args); } public double callDouble(Object... args) { return Calculation.castDouble(callObject(args)); } public boolean callBoolean(Object... args) { return Calculation.castBoolean(callObject(args)); } /** * This function is for internal use only. * @param nargs * @return */ IFunction cacheOverload(int nargs) { return getOverload(nargs); } }