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