1 /* 2 * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package jdk.nashorn.internal.objects; 27 28 import static jdk.nashorn.internal.runtime.ECMAErrors.typeError; 29 import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED; 30 31 import java.util.List; 32 import jdk.nashorn.internal.objects.annotations.Attribute; 33 import jdk.nashorn.internal.objects.annotations.Constructor; 34 import jdk.nashorn.internal.objects.annotations.Function; 35 import jdk.nashorn.internal.objects.annotations.ScriptClass; 36 import jdk.nashorn.internal.runtime.JSType; 37 import jdk.nashorn.internal.runtime.ScriptFunction; 38 import jdk.nashorn.internal.runtime.ScriptObject; 39 import jdk.nashorn.internal.runtime.ScriptRuntime; 40 41 /** 42 * ECMA 15.3 Function Objects 43 * 44 * Note: instances of this class are never created. This class is not even a 45 * subclass of ScriptObject. But, we use this class to generate prototype and 46 * constructor for "Function". 47 */ 48 @ScriptClass("Function") 49 public final class NativeFunction { 50 // do *not* create me! 51 private NativeFunction() { 52 } 53 54 /** 55 * ECMA 15.3.4.2 Function.prototype.toString ( ) 56 * 57 * @param self self reference 58 * @return string representation of Function 59 */ 60 @Function(attributes = Attribute.NOT_ENUMERABLE) 61 public static Object toString(final Object self) { 62 if (!(self instanceof ScriptFunction)) { 63 typeError("not.a.function", ScriptRuntime.safeToString(self)); 64 return UNDEFINED; 65 } 66 return ((ScriptFunction)self).toSource(); 67 } 68 69 /** 70 * ECMA 15.3.4.3 Function.prototype.apply (thisArg, argArray) 71 * 72 * @param self self reference 73 * @param thiz {@code this} arg for apply 74 * @param array array of argument for apply 75 * @return result of apply 76 */ 77 @Function(attributes = Attribute.NOT_ENUMERABLE) 78 public static Object apply(final Object self, final Object thiz, final Object array) { 79 if (!(self instanceof ScriptFunction)) { 80 typeError("not.a.function", ScriptRuntime.safeToString(self)); 81 return UNDEFINED; 82 } 83 84 Object[] args = null; 85 86 if (ScriptObject.isArray(array)) { 87 args = ((NativeArray)array).asObjectArray(); 88 } else if (array instanceof ScriptObject) { 89 // look for array-like object 90 final ScriptObject sobj = (ScriptObject)array; 91 final Object len = sobj.getLength(); 92 93 if (len == UNDEFINED || len == null) { 94 typeError("function.apply.expects.array"); 95 } 96 97 final int n = (int)JSType.toUint32(len); 98 if (n != JSType.toNumber(len)) { 99 typeError("function.apply.expects.array"); 100 } 101 102 args = new Object[(int)JSType.toUint32(len)]; 103 for (int i = 0; i < args.length; i++) { 104 args[i] = sobj.get(i); 105 } 106 } else if (array instanceof Object[]) { 107 args = (Object[])array; 108 } else if (array instanceof List) { 109 final List<?> list = (List<?>)array; 110 list.toArray(args = new Object[list.size()]); 111 } else if (array == null || array == UNDEFINED) { 112 args = ScriptRuntime.EMPTY_ARRAY; 113 } else { 114 typeError("function.apply.expects.array"); 115 } 116 117 return ScriptRuntime.apply((ScriptFunction)self, thiz, args); 118 } 119 120 /** 121 * ECMA 15.3.4.4 Function.prototype.call (thisArg [ , arg1 [ , arg2, ... ] ] ) 122 * 123 * @param self self reference 124 * @param args arguments for call 125 * @return result of call 126 */ 127 @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 1) 128 public static Object call(final Object self, final Object... args) { 129 if (!(self instanceof ScriptFunction)) { 130 typeError("not.a.function", ScriptRuntime.safeToString(self)); 131 return UNDEFINED; 132 } 133 134 Object thiz = (args.length == 0) ? UNDEFINED : args[0]; 135 Object[] arguments; 136 137 if (args.length > 1) { 138 arguments = new Object[args.length - 1]; 139 System.arraycopy(args, 1, arguments, 0, arguments.length); 140 } else { 141 arguments = ScriptRuntime.EMPTY_ARRAY; 142 } 143 144 return ScriptRuntime.apply((ScriptFunction)self, thiz, arguments); 145 } 146 147 /** 148 * ECMA 15.3.4.5 Function.prototype.bind (thisArg [, arg1 [, arg2, ...]]) 149 * 150 * @param self self reference 151 * @param args arguments for bind 152 * @return function with bound arguments 153 */ 154 @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 1) 155 public static Object bind(final Object self, final Object... args) { 156 if (!(self instanceof ScriptFunction)) { 157 typeError("not.a.function", ScriptRuntime.safeToString(self)); 158 return UNDEFINED; 159 } 160 161 final Object thiz = (args.length == 0) ? UNDEFINED : args[0]; 162 163 Object[] arguments; 164 if (args.length > 1) { 165 arguments = new Object[args.length - 1]; 166 System.arraycopy(args, 1, arguments, 0, arguments.length); 167 } else { 168 arguments = ScriptRuntime.EMPTY_ARRAY; 169 } 170 171 return ((ScriptFunction)self).makeBoundFunction(thiz, arguments); 172 } 173 174 /** 175 * Nashorn extension: Function.prototype.toSource 176 * 177 * @param self self reference 178 * @return source for function 179 */ 180 @Function(attributes = Attribute.NOT_ENUMERABLE) 181 public static Object toSource(final Object self) { 182 if (!(self instanceof ScriptFunction)) { 183 typeError("not.a.function", ScriptRuntime.safeToString(self)); 184 return UNDEFINED; 185 } 186 return ((ScriptFunction)self).toSource(); 187 } 188 189 /** 190 * ECMA 15.3.2.1 new Function (p1, p2, ... , pn, body) 191 * 192 * Constructor 193 * 194 * @param newObj is the new operator used for constructing this function 195 * @param self self reference 196 * @param args arguments 197 * @return new NativeFunction 198 */ 199 @Constructor(arity = 1) 200 public static Object function(final boolean newObj, final Object self, final Object... args) { 201 final StringBuilder sb = new StringBuilder(); 202 203 sb.append("(function ("); 204 if (args.length > 0) { 205 for (int i = 0; i < args.length - 1; i++) { 206 sb.append(JSType.toString(args[i])); 207 if (i < args.length - 2) { 208 sb.append(","); 209 } 210 } 211 } 212 sb.append(") {\n"); 213 if (args.length > 0) { 214 sb.append(JSType.toString(args[args.length - 1])); 215 sb.append('\n'); 216 } 217 sb.append("})"); 218 219 final Global global = Global.instance(); 220 221 return Global.directEval(global, sb.toString(), global, "<function>", Global.isStrict()); 222 } 223 }