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  *  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
KDE Logo
This file is part of the documentation for kjs Library Version 3.4.2.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Wed Feb 8 08:01:46 2006 by doxygen 1.4.4 written by Dimitri van Heesch, © 1997-2003