Fixed baseline regression. Obvious of sites that have tables w/ backgrounds,
[WebKit-https.git] / JavaScriptCore / kjs / internal.cpp
1 // -*- c-basic-offset: 2 -*-
2 /*
3  *  This file is part of the KDE libraries
4  *  Copyright (C) 1999-2001 Harri Porten (porten@kde.org)
5  *  Copyright (C) 2001 Peter Kelly (pmk@post.com)
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
51 extern int kjsyyparse();
52
53 using namespace KJS;
54
55 namespace 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 // ------------------------------ UndefinedImp ---------------------------------
72
73 UndefinedImp *UndefinedImp::staticUndefined = 0;
74
75 Value UndefinedImp::toPrimitive(ExecState */*exec*/, Type) const
76 {
77   return Value((ValueImp*)this);
78 }
79
80 bool UndefinedImp::toBoolean(ExecState */*exec*/) const
81 {
82   return false;
83 }
84
85 double UndefinedImp::toNumber(ExecState */*exec*/) const
86 {
87   return NaN;
88 }
89
90 UString UndefinedImp::toString(ExecState */*exec*/) const
91 {
92   return "undefined";
93 }
94
95 Object UndefinedImp::toObject(ExecState *exec) const
96 {
97   Object err = Error::create(exec, TypeError, I18N_NOOP("Undefined value"));
98   exec->setException(err);
99   return err;
100 }
101
102 // ------------------------------ NullImp --------------------------------------
103
104 NullImp *NullImp::staticNull = 0;
105
106 Value NullImp::toPrimitive(ExecState */*exec*/, Type) const
107 {
108   return Value((ValueImp*)this);
109 }
110
111 bool NullImp::toBoolean(ExecState */*exec*/) const
112 {
113   return false;
114 }
115
116 double NullImp::toNumber(ExecState */*exec*/) const
117 {
118   return 0.0;
119 }
120
121 UString NullImp::toString(ExecState */*exec*/) const
122 {
123   return "null";
124 }
125
126 Object NullImp::toObject(ExecState *exec) const
127 {
128   Object err = Error::create(exec, TypeError, I18N_NOOP("Null value"));
129   exec->setException(err);
130   return err;
131 }
132
133 // ------------------------------ BooleanImp -----------------------------------
134
135 BooleanImp* BooleanImp::staticTrue = 0;
136 BooleanImp* BooleanImp::staticFalse = 0;
137
138 Value BooleanImp::toPrimitive(ExecState */*exec*/, Type) const
139 {
140   return Value((ValueImp*)this);
141 }
142
143 bool BooleanImp::toBoolean(ExecState */*exec*/) const
144 {
145   return val;
146 }
147
148 double BooleanImp::toNumber(ExecState */*exec*/) const
149 {
150   return val ? 1.0 : 0.0;
151 }
152
153 UString BooleanImp::toString(ExecState */*exec*/) const
154 {
155   return val ? "true" : "false";
156 }
157
158 Object BooleanImp::toObject(ExecState *exec) const
159 {
160   List args;
161   args.append(Boolean(const_cast<BooleanImp*>(this)));
162   return Object::dynamicCast(exec->interpreter()->builtinBoolean().construct(exec,args));
163 }
164
165 // ------------------------------ StringImp ------------------------------------
166
167 StringImp::StringImp(const UString& v)
168   : val(v)
169 {
170 }
171
172 Value StringImp::toPrimitive(ExecState */*exec*/, Type) const
173 {
174   return Value((ValueImp*)this);
175 }
176
177 bool StringImp::toBoolean(ExecState */*exec*/) const
178 {
179   return (val.size() > 0);
180 }
181
182 double StringImp::toNumber(ExecState */*exec*/) const
183 {
184   return val.toDouble();
185 }
186
187 UString StringImp::toString(ExecState */*exec*/) const
188 {
189   return val;
190 }
191
192 Object StringImp::toObject(ExecState *exec) const
193 {
194   List args;
195   args.append(String(const_cast<StringImp*>(this)));
196   return Object::dynamicCast(exec->interpreter()->builtinString().construct(exec,args));
197 }
198
199 // ------------------------------ NumberImp ------------------------------------
200
201 NumberImp::NumberImp(double v)
202   : val(v)
203 {
204 }
205
206 Value NumberImp::toPrimitive(ExecState *, Type) const
207 {
208   return Number((NumberImp*)this);
209 }
210
211 bool NumberImp::toBoolean(ExecState *) const
212 {
213   return !((val == 0) /* || (iVal() == N0) */ || isNaN(val));
214 }
215
216 double NumberImp::toNumber(ExecState *) const
217 {
218   return val;
219 }
220
221 UString NumberImp::toString(ExecState *) const
222 {
223   return UString::from(val);
224 }
225
226 Object NumberImp::toObject(ExecState *exec) const
227 {
228   List args;
229   args.append(Number(const_cast<NumberImp*>(this)));
230   return Object::dynamicCast(exec->interpreter()->builtinNumber().construct(exec,args));
231 }
232
233 // ------------------------------ ReferenceImp ---------------------------------
234
235 ReferenceImp::ReferenceImp(const Value& v, const UString& p)
236   : base(v.imp()), prop(p)
237 {
238 }
239
240 void ReferenceImp::mark()
241 {
242   ValueImp::mark();
243   if (base && !base->marked())
244     base->mark();
245 }
246
247 Value ReferenceImp::toPrimitive(ExecState */*exec*/, Type /*preferredType*/) const
248 {
249   // invalid for Reference
250   assert(false);
251   return Value();
252 }
253
254 bool ReferenceImp::toBoolean(ExecState */*exec*/) const
255 {
256   // invalid for Reference
257   assert(false);
258   return false;
259 }
260
261 double ReferenceImp::toNumber(ExecState */*exec*/) const
262 {
263   // invalid for Reference
264   assert(false);
265   return 0;
266 }
267
268 UString ReferenceImp::toString(ExecState */*exec*/) const
269 {
270   // invalid for Reference
271   assert(false);
272   return UString::null;
273 }
274
275 Object ReferenceImp::toObject(ExecState */*exec*/) const
276 {
277   // invalid for Reference
278   assert(false);
279   return Object();
280 }
281
282 // ------------------------------ LabelStack -----------------------------------
283
284 LabelStack::LabelStack(const LabelStack &other)
285 {
286   tos = 0;
287   *this = other;
288 }
289
290 LabelStack &LabelStack::operator=(const LabelStack &other)
291 {
292   clear();
293   tos = 0;
294   StackElem *cur = 0;
295   StackElem *se = other.tos;
296   while (se) {
297     StackElem *newPrev = new StackElem;
298     newPrev->prev = 0;
299     newPrev->id = se->id;
300     if (cur)
301       cur->prev = newPrev;
302     else
303       tos = newPrev;
304     cur = newPrev;
305     se = se->prev;
306   }
307   return *this;
308 }
309
310 bool LabelStack::push(const UString &id)
311 {
312   if (id.isEmpty() || contains(id))
313     return false;
314
315   StackElem *newtos = new StackElem;
316   newtos->id = id;
317   newtos->prev = tos;
318   tos = newtos;
319   return true;
320 }
321
322 bool LabelStack::contains(const UString &id) const
323 {
324   if (id.isEmpty())
325     return true;
326
327   for (StackElem *curr = tos; curr; curr = curr->prev)
328     if (curr->id == id)
329       return true;
330
331   return false;
332 }
333
334 void LabelStack::pop()
335 {
336   if (tos) {
337     StackElem *prev = tos->prev;
338     delete tos;
339     tos = prev;
340   }
341 }
342
343 LabelStack::~LabelStack()
344 {
345   clear();
346 }
347
348 void LabelStack::clear()
349 {
350   StackElem *prev;
351
352   while (tos) {
353     prev = tos->prev;
354     delete tos;
355     tos = prev;
356   }
357 }
358
359 // ------------------------------ CompletionImp --------------------------------
360
361 CompletionImp::CompletionImp(ComplType c, const Value& v, const UString& t)
362   : comp(c), val(v.imp()), tar(t)
363 {
364 }
365
366 CompletionImp::~CompletionImp()
367 {
368 }
369
370 void CompletionImp::mark()
371 {
372   ValueImp::mark();
373
374   if (val && !val->marked())
375     val->mark();
376 }
377
378 Value CompletionImp::toPrimitive(ExecState */*exec*/, Type /*preferredType*/) const
379 {
380   // invalid for Completion
381   assert(false);
382   return Value();
383 }
384
385 bool CompletionImp::toBoolean(ExecState */*exec*/) const
386 {
387   // invalid for Completion
388   assert(false);
389   return false;
390 }
391
392 double CompletionImp::toNumber(ExecState */*exec*/) const
393 {
394   // invalid for Completion
395   assert(false);
396   return 0;
397 }
398
399 UString CompletionImp::toString(ExecState */*exec*/) const
400 {
401   // invalid for Completion
402   assert(false);
403   return UString::null;
404 }
405
406 Object CompletionImp::toObject(ExecState */*exec*/) const
407 {
408   // invalid for Completion
409   assert(false);
410   return Object();
411 }
412
413 // ------------------------------ ListImp --------------------------------------
414
415 #ifdef KJS_DEBUG_MEM
416 int ListImp::count = 0;
417 #endif
418
419 Value ListImp::toPrimitive(ExecState */*exec*/, Type /*preferredType*/) const
420 {
421   // invalid for List
422   assert(false);
423   return Value();
424 }
425
426 bool ListImp::toBoolean(ExecState */*exec*/) const
427 {
428   // invalid for List
429   assert(false);
430   return false;
431 }
432
433 double ListImp::toNumber(ExecState */*exec*/) const
434 {
435   // invalid for List
436   assert(false);
437   return 0;
438 }
439
440 UString ListImp::toString(ExecState */*exec*/) const
441 {
442   // invalid for List
443   assert(false);
444   return UString::null;
445 }
446
447 Object ListImp::toObject(ExecState */*exec*/) const
448 {
449   // invalid for List
450   assert(false);
451   return Object();
452 }
453
454 ListImp::ListImp()
455 {
456 #ifdef KJS_DEBUG_MEM
457   count++;
458 #endif
459
460   hook = new ListNode(Null(), 0L, 0L);
461   hook->next = hook;
462   hook->prev = hook;
463   //fprintf(stderr,"ListImp::ListImp %p hook=%p\n",this,hook);
464 }
465
466 ListImp::~ListImp()
467 {
468   //fprintf(stderr,"ListImp::~ListImp %p\n",this);
469 #ifdef KJS_DEBUG_MEM
470   count--;
471 #endif
472
473   clear();
474   delete hook;
475
476   if ( emptyList == this )
477     emptyList = 0L;
478 }
479
480 void ListImp::mark()
481 {
482   ListNode *n = hook->next;
483   while (n != hook) {
484     if (!n->member->marked())
485       n->member->mark();
486     n = n->next;
487   }
488   ValueImp::mark();
489 }
490
491 void ListImp::append(const Value& obj)
492 {
493   ListNode *n = new ListNode(obj, hook->prev, hook);
494   hook->prev->next = n;
495   hook->prev = n;
496 }
497
498 void ListImp::prepend(const Value& obj)
499 {
500   ListNode *n = new ListNode(obj, hook, hook->next);
501   hook->next->prev = n;
502   hook->next = n;
503 }
504
505 void ListImp::appendList(const List& lst)
506 {
507   ListIterator it = lst.begin();
508   ListIterator e = lst.end();
509   while(it != e) {
510     append(*it);
511     ++it;
512   }
513 }
514
515 void ListImp::prependList(const List& lst)
516 {
517   ListIterator it = lst.end();
518   ListIterator e = lst.begin();
519   while(it != e) {
520     --it;
521     prepend(*it);
522   }
523 }
524
525 void ListImp::removeFirst()
526 {
527   erase(hook->next);
528 }
529
530 void ListImp::removeLast()
531 {
532   erase(hook->prev);
533 }
534
535 void ListImp::remove(const Value &obj)
536 {
537   if (obj.isNull())
538     return;
539   ListNode *n = hook->next;
540   while (n != hook) {
541     if (n->member == obj.imp()) {
542       erase(n);
543       return;
544     }
545     n = n->next;
546   }
547 }
548
549 void ListImp::clear()
550 {
551   ListNode *n = hook->next;
552   while (n != hook) {
553     n = n->next;
554     delete n->prev;
555   }
556
557   hook->next = hook;
558   hook->prev = hook;
559 }
560
561 ListImp *ListImp::copy() const
562 {
563   ListImp* newList = new ListImp;
564
565   ListIterator e = end();
566   ListIterator it = begin();
567
568   while(it != e) {
569     newList->append(*it);
570     ++it;
571   }
572
573   //fprintf( stderr, "ListImp::copy returning newList=%p\n", newList );
574   return newList;
575 }
576
577 void ListImp::erase(ListNode *n)
578 {
579   if (n != hook) {
580     n->next->prev = n->prev;
581     n->prev->next = n->next;
582     delete n;
583   }
584 }
585
586 bool ListImp::isEmpty() const
587 {
588   return (hook->prev == hook);
589 }
590
591 int ListImp::size() const
592 {
593   int s = 0;
594   ListNode *node = hook;
595   while ((node = node->next) != hook)
596     s++;
597
598   return s;
599 }
600
601 Value ListImp::at(int i) const
602 {
603   if (i < 0 || i >= size())
604     return Undefined();
605
606   ListIterator it = begin();
607   int j = 0;
608   while ((j++ < i))
609     it++;
610
611   return *it;
612 }
613
614 ListImp *ListImp::emptyList = 0L;
615
616 ListImp *ListImp::empty()
617 {
618   if (!emptyList)
619     emptyList = new ListImp();
620   return emptyList;
621 }
622
623 // ------------------------------ ContextImp -----------------------------------
624
625
626 // ECMA 10.2
627 ContextImp::ContextImp(Object &glob, ExecState *exec, Object &thisV, CodeType type,
628                        ContextImp *_callingContext, FunctionImp *func, const List &args)
629 {
630   codeType = type;
631   callingCon = _callingContext;
632
633   // create and initialize activation object (ECMA 10.1.6)
634   if (type == FunctionCode || type == AnonymousCode ) {
635     activation = Object(new ActivationImp(exec,func,args));
636     variable = activation;
637   } else {
638     activation = Object();
639     variable = glob;
640   }
641
642   // ECMA 10.2
643   switch(type) {
644     case EvalCode:
645       if (callingCon) {
646         scope = callingCon->scopeChain().copy();
647         variable = callingCon->variableObject();
648         thisVal = callingCon->thisValue();
649         break;
650       } // else same as GlobalCode
651     case GlobalCode:
652       scope = List();
653       scope.append(glob);
654       thisVal = Object(static_cast<ObjectImp*>(glob.imp()));
655       break;
656     case FunctionCode:
657     case AnonymousCode:
658       if (type == FunctionCode) {
659         scope = func->scope().copy();
660         scope.prepend(activation);
661       } else {
662         scope = List();
663         scope.append(activation);
664         scope.append(glob);
665       }
666       variable = activation; // TODO: DontDelete ? (ECMA 10.2.3)
667       thisVal = thisV;
668       break;
669     }
670
671 }
672
673 ContextImp::~ContextImp()
674 {
675 }
676
677 void ContextImp::pushScope(const Object &s)
678 {
679   scope.prepend(s);
680 }
681
682 void ContextImp::popScope()
683 {
684   scope.removeFirst();
685 }
686
687 // ------------------------------ Parser ---------------------------------------
688
689 ProgramNode *Parser::progNode = 0;
690 int Parser::sid = 0;
691 #ifdef APPLE_CHANGES
692 static pthread_mutex_t parserLock = {_PTHREAD_MUTEX_SIG_init, {}};
693 #endif
694
695 ProgramNode *Parser::parse(const UChar *code, unsigned int length, int *sourceId,
696                            int *errLine, UString *errMsg)
697 {
698 #ifdef APPLE_CHANGES
699   pthread_mutex_lock(&parserLock);
700 #endif
701   if (errLine)
702     *errLine = -1;
703   if (errMsg)
704     *errMsg = 0;
705
706   Lexer::curr()->setCode(code, length);
707   progNode = 0;
708   sid++;
709   if (sourceId)
710     *sourceId = sid;
711   // Enable this (and the #define YYDEBUG in grammar.y) to debug a parse error
712   //extern int kjsyydebug;
713   //kjsyydebug=1;
714   int parseError = kjsyyparse();
715   ProgramNode *prog = progNode;
716   progNode = 0;
717   sid = -1;
718
719   if (parseError) {
720     int eline = Lexer::curr()->lineNo();
721     if (errLine)
722       *errLine = eline;
723     if (errMsg)
724       *errMsg = "Parse error at line " + UString::from(eline);
725 #ifndef NDEBUG
726     fprintf(stderr, "KJS: JavaScript parse error at line %d.\n", eline);
727 #endif
728     delete prog;
729 #ifdef APPLE_CHANGES
730     pthread_mutex_unlock(&parserLock);
731 #endif
732     return 0;
733   }
734
735 #ifdef APPLE_CHANGES
736   pthread_mutex_unlock(&parserLock);
737 #endif
738   return prog;
739 }
740
741 // ------------------------------ InterpreterImp -------------------------------
742
743 InterpreterImp* InterpreterImp::s_hook = 0L;
744
745 void InterpreterImp::globalInit()
746 {
747   //fprintf( stderr, "InterpreterImp::globalInit()\n" );
748   UndefinedImp::staticUndefined = new UndefinedImp();
749   UndefinedImp::staticUndefined->ref();
750   NullImp::staticNull = new NullImp();
751   NullImp::staticNull->ref();
752   BooleanImp::staticTrue = new BooleanImp(true);
753   BooleanImp::staticTrue->ref();
754   BooleanImp::staticFalse = new BooleanImp(false);
755   BooleanImp::staticFalse->ref();
756 }
757
758 void InterpreterImp::globalClear()
759 {
760   //fprintf( stderr, "InterpreterImp::globalClear()\n" );
761   UndefinedImp::staticUndefined->deref();
762   UndefinedImp::staticUndefined->setGcAllowed();
763   UndefinedImp::staticUndefined = 0L;
764   NullImp::staticNull->deref();
765   NullImp::staticNull->setGcAllowed();
766   NullImp::staticNull = 0L;
767   BooleanImp::staticTrue->deref();
768   BooleanImp::staticTrue->setGcAllowed();
769   BooleanImp::staticTrue = 0L;
770   BooleanImp::staticFalse->deref();
771   BooleanImp::staticFalse->setGcAllowed();
772   BooleanImp::staticFalse = 0L;
773 }
774
775 InterpreterImp::InterpreterImp(Interpreter *interp, const Object &glob)
776 {
777   // add this interpreter to the global chain
778   // as a root set for garbage collection
779 #ifdef APPLE_CHANGES
780   Collector::lock();
781 #endif
782   if (s_hook) {
783     prev = s_hook;
784     next = s_hook->next;
785     s_hook->next->prev = this;
786     s_hook->next = this;
787   } else {
788     // This is the first interpreter
789     s_hook = next = prev = this;
790     globalInit();
791   }
792 #ifdef APPLE_CHANGES
793   Collector::unlock();
794 #endif
795
796   m_interpreter = interp;
797   global = glob;
798   globExec = new ExecState(m_interpreter,0);
799   dbg = 0;
800   m_compatMode = Interpreter::NativeMode;
801
802   // initialize properties of the global object
803   initGlobalObject();
804
805   recursion = 0;
806 }
807
808 void InterpreterImp::initGlobalObject()
809 {
810   // Contructor prototype objects (Object.prototype, Array.prototype etc)
811
812   FunctionPrototypeImp *funcProto = new FunctionPrototypeImp(globExec);
813   b_FunctionPrototype = Object(funcProto);
814   ObjectPrototypeImp *objProto = new ObjectPrototypeImp(globExec,funcProto);
815   b_ObjectPrototype = Object(objProto);
816   funcProto->setPrototype(b_ObjectPrototype);
817
818   ArrayPrototypeImp *arrayProto = new ArrayPrototypeImp(globExec,objProto);
819   b_ArrayPrototype = Object(arrayProto);
820   StringPrototypeImp *stringProto = new StringPrototypeImp(globExec,objProto);
821   b_StringPrototype = Object(stringProto);
822   BooleanPrototypeImp *booleanProto = new BooleanPrototypeImp(globExec,objProto,funcProto);
823   b_BooleanPrototype = Object(booleanProto);
824   NumberPrototypeImp *numberProto = new NumberPrototypeImp(globExec,objProto,funcProto);
825   b_NumberPrototype = Object(numberProto);
826   DatePrototypeImp *dateProto = new DatePrototypeImp(globExec,objProto);
827   b_DatePrototype = Object(dateProto);
828   RegExpPrototypeImp *regexpProto = new RegExpPrototypeImp(globExec,objProto,funcProto);
829   b_RegExpPrototype = Object(regexpProto);
830   ErrorPrototypeImp *errorProto = new ErrorPrototypeImp(globExec,objProto,funcProto);
831   b_ErrorPrototype = Object(errorProto);
832
833   static_cast<ObjectImp*>(global.imp())->setPrototype(b_ObjectPrototype);
834
835   // Constructors (Object, Array, etc.)
836
837   ObjectObjectImp *objectObj = new ObjectObjectImp(globExec,objProto,funcProto);
838   b_Object = Object(objectObj);
839   FunctionObjectImp *funcObj = new FunctionObjectImp(globExec,funcProto);
840   b_Function = Object(funcObj);
841   ArrayObjectImp *arrayObj = new ArrayObjectImp(globExec,funcProto,arrayProto);
842   b_Array = Object(arrayObj);
843   StringObjectImp *stringObj = new StringObjectImp(globExec,funcProto,stringProto);
844   b_String = Object(stringObj);
845   BooleanObjectImp *booleanObj = new BooleanObjectImp(globExec,funcProto,booleanProto);
846   b_Boolean = Object(booleanObj);
847   NumberObjectImp *numberObj = new NumberObjectImp(globExec,funcProto,numberProto);
848   b_Number = Object(numberObj);
849   DateObjectImp *dateObj = new DateObjectImp(globExec,funcProto,dateProto);
850   b_Date = Object(dateObj);
851   RegExpObjectImp *regexpObj = new RegExpObjectImp(globExec,regexpProto,funcProto);
852   b_RegExp = Object(regexpObj);
853   ErrorObjectImp *errorObj = new ErrorObjectImp(globExec,funcProto,errorProto);
854   b_Error = Object(errorObj);
855
856   // Error object prototypes
857   b_evalErrorPrototype = Object(new NativeErrorPrototypeImp(globExec,errorProto,EvalError,
858                                                             "EvalError","EvalError"));
859   b_rangeErrorPrototype = Object(new NativeErrorPrototypeImp(globExec,errorProto,RangeError,
860                                                             "RangeError","RangeError"));
861   b_referenceErrorPrototype = Object(new NativeErrorPrototypeImp(globExec,errorProto,ReferenceError,
862                                                             "ReferenceError","ReferenceError"));
863   b_syntaxErrorPrototype = Object(new NativeErrorPrototypeImp(globExec,errorProto,SyntaxError,
864                                                             "SyntaxError","SyntaxError"));
865   b_typeErrorPrototype = Object(new NativeErrorPrototypeImp(globExec,errorProto,TypeError,
866                                                             "TypeError","TypeError"));
867   b_uriErrorPrototype = Object(new NativeErrorPrototypeImp(globExec,errorProto,URIError,
868                                                             "URIError","URIError"));
869
870   // Error objects
871   b_evalError = Object(new NativeErrorImp(globExec,funcProto,b_evalErrorPrototype));
872   b_rangeError = Object(new NativeErrorImp(globExec,funcProto,b_rangeErrorPrototype));
873   b_referenceError = Object(new NativeErrorImp(globExec,funcProto,b_referenceErrorPrototype));
874   b_syntaxError = Object(new NativeErrorImp(globExec,funcProto,b_syntaxErrorPrototype));
875   b_typeError = Object(new NativeErrorImp(globExec,funcProto,b_typeErrorPrototype));
876   b_uriError = Object(new NativeErrorImp(globExec,funcProto,b_uriErrorPrototype));
877
878   // ECMA 15.3.4.1
879   funcProto->put(globExec,"constructor", b_Function, DontEnum);
880
881   global.put(globExec,"Object", b_Object, DontEnum);
882   global.put(globExec,"Function", b_Function, DontEnum);
883   global.put(globExec,"Array", b_Array, DontEnum);
884   global.put(globExec,"Boolean", b_Boolean, DontEnum);
885   global.put(globExec,"String", b_String, DontEnum);
886   global.put(globExec,"Number", b_Number, DontEnum);
887   global.put(globExec,"Date", b_Date, DontEnum);
888   global.put(globExec,"RegExp", b_RegExp, DontEnum);
889   global.put(globExec,"Error", b_Error, DontEnum);
890   // Using Internal for those to have something != 0
891   // (see kjs_window). Maybe DontEnum would be ok too ?
892   global.put(globExec,"EvalError",b_evalError, Internal);
893   global.put(globExec,"RangeError",b_rangeError, Internal);
894   global.put(globExec,"ReferenceError",b_referenceError, Internal);
895   global.put(globExec,"SyntaxError",b_syntaxError, Internal);
896   global.put(globExec,"TypeError",b_typeError, Internal);
897   global.put(globExec,"URIError",b_uriError, Internal);
898
899   // Set the "constructor" property of all builtin constructors
900   objProto->put(globExec, "constructor", b_Object, DontEnum | DontDelete | ReadOnly);
901   funcProto->put(globExec, "constructor", b_Function, DontEnum | DontDelete | ReadOnly);
902   arrayProto->put(globExec, "constructor", b_Array, DontEnum | DontDelete | ReadOnly);
903   booleanProto->put(globExec, "constructor", b_Boolean, DontEnum | DontDelete | ReadOnly);
904   stringProto->put(globExec, "constructor", b_String, DontEnum | DontDelete | ReadOnly);
905   numberProto->put(globExec, "constructor", b_Number, DontEnum | DontDelete | ReadOnly);
906   dateProto->put(globExec, "constructor", b_Date, DontEnum | DontDelete | ReadOnly);
907   regexpProto->put(globExec, "constructor", b_RegExp, DontEnum | DontDelete | ReadOnly);
908   errorProto->put(globExec, "constructor", b_Error, DontEnum | DontDelete | ReadOnly);
909   b_evalErrorPrototype.put(globExec, "constructor", b_evalError, DontEnum | DontDelete | ReadOnly);
910   b_rangeErrorPrototype.put(globExec, "constructor", b_rangeError, DontEnum | DontDelete | ReadOnly);
911   b_referenceErrorPrototype.put(globExec, "constructor", b_referenceError, DontEnum | DontDelete | ReadOnly);
912   b_syntaxErrorPrototype.put(globExec, "constructor", b_syntaxError, DontEnum | DontDelete | ReadOnly);
913   b_typeErrorPrototype.put(globExec, "constructor", b_typeError, DontEnum | DontDelete | ReadOnly);
914   b_uriErrorPrototype.put(globExec, "constructor", b_uriError, DontEnum | DontDelete | ReadOnly);
915
916   // built-in values
917   global.put(globExec,"NaN",        Number(NaN), DontEnum);
918   global.put(globExec,"Infinity",   Number(Inf), DontEnum);
919   global.put(globExec,"undefined",  Undefined(), DontEnum);
920
921   // built-in functions
922   global.put(globExec,"eval",       Object(new GlobalFuncImp(globExec,funcProto,GlobalFuncImp::Eval,       1)), DontEnum);
923   global.put(globExec,"parseInt",   Object(new GlobalFuncImp(globExec,funcProto,GlobalFuncImp::ParseInt,   2)), DontEnum);
924   global.put(globExec,"parseFloat", Object(new GlobalFuncImp(globExec,funcProto,GlobalFuncImp::ParseFloat, 1)), DontEnum);
925   global.put(globExec,"isNaN",      Object(new GlobalFuncImp(globExec,funcProto,GlobalFuncImp::IsNaN,      1)), DontEnum);
926   global.put(globExec,"isFinite",   Object(new GlobalFuncImp(globExec,funcProto,GlobalFuncImp::IsFinite,   1)), DontEnum);
927   global.put(globExec,"escape",     Object(new GlobalFuncImp(globExec,funcProto,GlobalFuncImp::Escape,     1)), DontEnum);
928   global.put(globExec,"unescape",   Object(new GlobalFuncImp(globExec,funcProto,GlobalFuncImp::UnEscape,   1)), DontEnum);
929
930   // built-in objects
931   global.put(globExec,"Math", Object(new MathObjectImp(globExec,objProto)), DontEnum);
932 }
933
934 InterpreterImp::~InterpreterImp()
935 {
936   if (dbg)
937     dbg->detach(m_interpreter);
938   delete globExec;
939   globExec = 0L;
940   clear();
941 }
942
943 void InterpreterImp::clear()
944 {
945   //fprintf(stderr,"InterpreterImp::clear\n");
946   // remove from global chain (see init())
947 #ifdef APPLE_CHANGES
948   Collector::lock();
949 #endif
950   next->prev = prev;
951   prev->next = next;
952   s_hook = next;
953   if (s_hook == this)
954   {
955     // This was the last interpreter
956     s_hook = 0L;
957     globalClear();
958   }
959 #ifdef APPLE_CHANGES
960   Collector::unlock();
961 #endif
962 }
963
964 void InterpreterImp::mark()
965 {
966   //if (exVal && !exVal->marked())
967   //  exVal->mark();
968   //if (retVal && !retVal->marked())
969   //  retVal->mark();
970   if (UndefinedImp::staticUndefined && !UndefinedImp::staticUndefined->marked())
971     UndefinedImp::staticUndefined->mark();
972   if (NullImp::staticNull && !NullImp::staticNull->marked())
973     NullImp::staticNull->mark();
974   if (BooleanImp::staticTrue && !BooleanImp::staticTrue->marked())
975     BooleanImp::staticTrue->mark();
976   if (BooleanImp::staticFalse && !BooleanImp::staticFalse->marked())
977     BooleanImp::staticFalse->mark();
978   if (ListImp::emptyList && !ListImp::emptyList->marked())
979     ListImp::emptyList->mark();
980   //fprintf( stderr, "InterpreterImp::mark this=%p global.imp()=%p\n", this, global.imp() );
981   if (global.imp())
982     global.imp()->mark();
983   if (m_interpreter)
984     m_interpreter->mark();
985 }
986
987 bool InterpreterImp::checkSyntax(const UString &code)
988 {
989   // Parser::parse() returns 0 in a syntax error occurs, so we just check for that
990   ProgramNode *progNode = Parser::parse(code.data(),code.size(),0,0,0);
991   bool ok = (progNode != 0);
992   delete progNode;
993   return ok;
994 }
995
996 Completion InterpreterImp::evaluate(const UString &code, const Value &thisV)
997 {
998   // prevent against infinite recursion
999   if (recursion >= 20) {
1000     return Completion(Throw,Error::create(globExec,GeneralError,"Recursion too deep"));
1001   }
1002
1003   // parse the source code
1004   int sid;
1005   int errLine;
1006   UString errMsg;
1007   ProgramNode *progNode = Parser::parse(code.data(),code.size(),&sid,&errLine,&errMsg);
1008
1009   // notify debugger that source has been parsed
1010   if (dbg) {
1011     bool cont = dbg->sourceParsed(globExec,sid,code,errLine);
1012     if (!cont)
1013       return Completion(Break);
1014   }
1015
1016   // no program node means a syntax occurred
1017   if (!progNode) {
1018     Object err = Error::create(globExec,SyntaxError,errMsg.ascii(),errLine);
1019     err.put(globExec,"sid",Number(sid));
1020     return Completion(Throw,err);
1021   }
1022
1023   globExec->clearException();
1024
1025   recursion++;
1026   progNode->ref();
1027
1028   Object globalObj = globalObject();
1029   Object thisObj = globalObject();
1030
1031   if (!thisV.isNull()) {
1032     // "this" must be an object... use same rules as Function.prototype.apply()
1033     if (thisV.isA(NullType) || thisV.isA(UndefinedType))
1034       thisObj = globalObject();
1035     else {
1036       thisObj = thisV.toObject(globExec);
1037     }
1038   }
1039
1040   Completion res;
1041   if (globExec->hadException()) {
1042     // the thisArg.toObject() conversion above might have thrown an exception - if so,
1043     // propagate it back
1044     res = Completion(Throw,globExec->exception());
1045   }
1046   else {
1047     // execute the code
1048     ExecState *exec1 = 0;
1049     ContextImp *ctx = new ContextImp(globalObj, exec1, thisObj);
1050     ExecState *newExec = new ExecState(m_interpreter,ctx);
1051
1052     res = progNode->execute(newExec);
1053
1054     delete newExec;
1055     delete ctx;
1056   }
1057
1058   if (progNode->deref())
1059     delete progNode;
1060   recursion--;
1061
1062   return res;
1063 }
1064
1065 void InterpreterImp::setDebugger(Debugger *d)
1066 {
1067   if (d)
1068     d->detach(m_interpreter);
1069   dbg = d;
1070 }
1071
1072 // ------------------------------ InternalFunctionImp --------------------------
1073
1074 const ClassInfo InternalFunctionImp::info = {"Function", 0, 0, 0};
1075
1076 InternalFunctionImp::InternalFunctionImp(FunctionPrototypeImp *funcProto)
1077   : ObjectImp(Object(funcProto))
1078 {
1079 }
1080
1081 bool InternalFunctionImp::implementsHasInstance() const
1082 {
1083   return true;
1084 }
1085
1086 Boolean InternalFunctionImp::hasInstance(ExecState *exec, const Value &value)
1087 {
1088   if (value.type() != ObjectType)
1089     return Boolean(false);
1090
1091   Value prot = get(exec,"prototype");
1092   if (prot.type() != ObjectType && prot.type() != NullType) {
1093     Object err = Error::create(exec, TypeError, "Invalid prototype encountered "
1094                                "in instanceof operation.");
1095     exec->setException(err);
1096     return Boolean(false);
1097   }
1098
1099   Object v = Object(static_cast<ObjectImp*>(value.imp()));
1100   while ((v = Object::dynamicCast(v.prototype())).imp()) {
1101     if (v.imp() == prot.imp())
1102       return Boolean(true);
1103   }
1104   return Boolean(false);
1105 }
1106
1107 // ------------------------------ global functions -----------------------------
1108
1109 double KJS::roundValue(ExecState *exec, const Value &v)
1110 {
1111   if (v.type() == UndefinedType) /* TODO: see below */
1112     return 0.0;
1113   Number n = v.toNumber(exec);
1114   if (n.value() == 0.0)   /* TODO: -0, NaN, Inf */
1115     return 0.0;
1116   double d = floor(fabs(n.value()));
1117   if (n.value() < 0)
1118     d *= -1;
1119
1120   return d;
1121 }
1122
1123 #ifndef NDEBUG
1124 #include <stdio.h>
1125 void KJS::printInfo(ExecState *exec, const char *s, const Value &o, int lineno)
1126 {
1127   if (o.isNull())
1128     fprintf(stderr, "KJS: %s: (null)", s);
1129   else {
1130     Value v = o;
1131     if (o.isA(ReferenceType))
1132       v = o.getValue(exec);
1133
1134     UString name;
1135     switch ( v.type() ) {
1136     case UnspecifiedType:
1137       name = "Unspecified";
1138       break;
1139     case UndefinedType:
1140       name = "Undefined";
1141       break;
1142     case NullType:
1143       name = "Null";
1144       break;
1145     case BooleanType:
1146       name = "Boolean";
1147       break;
1148     case StringType:
1149       name = "String";
1150       break;
1151     case NumberType:
1152       name = "Number";
1153       break;
1154     case ObjectType:
1155       name = Object::dynamicCast(v).className();
1156       if (name.isNull())
1157         name = "(unknown class)";
1158       break;
1159     case ReferenceType:
1160       name = "Reference";
1161       break;
1162     case ListType:
1163       name = "List";
1164       break;
1165     case CompletionType:
1166       name = "Completion";
1167       break;
1168     default:
1169       break;
1170     }
1171     UString vString = v.toString(exec);
1172     if ( vString.size() > 50 )
1173       vString = vString.substr( 0, 50 ) + "...";
1174     // Can't use two UString::ascii() in the same fprintf call
1175     CString tempString( vString.cstring() );
1176
1177     fprintf(stderr, "KJS: %s: %s : %s (%p)",
1178             s, tempString.c_str(), name.ascii(), (void*)v.imp());
1179
1180     if (lineno >= 0)
1181       fprintf(stderr, ", line %d\n",lineno);
1182     else
1183       fprintf(stderr, "\n");
1184     if (!o.isNull())
1185       if (o.isA(ReferenceType)) {
1186         fprintf(stderr, "KJS: Was property '%s'\n", o.getPropertyName(exec).ascii());
1187         printInfo(exec,"of", o.getBase(exec));
1188       }
1189   }
1190 }
1191 #endif