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.api.scripting.ScriptObjectMirror; 33 import jdk.nashorn.internal.objects.annotations.Attribute; 34 import jdk.nashorn.internal.objects.annotations.Constructor; 35 import jdk.nashorn.internal.objects.annotations.Function; 36 import jdk.nashorn.internal.objects.annotations.ScriptClass; 37 import jdk.nashorn.internal.parser.Parser; 38 import jdk.nashorn.internal.runtime.Context; 39 import jdk.nashorn.internal.runtime.JSType; 40 import jdk.nashorn.internal.runtime.ParserException; 41 import jdk.nashorn.internal.runtime.ScriptFunction; 42 import jdk.nashorn.internal.runtime.ScriptObject; 43 import jdk.nashorn.internal.runtime.ScriptRuntime; 44 import jdk.nashorn.internal.runtime.Source; 45 46 /** 47 * ECMA 15.3 Function Objects 48 * 49 * Note: instances of this class are never created. This class is not even a 50 * subclass of ScriptObject. But, we use this class to generate prototype and 51 * constructor for "Function". 52 */ 53 @ScriptClass("Function") 54 public final class NativeFunction { 55 // do *not* create me! 56 private NativeFunction() { 57 } 58 59 /** 60 * ECMA 15.3.4.2 Function.prototype.toString ( ) 61 * 62 * @param self self reference 63 * @return string representation of Function 64 */ 65 @Function(attributes = Attribute.NOT_ENUMERABLE) 66 public static Object toString(final Object self) { 67 if (!(self instanceof ScriptFunction)) { 68 throw typeError("not.a.function", ScriptRuntime.safeToString(self)); 69 } 70 return ((ScriptFunction)self).toSource(); 71 } 72 73 /** 74 * ECMA 15.3.4.3 Function.prototype.apply (thisArg, argArray) 75 * 76 * @param self self reference 77 * @param thiz {@code this} arg for apply 78 * @param array array of argument for apply 79 * @return result of apply 80 */ 81 @Function(attributes = Attribute.NOT_ENUMERABLE) 82 public static Object apply(final Object self, final Object thiz, final Object array) { 83 if (!(self instanceof ScriptFunction)) { 84 throw typeError("not.a.function", ScriptRuntime.safeToString(self)); 85 } 86 87 Object[] args = null; 88 89 if (array instanceof ScriptObject) { 90 // look for array-like object 91 final ScriptObject sobj = (ScriptObject)array; 92 final Object len = sobj.getLength(); 93 final int n = (int)JSType.toUint32(len); 94 95 args = new Object[n]; 96 for (int i = 0; i < args.length; i++) { 97 args[i] = sobj.get(i); 98 } 99 } else if (array instanceof Object[]) { 100 args = (Object[])array; 101 } else if (array instanceof List) { 102 final List<?> list = (List<?>)array; 103 list.toArray(args = new Object[list.size()]); 104 } else if (array == null || array == UNDEFINED) { 105 args = ScriptRuntime.EMPTY_ARRAY; 106 } else if (array instanceof ScriptObjectMirror) { 107 // look for array-like ScriptObjectMirror object 108 final ScriptObjectMirror mirror = (ScriptObjectMirror)array; 109 final Object len = mirror.containsKey("length")? mirror.getMember("length") : Integer.valueOf(0); 110 final int n = (int)JSType.toUint32(len); 111 112 args = new Object[n]; 113 for (int i = 0; i < args.length; i++) { 114 args[i] = mirror.containsKey(i)? mirror.getSlot(i) : UNDEFINED; 115 } 116 } else { 117 throw typeError("function.apply.expects.array"); 118 } 119 120 return ScriptRuntime.apply((ScriptFunction)self, thiz, args); 121 } 122 123 /** 124 * ECMA 15.3.4.4 Function.prototype.call (thisArg [ , arg1 [ , arg2, ... ] ] ) 125 * 126 * @param self self reference 127 * @param args arguments for call 128 * @return result of call 129 */ 130 @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 1) 131 public static Object call(final Object self, final Object... args) { 132 if (!(self instanceof ScriptFunction)) { 133 throw typeError("not.a.function", ScriptRuntime.safeToString(self)); 134 } 135 136 Object thiz = (args.length == 0) ? UNDEFINED : args[0]; 137 Object[] arguments; 138 139 if (args.length > 1) { 140 arguments = new Object[args.length - 1]; 141 System.arraycopy(args, 1, arguments, 0, arguments.length); 142 } else { 143 arguments = ScriptRuntime.EMPTY_ARRAY; 144 } 145 146 return ScriptRuntime.apply((ScriptFunction)self, thiz, arguments); 147 } 148 149 /** 150 * ECMA 15.3.4.5 Function.prototype.bind (thisArg [, arg1 [, arg2, ...]]) 151 * 152 * @param self self reference 153 * @param args arguments for bind 154 * @return function with bound arguments 155 */ 156 @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 1) 157 public static Object bind(final Object self, final Object... args) { 158 if (!(self instanceof ScriptFunction)) { 159 throw typeError("not.a.function", ScriptRuntime.safeToString(self)); 160 } 161 162 final Object thiz = (args.length == 0) ? UNDEFINED : args[0]; 163 164 Object[] arguments; 165 if (args.length > 1) { 166 arguments = new Object[args.length - 1]; 167 System.arraycopy(args, 1, arguments, 0, arguments.length); 168 } else { 169 arguments = ScriptRuntime.EMPTY_ARRAY; 170 } 171 172 return ((ScriptFunctionImpl)self).makeBoundFunction(thiz, arguments); 173 } 174 175 /** 176 * Nashorn extension: Function.prototype.toSource 177 * 178 * @param self self reference 179 * @return source for function 180 */ 181 @Function(attributes = Attribute.NOT_ENUMERABLE) 182 public static Object toSource(final Object self) { 183 if (!(self instanceof ScriptFunction)) { 184 throw typeError("not.a.function", ScriptRuntime.safeToString(self)); 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 final StringBuilder paramListBuf = new StringBuilder(); 206 for (int i = 0; i < args.length - 1; i++) { 207 paramListBuf.append(JSType.toString(args[i])); 208 if (i < args.length - 2) { 209 paramListBuf.append(","); 210 } 211 } 212 213 final String paramList = paramListBuf.toString(); 214 if (! paramList.isEmpty()) { 215 checkFunctionParameters(paramList); 216 sb.append(paramList); 217 } 218 } 219 sb.append(") {\n"); 220 if (args.length > 0) { 221 final String funcBody = JSType.toString(args[args.length - 1]); 222 checkFunctionBody(funcBody); 223 sb.append(funcBody); 224 sb.append('\n'); 225 } 226 sb.append("})"); 227 228 final Global global = Global.instance(); 229 230 return Global.directEval(global, sb.toString(), global, "<function>", global.isStrictContext()); 231 } 232 233 private static void checkFunctionParameters(final String params) { 234 final Source src = new Source("<function>", params); 235 final Parser parser = new Parser(Global.getEnv(), src, new Context.ThrowErrorManager()); 236 try { 237 parser.parseFormalParameterList(); 238 } catch (final ParserException pe) { 239 pe.throwAsEcmaException(); 240 } 241 } 242 243 private static void checkFunctionBody(final String funcBody) { 244 final Source src = new Source("<function>", funcBody); 245 final Parser parser = new Parser(Global.getEnv(), src, new Context.ThrowErrorManager()); 246 try { 247 parser.parseFunctionBody(); 248 } catch (final ParserException pe) { 249 pe.throwAsEcmaException(); 250 } 251 } 252 } --- EOF ---