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

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

JavaScriptCore:

  • kjs/*: Roll KDE 3.0.2 changes in. Also switch to not using APPLE_CHANGES for some of the changes that we definitely want to contribute upstream.

WebCore:

  • khtml/*: Roll KDE 3.0.2 changes in. Also switch to not using APPLE_CHANGES for some of the changes that we definitely want to contribute upstream.
  • WebCore.pbproj/project.pbxproj: Add KWQStyle.mm, remove KWQStyle.h, moving contents into qstyle.h.
  • kwq/KWQApplication.mm: (QApplication::globalStrut): Remove _logNotYetImplemented().
  • kwq/KWQButton.mm: (QButton::QButton): Use plain release, not autorelease.
  • kwq/KWQComboBox.mm: (QComboBox::init): Use plain release, not autorelease.
  • kwq/KWQListBox.mm: (QListBox::QListBox): Use plain release, not autorelease.
  • kwq/KWQPainter.mm: (QPainter::drawArc): Use plain release, not autorelease.
  • kwq/KWQKHTMLPartBrowserExtension.mm: Remove import of KWQKHTMLPartImpl.h, now that it's always part of khtml_part.h.
  • kwq/KWQKHTMLPartImpl.cpp: Simplify.
  • kwq/KWQKHTMLPartImpl.h: Add wrapper to allow multiple inclusion. Don't include khtml_part.h any more, since that file now includes this one to minimize changes to KDE code that needs to get to functions in here.
  • kwq/KWQKHTMLPartImpl.mm: (KHTMLPart::onURL), (KHTMLPart::nodeActivated), (KHTMLPart::setStatusBarText): Moved here from khtml_part.cpp.
  • kwq/KWQLoaderImpl.mm: Include khtml_part.h instead of KWQKHTMLPartImpl.h.
  • kwq/KWQPushButton.mm: (buttonFontMetrics), (QPushButton::fontMetrics): Added. Used by the form code to size buttons.
  • kwq/KWQStyle.mm: Added. (QStyle::sizeFromContents): Added. Used by the form code to size buttons.
  • kwq/KWQStyle.h: Removed.
  • kwq/qt/qstyle.h: Moved contents of KWQStyle.h in here.
  • kwq/qt/qwidget.h: Include <qstyle.h> rather than KWQStyle.h.
  • kwq/WebCoreBridge.mm: (-[WebCoreBridge isFrameSet]): Call straight to impl.
  • kwq/kdeui/klineedit.h: Add KLineEdit::frameWidth().
  • kwq/qt/qnamespace.h: Remove GUIStyle, MacStyle, and WindowsStyle.
  • kwq/qt/qpaintdevice.h: Add QInternal, QInternal::Printer, and QPaintDevice::devType().
  • kwq/qt/qpainter.h: Add QPainter::device().
  • kwq/qt/qpushbutton.h: Add QPushButton::fontMetrics().
  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 13.2 KB
Line 
1// -*- c-basic-offset: 2 -*-
2/*
3 * This file is part of the KDE libraries
4 * Copyright (C) 1999-2002 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 <errno.h>
35#include <stdlib.h>
36#include <assert.h>
37#include <string.h>
38
39using namespace KJS;
40
41// ----------------------------- FunctionImp ----------------------------------
42
43const ClassInfo FunctionImp::info = {"Function", &InternalFunctionImp::info, 0, 0};
44
45namespace KJS {
46 class Parameter {
47 public:
48 Parameter(const UString &n) : name(n), next(0L) { }
49 ~Parameter() { delete next; }
50 UString name;
51 Parameter *next;
52 };
53};
54
55FunctionImp::FunctionImp(ExecState *exec, const UString &n)
56 : InternalFunctionImp(
57 static_cast<FunctionPrototypeImp*>(exec->interpreter()->builtinFunctionPrototype().imp())
58 ), param(0L), ident(n), argStack(0)
59{
60 Value protect(this);
61 argStack = new ListImp();
62 Value protectArgStack( argStack ); // this also calls setGcAllowed on argStack
63 //fprintf(stderr,"FunctionImp::FunctionImp this=%p argStack=%p\n");
64 put(exec,"arguments",Null(),ReadOnly|DontDelete|DontEnum);
65}
66
67FunctionImp::~FunctionImp()
68{
69 // The function shouldn't be deleted while it is still executed; argStack
70 // should be set to 0 by the last call to popArgs()
71 //assert(argStack->isEmpty());
72 // Accessing argStack from here is a problem though.
73 // When the function isn't used anymore, it's not marked, and neither is the
74 // argStack, so both can be deleted - in any order!
75 delete param;
76}
77
78void FunctionImp::mark()
79{
80 InternalFunctionImp::mark();
81 if (argStack && !argStack->marked())
82 argStack->mark();
83}
84
85bool FunctionImp::implementsCall() const
86{
87 return true;
88}
89
90Value FunctionImp::call(ExecState *exec, Object &thisObj, const List &args)
91{
92 Object globalObj = exec->interpreter()->globalObject();
93
94 Debugger *dbg = exec->interpreter()->imp()->debugger();
95 int sid = -1;
96 int lineno = -1;
97 if (dbg) {
98 if (inherits(&DeclaredFunctionImp::info)) {
99 sid = static_cast<DeclaredFunctionImp*>(this)->body->sourceId();
100 lineno = static_cast<DeclaredFunctionImp*>(this)->body->firstLine();
101 }
102
103 Object func(this);
104 bool cont = dbg->callEvent(exec,sid,lineno,func,args);
105 if (!cont) {
106 dbg->imp()->abort();
107 return Undefined();
108 }
109 }
110
111 // enter a new execution context
112 ContextImp ctx(globalObj, exec, thisObj, codeType(),
113 exec->context().imp(), this, args);
114 ExecState newExec(exec->interpreter(), &ctx);
115 newExec.setException(exec->exception()); // could be null
116
117 // In order to maintain our "arguments" property, we maintain a list of arguments
118 // properties from earlier in the execution stack. Upon return, we restore the
119 // previous arguments object using popArgs().
120 // Note: this does not appear to be part of the spec
121 if (codeType() == FunctionCode) {
122 assert(ctx.activationObject().inherits(&ActivationImp::info));
123 Object argsObj = static_cast<ActivationImp*>(ctx.activationObject().imp())->argumentsObject();
124 put(&newExec, "arguments", argsObj, DontDelete|DontEnum|ReadOnly);
125 pushArgs(&newExec, argsObj);
126 }
127
128 // assign user supplied arguments to parameters
129 processParameters(&newExec, args);
130 // add variable declarations (initialized to undefined)
131 processVarDecls(&newExec);
132
133 Completion comp = execute(&newExec);
134
135 // if an exception occured, propogate it back to the previous execution object
136 if (newExec.hadException())
137 exec->setException(newExec.exception());
138 if (codeType() == FunctionCode)
139 popArgs(&newExec);
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 CString cstr = args[0].toString(exec).cstring();
434 int radix = args[1].toInt32(exec);
435
436 char* endptr;
437 errno = 0;
438 long value = strtol(cstr.c_str(), &endptr, radix);
439 if (errno != 0 || endptr == cstr.c_str())
440 res = Number(NaN);
441 else
442 res = Number(value);
443 break;
444 }
445 case ParseFloat:
446 res = Number(args[0].toString(exec).toDouble( true /*tolerant*/ ));
447 break;
448 case IsNaN:
449 res = Boolean(isNaN(args[0].toNumber(exec)));
450 break;
451 case IsFinite: {
452 double n = args[0].toNumber(exec);
453 res = Boolean(!isNaN(n) && !isInf(n));
454 break;
455 }
456 case Escape: {
457 UString r = "", s, str = args[0].toString(exec);
458 const UChar *c = str.data();
459 for (int k = 0; k < str.size(); k++, c++) {
460 int u = c->unicode();
461 if (u > 255) {
462 char tmp[7];
463 sprintf(tmp, "%%u%04X", u);
464 s = UString(tmp);
465 } else if (strchr(non_escape, (char)u)) {
466 s = UString(c, 1);
467 } else {
468 char tmp[4];
469 sprintf(tmp, "%%%02X", u);
470 s = UString(tmp);
471 }
472 r += s;
473 }
474 res = String(r);
475 break;
476 }
477 case UnEscape: {
478 UString s, str = args[0].toString(exec);
479 int k = 0, len = str.size();
480 UChar u;
481 while (k < len) {
482 const UChar *c = str.data() + k;
483 if (*c == UChar('%') && k <= len - 6 && *(c+1) == UChar('u')) {
484 u = Lexer::convertUnicode((c+2)->unicode(), (c+3)->unicode(),
485 (c+4)->unicode(), (c+5)->unicode());
486 c = &u;
487 k += 5;
488 } else if (*c == UChar('%') && k <= len - 3) {
489 u = UChar(Lexer::convertHex((c+1)->unicode(), (c+2)->unicode()));
490 c = &u;
491 k += 2;
492 }
493 k++;
494 s += UString(c, 1);
495 }
496 res = String(s);
497 break;
498 }
499 }
500
501 return res;
502}
Note: See TracBrowser for help on using the repository browser.