source: webkit/trunk/JavaScriptCore/kjs/function.cpp@ 1371

Last change on this file since 1371 was 1326, checked in by darin, 23 years ago

JavaScriptCore:

Merged in changes from KDE 3.0.1.

  • kjs/collector.cpp:
  • kjs/date_object.cpp:
  • kjs/function.cpp:
  • kjs/internal.cpp:
  • kjs/lookup.h:
  • kjs/object.cpp:
  • kjs/operations.cpp:
  • kjs/regexp.cpp:
  • kjs/regexp_object.cpp:
  • kjs/regexp_object.h:
  • kjs/string_object.cpp:
  • kjs/testkjs.cpp:
  • kjs/ustring.cpp:
  • kjs/value.cpp:
  • kjs/value.h: Do the merge, and add APPLE_CHANGES as needed to make things compile.
  • kjs/date_object.lut.h: Re-generated.

WebCore:

Merged in changes from KDE 3.0.1.

  • kwq/kdecore/kurl.h:
  • kwq/KWQKURL.mm: (operator==): New, needed by some 3.0.1 code.
  • kwq/qt/qpalette.h: Add QPalette::NColorGroups and QColorGroup::NColorRoles.
  • kwq/KWQPalette.mm: Simplify by getting rid of "private" indirection. (QPalette::color): New, needed by some 3.0.1 code.
  • kwq/KWQColorGroup.mm: Simplify by getting rid of "private" indirection.
  • kwq/qt/qstring.h:
  • kwq/KWQString.mm: (QConstString::QConstString): Change parameter to const QChar * to match Qt so we compile.
  • kwq/qt/qtextedit.h:
  • kwq/KWQTextEdit.mm: (QTextEdit::setTabStopWidth): Add unimplemented placeholder, needed by some 3.0.1 code.
  • kwq/qt/qvaluelist.h:
  • kwq/KWQValueListImpl.h:
  • kwq/KWQValueListImpl.mm: Simplify implementation.
  • WebCore-tests.exp: Update for changes in QValueList implementation.
  • kwq/kdecore/klibloader.h: Add include of <kio/global.h> to make something compile.
  • kwq/khtml/java/kjavaappletcontext.h: Add JType and constructor that takes DCOPObject*.
  • kwq/kio/global.h: Add KIO::CacheControl.
  • khtml/css/css_ruleimpl.cpp:
  • khtml/css/css_ruleimpl.h:
  • khtml/css/css_stylesheetimpl.cpp:
  • khtml/css/css_stylesheetimpl.h:
  • khtml/css/css_valueimpl.cpp:
  • khtml/css/css_valueimpl.h:
  • khtml/css/cssparser.cpp:
  • khtml/css/cssparser.h:
  • khtml/css/cssstyleselector.cpp:
  • khtml/css/cssstyleselector.h:
  • khtml/css/html4.css:
  • khtml/dom/css_rule.cpp:
  • khtml/dom/css_rule.h:
  • khtml/dom/css_stylesheet.cpp:
  • khtml/dom/css_stylesheet.h:
  • khtml/dom/css_value.cpp:
  • khtml/dom/dom2_events.cpp:
  • khtml/dom/dom2_range.cpp:
  • khtml/dom/dom2_range.h:
  • khtml/dom/dom2_views.cpp:
  • khtml/dom/dom_doc.cpp:
  • khtml/dom/dom_element.cpp:
  • khtml/dom/dom_exception.h:
  • khtml/dom/dom_node.cpp:
  • khtml/dom/dom_string.cpp:
  • khtml/dom/dom_text.cpp:
  • khtml/dom/dom_xml.cpp:
  • khtml/dom/html_base.cpp:
  • khtml/dom/html_block.cpp:
  • khtml/dom/html_document.cpp:
  • khtml/dom/html_element.cpp:
  • khtml/dom/html_element.h:
  • khtml/dom/html_form.cpp:
  • khtml/dom/html_head.cpp:
  • khtml/dom/html_image.cpp:
  • khtml/dom/html_inline.cpp:
  • khtml/dom/html_list.cpp:
  • khtml/dom/html_misc.cpp:
  • khtml/dom/html_object.cpp:
  • khtml/dom/html_table.cpp:
  • khtml/ecma/kjs_html.cpp:
  • khtml/ecma/kjs_proxy.cpp:
  • khtml/ecma/kjs_traversal.cpp:
  • khtml/ecma/kjs_window.cpp:
  • khtml/html/html_baseimpl.cpp:
  • khtml/html/html_formimpl.cpp:
  • khtml/html/html_miscimpl.h:
  • khtml/html/html_objectimpl.cpp:
  • khtml/html/html_objectimpl.h:
  • khtml/html/htmlparser.cpp:
  • khtml/html/htmlparser.h:
  • khtml/html/htmltokenizer.cpp:
  • khtml/html/htmltokenizer.h:
  • khtml/khtml_part.cpp:
  • khtml/khtmlpart_p.h:
  • khtml/khtmlview.cpp:
  • khtml/misc/helper.cpp:
  • khtml/misc/khtmllayout.h:
  • khtml/misc/loader.cpp:
  • khtml/misc/loader.h:
  • khtml/misc/loader_client.h:
  • khtml/misc/shared.h: Added.
  • khtml/rendering/bidi.cpp:
  • khtml/rendering/break_lines.cpp:
  • khtml/rendering/font.cpp:
  • khtml/rendering/render_applet.cpp:
  • khtml/rendering/render_applet.h:
  • khtml/rendering/render_container.cpp:
  • khtml/rendering/render_form.cpp:
  • khtml/rendering/render_form.h:
  • khtml/rendering/render_frames.cpp:
  • khtml/rendering/render_image.cpp:
  • khtml/rendering/render_object.cpp:
  • khtml/rendering/render_object.h:
  • khtml/rendering/render_replaced.cpp:
  • khtml/rendering/render_replaced.h:
  • khtml/rendering/render_root.cpp:
  • khtml/rendering/render_style.cpp:
  • khtml/rendering/render_style.h:
  • khtml/rendering/render_table.cpp:
  • khtml/rendering/render_table.h:
  • khtml/rendering/render_text.cpp:
  • khtml/rendering/render_text.h:
  • khtml/xml/dom2_eventsimpl.h:
  • khtml/xml/dom2_rangeimpl.h:
  • khtml/xml/dom2_traversalimpl.cpp:
  • khtml/xml/dom2_traversalimpl.h:
  • khtml/xml/dom2_viewsimpl.h:
  • khtml/xml/dom_docimpl.cpp:
  • khtml/xml/dom_docimpl.h:
  • khtml/xml/dom_elementimpl.h:
  • khtml/xml/dom_nodeimpl.cpp:
  • khtml/xml/dom_nodeimpl.h:
  • khtml/xml/dom_stringimpl.cpp:
  • khtml/xml/dom_stringimpl.h:
  • khtml/xml/xml_tokenizer.h: Merge in 3.0.1 changes and add APPLE_CHANGES as necessary to get it to compile.
  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 13.5 KB
