kjs Library API Documentation

internal.cpp

00001 // -*- c-basic-offset: 2 -*-
00002 /*
00003  *  This file is part of the KDE libraries
00004  *  Copyright (C) 1999-2001 Harri Porten (porten@kde.org)
00005  *  Copyright (C) 2001 Peter Kelly (pmk@post.com)
00006  *
00007  *  This library is free software; you can redistribute it and/or
00008  *  modify it under the terms of the GNU Lesser General Public
00009  *  License as published by the Free Software Foundation; either
00010  *  version 2 of the License, or (at your option) any later version.
00011  *
00012  *  This library is distributed in the hope that it will be useful,
00013  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015  *  Lesser General Public License for more details.
00016  *
00017  *  You should have received a copy of the GNU Lesser General Public License
00018  *  along with this library; see the file COPYING.LIB.  If not, write to
00019  *  the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
00020  *  Boston, MA 02111-1307, USA.
00021  *
00022  */
00023 
00024 #include <stdio.h>
00025 #include <math.h>
00026 #include <assert.h>
00027 #ifndef NDEBUG
00028 #include <strings.h>      // for strdup
00029 #endif
00030 
00031 #include "array_object.h"
00032 #include "bool_object.h"
00033 #include "collector.h"
00034 #include "date_object.h"
00035 #include "debugger.h"
00036 #include "error_object.h"
00037 #include "function_object.h"
00038 #include "internal.h"
00039 #include "lexer.h"
00040 #include "math_object.h"
00041 #include "nodes.h"
00042 #include "number_object.h"
00043 #include "object.h"
00044 #include "object_object.h"
00045 #include "operations.h"
00046 #include "regexp_object.h"
00047 #include "string_object.h"
00048 
00049 #define I18N_NOOP(s) s
00050 
00051 extern int kjsyyparse();
00052 
00053 using namespace KJS;
00054 
00055 namespace KJS {
00056 #ifdef WORDS_BIGENDIAN
00057   unsigned char NaN_Bytes[] = { 0x7f, 0xf8, 0, 0, 0, 0, 0, 0 };
00058   unsigned char Inf_Bytes[] = { 0x7f, 0xf0, 0, 0, 0, 0, 0, 0 };
00059 #elif defined(arm)
00060   unsigned char NaN_Bytes[] = { 0, 0, 0xf8, 0x7f, 0, 0, 0, 0 };
00061   unsigned char Inf_Bytes[] = { 0, 0, 0xf0, 0x7f, 0, 0, 0, 0 };
00062 #else
00063   unsigned char NaN_Bytes[] = { 0, 0, 0, 0, 0, 0, 0xf8, 0x7f };
00064   unsigned char Inf_Bytes[] = { 0, 0, 0, 0, 0, 0, 0xf0, 0x7f };
00065 #endif
00066 
00067   const double NaN = *(const double*) NaN_Bytes;
00068   const double Inf = *(const double*) Inf_Bytes;
00069 };
00070 
00071 // ------------------------------ UndefinedImp ---------------------------------
00072 
00073 UndefinedImp *UndefinedImp::staticUndefined = 0;
00074 
00075 Value UndefinedImp::toPrimitive(ExecState */*exec*/, Type) const
00076 {
00077   return Value((ValueImp*)this);
00078 }
00079 
00080 bool UndefinedImp::toBoolean(ExecState */*exec*/) const
00081 {
00082   return false;
00083 }
00084 
00085 double UndefinedImp::toNumber(ExecState */*exec*/) const
00086 {
00087   return NaN;
00088 }
00089 
00090 UString UndefinedImp::toString(ExecState */*exec*/) const
00091 {
00092   return "undefined";
00093 }
00094 
00095 Object UndefinedImp::toObject(ExecState *exec) const
00096 {
00097   Object err = Error::create(exec, TypeError, I18N_NOOP("Undefined value"));
00098   exec->setException(err);
00099   return err;
00100 }
00101 
00102 // ------------------------------ NullImp --------------------------------------
00103 
00104 NullImp *NullImp::staticNull = 0;
00105 
00106 Value NullImp::toPrimitive(ExecState */*exec*/, Type) const
00107 {
00108   return Value((ValueImp*)this);
00109 }
00110 
00111 bool NullImp::toBoolean(ExecState */*exec*/) const
00112 {
00113   return false;
00114 }
00115 
00116 double NullImp::toNumber(ExecState */*exec*/) const
00117 {
00118   return 0.0;
00119 }
00120 
00121 UString NullImp::toString(ExecState */*exec*/) const
00122 {
00123   return "null";
00124 }
00125 
00126 Object NullImp::toObject(ExecState *exec) const
00127 {
00128   Object err = Error::create(exec, TypeError, I18N_NOOP("Null value"));
00129   exec->setException(err);
00130   return err;
00131 }
00132 
00133 // ------------------------------ BooleanImp -----------------------------------
00134 
00135 BooleanImp* BooleanImp::staticTrue = 0;
00136 BooleanImp* BooleanImp::staticFalse = 0;
00137 
00138 Value BooleanImp::toPrimitive(ExecState */*exec*/, Type) const
00139 {
00140   return Value((ValueImp*)this);
00141 }
00142 
00143 bool BooleanImp::toBoolean(ExecState */*exec*/) const
00144 {
00145   return val;
00146 }
00147 
00148 double BooleanImp::toNumber(ExecState */*exec*/) const
00149 {
00150   return val ? 1.0 : 0.0;
00151 }
00152 
00153 UString BooleanImp::toString(ExecState */*exec*/) const
00154 {
00155   return val ? "true" : "false";
00156 }
00157 
00158 Object BooleanImp::toObject(ExecState *exec) const
00159 {
00160   List args;
00161   args.append(Boolean(const_cast<BooleanImp*>(this)));
00162   return Object::dynamicCast(exec->interpreter()->builtinBoolean().construct(exec,args));
00163 }
00164 
00165 // ------------------------------ StringImp ------------------------------------
00166 
00167 StringImp::StringImp(const UString& v)
00168   : val(v)
00169 {
00170 }
00171 
00172 Value StringImp::toPrimitive(ExecState */*exec*/, Type) const
00173 {
00174   return Value((ValueImp*)this);
00175 }
00176 
00177 bool StringImp::toBoolean(ExecState */*exec*/) const
00178 {
00179   return (val.size() > 0);
00180 }
00181 
00182 double StringImp::toNumber(ExecState */*exec*/) const
00183 {
00184   return val.toDouble();
00185 }
00186 
00187 UString StringImp::toString(ExecState */*exec*/) const
00188 {
00189   return val;
00190 }
00191 
00192 Object StringImp::toObject(ExecState *exec) const
00193 {
00194   List args;
00195   args.append(String(const_cast<StringImp*>(this)));
00196   return Object::dynamicCast(exec->interpreter()->builtinString().construct(exec,args));
00197 }
00198 
00199 // ------------------------------ NumberImp ------------------------------------
00200 
00201 NumberImp::NumberImp(double v)
00202   : val(v)
00203 {
00204 }
00205 
00206 Value NumberImp::toPrimitive(ExecState *, Type) const
00207 {
00208   return Number((NumberImp*)this);
00209 }
00210 
00211 bool NumberImp::toBoolean(ExecState *) const
00212 {
00213   return !((val == 0) /* || (iVal() == N0) */ || isNaN(val));
00214 }
00215 
00216 double NumberImp::toNumber(ExecState *) const
00217 {
00218   return val;
00219 }
00220 
00221 UString NumberImp::toString(ExecState *) const
00222 {
00223   return UString::from(val);
00224 }
00225 
00226 Object NumberImp::toObject(ExecState *exec) const
00227 {
00228   List args;
00229   args.append(Number(const_cast<NumberImp*>(this)));
00230   return Object::dynamicCast(exec->interpreter()->builtinNumber().construct(exec,args));
00231 }
00232 
00233 // ------------------------------ Reference2 ---------------------------------
00234 
00235 Value Reference2::getValue(ExecState *exec) const
00236 {
00237   if (!isValid())
00238     return base();
00239 
00240   if (bs.isNull() || bs.type() == NullType) {
00241     UString m = I18N_NOOP("Can't find variable: ") + propertyName();
00242     Object err = Error::create(exec, ReferenceError, m.ascii());
00243     exec->setException(err);
00244     return err;
00245   }
00246 
00247   if (bs.type() != ObjectType) {
00248     UString m = I18N_NOOP("Base is not an object");
00249     Object err = Error::create(exec, ReferenceError, m.ascii());
00250     exec->setException(err);
00251     return err;
00252   }
00253 
00254   return static_cast<ObjectImp*>(bs.imp())->get(exec, propertyName());
00255 }
00256 
00257 void Reference2::putValue(ExecState *exec, const Value& w)
00258 {
00259 #ifdef KJS_VERBOSE
00260   printInfo(exec, (UString("setting property ")+
00261            propertyName()).cstring().c_str(), w);
00262 #endif
00263   if (bs.type() == NullType)
00264     exec->interpreter()->globalObject().put(exec, propertyName(), w);
00265   else
00266     static_cast<ObjectImp*>(bs.imp())->put(exec, propertyName(), w);
00267 }
00268 
00269 // ------------------------------ ReferenceImp ---------------------------------
00270 
00271 ReferenceImp::ReferenceImp(const Value& v, const UString& p)
00272   : base(v.imp()), prop(p)
00273 {
00274 }
00275 
00276 void ReferenceImp::mark()
00277 {
00278   ValueImp::mark();
00279   if (base && !base->marked())
00280     base->mark();
00281 }
00282 
00283 Value ReferenceImp::toPrimitive(ExecState */*exec*/, Type /*preferredType*/) const
00284 {
00285   // invalid for Reference
00286   assert(false);
00287   return Value();
00288 }
00289 
00290 bool ReferenceImp::toBoolean(ExecState */*exec*/) const
00291 {
00292   // invalid for Reference
00293   assert(false);
00294   return false;
00295 }
00296 
00297 double ReferenceImp::toNumber(ExecState */*exec*/) const
00298 {
00299   // invalid for Reference
00300   assert(false);
00301   return 0;
00302 }
00303 
00304 UString ReferenceImp::toString(ExecState */*exec*/) const
00305 {
00306   // invalid for Reference
00307   assert(false);
00308   return UString::null;
00309 }
00310 
00311 Object ReferenceImp::toObject(ExecState */*exec*/) const
00312 {
00313   // invalid for Reference
00314   assert(false);
00315   return Object();
00316 }
00317 
00318 // ------------------------------ LabelStack -----------------------------------
00319 
00320 LabelStack::LabelStack(const LabelStack &other)
00321 {
00322   tos = 0;
00323   *this = other;
00324 }
00325 
00326 LabelStack &LabelStack::operator=(const LabelStack &other)
00327 {
00328   clear();
00329   tos = 0;
00330   StackElem *cur = 0;
00331   StackElem *se = other.tos;
00332   while (se) {
00333     StackElem *newPrev = new StackElem;
00334     newPrev->prev = 0;
00335     newPrev->id = se->id;
00336     if (cur)
00337       cur->prev = newPrev;
00338     else
00339       tos = newPrev;
00340     cur = newPrev;
00341     se = se->prev;
00342   }
00343   return *this;
00344 }
00345 
00346 bool LabelStack::push(const UString &id)
00347 {
00348   if (id.isEmpty() || contains(id))
00349     return false;
00350 
00351   StackElem *newtos = new StackElem;
00352   newtos->id = id;
00353   newtos->prev = tos;
00354   tos = newtos;
00355   return true;
00356 }
00357 
00358 bool LabelStack::contains(const UString &id) const
00359 {
00360   if (id.isEmpty())
00361     return true;
00362 
00363   for (StackElem *curr = tos; curr; curr = curr->prev)
00364     if (curr->id == id)
00365       return true;
00366 
00367   return false;
00368 }
00369 
00370 void LabelStack::pop()
00371 {
00372   if (tos) {
00373     StackElem *prev = tos->prev;
00374     delete tos;
00375     tos = prev;
00376   }
00377 }
00378 
00379 LabelStack::~LabelStack()
00380 {
00381   clear();
00382 }
00383 
00384 void LabelStack::clear()
00385 {
00386   StackElem *prev;
00387 
00388   while (tos) {
00389     prev = tos->prev;
00390     delete tos;
00391     tos = prev;
00392   }
00393 }
00394 
00395 // ------------------------------ CompletionImp --------------------------------
00396 
00397 CompletionImp::CompletionImp(ComplType c, const Value& v, const UString& t)
00398   : comp(c), val(v.imp()), tar(t)
00399 {
00400 }
00401 
00402 CompletionImp::~CompletionImp()
00403 {
00404 }
00405 
00406 void CompletionImp::mark()
00407 {
00408   ValueImp::mark();
00409 
00410   if (val && !val->marked())
00411     val->mark();
00412 }
00413 
00414 Value CompletionImp::toPrimitive(ExecState */*exec*/, Type /*preferredType*/) const
00415 {
00416   // invalid for Completion
00417   assert(false);
00418   return Value();
00419 }
00420 
00421 bool CompletionImp::toBoolean(ExecState */*exec*/) const
00422 {
00423   // invalid for Completion
00424   assert(false);
00425   return false;
00426 }
00427 
00428 double CompletionImp::toNumber(ExecState */*exec*/) const
00429 {
00430   // invalid for Completion
00431   assert(false);
00432   return 0;
00433 }
00434 
00435 UString CompletionImp::toString(ExecState */*exec*/) const
00436 {
00437   // invalid for Completion
00438   assert(false);
00439   return UString::null;
00440 }
00441 
00442 Object CompletionImp::toObject(ExecState */*exec*/) const
00443 {
00444   // invalid for Completion
00445   assert(false);
00446   return Object();
00447 }
00448 
00449 // ------------------------------ ListImp --------------------------------------
00450 
00451 #ifdef KJS_DEBUG_MEM
00452 int ListImp::count = 0;
00453 #endif
00454 
00455 Value ListImp::toPrimitive(ExecState */*exec*/, Type /*preferredType*/) const
00456 {
00457   // invalid for List
00458   assert(false);
00459   return Value();
00460 }
00461 
00462 bool ListImp::toBoolean(ExecState */*exec*/) const
00463 {
00464   // invalid for List
00465   assert(false);
00466   return false;
00467 }
00468 
00469 double ListImp::toNumber(ExecState */*exec*/) const
00470 {
00471   // invalid for List
00472   assert(false);
00473   return 0;
00474 }
00475 
00476 UString ListImp::toString(ExecState */*exec*/) const
00477 {
00478   // invalid for List
00479   assert(false);
00480   return UString::null;
00481 }
00482 
00483 Object ListImp::toObject(ExecState */*exec*/) const
00484 {
00485   // invalid for List
00486   assert(false);
00487   return Object();
00488 }
00489 
00490 ListImp::ListImp()
00491 {
00492 #ifdef KJS_DEBUG_MEM
00493   count++;
00494 #endif
00495 
00496   hook = new ListNode(Null(), 0L, 0L);
00497   hook->next = hook;
00498   hook->prev = hook;
00499   //fprintf(stderr,"ListImp::ListImp %p hook=%p\n",this,hook);
00500 }
00501 
00502 ListImp::~ListImp()
00503 {
00504   //fprintf(stderr,"ListImp::~ListImp %p\n",this);
00505 #ifdef KJS_DEBUG_MEM
00506   count--;
00507 #endif
00508 
00509   clear();
00510   delete hook;
00511 
00512   if ( emptyList == this )
00513     emptyList = 0L;
00514 }
00515 
00516 void ListImp::mark()
00517 {
00518   ListNode *n = hook->next;
00519   while (n != hook) {
00520     if (!n->member->marked())
00521       n->member->mark();
00522     n = n->next;
00523   }
00524   ValueImp::mark();
00525 }
00526 
00527 void ListImp::append(const Value& obj)
00528 {
00529   ListNode *n = new ListNode(obj, hook->prev, hook);
00530   hook->prev->next = n;
00531   hook->prev = n;
00532 }
00533 
00534 void ListImp::prepend(const Value& obj)
00535 {
00536   ListNode *n = new ListNode(obj, hook, hook->next);
00537   hook->next->prev = n;
00538   hook->next = n;
00539 }
00540 
00541 void ListImp::appendList(const List& lst)
00542 {
00543   ListIterator it = lst.begin();
00544   ListIterator e = lst.end();
00545   while(it != e) {
00546     append(*it);
00547     ++it;
00548   }
00549 }
00550 
00551 void ListImp::prependList(const List& lst)
00552 {
00553   ListIterator it = lst.end();
00554   ListIterator e = lst.begin();
00555   while(it != e) {
00556     --it;
00557     prepend(*it);
00558   }
00559 }
00560 
00561 void ListImp::removeFirst()
00562 {
00563   erase(hook->next);
00564 }
00565 
00566 void ListImp::removeLast()
00567 {
00568   erase(hook->prev);
00569 }
00570 
00571 void ListImp::remove(const Value &obj)
00572 {
00573   if (obj.isNull())
00574     return;
00575   ListNode *n = hook->next;
00576   while (n != hook) {
00577     if (n->member == obj.imp()) {
00578       erase(n);
00579       return;
00580     }
00581     n = n->next;
00582   }
00583 }
00584 
00585 void ListImp::clear()
00586 {
00587   ListNode *n = hook->next;
00588   while (n != hook) {
00589     n = n->next;
00590     delete n->prev;
00591   }
00592 
00593   hook->next = hook;
00594   hook->prev = hook;
00595 }
00596 
00597 ListImp *ListImp::copy() const
00598 {
00599   ListImp* newList = new ListImp;
00600 
00601   ListIterator e = end();
00602   ListIterator it = begin();
00603 
00604   while(it != e) {
00605     newList->append(*it);
00606     ++it;
00607   }
00608 
00609   //fprintf( stderr, "ListImp::copy returning newList=%p\n", newList );
00610   return newList;
00611 }
00612 
00613 void ListImp::erase(ListNode *n)
00614 {
00615   if (n != hook) {
00616     n->next->prev = n->prev;
00617     n->prev->next = n->next;
00618     delete n;
00619   }
00620 }
00621 
00622 bool ListImp::isEmpty() const
00623 {
00624   return (hook->prev == hook);
00625 }
00626 
00627 int ListImp::size() const
00628 {
00629   int s = 0;
00630   ListNode *node = hook;
00631   while ((node = node->next) != hook)
00632     s++;
00633 
00634   return s;
00635 }
00636 
00637 Value ListImp::at(int i) const
00638 {
00639   if (i < 0 || i >= size())
00640     return Undefined();
00641 
00642   ListIterator it = begin();
00643   int j = 0;
00644   while ((j++ < i))
00645     it++;
00646 
00647   return *it;
00648 }
00649 
00650 ListImp *ListImp::emptyList = 0L;
00651 
00652 ListImp *ListImp::empty()
00653 {
00654   if (!emptyList)
00655     emptyList = new ListImp();
00656   return emptyList;
00657 }
00658 
00659 // ------------------------------ ContextImp -----------------------------------
00660 
00661 
00662 // ECMA 10.2
00663 ContextImp::ContextImp(Object &glob, ExecState *exec, Object &thisV, CodeType type,
00664                        ContextImp *_callingContext, FunctionImp *func, const List &args)
00665 {
00666   codeType = type;
00667   callingCon = _callingContext;
00668 
00669   // create and initialize activation object (ECMA 10.1.6)
00670   if (type == FunctionCode || type == AnonymousCode ) {
00671     activation = Object(new ActivationImp(exec,func,args));
00672     variable = activation;
00673   } else {
00674     activation = Object();
00675     variable = glob;
00676   }
00677 
00678   // ECMA 10.2
00679   switch(type) {
00680     case EvalCode:
00681       if (callingCon) {
00682     scope = callingCon->scopeChain().copy();
00683 #ifndef KJS_PURE_ECMA
00684     if (thisV.imp() != glob.imp())
00685       scope.prepend(thisV); // for deprecated Object.prototype.eval()
00686 #endif
00687     variable = callingCon->variableObject();
00688     thisVal = callingCon->thisValue();
00689     break;
00690       } // else same as GlobalCode
00691     case GlobalCode:
00692       scope = List();
00693       scope.append(glob);
00694       thisVal = Object(static_cast<ObjectImp*>(glob.imp()));
00695       break;
00696     case FunctionCode:
00697     case AnonymousCode:
00698       if (type == FunctionCode) {
00699     scope = func->scope().copy();
00700     scope.prepend(activation);
00701       } else {
00702     scope = List();
00703     scope.append(activation);
00704     scope.append(glob);
00705       }
00706       variable = activation; // TODO: DontDelete ? (ECMA 10.2.3)
00707       thisVal = thisV;
00708       break;
00709     }
00710 
00711 }
00712 
00713 ContextImp::~ContextImp()
00714 {
00715 }
00716 
00717 void ContextImp::pushScope(const Object &s)
00718 {
00719   scope.prepend(s);
00720 }
00721 
00722 void ContextImp::popScope()
00723 {
00724   scope.removeFirst();
00725 }
00726 
00727 // ------------------------------ Parser ---------------------------------------
00728 
00729 ProgramNode *Parser::progNode = 0;
00730 int Parser::sid = 0;
00731 
00732 ProgramNode *Parser::parse(const UChar *code, unsigned int length, int *sourceId,
00733                int *errLine, UString *errMsg)
00734 {
00735   if (errLine)
00736     *errLine = -1;
00737   if (errMsg)
00738     *errMsg = 0;
00739 
00740   Lexer::curr()->setCode(code, length);
00741   progNode = 0;
00742   sid++;
00743   if (sourceId)
00744     *sourceId = sid;
00745   // Enable this (and the #define YYDEBUG in grammar.y) to debug a parse error
00746   //extern int kjsyydebug;
00747   //kjsyydebug=1;
00748   int parseError = kjsyyparse();
00749   ProgramNode *prog = progNode;
00750   progNode = 0;
00751   //sid = -1;
00752 
00753   if (parseError) {
00754     int eline = Lexer::curr()->lineNo();
00755     if (errLine)
00756       *errLine = eline;
00757     if (errMsg)
00758       *errMsg = "Parse error at line " + UString::from(eline);
00759 #ifndef NDEBUG
00760     fprintf(stderr, "KJS: JavaScript parse error at line %d.\n", eline);
00761 #endif
00762     delete prog;
00763     return 0;
00764   }
00765 
00766   return prog;
00767 }
00768 
00769 // ------------------------------ InterpreterImp -------------------------------
00770 
00771 InterpreterImp* InterpreterImp::s_hook = 0L;
00772 
00773 void InterpreterImp::globalInit()
00774 {
00775   //fprintf( stderr, "InterpreterImp::globalInit()\n" );
00776   UndefinedImp::staticUndefined = new UndefinedImp();
00777   UndefinedImp::staticUndefined->ref();
00778   NullImp::staticNull = new NullImp();
00779   NullImp::staticNull->ref();
00780   BooleanImp::staticTrue = new BooleanImp(true);
00781   BooleanImp::staticTrue->ref();
00782   BooleanImp::staticFalse = new BooleanImp(false);
00783   BooleanImp::staticFalse->ref();
00784 }
00785 
00786 void InterpreterImp::globalClear()
00787 {
00788   //fprintf( stderr, "InterpreterImp::globalClear()\n" );
00789   UndefinedImp::staticUndefined->deref();
00790   UndefinedImp::staticUndefined->setGcAllowed();
00791   UndefinedImp::staticUndefined = 0L;
00792   NullImp::staticNull->deref();
00793   NullImp::staticNull->setGcAllowed();
00794   NullImp::staticNull = 0L;
00795   BooleanImp::staticTrue->deref();
00796   BooleanImp::staticTrue->setGcAllowed();
00797   BooleanImp::staticTrue = 0L;
00798   BooleanImp::staticFalse->deref();
00799   BooleanImp::staticFalse->setGcAllowed();
00800   BooleanImp::staticFalse = 0L;
00801 }
00802 
00803 InterpreterImp::InterpreterImp(Interpreter *interp, const Object &glob)
00804   : m_interpreter(interp),
00805     global(glob),
00806     dbg(0),
00807     m_compatMode(Interpreter::NativeMode),
00808     recursion(0)
00809 {
00810   // add this interpreter to the global chain
00811   // as a root set for garbage collection
00812   if (s_hook) {
00813     prev = s_hook;
00814     next = s_hook->next;
00815     s_hook->next->prev = this;
00816     s_hook->next = this;
00817   } else {
00818     // This is the first interpreter
00819     s_hook = next = prev = this;
00820     globalInit();
00821   }
00822 
00823   globExec = new ExecState(m_interpreter,0);
00824 
00825   // initialize properties of the global object
00826   initGlobalObject();
00827 }
00828 
00829 void InterpreterImp::initGlobalObject()
00830 {
00831   // Contructor prototype objects (Object.prototype, Array.prototype etc)
00832 
00833   FunctionPrototypeImp *funcProto = new FunctionPrototypeImp(globExec);
00834   b_FunctionPrototype = Object(funcProto);
00835   ObjectPrototypeImp *objProto = new ObjectPrototypeImp(globExec,funcProto);
00836   b_ObjectPrototype = Object(objProto);
00837   funcProto->setPrototype(b_ObjectPrototype);
00838 
00839   ArrayPrototypeImp *arrayProto = new ArrayPrototypeImp(globExec,objProto);
00840   b_ArrayPrototype = Object(arrayProto);
00841   StringPrototypeImp *stringProto = new StringPrototypeImp(globExec,objProto);
00842   b_StringPrototype = Object(stringProto);
00843   BooleanPrototypeImp *booleanProto = new BooleanPrototypeImp(globExec,objProto,funcProto);
00844   b_BooleanPrototype = Object(booleanProto);
00845   NumberPrototypeImp *numberProto = new NumberPrototypeImp(globExec,objProto,funcProto);
00846   b_NumberPrototype = Object(numberProto);
00847   DatePrototypeImp *dateProto = new DatePrototypeImp(globExec,objProto);
00848   b_DatePrototype = Object(dateProto);
00849   RegExpPrototypeImp *regexpProto = new RegExpPrototypeImp(globExec,objProto,funcProto);
00850   b_RegExpPrototype = Object(regexpProto);
00851   ErrorPrototypeImp *errorProto = new ErrorPrototypeImp(globExec,objProto,funcProto);
00852   b_ErrorPrototype = Object(errorProto);
00853 
00854   static_cast<ObjectImp*>(global.imp())->setPrototype(b_ObjectPrototype);
00855 
00856   // Constructors (Object, Array, etc.)
00857 
00858   b_Object = Object(new ObjectObjectImp(globExec, objProto, funcProto));
00859   b_Function = Object(new FunctionObjectImp(globExec, funcProto));
00860   b_Array = Object(new ArrayObjectImp(globExec, funcProto, arrayProto));
00861   b_String = Object(new StringObjectImp(globExec, funcProto, stringProto));
00862   b_Boolean = Object(new BooleanObjectImp(globExec, funcProto, booleanProto));
00863   b_Number = Object(new NumberObjectImp(globExec, funcProto, numberProto));
00864   b_Date = Object(new DateObjectImp(globExec,funcProto,dateProto));
00865   b_RegExp = Object(new RegExpObjectImp(globExec, funcProto, regexpProto));
00866   b_Error = Object(new ErrorObjectImp(globExec, funcProto, errorProto));
00867 
00868   // Error object prototypes
00869   b_evalErrorPrototype = Object(new NativeErrorPrototypeImp(globExec,errorProto,EvalError,
00870                                                             "EvalError","EvalError"));
00871   b_rangeErrorPrototype = Object(new NativeErrorPrototypeImp(globExec,errorProto,RangeError,
00872                                                             "RangeError","RangeError"));
00873   b_referenceErrorPrototype = Object(new NativeErrorPrototypeImp(globExec,errorProto,ReferenceError,
00874                                                             "ReferenceError","ReferenceError"));
00875   b_syntaxErrorPrototype = Object(new NativeErrorPrototypeImp(globExec,errorProto,SyntaxError,
00876                                                             "SyntaxError","SyntaxError"));
00877   b_typeErrorPrototype = Object(new NativeErrorPrototypeImp(globExec,errorProto,TypeError,
00878                                                             "TypeError","TypeError"));
00879   b_uriErrorPrototype = Object(new NativeErrorPrototypeImp(globExec,errorProto,URIError,
00880                                                             "URIError","URIError"));
00881 
00882   // Error objects
00883   b_evalError = Object(new NativeErrorImp(globExec,funcProto,b_evalErrorPrototype));
00884   b_rangeError = Object(new NativeErrorImp(globExec,funcProto,b_rangeErrorPrototype));
00885   b_referenceError = Object(new NativeErrorImp(globExec,funcProto,b_referenceErrorPrototype));
00886   b_syntaxError = Object(new NativeErrorImp(globExec,funcProto,b_syntaxErrorPrototype));
00887   b_typeError = Object(new NativeErrorImp(globExec,funcProto,b_typeErrorPrototype));
00888   b_uriError = Object(new NativeErrorImp(globExec,funcProto,b_uriErrorPrototype));
00889 
00890   // ECMA 15.3.4.1
00891   funcProto->put(globExec,"constructor", b_Function, DontEnum);
00892 
00893   global.put(globExec,"Object", b_Object, DontEnum);
00894   global.put(globExec,"Function", b_Function, DontEnum);
00895   global.put(globExec,"Array", b_Array, DontEnum);
00896   global.put(globExec,"Boolean", b_Boolean, DontEnum);
00897   global.put(globExec,"String", b_String, DontEnum);
00898   global.put(globExec,"Number", b_Number, DontEnum);
00899   global.put(globExec,"Date", b_Date, DontEnum);
00900   global.put(globExec,"RegExp", b_RegExp, DontEnum);
00901   global.put(globExec,"Error", b_Error, DontEnum);
00902   // Using Internal for those to have something != 0
00903   // (see kjs_window). Maybe DontEnum would be ok too ?
00904   global.put(globExec,"EvalError",b_evalError, Internal);
00905   global.put(globExec,"RangeError",b_rangeError, Internal);
00906   global.put(globExec,"ReferenceError",b_referenceError, Internal);
00907   global.put(globExec,"SyntaxError",b_syntaxError, Internal);
00908   global.put(globExec,"TypeError",b_typeError, Internal);
00909   global.put(globExec,"URIError",b_uriError, Internal);
00910 
00911   // Set the "constructor" property of all builtin constructors
00912   objProto->put(globExec, "constructor", b_Object, DontEnum | DontDelete | ReadOnly);
00913   funcProto->put(globExec, "constructor", b_Function, DontEnum | DontDelete | ReadOnly);
00914   arrayProto->put(globExec, "constructor", b_Array, DontEnum | DontDelete | ReadOnly);
00915   booleanProto->put(globExec, "constructor", b_Boolean, DontEnum | DontDelete | ReadOnly);
00916   stringProto->put(globExec, "constructor", b_String, DontEnum | DontDelete | ReadOnly);
00917   numberProto->put(globExec, "constructor", b_Number, DontEnum | DontDelete | ReadOnly);
00918   dateProto->put(globExec, "constructor", b_Date, DontEnum | DontDelete | ReadOnly);
00919   regexpProto->put(globExec, "constructor", b_RegExp, DontEnum | DontDelete | ReadOnly);
00920   errorProto->put(globExec, "constructor", b_Error, DontEnum | DontDelete | ReadOnly);
00921   b_evalErrorPrototype.put(globExec, "constructor", b_evalError, DontEnum | DontDelete | ReadOnly);
00922   b_rangeErrorPrototype.put(globExec, "constructor", b_rangeError, DontEnum | DontDelete | ReadOnly);
00923   b_referenceErrorPrototype.put(globExec, "constructor", b_referenceError, DontEnum | DontDelete | ReadOnly);
00924   b_syntaxErrorPrototype.put(globExec, "constructor", b_syntaxError, DontEnum | DontDelete | ReadOnly);
00925   b_typeErrorPrototype.put(globExec, "constructor", b_typeError, DontEnum | DontDelete | ReadOnly);
00926   b_uriErrorPrototype.put(globExec, "constructor", b_uriError, DontEnum | DontDelete | ReadOnly);
00927 
00928   // built-in values
00929   global.put(globExec, "NaN",        Number(NaN), DontEnum|DontDelete);
00930   global.put(globExec, "Infinity",   Number(Inf), DontEnum|DontDelete);
00931   global.put(globExec, "undefined",  Undefined(), DontEnum|DontDelete);
00932 
00933   // built-in functions
00934 #ifdef KJS_PURE_ECMA // otherwise as deprecated Object.prototype property
00935   global.put(globExec,"eval",       Object(new GlobalFuncImp(globExec,funcProto,GlobalFuncImp::Eval,       1)), DontEnum);
00936 #endif
00937   global.put(globExec,"parseInt",   Object(new GlobalFuncImp(globExec,funcProto,GlobalFuncImp::ParseInt,   2)), DontEnum);
00938   global.put(globExec,"parseFloat", Object(new GlobalFuncImp(globExec,funcProto,GlobalFuncImp::ParseFloat, 1)), DontEnum);
00939   global.put(globExec,"isNaN",      Object(new GlobalFuncImp(globExec,funcProto,GlobalFuncImp::IsNaN,      1)), DontEnum);
00940   global.put(globExec,"isFinite",   Object(new GlobalFuncImp(globExec,funcProto,GlobalFuncImp::IsFinite,   1)), DontEnum);
00941   global.put(globExec,"escape",     Object(new GlobalFuncImp(globExec,funcProto,GlobalFuncImp::Escape,     1)), DontEnum);
00942   global.put(globExec,"unescape",   Object(new GlobalFuncImp(globExec,funcProto,GlobalFuncImp::UnEscape,   1)), DontEnum);
00943 
00944   // built-in objects
00945   global.put(globExec,"Math", Object(new MathObjectImp(globExec,objProto)), DontEnum);
00946 }
00947 
00948 InterpreterImp::~InterpreterImp()
00949 {
00950   if (dbg)
00951     dbg->detach(m_interpreter);
00952   delete globExec;
00953   globExec = 0L;
00954   clear();
00955 }
00956 
00957 void InterpreterImp::clear()
00958 {
00959   //fprintf(stderr,"InterpreterImp::clear\n");
00960   // remove from global chain (see init())
00961   next->prev = prev;
00962   prev->next = next;
00963   s_hook = next;
00964   if (s_hook == this)
00965   {
00966     // This was the last interpreter
00967     s_hook = 0L;
00968     globalClear();
00969   }
00970 }
00971 
00972 void InterpreterImp::mark()
00973 {
00974   //if (exVal && !exVal->marked())
00975   //  exVal->mark();
00976   //if (retVal && !retVal->marked())
00977   //  retVal->mark();
00978   if (UndefinedImp::staticUndefined && !UndefinedImp::staticUndefined->marked())
00979     UndefinedImp::staticUndefined->mark();
00980   if (NullImp::staticNull && !NullImp::staticNull->marked())
00981     NullImp::staticNull->mark();
00982   if (BooleanImp::staticTrue && !BooleanImp::staticTrue->marked())
00983     BooleanImp::staticTrue->mark();
00984   if (BooleanImp::staticFalse && !BooleanImp::staticFalse->marked())
00985     BooleanImp::staticFalse->mark();
00986   if (ListImp::emptyList && !ListImp::emptyList->marked())
00987     ListImp::emptyList->mark();
00988   //fprintf( stderr, "InterpreterImp::mark this=%p global.imp()=%p\n", this, global.imp() );
00989   if (global.imp())
00990     global.imp()->mark();
00991   if (m_interpreter)
00992     m_interpreter->mark();
00993 }
00994 
00995 bool InterpreterImp::checkSyntax(const UString &code)
00996 {
00997   // Parser::parse() returns 0 in a syntax error occurs, so we just check for that
00998   ProgramNode *progNode = Parser::parse(code.data(),code.size(),0,0,0);
00999   bool ok = (progNode != 0);
01000   delete progNode;
01001   return ok;
01002 }
01003 
01004 Completion InterpreterImp::evaluate(const UString &code, const Value &thisV)
01005 {
01006   // prevent against infinite recursion
01007   if (recursion >= 20) {
01008     return Completion(Throw,Error::create(globExec,GeneralError,"Recursion too deep"));
01009   }
01010 
01011   // parse the source code
01012   int sid;
01013   int errLine;
01014   UString errMsg;
01015   ProgramNode *progNode = Parser::parse(code.data(),code.size(),&sid,&errLine,&errMsg);
01016 
01017   // notify debugger that source has been parsed
01018   if (dbg) {
01019     bool cont = dbg->sourceParsed(globExec,sid,code,errLine);
01020     if (!cont)
01021       return Completion(Break);
01022   }
01023 
01024   // no program node means a syntax error occurred
01025   if (!progNode) {
01026     Object err = Error::create(globExec,SyntaxError,errMsg.ascii(),errLine);
01027     err.put(globExec,"sid",Number(sid));
01028     return Completion(Throw,err);
01029   }
01030 
01031   globExec->clearException();
01032 
01033   recursion++;
01034   progNode->ref();
01035 
01036   Object globalObj = globalObject();
01037   Object thisObj = globalObject();
01038 
01039   if (!thisV.isNull()) {
01040     // "this" must be an object... use same rules as Function.prototype.apply()
01041     if (thisV.isA(NullType) || thisV.isA(UndefinedType))
01042       thisObj = globalObject();
01043     else {
01044       thisObj = thisV.toObject(globExec);
01045     }
01046   }
01047 
01048   Completion res;
01049   if (globExec->hadException()) {
01050     // the thisArg.toObject() conversion above might have thrown an exception - if so,
01051     // propagate it back
01052     res = Completion(Throw,globExec->exception());
01053   }
01054   else {
01055     // execute the code
01056     ExecState *exec1 = 0;
01057     ContextImp *ctx = new ContextImp(globalObj, exec1, thisObj);
01058     ExecState *newExec = new ExecState(m_interpreter,ctx);
01059 
01060     res = progNode->execute(newExec);
01061 
01062     delete newExec;
01063     delete ctx;
01064   }
01065 
01066   if (progNode->deref())
01067     delete progNode;
01068   recursion--;
01069 
01070   return res;
01071 }
01072 
01073 void InterpreterImp::setDebugger(Debugger *d)
01074 {
01075   if (d == dbg)
01076     return;
01077   // avoid recursion
01078   Debugger *old = dbg;
01079   dbg = d;
01080   if ( old )
01081     old->detach(m_interpreter);
01082 }
01083 
01084 // ------------------------------ InternalFunctionImp --------------------------
01085 
01086 const ClassInfo InternalFunctionImp::info = {"Function", 0, 0, 0};
01087 
01088 InternalFunctionImp::InternalFunctionImp(FunctionPrototypeImp *funcProto)
01089   : ObjectImp(Object(funcProto))
01090 {
01091 }
01092 
01093 bool InternalFunctionImp::implementsHasInstance() const
01094 {
01095   return true;
01096 }
01097 
01098 Boolean InternalFunctionImp::hasInstance(ExecState *exec, const Value &value)
01099 {
01100   if (value.type() != ObjectType)
01101     return Boolean(false);
01102 
01103   Value prot = get(exec,"prototype");
01104   if (prot.type() != ObjectType && prot.type() != NullType) {
01105     Object err = Error::create(exec, TypeError, "Invalid prototype encountered "
01106                                "in instanceof operation.");
01107     exec->setException(err);
01108     return Boolean(false);
01109   }
01110 
01111   Object v = Object(static_cast<ObjectImp*>(value.imp()));
01112   while ((v = Object::dynamicCast(v.prototype())).imp()) {
01113     if (v.imp() == prot.imp())
01114       return Boolean(true);
01115   }
01116   return Boolean(false);
01117 }
01118 
01119 // ------------------------------ global functions -----------------------------
01120 
01121 double KJS::roundValue(ExecState *exec, const Value &v)
01122 {
01123   if (v.type() == UndefinedType) /* TODO: see below */
01124     return 0.0;
01125   double n = v.toNumber(exec);
01126   if (n == 0.0)   /* TODO: -0, NaN, Inf */
01127     return 0.0;
01128   double d = floor(fabs(n));
01129   if (n < 0)
01130     d *= -1;
01131 
01132   return d;
01133 }
01134 
01135 #ifndef NDEBUG
01136 #include <stdio.h>
01137 void KJS::printInfo(ExecState *exec, const char *s, const Value &o, int lineno)
01138 {
01139   if (o.isNull())
01140     fprintf(stderr, "KJS: %s: (null)", s);
01141   else {
01142     Value v = o;
01143     if (o.isA(ReferenceType))
01144       v = o.getValue(exec);
01145 
01146     UString name;
01147     switch ( v.type() ) {
01148     case UnspecifiedType:
01149       name = "Unspecified";
01150       break;
01151     case UndefinedType:
01152       name = "Undefined";
01153       break;
01154     case NullType:
01155       name = "Null";
01156       break;
01157     case BooleanType:
01158       name = "Boolean";
01159       break;
01160     case StringType:
01161       name = "String";
01162       break;
01163     case NumberType:
01164       name = "Number";
01165       break;
01166     case ObjectType:
01167       name = Object::dynamicCast(v).className();
01168       if (name.isNull())
01169         name = "(unknown class)";
01170       break;
01171     case ReferenceType:
01172       name = "Reference";
01173       break;
01174     case ListType:
01175       name = "List";
01176       break;
01177     case CompletionType:
01178       name = "Completion";
01179       break;
01180     default:
01181       break;
01182     }
01183     bool hadExcep = exec->hadException();
01184     UString vString = v.toString(exec);
01185     if ( !hadExcep )
01186       exec->clearException();
01187     if ( vString.size() > 50 )
01188       vString = vString.substr( 0, 50 ) + "...";
01189     // Can't use two UString::ascii() in the same fprintf call
01190     CString tempString( vString.cstring() );
01191 
01192     fprintf(stderr, "KJS: %s: %s : %s (%p)",
01193             s, tempString.c_str(), name.ascii(), (void*)v.imp());
01194 
01195     if (lineno >= 0)
01196       fprintf(stderr, ", line %d\n",lineno);
01197     else
01198       fprintf(stderr, "\n");
01199     if (!o.isNull())
01200       if (o.isA(ReferenceType)) {
01201         fprintf(stderr, "KJS: Was property '%s'\n", o.getPropertyName(exec).ascii());
01202         printInfo(exec,"of", o.getBase(exec));
01203       }
01204   }
01205 }
01206 #endif
KDE Logo
This file is part of the documentation for kdelibs Version 3.1.0.
Documentation copyright © 1996-2002 the KDE developers.
Generated on Wed Oct 8 12:21:15 2003 by doxygen 1.2.18 written by Dimitri van Heesch, © 1997-2001