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

Last change on this file since 2249 was 1863, checked in by darin, 23 years ago
  • kjs/internal.cpp: (KJS::printInfo): Remove one more CompletionType that Maciej missed.
  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 28.4 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 <stdio.h>
25#include <math.h>
26#include <assert.h>
27#ifndef NDEBUG
28#include <strings.h> // for strdup
29#endif
30
31#include "array_object.h"
32#include "bool_object.h"
33#include "collector.h"
34#include "date_object.h"
35#include "debugger.h"
36#include "error_object.h"
37#include "function_object.h"
38#include "internal.h"
39#include "lexer.h"
40#include "math_object.h"
41#include "nodes.h"
42#include "number_object.h"
43#include "object.h"
44#include "object_object.h"
45#include "operations.h"
46#include "regexp_object.h"
47#include "string_object.h"
48
49#define I18N_NOOP(s) s
50
51extern int kjsyyparse();
52
53using namespace KJS;
54
55namespace KJS {
56#ifdef WORDS_BIGENDIAN
57 unsigned char NaN_Bytes[] = { 0x7f, 0xf8, 0, 0, 0, 0, 0, 0 };
58 unsigned char Inf_Bytes[] = { 0x7f, 0xf0, 0, 0, 0, 0, 0, 0 };
59#elif defined(arm)
60 unsigned char NaN_Bytes[] = { 0, 0, 0xf8, 0x7f, 0, 0, 0, 0 };
61 unsigned char Inf_Bytes[] = { 0, 0, 0xf0, 0x7f, 0, 0, 0, 0 };
62#else
63 unsigned char NaN_Bytes[] = { 0, 0, 0, 0, 0, 0, 0xf8, 0x7f };
64 unsigned char Inf_Bytes[] = { 0, 0, 0, 0, 0, 0, 0xf0, 0x7f };
65#endif
66
67 const double NaN = *(const double*) NaN_Bytes;
68 const double Inf = *(const double*) Inf_Bytes;
69};
70
71#ifdef APPLE_CHANGES
72static pthread_once_t interpreterLockOnce = PTHREAD_ONCE_INIT;
73static pthread_mutex_t interpreterLock;
74
75static void initializeInterpreterLock()
76{
77 pthread_mutexattr_t attr;
78
79 pthread_mutexattr_init(&attr);
80 pthread_mutexattr_settype (&attr, PTHREAD_MUTEX_RECURSIVE);
81
82 pthread_mutex_init(&interpreterLock, &attr);
83}
84
85static inline void lockInterpreter()
86{
87 pthread_once(&interpreterLockOnce, initializeInterpreterLock);
88 pthread_mutex_lock(&interpreterLock);
89}
90
91static inline void unlockInterpreter()
92{
93 pthread_mutex_unlock(&interpreterLock);
94}
95
96#endif
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(Boolean(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(Value(const_cast<StringImp*>(this)));
219 return Object::dynamicCast(exec->interpreter()->builtinString().construct(exec,args));
220}
221
222// ------------------------------ NumberImp ------------------------------------
223
224Value NumberImp::toPrimitive(ExecState *, Type) const
225{
226 return Number((NumberImp*)this);
227}
228
229bool NumberImp::toBoolean(ExecState *) const
230{
231 return !((val == 0) /* || (iVal() == N0) */ || isNaN(val));
232}
233
234double NumberImp::toNumber(ExecState *) const
235{
236 return val;
237}
238
239UString NumberImp::toString(ExecState *) const
240{
241 return UString::from(val);
242}
243
244Object NumberImp::toObject(ExecState *exec) const
245{
246 List args;
247 args.append(Number(const_cast<NumberImp*>(this)));
248 return Object::dynamicCast(exec->interpreter()->builtinNumber().construct(exec,args));
249}
250
251bool NumberImp::toUInt32(unsigned& uint32) const
252{
253 uint32 = (unsigned)val;
254 return (double)uint32 == val;
255}
256
257// ------------------------------ LabelStack -----------------------------------
258
259LabelStack::LabelStack(const LabelStack &other)
260{
261 tos = 0;
262 *this = other;
263}
264
265LabelStack &LabelStack::operator=(const LabelStack &other)
266{
267 clear();
268 tos = 0;
269 StackElem *cur = 0;
270 StackElem *se = other.tos;
271 while (se) {
272 StackElem *newPrev = new StackElem;
273 newPrev->prev = 0;
274 newPrev->id = se->id;
275 if (cur)
276 cur->prev = newPrev;
277 else
278 tos = newPrev;
279 cur = newPrev;
280 se = se->prev;
281 }
282 return *this;
283}
284
285bool LabelStack::push(const UString &id)
286{
287 if (id.isEmpty() || contains(id))
288 return false;
289
290 StackElem *newtos = new StackElem;
291 newtos->id = id;
292 newtos->prev = tos;
293 tos = newtos;
294 return true;
295}
296
297bool LabelStack::contains(const UString &id) const
298{
299 if (id.isEmpty())
300 return true;
301
302 for (StackElem *curr = tos; curr; curr = curr->prev)
303 if (curr->id == id)
304 return true;
305
306 return false;
307}
308
309void LabelStack::pop()
310{
311 if (tos) {
312 StackElem *prev = tos->prev;
313 delete tos;
314 tos = prev;
315 }
316}
317
318LabelStack::~LabelStack()
319{
320 clear();
321}
322
323void LabelStack::clear()
324{
325 StackElem *prev;
326
327 while (tos) {
328 prev = tos->prev;
329 delete tos;
330 tos = prev;
331 }
332}
333
334// ------------------------------ ListImp --------------------------------------
335
336#ifdef KJS_DEBUG_MEM
337int ListImp::count = 0;
338#endif
339
340Value ListImp::toPrimitive(ExecState */*exec*/, Type /*preferredType*/) const
341{
342 // invalid for List
343 assert(false);
344 return Value();
345}
346
347bool ListImp::toBoolean(ExecState */*exec*/) const
348{
349 // invalid for List
350 assert(false);
351 return false;
352}
353
354double ListImp::toNumber(ExecState */*exec*/) const
355{
356 // invalid for List
357 assert(false);
358 return 0;
359}
360
361UString ListImp::toString(ExecState */*exec*/) const
362{
363 // invalid for List
364 assert(false);
365 return UString::null;
366}
367
368Object ListImp::toObject(ExecState */*exec*/) const
369{
370 // invalid for List
371 assert(false);
372 return Object();
373}
374
375ListImp::ListImp()
376{
377#ifdef KJS_DEBUG_MEM
378 count++;
379#endif
380
381 hook = new ListNode(Null(), 0L, 0L);
382 hook->next = hook;
383 hook->prev = hook;
384 //fprintf(stderr,"ListImp::ListImp %p hook=%p\n",this,hook);
385}
386
387ListImp::~ListImp()
388{
389 //fprintf(stderr,"ListImp::~ListImp %p\n",this);
390#ifdef KJS_DEBUG_MEM
391 count--;
392#endif
393
394 clear();
395 delete hook;
396
397 if ( emptyList == this )
398 emptyList = 0L;
399}
400
401void ListImp::mark()
402{
403 ListNode *n = hook->next;
404 while (n != hook) {
405 if (!n->member->marked())
406 n->member->mark();
407 n = n->next;
408 }
409 ValueImp::mark();
410}
411
412void ListImp::append(const Value& obj)
413{
414 ListNode *n = new ListNode(obj, hook->prev, hook);
415 hook->prev->next = n;
416 hook->prev = n;
417}
418
419void ListImp::prepend(const Value& obj)
420{
421 ListNode *n = new ListNode(obj, hook, hook->next);
422 hook->next->prev = n;
423 hook->next = n;
424}
425
426void ListImp::appendList(const List& lst)
427{
428 ListIterator it = lst.begin();
429 ListIterator e = lst.end();
430 while(it != e) {
431 append(*it);
432 ++it;
433 }
434}
435
436void ListImp::prependList(const List& lst)
437{
438 ListIterator it = lst.end();
439 ListIterator e = lst.begin();
440 while(it != e) {
441 --it;
442 prepend(*it);
443 }
444}
445
446void ListImp::removeFirst()
447{
448 erase(hook->next);
449}
450
451void ListImp::removeLast()
452{
453 erase(hook->prev);
454}
455
456void ListImp::remove(const Value &obj)
457{
458 if (obj.isNull())
459 return;
460 ListNode *n = hook->next;
461 while (n != hook) {
462 if (n->member == obj.imp()) {
463 erase(n);
464 return;
465 }
466 n = n->next;
467 }
468}
469
470void ListImp::clear()
471{
472 ListNode *n = hook->next;
473 while (n != hook) {
474 n = n->next;
475 delete n->prev;
476 }
477
478 hook->next = hook;
479 hook->prev = hook;
480}
481
482ListImp *ListImp::copy() const
483{
484 ListImp* newList = new ListImp;
485
486 ListIterator e = end();
487 ListIterator it = begin();
488
489 while(it != e) {
490 newList->append(*it);
491 ++it;
492 }
493
494 //fprintf( stderr, "ListImp::copy returning newList=%p\n", newList );
495 return newList;
496}
497
498void ListImp::erase(ListNode *n)
499{
500 if (n != hook) {
501 n->next->prev = n->prev;
502 n->prev->next = n->next;
503 delete n;
504 }
505}
506
507bool ListImp::isEmpty() const
508{
509 return (hook->prev == hook);
510}
511
512int ListImp::size() const
513{
514 int s = 0;
515 ListNode *node = hook;
516 while ((node = node->next) != hook)
517 s++;
518
519 return s;
520}
521
522Value ListImp::at(int i) const
523{
524 if (i < 0 || i >= size())
525 return Undefined();
526
527 ListIterator it = begin();
528 int j = 0;
529 while ((j++ < i))
530 it++;
531
532 return *it;
533}
534
535ListImp *ListImp::emptyList = 0L;
536
537ListImp *ListImp::empty()
538{
539 if (!emptyList)
540 emptyList = new ListImp();
541 return emptyList;
542}
543
544// ------------------------------ ContextImp -----------------------------------
545
546
547// ECMA 10.2
548ContextImp::ContextImp(Object &glob, ExecState *exec, Object &thisV, CodeType type,
549 ContextImp *_callingContext, FunctionImp *func, const List &args)
550{
551 codeType = type;
552 callingCon = _callingContext;
553
554 // create and initialize activation object (ECMA 10.1.6)
555 if (type == FunctionCode || type == AnonymousCode ) {
556 activation = Object(new ActivationImp(exec,func,args));
557 variable = activation;
558 } else {
559 activation = Object();
560 variable = glob;
561 }
562
563 // ECMA 10.2
564 switch(type) {
565 case EvalCode:
566 if (callingCon) {
567 scope = callingCon->scopeChain().copy();
568 variable = callingCon->variableObject();
569 thisVal = callingCon->thisValue();
570 break;
571 } // else same as GlobalCode
572 case GlobalCode:
573 scope = List();
574 scope.append(glob);
575 thisVal = Object(static_cast<ObjectImp*>(glob.imp()));
576 break;
577 case FunctionCode:
578 case AnonymousCode:
579 if (type == FunctionCode) {
580 scope = func->scope().copy();
581 scope.prepend(activation);
582 } else {
583 scope = List();
584 scope.append(activation);
585 scope.append(glob);
586 }
587 variable = activation; // TODO: DontDelete ? (ECMA 10.2.3)
588 thisVal = thisV;
589 break;
590 }
591
592}
593
594ContextImp::~ContextImp()
595{
596}
597
598void ContextImp::pushScope(const Object &s)
599{
600 scope.prepend(s);
601}
602
603void ContextImp::popScope()
604{
605 scope.removeFirst();
606}
607
608// ------------------------------ Parser ---------------------------------------
609
610ProgramNode *Parser::progNode = 0;
611int Parser::sid = 0;
612
613ProgramNode *Parser::parse(const UChar *code, unsigned int length, int *sourceId,
614 int *errLine, UString *errMsg)
615{
616 if (errLine)
617 *errLine = -1;
618 if (errMsg)
619 *errMsg = 0;
620
621 Lexer::curr()->setCode(code, length);
622 progNode = 0;
623 sid++;
624 if (sourceId)
625 *sourceId = sid;
626 // Enable this (and the #define YYDEBUG in grammar.y) to debug a parse error
627 //extern int kjsyydebug;
628 //kjsyydebug=1;
629 int parseError = kjsyyparse();
630 ProgramNode *prog = progNode;
631 progNode = 0;
632 sid = -1;
633
634 if (parseError) {
635 int eline = Lexer::curr()->lineNo();
636 if (errLine)
637 *errLine = eline;
638 if (errMsg)
639 *errMsg = "Parse error at line " + UString::from(eline);
640#ifndef NDEBUG
641 fprintf(stderr, "KJS: JavaScript parse error at line %d.\n", eline);
642#endif
643 delete prog;
644 return 0;
645 }
646
647 return prog;
648}
649
650// ------------------------------ InterpreterImp -------------------------------
651
652InterpreterImp* InterpreterImp::s_hook = 0L;
653
654void InterpreterImp::globalInit()
655{
656 //fprintf( stderr, "InterpreterImp::globalInit()\n" );
657 UndefinedImp::staticUndefined = new UndefinedImp();
658 UndefinedImp::staticUndefined->ref();
659 NullImp::staticNull = new NullImp();
660 NullImp::staticNull->ref();
661 BooleanImp::staticTrue = new BooleanImp(true);
662 BooleanImp::staticTrue->ref();
663 BooleanImp::staticFalse = new BooleanImp(false);
664 BooleanImp::staticFalse->ref();
665}
666
667void InterpreterImp::globalClear()
668{
669 //fprintf( stderr, "InterpreterImp::globalClear()\n" );
670 UndefinedImp::staticUndefined->deref();
671 UndefinedImp::staticUndefined->setGcAllowed();
672 UndefinedImp::staticUndefined = 0L;
673 NullImp::staticNull->deref();
674 NullImp::staticNull->setGcAllowed();
675 NullImp::staticNull = 0L;
676 BooleanImp::staticTrue->deref();
677 BooleanImp::staticTrue->setGcAllowed();
678 BooleanImp::staticTrue = 0L;
679 BooleanImp::staticFalse->deref();
680 BooleanImp::staticFalse->setGcAllowed();
681 BooleanImp::staticFalse = 0L;
682}
683
684InterpreterImp::InterpreterImp(Interpreter *interp, const Object &glob)
685{
686 // add this interpreter to the global chain
687 // as a root set for garbage collection
688#ifdef APPLE_CHANGES
689 lockInterpreter();
690 m_interpreter = interp;
691#endif
692 if (s_hook) {
693 prev = s_hook;
694 next = s_hook->next;
695 s_hook->next->prev = this;
696 s_hook->next = this;
697 } else {
698 // This is the first interpreter
699 s_hook = next = prev = this;
700 globalInit();
701 }
702#ifdef APPLE_CHANGES
703 unlockInterpreter();
704#endif
705
706#ifndef APPLE_CHANGES
707 m_interpreter = interp;
708#endif
709 global = glob;
710 globExec = new ExecState(m_interpreter,0);
711 dbg = 0;
712 m_compatMode = Interpreter::NativeMode;
713
714 // initialize properties of the global object
715 initGlobalObject();
716
717 recursion = 0;
718}
719
720void InterpreterImp::initGlobalObject()
721{
722 // Contructor prototype objects (Object.prototype, Array.prototype etc)
723
724 FunctionPrototypeImp *funcProto = new FunctionPrototypeImp(globExec);
725 b_FunctionPrototype = Object(funcProto);
726 ObjectPrototypeImp *objProto = new ObjectPrototypeImp(globExec,funcProto);
727 b_ObjectPrototype = Object(objProto);
728 funcProto->setPrototype(b_ObjectPrototype);
729
730 ArrayPrototypeImp *arrayProto = new ArrayPrototypeImp(globExec,objProto);
731 b_ArrayPrototype = Object(arrayProto);
732 StringPrototypeImp *stringProto = new StringPrototypeImp(globExec,objProto);
733 b_StringPrototype = Object(stringProto);
734 BooleanPrototypeImp *booleanProto = new BooleanPrototypeImp(globExec,objProto,funcProto);
735 b_BooleanPrototype = Object(booleanProto);
736 NumberPrototypeImp *numberProto = new NumberPrototypeImp(globExec,objProto,funcProto);
737 b_NumberPrototype = Object(numberProto);
738 DatePrototypeImp *dateProto = new DatePrototypeImp(globExec,objProto);
739 b_DatePrototype = Object(dateProto);
740 RegExpPrototypeImp *regexpProto = new RegExpPrototypeImp(globExec,objProto,funcProto);
741 b_RegExpPrototype = Object(regexpProto);
742 ErrorPrototypeImp *errorProto = new ErrorPrototypeImp(globExec,objProto,funcProto);
743 b_ErrorPrototype = Object(errorProto);
744
745 static_cast<ObjectImp*>(global.imp())->setPrototype(b_ObjectPrototype);
746
747 // Constructors (Object, Array, etc.)
748 b_Object = Object(new ObjectObjectImp(globExec, objProto, funcProto));
749 b_Function = Object(new FunctionObjectImp(globExec, funcProto));
750 b_Array = Object(new ArrayObjectImp(globExec, funcProto, arrayProto));
751 b_String = Object(new StringObjectImp(globExec, funcProto, stringProto));
752 b_Boolean = Object(new BooleanObjectImp(globExec, funcProto, booleanProto));
753 b_Number = Object(new NumberObjectImp(globExec, funcProto, numberProto));
754 b_Date = Object(new DateObjectImp(globExec, funcProto, dateProto));
755 b_RegExp = Object(new RegExpObjectImp(globExec, funcProto, regexpProto));
756 b_Error = Object(new ErrorObjectImp(globExec, funcProto, errorProto));
757
758 // Error object prototypes
759 b_evalErrorPrototype = Object(new NativeErrorPrototypeImp(globExec,errorProto,EvalError,
760 "EvalError","EvalError"));
761 b_rangeErrorPrototype = Object(new NativeErrorPrototypeImp(globExec,errorProto,RangeError,
762 "RangeError","RangeError"));
763 b_referenceErrorPrototype = Object(new NativeErrorPrototypeImp(globExec,errorProto,ReferenceError,
764 "ReferenceError","ReferenceError"));
765 b_syntaxErrorPrototype = Object(new NativeErrorPrototypeImp(globExec,errorProto,SyntaxError,
766 "SyntaxError","SyntaxError"));
767 b_typeErrorPrototype = Object(new NativeErrorPrototypeImp(globExec,errorProto,TypeError,
768 "TypeError","TypeError"));
769 b_uriErrorPrototype = Object(new NativeErrorPrototypeImp(globExec,errorProto,URIError,
770 "URIError","URIError"));
771
772 // Error objects
773 b_evalError = Object(new NativeErrorImp(globExec,funcProto,b_evalErrorPrototype));
774 b_rangeError = Object(new NativeErrorImp(globExec,funcProto,b_rangeErrorPrototype));
775 b_referenceError = Object(new NativeErrorImp(globExec,funcProto,b_referenceErrorPrototype));
776 b_syntaxError = Object(new NativeErrorImp(globExec,funcProto,b_syntaxErrorPrototype));
777 b_typeError = Object(new NativeErrorImp(globExec,funcProto,b_typeErrorPrototype));
778 b_uriError = Object(new NativeErrorImp(globExec,funcProto,b_uriErrorPrototype));
779
780 // ECMA 15.3.4.1
781 funcProto->put(globExec,"constructor", b_Function, DontEnum);
782
783 global.put(globExec,"Object", b_Object, DontEnum);
784 global.put(globExec,"Function", b_Function, DontEnum);
785 global.put(globExec,"Array", b_Array, DontEnum);
786 global.put(globExec,"Boolean", b_Boolean, DontEnum);
787 global.put(globExec,"String", b_String, DontEnum);
788 global.put(globExec,"Number", b_Number, DontEnum);
789 global.put(globExec,"Date", b_Date, DontEnum);
790 global.put(globExec,"RegExp", b_RegExp, DontEnum);
791 global.put(globExec,"Error", b_Error, DontEnum);
792 // Using Internal for those to have something != 0
793 // (see kjs_window). Maybe DontEnum would be ok too ?
794 global.put(globExec,"EvalError",b_evalError, Internal);
795 global.put(globExec,"RangeError",b_rangeError, Internal);
796 global.put(globExec,"ReferenceError",b_referenceError, Internal);
797 global.put(globExec,"SyntaxError",b_syntaxError, Internal);
798 global.put(globExec,"TypeError",b_typeError, Internal);
799 global.put(globExec,"URIError",b_uriError, Internal);
800
801 // Set the "constructor" property of all builtin constructors
802 objProto->put(globExec, "constructor", b_Object, DontEnum | DontDelete | ReadOnly);
803 funcProto->put(globExec, "constructor", b_Function, DontEnum | DontDelete | ReadOnly);
804 arrayProto->put(globExec, "constructor", b_Array, DontEnum | DontDelete | ReadOnly);
805 booleanProto->put(globExec, "constructor", b_Boolean, DontEnum | DontDelete | ReadOnly);
806 stringProto->put(globExec, "constructor", b_String, DontEnum | DontDelete | ReadOnly);
807 numberProto->put(globExec, "constructor", b_Number, DontEnum | DontDelete | ReadOnly);
808 dateProto->put(globExec, "constructor", b_Date, DontEnum | DontDelete | ReadOnly);
809 regexpProto->put(globExec, "constructor", b_RegExp, DontEnum | DontDelete | ReadOnly);
810 errorProto->put(globExec, "constructor", b_Error, DontEnum | DontDelete | ReadOnly);
811 b_evalErrorPrototype.put(globExec, "constructor", b_evalError, DontEnum | DontDelete | ReadOnly);
812 b_rangeErrorPrototype.put(globExec, "constructor", b_rangeError, DontEnum | DontDelete | ReadOnly);
813 b_referenceErrorPrototype.put(globExec, "constructor", b_referenceError, DontEnum | DontDelete | ReadOnly);
814 b_syntaxErrorPrototype.put(globExec, "constructor", b_syntaxError, DontEnum | DontDelete | ReadOnly);
815 b_typeErrorPrototype.put(globExec, "constructor", b_typeError, DontEnum | DontDelete | ReadOnly);
816 b_uriErrorPrototype.put(globExec, "constructor", b_uriError, DontEnum | DontDelete | ReadOnly);
817
818 // built-in values
819 global.put(globExec, "NaN", Number(NaN), DontEnum|DontDelete);
820 global.put(globExec, "Infinity", Number(Inf), DontEnum|DontDelete);
821 global.put(globExec, "undefined", Undefined(), DontEnum|DontDelete);
822
823 // built-in functions
824 global.put(globExec,"eval", Object(new GlobalFuncImp(globExec,funcProto,GlobalFuncImp::Eval, 1)), DontEnum);
825 global.put(globExec,"parseInt", Object(new GlobalFuncImp(globExec,funcProto,GlobalFuncImp::ParseInt, 2)), DontEnum);
826 global.put(globExec,"parseFloat", Object(new GlobalFuncImp(globExec,funcProto,GlobalFuncImp::ParseFloat, 1)), DontEnum);
827 global.put(globExec,"isNaN", Object(new GlobalFuncImp(globExec,funcProto,GlobalFuncImp::IsNaN, 1)), DontEnum);
828 global.put(globExec,"isFinite", Object(new GlobalFuncImp(globExec,funcProto,GlobalFuncImp::IsFinite, 1)), DontEnum);
829 global.put(globExec,"escape", Object(new GlobalFuncImp(globExec,funcProto,GlobalFuncImp::Escape, 1)), DontEnum);
830 global.put(globExec,"unescape", Object(new GlobalFuncImp(globExec,funcProto,GlobalFuncImp::UnEscape, 1)), DontEnum);
831
832 // built-in objects
833 global.put(globExec,"Math", Object(new MathObjectImp(globExec,objProto)), DontEnum);
834}
835
836InterpreterImp::~InterpreterImp()
837{
838 if (dbg)
839 dbg->detach(m_interpreter);
840 delete globExec;
841 globExec = 0L;
842 clear();
843}
844
845void InterpreterImp::clear()
846{
847 //fprintf(stderr,"InterpreterImp::clear\n");
848 // remove from global chain (see init())
849#ifdef APPLE_CHANGES
850 lockInterpreter();
851#endif
852 next->prev = prev;
853 prev->next = next;
854 s_hook = next;
855 if (s_hook == this)
856 {
857 // This was the last interpreter
858 s_hook = 0L;
859 globalClear();
860 }
861#ifdef APPLE_CHANGES
862 unlockInterpreter();
863#endif
864}
865
866void InterpreterImp::mark()
867{
868 //if (exVal && !exVal->marked())
869 // exVal->mark();
870 //if (retVal && !retVal->marked())
871 // retVal->mark();
872 if (UndefinedImp::staticUndefined && !UndefinedImp::staticUndefined->marked())
873 UndefinedImp::staticUndefined->mark();
874 if (NullImp::staticNull && !NullImp::staticNull->marked())
875 NullImp::staticNull->mark();
876 if (BooleanImp::staticTrue && !BooleanImp::staticTrue->marked())
877 BooleanImp::staticTrue->mark();
878 if (BooleanImp::staticFalse && !BooleanImp::staticFalse->marked())
879 BooleanImp::staticFalse->mark();
880 if (ListImp::emptyList && !ListImp::emptyList->marked())
881 ListImp::emptyList->mark();
882 //fprintf( stderr, "InterpreterImp::mark this=%p global.imp()=%p\n", this, global.imp() );
883 if (global.imp())
884 global.imp()->mark();
885 if (m_interpreter)
886 m_interpreter->mark();
887}
888
889bool InterpreterImp::checkSyntax(const UString &code)
890{
891 // Parser::parse() returns 0 in a syntax error occurs, so we just check for that
892 ProgramNode *progNode = Parser::parse(code.data(),code.size(),0,0,0);
893 bool ok = (progNode != 0);
894 delete progNode;
895 return ok;
896}
897
898Completion InterpreterImp::evaluate(const UString &code, const Value &thisV)
899{
900#ifdef APPLE_CHANGES
901 lockInterpreter();
902#endif
903 // prevent against infinite recursion
904 if (recursion >= 20) {
905#ifdef APPLE_CHANGES
906 Completion result = Completion(Throw,Error::create(globExec,GeneralError,"Recursion too deep"));
907 unlockInterpreter();
908 return result;
909#else
910 return Completion(Throw,Error::create(globExec,GeneralError,"Recursion too deep"));
911#endif
912 }
913
914 // parse the source code
915 int sid;
916 int errLine;
917 UString errMsg;
918 ProgramNode *progNode = Parser::parse(code.data(),code.size(),&sid,&errLine,&errMsg);
919
920 // notify debugger that source has been parsed
921 if (dbg) {
922 bool cont = dbg->sourceParsed(globExec,sid,code,errLine);
923 if (!cont)
924#ifdef APPLE_CHANGES
925 {
926 pthread_mutex_unlock(&interpreterLock);
927 return Completion(Break);
928 }
929#else
930 return Completion(Break);
931#endif
932 }
933
934 // no program node means a syntax error occurred
935 if (!progNode) {
936 Object err = Error::create(globExec,SyntaxError,errMsg.ascii(),errLine);
937 err.put(globExec,"sid",Number(sid));
938#ifdef APPLE_CHANGES
939 unlockInterpreter();
940#endif
941 return Completion(Throw,err);
942 }
943
944 globExec->clearException();
945
946 recursion++;
947 progNode->ref();
948
949 Object globalObj = globalObject();
950 Object thisObj = globalObject();
951
952 if (!thisV.isNull()) {
953 // "this" must be an object... use same rules as Function.prototype.apply()
954 if (thisV.isA(NullType) || thisV.isA(UndefinedType))
955 thisObj = globalObject();
956 else {
957 thisObj = thisV.toObject(globExec);
958 }
959 }
960
961 Completion res;
962 if (globExec->hadException()) {
963 // the thisArg.toObject() conversion above might have thrown an exception - if so,
964 // propagate it back
965 res = Completion(Throw,globExec->exception());
966 }
967 else {
968 // execute the code
969 ExecState *exec1 = 0;
970 ContextImp *ctx = new ContextImp(globalObj, exec1, thisObj);
971 ExecState *newExec = new ExecState(m_interpreter,ctx);
972
973 res = progNode->execute(newExec);
974
975 delete newExec;
976 delete ctx;
977 }
978
979 if (progNode->deref())
980 delete progNode;
981 recursion--;
982
983#ifdef APPLE_CHANGES
984 unlockInterpreter();
985#endif
986 return res;
987}
988
989void InterpreterImp::setDebugger(Debugger *d)
990{
991 if (d)
992 d->detach(m_interpreter);
993 dbg = d;
994}
995
996// ------------------------------ InternalFunctionImp --------------------------
997
998const ClassInfo InternalFunctionImp::info = {"Function", 0, 0, 0};
999
1000InternalFunctionImp::InternalFunctionImp(FunctionPrototypeImp *funcProto)
1001 : ObjectImp(Object(funcProto))
1002{
1003}
1004
1005bool InternalFunctionImp::implementsHasInstance() const
1006{
1007 return true;
1008}
1009
1010Boolean InternalFunctionImp::hasInstance(ExecState *exec, const Value &value)
1011{
1012 if (value.type() != ObjectType)
1013 return Boolean(false);
1014
1015 Value prot = get(exec,prototypePropertyName);
1016 if (prot.type() != ObjectType && prot.type() != NullType) {
1017 Object err = Error::create(exec, TypeError, "Invalid prototype encountered "
1018 "in instanceof operation.");
1019 exec->setException(err);
1020 return Boolean(false);
1021 }
1022
1023 Object v = Object(static_cast<ObjectImp*>(value.imp()));
1024 while ((v = Object::dynamicCast(v.prototype())).imp()) {
1025 if (v.imp() == prot.imp())
1026 return Boolean(true);
1027 }
1028 return Boolean(false);
1029}
1030
1031// ------------------------------ global functions -----------------------------
1032
1033double KJS::roundValue(ExecState *exec, const Value &v)
1034{
1035 if (v.type() == UndefinedType) /* TODO: see below */
1036 return 0.0;
1037 Number n = v.toNumber(exec);
1038 if (n.value() == 0.0) /* TODO: -0, NaN, Inf */
1039 return 0.0;
1040 double d = floor(fabs(n.value()));
1041 if (n.value() < 0)
1042 d *= -1;
1043
1044 return d;
1045}
1046
1047#ifndef NDEBUG
1048#include <stdio.h>
1049void KJS::printInfo(ExecState *exec, const char *s, const Value &o, int lineno)
1050{
1051 if (o.isNull())
1052 fprintf(stderr, "KJS: %s: (null)", s);
1053 else {
1054 Value v = o;
1055
1056 UString name;
1057 switch ( v.type() ) {
1058 case UnspecifiedType:
1059 name = "Unspecified";
1060 break;
1061 case UndefinedType:
1062 name = "Undefined";
1063 break;
1064 case NullType:
1065 name = "Null";
1066 break;
1067 case BooleanType:
1068 name = "Boolean";
1069 break;
1070 case StringType:
1071 name = "String";
1072 break;
1073 case NumberType:
1074 name = "Number";
1075 break;
1076 case ObjectType:
1077 name = Object::dynamicCast(v).className();
1078 if (name.isNull())
1079 name = "(unknown class)";
1080 break;
1081 case ListType:
1082 name = "List";
1083 break;
1084 default:
1085 break;
1086 }
1087 UString vString = v.toString(exec);
1088 if ( vString.size() > 50 )
1089 vString = vString.substr( 0, 50 ) + "...";
1090 // Can't use two UString::ascii() in the same fprintf call
1091 CString tempString( vString.cstring() );
1092
1093 fprintf(stderr, "KJS: %s: %s : %s (%p)",
1094 s, tempString.c_str(), name.ascii(), (void*)v.imp());
1095
1096 if (lineno >= 0)
1097 fprintf(stderr, ", line %d\n",lineno);
1098 else
1099 fprintf(stderr, "\n");
1100 }
1101}
1102#endif
Note: See TracBrowser for help on using the repository browser.