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.3.1.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Sun Oct 17 11:28:50 2004 by doxygen 1.3.8 written by Dimitri van Heesch, © 1997-2003