1 // -*- c-basic-offset: 2 -*-
2 // krazy:excludeall=doublequote_chars (UStrings aren't QStrings)
4 * This file is part of the KDE libraries
5 * Copyright (C) 1999-2001 Harri Porten (porten@kde.org)
6 * Copyright (C) 2003, 2004, 2005, 2006 Apple Computer, Inc.
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
24 #include "function_object.h"
28 #include "scriptfunction.h"
29 #include "array_object.h"
41 // ------------------------------ FunctionPrototype -------------------------
43 FunctionPrototype::FunctionPrototype(ExecState
*exec
)
45 static const Identifier
* applyPropertyName
= new Identifier("apply");
46 static const Identifier
* callPropertyName
= new Identifier("call");
48 putDirect(exec
->propertyNames().length
, jsNumber(0), DontDelete
| ReadOnly
| DontEnum
);
49 putDirectFunction(new FunctionProtoFunc(exec
, this, FunctionProtoFunc::ToString
, 0, exec
->propertyNames().toString
), DontEnum
);
50 putDirectFunction(new FunctionProtoFunc(exec
, this, FunctionProtoFunc::Apply
, 2, *applyPropertyName
), DontEnum
);
51 putDirectFunction(new FunctionProtoFunc(exec
, this, FunctionProtoFunc::Call
, 1, *callPropertyName
), DontEnum
);
54 FunctionPrototype::~FunctionPrototype()
59 JSValue
*FunctionPrototype::callAsFunction(ExecState
* /*exec*/, JSObject
* /*thisObj*/, const List
&/*args*/)
64 // ------------------------------ FunctionProtoFunc -------------------------
66 FunctionProtoFunc::FunctionProtoFunc(ExecState
* exec
, FunctionPrototype
* funcProto
, int i
, int len
, const Identifier
& name
)
67 : InternalFunctionImp(funcProto
, name
)
70 putDirect(exec
->propertyNames().length
, len
, DontDelete
| ReadOnly
| DontEnum
);
73 JSValue
* FunctionProtoFunc::callAsFunction(ExecState
* exec
, JSObject
* thisObj
, const List
&args
)
75 JSValue
* result
= NULL
;
79 if (!thisObj
|| !thisObj
->inherits(&InternalFunctionImp::info
)) {
81 fprintf(stderr
,"attempted toString() call on null or non-function object\n");
83 return throwError(exec
, TypeError
);
85 if (thisObj
->inherits(&FunctionImp::info
)) {
86 return jsString(static_cast<FunctionImp
*>(thisObj
)->toSource());
87 } else if (thisObj
->inherits(&InternalFunctionImp::info
) &&
88 !static_cast<InternalFunctionImp
*>(thisObj
)->functionName().isNull()) {
89 result
= jsString("\nfunction " + static_cast<InternalFunctionImp
*>(thisObj
)->functionName().ustring() + "() {\n"
90 " [native code]\n}\n");
92 result
= jsString("[function]");
96 JSValue
*thisArg
= args
[0];
97 JSValue
*argArray
= args
[1];
98 JSObject
*func
= thisObj
;
100 if (!func
->implementsCall())
101 return throwError(exec
, TypeError
);
104 if (thisArg
->isUndefinedOrNull())
105 applyThis
= exec
->dynamicInterpreter()->globalObject();
107 applyThis
= thisArg
->toObject(exec
);
110 if (!argArray
->isUndefinedOrNull()) {
111 if (argArray
->isObject() &&
112 (static_cast<JSObject
*>(argArray
)->inherits(&ArrayInstance::info
) ||
113 static_cast<JSObject
*>(argArray
)->inherits(&Arguments::info
))) {
115 JSObject
*argArrayObj
= static_cast<JSObject
*>(argArray
);
116 unsigned int length
= argArrayObj
->get(exec
, exec
->propertyNames().length
)->toUInt32(exec
);
117 for (unsigned int i
= 0; i
< length
; i
++)
118 applyArgs
.append(argArrayObj
->get(exec
,i
));
121 return throwError(exec
, TypeError
);
123 result
= func
->call(exec
,applyThis
,applyArgs
);
127 JSValue
*thisArg
= args
[0];
128 JSObject
*func
= thisObj
;
130 if (!func
->implementsCall())
131 return throwError(exec
, TypeError
);
134 if (thisArg
->isUndefinedOrNull())
135 callThis
= exec
->dynamicInterpreter()->globalObject();
137 callThis
= thisArg
->toObject(exec
);
139 result
= func
->call(exec
,callThis
,args
.copyTail());
147 // ------------------------------ FunctionObjectImp ----------------------------
149 FunctionObjectImp::FunctionObjectImp(ExecState
* exec
, FunctionPrototype
* funcProto
)
150 : InternalFunctionImp(funcProto
)
152 putDirect(exec
->propertyNames().prototype
, funcProto
, DontEnum
|DontDelete
|ReadOnly
);
154 // no. of arguments for constructor
155 putDirect(exec
->propertyNames().length
, jsNumber(1), ReadOnly
|DontDelete
|DontEnum
);
158 FunctionObjectImp::~FunctionObjectImp()
162 bool FunctionObjectImp::implementsConstruct() const
167 // ECMA 15.3.2 The Function Constructor
168 JSObject
* FunctionObjectImp::construct(ExecState
* exec
, const List
& args
, const Identifier
& functionName
, const UString
& sourceURL
, int lineNumber
)
172 int argsSize
= args
.size();
175 } else if (argsSize
== 1) {
176 body
= args
[0]->toString(exec
);
178 p
= args
[0]->toString(exec
);
179 for (int k
= 1; k
< argsSize
- 1; k
++)
180 p
+= "," + args
[k
]->toString(exec
);
181 body
= args
[argsSize
-1]->toString(exec
);
184 // parse the source code
188 RefPtr
<FunctionBodyNode
> functionBody
= parser().parseFunctionBody(sourceURL
, lineNumber
, body
.data(), body
.size(), &sourceId
, &errLine
, &errMsg
);
190 // notify debugger that source has been parsed
191 Debugger
*dbg
= exec
->dynamicInterpreter()->debugger();
193 // make sure to pass in sourceURL, since it's useful for lazy event listeners, and empty for actual function ctor
194 bool cont
= dbg
->sourceParsed(exec
, sourceId
, sourceURL
, body
, lineNumber
, errLine
, errMsg
);
197 return new JSObject();
201 // no program node == syntax error - throw a syntax error
203 // we can't return a Completion(Throw) here, so just set the exception
205 return throwError(exec
, SyntaxError
, errMsg
, errLine
, sourceId
, sourceURL
);
207 ScopeChain scopeChain
;
208 scopeChain
.push(exec
->lexicalInterpreter()->globalObject());
210 FunctionImp
* fimp
= new FunctionImp(exec
, functionName
, functionBody
.get(), scopeChain
);
212 // parse parameter list. throw syntax error on illegal identifiers
214 const UChar
*c
= p
.data();
215 int i
= 0, params
= 0;
218 while (*c
== ' ' && i
< len
)
220 if (Lexer::isIdentStart(c
->uc
)) { // else error
221 param
= UString(c
, 1);
223 while (i
< len
&& (Lexer::isIdentPart(c
->uc
))) {
224 param
+= UString(c
, 1);
227 while (i
< len
&& *c
== ' ')
230 functionBody
->addParam(Identifier(param
));
233 } else if (*c
== ',') {
234 functionBody
->addParam(Identifier(param
));
240 return throwError(exec
, SyntaxError
, "Syntax error in parameter list");
245 JSObject
* objCons
= exec
->lexicalInterpreter()->builtinObject();
246 JSObject
* prototype
= objCons
->construct(exec
,List::empty());
247 prototype
->put(exec
, exec
->propertyNames().constructor
, fimp
, DontEnum
|DontDelete
|ReadOnly
);
248 fimp
->put(exec
, exec
->propertyNames().prototype
, prototype
, Internal
|DontDelete
);
252 // ECMA 15.3.2 The Function Constructor
253 JSObject
* FunctionObjectImp::construct(ExecState
* exec
, const List
& args
)
255 return construct(exec
, args
, "anonymous", UString(), 0);
258 // ECMA 15.3.1 The Function Constructor Called as a Function
259 JSValue
* FunctionObjectImp::callAsFunction(ExecState
* exec
, JSObject
* /*thisObj*/, const List
&args
)
261 return construct(exec
, args
);