# kjs Library API Documentation

Overview | Class Hierarchy | Classes | Classes (annotated) | Members | Source Files

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

This file is part of the documentation for kdelibs Version 3.1.5.
Documentation copyright © 1996-2002 the KDE developers.
Generated on Wed Jan 28 13:08:27 2004 by doxygen 1.3.4 written by Dimitri van Heesch, © 1997-2001