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 #ifndef NDEBUG
00029 #include <strings.h>      // for strdup
00030 #endif
00031 
00032 #include "array_object.h"
00033 #include "bool_object.h"
00034 #include "collector.h"
00035 #include "context.h"
00036 #include "date_object.h"
00037 #include "debugger.h"
00038 #include "error_object.h"
00039 #include "function_object.h"
00040 #include "internal.h"
00041 #include "lexer.h"
00042 #include "math_object.h"
00043 #include "nodes.h"
00044 #include "number_object.h"
00045 #include "object.h"
00046 #include "object_object.h"
00047 #include "operations.h"
00048 #include "regexp_object.h"
00049 #include "string_object.h"
00050 
00051 #define I18N_NOOP(s) s
00052 
00053 extern int kjsyyparse();
00054 
00055 using namespace KJS;
00056 
00057 namespace KJS {
00058   /* work around some strict alignment requirements 
00059      for double variables on some architectures (e.g. PA-RISC) */
00060   typedef union { unsigned char b[8]; double d; } kjs_double_t;
00061 
00062 #ifdef WORDS_BIGENDIAN
00063   static const kjs_double_t NaN_Bytes = { { 0x7f, 0xf8, 0, 0, 0, 0, 0, 0 } };
00064   static const kjs_double_t Inf_Bytes = { { 0x7f, 0xf0, 0, 0, 0, 0, 0, 0 } };
00065 #elif defined(arm)
00066   static const kjs_double_t NaN_Bytes = { { 0, 0, 0xf8, 0x7f, 0, 0, 0, 0 } };
00067   static const kjs_double_t Inf_Bytes = { { 0, 0, 0xf0, 0x7f, 0, 0, 0, 0 } };
00068 #else
00069   static const kjs_double_t NaN_Bytes = { { 0, 0, 0, 0, 0, 0, 0xf8, 0x7f } };
00070   static const kjs_double_t Inf_Bytes = { { 0, 0, 0, 0, 0, 0, 0xf0, 0x7f } };
00071 #endif
00072 
00073   const double NaN = NaN_Bytes.d;
00074   const double Inf = Inf_Bytes.d;
00075 }
00076 
00077 #ifdef KJS_THREADSUPPORT
00078 static pthread_once_t interpreterLockOnce = PTHREAD_ONCE_INIT;
00079 static pthread_mutex_t interpreterLock;
00080 
00081 static void initializeInterpreterLock()
00082 {
00083   pthread_mutexattr_t attr;
00084 
00085   pthread_mutexattr_init(&attr);
00086   pthread_mutexattr_settype (&attr, PTHREAD_MUTEX_RECURSIVE);
00087 
00088   pthread_mutex_init(&interpreterLock, &attr);
00089 }
00090 #endif
00091 
00092 static inline void lockInterpreter()
00093 {
00094 #ifdef KJS_THREADSUPPORT
00095   pthread_once(&interpreterLockOnce, initializeInterpreterLock);
00096   pthread_mutex_lock(&interpreterLock);
00097 #endif
00098 }
00099 
00100 static inline void unlockInterpreter()
00101 {
00102 #ifdef KJS_THREADSUPPORT
00103   pthread_mutex_unlock(&interpreterLock);
00104 #endif
00105 }
00106 
00107 // ------------------------------ UndefinedImp ---------------------------------
00108 
00109 UndefinedImp *UndefinedImp::staticUndefined = 0;
00110 
00111 Value UndefinedImp::toPrimitive(ExecState* /*exec*/, Type) const
00112 {
00113   return Value((ValueImp*)this);
00114 }
00115 
00116 bool UndefinedImp::toBoolean(ExecState* /*exec*/) const
00117 {
00118   return false;
00119 }
00120 
00121 double UndefinedImp::toNumber(ExecState* /*exec*/) const
00122 {
00123   return NaN;
00124 }
00125 
00126 UString UndefinedImp::toString(ExecState* /*exec*/) const
00127 {
00128   return "undefined";
00129 }
00130 
00131 Object UndefinedImp::toObject(ExecState *exec) const
00132 {
00133   Object err = Error::create(exec, TypeError, I18N_NOOP("Undefined value"));
00134   exec->setException(err);
00135   return err;
00136 }
00137 
00138 // ------------------------------ NullImp --------------------------------------
00139 
00140 NullImp *NullImp::staticNull = 0;
00141 
00142 Value NullImp::toPrimitive(ExecState* /*exec*/, Type) const
00143 {
00144   return Value((ValueImp*)this);
00145 }
00146 
00147 bool NullImp::toBoolean(ExecState* /*exec*/) const
00148 {
00149   return false;
00150 }
00151 
00152 double NullImp::toNumber(ExecState* /*exec*/) const
00153 {
00154   return 0.0;
00155 }
00156 
00157 UString NullImp::toString(ExecState* /*exec*/) const
00158 {
00159   return "null";
00160 }
00161 
00162 Object NullImp::toObject(ExecState *exec) const
00163 {
00164   Object err = Error::create(exec, TypeError, I18N_NOOP("Null value"));
00165   exec->setException(err);
00166   return err;
00167 }
00168 
00169 // ------------------------------ BooleanImp -----------------------------------
00170 
00171 BooleanImp* BooleanImp::staticTrue = 0;
00172 BooleanImp* BooleanImp::staticFalse = 0;
00173 
00174 Value BooleanImp::toPrimitive(ExecState* /*exec*/, Type) const
00175 {
00176   return Value((ValueImp*)this);
00177 }
00178 
00179 bool BooleanImp::toBoolean(ExecState* /*exec*/) const
00180 {
00181   return val;
00182 }
00183 
00184 double BooleanImp::toNumber(ExecState* /*exec*/) const
00185 {
00186   return val ? 1.0 : 0.0;
00187 }
00188 
00189 UString BooleanImp::toString(ExecState* /*exec*/) const
00190 {
00191   return val ? "true" : "false";
00192 }
00193 
00194 Object BooleanImp::toObject(ExecState *exec) const
00195 {
00196   List args;
00197   args.append(const_cast<BooleanImp*>(this));
00198   return Object::dynamicCast(exec->interpreter()->builtinBoolean().construct(exec,args));
00199 }
00200 
00201 // ------------------------------ StringImp ------------------------------------
00202 
00203 Value StringImp::toPrimitive(ExecState* /*exec*/, Type) const
00204 {
00205   return Value((ValueImp*)this);
00206 }
00207 
00208 bool StringImp::toBoolean(ExecState* /*exec*/) const
00209 {
00210   return (val.size() > 0);
00211 }
00212 
00213 double StringImp::toNumber(ExecState* /*exec*/) const
00214 {
00215   return val.toDouble();
00216 }
00217 
00218 UString StringImp::toString(ExecState* /*exec*/) const
00219 {
00220   return val;
00221 }
00222 
00223 Object StringImp::toObject(ExecState *exec) const
00224 {
00225   List args;
00226   args.append(const_cast<StringImp*>(this));
00227   return Object::dynamicCast(exec->interpreter()->builtinString().construct(exec,args));
00228 }
00229 
00230 // ------------------------------ NumberImp ------------------------------------
00231 
00232 NumberImp *NumberImp::staticNaN;
00233 
00234 ValueImp *NumberImp::create(int i)
00235 {
00236     if (SimpleNumber::fits(i))
00237         return SimpleNumber::make(i);
00238     NumberImp *imp = new NumberImp(static_cast<double>(i));
00239     imp->setGcAllowedFast();
00240     return imp;
00241 }
00242 
00243 ValueImp *NumberImp::create(double d)
00244 {
00245     if (SimpleNumber::fits(d))
00246         return SimpleNumber::make((int)d);
00247     if (isNaN(d))
00248         return staticNaN;
00249     NumberImp *imp = new NumberImp(d);
00250     imp->setGcAllowedFast();
00251     return imp;
00252 }
00253 
00254 Value NumberImp::toPrimitive(ExecState *, Type) const
00255 {
00256   return Number((NumberImp*)this);
00257 }
00258 
00259 bool NumberImp::toBoolean(ExecState *) const
00260 {
00261   return !((val == 0) /* || (iVal() == N0) */ || isNaN(val));
00262 }
00263 
00264 double NumberImp::toNumber(ExecState *) const
00265 {
00266   return val;
00267 }
00268 
00269 UString NumberImp::toString(ExecState *) const
00270 {
00271   if (val == 0.0) // +0.0 or -0.0
00272     return "0";
00273   return UString::from(val);
00274 }
00275 
00276 Object NumberImp::toObject(ExecState *exec) const
00277 {
00278   List args;
00279   args.append(const_cast<NumberImp*>(this));
00280   return Object::dynamicCast(exec->interpreter()->builtinNumber().construct(exec,args));
00281 }
00282 
00283 bool NumberImp::toUInt32(unsigned& uint32) const
00284 {
00285   uint32 = (unsigned)val;
00286   return (double)uint32 == val;
00287 }
00288 
00289 double SimpleNumber::negZero = -0.0;
00290 
00291 // ------------------------------ LabelStack -----------------------------------
00292 
00293 LabelStack::LabelStack(const LabelStack &other)
00294 {
00295   tos = 0;
00296   *this = other;
00297 }
00298 
00299 LabelStack &LabelStack::operator=(const LabelStack &other)
00300 {
00301   clear();
00302   tos = 0;
00303   StackElem *cur = 0;
00304   StackElem *se = other.tos;
00305   while (se) {
00306     StackElem *newPrev = new StackElem;
00307     newPrev->prev = 0;
00308     newPrev->id = se->id;
00309     if (cur)
00310       cur->prev = newPrev;
00311     else
00312       tos = newPrev;
00313     cur = newPrev;
00314     se = se->prev;
00315   }
00316   return *this;
00317 }
00318 
00319 bool LabelStack::push(const Identifier &id)
00320 {
00321   if (id.isEmpty() || contains(id))
00322     return false;
00323 
00324   StackElem *newtos = new StackElem;
00325   newtos->id = id;
00326   newtos->prev = tos;
00327   tos = newtos;
00328   return true;
00329 }
00330 
00331 bool LabelStack::contains(const Identifier &id) const
00332 {
00333   if (id.isEmpty())
00334     return true;
00335 
00336   for (StackElem *curr = tos; curr; curr = curr->prev)
00337     if (curr->id == id)
00338       return true;
00339 
00340   return false;
00341 }
00342 
00343 void LabelStack::pop()
00344 {
00345   if (tos) {
00346     StackElem *prev = tos->prev;
00347     delete tos;
00348     tos = prev;
00349   }
00350 }
00351 
00352 LabelStack::~LabelStack()
00353 {
00354   clear();
00355 }
00356 
00357 void LabelStack::clear()
00358 {
00359   StackElem *prev;
00360 
00361   while (tos) {
00362     prev = tos->prev;
00363     delete tos;
00364     tos = prev;
00365   }
00366 }
00367 
00368 // ------------------------------ ContextImp -----------------------------------
00369 
00370 
00371 // ECMA 10.2
00372 ContextImp::ContextImp(Object &glob, InterpreterImp *interpreter, Object &thisV, int _sourceId, CodeType type,
00373                        ContextImp *callingCon, FunctionImp *func, const List *args)
00374   : _interpreter(interpreter), _function(func), _arguments(args)
00375 {
00376   codeType = type;
00377   _callingContext = callingCon;
00378   tryCatch = 0;
00379 
00380   sourceId = _sourceId;
00381   line0 = 1;
00382   line1 = 1;
00383 
00384   if (func && func->inherits(&DeclaredFunctionImp::info))
00385     functionName = static_cast<DeclaredFunctionImp*>(func)->name();
00386   else
00387     functionName = Identifier::null();
00388 
00389   // create and initialize activation object (ECMA 10.1.6)
00390   if (type == FunctionCode) {
00391     activation = Object(new ActivationImp(func,*args));
00392     variable = activation;
00393   } else {
00394     activation = Object();
00395     variable = glob;
00396   }
00397 
00398   // ECMA 10.2
00399   switch(type) {
00400     case EvalCode:
00401       if (_callingContext) {
00402     scope = _callingContext->scopeChain();
00403 #ifndef KJS_PURE_ECMA
00404     if (thisV.imp() != glob.imp())
00405       scope.push(thisV.imp()); // for deprecated Object.prototype.eval()
00406 #endif
00407     variable = _callingContext->variableObject();
00408     thisVal = _callingContext->thisValue();
00409     break;
00410       } // else same as GlobalCode
00411     case GlobalCode:
00412       scope.clear();
00413       scope.push(glob.imp());
00414 #ifndef KJS_PURE_ECMA
00415       if (thisV.isValid())
00416           thisVal = thisV;
00417       else
00418 #endif
00419           thisVal = glob;
00420       break;
00421     case FunctionCode:
00422       scope = func->scope();
00423       scope.push(activation.imp());
00424       variable = activation; // TODO: DontDelete ? (ECMA 10.2.3)
00425       thisVal = thisV;
00426       break;
00427     }
00428 
00429   _interpreter->setContext(this);
00430 }
00431 
00432 ContextImp::~ContextImp()
00433 {
00434   _interpreter->setContext(_callingContext);
00435 }
00436 
00437 void ContextImp::mark()
00438 {
00439   for (ContextImp *context = this; context; context = context->_callingContext) {
00440     context->scope.mark();
00441   }
00442 }
00443 
00444 bool ContextImp::inTryCatch() const
00445 {
00446   const ContextImp *c = this;
00447   while (c && !c->tryCatch)
00448     c = c->_callingContext;
00449   return (c && c->tryCatch);
00450 }
00451 
00452 // ---------------------------- SourceCode -------------------------------------
00453 
00454 void SourceCode::cleanup()
00455 {
00456   if (interpreter && interpreter->debugger())
00457     interpreter->debugger()->sourceUnused(interpreter->globalExec(),sid);
00458   if (interpreter)
00459     interpreter->removeSourceCode(this);
00460   delete this;
00461 }
00462 
00463 // ------------------------------ Parser ---------------------------------------
00464 
00465 FunctionBodyNode *Parser::progNode = 0;
00466 int Parser::sid = 0;
00467 SourceCode *Parser::source = 0;
00468 
00469 FunctionBodyNode *Parser::parse(const UChar *code, unsigned int length, SourceCode **src,
00470                 int *errLine, UString *errMsg)
00471 {
00472   if (errLine)
00473     *errLine = -1;
00474   if (errMsg)
00475     *errMsg = 0;
00476 
00477   Lexer::curr()->setCode(code, length);
00478   progNode = 0;
00479   sid++;
00480 
00481   source = new SourceCode(sid);
00482   source->ref();
00483   *src = source;
00484 
00485   // Enable this (and the #define YYDEBUG in grammar.y) to debug a parse error
00486   //extern int kjsyydebug;
00487   //kjsyydebug=1;
00488   int parseError = kjsyyparse();
00489   if (Lexer::curr()->hadError())
00490     parseError = 1;
00491   Lexer::curr()->doneParsing();
00492   FunctionBodyNode *prog = progNode;
00493   progNode = 0;
00494   //sid = -1;
00495   source = 0;
00496 
00497   if (parseError) {
00498     int eline = Lexer::curr()->lineNo();
00499     if (errLine)
00500       *errLine = eline;
00501     if (errMsg)
00502       *errMsg = "Parse error at line " + UString::from(eline);
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 
01030     UString name;
01031     switch ( v.type() ) {
01032     case UnspecifiedType:
01033       name = "Unspecified";
01034       break;
01035     case UndefinedType:
01036       name = "Undefined";
01037       break;
01038     case NullType:
01039       name = "Null";
01040       break;
01041     case BooleanType:
01042       name = "Boolean";
01043       break;
01044     case StringType:
01045       name = "String";
01046       break;
01047     case NumberType:
01048       name = "Number";
01049       break;
01050     case ObjectType:
01051       name = Object::dynamicCast(v).className();
01052       if (name.isNull())
01053         name = "(unknown class)";
01054       break;
01055     }
01056     bool hadExcep = exec->hadException();
01057     UString vString = v.toString(exec);
01058     if ( !hadExcep )
01059       exec->clearException();
01060     if ( vString.size() > 50 )
01061       vString = vString.substr( 0, 50 ) + "...";
01062     // Can't use two UString::ascii() in the same fprintf call
01063     CString tempString( vString.cstring() );
01064 
01065     fprintf(stderr, "KJS: %s: %s : %s (%p)",
01066             s, tempString.c_str(), name.ascii(), (void*)v.imp());
01067 
01068     if (lineno >= 0)
01069       fprintf(stderr, ", line %d\n",lineno);
01070     else
01071       fprintf(stderr, "\n");
01072   }
01073 }
01074 #endif
KDE Logo
This file is part of the documentation for kjs Library Version 3.2.2.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Fri Jan 21 09:57:41 2005 by doxygen 1.3.6 written by Dimitri van Heesch, © 1997-2003