# kjs Library API Documentation

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

This file is part of the documentation for kjs Library Version 3.4.1.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Sat Jun 11 20:23:06 2005 by doxygen 1.4.1 written by Dimitri van Heesch, © 1997-2003