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   /* 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
KDE Logo
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