Line 
1// -*- c-basic-offset: 2 -*-
2/*
3 * This file is part of the KDE libraries
4 * Copyright (C) 1999-2000 Harri Porten ([email protected])
5 * Copyright (C) 2001 Peter Kelly ([email protected])
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
16 *
17 * You should have received a copy of the GNU Library General Public License
18 * along with this library; see the file COPYING.LIB. If not, write to
19 * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 * Boston, MA 02111-1307, USA.
21 *
22 */
23
24#include "function.h"
25
26#include "internal.h"
27#include "function_object.h"
28#include "lexer.h"
29#include "nodes.h"
30#include "operations.h"
31#include "debugger.h"
32
33#include <stdio.h>
34#include <assert.h>
35#include <string.h>
36
37using namespace KJS;
38
39// ------------------------------ FunctionImp ----------------------------------
40
41const ClassInfo FunctionImp::info = {"Function", &InternalFunctionImp::info, 0, 0};
42
43namespace KJS {
44 class Parameter {
45 public:
46 Parameter(const UString &n) : name(n), next(0L) { }
47 ~Parameter() { delete next; }
48 UString name;
49 Parameter *next;
50 };
51};
52
53FunctionImp::FunctionImp(ExecState *exec, const UString &n)
54 : InternalFunctionImp(
55 static_cast<FunctionPrototypeImp*>(exec->interpreter()->builtinFunctionPrototype().imp())
56 ), param(0L), ident(n), argStack(0)
57{
58 Value protect(this);
59 argStack = new ListImp();
60 Value protectArgStack( argStack ); // this also calls setGcAllowed on argStack
61 //fprintf(stderr,"FunctionImp::FunctionImp this=%p argStack=%p\n");
62 put(exec,"arguments",Null(),ReadOnly|DontDelete|DontEnum);
63}
64
65FunctionImp::~FunctionImp()
66{
67 // The function shouldn't be deleted while it is still executed; argStack
68 // should be set to 0 by the last call to popArgs()
69 //assert(argStack->isEmpty());
70 // Accessing argStack from here is a problem though.
71 // When the function isn't used anymore, it's not marked, and neither is the
72 // argStack, so both can be deleted - in any order!
73 delete param;
74}
75
76void FunctionImp::mark()
77{
78 InternalFunctionImp::mark();
79 if (argStack && !argStack->marked())
80 argStack->mark();
81}
82
83bool FunctionImp::implementsCall() const
84{
85 return true;
86}
87
88Value FunctionImp::call(ExecState *exec, Object &thisObj, const List &args)
89{
90 Object globalObj = exec->interpreter()->globalObject();
91
92 Debugger *dbg = exec->interpreter()->imp()->debugger();
93 int sid = -1;
94 int lineno = -1;
95 if (dbg) {
96 if (inherits(&DeclaredFunctionImp::info)) {
97 sid = static_cast<DeclaredFunctionImp*>(this)->body->sourceId();
98 lineno = static_cast<DeclaredFunctionImp*>(this)->body->firstLine();
99 }
100
101 Object func(this);
102 int cont = dbg->callEvent(exec,sid,lineno,func,args);
103 if (!cont) {
104 dbg->imp()->abort();
105 return Undefined();
106 }
107 }
108
109 // enter a new execution context
110 ContextImp *ctx = new ContextImp(globalObj, exec, thisObj,
111 codeType(), exec->context().imp(), this, args);
112 ExecState *newExec = new ExecState(exec->interpreter(),ctx);
113 newExec->setException(exec->exception()); // could be null
114
115 // In order to maintain our "arguments" property, we maintain a list of arguments
116 // properties from earlier in the execution stack. Upon return, we restore the
117 // previous arguments object using popArgs().
118 // Note: this does not appear to be part of the spec
119 if (codeType() == FunctionCode) {
120 assert(ctx->activationObject().inherits(&ActivationImp::info));
121 Object argsObj = static_cast<ActivationImp*>(ctx->activationObject().imp())->argumentsObject();
122 put(newExec,"arguments", argsObj, DontDelete|DontEnum|ReadOnly);
123 pushArgs(newExec,argsObj);
124 }
125
126 // assign user supplied arguments to parameters
127 processParameters(newExec,args);
128 // add variable declarations (initialized to undefined)
129 processVarDecls(newExec);
130
131 Completion comp = execute(newExec);
132
133 // if an exception occured, propogate it back to the previous execution object
134 if (newExec->hadException())
135 exec->setException(newExec->exception());
136 if (codeType() == FunctionCode)
137 popArgs(newExec);
138 delete newExec;
139 delete ctx;
140
141#ifdef KJS_VERBOSE
142 if (comp.complType() == Throw)
143 printInfo(exec,"throwing", comp.value());
144 else if (comp.complType() == ReturnValue)
145 printInfo(exec,"returning", comp.value());
146 else
147 fprintf(stderr, "returning: undefined\n");
148#endif
149
150 if (dbg) {
151 Object func(this);
152 int cont = dbg->returnEvent(exec,sid,lineno,func);
153 if (!cont) {
154 dbg->imp()->abort();
155 return Undefined();
156 }
157 }
158
159 if (comp.complType() == Throw) {
160 exec->setException(comp.value());
161 return comp.value();
162 }
163 else if (comp.complType() == ReturnValue)
164 return comp.value();
165 else
166 return Undefined();
167}
168
169void FunctionImp::addParameter(const UString &n)
170{
171 Parameter **p = &param;
172 while (*p)
173 p = &(*p)->next;
174
175 *p = new Parameter(n);
176}
177
178UString FunctionImp::parameterString() const
179{
180 UString s;
181 const Parameter * const *p = &param;
182 while (*p) {
183 if (!s.isEmpty())
184 s += ", ";
185 s += (*p)->name;
186 p = &(*p)->next;
187 }
188
189 return s;
190}
191
192
193// ECMA 10.1.3q
194void FunctionImp::processParameters(ExecState *exec, const List &args)
195{
196 Object variable = exec->context().imp()->variableObject();
197
198#ifdef KJS_VERBOSE
199 fprintf(stderr, "---------------------------------------------------\n"
200 "processing parameters for %s call\n",
201 name().isEmpty() ? "(internal)" : name().ascii());
202#endif
203
204 if (param) {
205 ListIterator it = args.begin();
206 Parameter **p = &param;
207 while (*p) {
208 if (it != args.end()) {
209#ifdef KJS_VERBOSE
210 fprintf(stderr, "setting parameter %s ", (*p)->name.ascii());
211 printInfo(exec,"to", *it);
212#endif
213 variable.put(exec,(*p)->name, *it);
214 it++;
215 } else
216 variable.put(exec,(*p)->name, Undefined());
217 p = &(*p)->next;
218 }
219 }
220#ifdef KJS_VERBOSE
221 else {
222 for (int i = 0; i < args.size(); i++)
223 printInfo(exec,"setting argument", args[i]);
224 }
225#endif
226}
227
228void FunctionImp::processVarDecls(ExecState */*exec*/)
229{
230}
231
232void FunctionImp::pushArgs(ExecState *exec, const Object &args)
233{
234 argStack->append(args);
235 put(exec,"arguments",args,ReadOnly|DontDelete|DontEnum);
236}
237
238void FunctionImp::popArgs(ExecState *exec)
239{
240 argStack->removeLast();
241 if (argStack->isEmpty()) {
242 put(exec,"arguments",Null(),ReadOnly|DontDelete|DontEnum);
243 }
244 else
245 put(exec,"arguments",argStack->at(argStack->size()-1),ReadOnly|DontDelete|DontEnum);
246}
247
248// ------------------------------ DeclaredFunctionImp --------------------------
249
250// ### is "Function" correct here?
251const ClassInfo DeclaredFunctionImp::info = {"Function", &FunctionImp::info, 0, 0};
252
253DeclaredFunctionImp::DeclaredFunctionImp(ExecState *exec, const UString &n,
254 FunctionBodyNode *b, const List &sc)
255 : FunctionImp(exec,n), body(b)
256{
257 Value protect(this);
258 body->ref();
259 setScope(sc.copy());
260}
261
262DeclaredFunctionImp::~DeclaredFunctionImp()
263{
264 if ( body->deref() )
265 delete body;
266}
267
268bool DeclaredFunctionImp::implementsConstruct() const
269{
270 return true;
271}
272
273// ECMA 13.2.2 [[Construct]]
274Object DeclaredFunctionImp::construct(ExecState *exec, const List &args)
275{
276 Object proto;
277 Value p = get(exec,"prototype");
278 if (p.type() == ObjectType)
279 proto = Object(static_cast<ObjectImp*>(p.imp()));
280 else
281 proto = exec->interpreter()->builtinObjectPrototype();
282
283 Object obj(new ObjectImp(proto));
284
285 Value res = call(exec,obj,args);
286
287 if (res.type() == ObjectType)
288 return Object::dynamicCast(res);
289 else
290 return obj;
291}
292
293Completion DeclaredFunctionImp::execute(ExecState *exec)
294{
295 Completion result = body->execute(exec);
296
297 if (result.complType() == Throw || result.complType() == ReturnValue)
298 return result;
299 return Completion(Normal, Undefined()); // TODO: or ReturnValue ?
300}
301
302void DeclaredFunctionImp::processVarDecls(ExecState *exec)
303{
304 body->processVarDecls(exec);
305}
306
307// ------------------------------ ArgumentsImp ---------------------------------
308
309const ClassInfo ArgumentsImp::info = {"Arguments", 0, 0, 0};
310
311// ECMA 10.1.8
312ArgumentsImp::ArgumentsImp(ExecState *exec, FunctionImp *func, const List &args)
313 : ObjectImp(exec->interpreter()->builtinObjectPrototype())
314{
315 Value protect(this);
316 put(exec,"callee", Object(func), DontEnum);
317 put(exec,"length", Number(args.size()), DontEnum);
318 if (!args.isEmpty()) {
319 ListIterator arg = args.begin();
320 for (int i = 0; arg != args.end(); arg++, i++) {
321 put(exec,UString::from(i), *arg, DontEnum);
322 }
323 }
324}
325
326// ------------------------------ ActivationImp --------------------------------
327
328const ClassInfo ActivationImp::info = {"Activation", 0, 0, 0};
329
330// ECMA 10.1.6
331ActivationImp::ActivationImp(ExecState *exec, FunctionImp *f, const List &args)
332 : ObjectImp()
333{
334 Value protect(this);
335 arguments = new ArgumentsImp(exec,f, args);
336 put(exec, "arguments", Object(arguments), Internal|DontDelete);
337}
338
339ActivationImp::~ActivationImp()
340{
341 arguments->setGcAllowed();
342}
343
344// ------------------------------ GlobalFunc -----------------------------------
345
346
347GlobalFuncImp::GlobalFuncImp(ExecState *exec, FunctionPrototypeImp *funcProto, int i, int len)
348 : InternalFunctionImp(funcProto), id(i)
349{
350 Value protect(this);
351 put(exec,"length",Number(len),DontDelete|ReadOnly|DontEnum);
352}
353
354CodeType GlobalFuncImp::codeType() const
355{
356 return id == Eval ? EvalCode : codeType();
357}
358
359bool GlobalFuncImp::implementsCall() const
360{
361 return true;
362}
363
364Value GlobalFuncImp::call(ExecState *exec, Object &/*thisObj*/, const List &args)
365{
366 Value res;
367
368 static const char non_escape[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
369 "abcdefghijklmnopqrstuvwxyz"
370 "0123456789@*_+-./";
371
372 switch (id) {
373 case Eval: { // eval()
374 Value x = args[0];
375 if (x.type() != StringType)
376 return x;
377 else {
378 UString s = x.toString(exec);
379
380 int sid;
381 int errLine;
382 UString errMsg;
383 ProgramNode *progNode = Parser::parse(s.data(),s.size(),&sid,&errLine,&errMsg);
384
385 // no program node means a syntax occurred
386 if (!progNode) {
387 Object err = Error::create(exec,SyntaxError,errMsg.ascii(),errLine);
388 err.put(exec,"sid",Number(sid));
389 exec->setException(err);
390 return err;
391 }
392
393 progNode->ref();
394
395 // enter a new execution context
396 Object glob(exec->interpreter()->globalObject());
397 Object thisVal(Object::dynamicCast(exec->context().thisValue()));
398 ContextImp *ctx = new ContextImp(glob,
399 exec,
400 thisVal,
401 EvalCode,
402 exec->context().imp());
403
404 ExecState *newExec = new ExecState(exec->interpreter(),ctx);
405 newExec->setException(exec->exception()); // could be null
406
407 // execute the code
408 Completion c = progNode->execute(newExec);
409
410 // if an exception occured, propogate it back to the previous execution object
411 if (newExec->hadException())
412 exec->setException(newExec->exception());
413 delete newExec;
414 delete ctx;
415
416 if ( progNode->deref() )
417 delete progNode;
418 if (c.complType() == ReturnValue)
419 return c;
420 // ### setException() on throw?
421 else if (c.complType() == Normal) {
422 if (c.isValueCompletion())
423 return c.value();
424 else
425 return Undefined();
426 } else {
427 return c;
428 }
429 }
430 break;
431 }
432 case ParseInt: {
433 String str = args[0].toString(exec);
434 int radix = args[1].toInt32(exec);
435 if (radix == 0)
436 radix = 10;
437 else if (radix < 2 || radix > 36) {
438 res = Number(NaN);
439 return res;
440 }
441 /* TODO: use radix */
442 // Can't use toULong(), we want to accept floating point values too
443 double value = str.value().toDouble( true /*tolerant*/ );
444 if ( isNaN(value) )
445 res = Number(NaN);
446 else
447 res = Number(static_cast<long>(value)); // remove floating-point part
448 break;
449 }
450 case ParseFloat: {
451 String str = args[0].toString(exec);
452 res = Number(str.value().toDouble( true /*tolerant*/ ));
453 break;
454 }
455 case IsNaN:
456 res = Boolean(isNaN(args[0].toNumber(exec)));
457 break;
458 case IsFinite: {
459 Number n = args[0].toNumber(exec);
460 res = Boolean(!n.isNaN() && !n.isInf());
461 break;
462 }
463 case Escape: {
464 UString r = "", s, str = args[0].toString(exec);
465 const UChar *c = str.data();
466 for (int k = 0; k < str.size(); k++, c++) {
467 int u = c->unicode();
468 if (u > 255) {
469 char tmp[7];
470 sprintf(tmp, "%%u%04X", u);
471 s = UString(tmp);
472 } else if (strchr(non_escape, (char)u)) {
473 s = UString(c, 1);
474 } else {
475 char tmp[4];
476 sprintf(tmp, "%%%02X", u);
477 s = UString(tmp);
478 }
479 r += s;
480 }
481 res = String(r);
482 break;
483 }
484 case UnEscape: {
485 UString s, str = args[0].toString(exec);
486 int k = 0, len = str.size();
487 while (k < len) {
488 const UChar *c = str.data() + k;
489 UChar u;
490 if (*c == UChar('%') && k <= len - 6 && *(c+1) == UChar('u')) {
491 u = Lexer::convertUnicode((c+2)->unicode(), (c+3)->unicode(),
492 (c+4)->unicode(), (c+5)->unicode());
493 c = &u;
494 k += 5;
495 } else if (*c == UChar('%') && k <= len - 3) {
496 u = UChar(Lexer::convertHex((c+1)->unicode(), (c+2)->unicode()));
497 c = &u;
498 k += 2;
499 }
500 k++;
501 s += UString(c, 1);
502 }
503 res = String(s);
504 break;
505 }
506 }
507
508 return res;
509}
Note: See TracBrowser for help on using the repository browser.