package org.dynjs.runtime; import java.util.List; import org.dynjs.parser.ast.FunctionDeclaration; import org.dynjs.parser.ast.VariableDeclaration; public class BoundFunction extends AbstractFunction { private static final String[] EMPTY_STRINGS = new String[0]; private static String[] figureBoundParameters(JSFunction fn, Object[] boundArgs) { String[] formalParams = fn.getFormalParameters(); int numRemainingArgs = formalParams.length - boundArgs.length; if ( numRemainingArgs <= 0 ) { return EMPTY_STRINGS; } String[] remainingParams = new String[numRemainingArgs]; System.arraycopy(formalParams, boundArgs.length, remainingParams, 0, numRemainingArgs); return remainingParams; } private JSFunction target; private Object boundThis; private Object[] boundArgs; public BoundFunction(GlobalContext globalContext, LexicalEnvironment scope, final JSFunction target, final Object boundThis, final Object[] boundArgs) { super(globalContext, scope, true, figureBoundParameters(target, boundArgs)); this.target = target; this.boundThis = boundThis; this.boundArgs = boundArgs; } @Override public Object call(ExecutionContext context) { Arguments argsObj = (Arguments) context.resolve("arguments").getValue(context); int numExtraArgs = (int) argsObj.get(context, "length"); Object[] args = new Object[ this.boundArgs.length + numExtraArgs ]; System.arraycopy(this.boundArgs, 0, args, 0, this.boundArgs.length); for ( int i = 0 ; i < numExtraArgs ; ++i ) { Object v = argsObj.get( context, "" + i ); if ( v instanceof Reference ) { v = ((Reference) v).getValue(context); } args[i + this.boundArgs.length ] = v; } return context.call(this.target, this.boundThis, args); } /* @Override public Object call(ExecutionContext context, Object self, Object... args) { // 15.3.4.5.1 System.err.println( "called args: " + args.length + " // " + Arrays.asList( args ) ); Object[] allArgs = new Object[boundArgs.length + args.length]; for (int i = 0; i < boundArgs.length; ++i) { allArgs[i] = boundArgs[i]; } for (int i = boundArgs.length, j = 0; i < boundArgs.length + args.length; ++i, ++j) { allArgs[i] = args[j]; } if (self != Types.UNDEFINED) { return context.call(this.target, self, allArgs); } else { return context.call(this.target, this.boundThis, allArgs); } } */ @Override public boolean hasInstance(ExecutionContext context, Object v) { // 15.3.4.5.3 return target.hasInstance(context, v); } @Override public JSObject createNewObject(ExecutionContext context) { return target.createNewObject(context); } @Override public String getFileName() { return target.getFileName(); } @Override public String getDebugContext() { return "bound-function:" + target.getDebugContext(); } @Override public List<FunctionDeclaration> getFunctionDeclarations() { return target.getFunctionDeclarations(); } @Override public List<VariableDeclaration> getVariableDeclarations() { return target.getVariableDeclarations(); } }