2 * Copyright (C) 1999-2001 Harri Porten (porten@kde.org)
3 * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 #include "function_object.h"
24 #include "JSGlobalObject.h"
26 #include "array_object.h"
35 #include <wtf/Assertions.h>
39 // ------------------------------ FunctionPrototype -------------------------
41 static JSValue
* functionProtoFuncToString(ExecState
*, JSObject
*, const List
&);
42 static JSValue
* functionProtoFuncApply(ExecState
*, JSObject
*, const List
&);
43 static JSValue
* functionProtoFuncCall(ExecState
*, JSObject
*, const List
&);
45 FunctionPrototype::FunctionPrototype(ExecState
* exec
)
47 static const Identifier
* applyPropertyName
= new Identifier("apply");
48 static const Identifier
* callPropertyName
= new Identifier("call");
50 putDirect(exec
->propertyNames().length
, jsNumber(0), DontDelete
| ReadOnly
| DontEnum
);
52 putDirectFunction(new PrototypeFunction(exec
, this, 0, exec
->propertyNames().toString
, functionProtoFuncToString
), DontEnum
);
53 putDirectFunction(new PrototypeFunction(exec
, this, 2, *applyPropertyName
, functionProtoFuncApply
), DontEnum
);
54 putDirectFunction(new PrototypeFunction(exec
, this, 1, *callPropertyName
, functionProtoFuncCall
), DontEnum
);
58 JSValue
* FunctionPrototype::callAsFunction(ExecState
*, JSObject
*, const List
&)
65 JSValue
* functionProtoFuncToString(ExecState
* exec
, JSObject
* thisObj
, const List
&)
67 if (!thisObj
|| !thisObj
->inherits(&InternalFunctionImp::info
)) {
69 fprintf(stderr
,"attempted toString() call on null or non-function object\n");
71 return throwError(exec
, TypeError
);
74 if (thisObj
->inherits(&FunctionImp::info
)) {
75 FunctionImp
* fi
= static_cast<FunctionImp
*>(thisObj
);
76 return jsString("function " + fi
->functionName().ustring() + "(" + fi
->body
->paramString() + ") " + fi
->body
->toString());
79 return jsString("function " + static_cast<InternalFunctionImp
*>(thisObj
)->functionName().ustring() + "() {\n [native code]\n}");
82 JSValue
* functionProtoFuncApply(ExecState
* exec
, JSObject
* thisObj
, const List
& args
)
84 if (!thisObj
->implementsCall())
85 return throwError(exec
, TypeError
);
87 JSValue
* thisArg
= args
[0];
88 JSValue
* argArray
= args
[1];
91 if (thisArg
->isUndefinedOrNull())
92 applyThis
= exec
->dynamicGlobalObject();
94 applyThis
= thisArg
->toObject(exec
);
97 if (!argArray
->isUndefinedOrNull()) {
98 if (argArray
->isObject() &&
99 (static_cast<JSObject
*>(argArray
)->inherits(&ArrayInstance::info
) ||
100 static_cast<JSObject
*>(argArray
)->inherits(&Arguments::info
))) {
102 JSObject
* argArrayObj
= static_cast<JSObject
*>(argArray
);
103 unsigned int length
= argArrayObj
->get(exec
, exec
->propertyNames().length
)->toUInt32(exec
);
104 for (unsigned int i
= 0; i
< length
; i
++)
105 applyArgs
.append(argArrayObj
->get(exec
, i
));
107 return throwError(exec
, TypeError
);
110 return thisObj
->call(exec
, applyThis
, applyArgs
);
113 JSValue
* functionProtoFuncCall(ExecState
* exec
, JSObject
* thisObj
, const List
& args
)
115 if (!thisObj
->implementsCall())
116 return throwError(exec
, TypeError
);
118 JSValue
* thisArg
= args
[0];
121 if (thisArg
->isUndefinedOrNull())
122 callThis
= exec
->dynamicGlobalObject();
124 callThis
= thisArg
->toObject(exec
);
127 args
.getSlice(1, argsTail
);
128 return thisObj
->call(exec
, callThis
, argsTail
);
131 // ------------------------------ FunctionObjectImp ----------------------------
133 FunctionObjectImp::FunctionObjectImp(ExecState
* exec
, FunctionPrototype
* functionPrototype
)
134 : InternalFunctionImp(functionPrototype
, functionPrototype
->classInfo()->className
)
136 putDirect(exec
->propertyNames().prototype
, functionPrototype
, DontEnum
| DontDelete
| ReadOnly
);
138 // Number of arguments for constructor
139 putDirect(exec
->propertyNames().length
, jsNumber(1), ReadOnly
| DontDelete
| DontEnum
);
142 bool FunctionObjectImp::implementsConstruct() const
147 // ECMA 15.3.2 The Function Constructor
148 JSObject
* FunctionObjectImp::construct(ExecState
* exec
, const List
& args
, const Identifier
& functionName
, const UString
& sourceURL
, int lineNumber
)
152 int argsSize
= args
.size();
155 else if (argsSize
== 1)
156 body
= args
[0]->toString(exec
);
158 p
= args
[0]->toString(exec
);
159 for (int k
= 1; k
< argsSize
- 1; k
++)
160 p
+= "," + args
[k
]->toString(exec
);
161 body
= args
[argsSize
- 1]->toString(exec
);
164 // parse the source code
168 RefPtr
<FunctionBodyNode
> functionBody
= parser().parse
<FunctionBodyNode
>(sourceURL
, lineNumber
, body
.data(), body
.size(), &sourceId
, &errLine
, &errMsg
);
170 // notify debugger that source has been parsed
171 Debugger
* dbg
= exec
->dynamicGlobalObject()->debugger();
173 // send empty sourceURL to indicate constructed code
174 bool cont
= dbg
->sourceParsed(exec
, sourceId
, UString(), body
, lineNumber
, errLine
, errMsg
);
177 return new JSObject();
181 // No program node == syntax error - throw a syntax error
183 // We can't return a Completion(Throw) here, so just set the exception
185 return throwError(exec
, SyntaxError
, errMsg
, errLine
, sourceId
, sourceURL
);
187 ScopeChain scopeChain
;
188 scopeChain
.push(exec
->lexicalGlobalObject());
190 FunctionImp
* fimp
= new FunctionImp(exec
, functionName
, functionBody
.get(), scopeChain
);
192 // parse parameter list. throw syntax error on illegal identifiers
194 const UChar
* c
= p
.data();
195 int i
= 0, params
= 0;
198 while (*c
== ' ' && i
< len
)
200 if (Lexer::isIdentStart(c
->uc
)) { // else error
201 param
= UString(c
, 1);
203 while (i
< len
&& (Lexer::isIdentPart(c
->uc
))) {
204 param
+= UString(c
, 1);
207 while (i
< len
&& *c
== ' ')
210 functionBody
->parameters().append(Identifier(param
));
213 } else if (*c
== ',') {
214 functionBody
->parameters().append(Identifier(param
));
220 return throwError(exec
, SyntaxError
, "Syntax error in parameter list");
225 JSObject
* objCons
= exec
->lexicalGlobalObject()->objectConstructor();
226 JSObject
* prototype
= objCons
->construct(exec
, exec
->emptyList());
227 prototype
->putDirect(exec
->propertyNames().constructor
, fimp
, DontEnum
| DontDelete
| ReadOnly
);
228 fimp
->putDirect(exec
->propertyNames().prototype
, prototype
, Internal
| DontDelete
);
232 // ECMA 15.3.2 The Function Constructor
233 JSObject
* FunctionObjectImp::construct(ExecState
* exec
, const List
& args
)
235 return construct(exec
, args
, "anonymous", UString(), 0);
238 // ECMA 15.3.1 The Function Constructor Called as a Function
239 JSValue
* FunctionObjectImp::callAsFunction(ExecState
* exec
, JSObject
*, const List
& args
)
241 return construct(exec
, args
);