source: webkit/trunk/JavaScriptCore/kjs/internal.cpp@ 3745

Last change on this file since 3745 was 3745, checked in by darin, 22 years ago

Reviewed by Maciej.

  • got rid of some framework initialization (working on bug 2959353)
  • kjs/identifier.h: Turn Identifier:null into Identifier:null().
  • kjs/identifier.cpp: Removed Identifier:null and added Identifier:null().
  • kjs/internal.cpp: Made NaN_Bytes and Inf_Bytes const.
  • kjs/completion.h: Use Identifier:null() instead of Identifier:null.
  • kjs/function.h: Ditto.
  • kjs/function_object.cpp: (FunctionObjectImp::construct): Ditto.
  • kjs/nodes.cpp: (FuncExprNode::evaluate): Use Identifier:null() instead of Identifier:null.
  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 25.9 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 * Copyright (C) 2003 Apple Computer, Inc.
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Library 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.
12 *
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 * Library General Public License for more details.
17 *
18 * You should have received a copy of the GNU Library General Public License
19 * along with this library; see the file COPYING.LIB. If not, write to
20 * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21 * Boston, MA 02111-1307, USA.
22 *
23 */
24
25#include <stdio.h>
26#include <math.h>
27#include <assert.h>
28#ifndef NDEBUG
29#include <strings.h> // for strdup
30#endif
31
32#include "array_object.h"
33#include "bool_object.h"
34#include "collector.h"
35#include "context.h"
36#include "date_object.h"
37#include "debugger.h"
38#include "error_object.h"
39#include "function_object.h"
40#include "internal.h"
41#include "lexer.h"
42#include "math_object.h"
43#include "nodes.h"
44#include "number_object.h"
45#include "object.h"
46#include "object_object.h"
47#include "operations.h"
48#include "regexp_object.h"
49#include "string_object.h"
50
51#define I18N_NOOP(s) s
52
53extern int kjsyyparse();
54
55using namespace KJS;
56
57namespace KJS {
58#ifdef WORDS_BIGENDIAN
59 const unsigned char NaN_Bytes[] = { 0x7f, 0xf8, 0, 0, 0, 0, 0, 0 };
60 const unsigned char Inf_Bytes[] = { 0x7f, 0xf0, 0, 0, 0, 0, 0, 0 };
61#elif defined(arm)
62 const unsigned char NaN_Bytes[] = { 0, 0, 0xf8, 0x7f, 0, 0, 0, 0 };
63 const unsigned char Inf_Bytes[] = { 0, 0, 0xf0, 0x7f, 0, 0, 0, 0 };
64#else
65 const unsigned char NaN_Bytes[] = { 0, 0, 0, 0, 0, 0, 0xf8, 0x7f };
66 const unsigned char Inf_Bytes[] = { 0, 0, 0, 0, 0, 0, 0xf0, 0x7f };
67#endif
68
69 const double NaN = *(const double*) NaN_Bytes;
70 const double Inf = *(const double*) Inf_Bytes;
71};
72
73static pthread_once_t interpreterLockOnce = PTHREAD_ONCE_INIT;
74static pthread_mutex_t interpreterLock;
75
76static void initializeInterpreterLock()
77{
78 pthread_mutexattr_t attr;
79
80 pthread_mutexattr_init(&attr);
81 pthread_mutexattr_settype (&attr, PTHREAD_MUTEX_RECURSIVE);
82
83 pthread_mutex_init(&interpreterLock, &attr);
84}
85
86static inline void lockInterpreter()
87{
88 pthread_once(&interpreterLockOnce, initializeInterpreterLock);
89 pthread_mutex_lock(&interpreterLock);
90}
91
92static inline void unlockInterpreter()
93{
94 pthread_mutex_unlock(&interpreterLock);
95}
96
97
98
99// ------------------------------ UndefinedImp ---------------------------------
100
101UndefinedImp *UndefinedImp::staticUndefined = 0;
102
103Value UndefinedImp::toPrimitive(ExecState */*exec*/, Type) const
104{
105 return Value((ValueImp*)this);
106}
107
108bool UndefinedImp::toBoolean(ExecState */*exec*/) const
109{
110 return false;
111}
112
113double UndefinedImp::toNumber(ExecState */*exec*/) const
114{
115 return NaN;
116}
117
118UString UndefinedImp::toString(ExecState */*exec*/) const
119{
120 return "undefined";
121}
122
123Object UndefinedImp::toObject(ExecState *exec) const
124{
125 Object err = Error::create(exec, TypeError, I18N_NOOP("Undefined value"));
126 exec->setException(err);
127 return err;
128}
129
130// ------------------------------ NullImp --------------------------------------
131
132NullImp *NullImp::staticNull = 0;
133
134Value NullImp::toPrimitive(ExecState */*exec*/, Type) const
135{
136 return Value((ValueImp*)this);
137}
138
139bool NullImp::toBoolean(ExecState */*exec*/) const
140{
141 return false;
142}
143
144double NullImp::toNumber(ExecState */*exec*/) const
145{
146 return 0.0;
147}
148
149UString NullImp::toString(ExecState */*exec*/) const
150{
151 return "null";
152}
153
154Object NullImp::toObject(ExecState *exec) const
155{
156 Object err = Error::create(exec, TypeError, I18N_NOOP("Null value"));
157 exec->setException(err);
158 return err;
159}
160
161// ------------------------------ BooleanImp -----------------------------------
162
163BooleanImp* BooleanImp::staticTrue = 0;
164BooleanImp* BooleanImp::staticFalse = 0;
165
166Value BooleanImp::toPrimitive(ExecState */*exec*/, Type) const
167{
168 return Value((ValueImp*)this);
169}
170
171bool BooleanImp::toBoolean(ExecState */*exec*/) const
172{
173 return val;
174}
175
176double BooleanImp::toNumber(ExecState */*exec*/) const
177{
178 return val ? 1.0 : 0.0;
179}
180
181UString BooleanImp::toString(ExecState */*exec*/) const
182{
183 return val ? "true" : "false";
184}
185
186Object BooleanImp::toObject(ExecState *exec) const
187{
188 List args;
189 args.append(const_cast<BooleanImp*>(this));
190 return Object::dynamicCast(exec->interpreter()->builtinBoolean().construct(exec,args));
191}
192
193// ------------------------------ StringImp ------------------------------------
194
195Value StringImp::toPrimitive(ExecState */*exec*/, Type) const
196{
197 return Value((ValueImp*)this);
198}
199
200bool StringImp::toBoolean(ExecState */*exec*/) const
201{
202 return (val.size() > 0);
203}
204
205double StringImp::toNumber(ExecState */*exec*/) const
206{
207 return val.toDouble();
208}
209
210UString StringImp::toString(ExecState */*exec*/) const
211{
212 return val;
213}
214
215Object StringImp::toObject(ExecState *exec) const
216{
217 List args;
218 args.append(const_cast<StringImp*>(this));
219 return Object::dynamicCast(exec->interpreter()->builtinString().construct(exec,args));
220}
221
222// ------------------------------ NumberImp ------------------------------------
223
224NumberImp *NumberImp::staticNaN;
225
226ValueImp *NumberImp::create(int i)
227{
228 if (SimpleNumber::fits(i))
229 return SimpleNumber::make(i);
230 NumberImp *imp = new NumberImp(static_cast<double>(i));
231 imp->setGcAllowedFast();
232 return imp;
233}
234
235ValueImp *NumberImp::create(double d)
236{
237 if (SimpleNumber::fits(d))
238 return SimpleNumber::make((int)d);
239 if (isNaN(d))
240 return staticNaN;
241 NumberImp *imp = new NumberImp(d);
242 imp->setGcAllowedFast();
243 return imp;
244}
245
246Value NumberImp::toPrimitive(ExecState *, Type) const
247{
248 return Number((NumberImp*)this);
249}
250
251bool NumberImp::toBoolean(ExecState *) const
252{
253 return !((val == 0) /* || (iVal() == N0) */ || isNaN(val));
254}
255
256double NumberImp::toNumber(ExecState *) const
257{
258 return val;
259}
260
261UString NumberImp::toString(ExecState *) const
262{
263 return UString::from(val);
264}
265
266Object NumberImp::toObject(ExecState *exec) const
267{
268 List args;
269 args.append(const_cast<NumberImp*>(this));
270 return Object::dynamicCast(exec->interpreter()->builtinNumber().construct(exec,args));
271}
272
273bool NumberImp::toUInt32(unsigned& uint32) const
274{
275 uint32 = (unsigned)val;
276 return (double)uint32 == val;
277}
278
279// ------------------------------ LabelStack -----------------------------------
280
281LabelStack::LabelStack(const LabelStack &other)
282{
283 tos = 0;
284 *this = other;
285}
286
287LabelStack &LabelStack::operator=(const LabelStack &other)
288{
289 clear();
290 tos = 0;
291 StackElem *cur = 0;
292 StackElem *se = other.tos;
293 while (se) {
294 StackElem *newPrev = new StackElem;
295 newPrev->prev = 0;
296 newPrev->id = se->id;
297 if (cur)
298 cur->prev = newPrev;
299 else
300 tos = newPrev;
301 cur = newPrev;
302 se = se->prev;
303 }
304 return *this;
305}
306
307bool LabelStack::push(const Identifier &id)
308{
309 if (id.isEmpty() || contains(id))
310 return false;
311
312 StackElem *newtos = new StackElem;
313 newtos->id = id;
314 newtos->prev = tos;
315 tos = newtos;
316 return true;
317}
318
319bool LabelStack::contains(const Identifier &id) const
320{
321 if (id.isEmpty())
322 return true;
323
324 for (StackElem *curr = tos; curr; curr = curr->prev)
325 if (curr->id == id)
326 return true;
327
328 return false;
329}
330
331void LabelStack::pop()
332{
333 if (tos) {
334 StackElem *prev = tos->prev;
335 delete tos;
336 tos = prev;
337 }
338}
339
340LabelStack::~LabelStack()
341{
342 clear();
343}
344
345void LabelStack::clear()
346{
347 StackElem *prev;
348
349 while (tos) {
350 prev = tos->prev;
351 delete tos;
352 tos = prev;
353 }
354}
355
356// ------------------------------ ContextImp -----------------------------------
357
358// ECMA 10.2
359ContextImp::ContextImp(Object &glob, InterpreterImp *interpreter, Object &thisV, CodeType type,
360 ContextImp *callingCon, FunctionImp *func, const List *args)
361 : _interpreter(interpreter), _function(func), _arguments(args)
362{
363 codeType = type;
364 _callingContext = callingCon;
365
366 // create and initialize activation object (ECMA 10.1.6)
367 if (type == FunctionCode || type == AnonymousCode ) {
368 activation = Object(new ActivationImp(func, *args));
369 variable = activation;
370 } else {
371 activation = Object();
372 variable = glob;
373 }
374
375 // ECMA 10.2
376 switch(type) {
377 case EvalCode:
378 if (_callingContext) {
379 scope = _callingContext->scopeChain();
380 variable = _callingContext->variableObject();
381 thisVal = _callingContext->thisValue();
382 break;
383 } // else same as GlobalCode
384 case GlobalCode:
385 scope.clear();
386 scope.push(glob.imp());
387 thisVal = Object(static_cast<ObjectImp*>(glob.imp()));
388 break;
389 case FunctionCode:
390 case AnonymousCode:
391 if (type == FunctionCode) {
392 scope = func->scope();
393 scope.push(activation.imp());
394 } else {
395 scope.clear();
396 scope.push(glob.imp());
397 scope.push(activation.imp());
398 }
399 variable = activation; // TODO: DontDelete ? (ECMA 10.2.3)
400 thisVal = thisV;
401 break;
402 }
403
404 _interpreter->setContext(this);
405}
406
407ContextImp::~ContextImp()
408{
409 _interpreter->setContext(_callingContext);
410}
411
412void ContextImp::mark()
413{
414 for (ContextImp *context = this; context; context = context->_callingContext) {
415 context->scope.mark();
416 }
417}
418
419// ------------------------------ Parser ---------------------------------------
420
421ProgramNode *Parser::progNode = 0;
422int Parser::sid = 0;
423
424ProgramNode *Parser::parse(const UChar *code, unsigned int length, int *sourceId,
425 int *errLine, UString *errMsg)
426{
427 if (errLine)
428 *errLine = -1;
429 if (errMsg)
430 *errMsg = 0;
431
432 Lexer::curr()->setCode(code, length);
433 progNode = 0;
434 sid++;
435 if (sourceId)
436 *sourceId = sid;
437 // Enable this (and the #define YYDEBUG in grammar.y) to debug a parse error
438 //extern int kjsyydebug;
439 //kjsyydebug=1;
440 int parseError = kjsyyparse();
441 ProgramNode *prog = progNode;
442 progNode = 0;
443 sid = -1;
444
445 if (parseError) {
446 int eline = Lexer::curr()->lineNo();
447 if (errLine)
448 *errLine = eline;
449 if (errMsg)
450 *errMsg = "Parse error at line " + UString::from(eline);
451#ifndef NDEBUG
452 fprintf(stderr, "KJS: JavaScript parse error at line %d.\n", eline);
453#endif
454 delete prog;
455 return 0;
456 }
457
458 return prog;
459}
460
461// ------------------------------ InterpreterImp -------------------------------
462
463InterpreterImp* InterpreterImp::s_hook = 0L;
464
465void InterpreterImp::globalInit()
466{
467 //fprintf( stderr, "InterpreterImp::globalInit()\n" );
468 UndefinedImp::staticUndefined = new UndefinedImp();
469 UndefinedImp::staticUndefined->ref();
470 NullImp::staticNull = new NullImp();
471 NullImp::staticNull->ref();
472 BooleanImp::staticTrue = new BooleanImp(true);
473 BooleanImp::staticTrue->ref();
474 BooleanImp::staticFalse = new BooleanImp(false);
475 BooleanImp::staticFalse->ref();
476 NumberImp::staticNaN = new NumberImp(NaN);
477 NumberImp::staticNaN->ref();
478}
479
480void InterpreterImp::globalClear()
481{
482 //fprintf( stderr, "InterpreterImp::globalClear()\n" );
483 UndefinedImp::staticUndefined->deref();
484 UndefinedImp::staticUndefined->setGcAllowed();
485 UndefinedImp::staticUndefined = 0L;
486 NullImp::staticNull->deref();
487 NullImp::staticNull->setGcAllowed();
488 NullImp::staticNull = 0L;
489 BooleanImp::staticTrue->deref();
490 BooleanImp::staticTrue->setGcAllowed();
491 BooleanImp::staticTrue = 0L;
492 BooleanImp::staticFalse->deref();
493 BooleanImp::staticFalse->setGcAllowed();
494 BooleanImp::staticFalse = 0L;
495 NumberImp::staticNaN->deref();
496 NumberImp::staticNaN->setGcAllowed();
497 NumberImp::staticNaN = 0;
498}
499
500InterpreterImp::InterpreterImp(Interpreter *interp, const Object &glob)
501 : _context(0)
502{
503 // add this interpreter to the global chain
504 // as a root set for garbage collection
505 lockInterpreter();
506 m_interpreter = interp;
507 if (s_hook) {
508 prev = s_hook;
509 next = s_hook->next;
510 s_hook->next->prev = this;
511 s_hook->next = this;
512 } else {
513 // This is the first interpreter
514 s_hook = next = prev = this;
515 globalInit();
516 }
517 unlockInterpreter();
518
519 global = glob;
520 globExec = new ExecState(m_interpreter,0);
521 dbg = 0;
522 m_compatMode = Interpreter::NativeMode;
523
524 // initialize properties of the global object
525 initGlobalObject();
526
527 recursion = 0;
528}
529
530void InterpreterImp::lock()
531{
532 lockInterpreter();
533}
534
535void InterpreterImp::unlock()
536{
537 unlockInterpreter();
538}
539
540void InterpreterImp::initGlobalObject()
541{
542 // Contructor prototype objects (Object.prototype, Array.prototype etc)
543
544 FunctionPrototypeImp *funcProto = new FunctionPrototypeImp(globExec);
545 b_FunctionPrototype = Object(funcProto);
546 ObjectPrototypeImp *objProto = new ObjectPrototypeImp(globExec,funcProto);
547 b_ObjectPrototype = Object(objProto);
548 funcProto->setPrototype(b_ObjectPrototype);
549
550 ArrayPrototypeImp *arrayProto = new ArrayPrototypeImp(globExec,objProto);
551 b_ArrayPrototype = Object(arrayProto);
552 StringPrototypeImp *stringProto = new StringPrototypeImp(globExec,objProto);
553 b_StringPrototype = Object(stringProto);
554 BooleanPrototypeImp *booleanProto = new BooleanPrototypeImp(globExec,objProto,funcProto);
555 b_BooleanPrototype = Object(booleanProto);
556 NumberPrototypeImp *numberProto = new NumberPrototypeImp(globExec,objProto,funcProto);
557 b_NumberPrototype = Object(numberProto);
558 DatePrototypeImp *dateProto = new DatePrototypeImp(globExec,objProto);
559 b_DatePrototype = Object(dateProto);
560 RegExpPrototypeImp *regexpProto = new RegExpPrototypeImp(globExec,objProto,funcProto);
561 b_RegExpPrototype = Object(regexpProto);
562 ErrorPrototypeImp *errorProto = new ErrorPrototypeImp(globExec,objProto,funcProto);
563 b_ErrorPrototype = Object(errorProto);
564
565 static_cast<ObjectImp*>(global.imp())->setPrototype(b_ObjectPrototype);
566
567 // Constructors (Object, Array, etc.)
568 b_Object = Object(new ObjectObjectImp(globExec, objProto, funcProto));
569 b_Function = Object(new FunctionObjectImp(globExec, funcProto));
570 b_Array = Object(new ArrayObjectImp(globExec, funcProto, arrayProto));
571 b_String = Object(new StringObjectImp(globExec, funcProto, stringProto));
572 b_Boolean = Object(new BooleanObjectImp(globExec, funcProto, booleanProto));
573 b_Number = Object(new NumberObjectImp(globExec, funcProto, numberProto));
574 b_Date = Object(new DateObjectImp(globExec, funcProto, dateProto));
575 b_RegExp = Object(new RegExpObjectImp(globExec, funcProto, regexpProto));
576 b_Error = Object(new ErrorObjectImp(globExec, funcProto, errorProto));
577
578 // Error object prototypes
579 b_evalErrorPrototype = Object(new NativeErrorPrototypeImp(globExec,errorProto,EvalError,
580 "EvalError","EvalError"));
581 b_rangeErrorPrototype = Object(new NativeErrorPrototypeImp(globExec,errorProto,RangeError,
582 "RangeError","RangeError"));
583 b_referenceErrorPrototype = Object(new NativeErrorPrototypeImp(globExec,errorProto,ReferenceError,
584 "ReferenceError","ReferenceError"));
585 b_syntaxErrorPrototype = Object(new NativeErrorPrototypeImp(globExec,errorProto,SyntaxError,
586 "SyntaxError","SyntaxError"));
587 b_typeErrorPrototype = Object(new NativeErrorPrototypeImp(globExec,errorProto,TypeError,
588 "TypeError","TypeError"));
589 b_uriErrorPrototype = Object(new NativeErrorPrototypeImp(globExec,errorProto,URIError,
590 "URIError","URIError"));
591
592 // Error objects
593 b_evalError = Object(new NativeErrorImp(globExec,funcProto,b_evalErrorPrototype));
594 b_rangeError = Object(new NativeErrorImp(globExec,funcProto,b_rangeErrorPrototype));
595 b_referenceError = Object(new NativeErrorImp(globExec,funcProto,b_referenceErrorPrototype));
596 b_syntaxError = Object(new NativeErrorImp(globExec,funcProto,b_syntaxErrorPrototype));
597 b_typeError = Object(new NativeErrorImp(globExec,funcProto,b_typeErrorPrototype));
598 b_uriError = Object(new NativeErrorImp(globExec,funcProto,b_uriErrorPrototype));
599
600 // ECMA 15.3.4.1
601 funcProto->put(globExec,"constructor", b_Function, DontEnum);
602
603 global.put(globExec,"Object", b_Object, DontEnum);
604 global.put(globExec,"Function", b_Function, DontEnum);
605 global.put(globExec,"Array", b_Array, DontEnum);
606 global.put(globExec,"Boolean", b_Boolean, DontEnum);
607 global.put(globExec,"String", b_String, DontEnum);
608 global.put(globExec,"Number", b_Number, DontEnum);
609 global.put(globExec,"Date", b_Date, DontEnum);
610 global.put(globExec,"RegExp", b_RegExp, DontEnum);
611 global.put(globExec,"Error", b_Error, DontEnum);
612 // Using Internal for those to have something != 0
613 // (see kjs_window). Maybe DontEnum would be ok too ?
614 global.put(globExec,"EvalError",b_evalError, Internal);
615 global.put(globExec,"RangeError",b_rangeError, Internal);
616 global.put(globExec,"ReferenceError",b_referenceError, Internal);
617 global.put(globExec,"SyntaxError",b_syntaxError, Internal);
618 global.put(globExec,"TypeError",b_typeError, Internal);
619 global.put(globExec,"URIError",b_uriError, Internal);
620
621 // Set the "constructor" property of all builtin constructors
622 objProto->put(globExec, "constructor", b_Object, DontEnum | DontDelete | ReadOnly);
623 funcProto->put(globExec, "constructor", b_Function, DontEnum | DontDelete | ReadOnly);
624 arrayProto->put(globExec, "constructor", b_Array, DontEnum | DontDelete | ReadOnly);
625 booleanProto->put(globExec, "constructor", b_Boolean, DontEnum | DontDelete | ReadOnly);
626 stringProto->put(globExec, "constructor", b_String, DontEnum | DontDelete | ReadOnly);
627 numberProto->put(globExec, "constructor", b_Number, DontEnum | DontDelete | ReadOnly);
628 dateProto->put(globExec, "constructor", b_Date, DontEnum | DontDelete | ReadOnly);
629 regexpProto->put(globExec, "constructor", b_RegExp, DontEnum | DontDelete | ReadOnly);
630 errorProto->put(globExec, "constructor", b_Error, DontEnum | DontDelete | ReadOnly);
631 b_evalErrorPrototype.put(globExec, "constructor", b_evalError, DontEnum | DontDelete | ReadOnly);
632 b_rangeErrorPrototype.put(globExec, "constructor", b_rangeError, DontEnum | DontDelete | ReadOnly);
633 b_referenceErrorPrototype.put(globExec, "constructor", b_referenceError, DontEnum | DontDelete | ReadOnly);
634 b_syntaxErrorPrototype.put(globExec, "constructor", b_syntaxError, DontEnum | DontDelete | ReadOnly);
635 b_typeErrorPrototype.put(globExec, "constructor", b_typeError, DontEnum | DontDelete | ReadOnly);
636 b_uriErrorPrototype.put(globExec, "constructor", b_uriError, DontEnum | DontDelete | ReadOnly);
637
638 // built-in values
639 global.put(globExec, "NaN", Number(NaN), DontEnum|DontDelete);
640 global.put(globExec, "Infinity", Number(Inf), DontEnum|DontDelete);
641 global.put(globExec, "undefined", Undefined(), DontEnum|DontDelete);
642
643 // built-in functions
644 global.put(globExec,"eval", Object(new GlobalFuncImp(globExec,funcProto,GlobalFuncImp::Eval, 1)), DontEnum);
645 global.put(globExec,"parseInt", Object(new GlobalFuncImp(globExec,funcProto,GlobalFuncImp::ParseInt, 2)), DontEnum);
646 global.put(globExec,"parseFloat", Object(new GlobalFuncImp(globExec,funcProto,GlobalFuncImp::ParseFloat, 1)), DontEnum);
647 global.put(globExec,"isNaN", Object(new GlobalFuncImp(globExec,funcProto,GlobalFuncImp::IsNaN, 1)), DontEnum);
648 global.put(globExec,"isFinite", Object(new GlobalFuncImp(globExec,funcProto,GlobalFuncImp::IsFinite, 1)), DontEnum);
649 global.put(globExec,"escape", Object(new GlobalFuncImp(globExec,funcProto,GlobalFuncImp::Escape, 1)), DontEnum);
650 global.put(globExec,"unescape", Object(new GlobalFuncImp(globExec,funcProto,GlobalFuncImp::UnEscape, 1)), DontEnum);
651#ifndef NDEBUG
652 global.put(globExec,"kjsprint", Object(new GlobalFuncImp(globExec,funcProto,GlobalFuncImp::KJSPrint, 1)), DontEnum);
653#endif
654
655 // built-in objects
656 global.put(globExec,"Math", Object(new MathObjectImp(globExec,objProto)), DontEnum);
657}
658
659InterpreterImp::~InterpreterImp()
660{
661 if (dbg)
662 dbg->detach(m_interpreter);
663 delete globExec;
664 globExec = 0L;
665 clear();
666}
667
668void InterpreterImp::clear()
669{
670 //fprintf(stderr,"InterpreterImp::clear\n");
671 // remove from global chain (see init())
672#if APPLE_CHANGES
673 lockInterpreter();
674#endif
675 next->prev = prev;
676 prev->next = next;
677 s_hook = next;
678 if (s_hook == this)
679 {
680 // This was the last interpreter
681 s_hook = 0L;
682 globalClear();
683 }
684#if APPLE_CHANGES
685 unlockInterpreter();
686#endif
687}
688
689void InterpreterImp::mark()
690{
691 //if (exVal && !exVal->marked())
692 // exVal->mark();
693 //if (retVal && !retVal->marked())
694 // retVal->mark();
695 if (UndefinedImp::staticUndefined && !UndefinedImp::staticUndefined->marked())
696 UndefinedImp::staticUndefined->mark();
697 if (NullImp::staticNull && !NullImp::staticNull->marked())
698 NullImp::staticNull->mark();
699 if (BooleanImp::staticTrue && !BooleanImp::staticTrue->marked())
700 BooleanImp::staticTrue->mark();
701 if (BooleanImp::staticFalse && !BooleanImp::staticFalse->marked())
702 BooleanImp::staticFalse->mark();
703 //fprintf( stderr, "InterpreterImp::mark this=%p global.imp()=%p\n", this, global.imp() );
704 if (global.imp())
705 global.imp()->mark();
706 if (m_interpreter)
707 m_interpreter->mark();
708 if (_context)
709 _context->mark();
710}
711
712bool InterpreterImp::checkSyntax(const UString &code)
713{
714 // Parser::parse() returns 0 in a syntax error occurs, so we just check for that
715 ProgramNode *progNode = Parser::parse(code.data(),code.size(),0,0,0);
716 bool ok = (progNode != 0);
717 delete progNode;
718 return ok;
719}
720
721Completion InterpreterImp::evaluate(const UString &code, const Value &thisV)
722{
723#if APPLE_CHANGES
724 lockInterpreter();
725#endif
726 // prevent against infinite recursion
727 if (recursion >= 20) {
728#if APPLE_CHANGES
729 Completion result = Completion(Throw,Error::create(globExec,GeneralError,"Recursion too deep"));
730 unlockInterpreter();
731 return result;
732#else
733 return Completion(Throw,Error::create(globExec,GeneralError,"Recursion too deep"));
734#endif
735 }
736
737 // parse the source code
738 int sid;
739 int errLine;
740 UString errMsg;
741 ProgramNode *progNode = Parser::parse(code.data(),code.size(),&sid,&errLine,&errMsg);
742
743 // notify debugger that source has been parsed
744 if (dbg) {
745 bool cont = dbg->sourceParsed(globExec,sid,code,errLine);
746 if (!cont)
747#if APPLE_CHANGES
748 {
749 unlockInterpreter();
750 return Completion(Break);
751 }
752#else
753 return Completion(Break);
754#endif
755 }
756
757 // no program node means a syntax error occurred
758 if (!progNode) {
759 Object err = Error::create(globExec,SyntaxError,errMsg.ascii(),errLine);
760 err.put(globExec,"sid",Number(sid));
761#if APPLE_CHANGES
762 unlockInterpreter();
763#endif
764 return Completion(Throw,err);
765 }
766
767 globExec->clearException();
768
769 recursion++;
770 progNode->ref();
771
772 Object &globalObj = globalObject();
773 Object thisObj = globalObject();
774
775 if (!thisV.isNull()) {
776 // "this" must be an object... use same rules as Function.prototype.apply()
777 if (thisV.isA(NullType) || thisV.isA(UndefinedType))
778 thisObj = globalObject();
779 else {
780 thisObj = thisV.toObject(globExec);
781 }
782 }
783
784 Completion res;
785 if (globExec->hadException()) {
786 // the thisArg.toObject() conversion above might have thrown an exception - if so,
787 // propagate it back
788 res = Completion(Throw,globExec->exception());
789 }
790 else {
791 // execute the code
792 ContextImp ctx(globalObj, this, thisObj);
793 ExecState newExec(m_interpreter,&ctx);
794 res = progNode->execute(&newExec);
795 }
796
797 if (progNode->deref())
798 delete progNode;
799 recursion--;
800
801#if APPLE_CHANGES
802 unlockInterpreter();
803#endif
804 return res;
805}
806
807void InterpreterImp::setDebugger(Debugger *d)
808{
809 if (d)
810 d->detach(m_interpreter);
811 dbg = d;
812}
813
814// ------------------------------ InternalFunctionImp --------------------------
815
816const ClassInfo InternalFunctionImp::info = {"Function", 0, 0, 0};
817
818InternalFunctionImp::InternalFunctionImp(FunctionPrototypeImp *funcProto)
819 : ObjectImp(funcProto)
820{
821}
822
823bool InternalFunctionImp::implementsHasInstance() const
824{
825 return true;
826}
827
828Boolean InternalFunctionImp::hasInstance(ExecState *exec, const Value &value)
829{
830 if (value.type() != ObjectType)
831 return Boolean(false);
832
833 Value prot = get(exec,prototypePropertyName);
834 if (prot.type() != ObjectType && prot.type() != NullType) {
835 Object err = Error::create(exec, TypeError, "Invalid prototype encountered "
836 "in instanceof operation.");
837 exec->setException(err);
838 return Boolean(false);
839 }
840
841 Object v = Object(static_cast<ObjectImp*>(value.imp()));
842 while ((v = Object::dynamicCast(v.prototype())).imp()) {
843 if (v.imp() == prot.imp())
844 return Boolean(true);
845 }
846 return Boolean(false);
847}
848
849// ------------------------------ global functions -----------------------------
850
851double KJS::roundValue(ExecState *exec, const Value &v)
852{
853 if (v.type() == UndefinedType) /* TODO: see below */
854 return 0.0;
855 Number n = v.toNumber(exec);
856 if (n.value() == 0.0) /* TODO: -0, NaN, Inf */
857 return 0.0;
858 double d = floor(fabs(n.value()));
859 if (n.value() < 0)
860 d *= -1;
861
862 return d;
863}
864
865#ifndef NDEBUG
866#include <stdio.h>
867void KJS::printInfo(ExecState *exec, const char *s, const Value &o, int lineno)
868{
869 if (o.isNull())
870 fprintf(stderr, "KJS: %s: (null)", s);
871 else {
872 Value v = o;
873
874 UString name;
875 switch ( v.type() ) {
876 case UnspecifiedType:
877 name = "Unspecified";
878 break;
879 case UndefinedType:
880 name = "Undefined";
881 break;
882 case NullType:
883 name = "Null";
884 break;
885 case BooleanType:
886 name = "Boolean";
887 break;
888 case StringType:
889 name = "String";
890 break;
891 case NumberType:
892 name = "Number";
893 break;
894 case ObjectType:
895 name = Object::dynamicCast(v).className();
896 if (name.isNull())
897 name = "(unknown class)";
898 break;
899 }
900 UString vString = v.toString(exec);
901 if ( vString.size() > 50 )
902 vString = vString.substr( 0, 50 ) + "...";
903 // Can't use two UString::ascii() in the same fprintf call
904 CString tempString( vString.cstring() );
905
906 fprintf(stderr, "KJS: %s: %s : %s (%p)",
907 s, tempString.c_str(), name.ascii(), (void*)v.imp());
908
909 if (lineno >= 0)
910 fprintf(stderr, ", line %d\n",lineno);
911 else
912 fprintf(stderr, "\n");
913 }
914}
915#endif
Note: See TracBrowser for help on using the repository browser.