Changeset 798 in webkit for trunk/JavaScriptCore
- Timestamp:
- Mar 21, 2002, 4:31:57 PM (23 years ago)
- Location:
- trunk/JavaScriptCore/kjs
- Files:
-
- 8 added
- 3 deleted
- 49 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/JavaScriptCore/kjs/Makefile.am
r550 r798 4 4 libkjs_o_LDFLAGS = -Wl,-r -nostdlib 5 5 libkjs_o_AR = $(OBJCXXLD) $(AM_OBJCXXFLAGS) $(OBJCXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) $(libkjs_o_LDFLAGS) -o 6 7 INCLUDES = $(KWQ_INCLUDES) 6 8 7 9 libkjs_o_SOURCES = \ … … 22 24 function_object.cpp \ 23 25 function_object.h \ 24 global_object.cpp \25 26 grammar.cpp \ 26 27 grammar.h \ 27 28 internal.cpp \ 28 29 internal.h \ 29 kjs.cpp \30 kjs.h \30 interpreter.cpp \ 31 interpreter.h \ 31 32 lexer.cpp \ 32 33 lexer.h \ … … 47 48 operations.cpp \ 48 49 operations.h \ 50 property_map.cpp \ 51 property_map.h \ 49 52 regexp.cpp \ 50 53 regexp.h \ … … 57 60 ustring.cpp \ 58 61 ustring.h \ 62 value.cpp \ 63 value.h \ 59 64 $(NULL) 60 65 … … 76 81 touch ./grammar-stamp 77 82 78 BUILT_SOURCES = $(GRAMMAR_FILES) grammar-stamp 83 LUT_FILES = math_object.lut.h lexer.lut.h array_object.lut.h date_object.lut.h string_object.lut.h number_object.lut.h 84 85 lexer.lut.h: keywords.table 86 ./create_hash_table keywords.table -i > lexer.lut.h; 87 88 array_object.lut.h: array_object.cpp 89 ./create_hash_table array_object.cpp -i > array_object.lut.h 90 91 math_object.lut.h: math_object.cpp 92 ./create_hash_table math_object.cpp -i > math_object.lut.h 93 94 date_object.lut.h: date_object.cpp 95 ./create_hash_table date_object.cpp -i > date_object.lut.h 96 97 number_object.lut.h: number_object.cpp 98 ./create_hash_table number_object.cpp -i > number_object.lut.h 99 100 string_object.lut.h: string_object.cpp 101 ./create_hash_table string_object.cpp -i > string_object.lut.h 102 103 104 105 BUILT_SOURCES = $(GRAMMAR_FILES) $(LUT_FILES) grammar-stamp 79 106 80 107 CLEANFILES = $(BUILT_SOURCES) -
trunk/JavaScriptCore/kjs/array_object.cpp
r6 r798 1 // -*- c-basic-offset: 2 -*- 1 2 /* 2 3 * This file is part of the KDE libraries … … 16 17 * License along with this library; if not, write to the Free Software 17 18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 * 18 20 */ 19 21 20 #include "kjs.h" 22 #include "value.h" 23 #include "object.h" 24 #include "types.h" 25 #include "interpreter.h" 21 26 #include "operations.h" 22 #include "types.h"23 27 #include "array_object.h" 28 #include "internal.h" 29 #include "error_object.h" 30 31 #include "array_object.lut.h" 32 24 33 #include <stdio.h> 34 #include <assert.h> 25 35 26 36 using namespace KJS; 27 37 28 ArrayObject::ArrayObject(const Object &funcProto, 29 const Object &arrayProto) 30 : ConstructorImp(funcProto, 1) 31 { 38 // ------------------------------ ArrayInstanceImp ----------------------------- 39 40 const ClassInfo ArrayInstanceImp::info = {"Array", 0, 0, 0}; 41 42 ArrayInstanceImp::ArrayInstanceImp(const Object &proto) 43 : ObjectImp(proto) 44 { 45 } 46 47 // Special implementation of [[Put]] - see ECMA 15.4.5.1 48 void ArrayInstanceImp::put(ExecState *exec, const UString &propertyName, const Value &value, int attr) 49 { 50 if ((attr == None || attr == DontDelete) && !canPut(exec,propertyName)) 51 return; 52 53 if (hasProperty(exec,propertyName)) { 54 if (propertyName == "length") { 55 Value len = get(exec,"length"); 56 unsigned int oldLen = len.toUInt32(exec); 57 unsigned int newLen = value.toUInt32(exec); 58 // shrink array 59 for (unsigned int u = newLen; u < oldLen; u++) { 60 UString p = UString::from(u); 61 if (hasProperty(exec, p, false)) 62 deleteProperty(exec, p); 63 } 64 ObjectImp::put(exec, "length", Number(newLen), DontEnum | DontDelete); 65 return; 66 } 67 // put(p, v); 68 } // } else 69 ObjectImp::put(exec, propertyName, value, attr); 70 71 // array index ? 72 unsigned int idx; 73 if (!sscanf(propertyName.cstring().c_str(), "%u", &idx)) /* TODO */ 74 return; 75 76 // do we need to update/create the length property ? 77 if (hasProperty(exec, "length", false)) { 78 Value len = get(exec, "length"); 79 if (idx < len.toUInt32(exec)) 80 return; 81 } 82 83 ObjectImp::put(exec, "length", Number(idx+1), DontDelete | DontEnum); 84 } 85 86 void ArrayInstanceImp::putDirect(ExecState *exec, const UString &propertyName, const Value &value, int attr) 87 { 88 ObjectImp::put(exec,propertyName,value,attr); 89 } 90 // ------------------------------ ArrayPrototypeImp ---------------------------- 91 92 const ClassInfo ArrayPrototypeImp::info = {"Array", &ArrayInstanceImp::info, &arrayTable, 0}; 93 94 /* Source for array_object.lut.h 95 @begin arrayTable 13 96 toString ArrayProtoFuncImp::ToString DontEnum|Function 0 97 toLocaleString ArrayProtoFuncImp::ToLocaleString DontEnum|Function 0 98 concat ArrayProtoFuncImp::Concat DontEnum|Function 1 99 join ArrayProtoFuncImp::Join DontEnum|Function 1 100 pop ArrayProtoFuncImp::Pop DontEnum|Function 0 101 push ArrayProtoFuncImp::Push DontEnum|Function 1 102 reverse ArrayProtoFuncImp::Reverse DontEnum|Function 0 103 shift ArrayProtoFuncImp::Shift DontEnum|Function 0 104 slice ArrayProtoFuncImp::Slice DontEnum|Function 2 105 sort ArrayProtoFuncImp::Sort DontEnum|Function 1 106 splice ArrayProtoFuncImp::Splice DontEnum|Function 2 107 unshift ArrayProtoFuncImp::UnShift DontEnum|Function 1 108 @end 109 */ 110 111 // ECMA 15.4.4 112 ArrayPrototypeImp::ArrayPrototypeImp(ExecState *exec, 113 ObjectPrototypeImp *objProto) 114 : ArrayInstanceImp(Object(objProto)) 115 { 116 Value protect(this); 117 setInternalValue(Null()); 118 119 // The constructor will be added later, by InterpreterImp, once ArrayObjectImp has been constructed. 120 put(exec,"length", Number(0), DontEnum | DontDelete); 121 } 122 123 Value ArrayPrototypeImp::get(ExecState *exec, const UString &propertyName) const 124 { 125 //fprintf( stderr, "ArrayPrototypeImp::get(%s)\n", propertyName.ascii() ); 126 return lookupGetFunction<ArrayProtoFuncImp, ArrayInstanceImp>( exec, propertyName, &arrayTable, this ); 127 } 128 129 // ------------------------------ ArrayProtoFuncImp ---------------------------- 130 131 ArrayProtoFuncImp::ArrayProtoFuncImp(ExecState *exec, int i, int len) 132 : InternalFunctionImp( 133 static_cast<FunctionPrototypeImp*>(exec->interpreter()->builtinFunctionPrototype().imp()) 134 ), id(i) 135 { 136 Value protect(this); 137 put(exec,"length",Number(len),DontDelete|ReadOnly|DontEnum); 138 } 139 140 bool ArrayProtoFuncImp::implementsCall() const 141 { 142 return true; 143 } 144 145 // ECMA 15.4.4 146 Value ArrayProtoFuncImp::call(ExecState *exec, Object &thisObj, const List &args) 147 { 148 unsigned int length = thisObj.get(exec,"length").toUInt32(exec); 149 150 Value result; 151 switch (id) { 152 case ToLocaleString: 153 // TODO - see 15.4.4.3 154 // fall through 155 case ToString: 156 157 if (!thisObj.inherits(&ArrayInstanceImp::info)) { 158 Object err = Error::create(exec,TypeError); 159 exec->setException(err); 160 return err; 161 } 162 163 // fall through 164 165 case Join: { 166 UString separator = ","; 167 UString str = ""; 168 169 if (args.size() > 0) 170 separator = args[0].toString(exec); 171 for (unsigned int k = 0; k < length; k++) { 172 if (k >= 1) 173 str += separator; 174 Value element = thisObj.get(exec,UString::from(k)); 175 if (element.type() != UndefinedType && element.type() != NullType) 176 str += element.toString(exec); 177 } 178 result = String(str); 179 break; 180 } 181 case Concat: { 182 Object arr = Object::dynamicCast(exec->interpreter()->builtinArray().construct(exec,List::empty())); 183 int n = 0; 184 Value curArg = thisObj; 185 Object curObj = Object::dynamicCast(thisObj); 186 ListIterator it = args.begin(); 187 for (;;) { 188 if (curArg.type() == ObjectType && 189 curObj.inherits(&ArrayInstanceImp::info)) { 190 unsigned int k = 0; 191 if (n > 0) 192 length = curObj.get(exec,"length").toUInt32(exec); 193 while (k < length) { 194 UString p = UString::from(k); 195 if (curObj.hasProperty(exec,p)) 196 arr.put(exec,UString::from(n), curObj.get(exec,p)); 197 n++; 198 k++; 199 } 200 } else { 201 arr.put(exec,UString::from(n), curArg); 202 n++; 203 } 204 if (it == args.end()) 205 break; 206 curArg = *it; 207 curObj = Object::dynamicCast(it++); // may be 0 208 } 209 arr.put(exec,"length", Number(n), DontEnum | DontDelete); 210 211 result = arr; 212 break; 213 } 214 case Pop:{ 215 216 if (length == 0) { 217 thisObj.put(exec, "length", Number(length), DontEnum | DontDelete); 218 result = Undefined(); 219 } else { 220 UString str = UString::from(length - 1); 221 result = thisObj.get(exec,str); 222 thisObj.deleteProperty(exec, str); 223 thisObj.put(exec, "length", Number(length - 1), DontEnum | DontDelete); 224 } 225 break; 226 } 227 case Push: { 228 for (int n = 0; n < args.size(); n++) 229 thisObj.put(exec,UString::from(length + n), args[n]); 230 length += args.size(); 231 thisObj.put(exec,"length", Number(length), DontEnum | DontDelete); 232 result = Number(length); 233 break; 234 } 235 case Reverse: { 236 237 unsigned int middle = length / 2; 238 239 for (unsigned int k = 0; k < middle; k++) { 240 UString str = UString::from(k); 241 UString str2 = UString::from(length - k - 1); 242 Value obj = thisObj.get(exec,str); 243 Value obj2 = thisObj.get(exec,str2); 244 if (thisObj.hasProperty(exec,str2)) { 245 if (thisObj.hasProperty(exec,str)) { 246 thisObj.put(exec, str, obj2); 247 thisObj.put(exec, str2, obj); 248 } else { 249 thisObj.put(exec, str, obj2); 250 thisObj.deleteProperty(exec, str2); 251 } 252 } else { 253 if (thisObj.hasProperty(exec, str)) { 254 thisObj.deleteProperty(exec, str); 255 thisObj.put(exec, str2, obj); 256 } else { 257 // why delete something that's not there ? Strange. 258 thisObj.deleteProperty(exec, str); 259 thisObj.deleteProperty(exec, str2); 260 } 261 } 262 } 263 result = thisObj; 264 break; 265 } 266 case Shift: { 267 if (length == 0) { 268 thisObj.put(exec, "length", Number(length), DontEnum | DontDelete); 269 result = Undefined(); 270 } else { 271 result = thisObj.get(exec, "0"); 272 for(unsigned int k = 1; k < length; k++) { 273 UString str = UString::from(k); 274 UString str2 = UString::from(k-1); 275 if (thisObj.hasProperty(exec, str)) { 276 Value obj = thisObj.get(exec, str); 277 thisObj.put(exec, str2, obj); 278 } else 279 thisObj.deleteProperty(exec, str2); 280 } 281 thisObj.deleteProperty(exec, UString::from(length - 1)); 282 thisObj.put(exec, "length", Number(length - 1), DontEnum | DontDelete); 283 } 284 break; 285 } 286 case Slice: { 287 // http://developer.netscape.com/docs/manuals/js/client/jsref/array.htm#1193713 or 15.4.4.10 288 289 // We return a new array 290 Object resObj = Object::dynamicCast(exec->interpreter()->builtinArray().construct(exec,List::empty())); 291 result = resObj; 292 int begin = args[0].toUInt32(exec); 293 if ( begin < 0 ) 294 begin = maxInt( begin + length, 0 ); 295 else 296 begin = minInt( begin, length ); 297 int end = length; 298 if (args[1].type() != UndefinedType) 299 { 300 end = args[1].toUInt32(exec); 301 if ( end < 0 ) 302 end = maxInt( end + length, 0 ); 303 else 304 end = minInt( end, length ); 305 } 306 307 //printf( "Slicing from %d to %d \n", begin, end ); 308 for(unsigned int k = 0; k < (unsigned int) end-begin; k++) { 309 UString str = UString::from(k+begin); 310 if (thisObj.hasProperty(exec,str)) { 311 UString str2 = UString::from(k); 312 Value obj = thisObj.get(exec, str); 313 resObj.put(exec, str2, obj); 314 } 315 } 316 resObj.put(exec, "length", Number(end - begin), DontEnum | DontDelete); 317 break; 318 } 319 case Sort:{ 320 #if 0 321 printf("KJS Array::Sort length=%d\n", length); 322 for ( unsigned int i = 0 ; i<length ; ++i ) 323 printf("KJS Array::Sort: %d: %s\n", i, thisObj.get(UString::from(i)).toString().value().ascii() ); 324 #endif 325 Object sortFunction; 326 bool useSortFunction = (args[0].type() != UndefinedType); 327 if (useSortFunction) 328 { 329 sortFunction = args[0].toObject(exec); 330 if (!sortFunction.implementsCall()) 331 useSortFunction = false; 332 } 333 334 if (length == 0) { 335 thisObj.put(exec, "length", Number(0), DontEnum | DontDelete); 336 result = Undefined(); 337 break; 338 } 339 340 // "Min" sort. Not the fastest, but definitely less code than heapsort 341 // or quicksort, and much less swapping than bubblesort/insertionsort. 342 for ( unsigned int i = 0 ; i<length-1 ; ++i ) 343 { 344 Value iObj = thisObj.get(exec,UString::from(i)); 345 unsigned int themin = i; 346 Value minObj = iObj; 347 for ( unsigned int j = i+1 ; j<length ; ++j ) 348 { 349 Value jObj = thisObj.get(exec,UString::from(j)); 350 int cmp; 351 if ( useSortFunction ) 352 { 353 List l; 354 l.append(jObj); 355 l.append(minObj); 356 Object thisObj = exec->interpreter()->globalObject(); 357 cmp = sortFunction.call(exec,thisObj, l ).toInt32(exec); 358 } 359 else 360 cmp = (jObj.toString(exec) < minObj.toString(exec)) ? -1 : 1; 361 if ( cmp < 0 ) 362 { 363 themin = j; 364 minObj = jObj; 365 } 366 } 367 // Swap themin and i 368 if ( themin > i ) 369 { 370 //printf("KJS Array::Sort: swapping %d and %d\n", i, themin ); 371 thisObj.put( exec, UString::from(i), minObj ); 372 thisObj.put( exec, UString::from(themin), iObj ); 373 } 374 } 375 #if 0 376 printf("KJS Array::Sort -- Resulting array:\n"); 377 for ( unsigned int i = 0 ; i<length ; ++i ) 378 printf("KJS Array::Sort: %d: %s\n", i, thisObj.get(UString::from(i)).toString().value().ascii() ); 379 #endif 380 result = thisObj; 381 break; 382 } 383 case Splice: { 384 // 15.4.4.12 - oh boy this is huge 385 Object resObj = Object::dynamicCast(exec->interpreter()->builtinArray().construct(exec,List::empty())); 386 result = resObj; 387 int begin = args[0].toUInt32(exec); 388 if ( begin < 0 ) 389 begin = maxInt( begin + length, 0 ); 390 else 391 begin = minInt( begin, length ); 392 unsigned int deleteCount = minInt( maxInt( args[1].toUInt32(exec), 0 ), length - begin ); 393 394 //printf( "Splicing from %d, deleteCount=%d \n", begin, deleteCount ); 395 for(unsigned int k = 0; k < deleteCount; k++) { 396 UString str = UString::from(k+begin); 397 if (thisObj.hasProperty(exec,str)) { 398 UString str2 = UString::from(k); 399 Value obj = thisObj.get(exec, str); 400 resObj.put(exec, str2, obj); 401 } 402 } 403 resObj.put(exec, "length", Number(deleteCount), DontEnum | DontDelete); 404 405 unsigned int additionalArgs = maxInt( args.size() - 2, 0 ); 406 if ( additionalArgs != deleteCount ) 407 { 408 if ( additionalArgs < deleteCount ) 409 { 410 for ( unsigned int k = begin; k < length - deleteCount; ++k ) 411 { 412 UString str = UString::from(k+deleteCount); 413 UString str2 = UString::from(k+additionalArgs); 414 if (thisObj.hasProperty(exec,str)) { 415 Value obj = thisObj.get(exec, str); 416 thisObj.put(exec, str2, obj); 417 } 418 else 419 thisObj.deleteProperty(exec, str2); 420 } 421 for ( unsigned int k = length ; k > length - deleteCount + additionalArgs; --k ) 422 thisObj.deleteProperty(exec, UString::from(k-1)); 423 } 424 else 425 { 426 for ( unsigned int k = length - deleteCount; (int)k > begin; --k ) 427 { 428 UString str = UString::from(k+deleteCount-1); 429 UString str2 = UString::from(k+additionalArgs-1); 430 if (thisObj.hasProperty(exec,str)) { 431 Value obj = thisObj.get(exec, str); 432 thisObj.put(exec, str2, obj); 433 } 434 else 435 thisObj.deleteProperty(exec, str2); 436 } 437 } 438 } 439 for ( unsigned int k = 0; k < additionalArgs; ++k ) 440 { 441 thisObj.put(exec, UString::from(k+begin), args[k+2]); 442 } 443 thisObj.put(exec, "length", Number(length - deleteCount + additionalArgs), DontEnum | DontDelete); 444 break; 445 } 446 case UnShift: { // 15.4.4.13 447 unsigned int nrArgs = args.size(); 448 for ( unsigned int k = length; k > 0; --k ) 449 { 450 UString str = UString::from(k-1); 451 UString str2 = UString::from(k+nrArgs-1); 452 if (thisObj.hasProperty(exec,str)) { 453 Value obj = thisObj.get(exec, str); 454 thisObj.put(exec, str2, obj); 455 } else { 456 thisObj.deleteProperty(exec, str2); 457 } 458 } 459 for ( unsigned int k = 0; k < nrArgs; ++k ) 460 thisObj.put(exec, UString::from(k), args[k]); 461 result = Number(length + nrArgs); 462 thisObj.put(exec, "length", result, DontEnum | DontDelete); 463 break; 464 } 465 default: 466 assert(0); 467 break; 468 } 469 return result; 470 } 471 472 // ------------------------------ ArrayObjectImp ------------------------------- 473 474 ArrayObjectImp::ArrayObjectImp(ExecState *exec, 475 FunctionPrototypeImp *funcProto, 476 ArrayPrototypeImp *arrayProto) 477 : InternalFunctionImp(funcProto) 478 { 479 Value protect(this); 32 480 // ECMA 15.4.3.1 Array.prototype 33 setPrototypeProperty(arrayProto); 34 } 35 36 // ECMA 15.6.1 37 Completion ArrayObject::execute(const List &args) 38 { 39 // equivalent to 'new Array(....)' 40 KJSO result = construct(args); 41 42 return Completion(ReturnValue, result); 43 } 44 45 // ECMA 15.6.2 46 Object ArrayObject::construct(const List &args) 47 { 48 Object result = Object::create(ArrayClass); 481 put(exec,"prototype", Object(arrayProto), DontEnum|DontDelete|ReadOnly); 482 483 // no. of arguments for constructor 484 put(exec,"length", Number(1), ReadOnly|DontDelete|DontEnum); 485 } 486 487 bool ArrayObjectImp::implementsConstruct() const 488 { 489 return true; 490 } 491 492 // ECMA 15.4.2 493 Object ArrayObjectImp::construct(ExecState *exec, const List &args) 494 { 495 Object result(new ArrayInstanceImp(exec->interpreter()->builtinArrayPrototype())); 49 496 50 497 unsigned int len; 51 498 ListIterator it = args.begin(); 52 499 // a single argument might denote the array size 53 if (args.size() == 1 && it-> isA(NumberType))54 len = it->toUInt32( );500 if (args.size() == 1 && it->type() == NumberType) 501 len = it->toUInt32(exec); 55 502 else { 56 503 // initialize array 57 504 len = args.size(); 58 505 for (unsigned int u = 0; it != args.end(); it++, u++) 59 result.put( UString::from(u), *it);506 result.put(exec, UString::from(u), *it); 60 507 } 61 508 62 509 // array size 63 result.put("length", len, DontEnum | DontDelete); 510 result.put(exec, "length", Number(len), DontEnum | DontDelete); 511 static_cast<ArrayInstanceImp*>(result.imp())->putDirect(exec, "length", Number(len), DontEnum | DontDelete); 64 512 65 513 return result; 66 514 } 67 515 68 // ECMA 15.6.4 69 ArrayPrototype::ArrayPrototype(const Object& proto) 70 : ObjectImp(ArrayClass, Null(), proto) 71 { 72 // The constructor will be added later in ArrayObject's constructor 73 74 put("length", 0u, DontEnum | DontDelete); 75 } 76 77 KJSO ArrayPrototype::get(const UString &p) const 78 { 79 int id; 80 if(p == "toString") 81 id = ArrayProtoFunc::ToString; 82 else if(p == "toLocaleString") 83 id = ArrayProtoFunc::ToLocaleString; 84 else if(p == "concat") 85 id = ArrayProtoFunc::Concat; 86 else if (p == "join") 87 id = ArrayProtoFunc::Join; 88 else if(p == "pop") 89 id = ArrayProtoFunc::Pop; 90 else if(p == "push") 91 id = ArrayProtoFunc::Push; 92 else if(p == "reverse") 93 id = ArrayProtoFunc::Reverse; 94 else if(p == "shift") 95 id = ArrayProtoFunc::Shift; 96 else if(p == "slice") 97 id = ArrayProtoFunc::Slice; 98 else if(p == "sort") 99 id = ArrayProtoFunc::Sort; 100 else if(p == "splice") 101 id = ArrayProtoFunc::Splice; 102 else if(p == "unshift") 103 id = ArrayProtoFunc::UnShift; 104 else 105 return Imp::get(p); 106 107 return Function(new ArrayProtoFunc(id)); 108 } 109 110 // ECMA 15.4.4 111 Completion ArrayProtoFunc::execute(const List &args) 112 { 113 KJSO result, obj, obj2; 114 Object thisObj = Object::dynamicCast(thisValue()); 115 unsigned int length = thisObj.get("length").toUInt32(); 116 unsigned int middle; 117 UString str = "", str2; 118 UString separator = ","; 119 120 switch (id) { 121 case ToLocaleString: 122 /* TODO */ 123 // fall trough 124 case ToString: 125 if (!thisObj.getClass() == ArrayClass) { 126 result = Error::create(TypeError); 127 break; 128 } 129 // fall trough 130 case Join: 131 { 132 if (!args[0].isA(UndefinedType)) 133 separator = args[0].toString().value(); 134 for (unsigned int k = 0; k < length; k++) { 135 if (k >= 1) 136 str += separator; 137 obj = thisObj.get(UString::from(k)); 138 if (!obj.isA(UndefinedType) && !obj.isA(NullType)) 139 str += obj.toString().value(); 140 } 141 } 142 result = String(str); 143 break; 144 case Concat: { 145 result = Object::create(ArrayClass); 146 int n = 0; 147 obj = thisObj; 148 ListIterator it = args.begin(); 149 for (;;) { 150 if (obj.isA(ObjectType) && 151 static_cast<Object&>(obj).getClass() == ArrayClass) { 152 unsigned int k = 0; 153 if (n > 0) 154 length = obj.get("length").toUInt32(); 155 while (k < length) { 156 UString p = UString::from(k); 157 if (obj.hasProperty(p)) 158 result.put(UString::from(n), obj.get(p)); 159 n++; 160 k++; 161 } 162 } else { 163 result.put(UString::from(n), obj); 164 n++; 165 } 166 if (it == args.end()) 167 break; 168 obj = it++; 169 } 170 result.put("length", Number(n), DontEnum | DontDelete); 171 } 172 break; 173 case Pop: 174 if (length == 0) { 175 thisObj.put("length", Number(length), DontEnum | DontDelete); 176 result = Undefined(); 177 } else { 178 str = UString::from(length - 1); 179 result = thisObj.get(str); 180 thisObj.deleteProperty(str); 181 thisObj.put("length", length - 1, DontEnum | DontDelete); 182 } 183 break; 184 case Push: 185 { 186 for (int n = 0; n < args.size(); n++) 187 thisObj.put(UString::from(length + n), args[n]); 188 length += args.size(); 189 thisObj.put("length", length, DontEnum | DontDelete); 190 result = Number(length); 191 } 192 break; 193 case Reverse: 194 { 195 middle = length / 2; 196 for (unsigned int k = 0; k < middle; k++) { 197 str = UString::from(k); 198 str2 = UString::from(length - k - 1); 199 obj = thisObj.get(str); 200 obj2 = thisObj.get(str2); 201 if (thisObj.hasProperty(str2)) { 202 if (thisObj.hasProperty(str)) { 203 thisObj.put(str, obj2); 204 thisObj.put(str2, obj); 205 } else { 206 thisObj.put(str, obj2); 207 thisObj.deleteProperty(str2); 208 } 209 } else { 210 if (thisObj.hasProperty(str)) { 211 thisObj.deleteProperty(str); 212 thisObj.put(str2, obj); 213 } else { 214 // why delete something that's not there ? Strange. 215 thisObj.deleteProperty(str); 216 thisObj.deleteProperty(str2); 217 } 218 } 219 } 220 } 221 result = thisObj; 222 break; 223 case Shift: 224 if (length == 0) { 225 thisObj.put("length", Number(length), DontEnum | DontDelete); 226 result = Undefined(); 227 } else { 228 result = thisObj.get("0"); 229 for(unsigned int k = 1; k < length; k++) { 230 str = UString::from(k); 231 str2 = UString::from(k-1); 232 if (thisObj.hasProperty(str)) { 233 obj = thisObj.get(str); 234 thisObj.put(str2, obj); 235 } else 236 thisObj.deleteProperty(str2); 237 } 238 thisObj.deleteProperty(UString::from(length - 1)); 239 thisObj.put("length", length - 1, DontEnum | DontDelete); 240 } 241 break; 242 case Slice: // http://developer.netscape.com/docs/manuals/js/client/jsref/array.htm#1193713 243 { 244 result = Object::create(ArrayClass); // We return a new array 245 int begin = args[0].toUInt32(); 246 int end = length; 247 if (!args[1].isA(UndefinedType)) 248 { 249 end = args[1].toUInt32(); 250 if ( end < 0 ) 251 end += length; 252 } 253 // safety tests 254 if ( begin < 0 || end < 0 || begin >= end ) { 255 result.put("length", Number(0), DontEnum | DontDelete); 256 break; 257 } 258 //printf( "Slicing from %d to %d \n", begin, end ); 259 for(unsigned int k = 0; k < (unsigned int) end-begin; k++) { 260 str = UString::from(k+begin); 261 str2 = UString::from(k); 262 if (thisObj.hasProperty(str)) { 263 obj = thisObj.get(str); 264 result.put(str2, obj); 265 } 266 } 267 result.put("length", end - begin, DontEnum | DontDelete); 268 break; 269 } 270 case Sort: 271 { 272 #if 0 273 printf("KJS Array::Sort length=%d\n", length); 274 for ( unsigned int i = 0 ; i<length ; ++i ) 275 printf("KJS Array::Sort: %d: %s\n", i, thisObj.get(UString::from(i)).toString().value().ascii() ); 276 #endif 277 Object sortFunction; 278 bool useSortFunction = !args[0].isA(UndefinedType); 279 if (useSortFunction) 280 { 281 sortFunction = args[0].toObject(); 282 if (!sortFunction.implementsCall()) 283 useSortFunction = false; 284 } 285 286 if (length == 0) { 287 thisObj.put("length", Number(0), DontEnum | DontDelete); 288 result = Undefined(); 289 break; 290 } 291 292 // "Min" sort. Not the fastest, but definitely less code than heapsort 293 // or quicksort, and much less swapping than bubblesort/insertionsort. 294 for ( unsigned int i = 0 ; i<length-1 ; ++i ) 295 { 296 KJSO iObj = thisObj.get(UString::from(i)); 297 unsigned int themin = i; 298 KJSO minObj = iObj; 299 for ( unsigned int j = i+1 ; j<length ; ++j ) 300 { 301 KJSO jObj = thisObj.get(UString::from(j)); 302 int cmp; 303 if ( useSortFunction ) 304 { 305 List l; 306 l.append(jObj); 307 l.append(minObj); 308 cmp = sortFunction.executeCall( Global::current(), &l ).toInt32(); 309 } 310 else 311 cmp = ( jObj.toString().value() < minObj.toString().value() ) ? -1 : 1; 312 if ( cmp < 0 ) 313 { 314 themin = j; 315 minObj = jObj; 316 } 317 } 318 // Swap themin and i 319 if ( themin > i ) 320 { 321 //printf("KJS Array::Sort: swapping %d and %d\n", i, themin ); 322 thisObj.put( UString::from(i), minObj ); 323 thisObj.put( UString::from(themin), iObj ); 324 } 325 } 326 #if 0 327 printf("KJS Array::Sort -- Resulting array:\n"); 328 for ( unsigned int i = 0 ; i<length ; ++i ) 329 printf("KJS Array::Sort: %d: %s\n", i, thisObj.get(UString::from(i)).toString().value().ascii() ); 330 #endif 331 result = thisObj; 332 break; 333 } 334 // TODO Splice 335 // TODO Unshift 336 default: 337 result = Undefined(); 338 } 339 340 return Completion(ReturnValue, result); 341 } 516 bool ArrayObjectImp::implementsCall() const 517 { 518 return true; 519 } 520 521 // ECMA 15.6.1 522 Value ArrayObjectImp::call(ExecState *exec, Object &/*thisObj*/, const List &args) 523 { 524 // equivalent to 'new Array(....)' 525 return construct(exec,args); 526 } 527 -
trunk/JavaScriptCore/kjs/array_object.h
r6 r798 1 // -*- c-basic-offset: 2 -*- 1 2 /* 2 3 * This file is part of the KDE libraries … … 16 17 * License along with this library; if not, write to the Free Software 17 18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 * 20 * $Id$ 18 21 */ 19 22 … … 21 24 #define _ARRAY_OBJECT_H_ 22 25 23 #include " object.h"24 #include "function .h"26 #include "internal.h" 27 #include "function_object.h" 25 28 26 29 namespace KJS { 27 30 28 class Array Object : public ConstructorImp {31 class ArrayInstanceImp : public ObjectImp { 29 32 public: 30 ArrayObject(const Object &funcProto, const Object &arrayProto); 31 Completion execute(const List &); 32 Object construct(const List &); 33 ArrayInstanceImp(const Object &proto); 34 35 virtual void put(ExecState *exec, const UString &propertyName, const Value &value, int attr = None); 36 virtual void putDirect(ExecState *exec, const UString &propertyName, const Value &value, int attr = None); 37 38 virtual const ClassInfo *classInfo() const { return &info; } 39 static const ClassInfo info; 33 40 }; 34 41 35 class ArrayPrototype : public ObjectImp {42 class ArrayPrototypeImp : public ArrayInstanceImp { 36 43 public: 37 ArrayPrototype(const Object& proto); 38 virtual KJSO get(const UString &p) const; 44 ArrayPrototypeImp(ExecState *exec, 45 ObjectPrototypeImp *objProto); 46 Value get(ExecState *exec, const UString &p) const; 47 virtual const ClassInfo *classInfo() const { return &info; } 48 static const ClassInfo info; 39 49 }; 40 50 41 class ArrayProtoFunc : public InternalFunctionImp {51 class ArrayProtoFuncImp : public InternalFunctionImp { 42 52 public: 43 ArrayProtoFunc(int i) : id(i) { } 44 Completion execute(const List &); 53 ArrayProtoFuncImp(ExecState *exec, int i, int len); 54 55 virtual bool implementsCall() const; 56 virtual Value call(ExecState *exec, Object &thisObj, const List &args); 57 45 58 enum { ToString, ToLocaleString, Concat, Join, Pop, Push, 46 59 Reverse, Shift, Slice, Sort, Splice, UnShift }; … … 49 62 }; 50 63 64 class ArrayObjectImp : public InternalFunctionImp { 65 public: 66 ArrayObjectImp(ExecState *exec, 67 FunctionPrototypeImp *funcProto, 68 ArrayPrototypeImp *arrayProto); 69 70 virtual bool implementsConstruct() const; 71 virtual Object construct(ExecState *exec, const List &args); 72 virtual bool implementsCall() const; 73 virtual Value call(ExecState *exec, Object &thisObj, const List &args); 74 75 }; 76 51 77 }; // namespace 52 78 -
trunk/JavaScriptCore/kjs/bool_object.cpp
r6 r798 1 // -*- c-basic-offset: 2 -*- 1 2 /* 2 3 * This file is part of the KDE libraries … … 16 17 * License along with this library; if not, write to the Free Software 17 18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 * 18 20 */ 19 21 20 #include "kjs.h" 22 #include "value.h" 23 #include "object.h" 24 #include "types.h" 25 #include "interpreter.h" 21 26 #include "operations.h" 22 #include "types.h"23 27 #include "bool_object.h" 24 28 #include "error_object.h" 25 29 30 #include <assert.h> 31 26 32 using namespace KJS; 27 33 28 BooleanObject::BooleanObject(const KJSO& funcProto, const KJSO &booleanProto) 29 : ConstructorImp(funcProto, 1) 34 // ------------------------------ BooleanInstanceImp --------------------------- 35 36 const ClassInfo BooleanInstanceImp::info = {"Boolean", 0, 0, 0}; 37 38 BooleanInstanceImp::BooleanInstanceImp(const Object &proto) 39 : ObjectImp(proto) 30 40 { 31 // Boolean.prototype 32 setPrototypeProperty(booleanProto); 41 } 42 43 // ------------------------------ BooleanPrototypeImp -------------------------- 44 45 // ECMA 15.6.4 46 47 BooleanPrototypeImp::BooleanPrototypeImp(ExecState *exec, 48 ObjectPrototypeImp *objectProto, 49 FunctionPrototypeImp *funcProto) 50 : BooleanInstanceImp(Object(objectProto)) 51 { 52 Value protect(this); 53 // The constructor will be added later by InterpreterImp::InterpreterImp() 54 55 put(exec,"toString", Object(new BooleanProtoFuncImp(exec,funcProto,BooleanProtoFuncImp::ToString,0)), DontEnum); 56 put(exec,"valueOf", Object(new BooleanProtoFuncImp(exec,funcProto,BooleanProtoFuncImp::ValueOf,0)), DontEnum); 57 setInternalValue(Boolean(false)); 58 } 59 60 61 // ------------------------------ BooleanProtoFuncImp -------------------------- 62 63 BooleanProtoFuncImp::BooleanProtoFuncImp(ExecState *exec, 64 FunctionPrototypeImp *funcProto, int i, int len) 65 : InternalFunctionImp(funcProto), id(i) 66 { 67 Value protect(this); 68 put(exec,"length",Number(len),DontDelete|ReadOnly|DontEnum); 69 } 70 71 72 bool BooleanProtoFuncImp::implementsCall() const 73 { 74 return true; 75 } 76 77 78 // ECMA 15.6.4.2 + 15.6.4.3 79 Value BooleanProtoFuncImp::call(ExecState *exec, Object &thisObj, const List &/*args*/) 80 { 81 // no generic function. "this" has to be a Boolean object 82 if (!thisObj.inherits(&BooleanInstanceImp::info)) { 83 Object err = Error::create(exec,TypeError); 84 exec->setException(err); 85 return err; 86 } 87 88 // execute "toString()" or "valueOf()", respectively 89 90 Value v = thisObj.internalValue(); 91 assert(!v.isNull()); 92 93 if (id == ToString) 94 return String(v.toString(exec)); 95 else 96 return Boolean(v.toBoolean(exec)); /* TODO: optimize for bool case */ 97 } 98 99 // ------------------------------ BooleanObjectImp ----------------------------- 100 101 102 BooleanObjectImp::BooleanObjectImp(ExecState *exec, FunctionPrototypeImp *funcProto, 103 BooleanPrototypeImp *booleanProto) 104 : InternalFunctionImp(funcProto) 105 { 106 Value protect(this); 107 put(exec,"prototype", Object(booleanProto),DontEnum|DontDelete|ReadOnly); 108 109 // no. of arguments for constructor 110 put(exec,"length", Number(1), ReadOnly|DontDelete|DontEnum); 111 } 112 113 114 bool BooleanObjectImp::implementsConstruct() const 115 { 116 return true; 117 } 118 119 // ECMA 15.6.2 120 Object BooleanObjectImp::construct(ExecState *exec, const List &args) 121 { 122 Object proto = exec->interpreter()->builtinBooleanPrototype(); 123 Object obj(new BooleanInstanceImp(proto)); 124 125 Boolean b; 126 if (args.size() > 0) 127 b = args.begin()->toBoolean(exec); 128 else 129 b = Boolean(false); 130 131 obj.setInternalValue(b); 132 133 return obj; 134 } 135 136 bool BooleanObjectImp::implementsCall() const 137 { 138 return true; 33 139 } 34 140 35 141 // ECMA 15.6.1 36 Completion BooleanObject::execute(const List &args)142 Value BooleanObjectImp::call(ExecState *exec, Object &/*thisObj*/, const List &args) 37 143 { 38 Boolean b;39 40 144 if (args.isEmpty()) 41 b =Boolean(false);145 return Boolean(false); 42 146 else 43 b = args[0].toBoolean(); 44 45 return Completion(ReturnValue, b); 147 return Boolean(args[0].toBoolean(exec)); /* TODO: optimize for bool case */ 46 148 } 47 149 48 // ECMA 15.6.249 Object BooleanObject::construct(const List &args)50 {51 Boolean b;52 if (args.size() > 0)53 b = args.begin()->toBoolean();54 else55 b = Boolean(false);56 57 return Object::create(BooleanClass, b);58 }59 60 // ECMA 15.6.461 BooleanPrototype::BooleanPrototype(const Object& proto)62 : ObjectImp(BooleanClass, Boolean(false), proto)63 {64 // The constructor will be added later in BooleanObject's constructor65 }66 67 KJSO BooleanPrototype::get(const UString &p) const68 {69 if (p == "toString")70 return Function(new BooleanProtoFunc(ToString));71 else if (p == "valueOf")72 return Function(new BooleanProtoFunc(ValueOf));73 else74 return Imp::get(p);75 }76 77 BooleanProtoFunc::BooleanProtoFunc(int i)78 : id(i)79 {80 }81 82 // ECMA 15.6.4.2 + 15.6.4.383 Completion BooleanProtoFunc::execute(const List &)84 {85 KJSO result;86 87 Object thisObj = Object::dynamicCast(thisValue());88 89 // no generic function. "this" has to be a Boolean object90 if (thisObj.isNull() || thisObj.getClass() != BooleanClass) {91 result = Error::create(TypeError);92 return Completion(ReturnValue, result);93 }94 95 // execute "toString()" or "valueOf()", respectively96 KJSO v = thisObj.internalValue();97 if (id == BooleanPrototype::ToString)98 result = v.toString();99 else100 result = v.toBoolean();101 102 return Completion(ReturnValue, result);103 } -
trunk/JavaScriptCore/kjs/bool_object.h
r6 r798 1 // -*- c-basic-offset: 2 -*- 1 2 /* 2 3 * This file is part of the KDE libraries … … 16 17 * License along with this library; if not, write to the Free Software 17 18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 * 20 * $Id$ 18 21 */ 19 22 … … 21 24 #define _BOOL_OBJECT_H_ 22 25 23 #include " object.h"24 #include "function .h"26 #include "internal.h" 27 #include "function_object.h" 25 28 26 29 namespace KJS { 27 30 28 class Boolean Object : public ConstructorImp {31 class BooleanInstanceImp : public ObjectImp { 29 32 public: 30 BooleanObject(const KJSO& funcProto, const KJSO &booleanProto); 31 Completion execute(const List &); 32 Object construct(const List &); 33 BooleanInstanceImp(const Object &proto); 34 35 virtual const ClassInfo *classInfo() const { return &info; } 36 static const ClassInfo info; 33 37 }; 34 38 35 class BooleanPrototype : public ObjectImp { 39 /** 40 * @internal 41 * 42 * The initial value of Boolean.prototype (and thus all objects created 43 * with the Boolean constructor 44 */ 45 class BooleanPrototypeImp : public BooleanInstanceImp { 36 46 public: 37 BooleanPrototype (const Object& proto);38 virtual KJSO get(const UString &p) const;39 enum { ToString, ValueOf };47 BooleanPrototypeImp(ExecState *exec, 48 ObjectPrototypeImp *objectProto, 49 FunctionPrototypeImp *funcProto); 40 50 }; 41 51 42 class BooleanProtoFunc : public InternalFunctionImp { 52 /** 53 * @internal 54 * 55 * Class to implement all methods that are properties of the 56 * Boolean.prototype object 57 */ 58 class BooleanProtoFuncImp : public InternalFunctionImp { 43 59 public: 44 BooleanProtoFunc(int i); 45 Completion execute(const List &); 60 BooleanProtoFuncImp(ExecState *exec, 61 FunctionPrototypeImp *funcProto, int i, int len); 62 63 virtual bool implementsCall() const; 64 virtual Value call(ExecState *exec, Object &thisObj, const List &args); 65 66 enum { ToString, ValueOf }; 46 67 private: 47 68 int id; 69 }; 70 71 /** 72 * @internal 73 * 74 * The initial value of the the global variable's "Boolean" property 75 */ 76 class BooleanObjectImp : public InternalFunctionImp { 77 friend class BooleanProtoFuncImp; 78 public: 79 BooleanObjectImp(ExecState *exec, FunctionPrototypeImp *funcProto, 80 BooleanPrototypeImp *booleanProto); 81 82 virtual bool implementsConstruct() const; 83 virtual Object construct(ExecState *exec, const List &args); 84 85 virtual bool implementsCall() const; 86 virtual Value call(ExecState *exec, Object &thisObj, const List &args); 48 87 }; 49 88 -
trunk/JavaScriptCore/kjs/collector.cpp
r6 r798 1 // -*- c-basic-offset: 2 -*- 1 2 /* 2 3 * This file is part of the KDE libraries 3 4 * Copyright (C) 1999-2000 Harri Porten ([email protected]) 5 * Copyright (C) 2001 Peter Kelly ([email protected]) 4 6 * 5 7 * This library is free software; you can redistribute it and/or … … 16 18 * License along with this library; if not, write to the Free Software 17 19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 20 * 21 * $Id$ 18 22 */ 19 23 20 24 #include "collector.h" 21 #include "object.h"22 25 #include "internal.h" 23 26 … … 25 28 #include <string.h> 26 29 #include <assert.h> 30 #ifdef KJS_DEBUG_MEM 31 #include <typeinfo> 32 #endif 27 33 28 34 namespace KJS { … … 62 68 unsigned long Collector::filled = 0; 63 69 unsigned long Collector::softLimit = KJS_MEM_INCREMENT; 70 71 unsigned long Collector::timesFilled = 0; 72 unsigned long Collector::increaseLimitAt = 1; 73 74 bool Collector::memLimitReached = false; 75 64 76 #ifdef KJS_DEBUG_MEM 65 77 bool Collector::collecting = false; … … 71 83 return 0L; 72 84 85 // Try and deal with memory requirements in a scalable way. Simple scripts 86 // should only require small amounts of memory, but for complex scripts we don't 87 // want to end up running the garbage collector hundreds of times a second. 73 88 if (filled >= softLimit) { 89 timesFilled++; 74 90 collect(); 75 if (filled >= softLimit && softLimit < KJS_MEM_LIMIT) // we are actually using all this memory 91 92 if (filled >= softLimit && softLimit < KJS_MEM_LIMIT) { 93 // Even after collection we are still using more than the limit, so increase 94 // the limit 76 95 softLimit *= 2; 96 } 97 else if (timesFilled == increaseLimitAt && increaseLimitAt < 128) { 98 // The allowed memory limit keeps getting reached (lots of objects created 99 // and deleted). Increase it a bit so GC gets run less often. 100 timesFilled = 0; 101 softLimit *= 2; 102 increaseLimitAt *= 2; 103 } 77 104 } 78 105 79 106 void *m = malloc(s); 80 81 // hack to ensure obj is protected from GC before any constructors are run 82 // (prev = marked, next = gcallowed) 83 static_cast<Imp*>(m)->prev = 0; 84 static_cast<Imp*>(m)->next = 0; 107 #ifdef KJS_DEBUG_MEM 108 //fprintf( stderr, "allocate: size=%d valueimp=%p\n",s,m); 109 #endif 110 111 // VI_CREATED and VI_GCALLOWED being unset ensure that value 112 // is protected from GC before any constructors are run 113 static_cast<ValueImp*>(m)->_flags = 0; 85 114 86 115 if (!root) { … … 99 128 if (block->filled >= block->size) { 100 129 #ifdef KJS_DEBUG_MEM 101 printf("allocating new block of size %d\n", block->size);130 //fprintf( stderr, "allocating new block of size %d\n", block->size); 102 131 #endif 103 132 CollectorBlock *tmp = new CollectorBlock(BlockSize); … … 116 145 117 146 if (softLimit >= KJS_MEM_LIMIT) { 118 KJScriptImp::setException("Out of memory"); 147 memLimitReached = true; 148 fprintf(stderr,"Out of memory"); 119 149 } 120 150 … … 125 155 * Mark-sweep garbage collection. 126 156 */ 127 void Collector::collect() 128 { 129 #ifdef KJS_DEBUG_MEM 130 printf("collecting %d objects total\n", Imp::count); 131 collecting = true; 132 #endif 133 134 // MARK: first set all ref counts to 0 .... 157 bool Collector::collect() 158 { 159 #ifdef KJS_DEBUG_MEM 160 fprintf(stderr,"Collector::collect()\n"); 161 #endif 162 bool deleted = false; 163 // MARK: first unmark everything 135 164 CollectorBlock *block = root; 136 165 while (block) { 137 #ifdef KJS_DEBUG_MEM 138 printf("cleaning block filled %d out of %d\n", block->filled, block->size); 139 #endif 140 Imp **r = (Imp**)block->mem; 166 ValueImp **r = (ValueImp**)block->mem; 141 167 assert(r); 142 168 for (int i = 0; i < block->size; i++, r++) 143 169 if (*r) { 144 (*r)-> setMarked(false);145 } 146 block = block->next; 147 } 148 149 // ... increase counter forall referenced objects recursively170 (*r)->_flags &= ~ValueImp::VI_MARKED; 171 } 172 block = block->next; 173 } 174 175 // mark all referenced objects recursively 150 176 // starting out from the set of root objects 151 if ( KJScriptImp::hook) {152 KJScriptImp *scr = KJScriptImp::hook;177 if (InterpreterImp::s_hook) { 178 InterpreterImp *scr = InterpreterImp::s_hook; 153 179 do { 180 //fprintf( stderr, "Collector marking interpreter %p\n",(void*)scr); 154 181 scr->mark(); 155 182 scr = scr->next; 156 } while (scr != KJScriptImp::hook);183 } while (scr != InterpreterImp::s_hook); 157 184 } 158 185 … … 160 187 block = root; 161 188 while (block) { 162 Imp **r = (Imp**)block->mem;189 ValueImp **r = (ValueImp**)block->mem; 163 190 assert(r); 164 191 for (int i = 0; i < block->size; i++, r++) 165 if (*r && (*r)->created() && ((*r)->refcount || !(*r)->gcAllowed()) && !(*r)->marked()) 166 (*r)->mark(); 192 { 193 ValueImp *imp = (*r); 194 // Check for created=true, marked=false and (gcallowed=false or refcount>0) 195 if (imp && 196 (imp->_flags & (ValueImp::VI_CREATED|ValueImp::VI_MARKED)) == ValueImp::VI_CREATED && 197 ( (imp->_flags & ValueImp::VI_GCALLOWED) == 0 || imp->refcount ) ) { 198 //fprintf( stderr, "Collector marking imp=%p\n",(void*)imp); 199 imp->mark(); 200 } 201 } 167 202 block = block->next; 168 203 } … … 171 206 block = root; 172 207 while (block) { 173 Imp **r = (Imp**)block->mem;208 ValueImp **r = (ValueImp**)block->mem; 174 209 int del = 0; 175 210 for (int i = 0; i < block->size; i++, r++) { 176 if (*r && ((*r)->refcount == 0) && !(*r)->marked() && (*r)->gcAllowed()) { 177 // emulate destructing part of 'operator delete()' 178 (*r)->~Imp(); 179 free(*r); 180 *r = 0L; 181 del++; 211 ValueImp *imp = (*r); 212 // Can delete if refcount==0, created==true, gcAllowed==true, and marked==false 213 // Make sure to update the test if you add more bits to _flags. 214 if (imp && 215 !imp->refcount && imp->_flags == (ValueImp::VI_GCALLOWED | ValueImp::VI_CREATED)) { 216 // emulate destructing part of 'operator delete()' 217 //fprintf( stderr, "Collector::deleting ValueImp %p (%s)\n", (void*)imp, typeid(*imp).name()); 218 imp->~ValueImp(); 219 free(imp); 220 *r = 0L; 221 del++; 182 222 } 183 223 } … … 185 225 block->filled -= del; 186 226 block = block->next; 187 } 188 189 // delete the emtpy containers 227 if (del) 228 deleted = true; 229 } 230 231 // delete the empty containers 190 232 block = root; 191 233 while (block) { … … 193 235 if (block->filled == 0) { 194 236 if (block->prev) 195 237 block->prev->next = next; 196 238 if (block == root) 197 239 root = next; 198 240 if (next) 199 241 next->prev = block->prev; 200 242 if (block == currentBlock) // we don't want a dangling pointer 201 243 currentBlock = 0L; 202 244 assert(block != root); 203 245 delete block; … … 205 247 block = next; 206 248 } 207 208 #ifdef KJS_DEBUG_MEM 209 collecting = false; 210 #endif 211 } 249 #if 0 250 // This is useful to track down memory leaks 251 static int s_count = 0; 252 fprintf(stderr, "Collector done (was run %d)\n",s_count); 253 if (s_count++ % 50 == 2) 254 finalCheck(); 255 #endif 256 return deleted; 257 } 258 259 #ifdef KJS_DEBUG_MEM 260 void Collector::finalCheck() 261 { 262 CollectorBlock *block = root; 263 while (block) { 264 ValueImp **r = (ValueImp**)block->mem; 265 for (int i = 0; i < block->size; i++, r++) { 266 if (*r ) { 267 fprintf( stderr, "Collector::finalCheck() still having ValueImp %p (%s) [marked:%d gcAllowed:%d created:%d refcount:%d]\n", 268 (void*)(*r), typeid( **r ).name(), 269 (bool)((*r)->_flags & ValueImp::VI_MARKED), 270 (bool)((*r)->_flags & ValueImp::VI_GCALLOWED), 271 (bool)((*r)->_flags & ValueImp::VI_CREATED), 272 (*r)->refcount); 273 } 274 } 275 block = block->next; 276 } 277 } 278 #endif -
trunk/JavaScriptCore/kjs/collector.h
r6 r798 1 // -*- c-basic-offset: 2 -*- 1 2 /* 2 3 * This file is part of the KDE libraries 3 4 * Copyright (C) 1999-2000 Harri Porten ([email protected]) 5 * Copyright (C) 2001 Peter Kelly ([email protected]) 4 6 * 5 7 * This library is free software; you can redistribute it and/or … … 16 18 * License along with this library; if not, write to the Free Software 17 19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 20 * 21 * $Id$ 18 22 */ 19 23 … … 40 44 #include <stdlib.h> 41 45 46 // for DEBUG_* 47 #include "value.h" 48 #include "object.h" 49 #include "types.h" 50 #include "interpreter.h" 51 42 52 namespace KJS { 43 53 44 class Imp;45 54 class CollectorBlock; 46 55 … … 66 75 * Run the garbage collection. This involves calling the delete operator 67 76 * on each object and freeing the used memory. 68 * In the current implemenation this will basically free all registered69 * object regardless whether they are still references by others or not.70 *71 77 */ 72 static voidcollect();78 static bool collect(); 73 79 static int size() { return filled; } 80 static bool outOfMemory() { return memLimitReached; } 74 81 75 82 #ifdef KJS_DEBUG_MEM 83 /** Check that nothing is left when the last interpreter gets deleted */ 84 static void finalCheck(); 76 85 /** 77 86 * @internal … … 84 93 static unsigned long filled; 85 94 static unsigned long softLimit; 95 static unsigned long timesFilled; 96 static unsigned long increaseLimitAt; 97 static bool memLimitReached; 86 98 enum { BlockSize = 100 }; 87 99 }; -
trunk/JavaScriptCore/kjs/date_object.cpp
r6 r798 1 // -*- c-basic-offset: 2 -*- 1 2 /* 2 3 * This file is part of the KDE libraries … … 16 17 * License along with this library; if not, write to the Free Software 17 18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 * 20 * $Id$ 18 21 */ 19 22 … … 46 49 #include <string.h> 47 50 #include <stdio.h> 51 #include <stdlib.h> 48 52 #include <locale.h> 49 50 #include "kjs.h" 53 #include <ctype.h> 54 51 55 #include "date_object.h" 52 53 namespace KJS { 54 55 class DateObjectFunc : public InternalFunctionImp { 56 public: 57 DateObjectFunc(int i) : id(i) { }; 58 Completion execute(const List &); 59 enum { Parse, UTC }; 60 private: 61 int id; 62 }; 63 64 class DateProtoFunc : public InternalFunctionImp { 65 public: 66 DateProtoFunc(int i, bool u); 67 Completion execute(const List &); 68 enum { ToString, ToDateString, ToTimeString, ToLocaleString, 69 ToLocaleDateString, ToLocaleTimeString, ValueOf, GetTime, 70 GetFullYear, GetMonth, GetDate, GetDay, GetHours, GetMinutes, 71 GetSeconds, GetMilliSeconds, GetTimezoneOffset, SetTime, 72 SetMilliSeconds, SetSeconds, SetMinutes, SetHours, SetDate, 73 SetMonth, SetFullYear, ToUTCString, 74 // non-normative properties (Appendix B) 75 GetYear, SetYear, ToGMTString }; 76 private: 77 int id; 78 bool utc; 79 }; 80 81 // helper functions 82 KJSO parseDate(const String &s); 83 KJSO timeClip(const KJSO &t); 84 }; 56 #include "error_object.h" 57 #include "operations.h" 58 59 #include "date_object.lut.h" 85 60 86 61 using namespace KJS; 87 62 88 KJSO KJS::parseDate(const String &s) 63 // ------------------------------ DateInstanceImp ------------------------------ 64 65 const ClassInfo DateInstanceImp::info = {"Date", 0, 0, 0}; 66 67 DateInstanceImp::DateInstanceImp(const Object &proto) 68 : ObjectImp(proto) 69 { 70 } 71 72 // ------------------------------ DatePrototypeImp ----------------------------- 73 74 const ClassInfo DatePrototypeImp::info = {"Date", 0, &dateTable, 0}; 75 76 /* Source for date_object.lut.h 77 We use a negative ID to denote the "UTC" variant. 78 @begin dateTable 61 79 toString DateProtoFuncImp::ToString DontEnum|Function 0 80 toUTCString -DateProtoFuncImp::ToString DontEnum|Function 0 81 toDateString DateProtoFuncImp::ToDateString DontEnum|Function 0 82 toTimeString DateProtoFuncImp::ToTimeString DontEnum|Function 0 83 toLocaleString DateProtoFuncImp::ToLocaleString DontEnum|Function 0 84 toLocaleDateString DateProtoFuncImp::ToLocaleDateString DontEnum|Function 0 85 toLocaleTimeString DateProtoFuncImp::ToLocaleTimeString DontEnum|Function 0 86 valueOf DateProtoFuncImp::ValueOf DontEnum|Function 0 87 getTime DateProtoFuncImp::GetTime DontEnum|Function 0 88 getFullYear DateProtoFuncImp::GetFullYear DontEnum|Function 0 89 getUTCFullYear -DateProtoFuncImp::GetFullYear DontEnum|Function 0 90 toGMTString DateProtoFuncImp::ToGMTString DontEnum|Function 0 91 getMonth DateProtoFuncImp::GetMonth DontEnum|Function 0 92 getUTCMonth -DateProtoFuncImp::GetMonth DontEnum|Function 0 93 getDate DateProtoFuncImp::GetDate DontEnum|Function 0 94 getUTCDate -DateProtoFuncImp::GetDate DontEnum|Function 0 95 getDay DateProtoFuncImp::GetDay DontEnum|Function 0 96 getUTCDay -DateProtoFuncImp::GetDay DontEnum|Function 0 97 getHours DateProtoFuncImp::GetHours DontEnum|Function 0 98 getUTCHours -DateProtoFuncImp::GetHours DontEnum|Function 0 99 getMinutes DateProtoFuncImp::GetMinutes DontEnum|Function 0 100 getUTCMinutes -DateProtoFuncImp::GetMinutes DontEnum|Function 0 101 getSeconds DateProtoFuncImp::GetSeconds DontEnum|Function 0 102 getUTCSeconds -DateProtoFuncImp::GetSeconds DontEnum|Function 0 103 getMilliseconds DateProtoFuncImp::GetMilliSeconds DontEnum|Function 0 104 getUTCMilliseconds -DateProtoFuncImp::GetMilliSeconds DontEnum|Function 0 105 getTimezoneOffset DateProtoFuncImp::GetTimezoneOffset DontEnum|Function 0 106 setTime DateProtoFuncImp::SetTime DontEnum|Function 1 107 setMilliseconds DateProtoFuncImp::SetMilliSeconds DontEnum|Function 1 108 setUTCMilliseconds -DateProtoFuncImp::SetMilliSeconds DontEnum|Function 1 109 setSeconds DateProtoFuncImp::SetSeconds DontEnum|Function 2 110 setUTCSeconds -DateProtoFuncImp::SetSeconds DontEnum|Function 2 111 setMinutes DateProtoFuncImp::SetMinutes DontEnum|Function 3 112 setUTCMinutes -DateProtoFuncImp::SetMinutes DontEnum|Function 3 113 setHours DateProtoFuncImp::SetHours DontEnum|Function 4 114 setUTCHours -DateProtoFuncImp::SetHours DontEnum|Function 4 115 setDate DateProtoFuncImp::SetDate DontEnum|Function 1 116 setUTCDate -DateProtoFuncImp::SetDate DontEnum|Function 1 117 setMonth DateProtoFuncImp::SetMonth DontEnum|Function 2 118 setUTCMonth -DateProtoFuncImp::SetMonth DontEnum|Function 2 119 setFullYear DateProtoFuncImp::SetFullYear DontEnum|Function 3 120 setUTCFullYear -DateProtoFuncImp::SetFullYear DontEnum|Function 3 121 setYear DateProtoFuncImp::SetYear DontEnum|Function 1 122 getYear DateProtoFuncImp::GetYear DontEnum|Function 0 123 toGMTString DateProtoFuncImp::ToGMTString DontEnum|Function 0 124 @end 125 */ 126 // ECMA 15.9.4 127 128 DatePrototypeImp::DatePrototypeImp(ExecState *, 129 ObjectPrototypeImp *objectProto) 130 : DateInstanceImp(Object(objectProto)) 131 { 132 Value protect(this); 133 setInternalValue(Number(NaN)); 134 // The constructor will be added later, after DateObjectImp has been built 135 } 136 137 Value DatePrototypeImp::get(ExecState *exec, const UString &propertyName) const 138 { 139 return lookupGetFunction<DateProtoFuncImp, ObjectImp>( exec, propertyName, &dateTable, this ); 140 } 141 142 // ------------------------------ DateProtoFuncImp ----------------------------- 143 144 DateProtoFuncImp::DateProtoFuncImp(ExecState *exec, int i, int len) 145 : InternalFunctionImp( 146 static_cast<FunctionPrototypeImp*>(exec->interpreter()->builtinFunctionPrototype().imp()) 147 ), id(abs(i)), utc(i<0) 148 // We use a negative ID to denote the "UTC" variant. 149 { 150 Value protect(this); 151 put(exec,"length",Number(len),DontDelete|ReadOnly|DontEnum); 152 } 153 154 bool DateProtoFuncImp::implementsCall() const 155 { 156 return true; 157 } 158 159 Value DateProtoFuncImp::call(ExecState *exec, Object &thisObj, const List &args) 160 { 161 if ((id == ToString || id == ValueOf || id == GetTime || id == SetTime) && 162 !thisObj.inherits(&DateInstanceImp::info)) { 163 // non-generic function called on non-date object 164 165 // ToString and ValueOf are generic according to the spec, but the mozilla 166 // tests suggest otherwise... 167 Object err = Error::create(exec,TypeError); 168 exec->setException(err); 169 return err; 170 } 171 172 173 Value result; 174 UString s; 175 const int bufsize=100; 176 char timebuffer[bufsize]; 177 char *oldlocale = setlocale(LC_TIME,NULL); 178 if (!oldlocale) 179 oldlocale = setlocale(LC_ALL, NULL); 180 Value v = thisObj.internalValue(); 181 double milli = v.toNumber(exec); 182 time_t tv = (time_t) floor(milli / 1000.0); 183 int ms = int(milli - tv * 1000.0); 184 185 struct tm *t; 186 if (utc) 187 t = gmtime(&tv); 188 else 189 t = localtime(&tv); 190 191 switch (id) { 192 case ToString: 193 s = ctime(&tv); 194 result = String(s.substr(0, s.size() - 1)); 195 break; 196 case ToDateString: 197 case ToTimeString: 198 case ToGMTString: 199 setlocale(LC_TIME,"C"); 200 if (id == DateProtoFuncImp::ToDateString) { 201 strftime(timebuffer, bufsize, "%x",t); 202 } else if (id == DateProtoFuncImp::ToTimeString) { 203 strftime(timebuffer, bufsize, "%X",t); 204 } else { 205 t = gmtime(&tv); 206 strftime(timebuffer, bufsize, "%a, %d-%b-%y %H:%M:%S %Z", t); 207 } 208 setlocale(LC_TIME,oldlocale); 209 result = String(timebuffer); 210 break; 211 case ToLocaleString: 212 strftime(timebuffer, bufsize, "%c", t); 213 result = String(timebuffer); 214 break; 215 case ToLocaleDateString: 216 strftime(timebuffer, bufsize, "%x", t); 217 result = String(timebuffer); 218 break; 219 case ToLocaleTimeString: 220 strftime(timebuffer, bufsize, "%X", t); 221 result = String(timebuffer); 222 break; 223 case ValueOf: 224 result = Number(milli); 225 break; 226 case GetTime: 227 result = Number(milli); 228 break; 229 case GetYear: 230 // IE returns the full year even in getYear. 231 if ( exec->interpreter()->compatMode() == Interpreter::IECompat ) 232 result = Number(1900 + t->tm_year); 233 else 234 result = Number(t->tm_year); 235 break; 236 case GetFullYear: 237 result = Number(1900 + t->tm_year); 238 break; 239 case GetMonth: 240 result = Number(t->tm_mon); 241 break; 242 case GetDate: 243 result = Number(t->tm_mday); 244 break; 245 case GetDay: 246 result = Number(t->tm_wday); 247 break; 248 case GetHours: 249 result = Number(t->tm_hour); 250 break; 251 case GetMinutes: 252 result = Number(t->tm_min); 253 break; 254 case GetSeconds: 255 result = Number(t->tm_sec); 256 break; 257 case GetMilliSeconds: 258 result = Number(ms); 259 break; 260 case GetTimezoneOffset: 261 #if defined BSD || defined(__APPLE__) 262 result = Number(-( t->tm_gmtoff / 60 ) + ( t->tm_isdst ? 60 : 0 )); 263 #else 264 # if defined(__BORLANDC__) 265 #error please add daylight savings offset here! 266 result = Number(_timezone / 60 - (_daylight ? 60 : 0)); 267 # else 268 result = Number(( timezone / 60 - ( daylight ? 60 : 0 ))); 269 # endif 270 #endif 271 break; 272 case SetTime: 273 milli = roundValue(exec,args[0]); 274 result = Number(milli); 275 thisObj.setInternalValue(result); 276 break; 277 case SetMilliSeconds: 278 ms = args[0].toInt32(exec); 279 break; 280 case SetSeconds: 281 t->tm_sec = args[0].toInt32(exec); 282 break; 283 case SetMinutes: 284 t->tm_min = args[0].toInt32(exec); 285 break; 286 case SetHours: 287 t->tm_hour = args[0].toInt32(exec); 288 break; 289 case SetDate: 290 t->tm_mday = args[0].toInt32(exec); 291 break; 292 case SetMonth: 293 t->tm_mon = args[0].toInt32(exec); 294 break; 295 case SetFullYear: 296 t->tm_year = args[0].toInt32(exec) - 1900; 297 break; 298 case SetYear: 299 t->tm_year = args[0].toInt32(exec) >= 1900 ? args[0].toInt32(exec) - 1900 : args[0].toInt32(exec); 300 break; 301 } 302 303 if (id == SetYear || id == SetMilliSeconds || id == SetSeconds || 304 id == SetMinutes || id == SetHours || id == SetDate || 305 id == SetMonth || id == SetFullYear ) { 306 result = Number(mktime(t) * 1000.0 + ms); 307 thisObj.setInternalValue(result); 308 } 309 310 return result; 311 } 312 313 // ------------------------------ DateObjectImp -------------------------------- 314 315 // TODO: MakeTime (15.9.11.1) etc. ? 316 317 DateObjectImp::DateObjectImp(ExecState *exec, 318 FunctionPrototypeImp *funcProto, 319 DatePrototypeImp *dateProto) 320 : InternalFunctionImp(funcProto) 321 { 322 Value protect(this); 323 // ECMA 15.9.4.1 Date.prototype 324 put(exec,"prototype", Object(dateProto), DontEnum|DontDelete|ReadOnly); 325 326 put(exec,"parse", Object(new DateObjectFuncImp(exec,funcProto,DateObjectFuncImp::Parse, 1)), DontEnum); 327 put(exec,"UTC", Object(new DateObjectFuncImp(exec,funcProto,DateObjectFuncImp::UTC, 7)), DontEnum); 328 329 // no. of arguments for constructor 330 put(exec,"length", Number(7), ReadOnly|DontDelete|DontEnum); 331 } 332 333 bool DateObjectImp::implementsConstruct() const 334 { 335 return true; 336 } 337 338 // ECMA 15.9.3 339 Object DateObjectImp::construct(ExecState *exec, const List &args) 340 { 341 int numArgs = args.size(); 342 343 #ifdef KJS_VERBOSE 344 fprintf(stderr,"DateObjectImp::construct - %d args\n", numArgs); 345 #endif 346 Value value; 347 348 if (numArgs == 0) { // new Date() ECMA 15.9.3.3 349 #if HAVE_SYS_TIMEB_H 350 # if defined(__BORLANDC__) 351 struct timeb timebuffer; 352 ftime(&timebuffer); 353 # else 354 struct _timeb timebuffer; 355 _ftime(&timebuffer); 356 # endif 357 double utc = floor((double)timebuffer.time * 1000.0 + (double)timebuffer.millitm); 358 #else 359 struct timeval tv; 360 gettimeofday(&tv, 0L); 361 double utc = floor((double)tv.tv_sec * 1000.0 + (double)tv.tv_usec / 1000.0); 362 #endif 363 value = Number(utc); 364 } else if (numArgs == 1) { 365 UString s = args[0].toString(exec); 366 double d = s.toDouble(); 367 if (isNaN(d)) 368 value = parseDate(s); 369 else 370 value = Number(d); 371 } else { 372 struct tm t; 373 memset(&t, 0, sizeof(t)); 374 Number y = args[0].toNumber(exec); 375 // TODO: check for NaN 376 int year = y.toInt32(exec); 377 t.tm_year = (year >= 0 && year <= 99) ? year : year - 1900; 378 t.tm_mon = args[1].toInt32(exec); 379 t.tm_mday = (numArgs >= 3) ? args[2].toInt32(exec) : 1; 380 t.tm_hour = (numArgs >= 4) ? args[3].toInt32(exec) : 0; 381 t.tm_min = (numArgs >= 5) ? args[4].toInt32(exec) : 0; 382 t.tm_sec = (numArgs >= 6) ? args[5].toInt32(exec) : 0; 383 t.tm_isdst = -1; 384 int ms = (numArgs >= 7) ? args[6].toInt32(exec) : 0; 385 value = Number(mktime(&t) * 1000.0 + ms); 386 } 387 388 Object proto = exec->interpreter()->builtinDatePrototype(); 389 Object ret(new DateInstanceImp(proto)); 390 ret.setInternalValue(timeClip(value)); 391 return ret; 392 } 393 394 bool DateObjectImp::implementsCall() const 395 { 396 return true; 397 } 398 399 // ECMA 15.9.2 400 Value DateObjectImp::call(ExecState */*exec*/, Object &/*thisObj*/, const List &/*args*/) 401 { 402 #ifdef KJS_VERBOSE 403 fprintf(stderr,"DateObjectImp::call - current time\n"); 404 #endif 405 time_t t = time(0L); 406 UString s(ctime(&t)); 407 408 // return formatted string minus trailing \n 409 return String(s.substr(0, s.size() - 1)); 410 } 411 412 // ------------------------------ DateObjectFuncImp ---------------------------- 413 414 DateObjectFuncImp::DateObjectFuncImp(ExecState *exec, FunctionPrototypeImp *funcProto, 415 int i, int len) 416 : InternalFunctionImp(funcProto), id(i) 417 { 418 Value protect(this); 419 put(exec,"length",Number(len),DontDelete|ReadOnly|DontEnum); 420 } 421 422 bool DateObjectFuncImp::implementsCall() const 423 { 424 return true; 425 } 426 427 // ECMA 15.9.4.2 - 3 428 Value DateObjectFuncImp::call(ExecState *exec, Object &/*thisObj*/, const List &args) 429 { 430 if (id == Parse) { 431 if (args[0].type() == StringType) 432 return parseDate(args[0].toString(exec)); 433 else 434 return Undefined(); 435 } 436 else { // UTC 437 struct tm t; 438 memset(&t, 0, sizeof(t)); 439 int n = args.size(); 440 Number y = args[0].toNumber(exec); 441 // TODO: check for NaN 442 int year = y.toInt32(exec); 443 t.tm_year = (year >= 0 && year <= 99) ? year : year - 1900; 444 t.tm_mon = args[1].toInt32(exec); 445 t.tm_mday = (n >= 3) ? args[2].toInt32(exec) : 1; 446 t.tm_hour = (n >= 4) ? args[3].toInt32(exec) : 0; 447 t.tm_min = (n >= 5) ? args[4].toInt32(exec) : 0; 448 t.tm_sec = (n >= 6) ? args[5].toInt32(exec) : 0; 449 int ms = (n >= 7) ? args[6].toInt32(exec) : 0; 450 return Number(mktime(&t) * 1000.0 + ms); 451 } 452 } 453 454 // ----------------------------------------------------------------------------- 455 456 457 Value KJS::parseDate(const String &s) 89 458 { 90 459 UString u = s.value(); 460 #ifdef KJS_VERBOSE 461 fprintf(stderr,"KJS::parseDate %s\n",u.ascii()); 462 #endif 91 463 int firstSlash = u.find('/'); 92 464 if ( firstSlash == -1 ) 93 465 { 94 /* TODO parse dates like "December 25, 1995 23:15:00"*/ 95 fprintf(stderr,"KJS::parseDate parsing for this format isn't implemented\n%s", u.ascii()); 96 return Number(0); 466 time_t seconds = KRFCDate_parseDate( u ); 467 #ifdef KJS_VERBOSE 468 fprintf(stderr,"KRFCDate_parseDate returned seconds=%d\n",seconds); 469 #endif 470 if ( seconds == -1 ) 471 return Undefined(); 472 else 473 return Number(seconds * 1000.0); 97 474 } 98 475 else … … 127 504 } 128 505 129 KJSO KJS::timeClip(const KJSO &t) 506 ///// Awful duplication from krfcdate.cpp - we don't link to kdecore 507 508 static unsigned int ymdhms_to_seconds(int year, int mon, int day, int hour, int minute, int second) 509 { 510 unsigned int ret = (day - 32075) /* days */ 511 + 1461L * (year + 4800L + (mon - 14) / 12) / 4 512 + 367 * (mon - 2 - (mon - 14) / 12 * 12) / 12 513 - 3 * ((year + 4900L + (mon - 14) / 12) / 100) / 4 514 - 2440588; 515 ret = 24*ret + hour; /* hours */ 516 ret = 60*ret + minute; /* minutes */ 517 ret = 60*ret + second; /* seconds */ 518 519 return ret; 520 } 521 522 static const char haystack[37]="janfebmaraprmayjunjulaugsepoctnovdec"; 523 524 // we follow the recommendation of rfc2822 to consider all 525 // obsolete time zones not listed here equivalent to "-0000" 526 static const struct { 527 const char *tzName; 528 int tzOffset; 529 } known_zones[] = { 530 { "UT", 0 }, 531 { "GMT", 0 }, 532 { "EST", -300 }, 533 { "EDT", -240 }, 534 { "CST", -360 }, 535 { "CDT", -300 }, 536 { "MST", -420 }, 537 { "MDT", -360 }, 538 { "PST", -480 }, 539 { "PDT", -420 }, 540 { 0, 0 } 541 }; 542 543 time_t KJS::KRFCDate_parseDate(const UString &_date) 544 { 545 // This parse a date in the form: 546 // Wednesday, 09-Nov-99 23:12:40 GMT 547 // or 548 // Sat, 01-Jan-2000 08:00:00 GMT 549 // or 550 // Sat, 01 Jan 2000 08:00:00 GMT 551 // or 552 // 01 Jan 99 22:00 +0100 (exceptions in rfc822/rfc2822) 553 // ### non RFC format, added for Javascript: 554 // [Wednesday] January 09 1999 23:12:40 GMT 555 // 556 // We ignore the weekday 557 // 558 time_t result = 0; 559 int offset = 0; 560 char *newPosStr; 561 const char *dateString = _date.ascii(); 562 int day = 0; 563 char monthStr[4]; 564 int month = -1; // not set yet 565 int year = 0; 566 int hour = 0; 567 int minute = 0; 568 int second = 0; 569 570 // Skip leading space 571 while(*dateString && isspace(*dateString)) 572 dateString++; 573 574 const char *wordStart = dateString; 575 // Check contents of first words if not number 576 while(*dateString && !isdigit(*dateString)) 577 { 578 if ( isspace(*dateString) && dateString - wordStart >= 3 ) 579 { 580 monthStr[0] = tolower(*wordStart++); 581 monthStr[1] = tolower(*wordStart++); 582 monthStr[2] = tolower(*wordStart++); 583 monthStr[3] = '\0'; 584 //fprintf(stderr,"KJS::parseDate found word starting with '%s'\n", monthStr); 585 const char *str = strstr(haystack, monthStr); 586 if (str) 587 month = (str-haystack)/3; // Jan=00, Feb=01, Mar=02, .. 588 while(*dateString && isspace(*dateString)) 589 dateString++; 590 wordStart = dateString; 591 } 592 else 593 dateString++; 594 } 595 596 while(*dateString && isspace(*dateString)) 597 dateString++; 598 599 if (!*dateString) 600 return result; // Invalid date 601 602 // ' 09-Nov-99 23:12:40 GMT' 603 day = strtol(dateString, &newPosStr, 10); 604 dateString = newPosStr; 605 606 if ((day < 1) || (day > 31)) 607 return result; // Invalid date; 608 if (!*dateString) 609 return result; // Invalid date 610 611 if (*dateString == '-') 612 dateString++; 613 614 while(*dateString && isspace(*dateString)) 615 dateString++; 616 617 if ( month == -1 ) // not found yet 618 { 619 for(int i=0; i < 3;i++) 620 { 621 if (!*dateString || (*dateString == '-') || isspace(*dateString)) 622 return result; // Invalid date 623 monthStr[i] = tolower(*dateString++); 624 } 625 monthStr[3] = '\0'; 626 627 newPosStr = (char*)strstr(haystack, monthStr); 628 629 if (!newPosStr) 630 return result; // Invalid date 631 632 month = (newPosStr-haystack)/3; // Jan=00, Feb=01, Mar=02, .. 633 634 if ((month < 0) || (month > 11)) 635 return result; // Invalid date 636 637 while(*dateString && (*dateString != '-') && !isspace(*dateString)) 638 dateString++; 639 640 if (!*dateString) 641 return result; // Invalid date 642 643 // '-99 23:12:40 GMT' 644 if ((*dateString != '-') && !isspace(*dateString)) 645 return result; // Invalid date 646 dateString++; 647 } 648 649 if ((month < 0) || (month > 11)) 650 return result; // Invalid date 651 652 // '99 23:12:40 GMT' 653 year = strtol(dateString, &newPosStr, 10); 654 dateString = newPosStr; 655 656 // Y2K: Solve 2 digit years 657 if ((year >= 0) && (year < 50)) 658 year += 2000; 659 660 if ((year >= 50) && (year < 100)) 661 year += 1900; // Y2K 662 663 if ((year < 1900) || (year > 2500)) 664 return result; // Invalid date 665 666 // Don't fail if the time is missing. 667 if (*dateString) 668 { 669 // ' 23:12:40 GMT' 670 if (!isspace(*dateString++)) 671 return result; // Invalid date 672 673 hour = strtol(dateString, &newPosStr, 10); 674 dateString = newPosStr; 675 676 if ((hour < 0) || (hour > 23)) 677 return result; // Invalid date 678 679 if (!*dateString) 680 return result; // Invalid date 681 682 // ':12:40 GMT' 683 if (*dateString++ != ':') 684 return result; // Invalid date 685 686 minute = strtol(dateString, &newPosStr, 10); 687 dateString = newPosStr; 688 689 if ((minute < 0) || (minute > 59)) 690 return result; // Invalid date 691 692 if (!*dateString) 693 return result; // Invalid date 694 695 // ':40 GMT' 696 if (*dateString != ':' && !isspace(*dateString)) 697 return result; // Invalid date 698 699 // seconds are optional in rfc822 + rfc2822 700 if (*dateString ==':') { 701 dateString++; 702 703 second = strtol(dateString, &newPosStr, 10); 704 dateString = newPosStr; 705 706 if ((second < 0) || (second > 59)) 707 return result; // Invalid date 708 } else { 709 dateString++; 710 } 711 712 while(*dateString && isspace(*dateString)) 713 dateString++; 714 } 715 716 // don't fail if the time zone is missing, some 717 // broken mail-/news-clients omit the time zone 718 if (*dateString) { 719 720 if ((*dateString == '+') || (*dateString == '-')) { 721 offset = strtol(dateString, &newPosStr, 10); 722 723 if ((offset < -9959) || (offset > 9959)) 724 return result; // Invalid date 725 726 int sgn = (offset < 0)? -1:1; 727 offset = abs(offset); 728 offset = ((offset / 100)*60 + (offset % 100))*sgn; 729 } else { 730 for (int i=0; known_zones[i].tzName != 0; i++) { 731 if (0 == strncasecmp(dateString, known_zones[i].tzName, strlen(known_zones[i].tzName))) { 732 offset = known_zones[i].tzOffset; 733 break; 734 } 735 } 736 } 737 } 738 if (sizeof(time_t) == 4) 739 { 740 if ((time_t)-1 < 0) 741 { 742 if (year >= 2038) 743 { 744 year = 2038; 745 month = 0; 746 day = 1; 747 hour = 0; 748 minute = 0; 749 second = 0; 750 } 751 } 752 else 753 { 754 if (year >= 2115) 755 { 756 year = 2115; 757 month = 0; 758 day = 1; 759 hour = 0; 760 minute = 0; 761 second = 0; 762 } 763 } 764 } 765 766 result = ymdhms_to_seconds(year, month+1, day, hour, minute, second); 767 768 // avoid negative time values 769 if ((offset > 0) && (offset > result)) 770 offset = 0; 771 772 result -= offset*60; 773 774 // If epoch 0 return epoch +1 which is Thu, 01-Jan-70 00:00:01 GMT 775 // This is so that parse error and valid epoch 0 return values won't 776 // be the same for sensitive applications... 777 if (result < 1) result = 1; 778 779 return result; 780 } 781 782 783 Value KJS::timeClip(const Value &t) 130 784 { 131 785 /* TODO */ … … 133 787 } 134 788 135 DateObject::DateObject(const Object& funcProto, const Object &dateProto)136 : ConstructorImp(funcProto, 7)137 {138 // ECMA 15.9.4.1 Date.prototype139 setPrototypeProperty(dateProto);140 }141 142 // ECMA 15.9.2143 Completion DateObject::execute(const List &)144 {145 time_t t = time(0L);146 UString s(ctime(&t));147 148 // return formatted string minus trailing \n149 return Completion(ReturnValue, String(s.substr(0, s.size() - 1)));150 }151 152 // ECMA 15.9.3153 Object DateObject::construct(const List &args)154 {155 KJSO value;156 157 int numArgs = args.size();158 159 if (numArgs == 0) { // new Date() ECMA 15.9.3.3160 #if HAVE_SYS_TIMEB_H161 # if defined(__BORLANDC__)162 struct timeb timebuffer;163 ftime(&timebuffer);164 # else165 struct _timeb timebuffer;166 _ftime(&timebuffer);167 # endif168 double utc = floor((double)timebuffer.time * 1000.0 + (double)timebuffer.millitm);169 #else170 struct timeval tv;171 gettimeofday(&tv, 0L);172 double utc = floor((double)tv.tv_sec * 1000.0 + (double)tv.tv_usec / 1000.0);173 #endif174 value = Number(utc);175 } else if (numArgs == 1) {176 KJSO p = args[0].toPrimitive();177 if (p.isA(StringType))178 value = parseDate(p.toString());179 else180 value = p.toNumber();181 } else {182 struct tm t;183 memset(&t, 0, sizeof(t));184 Number y = args[0].toNumber();185 /* TODO: check for NaN */186 int year = y.toInt32();187 t.tm_year = (year >= 0 && year <= 99) ? year : year - 1900;188 t.tm_mon = args[1].toInt32();189 t.tm_mday = (numArgs >= 3) ? args[2].toInt32() : 1;190 t.tm_hour = (numArgs >= 4) ? args[3].toInt32() : 0;191 t.tm_min = (numArgs >= 5) ? args[4].toInt32() : 0;192 t.tm_sec = (numArgs >= 6) ? args[5].toInt32() : 0;193 t.tm_isdst = -1;194 int ms = (numArgs >= 7) ? args[6].toInt32() : 0;195 value = Number(mktime(&t) * 1000.0 + ms);196 }197 198 return Object::create(DateClass, timeClip(value));199 }200 201 KJSO DateObject::get(const UString &p) const202 {203 int id;204 205 if (p == "parse")206 id = DateObjectFunc::Parse;207 else if (p == "UTC")208 id = DateObjectFunc::UTC;209 else210 return Imp::get(p);211 212 return Function(new DateObjectFunc(id));213 }214 215 // ECMA 15.9.4.2 - 3216 Completion DateObjectFunc::execute(const List &args)217 {218 KJSO result;219 220 if (id == Parse)221 if (args[0].isA(StringType))222 result = parseDate(args[0].toString());223 else224 result = Undefined();225 else {226 struct tm t;227 memset(&t, 0, sizeof(t));228 int n = args.size();229 Number y = args[0].toNumber();230 /* TODO: check for NaN */231 int year = y.toInt32();232 t.tm_year = (year >= 0 && year <= 99) ? year : year - 1900;233 t.tm_mon = args[1].toInt32();234 t.tm_mday = (n >= 3) ? args[2].toInt32() : 1;235 t.tm_hour = (n >= 4) ? args[3].toInt32() : 0;236 t.tm_min = (n >= 5) ? args[4].toInt32() : 0;237 t.tm_sec = (n >= 6) ? args[5].toInt32() : 0;238 int ms = (n >= 7) ? args[6].toInt32() : 0;239 result = Number(mktime(&t) * 1000.0 + ms);240 }241 242 return Completion(ReturnValue, result);243 }244 245 // ECMA 15.9.4246 DatePrototype::DatePrototype(const Object& proto)247 : ObjectImp(DateClass, Number(NaN), proto)248 {249 // The constructor will be added later in DateObject's constructor250 }251 252 KJSO DatePrototype::get(const UString &p) const253 {254 int id;255 256 if (p == "toString" || p == "toUTCString")257 id = DateProtoFunc::ToString;258 else if (p == "toDateString")259 id = DateProtoFunc::ToDateString;260 else if (p == "toTimeString")261 id = DateProtoFunc::ToTimeString;262 else if (p == "toLocaleString")263 id = DateProtoFunc::ToLocaleString;264 else if (p == "toLocaleDateString")265 id = DateProtoFunc::ToLocaleDateString;266 else if (p == "toLocaleTimeString")267 id = DateProtoFunc::ToLocaleTimeString;268 else if (p == "valueOf")269 id = DateProtoFunc::ValueOf;270 else if (p == "getTime")271 id = DateProtoFunc::GetTime;272 else if (p == "getFullYear" || p == "getUTCFullYear")273 id = DateProtoFunc::GetFullYear;274 else if (p == "toGMTString")275 id = DateProtoFunc::ToGMTString;276 else if (p == "getMonth" || p == "getUTCMonth")277 id = DateProtoFunc::GetMonth;278 else if (p == "getDate" || p == "getUTCDate")279 id = DateProtoFunc::GetDate;280 else if (p == "getDay" || p == "getUTCDay")281 id = DateProtoFunc::GetDay;282 else if (p == "getHours" || p == "getUTCHours")283 id = DateProtoFunc::GetHours;284 else if (p == "getMinutes" || p == "getUTCMinutes")285 id = DateProtoFunc::GetMinutes;286 else if (p == "getSeconds" || p == "getUTCSeconds")287 id = DateProtoFunc::GetSeconds;288 else if (p == "getMilliseconds" || p == "getUTCMilliseconds")289 id = DateProtoFunc::GetMilliSeconds;290 else if (p == "getTimezoneOffset")291 id = DateProtoFunc::GetTimezoneOffset;292 else if (p == "setTime")293 id = DateProtoFunc::SetTime;294 else if (p == "setMilliseconds" || p == "setUTCMilliseconds")295 id = DateProtoFunc::SetMilliSeconds;296 else if (p == "setSeconds" || p == "setUTCSeconds")297 id = DateProtoFunc::SetSeconds;298 else if (p == "setMinutes" || p == "setUTCMinutes")299 id = DateProtoFunc::SetMinutes;300 else if (p == "setHours" || p == "setUTCHours")301 id = DateProtoFunc::SetHours;302 else if (p == "setDate" || p == "setUTCDate")303 id = DateProtoFunc::SetDate;304 else if (p == "setMonth" || p == "setUTCMonth")305 id = DateProtoFunc::SetMonth;306 else if (p == "setFullYear" || p == "setUTCFullYear")307 id = DateProtoFunc::SetFullYear;308 else if (p == "setYear" )309 id = DateProtoFunc::SetYear;310 // non-normative311 else if (p == "getYear")312 id = DateProtoFunc::GetYear;313 else if (p == "toGMTString")314 id = DateProtoFunc::ToGMTString;315 else316 return Undefined();317 318 bool utc = (p.find("UTC") >= 0) ? true : false;319 return Function(new DateProtoFunc(id, utc));320 }321 322 DateProtoFunc::DateProtoFunc(int i, bool u) : id(i), utc(u)323 {324 }325 326 Completion DateProtoFunc::execute(const List &args)327 {328 KJSO result;329 UString s;330 const int bufsize=100;331 char timebuffer[bufsize];332 char *oldlocale = setlocale(LC_TIME,NULL);333 if (!oldlocale)334 oldlocale = setlocale(LC_ALL, NULL);335 Object thisObj = Object::dynamicCast(thisValue());336 KJSO v = thisObj.internalValue();337 double milli = v.toNumber().value();338 time_t tv = (time_t) floor(milli / 1000.0);339 int ms = int(milli - tv * 1000.0);340 341 struct tm *t;342 if (utc)343 t = gmtime(&tv);344 else345 t = localtime(&tv);346 347 switch (id) {348 case ToString:349 s = ctime(&tv);350 result = String(s.substr(0, s.size() - 1));351 break;352 case ToDateString:353 case ToTimeString:354 case ToGMTString:355 setlocale(LC_TIME,"C");356 if (id == DateProtoFunc::ToDateString) {357 strftime(timebuffer, bufsize, "%x",t);358 } else if (id == DateProtoFunc::ToTimeString) {359 strftime(timebuffer, bufsize, "%X",t);360 } else {361 t = gmtime(&tv);362 strftime(timebuffer, bufsize, "%a, %d-%b-%y %H:%M:%S %Z", t);363 }364 setlocale(LC_TIME,oldlocale);365 result = String(timebuffer);366 break;367 case ToLocaleString:368 strftime(timebuffer, bufsize, "%c", t);369 result = String(timebuffer);370 break;371 case ToLocaleDateString:372 strftime(timebuffer, bufsize, "%x", t);373 result = String(timebuffer);374 break;375 case ToLocaleTimeString:376 strftime(timebuffer, bufsize, "%X", t);377 result = String(timebuffer);378 break;379 case ValueOf:380 result = Number(milli);381 break;382 case GetTime:383 if (thisObj.getClass() == DateClass)384 result = Number(milli);385 else386 result = Error::create(TypeError);387 break;388 case GetYear:389 result = Number(t->tm_year);390 break;391 case GetFullYear:392 result = Number(1900 + t->tm_year);393 break;394 case GetMonth:395 result = Number(t->tm_mon);396 break;397 case GetDate:398 result = Number(t->tm_mday);399 break;400 case GetDay:401 result = Number(t->tm_wday);402 break;403 case GetHours:404 result = Number(t->tm_hour);405 break;406 case GetMinutes:407 result = Number(t->tm_min);408 break;409 case GetSeconds:410 result = Number(t->tm_sec);411 break;412 case GetMilliSeconds:413 result = Undefined();414 break;415 case GetTimezoneOffset:416 #if defined BSD || defined(__APPLE__)417 result = Number(-( t->tm_gmtoff / 60 ) + ( t->tm_isdst ? 60 : 0 ));418 #else419 # if defined(__BORLANDC__)420 #error please add daylight savings offset here!421 result = Number(_timezone / 60 - (_daylight ? 60 : 0));422 # else423 result = Number(( timezone / 60 - ( daylight ? 60 : 0 )));424 # endif425 #endif426 break;427 case SetTime:428 milli = args[0].round();429 result = Number(milli);430 thisObj.setInternalValue(result);431 break;432 case SetMilliSeconds:433 ms = args[0].toInt32();434 break;435 case SetSeconds:436 t->tm_sec = args[0].toInt32();437 break;438 case SetMinutes:439 t->tm_min = args[0].toInt32();440 break;441 case SetHours:442 t->tm_hour = args[0].toInt32();443 break;444 case SetDate:445 t->tm_mday = args[0].toInt32();446 break;447 case SetMonth:448 t->tm_mon = args[0].toInt32();449 break;450 case SetFullYear:451 t->tm_year = args[0].toInt32() - 1900;452 break;453 case SetYear:454 t->tm_year = args[0].toInt32() >= 1900 ? args[0].toInt32() - 1900 : args[0].toInt32();455 break;456 }457 458 if (id == SetYear || id == SetMilliSeconds || id == SetSeconds ||459 id == SetMinutes || id == SetHours || id == SetDate ||460 id == SetMonth || id == SetFullYear ) {461 result = Number(mktime(t) * 1000.0 + ms);462 thisObj.setInternalValue(result);463 }464 465 return Completion(ReturnValue, result);466 } -
trunk/JavaScriptCore/kjs/date_object.h
r6 r798 1 // -*- c-basic-offset: 2 -*- 1 2 /* 2 3 * This file is part of the KDE libraries … … 16 17 * License along with this library; if not, write to the Free Software 17 18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 * 20 * $Id$ 18 21 */ 19 22 … … 21 24 #define _DATE_OBJECT_H_ 22 25 23 #include " object.h"24 #include "function .h"26 #include "internal.h" 27 #include "function_object.h" 25 28 26 29 namespace KJS { 27 30 28 class Date Object : public ConstructorImp {31 class DateInstanceImp : public ObjectImp { 29 32 public: 30 DateObject(const Object& funcProto, const Object &dateProto); 33 DateInstanceImp(const Object &proto); 34 35 virtual const ClassInfo *classInfo() const { return &info; } 36 static const ClassInfo info; 37 }; 38 39 /** 40 * @internal 41 * 42 * The initial value of Date.prototype (and thus all objects created 43 * with the Date constructor 44 */ 45 class DatePrototypeImp : public DateInstanceImp { 46 public: 47 DatePrototypeImp(ExecState *exec, ObjectPrototypeImp *objectProto); 48 Value get(ExecState *exec, const UString &p) const; 49 virtual const ClassInfo *classInfo() const { return &info; } 50 static const ClassInfo info; 51 }; 52 53 /** 54 * @internal 55 * 56 * Class to implement all methods that are properties of the 57 * Date.prototype object 58 */ 59 class DateProtoFuncImp : public InternalFunctionImp { 60 public: 61 DateProtoFuncImp(ExecState *exec, int i, int len); 62 63 virtual bool implementsCall() const; 64 virtual Value call(ExecState *exec, Object &thisObj, const List &args); 65 66 67 Completion execute(const List &); 68 enum { ToString, ToDateString, ToTimeString, ToLocaleString, 69 ToLocaleDateString, ToLocaleTimeString, ValueOf, GetTime, 70 GetFullYear, GetMonth, GetDate, GetDay, GetHours, GetMinutes, 71 GetSeconds, GetMilliSeconds, GetTimezoneOffset, SetTime, 72 SetMilliSeconds, SetSeconds, SetMinutes, SetHours, SetDate, 73 SetMonth, SetFullYear, ToUTCString, 74 // non-normative properties (Appendix B) 75 GetYear, SetYear, ToGMTString }; 76 private: 77 int id; 78 bool utc; 79 }; 80 81 /** 82 * @internal 83 * 84 * The initial value of the the global variable's "Date" property 85 */ 86 class DateObjectImp : public InternalFunctionImp { 87 public: 88 DateObjectImp(ExecState *exec, 89 FunctionPrototypeImp *funcProto, 90 DatePrototypeImp *dateProto); 91 92 virtual bool implementsConstruct() const; 93 virtual Object construct(ExecState *exec, const List &args); 94 virtual bool implementsCall() const; 95 virtual Value call(ExecState *exec, Object &thisObj, const List &args); 96 31 97 Completion execute(const List &); 32 98 Object construct(const List &); 33 KJSO get(const UString &p) const;34 99 }; 35 100 36 class DatePrototype : public ObjectImp { 101 /** 102 * @internal 103 * 104 * Class to implement all methods that are properties of the 105 * Date object 106 */ 107 class DateObjectFuncImp : public InternalFunctionImp { 37 108 public: 38 DatePrototype(const Object& proto); 39 virtual KJSO get(const UString &p) const; 109 DateObjectFuncImp(ExecState *exec, FunctionPrototypeImp *funcProto, 110 int i, int len); 111 112 virtual bool implementsCall() const; 113 virtual Value call(ExecState *exec, Object &thisObj, const List &args); 114 115 enum { Parse, UTC }; 116 private: 117 int id; 40 118 }; 119 120 // helper functions 121 Value parseDate(const String &s); 122 time_t KRFCDate_parseDate(const UString &_date); 123 Value timeClip(const Value &t); 41 124 42 125 }; // namespace -
trunk/JavaScriptCore/kjs/debugger.cpp
r6 r798 1 // -*- c-basic-offset: 2 -*- 1 2 /* 2 3 * This file is part of the KDE libraries 3 4 * Copyright (C) 1999-2001 Harri Porten ([email protected]) 5 * Copyright (C) 2001 Peter Kelly ([email protected]) 4 6 * 5 7 * This library is free software; you can redistribute it and/or … … 16 18 * License along with this library; if not, write to the Free Software 17 19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 20 * 21 * $Id$ 18 22 */ 19 23 20 #ifdef KJS_DEBUGGER21 22 24 #include "debugger.h" 23 #include "kjs.h" 25 #include "value.h" 26 #include "object.h" 27 #include "types.h" 28 #include "interpreter.h" 24 29 #include "internal.h" 25 30 #include "ustring.h" … … 27 32 using namespace KJS; 28 33 29 Debugger::Debugger(KJScript *engine) 30 : eng(0L), 31 sid(-1) 34 // ------------------------------ Debugger ------------------------------------- 35 36 namespace KJS { 37 struct AttachedInterpreter 38 { 39 public: 40 AttachedInterpreter(Interpreter *i) : interp(i) {} 41 Interpreter *interp; 42 AttachedInterpreter *next; 43 }; 44 45 } 46 47 Debugger::Debugger() 32 48 { 33 attach(engine);49 rep = new DebuggerImp(); 34 50 } 35 51 36 52 Debugger::~Debugger() 37 53 { 38 detach(); 54 // detach from all interpreters 55 while (rep->interps) 56 detach(rep->interps->interp); 57 58 delete rep; 39 59 } 40 60 41 void Debugger::attach( KJScript *e)61 void Debugger::attach(Interpreter *interp) 42 62 { 43 dmode = Disabled; 44 if (e) { 45 if (!eng || e->rep != eng->rep) { 46 eng = e; 47 eng->rep->attachDebugger(this); 48 } 49 } else { 50 eng = 0L; 63 if (interp->imp()->debugger() != this) 64 interp->imp()->setDebugger(this); 65 66 // add to the list of attached interpreters 67 if (!rep->interps) 68 rep->interps = new AttachedInterpreter(interp); 69 else { 70 AttachedInterpreter *ai = rep->interps; 71 while (ai->next) 72 ai = ai->next; 73 ai->next = new AttachedInterpreter(interp);; 51 74 } 52 reset();53 75 } 54 76 55 KJScript *Debugger::engine() const 77 void Debugger::detach(Interpreter *interp) 56 78 { 57 return eng; 79 if (interp->imp()->debugger() == this) 80 interp->imp()->setDebugger(this); 81 82 // remove from the list of attached interpreters 83 if (rep->interps->interp == interp) { 84 AttachedInterpreter *old = rep->interps; 85 rep->interps = rep->interps->next; 86 delete old; 87 } 88 89 AttachedInterpreter *ai = rep->interps; 90 while (ai->next && ai->next->interp != interp) 91 ai = ai->next; 92 if (ai->next) { 93 AttachedInterpreter *old = ai->next; 94 ai->next = ai->next->next; 95 delete old; 96 } 58 97 } 59 98 60 void Debugger::detach() 61 { 62 reset(); 63 if (!eng) 64 return; 65 eng->rep->attachDebugger(0L); 66 eng = 0L; 67 } 68 69 void Debugger::setMode(Mode m) 70 { 71 dmode = m; 72 } 73 74 Debugger::Mode Debugger::mode() const 75 { 76 return dmode; 77 } 78 79 // supposed to be overriden by the user 80 bool Debugger::stopEvent() 99 bool Debugger::sourceParsed(ExecState */*exec*/, int /*sourceId*/, 100 const UString &/*source*/, int /*errorLine*/) 81 101 { 82 102 return true; 83 103 } 84 104 85 void Debugger::callEvent(const UString &, const UString &)105 bool Debugger::sourceUnused(ExecState */*exec*/, int /*sourceId*/) 86 106 { 107 return true; 87 108 } 88 109 89 void Debugger::returnEvent() 110 bool Debugger::exception(ExecState */*exec*/, int /*sourceId*/, int /*lineno*/, 111 Object &/*exceptionObj*/) 90 112 { 113 return true; 91 114 } 92 115 93 void Debugger::reset() 116 bool Debugger::atStatement(ExecState */*exec*/, int /*sourceId*/, int /*firstLine*/, 117 int /*lastLine*/) 94 118 { 95 l = -1;119 return true; 96 120 } 97 121 98 int Debugger::freeSourceId() const 122 bool Debugger::callEvent(ExecState */*exec*/, int /*sourceId*/, int /*lineno*/, 123 Object &/*function*/, const List &/*args*/) 99 124 { 100 return eng ? eng->rep->sourceId()+1 : -1;125 return true; 101 126 } 102 127 103 bool Debugger::setBreakpoint(int id, int line) 128 bool Debugger::returnEvent(ExecState */*exec*/, int /*sourceId*/, int /*lineno*/, 129 Object &/*function*/) 104 130 { 105 if (!eng) 106 return false; 107 return eng->rep->setBreakpoint(id, line, true); 131 return true; 108 132 } 109 133 110 bool Debugger::deleteBreakpoint(int id, int line)111 {112 if (!eng)113 return false;114 return eng->rep->setBreakpoint(id, line, false);115 }116 117 void Debugger::clearAllBreakpoints(int id)118 {119 if (!eng)120 return;121 eng->rep->setBreakpoint(id, -1, false);122 }123 124 UString Debugger::varInfo(const UString &ident)125 {126 if (!eng)127 return UString();128 129 int dot = ident.find('.');130 if (dot < 0)131 dot = ident.size();132 UString sub = ident.substr(0, dot);133 KJSO obj;134 // resolve base135 if (sub == "this") {136 obj = Context::current()->thisValue();137 } else {138 const List *chain = Context::current()->pScopeChain();139 ListIterator scope = chain->begin();140 while (scope != chain->end()) {141 if (scope->hasProperty(ident)) {142 obj = scope->get(ident);143 break;144 }145 scope++;146 }147 if (scope == chain->end())148 return UString();149 }150 // look up each part of a.b.c.151 while (dot < ident.size()) {152 int olddot = dot;153 dot = ident.find('.', olddot+1);154 if (dot < 0)155 dot = ident.size();156 sub = ident.substr(olddot+1, dot-olddot-1);157 obj = obj.get(sub);158 if (!obj.isDefined())159 break;160 }161 162 return sub + "=" + objInfo(obj) + ":" + UString(obj.imp()->typeInfo()->name);163 }164 165 // called by varInfo() and recursively by itself on each properties166 UString Debugger::objInfo(const KJSO &obj) const167 {168 const char *cnames[] = { "Undefined", "Array", "String", "Boolean",169 "Number", "Object", "Date", "RegExp",170 "Error", "Function" };171 PropList *plist = obj.imp()->propList(0, 0, false);172 if (!plist)173 return obj.toString().value();174 else {175 UString result = "{";176 while (1) {177 result += plist->name + "=";178 KJSO p = obj.get(plist->name);179 result += objInfo(p) + ":";180 Object obj = Object::dynamicCast(p);181 if (obj.isNull())182 result += p.imp()->typeInfo()->name;183 else184 result += cnames[int(obj.getClass())];185 plist = plist->next;186 if (!plist)187 break;188 result += ",";189 }190 result += "}";191 return result;192 }193 }194 195 bool Debugger::setVar(const UString &ident, const KJSO &value)196 {197 if (!eng)198 return false;199 const List *chain = Context::current()->pScopeChain();200 ListIterator scope = chain->begin();201 while (scope != chain->end()) {202 if (scope->hasProperty(ident)) {203 if (!scope->canPut(ident))204 return false;205 scope->put(ident, value);206 return true;207 }208 scope++;209 }210 // didn't find variable211 return false;212 }213 214 // called from the scripting engine each time a statement node is hit.215 bool Debugger::hit(int line, bool breakPoint)216 {217 l = line;218 if (!eng)219 return true;220 221 if (!breakPoint && ( mode() == Continue || mode() == Disabled ) )222 return true;223 224 bool ret = stopEvent();225 eng->init(); // in case somebody used a different interpreter meanwhile226 return ret;227 }228 229 #endif -
trunk/JavaScriptCore/kjs/debugger.h
r6 r798 1 // -*- c-basic-offset: 2 -*- 1 2 /* 2 3 * This file is part of the KDE libraries 3 4 * Copyright (C) 1999-2001 Harri Porten ([email protected]) 5 * Copyright (C) 2001 Peter Kelly ([email protected]) 4 6 * 5 7 * This library is free software; you can redistribute it and/or … … 16 18 * License along with this library; if not, write to the Free Software 17 19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 20 * 21 * $Id$ 18 22 */ 19 23 … … 21 25 #define _KJSDEBUGGER_H_ 22 26 23 #include "internal.h"24 25 27 namespace KJS { 26 28 27 // 28 // NOTE: this interface is not ready, yet. Do not use unless you 29 // don't mind source and binary incompatible changes that may arise 30 // before the final version is released. 31 // 32 33 #ifdef KJS_DEBUGGER 29 class DebuggerImp; 30 class Interpreter; 31 class ExecState; 32 class Object; 33 class UString; 34 class List; 35 36 /** 37 * @internal 38 * 39 * Provides an interface which receives notification about various 40 * script-execution related events such as statement execution and function 41 * calls. 42 * 43 * WARNING: This interface is still a work in progress and is not yet 44 * offically publicly available. It is likely to change in binary incompatible 45 * (and possibly source incompatible) ways in future versions. It is 46 * anticipated that at some stage the interface will be frozen and made 47 * available for general use. 48 */ 34 49 class Debugger { 35 friend class KJScriptImp;36 friend class StatementNode;37 friend class DeclaredFunctionImp;38 friend class FunctionImp;39 50 public: 40 /** 41 * Available modes of the debugger. 42 */ 43 enum Mode { Disabled = 0, Next, Step, Continue, Stop }; 44 /** 45 * Construct a debugger and attach it to the scripting engine s. 46 */ 47 Debugger(KJScript *s); 48 /** 49 * Destruct the debugger and detach from the scripting engine we 50 * might have been attached to. 51 52 /** 53 * Creates a new debugger 54 */ 55 Debugger(); 56 57 /** 58 * Destroys the debugger. If the debugger is attached to any interpreters, 59 * it is automatically detached. 51 60 */ 52 61 virtual ~Debugger(); 53 /** 54 * Attaches the debugger to specified scripting engine. 55 */ 56 void attach(KJScript *e); 57 /** 58 * Returns the engine the interpreter is currently attached to. Null 59 * if there isn't any. 60 */ 61 KJScript* engine() const; 62 /** 63 * Detach the debugger from any scripting engine. 64 */ 65 void detach(); 66 /** 67 * Set debugger into specified mode. This will influence further behaviour 68 * if execution of the programm is started or continued. 69 */ 70 virtual void setMode(Mode m); 71 /** 72 * Returns the current operation mode. 73 */ 74 Mode mode() const; 75 /** 76 * Returns the line number the debugger currently has stopped at. 77 * -1 if the debugger is not in a break status. 78 */ 79 int lineNumber() const { return l; } 80 /** 81 * Returns the source id the debugger currently has stopped at. 82 * -1 if the debugger is not in a break status. 83 */ 84 int sourceId() const { return sid; } 85 /** 86 * Sets a breakpoint in the first statement where line lies in between 87 * the statements range. Returns true if sucessfull, false if no 88 * matching statement could be found. 89 */ 90 bool setBreakpoint(int id, int line); 91 bool deleteBreakpoint(int id, int line); 92 void clearAllBreakpoints(int id=-1); 93 /** 94 * Returns the value of ident out of the current context in string form 95 */ 96 UString varInfo(const UString &ident); 97 /** 98 * Set variable ident to value. Returns true if successful, false if 99 * the specified variable doesn't exist or isn't writable. 100 */ 101 bool setVar(const UString &ident, const KJSO &value); 102 103 protected: 104 /** 105 * Invoked in case a breakpoint or the next statement is reached in step 106 * mode. The return value decides whether execution will continue. True 107 * denotes continuation, false an abortion, respectively. 108 * 109 * The default implementation does nothing. Overload this method if 110 * you want to process this event. 111 */ 112 virtual bool stopEvent(); 113 /** 114 * Returns an integer that will be assigned to the code passed 115 * next to one of the KJScript::evaluate() methods. It's basically 116 * a counter to will only be reset to 0 on KJScript::clear(). 117 * 118 * This information is useful in case you evaluate multiple blocks of 119 * code containing some function declarations. Keep a map of source id/ 120 * code pairs, query sourceId() in case of a stopEvent() and update 121 * your debugger window with the matching source code. 122 */ 123 int freeSourceId() const; 124 /** 125 * Invoked on each function call. Use together with @ref returnEvent 62 63 DebuggerImp *imp() const { return rep; } 64 65 /** 66 * Attaches the debugger to specified interpreter. This will cause this 67 * object to receive notification of events from the interpreter. 68 * 69 * If the interpreter is deleted, the debugger will automatically be 70 * detached. 71 * 72 * Note: only one debugger can be attached to an interpreter at a time. 73 * Attaching another debugger to the same interpreter will cause the 74 * original debugger to be detached from that interpreter. 75 * 76 * @param interp The interpreter to attach to 77 * 78 * @see detach() 79 */ 80 void attach(Interpreter *interp); 81 82 /** 83 * Detach the debugger from an interpreter 84 * 85 * @param interp The interpreter to detach from. If 0, the debugger will be 86 * detached from all interpreters to which it is attached. 87 * 88 * @see attach() 89 */ 90 void detach(Interpreter *interp); 91 92 /** 93 * Called to notify the debugger that some javascript source code has 94 * been parsed. For calls to Interpreter::evaluate(), this will be called 95 * with the supplied source code before any other code is parsed. 96 * Other situations in which this may be called include creation of a 97 * function using the Function() constructor, or the eval() function. 98 * 99 * The default implementation does nothing. Override this method if 100 * you want to process this event. 101 * 102 * @param exec The current execution state 103 * @param sourceId The ID of the source code (corresponds to the 104 * sourceId supplied in other functions such as @ref atStatement() 105 * @param source The source code that was parsed 106 * @param errorLine The line number at which parsing encountered an 107 * error, or -1 if the source code was valid and parsed succesfully 108 * @return true if execution should be continue, false if it should 109 * be aborted 110 */ 111 virtual bool sourceParsed(ExecState *exec, int sourceId, 112 const UString &source, int errorLine); 113 114 /** 115 * Called when all functions/programs associated with a particular 116 * sourceId have been deleted. After this function has been called for 117 * a particular sourceId, that sourceId will not be used again. 118 * 119 * The default implementation does nothing. Override this method if 120 * you want to process this event. 121 * 122 * @param exec The current execution state 123 * @param sourceId The ID of the source code (corresponds to the 124 * sourceId supplied in other functions such as atLine() 125 * @return true if execution should be continue, false if it should 126 * be aborted 127 */ 128 virtual bool sourceUnused(ExecState *exec, int sourceId); 129 130 /** 131 * Called when an exception is thrown during script execution. 132 * 133 * The default implementation does nothing. Override this method if 134 * you want to process this event. 135 * 136 * @param exec The current execution state 137 * @param sourceId The ID of the source code being executed 138 * @param lineno The line at which the error occurred 139 * @param exceptionObj The exception object 140 * @return true if execution should be continue, false if it should 141 * be aborted 142 */ 143 virtual bool exception(ExecState *exec, int sourceId, int lineno, 144 Object &exceptionObj); 145 146 /** 147 * Called when a line of the script is reached (before it is executed) 148 * 149 * The default implementation does nothing. Override this method if 150 * you want to process this event. 151 * 152 * @param exec The current execution state 153 * @param sourceId The ID of the source code being executed 154 * @param firstLine The starting line of the statement that is about to be 155 * executed 156 * @param firstLine The ending line of the statement that is about to be 157 * executed (usually the same as firstLine) 158 * @return true if execution should be continue, false if it should 159 * be aborted 160 */ 161 virtual bool atStatement(ExecState *exec, int sourceId, int firstLine, 162 int lastLine); 163 /** 164 * Called on each function call. Use together with @ref #returnEvent 126 165 * if you want to keep track of the call stack. 127 */ 128 virtual void callEvent(const UString &fn = UString::null, 129 const UString &s = UString::null); 130 /** 131 * Invoked on each function exit. 132 */ 133 virtual void returnEvent(); 166 * 167 * Note: This only gets called for functions that are declared in ECMAScript 168 * source code or passed to eval(), not for internal KJS or 169 * application-supplied functions. 170 * 171 * The default implementation does nothing. Override this method if 172 * you want to process this event. 173 * 174 * @param exec The current execution state 175 * @param sourceId The ID of the source code being executed 176 * @param lineno The line that is about to be executed 177 * @param function The function being called 178 * @param args The arguments that were passed to the function 179 * line is being executed 180 * @return true if execution should be continue, false if it should 181 * be aborted 182 */ 183 virtual bool callEvent(ExecState *exec, int sourceId, int lineno, 184 Object &function, const List &args); 185 186 /** 187 * Called on each function exit. The function being returned from is that 188 * which was supplied in the last callEvent(). 189 * 190 * Note: This only gets called for functions that are declared in ECMAScript 191 * source code or passed to eval(), not for internal KJS or 192 * application-supplied functions. 193 * 194 * The default implementation does nothing. Override this method if 195 * you want to process this event. 196 * 197 * @param exec The current execution state 198 * @param sourceId The ID of the source code being executed 199 * @param lineno The line that is about to be executed 200 * @param function The function being called 201 * @return true if execution should be continue, false if it should 202 * be aborted 203 */ 204 virtual bool returnEvent(ExecState *exec, int sourceId, int lineno, 205 Object &function); 134 206 135 207 private: 136 void reset(); 137 bool hit(int line, bool breakPoint); 138 void setSourceId(int i) { sid = i; } 139 UString objInfo(const KJSO &obj) const; 140 141 KJScript *eng; 142 Mode dmode; 143 int l; 144 int sid; 208 DebuggerImp *rep; 145 209 }; 210 211 }; 212 146 213 #endif 147 148 };149 150 #endif -
trunk/JavaScriptCore/kjs/error_object.cpp
r6 r798 1 // -*- c-basic-offset: 2 -*- 1 2 /* 2 3 * This file is part of the KDE libraries … … 16 17 * License along with this library; if not, write to the Free Software 17 18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 * 18 20 */ 19 21 20 #include "kjs.h" 22 #include "value.h" 23 #include "object.h" 24 #include "types.h" 25 #include "interpreter.h" 21 26 #include "operations.h" 22 #include "types.h"23 #include "internal.h"24 27 #include "error_object.h" 25 #include "debugger.h"28 //#include "debugger.h" 26 29 27 30 using namespace KJS; 28 31 29 const char *ErrorObject::errName[] = { 30 "No Error", 31 "Error", 32 "EvalError", 33 "RangeError", 34 "ReferenceError", 35 "SyntaxError", 36 "TypeError", 37 "URIError" 38 }; 32 // ------------------------------ ErrorPrototypeImp ---------------------------- 39 33 40 ErrorObject::ErrorObject(const Object &funcProto, const Object &errProto, 41 ErrorType t) 42 : ConstructorImp(funcProto, 1), errType(t) 34 // ECMA 15.9.4 35 ErrorPrototypeImp::ErrorPrototypeImp(ExecState *exec, 36 ObjectPrototypeImp *objectProto, 37 FunctionPrototypeImp *funcProto) 38 : ObjectImp(Object(objectProto)) 43 39 { 44 // ECMA 15.11.3.1 Error.prototype45 set PrototypeProperty(errProto);46 const char *n = errName[errType];40 Value protect(this); 41 setInternalValue(Undefined()); 42 // The constructor will be added later in ErrorObjectImp's constructor 47 43 48 put("name", String(n)); 44 put(exec, "name", String("Error"), DontEnum); 45 put(exec, "message", String("Unknown error"), DontEnum); 46 put(exec, "toString", Object(new ErrorProtoFuncImp(exec,funcProto)), DontEnum); 49 47 } 50 48 51 ErrorObject::ErrorObject(const Object& proto, ErrorType t, 52 const char *m, int l) 53 : ConstructorImp(proto, 1), errType(t) 49 // ------------------------------ ErrorProtoFuncImp ---------------------------- 50 51 ErrorProtoFuncImp::ErrorProtoFuncImp(ExecState *exec, FunctionPrototypeImp *funcProto) 52 : InternalFunctionImp(funcProto) 54 53 { 55 const char *n = errName[errType]; 56 57 put("name", String(n)); 58 put("message", String(m)); 59 put("line", Number(l)); 60 #ifdef KJS_DEBUGGER 61 Debugger *dbg = KJScriptImp::current()->debugger(); 62 if (dbg) 63 put("sid", Number(dbg->sourceId())); 64 #endif 54 Value protect(this); 55 put(exec,"length",Number(0),DontDelete|ReadOnly|DontEnum); 65 56 } 66 57 67 // ECMA 15.9.2 68 Completion ErrorObject::execute(const List &args) 58 bool ErrorProtoFuncImp::implementsCall() const 69 59 { 70 // "Error()" gives the sames result as "new Error()" 71 return Completion(ReturnValue, construct(args)); 60 return true; 72 61 } 73 62 74 // ECMA 15.9.3 75 Object ErrorObject::construct(const List &args) 63 Value ErrorProtoFuncImp::call(ExecState *exec, Object &thisObj, const List &/*args*/) 76 64 { 77 if (args.isEmpty() == 1 || !args[0].isDefined())78 return Object::create(ErrorClass, Undefined());65 // toString() 66 UString s = "Error"; 79 67 80 String message = args[0].toString(); 81 return Object::create(ErrorClass, message); 82 } 68 Value v = thisObj.get(exec,"name"); 69 if (v.type() != UndefinedType) { 70 s = v.toString(exec); 71 } 83 72 84 Object ErrorObject::create(ErrorType e, const char *m, int l) 85 { 86 Global global(Global::current()); 87 KJSO prot = Global::current().get("[[Error.prototype]]"); 88 assert(prot.isObject()); 89 Imp *d = new ErrorObject(Object(prot.imp()), e, m, l); 90 91 return Object(d); 92 } 93 94 // ECMA 15.9.4 95 ErrorPrototype::ErrorPrototype(const Object& proto) 96 : ObjectImp(ErrorClass, Undefined(), proto) 97 { 98 // The constructor will be added later in ErrorObject's constructor 99 } 100 101 KJSO ErrorPrototype::get(const UString &p) const 102 { 103 const char *s; 104 105 /* TODO: are these properties dynamic, i.e. should we put() them ? */ 106 if (p == "name") 107 s = "Error"; 108 else if (p == "message") 109 s = "Error message."; 110 else if (p == "toString") 111 return Function(new ErrorProtoFunc()); 112 else 113 return Imp::get(p); 73 v = thisObj.get(exec,"message"); 74 if (v.type() != UndefinedType) { 75 s += ": "+v.toString(exec); 76 } 114 77 115 78 return String(s); 116 79 } 117 80 118 Completion ErrorProtoFunc::execute(const List &) 81 // ------------------------------ ErrorObjectImp ------------------------------- 82 83 ErrorObjectImp::ErrorObjectImp(ExecState *exec, FunctionPrototypeImp *funcProto, 84 ErrorPrototypeImp *errorProto) 85 : InternalFunctionImp(funcProto) 119 86 { 120 // toString()121 const char *s = "Error message.";122 123 return Completion(ReturnValue, String(s));87 Value protect(this); 88 // ECMA 15.11.3.1 Error.prototype 89 put(exec, "prototype", Object(errorProto), DontEnum|DontDelete|ReadOnly); 90 //put(exec, "name", String(n)); 124 91 } 125 92 93 bool ErrorObjectImp::implementsConstruct() const 94 { 95 return true; 96 } 97 98 // ECMA 15.9.3 99 Object ErrorObjectImp::construct(ExecState *exec, const List &args) 100 { 101 Object proto = Object::dynamicCast(exec->interpreter()->builtinErrorPrototype()); 102 Object obj(new ObjectImp(proto)); 103 104 if (!args.isEmpty() && args[0].type() != UndefinedType) { 105 obj.put(exec,"message", String(args[0].toString(exec))); 106 } 107 108 return obj; 109 } 110 111 bool ErrorObjectImp::implementsCall() const 112 { 113 return true; 114 } 115 116 // ECMA 15.9.2 117 Value ErrorObjectImp::call(ExecState *exec, Object &/*thisObj*/, const List &args) 118 { 119 // "Error()" gives the sames result as "new Error()" 120 return construct(exec,args); 121 } 122 123 // ------------------------------ NativeErrorPrototypeImp ---------------------- 124 125 NativeErrorPrototypeImp::NativeErrorPrototypeImp(ExecState *exec, ErrorPrototypeImp *errorProto, 126 ErrorType et, UString name, UString message) 127 : ObjectImp(Object(errorProto)) 128 { 129 Value protect(this); 130 errType = et; 131 put(exec,"name",String(name)); 132 put(exec,"message",String(message)); 133 } 134 135 // ------------------------------ NativeErrorImp ------------------------------- 136 137 const ClassInfo NativeErrorImp::info = {"Error", &InternalFunctionImp::info, 0, 0}; 138 139 NativeErrorImp::NativeErrorImp(ExecState *exec, FunctionPrototypeImp *funcProto, 140 const Object &prot) 141 : InternalFunctionImp(funcProto), proto(0) 142 { 143 Value protect(this); 144 proto = static_cast<ObjectImp*>(prot.imp()); 145 146 put(exec,"length",Number(1),DontDelete|ReadOnly|DontEnum); // ECMA 15.11.7.5 147 put(exec,"prototype",prot); 148 } 149 150 bool NativeErrorImp::implementsConstruct() const 151 { 152 return true; 153 } 154 155 Object NativeErrorImp::construct(ExecState *exec, const List &args) 156 { 157 Object obj(new ObjectImp(Object(proto))); 158 if (args[0].type() != UndefinedType) 159 obj.put(exec, "message", String(args[0].toString(exec))); 160 return obj; 161 } 162 163 bool NativeErrorImp::implementsCall() const 164 { 165 return true; 166 } 167 168 Value NativeErrorImp::call(ExecState *exec, Object &/*thisObj*/, const List &args) 169 { 170 return construct(exec,args); 171 } 172 173 void NativeErrorImp::mark() 174 { 175 ObjectImp::mark(); 176 if (proto && !proto->marked()) 177 proto->mark(); 178 } 179 -
trunk/JavaScriptCore/kjs/error_object.h
r6 r798 1 // -*- c-basic-offset: 2 -*- 1 2 /* 2 3 * This file is part of the KDE libraries … … 16 17 * License along with this library; if not, write to the Free Software 17 18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 * 20 * $Id$ 18 21 */ 19 22 … … 21 24 #define _ERROR_OBJECT_H_ 22 25 23 #include " object.h"24 #include "function .h"26 #include "internal.h" 27 #include "function_object.h" 25 28 26 29 namespace KJS { 27 30 28 class Error Object : public ConstructorImp {31 class ErrorPrototypeImp : public ObjectImp { 29 32 public: 30 ErrorObject(const Object &funcProto, const Object &errProto, 31 ErrorType t = GeneralError); 32 ErrorObject(const Object& proto, ErrorType t, const char *m, int l = -1); 33 Completion execute(const List &); 34 Object construct(const List &); 35 static Object create(ErrorType e, const char *m, int ln); 33 ErrorPrototypeImp(ExecState *exec, 34 ObjectPrototypeImp *objectProto, 35 FunctionPrototypeImp *funcProto); 36 }; 37 38 class ErrorProtoFuncImp : public InternalFunctionImp { 39 public: 40 ErrorProtoFuncImp(ExecState *exec, FunctionPrototypeImp *funcProto); 41 virtual bool implementsCall() const; 42 virtual Value call(ExecState *exec, Object &thisObj, const List &args); 43 }; 44 45 class ErrorObjectImp : public InternalFunctionImp { 46 public: 47 ErrorObjectImp(ExecState *exec, FunctionPrototypeImp *funcProto, 48 ErrorPrototypeImp *errorProto); 49 50 virtual bool implementsConstruct() const; 51 virtual Object construct(ExecState *exec, const List &args); 52 53 virtual bool implementsCall() const; 54 virtual Value call(ExecState *exec, Object &thisObj, const List &args); 55 }; 56 57 58 59 60 61 class NativeErrorPrototypeImp : public ObjectImp { 62 public: 63 NativeErrorPrototypeImp(ExecState *exec, ErrorPrototypeImp *errorProto, 64 ErrorType et, UString name, UString message); 36 65 private: 37 66 ErrorType errType; 38 static const char *errName[];39 67 }; 40 68 41 class ErrorPrototype : public ObjectImp {69 class NativeErrorImp : public InternalFunctionImp { 42 70 public: 43 ErrorPrototype(const Object& proto); 44 virtual KJSO get(const UString &p) const; 45 }; 71 NativeErrorImp(ExecState *exec, FunctionPrototypeImp *funcProto, 72 const Object &prot); 46 73 47 class ErrorProtoFunc : public InternalFunctionImp { 48 public: 49 ErrorProtoFunc() { } 50 Completion execute(const List &); 74 virtual bool implementsConstruct() const; 75 virtual Object construct(ExecState *exec, const List &args); 76 virtual bool implementsCall() const; 77 virtual Value call(ExecState *exec, Object &thisObj, const List &args); 78 79 virtual void mark(); 80 81 virtual const ClassInfo *classInfo() const { return &info; } 82 static const ClassInfo info; 83 private: 84 ObjectImp *proto; 51 85 }; 52 86 -
trunk/JavaScriptCore/kjs/function.cpp
r6 r798 1 // -*- c-basic-offset: 2 -*- 1 2 /* 2 3 * This file is part of the KDE libraries 3 4 * Copyright (C) 1999-2000 Harri Porten ([email protected]) 5 * Copyright (C) 2001 Peter Kelly ([email protected]) 4 6 * 5 7 * This library is free software; you can redistribute it and/or … … 17 19 * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, 18 20 * Boston, MA 02111-1307, USA. 21 * 19 22 */ 20 23 21 24 #include "function.h" 22 25 23 #include "kjs.h"24 #include "types.h"25 26 #include "internal.h" 27 #include "function_object.h" 28 #include "lexer.h" 29 #include "nodes.h" 26 30 #include "operations.h" 27 #include " nodes.h"28 #ifndef NDEBUG 31 #include "debugger.h" 32 29 33 #include <stdio.h> 30 #endif 34 #include <assert.h> 35 #include <string.h> 31 36 32 37 using namespace KJS; 33 38 34 const TypeInfo FunctionImp::info = { "Function", FunctionType, 35 &ObjectImp::info, 0, 0 }; 36 const TypeInfo InternalFunctionImp::info = { "InternalFunction", 37 InternalFunctionType, 38 &FunctionImp::info, 0, 0 }; 39 const TypeInfo ConstructorImp::info = { "Function", ConstructorType, 40 &InternalFunctionImp::info, 0, 0 }; 39 // ------------------------------ FunctionImp ---------------------------------- 40 41 const ClassInfo FunctionImp::info = {"Function", &InternalFunctionImp::info, 0, 0}; 41 42 42 43 namespace KJS { 43 44 44 class Parameter { 45 45 public: … … 49 49 Parameter *next; 50 50 }; 51 52 51 }; 53 52 54 FunctionImp::FunctionImp( )55 : ObjectImp(/*TODO*/BooleanClass), param(0L)56 { 57 } 58 59 FunctionImp::FunctionImp(const UString &n) 60 : ObjectImp(/*TODO*/BooleanClass), ident(n), param(0L)61 { 53 FunctionImp::FunctionImp(ExecState *exec, const UString &n) 54 : InternalFunctionImp( 55 static_cast<FunctionPrototypeImp*>(exec->interpreter()->builtinFunctionPrototype().imp()) 56 ), param(0L), ident(n), argStack(0) 57 { 58 Value protect(this); 59 argStack = new ListImp(); 60 put(exec,"arguments",Null(),ReadOnly|DontDelete|DontEnum); 62 61 } 63 62 64 63 FunctionImp::~FunctionImp() 65 64 { 65 argStack->setGcAllowed(); 66 // The function shouldn't be deleted while it is still executed; argStack 67 // should be set to 0 by the last call to popArgs() 68 assert(argStack->isEmpty()); 66 69 delete param; 67 70 } 68 71 69 KJSO FunctionImp::thisValue() const 70 { 71 return KJSO(Context::current()->thisValue()); 72 void FunctionImp::mark() 73 { 74 InternalFunctionImp::mark(); 75 if (argStack && !argStack->marked()) 76 argStack->mark(); 77 } 78 79 bool FunctionImp::implementsCall() const 80 { 81 return true; 82 } 83 84 Value FunctionImp::call(ExecState *exec, Object &thisObj, const List &args) 85 { 86 Object globalObj = exec->interpreter()->globalObject(); 87 88 Debugger *dbg = exec->interpreter()->imp()->debugger(); 89 int sid = -1; 90 int lineno = -1; 91 if (dbg) { 92 if (inherits(&DeclaredFunctionImp::info)) { 93 sid = static_cast<DeclaredFunctionImp*>(this)->body->sourceId(); 94 lineno = static_cast<DeclaredFunctionImp*>(this)->body->firstLine(); 95 } 96 97 Object func(this); 98 int cont = dbg->callEvent(exec,sid,lineno,func,args); 99 if (!cont) { 100 dbg->imp()->abort(); 101 return Undefined(); 102 } 103 } 104 105 // enter a new execution context 106 ContextImp *ctx = new ContextImp(globalObj, exec, thisObj, 107 codeType(), exec->context().imp(), this, args); 108 ExecState *newExec = new ExecState(exec->interpreter(),ctx); 109 newExec->setException(exec->exception()); // could be null 110 111 // In order to maintain our "arguments" property, we maintain a list of arguments 112 // properties from earlier in the execution stack. Upon return, we restore the 113 // previous arguments object using popArgs(). 114 // Note: this does not appear to be part of the spec 115 if (codeType() == FunctionCode) { 116 assert(ctx->activationObject().inherits(&ActivationImp::info)); 117 Object argsObj = static_cast<ActivationImp*>(ctx->activationObject().imp())->argumentsObject(); 118 put(newExec,"arguments", argsObj, DontDelete|DontEnum|ReadOnly); 119 pushArgs(newExec,argsObj); 120 } 121 122 // assign user supplied arguments to parameters 123 processParameters(newExec,args); 124 // add variable declarations (initialized to undefined) 125 processVarDecls(newExec); 126 127 Completion comp = execute(newExec); 128 129 // if an exception occured, propogate it back to the previous execution object 130 if (newExec->hadException()) 131 exec->setException(newExec->exception()); 132 if (codeType() == FunctionCode) 133 popArgs(newExec); 134 delete newExec; 135 delete ctx; 136 137 #ifdef KJS_VERBOSE 138 if (comp.complType() == Throw) 139 printInfo(exec,"throwing", comp.value()); 140 else if (comp.complType() == ReturnValue) 141 printInfo(exec,"returning", comp.value()); 142 else 143 fprintf(stderr, "returning: undefined\n"); 144 #endif 145 146 if (dbg) { 147 Object func(this); 148 int cont = dbg->returnEvent(exec,sid,lineno,func); 149 if (!cont) { 150 dbg->imp()->abort(); 151 return Undefined(); 152 } 153 } 154 155 if (comp.complType() == Throw) { 156 exec->setException(comp.value()); 157 return comp.value(); 158 } 159 else if (comp.complType() == ReturnValue) 160 return comp.value(); 161 else 162 return Undefined(); 72 163 } 73 164 … … 81 172 } 82 173 83 void FunctionImp::setLength(int l) 84 { 85 put("length", Number(l), ReadOnly|DontDelete|DontEnum); 86 } 87 88 // ECMA 10.1.3 89 void FunctionImp::processParameters(const List *args) 90 { 91 KJSO variable = Context::current()->variableObject(); 92 93 assert(args); 174 175 // ECMA 10.1.3q 176 void FunctionImp::processParameters(ExecState *exec, const List &args) 177 { 178 Object variable = exec->context().imp()->variableObject(); 94 179 95 180 #ifdef KJS_VERBOSE … … 100 185 101 186 if (param) { 102 ListIterator it = args ->begin();187 ListIterator it = args.begin(); 103 188 Parameter **p = ¶m; 104 189 while (*p) { 105 if (it != args ->end()) {190 if (it != args.end()) { 106 191 #ifdef KJS_VERBOSE 107 192 fprintf(stderr, "setting parameter %s ", (*p)->name.ascii()); 108 printInfo( "to", *it);193 printInfo(exec,"to", *it); 109 194 #endif 110 variable.put( (*p)->name, *it);195 variable.put(exec,(*p)->name, *it); 111 196 it++; 112 197 } else 113 variable.put( (*p)->name, Undefined());198 variable.put(exec,(*p)->name, Undefined()); 114 199 p = &(*p)->next; 115 200 } … … 117 202 #ifdef KJS_VERBOSE 118 203 else { 119 for (int i = 0; i < args ->size(); i++)120 printInfo( "setting argument", (*args)[i]);204 for (int i = 0; i < args.size(); i++) 205 printInfo(exec,"setting argument", args[i]); 121 206 } 122 207 #endif 123 #ifdef KJS_DEBUGGER 124 if (KJScriptImp::current()->debugger()) { 125 UString argStr; 126 for (int i = 0; i < args->size(); i++) { 127 if (i > 0) 128 argStr += ", "; 129 Imp *a = (*args)[i].imp(); 130 argStr += a->toString().value() + " : " + UString(a->typeInfo()->name); 131 } 132 UString n = name().isEmpty() ? UString( "(internal)" ) : name(); 133 KJScriptImp::current()->debugger()->callEvent(n, argStr); 134 } 135 #endif 136 } 137 138 // ECMA 13.2.1 139 KJSO FunctionImp::executeCall(Imp *thisV, const List *args) 140 { 141 return executeCall(thisV,args,0); 142 } 143 144 KJSO FunctionImp::executeCall(Imp *thisV, const List *args, const List *extraScope) 145 { 146 bool dummyList = false; 147 if (!args) { 148 args = new List(); 149 dummyList = true; 150 } 151 152 KJScriptImp *curr = KJScriptImp::current(); 153 Context *save = curr->context(); 154 155 Context *ctx = new Context(codeType(), save, this, args, thisV); 156 curr->setContext(ctx); 157 158 int numScopes = 0; 159 if (extraScope) { 160 ListIterator scopeIt = extraScope->begin(); 161 for (; scopeIt != extraScope->end(); scopeIt++) { 162 KJSO obj(*scopeIt); 163 ctx->pushScope(obj); 164 numScopes++; 165 } 166 } 167 168 // assign user supplied arguments to parameters 169 processParameters(args); 170 171 Completion comp = execute(*args); 172 173 if (dummyList) 174 delete args; 175 176 int i; 177 for (i = 0; i < numScopes; i++) 178 ctx->popScope(); 179 180 put("arguments", Null()); 181 delete ctx; 182 curr->setContext(save); 183 184 #ifdef KJS_VERBOSE 185 if (comp.complType() == Throw) 186 printInfo("throwing", comp.value()); 187 else if (comp.complType() == ReturnValue) 188 printInfo("returning", comp.value()); 208 } 209 210 void FunctionImp::processVarDecls(ExecState */*exec*/) 211 { 212 } 213 214 void FunctionImp::pushArgs(ExecState *exec, const Object &args) 215 { 216 argStack->append(args); 217 put(exec,"arguments",args,ReadOnly|DontDelete|DontEnum); 218 } 219 220 void FunctionImp::popArgs(ExecState *exec) 221 { 222 argStack->removeLast(); 223 if (argStack->isEmpty()) { 224 put(exec,"arguments",Null(),ReadOnly|DontDelete|DontEnum); 225 } 189 226 else 190 fprintf(stderr, "returning: undefined\n"); 191 #endif 192 #ifdef KJS_DEBUGGER 193 if (KJScriptImp::current()->debugger()) 194 KJScriptImp::current()->debugger()->returnEvent(); 195 #endif 196 197 if (comp.complType() == Throw) 198 return comp.value(); 199 else if (comp.complType() == ReturnValue) 200 return comp.value(); 227 put(exec,"arguments",argStack->at(argStack->size()-1),ReadOnly|DontDelete|DontEnum); 228 } 229 230 // ------------------------------ DeclaredFunctionImp -------------------------- 231 232 // ### is "Function" correct here? 233 const ClassInfo DeclaredFunctionImp::info = {"Function", &FunctionImp::info, 0, 0}; 234 235 DeclaredFunctionImp::DeclaredFunctionImp(ExecState *exec, const UString &n, 236 FunctionBodyNode *b, const List &sc) 237 : FunctionImp(exec,n), body(b) 238 { 239 Value protect(this); 240 body->ref(); 241 setScope(sc.copy()); 242 } 243 244 DeclaredFunctionImp::~DeclaredFunctionImp() 245 { 246 if ( body->deref() ) 247 delete body; 248 } 249 250 bool DeclaredFunctionImp::implementsConstruct() const 251 { 252 return true; 253 } 254 255 // ECMA 13.2.2 [[Construct]] 256 Object DeclaredFunctionImp::construct(ExecState *exec, const List &args) 257 { 258 Object proto; 259 Value p = get(exec,"prototype"); 260 if (p.type() == ObjectType) 261 proto = Object(static_cast<ObjectImp*>(p.imp())); 201 262 else 202 return Undefined(); 203 } 204 205 UString FunctionImp::name() const 206 { 207 return ident; 208 } 209 210 InternalFunctionImp::InternalFunctionImp() 211 { 212 } 213 214 InternalFunctionImp::InternalFunctionImp(int l) 215 { 216 if (l >= 0) 217 setLength(l); 218 } 219 220 InternalFunctionImp::InternalFunctionImp(const UString &n) 221 : FunctionImp(n) 222 { 223 } 224 225 String InternalFunctionImp::toString() const 226 { 227 if (name().isNull()) 228 return UString("(Internal function)"); 263 proto = exec->interpreter()->builtinObjectPrototype(); 264 265 Object obj(new ObjectImp(proto)); 266 267 Value res = call(exec,obj,args); 268 269 if (res.type() == ObjectType) 270 return Object::dynamicCast(res); 229 271 else 230 return UString("function " + name() + "()"); 231 } 232 233 Completion InternalFunctionImp::execute(const List &) 234 { 235 return Completion(ReturnValue, Undefined()); 236 } 237 238 ConstructorImp::ConstructorImp() { 239 setPrototype(Global::current().functionPrototype()); 240 // TODO ??? put("constructor", this); 241 setLength(1); 242 } 243 244 ConstructorImp::ConstructorImp(const UString &n) 245 : InternalFunctionImp(n) 246 { 247 } 248 249 ConstructorImp::ConstructorImp(const KJSO &p, int len) 250 { 251 setPrototype(p); 252 // TODO ??? put("constructor", *this); 253 setLength(len); 254 } 255 256 ConstructorImp::ConstructorImp(const UString &n, const KJSO &p, int len) 257 : InternalFunctionImp(n) 258 { 259 setPrototype(p); 260 // TODO ??? put("constructor", *this); 261 setLength(len); 262 } 263 264 ConstructorImp::~ConstructorImp() { } 265 266 Completion ConstructorImp::execute(const List &) 267 { 268 /* TODO */ 269 return Completion(ReturnValue, Null()); 270 } 271 272 Function::Function(Imp *d) 273 : KJSO(d) 274 { 275 if (d) { 276 static_cast<FunctionImp*>(rep)->attr = ImplicitNone; 277 assert(Global::current().hasProperty("[[Function.prototype]]")); 278 setPrototype(Global::current().functionPrototype()); 279 } 280 } 281 282 Completion Function::execute(const List &args) 283 { 284 assert(rep); 285 return static_cast<FunctionImp*>(rep)->execute(args); 286 } 287 288 bool Function::hasAttribute(FunctionAttribute a) const 289 { 290 assert(rep); 291 return static_cast<FunctionImp*>(rep)->hasAttribute(a); 292 } 293 294 #if 0 295 InternalFunction::InternalFunction(Imp *d) 296 : Function(d) 297 { 298 param = 0L; 299 } 300 301 InternalFunction::~InternalFunction() 302 { 303 } 304 #endif 305 306 Constructor::Constructor(Imp *d) 307 : Function(d) 308 { 309 if (d) { 310 assert(Global::current().hasProperty("[[Function.prototype]]")); 311 setPrototype(Global::current().get("[[Function.prototype]]")); 312 put("constructor", *this); 313 KJSO tmp(d); // protect from GC 314 ((FunctionImp*)d)->setLength(1); 315 } 316 } 317 318 #if 0 319 Constructor::Constructor(const Object& proto, int len) 320 { 321 setPrototype(proto); 322 put("constructor", *this); 323 put("length", len, DontEnum); 324 } 325 #endif 326 327 Constructor::~Constructor() 328 { 329 } 330 331 Completion Constructor::execute(const List &) 332 { 333 /* TODO: call construct instead ? */ 334 return Completion(ReturnValue, Undefined()); 335 } 336 337 Object Constructor::construct(const List &args) 338 { 339 assert(rep && rep->type() == ConstructorType); 340 return ((ConstructorImp*)rep)->construct(args); 341 } 342 343 Constructor Constructor::dynamicCast(const KJSO &obj) 344 { 345 // return null object on type mismatch 346 if (!obj.isA(ConstructorType)) 347 return Constructor(0L); 348 349 return Constructor(obj.imp()); 350 } 351 352 KJSO Function::thisValue() const 353 { 354 return KJSO(Context::current()->thisValue()); 355 } 272 return obj; 273 } 274 275 Completion DeclaredFunctionImp::execute(ExecState *exec) 276 { 277 Completion result = body->execute(exec); 278 279 if (result.complType() == Throw || result.complType() == ReturnValue) 280 return result; 281 return Completion(Normal, Undefined()); // TODO: or ReturnValue ? 282 } 283 284 void DeclaredFunctionImp::processVarDecls(ExecState *exec) 285 { 286 body->processVarDecls(exec); 287 } 288 289 // ------------------------------ ArgumentsImp --------------------------------- 290 291 const ClassInfo ArgumentsImp::info = {"Arguments", 0, 0, 0}; 292 293 // ECMA 10.1.8 294 ArgumentsImp::ArgumentsImp(ExecState *exec, FunctionImp *func, const List &args) 295 : ObjectImp(exec->interpreter()->builtinObjectPrototype()) 296 { 297 Value protect(this); 298 put(exec,"callee", Object(func), DontEnum); 299 put(exec,"length", Number(args.size()), DontEnum); 300 if (!args.isEmpty()) { 301 ListIterator arg = args.begin(); 302 for (int i = 0; arg != args.end(); arg++, i++) { 303 put(exec,UString::from(i), *arg, DontEnum); 304 } 305 } 306 } 307 308 // ------------------------------ ActivationImp -------------------------------- 309 310 const ClassInfo ActivationImp::info = {"Activation", 0, 0, 0}; 311 312 // ECMA 10.1.6 313 ActivationImp::ActivationImp(ExecState *exec, FunctionImp *f, const List &args) 314 : ObjectImp() 315 { 316 Value protect(this); 317 arguments = new ArgumentsImp(exec,f, args); 318 put(exec, "arguments", Object(arguments), Internal|DontDelete); 319 } 320 321 ActivationImp::~ActivationImp() 322 { 323 arguments->setGcAllowed(); 324 } 325 326 // ------------------------------ GlobalFunc ----------------------------------- 327 328 329 GlobalFuncImp::GlobalFuncImp(ExecState *exec, FunctionPrototypeImp *funcProto, int i, int len) 330 : InternalFunctionImp(funcProto), id(i) 331 { 332 Value protect(this); 333 put(exec,"length",Number(len),DontDelete|ReadOnly|DontEnum); 334 } 335 336 CodeType GlobalFuncImp::codeType() const 337 { 338 return id == Eval ? EvalCode : codeType(); 339 } 340 341 bool GlobalFuncImp::implementsCall() const 342 { 343 return true; 344 } 345 346 Value GlobalFuncImp::call(ExecState *exec, Object &/*thisObj*/, const List &args) 347 { 348 Value res; 349 350 static const char non_escape[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" 351 "abcdefghijklmnopqrstuvwxyz" 352 "0123456789@*_+-./"; 353 354 if (id == Eval) { // eval() 355 Value x = args[0]; 356 if (x.type() != StringType) 357 return x; 358 else { 359 UString s = x.toString(exec); 360 361 int sid; 362 int errLine; 363 UString errMsg; 364 ProgramNode *progNode = Parser::parse(s.data(),s.size(),&sid,&errLine,&errMsg); 365 366 // no program node means a syntax occurred 367 if (!progNode) { 368 Object err = Error::create(exec,SyntaxError,errMsg.ascii(),errLine); 369 err.put(exec,"sid",Number(sid)); 370 exec->setException(err); 371 return err; 372 } 373 374 progNode->ref(); 375 376 // enter a new execution context 377 Object glob(exec->interpreter()->globalObject()); 378 Object thisVal(Object::dynamicCast(exec->context().thisValue())); 379 ContextImp *ctx = new ContextImp(glob, 380 exec, 381 thisVal, 382 EvalCode, 383 exec->context().imp()); 384 385 ExecState *newExec = new ExecState(exec->interpreter(),ctx); 386 newExec->setException(exec->exception()); // could be null 387 388 // execute the code 389 Completion c = progNode->execute(newExec); 390 391 // if an exception occured, propogate it back to the previous execution object 392 if (newExec->hadException()) 393 exec->setException(newExec->exception()); 394 delete newExec; 395 delete ctx; 396 397 if ( progNode->deref() ) 398 delete progNode; 399 if (c.complType() == ReturnValue) 400 return c; 401 // ### setException() on throw? 402 else if (c.complType() == Normal) { 403 if (c.isValueCompletion()) 404 return c.value(); 405 else 406 return Undefined(); 407 } else 408 return c; 409 } 410 } else if (id == ParseInt) { 411 String str = args[0].toString(exec); 412 int radix = args[1].toInt32(exec); 413 if (radix == 0) 414 radix = 10; 415 else if (radix < 2 || radix > 36) { 416 res = Number(NaN); 417 return res; 418 } 419 /* TODO: use radix */ 420 // Can't use toULong(), we want to accept floating point values too 421 double value = str.value().toDouble( true /*tolerant*/ ); 422 if ( isNaN(value) ) 423 res = Number(NaN); 424 else 425 res = Number(static_cast<long>(value)); // remove floating-point part 426 } else if (id == ParseFloat) { 427 String str = args[0].toString(exec); 428 res = Number(str.value().toDouble( true /*tolerant*/ )); 429 } else if (id == IsNaN) { 430 res = Boolean(isNaN(args[0].toNumber(exec))); 431 } else if (id == IsFinite) { 432 Number n = args[0].toNumber(exec); 433 res = Boolean(!n.isNaN() && !n.isInf()); 434 } else if (id == Escape) { 435 UString r = "", s, str = args[0].toString(exec); 436 const UChar *c = str.data(); 437 for (int k = 0; k < str.size(); k++, c++) { 438 int u = c->unicode(); 439 if (u > 255) { 440 char tmp[7]; 441 sprintf(tmp, "%%u%04X", u); 442 s = UString(tmp); 443 } else if (strchr(non_escape, (char)u)) { 444 s = UString(c, 1); 445 } else { 446 char tmp[4]; 447 sprintf(tmp, "%%%02X", u); 448 s = UString(tmp); 449 } 450 r += s; 451 } 452 res = String(r); 453 } else if (id == UnEscape) { 454 UString s, str = args[0].toString(exec); 455 int k = 0, len = str.size(); 456 while (k < len) { 457 const UChar *c = str.data() + k; 458 UChar u; 459 if (*c == UChar('%') && k <= len - 6 && *(c+1) == UChar('u')) { 460 u = Lexer::convertUnicode((c+2)->unicode(), (c+3)->unicode(), 461 (c+4)->unicode(), (c+5)->unicode()); 462 c = &u; 463 k += 5; 464 } else if (*c == UChar('%') && k <= len - 3) { 465 u = UChar(Lexer::convertHex((c+1)->unicode(), (c+2)->unicode())); 466 c = &u; 467 k += 2; 468 } 469 k++; 470 s += UString(c, 1); 471 } 472 res = String(s); 473 } 474 475 return res; 476 } -
trunk/JavaScriptCore/kjs/function.h
r6 r798 1 // -*- c-basic-offset: 2 -*- 1 2 /* 2 3 * This file is part of the KDE libraries … … 17 18 * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, 18 19 * Boston, MA 02111-1307, USA. 20 * 21 * $Id$ 19 22 */ 20 23 … … 22 25 #define _KJS_FUNCTION_H_ 23 26 24 #include <assert.h> 25 26 #include "object.h" 27 #include "types.h" 27 #include "internal.h" 28 28 29 29 namespace KJS { 30 30 31 enum CodeType { GlobalCode,32 EvalCode,33 FunctionCode,34 AnonymousCode,35 HostCode };36 37 enum FunctionAttribute { ImplicitNone, ImplicitThis, ImplicitParents };38 39 class Function;40 31 class Parameter; 41 32 42 33 /** 43 * @short Implementation class for Functions.34 * @short Implementation class for internal Functions. 44 35 */ 45 class FunctionImp : public ObjectImp {36 class FunctionImp : public InternalFunctionImp { 46 37 friend class Function; 38 friend class ActivationImp; 47 39 public: 48 FunctionImp(); 49 FunctionImp(const UString &n); 40 FunctionImp(ExecState *exec, const UString &n = UString::null); 50 41 virtual ~FunctionImp(); 51 virtual const TypeInfo* typeInfo() const { return &info; } 52 static const TypeInfo info; 53 virtual Completion execute(const List &) = 0; 54 bool hasAttribute(FunctionAttribute a) const { return (attr & a) != 0; } 42 43 virtual void mark(); 44 45 virtual bool implementsCall() const; 46 virtual Value call(ExecState *exec, Object &thisObj, const List &args); 47 48 void addParameter(const UString &n); 55 49 virtual CodeType codeType() const = 0; 56 KJSO thisValue() const; 57 v oid addParameter(const UString &n);58 void setLength(int l);59 KJSO executeCall(Imp *thisV, const List *args); 60 KJSO executeCall(Imp *thisV, const List *args, const List *extraScope);61 UString name() const;50 51 virtual Completion execute(ExecState *exec) = 0; 52 UString name() const { return ident; } 53 54 virtual const ClassInfo *classInfo() const { return &info; } 55 static const ClassInfo info; 62 56 protected: 57 Parameter *param; 63 58 UString ident; 64 FunctionAttribute attr; 65 Parameter *param; 59 66 60 private: 67 void processParameters(const List *); 61 void processParameters(ExecState *exec, const List &); 62 virtual void processVarDecls(ExecState *exec); 63 64 void pushArgs(ExecState *exec, const Object &args); 65 void popArgs(ExecState *exec); 66 ListImp *argStack; 68 67 }; 69 68 70 /** 71 * @short Abstract base class for internal functions. 72 */ 73 class InternalFunctionImp : public FunctionImp { 69 class DeclaredFunctionImp : public FunctionImp { 74 70 public: 75 InternalFunctionImp(); 76 InternalFunctionImp(int l); 77 InternalFunctionImp(const UString &n); 78 virtual ~InternalFunctionImp() { } 79 virtual String toString() const; 80 virtual KJSO toPrimitive(Type) const { return toString(); } 81 virtual const TypeInfo* typeInfo() const { return &info; } 82 static const TypeInfo info; 83 virtual Completion execute(const List &); 84 virtual CodeType codeType() const { return HostCode; } 71 DeclaredFunctionImp(ExecState *exec, const UString &n, 72 FunctionBodyNode *b, const List &sc); 73 ~DeclaredFunctionImp(); 74 75 bool implementsConstruct() const; 76 Object construct(ExecState *exec, const List &args); 77 78 virtual Completion execute(ExecState *exec); 79 CodeType codeType() const { return FunctionCode; } 80 FunctionBodyNode *body; 81 82 virtual const ClassInfo *classInfo() const { return &info; } 83 static const ClassInfo info; 84 private: 85 virtual void processVarDecls(ExecState *exec); 85 86 }; 86 87 87 /** 88 * @short Base class for Function objects. 89 */ 90 class Function : public KJSO{88 89 90 91 class ArgumentsImp : public ObjectImp { 91 92 public: 92 Function(Imp *); 93 virtual ~Function() { } 94 Completion execute(const List &); 95 bool hasAttribute(FunctionAttribute a) const; 96 CodeType codeType() const { return HostCode; } 97 KJSO thisValue() const; 98 }; 99 100 /** 101 * @short Implementation class for Constructors. 102 */ 103 class ConstructorImp : public InternalFunctionImp { 104 public: 105 ConstructorImp(); 106 ConstructorImp(const UString &n); /* TODO: add length */ 107 ConstructorImp(const KJSO &, int); 108 ConstructorImp(const UString &n, const KJSO &p, int len); 109 virtual ~ConstructorImp(); 110 virtual const TypeInfo* typeInfo() const { return &info; } 111 static const TypeInfo info; 112 virtual Completion execute(const List &); 113 virtual Object construct(const List &) = 0; 93 ArgumentsImp(ExecState *exec, FunctionImp *func, const List &args); 94 95 virtual const ClassInfo *classInfo() const { return &info; } 96 static const ClassInfo info; 114 97 }; 115 98 116 /** 117 * @short Constructor object for use with the 'new' operator 118 */ 119 class Constructor : public Function { 99 class ActivationImp : public ObjectImp { 120 100 public: 121 Constructor(Imp *);122 virtual ~Constructor();123 // Constructor(const Object& proto, int len); 124 /**125 * @return @ref ConstructorType 126 */127 Completion execute(const List &);128 Object construct(const List &args);129 static Constructor dynamicCast(const KJSO &obj);101 ActivationImp(ExecState *exec, FunctionImp *f, const List &args); 102 ~ActivationImp(); 103 104 Object argumentsObject() { return Object(arguments); } 105 106 virtual const ClassInfo *classInfo() const { return &info; } 107 static const ClassInfo info; 108 private: 109 ObjectImp* arguments; 130 110 }; 111 112 class GlobalFuncImp : public InternalFunctionImp { 113 public: 114 GlobalFuncImp(ExecState *exec, FunctionPrototypeImp *funcProto, int i, int len); 115 virtual bool implementsCall() const; 116 virtual Value call(ExecState *exec, Object &thisObj, const List &args); 117 virtual CodeType codeType() const; 118 enum { Eval, ParseInt, ParseFloat, IsNaN, IsFinite, Escape, UnEscape }; 119 private: 120 int id; 121 }; 122 123 131 124 132 125 }; // namespace -
trunk/JavaScriptCore/kjs/function_object.cpp
r6 r798 1 // -*- c-basic-offset: 2 -*- 1 2 /* 2 3 * This file is part of the KDE libraries 3 * Copyright (C) 1999-200 0Harri Porten ([email protected])4 * Copyright (C) 1999-2001 Harri Porten ([email protected]) 4 5 * 5 6 * This library is free software; you can redistribute it and/or … … 16 17 * License along with this library; if not, write to the Free Software 17 18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 * 18 20 */ 19 21 20 22 #include "function_object.h" 21 23 #include "internal.h" 24 #include "function.h" 25 #include "array_object.h" 26 #include "nodes.h" 22 27 #include "lexer.h" 23 #include "nodes.h" 24 #include "error_object.h" 25 26 extern int kjsyyparse(); 28 #include "debugger.h" 29 #include "object.h" 30 31 #include <assert.h> 32 #include <stdio.h> 33 #include <string.h> 27 34 28 35 using namespace KJS; 29 36 30 FunctionObject::FunctionObject(const Object& funcProto) 31 : ConstructorImp(funcProto, 1) 32 { 33 // ECMA 15.3.3.1 Function.prototype 34 setPrototypeProperty(funcProto); 35 } 36 37 // ECMA 15.3.1 The Function Constructor Called as a Function 38 Completion FunctionObject::execute(const List &args) 39 { 40 return Completion(ReturnValue, construct(args)); 37 // ------------------------------ FunctionPrototypeImp ------------------------- 38 39 FunctionPrototypeImp::FunctionPrototypeImp(ExecState *exec) 40 : InternalFunctionImp(0) 41 { 42 Value protect(this); 43 put(exec, "toString", Object(new FunctionProtoFuncImp(exec, this, FunctionProtoFuncImp::ToString, 0)), DontEnum); 44 put(exec, "apply", Object(new FunctionProtoFuncImp(exec, this, FunctionProtoFuncImp::Apply, 2)), DontEnum); 45 put(exec, "call", Object(new FunctionProtoFuncImp(exec, this, FunctionProtoFuncImp::Call, 1)), DontEnum); 46 } 47 48 FunctionPrototypeImp::~FunctionPrototypeImp() 49 { 50 } 51 52 bool FunctionPrototypeImp::implementsCall() const 53 { 54 return true; 55 } 56 57 // ECMA 15.3.4 58 Value FunctionPrototypeImp::call(ExecState */*exec*/, Object &/*thisObj*/, const List &/*args*/) 59 { 60 return Undefined(); 61 } 62 63 // ------------------------------ FunctionProtoFuncImp ------------------------- 64 65 FunctionProtoFuncImp::FunctionProtoFuncImp(ExecState *exec, 66 FunctionPrototypeImp *funcProto, int i, int len) 67 : InternalFunctionImp(funcProto), id(i) 68 { 69 Value protect(this); 70 put(exec,"length",Number(len),DontDelete|ReadOnly|DontEnum); 71 } 72 73 74 bool FunctionProtoFuncImp::implementsCall() const 75 { 76 return true; 77 } 78 79 Value FunctionProtoFuncImp::call(ExecState *exec, Object &thisObj, const List &args) 80 { 81 Value result; 82 83 switch (id) { 84 case ToString: { 85 // ### also make this work for internal functions 86 // ### return the text of the function body (see 15.3.4.2) 87 if (thisObj.isNull() || !thisObj.inherits(&InternalFunctionImp::info)) { 88 #ifndef NDEBUG 89 fprintf(stderr,"attempted toString() call on null or non-function object\n"); 90 #endif 91 Object err = Error::create(exec,TypeError); 92 exec->setException(err); 93 return err; 94 } 95 if (thisObj.inherits(&FunctionImp::info) && 96 !static_cast<FunctionImp*>(thisObj.imp())->name().isNull()) { 97 result = String("function " + static_cast<FunctionImp*>(thisObj.imp())->name() + "()"); 98 } 99 else { 100 result = String("(Internal function)"); 101 } 102 } 103 break; 104 case Apply: { 105 Value thisArg = args[0]; 106 Value argArray = args[1]; 107 Object func = thisObj; 108 109 if (!func.implementsCall()) { 110 Object err = Error::create(exec,TypeError); 111 exec->setException(err); 112 return err; 113 } 114 115 Object applyThis; 116 if (thisArg.isA(NullType) || thisArg.isA(UndefinedType)) 117 applyThis = exec->interpreter()->globalObject(); 118 else 119 applyThis = thisArg.toObject(exec); 120 121 List applyArgs; 122 if (!argArray.isA(NullType) && !argArray.isA(UndefinedType)) { 123 if ((argArray.isA(ObjectType) && 124 Object::dynamicCast(argArray).inherits(&ArrayInstanceImp::info)) || 125 Object::dynamicCast(argArray).inherits(&ArgumentsImp::info)) { 126 127 Object argArrayObj = Object::dynamicCast(argArray); 128 unsigned int length = argArrayObj.get(exec,"length").toUInt32(exec); 129 for (uint i = 0; i < length; i++) 130 applyArgs.append(argArrayObj.get(exec,UString::from(i))); 131 } 132 else { 133 Object err = Error::create(exec,TypeError); 134 exec->setException(err); 135 return err; 136 } 137 } 138 result = func.call(exec,applyThis,applyArgs); 139 } 140 break; 141 case Call: { 142 Value thisArg = args[0]; 143 Object func = thisObj; 144 145 if (!func.implementsCall()) { 146 Object err = Error::create(exec,TypeError); 147 exec->setException(err); 148 return err; 149 } 150 151 Object callThis; 152 if (thisArg.isA(NullType) || thisArg.isA(UndefinedType)) 153 callThis = exec->interpreter()->globalObject(); 154 else 155 callThis = thisArg.toObject(exec); 156 157 List callArgs = args.copy(); 158 callArgs.removeFirst(); 159 result = func.call(exec,callThis,callArgs); 160 } 161 break; 162 } 163 164 return result; 165 } 166 167 // ------------------------------ FunctionObjectImp ---------------------------- 168 169 FunctionObjectImp::FunctionObjectImp(ExecState *exec, FunctionPrototypeImp *funcProto) 170 : InternalFunctionImp(funcProto) 171 { 172 Value protect(this); 173 put(exec,"prototype", Object(funcProto), DontEnum|DontDelete|ReadOnly); 174 175 // no. of arguments for constructor 176 put(exec,"length", Number(1), ReadOnly|DontDelete|DontEnum); 177 } 178 179 FunctionObjectImp::~FunctionObjectImp() 180 { 181 } 182 183 bool FunctionObjectImp::implementsConstruct() const 184 { 185 return true; 41 186 } 42 187 43 188 // ECMA 15.3.2 The Function Constructor 44 Object FunctionObject ::construct(const List &args)189 Object FunctionObjectImp::construct(ExecState *exec, const List &args) 45 190 { 46 191 UString p(""); … … 50 195 body = ""; 51 196 } else if (argsSize == 1) { 52 body = args[0].toString( ).value();197 body = args[0].toString(exec); 53 198 } else { 54 p = args[0].toString( ).value();199 p = args[0].toString(exec); 55 200 for (int k = 1; k < argsSize - 1; k++) 56 p += "," + args[k].toString().value(); 57 body = args[argsSize-1].toString().value(); 58 } 59 60 Lexer::curr()->setCode(body.data(), body.size()); 61 62 KJScriptImp::current()->pushStack(); 63 int yp = kjsyyparse(); 64 ProgramNode *progNode = KJScriptImp::current()->progNode(); 65 KJScriptImp::current()->popStack(); 66 if (yp) { 67 /* TODO: free nodes */ 68 return ErrorObject::create(SyntaxError, 69 I18N_NOOP("Syntax error in function body"), -1); 201 p += "," + args[k].toString(exec); 202 body = args[argsSize-1].toString(exec); 203 } 204 205 // parse the source code 206 int sid; 207 int errLine; 208 UString errMsg; 209 ProgramNode *progNode = Parser::parse(body.data(),body.size(),&sid,&errLine,&errMsg); 210 211 // notify debugger that source has been parsed 212 Debugger *dbg = exec->interpreter()->imp()->debugger(); 213 if (dbg) { 214 bool cont = dbg->sourceParsed(exec,sid,body,errLine); 215 if (!cont) { 216 dbg->imp()->abort(); 217 return Object(new ObjectImp()); 218 } 219 } 220 221 // no program node == syntax error - throw a syntax error 222 if (!progNode) { 223 Object err = Error::create(exec,SyntaxError,errMsg.ascii(),errLine); 224 // we can't return a Completion(Throw) here, so just set the exception 225 // and return it 226 exec->setException(err); 227 return err; 70 228 } 71 229 72 230 List scopeChain; 73 scopeChain.append( Global::current());231 scopeChain.append(exec->interpreter()->globalObject()); 74 232 FunctionBodyNode *bodyNode = progNode; 75 FunctionImp *fimp = new DeclaredFunctionImp(UString::null, bodyNode, 76 &scopeChain); 233 234 FunctionImp *fimp = new DeclaredFunctionImp(exec, UString::null, bodyNode, 235 scopeChain); 77 236 Object ret(fimp); // protect from GC 78 237 … … 106 265 } // else error 107 266 } 108 return ErrorObject::create(SyntaxError,267 Object err = Error::create(exec,SyntaxError, 109 268 I18N_NOOP("Syntax error in parameter list"), 110 269 -1); 111 } 112 113 fimp->setLength(params); 114 fimp->setPrototypeProperty(Global::current().functionPrototype()); 270 exec->setException(err); 271 return err; 272 } 273 274 fimp->put(exec,"length", Number(params),ReadOnly|DontDelete|DontEnum); 275 List consArgs; 276 277 Object objCons = exec->interpreter()->builtinObject(); 278 Object prototype = objCons.construct(exec,List::empty()); 279 prototype.put(exec, "constructor", 280 Object(fimp), DontEnum|DontDelete|ReadOnly); 281 fimp->put(exec,"prototype",prototype,DontEnum|DontDelete|ReadOnly); 282 fimp->put(exec,"arguments",Null(),DontEnum|DontDelete|ReadOnly); 115 283 return ret; 116 284 } 117 285 118 FunctionPrototype::FunctionPrototype(const Object &p) 119 : ObjectImp(FunctionClass, Null(), p) 120 { 121 } 286 bool FunctionObjectImp::implementsCall() const 287 { 288 return true; 289 } 290 291 // ECMA 15.3.1 The Function Constructor Called as a Function 292 Value FunctionObjectImp::call(ExecState *exec, Object &/*thisObj*/, const List &args) 293 { 294 return construct(exec,args); 295 } 296 -
trunk/JavaScriptCore/kjs/function_object.h
r6 r798 1 // -*- c-basic-offset: 2 -*- 1 2 /* 2 3 * This file is part of the KDE libraries … … 16 17 * License along with this library; if not, write to the Free Software 17 18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 * 20 * $Id$ 18 21 */ 19 22 … … 21 24 #define _FUNCTION_OBJECT_H_ 22 25 23 #include "object.h" 26 #include "internal.h" 27 #include "object_object.h" 24 28 #include "function.h" 25 29 26 30 namespace KJS { 27 31 28 class FunctionPrototype : public ObjectImp { 32 /** 33 * @internal 34 * 35 * The initial value of Function.prototype (and thus all objects created 36 * with the Function constructor 37 */ 38 class FunctionPrototypeImp : public InternalFunctionImp { 29 39 public: 30 FunctionPrototype(const Object &p); 40 FunctionPrototypeImp(ExecState *exec); 41 virtual ~FunctionPrototypeImp(); 42 43 virtual bool implementsCall() const; 44 virtual Value call(ExecState *exec, Object &thisObj, const List &args); 31 45 }; 32 46 33 class FunctionObject : public ConstructorImp { 47 /** 48 * @internal 49 * 50 * Class to implement all methods that are properties of the 51 * Function.prototype object 52 */ 53 class FunctionProtoFuncImp : public InternalFunctionImp { 34 54 public: 35 FunctionObject(const Object &funcProto); 36 Completion execute(const List &); 37 Object construct(const List &); 55 FunctionProtoFuncImp(ExecState *exec, 56 FunctionPrototypeImp *funcProto, int i, int len); 57 58 virtual bool implementsCall() const; 59 virtual Value call(ExecState *exec, Object &thisObj, const List &args); 60 61 enum { ToString, Apply, Call }; 62 private: 63 int id; 64 }; 65 66 /** 67 * @internal 68 * 69 * The initial value of the the global variable's "Function" property 70 */ 71 class FunctionObjectImp : public InternalFunctionImp { 72 public: 73 FunctionObjectImp(ExecState *exec, FunctionPrototypeImp *funcProto); 74 virtual ~FunctionObjectImp(); 75 76 virtual bool implementsConstruct() const; 77 virtual Object construct(ExecState *exec, const List &args); 78 virtual bool implementsCall() const; 79 virtual Value call(ExecState *exec, Object &thisObj, const List &args); 38 80 }; 39 81 40 82 }; // namespace 41 83 42 #endif 84 #endif // _FUNCTION_OBJECT_H_ -
trunk/JavaScriptCore/kjs/grammar.y
r6 r798 18 18 * License along with this library; if not, write to the Free Software 19 19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 20 * 21 * $Id$ 20 22 */ 21 23 … … 24 26 #endif 25 27 #include <string.h> 26 #include "kjs.h" 28 #include <stdlib.h> 29 #include "value.h" 30 #include "object.h" 31 #include "types.h" 32 #include "interpreter.h" 27 33 #include "nodes.h" 28 34 #include "lexer.h" 35 #include "internal.h" 29 36 30 37 /* default values for bison */ 31 38 #define YYDEBUG 0 32 39 #define YYMAXDEPTH 0 33 #ifdef KJS_DEBUGGER 40 #ifdef APPLE_CHANGES 41 #else 34 42 #define YYERROR_VERBOSE 35 #define DBG(l, s, e) { l->setLoc(s.first_line, e.last_line); } // location36 #else37 #undef YYLSP_NEEDED38 #define DBG(l, s, e)39 43 #endif 44 #define DBG(l, s, e) { l->setLoc(s.first_line, e.last_line, Parser::sid); } // location 40 45 41 46 extern int yylex(); … … 111 116 112 117 /* automatically inserted semicolon */ 113 %token AUTO 118 %token AUTOPLUSPLUS AUTOMINUSMINUS 114 119 115 120 /* non-terminal types */ … … 163 168 if (!l->scanRegExp()) YYABORT; 164 169 $$ = new RegExpNode(l->pattern,l->flags);} 170 | DIVEQUAL /* a RegExp starting with /= ! */ 171 { Lexer *l = Lexer::curr(); 172 if (!l->scanRegExp()) YYABORT; 173 $$ = new RegExpNode(UString('=')+l->pattern,l->flags);} 165 174 ; 166 175 … … 259 268 | TYPEOF UnaryExpr { $$ = new TypeOfNode($2); } 260 269 | PLUSPLUS UnaryExpr { $$ = new PrefixNode(OpPlusPlus, $2); } 261 | AUTO PLUSPLUS UnaryExpr { $$ = new PrefixNode(OpPlusPlus, $3); }270 | AUTOPLUSPLUS UnaryExpr { $$ = new PrefixNode(OpPlusPlus, $2); } 262 271 | MINUSMINUS UnaryExpr { $$ = new PrefixNode(OpMinusMinus, $2); } 263 | AUTO MINUSMINUS UnaryExpr { $$ = new PrefixNode(OpMinusMinus, $3); }272 | AUTOMINUSMINUS UnaryExpr { $$ = new PrefixNode(OpMinusMinus, $2); } 264 273 | '+' UnaryExpr { $$ = new UnaryPlusNode($2); } 265 274 | '-' UnaryExpr { $$ = new NegateNode($2); } … … 390 399 Block: 391 400 '{' '}' { $$ = new BlockNode(0L); DBG($$, @2, @2); } 392 | '{' S tatementList'}' { $$ = new BlockNode($2); DBG($$, @3, @3); }401 | '{' SourceElements '}' { $$ = new BlockNode($2); DBG($$, @3, @3); } 393 402 ; 394 403 … … 597 606 598 607 FunctionBody: 599 '{' '}' /* TODO: spec ??? */ { $$ = new FunctionBodyNode(0L); } 600 | '{' SourceElements '}' { $$ = new FunctionBodyNode($2); } 608 '{' '}' /* TODO: spec ??? */ { $$ = new FunctionBodyNode(0L); 609 DBG($$, @1, @2);} 610 | '{' SourceElements '}' { $$ = new FunctionBodyNode($2); 611 DBG($$, @1, @3);} 601 612 ; 602 613 603 614 Program: 604 SourceElements { $$ = new ProgramNode($1); 605 KJScriptImp::current()->setProgNode($$); } 615 /* nothing, empty script */ { $$ = new ProgramNode(0L); 616 Parser::progNode = $$; } 617 | SourceElements { $$ = new ProgramNode($1); 618 Parser::progNode = $$; } 606 619 ; 607 620 -
trunk/JavaScriptCore/kjs/internal.cpp
r6 r798 1 // -*- c-basic-offset: 2 -*- 1 2 /* 2 3 * This file is part of the KDE libraries 3 4 * Copyright (C) 1999-2001 Harri Porten ([email protected]) 5 * Copyright (C) 2001 Peter Kelly ([email protected]) 4 6 * 5 7 * This library is free software; you can redistribute it and/or … … 17 19 * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, 18 20 * Boston, MA 02111-1307, USA. 21 * 19 22 */ 20 23 24 #include <stdio.h> 25 #include <math.h> 26 #include <assert.h> 27 #ifndef NDEBUG 28 #include <strings.h> // for strdup 29 #endif 30 31 #include "array_object.h" 32 #include "bool_object.h" 33 #include "collector.h" 34 #include "date_object.h" 35 #include "debugger.h" 36 #include "error_object.h" 37 #include "function_object.h" 21 38 #include "internal.h" 22 23 #include <assert.h> 24 #include <stdio.h> 25 26 #include "kjs.h" 39 #include "lexer.h" 40 #include "math_object.h" 41 #include "nodes.h" 42 #include "number_object.h" 27 43 #include "object.h" 28 #include " types.h"44 #include "object_object.h" 29 45 #include "operations.h" 30 #include "regexp.h" 31 #include "nodes.h" 32 #include "lexer.h" 33 #include "collector.h" 34 #include "debugger.h" 46 #include "regexp_object.h" 47 #include "string_object.h" 35 48 36 49 #define I18N_NOOP(s) s … … 40 53 using namespace KJS; 41 54 42 const TypeInfo UndefinedImp::info = { "Undefined", UndefinedType, 0, 0, 0 }; 43 const TypeInfo NullImp::info = { "Null", NullType, 0, 0, 0 }; 44 const TypeInfo NumberImp::info = { "Number", NumberType, 0, 0,0 }; 45 const TypeInfo StringImp::info = { "String", StringType, 0, 0, 0 }; 46 const TypeInfo BooleanImp::info = { "Boolean", BooleanType, 0, 0, 0 }; 47 const TypeInfo CompletionImp::info = { "Completion", CompletionType, 0, 0, 0 }; 48 const TypeInfo ReferenceImp::info = { "Reference", ReferenceType, 0, 0, 0 }; 55 namespace KJS { 56 #ifdef WORDS_BIGENDIAN 57 unsigned char NaN_Bytes[] = { 0x7f, 0xf8, 0, 0, 0, 0, 0, 0 }; 58 unsigned char Inf_Bytes[] = { 0x7f, 0xf0, 0, 0, 0, 0, 0, 0 }; 59 #elif defined(arm) 60 unsigned char NaN_Bytes[] = { 0, 0, 0xf8, 0x7f, 0, 0, 0, 0 }; 61 unsigned char Inf_Bytes[] = { 0, 0, 0xf0, 0x7f, 0, 0, 0, 0 }; 62 #else 63 unsigned char NaN_Bytes[] = { 0, 0, 0, 0, 0, 0, 0xf8, 0x7f }; 64 unsigned char Inf_Bytes[] = { 0, 0, 0, 0, 0, 0, 0xf0, 0x7f }; 65 #endif 66 67 const double NaN = *(const double*) NaN_Bytes; 68 const double Inf = *(const double*) Inf_Bytes; 69 }; 70 71 // ------------------------------ UndefinedImp --------------------------------- 49 72 50 73 UndefinedImp *UndefinedImp::staticUndefined = 0; 51 74 52 UndefinedImp::UndefinedImp() 53 { 54 } 55 56 KJSO UndefinedImp::toPrimitive(Type) const 57 { 58 return (Imp*)this; 59 } 60 61 Boolean UndefinedImp::toBoolean() const 62 { 63 return Boolean(false); 64 } 65 66 Number UndefinedImp::toNumber() const 67 { 68 return Number(NaN); 69 } 70 71 String UndefinedImp::toString() const 72 { 73 return String("undefined"); 74 } 75 76 Object UndefinedImp::toObject() const 77 { 78 return Error::createObject(TypeError, I18N_NOOP("Undefined value")); 79 } 75 Value UndefinedImp::toPrimitive(ExecState */*exec*/, Type) const 76 { 77 return Value((ValueImp*)this); 78 } 79 80 bool UndefinedImp::toBoolean(ExecState */*exec*/) const 81 { 82 return false; 83 } 84 85 double UndefinedImp::toNumber(ExecState */*exec*/) const 86 { 87 return NaN; 88 } 89 90 UString UndefinedImp::toString(ExecState */*exec*/) const 91 { 92 return "undefined"; 93 } 94 95 Object UndefinedImp::toObject(ExecState *exec) const 96 { 97 Object err = Error::create(exec, TypeError, I18N_NOOP("Undefined value")); 98 exec->setException(err); 99 return err; 100 } 101 102 // ------------------------------ NullImp -------------------------------------- 80 103 81 104 NullImp *NullImp::staticNull = 0; 82 105 83 NullImp::NullImp() 84 { 85 } 86 87 KJSO NullImp::toPrimitive(Type) const 88 { 89 return (Imp*)this; 90 } 91 92 Boolean NullImp::toBoolean() const 93 { 94 return Boolean(false); 95 } 96 97 Number NullImp::toNumber() const 98 { 99 return Number(0); 100 } 101 102 String NullImp::toString() const 103 { 104 return String("null"); 105 } 106 107 Object NullImp::toObject() const 108 { 109 return Error::createObject(TypeError, I18N_NOOP("Null value")); 110 } 106 Value NullImp::toPrimitive(ExecState */*exec*/, Type) const 107 { 108 return Value((ValueImp*)this); 109 } 110 111 bool NullImp::toBoolean(ExecState */*exec*/) const 112 { 113 return false; 114 } 115 116 double NullImp::toNumber(ExecState */*exec*/) const 117 { 118 return 0.0; 119 } 120 121 UString NullImp::toString(ExecState */*exec*/) const 122 { 123 return "null"; 124 } 125 126 Object NullImp::toObject(ExecState *exec) const 127 { 128 Object err = Error::create(exec, TypeError, I18N_NOOP("Null value")); 129 exec->setException(err); 130 return err; 131 } 132 133 // ------------------------------ BooleanImp ----------------------------------- 111 134 112 135 BooleanImp* BooleanImp::staticTrue = 0; 113 136 BooleanImp* BooleanImp::staticFalse = 0; 114 137 115 KJSO BooleanImp::toPrimitive(Type) const 116 { 117 return (Imp*)this; 118 } 119 120 Boolean BooleanImp::toBoolean() const 121 { 122 return Boolean((BooleanImp*)this); 123 } 124 125 Number BooleanImp::toNumber() const 126 { 127 return Number(val ? 1 : 0); 128 } 129 130 String BooleanImp::toString() const 131 { 132 return String(val ? "true" : "false"); 133 } 134 135 Object BooleanImp::toObject() const 136 { 137 return Object::create(BooleanClass, Boolean((BooleanImp*)this)); 138 } 138 Value BooleanImp::toPrimitive(ExecState */*exec*/, Type) const 139 { 140 return Value((ValueImp*)this); 141 } 142 143 bool BooleanImp::toBoolean(ExecState */*exec*/) const 144 { 145 return val; 146 } 147 148 double BooleanImp::toNumber(ExecState */*exec*/) const 149 { 150 return val ? 1.0 : 0.0; 151 } 152 153 UString BooleanImp::toString(ExecState */*exec*/) const 154 { 155 return val ? "true" : "false"; 156 } 157 158 Object BooleanImp::toObject(ExecState *exec) const 159 { 160 List args; 161 args.append(Boolean(const_cast<BooleanImp*>(this))); 162 return Object::dynamicCast(exec->interpreter()->builtinBoolean().construct(exec,args)); 163 } 164 165 // ------------------------------ StringImp ------------------------------------ 166 167 StringImp::StringImp(const UString& v) 168 : val(v) 169 { 170 } 171 172 Value StringImp::toPrimitive(ExecState */*exec*/, Type) const 173 { 174 return Value((ValueImp*)this); 175 } 176 177 bool StringImp::toBoolean(ExecState */*exec*/) const 178 { 179 return (val.size() > 0); 180 } 181 182 double StringImp::toNumber(ExecState */*exec*/) const 183 { 184 return val.toDouble(); 185 } 186 187 UString StringImp::toString(ExecState */*exec*/) const 188 { 189 return val; 190 } 191 192 Object StringImp::toObject(ExecState *exec) const 193 { 194 List args; 195 args.append(String(const_cast<StringImp*>(this))); 196 return Object::dynamicCast(exec->interpreter()->builtinString().construct(exec,args)); 197 } 198 199 // ------------------------------ NumberImp ------------------------------------ 139 200 140 201 NumberImp::NumberImp(double v) … … 143 204 } 144 205 145 KJSO NumberImp::toPrimitive(Type) const 146 { 147 return (Imp*)this; 148 } 149 150 Boolean NumberImp::toBoolean() const 151 { 152 bool b = !((val == 0) /* || (iVal() == N0) */ || isNaN(val)); 153 154 return Boolean(b); 155 } 156 157 Number NumberImp::toNumber() const 206 Value NumberImp::toPrimitive(ExecState *, Type) const 158 207 { 159 208 return Number((NumberImp*)this); 160 209 } 161 210 162 String NumberImp::toString() const 163 { 164 return String(UString::from(val)); 165 } 166 167 Object NumberImp::toObject() const 168 { 169 return Object::create(NumberClass, Number((NumberImp*)this)); 170 } 171 172 StringImp::StringImp(const UString& v) 173 : val(v) 174 { 175 } 176 177 KJSO StringImp::toPrimitive(Type) const 178 { 179 return (Imp*)this; 180 } 181 182 Boolean StringImp::toBoolean() const 183 { 184 return Boolean(val.size() > 0); 185 } 186 187 Number StringImp::toNumber() const 188 { 189 return Number(val.toDouble()); 190 } 191 192 String StringImp::toString() const 193 { 194 return String((StringImp*)this); 195 } 196 197 Object StringImp::toObject() const 198 { 199 return Object::create(StringClass, String((StringImp*)this)); 200 } 201 202 ReferenceImp::ReferenceImp(const KJSO& b, const UString& p) 203 : base(b), prop(p) 204 { 205 } 206 207 void ReferenceImp::mark(Imp*) 208 { 209 Imp::mark(); 210 Imp *im = base.imp(); 211 if (im && !im->marked()) 212 im->mark(); 213 } 214 215 CompletionImp::CompletionImp(Compl c, const KJSO& v, const UString& t) 216 : comp(c), val(v), tar(t) 217 { 218 } 219 220 void CompletionImp::mark(Imp*) 221 { 222 Imp::mark(); 223 Imp *im = val.imp(); 224 if (im && !im->marked()) 225 im->mark(); 226 } 227 228 RegExpImp::RegExpImp() 229 : ObjectImp(RegExpClass), reg(0L) 230 { 231 } 232 233 RegExpImp::~RegExpImp() 234 { 235 delete reg; 236 } 211 bool NumberImp::toBoolean(ExecState *) const 212 { 213 return !((val == 0) /* || (iVal() == N0) */ || isNaN(val)); 214 } 215 216 double NumberImp::toNumber(ExecState *) const 217 { 218 return val; 219 } 220 221 UString NumberImp::toString(ExecState *) const 222 { 223 return UString::from(val); 224 } 225 226 Object NumberImp::toObject(ExecState *exec) const 227 { 228 List args; 229 args.append(Number(const_cast<NumberImp*>(this))); 230 return Object::dynamicCast(exec->interpreter()->builtinNumber().construct(exec,args)); 231 } 232 233 // ------------------------------ ReferenceImp --------------------------------- 234 235 ReferenceImp::ReferenceImp(const Value& v, const UString& p) 236 : base(v.imp()), prop(p) 237 { 238 } 239 240 void ReferenceImp::mark() 241 { 242 ValueImp::mark(); 243 if (base && !base->marked()) 244 base->mark(); 245 } 246 247 Value ReferenceImp::toPrimitive(ExecState */*exec*/, Type /*preferredType*/) const 248 { 249 // invalid for Reference 250 assert(false); 251 return Value(); 252 } 253 254 bool ReferenceImp::toBoolean(ExecState */*exec*/) const 255 { 256 // invalid for Reference 257 assert(false); 258 return false; 259 } 260 261 double ReferenceImp::toNumber(ExecState */*exec*/) const 262 { 263 // invalid for Reference 264 assert(false); 265 return 0; 266 } 267 268 UString ReferenceImp::toString(ExecState */*exec*/) const 269 { 270 // invalid for Reference 271 assert(false); 272 return UString::null; 273 } 274 275 Object ReferenceImp::toObject(ExecState */*exec*/) const 276 { 277 // invalid for Reference 278 assert(false); 279 return Object(); 280 } 281 282 // ------------------------------ LabelStack ----------------------------------- 283 284 LabelStack::LabelStack(const LabelStack &other) 285 { 286 tos = 0; 287 *this = other; 288 } 289 290 LabelStack &LabelStack::operator=(const LabelStack &other) 291 { 292 clear(); 293 tos = 0; 294 StackElem *cur = 0; 295 StackElem *se = other.tos; 296 while (se) { 297 StackElem *newPrev = new StackElem; 298 newPrev->prev = 0; 299 newPrev->id = se->id; 300 if (cur) 301 cur->prev = newPrev; 302 else 303 tos = newPrev; 304 cur = newPrev; 305 se = se->prev; 306 } 307 return *this; 308 } 309 310 bool LabelStack::push(const UString &id) 311 { 312 if (id.isEmpty() || contains(id)) 313 return false; 314 315 StackElem *newtos = new StackElem; 316 newtos->id = id; 317 newtos->prev = tos; 318 tos = newtos; 319 return true; 320 } 321 322 bool LabelStack::contains(const UString &id) const 323 { 324 if (id.isEmpty()) 325 return true; 326 327 for (StackElem *curr = tos; curr; curr = curr->prev) 328 if (curr->id == id) 329 return true; 330 331 return false; 332 } 333 334 void LabelStack::pop() 335 { 336 if (tos) { 337 StackElem *prev = tos->prev; 338 delete tos; 339 tos = prev; 340 } 341 } 342 343 LabelStack::~LabelStack() 344 { 345 clear(); 346 } 347 348 void LabelStack::clear() 349 { 350 StackElem *prev; 351 352 while (tos) { 353 prev = tos->prev; 354 delete tos; 355 tos = prev; 356 } 357 } 358 359 // ------------------------------ CompletionImp -------------------------------- 360 361 CompletionImp::CompletionImp(ComplType c, const Value& v, const UString& t) 362 : comp(c), val(v.imp()), tar(t) 363 { 364 } 365 366 CompletionImp::~CompletionImp() 367 { 368 } 369 370 void CompletionImp::mark() 371 { 372 ValueImp::mark(); 373 374 if (val && !val->marked()) 375 val->mark(); 376 } 377 378 Value CompletionImp::toPrimitive(ExecState */*exec*/, Type /*preferredType*/) const 379 { 380 // invalid for Completion 381 assert(false); 382 return Value(); 383 } 384 385 bool CompletionImp::toBoolean(ExecState */*exec*/) const 386 { 387 // invalid for Completion 388 assert(false); 389 return false; 390 } 391 392 double CompletionImp::toNumber(ExecState */*exec*/) const 393 { 394 // invalid for Completion 395 assert(false); 396 return 0; 397 } 398 399 UString CompletionImp::toString(ExecState */*exec*/) const 400 { 401 // invalid for Completion 402 assert(false); 403 return UString::null; 404 } 405 406 Object CompletionImp::toObject(ExecState */*exec*/) const 407 { 408 // invalid for Completion 409 assert(false); 410 return Object(); 411 } 412 413 // ------------------------------ ListImp -------------------------------------- 414 415 #ifdef KJS_DEBUG_MEM 416 int ListImp::count = 0; 417 #endif 418 419 Value ListImp::toPrimitive(ExecState */*exec*/, Type /*preferredType*/) const 420 { 421 // invalid for List 422 assert(false); 423 return Value(); 424 } 425 426 bool ListImp::toBoolean(ExecState */*exec*/) const 427 { 428 // invalid for List 429 assert(false); 430 return false; 431 } 432 433 double ListImp::toNumber(ExecState */*exec*/) const 434 { 435 // invalid for List 436 assert(false); 437 return 0; 438 } 439 440 UString ListImp::toString(ExecState */*exec*/) const 441 { 442 // invalid for List 443 assert(false); 444 return UString::null; 445 } 446 447 Object ListImp::toObject(ExecState */*exec*/) const 448 { 449 // invalid for List 450 assert(false); 451 return Object(); 452 } 453 454 ListImp::ListImp() 455 { 456 #ifdef KJS_DEBUG_MEM 457 count++; 458 #endif 459 460 hook = new ListNode(Null(), 0L, 0L); 461 hook->next = hook; 462 hook->prev = hook; 463 //fprintf(stderr,"ListImp::ListImp %p hook=%p\n",this,hook); 464 } 465 466 ListImp::~ListImp() 467 { 468 //fprintf(stderr,"ListImp::~ListImp %p\n",this); 469 #ifdef KJS_DEBUG_MEM 470 count--; 471 #endif 472 473 clear(); 474 delete hook; 475 } 476 477 void ListImp::mark() 478 { 479 ListNode *n = hook->next; 480 while (n != hook) { 481 if (!n->member->marked()) 482 n->member->mark(); 483 n = n->next; 484 } 485 ValueImp::mark(); 486 } 487 488 void ListImp::append(const Value& obj) 489 { 490 ListNode *n = new ListNode(obj, hook->prev, hook); 491 hook->prev->next = n; 492 hook->prev = n; 493 } 494 495 void ListImp::prepend(const Value& obj) 496 { 497 ListNode *n = new ListNode(obj, hook, hook->next); 498 hook->next->prev = n; 499 hook->next = n; 500 } 501 502 void ListImp::appendList(const List& lst) 503 { 504 ListIterator it = lst.begin(); 505 ListIterator e = lst.end(); 506 while(it != e) { 507 append(*it); 508 ++it; 509 } 510 } 511 512 void ListImp::prependList(const List& lst) 513 { 514 ListIterator it = lst.end(); 515 ListIterator e = lst.begin(); 516 while(it != e) { 517 --it; 518 prepend(*it); 519 } 520 } 521 522 void ListImp::removeFirst() 523 { 524 erase(hook->next); 525 } 526 527 void ListImp::removeLast() 528 { 529 erase(hook->prev); 530 } 531 532 void ListImp::remove(const Value &obj) 533 { 534 if (obj.isNull()) 535 return; 536 ListNode *n = hook->next; 537 while (n != hook) { 538 if (n->member == obj.imp()) { 539 erase(n); 540 return; 541 } 542 n = n->next; 543 } 544 } 545 546 void ListImp::clear() 547 { 548 ListNode *n = hook->next; 549 while (n != hook) { 550 n = n->next; 551 delete n->prev; 552 } 553 554 hook->next = hook; 555 hook->prev = hook; 556 } 557 558 ListImp *ListImp::copy() const 559 { 560 ListImp* newList = new ListImp; 561 562 ListIterator e = end(); 563 ListIterator it = begin(); 564 565 while(it != e) { 566 newList->append(*it); 567 ++it; 568 } 569 570 //fprintf( stderr, "ListImp::copy returning newList=%p\n", newList ); 571 return newList; 572 } 573 574 void ListImp::erase(ListNode *n) 575 { 576 if (n != hook) { 577 n->next->prev = n->prev; 578 n->prev->next = n->next; 579 delete n; 580 } 581 } 582 583 bool ListImp::isEmpty() const 584 { 585 return (hook->prev == hook); 586 } 587 588 int ListImp::size() const 589 { 590 int s = 0; 591 ListNode *node = hook; 592 while ((node = node->next) != hook) 593 s++; 594 595 return s; 596 } 597 598 Value ListImp::at(int i) const 599 { 600 if (i < 0 || i >= size()) 601 return Undefined(); 602 603 ListIterator it = begin(); 604 int j = 0; 605 while ((j++ < i)) 606 it++; 607 608 return *it; 609 } 610 611 ListImp *ListImp::emptyList = 0L; 612 613 ListImp *ListImp::empty() 614 { 615 if (!emptyList) 616 emptyList = new ListImp(); 617 return emptyList; 618 } 619 620 // ------------------------------ ContextImp ----------------------------------- 621 237 622 238 623 // ECMA 10.2 239 Context::Context(CodeType type, Context *callingContext, 240 FunctionImp *func, const List *args, Imp *thisV) 241 { 242 Global glob(Global::current()); 624 ContextImp::ContextImp(Object &glob, ExecState *exec, Object &thisV, CodeType type, 625 ContextImp *_callingContext, FunctionImp *func, const List &args) 626 { 627 codeType = type; 628 callingCon = _callingContext; 243 629 244 630 // create and initialize activation object (ECMA 10.1.6) 245 if (type == FunctionCode || type == AnonymousCode || type == HostCode) {246 activation = new ActivationImp(func, args);631 if (type == FunctionCode || type == AnonymousCode ) { 632 activation = Object(new ActivationImp(exec,func,args)); 247 633 variable = activation; 248 634 } else { 249 activation = KJSO();635 activation = Object(); 250 636 variable = glob; 251 637 } … … 254 640 switch(type) { 255 641 case EvalCode: 256 if (callingCon text) {257 scope Chain = callingContext->copyOfChain();258 variable = callingCon text->variableObject();259 thisVal = callingCon text->thisValue();642 if (callingCon) { 643 scope = callingCon->scopeChain().copy(); 644 variable = callingCon->variableObject(); 645 thisVal = callingCon->thisValue(); 260 646 break; 261 647 } // else same as GlobalCode 262 648 case GlobalCode: 263 scope Chain = newList();264 scope Chain->append(glob);265 thisVal = glob.imp();649 scope = List(); 650 scope.append(glob); 651 thisVal = Object(static_cast<ObjectImp*>(glob.imp())); 266 652 break; 267 653 case FunctionCode: 268 654 case AnonymousCode: 269 655 if (type == FunctionCode) { 270 scope Chain = ((DeclaredFunctionImp*)func)->scopeChain()->copy();271 scope Chain->prepend(activation);656 scope = func->scope().copy(); 657 scope.prepend(activation); 272 658 } else { 273 scope Chain = newList();274 scope Chain->append(activation);275 scope Chain->append(glob);659 scope = List(); 660 scope.append(activation); 661 scope.append(glob); 276 662 } 277 variable = activation; /* TODO: DontDelete ? (ECMA 10.2.3) */ 278 if (thisV->type() >= ObjectType) { 279 thisVal = thisV; 280 } 281 else 282 thisVal = glob.imp(); 283 break; 284 case HostCode: 285 if (thisV->type() >= ObjectType) 286 thisVal = thisV; 287 else 288 thisVal = glob; 289 variable = activation; /* TODO: DontDelete (ECMA 10.2.4) */ 290 scopeChain = new List(); 291 scopeChain->append(activation); 292 if (func->hasAttribute(ImplicitThis)) 293 scopeChain->append(KJSO(thisVal)); 294 if (func->hasAttribute(ImplicitParents)) { 295 /* TODO ??? */ 296 } 297 scopeChain->append(glob); 663 variable = activation; // TODO: DontDelete ? (ECMA 10.2.3) 664 thisVal = thisV; 298 665 break; 299 666 } 300 } 301 302 Context::~Context() 303 { 304 delete scopeChain; 305 } 306 307 Context *Context::current() 308 { 309 return KJScriptImp::curr ? KJScriptImp::curr->con : 0L; 310 } 311 312 void Context::setCurrent(Context *c) 313 { 314 KJScriptImp::current()->con = c; 315 } 316 317 void Context::pushScope(const KJSO &s) 318 { 319 scopeChain->prepend(s); 320 } 321 322 void Context::popScope() 323 { 324 scopeChain->removeFirst(); 325 } 326 327 List* Context::copyOfChain() 328 { 329 return scopeChain->copy(); 330 } 331 332 333 AnonymousFunction::AnonymousFunction() 334 : Function(0L) 335 { 336 /* TODO */ 337 } 338 339 DeclaredFunctionImp::DeclaredFunctionImp(const UString &n, 340 FunctionBodyNode *b, const List *sc) 341 : ConstructorImp(n), body(b), scopes(sc->copy()) 342 { 343 } 344 345 DeclaredFunctionImp::~DeclaredFunctionImp() 346 { 347 delete scopes; 348 } 349 350 // step 2 of ECMA 13.2.1. rest in FunctionImp::executeCall() 351 Completion DeclaredFunctionImp::execute(const List &) 352 { 353 /* TODO */ 354 355 #ifdef KJS_DEBUGGER 356 Debugger *dbg = KJScriptImp::current()->debugger(); 357 int oldSourceId = -1; 358 if (dbg) { 359 oldSourceId = dbg->sourceId(); 360 dbg->setSourceId(body->sourceId()); 361 } 667 668 } 669 670 ContextImp::~ContextImp() 671 { 672 } 673 674 void ContextImp::pushScope(const Object &s) 675 { 676 scope.prepend(s); 677 } 678 679 void ContextImp::popScope() 680 { 681 scope.removeFirst(); 682 } 683 684 // ------------------------------ Parser --------------------------------------- 685 686 ProgramNode *Parser::progNode = 0; 687 int Parser::sid = 0; 688 689 ProgramNode *Parser::parse(const UChar *code, unsigned int length, int *sourceId, 690 int *errLine, UString *errMsg) 691 { 692 if (errLine) 693 *errLine = -1; 694 if (errMsg) 695 *errMsg = 0; 696 697 Lexer::curr()->setCode(code, length); 698 progNode = 0; 699 sid++; 700 if (sourceId) 701 *sourceId = sid; 702 // Enable this (and the #define YYDEBUG in grammar.y) to debug a parse error 703 //extern int kjsyydebug; 704 //kjsyydebug=1; 705 int parseError = kjsyyparse(); 706 ProgramNode *prog = progNode; 707 progNode = 0; 708 sid = -1; 709 710 if (parseError) { 711 int eline = Lexer::curr()->lineNo(); 712 if (errLine) 713 *errLine = eline; 714 if (errMsg) 715 *errMsg = "Parse error at line " + UString::from(eline); 716 #ifndef NDEBUG 717 fprintf(stderr, "KJS: JavaScript parse error at line %d.\n", eline); 362 718 #endif 363 364 Completion result = body->execute(); 365 366 #ifdef KJS_DEBUGGER 367 if (dbg) { 368 dbg->setSourceId(oldSourceId); 369 } 370 #endif 371 372 if (result.complType() == Throw || result.complType() == ReturnValue) 373 return result; 374 return Completion(Normal, Undefined()); /* TODO: or ReturnValue ? */ 375 } 376 377 // ECMA 13.2.2 [[Construct]] 378 Object DeclaredFunctionImp::construct(const List &args) 379 { 380 Object obj(ObjectClass); 381 KJSO p = get("prototype"); 382 if (p.isObject()) 383 obj.setPrototype(p); 384 else 385 obj.setPrototype(Global::current().objectPrototype()); 386 387 KJSO res = executeCall(obj.imp(), &args); 388 389 Object v = Object::dynamicCast(res); 390 if (v.isNull()) 391 return obj; 392 else 393 return v; 394 } 395 396 Completion AnonymousFunction::execute(const List &) 397 { 398 /* TODO */ 399 return Completion(Normal, Null()); 400 } 401 402 // ECMA 10.1.8 403 class ArgumentsObject : public ObjectImp { 404 public: 405 ArgumentsObject(FunctionImp *func, const List *args); 406 }; 407 408 ArgumentsObject::ArgumentsObject(FunctionImp *func, const List *args) 409 : ObjectImp(UndefClass) 410 { 411 put("callee", Function(func), DontEnum); 412 if (args) { 413 put("length", Number(args->size()), DontEnum); 414 ListIterator arg = args->begin(); 415 for (int i = 0; arg != args->end(); arg++, i++) { 416 put(UString::from(i), *arg, DontEnum); 417 } 418 } 419 } 420 421 const TypeInfo ActivationImp::info = { "Activation", ActivationType, 0, 0, 0 }; 422 423 // ECMA 10.1.6 424 ActivationImp::ActivationImp(FunctionImp *f, const List *args) 425 { 426 KJSO aobj(new ArgumentsObject(f, args)); 427 put("arguments", aobj, DontDelete); 428 /* TODO: this is here to get myFunc.arguments and myFunc.a1 going. 429 I can't see this described in the spec but it's possible in browsers. */ 430 if (!f->name().isNull()) 431 f->put("arguments", aobj); 432 } 433 434 ExecutionStack::ExecutionStack() 435 : progNode(0L), firstNode(0L), prev(0) 436 { 437 } 438 439 ExecutionStack* ExecutionStack::push() 440 { 441 ExecutionStack *s = new ExecutionStack(); 442 s->prev = this; 443 444 return s; 445 } 446 447 ExecutionStack* ExecutionStack::pop() 448 { 449 ExecutionStack *s = prev; 450 delete this; 451 452 return s; 453 } 454 455 KJScriptImp* KJScriptImp::curr = 0L; 456 KJScriptImp* KJScriptImp::hook = 0L; 457 int KJScriptImp::instances = 0; 458 int KJScriptImp::running = 0; 459 460 KJScriptImp::KJScriptImp(KJScript *s) 461 : scr(s), 462 initialized(false), 463 glob(0L), 464 #ifdef KJS_DEBUGGER 465 dbg(0L), 466 #endif 467 retVal(0L) 468 { 469 instances++; 470 KJScriptImp::curr = this; 471 // are we the first interpreter instance ? Initialize some stuff 472 if (instances == 1) 473 globalInit(); 474 stack = new ExecutionStack(); 475 clearException(); 476 lex = new Lexer(); 477 } 478 479 KJScriptImp::~KJScriptImp() 480 { 481 KJScriptImp::curr = this; 482 483 #ifdef KJS_DEBUGGER 484 attachDebugger(0L); 485 #endif 486 487 clear(); 488 489 delete lex; 490 lex = 0L; 491 492 delete stack; 493 stack = 0L; 494 495 KJScriptImp::curr = 0L; 496 // are we the last of our kind ? Free global stuff. 497 if (instances == 1) 498 globalClear(); 499 instances--; 500 } 501 502 void KJScriptImp::globalInit() 503 { 719 delete prog; 720 return 0; 721 } 722 723 return prog; 724 } 725 726 // ------------------------------ InterpreterImp ------------------------------- 727 728 InterpreterImp* InterpreterImp::s_hook = 0L; 729 730 void InterpreterImp::globalInit() 731 { 732 //fprintf( stderr, "InterpreterImp::globalInit()\n" ); 504 733 UndefinedImp::staticUndefined = new UndefinedImp(); 505 734 UndefinedImp::staticUndefined->ref(); … … 512 741 } 513 742 514 void KJScriptImp::globalClear() 515 { 743 void InterpreterImp::globalClear() 744 { 745 //fprintf( stderr, "InterpreterImp::globalClear()\n" ); 516 746 UndefinedImp::staticUndefined->deref(); 747 UndefinedImp::staticUndefined->setGcAllowed(); 517 748 UndefinedImp::staticUndefined = 0L; 518 749 NullImp::staticNull->deref(); 750 NullImp::staticNull->setGcAllowed(); 519 751 NullImp::staticNull = 0L; 520 752 BooleanImp::staticTrue->deref(); 753 BooleanImp::staticTrue->setGcAllowed(); 521 754 BooleanImp::staticTrue = 0L; 522 755 BooleanImp::staticFalse->deref(); 756 BooleanImp::staticFalse->setGcAllowed(); 523 757 BooleanImp::staticFalse = 0L; 524 758 } 525 759 526 void KJScriptImp::mark() 527 { 528 if (exVal && !exVal->marked()) 529 exVal->mark(); 530 if (retVal && !retVal->marked()) 531 retVal->mark(); 532 UndefinedImp::staticUndefined->mark(); 533 NullImp::staticNull->mark(); 534 BooleanImp::staticTrue->mark(); 535 BooleanImp::staticFalse->mark(); 536 } 537 538 void KJScriptImp::init() 539 { 540 KJScriptImp::curr = this; 541 542 clearException(); 543 retVal = 0L; 544 545 if (!initialized) { 546 // add this interpreter to the global chain 547 // as a root set for garbage collection 548 if (hook) { 549 prev = hook; 550 next = hook->next; 551 hook->next->prev = this; 552 hook->next = this; 553 } else { 554 hook = next = prev = this; 760 InterpreterImp::InterpreterImp(Interpreter *interp, const Object &glob) 761 { 762 // add this interpreter to the global chain 763 // as a root set for garbage collection 764 if (s_hook) { 765 prev = s_hook; 766 next = s_hook->next; 767 s_hook->next->prev = this; 768 s_hook->next = this; 769 } else { 770 // This is the first interpreter 771 s_hook = next = prev = this; 772 globalInit(); 773 } 774 775 m_interpreter = interp; 776 global = glob; 777 globExec = new ExecState(m_interpreter,0); 778 dbg = 0; 779 m_compatMode = Interpreter::NativeMode; 780 781 // initialize properties of the global object 782 783 // Contructor prototype objects (Object.prototype, Array.prototype etc) 784 785 FunctionPrototypeImp *funcProto = new FunctionPrototypeImp(globExec); 786 b_FunctionPrototype = Object(funcProto); 787 ObjectPrototypeImp *objProto = new ObjectPrototypeImp(globExec,funcProto); 788 b_ObjectPrototype = Object(objProto); 789 funcProto->setPrototype(b_ObjectPrototype); 790 791 ArrayPrototypeImp *arrayProto = new ArrayPrototypeImp(globExec,objProto); 792 b_ArrayPrototype = Object(arrayProto); 793 StringPrototypeImp *stringProto = new StringPrototypeImp(globExec,objProto); 794 b_StringPrototype = Object(stringProto); 795 BooleanPrototypeImp *booleanProto = new BooleanPrototypeImp(globExec,objProto,funcProto); 796 b_BooleanPrototype = Object(booleanProto); 797 NumberPrototypeImp *numberProto = new NumberPrototypeImp(globExec,objProto,funcProto); 798 b_NumberPrototype = Object(numberProto); 799 DatePrototypeImp *dateProto = new DatePrototypeImp(globExec,objProto); 800 b_DatePrototype = Object(dateProto); 801 RegExpPrototypeImp *regexpProto = new RegExpPrototypeImp(globExec,objProto,funcProto); 802 b_RegExpPrototype = Object(regexpProto); 803 ErrorPrototypeImp *errorProto = new ErrorPrototypeImp(globExec,objProto,funcProto); 804 b_ErrorPrototype = Object(errorProto); 805 806 static_cast<ObjectImp*>(global.imp())->setPrototype(b_ObjectPrototype); 807 808 // Constructors (Object, Array, etc.) 809 810 ObjectObjectImp *objectObj = new ObjectObjectImp(globExec,objProto,funcProto); 811 b_Object = Object(objectObj); 812 FunctionObjectImp *funcObj = new FunctionObjectImp(globExec,funcProto); 813 b_Function = Object(funcObj); 814 ArrayObjectImp *arrayObj = new ArrayObjectImp(globExec,funcProto,arrayProto); 815 b_Array = Object(arrayObj); 816 StringObjectImp *stringObj = new StringObjectImp(globExec,funcProto,stringProto); 817 b_String = Object(stringObj); 818 BooleanObjectImp *booleanObj = new BooleanObjectImp(globExec,funcProto,booleanProto); 819 b_Boolean = Object(booleanObj); 820 NumberObjectImp *numberObj = new NumberObjectImp(globExec,funcProto,numberProto); 821 b_Number = Object(numberObj); 822 DateObjectImp *dateObj = new DateObjectImp(globExec,funcProto,dateProto); 823 b_Date = Object(dateObj); 824 RegExpObjectImp *regexpObj = new RegExpObjectImp(globExec,regexpProto,funcProto); 825 b_RegExp = Object(regexpObj); 826 ErrorObjectImp *errorObj = new ErrorObjectImp(globExec,funcProto,errorProto); 827 b_Error = Object(errorObj); 828 829 // Error object prototypes 830 b_evalErrorPrototype = Object(new NativeErrorPrototypeImp(globExec,errorProto,EvalError, 831 "EvalError","EvalError")); 832 b_rangeErrorPrototype = Object(new NativeErrorPrototypeImp(globExec,errorProto,RangeError, 833 "RangeError","RangeError")); 834 b_referenceErrorPrototype = Object(new NativeErrorPrototypeImp(globExec,errorProto,ReferenceError, 835 "ReferenceError","ReferenceError")); 836 b_syntaxErrorPrototype = Object(new NativeErrorPrototypeImp(globExec,errorProto,SyntaxError, 837 "SyntaxError","SyntaxError")); 838 b_typeErrorPrototype = Object(new NativeErrorPrototypeImp(globExec,errorProto,TypeError, 839 "TypeError","TypeError")); 840 b_uriErrorPrototype = Object(new NativeErrorPrototypeImp(globExec,errorProto,URIError, 841 "URIError","URIError")); 842 843 // Error objects 844 b_evalError = Object(new NativeErrorImp(globExec,funcProto,b_evalErrorPrototype)); 845 b_rangeError = Object(new NativeErrorImp(globExec,funcProto,b_rangeErrorPrototype)); 846 b_referenceError = Object(new NativeErrorImp(globExec,funcProto,b_referenceErrorPrototype)); 847 b_syntaxError = Object(new NativeErrorImp(globExec,funcProto,b_syntaxErrorPrototype)); 848 b_typeError = Object(new NativeErrorImp(globExec,funcProto,b_typeErrorPrototype)); 849 b_uriError = Object(new NativeErrorImp(globExec,funcProto,b_uriErrorPrototype)); 850 851 // ECMA 15.3.4.1 852 funcProto->put(globExec,"constructor", b_Function, DontEnum); 853 854 global.put(globExec,"Object", b_Object, DontEnum); 855 global.put(globExec,"Function", b_Function, DontEnum); 856 global.put(globExec,"Array", b_Array, DontEnum); 857 global.put(globExec,"Boolean", b_Boolean, DontEnum); 858 global.put(globExec,"String", b_String, DontEnum); 859 global.put(globExec,"Number", b_Number, DontEnum); 860 global.put(globExec,"Date", b_Date, DontEnum); 861 global.put(globExec,"RegExp", b_RegExp, DontEnum); 862 global.put(globExec,"Error", b_Error, DontEnum); 863 // Using Internal for those to have something != 0 864 // (see kjs_window). Maybe DontEnum would be ok too ? 865 global.put(globExec,"EvalError",b_evalError, Internal); 866 global.put(globExec,"RangeError",b_rangeError, Internal); 867 global.put(globExec,"ReferenceError",b_referenceError, Internal); 868 global.put(globExec,"SyntaxError",b_syntaxError, Internal); 869 global.put(globExec,"TypeError",b_typeError, Internal); 870 global.put(globExec,"URIError",b_uriError, Internal); 871 872 // Set the "constructor" property of all builtin constructors 873 objProto->put(globExec, "constructor", b_Object, DontEnum | DontDelete | ReadOnly); 874 funcProto->put(globExec, "constructor", b_Function, DontEnum | DontDelete | ReadOnly); 875 arrayProto->put(globExec, "constructor", b_Array, DontEnum | DontDelete | ReadOnly); 876 booleanProto->put(globExec, "constructor", b_Boolean, DontEnum | DontDelete | ReadOnly); 877 stringProto->put(globExec, "constructor", b_String, DontEnum | DontDelete | ReadOnly); 878 numberProto->put(globExec, "constructor", b_Number, DontEnum | DontDelete | ReadOnly); 879 dateProto->put(globExec, "constructor", b_Date, DontEnum | DontDelete | ReadOnly); 880 regexpProto->put(globExec, "constructor", b_RegExp, DontEnum | DontDelete | ReadOnly); 881 errorProto->put(globExec, "constructor", b_Error, DontEnum | DontDelete | ReadOnly); 882 b_evalErrorPrototype.put(globExec, "constructor", b_evalError, DontEnum | DontDelete | ReadOnly); 883 b_rangeErrorPrototype.put(globExec, "constructor", b_rangeError, DontEnum | DontDelete | ReadOnly); 884 b_referenceErrorPrototype.put(globExec, "constructor", b_referenceError, DontEnum | DontDelete | ReadOnly); 885 b_syntaxErrorPrototype.put(globExec, "constructor", b_syntaxError, DontEnum | DontDelete | ReadOnly); 886 b_typeErrorPrototype.put(globExec, "constructor", b_typeError, DontEnum | DontDelete | ReadOnly); 887 b_uriErrorPrototype.put(globExec, "constructor", b_uriError, DontEnum | DontDelete | ReadOnly); 888 889 // built-in values 890 global.put(globExec,"NaN", Number(NaN), DontEnum); 891 global.put(globExec,"Infinity", Number(Inf), DontEnum); 892 global.put(globExec,"undefined", Undefined(), DontEnum); 893 894 // built-in functions 895 global.put(globExec,"eval", Object(new GlobalFuncImp(globExec,funcProto,GlobalFuncImp::Eval, 1)), DontEnum); 896 global.put(globExec,"parseInt", Object(new GlobalFuncImp(globExec,funcProto,GlobalFuncImp::ParseInt, 2)), DontEnum); 897 global.put(globExec,"parseFloat", Object(new GlobalFuncImp(globExec,funcProto,GlobalFuncImp::ParseFloat, 1)), DontEnum); 898 global.put(globExec,"isNaN", Object(new GlobalFuncImp(globExec,funcProto,GlobalFuncImp::IsNaN, 1)), DontEnum); 899 global.put(globExec,"isFinite", Object(new GlobalFuncImp(globExec,funcProto,GlobalFuncImp::IsFinite, 1)), DontEnum); 900 global.put(globExec,"escape", Object(new GlobalFuncImp(globExec,funcProto,GlobalFuncImp::Escape, 1)), DontEnum); 901 global.put(globExec,"unescape", Object(new GlobalFuncImp(globExec,funcProto,GlobalFuncImp::UnEscape, 1)), DontEnum); 902 903 // built-in objects 904 global.put(globExec,"Math", Object(new MathObjectImp(globExec,objProto)), DontEnum); 905 906 recursion = 0; 907 } 908 909 InterpreterImp::~InterpreterImp() 910 { 911 if (dbg) 912 dbg->detach(m_interpreter); 913 delete globExec; 914 globExec = 0L; 915 clear(); 916 } 917 918 void InterpreterImp::clear() 919 { 920 //fprintf(stderr,"InterpreterImp::clear\n"); 921 // remove from global chain (see init()) 922 next->prev = prev; 923 prev->next = next; 924 s_hook = next; 925 if (s_hook == this) 926 { 927 // This was the last interpreter 928 s_hook = 0L; 929 globalClear(); 930 } 931 } 932 933 void InterpreterImp::mark() 934 { 935 //if (exVal && !exVal->marked()) 936 // exVal->mark(); 937 //if (retVal && !retVal->marked()) 938 // retVal->mark(); 939 if (UndefinedImp::staticUndefined && !UndefinedImp::staticUndefined->marked()) 940 UndefinedImp::staticUndefined->mark(); 941 if (NullImp::staticNull && !NullImp::staticNull->marked()) 942 NullImp::staticNull->mark(); 943 if (BooleanImp::staticTrue && !BooleanImp::staticTrue->marked()) 944 BooleanImp::staticTrue->mark(); 945 if (BooleanImp::staticFalse && !BooleanImp::staticFalse->marked()) 946 BooleanImp::staticFalse->mark(); 947 if (ListImp::emptyList && !ListImp::emptyList->marked()) 948 ListImp::emptyList->mark(); 949 //fprintf( stderr, "InterpreterImp::mark this=%p global.imp()=%p\n", this, global.imp() ); 950 if (global.imp()) 951 global.imp()->mark(); 952 if (m_interpreter) 953 m_interpreter->mark(); 954 } 955 956 bool InterpreterImp::checkSyntax(const UString &code) 957 { 958 // Parser::parse() returns 0 in a syntax error occurs, so we just check for that 959 ProgramNode *progNode = Parser::parse(code.data(),code.size(),0,0,0); 960 bool ok = (progNode != 0); 961 delete progNode; 962 return ok; 963 } 964 965 Completion InterpreterImp::evaluate(const UString &code, const Value &thisV) 966 { 967 // prevent against infinite recursion 968 if (recursion >= 20) { 969 return Completion(Throw,Error::create(globExec,GeneralError,"Recursion too deep")); 970 } 971 972 // parse the source code 973 int sid; 974 int errLine; 975 UString errMsg; 976 ProgramNode *progNode = Parser::parse(code.data(),code.size(),&sid,&errLine,&errMsg); 977 978 // notify debugger that source has been parsed 979 if (dbg) { 980 bool cont = dbg->sourceParsed(globExec,sid,code,errLine); 981 if (!cont) 982 return Completion(Break); 983 } 984 985 // no program node means a syntax occurred 986 if (!progNode) { 987 Object err = Error::create(globExec,SyntaxError,errMsg.ascii(),errLine); 988 err.put(globExec,"sid",Number(sid)); 989 return Completion(Throw,err); 990 } 991 992 globExec->clearException(); 993 994 recursion++; 995 progNode->ref(); 996 997 Object globalObj = globalObject(); 998 Object thisObj = globalObject(); 999 1000 if (!thisV.isNull()) { 1001 // "this" must be an object... use same rules as Function.prototype.apply() 1002 if (thisV.isA(NullType) || thisV.isA(UndefinedType)) 1003 thisObj = globalObject(); 1004 else { 1005 thisObj = thisV.toObject(globExec); 555 1006 } 556 557 glob.init(); 558 con = new Context(); 559 firstN = 0L; 560 progN = 0L; 561 recursion = 0; 562 errMsg = ""; 563 initialized = true; 564 #ifdef KJS_DEBUGGER 565 sid = -1; 566 #endif 567 } 568 } 569 570 void KJScriptImp::clear() 571 { 572 if ( recursion ) { 573 #ifndef NDEBUG 574 fprintf(stderr, "KJS: ignoring clear() while running\n"); 575 #endif 576 return; 577 } 578 KJScriptImp *old = curr; 579 if (initialized) { 580 KJScriptImp::curr = this; 581 582 Node::setFirstNode(firstNode()); 583 Node::deleteAllNodes(); 584 setFirstNode(0L); 585 setProgNode(0L); 586 587 clearException(); 588 retVal = 0L; 589 590 delete con; con = 0L; 591 glob.clear(); 592 593 Collector::collect(); 594 595 // remove from global chain (see init()) 596 next->prev = prev; 597 prev->next = next; 598 hook = next; 599 if (hook == this) 600 hook = 0L; 601 602 #ifdef KJS_DEBUGGER 603 sid = -1; 604 #endif 605 606 initialized = false; 607 } 608 if (old != this) 609 KJScriptImp::curr = old; 610 } 611 612 bool KJScriptImp::evaluate(const UChar *code, unsigned int length, const KJSO &thisV, 613 bool onlyCheckSyntax) 614 { 615 init(); 616 617 #ifdef KJS_DEBUGGER 618 sid++; 619 if (debugger()) 620 debugger()->setSourceId(sid); 621 #endif 622 if (recursion > 7) { 623 fprintf(stderr, "KJS: breaking out of recursion\n"); 624 return true; 625 } else if (recursion > 0) { 626 #ifndef NDEBUG 627 fprintf(stderr, "KJS: entering recursion level %d\n", recursion); 628 #endif 629 pushStack(); 630 } 631 632 assert(Lexer::curr()); 633 Lexer::curr()->setCode(code, length); 634 Node::setFirstNode(firstNode()); 635 int parseError = kjsyyparse(); 636 setFirstNode(Node::firstNode()); 637 638 if (parseError) { 639 errType = 99; /* TODO */ 640 errLine = Lexer::curr()->lineNo(); 641 errMsg = "Parse error at line " + UString::from(errLine); 642 #ifndef NDEBUG 643 fprintf(stderr, "JavaScript parse error at line %d.\n", errLine); 644 #endif 645 /* TODO: either clear everything or keep previously 646 parsed function definitions */ 647 // Node::deleteAllNodes(); 648 return false; 649 } 650 651 if (onlyCheckSyntax) 652 return true; 653 654 clearException(); 655 656 KJSO oldVar; 657 if (!thisV.isNull()) { 658 context()->setThisValue(thisV); 659 context()->pushScope(thisV); 660 oldVar = context()->variableObject(); 661 context()->setVariableObject(thisV); 662 } 663 664 running++; 665 recursion++; 666 assert(progNode()); 667 Completion res = progNode()->execute(); 1007 } 1008 1009 Completion res; 1010 if (globExec->hadException()) { 1011 // the thisArg.toObject() conversion above might have thrown an exception - if so, 1012 // propagate it back 1013 res = Completion(Throw,globExec->exception()); 1014 } 1015 else { 1016 // execute the code 1017 ExecState *exec1 = 0; 1018 ContextImp *ctx = new ContextImp(globalObj, exec1, thisObj); 1019 ExecState *newExec = new ExecState(m_interpreter,ctx); 1020 1021 res = progNode->execute(newExec); 1022 1023 delete newExec; 1024 delete ctx; 1025 } 1026 1027 if (progNode->deref()) 1028 delete progNode; 668 1029 recursion--; 669 running--; 670 671 if (hadException()) { 672 KJSO err = exception(); 673 errType = 99; /* TODO */ 674 errLine = err.get("line").toInt32(); 675 errMsg = err.get("name").toString().value() + ". "; 676 errMsg += err.get("message").toString().value(); 677 #ifdef KJS_DEBUGGER 678 if (dbg) 679 dbg->setSourceId(err.get("sid").toInt32()); 680 #endif 681 clearException(); 682 } else { 683 errType = 0; 684 errLine = -1; 685 errMsg = ""; 686 687 // catch return value 688 retVal = 0L; 689 if (res.complType() == ReturnValue || !thisV.isNull()) 690 retVal = res.value().imp(); 691 } 692 693 if (!thisV.isNull()) { 694 context()->popScope(); 695 context()->setVariableObject(oldVar); 696 } 697 698 if (progNode()) 699 progNode()->deleteGlobalStatements(); 700 701 if (recursion > 0) { 702 popStack(); 703 } 704 705 return !errType; 706 } 707 708 void KJScriptImp::pushStack() 709 { 710 stack = stack->push(); 711 } 712 713 void KJScriptImp::popStack() 714 { 715 stack = stack->pop(); 716 assert(stack); 717 } 718 719 bool KJScriptImp::call(const KJSO &scope, const UString &func, const List &args) 720 { 721 init(); 722 KJSO callScope(scope); 723 if (callScope.isNull()) 724 callScope = Global::current().imp(); 725 if (!callScope.hasProperty(func)) { 726 #ifndef NDEBUG 727 fprintf(stderr, "couldn't resolve function name %s. call() failed\n", 728 func.ascii()); 729 #endif 730 return false; 731 } 732 KJSO v = callScope.get(func); 733 if (!v.isA(ConstructorType)) { 734 #ifndef NDEBUG 735 fprintf(stderr, "%s is not a function. call() failed.\n", func.ascii()); 736 #endif 737 return false; 738 } 739 running++; 740 recursion++; 741 static_cast<ConstructorImp*>(v.imp())->executeCall(scope.imp(), &args); 742 recursion--; 743 running--; 744 return !hadException(); 745 } 746 747 bool KJScriptImp::call(const KJSO &func, const KJSO &thisV, 748 const List &args, const List &extraScope) 749 { 750 init(); 751 if(!func.implementsCall()) 752 return false; 753 754 running++; 755 recursion++; 756 retVal = func.executeCall(thisV, &args, &extraScope).imp(); 757 recursion--; 758 running--; 759 760 return !hadException(); 761 } 762 763 void KJScriptImp::setException(Imp *e) 764 { 765 assert(curr); 766 curr->exVal = e; 767 curr->exMsg = "Exception"; // not very meaningful but we use !0L to test 768 } 769 770 void KJScriptImp::setException(const char *msg) 771 { 772 assert(curr); 773 curr->exVal = 0L; // will be created later on exception() 774 curr->exMsg = msg; 775 } 776 777 KJSO KJScriptImp::exception() 778 { 779 assert(curr); 780 if (!curr->exMsg) 781 return Undefined(); 782 if (curr->exVal) 783 return curr->exVal; 784 return Error::create(GeneralError, curr->exMsg); 785 } 786 787 void KJScriptImp::clearException() 788 { 789 assert(curr); 790 curr->exMsg = 0L; 791 curr->exVal = 0L; 792 } 793 794 #ifdef KJS_DEBUGGER 795 void KJScriptImp::attachDebugger(Debugger *d) 796 { 797 static bool detaching = false; 798 if (detaching) // break circular detaching 799 return; 800 801 if (dbg) { 802 detaching = true; 803 dbg->detach(); 804 detaching = false; 805 } 806 1030 1031 return res; 1032 } 1033 1034 void InterpreterImp::setDebugger(Debugger *d) 1035 { 1036 if (d) 1037 d->detach(m_interpreter); 807 1038 dbg = d; 808 1039 } 809 1040 810 bool KJScriptImp::setBreakpoint(int id, int line, bool set) 811 { 812 init(); 813 return Node::setBreakpoint(firstNode(), id, line, set); 814 } 815 816 #endif 817 818 bool PropList::contains(const UString &name) 819 { 820 PropList *p = this; 821 while (p) { 822 if (name == p->name) 823 return true; 824 p = p->next; 825 } 826 return false; 827 } 828 829 bool LabelStack::push(const UString &id) 830 { 831 if (id.isEmpty() || contains(id)) 832 return false; 833 834 StackElm *newtos = new StackElm; 835 newtos->id = id; 836 newtos->prev = tos; 837 tos = newtos; 1041 // ------------------------------ InternalFunctionImp -------------------------- 1042 1043 const ClassInfo InternalFunctionImp::info = {"Function", 0, 0, 0}; 1044 1045 InternalFunctionImp::InternalFunctionImp(FunctionPrototypeImp *funcProto) 1046 : ObjectImp(Object(funcProto)) 1047 { 1048 } 1049 1050 bool InternalFunctionImp::implementsHasInstance() const 1051 { 838 1052 return true; 839 1053 } 840 1054 841 bool LabelStack::contains(const UString &id) const 842 { 843 if (id.isEmpty()) 844 return true; 845 846 for (StackElm *curr = tos; curr; curr = curr->prev) 847 if (curr->id == id) 848 return true; 849 850 return false; 851 } 852 853 void LabelStack::pop() 854 { 855 if (tos) { 856 StackElm *prev = tos->prev; 857 delete tos; 858 tos = prev; 859 } 860 } 861 862 LabelStack::~LabelStack() 863 { 864 StackElm *prev; 865 866 while (tos) { 867 prev = tos->prev; 868 delete tos; 869 tos = prev; 870 } 871 } 872 873 // ECMA 15.3.5.3 [[HasInstance]] 874 // see comment in header file 875 KJSO KJS::hasInstance(const KJSO &F, const KJSO &V) 876 { 877 if (V.isObject()) { 878 KJSO prot = F.get("prototype"); 879 if (!prot.isObject()) 880 return Error::create(TypeError, "Invalid prototype encountered " 881 "in instanceof operation."); 882 Imp *v = V.imp(); 883 while ((v = v->prototype())) { 884 if (v == prot.imp()) 885 return Boolean(true); 886 } 1055 Boolean InternalFunctionImp::hasInstance(ExecState *exec, const Value &value) 1056 { 1057 if (value.type() != ObjectType) 1058 return Boolean(false); 1059 1060 Value prot = get(exec,"prototype"); 1061 if (prot.type() != ObjectType && prot.type() != NullType) { 1062 Object err = Error::create(exec, TypeError, "Invalid prototype encountered " 1063 "in instanceof operation."); 1064 exec->setException(err); 1065 return Boolean(false); 1066 } 1067 1068 Object v = Object(static_cast<ObjectImp*>(value.imp())); 1069 while ((v = Object::dynamicCast(v.prototype())).imp()) { 1070 if (v.imp() == prot.imp()) 1071 return Boolean(true); 887 1072 } 888 1073 return Boolean(false); 1074 } 1075 1076 // ------------------------------ global functions ----------------------------- 1077 1078 double KJS::roundValue(ExecState *exec, const Value &v) 1079 { 1080 if (v.type() == UndefinedType) /* TODO: see below */ 1081 return 0.0; 1082 Number n = v.toNumber(exec); 1083 if (n.value() == 0.0) /* TODO: -0, NaN, Inf */ 1084 return 0.0; 1085 double d = floor(fabs(n.value())); 1086 if (n.value() < 0) 1087 d *= -1; 1088 1089 return d; 889 1090 } 890 1091 891 1092 #ifndef NDEBUG 892 1093 #include <stdio.h> 893 void KJS::printInfo( const char *s, const KJSO &o ) 894 { 895 if (o.isNull()) 896 fprintf(stderr, "%s: (null)\n", s); 897 else { 898 KJSO v = o; 899 if (o.isA(ReferenceType)) 900 v = o.getValue(); 901 fprintf(stderr, "JS: %s: %s : %s (%p)\n", 902 s, 903 v.toString().value().ascii(), 904 v.imp()->typeInfo()->name, 905 (void*)v.imp()); 1094 void KJS::printInfo(ExecState *exec, const char *s, const Value &o, int lineno) 1095 { 1096 if (o.isNull()) 1097 fprintf(stderr, "KJS: %s: (null)", s); 1098 else { 1099 Value v = o; 1100 if (o.isA(ReferenceType)) 1101 v = o.getValue(exec); 1102 1103 UString name; 1104 switch ( v.type() ) { 1105 case UnspecifiedType: 1106 name = "Unspecified"; 1107 break; 1108 case UndefinedType: 1109 name = "Undefined"; 1110 break; 1111 case NullType: 1112 name = "Null"; 1113 break; 1114 case BooleanType: 1115 name = "Boolean"; 1116 break; 1117 case StringType: 1118 name = "String"; 1119 break; 1120 case NumberType: 1121 name = "Number"; 1122 break; 1123 case ObjectType: 1124 name = Object::dynamicCast(v).className(); 1125 if (name.isNull()) 1126 name = "(unknown class)"; 1127 break; 1128 case ReferenceType: 1129 name = "Reference"; 1130 break; 1131 case ListType: 1132 name = "List"; 1133 break; 1134 case CompletionType: 1135 name = "Completion"; 1136 break; 1137 default: 1138 break; 1139 } 1140 UString vString = v.toString(exec); 1141 if ( vString.size() > 50 ) 1142 vString = vString.substr( 0, 50 ) + "..."; 1143 // Can't use two UString::ascii() in the same fprintf call 1144 CString tempString( vString.cstring() ); 1145 1146 fprintf(stderr, "KJS: %s: %s : %s (%p)", 1147 s, tempString.c_str(), name.ascii(), (void*)v.imp()); 1148 1149 if (lineno >= 0) 1150 fprintf(stderr, ", line %d\n",lineno); 1151 else 1152 fprintf(stderr, "\n"); 1153 if (!o.isNull()) 906 1154 if (o.isA(ReferenceType)) { 907 fprintf(stderr, "JS: Was property '%s'\n", o.getPropertyName().ascii());908 printInfo("of", o.getBase());1155 fprintf(stderr, "KJS: Was property '%s'\n", o.getPropertyName(exec).ascii()); 1156 printInfo(exec,"of", o.getBase(exec)); 909 1157 } 910 1158 } 911 1159 } 912 1160 #endif -
trunk/JavaScriptCore/kjs/internal.h
r6 r798 1 // -*- c-basic-offset: 2 -*- 1 2 /* 2 3 * This file is part of the KDE libraries 3 * Copyright (C) 1999-2000 Harri Porten ([email protected]) 4 * Copyright (C) 1999-2001 Harri Porten ([email protected]) 5 * Copyright (C) 2001 Peter Kelly ([email protected]) 4 6 * 5 7 * This library is free software; you can redistribute it and/or … … 17 19 * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, 18 20 * Boston, MA 02111-1307, USA. 21 * 19 22 */ 20 23 … … 22 25 #define _INTERNAL_H_ 23 26 24 #ifdef HAVE_CONFIG_H 25 #include <config.h> 26 #endif 27 28 #include "kjs.h" 27 #include "ustring.h" 28 #include "value.h" 29 29 #include "object.h" 30 #include "function.h" 30 #include "types.h" 31 #include "interpreter.h" 31 32 32 33 #define I18N_NOOP(s) s … … 34 35 namespace KJS { 35 36 36 class Boolean; 37 class Number; 38 class String; 39 class Object; 40 class RegExp; 41 class Node; 37 static const double D16 = 65536.0; 38 static const double D32 = 4294967296.0; 39 40 class ProgramNode; 42 41 class FunctionBodyNode; 43 class ProgramNode;44 #ifdef KJS_DEBUGGER 42 class FunctionPrototypeImp; 43 class FunctionImp; 45 44 class Debugger; 46 #endif 47 48 class UndefinedImp : public Imp { 49 public: 50 UndefinedImp(); 45 46 // --------------------------------------------------------------------------- 47 // Primitive impls 48 // --------------------------------------------------------------------------- 49 50 class UndefinedImp : public ValueImp { 51 public: 52 UndefinedImp() {} 51 53 virtual ~UndefinedImp() { } 52 virtual KJSO toPrimitive(Type preferred = UndefinedType) const; 53 virtual Boolean toBoolean() const;54 virtual Number toNumber() const; 55 virtual String toString() const;56 virtual Object toObject() const;57 58 virtual const TypeInfo* typeInfo() const { return &info; }59 static const TypeInfo info;60 54 55 Type type() const { return UndefinedType; } 56 57 Value toPrimitive(ExecState *exec, Type preferred = UnspecifiedType) const; 58 bool toBoolean(ExecState *exec) const; 59 double toNumber(ExecState *exec) const; 60 UString toString(ExecState *exec) const; 61 Object toObject(ExecState *exec) const; 62 61 63 static UndefinedImp *staticUndefined; 62 64 }; 63 65 64 class NullImp : public Imp {65 public: 66 NullImp() ;66 class NullImp : public ValueImp { 67 public: 68 NullImp() {} 67 69 virtual ~NullImp() { } 68 virtual KJSO toPrimitive(Type preferred = UndefinedType) const; 69 virtual Boolean toBoolean() const;70 virtual Number toNumber() const; 71 virtual String toString() const;72 virtual Object toObject() const;73 74 virtual const TypeInfo* typeInfo() const { return &info; }75 static const TypeInfo info;70 71 Type type() const { return NullType; } 72 73 Value toPrimitive(ExecState *exec, Type preferred = UnspecifiedType) const; 74 bool toBoolean(ExecState *exec) const; 75 double toNumber(ExecState *exec) const; 76 UString toString(ExecState *exec) const; 77 Object toObject(ExecState *exec) const; 76 78 77 79 static NullImp *staticNull; 78 80 }; 79 81 80 class BooleanImp : public Imp {82 class BooleanImp : public ValueImp { 81 83 public: 82 84 virtual ~BooleanImp() { } 83 85 BooleanImp(bool v = false) : val(v) { } 84 86 bool value() const { return val; } 85 virtual KJSO toPrimitive(Type preferred = UndefinedType) const; 86 virtual Boolean toBoolean() const; 87 virtual Number toNumber() const; 88 virtual String toString() const; 89 virtual Object toObject() const; 90 91 virtual const TypeInfo* typeInfo() const { return &info; } 92 static const TypeInfo info; 93 94 static BooleanImp *staticTrue, *staticFalse; 87 88 Type type() const { return BooleanType; } 89 90 Value toPrimitive(ExecState *exec, Type preferred = UnspecifiedType) const; 91 bool toBoolean(ExecState *exec) const; 92 double toNumber(ExecState *exec) const; 93 UString toString(ExecState *exec) const; 94 Object toObject(ExecState *exec) const; 95 96 static BooleanImp *staticTrue; 97 static BooleanImp *staticFalse; 95 98 private: 96 99 bool val; 97 100 }; 98 101 99 class NumberImp : public Imp { 102 class StringImp : public ValueImp { 103 public: 104 StringImp(const UString& v); 105 virtual ~StringImp() { } 106 UString value() const { return val; } 107 108 Type type() const { return StringType; } 109 110 Value toPrimitive(ExecState *exec, Type preferred = UnspecifiedType) const; 111 bool toBoolean(ExecState *exec) const; 112 double toNumber(ExecState *exec) const; 113 UString toString(ExecState *exec) const; 114 Object toObject(ExecState *exec) const; 115 116 private: 117 UString val; 118 }; 119 120 class NumberImp : public ValueImp { 100 121 public: 101 122 NumberImp(double v); 102 123 virtual ~NumberImp() { } 103 124 double value() const { return val; } 104 virtual KJSO toPrimitive(Type preferred = UndefinedType) const; 105 virtual Boolean toBoolean() const; 106 virtual Number toNumber() const; 107 virtual String toString() const; 108 virtual Object toObject() const; 109 110 virtual const TypeInfo* typeInfo() const { return &info; } 111 static const TypeInfo info; 125 126 Type type() const { return NumberType; } 127 128 Value toPrimitive(ExecState *exec, Type preferred = UnspecifiedType) const; 129 bool toBoolean(ExecState *exec) const; 130 double toNumber(ExecState *exec) const; 131 UString toString(ExecState *exec) const; 132 Object toObject(ExecState *exec) const; 133 112 134 private: 113 135 double val; 114 136 }; 115 137 116 class StringImp : public Imp { 117 public: 118 StringImp(const UString& v); 119 virtual ~StringImp() { } 120 UString value() const { return val; } 121 virtual KJSO toPrimitive(Type preferred = UndefinedType) const; 122 virtual Boolean toBoolean() const; 123 virtual Number toNumber() const; 124 virtual String toString() const; 125 virtual Object toObject() const; 126 127 virtual const TypeInfo* typeInfo() const { return &info; } 128 static const TypeInfo info; 129 private: 130 UString val; 131 }; 132 133 class ReferenceImp : public Imp { 134 public: 135 ReferenceImp(const KJSO& b, const UString& p); 138 // --------------------------------------------------------------------------- 139 // Internal type impls 140 // --------------------------------------------------------------------------- 141 142 class ReferenceImp : public ValueImp { 143 public: 144 145 ReferenceImp(const Value& v, const UString& p); 136 146 virtual ~ReferenceImp() { } 137 virtual void mark(Imp*); 138 KJSO getBase() const { return base; } 147 virtual void mark(); 148 149 Value toPrimitive(ExecState *exec, Type preferred = UnspecifiedType) const; 150 bool toBoolean(ExecState *exec) const; 151 double toNumber(ExecState *exec) const; 152 UString toString(ExecState *exec) const; 153 Object toObject(ExecState *exec) const; 154 155 Value getBase() const { return Value(base); } 139 156 UString getPropertyName() const { return prop; } 140 157 141 virtual const TypeInfo* typeInfo() const { return &info; }142 static const TypeInfo info; 143 private: 144 KJSObase;158 Type type() const { return ReferenceType; } 159 160 private: 161 ValueImp *base; 145 162 UString prop; 146 163 }; 147 164 148 class CompletionImp : public Imp { 149 public: 150 CompletionImp(Compl c, const KJSO& v, const UString& t); 151 virtual ~CompletionImp() { } 152 virtual void mark(Imp*); 153 Compl completion() const { return comp; } 154 KJSO value() const { return val; } 165 class CompletionImp : public ValueImp { 166 public: 167 Type type() const { return CompletionType; } 168 169 CompletionImp(ComplType c, const Value& v, const UString& t); 170 virtual ~CompletionImp(); 171 virtual void mark(); 172 173 Value toPrimitive(ExecState *exec, Type preferred = UnspecifiedType) const; 174 bool toBoolean(ExecState *exec) const; 175 double toNumber(ExecState *exec) const; 176 UString toString(ExecState *exec) const; 177 Object toObject(ExecState *exec) const; 178 179 ComplType complType() const { return comp; } 180 Value value() const { return Value(val); } 155 181 UString target() const { return tar; } 156 182 157 virtual const TypeInfo* typeInfo() const { return &info; } 158 static const TypeInfo info; 159 private: 160 Compl comp; 161 KJSO val; 183 private: 184 ComplType comp; 185 ValueImp * val; 162 186 UString tar; 163 187 }; 164 188 165 class RegExpImp : public ObjectImp { 166 public: 167 RegExpImp(); 168 ~RegExpImp(); 169 void setRegExp(RegExp *r) { reg = r; } 170 RegExp* regExp() const { return reg; } 171 private: 172 RegExp *reg; 173 }; 174 175 class StatementNode; 176 class UString; 177 178 class Reference : public KJSO { 179 public: 180 Reference(const KJSO& b, const UString &p); 181 virtual ~Reference(); 189 /** 190 * @internal 191 */ 192 class ListNode { 193 friend class List; 194 friend class ListImp; 195 friend class ListIterator; 196 ListNode(Value val, ListNode *p, ListNode *n) 197 : member(val.imp()), prev(p), next(n) {}; 198 ValueImp *member; 199 ListNode *prev, *next; 200 }; 201 202 class ListImp : public ValueImp { 203 friend class ListIterator; 204 friend class List; 205 friend class InterpreterImp; 206 public: 207 ListImp(); 208 ~ListImp(); 209 210 Type type() const { return ListType; } 211 212 virtual void mark(); 213 214 Value toPrimitive(ExecState *exec, Type preferred = UnspecifiedType) const; 215 bool toBoolean(ExecState *exec) const; 216 double toNumber(ExecState *exec) const; 217 UString toString(ExecState *exec) const; 218 Object toObject(ExecState *exec) const; 219 220 void append(const Value& val); 221 void prepend(const Value& val); 222 void appendList(const List& lst); 223 void prependList(const List& lst); 224 void removeFirst(); 225 void removeLast(); 226 void remove(const Value &val); 227 void clear(); 228 ListImp *copy() const; 229 ListIterator begin() const { return ListIterator(hook->next); } 230 ListIterator end() const { return ListIterator(hook); } 231 // bool isEmpty() const { return (hook->prev == hook); } 232 bool isEmpty() const; 233 int size() const; 234 Value at(int i) const; 235 Value operator[](int i) const { return at(i); } 236 static ListImp* empty(); 237 238 #ifdef KJS_DEBUG_MEM 239 static int count; 240 #endif 241 private: 242 void erase(ListNode *n); 243 ListNode *hook; 244 static ListImp *emptyList; 182 245 }; 183 246 … … 189 252 LabelStack(): tos(0L) {} 190 253 ~LabelStack(); 254 255 LabelStack(const LabelStack &other); 256 LabelStack &operator=(const LabelStack &other); 191 257 192 258 /** … … 204 270 void pop(); 205 271 private: 206 struct StackEl m {272 struct StackElem { 207 273 UString id; 208 StackEl m *prev;274 StackElem *prev; 209 275 }; 210 276 211 StackElm *tos; 212 }; 277 StackElem *tos; 278 void clear(); 279 }; 280 281 282 // --------------------------------------------------------------------------- 283 // Parsing & evaluateion 284 // --------------------------------------------------------------------------- 285 286 enum CodeType { GlobalCode, 287 EvalCode, 288 FunctionCode, 289 AnonymousCode }; 213 290 214 291 /** 215 292 * @short Execution context. 216 293 */ 217 class Context { 218 public: 219 Context(CodeType type = GlobalCode, Context *callingContext = 0L, 220 FunctionImp *func = 0L, const List *args = 0L, Imp *thisV = 0L); 221 virtual ~Context(); 222 static Context *current(); 223 static void setCurrent(Context *c); 224 const List *pScopeChain() const { return scopeChain; } 225 void pushScope(const KJSO &s); 294 class ContextImp { 295 public: 296 ContextImp(Object &glob, ExecState *exec, Object &thisV, CodeType type = GlobalCode, 297 ContextImp *_callingContext = 0L, FunctionImp *func = 0L, const List &args = List()); 298 virtual ~ContextImp(); 299 300 const List scopeChain() const { return scope; } 301 Object variableObject() const { return variable; } 302 void setVariableObject(const Object &v) { variable = v; } 303 Object thisValue() const { return thisVal; } 304 ContextImp *callingContext() { return callingCon; } 305 Object activationObject() { return activation; } 306 307 void pushScope(const Object &s); 226 308 void popScope(); 227 List *copyOfChain();228 KJSO variableObject() const { return variable; }229 void setVariableObject( const KJSO &obj ) { variable = obj; }230 KJSO thisValue() const { return thisVal; }231 void setThisValue(const KJSO &t) { thisVal = t; }232 309 LabelStack *seenLabels() { return &ls; } 233 private: 310 311 private: 312 313 List scope; 314 Object variable; 315 Object thisVal; 316 ContextImp *callingCon; 317 Object activation; 318 319 234 320 LabelStack ls; 235 KJSO thisVal; 236 KJSO activation; 237 KJSO variable; 238 List *scopeChain; 239 }; 240 241 class DeclaredFunctionImp : public ConstructorImp { 242 public: 243 DeclaredFunctionImp(const UString &n, FunctionBodyNode *b, 244 const List *sc); 245 ~DeclaredFunctionImp(); 246 Completion execute(const List &); 247 Object construct(const List &); 248 CodeType codeType() const { return FunctionCode; } 249 List *scopeChain() const { return scopes; } 250 private: 251 FunctionBodyNode *body; 252 List *scopes; 253 }; 254 255 class AnonymousFunction : public Function { 256 public: 257 AnonymousFunction(); 258 Completion execute(const List &); 259 CodeType codeType() const { return AnonymousCode; } 260 }; 261 262 class ActivationImp : public Imp { 263 public: 264 ActivationImp(FunctionImp *f, const List *args); 265 virtual const TypeInfo* typeInfo() const { return &info; } 266 static const TypeInfo info; 267 }; 268 269 class ExecutionStack { 270 public: 271 ExecutionStack(); 272 ExecutionStack *push(); 273 ExecutionStack *pop(); 274 275 ProgramNode *progNode; 276 Node *firstNode; 277 private: 278 ExecutionStack *prev; 279 }; 280 281 class KJScriptImp { 282 friend class ::KJScript; 283 friend class Lexer; 284 friend class Context; 285 friend class Global; 321 CodeType codeType; 322 }; 323 324 /** 325 * @internal 326 * 327 * Parses ECMAScript source code and converts into ProgramNode objects, which 328 * represent the root of a parse tree. This class provides a conveniant workaround 329 * for the problem of the bison parser working in a static context. 330 */ 331 class Parser { 332 public: 333 static ProgramNode *parse(const UChar *code, unsigned int length, int *sourceId = 0, 334 int *errLine = 0, UString *errMsg = 0); 335 336 static ProgramNode *progNode; 337 static int sid; 338 }; 339 340 class InterpreterImp { 286 341 friend class Collector; 287 342 public: 288 KJScriptImp(KJScript *s); 289 ~KJScriptImp(); 343 static void globalInit(); 344 static void globalClear(); 345 346 InterpreterImp(Interpreter *interp, const Object &glob); 347 ~InterpreterImp(); 348 349 Object globalObject() const { return global; } 350 Interpreter* interpreter() const { return m_interpreter; } 351 290 352 void mark(); 291 static KJScriptImp *current() { return curr; } 292 static void setException(Imp *e); 293 static void setException(const char *msg); 294 static bool hadException(); 295 static KJSO exception(); 296 static void clearException(); 297 298 Context *context() const { return con; } 299 void setContext(Context *c) { con = c; } 300 301 #ifdef KJS_DEBUGGER 302 /** 303 * Attach debugger d to this engine. If there already was another instance 304 * attached it will be detached. 305 */ 306 void attachDebugger(Debugger *d); 353 354 ExecState *globalExec() { return globExec; } 355 bool checkSyntax(const UString &code); 356 Completion evaluate(const UString &code, const Value &thisV); 307 357 Debugger *debugger() const { return dbg; } 308 int sourceId() const { return sid; } 309 bool setBreakpoint(int id, int line, bool set); 358 void setDebugger(Debugger *d); 359 360 Object builtinObject() const { return b_Object; } 361 Object builtinFunction() const { return b_Function; } 362 Object builtinArray() const { return b_Array; } 363 Object builtinBoolean() const { return b_Boolean; } 364 Object builtinString() const { return b_String; } 365 Object builtinNumber() const { return b_Number; } 366 Object builtinDate() const { return b_Date; } 367 Object builtinRegExp() const { return b_RegExp; } 368 Object builtinError() const { return b_Error; } 369 370 Object builtinObjectPrototype() const { return b_ObjectPrototype; } 371 Object builtinFunctionPrototype() const { return b_FunctionPrototype; } 372 Object builtinArrayPrototype() const { return b_ArrayPrototype; } 373 Object builtinBooleanPrototype() const { return b_BooleanPrototype; } 374 Object builtinStringPrototype() const { return b_StringPrototype; } 375 Object builtinNumberPrototype() const { return b_NumberPrototype; } 376 Object builtinDatePrototype() const { return b_DatePrototype; } 377 Object builtinRegExpPrototype() const { return b_RegExpPrototype; } 378 Object builtinErrorPrototype() const { return b_ErrorPrototype; } 379 380 Object builtinEvalError() const { return b_evalError; } 381 Object builtinRangeError() const { return b_rangeError; } 382 Object builtinReferenceError() const { return b_referenceError; } 383 Object builtinSyntaxError() const { return b_syntaxError; } 384 Object builtinTypeError() const { return b_typeError; } 385 Object builtinURIError() const { return b_uriError; } 386 387 Object builtinEvalErrorPrototype() const { return b_evalErrorPrototype; } 388 Object builtinRangeErrorPrototype() const { return b_rangeErrorPrototype; } 389 Object builtinReferenceErrorPrototype() const { return b_referenceErrorPrototype; } 390 Object builtinSyntaxErrorPrototype() const { return b_syntaxErrorPrototype; } 391 Object builtinTypeErrorPrototype() const { return b_typeErrorPrototype; } 392 Object builtinURIErrorPrototype() const { return b_uriErrorPrototype; } 393 394 void setCompatMode(Interpreter::CompatMode mode) { m_compatMode = mode; } 395 Interpreter::CompatMode compatMode() const { return m_compatMode; } 396 397 // Chained list of interpreters (ring) 398 static InterpreterImp* firstInterpreter() { return s_hook; } 399 InterpreterImp *nextInterpreter() const { return next; } 400 InterpreterImp *prevInterpreter() const { return prev; } 401 402 private: 403 void clear(); 404 Interpreter *m_interpreter; 405 Object global; 406 Debugger *dbg; 407 408 // Built-in properties of the object prototype. These are accessible 409 // from here even if they are replaced by js code (e.g. assigning to 410 // Array.prototype) 411 412 Object b_Object; 413 Object b_Function; 414 Object b_Array; 415 Object b_Boolean; 416 Object b_String; 417 Object b_Number; 418 Object b_Date; 419 Object b_RegExp; 420 Object b_Error; 421 422 Object b_ObjectPrototype; 423 Object b_FunctionPrototype; 424 Object b_ArrayPrototype; 425 Object b_BooleanPrototype; 426 Object b_StringPrototype; 427 Object b_NumberPrototype; 428 Object b_DatePrototype; 429 Object b_RegExpPrototype; 430 Object b_ErrorPrototype; 431 432 Object b_evalError; 433 Object b_rangeError; 434 Object b_referenceError; 435 Object b_syntaxError; 436 Object b_typeError; 437 Object b_uriError; 438 439 Object b_evalErrorPrototype; 440 Object b_rangeErrorPrototype; 441 Object b_referenceErrorPrototype; 442 Object b_syntaxErrorPrototype; 443 Object b_typeErrorPrototype; 444 Object b_uriErrorPrototype; 445 446 ExecState *globExec; 447 Interpreter::CompatMode m_compatMode; 448 449 // Chained list of interpreters (ring) - for collector 450 static InterpreterImp* s_hook; 451 InterpreterImp *next, *prev; 452 453 int recursion; 454 }; 455 456 class AttachedInterpreter; 457 class DebuggerImp { 458 public: 459 460 DebuggerImp() { 461 interps = 0; 462 isAborted = false; 463 } 464 465 void abort() { isAborted = true; } 466 bool aborted() const { return isAborted; } 467 468 AttachedInterpreter *interps; 469 bool isAborted; 470 }; 471 472 473 474 class InternalFunctionImp : public ObjectImp { 475 public: 476 InternalFunctionImp(FunctionPrototypeImp *funcProto); 477 bool implementsHasInstance() const; 478 Boolean hasInstance(ExecState *exec, const Value &value); 479 480 virtual const ClassInfo *classInfo() const { return &info; } 481 static const ClassInfo info; 482 }; 483 484 // helper function for toInteger, toInt32, toUInt32 and toUInt16 485 double roundValue(ExecState *exec, const Value &v); 486 487 #ifndef NDEBUG 488 void printInfo(ExecState *exec, const char *s, const Value &o, int lineno = -1); 310 489 #endif 311 private:312 /**313 * Initialize global object and context. For internal use only.314 */315 void init();316 void clear();317 /**318 * Called when the first interpreter is instanciated. Initializes319 * global pointers.320 */321 void globalInit();322 /**323 * Called when the last interpreter instance is destroyed. Frees324 * globally allocated memory.325 */326 void globalClear();327 bool evaluate(const UChar *code, unsigned int length, const KJSO &thisV = KJSO(),328 bool onlyCheckSyntax = false);329 bool call(const KJSO &scope, const UString &func, const List &args);330 bool call(const KJSO &func, const KJSO &thisV,331 const List &args, const List &extraScope);332 333 public:334 ProgramNode *progNode() const { return stack->progNode; }335 void setProgNode(ProgramNode *p) { stack->progNode = p; }336 Node *firstNode() const { return stack->firstNode; }337 void setFirstNode(Node *n) { stack->firstNode = n; }338 void pushStack();339 void popStack();340 KJScriptImp *next, *prev;341 KJScript *scr;342 ExecutionStack *stack;343 344 private:345 ProgramNode *progN;346 Node *firstN;347 348 static KJScriptImp *curr, *hook;349 static int instances; // total number of instances350 static int running; // total number running351 bool initialized;352 Lexer *lex;353 Context *con;354 Global glob;355 int errType, errLine;356 UString errMsg;357 #ifdef KJS_DEBUGGER358 Debugger *dbg;359 int sid;360 #endif361 const char *exMsg;362 Imp *exVal;363 Imp *retVal;364 int recursion;365 };366 367 inline bool KJScriptImp::hadException()368 {369 assert(curr);370 return curr->exMsg;371 }372 373 /**374 * @short Struct used to return the property names of an object375 */376 class PropList {377 public:378 PropList(UString nm = UString::null, PropList *nx = 0) :379 name(nm), next(nx) {};380 ~PropList() {381 if(next) delete next;382 }383 /**384 * The property name385 */386 UString name;387 /**388 * The next property389 */390 PropList *next;391 bool contains(const UString &name);392 };393 394 /* TODO just temporary until functions are objects and this becomes395 a member function. Called by RelationNode for 'instanceof' operator. */396 KJSO hasInstance(const KJSO &F, const KJSO &V);397 398 // #define KJS_VERBOSE399 #ifndef NDEBUG400 void printInfo( const char *s, const KJSO &o );401 #endif402 490 403 491 }; // namespace 404 492 405 493 406 #endif 494 #endif // _INTERNAL_H_ -
trunk/JavaScriptCore/kjs/lexer.cpp
r6 r798 1 // -*- c-basic-offset: 2 -*- 1 2 /* 2 3 * This file is part of the KDE libraries … … 17 18 * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, 18 19 * Boston, MA 02111-1307, USA. 20 * 21 * $Id$ 19 22 */ 20 23 … … 29 32 #include <assert.h> 30 33 31 #include "kjs.h" 34 #include "value.h" 35 #include "object.h" 36 #include "types.h" 37 #include "interpreter.h" 32 38 #include "nodes.h" 33 39 #include "lexer.h" … … 39 45 using namespace KJS; 40 46 47 static Lexer *currLexer = 0; 48 41 49 #ifndef KDE_USE_FINAL 42 50 #include "grammar.h" … … 45 53 #include "lexer.lut.h" 46 54 47 #ifdef KJS_DEBUGGER48 55 extern YYLTYPE yylloc; // global bison variable holding token info 49 #endif50 56 51 57 // a bridge for yacc from the C world to C++ … … 58 64 : yylineno(0), 59 65 size8(128), size16(128), restrKeyword(false), 60 stackToken(-1), pos(0),66 eatNextIdentifier(false), stackToken(-1), lastToken(-1), pos(0), 61 67 code(0), length(0), 62 68 #ifndef KJS_PURE_ECMA … … 68 74 buffer8 = new char[size8]; 69 75 buffer16 = new UChar[size16]; 76 currLexer = this; 70 77 71 78 } … … 79 86 Lexer *Lexer::curr() 80 87 { 81 assert(KJScriptImp::current()); 82 return KJScriptImp::current()->lex; 88 if (!currLexer) { 89 // create singleton instance 90 currLexer = new Lexer(); 91 } 92 return currLexer; 83 93 } 84 94 … … 88 98 restrKeyword = false; 89 99 delimited = false; 100 eatNextIdentifier = false; 90 101 stackToken = -1; 102 lastToken = -1; 91 103 pos = 0; 92 104 code = c; 93 105 length = len; 106 skipLF = false; 107 skipCR = false; 94 108 #ifndef KJS_PURE_ECMA 95 109 bol = true; … … 128 142 done = false; 129 143 terminator = false; 144 skipLF = false; 145 skipCR = false; 130 146 131 147 // did we push a token on the stack previously ? … … 138 154 139 155 while (!done) { 156 if (skipLF && current != '\n') // found \r but not \n afterwards 157 skipLF = false; 158 if (skipCR && current != '\r') // found \n but not \r afterwards 159 skipCR = false; 160 if (skipLF || skipCR) // found \r\n or \n\r -> eat the second one 161 { 162 skipLF = false; 163 skipCR = false; 164 shift(1); 165 } 140 166 switch (state) { 141 167 case Start: … … 316 342 record8(current); 317 343 state = InOctal; 344 } else if (isDecimalDigit(current)) { 345 record8(current); 346 state = InDecimal; 318 347 } else { 319 348 setDone(Number); … … 330 359 if (isOctalDigit(current)) { 331 360 record8(current); 361 } 362 else if (isDecimalDigit(current)) { 363 record8(current); 364 state = InDecimal; 332 365 } else 333 366 setDone(Octal); … … 434 467 #endif 435 468 469 if (state != Identifier && eatNextIdentifier) 470 eatNextIdentifier = false; 471 436 472 restrKeyword = false; 437 473 delimited = false; 438 #ifdef KJS_DEBUGGER439 474 yylloc.first_line = yylineno; // ??? 440 475 yylloc.last_line = yylineno; 441 #endif442 476 443 477 switch (state) { 444 478 case Eof: 445 return 0; 479 token = 0; 480 break; 446 481 case Other: 447 482 if(token == '}' || token == ';') { 448 483 delimited = true; 449 484 } 450 return token;485 break; 451 486 case Identifier: 452 487 if ((token = Lookup::find(&mainTable, buffer16, pos16)) < 0) { 488 // Lookup for keyword failed, means this is an identifier 489 // Apply anonymous-function hack below (eat the identifier) 490 if (eatNextIdentifier) { 491 eatNextIdentifier = false; 492 UString debugstr(buffer16, pos16); fprintf(stderr,"Anonymous function hack: eating identifier %s\n",debugstr.ascii()); 493 token = lex(); 494 break; 495 } 453 496 /* TODO: close leak on parse error. same holds true for String */ 454 497 kjsyylval.ustr = new UString(buffer16, pos16); 455 return IDENT; 498 token = IDENT; 499 break; 456 500 } 501 502 eatNextIdentifier = false; 503 // Hack for "f = function somename() { ... }", too hard to get into the grammar 504 if (token == FUNCTION && lastToken == '=' ) 505 eatNextIdentifier = true; 506 457 507 if (token == CONTINUE || token == BREAK || 458 508 token == RETURN || token == THROW) 459 509 restrKeyword = true; 460 return token;510 break; 461 511 case String: 462 kjsyylval.ustr = new UString(buffer16, pos16); return STRING; 512 kjsyylval.ustr = new UString(buffer16, pos16); 513 token = STRING; 514 break; 463 515 case Number: 464 516 kjsyylval.dval = dval; 465 return NUMBER; 517 token = NUMBER; 518 break; 466 519 case Bad: 467 520 fprintf(stderr, "yylex: ERROR.\n"); … … 471 524 return -1; 472 525 } 526 lastToken = token; 527 return token; 473 528 } 474 529 … … 479 534 } 480 535 481 bool Lexer::isLineTerminator() const 482 { 483 return (current == '\n' || current == '\r'); 536 bool Lexer::isLineTerminator() 537 { 538 bool cr = (current == '\r'); 539 bool lf = (current == '\n'); 540 if (cr) 541 skipLF = true; 542 else if (lf) 543 skipCR = true; 544 return cr || lf; 484 545 } 485 546 … … 541 602 } else if (c1 == '+' && c2 == '+') { 542 603 shift(2); 543 if (terminator) { 544 // automatic semicolon insertion 545 stackToken = PLUSPLUS; 546 return AUTO; 547 } else 604 if (terminator) 605 return AUTOPLUSPLUS; 606 else 548 607 return PLUSPLUS; 549 608 } else if (c1 == '-' && c2 == '-') { 550 609 shift(2); 551 if (terminator) { 552 // automatic semicolon insertion 553 stackToken = MINUSMINUS; 554 return AUTO; 555 } else 610 if (terminator) 611 return AUTOMINUSMINUS; 612 else 556 613 return MINUSMINUS; 557 614 } else if (c1 == '=' && c2 == '=') { … … 716 773 pos16 = 0; 717 774 bool lastWasEscape = false; 775 bool inBrackets = false; 718 776 719 777 while (1) { 720 778 if (isLineTerminator() || current == 0) 721 779 return false; 722 else if (current != '/' || lastWasEscape == true )780 else if (current != '/' || lastWasEscape == true || inBrackets == true) 723 781 { 782 // keep track of '[' and ']' 783 if ( !lastWasEscape ) { 784 if ( current == '[' && !inBrackets ) 785 inBrackets = true; 786 if ( current == ']' && inBrackets ) 787 inBrackets = false; 788 } 724 789 record16(current); 725 790 lastWasEscape = 726 791 !lastWasEscape && (current == '\\'); 727 792 } 728 else { 793 else { // end of regexp 729 794 pattern = UString(buffer16, pos16); 730 795 pos16 = 0; -
trunk/JavaScriptCore/kjs/lexer.h
r6 r798 1 // -*- c-basic-offset: 2 -*- 1 2 /* 2 3 * This file is part of the KDE libraries … … 17 18 * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, 18 19 * Boston, MA 02111-1307, USA. 20 * 21 * $Id$ 19 22 */ 20 23 … … 64 67 Other, 65 68 Bad }; 66 69 67 70 bool scanRegExp(); 68 71 UString pattern, flags; … … 79 82 // encountered delimiter like "'" and "}" on last run 80 83 bool delimited; 84 bool skipLF; 85 bool skipCR; 86 bool eatNextIdentifier; 81 87 int stackToken; 88 int lastToken; 82 89 83 90 State state; … … 88 95 89 96 bool isWhiteSpace() const; 90 bool isLineTerminator() const;97 bool isLineTerminator(); 91 98 bool isHexDigit(unsigned short c) const; 92 99 bool isOctalDigit(unsigned short c) const; … … 120 127 unsigned short current, next1, next2, next3; 121 128 122 struct keyword {123 const char *name;124 int token;125 };126 127 129 // for future extensions 128 130 class LexerPrivate; -
trunk/JavaScriptCore/kjs/lexer.lut.h
r6 r798 1 /* automatically generated from keywords.table. DO NOT EDIT ! */ 1 /* Automatically generated from keywords.table using ./create_hash_table. DO NOT EDIT ! */ 2 3 #include "lookup.h" 2 4 3 5 namespace KJS { 4 6 5 const struct HashEntry 2mainTableEntries[] = {6 { "instanceof", INSTANCEOF, 0, &mainTableEntries[63] },7 { "var", VAR, 0, &mainTableEntries[47] },8 { "case", CASE, 0, &mainTableEntries[41] },9 { "default", DEFAULT, 0, &mainTableEntries[54] },10 { "while", WHILE, 0, &mainTableEntries[46] },11 { 0, 0, 0, 0 },12 { "do", DO, 0, 0 },13 { "typeof", TYPEOF, 0, 0 },14 { "continue", CONTINUE, 0, 0 },15 { "function", FUNCTION, 0, 0 },16 { "in", IN, 0, 0 },17 { "import", RESERVED, 0, 0 },18 { "delete", DELETE, 0, 0 },19 { "finally", FINALLY, 0, 0 },20 { 0, 0, 0, 0 },21 { "else", ELSE, 0, 0 },22 { "return", RETURN, 0, 0 },23 { "debugger", RESERVED, 0, 0 },24 { "const", RESERVED, 0, &mainTableEntries[48] },25 { "package", RESERVED, 0, 0 },26 { "double", RESERVED, 0, &mainTableEntries[53] },27 { 0, 0, 0, 0 },28 { "long", RESERVED, 0, 0 },29 { "catch", CATCH, 0, &mainTableEntries[45] },30 { "void", VOID, 0, &mainTableEntries[59] },31 { "break", BREAK, 0, &mainTableEntries[49] },32 { "byte", RESERVED, 0, &mainTableEntries[62] },33 { "enum", RESERVED, 0, &mainTableEntries[58] },34 { 0, 0, 0, 0 },35 { 0, 0, 0, 0 },36 { "this", THIS, 0, &mainTableEntries[50] },37 { "false", FALSETOKEN, 0, &mainTableEntries[44] },38 { "abstract", RESERVED, 0, &mainTableEntries[56] },39 { "null", NULLTOKEN, 0, &mainTableEntries[61] },40 { "with", WITH, 0, 0 },41 { 0, 0, 0, 0 },42 { 0, 0, 0, 0 },43 { 0, 0, 0, 0 },44 { "true", TRUETOKEN, 0, 0 },45 { "boolean", RESERVED, 0, 0 },46 { "for", FOR, 0, 0 },47 { "new", NEW, 0, &mainTableEntries[42] },48 { "if", IF, 0, &mainTableEntries[43] },49 { "switch", SWITCH, 0, &mainTableEntries[55] },50 { "throw", THROW, 0, &mainTableEntries[52] },51 { "try", TRY, 0, &mainTableEntries[64] },52 { "char", RESERVED, 0, 0 },53 { "class", RESERVED, 0, &mainTableEntries[51] },54 { "export", RESERVED, 0, 0 },55 { "extends", RESERVED, 0, &mainTableEntries[57] },56 { "final", RESERVED, 0, 0 },57 { "float", RESERVED, 0, 0 },58 { "goto", RESERVED, 0, 0 },59 { "implements", RESERVED, 0, 0 },60 { "int", RESERVED, 0, &mainTableEntries[66] },61 { "interface", RESERVED, 0, 0 },62 { "native", RESERVED, 0, 0 },63 { "private", RESERVED, 0, 0 },64 { "protected", RESERVED, 0, &mainTableEntries[60] },65 { "public", RESERVED, 0, 0 },66 { "short", RESERVED, 0, 0 },67 { "static", RESERVED, 0, 0 },68 { "super", RESERVED, 0, 0 },69 { "synchronized", RESERVED, 0, &mainTableEntries[65] },70 { "throws", RESERVED, 0, 0 },71 { "transient", RESERVED, 0, 0 },72 { "volatile", RESERVED, 0, 0 }7 const struct HashEntry mainTableEntries[] = { 8 { "instanceof", INSTANCEOF, 0, 0, &mainTableEntries[63] }, 9 { "var", VAR, 0, 0, &mainTableEntries[47] }, 10 { "case", CASE, 0, 0, &mainTableEntries[41] }, 11 { "default", DEFAULT, 0, 0, &mainTableEntries[54] }, 12 { "while", WHILE, 0, 0, &mainTableEntries[46] }, 13 { 0, 0, 0, 0, 0 }, 14 { "do", DO, 0, 0, 0 }, 15 { "typeof", TYPEOF, 0, 0, 0 }, 16 { "continue", CONTINUE, 0, 0, 0 }, 17 { "function", FUNCTION, 0, 0, 0 }, 18 { "in", IN, 0, 0, 0 }, 19 { "import", RESERVED, 0, 0, 0 }, 20 { "delete", DELETE, 0, 0, 0 }, 21 { "finally", FINALLY, 0, 0, 0 }, 22 { 0, 0, 0, 0, 0 }, 23 { "else", ELSE, 0, 0, 0 }, 24 { "return", RETURN, 0, 0, 0 }, 25 { "debugger", RESERVED, 0, 0, 0 }, 26 { "const", RESERVED, 0, 0, &mainTableEntries[48] }, 27 { "package", RESERVED, 0, 0, 0 }, 28 { "double", RESERVED, 0, 0, &mainTableEntries[53] }, 29 { 0, 0, 0, 0, 0 }, 30 { "long", RESERVED, 0, 0, 0 }, 31 { "catch", CATCH, 0, 0, &mainTableEntries[45] }, 32 { "void", VOID, 0, 0, &mainTableEntries[59] }, 33 { "break", BREAK, 0, 0, &mainTableEntries[49] }, 34 { "byte", RESERVED, 0, 0, &mainTableEntries[62] }, 35 { "enum", RESERVED, 0, 0, &mainTableEntries[58] }, 36 { 0, 0, 0, 0, 0 }, 37 { 0, 0, 0, 0, 0 }, 38 { "this", THIS, 0, 0, &mainTableEntries[50] }, 39 { "false", FALSETOKEN, 0, 0, &mainTableEntries[44] }, 40 { "abstract", RESERVED, 0, 0, &mainTableEntries[56] }, 41 { "null", NULLTOKEN, 0, 0, &mainTableEntries[61] }, 42 { "with", WITH, 0, 0, 0 }, 43 { 0, 0, 0, 0, 0 }, 44 { 0, 0, 0, 0, 0 }, 45 { 0, 0, 0, 0, 0 }, 46 { "true", TRUETOKEN, 0, 0, 0 }, 47 { "boolean", RESERVED, 0, 0, 0 }, 48 { "for", FOR, 0, 0, 0 }, 49 { "new", NEW, 0, 0, &mainTableEntries[42] }, 50 { "if", IF, 0, 0, &mainTableEntries[43] }, 51 { "switch", SWITCH, 0, 0, &mainTableEntries[55] }, 52 { "throw", THROW, 0, 0, &mainTableEntries[52] }, 53 { "try", TRY, 0, 0, &mainTableEntries[64] }, 54 { "char", RESERVED, 0, 0, 0 }, 55 { "class", RESERVED, 0, 0, &mainTableEntries[51] }, 56 { "export", RESERVED, 0, 0, 0 }, 57 { "extends", RESERVED, 0, 0, &mainTableEntries[57] }, 58 { "final", RESERVED, 0, 0, 0 }, 59 { "float", RESERVED, 0, 0, 0 }, 60 { "goto", RESERVED, 0, 0, 0 }, 61 { "implements", RESERVED, 0, 0, 0 }, 62 { "int", RESERVED, 0, 0, &mainTableEntries[66] }, 63 { "interface", RESERVED, 0, 0, 0 }, 64 { "native", RESERVED, 0, 0, 0 }, 65 { "private", RESERVED, 0, 0, 0 }, 66 { "protected", RESERVED, 0, 0, &mainTableEntries[60] }, 67 { "public", RESERVED, 0, 0, 0 }, 68 { "short", RESERVED, 0, 0, 0 }, 69 { "static", RESERVED, 0, 0, 0 }, 70 { "super", RESERVED, 0, 0, 0 }, 71 { "synchronized", RESERVED, 0, 0, &mainTableEntries[65] }, 72 { "throws", RESERVED, 0, 0, 0 }, 73 { "transient", RESERVED, 0, 0, 0 }, 74 { "volatile", RESERVED, 0, 0, 0 } 73 75 }; 74 76 75 const struct HashTable 2mainTable = { 2, 67, mainTableEntries, 41 };77 const struct HashTable mainTable = { 2, 67, mainTableEntries, 41 }; 76 78 77 79 }; // namespace -
trunk/JavaScriptCore/kjs/lookup.cpp
r6 r798 1 // -*- c-basic-offset: 2 -*- 1 2 /* 2 3 * This file is part of the KDE libraries … … 16 17 * License along with this library; if not, write to the Free Software 17 18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 * 20 * $Id$ 18 21 */ 19 22 … … 29 32 using namespace KJS; 30 33 31 int Lookup::find(const struct HashTable *table, 32 const UChar *c, unsigned int len) 33 { 34 // we only know about version 1 so far 35 if (table->type != 1) { 36 fprintf(stderr, "Unknown hash table version.\n"); 37 return -1; 38 } 39 40 int h = hash(c, len) % table->hashSize; 41 const HashEntry *e = &table->entries[h]; 42 43 // empty bucket ? 44 if (!e->c) 45 return -1; 46 47 do { 48 // compare strings 49 #ifdef KJS_SWAPPED_CHAR 50 /* TODO: not exactly as optimized as the other version ... */ 51 if (len == e->len) { 52 const UChar *u = (const UChar*)e->c; 53 const UChar *c2 = c; 54 unsigned int i; 55 for (i = 0; i < len; i++, u++, c2++) 56 if (!(*c2 == UChar(u->low(), u->high()))) // reverse byte order 57 goto next; 58 return e->value; 59 } 60 next: 61 #else 62 if ((len == e->len) && (memcmp(c, e->c, len * sizeof(UChar)) == 0)) 63 return e->value; 64 #endif 65 // try next bucket 66 e = e->next; 67 } while (e); 68 69 return -1; 70 } 71 72 int Lookup::find(const struct HashTable *table, const UString &s) 73 { 74 return find(table, s.data(), s.size()); 75 } 76 77 int Lookup::find(const struct HashTable2 *table, 78 const UChar *c, unsigned int len) 34 const HashEntry* Lookup::findEntry( const struct HashTable *table, 35 const UChar *c, unsigned int len ) 79 36 { 80 37 if (table->type != 2) { 81 fprintf(stderr, " Unknown hash table version.\n");82 return -1;38 fprintf(stderr, "KJS: Unknown hash table version.\n"); 39 return 0; 83 40 } 84 85 41 char *ascii = new char[len+1]; 86 42 unsigned int i; … … 94 50 95 51 int h = hash(ascii) % table->hashSize; 96 const HashEntry 2*e = &table->entries[h];52 const HashEntry *e = &table->entries[h]; 97 53 98 54 // empty bucket ? 99 55 if (!e->s) { 100 56 delete [] ascii; 101 return -1;57 return 0; 102 58 } 103 59 … … 106 62 if (strcmp(ascii, e->s) == 0) { 107 63 delete [] ascii; 108 return e ->value;64 return e; 109 65 } 110 66 // try next bucket … … 113 69 114 70 delete [] ascii; 71 return 0; 72 } 73 74 const HashEntry* Lookup::findEntry( const struct HashTable *table, 75 const UString &s ) 76 { 77 return findEntry( table, s.data(), s.size() ); 78 } 79 80 int Lookup::find(const struct HashTable *table, 81 const UChar *c, unsigned int len) 82 { 83 const HashEntry *entry = findEntry( table, c, len ); 84 if (entry) 85 return entry->value; 115 86 return -1; 116 87 } 117 88 118 int Lookup::find(const struct HashTable 2*table, const UString &s)89 int Lookup::find(const struct HashTable *table, const UString &s) 119 90 { 120 91 return find(table, s.data(), s.size()); -
trunk/JavaScriptCore/kjs/lookup.h
r6 r798 1 // -*- c-basic-offset: 2 -*- 1 2 /* 2 3 * This file is part of the KDE libraries … … 16 17 * License along with this library; if not, write to the Free Software 17 18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 * 20 * $Id$ 18 21 */ 19 22 … … 22 25 23 26 #include "ustring.h" 27 #include "value.h" 28 #include <stdio.h> 24 29 25 30 namespace KJS { 26 31 27 #if 1 // obsolete version 1 32 /** 33 * An entry in a hash table. 34 */ 28 35 struct HashEntry { 29 unsigned int len; 30 const void *c; // unicode data 36 /** s is the key (e.g. a property name) */ 37 const char *s; 38 /** value is the result value (usually an enum value) */ 31 39 int value; 40 /** attr is a set for flags (e.g. the property flags, see object.h) */ 41 short int attr; 42 /** params is another number. For property hashtables, it is used to 43 denote the number of argument of the function */ 44 short int params; 45 /** next is the pointer to the next entry for the same hash value */ 32 46 const HashEntry *next; 33 47 }; 34 48 49 /** 50 * A hash table 51 * Usually the hashtable is generated by the create_hash_table script, from a .table file. 52 * 53 * The implementation uses an array of entries, "size" is the total size of that array. 54 * The entries between 0 and hashSize-1 are the entry points 55 * for each hash value, and the entries between hashSize and size-1 56 * are the overflow entries for the hash values that need one. 57 * The "next" pointer of the entry links entry points to overflow entries, 58 * and links overflow entries between them. 59 */ 35 60 struct HashTable { 61 /** type is a version number. Currently always 2 */ 36 62 int type; 63 /** size is the total number of entries in the hashtable, including the null entries, 64 * i.e. the size of the "entries" array. 65 * Used to iterate over all entries in the table */ 37 66 int size; 67 /** pointer to the array of entries 68 * Mind that some entries in the array are null (0,0,0,0). */ 38 69 const HashEntry *entries; 39 int hashSize; 40 }; 41 #endif 42 43 // version 2 44 struct HashEntry2 { 45 const char *s; 46 int value; 47 int attr; 48 const HashEntry2 *next; 49 }; 50 51 struct HashTable2 { 52 int type; 53 int size; 54 const HashEntry2 *entries; 70 /** the maximum value for the hash. Always smaller than size. */ 55 71 int hashSize; 56 72 }; … … 61 77 class Lookup { 62 78 public: 63 #if 1 // obsolete 79 /** Find an entry in the table, and return its value (i.e. the value field of HashEntry) */ 64 80 static int find(const struct HashTable *table, const UString &s); 65 81 static int find(const struct HashTable *table, 66 82 const UChar *c, unsigned int len); 83 84 /** 85 * Find an entry in the table, and return the entry 86 * This variant gives access to the other attributes of the entry, 87 * especially the attr field. 88 */ 89 static const HashEntry* findEntry(const struct HashTable *table, 90 const UString &s); 91 static const HashEntry* findEntry(const struct HashTable *table, 92 const UChar *c, unsigned int len); 93 94 /** Calculate the hash value for a given key */ 95 static unsigned int hash(const UString &key); 96 static unsigned int hash(const UChar *c, unsigned int len); 97 static unsigned int hash(const char *s); 98 }; 99 100 class ExecState; 101 class UString; 102 /** @internal 103 * Helper for lookupFunction and lookupValueOrFunction */ 104 template <class FuncImp> 105 inline Value lookupOrCreateFunction(ExecState *exec, const UString &propertyName, 106 const ObjectImp *thisObj, int token, int params, int attr) 107 { 108 // Look for cached value in dynamic map of properties (in ObjectImp) 109 ValueImp * cachedVal = thisObj->ObjectImp::getDirect(propertyName); 110 /*if (cachedVal) 111 fprintf(stderr, "lookupOrCreateFunction: Function -> looked up in ObjectImp, found type=%d\n", cachedVal->type());*/ 112 if (cachedVal) 113 return Value(cachedVal); 114 115 Value val = Value(new FuncImp(exec,token, params)); 116 ObjectImp *thatObj = const_cast<ObjectImp *>(thisObj); 117 thatObj->ObjectImp::put(exec, propertyName, val, attr); 118 return val; 119 } 120 121 /** 122 * Helper method for property lookups 123 * 124 * This method does it all (looking in the hashtable, checking for function 125 * overrides, creating the function or retrieving from cache, calling 126 * getValueProperty in case of a non-function property, forwarding to parent if 127 * unknown property). 128 * 129 * Template arguments: 130 * @param FuncImp the class which implements this object's functions 131 * @param ThisImp the class of "this". It must implement the getValueProperty(exec,token) method, 132 * for non-function properties. 133 * @param ParentImp the class of the parent, to propagate the lookup. 134 * 135 * Method arguments: 136 * @param exec execution state, as usual 137 * @param propertyName the property we're looking for 138 * @param table the static hashtable for this class 139 * @param thisObj "this" 140 */ 141 template <class FuncImp, class ThisImp, class ParentImp> 142 inline Value lookupGet(ExecState *exec, const UString &propertyName, 143 const HashTable* table, const ThisImp* thisObj) 144 { 145 const HashEntry* entry = Lookup::findEntry(table, propertyName); 146 147 if (!entry) // not found, forward to parent 148 return thisObj->ParentImp::get(exec, propertyName); 149 150 //fprintf(stderr, "lookupGet: found value=%d attr=%d\n", entry->value, entry->attr); 151 if (entry->attr & Function) 152 return lookupOrCreateFunction<FuncImp>(exec, propertyName, thisObj, entry->value, entry->params, entry->attr); 153 return thisObj->getValueProperty(exec, entry->value); 154 } 155 156 /** 157 * Simplified version of lookupGet in case there are only functions. 158 * Using this instead of lookupGet prevents 'this' from implementing a dummy getValueProperty. 159 */ 160 template <class FuncImp, class ParentImp> 161 inline Value lookupGetFunction(ExecState *exec, const UString &propertyName, 162 const HashTable* table, const ObjectImp* thisObj) 163 { 164 const HashEntry* entry = Lookup::findEntry(table, propertyName); 165 166 if (!entry) // not found, forward to parent 167 return static_cast<const ParentImp *>(thisObj)->ParentImp::get(exec, propertyName); 168 169 if (entry->attr & Function) 170 return lookupOrCreateFunction<FuncImp>(exec, propertyName, thisObj, entry->value, entry->params, entry->attr); 171 172 fprintf(stderr, "Function bit not set! Shouldn't happen in lookupGetFunction!\n" ); 173 return Undefined(); 174 }; 175 176 /** 177 * Simplified version of lookupGet in case there are no functions, only "values". 178 * Using this instead of lookupGet removes the need for a FuncImp class. 179 */ 180 template <class ThisImp, class ParentImp> 181 inline Value lookupGetValue(ExecState *exec, const UString &propertyName, 182 const HashTable* table, const ThisImp* thisObj) 183 { 184 const HashEntry* entry = Lookup::findEntry(table, propertyName); 185 186 if (!entry) // not found, forward to parent 187 return thisObj->ParentImp::get(exec, propertyName); 188 189 if (entry->attr & Function) 190 fprintf(stderr, "Function bit set! Shouldn't happen in lookupGetValue! propertyName was %s\n", propertyName.ascii() ); 191 return thisObj->getValueProperty(exec, entry->value); 192 } 193 194 /** 195 * This one is for "put". 196 * Lookup hash entry for property to be set, and set the value. 197 */ 198 template <class ThisImp, class ParentImp> 199 inline void lookupPut(ExecState *exec, const UString &propertyName, 200 const Value& value, int attr, 201 const HashTable* table, const ThisImp* thisObj) 202 { 203 const HashEntry* entry = Lookup::findEntry(table, propertyName); 204 205 if (!entry) // not found: forward to parent 206 thisObj->ParentImp::put(exec, propertyName, value, attr); 207 else if (entry->attr & Function) // function: put as override property 208 thisObj->ObjectImp::put(exec, propertyName, value, attr); 209 else if (entry->attr & ReadOnly) // readonly! Can't put! 210 #ifdef KJS_VERBOSE 211 fprintf(stderr,"WARNING: Attempt to change value of readonly property '%s'\n",propertyName.ascii()); 212 #else 213 ; // do nothing 67 214 #endif 68 static int find(const struct HashTable2 *table, const UString &s); 69 static int find(const struct HashTable2 *table, 70 const UChar *c, unsigned int len); 71 static unsigned int hash(const UChar *c, unsigned int len); 72 static unsigned int hash(const UString &key); 73 static unsigned int hash(const char *s); 74 private: 75 HashTable *table; 76 }; 77 215 else 216 thisObj->putValueProperty(exec, entry->value, value, attr); 217 } 218 219 /* 220 * List of things to do when porting an objectimp to the 'static hashtable' mechanism: 221 * - write the hashtable source, between @begin and @end 222 * - add a rule to build the .lut.h 223 * - include the .lut.h 224 * - mention the table in the classinfo (add a classinfo if necessary) 225 * - write/update the class enum (for the tokens) 226 * - turn get() into getValueProperty(), put() into putValueProperty(), using a switch and removing funcs 227 * - write get() and/or put() using a template method 228 * - cleanup old stuff (e.g. hasProperty) 229 * - compile, test, commit ;) 230 */ 78 231 }; // namespace 79 232 -
trunk/JavaScriptCore/kjs/math_object.cpp
r6 r798 1 // -*- c-basic-offset: 2 -*- 1 2 /* 2 3 * This file is part of the KDE libraries … … 16 17 * License along with this library; if not, write to the Free Software 17 18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 * 20 * $Id$ 18 21 */ 19 22 20 23 #include <math.h> 21 24 #include <stdlib.h> 22 23 #include "kjs.h" 25 #include <stdio.h> 26 #include <assert.h> 27 28 #include "value.h" 29 #include "object.h" 24 30 #include "types.h" 31 #include "interpreter.h" 25 32 #include "operations.h" 26 33 #include "math_object.h" 27 #include "lookup.h"28 34 29 35 #include "math_object.lut.h" … … 31 37 using namespace KJS; 32 38 33 KJSO Math::get(const UString &p) const 34 { 35 int token = Lookup::find(&mathTable, p); 36 37 if (token < 0) 38 return Imp::get(p); 39 40 double d; 41 int len = 1; 39 // ------------------------------ MathObjectImp -------------------------------- 40 41 const ClassInfo MathObjectImp::info = { "Math", 0, &mathTable, 0 }; 42 43 /* Source for math_object.lut.h 44 @begin mathTable 21 45 E MathObjectImp::Euler DontEnum 46 LN2 MathObjectImp::Ln2 DontEnum 47 LN10 MathObjectImp::Ln10 DontEnum 48 LOG2E MathObjectImp::Log2E DontEnum 49 LOG10E MathObjectImp::Log10E DontEnum 50 PI MathObjectImp::Pi DontEnum 51 SQRT1_2 MathObjectImp::Sqrt1_2 DontEnum 52 SQRT2 MathObjectImp::Sqrt2 DontEnum 53 abs MathObjectImp::Abs DontEnum|Function 1 54 acos MathObjectImp::ACos DontEnum|Function 1 55 asin MathObjectImp::ASin DontEnum|Function 1 56 atan MathObjectImp::ATan DontEnum|Function 1 57 atan2 MathObjectImp::ATan2 DontEnum|Function 2 58 ceil MathObjectImp::Ceil DontEnum|Function 1 59 cos MathObjectImp::Cos DontEnum|Function 1 60 exp MathObjectImp::Exp DontEnum|Function 1 61 floor MathObjectImp::Floor DontEnum|Function 1 62 log MathObjectImp::Log DontEnum|Function 1 63 max MathObjectImp::Max DontEnum|Function 2 64 min MathObjectImp::Min DontEnum|Function 2 65 pow MathObjectImp::Pow DontEnum|Function 2 66 random MathObjectImp::Random DontEnum|Function 0 67 round MathObjectImp::Round DontEnum|Function 1 68 sin MathObjectImp::Sin DontEnum|Function 1 69 sqrt MathObjectImp::Sqrt DontEnum|Function 1 70 tan MathObjectImp::Tan DontEnum|Function 1 71 @end 72 */ 73 74 MathObjectImp::MathObjectImp(ExecState * /*exec*/, 75 ObjectPrototypeImp *objProto) 76 : ObjectImp(Object(objProto)) 77 { 78 } 79 80 // ECMA 15.8 81 Value MathObjectImp::get(ExecState *exec, const UString &propertyName) const 82 { 83 return lookupGet<MathFuncImp, MathObjectImp, ObjectImp>( exec, propertyName, &mathTable, this ); 84 } 85 86 Value MathObjectImp::getValueProperty(ExecState *, int token) const 87 { 88 double d = -42; // ;) 42 89 switch (token) { 43 case Math::Euler:90 case Euler: 44 91 d = exp(1.0); 45 92 break; 46 case Math::Ln2:93 case Ln2: 47 94 d = log(2.0); 48 95 break; 49 case Math::Ln10:96 case Ln10: 50 97 d = log(10.0); 51 98 break; 52 case Math::Log2E:99 case Log2E: 53 100 d = 1.0/log(2.0); 54 101 break; 55 case Math::Log10E:102 case Log10E: 56 103 d = 1.0/log(10.0); 57 104 break; 58 case Math::Pi:105 case Pi: 59 106 d = 2.0 * asin(1.0); 60 107 break; 61 case Math::Sqrt1_2:108 case Sqrt1_2: 62 109 d = sqrt(0.5); 63 110 break; 64 case Math::Sqrt2:111 case Sqrt2: 65 112 d = sqrt(2.0); 66 113 break; 67 114 default: 68 if (token == Math::Min || token == Math::Max || token == Math::Pow) 69 len = 2; 70 return Function(new MathFunc(token, len)); 71 }; 115 fprintf( stderr, "Internal error in MathObjectImp: unhandled token %d\n", token ); 116 break; 117 } 72 118 73 119 return Number(d); 74 120 } 75 121 76 bool Math::hasProperty(const UString &p, bool recursive) const 77 { 78 return (Lookup::find(&mathTable, p) >= 0 || 79 (recursive && Imp::hasProperty(p, recursive))); 80 } 81 82 Completion MathFunc::execute(const List &args) 83 { 84 KJSO v = args[0]; 85 Number n = v.toNumber(); 122 // ------------------------------ MathObjectImp -------------------------------- 123 124 MathFuncImp::MathFuncImp(ExecState *exec, int i, int l) 125 : InternalFunctionImp( 126 static_cast<FunctionPrototypeImp*>(exec->interpreter()->builtinFunctionPrototype().imp()) 127 ), id(i) 128 { 129 Value protect(this); 130 put(exec,"length",Number(l),DontDelete|ReadOnly|DontEnum); 131 } 132 133 bool MathFuncImp::implementsCall() const 134 { 135 return true; 136 } 137 138 Value MathFuncImp::call(ExecState *exec, Object &/*thisObj*/, const List &args) 139 { 140 Value v = args[0]; 141 Number n = v.toNumber(exec); 86 142 double arg = n.value(); 87 143 88 KJSOv2 = args[1];89 Number n2 = v2.toNumber( );144 Value v2 = args[1]; 145 Number n2 = v2.toNumber(exec); 90 146 double arg2 = n2.value(); 91 147 double result; 92 148 93 149 switch (id) { 94 case Math ::Abs:95 result = ( arg < 0 ) ? (-arg) : arg;96 break; 97 case Math ::ACos:150 case MathObjectImp::Abs: 151 result = ( arg < 0 || arg == -0) ? (-arg) : arg; 152 break; 153 case MathObjectImp::ACos: 98 154 result = ::acos(arg); 99 155 break; 100 case Math ::ASin:156 case MathObjectImp::ASin: 101 157 result = ::asin(arg); 102 158 break; 103 case Math ::ATan:159 case MathObjectImp::ATan: 104 160 result = ::atan(arg); 105 161 break; 106 case Math ::ATan2:162 case MathObjectImp::ATan2: 107 163 result = ::atan2(arg, arg2); 108 164 break; 109 case Math ::Ceil:165 case MathObjectImp::Ceil: 110 166 result = ::ceil(arg); 111 167 break; 112 case Math ::Cos:168 case MathObjectImp::Cos: 113 169 result = ::cos(arg); 114 170 break; 115 case Math ::Exp:171 case MathObjectImp::Exp: 116 172 result = ::exp(arg); 117 173 break; 118 case Math ::Floor:174 case MathObjectImp::Floor: 119 175 result = ::floor(arg); 120 176 break; 121 case Math ::Log:177 case MathObjectImp::Log: 122 178 result = ::log(arg); 123 179 break; 124 case Math::Max: 125 result = ( arg > arg2 ) ? arg : arg2; 126 break; 127 case Math::Min: 128 result = ( arg < arg2 ) ? arg : arg2; 129 break; 130 case Math::Pow: 131 result = ::pow(arg, arg2); 132 break; 133 case Math::Random: 180 case MathObjectImp::Max: { 181 unsigned int argsCount = args.size(); 182 result = -Inf; 183 for ( unsigned int k = 0 ; k < argsCount ; ++k ) { 184 double val = args[k].toNumber(exec); 185 if ( isNaN( val ) ) 186 { 187 result = NaN; 188 break; 189 } 190 if ( val > result ) 191 result = val; 192 } 193 break; 194 } 195 case MathObjectImp::Min: { 196 unsigned int argsCount = args.size(); 197 result = +Inf; 198 for ( unsigned int k = 0 ; k < argsCount ; ++k ) { 199 double val = args[k].toNumber(exec); 200 if ( isNaN( val ) ) 201 { 202 result = NaN; 203 break; 204 } 205 if ( val < result ) 206 result = val; 207 } 208 break; 209 } 210 case MathObjectImp::Pow: 211 // ECMA 15.8.2.1.13 (::pow takes care of most of the critera) 212 if (KJS::isNaN(arg2)) 213 result = NaN; 214 else if (arg2 == 0) 215 result = 1; 216 else if (KJS::isNaN(arg) && arg2 != 0) 217 result = NaN; 218 else if (::fabs(arg) > 1 && KJS::isPosInf(arg2)) 219 result = Inf; 220 else if (::fabs(arg) > 1 && KJS::isNegInf(arg2)) 221 result = +0; 222 else if (::fabs(arg) == 1 && KJS::isPosInf(arg2)) 223 result = NaN; 224 else if (::fabs(arg) == 1 && KJS::isNegInf(arg2)) 225 result = NaN; 226 else if (::fabs(arg) < 1 && KJS::isPosInf(arg2)) 227 result = +0; 228 else if (::fabs(arg) < 1 && KJS::isNegInf(arg2)) 229 result = Inf; 230 else 231 result = ::pow(arg, arg2); 232 break; 233 case MathObjectImp::Random: 134 234 result = ::rand(); 135 235 result = result / RAND_MAX; 136 236 break; 137 case Math ::Round:237 case MathObjectImp::Round: 138 238 if (isNaN(arg)) 139 239 result = arg; … … 145 245 result = (double)(arg >= 0.0 ? int(arg + 0.5) : int(arg - 0.5)); 146 246 break; 147 case Math ::Sin:247 case MathObjectImp::Sin: 148 248 result = ::sin(arg); 149 249 break; 150 case Math ::Sqrt:250 case MathObjectImp::Sqrt: 151 251 result = ::sqrt(arg); 152 252 break; 153 case Math ::Tan:253 case MathObjectImp::Tan: 154 254 result = ::tan(arg); 155 255 break; … … 160 260 } 161 261 162 return Completion(ReturnValue, Number(result));163 } 262 return Number(result); 263 } -
trunk/JavaScriptCore/kjs/math_object.h
r6 r798 1 // -*- c-basic-offset: 2 -*- 1 2 /* 2 3 * This file is part of the KDE libraries … … 16 17 * License along with this library; if not, write to the Free Software 17 18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 * 20 * $Id$ 18 21 */ 19 22 … … 21 24 #define _MATH_OBJECT_H_ 22 25 23 #include " object.h"24 #include "function .h"26 #include "internal.h" 27 #include "function_object.h" 25 28 26 29 namespace KJS { 27 30 28 class Math : public ObjectImp {31 class MathObjectImp : public ObjectImp { 29 32 public: 30 Math() : ObjectImp(BooleanClass) { } 31 virtual KJSO get(const UString &p) const; 32 virtual bool hasProperty(const UString &p, bool recursive = true) const; 33 MathObjectImp(ExecState *exec, 34 ObjectPrototypeImp *objProto); 35 Value get(ExecState *exec, const UString &p) const; 36 Value getValueProperty(ExecState *exec, int token) const; 37 virtual const ClassInfo *classInfo() const { return &info; } 38 static const ClassInfo info; 33 39 enum { Euler, Ln2, Ln10, Log2E, Log10E, Pi, Sqrt1_2, Sqrt2, 34 35 40 Abs, ACos, ASin, ATan, ATan2, Ceil, Cos, Pow, 41 Exp, Floor, Log, Max, Min, Random, Round, Sin, Sqrt, Tan }; 36 42 }; 37 43 38 class MathFunc : public InternalFunctionImp {44 class MathFuncImp : public InternalFunctionImp { 39 45 public: 40 MathFunc(int i, int l) : InternalFunctionImp(l), id(i) { } 41 Completion execute(const List &); 46 MathFuncImp(ExecState *exec, int i, int l); 47 virtual bool implementsCall() const; 48 virtual Value call(ExecState *exec, Object &thisObj, const List &args); 42 49 private: 43 50 int id; -
trunk/JavaScriptCore/kjs/math_object.lut.h
r6 r798 1 /* automatically generated from math.table. DO NOT EDIT ! */ 1 /* Automatically generated from math_object.cpp using ./create_hash_table. DO NOT EDIT ! */ 2 3 #include "lookup.h" 2 4 3 5 namespace KJS { 4 6 5 const struct HashEntry2 mathTableEntries[] = { 6 { "atan", Math::ATan, DontEnum|ReadOnly, &mathTableEntries[25] }, 7 { 0, 0, 0, 0 }, 8 { "SQRT2", Math::Sqrt2, DontEnum|ReadOnly, &mathTableEntries[23] }, 9 { 0, 0, 0, 0 }, 10 { 0, 0, 0, 0 }, 11 { 0, 0, 0, 0 }, 12 { "E", Math::Euler, DontEnum|ReadOnly, &mathTableEntries[21] }, 13 { "asin", Math::ASin, DontEnum|ReadOnly, &mathTableEntries[26] }, 14 { "atan2", Math::ATan2, DontEnum|ReadOnly, &mathTableEntries[31] }, 15 { "LOG2E", Math::Log2E, DontEnum|ReadOnly, &mathTableEntries[27] }, 16 { "cos", Math::Cos, DontEnum|ReadOnly, 0 }, 17 { "max", Math::Max, DontEnum|ReadOnly, &mathTableEntries[28] }, 18 { 0, 0, 0, 0 }, 19 { 0, 0, 0, 0 }, 20 { "LOG10E", Math::Log10E, DontEnum|ReadOnly, &mathTableEntries[24] }, 21 { "LN2", Math::Ln2, DontEnum|ReadOnly, &mathTableEntries[30] }, 22 { "abs", Math::Abs, DontEnum|ReadOnly, 0 }, 23 { "sqrt", Math::Sqrt, DontEnum|ReadOnly, 0 }, 24 { "exp", Math::Exp, DontEnum|ReadOnly, 0 }, 25 { 0, 0, 0, 0 }, 26 { "LN10", Math::Ln10, DontEnum|ReadOnly, &mathTableEntries[22] }, 27 { "PI", Math::Pi, DontEnum|ReadOnly, &mathTableEntries[29] }, 28 { "SQRT1_2", Math::Sqrt1_2, DontEnum|ReadOnly, 0 }, 29 { "acos", Math::ACos, DontEnum|ReadOnly, 0 }, 30 { "ceil", Math::Ceil, DontEnum|ReadOnly, 0 }, 31 { "floor", Math::Floor, DontEnum|ReadOnly, 0 }, 32 { "log", Math::Log, DontEnum|ReadOnly, 0 }, 33 { "min", Math::Min, DontEnum|ReadOnly, 0 }, 34 { "random", Math::Random, DontEnum|ReadOnly, 0 }, 35 { "round", Math::Round, DontEnum|ReadOnly, 0 }, 36 { "sin", Math::Sin, DontEnum|ReadOnly, 0 }, 37 { "tan", Math::Tan, DontEnum|ReadOnly, 0 } 7 const struct HashEntry mathTableEntries[] = { 8 { "atan", MathObjectImp::ATan, DontEnum|Function, 1, &mathTableEntries[25] }, 9 { 0, 0, 0, 0, 0 }, 10 { "SQRT2", MathObjectImp::Sqrt2, DontEnum, 0, &mathTableEntries[23] }, 11 { 0, 0, 0, 0, 0 }, 12 { 0, 0, 0, 0, 0 }, 13 { 0, 0, 0, 0, 0 }, 14 { "E", MathObjectImp::Euler, DontEnum, 0, &mathTableEntries[21] }, 15 { "asin", MathObjectImp::ASin, DontEnum|Function, 1, &mathTableEntries[26] }, 16 { "atan2", MathObjectImp::ATan2, DontEnum|Function, 2, &mathTableEntries[32] }, 17 { "LOG2E", MathObjectImp::Log2E, DontEnum, 0, &mathTableEntries[27] }, 18 { "cos", MathObjectImp::Cos, DontEnum|Function, 1, 0 }, 19 { "max", MathObjectImp::Max, DontEnum|Function, 2, &mathTableEntries[29] }, 20 { 0, 0, 0, 0, 0 }, 21 { 0, 0, 0, 0, 0 }, 22 { "LOG10E", MathObjectImp::Log10E, DontEnum, 0, &mathTableEntries[24] }, 23 { "LN2", MathObjectImp::Ln2, DontEnum, 0, &mathTableEntries[31] }, 24 { "abs", MathObjectImp::Abs, DontEnum|Function, 1, 0 }, 25 { "sqrt", MathObjectImp::Sqrt, DontEnum|Function, 1, 0 }, 26 { "exp", MathObjectImp::Exp, DontEnum|Function, 1, 0 }, 27 { 0, 0, 0, 0, 0 }, 28 { "LN10", MathObjectImp::Ln10, DontEnum, 0, &mathTableEntries[22] }, 29 { "PI", MathObjectImp::Pi, DontEnum, 0, &mathTableEntries[28] }, 30 { "SQRT1_2", MathObjectImp::Sqrt1_2, DontEnum, 0, 0 }, 31 { "acos", MathObjectImp::ACos, DontEnum|Function, 1, 0 }, 32 { "ceil", MathObjectImp::Ceil, DontEnum|Function, 1, 0 }, 33 { "floor", MathObjectImp::Floor, DontEnum|Function, 1, 0 }, 34 { "log", MathObjectImp::Log, DontEnum|Function, 1, 0 }, 35 { "min", MathObjectImp::Min, DontEnum|Function, 2, 0 }, 36 { "pow", MathObjectImp::Pow, DontEnum|Function, 2, &mathTableEntries[30] }, 37 { "random", MathObjectImp::Random, DontEnum|Function, 0, 0 }, 38 { "round", MathObjectImp::Round, DontEnum|Function, 1, 0 }, 39 { "sin", MathObjectImp::Sin, DontEnum|Function, 1, 0 }, 40 { "tan", MathObjectImp::Tan, DontEnum|Function, 1, 0 } 38 41 }; 39 42 40 const struct HashTable 2 mathTable = { 2, 32, mathTableEntries, 21 };43 const struct HashTable mathTable = { 2, 33, mathTableEntries, 21 }; 41 44 42 45 }; // namespace -
trunk/JavaScriptCore/kjs/nodes.cpp
r6 r798 1 // -*- c-basic-offset: 2 -*- 1 2 /* 2 3 * This file is part of the KDE libraries 3 4 * Copyright (C) 1999-2001 Harri Porten ([email protected]) 5 * Copyright (C) 2001 Peter Kelly ([email protected]) 4 6 * 5 7 * This library is free software; you can redistribute it and/or … … 17 19 * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, 18 20 * Boston, MA 02111-1307, USA. 21 * 19 22 */ 20 23 … … 22 25 23 26 #include <assert.h> 27 #include <iostream.h> 28 #include <math.h> 24 29 #include <stdio.h> 25 #include <math.h> 26 27 #include "kjs.h" 30 #ifdef KJS_DEBUG_MEM 31 #include <typeinfo> 32 #endif 33 34 #include "collector.h" 35 #include "debugger.h" 36 #include "function_object.h" 37 #include "internal.h" 38 #include "value.h" 39 #include "object.h" 40 #include "types.h" 41 #include "interpreter.h" 42 #include "lexer.h" 43 #include "operations.h" 28 44 #include "ustring.h" 29 #include "lexer.h"30 #include "types.h"31 #include "internal.h"32 #include "operations.h"33 #include "regexp_object.h"34 #include "debugger.h"35 45 36 46 using namespace KJS; 37 47 38 #ifdef KJS_DEBUGGER 39 #define KJS_BREAKPOINT if (!hitStatement()) return Completion(Normal); 40 #define KJS_ABORTPOINT if (abortStatement()) return Completion(Normal); 41 #else 42 #define KJS_BREAKPOINT 43 #define KJS_ABORTPOINT 48 #define KJS_BREAKPOINT \ 49 if (!hitStatement(exec)) \ 50 return Completion(Normal); 51 52 #define KJS_ABORTPOINT \ 53 if (exec->interpreter()->imp()->debugger() && \ 54 exec->interpreter()->imp()->debugger()->imp()->aborted()) \ 55 return Completion(Normal); 56 57 #define KJS_CHECKEXCEPTION \ 58 if (exec->hadException()) \ 59 return Completion(Throw, exec->exception()); \ 60 if (Collector::outOfMemory()) \ 61 return Completion(Throw, Error::create(exec,GeneralError,"Out of memory")); 62 63 #define KJS_CHECKEXCEPTIONVALUE \ 64 if (exec->hadException()) \ 65 return exec->exception(); \ 66 if (Collector::outOfMemory()) \ 67 return Undefined(); // will be picked up by KJS_CHECKEXCEPTION 68 69 #define KJS_CHECKEXCEPTIONLIST \ 70 if (exec->hadException()) \ 71 return List(); \ 72 if (Collector::outOfMemory()) \ 73 return List(); // will be picked up by KJS_CHECKEXCEPTION 74 75 #ifdef KJS_DEBUG_MEM 76 std::list<Node *> Node::s_nodes; 44 77 #endif 45 46 int Node::nodeCount = 0; 47 Node* Node::first = 0; 78 // ------------------------------ Node ----------------------------------------- 48 79 49 80 Node::Node() 50 81 { 51 assert(Lexer::curr());52 82 line = Lexer::curr()->lineNo(); 53 nodeCount++; 54 // cout << "Node()" << endl; 55 56 // create a list of allocated objects. Makes 57 // deleting (even after a parse error) quite easy 58 next = first; 59 prev = 0L; 60 if (first) 61 first->prev = this; 62 first = this; 83 refcount = 0; 84 #ifdef KJS_DEBUG_MEM 85 s_nodes.push_back( this ); 86 #endif 63 87 } 64 88 65 89 Node::~Node() 66 90 { 67 // cout << "~Node()" << endl; 68 if (next) 69 next->prev = prev; 70 if (prev) 71 prev->next = next; 72 nodeCount--; 73 } 74 75 void Node::deleteAllNodes() 76 { 77 Node *tmp, *n = first; 78 79 while ((tmp = n)) { 80 n = n->next; 81 delete tmp; 82 } 83 first = 0L; 84 // assert(nodeCount == 0); 85 } 86 87 KJSO Node::throwError(ErrorType e, const char *msg) 88 { 89 return Error::create(e, msg, lineNo()); 90 } 91 92 #ifdef KJS_DEBUGGER 93 void StatementNode::setLoc(int line0, int line1) 91 #ifdef KJS_DEBUG_MEM 92 s_nodes.remove( this ); 93 #endif 94 } 95 96 #ifdef KJS_DEBUG_MEM 97 void Node::finalCheck() 98 { 99 fprintf( stderr, "Node::finalCheck(): list count : %d\n", s_nodes.size() ); 100 std::list<Node *>::iterator it = s_nodes.begin(); 101 for ( uint i = 0; it != s_nodes.end() ; ++it, ++i ) 102 fprintf( stderr, "[%d] Still having node %p (%s) (refcount %d)\n", i, (void*)*it, typeid( **it ).name(), (*it)->refcount ); 103 } 104 #endif 105 106 Value Node::throwError(ExecState *exec, ErrorType e, const char *msg) 107 { 108 Object err = Error::create(exec, e, msg, lineNo(), sourceId()); 109 exec->setException(err); 110 return err; 111 } 112 113 // ------------------------------ StatementNode -------------------------------- 114 StatementNode::StatementNode() : l0(-1), l1(-1), sid(-1), breakPoint(false) 115 { 116 } 117 118 StatementNode::~StatementNode() 119 { 120 } 121 122 void StatementNode::setLoc(int line0, int line1, int sourceId) 94 123 { 95 124 l0 = line0; 96 125 l1 = line1; 97 sid = KJScriptImp::current()->sourceId(); 98 } 99 100 bool StatementNode::hitStatement() 101 { 102 if (KJScriptImp::current()->debugger()) 103 return KJScriptImp::current()->debugger()->hit(firstLine(), breakPoint); 126 sid = sourceId; 127 } 128 129 // return true if the debugger wants us to stop at this point 130 bool StatementNode::hitStatement(ExecState *exec) 131 { 132 Debugger *dbg = exec->interpreter()->imp()->debugger(); 133 if (dbg) 134 return dbg->atStatement(exec,sid,l0,l1); 104 135 else 105 return true; 136 return true; // continue 106 137 } 107 138 108 139 // return true if the debugger wants us to stop at this point 109 bool StatementNode::abortStatement() 110 { 111 if (KJScriptImp::current()->debugger() && 112 KJScriptImp::current()->debugger()->mode() == Debugger::Stop) 113 return true; 114 115 return false; 116 } 117 118 bool Node::setBreakpoint(Node *firstNode, int id, int line, bool set) 119 { 120 while (firstNode) { 121 if (firstNode->setBreakpoint(id, line, set) && line >= 0) // line<0 for all 122 return true; 123 firstNode = firstNode->next; 124 } 125 return false; 126 } 127 128 /** 129 * Try to set or delete a breakpoint depending on the value of set. 130 * The call will return true if successful, i.e. if line is inside 131 * of the statement's range. Additionally, a breakpoint had to 132 * be set already if you tried to delete with set=false. 133 */ 134 bool StatementNode::setBreakpoint(int id, int line, bool set) 135 { 136 // in our source unit and line range ? 137 if (id != sid || ((line < l0 || line > l1) && line >= 0)) 140 bool StatementNode::abortStatement(ExecState *exec) 141 { 142 Debugger *dbg = exec->interpreter()->imp()->debugger(); 143 if (dbg) 144 return dbg->imp()->aborted(); 145 else 138 146 return false; 139 140 if (!set && !breakPoint) 141 return false; 142 143 breakPoint = set; 144 return true; 145 } 146 #endif 147 148 KJSO NullNode::evaluate() 147 } 148 149 // ------------------------------ NullNode ------------------------------------- 150 151 Value NullNode::evaluate(ExecState */*exec*/) 149 152 { 150 153 return Null(); 151 154 } 152 155 153 KJSO BooleanNode::evaluate() 156 // ------------------------------ BooleanNode ---------------------------------- 157 158 Value BooleanNode::evaluate(ExecState */*exec*/) 154 159 { 155 160 return Boolean(value); 156 161 } 157 162 158 KJSO NumberNode::evaluate() 163 // ------------------------------ NumberNode ----------------------------------- 164 165 Value NumberNode::evaluate(ExecState */*exec*/) 159 166 { 160 167 return Number(value); 161 168 } 162 169 163 KJSO StringNode::evaluate() 170 // ------------------------------ StringNode ----------------------------------- 171 172 Value StringNode::evaluate(ExecState */*exec*/) 164 173 { 165 174 return String(value); 166 175 } 167 176 168 KJSO RegExpNode::evaluate() 177 // ------------------------------ RegExpNode ----------------------------------- 178 179 Value RegExpNode::evaluate(ExecState *exec) 169 180 { 170 181 List list; … … 174 185 list.append(f); 175 186 176 // very ugly177 KJSO r = Global::current().get("RegExp");178 RegExpObject *r2 = (RegExpObject*)r.imp(); 179 return r2->construct(list); 180 } 187 Object reg = exec->interpreter()->imp()->builtinRegExp(); 188 return reg.construct(exec,list); 189 } 190 191 // ------------------------------ ThisNode ------------------------------------- 181 192 182 193 // ECMA 11.1.1 183 KJSO ThisNode::evaluate() 184 { 185 return Context::current()->thisValue(); 186 } 194 Value ThisNode::evaluate(ExecState *exec) 195 { 196 return exec->context().thisValue(); 197 } 198 199 // ------------------------------ ResolveNode ---------------------------------- 187 200 188 201 // ECMA 11.1.2 & 10.1.4 189 KJSO ResolveNode::evaluate() 190 { 191 assert(Context::current()); 192 const List *chain = Context::current()->pScopeChain(); 193 assert(chain); 194 ListIterator scope = chain->begin(); 195 196 while (scope != chain->end()) { 197 if (scope->hasProperty(ident)) { 198 // cout << "Resolve: found '" << ident.ascii() << "'" 199 // << " type " << scope->get(ident).imp()->typeInfo()->name << endl; 200 return Reference(*scope, ident); 202 Value ResolveNode::evaluate(ExecState *exec) 203 { 204 const List chain = exec->context().scopeChain(); 205 ListIterator scope = chain.begin(); 206 207 while (scope != chain.end()) { 208 ObjectImp *o = static_cast<ObjectImp*>((*scope).imp()); 209 210 //cout << "Resolve: looking at '" << ident.ascii() << "'" 211 // << " in " << (void*)o << " " << o->classInfo()->className << endl; 212 if (o->hasProperty(exec,ident)) { 213 //cout << "Resolve: FOUND '" << ident.ascii() << "'" 214 // << " in " << (void*)o << " " << o->classInfo()->className << endl; 215 return Reference(Object(o), ident); 201 216 } 202 217 scope++; … … 204 219 205 220 // identifier not found 206 //cout << "Resolve: didn't find '" << ident.ascii() << "'" << endl;221 //cout << "Resolve: didn't find '" << ident.ascii() << "'" << endl; 207 222 return Reference(Null(), ident); 208 223 } 209 224 225 // ------------------------------ GroupNode ------------------------------------ 226 227 GroupNode::~GroupNode() 228 { 229 } 230 231 void GroupNode::ref() 232 { 233 Node::ref(); 234 if ( group ) 235 group->ref(); 236 } 237 238 bool GroupNode::deref() 239 { 240 if ( group && group->deref() ) 241 delete group; 242 return Node::deref(); 243 } 244 245 // ECMA 11.1.6 246 Value GroupNode::evaluate(ExecState *exec) 247 { 248 return group->evaluate(exec); 249 } 250 251 // ------------------------------ ElisionNode ---------------------------------- 252 253 ElisionNode::~ElisionNode() 254 { 255 } 256 257 void ElisionNode::ref() 258 { 259 Node::ref(); 260 if ( elision ) 261 elision->ref(); 262 } 263 264 bool ElisionNode::deref() 265 { 266 if ( elision && elision->deref() ) 267 delete elision; 268 return Node::deref(); 269 } 270 210 271 // ECMA 11.1.4 211 KJSO ArrayNode::evaluate() 212 { 213 KJSO array; 272 Value ElisionNode::evaluate(ExecState *exec) 273 { 274 if (elision) 275 return Number(elision->evaluate(exec).toNumber(exec) + 1); 276 else 277 return Number(1); 278 } 279 280 // ------------------------------ ElementNode ---------------------------------- 281 282 ElementNode::~ElementNode() 283 { 284 } 285 286 void ElementNode::ref() 287 { 288 Node::ref(); 289 if ( list ) 290 list->ref(); 291 if ( elision ) 292 elision->ref(); 293 if ( node ) 294 node->ref(); 295 } 296 297 bool ElementNode::deref() 298 { 299 if ( list && list->deref() ) 300 delete list; 301 if ( elision && elision->deref() ) 302 delete elision; 303 if ( node && node->deref() ) 304 delete node; 305 return Node::deref(); 306 } 307 308 // ECMA 11.1.4 309 Value ElementNode::evaluate(ExecState *exec) 310 { 311 Object array; 312 Value val; 313 int length = 0; 314 int elisionLen = elision ? elision->evaluate(exec).toInt32(exec) : 0; 315 KJS_CHECKEXCEPTIONVALUE 316 317 if (list) { 318 array = Object(static_cast<ObjectImp*>(list->evaluate(exec).imp())); 319 KJS_CHECKEXCEPTIONVALUE 320 val = node->evaluate(exec).getValue(exec); 321 length = array.get(exec,"length").toInt32(exec); 322 } else { 323 Value newArr = exec->interpreter()->builtinArray().construct(exec,List::empty()); 324 array = Object(static_cast<ObjectImp*>(newArr.imp())); 325 val = node->evaluate(exec).getValue(exec); 326 KJS_CHECKEXCEPTIONVALUE 327 } 328 329 array.put(exec, UString::from(elisionLen + length), val); 330 331 return array; 332 } 333 334 // ------------------------------ ArrayNode ------------------------------------ 335 336 ArrayNode::~ArrayNode() 337 { 338 } 339 340 void ArrayNode::ref() 341 { 342 Node::ref(); 343 if ( element ) 344 element->ref(); 345 if ( elision ) 346 elision->ref(); 347 } 348 349 bool ArrayNode::deref() 350 { 351 if ( element && element->deref() ) 352 delete element; 353 if ( elision && elision->deref() ) 354 delete elision; 355 return Node::deref(); 356 } 357 358 // ECMA 11.1.4 359 Value ArrayNode::evaluate(ExecState *exec) 360 { 361 Object array; 214 362 int length; 215 int elisionLen = elision ? elision->evaluate().toInt32() : 0; 363 int elisionLen = elision ? elision->evaluate(exec).toInt32(exec) : 0; 364 KJS_CHECKEXCEPTIONVALUE 216 365 217 366 if (element) { 218 array = element->evaluate(); 219 length = opt ? array.get("length").toInt32() : 0; 367 array = Object(static_cast<ObjectImp*>(element->evaluate(exec).imp())); 368 KJS_CHECKEXCEPTIONVALUE 369 length = opt ? array.get(exec,"length").toInt32(exec) : 0; 220 370 } else { 221 array = Object::create(ArrayClass); 371 Value newArr = exec->interpreter()->builtinArray().construct(exec,List::empty()); 372 array = Object(static_cast<ObjectImp*>(newArr.imp())); 222 373 length = 0; 223 374 } 224 375 225 376 if (opt) 226 array.put( "length", Number(elisionLen + length), DontEnum | DontDelete);377 array.put(exec,"length", Number(elisionLen + length), DontEnum | DontDelete); 227 378 228 379 return array; 229 380 } 230 381 231 // ECMA 11.1.4 232 KJSO ElementNode::evaluate() 233 { 234 KJSO array, val; 235 int length = 0; 236 int elisionLen = elision ? elision->evaluate().toInt32() : 0; 237 382 // ------------------------------ ObjectLiteralNode ---------------------------- 383 384 ObjectLiteralNode::~ObjectLiteralNode() 385 { 386 } 387 388 void ObjectLiteralNode::ref() 389 { 390 Node::ref(); 391 if ( list ) 392 list->ref(); 393 } 394 395 bool ObjectLiteralNode::deref() 396 { 397 if ( list && list->deref() ) 398 delete list; 399 return Node::deref(); 400 } 401 402 // ECMA 11.1.5 403 Value ObjectLiteralNode::evaluate(ExecState *exec) 404 { 405 if (list) 406 return list->evaluate(exec); 407 408 return exec->interpreter()->builtinObject().construct(exec,List::empty()); 409 } 410 411 // ------------------------------ PropertyValueNode ---------------------------- 412 413 PropertyValueNode::~PropertyValueNode() 414 { 415 } 416 417 void PropertyValueNode::ref() 418 { 419 Node::ref(); 420 if ( name ) 421 name->ref(); 422 if ( assign ) 423 assign->ref(); 424 if ( list ) 425 list->ref(); 426 } 427 428 bool PropertyValueNode::deref() 429 { 430 if ( name && name->deref() ) 431 delete name; 432 if ( assign && assign->deref() ) 433 delete assign; 434 if ( list && list->deref() ) 435 delete list; 436 return Node::deref(); 437 } 438 439 // ECMA 11.1.5 440 Value PropertyValueNode::evaluate(ExecState *exec) 441 { 442 Object obj; 238 443 if (list) { 239 array = list->evaluate(); 240 val = node->evaluate().getValue(); 241 length = array.get("length").toInt32(); 242 } else { 243 array = Object::create(ArrayClass); 244 val = node->evaluate().getValue(); 444 obj = Object(static_cast<ObjectImp*>(list->evaluate(exec).imp())); 445 KJS_CHECKEXCEPTIONVALUE 245 446 } 246 247 array.putArrayElement(UString::from(elisionLen + length), val); 248 249 return array; 250 } 251 252 // ECMA 11.1.4 253 KJSO ElisionNode::evaluate() 254 { 255 if (elision) 256 return Number(elision->evaluate().toNumber().value() + 1); 257 else 258 return Number(1); 259 } 447 else { 448 Value newObj = exec->interpreter()->builtinObject().construct(exec,List::empty()); 449 obj = Object(static_cast<ObjectImp*>(newObj.imp())); 450 } 451 Value n = name->evaluate(exec); 452 KJS_CHECKEXCEPTIONVALUE 453 Value a = assign->evaluate(exec); 454 KJS_CHECKEXCEPTIONVALUE 455 Value v = a.getValue(exec); 456 457 obj.put(exec,n.toString(exec), v); 458 459 return obj; 460 } 461 462 // ------------------------------ PropertyNode --------------------------------- 260 463 261 464 // ECMA 11.1.5 262 KJSO ObjectLiteralNode::evaluate() 263 { 264 if (list) 265 return list->evaluate(); 266 267 return Object::create(ObjectClass); 268 } 269 270 // ECMA 11.1.5 271 KJSO PropertyValueNode::evaluate() 272 { 273 KJSO obj; 274 if (list) 275 obj = list->evaluate(); 276 else 277 obj = Object::create(ObjectClass); 278 KJSO n = name->evaluate(); 279 KJSO a = assign->evaluate(); 280 KJSO v = a.getValue(); 281 282 obj.put(n.toString().value(), v); 283 284 return obj; 285 } 286 287 // ECMA 11.1.5 288 KJSO PropertyNode::evaluate() 289 { 290 KJSO s; 465 Value PropertyNode::evaluate(ExecState */*exec*/) 466 { 467 Value s; 291 468 292 469 if (str.isNull()) { … … 298 475 } 299 476 300 // ECMA 11.1.6 301 KJSO GroupNode::evaluate() 302 { 303 return group->evaluate(); 477 // ------------------------------ AccessorNode1 -------------------------------- 478 479 AccessorNode1::~AccessorNode1() 480 { 481 } 482 483 void AccessorNode1::ref() 484 { 485 Node::ref(); 486 if ( expr1 ) 487 expr1->ref(); 488 if ( expr2 ) 489 expr2->ref(); 490 } 491 492 bool AccessorNode1::deref() 493 { 494 if ( expr1 && expr1->deref() ) 495 delete expr1; 496 if ( expr2 && expr2->deref() ) 497 delete expr2; 498 return Node::deref(); 304 499 } 305 500 306 501 // ECMA 11.2.1a 307 KJSO AccessorNode1::evaluate() 308 { 309 KJSO e1 = expr1->evaluate(); 310 KJSO v1 = e1.getValue(); 311 KJSO e2 = expr2->evaluate(); 312 KJSO v2 = e2.getValue(); 313 Object o = v1.toObject(); 314 String s = v2.toString(); 502 Value AccessorNode1::evaluate(ExecState *exec) 503 { 504 Value e1 = expr1->evaluate(exec); 505 KJS_CHECKEXCEPTIONVALUE 506 Value v1 = e1.getValue(exec); 507 Value e2 = expr2->evaluate(exec); 508 KJS_CHECKEXCEPTIONVALUE 509 Value v2 = e2.getValue(exec); 510 Object o = v1.toObject(exec); 511 String s = v2.toString(exec); 315 512 return Reference(o, s.value()); 316 513 } 317 514 515 // ------------------------------ AccessorNode2 -------------------------------- 516 517 AccessorNode2::~AccessorNode2() 518 { 519 } 520 521 void AccessorNode2::ref() 522 { 523 Node::ref(); 524 if ( expr ) 525 expr->ref(); 526 } 527 528 bool AccessorNode2::deref() 529 { 530 if ( expr && expr->deref() ) 531 delete expr; 532 return Node::deref(); 533 } 534 318 535 // ECMA 11.2.1b 319 KJSO AccessorNode2::evaluate() 320 { 321 KJSO e = expr->evaluate(); 322 KJSO v = e.getValue(); 323 KJSO o = v.toObject(); 536 Value AccessorNode2::evaluate(ExecState *exec) 537 { 538 Value e = expr->evaluate(exec); 539 KJS_CHECKEXCEPTIONVALUE 540 Value v = e.getValue(exec); 541 Object o = v.toObject(exec); 324 542 return Reference(o, ident); 325 543 } 326 544 545 // ------------------------------ ArgumentListNode ----------------------------- 546 547 ArgumentListNode::ArgumentListNode(Node *e) : list(0L), expr(e) 548 { 549 } 550 551 ArgumentListNode::ArgumentListNode(ArgumentListNode *l, Node *e) 552 : list(l), expr(e) 553 { 554 } 555 556 ArgumentListNode::~ArgumentListNode() 557 { 558 } 559 560 void ArgumentListNode::ref() 561 { 562 Node::ref(); 563 if ( expr ) 564 expr->ref(); 565 if ( list ) 566 list->ref(); 567 } 568 569 bool ArgumentListNode::deref() 570 { 571 if ( expr && expr->deref() ) 572 delete expr; 573 if ( list && list->deref() ) 574 delete list; 575 return Node::deref(); 576 } 577 578 Value ArgumentListNode::evaluate(ExecState */*exec*/) 579 { 580 assert(0); 581 return Value(); // dummy, see evaluateList() 582 } 583 584 // ECMA 11.2.4 585 List ArgumentListNode::evaluateList(ExecState *exec) 586 { 587 List l; 588 if (list) { 589 l = list->evaluateList(exec); 590 KJS_CHECKEXCEPTIONLIST 591 } 592 593 Value e = expr->evaluate(exec); 594 KJS_CHECKEXCEPTIONLIST 595 Value v = e.getValue(exec); 596 597 l.append(v); 598 599 return l; 600 } 601 602 // ------------------------------ ArgumentsNode -------------------------------- 603 604 ArgumentsNode::ArgumentsNode(ArgumentListNode *l) : list(l) 605 { 606 } 607 608 ArgumentsNode::~ArgumentsNode() 609 { 610 } 611 612 void ArgumentsNode::ref() 613 { 614 Node::ref(); 615 if ( list ) 616 list->ref(); 617 } 618 619 bool ArgumentsNode::deref() 620 { 621 if ( list && list->deref() ) 622 delete list; 623 return Node::deref(); 624 } 625 626 Value ArgumentsNode::evaluate(ExecState */*exec*/) 627 { 628 assert(0); 629 return Value(); // dummy, see evaluateList() 630 } 631 632 // ECMA 11.2.4 633 List ArgumentsNode::evaluateList(ExecState *exec) 634 { 635 if (!list) 636 return List(); 637 638 return list->evaluateList(exec); 639 } 640 641 // ------------------------------ NewExprNode ---------------------------------- 642 327 643 // ECMA 11.2.2 328 KJSO NewExprNode::evaluate() 329 { 330 KJSO e = expr->evaluate(); 331 KJSO v = e.getValue(); 332 333 List *argList = args ? args->evaluateList() : 0; 334 335 if (!v.isObject()) { 336 delete argList; 337 return throwError(TypeError, "Expression is no object. Cannot be new'ed"); 644 645 NewExprNode::~NewExprNode() 646 { 647 } 648 649 void NewExprNode::ref() 650 { 651 Node::ref(); 652 if ( expr ) 653 expr->ref(); 654 if ( args ) 655 args->ref(); 656 } 657 658 bool NewExprNode::deref() 659 { 660 if ( expr && expr->deref() ) 661 delete expr; 662 if ( args && args->deref() ) 663 delete args; 664 return Node::deref(); 665 } 666 667 Value NewExprNode::evaluate(ExecState *exec) 668 { 669 Value e = expr->evaluate(exec); 670 KJS_CHECKEXCEPTIONVALUE 671 Value v = e.getValue(exec); 672 673 List argList; 674 if (args) { 675 argList = args->evaluateList(exec); 676 KJS_CHECKEXCEPTIONVALUE 338 677 } 339 678 340 Constructor constr = Constructor::dynamicCast(v); 341 if (constr.isNull()) { 342 delete argList; 343 return throwError(TypeError, "Expression is no constructor."); 679 if (v.type() != ObjectType) { 680 return throwError(exec, TypeError, "Expression is no object. Cannot be new'ed"); 344 681 } 345 682 346 if (!argList)347 argList = new List;348 349 KJSO res = constr.construct(*argList);350 351 delete argList;683 Object constr = Object(static_cast<ObjectImp*>(v.imp())); 684 if (!constr.implementsConstruct()) { 685 return throwError(exec, TypeError, "Expression is no constructor."); 686 } 687 688 Value res = constr.construct(exec,argList); 352 689 353 690 return res; 354 691 } 355 692 693 // ------------------------------ FunctionCallNode ----------------------------- 694 695 FunctionCallNode::~FunctionCallNode() 696 { 697 } 698 699 void FunctionCallNode::ref() 700 { 701 Node::ref(); 702 if ( expr ) 703 expr->ref(); 704 if ( args ) 705 args->ref(); 706 } 707 708 bool FunctionCallNode::deref() 709 { 710 if ( expr && expr->deref() ) 711 delete expr; 712 if ( args && args->deref() ) 713 delete args; 714 return Node::deref(); 715 } 716 356 717 // ECMA 11.2.3 357 KJSO FunctionCallNode::evaluate() 358 { 359 KJSO e = expr->evaluate(); 360 361 List *argList = args->evaluateList(); 362 363 KJSO v = e.getValue(); 364 365 if (!v.isObject()) { 718 Value FunctionCallNode::evaluate(ExecState *exec) 719 { 720 Value e = expr->evaluate(exec); 721 KJS_CHECKEXCEPTIONVALUE 722 723 List argList = args->evaluateList(exec); 724 725 KJS_CHECKEXCEPTIONVALUE 726 727 Value v = e.getValue(exec); 728 729 if (v.type() != ObjectType) { 366 730 #ifndef NDEBUG 367 printInfo( "Failed function call attempt on",e);731 printInfo(exec, "WARNING: Failed function call attempt on", e, line); 368 732 #endif 369 delete argList; 370 return throwError(TypeError, "Expression is no object. Cannot be called."); 733 return throwError(exec, TypeError, "Expression is no object. Cannot be called."); 371 734 } 372 735 373 if (!v.implementsCall()) { 736 Object func = Object(static_cast<ObjectImp*>(v.imp())); 737 738 if (!func.implementsCall()) { 374 739 #ifndef NDEBUG 375 printInfo( "Failed function call attempt on",e);740 printInfo(exec, "Failed function call attempt on", e, line); 376 741 #endif 377 delete argList; 378 return throwError(TypeError, "Expression does not allow calls."); 742 return throwError(exec, TypeError, "Expression does not allow calls."); 379 743 } 380 744 381 KJSO o;382 if (e. isA(ReferenceType))383 o = e.getBase();745 Value thisVal; 746 if (e.type() == ReferenceType) 747 thisVal = e.getBase(exec); 384 748 else 385 o = Null(); 386 387 if (o.isA(ActivationType)) 388 o = Null(); 389 390 #ifdef KJS_DEBUGGER 391 steppingInto(true); 392 #endif 393 394 KJSO result = v.executeCall(o, argList); 395 396 #ifdef KJS_DEBUGGER 397 steppingInto(false); 398 #endif 399 400 delete argList; 749 thisVal = Null(); 750 751 if (thisVal.type() == ObjectType && 752 Object::dynamicCast(thisVal).inherits(&ActivationImp::info)) 753 thisVal = Null(); 754 755 if (thisVal.type() != ObjectType) { 756 // ECMA 11.2.3 says that in this situation the this value should be null. 757 // However, section 10.2.3 says that in the case where the value provided 758 // by the caller is null, the global object should be used. It also says 759 // that the section does not apply to interal functions, but for simplicity 760 // of implementation we use the global object anyway here. This guarantees 761 // that in host objects you always get a valid object for this. 762 // thisVal = Null(); 763 thisVal = exec->interpreter()->globalObject(); 764 } 765 766 Object thisObj = Object::dynamicCast(thisVal); 767 Value result = func.call(exec,thisObj, argList); 401 768 402 769 return result; 403 770 } 404 771 405 #ifdef KJS_DEBUGGER 406 void FunctionCallNode::steppingInto(bool in) 407 { 408 Debugger *dbg = KJScriptImp::current()->debugger(); 409 if (!dbg) 410 return; 411 if (in) { 412 // before entering function. Don't step inside if 'Next' is chosen. 413 previousMode = dbg->mode(); 414 if (previousMode == Debugger::Next) 415 dbg->setMode(Debugger::Continue); 416 } else { 417 // restore mode after leaving function 418 dbg->setMode(previousMode); 772 // ------------------------------ PostfixNode ---------------------------------- 773 774 PostfixNode::~PostfixNode() 775 { 776 } 777 778 void PostfixNode::ref() 779 { 780 Node::ref(); 781 if ( expr ) 782 expr->ref(); 783 } 784 785 bool PostfixNode::deref() 786 { 787 if ( expr && expr->deref() ) 788 delete expr; 789 return Node::deref(); 790 } 791 792 // ECMA 11.3 793 Value PostfixNode::evaluate(ExecState *exec) 794 { 795 Value e = expr->evaluate(exec); 796 KJS_CHECKEXCEPTIONVALUE 797 Value v = e.getValue(exec); 798 Number n = v.toNumber(exec); 799 800 double newValue = (oper == OpPlusPlus) ? n.value() + 1 : n.value() - 1; 801 Value n2 = Number(newValue); 802 803 e.putValue(exec,n2); 804 805 return n; 806 } 807 808 // ------------------------------ DeleteNode ----------------------------------- 809 810 DeleteNode::~DeleteNode() 811 { 812 } 813 814 void DeleteNode::ref() 815 { 816 Node::ref(); 817 if ( expr ) 818 expr->ref(); 819 } 820 821 bool DeleteNode::deref() 822 { 823 if ( expr && expr->deref() ) 824 delete expr; 825 return Node::deref(); 826 } 827 828 // ECMA 11.4.1 829 Value DeleteNode::evaluate(ExecState *exec) 830 { 831 Value e = expr->evaluate(exec); 832 KJS_CHECKEXCEPTIONVALUE 833 if (e.type() != ReferenceType) 834 return Boolean(true); 835 Value b = e.getBase(exec); 836 UString n = e.getPropertyName(exec); 837 838 // The spec doesn't mention what to do if the base is null... just return true 839 if (b.type() != ObjectType) { 840 assert(b.type() == NullType); 841 return Boolean(true); 419 842 } 420 } 421 #endif 422 423 KJSO ArgumentsNode::evaluate() 424 { 425 assert(0); 426 return KJSO(); // dummy, see evaluateList() 427 } 428 429 // ECMA 11.2.4 430 List* ArgumentsNode::evaluateList() 431 { 432 if (!list) 433 return new List(); 434 435 return list->evaluateList(); 436 } 437 438 KJSO ArgumentListNode::evaluate() 439 { 440 assert(0); 441 return KJSO(); // dummy, see evaluateList() 442 } 443 444 // ECMA 11.2.4 445 List* ArgumentListNode::evaluateList() 446 { 447 KJSO e = expr->evaluate(); 448 KJSO v = e.getValue(); 449 450 if (!list) { 451 List *l = new List(); 452 l->append(v); 453 return l; 454 } 455 456 List *l = list->evaluateList(); 457 l->append(v); 458 459 return l; 460 } 461 462 // ECMA 11.8 463 KJSO RelationalNode::evaluate() 464 { 465 KJSO e1 = expr1->evaluate(); 466 KJSO v1 = e1.getValue(); 467 KJSO e2 = expr2->evaluate(); 468 KJSO v2 = e2.getValue(); 469 470 bool b; 471 if (oper == OpLess || oper == OpGreaterEq) { 472 int r = relation(v1, v2); 473 if (r < 0) 474 b = false; 475 else 476 b = (oper == OpLess) ? (r == 1) : (r == 0); 477 } else if (oper == OpGreater || oper == OpLessEq) { 478 int r = relation(v2, v1); 479 if (r < 0) 480 b = false; 481 else 482 b = (oper == OpGreater) ? (r == 1) : (r == 0); 483 } else if (oper == OpIn) { 484 /* Is all of this OK for host objects? */ 485 if (!v2.isObject()) 486 return throwError( TypeError, 487 "Shift expression not an object into IN expression." ); 488 b = v2.hasProperty(v1.toString().value()); 489 } else { 490 /* TODO: should apply to Function _objects_ only */ 491 if (!v2.derivedFrom("Function")) 492 return throwError(TypeError, 493 "Called instanceof operator on non-function object." ); 494 return hasInstance(v2, v1); /* TODO: make object member function */ 495 } 496 497 return Boolean(b); 498 } 499 500 // ECMA 11.9 501 KJSO EqualNode::evaluate() 502 { 503 KJSO e1 = expr1->evaluate(); 504 KJSO e2 = expr2->evaluate(); 505 KJSO v1 = e1.getValue(); 506 KJSO v2 = e2.getValue(); 507 508 bool result; 509 if (oper == OpEqEq || oper == OpNotEq) { 510 // == and != 511 bool eq = equal(v1, v2); 512 result = oper == OpEqEq ? eq : !eq; 513 } else { 514 // === and !== 515 bool eq = strictEqual(v1, v2); 516 result = oper == OpStrEq ? eq : !eq; 517 } 518 return Boolean(result); 519 } 520 521 // ECMA 11.10 522 KJSO BitOperNode::evaluate() 523 { 524 KJSO e1 = expr1->evaluate(); 525 KJSO v1 = e1.getValue(); 526 KJSO e2 = expr2->evaluate(); 527 KJSO v2 = e2.getValue(); 528 int i1 = v1.toInt32(); 529 int i2 = v2.toInt32(); 530 int result; 531 if (oper == OpBitAnd) 532 result = i1 & i2; 533 else if (oper == OpBitXOr) 534 result = i1 ^ i2; 535 else 536 result = i1 | i2; 537 538 return Number(result); 539 } 540 541 // ECMA 11.11 542 KJSO BinaryLogicalNode::evaluate() 543 { 544 KJSO e1 = expr1->evaluate(); 545 KJSO v1 = e1.getValue(); 546 Boolean b1 = v1.toBoolean(); 547 if ((!b1.value() && oper == OpAnd) || (b1.value() && oper == OpOr)) 548 return v1; 549 550 KJSO e2 = expr2->evaluate(); 551 KJSO v2 = e2.getValue(); 552 553 return v2; 554 } 555 556 // ECMA 11.12 557 KJSO ConditionalNode::evaluate() 558 { 559 KJSO e = logical->evaluate(); 560 KJSO v = e.getValue(); 561 Boolean b = v.toBoolean(); 562 563 if (b.value()) 564 e = expr1->evaluate(); 565 else 566 e = expr2->evaluate(); 567 568 return e.getValue(); 569 } 570 571 // ECMA 11.13 572 KJSO AssignNode::evaluate() 573 { 574 KJSO l, e, v; 575 ErrorType err; 576 if (oper == OpEqual) { 577 l = left->evaluate(); 578 e = expr->evaluate(); 579 v = e.getValue(); 580 } else { 581 l = left->evaluate(); 582 KJSO v1 = l.getValue(); 583 e = expr->evaluate(); 584 KJSO v2 = e.getValue(); 585 int i1 = v1.toInt32(); 586 int i2 = v2.toInt32(); 587 switch (oper) { 588 case OpMultEq: 589 v = mult(v1, v2, '*'); 590 break; 591 case OpDivEq: 592 v = mult(v1, v2, '/'); 593 break; 594 case OpPlusEq: 595 v = add(v1, v2, '+'); 596 break; 597 case OpMinusEq: 598 v = add(v1, v2, '-'); 599 break; 600 case OpLShift: 601 v = Number(i1 <<= i2); 602 break; 603 case OpRShift: 604 v = Number(i1 >>= i2); 605 break; 606 case OpURShift: 607 i1 = v1.toUInt32(); 608 v = Number(i1 >>= i2); 609 break; 610 case OpAndEq: 611 v = Number(i1 &= i2); 612 break; 613 case OpXOrEq: 614 v = Number(i1 ^= i2); 615 break; 616 case OpOrEq: 617 v = Number(i1 |= i2); 618 break; 619 case OpModEq: 620 v = Number(i1 %= i2); 621 break; 622 default: 623 v = Undefined(); 624 } 625 err = l.putValue(v); 626 }; 627 628 err = l.putValue(v); 629 if (err == NoError) 630 return v; 631 else 632 return throwError(err, "Invalid reference."); 633 } 634 635 // ECMA 11.3 636 KJSO PostfixNode::evaluate() 637 { 638 KJSO e = expr->evaluate(); 639 KJSO v = e.getValue(); 640 Number n = v.toNumber(); 641 642 double newValue = (oper == OpPlusPlus) ? n.value() + 1 : n.value() - 1; 643 KJSO n2 = Number(newValue); 644 645 e.putValue(n2); 646 647 return n; 648 } 649 650 // ECMA 11.4.1 651 KJSO DeleteNode::evaluate() 652 { 653 KJSO e = expr->evaluate(); 654 if (!e.isA(ReferenceType)) 655 return Boolean(true); 656 KJSO b = e.getBase(); 657 UString n = e.getPropertyName(); 658 bool ret = b.deleteProperty(n); 843 844 Object o = Object(static_cast<ObjectImp*>(b.imp())); 845 846 bool ret = o.deleteProperty(exec,n); 659 847 660 848 return Boolean(ret); 661 849 } 662 850 851 // ------------------------------ VoidNode ------------------------------------- 852 853 VoidNode::~VoidNode() 854 { 855 } 856 857 void VoidNode::ref() 858 { 859 Node::ref(); 860 if ( expr ) 861 expr->ref(); 862 } 863 864 bool VoidNode::deref() 865 { 866 if ( expr && expr->deref() ) 867 delete expr; 868 return Node::deref(); 869 } 870 663 871 // ECMA 11.4.2 664 KJSO VoidNode::evaluate() 665 { 666 KJSO dummy1 = expr->evaluate(); 667 KJSO dummy2 = dummy1.getValue(); 872 Value VoidNode::evaluate(ExecState *exec) 873 { 874 Value dummy1 = expr->evaluate(exec); 875 KJS_CHECKEXCEPTIONVALUE 876 Value dummy2 = dummy1.getValue(exec); 668 877 669 878 return Undefined(); 670 879 } 671 880 881 // ------------------------------ TypeOfNode ----------------------------------- 882 883 TypeOfNode::~TypeOfNode() 884 { 885 } 886 887 void TypeOfNode::ref() 888 { 889 Node::ref(); 890 if ( expr ) 891 expr->ref(); 892 } 893 894 bool TypeOfNode::deref() 895 { 896 if ( expr && expr->deref() ) 897 delete expr; 898 return Node::deref(); 899 } 900 672 901 // ECMA 11.4.3 673 KJSO TypeOfNode::evaluate()902 Value TypeOfNode::evaluate(ExecState *exec) 674 903 { 675 904 const char *s = 0L; 676 KJSO e = expr->evaluate(); 677 if (e.isA(ReferenceType)) { 678 KJSO b = e.getBase(); 679 if (b.isA(NullType)) 905 Value e = expr->evaluate(exec); 906 KJS_CHECKEXCEPTIONVALUE 907 if (e.type() == ReferenceType) { 908 Value b = e.getBase(exec); 909 if (b.type() == NullType) 680 910 return String("undefined"); 681 911 } 682 KJSO v = e.getValue();912 Value v = e.getValue(exec); 683 913 switch (v.type()) 684 914 { … … 699 929 break; 700 930 default: 701 if (v. implementsCall())931 if (v.type() == ObjectType && static_cast<ObjectImp*>(v.imp())->implementsCall()) 702 932 s = "function"; 703 933 else … … 709 939 } 710 940 941 // ------------------------------ PrefixNode ----------------------------------- 942 943 PrefixNode::~PrefixNode() 944 { 945 } 946 947 void PrefixNode::ref() 948 { 949 Node::ref(); 950 if ( expr ) 951 expr->ref(); 952 } 953 954 bool PrefixNode::deref() 955 { 956 if ( expr && expr->deref() ) 957 delete expr; 958 return Node::deref(); 959 } 960 711 961 // ECMA 11.4.4 and 11.4.5 712 KJSO PrefixNode::evaluate() 713 { 714 KJSO e = expr->evaluate(); 715 KJSO v = e.getValue(); 716 Number n = v.toNumber(); 962 Value PrefixNode::evaluate(ExecState *exec) 963 { 964 Value e = expr->evaluate(exec); 965 KJS_CHECKEXCEPTIONVALUE 966 Value v = e.getValue(exec); 967 Number n = v.toNumber(exec); 717 968 718 969 double newValue = (oper == OpPlusPlus) ? n.value() + 1 : n.value() - 1; 719 KJSOn2 = Number(newValue);720 721 e.putValue( n2);970 Value n2 = Number(newValue); 971 972 e.putValue(exec,n2); 722 973 723 974 return n2; 724 975 } 725 976 977 // ------------------------------ UnaryPlusNode -------------------------------- 978 979 UnaryPlusNode::~UnaryPlusNode() 980 { 981 } 982 983 void UnaryPlusNode::ref() 984 { 985 Node::ref(); 986 if ( expr ) 987 expr->ref(); 988 } 989 990 bool UnaryPlusNode::deref() 991 { 992 if ( expr && expr->deref() ) 993 delete expr; 994 return Node::deref(); 995 } 996 726 997 // ECMA 11.4.6 727 KJSO UnaryPlusNode::evaluate() 728 { 729 KJSO e = expr->evaluate(); 730 KJSO v = e.getValue(); 731 732 return v.toNumber(); 998 Value UnaryPlusNode::evaluate(ExecState *exec) 999 { 1000 Value e = expr->evaluate(exec); 1001 KJS_CHECKEXCEPTIONVALUE 1002 Value v = e.getValue(exec); 1003 1004 return Number(v.toNumber(exec)); /* TODO: optimize */ 1005 } 1006 1007 // ------------------------------ NegateNode ----------------------------------- 1008 1009 NegateNode::~NegateNode() 1010 { 1011 } 1012 1013 void NegateNode::ref() 1014 { 1015 Node::ref(); 1016 if ( expr ) 1017 expr->ref(); 1018 } 1019 1020 bool NegateNode::deref() 1021 { 1022 if ( expr && expr->deref() ) 1023 delete expr; 1024 return Node::deref(); 733 1025 } 734 1026 735 1027 // ECMA 11.4.7 736 KJSO NegateNode::evaluate() 737 { 738 KJSO e = expr->evaluate(); 739 KJSO v = e.getValue(); 740 Number n = v.toNumber(); 1028 Value NegateNode::evaluate(ExecState *exec) 1029 { 1030 Value e = expr->evaluate(exec); 1031 KJS_CHECKEXCEPTIONVALUE 1032 Value v = e.getValue(exec); 1033 Number n = v.toNumber(exec); 741 1034 742 1035 double d = -n.value(); … … 745 1038 } 746 1039 1040 // ------------------------------ BitwiseNotNode ------------------------------- 1041 1042 BitwiseNotNode::~BitwiseNotNode() 1043 { 1044 } 1045 1046 void BitwiseNotNode::ref() 1047 { 1048 Node::ref(); 1049 if ( expr ) 1050 expr->ref(); 1051 } 1052 1053 bool BitwiseNotNode::deref() 1054 { 1055 if ( expr && expr->deref() ) 1056 delete expr; 1057 return Node::deref(); 1058 } 1059 747 1060 // ECMA 11.4.8 748 KJSO BitwiseNotNode::evaluate() 749 { 750 KJSO e = expr->evaluate(); 751 KJSO v = e.getValue(); 752 int i32 = v.toInt32(); 1061 Value BitwiseNotNode::evaluate(ExecState *exec) 1062 { 1063 Value e = expr->evaluate(exec); 1064 KJS_CHECKEXCEPTIONVALUE 1065 Value v = e.getValue(exec); 1066 int i32 = v.toInt32(exec); 753 1067 754 1068 return Number(~i32); 755 1069 } 756 1070 1071 // ------------------------------ LogicalNotNode ------------------------------- 1072 1073 LogicalNotNode::~LogicalNotNode() 1074 { 1075 } 1076 1077 void LogicalNotNode::ref() 1078 { 1079 Node::ref(); 1080 if ( expr ) 1081 expr->ref(); 1082 } 1083 1084 bool LogicalNotNode::deref() 1085 { 1086 if ( expr && expr->deref() ) 1087 delete expr; 1088 return Node::deref(); 1089 } 1090 757 1091 // ECMA 11.4.9 758 KJSO LogicalNotNode::evaluate() 759 { 760 KJSO e = expr->evaluate(); 761 KJSO v = e.getValue(); 762 Boolean b = v.toBoolean(); 763 764 return Boolean(!b.value()); 1092 Value LogicalNotNode::evaluate(ExecState *exec) 1093 { 1094 Value e = expr->evaluate(exec); 1095 KJS_CHECKEXCEPTIONVALUE 1096 Value v = e.getValue(exec); 1097 bool b = v.toBoolean(exec); 1098 1099 return Boolean(!b); 1100 } 1101 1102 // ------------------------------ MultNode ------------------------------------- 1103 1104 MultNode::~MultNode() 1105 { 1106 } 1107 1108 void MultNode::ref() 1109 { 1110 Node::ref(); 1111 if ( term1 ) 1112 term1->ref(); 1113 if ( term2 ) 1114 term2->ref(); 1115 } 1116 1117 bool MultNode::deref() 1118 { 1119 if ( term1 && term1->deref() ) 1120 delete term1; 1121 if ( term2 && term2->deref() ) 1122 delete term2; 1123 return Node::deref(); 765 1124 } 766 1125 767 1126 // ECMA 11.5 768 KJSO MultNode::evaluate() 769 { 770 KJSO t1 = term1->evaluate(); 771 KJSO v1 = t1.getValue(); 772 773 KJSO t2 = term2->evaluate(); 774 KJSO v2 = t2.getValue(); 775 776 return mult(v1, v2, oper); 1127 Value MultNode::evaluate(ExecState *exec) 1128 { 1129 Value t1 = term1->evaluate(exec); 1130 KJS_CHECKEXCEPTIONVALUE 1131 Value v1 = t1.getValue(exec); 1132 1133 Value t2 = term2->evaluate(exec); 1134 KJS_CHECKEXCEPTIONVALUE 1135 Value v2 = t2.getValue(exec); 1136 1137 return mult(exec,v1, v2, oper); 1138 } 1139 1140 // ------------------------------ AddNode -------------------------------------- 1141 1142 AddNode::~AddNode() 1143 { 1144 } 1145 1146 void AddNode::ref() 1147 { 1148 Node::ref(); 1149 if ( term1 ) 1150 term1->ref(); 1151 if ( term2 ) 1152 term2->ref(); 1153 } 1154 1155 bool AddNode::deref() 1156 { 1157 if ( term1 && term1->deref() ) 1158 delete term1; 1159 if ( term2 && term2->deref() ) 1160 delete term2; 1161 return Node::deref(); 1162 } 1163 1164 // ECMA 11.6 1165 Value AddNode::evaluate(ExecState *exec) 1166 { 1167 Value t1 = term1->evaluate(exec); 1168 KJS_CHECKEXCEPTIONVALUE 1169 Value v1 = t1.getValue(exec); 1170 1171 Value t2 = term2->evaluate(exec); 1172 KJS_CHECKEXCEPTIONVALUE 1173 Value v2 = t2.getValue(exec); 1174 1175 return add(exec,v1, v2, oper); 1176 } 1177 1178 // ------------------------------ ShiftNode ------------------------------------ 1179 1180 ShiftNode::~ShiftNode() 1181 { 1182 } 1183 1184 void ShiftNode::ref() 1185 { 1186 Node::ref(); 1187 if ( term1 ) 1188 term1->ref(); 1189 if ( term2 ) 1190 term2->ref(); 1191 } 1192 1193 bool ShiftNode::deref() 1194 { 1195 if ( term1 && term1->deref() ) 1196 delete term1; 1197 if ( term2 && term2->deref() ) 1198 delete term2; 1199 return Node::deref(); 777 1200 } 778 1201 779 1202 // ECMA 11.7 780 KJSO ShiftNode::evaluate() 781 { 782 KJSO t1 = term1->evaluate(); 783 KJSO v1 = t1.getValue(); 784 KJSO t2 = term2->evaluate(); 785 KJSO v2 = t2.getValue(); 786 unsigned int i2 = v2.toUInt32(); 1203 Value ShiftNode::evaluate(ExecState *exec) 1204 { 1205 Value t1 = term1->evaluate(exec); 1206 KJS_CHECKEXCEPTIONVALUE 1207 Value v1 = t1.getValue(exec); 1208 Value t2 = term2->evaluate(exec); 1209 KJS_CHECKEXCEPTIONVALUE 1210 Value v2 = t2.getValue(exec); 1211 unsigned int i2 = v2.toUInt32(exec); 787 1212 i2 &= 0x1f; 788 1213 … … 790 1215 switch (oper) { 791 1216 case OpLShift: 792 result = v1.toInt32( ) << i2;1217 result = v1.toInt32(exec) << i2; 793 1218 break; 794 1219 case OpRShift: 795 result = v1.toInt32( ) >> i2;1220 result = v1.toInt32(exec) >> i2; 796 1221 break; 797 1222 case OpURShift: 798 result = v1.toUInt32( ) >> i2;1223 result = v1.toUInt32(exec) >> i2; 799 1224 break; 800 1225 default: … … 806 1231 } 807 1232 808 // ECMA 11.6 809 KJSO AddNode::evaluate() 810 { 811 KJSO t1 = term1->evaluate(); 812 KJSO v1 = t1.getValue(); 813 814 KJSO t2 = term2->evaluate(); 815 KJSO v2 = t2.getValue(); 816 817 return add(v1, v2, oper); 1233 // ------------------------------ RelationalNode ------------------------------- 1234 1235 RelationalNode::~RelationalNode() 1236 { 1237 } 1238 1239 void RelationalNode::ref() 1240 { 1241 Node::ref(); 1242 if ( expr1 ) 1243 expr1->ref(); 1244 if ( expr2 ) 1245 expr2->ref(); 1246 } 1247 1248 bool RelationalNode::deref() 1249 { 1250 if ( expr1 && expr1->deref() ) 1251 delete expr1; 1252 if ( expr2 && expr2->deref() ) 1253 delete expr2; 1254 return Node::deref(); 1255 } 1256 1257 // ECMA 11.8 1258 Value RelationalNode::evaluate(ExecState *exec) 1259 { 1260 Value e1 = expr1->evaluate(exec); 1261 KJS_CHECKEXCEPTIONVALUE 1262 Value v1 = e1.getValue(exec); 1263 Value e2 = expr2->evaluate(exec); 1264 KJS_CHECKEXCEPTIONVALUE 1265 Value v2 = e2.getValue(exec); 1266 1267 bool b; 1268 if (oper == OpLess || oper == OpGreaterEq) { 1269 int r = relation(exec, v1, v2); 1270 if (r < 0) 1271 b = false; 1272 else 1273 b = (oper == OpLess) ? (r == 1) : (r == 0); 1274 } else if (oper == OpGreater || oper == OpLessEq) { 1275 int r = relation(exec, v2, v1); 1276 if (r < 0) 1277 b = false; 1278 else 1279 b = (oper == OpGreater) ? (r == 1) : (r == 0); 1280 } else if (oper == OpIn) { 1281 // Is all of this OK for host objects? 1282 if (v2.type() != ObjectType) 1283 return throwError(exec, TypeError, 1284 "Shift expression not an object into IN expression." ); 1285 Object o2(static_cast<ObjectImp*>(v2.imp())); 1286 b = o2.hasProperty(exec,v1.toString(exec)); 1287 } else { 1288 if (v2.type() != ObjectType) 1289 return throwError(exec, TypeError, 1290 "Called instanceof operator on non-object." ); 1291 1292 Object o2(static_cast<ObjectImp*>(v2.imp())); 1293 if (!o2.implementsHasInstance()) { 1294 // According to the spec, only some types of objects "imlement" the [[HasInstance]] property. 1295 // But we are supposed to throw an exception where the object does not "have" the [[HasInstance]] 1296 // property. It seems that all object have the property, but not all implement it, so in this 1297 // case we return false (consistent with mozilla) 1298 return Boolean(false); 1299 // return throwError(exec, TypeError, 1300 // "Object does not implement the [[HasInstance]] method." ); 1301 } 1302 return o2.hasInstance(exec, v1); 1303 } 1304 1305 return Boolean(b); 1306 } 1307 1308 // ------------------------------ EqualNode ------------------------------------ 1309 1310 EqualNode::~EqualNode() 1311 { 1312 } 1313 1314 void EqualNode::ref() 1315 { 1316 Node::ref(); 1317 if ( expr1 ) 1318 expr1->ref(); 1319 if ( expr2 ) 1320 expr2->ref(); 1321 } 1322 1323 bool EqualNode::deref() 1324 { 1325 if ( expr1 && expr1->deref() ) 1326 delete expr1; 1327 if ( expr2 && expr2->deref() ) 1328 delete expr2; 1329 return Node::deref(); 1330 } 1331 1332 // ECMA 11.9 1333 Value EqualNode::evaluate(ExecState *exec) 1334 { 1335 Value e1 = expr1->evaluate(exec); 1336 KJS_CHECKEXCEPTIONVALUE 1337 Value e2 = expr2->evaluate(exec); 1338 KJS_CHECKEXCEPTIONVALUE 1339 Value v1 = e1.getValue(exec); 1340 Value v2 = e2.getValue(exec); 1341 1342 bool result; 1343 if (oper == OpEqEq || oper == OpNotEq) { 1344 // == and != 1345 bool eq = equal(exec,v1, v2); 1346 result = oper == OpEqEq ? eq : !eq; 1347 } else { 1348 // === and !== 1349 bool eq = strictEqual(exec,v1, v2); 1350 result = oper == OpStrEq ? eq : !eq; 1351 } 1352 return Boolean(result); 1353 } 1354 1355 // ------------------------------ BitOperNode ---------------------------------- 1356 1357 BitOperNode::~BitOperNode() 1358 { 1359 } 1360 1361 void BitOperNode::ref() 1362 { 1363 Node::ref(); 1364 if ( expr1 ) 1365 expr1->ref(); 1366 if ( expr2 ) 1367 expr2->ref(); 1368 } 1369 1370 bool BitOperNode::deref() 1371 { 1372 if ( expr1 && expr1->deref() ) 1373 delete expr1; 1374 if ( expr2 && expr2->deref() ) 1375 delete expr2; 1376 return Node::deref(); 1377 } 1378 1379 // ECMA 11.10 1380 Value BitOperNode::evaluate(ExecState *exec) 1381 { 1382 Value e1 = expr1->evaluate(exec); 1383 KJS_CHECKEXCEPTIONVALUE 1384 Value v1 = e1.getValue(exec); 1385 Value e2 = expr2->evaluate(exec); 1386 KJS_CHECKEXCEPTIONVALUE 1387 Value v2 = e2.getValue(exec); 1388 int i1 = v1.toInt32(exec); 1389 int i2 = v2.toInt32(exec); 1390 int result; 1391 if (oper == OpBitAnd) 1392 result = i1 & i2; 1393 else if (oper == OpBitXOr) 1394 result = i1 ^ i2; 1395 else 1396 result = i1 | i2; 1397 1398 return Number(result); 1399 } 1400 1401 // ------------------------------ BinaryLogicalNode ---------------------------- 1402 1403 BinaryLogicalNode::~BinaryLogicalNode() 1404 { 1405 } 1406 1407 void BinaryLogicalNode::ref() 1408 { 1409 Node::ref(); 1410 if ( expr1 ) 1411 expr1->ref(); 1412 if ( expr2 ) 1413 expr2->ref(); 1414 } 1415 1416 bool BinaryLogicalNode::deref() 1417 { 1418 if ( expr1 && expr1->deref() ) 1419 delete expr1; 1420 if ( expr2 && expr2->deref() ) 1421 delete expr2; 1422 return Node::deref(); 1423 } 1424 1425 // ECMA 11.11 1426 Value BinaryLogicalNode::evaluate(ExecState *exec) 1427 { 1428 Value e1 = expr1->evaluate(exec); 1429 KJS_CHECKEXCEPTIONVALUE 1430 Value v1 = e1.getValue(exec); 1431 bool b1 = v1.toBoolean(exec); 1432 if ((!b1 && oper == OpAnd) || (b1 && oper == OpOr)) 1433 return v1; 1434 1435 Value e2 = expr2->evaluate(exec); 1436 KJS_CHECKEXCEPTIONVALUE 1437 Value v2 = e2.getValue(exec); 1438 1439 return v2; 1440 } 1441 1442 // ------------------------------ ConditionalNode ------------------------------ 1443 1444 ConditionalNode::~ConditionalNode() 1445 { 1446 } 1447 1448 void ConditionalNode::ref() 1449 { 1450 Node::ref(); 1451 if ( expr1 ) 1452 expr1->ref(); 1453 if ( expr2 ) 1454 expr2->ref(); 1455 if ( logical ) 1456 logical->ref(); 1457 } 1458 1459 bool ConditionalNode::deref() 1460 { 1461 if ( expr1 && expr1->deref() ) 1462 delete expr1; 1463 if ( expr2 && expr2->deref() ) 1464 delete expr2; 1465 if ( logical && logical->deref() ) 1466 delete logical; 1467 return Node::deref(); 1468 } 1469 1470 // ECMA 11.12 1471 Value ConditionalNode::evaluate(ExecState *exec) 1472 { 1473 Value e = logical->evaluate(exec); 1474 KJS_CHECKEXCEPTIONVALUE 1475 Value v = e.getValue(exec); 1476 bool b = v.toBoolean(exec); 1477 1478 if (b) 1479 e = expr1->evaluate(exec); 1480 else 1481 e = expr2->evaluate(exec); 1482 KJS_CHECKEXCEPTIONVALUE 1483 1484 return e.getValue(exec); 1485 } 1486 1487 // ------------------------------ AssignNode ----------------------------------- 1488 1489 AssignNode::~AssignNode() 1490 { 1491 } 1492 1493 void AssignNode::ref() 1494 { 1495 Node::ref(); 1496 if ( left ) 1497 left->ref(); 1498 if ( expr ) 1499 expr->ref(); 1500 } 1501 1502 bool AssignNode::deref() 1503 { 1504 if ( left && left->deref() ) 1505 delete left; 1506 if ( expr && expr->deref() ) 1507 delete expr; 1508 return Node::deref(); 1509 } 1510 1511 // ECMA 11.13 1512 Value AssignNode::evaluate(ExecState *exec) 1513 { 1514 1515 Value l, e, v; 1516 if (oper == OpEqual) { 1517 l = left->evaluate(exec); 1518 KJS_CHECKEXCEPTIONVALUE 1519 e = expr->evaluate(exec); 1520 KJS_CHECKEXCEPTIONVALUE 1521 v = e.getValue(exec); 1522 } else { 1523 l = left->evaluate(exec); 1524 KJS_CHECKEXCEPTIONVALUE 1525 Value v1 = l.getValue(exec); 1526 e = expr->evaluate(exec); 1527 KJS_CHECKEXCEPTIONVALUE 1528 Value v2 = e.getValue(exec); 1529 int i1 = v1.toInt32(exec); 1530 int i2 = v2.toInt32(exec); 1531 unsigned int ui; 1532 switch (oper) { 1533 case OpMultEq: 1534 v = mult(exec, v1, v2, '*'); 1535 break; 1536 case OpDivEq: 1537 v = mult(exec, v1, v2, '/'); 1538 break; 1539 case OpPlusEq: 1540 v = add(exec, v1, v2, '+'); 1541 break; 1542 case OpMinusEq: 1543 v = add(exec, v1, v2, '-'); 1544 break; 1545 case OpLShift: 1546 v = Number(i1 <<= i2); 1547 break; 1548 case OpRShift: 1549 v = Number(i1 >>= i2); 1550 break; 1551 case OpURShift: 1552 ui = v1.toUInt32(exec); 1553 v = Number(ui >>= i2); 1554 break; 1555 case OpAndEq: 1556 v = Number(i1 &= i2); 1557 break; 1558 case OpXOrEq: 1559 v = Number(i1 ^= i2); 1560 break; 1561 case OpOrEq: 1562 v = Number(i1 |= i2); 1563 break; 1564 case OpModEq: { 1565 double d1 = v1.toNumber(exec); 1566 double d2 = v2.toNumber(exec); 1567 v = Number(fmod(d1,d2)); 1568 } 1569 break; 1570 default: 1571 v = Undefined(); 1572 } 1573 }; 1574 l.putValue(exec,v); 1575 1576 KJS_CHECKEXCEPTIONVALUE 1577 1578 return v; 1579 } 1580 1581 // ------------------------------ CommaNode ------------------------------------ 1582 1583 CommaNode::~CommaNode() 1584 { 1585 } 1586 1587 void CommaNode::ref() 1588 { 1589 Node::ref(); 1590 if ( expr1 ) 1591 expr1->ref(); 1592 if ( expr2 ) 1593 expr2->ref(); 1594 } 1595 1596 bool CommaNode::deref() 1597 { 1598 if ( expr1 && expr1->deref() ) 1599 delete expr1; 1600 if ( expr2 && expr2->deref() ) 1601 delete expr2; 1602 return Node::deref(); 818 1603 } 819 1604 820 1605 // ECMA 11.14 821 KJSO CommaNode::evaluate() 822 { 823 KJSO e = expr1->evaluate(); 824 KJSO dummy = e.getValue(); // ignore return value 825 e = expr2->evaluate(); 826 827 return e.getValue(); 1606 Value CommaNode::evaluate(ExecState *exec) 1607 { 1608 Value e = expr1->evaluate(exec); 1609 KJS_CHECKEXCEPTIONVALUE 1610 Value dummy = e.getValue(exec); // ignore return value 1611 e = expr2->evaluate(exec); 1612 KJS_CHECKEXCEPTIONVALUE 1613 1614 return e.getValue(exec); 1615 } 1616 1617 // ------------------------------ StatListNode --------------------------------- 1618 1619 StatListNode::~StatListNode() 1620 { 1621 } 1622 1623 void StatListNode::ref() 1624 { 1625 Node::ref(); 1626 if ( statement ) 1627 statement->ref(); 1628 if ( list ) 1629 list->ref(); 1630 } 1631 1632 bool StatListNode::deref() 1633 { 1634 if ( statement && statement->deref() ) 1635 delete statement; 1636 if ( list && list->deref() ) 1637 delete list; 1638 return Node::deref(); 828 1639 } 829 1640 830 1641 // ECMA 12.1 831 Completion BlockNode::execute() 832 { 833 if (!statlist) 834 return Completion(Normal); 835 836 return statlist->execute(); 837 } 838 839 // ECMA 12.1 840 Completion StatListNode::execute() 1642 Completion StatListNode::execute(ExecState *exec) 841 1643 { 842 1644 if (!list) { 843 Completion c = statement->execute( );1645 Completion c = statement->execute(exec); 844 1646 KJS_ABORTPOINT 845 if ( KJScriptImp::hadException()) {846 KJSO ex = KJScriptImp::exception();847 KJScriptImp::clearException();1647 if (exec->hadException()) { 1648 Value ex = exec->exception(); 1649 exec->clearException(); 848 1650 return Completion(Throw, ex); 849 } else 1651 } 1652 else 850 1653 return c; 851 1654 } 852 1655 853 Completion l = list->execute( );1656 Completion l = list->execute(exec); 854 1657 KJS_ABORTPOINT 855 1658 if (l.complType() != Normal) 856 1659 return l; 857 Completion e = statement->execute( );1660 Completion e = statement->execute(exec); 858 1661 KJS_ABORTPOINT; 859 if (KJScriptImp::hadException()) { 860 KJSO ex = KJScriptImp::exception(); 861 KJScriptImp::clearException(); 1662 1663 if (exec->hadException()) { 1664 Value ex = exec->exception(); 1665 exec->clearException(); 862 1666 return Completion(Throw, ex); 863 1667 } 864 1668 865 KJSOv = e.isValueCompletion() ? e.value() : l.value();1669 Value v = e.isValueCompletion() ? e.value() : l.value(); 866 1670 867 1671 return Completion(e.complType(), v, e.target() ); 868 1672 } 869 1673 1674 void StatListNode::processVarDecls(ExecState *exec) 1675 { 1676 statement->processVarDecls(exec); 1677 1678 if (list) 1679 list->processVarDecls(exec); 1680 } 1681 1682 // ------------------------------ AssignExprNode ------------------------------- 1683 1684 AssignExprNode::~AssignExprNode() 1685 { 1686 } 1687 1688 void AssignExprNode::ref() 1689 { 1690 Node::ref(); 1691 if ( expr ) 1692 expr->ref(); 1693 } 1694 1695 bool AssignExprNode::deref() 1696 { 1697 if ( expr && expr->deref() ) 1698 delete expr; 1699 return Node::deref(); 1700 } 1701 870 1702 // ECMA 12.2 871 Completion VarStatementNode::execute() 872 { 873 KJS_BREAKPOINT; 874 875 (void) list->evaluate(); // returns 0L 876 877 return Completion(Normal); 1703 Value AssignExprNode::evaluate(ExecState *exec) 1704 { 1705 return expr->evaluate(exec); 1706 } 1707 1708 // ------------------------------ VarDeclNode ---------------------------------- 1709 1710 VarDeclNode::VarDeclNode(const UString *id, AssignExprNode *in) 1711 : ident(*id), init(in) 1712 { 1713 } 1714 1715 VarDeclNode::~VarDeclNode() 1716 { 1717 } 1718 1719 void VarDeclNode::ref() 1720 { 1721 Node::ref(); 1722 if ( init ) 1723 init->ref(); 1724 } 1725 1726 bool VarDeclNode::deref() 1727 { 1728 if ( init && init->deref() ) 1729 delete init; 1730 return Node::deref(); 878 1731 } 879 1732 880 1733 // ECMA 12.2 881 KJSO VarDeclNode::evaluate()882 { 883 KJSO variable = Context::current()->variableObject();884 885 KJSOval, tmp;1734 Value VarDeclNode::evaluate(ExecState *exec) 1735 { 1736 Object variable = Object::dynamicCast(exec->context().variableObject()); 1737 1738 Value val, tmp; 886 1739 if (init) { 887 tmp = init->evaluate(); 888 val = tmp.getValue(); 1740 tmp = init->evaluate(exec); 1741 KJS_CHECKEXCEPTIONVALUE 1742 val = tmp.getValue(exec); 889 1743 } else { 890 if ( variable.hasProperty( ident ) ) // already declared ?891 return KJSO();1744 if ( variable.hasProperty(exec, ident ) ) // already declared ? 1745 return Value(); 892 1746 val = Undefined(); 893 1747 } 894 variable.put(ident, val, DontDelete); 895 896 // spec wants to return ident. But what for ? Will be ignored above. 897 return KJSO(); 898 } 1748 1749 #ifdef KJS_VERBOSE 1750 printInfo(exec,(UString("new variable ")+ident).cstring().c_str(),val); 1751 #endif 1752 // We use Internal to bypass all checks in derived objects, e.g. so that 1753 // "var location" creates a dynamic property instead of activating window.location. 1754 variable.put(exec, ident, val, DontDelete | Internal); 1755 1756 return String(ident); 1757 } 1758 1759 void VarDeclNode::processVarDecls(ExecState *exec) 1760 { 1761 Object variable = exec->context().variableObject(); 1762 variable.put(exec,ident, Undefined(), DontDelete); 1763 } 1764 1765 // ------------------------------ VarDeclListNode ------------------------------ 1766 1767 VarDeclListNode::~VarDeclListNode() 1768 { 1769 } 1770 1771 void VarDeclListNode::ref() 1772 { 1773 Node::ref(); 1774 if ( list ) 1775 list->ref(); 1776 if ( var ) 1777 var->ref(); 1778 } 1779 1780 bool VarDeclListNode::deref() 1781 { 1782 if ( list && list->deref() ) 1783 delete list; 1784 if ( var && var->deref() ) 1785 delete var; 1786 return Node::deref(); 1787 } 1788 899 1789 900 1790 // ECMA 12.2 901 KJSO VarDeclListNode::evaluate()1791 Value VarDeclListNode::evaluate(ExecState *exec) 902 1792 { 903 1793 if (list) 904 (void) list->evaluate(); 905 906 (void) var->evaluate(); 907 908 return KJSO(); 1794 (void) list->evaluate(exec); 1795 KJS_CHECKEXCEPTIONVALUE 1796 1797 (void) var->evaluate(exec); 1798 KJS_CHECKEXCEPTIONVALUE 1799 1800 return Undefined(); 1801 } 1802 1803 void VarDeclListNode::processVarDecls(ExecState *exec) 1804 { 1805 if (list) 1806 list->processVarDecls(exec); 1807 1808 var->processVarDecls(exec); 1809 } 1810 1811 // ------------------------------ VarStatementNode ----------------------------- 1812 1813 VarStatementNode::~VarStatementNode() 1814 { 1815 } 1816 1817 void VarStatementNode::ref() 1818 { 1819 Node::ref(); 1820 if ( list ) 1821 list->ref(); 1822 } 1823 1824 bool VarStatementNode::deref() 1825 { 1826 if ( list && list->deref() ) 1827 delete list; 1828 return Node::deref(); 909 1829 } 910 1830 911 1831 // ECMA 12.2 912 KJSO AssignExprNode::evaluate() 913 { 914 return expr->evaluate(); 915 } 1832 Completion VarStatementNode::execute(ExecState *exec) 1833 { 1834 KJS_BREAKPOINT; 1835 1836 (void) list->evaluate(exec); // returns 0L 1837 KJS_CHECKEXCEPTION 1838 1839 return Completion(Normal); 1840 } 1841 1842 void VarStatementNode::processVarDecls(ExecState *exec) 1843 { 1844 list->processVarDecls(exec); 1845 } 1846 1847 // ------------------------------ BlockNode ------------------------------------ 1848 1849 BlockNode::~BlockNode() 1850 { 1851 } 1852 1853 void BlockNode::ref() 1854 { 1855 Node::ref(); 1856 if ( source ) 1857 source->ref(); 1858 } 1859 1860 bool BlockNode::deref() 1861 { 1862 if ( source && source->deref() ) 1863 delete source; 1864 return Node::deref(); 1865 } 1866 1867 // ECMA 12.1 1868 Completion BlockNode::execute(ExecState *exec) 1869 { 1870 if (!source) 1871 return Completion(Normal); 1872 1873 source->processFuncDecl(exec); 1874 1875 return source->execute(exec); 1876 } 1877 1878 void BlockNode::processVarDecls(ExecState *exec) 1879 { 1880 if (source) 1881 source->processVarDecls(exec); 1882 } 1883 1884 // ------------------------------ EmptyStatementNode --------------------------- 916 1885 917 1886 // ECMA 12.3 918 Completion EmptyStatementNode::execute( )1887 Completion EmptyStatementNode::execute(ExecState */*exec*/) 919 1888 { 920 1889 return Completion(Normal); 921 1890 } 922 1891 1892 // ------------------------------ ExprStatementNode ---------------------------- 1893 1894 ExprStatementNode::~ExprStatementNode() 1895 { 1896 } 1897 1898 void ExprStatementNode::ref() 1899 { 1900 Node::ref(); 1901 if ( expr ) 1902 expr->ref(); 1903 } 1904 1905 bool ExprStatementNode::deref() 1906 { 1907 if ( expr && expr->deref() ) 1908 delete expr; 1909 return Node::deref(); 1910 } 1911 1912 // ECMA 12.4 1913 Completion ExprStatementNode::execute(ExecState *exec) 1914 { 1915 KJS_BREAKPOINT; 1916 1917 Value e = expr->evaluate(exec); 1918 KJS_CHECKEXCEPTION 1919 Value v = e.getValue(exec); 1920 1921 return Completion(Normal, v); 1922 } 1923 1924 // ------------------------------ IfNode --------------------------------------- 1925 1926 IfNode::~IfNode() 1927 { 1928 } 1929 1930 void IfNode::ref() 1931 { 1932 Node::ref(); 1933 if ( statement1 ) 1934 statement1->ref(); 1935 if ( statement2 ) 1936 statement2->ref(); 1937 if ( expr ) 1938 expr->ref(); 1939 } 1940 1941 bool IfNode::deref() 1942 { 1943 if ( statement1 && statement1->deref() ) 1944 delete statement1; 1945 if ( statement2 && statement2->deref() ) 1946 delete statement2; 1947 if ( expr && expr->deref() ) 1948 delete expr; 1949 return Node::deref(); 1950 } 1951 1952 // ECMA 12.5 1953 Completion IfNode::execute(ExecState *exec) 1954 { 1955 KJS_BREAKPOINT; 1956 1957 Value e = expr->evaluate(exec); 1958 KJS_CHECKEXCEPTION 1959 Value v = e.getValue(exec); 1960 bool b = v.toBoolean(exec); 1961 1962 // if ... then 1963 if (b) 1964 return statement1->execute(exec); 1965 1966 // no else 1967 if (!statement2) 1968 return Completion(Normal); 1969 1970 // else 1971 return statement2->execute(exec); 1972 } 1973 1974 void IfNode::processVarDecls(ExecState *exec) 1975 { 1976 statement1->processVarDecls(exec); 1977 1978 if (statement2) 1979 statement2->processVarDecls(exec); 1980 } 1981 1982 // ------------------------------ DoWhileNode ---------------------------------- 1983 1984 DoWhileNode::~DoWhileNode() 1985 { 1986 } 1987 1988 void DoWhileNode::ref() 1989 { 1990 Node::ref(); 1991 if ( statement ) 1992 statement->ref(); 1993 if ( expr ) 1994 expr->ref(); 1995 } 1996 1997 bool DoWhileNode::deref() 1998 { 1999 if ( statement && statement->deref() ) 2000 delete statement; 2001 if ( expr && expr->deref() ) 2002 delete expr; 2003 return Node::deref(); 2004 } 2005 2006 // ECMA 12.6.1 2007 Completion DoWhileNode::execute(ExecState *exec) 2008 { 2009 KJS_BREAKPOINT; 2010 2011 Value be, bv; 2012 Completion c; 2013 Value value; 2014 2015 do { 2016 // bail out on error 2017 KJS_CHECKEXCEPTION 2018 2019 c = statement->execute(exec); 2020 if (!((c.complType() == Continue) && ls.contains(c.target()))) { 2021 if ((c.complType() == Break) && ls.contains(c.target())) 2022 return Completion(Normal, value); 2023 if (c.complType() != Normal) 2024 return c; 2025 } 2026 be = expr->evaluate(exec); 2027 KJS_CHECKEXCEPTION 2028 bv = be.getValue(exec); 2029 } while (bv.toBoolean(exec)); 2030 2031 return Completion(Normal, value); 2032 } 2033 2034 void DoWhileNode::processVarDecls(ExecState *exec) 2035 { 2036 statement->processVarDecls(exec); 2037 } 2038 2039 // ------------------------------ WhileNode ------------------------------------ 2040 2041 WhileNode::~WhileNode() 2042 { 2043 } 2044 2045 void WhileNode::ref() 2046 { 2047 Node::ref(); 2048 if ( statement ) 2049 statement->ref(); 2050 if ( expr ) 2051 expr->ref(); 2052 } 2053 2054 bool WhileNode::deref() 2055 { 2056 if ( statement && statement->deref() ) 2057 delete statement; 2058 if ( expr && expr->deref() ) 2059 delete expr; 2060 return Node::deref(); 2061 } 2062 2063 // ECMA 12.6.2 2064 Completion WhileNode::execute(ExecState *exec) 2065 { 2066 KJS_BREAKPOINT; 2067 2068 Value be, bv; 2069 Completion c; 2070 bool b(false); 2071 Value value; 2072 2073 while (1) { 2074 be = expr->evaluate(exec); 2075 KJS_CHECKEXCEPTION 2076 bv = be.getValue(exec); 2077 b = bv.toBoolean(exec); 2078 2079 // bail out on error 2080 KJS_CHECKEXCEPTION 2081 2082 if (!b) 2083 return Completion(Normal, value); 2084 2085 c = statement->execute(exec); 2086 if (c.isValueCompletion()) 2087 value = c.value(); 2088 2089 if ((c.complType() == Continue) && ls.contains(c.target())) 2090 continue; 2091 if ((c.complType() == Break) && ls.contains(c.target())) 2092 return Completion(Normal, value); 2093 if (c.complType() != Normal) 2094 return c; 2095 } 2096 } 2097 2098 void WhileNode::processVarDecls(ExecState *exec) 2099 { 2100 statement->processVarDecls(exec); 2101 } 2102 2103 // ------------------------------ ForNode -------------------------------------- 2104 2105 ForNode::~ForNode() 2106 { 2107 } 2108 2109 void ForNode::ref() 2110 { 2111 Node::ref(); 2112 if ( statement ) 2113 statement->ref(); 2114 if ( expr1 ) 2115 expr1->ref(); 2116 if ( expr2 ) 2117 expr2->ref(); 2118 if ( expr3 ) 2119 expr3->ref(); 2120 } 2121 2122 bool ForNode::deref() 2123 { 2124 if ( statement && statement->deref() ) 2125 delete statement; 2126 if ( expr1 && expr1->deref() ) 2127 delete expr1; 2128 if ( expr2 && expr2->deref() ) 2129 delete expr2; 2130 if ( expr3 && expr3->deref() ) 2131 delete expr3; 2132 return Node::deref(); 2133 } 2134 923 2135 // ECMA 12.6.3 924 Completion ForNode::execute( )925 { 926 KJSOe, v, cval;927 Booleanb;2136 Completion ForNode::execute(ExecState *exec) 2137 { 2138 Value e, v, cval; 2139 bool b; 928 2140 929 2141 if (expr1) { 930 e = expr1->evaluate(); 931 v = e.getValue(); 2142 e = expr1->evaluate(exec); 2143 KJS_CHECKEXCEPTION 2144 v = e.getValue(exec); 932 2145 } 933 2146 while (1) { 934 2147 if (expr2) { 935 e = expr2->evaluate(); 936 v = e.getValue(); 937 b = v.toBoolean(); 938 if (b.value() == false) 2148 e = expr2->evaluate(exec); 2149 KJS_CHECKEXCEPTION 2150 v = e.getValue(exec); 2151 b = v.toBoolean(exec); 2152 if (b == false) 939 2153 return Completion(Normal, cval); 940 2154 } 941 2155 // bail out on error 942 if (KJScriptImp::hadException()) 943 return Completion(Throw, KJScriptImp::exception()); 944 945 Completion c = stat->execute(); 2156 KJS_CHECKEXCEPTION 2157 2158 Completion c = statement->execute(exec); 946 2159 if (c.isValueCompletion()) 947 2160 cval = c.value(); … … 953 2166 } 954 2167 if (expr3) { 955 e = expr3->evaluate(); 956 v = e.getValue(); 2168 e = expr3->evaluate(exec); 2169 KJS_CHECKEXCEPTION 2170 v = e.getValue(exec); 957 2171 } 958 2172 } 959 2173 } 960 2174 2175 void ForNode::processVarDecls(ExecState *exec) 2176 { 2177 if (expr1) 2178 expr1->processVarDecls(exec); 2179 2180 statement->processVarDecls(exec); 2181 } 2182 2183 // ------------------------------ ForInNode ------------------------------------ 2184 2185 ForInNode::ForInNode(Node *l, Node *e, StatementNode *s) 2186 : init(0L), lexpr(l), expr(e), varDecl(0L), statement(s) 2187 { 2188 } 2189 2190 ForInNode::ForInNode(const UString *i, AssignExprNode *in, Node *e, StatementNode *s) 2191 : ident(*i), init(in), expr(e), statement(s) 2192 { 2193 // for( var foo = bar in baz ) 2194 varDecl = new VarDeclNode(&ident, init); 2195 lexpr = new ResolveNode(&ident); 2196 } 2197 2198 ForInNode::~ForInNode() 2199 { 2200 } 2201 2202 void ForInNode::ref() 2203 { 2204 Node::ref(); 2205 if ( statement ) 2206 statement->ref(); 2207 if ( expr ) 2208 expr->ref(); 2209 if ( lexpr ) 2210 lexpr->ref(); 2211 if ( init ) 2212 init->ref(); 2213 if ( varDecl ) 2214 varDecl->ref(); 2215 } 2216 2217 bool ForInNode::deref() 2218 { 2219 if ( statement && statement->deref() ) 2220 delete statement; 2221 if ( expr && expr->deref() ) 2222 delete expr; 2223 if ( lexpr && lexpr->deref() ) 2224 delete lexpr; 2225 if ( init && init->deref() ) 2226 delete init; 2227 if ( varDecl && varDecl->deref() ) 2228 delete varDecl; 2229 return Node::deref(); 2230 } 2231 961 2232 // ECMA 12.6.4 962 Completion ForInNode::execute() 963 { 964 KJSO e, v, retval; 2233 Completion ForInNode::execute(ExecState *exec) 2234 { 2235 Value e, retval; 2236 Object v; 965 2237 Completion c; 966 VarDeclNode *vd = 0; 967 const PropList *lst, *curr; 968 969 // This should be done in the constructor 970 if (!lexpr) { // for( var foo = bar in baz ) 971 vd = new VarDeclNode(&ident, init); 972 vd->evaluate(); 973 974 lexpr = new ResolveNode(&ident); 2238 List propList; 2239 2240 if ( varDecl ) { 2241 varDecl->evaluate(exec); 2242 KJS_CHECKEXCEPTION 975 2243 } 976 2244 977 e = expr->evaluate(); 978 v = e.getValue().toObject(); 979 curr = lst = v.imp()->propList(); 980 981 while (curr) { 982 if (!v.hasProperty(curr->name)) { 983 curr = curr->next; 2245 e = expr->evaluate(exec); 2246 KJS_CHECKEXCEPTION 2247 v = e.getValue(exec).toObject(exec); 2248 propList = v.propList(exec); 2249 2250 ListIterator propIt = propList.begin(); 2251 2252 while (propIt != propList.end()) { 2253 UString name = propIt->getPropertyName(exec); 2254 if (!v.hasProperty(exec,name)) { 2255 propIt++; 984 2256 continue; 985 2257 } 986 2258 987 e = lexpr->evaluate(); 988 e.putValue(String(curr->name)); 989 990 c = stat->execute(); 2259 e = lexpr->evaluate(exec); 2260 KJS_CHECKEXCEPTION 2261 e.putValue(exec,String(name)); 2262 2263 c = statement->execute(exec); 991 2264 if (c.isValueCompletion()) 992 2265 retval = c.value(); … … 996 2269 break; 997 2270 if (c.complType() != Normal) { 998 delete lst;999 2271 return c; 1000 2272 } 1001 2273 } 1002 2274 1003 curr = curr->next;2275 propIt++; 1004 2276 } 1005 2277 1006 delete lst; 2278 // bail out on error 2279 KJS_CHECKEXCEPTION 2280 1007 2281 return Completion(Normal, retval); 1008 2282 } 1009 2283 1010 // ECMA 12.4 1011 Completion ExprStatementNode::execute() 2284 void ForInNode::processVarDecls(ExecState *exec) 2285 { 2286 statement->processVarDecls(exec); 2287 } 2288 2289 // ------------------------------ ContinueNode --------------------------------- 2290 2291 // ECMA 12.7 2292 Completion ContinueNode::execute(ExecState *exec) 1012 2293 { 1013 2294 KJS_BREAKPOINT; 1014 2295 1015 KJSO e = expr->evaluate(); 1016 KJSO v = e.getValue(); 1017 1018 return Completion(Normal, v); 1019 } 1020 1021 // ECMA 12.5 1022 Completion IfNode::execute() 1023 { 1024 KJS_BREAKPOINT; 1025 1026 KJSO e = expr->evaluate(); 1027 KJSO v = e.getValue(); 1028 Boolean b = v.toBoolean(); 1029 1030 // if ... then 1031 if (b.value()) 1032 return statement1->execute(); 1033 1034 // no else 1035 if (!statement2) 1036 return Completion(Normal); 1037 1038 // else 1039 return statement2->execute(); 1040 } 1041 1042 // ECMA 12.6.1 1043 Completion DoWhileNode::execute() 1044 { 1045 KJS_BREAKPOINT; 1046 1047 KJSO be, bv; 1048 Completion c; 1049 KJSO value; 1050 1051 do { 1052 // bail out on error 1053 if (KJScriptImp::hadException()) 1054 return Completion(Throw, KJScriptImp::exception()); 1055 1056 c = statement->execute(); 1057 if (!((c.complType() == Continue) && ls.contains(c.target()))) { 1058 if ((c.complType() == Break) && ls.contains(c.target())) 1059 return Completion(Normal, value); 1060 if (c.complType() != Normal) 1061 return c; 1062 } 1063 be = expr->evaluate(); 1064 bv = be.getValue(); 1065 } while (bv.toBoolean().value()); 1066 1067 return Completion(Normal, value); 1068 } 1069 1070 // ECMA 12.6.2 1071 Completion WhileNode::execute() 1072 { 1073 KJS_BREAKPOINT; 1074 1075 KJSO be, bv; 1076 Completion c; 1077 Boolean b(false); 1078 KJSO value; 1079 1080 while (1) { 1081 be = expr->evaluate(); 1082 bv = be.getValue(); 1083 b = bv.toBoolean(); 1084 1085 // bail out on error 1086 if (KJScriptImp::hadException()) 1087 return Completion(Throw, KJScriptImp::exception()); 1088 1089 if (!b.value()) 1090 return Completion(Normal, value); 1091 1092 c = statement->execute(); 1093 if (c.isValueCompletion()) 1094 value = c.value(); 1095 1096 if ((c.complType() == Continue) && ls.contains(c.target())) 1097 continue; 1098 if ((c.complType() == Break) && ls.contains(c.target())) 1099 return Completion(Normal, value); 1100 if (c.complType() != Normal) 1101 return c; 1102 } 1103 } 1104 1105 // ECMA 12.7 1106 Completion ContinueNode::execute() 1107 { 1108 KJS_BREAKPOINT; 1109 1110 KJSO dummy; 1111 return Context::current()->seenLabels()->contains(ident) ? 2296 Value dummy; 2297 return exec->context().imp()->seenLabels()->contains(ident) ? 1112 2298 Completion(Continue, dummy, ident) : 1113 2299 Completion(Throw, 1114 throwError(SyntaxError, "Label not found in containing block")); 1115 } 2300 throwError(exec, SyntaxError, "Label not found in containing block")); 2301 } 2302 2303 // ------------------------------ BreakNode ------------------------------------ 1116 2304 1117 2305 // ECMA 12.8 1118 Completion BreakNode::execute( )2306 Completion BreakNode::execute(ExecState *exec) 1119 2307 { 1120 2308 KJS_BREAKPOINT; 1121 2309 1122 KJSOdummy;1123 return Context::current()->seenLabels()->contains(ident) ?2310 Value dummy; 2311 return exec->context().imp()->seenLabels()->contains(ident) ? 1124 2312 Completion(Break, dummy, ident) : 1125 2313 Completion(Throw, 1126 throwError(SyntaxError, "Label not found in containing block")); 2314 throwError(exec, SyntaxError, "Label not found in containing block")); 2315 } 2316 2317 // ------------------------------ ReturnNode ----------------------------------- 2318 2319 ReturnNode::~ReturnNode() 2320 { 2321 } 2322 2323 void ReturnNode::ref() 2324 { 2325 Node::ref(); 2326 if ( value ) 2327 value->ref(); 2328 } 2329 2330 bool ReturnNode::deref() 2331 { 2332 if ( value && value->deref() ) 2333 delete value; 2334 return Node::deref(); 1127 2335 } 1128 2336 1129 2337 // ECMA 12.9 1130 Completion ReturnNode::execute( )2338 Completion ReturnNode::execute(ExecState *exec) 1131 2339 { 1132 2340 KJS_BREAKPOINT; … … 1135 2343 return Completion(ReturnValue, Undefined()); 1136 2344 1137 KJSO e = value->evaluate(); 1138 KJSO v = e.getValue(); 2345 Value e = value->evaluate(exec); 2346 KJS_CHECKEXCEPTION 2347 Value v = e.getValue(exec); 1139 2348 1140 2349 return Completion(ReturnValue, v); 1141 2350 } 1142 2351 2352 // ------------------------------ WithNode ------------------------------------- 2353 2354 WithNode::~WithNode() 2355 { 2356 } 2357 2358 void WithNode::ref() 2359 { 2360 Node::ref(); 2361 if ( statement ) 2362 statement->ref(); 2363 if ( expr ) 2364 expr->ref(); 2365 } 2366 2367 bool WithNode::deref() 2368 { 2369 if ( statement && statement->deref() ) 2370 delete statement; 2371 if ( expr && expr->deref() ) 2372 delete expr; 2373 return Node::deref(); 2374 } 2375 1143 2376 // ECMA 12.10 1144 Completion WithNode::execute( )2377 Completion WithNode::execute(ExecState *exec) 1145 2378 { 1146 2379 KJS_BREAKPOINT; 1147 2380 1148 KJSO e = expr->evaluate(); 1149 KJSO v = e.getValue(); 1150 Object o = v.toObject(); 1151 Context::current()->pushScope(o); 1152 Completion res = stat->execute(); 1153 Context::current()->popScope(); 2381 Value e = expr->evaluate(exec); 2382 KJS_CHECKEXCEPTION 2383 Value v = e.getValue(exec); 2384 Object o = v.toObject(exec); 2385 KJS_CHECKEXCEPTION 2386 exec->context().imp()->pushScope(o); 2387 Completion res = statement->execute(exec); 2388 exec->context().imp()->popScope(); 1154 2389 1155 2390 return res; 2391 } 2392 2393 void WithNode::processVarDecls(ExecState *exec) 2394 { 2395 statement->processVarDecls(exec); 2396 } 2397 2398 // ------------------------------ CaseClauseNode ------------------------------- 2399 2400 CaseClauseNode::~CaseClauseNode() 2401 { 2402 } 2403 2404 void CaseClauseNode::ref() 2405 { 2406 Node::ref(); 2407 if ( expr ) 2408 expr->ref(); 2409 if ( list ) 2410 list->ref(); 2411 } 2412 2413 bool CaseClauseNode::deref() 2414 { 2415 if ( expr && expr->deref() ) 2416 delete expr; 2417 if ( list && list->deref() ) 2418 delete list; 2419 return Node::deref(); 2420 } 2421 2422 // ECMA 12.11 2423 Value CaseClauseNode::evaluate(ExecState *exec) 2424 { 2425 Value e = expr->evaluate(exec); 2426 KJS_CHECKEXCEPTIONVALUE 2427 Value v = e.getValue(exec); 2428 2429 return v; 2430 } 2431 2432 // ECMA 12.11 2433 Completion CaseClauseNode::evalStatements(ExecState *exec) 2434 { 2435 if (list) 2436 return list->execute(exec); 2437 else 2438 return Completion(Normal, Undefined()); 2439 } 2440 2441 void CaseClauseNode::processVarDecls(ExecState *exec) 2442 { 2443 if (list) 2444 list->processVarDecls(exec); 2445 } 2446 2447 // ------------------------------ ClauseListNode ------------------------------- 2448 2449 ClauseListNode::~ClauseListNode() 2450 { 2451 } 2452 2453 void ClauseListNode::ref() 2454 { 2455 Node::ref(); 2456 if ( cl ) 2457 cl->ref(); 2458 if ( nx ) 2459 nx->ref(); 2460 } 2461 2462 bool ClauseListNode::deref() 2463 { 2464 if ( cl && cl->deref() ) 2465 delete cl; 2466 if ( nx && nx->deref() ) 2467 delete nx; 2468 return Node::deref(); 2469 } 2470 2471 Value ClauseListNode::evaluate(ExecState */*exec*/) 2472 { 2473 /* should never be called */ 2474 assert(false); 2475 return Value(); 1156 2476 } 1157 2477 … … 1167 2487 } 1168 2488 2489 void ClauseListNode::processVarDecls(ExecState *exec) 2490 { 2491 if (cl) 2492 cl->processVarDecls(exec); 2493 if (nx) 2494 nx->processVarDecls(exec); 2495 } 2496 2497 // ------------------------------ CaseBlockNode -------------------------------- 2498 2499 CaseBlockNode::~CaseBlockNode() 2500 { 2501 } 2502 2503 void CaseBlockNode::ref() 2504 { 2505 Node::ref(); 2506 if ( def ) 2507 def->ref(); 2508 if ( list1 ) 2509 list1->ref(); 2510 if ( list2 ) 2511 list2->ref(); 2512 } 2513 2514 bool CaseBlockNode::deref() 2515 { 2516 if ( def && def->deref() ) 2517 delete def; 2518 if ( list1 && list1->deref() ) 2519 delete list1; 2520 if ( list2 && list2->deref() ) 2521 delete list2; 2522 return Node::deref(); 2523 } 2524 2525 Value CaseBlockNode::evaluate(ExecState */*exec*/) 2526 { 2527 /* should never be called */ 2528 assert(false); 2529 return Value(); 2530 } 2531 1169 2532 // ECMA 12.11 1170 Completion SwitchNode::execute() 1171 { 1172 KJS_BREAKPOINT; 1173 1174 KJSO e = expr->evaluate(); 1175 KJSO v = e.getValue(); 1176 Completion res = block->evalBlock(v); 1177 1178 if ((res.complType() == Break) && ls.contains(res.target())) 1179 return Completion(Normal, res.value()); 1180 else 1181 return res; 1182 } 1183 1184 // ECMA 12.11 1185 Completion CaseBlockNode::evalBlock(const KJSO& input) 1186 { 1187 KJSO v; 2533 Completion CaseBlockNode::evalBlock(ExecState *exec, const Value& input) 2534 { 2535 Value v; 1188 2536 Completion res; 1189 2537 ClauseListNode *a = list1, *b = list2; … … 1194 2542 clause = a->clause(); 1195 2543 a = a->next(); 1196 v = clause->evaluate(); 1197 if (strictEqual(input, v)) { 1198 res = clause->evalStatements(); 2544 v = clause->evaluate(exec); 2545 KJS_CHECKEXCEPTION 2546 if (strictEqual(exec, input, v)) { 2547 res = clause->evalStatements(exec); 1199 2548 if (res.complType() != Normal) 1200 2549 return res; 1201 2550 while (a) { 1202 res = a->clause()->evalStatements( );2551 res = a->clause()->evalStatements(exec); 1203 2552 if (res.complType() != Normal) 1204 2553 return res; … … 1213 2562 clause = b->clause(); 1214 2563 b = b->next(); 1215 v = clause->evaluate(); 1216 if (strictEqual(input, v)) { 1217 res = clause->evalStatements(); 2564 v = clause->evaluate(exec); 2565 KJS_CHECKEXCEPTION 2566 if (strictEqual(exec, input, v)) { 2567 res = clause->evalStatements(exec); 1218 2568 if (res.complType() != Normal) 1219 2569 return res; … … 1224 2574 // default clause 1225 2575 if (def) { 1226 res = def->evalStatements( );2576 res = def->evalStatements(exec); 1227 2577 if (res.complType() != Normal) 1228 2578 return res; … … 1232 2582 while (b) { 1233 2583 clause = b->clause(); 1234 res = clause->evalStatements( );2584 res = clause->evalStatements(exec); 1235 2585 if (res.complType() != Normal) 1236 2586 return res; … … 1238 2588 } 1239 2589 2590 // bail out on error 2591 KJS_CHECKEXCEPTION 2592 1240 2593 return Completion(Normal); 1241 2594 } 1242 2595 2596 void CaseBlockNode::processVarDecls(ExecState *exec) 2597 { 2598 if (list1) 2599 list1->processVarDecls(exec); 2600 if (def) 2601 def->processVarDecls(exec); 2602 if (list2) 2603 list2->processVarDecls(exec); 2604 } 2605 2606 // ------------------------------ SwitchNode ----------------------------------- 2607 2608 SwitchNode::~SwitchNode() 2609 { 2610 } 2611 2612 void SwitchNode::ref() 2613 { 2614 Node::ref(); 2615 if ( expr ) 2616 expr->ref(); 2617 if ( block ) 2618 block->ref(); 2619 } 2620 2621 bool SwitchNode::deref() 2622 { 2623 if ( expr && expr->deref() ) 2624 delete expr; 2625 if ( block && block->deref() ) 2626 delete block; 2627 return Node::deref(); 2628 } 2629 1243 2630 // ECMA 12.11 1244 KJSO CaseClauseNode::evaluate() 1245 { 1246 KJSO e = expr->evaluate(); 1247 KJSO v = e.getValue(); 1248 1249 return v; 1250 } 1251 1252 // ECMA 12.11 1253 Completion CaseClauseNode::evalStatements() 1254 { 1255 if (list) 1256 return list->execute(); 2631 Completion SwitchNode::execute(ExecState *exec) 2632 { 2633 KJS_BREAKPOINT; 2634 2635 Value e = expr->evaluate(exec); 2636 KJS_CHECKEXCEPTION 2637 Value v = e.getValue(exec); 2638 Completion res = block->evalBlock(exec,v); 2639 2640 if ((res.complType() == Break) && ls.contains(res.target())) 2641 return Completion(Normal, res.value()); 1257 2642 else 1258 return Completion(Normal, Undefined()); 2643 return res; 2644 } 2645 2646 void SwitchNode::processVarDecls(ExecState *exec) 2647 { 2648 block->processVarDecls(exec); 2649 } 2650 2651 // ------------------------------ LabelNode ------------------------------------ 2652 2653 LabelNode::~LabelNode() 2654 { 2655 } 2656 2657 void LabelNode::ref() 2658 { 2659 Node::ref(); 2660 if ( statement ) 2661 statement->ref(); 2662 } 2663 2664 bool LabelNode::deref() 2665 { 2666 if ( statement && statement->deref() ) 2667 delete statement; 2668 return Node::deref(); 1259 2669 } 1260 2670 1261 2671 // ECMA 12.12 1262 Completion LabelNode::execute( )2672 Completion LabelNode::execute(ExecState *exec) 1263 2673 { 1264 2674 Completion e; 1265 2675 1266 if (! Context::current()->seenLabels()->push(label)) {2676 if (!exec->context().imp()->seenLabels()->push(label)) { 1267 2677 return Completion( Throw, 1268 throwError( SyntaxError, "Duplicated label found" ));2678 throwError(exec, SyntaxError, "Duplicated label found" )); 1269 2679 }; 1270 e = stat ->execute();1271 Context::current()->seenLabels()->pop();2680 e = statement->execute(exec); 2681 exec->context().imp()->seenLabels()->pop(); 1272 2682 1273 2683 if ((e.complType() == Break) && (e.target() == label)) … … 1277 2687 } 1278 2688 2689 void LabelNode::processVarDecls(ExecState *exec) 2690 { 2691 statement->processVarDecls(exec); 2692 } 2693 2694 // ------------------------------ ThrowNode ------------------------------------ 2695 2696 ThrowNode::~ThrowNode() 2697 { 2698 } 2699 2700 void ThrowNode::ref() 2701 { 2702 Node::ref(); 2703 if ( expr ) 2704 expr->ref(); 2705 } 2706 2707 bool ThrowNode::deref() 2708 { 2709 if ( expr && expr->deref() ) 2710 delete expr; 2711 return Node::deref(); 2712 } 2713 1279 2714 // ECMA 12.13 1280 Completion ThrowNode::execute( )2715 Completion ThrowNode::execute(ExecState *exec) 1281 2716 { 1282 2717 KJS_BREAKPOINT; 1283 2718 1284 KJSO v = expr->evaluate().getValue(); 2719 Value e = expr->evaluate(exec); 2720 KJS_CHECKEXCEPTION 2721 Value v = e.getValue(exec); 2722 2723 // bail out on error 2724 KJS_CHECKEXCEPTION 1285 2725 1286 2726 return Completion(Throw, v); 1287 2727 } 1288 2728 2729 // ------------------------------ CatchNode ------------------------------------ 2730 2731 CatchNode::~CatchNode() 2732 { 2733 } 2734 2735 void CatchNode::ref() 2736 { 2737 Node::ref(); 2738 if ( block ) 2739 block->ref(); 2740 } 2741 2742 bool CatchNode::deref() 2743 { 2744 if ( block && block->deref() ) 2745 delete block; 2746 return Node::deref(); 2747 } 2748 2749 Completion CatchNode::execute(ExecState */*exec*/) 2750 { 2751 // should never be reached. execute(exec, arg) is used instead 2752 assert(0L); 2753 return Completion(); 2754 } 2755 1289 2756 // ECMA 12.14 1290 Completion TryNode::execute() 2757 Completion CatchNode::execute(ExecState *exec, const Value &arg) 2758 { 2759 /* TODO: correct ? Not part of the spec */ 2760 2761 exec->clearException(); 2762 2763 Object obj(new ObjectImp()); 2764 obj.put(exec, ident, arg, DontDelete); 2765 exec->context().imp()->pushScope(obj); 2766 Completion c = block->execute(exec); 2767 exec->context().imp()->popScope(); 2768 2769 return c; 2770 } 2771 2772 void CatchNode::processVarDecls(ExecState *exec) 2773 { 2774 block->processVarDecls(exec); 2775 } 2776 2777 // ------------------------------ FinallyNode ---------------------------------- 2778 2779 FinallyNode::~FinallyNode() 2780 { 2781 } 2782 2783 void FinallyNode::ref() 2784 { 2785 Node::ref(); 2786 if ( block ) 2787 block->ref(); 2788 } 2789 2790 bool FinallyNode::deref() 2791 { 2792 if ( block && block->deref() ) 2793 delete block; 2794 return Node::deref(); 2795 } 2796 2797 // ECMA 12.14 2798 Completion FinallyNode::execute(ExecState *exec) 2799 { 2800 return block->execute(exec); 2801 } 2802 2803 void FinallyNode::processVarDecls(ExecState *exec) 2804 { 2805 block->processVarDecls(exec); 2806 } 2807 2808 // ------------------------------ TryNode -------------------------------------- 2809 2810 TryNode::~TryNode() 2811 { 2812 } 2813 2814 void TryNode::ref() 2815 { 2816 Node::ref(); 2817 if ( block ) 2818 block->ref(); 2819 if ( _final ) 2820 _final->ref(); 2821 if ( _catch ) 2822 _catch->ref(); 2823 } 2824 2825 bool TryNode::deref() 2826 { 2827 if ( block && block->deref() ) 2828 delete block; 2829 if ( _final && _final->deref() ) 2830 delete _final; 2831 if ( _catch && _catch->deref() ) 2832 delete _catch; 2833 return Node::deref(); 2834 } 2835 2836 // ECMA 12.14 2837 Completion TryNode::execute(ExecState *exec) 1291 2838 { 1292 2839 KJS_BREAKPOINT; … … 1294 2841 Completion c, c2; 1295 2842 1296 c = block->execute( );2843 c = block->execute(exec); 1297 2844 1298 2845 if (!_final) { 1299 2846 if (c.complType() != Throw) 1300 2847 return c; 1301 return _catch->execute( c.value());2848 return _catch->execute(exec,c.value()); 1302 2849 } 1303 2850 1304 2851 if (!_catch) { 1305 c2 = _final->execute( );2852 c2 = _final->execute(exec); 1306 2853 return (c2.complType() == Normal) ? c : c2; 1307 2854 } 1308 2855 1309 2856 if (c.complType() == Throw) 1310 c = _catch->execute( c.value());1311 1312 c2 = _final->execute( );2857 c = _catch->execute(exec,c.value()); 2858 2859 c2 = _final->execute(exec); 1313 2860 return (c2.complType() == Normal) ? c : c2; 1314 2861 } 1315 2862 1316 Completion CatchNode::execute() 1317 { 1318 // should never be reached. execute(const KJS &arg) is used instead 1319 assert(0L); 1320 return Completion(); 1321 } 1322 1323 // ECMA 12.14 1324 Completion CatchNode::execute(const KJSO &arg) 1325 { 1326 /* TODO: correct ? Not part of the spec */ 1327 KJScriptImp::clearException(); 1328 1329 Object obj; 1330 obj.put(ident, arg, DontDelete); 1331 Context::current()->pushScope(obj); 1332 Completion c = block->execute(); 1333 Context::current()->popScope(); 1334 1335 return c; 1336 } 1337 1338 // ECMA 12.14 1339 Completion FinallyNode::execute() 1340 { 1341 return block->execute(); 1342 } 2863 void TryNode::processVarDecls(ExecState *exec) 2864 { 2865 block->processVarDecls(exec); 2866 if (_final) 2867 _final->processVarDecls(exec); 2868 if (_catch) 2869 _catch->processVarDecls(exec); 2870 } 2871 2872 // ------------------------------ ParameterNode -------------------------------- 2873 2874 ParameterNode::~ParameterNode() 2875 { 2876 } 2877 2878 void ParameterNode::ref() 2879 { 2880 Node::ref(); 2881 if ( next ) 2882 next->ref(); 2883 } 2884 2885 bool ParameterNode::deref() 2886 { 2887 if ( next && next->deref() ) 2888 delete next; 2889 return Node::deref(); 2890 } 2891 2892 ParameterNode* ParameterNode::append(const UString *i) 2893 { 2894 ParameterNode *p = this; 2895 while (p->next) 2896 p = p->next; 2897 2898 p->next = new ParameterNode(i); 2899 2900 return this; 2901 } 2902 2903 // ECMA 13 2904 Value ParameterNode::evaluate(ExecState */*exec*/) 2905 { 2906 return Undefined(); 2907 } 2908 2909 // ------------------------------ FunctionBodyNode ----------------------------- 2910 1343 2911 1344 2912 FunctionBodyNode::FunctionBodyNode(SourceElementsNode *s) 1345 2913 : source(s) 1346 2914 { 1347 #ifdef KJS_DEBUGGER 1348 setLoc(-1, -1); 1349 #endif 2915 setLoc(-1, -1, -1); 2916 //fprintf(stderr,"FunctionBodyNode::FunctionBodyNode %p\n",this); 2917 } 2918 2919 FunctionBodyNode::~FunctionBodyNode() 2920 { 2921 //fprintf(stderr,"FunctionBodyNode::~FunctionBodyNode %p\n",this); 2922 } 2923 2924 void FunctionBodyNode::ref() 2925 { 2926 Node::ref(); 2927 if ( source ) 2928 source->ref(); 2929 //fprintf( stderr, "FunctionBodyNode::ref() %p. Refcount now %d\n", (void*)this, refcount); 2930 } 2931 2932 bool FunctionBodyNode::deref() 2933 { 2934 if ( source && source->deref() ) 2935 delete source; 2936 //fprintf( stderr, "FunctionBodyNode::deref() %p. Refcount now %d\n", (void*)this, refcount-1); 2937 return Node::deref(); 1350 2938 } 1351 2939 1352 2940 // ECMA 13 + 14 for ProgramNode 1353 Completion FunctionBodyNode::execute( )2941 Completion FunctionBodyNode::execute(ExecState *exec) 1354 2942 { 1355 2943 /* TODO: workaround for empty body which I don't see covered by the spec */ … … 1357 2945 return Completion(ReturnValue, Undefined()); 1358 2946 1359 source->processFuncDecl(); 1360 1361 return source->execute(); 2947 source->processFuncDecl(exec); 2948 2949 return source->execute(exec); 2950 } 2951 2952 void FunctionBodyNode::processFuncDecl(ExecState *exec) 2953 { 2954 if (source) 2955 source->processFuncDecl(exec); 2956 } 2957 2958 void FunctionBodyNode::processVarDecls(ExecState *exec) 2959 { 2960 if (source) 2961 source->processVarDecls(exec); 2962 } 2963 2964 // ------------------------------ FuncDeclNode --------------------------------- 2965 2966 FuncDeclNode::~FuncDeclNode() 2967 { 2968 } 2969 2970 void FuncDeclNode::ref() 2971 { 2972 Node::ref(); 2973 if ( param ) 2974 param->ref(); 2975 if ( body ) 2976 body->ref(); 2977 } 2978 2979 bool FuncDeclNode::deref() 2980 { 2981 if ( param && param->deref() ) 2982 delete param; 2983 if ( body && body->deref() ) 2984 delete body; 2985 return Node::deref(); 1362 2986 } 1363 2987 1364 2988 // ECMA 13 1365 void FuncDeclNode::processFuncDecl() 1366 { 1367 const List *sc = Context::current()->pScopeChain(); 1368 /* TODO: let this be an object with [[Class]] property "Function" */ 1369 FunctionImp *fimp = new DeclaredFunctionImp(ident, body, sc); 1370 Function func(fimp); // protect from GC 1371 fimp->put("prototype", Object::create(ObjectClass), DontDelete); 2989 void FuncDeclNode::processFuncDecl(ExecState *exec) 2990 { 2991 const List sc = exec->context().imp()->scopeChain(); 2992 2993 // TODO: let this be an object with [[Class]] property "Function" 2994 FunctionImp *fimp = new DeclaredFunctionImp(exec, ident, body, sc); 2995 Object func(fimp); // protect from GC 2996 2997 // Value proto = exec->interpreter()->builtinObject().construct(exec,List::empty()); 2998 List empty; 2999 Value proto = exec->interpreter()->builtinObject().construct(exec,empty); 3000 func.put(exec, "prototype", proto, Internal|DontDelete); 1372 3001 1373 3002 int plen = 0; … … 1375 3004 fimp->addParameter(p->ident()); 1376 3005 1377 fimp->setLength(plen); 1378 1379 Context::current()->variableObject().put(ident, func); 1380 } 3006 func.put(exec, "length", Number(plen), ReadOnly|DontDelete|DontEnum); 3007 3008 exec->context().imp()->variableObject().put(exec,ident,func); 3009 3010 if (body) { 3011 // hack the scope so that the function gets put as a property of func, and it's scope 3012 // contains the func as well as our current scope 3013 Object oldVar = exec->context().imp()->variableObject(); 3014 exec->context().imp()->setVariableObject(func); 3015 exec->context().imp()->pushScope(func); 3016 body->processFuncDecl(exec); 3017 exec->context().imp()->popScope(); 3018 exec->context().imp()->setVariableObject(oldVar); 3019 } 3020 } 3021 3022 // ------------------------------ FuncExprNode --------------------------------- 3023 3024 FuncExprNode::~FuncExprNode() 3025 { 3026 } 3027 3028 void FuncExprNode::ref() 3029 { 3030 Node::ref(); 3031 if ( param ) 3032 param->ref(); 3033 if ( body ) 3034 body->ref(); 3035 } 3036 3037 bool FuncExprNode::deref() 3038 { 3039 if ( param && param->deref() ) 3040 delete param; 3041 if ( body && body->deref() ) 3042 delete body; 3043 return Node::deref(); 3044 } 3045 1381 3046 1382 3047 // ECMA 13 1383 KJSO FuncExprNode::evaluate() 1384 { 1385 const List *sc = Context::current()->pScopeChain(); 1386 FunctionImp *fimp = new DeclaredFunctionImp(UString::null, body, sc->copy()); 1387 Function ret(fimp); 3048 Value FuncExprNode::evaluate(ExecState *exec) 3049 { 3050 const List sc = exec->context().scopeChain(); 3051 FunctionImp *fimp = new DeclaredFunctionImp(exec, UString::null, body, sc); 3052 Value ret(fimp); 3053 List empty; 3054 Value proto = exec->interpreter()->builtinObject().construct(exec,empty); 3055 fimp->put(exec, "prototype", proto, Internal|DontDelete); 1388 3056 1389 3057 int plen = 0; 1390 3058 for(ParameterNode *p = param; p != 0L; p = p->nextParam(), plen++) 1391 3059 fimp->addParameter(p->ident()); 1392 fimp-> setLength(plen);3060 fimp->put(exec,"length", Number(plen), ReadOnly|DontDelete|DontEnum); 1393 3061 1394 3062 return ret; 1395 3063 } 1396 3064 1397 ParameterNode* ParameterNode::append(const UString *i) 1398 { 1399 ParameterNode *p = this; 1400 while (p->next) 1401 p = p->next; 1402 1403 p->next = new ParameterNode(i); 1404 1405 return this; 1406 } 1407 1408 // ECMA 13 1409 KJSO ParameterNode::evaluate() 1410 { 1411 return Undefined(); 1412 } 1413 1414 void ProgramNode::deleteGlobalStatements() 1415 { 1416 source->deleteStatements(); 3065 // ------------------------------ SourceElementNode ---------------------------- 3066 3067 SourceElementNode::~SourceElementNode() 3068 { 3069 } 3070 3071 void SourceElementNode::ref() 3072 { 3073 Node::ref(); 3074 if ( statement ) 3075 statement->ref(); 3076 if ( function ) 3077 function->ref(); 3078 } 3079 3080 bool SourceElementNode::deref() 3081 { 3082 if ( statement && statement->deref() ) 3083 delete statement; 3084 if ( function && function->deref() ) 3085 delete function; 3086 return Node::deref(); 1417 3087 } 1418 3088 1419 3089 // ECMA 14 1420 Completion SourceElementsNode::execute() 1421 { 1422 if (KJScriptImp::hadException()) 1423 return Completion(Throw, KJScriptImp::exception()); 3090 Completion SourceElementNode::execute(ExecState *exec) 3091 { 3092 if (statement) 3093 return statement->execute(exec); 3094 3095 return Completion(Normal); 3096 } 3097 3098 // ECMA 14 3099 void SourceElementNode::processFuncDecl(ExecState *exec) 3100 { 3101 if (function) 3102 function->processFuncDecl(exec); 3103 } 3104 3105 void SourceElementNode::processVarDecls(ExecState *exec) 3106 { 3107 if (statement) 3108 statement->processVarDecls(exec); 3109 } 3110 3111 // ------------------------------ SourceElementsNode --------------------------- 3112 3113 SourceElementsNode::~SourceElementsNode() 3114 { 3115 } 3116 3117 void SourceElementsNode::ref() 3118 { 3119 Node::ref(); 3120 if ( element ) 3121 element->ref(); 3122 if ( elements ) 3123 elements->ref(); 3124 } 3125 3126 bool SourceElementsNode::deref() 3127 { 3128 if ( element && element->deref() ) 3129 delete element; 3130 if ( elements && elements->deref() ) 3131 delete elements; 3132 return Node::deref(); 3133 } 3134 3135 // ECMA 14 3136 Completion SourceElementsNode::execute(ExecState *exec) 3137 { 3138 KJS_CHECKEXCEPTION 1424 3139 1425 3140 if (!elements) 1426 return element->execute(); 1427 1428 Completion c1 = elements->execute(); 1429 if (KJScriptImp::hadException()) 1430 return Completion(Throw, KJScriptImp::exception()); 3141 return element->execute(exec); 3142 3143 Completion c1 = elements->execute(exec); 3144 KJS_CHECKEXCEPTION 1431 3145 if (c1.complType() != Normal) 1432 3146 return c1; 1433 3147 1434 Completion c2 = element->execute(); 1435 if (KJScriptImp::hadException()) 1436 return Completion(Throw, KJScriptImp::exception()); 1437 1438 return c2; 3148 Completion c2 = element->execute(exec); 3149 KJS_CHECKEXCEPTION 3150 3151 // The spec says to return c2 here, but it seems that mozilla returns c1 if 3152 // c2 doesn't have a value 3153 if (c2.complType() == Normal && c2.value().isNull()) 3154 return c1; 3155 else 3156 return c2; 1439 3157 } 1440 3158 1441 3159 // ECMA 14 1442 void SourceElementsNode::processFuncDecl( )3160 void SourceElementsNode::processFuncDecl(ExecState *exec) 1443 3161 { 1444 3162 if (elements) 1445 elements->processFuncDecl(); 1446 1447 element->processFuncDecl(); 1448 } 1449 1450 void SourceElementsNode::deleteStatements() 1451 { 1452 element->deleteStatements(); 1453 3163 elements->processFuncDecl(exec); 3164 3165 element->processFuncDecl(exec); 3166 } 3167 3168 void SourceElementsNode::processVarDecls(ExecState *exec) 3169 { 1454 3170 if (elements) 1455 elements->deleteStatements(); 1456 } 1457 1458 // ECMA 14 1459 Completion SourceElementNode::execute() 1460 { 1461 if (statement) 1462 return statement->execute(); 1463 1464 return Completion(Normal); 1465 } 1466 1467 // ECMA 14 1468 void SourceElementNode::processFuncDecl() 1469 { 1470 if (function) 1471 function->processFuncDecl(); 1472 } 1473 1474 void SourceElementNode::deleteStatements() 1475 { 1476 delete statement; 1477 } 1478 1479 ArgumentListNode::ArgumentListNode(Node *e) : list(0L), expr(e) {} 1480 1481 VarDeclNode::VarDeclNode(const UString *id, AssignExprNode *in) 1482 : ident(*id), init(in) { } 1483 1484 ArgumentListNode::ArgumentListNode(ArgumentListNode *l, Node *e) : 1485 list(l), expr(e) {} 1486 1487 ArgumentsNode::ArgumentsNode(ArgumentListNode *l) : list(l) {} 3171 elements->processVarDecls(exec); 3172 3173 element->processVarDecls(exec); 3174 } 3175 3176 ProgramNode::ProgramNode(SourceElementsNode *s): FunctionBodyNode(s) { 3177 //fprintf(stderr,"ProgramNode::ProgramNode %p\n",this); 3178 } 3179 3180 ProgramNode::~ProgramNode() { 3181 //fprintf(stderr,"ProgramNode::~ProgramNode %p\n",this); 3182 } -
trunk/JavaScriptCore/kjs/nodes.h
r6 r798 1 // -*- c-basic-offset: 2 -*- 1 2 /* 2 3 * This file is part of the KDE libraries 3 4 * Copyright (C) 1999-2000 Harri Porten ([email protected]) 5 * Copyright (C) 2001 Peter Kelly ([email protected]) 4 6 * 5 7 * This library is free software; you can redistribute it and/or … … 17 19 * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, 18 20 * Boston, MA 02111-1307, USA. 21 * 22 * $Id$ 19 23 */ 20 24 … … 23 27 24 28 #include "internal.h" 25 #include "ustring.h" 26 #include "object.h" 27 #include "types.h" 28 #include "debugger.h" 29 //#include "debugger.h" 30 #ifndef NDEBUG 31 #ifndef __osf__ 32 #include <list> 33 #endif 34 #endif 29 35 30 36 namespace KJS { 31 37 32 class KJSO;33 38 class RegExp; 34 39 class SourceElementsNode; … … 70 75 Node(); 71 76 virtual ~Node(); 72 virtual KJSO evaluate() = 0; 77 virtual Value evaluate(ExecState *exec) = 0; 78 virtual void processVarDecls(ExecState */*exec*/) {} 73 79 int lineNo() const { return line; } 74 static Node *firstNode() { return first; } 75 static void setFirstNode(Node *n) { first = n; } 76 static void deleteAllNodes(); 77 #ifdef KJS_DEBUGGER 78 static bool setBreakpoint(Node *firstNode, int id, int line, bool set); 79 virtual bool setBreakpoint(int, int, bool) { return false; } 80 81 public: 82 // reference counting mechanism 83 virtual void ref() { refcount++; } 84 #ifdef KJS_DEBUG_MEM 85 virtual bool deref() { assert( refcount > 0 ); return (!--refcount); } 86 #else 87 virtual bool deref() { return (!--refcount); } 88 #endif 89 90 91 #ifdef KJS_DEBUG_MEM 92 static void finalCheck(); 80 93 #endif 81 94 protected: 82 KJSO throwError(ErrorType e, const char *msg); 83 private: 84 // disallow assignment and copy-construction 85 Node(const Node &); 95 Value throwError(ExecState *exec, ErrorType e, const char *msg); 96 int line; 97 unsigned int refcount; 98 virtual int sourceId() const { return -1; } 99 private: 100 #ifdef KJS_DEBUG_MEM 101 // List of all nodes, for debugging purposes. Don't remove! 102 static std::list<Node *> s_nodes; 103 #endif 104 // disallow assignment 86 105 Node& operator=(const Node&); 87 int line; 88 static int nodeCount; 89 static Node *first; 90 Node *next, *prev; 106 Node(const Node &other); 91 107 }; 92 108 93 109 class StatementNode : public Node { 94 110 public: 95 #ifdef KJS_DEBUGGER 96 StatementNode() : l0(-1), l1(-1), sid(-1), breakPoint(false) { }97 void setLoc(int line0, int line1 );111 StatementNode(); 112 ~StatementNode(); 113 void setLoc(int line0, int line1, int sourceId); 98 114 int firstLine() const { return l0; } 99 115 int lastLine() const { return l1; } 100 116 int sourceId() const { return sid; } 101 bool hitStatement(); 102 bool abortStatement(); 103 virtual bool setBreakpoint(int id, int line, bool set); 104 #endif 105 virtual Completion execute() = 0; 117 bool hitStatement(ExecState *exec); 118 bool abortStatement(ExecState *exec); 119 virtual Completion execute(ExecState *exec) = 0; 106 120 void pushLabel(const UString *id) { 107 121 if (id) ls.push(*id); … … 110 124 LabelStack ls; 111 125 private: 112 KJSO evaluate() { return Undefined(); } 113 #ifdef KJS_DEBUGGER 126 Value evaluate(ExecState */*exec*/) { return Undefined(); } 114 127 int l0, l1; 115 128 int sid; 116 129 bool breakPoint; 117 #endif118 130 }; 119 131 120 132 class NullNode : public Node { 121 133 public: 122 KJSO evaluate(); 134 NullNode() {} 135 Value evaluate(ExecState *exec); 123 136 }; 124 137 … … 126 139 public: 127 140 BooleanNode(bool v) : value(v) {} 128 KJSO evaluate();141 Value evaluate(ExecState *exec); 129 142 private: 130 143 bool value; … … 134 147 public: 135 148 NumberNode(double v) : value(v) { } 136 KJSO evaluate();149 Value evaluate(ExecState *exec); 137 150 private: 138 151 double value; … … 142 155 public: 143 156 StringNode(const UString *v) { value = *v; } 144 KJSO evaluate();157 Value evaluate(ExecState *exec); 145 158 private: 146 159 UString value; … … 151 164 RegExpNode(const UString &p, const UString &f) 152 165 : pattern(p), flags(f) { } 153 KJSO evaluate();166 Value evaluate(ExecState *exec); 154 167 private: 155 168 UString pattern, flags; … … 158 171 class ThisNode : public Node { 159 172 public: 160 KJSO evaluate(); 173 ThisNode() {} 174 Value evaluate(ExecState *exec); 161 175 }; 162 176 … … 164 178 public: 165 179 ResolveNode(const UString *s) : ident(*s) { } 166 KJSO evaluate();180 Value evaluate(ExecState *exec); 167 181 private: 168 182 UString ident; … … 172 186 public: 173 187 GroupNode(Node *g) : group(g) { } 174 KJSO evaluate(); 188 virtual void ref(); 189 virtual bool deref(); 190 virtual ~GroupNode(); 191 Value evaluate(ExecState *exec); 175 192 private: 176 193 Node *group; … … 180 197 public: 181 198 ElisionNode(ElisionNode *e) : elision(e) { } 182 KJSO evaluate(); 199 virtual void ref(); 200 virtual bool deref(); 201 virtual ~ElisionNode(); 202 Value evaluate(ExecState *exec); 183 203 private: 184 204 ElisionNode *elision; … … 190 210 ElementNode(ElementNode *l, ElisionNode *e, Node *n) 191 211 : list(l), elision(e), node(n) { } 192 KJSO evaluate(); 212 virtual void ref(); 213 virtual bool deref(); 214 virtual ~ElementNode(); 215 Value evaluate(ExecState *exec); 193 216 private: 194 217 ElementNode *list; … … 204 227 ArrayNode(ElisionNode *eli, ElementNode *ele) 205 228 : element(ele), elision(eli), opt(true) { } 206 KJSO evaluate(); 229 virtual void ref(); 230 virtual bool deref(); 231 virtual ~ArrayNode(); 232 Value evaluate(ExecState *exec); 207 233 private: 208 234 ElementNode *element; … … 214 240 public: 215 241 ObjectLiteralNode(Node *l) : list(l) { } 216 KJSO evaluate(); 242 virtual void ref(); 243 virtual bool deref(); 244 virtual ~ObjectLiteralNode(); 245 Value evaluate(ExecState *exec); 217 246 private: 218 247 Node *list; … … 223 252 PropertyValueNode(Node *n, Node *a, Node *l = 0L) 224 253 : name(n), assign(a), list(l) { } 225 KJSO evaluate(); 254 virtual void ref(); 255 virtual bool deref(); 256 virtual ~PropertyValueNode(); 257 Value evaluate(ExecState *exec); 226 258 private: 227 259 Node *name, *assign, *list; … … 232 264 PropertyNode(double d) : numeric(d) { } 233 265 PropertyNode(const UString *s) : str(*s) { } 234 KJSO evaluate();266 Value evaluate(ExecState *exec); 235 267 private: 236 268 double numeric; … … 241 273 public: 242 274 AccessorNode1(Node *e1, Node *e2) : expr1(e1), expr2(e2) {} 243 KJSO evaluate(); 275 virtual void ref(); 276 virtual bool deref(); 277 virtual ~AccessorNode1(); 278 Value evaluate(ExecState *exec); 244 279 private: 245 280 Node *expr1; … … 250 285 public: 251 286 AccessorNode2(Node *e, const UString *s) : expr(e), ident(*s) { } 252 KJSO evaluate(); 287 virtual void ref(); 288 virtual bool deref(); 289 virtual ~AccessorNode2(); 290 Value evaluate(ExecState *exec); 253 291 private: 254 292 Node *expr; … … 260 298 ArgumentListNode(Node *e); 261 299 ArgumentListNode(ArgumentListNode *l, Node *e); 262 KJSO evaluate(); 263 List *evaluateList(); 300 virtual void ref(); 301 virtual bool deref(); 302 virtual ~ArgumentListNode(); 303 Value evaluate(ExecState *exec); 304 List evaluateList(ExecState *exec); 264 305 private: 265 306 ArgumentListNode *list; … … 270 311 public: 271 312 ArgumentsNode(ArgumentListNode *l); 272 KJSO evaluate(); 273 List *evaluateList(); 313 virtual void ref(); 314 virtual bool deref(); 315 virtual ~ArgumentsNode(); 316 Value evaluate(ExecState *exec); 317 List evaluateList(ExecState *exec); 274 318 private: 275 319 ArgumentListNode *list; … … 280 324 NewExprNode(Node *e) : expr(e), args(0L) {} 281 325 NewExprNode(Node *e, ArgumentsNode *a) : expr(e), args(a) {} 282 KJSO evaluate(); 326 virtual void ref(); 327 virtual bool deref(); 328 virtual ~NewExprNode(); 329 Value evaluate(ExecState *exec); 283 330 private: 284 331 Node *expr; … … 289 336 public: 290 337 FunctionCallNode(Node *e, ArgumentsNode *a) : expr(e), args(a) {} 291 KJSO evaluate(); 292 #ifdef KJS_DEBUGGER 293 void steppingInto(bool in); 294 Debugger::Mode previousMode; 295 #endif 338 virtual void ref(); 339 virtual bool deref(); 340 virtual ~FunctionCallNode(); 341 Value evaluate(ExecState *exec); 296 342 private: 297 343 Node *expr; … … 302 348 public: 303 349 PostfixNode(Node *e, Operator o) : expr(e), oper(o) {} 304 KJSO evaluate(); 350 virtual void ref(); 351 virtual bool deref(); 352 virtual ~PostfixNode(); 353 Value evaluate(ExecState *exec); 305 354 private: 306 355 Node *expr; … … 311 360 public: 312 361 DeleteNode(Node *e) : expr(e) {} 313 KJSO evaluate(); 362 virtual void ref(); 363 virtual bool deref(); 364 virtual ~DeleteNode(); 365 Value evaluate(ExecState *exec); 314 366 private: 315 367 Node *expr; … … 319 371 public: 320 372 VoidNode(Node *e) : expr(e) {} 321 KJSO evaluate(); 373 virtual void ref(); 374 virtual bool deref(); 375 virtual ~VoidNode(); 376 Value evaluate(ExecState *exec); 322 377 private: 323 378 Node *expr; … … 327 382 public: 328 383 TypeOfNode(Node *e) : expr(e) {} 329 KJSO evaluate(); 384 virtual void ref(); 385 virtual bool deref(); 386 virtual ~TypeOfNode(); 387 Value evaluate(ExecState *exec); 330 388 private: 331 389 Node *expr; … … 335 393 public: 336 394 PrefixNode(Operator o, Node *e) : oper(o), expr(e) {} 337 KJSO evaluate(); 395 virtual void ref(); 396 virtual bool deref(); 397 virtual ~PrefixNode(); 398 Value evaluate(ExecState *exec); 338 399 private: 339 400 Operator oper; … … 344 405 public: 345 406 UnaryPlusNode(Node *e) : expr(e) {} 346 KJSO evaluate(); 407 virtual void ref(); 408 virtual bool deref(); 409 virtual ~UnaryPlusNode(); 410 Value evaluate(ExecState *exec); 347 411 private: 348 412 Node *expr; … … 352 416 public: 353 417 NegateNode(Node *e) : expr(e) {} 354 KJSO evaluate(); 418 virtual void ref(); 419 virtual bool deref(); 420 virtual ~NegateNode(); 421 Value evaluate(ExecState *exec); 355 422 private: 356 423 Node *expr; … … 360 427 public: 361 428 BitwiseNotNode(Node *e) : expr(e) {} 362 KJSO evaluate(); 429 virtual void ref(); 430 virtual bool deref(); 431 virtual ~BitwiseNotNode(); 432 Value evaluate(ExecState *exec); 363 433 private: 364 434 Node *expr; … … 368 438 public: 369 439 LogicalNotNode(Node *e) : expr(e) {} 370 KJSO evaluate(); 440 virtual void ref(); 441 virtual bool deref(); 442 virtual ~LogicalNotNode(); 443 Value evaluate(ExecState *exec); 371 444 private: 372 445 Node *expr; … … 376 449 public: 377 450 MultNode(Node *t1, Node *t2, char op) : term1(t1), term2(t2), oper(op) {} 378 KJSO evaluate(); 451 virtual void ref(); 452 virtual bool deref(); 453 virtual ~MultNode(); 454 Value evaluate(ExecState *exec); 379 455 private: 380 456 Node *term1, *term2; … … 385 461 public: 386 462 AddNode(Node *t1, Node *t2, char op) : term1(t1), term2(t2), oper(op) {} 387 KJSO evaluate(); 463 virtual void ref(); 464 virtual bool deref(); 465 virtual ~AddNode(); 466 Value evaluate(ExecState *exec); 388 467 private: 389 468 Node *term1, *term2; … … 395 474 ShiftNode(Node *t1, Operator o, Node *t2) 396 475 : term1(t1), term2(t2), oper(o) {} 397 KJSO evaluate(); 476 virtual void ref(); 477 virtual bool deref(); 478 virtual ~ShiftNode(); 479 Value evaluate(ExecState *exec); 398 480 private: 399 481 Node *term1, *term2; … … 405 487 RelationalNode(Node *e1, Operator o, Node *e2) : 406 488 expr1(e1), expr2(e2), oper(o) {} 407 KJSO evaluate(); 489 virtual void ref(); 490 virtual bool deref(); 491 virtual ~RelationalNode(); 492 Value evaluate(ExecState *exec); 408 493 private: 409 494 Node *expr1, *expr2; … … 415 500 EqualNode(Node *e1, Operator o, Node *e2) 416 501 : expr1(e1), expr2(e2), oper(o) {} 417 KJSO evaluate(); 502 virtual void ref(); 503 virtual bool deref(); 504 virtual ~EqualNode(); 505 Value evaluate(ExecState *exec); 418 506 private: 419 507 Node *expr1, *expr2; … … 425 513 BitOperNode(Node *e1, Operator o, Node *e2) : 426 514 expr1(e1), expr2(e2), oper(o) {} 427 KJSO evaluate(); 515 virtual void ref(); 516 virtual bool deref(); 517 virtual ~BitOperNode(); 518 Value evaluate(ExecState *exec); 428 519 private: 429 520 Node *expr1, *expr2; … … 431 522 }; 432 523 524 /** expr1 && expr2, expr1 || expr2 */ 433 525 class BinaryLogicalNode : public Node { 434 526 public: 435 527 BinaryLogicalNode(Node *e1, Operator o, Node *e2) : 436 528 expr1(e1), expr2(e2), oper(o) {} 437 KJSO evaluate(); 529 virtual void ref(); 530 virtual bool deref(); 531 virtual ~BinaryLogicalNode(); 532 Value evaluate(ExecState *exec); 438 533 private: 439 534 Node *expr1, *expr2; … … 441 536 }; 442 537 538 /** The ternary operator, "logical ? expr1 : expr2" */ 443 539 class ConditionalNode : public Node { 444 540 public: 445 541 ConditionalNode(Node *l, Node *e1, Node *e2) : 446 542 logical(l), expr1(e1), expr2(e2) {} 447 KJSO evaluate(); 543 virtual void ref(); 544 virtual bool deref(); 545 virtual ~ConditionalNode(); 546 Value evaluate(ExecState *exec); 448 547 private: 449 548 Node *logical, *expr1, *expr2; … … 453 552 public: 454 553 AssignNode(Node *l, Operator o, Node *e) : left(l), oper(o), expr(e) {} 455 KJSO evaluate(); 554 virtual void ref(); 555 virtual bool deref(); 556 virtual ~AssignNode(); 557 Value evaluate(ExecState *exec); 456 558 private: 457 559 Node *left; … … 463 565 public: 464 566 CommaNode(Node *e1, Node *e2) : expr1(e1), expr2(e2) {} 465 KJSO evaluate(); 567 virtual void ref(); 568 virtual bool deref(); 569 virtual ~CommaNode(); 570 Value evaluate(ExecState *exec); 466 571 private: 467 572 Node *expr1, *expr2; … … 472 577 StatListNode(StatementNode *s) : statement(s), list(0L) { } 473 578 StatListNode(StatListNode *l, StatementNode *s) : statement(s), list(l) { } 474 Completion execute(); 579 virtual void ref(); 580 virtual bool deref(); 581 virtual ~StatListNode(); 582 virtual Completion execute(ExecState *exec); 583 virtual void processVarDecls(ExecState *exec); 475 584 private: 476 585 StatementNode *statement; … … 481 590 public: 482 591 AssignExprNode(Node *e) : expr(e) {} 483 KJSO evaluate(); 592 virtual void ref(); 593 virtual bool deref(); 594 virtual ~AssignExprNode(); 595 Value evaluate(ExecState *exec); 484 596 private: 485 597 Node *expr; … … 489 601 public: 490 602 VarDeclNode(const UString *id, AssignExprNode *in); 491 KJSO evaluate(); 603 virtual void ref(); 604 virtual bool deref(); 605 virtual ~VarDeclNode(); 606 Value evaluate(ExecState *exec); 607 virtual void processVarDecls(ExecState *exec); 492 608 private: 493 609 UString ident; … … 499 615 VarDeclListNode(VarDeclNode *v) : list(0L), var(v) {} 500 616 VarDeclListNode(Node *l, VarDeclNode *v) : list(l), var(v) {} 501 KJSO evaluate(); 617 virtual void ref(); 618 virtual bool deref(); 619 virtual ~VarDeclListNode(); 620 Value evaluate(ExecState *exec); 621 virtual void processVarDecls(ExecState *exec); 502 622 private: 503 623 Node *list; … … 508 628 public: 509 629 VarStatementNode(VarDeclListNode *l) : list(l) {} 510 Completion execute(); 630 virtual void ref(); 631 virtual bool deref(); 632 virtual ~VarStatementNode(); 633 virtual Completion execute(ExecState *exec); 634 virtual void processVarDecls(ExecState *exec); 511 635 private: 512 636 VarDeclListNode *list; … … 515 639 class BlockNode : public StatementNode { 516 640 public: 517 BlockNode(StatListNode *s) : statlist(s) {} 518 Completion execute(); 519 private: 520 StatListNode *statlist; 641 BlockNode(SourceElementsNode *s) : source(s) {} 642 virtual void ref(); 643 virtual bool deref(); 644 virtual ~BlockNode(); 645 virtual Completion execute(ExecState *exec); 646 virtual void processVarDecls(ExecState *exec); 647 private: 648 SourceElementsNode *source; 521 649 }; 522 650 … … 524 652 public: 525 653 EmptyStatementNode() { } // debug 526 Completion execute();654 virtual Completion execute(ExecState *exec); 527 655 }; 528 656 … … 530 658 public: 531 659 ExprStatementNode(Node *e) : expr(e) { } 532 Completion execute(); 660 virtual void ref(); 661 virtual bool deref(); 662 virtual ~ExprStatementNode(); 663 virtual Completion execute(ExecState *exec); 533 664 private: 534 665 Node *expr; … … 539 670 IfNode(Node *e, StatementNode *s1, StatementNode *s2) 540 671 : expr(e), statement1(s1), statement2(s2) {} 541 Completion execute(); 672 virtual void ref(); 673 virtual bool deref(); 674 virtual ~IfNode(); 675 virtual Completion execute(ExecState *exec); 676 virtual void processVarDecls(ExecState *exec); 542 677 private: 543 678 Node *expr; … … 548 683 public: 549 684 DoWhileNode(StatementNode *s, Node *e) : statement(s), expr(e) {} 550 Completion execute(); 685 virtual void ref(); 686 virtual bool deref(); 687 virtual ~DoWhileNode(); 688 virtual Completion execute(ExecState *exec); 689 virtual void processVarDecls(ExecState *exec); 551 690 private: 552 691 StatementNode *statement; … … 557 696 public: 558 697 WhileNode(Node *e, StatementNode *s) : expr(e), statement(s) {} 559 Completion execute(); 698 virtual void ref(); 699 virtual bool deref(); 700 virtual ~WhileNode(); 701 virtual Completion execute(ExecState *exec); 702 virtual void processVarDecls(ExecState *exec); 560 703 private: 561 704 Node *expr; … … 566 709 public: 567 710 ForNode(Node *e1, Node *e2, Node *e3, StatementNode *s) : 568 expr1(e1), expr2(e2), expr3(e3), stat(s) {} 569 Completion execute(); 711 expr1(e1), expr2(e2), expr3(e3), statement(s) {} 712 virtual void ref(); 713 virtual bool deref(); 714 virtual ~ForNode(); 715 virtual Completion execute(ExecState *exec); 716 virtual void processVarDecls(ExecState *exec); 570 717 private: 571 718 Node *expr1, *expr2, *expr3; 572 StatementNode *stat ;719 StatementNode *statement; 573 720 }; 574 721 575 722 class ForInNode : public StatementNode { 576 723 public: 577 ForInNode(Node *l, Node *e, StatementNode *s) : 578 init(0L), lexpr(l), expr(e), stat(s) {} 579 ForInNode(const UString *i, AssignExprNode *in, Node *e, StatementNode *s) 580 : ident(*i), init(in), lexpr(0L), expr(e), stat(s) {} 581 Completion execute(); 724 ForInNode(Node *l, Node *e, StatementNode *s); 725 ForInNode(const UString *i, AssignExprNode *in, Node *e, StatementNode *s); 726 virtual void ref(); 727 virtual bool deref(); 728 virtual ~ForInNode(); 729 virtual Completion execute(ExecState *exec); 730 virtual void processVarDecls(ExecState *exec); 582 731 private: 583 732 UString ident; 584 733 AssignExprNode *init; 585 734 Node *lexpr, *expr; 586 StatementNode *stat; 735 VarDeclNode *varDecl; 736 StatementNode *statement; 587 737 }; 588 738 … … 591 741 ContinueNode() { } 592 742 ContinueNode(const UString *i) : ident(*i) { } 593 Completion execute();743 virtual Completion execute(ExecState *exec); 594 744 private: 595 745 UString ident; … … 600 750 BreakNode() { } 601 751 BreakNode(const UString *i) : ident(*i) { } 602 Completion execute();752 virtual Completion execute(ExecState *exec); 603 753 private: 604 754 UString ident; … … 608 758 public: 609 759 ReturnNode(Node *v) : value(v) {} 610 Completion execute(); 760 virtual void ref(); 761 virtual bool deref(); 762 virtual ~ReturnNode(); 763 virtual Completion execute(ExecState *exec); 611 764 private: 612 765 Node *value; … … 615 768 class WithNode : public StatementNode { 616 769 public: 617 WithNode(Node *e, StatementNode *s) : expr(e), stat(s) {} 618 Completion execute(); 619 private: 620 Node *expr; 621 StatementNode *stat; 770 WithNode(Node *e, StatementNode *s) : expr(e), statement(s) {} 771 virtual void ref(); 772 virtual bool deref(); 773 virtual ~WithNode(); 774 virtual Completion execute(ExecState *exec); 775 virtual void processVarDecls(ExecState *exec); 776 private: 777 Node *expr; 778 StatementNode *statement; 622 779 }; 623 780 … … 625 782 public: 626 783 CaseClauseNode(Node *e, StatListNode *l) : expr(e), list(l) { } 627 KJSO evaluate(); 628 Completion evalStatements(); 784 virtual void ref(); 785 virtual bool deref(); 786 virtual ~CaseClauseNode(); 787 Value evaluate(ExecState *exec); 788 Completion evalStatements(ExecState *exec); 789 virtual void processVarDecls(ExecState *exec); 629 790 private: 630 791 Node *expr; … … 635 796 public: 636 797 ClauseListNode(CaseClauseNode *c) : cl(c), nx(0L) { } 798 virtual void ref(); 799 virtual bool deref(); 800 virtual ~ClauseListNode(); 637 801 ClauseListNode* append(CaseClauseNode *c); 638 KJSO evaluate() { /* should never be called */ return KJSO(); }802 Value evaluate(ExecState *exec); 639 803 CaseClauseNode *clause() const { return cl; } 640 804 ClauseListNode *next() const { return nx; } 805 virtual void processVarDecls(ExecState *exec); 641 806 private: 642 807 CaseClauseNode *cl; … … 648 813 CaseBlockNode(ClauseListNode *l1, CaseClauseNode *d, ClauseListNode *l2) 649 814 : list1(l1), def(d), list2(l2) { } 650 KJSO evaluate() { /* should never be called */ return KJSO(); } 651 Completion evalBlock(const KJSO& input); 815 virtual void ref(); 816 virtual bool deref(); 817 virtual ~CaseBlockNode(); 818 Value evaluate(ExecState *exec); 819 Completion evalBlock(ExecState *exec, const Value& input); 820 virtual void processVarDecls(ExecState *exec); 652 821 private: 653 822 ClauseListNode *list1; … … 659 828 public: 660 829 SwitchNode(Node *e, CaseBlockNode *b) : expr(e), block(b) { } 661 Completion execute(); 830 virtual void ref(); 831 virtual bool deref(); 832 virtual ~SwitchNode(); 833 virtual Completion execute(ExecState *exec); 834 virtual void processVarDecls(ExecState *exec); 662 835 private: 663 836 Node *expr; … … 667 840 class LabelNode : public StatementNode { 668 841 public: 669 LabelNode(const UString *l, StatementNode *s) : label(*l), stat(s) { } 670 Completion execute(); 842 LabelNode(const UString *l, StatementNode *s) : label(*l), statement(s) { } 843 virtual void ref(); 844 virtual bool deref(); 845 virtual ~LabelNode(); 846 virtual Completion execute(ExecState *exec); 847 virtual void processVarDecls(ExecState *exec); 671 848 private: 672 849 UString label; 673 StatementNode *stat ;850 StatementNode *statement; 674 851 }; 675 852 … … 677 854 public: 678 855 ThrowNode(Node *e) : expr(e) {} 679 Completion execute(); 856 virtual void ref(); 857 virtual bool deref(); 858 virtual ~ThrowNode(); 859 virtual Completion execute(ExecState *exec); 680 860 private: 681 861 Node *expr; … … 684 864 class CatchNode : public StatementNode { 685 865 public: 686 CatchNode(UString *i, StatementNode *b) : ident(*i), block(b) {} 687 Completion execute(); 688 Completion execute(const KJSO &arg); 866 CatchNode(const UString *i, StatementNode *b) : ident(*i), block(b) {} 867 virtual void ref(); 868 virtual bool deref(); 869 virtual ~CatchNode(); 870 virtual Completion execute(ExecState *exec); 871 Completion execute(ExecState *exec, const Value &arg); 872 virtual void processVarDecls(ExecState *exec); 689 873 private: 690 874 UString ident; … … 695 879 public: 696 880 FinallyNode(StatementNode *b) : block(b) {} 697 Completion execute(); 881 virtual void ref(); 882 virtual bool deref(); 883 virtual ~FinallyNode(); 884 virtual Completion execute(ExecState *exec); 885 virtual void processVarDecls(ExecState *exec); 698 886 private: 699 887 StatementNode *block; … … 704 892 TryNode(StatementNode *b, Node *c = 0L, Node *f = 0L) 705 893 : block(b), _catch((CatchNode*)c), _final((FinallyNode*)f) {} 706 Completion execute(); 894 virtual void ref(); 895 virtual bool deref(); 896 virtual ~TryNode(); 897 virtual Completion execute(ExecState *exec); 898 virtual void processVarDecls(ExecState *exec); 707 899 private: 708 900 StatementNode *block; … … 715 907 ParameterNode(const UString *i) : id(*i), next(0L) { } 716 908 ParameterNode *append(const UString *i); 717 KJSO evaluate(); 909 virtual void ref(); 910 virtual bool deref(); 911 virtual ~ParameterNode(); 912 Value evaluate(ExecState *exec); 718 913 UString ident() { return id; } 719 914 ParameterNode *nextParam() { return next; } … … 726 921 class FunctionBodyNode : public StatementNode { 727 922 public: 728 FunctionBodyNode(SourceElementsNode *s); 729 Completion execute(); 923 FunctionBodyNode(SourceElementsNode *s); 924 virtual void ref(); 925 virtual bool deref(); 926 virtual ~FunctionBodyNode(); 927 Completion execute(ExecState *exec); 928 virtual void processFuncDecl(ExecState *exec); 929 virtual void processVarDecls(ExecState *exec); 730 930 protected: 731 931 SourceElementsNode *source; 732 932 }; 733 933 … … 736 936 FuncDeclNode(const UString *i, ParameterNode *p, FunctionBodyNode *b) 737 937 : ident(*i), param(p), body(b) { } 738 Completion execute() { /* empty */ return Completion(); } 739 void processFuncDecl(); 938 virtual void ref(); 939 virtual bool deref(); 940 virtual ~FuncDeclNode(); 941 Completion execute(ExecState */*exec*/) 942 { /* empty */ return Completion(); } 943 void processFuncDecl(ExecState *exec); 740 944 private: 741 945 UString ident; … … 748 952 FuncExprNode(ParameterNode *p, FunctionBodyNode *b) 749 953 : param(p), body(b) { } 750 KJSO evaluate(); 954 virtual void ref(); 955 virtual bool deref(); 956 virtual ~FuncExprNode(); 957 Value evaluate(ExecState *exec); 751 958 private: 752 959 ParameterNode *param; … … 758 965 SourceElementNode(StatementNode *s) { statement = s; function = 0L; } 759 966 SourceElementNode(FuncDeclNode *f) { function = f; statement = 0L;} 760 Completion execute(); 761 virtual void processFuncDecl(); 762 void deleteStatements(); 967 virtual void ref(); 968 virtual bool deref(); 969 virtual ~SourceElementNode(); 970 Completion execute(ExecState *exec); 971 virtual void processFuncDecl(ExecState *exec); 972 virtual void processVarDecls(ExecState *exec); 763 973 private: 764 974 StatementNode *statement; … … 766 976 }; 767 977 978 // A linked list of source element nodes 768 979 class SourceElementsNode : public StatementNode { 769 980 public: … … 771 982 SourceElementsNode(SourceElementsNode *s1, SourceElementNode *s2) 772 983 { elements = s1; element = s2; } 773 Completion execute(); 774 virtual void processFuncDecl(); 775 void deleteStatements(); 776 private: 777 SourceElementNode *element; 778 SourceElementsNode *elements; 984 virtual void ref(); 985 virtual bool deref(); 986 virtual ~SourceElementsNode(); 987 Completion execute(ExecState *exec); 988 virtual void processFuncDecl(ExecState *exec); 989 virtual void processVarDecls(ExecState *exec); 990 private: 991 SourceElementNode *element; // 'this' element 992 SourceElementsNode *elements; // pointer to next 779 993 }; 780 994 781 995 class ProgramNode : public FunctionBodyNode { 782 996 public: 783 ProgramNode(SourceElementsNode *s) : FunctionBodyNode(s) { } 784 void deleteGlobalStatements(); 997 ProgramNode(SourceElementsNode *s); 998 ~ProgramNode(); 999 private: 1000 // Disallow copy 1001 ProgramNode(const ProgramNode &other); 785 1002 }; 786 1003 -
trunk/JavaScriptCore/kjs/number_object.cpp
r6 r798 1 // -*- c-basic-offset: 2 -*- 1 2 /* 2 3 * This file is part of the KDE libraries … … 16 17 * License along with this library; if not, write to the Free Software 17 18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 * 20 * $Id$ 18 21 */ 19 22 20 #include "kjs.h" 23 #include "value.h" 24 #include "object.h" 25 #include "types.h" 26 #include "interpreter.h" 21 27 #include "operations.h" 22 28 #include "number_object.h" 29 #include "error_object.h" 30 31 #include "number_object.lut.h" 23 32 24 33 using namespace KJS; 25 34 26 NumberObject::NumberObject(const Object& funcProto, const Object &numProto) 27 : ConstructorImp(funcProto, 1) 35 36 // ------------------------------ NumberInstanceImp ---------------------------- 37 38 const ClassInfo NumberInstanceImp::info = {"Number", 0, 0, 0}; 39 40 NumberInstanceImp::NumberInstanceImp(const Object &proto) 41 : ObjectImp(proto) 28 42 { 29 // Number.Prototype 30 setPrototypeProperty(numProto); 43 } 44 // ------------------------------ NumberPrototypeImp --------------------------- 45 46 // ECMA 15.7.4 47 48 NumberPrototypeImp::NumberPrototypeImp(ExecState *exec, 49 ObjectPrototypeImp *objProto, 50 FunctionPrototypeImp *funcProto) 51 : NumberInstanceImp(Object(objProto)) 52 { 53 Value protect(this); 54 setInternalValue(Number(0)); 55 56 // The constructor will be added later, after NumberObjectImp has been constructed 57 58 put(exec,"toString", Object(new NumberProtoFuncImp(exec,funcProto,NumberProtoFuncImp::ToString, 1)), DontEnum); 59 put(exec,"toLocaleString", Object(new NumberProtoFuncImp(exec,funcProto,NumberProtoFuncImp::ToLocaleString, 0)), DontEnum); 60 put(exec,"valueOf", Object(new NumberProtoFuncImp(exec,funcProto,NumberProtoFuncImp::ValueOf, 0)), DontEnum); 31 61 } 32 62 33 // ECMA 15.7.3 34 KJSO NumberObject::get(const UString &p) const 63 64 // ------------------------------ NumberProtoFuncImp --------------------------- 65 66 NumberProtoFuncImp::NumberProtoFuncImp(ExecState *exec, 67 FunctionPrototypeImp *funcProto, int i, int len) 68 : InternalFunctionImp(funcProto), id(i) 35 69 { 36 double d; 37 38 if (p == "NaN") 39 d = NaN; 40 else if (p == "NEGATIVE_INFINITY") 41 d = -Inf; 42 else if (p == "POSITIVE_INFINITY") 43 d = Inf; 44 else 45 return Imp::get(p); 46 47 return Number(d); 70 Value protect(this); 71 put(exec,"length",Number(len),DontDelete|ReadOnly|DontEnum); 48 72 } 49 73 74 75 bool NumberProtoFuncImp::implementsCall() const 76 { 77 return true; 78 } 79 80 // ECMA 15.7.4.2 - 15.7.4.7 81 Value NumberProtoFuncImp::call(ExecState *exec, Object &thisObj, const List &/*args*/) 82 { 83 Value result; 84 85 // no generic function. "this" has to be a Number object 86 if (!thisObj.inherits(&NumberInstanceImp::info)) { 87 Object err = Error::create(exec,TypeError); 88 exec->setException(err); 89 return err; 90 } 91 92 // execute "toString()" or "valueOf()", respectively 93 Value v = thisObj.internalValue(); 94 switch (id) { 95 case ToString: 96 case ToLocaleString: /* TODO */ 97 result = String(v.toString(exec)); 98 break; 99 case ValueOf: 100 result = Number(v.toNumber(exec)); 101 break; 102 } 103 104 return result; 105 } 106 107 // ------------------------------ NumberObjectImp ------------------------------ 108 109 const ClassInfo NumberObjectImp::info = {"Number", &InternalFunctionImp::info, &numberTable, 0}; 110 //const ClassInfo NumberObjectImp::info = {"Number", 0, &numberTable, 0}; 111 112 /* Source for number_object.lut.h 113 @begin numberTable 5 114 NaN NumberObjectImp::NaNValue DontEnum 115 NEGATIVE_INFINITY NumberObjectImp::NegInfinity DontEnum 116 POSITIVE_INFINITY NumberObjectImp::PosInfinity DontEnum 117 MAX_VALUE NumberObjectImp::MaxValue DontEnum 118 MIN_VALUE NumberObjectImp::MinValue DontEnum 119 @end 120 */ 121 NumberObjectImp::NumberObjectImp(ExecState *exec, 122 FunctionPrototypeImp *funcProto, 123 NumberPrototypeImp *numberProto) 124 : InternalFunctionImp(funcProto) 125 { 126 Value protect(this); 127 // Number.Prototype 128 put(exec,"prototype", Value(numberProto),DontEnum|DontDelete|ReadOnly); 129 130 // no. of arguments for constructor 131 put(exec,"length", Number(1), ReadOnly|DontDelete|DontEnum); 132 } 133 134 Value NumberObjectImp::get(ExecState *exec, const UString &propertyName) const 135 { 136 return lookupGetValue<NumberObjectImp, InternalFunctionImp>( exec, propertyName, &numberTable, this ); 137 } 138 139 Value NumberObjectImp::getValueProperty(ExecState *, int token) const 140 { 141 // ECMA 15.7.3 142 switch(token) { 143 case NaNValue: 144 return Number(NaN); 145 case NegInfinity: 146 return Number(-Inf); 147 case PosInfinity: 148 return Number(Inf); 149 case MaxValue: 150 return Number(1.7976931348623157E+308); 151 case MinValue: 152 return Number(5E-324); 153 } 154 return Null(); 155 } 156 157 bool NumberObjectImp::implementsConstruct() const 158 { 159 return true; 160 } 161 162 50 163 // ECMA 15.7.1 51 Completion NumberObject::execute(const List &args)164 Object NumberObjectImp::construct(ExecState *exec, const List &args) 52 165 { 166 Object proto = exec->interpreter()->builtinNumberPrototype(); 167 Object obj(new NumberInstanceImp(proto)); 168 53 169 Number n; 54 170 if (args.isEmpty()) 55 171 n = Number(0); 56 172 else 57 n = args[0].toNumber( );173 n = args[0].toNumber(exec); 58 174 59 return Completion(ReturnValue, n); 175 obj.setInternalValue(n); 176 177 return obj; 178 } 179 180 bool NumberObjectImp::implementsCall() const 181 { 182 return true; 60 183 } 61 184 62 185 // ECMA 15.7.2 63 Object NumberObject::construct(const List &args)186 Value NumberObjectImp::call(ExecState *exec, Object &/*thisObj*/, const List &args) 64 187 { 65 Number n;66 188 if (args.isEmpty()) 67 n =Number(0);189 return Number(0); 68 190 else 69 n = args[0].toNumber(); 70 71 return Object::create(NumberClass, n); 191 return Number(args[0].toNumber(exec)); 72 192 } 73 74 class NumberProtoFunc : public InternalFunctionImp {75 public:76 NumberProtoFunc(int i) : id (i) { }77 Completion execute(const List &);78 enum { ToString, ToLocaleString, ValueOf };79 private:80 int id;81 };82 83 // ECMA 15.7.4.2 - 15.7.4.784 Completion NumberProtoFunc::execute(const List &)85 {86 KJSO result;87 88 Object thisObj = Object::dynamicCast(thisValue());89 90 // no generic function. "this" has to be a Number object91 if (thisObj.isNull() || thisObj.getClass() != NumberClass) {92 result = Error::create(TypeError);93 return Completion(ReturnValue, result);94 }95 96 // execute "toString()" or "valueOf()", respectively97 KJSO v = thisObj.internalValue();98 switch (id) {99 case ToString:100 case ToLocaleString: /* TODO */101 result = v.toString();102 break;103 case ValueOf:104 result = v.toNumber();105 break;106 }107 108 return Completion(ReturnValue, result);109 }110 111 // ECMA 15.7.4112 NumberPrototype::NumberPrototype(const Object& proto)113 : ObjectImp(NumberClass, Number(0), proto)114 {115 // The constructor will be added later in NumberObject's constructor116 }117 118 KJSO NumberPrototype::get(const UString &p) const119 {120 int t;121 if (p == "toString")122 t = NumberProtoFunc::ToString;123 else if (p == "toLocaleString")124 t = NumberProtoFunc::ToLocaleString;125 else if (p == "valueOf")126 t = NumberProtoFunc::ValueOf;127 else128 return Imp::get(p);129 130 return Function(new NumberProtoFunc(t));131 } -
trunk/JavaScriptCore/kjs/number_object.h
r6 r798 1 // -*- c-basic-offset: 2 -*- 1 2 /* 2 3 * This file is part of the KDE libraries … … 16 17 * License along with this library; if not, write to the Free Software 17 18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 * 20 * $Id$ 18 21 */ 19 22 … … 21 24 #define _NUMBER_OBJECT_H_ 22 25 23 #include " object.h"24 #include "function .h"26 #include "internal.h" 27 #include "function_object.h" 25 28 26 29 namespace KJS { 27 30 28 class Number Object : public ConstructorImp {31 class NumberInstanceImp : public ObjectImp { 29 32 public: 30 NumberObject(const Object& funcProto, const Object &numProto); 31 virtual KJSO get(const UString &p) const; 33 NumberInstanceImp(const Object &proto); 34 35 virtual const ClassInfo *classInfo() const { return &info; } 36 static const ClassInfo info; 37 }; 38 39 /** 40 * @internal 41 * 42 * The initial value of Number.prototype (and thus all objects created 43 * with the Number constructor 44 */ 45 class NumberPrototypeImp : public NumberInstanceImp { 46 public: 47 NumberPrototypeImp(ExecState *exec, 48 ObjectPrototypeImp *objProto, 49 FunctionPrototypeImp *funcProto); 50 }; 51 52 /** 53 * @internal 54 * 55 * Class to implement all methods that are properties of the 56 * Number.prototype object 57 */ 58 class NumberProtoFuncImp : public InternalFunctionImp { 59 public: 60 NumberProtoFuncImp(ExecState *exec, FunctionPrototypeImp *funcProto, 61 int i, int len); 62 63 virtual bool implementsCall() const; 64 virtual Value call(ExecState *exec, Object &thisObj, const List &args); 65 66 enum { ToString, ToLocaleString, ValueOf }; 67 private: 68 int id; 69 }; 70 71 /** 72 * @internal 73 * 74 * The initial value of the the global variable's "Number" property 75 */ 76 class NumberObjectImp : public InternalFunctionImp { 77 public: 78 NumberObjectImp(ExecState *exec, 79 FunctionPrototypeImp *funcProto, 80 NumberPrototypeImp *numberProto); 81 82 virtual bool implementsConstruct() const; 83 virtual Object construct(ExecState *exec, const List &args); 84 85 virtual bool implementsCall() const; 86 virtual Value call(ExecState *exec, Object &thisObj, const List &args); 87 88 Value get(ExecState *exec, const UString &p) const; 89 Value getValueProperty(ExecState *exec, int token) const; 90 virtual const ClassInfo *classInfo() const { return &info; } 91 static const ClassInfo info; 92 enum { NaNValue, NegInfinity, PosInfinity, MaxValue, MinValue }; 93 32 94 Completion execute(const List &); 33 95 Object construct(const List &); 34 };35 36 class NumberPrototype : public ObjectImp {37 public:38 NumberPrototype(const Object& proto);39 virtual KJSO get(const UString &p) const;40 96 }; 41 97 -
trunk/JavaScriptCore/kjs/object.cpp
r6 r798 1 // -*- c-basic-offset: 2 -*- 1 2 /* 2 3 * This file is part of the KDE libraries 3 * Copyright (C) 1999-2000 Harri Porten ([email protected]) 4 * Copyright (C) 1999-2001 Harri Porten ([email protected]) 5 * Copyright (C) 2001 Peter Kelly ([email protected]) 4 6 * 5 7 * This library is free software; you can redistribute it and/or … … 17 19 * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, 18 20 * Boston, MA 02111-1307, USA. 21 * 22 * $Id$ 19 23 */ 20 24 25 #include "value.h" 21 26 #include "object.h" 22 23 #ifdef HAVE_CONFIG_H 24 #include <config.h> 25 #endif 27 #include "types.h" 28 #include "interpreter.h" 29 #include "lookup.h" 30 31 #include <assert.h> 32 #include <math.h> 26 33 #include <stdio.h> 27 #include <string.h> 28 #include <math.h> 29 30 #include "kjs.h" 31 #include "types.h" 34 32 35 #include "internal.h" 36 #include "collector.h" 33 37 #include "operations.h" 34 #include "collector.h"35 38 #include "error_object.h" 36 37 namespace KJS { 38 39 #ifdef WORDS_BIGENDIAN 40 unsigned char NaN_Bytes[] = { 0x7f, 0xf8, 0, 0, 0, 0, 0, 0 }; 41 unsigned char Inf_Bytes[] = { 0x7f, 0xf0, 0, 0, 0, 0, 0, 0 }; 42 #elif defined(arm) 43 unsigned char NaN_Bytes[] = { 0, 0, 0xf8, 0x7f, 0, 0, 0, 0 }; 44 unsigned char Inf_Bytes[] = { 0, 0, 0xf0, 0x7f, 0, 0, 0, 0 }; 45 #else 46 unsigned char NaN_Bytes[] = { 0, 0, 0, 0, 0, 0, 0xf8, 0x7f }; 47 unsigned char Inf_Bytes[] = { 0, 0, 0, 0, 0, 0, 0xf0, 0x7f }; 48 #endif 49 50 const double NaN = *(const double*) NaN_Bytes; 51 const double Inf = *(const double*) Inf_Bytes; 52 const double D16 = 65536.0; 53 const double D31 = 2147483648.0; /* TODO: remove in next version */ 54 const double D32 = 4294967296.0; 55 56 // TODO: -0 57 }; 39 #include "nodes.h" 40 #include "property_map.h" 58 41 59 42 using namespace KJS; 60 43 61 const TypeInfo Imp::info = { "Imp", AbstractType, 0, 0, 0 }; 62 63 namespace KJS { 64 struct Property { 65 UString name; 66 Imp *object; 67 int attribute; 68 Property *next; 69 }; 70 } 71 72 KJSO::KJSO() 73 : rep(0) 74 { 75 #ifdef KJS_DEBUG_MEM 76 count++; 77 #endif 78 } 79 80 KJSO::KJSO(Imp *d) 81 : rep(d) 82 { 83 #ifdef KJS_DEBUG_MEM 84 count++; 85 #endif 86 87 if (rep) { 88 rep->ref(); 89 rep->setGcAllowed(true); 90 } 91 } 92 93 KJSO::KJSO(const KJSO &o) 94 { 95 #ifdef KJS_DEBUG_MEM 96 count++; 97 #endif 98 99 rep = o.rep; 100 if (rep) { 101 rep->ref(); 102 rep->setGcAllowed(true); 103 } 104 } 105 106 KJSO& KJSO::operator=(const KJSO &o) 107 { 108 if (rep) 109 rep->deref(); 110 rep = o.rep; 111 if (rep) { 112 rep->ref(); 113 rep->setGcAllowed(true); 114 } 115 44 // ------------------------------ Object --------------------------------------- 45 46 Object::Object() : Value() 47 { 48 } 49 50 Object::Object(ObjectImp *v) : Value(v) 51 { 52 } 53 54 Object::Object(const Object &v) : Value(v) 55 { 56 } 57 58 Object::~Object() 59 { 60 } 61 62 Object& Object::operator=(const Object &v) 63 { 64 Value::operator=(v); 116 65 return *this; 117 66 } 118 67 119 KJSO::~KJSO() 120 { 121 #ifdef KJS_DEBUG_MEM 122 count--; 123 #endif 124 125 if (rep) 126 rep->deref(); 127 } 128 129 bool KJSO::isDefined() const 130 { 131 return !isA(UndefinedType); 132 } 133 134 bool KJSO::isNull() const 135 { 136 return !rep; 137 } 138 139 Type KJSO::type() const 140 { 141 #ifdef KJS_VERBOSE 142 if (!rep) 143 fprintf(stderr, "requesting type of null object\n"); 144 #endif 145 146 return rep ? rep->typeInfo()->type : UndefinedType; 147 } 148 149 bool KJSO::isObject() const 150 { 151 return (type() >= ObjectType); 152 } 153 154 bool KJSO::isA(const char *s) const 155 { 156 assert(rep); 157 const TypeInfo *info = rep->typeInfo(); 158 159 if (!s || !info || !info->name) 68 const ClassInfo *Object::classInfo() const 69 { 70 return static_cast<ObjectImp*>(rep)->classInfo(); 71 } 72 73 bool Object::inherits(const ClassInfo *cinfo) const 74 { 75 return static_cast<ObjectImp*>(rep)->inherits(cinfo); 76 } 77 78 Object Object::dynamicCast(const Value &v) 79 { 80 if (v.isNull() || v.type() != ObjectType) 81 return Object(0); 82 83 return Object(static_cast<ObjectImp*>(v.imp())); 84 } 85 86 Value Object::prototype() const 87 { 88 return Value(static_cast<ObjectImp*>(rep)->prototype()); 89 } 90 91 UString Object::className() const 92 { 93 return static_cast<ObjectImp*>(rep)->className(); 94 } 95 96 Value Object::get(ExecState *exec, const UString &propertyName) const 97 { 98 return static_cast<ObjectImp*>(rep)->get(exec,propertyName); 99 } 100 101 void Object::put(ExecState *exec, const UString &propertyName, const Value &value, int attr) 102 { 103 static_cast<ObjectImp*>(rep)->put(exec,propertyName,value,attr); 104 } 105 106 bool Object::canPut(ExecState *exec, const UString &propertyName) const 107 { 108 return static_cast<ObjectImp*>(rep)->canPut(exec,propertyName); 109 } 110 111 bool Object::hasProperty(ExecState *exec, const UString &propertyName, bool recursive) const 112 { 113 return static_cast<ObjectImp*>(rep)->hasProperty(exec,propertyName,recursive); 114 } 115 116 bool Object::deleteProperty(ExecState *exec, const UString &propertyName) 117 { 118 return static_cast<ObjectImp*>(rep)->deleteProperty(exec,propertyName); 119 } 120 121 Value Object::defaultValue(ExecState *exec, Type hint) const 122 { 123 return static_cast<ObjectImp*>(rep)->defaultValue(exec,hint); 124 } 125 126 bool Object::implementsConstruct() const 127 { 128 return static_cast<ObjectImp*>(rep)->implementsConstruct(); 129 } 130 131 Object Object::construct(ExecState *exec, const List &args) 132 { 133 return static_cast<ObjectImp*>(rep)->construct(exec,args); 134 } 135 136 bool Object::implementsCall() const 137 { 138 return static_cast<ObjectImp*>(rep)->implementsCall(); 139 } 140 141 Value Object::call(ExecState *exec, Object &thisObj, const List &args) 142 { 143 return static_cast<ObjectImp*>(rep)->call(exec,thisObj,args); 144 } 145 146 bool Object::implementsHasInstance() const 147 { 148 return static_cast<ObjectImp*>(rep)->implementsHasInstance(); 149 } 150 151 Boolean Object::hasInstance(ExecState *exec, const Value &value) 152 { 153 return static_cast<ObjectImp*>(rep)->hasInstance(exec,value); 154 } 155 156 const List Object::scope() const 157 { 158 return static_cast<ObjectImp*>(rep)->scope(); 159 } 160 161 void Object::setScope(const List &s) 162 { 163 static_cast<ObjectImp*>(rep)->setScope(s); 164 } 165 166 List Object::propList(ExecState *exec, bool recursive) 167 { 168 return static_cast<ObjectImp*>(rep)->propList(exec,recursive); 169 } 170 171 Value Object::internalValue() const 172 { 173 return static_cast<ObjectImp*>(rep)->internalValue(); 174 } 175 176 void Object::setInternalValue(const Value &v) 177 { 178 static_cast<ObjectImp*>(rep)->setInternalValue(v); 179 } 180 181 // ------------------------------ ObjectImp ------------------------------------ 182 183 ObjectImp::ObjectImp(const Object &proto) 184 : _prop(0), _proto(static_cast<ObjectImp*>(proto.imp())), _internalValue(0L), _scope(0) 185 { 186 //fprintf(stderr,"ObjectImp::ObjectImp %p %s\n",(void*)this); 187 _scope = ListImp::empty(); 188 _prop = new PropertyMap(); 189 } 190 191 ObjectImp::ObjectImp() 192 { 193 //fprintf(stderr,"ObjectImp::ObjectImp %p %s\n",(void*)this); 194 _prop = 0; 195 _proto = NullImp::staticNull; 196 _internalValue = 0L; 197 _scope = ListImp::empty(); 198 _prop = new PropertyMap(); 199 } 200 201 ObjectImp::~ObjectImp() 202 { 203 //fprintf(stderr,"ObjectImp::~ObjectImp %p\n",(void*)this); 204 if (_proto) 205 _proto->setGcAllowed(); 206 if (_internalValue) 207 _internalValue->setGcAllowed(); 208 if (_scope) 209 _scope->setGcAllowed(); 210 delete _prop; 211 } 212 213 void ObjectImp::mark() 214 { 215 //fprintf(stderr,"ObjectImp::mark() %p\n",(void*)this); 216 ValueImp::mark(); 217 218 if (_proto && !_proto->marked()) 219 _proto->mark(); 220 221 PropertyMapNode *node = _prop->first(); 222 while (node) { 223 if (!node->value->marked()) 224 node->value->mark(); 225 node = node->next(); 226 } 227 228 if (_internalValue && !_internalValue->marked()) 229 _internalValue->mark(); 230 if (_scope && !_scope->marked()) 231 _scope->mark(); 232 } 233 234 const ClassInfo *ObjectImp::classInfo() const 235 { 236 return 0; 237 } 238 239 bool ObjectImp::inherits(const ClassInfo *info) const 240 { 241 if (!info) 160 242 return false; 161 243 162 if (info->type == HostType && strcmp(s, "HostObject") == 0) 163 return true; 164 165 return (strcmp(s, info->name) == 0); 166 } 167 168 bool KJSO::derivedFrom(const char *s) const 169 { 170 if (!s) 244 const ClassInfo *ci = classInfo(); 245 if (!ci) 171 246 return false; 172 247 173 assert(rep); 174 const TypeInfo *info = rep->typeInfo(); 175 while (info) { 176 if (info->name && strcmp(s, info->name) == 0) 177 return true; 178 info = info->base; 179 } 180 181 return false; 182 } 183 184 KJSO KJSO::toPrimitive(Type preferred) const 185 { 186 assert(rep); 187 return rep->toPrimitive(preferred); 188 } 189 190 Boolean KJSO::toBoolean() const 191 { 192 assert(rep); 193 return rep->toBoolean(); 194 } 195 196 Number KJSO::toNumber() const 197 { 198 assert(rep); 199 return rep->toNumber(); 200 } 201 202 // helper function for toInteger, toInt32, toUInt32 and toUInt16 203 double KJSO::round() const 204 { 205 if (isA(UndefinedType)) /* TODO: see below */ 206 return 0.0; 207 Number n = toNumber(); 208 if (n.value() == 0.0) /* TODO: -0, NaN, Inf */ 209 return 0.0; 210 double d = floor(fabs(n.value())); 211 if (n.value() < 0) 212 d *= -1; 213 214 return d; 215 } 216 217 // ECMA 9.4 218 Number KJSO::toInteger() const 219 { 220 return Number(round()); 221 } 222 223 // ECMA 9.5 224 int KJSO::toInt32() const 225 { 226 double d = round(); 227 double d32 = fmod(d, D32); 228 229 if (d32 >= D32 / 2.0) 230 d32 -= D32; 231 232 return static_cast<int>(d32); 233 } 234 235 // ECMA 9.6 236 unsigned int KJSO::toUInt32() const 237 { 238 double d = round(); 239 double d32 = fmod(d, D32); 240 241 return static_cast<unsigned int>(d32); 242 } 243 244 // ECMA 9.7 245 unsigned short KJSO::toUInt16() const 246 { 247 double d = round(); 248 double d16 = fmod(d, D16); 249 250 return static_cast<unsigned short>(d16); 251 } 252 253 String KJSO::toString() const 254 { 255 assert(rep); 256 return rep->toString(); 257 } 258 259 Object KJSO::toObject() const 260 { 261 assert(rep); 262 if (isObject()) 263 return Object(rep); 264 265 return rep->toObject(); 266 } 267 268 bool KJSO::implementsCall() const 269 { 270 return (type() == FunctionType || 271 type() == InternalFunctionType || 272 type() == ConstructorType || 273 type() == DeclaredFunctionType || 274 type() == AnonymousFunctionType); 275 } 276 277 // [[call]] 278 KJSO KJSO::executeCall(const KJSO &thisV, const List *args) 279 { 280 assert(rep); 281 assert(implementsCall()); 282 return (static_cast<FunctionImp*>(rep))->executeCall(thisV.imp(), args); 283 } 284 285 KJSO KJSO::executeCall(const KJSO &thisV, const List *args, const List *extraScope) const 286 { 287 assert(rep); 288 assert(implementsCall()); 289 return (static_cast<FunctionImp*>(rep))->executeCall(thisV.imp(), args, extraScope); 290 } 291 292 void KJSO::setConstructor(KJSO c) 293 { 294 put("constructor", c, DontEnum | DontDelete | ReadOnly); 295 } 296 297 // ECMA 8.7.1 298 KJSO KJSO::getBase() const 299 { 300 if (!isA(ReferenceType)) 301 return Error::create(ReferenceError, I18N_NOOP("Invalid reference base")); 302 303 return ((ReferenceImp*)rep)->getBase(); 304 } 305 306 // ECMA 8.7.2 307 UString KJSO::getPropertyName() const 308 { 309 if (!isA(ReferenceType)) 310 // the spec wants a runtime error here. But getValue() and putValue() 311 // will catch this case on their own earlier. When returning a Null 312 // string we should be on the safe side. 313 return UString(); 314 315 return ((ReferenceImp*)rep)->getPropertyName(); 316 } 317 318 // ECMA 8.7.1 319 KJSO KJSO::getValue() const 320 { 321 if (!isA(ReferenceType)) { 322 return *this; 323 } 324 KJSO o = getBase(); 325 if (o.isNull() || o.isA(NullType)) { 326 UString m = I18N_NOOP("Can't find variable: ") + getPropertyName(); 327 return Error::create(ReferenceError, m.ascii()); 328 } 329 330 return o.get(getPropertyName()); 331 } 332 333 /* TODO: remove in next version */ 334 KJSO KJSO::getValue() 335 { 336 return const_cast<const KJSO*>(this)->getValue(); 337 } 338 339 // ECMA 8.7.2 340 ErrorType KJSO::putValue(const KJSO& v) 341 { 342 if (!isA(ReferenceType)) 343 return ReferenceError; 344 345 KJSO o = getBase(); 346 if (o.isA(NullType)) 347 Global::current().put(getPropertyName(), v); 348 else { 349 // are we writing into an array ? 350 if (o.isA(ObjectType) && (o.toObject().getClass() == ArrayClass)) 351 o.putArrayElement(getPropertyName(), v); 248 while (ci && ci != info) 249 ci = ci->parentClass; 250 251 return (ci == info); 252 } 253 254 Type ObjectImp::type() const 255 { 256 return ObjectType; 257 } 258 259 Value ObjectImp::prototype() const 260 { 261 return Value(_proto); 262 } 263 264 void ObjectImp::setPrototype(const Value &proto) 265 { 266 _proto = proto.imp(); 267 } 268 269 UString ObjectImp::className() const 270 { 271 const ClassInfo *ci = classInfo(); 272 if ( ci ) 273 return ci->className; 274 return "Object"; 275 } 276 277 Value ObjectImp::get(ExecState *exec, const UString &propertyName) const 278 { 279 if (propertyName == "__proto__") { 280 Object proto = Object::dynamicCast(prototype()); 281 // non-standard netscape extension 282 if (proto.isNull()) 283 return Null(); 352 284 else 353 o.put(getPropertyName(), v); 354 } 355 356 return NoError; 357 } 358 359 void KJSO::setPrototype(const KJSO& p) 360 { 361 assert(rep); 362 rep->setPrototype(p); 363 } 364 365 void KJSO::setPrototypeProperty(const KJSO& p) 366 { 367 assert(rep); 368 put("prototype", p, DontEnum | DontDelete | ReadOnly); 369 } 370 371 KJSO KJSO::prototype() const 372 { 373 if (rep) 374 return KJSO(rep->proto); 375 else 376 return KJSO(); 377 } 378 379 // ECMA 8.6.2.1 380 KJSO KJSO::get(const UString &p) const 381 { 382 assert(rep); 383 return rep->get(p); 285 return proto; 286 } 287 288 ValueImp *imp = getDirect(propertyName); 289 if ( imp ) 290 return Value(imp); 291 292 Object proto = Object::dynamicCast(prototype()); 293 if (proto.isNull()) 294 return Undefined(); 295 296 return proto.get(exec,propertyName); 297 } 298 299 // This get method only looks at the property map. 300 // A bit like hasProperty(recursive=false), this doesn't go to the prototype. 301 // This is used e.g. by lookupOrCreateFunction (to cache a function, we don't want 302 // to look up in the prototype, it might already exist there) 303 ValueImp* ObjectImp::getDirect(const UString& propertyName) const 304 { 305 return _prop->get(propertyName); 384 306 } 385 307 386 308 // ECMA 8.6.2.2 387 void KJSO::put(const UString &p, const KJSO& v) 388 { 389 assert(rep); 390 rep->put(p, v); 391 } 392 393 // ECMA 8.6.2.2 394 void KJSO::put(const UString &p, const KJSO& v, int attr) 395 { 396 static_cast<Imp*>(rep)->put(p, v, attr); 397 } 398 399 // provided for convenience. 400 void KJSO::put(const UString &p, double d, int attr) 401 { 402 put(p, Number(d), attr); 403 } 404 405 // provided for convenience. 406 void KJSO::put(const UString &p, int i, int attr) 407 { 408 put(p, Number(i), attr); 409 } 410 411 // provided for convenience. 412 void KJSO::put(const UString &p, unsigned int u, int attr) 413 { 414 put(p, Number(u), attr); 415 } 416 417 // ECMA 15.4.5.1 418 void KJSO::putArrayElement(const UString &p, const KJSO& v) 419 { 420 assert(rep); 421 rep->putArrayElement(p, v); 422 } 423 424 // ECMA 8.6.2.3 425 bool KJSO::canPut(const UString &p) const 426 { 427 assert(rep); 428 return rep->canPut(p); 429 } 430 431 // ECMA 8.6.2.4 432 bool KJSO::hasProperty(const UString &p, bool recursive) const 433 { 434 assert(rep); 435 return rep->hasProperty(p, recursive); 436 } 437 438 // ECMA 8.6.2.5 439 bool KJSO::deleteProperty(const UString &p) 440 { 441 assert(rep); 442 return rep->deleteProperty(p); 443 } 444 445 Object::Object(Imp *d) : KJSO(d) { } 446 447 Object::Object(Class c) : KJSO(new ObjectImp(c)) { } 448 449 Object::Object(Class c, const KJSO& v) : KJSO(new ObjectImp(c, v)) { } 450 451 Object::Object(Class c, const KJSO& v, const Object& p) 452 : KJSO(new ObjectImp(c, v)) 453 { 454 setPrototype(p); 455 } 456 457 Object::~Object() { } 458 459 void Object::setClass(Class c) 460 { 461 static_cast<ObjectImp*>(rep)->cl = c; 462 } 463 464 Class Object::getClass() const 465 { 466 assert(rep); 467 return static_cast<ObjectImp*>(rep)->cl; 468 } 469 470 void Object::setInternalValue(const KJSO& v) 471 { 472 assert(rep); 473 static_cast<ObjectImp*>(rep)->val = v.imp(); 474 } 475 476 KJSO Object::internalValue() 477 { 478 assert(rep); 479 return KJSO(static_cast<ObjectImp*>(rep)->val); 480 } 481 482 Object Object::create(Class c) 483 { 484 return Object::create(c, KJSO()); 485 } 486 487 // factory 488 Object Object::create(Class c, const KJSO& val) 489 { 490 Global global(Global::current()); 491 Object obj = Object(); 492 obj.setClass(c); 493 obj.setInternalValue(val); 494 495 UString p = "[["; 496 switch (c) { 497 case UndefClass: 498 case ObjectClass: 499 p += "Object"; 500 break; 501 case FunctionClass: 502 p += "Function"; 503 break; 504 case ArrayClass: 505 p += "Array"; 506 obj.put("length", Number(0), DontEnum | DontDelete); 507 break; 508 case StringClass: 509 p += "String"; 510 obj.put("length", val.toString().value().size()); 511 break; 512 case BooleanClass: 513 p += "Boolean"; 514 break; 515 case NumberClass: 516 p += "Number"; 517 break; 518 case DateClass: 519 p += "Date"; 520 break; 521 case RegExpClass: 522 p += "RegExp"; 523 break; 524 case ErrorClass: 525 p += "Error"; 526 break; 527 } 528 p += ".prototype]]"; 529 530 // KJSO prot = global.get(p).get("prototype"); 531 KJSO prot = global.get(p); 532 assert(prot.isDefined()); 533 534 obj.setPrototype(prot); 535 return obj; 536 } 537 538 Object Object::create(Class c, const KJSO& val, const Object& p) 539 { 540 Global global(Global::current()); 541 Object obj = Object(); 542 Object prot; 543 obj.setClass(c); 544 obj.setInternalValue(val); 545 546 prot = p; 547 obj.setPrototype(prot); 548 return obj; 549 } 550 551 Object Object::dynamicCast(const KJSO &obj) 552 { 553 // return null object on type mismatch 554 if (!obj.isA(ObjectType)) 555 return Object(0L); 556 557 return Object(obj.imp()); 558 559 } 560 561 #ifdef KJS_DEBUG_MEM 562 int KJSO::count = 0; 563 int Imp::count = 0; 564 int List::count = 0; 565 #endif 566 567 Imp::Imp() 568 : refcount(0), prop(0), proto(0) 569 { 570 setCreated(true); 571 #ifdef KJS_DEBUG_MEM 572 count++; 573 #endif 574 } 575 576 Imp::~Imp() 577 { 578 #ifdef KJS_DEBUG_MEM 579 assert(Collector::collecting); 580 count--; 581 #endif 582 583 // dangling pointer during garbage collection ! 584 // if (proto) 585 // proto->deref(); 586 587 // delete attached properties 588 Property *tmp, *p = prop; 589 while (p) { 590 tmp = p; 591 p = p->next; 592 delete tmp; 593 } 594 } 595 596 KJSO Imp::toPrimitive(Type preferred) const 597 { 598 return defaultValue(preferred); 599 /* TODO: is there still any need to throw a runtime error _here_ ? */ 600 } 601 602 Boolean Imp::toBoolean() const 603 { 604 return Boolean(); 605 } 606 607 Number Imp::toNumber() const 608 { 609 return Number(); 610 } 611 612 String Imp::toString() const 613 { 614 return String(); 615 } 616 617 Object Imp::toObject() const 618 { 619 return Object(Error::create(TypeError).imp()); 620 } 621 622 623 PropList* Imp::propList(PropList *first, PropList *last, bool recursive) const 624 { 625 Property *pr = prop; 626 while(pr) { 627 if (!(pr->attribute & DontEnum) && !first->contains(pr->name)) { 628 if(last) { 629 last->next = new PropList(); 630 last = last->next; 631 } else { 632 first = new PropList(); 633 last = first; 634 } 635 last->name = pr->name; 636 } 637 pr = pr->next; 638 } 639 if (proto && recursive) 640 proto->propList(first, last); 641 642 return first; 643 } 644 645 KJSO Imp::get(const UString &p) const 646 { 647 Property *pr = prop; 648 while (pr) { 649 if (pr->name == p) { 650 return pr->object; 651 } 652 pr = pr->next; 653 } 654 655 if (!proto) 656 return Undefined(); 657 658 return proto->get(p); 659 } 660 661 // may be overriden 662 void Imp::put(const UString &p, const KJSO& v) 663 { 664 put(p, v, None); 665 } 666 667 // ECMA 8.6.2.2 668 void Imp::put(const UString &p, const KJSO& v, int attr) 669 { 309 void ObjectImp::put(ExecState *exec, const UString &propertyName, 310 const Value &value, int attr) 311 { 312 assert(!value.isNull()); 313 assert(value.type() != ReferenceType); 314 assert(value.type() != CompletionType); 315 assert(value.type() != ListType); 316 670 317 /* TODO: check for write permissions directly w/o this call */ 318 /* Doesn't look very easy with the PropertyMap API - David */ 671 319 // putValue() is used for JS assignemnts. It passes no attribute. 672 320 // Assume that a C++ implementation knows what it is doing 673 321 // and let it override the canPut() check. 674 if (attr == None && !canPut(p)) 322 if ((attr == None || attr == DontDelete) && !canPut(exec,propertyName)) { 323 #ifdef KJS_VERBOSE 324 fprintf( stderr, "WARNING: canPut %s said NO\n", propertyName.ascii() ); 325 #endif 675 326 return; 676 677 Property *pr; 678 679 if (prop) { 680 pr = prop; 681 while (pr) { 682 if (pr->name == p) { 683 // replace old value 684 pr->object = v.imp(); 685 pr->attribute = attr; 686 return; 327 } 328 329 if (propertyName == "__proto__") { 330 // non-standard netscape extension 331 setPrototype(value); 332 return; 333 } 334 335 _prop->put(propertyName,value.imp(),attr); 336 } 337 338 // ECMA 8.6.2.3 339 bool ObjectImp::canPut(ExecState *, const UString &propertyName) const 340 { 341 PropertyMapNode *node = _prop->getNode(propertyName); 342 if (node) 343 return!(node->attr & ReadOnly); 344 345 // Look in the static hashtable of properties 346 const HashEntry* e = findPropertyHashEntry(propertyName); 347 if (e) 348 return !(e->attr & ReadOnly); 349 350 // Don't look in the prototype here. We can always put an override 351 // in the object, even if the prototype has a ReadOnly property. 352 return true; 353 } 354 355 // ECMA 8.6.2.4 356 bool ObjectImp::hasProperty(ExecState *exec, const UString &propertyName, bool recursive) const 357 { 358 if (propertyName == "__proto__") 359 return true; 360 if (_prop->get(propertyName)) 361 return true; 362 363 // Look in the static hashtable of properties 364 if (findPropertyHashEntry(propertyName)) 365 return true; 366 367 // Look in the prototype 368 Object proto = Object::dynamicCast(prototype()); 369 if (proto.isNull() || !recursive) 370 return false; 371 372 return proto.hasProperty(exec,propertyName); 373 } 374 375 // ECMA 8.6.2.5 376 bool ObjectImp::deleteProperty(ExecState */*exec*/, const UString &propertyName) 377 { 378 PropertyMapNode *node = _prop->getNode(propertyName); 379 if (node) { 380 if ((node->attr & DontDelete)) 381 return false; 382 _prop->remove(propertyName); 383 return true; 384 } 385 386 // Look in the static hashtable of properties 387 if (findPropertyHashEntry(propertyName)) 388 return false; // No builtin property can be deleted 389 return true; 390 } 391 392 void ObjectImp::deleteAllProperties( ExecState * ) 393 { 394 _prop->clear(); 395 } 396 397 // ECMA 8.6.2.6 398 Value ObjectImp::defaultValue(ExecState *exec, Type hint) const 399 { 400 if (hint != StringType && hint != NumberType) { 401 /* Prefer String for Date objects */ 402 if (_proto == exec->interpreter()->builtinDatePrototype().imp()) 403 hint = StringType; 404 else 405 hint = NumberType; 406 } 407 408 Value v; 409 if (hint == StringType) 410 v = get(exec,"toString"); 411 else 412 v = get(exec,"valueOf"); 413 414 if (v.type() == ObjectType) { 415 Object o = Object(static_cast<ObjectImp*>(v.imp())); 416 if (o.implementsCall()) { // spec says "not primitive type" but ... 417 Object thisObj = Object(const_cast<ObjectImp*>(this)); 418 Value def = o.call(exec,thisObj,List::empty()); 419 Type defType = def.type(); 420 if (defType == UnspecifiedType || defType == UndefinedType || 421 defType == NullType || defType == BooleanType || 422 defType == StringType || defType == NumberType) { 423 return def; 687 424 } 688 pr = pr->next;689 425 } 690 426 } 691 427 692 // add new property 693 pr = new Property; 694 pr->name = p; 695 pr->object = v.imp(); 696 pr->attribute = attr; 697 pr->next = prop; 698 prop = pr; 699 } 700 701 // ECMA 8.6.2.3 702 bool Imp::canPut(const UString &p) const 703 { 704 if (prop) { 705 const Property *pr = prop; 706 while (pr) { 707 if (pr->name == p) 708 return !(pr->attribute & ReadOnly); 709 pr = pr->next; 428 if (hint == StringType) 429 v = get(exec,"valueOf"); 430 else 431 v = get(exec,"toString"); 432 433 if (v.type() == ObjectType) { 434 Object o = Object(static_cast<ObjectImp*>(v.imp())); 435 if (o.implementsCall()) { // spec says "not primitive type" but ... 436 Object thisObj = Object(const_cast<ObjectImp*>(this)); 437 Value def = o.call(exec,thisObj,List::empty()); 438 Type defType = def.type(); 439 if (defType == UnspecifiedType || defType == UndefinedType || 440 defType == NullType || defType == BooleanType || 441 defType == StringType || defType == NumberType) { 442 return def; 443 } 710 444 } 711 445 } 712 if (!proto) 713 return true; 714 715 return proto->canPut(p); 716 } 717 718 // ECMA 8.6.2.4 719 bool Imp::hasProperty(const UString &p, bool recursive) const 720 { 721 const Property *pr = prop; 722 while (pr) { 723 if (pr->name == p) 724 return true; 725 pr = pr->next; 726 } 727 728 if (!proto || !recursive) 729 return false; 730 731 return proto->hasProperty(p); 732 } 733 734 // ECMA 8.6.2.5 735 bool Imp::deleteProperty(const UString &p) 736 { 737 Property *pr = prop; 738 Property **prev = ∝ 739 while (pr) { 740 if (pr->name == p) { 741 if ((pr->attribute & DontDelete)) 742 return false; 743 *prev = pr->next; 744 delete pr; 745 return true; 446 447 Object err = Error::create(exec, TypeError, I18N_NOOP("No default value")); 448 exec->setException(err); 449 return err; 450 } 451 452 const HashEntry* ObjectImp::findPropertyHashEntry( const UString& propertyName ) const 453 { 454 const ClassInfo *info = classInfo(); 455 while (info) { 456 if (info->propHashTable) { 457 const HashEntry *e = Lookup::findEntry(info->propHashTable, propertyName); 458 if (e) 459 return e; 746 460 } 747 prev = &(pr->next); 748 pr = pr->next; 749 } 461 info = info->parentClass; 462 } 463 return 0L; 464 } 465 466 bool ObjectImp::implementsConstruct() const 467 { 468 return false; 469 } 470 471 Object ObjectImp::construct(ExecState */*exec*/, const List &/*args*/) 472 { 473 assert(false); 474 return Object(0); 475 } 476 477 bool ObjectImp::implementsCall() const 478 { 479 return false; 480 } 481 482 Value ObjectImp::call(ExecState */*exec*/, Object &/*thisObj*/, const List &/*args*/) 483 { 484 assert(false); 485 return Object(0); 486 } 487 488 bool ObjectImp::implementsHasInstance() const 489 { 490 return false; 491 } 492 493 Boolean ObjectImp::hasInstance(ExecState */*exec*/, const Value &/*value*/) 494 { 495 assert(false); 496 return Boolean(false); 497 } 498 499 const List ObjectImp::scope() const 500 { 501 return _scope; 502 } 503 504 void ObjectImp::setScope(const List &s) 505 { 506 if (_scope) _scope->setGcAllowed(); 507 _scope = static_cast<ListImp*>(s.imp()); 508 } 509 510 List ObjectImp::propList(ExecState *exec, bool recursive) 511 { 512 List list; 513 if (_proto && _proto->type() == ObjectType && recursive) 514 list = static_cast<ObjectImp*>(_proto)->propList(exec,recursive); 515 516 517 PropertyMapNode *node = _prop->first(); 518 while (node) { 519 if (!(node->attr & DontEnum)) 520 list.append(Reference(Object(this), node->name)); 521 node = node->next(); 522 } 523 524 // Add properties from the static hashtable of properties 525 const ClassInfo *info = classInfo(); 526 while (info) { 527 if (info->propHashTable) { 528 int size = info->propHashTable->size; 529 const HashEntry *e = info->propHashTable->entries; 530 for (int i = 0; i < size; ++i, ++e) { 531 if ( e->s && !(e->attr & DontEnum) ) 532 list.append(Reference(Object(this), e->s)); /// ######### check for duplicates with the propertymap 533 } 534 } 535 info = info->parentClass; 536 } 537 538 return list; 539 } 540 541 Value ObjectImp::internalValue() const 542 { 543 return Value(_internalValue); 544 } 545 546 void ObjectImp::setInternalValue(const Value &v) 547 { 548 _internalValue = v.imp(); 549 } 550 551 // The following functions simply call the corresponding functions in ValueImp 552 // but are overridden in case of future needs 553 554 Value ObjectImp::toPrimitive(ExecState *exec, Type preferredType) const 555 { 556 return defaultValue(exec,preferredType); 557 } 558 559 bool ObjectImp::toBoolean(ExecState */*exec*/) const 560 { 750 561 return true; 751 562 } 752 563 753 // ECMA 15.4.5.1 754 void Imp::putArrayElement(const UString &p, const KJSO& v) 755 { 756 if (!canPut(p)) 757 return; 758 759 if (hasProperty(p)) { 760 if (p == "length") { 761 KJSO len = get("length"); 762 unsigned int oldLen = len.toUInt32(); 763 unsigned int newLen = v.toUInt32(); 764 // shrink array 765 for (unsigned int u = newLen; u < oldLen; u++) { 766 UString p = UString::from(u); 767 if (hasProperty(p, false)) 768 deleteProperty(p); 769 } 770 put("length", Number(newLen), DontEnum | DontDelete); 771 return; 772 } 773 // put(p, v); 774 } // } else 775 put(p, v); 776 777 // array index ? 778 unsigned int idx; 779 if (!sscanf(p.cstring().c_str(), "%u", &idx)) /* TODO */ 780 return; 781 782 // do we need to update/create the length property ? 783 if (hasProperty("length", false)) { 784 KJSO len = get("length"); 785 if (idx < len.toUInt32()) 786 return; 787 } 788 789 put("length", Number(idx+1), DontDelete | DontEnum); 790 } 791 792 bool Imp::implementsCall() const 793 { 794 return (type() == FunctionType || 795 type() == InternalFunctionType || 796 type() == ConstructorType || 797 type() == DeclaredFunctionType || 798 type() == AnonymousFunctionType); 799 } 800 801 // ECMA 8.6.2.6 (new draft) 802 KJSO Imp::defaultValue(Type hint) const 803 { 804 KJSO o; 805 806 /* TODO String on Date object */ 807 if (hint != StringType && hint != NumberType) 808 hint = NumberType; 809 810 if (hint == StringType) 811 o = get("toString"); 812 else 813 o = get("valueOf"); 814 815 Imp *that = const_cast<Imp*>(this); 816 if (o.implementsCall()) { // spec says "not primitive type" but ... 817 FunctionImp *f = static_cast<FunctionImp*>(o.imp()); 818 KJSO s = f->executeCall(that, 0L); 819 if (!s.isObject()) 820 return s; 821 } 822 823 if (hint == StringType) 824 o = get("valueOf"); 825 else 826 o = get("toString"); 827 828 if (o.implementsCall()) { 829 FunctionImp *f = static_cast<FunctionImp*>(o.imp()); 830 KJSO s = f->executeCall(that, 0L); 831 if (!s.isObject()) 832 return s; 833 } 834 835 return Error::create(TypeError, I18N_NOOP("No default value")); 836 } 837 838 void Imp::mark(Imp*) 839 { 840 setMarked(true); 841 842 if (proto && !proto->marked()) 843 proto->mark(); 844 845 struct Property *p = prop; 846 while (p) { 847 if (p->object && !p->object->marked()) 848 p->object->mark(); 849 p = p->next; 850 } 851 } 852 853 bool Imp::marked() const 854 { 855 return prev; 856 } 857 858 void Imp::setPrototype(const KJSO& p) 859 { 860 if (proto) 861 proto->deref(); 862 proto = p.imp(); 863 if (proto) 864 proto->ref(); 865 } 866 867 void Imp::setPrototypeProperty(const KJSO &p) 868 { 869 put("prototype", p, DontEnum | DontDelete | ReadOnly); 870 } 871 872 void Imp::setConstructor(const KJSO& c) 873 { 874 put("constructor", c, DontEnum | DontDelete | ReadOnly); 875 } 876 877 void* Imp::operator new(size_t s) 878 { 879 return Collector::allocate(s); 880 } 881 882 void Imp::operator delete(void*, size_t) 883 { 884 // deprecated. a mistake. 885 } 886 887 void Imp::operator delete(void*) 888 { 889 // Do nothing. So far. 890 } 891 892 void Imp::setMarked(bool m) 893 { 894 prev = m ? this : 0L; 895 } 896 897 void Imp::setGcAllowed(bool a) 898 { 899 next = this; 900 if (a) 901 next++; 902 } 903 904 bool Imp::gcAllowed() const 905 { 906 return (next && next != this); 907 } 908 909 void Imp::setCreated(bool c) 910 { 911 next = c ? this : 0L; 912 } 913 914 bool Imp::created() const 915 { 916 return next; 917 } 918 919 ObjectImp::ObjectImp(Class c) : cl(c), val(0L) { } 920 921 ObjectImp::ObjectImp(Class c, const KJSO &v) : cl(c), val(v.imp()) { } 922 923 ObjectImp::ObjectImp(Class c, const KJSO &v, const KJSO &p) 924 : cl(c), val(v.imp()) 925 { 926 setPrototype(p); 927 } 928 929 ObjectImp::~ObjectImp() { } 930 931 Boolean ObjectImp::toBoolean() const 932 { 933 return Boolean(true); 934 } 935 936 Number ObjectImp::toNumber() const 937 { 938 return toPrimitive(NumberType).toNumber(); 939 } 940 941 String ObjectImp::toString() const 942 { 943 KJSO tmp; 944 String res; 945 946 if (hasProperty("toString") && (tmp = get("toString")).implementsCall()) { 947 // TODO live w/o hack 948 res = tmp.executeCall(KJSO(const_cast<ObjectImp*>(this)), 0L).toString(); 949 } else { 950 tmp = toPrimitive(StringType); 951 res = tmp.toString(); 952 } 953 954 return res; 955 } 956 957 const TypeInfo ObjectImp::info = { "Object", ObjectType, 0, 0, 0 }; 958 959 Object ObjectImp::toObject() const 564 double ObjectImp::toNumber(ExecState *exec) const 565 { 566 Value prim = toPrimitive(exec,NumberType); 567 if (exec->hadException()) // should be picked up soon in nodes.cpp 568 return 0.0; 569 return prim.toNumber(exec); 570 } 571 572 int ObjectImp::toInteger(ExecState *exec) const 573 { 574 return ValueImp::toInteger(exec); 575 } 576 577 int ObjectImp::toInt32(ExecState *exec) const 578 { 579 return ValueImp::toInt32(exec); 580 } 581 582 unsigned int ObjectImp::toUInt32(ExecState *exec) const 583 { 584 return ValueImp::toUInt32(exec); 585 } 586 587 unsigned short ObjectImp::toUInt16(ExecState *exec) const 588 { 589 return ValueImp::toUInt16(exec); 590 } 591 592 UString ObjectImp::toString(ExecState *exec) const 593 { 594 Value prim = toPrimitive(exec,StringType); 595 if (exec->hadException()) // should be picked up soon in nodes.cpp 596 return ""; 597 return prim.toString(exec); 598 } 599 600 Object ObjectImp::toObject(ExecState */*exec*/) const 960 601 { 961 602 return Object(const_cast<ObjectImp*>(this)); 962 603 } 963 604 964 KJSO ObjectImp::toPrimitive(Type preferred) const 965 { 966 // ### Imp already does that now. Remove in KDE 3.0. 967 return defaultValue(preferred); 968 /* TODO: is there still any need to throw a runtime error _here_ ? */ 969 } 970 971 void ObjectImp::mark(Imp*) 972 { 973 // mark objects from the base 974 Imp::mark(); 975 976 // mark internal value, if any and it has not been visited yet 977 if (val && !val->marked()) 978 val->mark(); 979 } 980 981 HostImp::HostImp() 982 { 983 setPrototype(Global::current().objectPrototype()); 984 //printf("HostImp::HostImp() %p\n",this); 985 } 986 987 HostImp::~HostImp() { } 988 989 Boolean HostImp::toBoolean() const 990 { 991 return Boolean(true); 992 } 993 994 String HostImp::toString() const 995 { 996 // Exact copy of ObjectImp::toString.... 997 KJSO tmp; 998 String res; 999 1000 if (hasProperty("toString") && (tmp = get("toString")).implementsCall()) { 1001 // TODO live w/o hack 1002 res = tmp.executeCall(KJSO(const_cast<HostImp*>(this)), 0L).toString(); 1003 } else { 1004 tmp = toPrimitive(StringType); 1005 res = tmp.toString(); 1006 } 1007 1008 return res; 1009 } 1010 1011 const TypeInfo HostImp::info = { "HostObject", HostType, 0, 0, 0 }; 1012 1013 Object Error::createObject(ErrorType e, const char *m, int l) 1014 { 1015 Context *context = Context::current(); 1016 if (!context) 1017 return Object(); 1018 1019 Object err = ErrorObject::create(e, m, l); 1020 1021 if (!KJScriptImp::hadException()) 1022 KJScriptImp::setException(err.imp()); 1023 1024 const struct ErrorStruct { 1025 ErrorType e; 1026 const char *s; 1027 } errtab[] = { 1028 { GeneralError, I18N_NOOP("General error") }, 1029 { EvalError, I18N_NOOP("Evaluation error") }, 1030 { RangeError, I18N_NOOP("Range error") }, 1031 { ReferenceError, I18N_NOOP("Reference error") }, 1032 { SyntaxError, I18N_NOOP("Syntax error") }, 1033 { TypeError, I18N_NOOP("Type error") }, 1034 { URIError, I18N_NOOP("URI error") }, 1035 { (ErrorType)0, 0 } 1036 }; 1037 1038 const char *estr = I18N_NOOP("Unknown error"); 1039 const ErrorStruct *estruct = errtab; 1040 while (estruct->e) { 1041 if (estruct->e == e) { 1042 estr = estruct->s; 1043 break; 1044 } 1045 estruct++; 1046 } 1047 605 606 // ------------------------------ Error ---------------------------------------- 607 608 const char * const errorNamesArr[] = { 609 I18N_NOOP("Error"), // GeneralError 610 I18N_NOOP("Evaluation error"), // EvalError 611 I18N_NOOP("Range error"), // RangeError 612 I18N_NOOP("Reference error"), // ReferenceError 613 I18N_NOOP("Syntax error"), // SyntaxError 614 I18N_NOOP("Type error"), // TypeError 615 I18N_NOOP("URI error"), // URIError 616 }; 617 618 const char * const * const Error::errorNames = errorNamesArr; 619 620 Object Error::create(ExecState *exec, ErrorType errtype, const char *message, 621 int lineno, int sourceId) 622 { 623 Object cons; 624 625 switch (errtype) { 626 case EvalError: 627 cons = exec->interpreter()->builtinEvalError(); 628 break; 629 case RangeError: 630 cons = exec->interpreter()->builtinRangeError(); 631 break; 632 case ReferenceError: 633 cons = exec->interpreter()->builtinReferenceError(); 634 break; 635 case SyntaxError: 636 cons = exec->interpreter()->builtinSyntaxError(); 637 break; 638 case TypeError: 639 cons = exec->interpreter()->builtinTypeError(); 640 break; 641 case URIError: 642 cons = exec->interpreter()->builtinURIError(); 643 break; 644 default: 645 cons = exec->interpreter()->builtinError(); 646 break; 647 } 648 649 if (!message) 650 message = errorNames[errtype]; 651 List args; 652 args.append(String(message)); 653 Object err = Object::dynamicCast(cons.construct(exec,args)); 654 655 if (lineno != -1) 656 err.put(exec, "line", Number(lineno)); 657 if (sourceId != -1) 658 err.put(exec, "sourceId", Number(sourceId)); 659 660 return err; 661 662 /* 1048 663 #ifndef NDEBUG 1049 664 const char *msg = err.get("message").toString().value().ascii(); 1050 665 if (l >= 0) 1051 fprintf(stderr, " JS: %s at line %d. %s\n", estr, l, msg);666 fprintf(stderr, "KJS: %s at line %d. %s\n", estr, l, msg); 1052 667 else 1053 fprintf(stderr, " JS: %s. %s\n", estr, msg);668 fprintf(stderr, "KJS: %s. %s\n", estr, msg); 1054 669 #endif 1055 670 1056 671 return err; 1057 } 1058 1059 KJSO Error::create(ErrorType e, const char *m, int l) 1060 { 1061 return KJSO(createObject(e, m, l).imp()); 1062 } 672 */ 673 } 674 -
trunk/JavaScriptCore/kjs/object.h
r6 r798 1 // -*- c-basic-offset: 2 -*- 1 2 /* 2 3 * This file is part of the KDE libraries 3 4 * Copyright (C) 1999-2001 Harri Porten ([email protected]) 5 * Copyright (C) 2001 Peter Kelly ([email protected]) 4 6 * 5 7 * This library is free software; you can redistribute it and/or … … 17 19 * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, 18 20 * Boston, MA 02111-1307, USA. 21 * 19 22 */ 23 20 24 21 25 #ifndef _KJS_OBJECT_H_ 22 26 #define _KJS_OBJECT_H_ 23 27 24 #include <stdlib.h> 25 26 #include "ustring.h" 27 28 /** 29 * @short Main namespace 30 */ 28 // Objects 29 30 #include "value.h" 31 #include "types.h" 32 31 33 namespace KJS { 32 34 35 class ObjectImpPrivate; 36 class PropertyMap; 37 class HashTable; 38 class HashEntry; 39 class ListImp; 40 41 // ECMA 262-3 8.6.1 42 // Attributes (only applicable to the Object type) 43 enum Attribute { None = 0, 44 ReadOnly = 1 << 1, // property can be only read, not written 45 DontEnum = 1 << 2, // property doesn't appear in (for .. in ..) 46 DontDelete = 1 << 3, // property can't be deleted 47 Internal = 1 << 4, // an internal property, set to by pass checks 48 Function = 1 << 5 }; // property is a function - only used by static hashtables 49 33 50 /** 34 * Types of classes derived from KJSO51 * Class Information 35 52 */ 36 enum Type { // main types 37 AbstractType = 1, 38 UndefinedType, 39 NullType, 40 BooleanType, 41 NumberType, 42 StringType, 43 ObjectType, 44 HostType, 45 ReferenceType, 46 CompletionType, 47 // extended types 48 FunctionType, 49 InternalFunctionType, 50 DeclaredFunctionType, 51 AnonymousFunctionType, 52 ConstructorType, 53 ActivationType 54 }; 55 56 /** 57 * Property attributes. 58 */ 59 enum Attribute { None = 0, 60 ReadOnly = 1 << 1, 61 DontEnum = 1 << 2, 62 DontDelete = 1 << 3, 63 Internal = 1 << 4 }; 64 65 /** 66 * Types of classes derived from @ref Object. 67 */ 68 enum Class { UndefClass, 69 ArrayClass, 70 StringClass, 71 BooleanClass, 72 NumberClass, 73 ObjectClass, 74 DateClass, 75 RegExpClass, 76 ErrorClass, 77 FunctionClass }; 78 79 /** 80 * Completion types. 81 */ 82 enum Compl { Normal, Break, Continue, ReturnValue, Throw }; 83 84 /** 85 * Error codes. 86 */ 87 enum ErrorType { NoError = 0, 88 GeneralError, 89 EvalError, 90 RangeError, 91 ReferenceError, 92 SyntaxError, 93 TypeError, 94 URIError }; 95 96 extern const double NaN; 97 extern const double Inf; 98 99 // forward declarations 100 class Imp; 101 class Boolean; 102 class Number; 103 class String; 104 class Object; 105 struct Property; 106 class PropList; 107 class List; 108 109 /** 110 * @short Type information. 111 */ 112 struct TypeInfo { 113 /** 114 * A string denoting the type name. Example: "Number". 115 */ 116 const char *name; 117 /** 118 * One of the @ref KJS::Type enums. 119 */ 120 Type type; 121 /** 122 * Pointer to the type information of the base class. 123 * NULL if there is none. 124 */ 125 const TypeInfo *base; 126 /** 127 * Additional specifier for your own use. 128 */ 129 int extra; 130 /** 131 * Reserved for future extensions (internal). 53 struct ClassInfo { 54 /** 55 * A string denoting the class name. Example: "Window". 56 */ 57 const char* className; 58 /** 59 * Pointer to the class information of the base class. 60 * 0L if there is none. 61 */ 62 const ClassInfo *parentClass; 63 /** 64 * Static hash-table of properties. 65 */ 66 const HashTable *propHashTable; 67 /** 68 * Reserved for future extension. 132 69 */ 133 70 void *dummy; … … 135 72 136 73 /** 137 * @short Main base class for every KJS object.74 * Represents an Object. This is a wrapper for ObjectImp 138 75 */ 139 class KJSO { 140 friend class ElementNode; 76 class Object : public Value { 141 77 public: 142 /** 143 * Constructor. 144 */ 145 KJSO(); 146 /** 147 * @internal 148 */ 149 KJSO(Imp *d); 150 /** 151 * Copy constructor. 152 */ 153 KJSO(const KJSO &); 154 /* 155 * Assignment operator 156 */ 157 KJSO& operator=(const KJSO &); 158 /** 159 * Destructor. 160 */ 161 virtual ~KJSO(); 162 /** 163 * @return True if this object is null, i.e. if there is no data attached 164 * to this object. Don't confuse this with the Null object. 165 */ 166 bool isNull() const; 167 /** 168 * @return True if this objects is of any other value than Undefined. 169 */ 170 bool isDefined() const; 171 /** 172 * @return the type of the object. One of the @ref KJS::Type enums. 173 */ 78 Object(); 79 explicit Object(ObjectImp *v); 80 Object(const Object &v); 81 virtual ~Object(); 82 83 Object& operator=(const Object &v); 84 85 virtual const ClassInfo *classInfo() const; 86 bool inherits(const ClassInfo *cinfo) const; 87 88 /** 89 * Converts a Value into an Object. If the value's type is not ObjectType, 90 * a null object will be returned (i.e. one with it's internal pointer set 91 * to 0). If you do not know for sure whether the value is of type 92 * ObjectType, you should check the @ref isNull() methods afterwards before 93 * calling any methods on the Object. 94 * 95 * @return The value converted to an object 96 */ 97 static Object dynamicCast(const Value &v); 98 99 /** 100 * Returns the prototype of this object. Note that this is not the same as 101 * the "prototype" property. 102 * 103 * See ECMA 8.6.2 104 * 105 * @return The object's prototype 106 */ 107 Value prototype() const; 108 109 /** 110 * Returns the class name of the object 111 * 112 * See ECMA 8.6.2 113 * 114 * @return The object's class name 115 */ 116 UString className() const; 117 118 /** 119 * Retrieves the specified property from the object. If neither the object 120 * or any other object in it's prototype chain have the property, this 121 * function will return Undefined. 122 * 123 * See ECMA 8.6.2.1 124 * 125 * @param exec The current execution state 126 * @param propertyName The name of the property to retrieve 127 * 128 * @return The specified property, or Undefined 129 */ 130 Value get(ExecState *exec, const UString &propertyName) const; 131 132 /** 133 * Sets the specified property. 134 * 135 * See ECMA 8.6.2.2 136 * 137 * @param exec The current execution state 138 * @param propertyName The name of the property to set 139 * @param propertyValue The value to set 140 */ 141 void put(ExecState *exec, const UString &propertyName, 142 const Value &value, int attr = None); 143 144 /** 145 * Used to check whether or not a particular property is allowed to be set 146 * on an object 147 * 148 * See ECMA 8.6.2.3 149 * 150 * @param exec The current execution state 151 * @param propertyName The name of the property 152 * @return true if the property can be set, otherwise false 153 */ 154 bool canPut(ExecState *exec, const UString &propertyName) const; 155 156 /** 157 * Checks to see whether the object (or any object in it's prototype chain) 158 * has a property with the specified name. 159 * 160 * See ECMA 8.6.2.4 161 * 162 * @param exec The current execution state 163 * @param propertyName The name of the property to check for 164 * @return true if the object has the property, otherwise false 165 */ 166 bool hasProperty(ExecState *exec, const UString &propertyName, 167 bool recursive = true) const; 168 169 /** 170 * Removes the specified property from the object. 171 * 172 * See ECMA 8.6.2.5 173 * 174 * @param exec The current execution state 175 * @param propertyName The name of the property to delete 176 * @return true if the property was successfully deleted or did not 177 * exist on the object. false if deleting the specified property is not 178 * allowed. 179 */ 180 bool deleteProperty(ExecState *exec, const UString &propertyName); 181 182 /** 183 * Converts the object into a primitive value. The value return may differ 184 * depending on the supplied hint 185 * 186 * See ECMA 8.6.2.6 187 * 188 * @param exec The current execution state 189 * @param hint The desired primitive type to convert to 190 * @return A primitive value converted from the objetc. Note that the 191 * type of primitive value returned may not be the same as the requested 192 * hint. 193 */ 194 Value defaultValue(ExecState *exec, Type hint) const; 195 196 /** 197 * Whether or not the object implements the construct() method. If this 198 * returns false you should not call the construct() method on this 199 * object (typically, an assertion will fail to indicate this). 200 * 201 * @return true if this object implements the construct() method, otherwise 202 * false 203 */ 204 bool implementsConstruct() const; 205 206 /** 207 * Creates a new object based on this object. Typically this means the 208 * following: 209 * 1. A new object is created 210 * 2. The prototype of the new object is set to the value of this object's 211 * "prototype" property 212 * 3. The call() method of this object is called, with the new object 213 * passed as the this value 214 * 4. The new object is returned 215 * 216 * In some cases, Host objects may differ from these semantics, although 217 * this is discouraged. 218 * 219 * If an error occurs during construction, the execution state's exception 220 * will be set. This can be tested for with @ref ExecState::hadException(). 221 * Under some circumstances, the exception object may also be returned. 222 * 223 * Note: This function should not be called if implementsConstruct() returns 224 * false, in which case it will result in an assertion failure. 225 * 226 * @param exec The current execution state 227 * @param args The arguments to be passed to call() once the new object has 228 * been created 229 * @return The newly created & initialized object 230 */ 231 Object construct(ExecState *exec, const List &args); 232 233 /** 234 * Whether or not the object implements the call() method. If this returns 235 * false you should not call the call() method on this object (typically, 236 * an assertion will fail to indicate this). 237 * 238 * @return true if this object implements the call() method, otherwise 239 * false 240 */ 241 bool implementsCall() const; 242 243 244 /** 245 * Calls this object as if it is a function. 246 * 247 * Note: This function should not be called if implementsCall() returns 248 * false, in which case it will result in an assertion failure. 249 * 250 * See ECMA 8.6.2.3 251 * 252 * @param exec The current execution state 253 * @param thisObj The obj to be used as "this" within function execution. 254 * Note that in most cases this will be different from the C++ "this" 255 * object. For example, if the ECMAScript code "window.location.toString()" 256 * is executed, call() will be invoked on the C++ object which implements 257 * the toString method, with the thisObj being window.location 258 * @param args List of arguments to be passed to the function 259 * @return The return value from the function 260 */ 261 Value call(ExecState *exec, Object &thisObj, const List &args); 262 263 /** 264 * Whether or not the object implements the hasInstance() method. If this 265 * returns false you should not call the hasInstance() method on this 266 * object (typically, an assertion will fail to indicate this). 267 * 268 * @return true if this object implements the hasInstance() method, 269 * otherwise false 270 */ 271 bool implementsHasInstance() const; 272 273 /** 274 * Checks whether value delegates behaviour to this object. Used by the 275 * instanceof operator. 276 * 277 * @param exec The current execution state 278 * @param value The value to check 279 * @return true if value delegates behaviour to this object, otherwise 280 * false 281 */ 282 Boolean hasInstance(ExecState *exec, const Value &value); 283 284 /** 285 * Returns the scope of this object. This is used when execution declared 286 * functions - the execution context for the function is initialized with 287 * extra object in it's scope. An example of this is functions declared 288 * inside other functions: 289 * 290 * function f() { 291 * 292 * function b() { 293 * return prototype; 294 * } 295 * 296 * var x = 4; 297 * // do some stuff 298 * } 299 * f.prototype = new String(); 300 * 301 * When the function f.b is executed, its scope will include properties of 302 * f. So in the example above the return value of f.b() would be the new 303 * String object that was assigned to f.prototype. 304 * 305 * @param exec The current execution state 306 * @return The function's scope 307 */ 308 const List scope() const; 309 void setScope(const List &s); 310 311 /** 312 * Returns a List of References to all the properties of the object. Used 313 * in "for x in y" statements. The list is created new, so it can be freely 314 * modified without affecting the object's properties. It should be deleted 315 * by the caller. 316 * 317 * Subclasses can override this method in ObjectImpl to provide the 318 * appearance of 319 * having extra properties other than those set specifically with put(). 320 * 321 * @param exec The current execution state 322 * @param recursive Whether or not properties in the object's prototype 323 * chain should be 324 * included in the list. 325 * @return A List of References to properties of the object. 326 **/ 327 List propList(ExecState *exec, bool recursive = true); 328 329 /** 330 * Returns the internal value of the object. This is used for objects such 331 * as String and Boolean which are wrappers for native types. The interal 332 * value is the actual value represented by the wrapper objects. 333 * 334 * @see ECMA 8.6.2 335 * @return The internal value of the object 336 */ 337 Value internalValue() const; 338 339 /** 340 * Sets the internal value of the object 341 * 342 * @see internalValue() 343 * 344 * @param v The new internal value 345 */ 346 void setInternalValue(const Value &v); 347 }; 348 349 class ObjectImp : public ValueImp { 350 public: 351 /** 352 * Creates a new ObjectImp with the specified prototype 353 * 354 * @param proto The prototype 355 */ 356 ObjectImp(const Object &proto); 357 358 /** 359 * Creates a new ObjectImp with a prototype of Null() 360 * (that is, the ECMAScript "null" value, not a null Object). 361 * 362 */ 363 ObjectImp(); 364 365 virtual ~ObjectImp(); 366 367 virtual void mark(); 368 174 369 Type type() const; 175 /** 176 * Check whether object is of a certain type 177 * @param t type to check for 178 */ 179 bool isA(Type t) const { return (type() == t); } 180 /** 181 * Check whether object is of a certain type. Allows checking of 182 * host objects, too. 183 * @param type name (Number, Boolean etc.) 184 */ 185 bool isA(const char *s) const; 186 /** 187 * Use this method when checking for objects. It's safer than checking 188 * for a single object type with @ref isA(). 189 */ 190 bool isObject() const; 191 /** 192 * Examine the inheritance structure of this object. 193 * @param t Name of the base class. 194 * @return True if object is of type t or a derived from such a type. 195 */ 196 bool derivedFrom(const char *s) const; 197 198 /** 199 * @return Conversion to primitive type (Undefined, Boolean, Number 200 * or String) 201 * @param preferred Optional hint. Either StringType or NumberType. 202 */ 203 KJSO toPrimitive(Type preferred = UndefinedType) const; // ECMA 9.1 204 /** 205 * @return Conversion to Boolean type. 206 */ 207 Boolean toBoolean() const; // ECMA 9.2 208 /** 209 * @return Conversion to Number type. 210 */ 211 Number toNumber() const; // ECMA 9.3 212 /** 213 * @return Conversion to double. 0.0 if conversion failed. 214 */ 215 double round() const; 216 /** 217 * @return Conversion to Number type containing an integer value. 218 */ 219 Number toInteger() const; // ECMA 9.4 220 /** 221 * @return Conversion to signed integer value. 222 */ 223 int toInt32() const; // ECMA 9.5 224 /** 225 * @return Conversion to unsigned integer value. 226 */ 227 unsigned int toUInt32() const; // ECMA 9.6 228 /** 229 * @return Conversion to unsigned short value. 230 */ 231 unsigned short toUInt16() const; // ECMA 9.7 232 /** 233 * @return Conversion to String type. 234 */ 235 String toString() const; // ECMA 9.8 236 /** 237 * @return Conversion to Object type. 238 */ 239 Object toObject() const; // ECMA 9.9 240 241 // Properties 242 /** 243 * Set the internal [[Prototype]] property of this object. 244 * @param p A prototype object. 245 */ 246 void setPrototype(const KJSO &p); 247 /** 248 * Set the "prototype" property of this object. Different from 249 * the internal [[Prototype]] property. 250 * @param p A prototype object. 251 */ 252 void setPrototypeProperty(const KJSO &p); 253 /** 254 * @return The internal [[prototype]] property. 255 */ 256 KJSO prototype() const; 257 /** 258 * The internal [[Get]] method. 259 * @return The value of property p. 260 */ 261 KJSO get(const UString &p) const; 262 /** 263 * The internal [[HasProperty]] method. 264 * @param p Property name. 265 * @param recursive Indicates whether prototypes are searched as well. 266 * @return Boolean value indicating whether the object already has a 267 * member with the given name p. 268 */ 269 bool hasProperty(const UString &p, bool recursive = true) const; 270 /** 271 * The internal [[Put]] method. Sets the specified property to the value v. 272 * @param p Property name. 273 * @param v Value. 274 */ 275 void put(const UString &p, const KJSO& v); 276 /** 277 * The internal [[CanPut]] method. 278 * @param p Property name. 279 * @return A boolean value indicating whether a [[Put]] operation with 280 * p succeed. 281 */ 282 bool canPut(const UString &p) const; 283 /** 284 * The internal [[Delete]] method. Removes the specified property from 285 * the object. 286 * @param p Property name. 287 * @return True if the property was deleted successfully or didn't exist 288 * in the first place. False if the DontDelete attribute was set. 289 */ 290 bool deleteProperty(const UString &p); 291 /** 292 * Same as above put() method except the additional attribute. Right now, 293 * this only works with native types as Host Objects don't reimplement 294 * this method. 295 * @param attr One of @ref KJS::Attribute. 296 */ 297 void put(const UString &p, const KJSO& v, int attr); 298 /** 299 * Convenience function for adding a Number property constructed from 300 * a double value. 301 */ 302 void put(const UString &p, double d, int attr = None); 303 /** 304 * Convenience function for adding a Number property constructed from 305 * an integer value. 306 */ 307 void put(const UString &p, int i, int attr = None); 308 /** 309 * Convenience function for adding a Number property constructed from 310 * an unsigned integer value. 311 */ 312 void put(const UString &p, unsigned int u, int attr = None); 313 314 /** 315 * Reference method. 316 * @return Reference base if object is a reference. Throws 317 * a ReferenceError otherwise. 318 */ 319 KJSO getBase() const; 320 /** 321 * Reference method. 322 * @return Property name of a reference. Null string if object is not 323 * a reference. 324 */ 325 UString getPropertyName() const; 326 /** 327 * Reference method. 328 * @return Referenced value. This object if no reference. 329 */ 330 KJSO getValue() const; 331 KJSO getValue(); /* TODO: remove in next version */ 332 /** 333 * Reference method. Set referenced value to v. 334 */ 335 ErrorType putValue(const KJSO& v); 336 337 /** 338 * @return True if object supports @ref executeCall() method. That's the 339 * case for all objects derived from FunctionType. 340 */ 341 bool implementsCall() const; 342 /** 343 * Execute function implemented via the @ref Function::execute() method. 344 * 345 * Note: check availability via @ref implementsCall() beforehand. 346 * @param thisV Object serving as the 'this' value. 347 * @param args Pointer to the list of arguments or null. 348 * @return Result of the function call. 349 */ 350 KJSO executeCall(const KJSO &thisV, const List *args); 351 KJSO executeCall(const KJSO &thisV, const List *args, const List *extraScope) const; 352 353 /** 354 * Set this object's constructor. 355 */ 356 void setConstructor(KJSO c); 357 358 /** 359 * @return A Pointer to the internal implementation. 360 */ 361 Imp *imp() const { return rep; } 362 363 #ifdef KJS_DEBUG_MEM 364 /** 365 * @internal 366 */ 367 static int count; 368 #endif 369 protected: 370 /** 371 * Pointer to the internal implementation. 372 */ 373 Imp *rep; 374 370 371 /** 372 * A pointer to a ClassInfo struct for this class. This provides a basic 373 * facility for run-time type information, and can be used to check an 374 * object's class an inheritance (see @ref inherits()). This should 375 * always return a statically declared pointer, or 0 to indicate that 376 * there is no class information. 377 * 378 * This is primarily useful if you have application-defined classes that you 379 * wish to check against for casting purposes. 380 * 381 * For example, to specify the class info for classes FooImp and BarImp, 382 * where FooImp inherits from BarImp, you would add the following in your 383 * class declarations: 384 * 385 * class BarImp : public ObjectImp { 386 * virtual const ClassInfo *classInfo() const { return &info; } 387 * static const ClassInfo info; 388 * // ... 389 * }; 390 * 391 * class FooImp : public ObjectImp { 392 * virtual const ClassInfo *classInfo() const { return &info; } 393 * static const ClassInfo info; 394 * // ... 395 * }; 396 * 397 * And in your source file: 398 * 399 * const ClassInfo BarImp::info = {0, 0, 0}; // no parent class 400 * const ClassInfo FooImp::info = {&BarImp::info, 0, 0}; 401 * 402 * @see inherits() 403 */ 404 virtual const ClassInfo *classInfo() const; 405 406 /** 407 * Checks whether this object inherits from the class with the specified 408 * classInfo() pointer. This requires that both this class and the other 409 * class return a non-NULL pointer for their classInfo() methods (otherwise 410 * it will return false). 411 * 412 * For example, for two ObjectImp pointers obj1 and obj2, you can check 413 * if obj1's class inherits from obj2's class using the following: 414 * 415 * if (obj1->inherits(obj2->classInfo())) { 416 * // ... 417 * } 418 * 419 * If you have a handle to a statically declared ClassInfo, such as in the 420 * @ref classInfo() example, you can check for inheritance without needing 421 * an instance of the other class: 422 * 423 * if (obj1->inherits(FooImp::info)) { 424 * // ... 425 * } 426 * 427 * @param cinfo The ClassInfo pointer for the class you want to check 428 * inheritance against. 429 * @return true if this object's class inherits from class with the 430 * ClassInfo pointer specified in cinfo 431 */ 432 bool inherits(const ClassInfo *cinfo) const; 433 434 // internal properties (ECMA 262-3 8.6.2) 435 436 /** 437 * Implementation of the [[Prototype]] internal property (implemented by 438 * all Objects) 439 * 440 * @see Object::prototype() 441 */ 442 Value prototype() const; 443 void setPrototype(const Value &proto); 444 445 /** 446 * Implementation of the [[Class]] internal property (implemented by all 447 * Objects) 448 * 449 * The default implementation uses classInfo(). 450 * You should either implement @ref classInfo(), or 451 * if you simply need a classname, you can reimplement @ref className() 452 * instead. 453 * 454 * @see Object::className() 455 */ 456 virtual UString className() const; 457 458 /** 459 * Implementation of the [[Get]] internal property (implemented by all 460 * Objects) 461 * 462 * @see Object::get() 463 */ 464 // [[Get]] - must be implemented by all Objects 465 virtual Value get(ExecState *exec, const UString &propertyName) const; 466 467 /** 468 * Implementation of the [[Put]] internal property (implemented by all 469 * Objects) 470 * 471 * @see Object::put() 472 */ 473 virtual void put(ExecState *exec, const UString &propertyName, 474 const Value &value, int attr = None); 475 476 /** 477 * Implementation of the [[CanPut]] internal property (implemented by all 478 * Objects) 479 * 480 * @see Object::canPut() 481 */ 482 virtual bool canPut(ExecState *exec, const UString &propertyName) const; 483 484 /** 485 * Implementation of the [[HasProperty]] internal property (implemented by 486 * all Objects) 487 * 488 * @see Object::hasProperty() 489 */ 490 virtual bool hasProperty(ExecState *exec, const UString &propertyName, 491 bool recursive = true) const; 492 493 /** 494 * Implementation of the [[Delete]] internal property (implemented by all 495 * Objects) 496 * 497 * @see Object::deleteProperty() 498 */ 499 virtual bool deleteProperty(ExecState *exec, 500 const UString &propertyName); 501 502 /** 503 * Remove all properties from this object. 504 * This doesn't take DontDelete into account, and isn't in the ECMA spec. 505 * It's simply a quick way to remove everything before destroying. 506 */ 507 void deleteAllProperties( ExecState * ); 508 509 /** 510 * Implementation of the [[DefaultValue]] internal property (implemented by 511 * all Objects) 512 * 513 * @see Object::defaultValue() 514 */ 515 virtual Value defaultValue(ExecState *exec, Type hint) const; 516 517 virtual bool implementsConstruct() const; 518 /** 519 * Implementation of the [[Construct]] internal property 520 * 521 * @see Object::construct() 522 */ 523 virtual Object construct(ExecState *exec, const List &args); 524 525 virtual bool implementsCall() const; 526 /** 527 * Implementation of the [[Call]] internal property 528 * 529 * @see Object::call() 530 */ 531 virtual Value call(ExecState *exec, Object &thisObj, 532 const List &args); 533 534 virtual bool implementsHasInstance() const; 535 /** 536 * Implementation of the [[HasInstance]] internal property 537 * 538 * @see Object::hasInstance() 539 */ 540 virtual Boolean hasInstance(ExecState *exec, const Value &value); 541 542 /** 543 * Implementation of the [[Scope]] internal property 544 * 545 * @see Object::scope() 546 */ 547 const List scope() const; 548 void setScope(const List &s); 549 550 List propList(ExecState *exec, bool recursive = true); 551 552 Value internalValue() const; 553 void setInternalValue(const Value &v); 554 555 Value toPrimitive(ExecState *exec, 556 Type preferredType = UnspecifiedType) const; 557 bool toBoolean(ExecState *exec) const; 558 double toNumber(ExecState *exec) const; 559 int toInteger(ExecState *exec) const; 560 int toInt32(ExecState *exec) const; 561 unsigned int toUInt32(ExecState *exec) const; 562 unsigned short toUInt16(ExecState *exec) const; 563 UString toString(ExecState *exec) const; 564 Object toObject(ExecState *exec) const; 565 566 ValueImp* getDirect(const UString& propertyName) const; 375 567 private: 376 void putArrayElement(const UString &p, const KJSO &v); 377 }; // end of KJSO 568 const HashEntry* findPropertyHashEntry( const UString& propertyName ) const; 569 ObjectImpPrivate *_od; 570 PropertyMap *_prop; 571 ValueImp *_proto; 572 ValueImp *_internalValue; 573 ListImp *_scope; 574 }; 378 575 379 576 /** 380 * @short Base for all implementation classes. 577 * Types of Native Errors available. For custom errors, GeneralError 578 * should be used. 381 579 */ 382 class Imp { 383 friend class KJSO; 384 friend class Collector; 385 friend class ForInNode; 386 friend class Debugger; 387 public: 388 Imp(); 389 public: 390 virtual KJSO toPrimitive(Type preferred = UndefinedType) const; // ECMA 9.1 391 virtual Boolean toBoolean() const; // ECMA 9.2 392 virtual Number toNumber() const; // ECMA 9.3 393 virtual String toString() const; // ECMA 9.8 394 virtual Object toObject() const; // ECMA 9.9 395 396 // properties 397 virtual KJSO get(const UString &p) const; 398 virtual bool hasProperty(const UString &p, bool recursive = true) const; 399 virtual void put(const UString &p, const KJSO& v); 400 void put(const UString &p, const KJSO& v, int attr); 401 virtual bool canPut(const UString &p) const; 402 virtual bool deleteProperty(const UString &p); 403 virtual KJSO defaultValue(Type hint) const; 404 405 bool implementsCall() const; 406 407 /** 408 * @internal Reserved for mark & sweep garbage collection 409 */ 410 virtual void mark(Imp *imp = 0L); 411 bool marked() const; 412 413 Type type() const { return typeInfo()->type; } 414 /** 415 * @return The TypeInfo struct describing this object. 416 */ 417 virtual const TypeInfo* typeInfo() const { return &info; } 418 419 void setPrototype(const KJSO& p); 420 Imp* prototype() const { return proto; } 421 void setPrototypeProperty(const KJSO &p); 422 void setConstructor(const KJSO& c); 423 424 void* operator new(size_t); 425 void operator delete(void*); 426 /** 427 * @deprecated 428 */ 429 void operator delete(void*, size_t); 430 431 #ifdef KJS_DEBUG_MEM 432 /** 433 * @internal 434 */ 435 static int count; 436 #endif 437 protected: 438 virtual ~Imp(); 439 private: 440 Imp(const Imp&); 441 Imp& operator=(const Imp&); 442 void putArrayElement(const UString &p, const KJSO& v); 443 444 /** 445 * Get the property names for this object. To be used by for .. in loops 446 * @return The (pointer to the) first element of a PropList, to be deleted 447 * by the caller, or 0 if there are no enumerable properties 448 */ 449 PropList *propList(PropList *first = 0L, PropList *last = 0L, 450 bool recursive = true) const; 451 452 public: 453 // reference counting mechanism 454 inline Imp* ref() { refcount++; return this; } 455 inline bool deref() { return (!--refcount); } 456 unsigned int refcount; 457 458 private: 459 Property *prop; 460 Imp *proto; 461 static const TypeInfo info; 462 463 // reserved for memory managment - currently used as flags for garbage collection 464 // (prev != 0) = marked, (next != 0) = created, (next != this) = created and gc allowed 465 Imp *prev, *next; 466 // for future extensions 467 class ImpInternal; 468 ImpInternal *internal; 469 470 void setMarked(bool m); 471 void setGcAllowed(bool a); 472 bool gcAllowed() const; 473 void setCreated(bool c); 474 bool created() const; 475 }; 476 477 /** 478 * @short General implementation class for Objects 479 */ 480 class ObjectImp : public Imp { 481 friend class Object; 482 public: 483 ObjectImp(Class c); 484 ObjectImp(Class c, const KJSO &v); 485 ObjectImp(Class c, const KJSO &v, const KJSO &p); 486 virtual ~ObjectImp(); 487 virtual KJSO toPrimitive(Type preferred = UndefinedType) const; 488 virtual Boolean toBoolean() const; 489 virtual Number toNumber() const; 490 virtual String toString() const; 491 virtual Object toObject() const; 492 493 virtual const TypeInfo* typeInfo() const { return &info; } 494 static const TypeInfo info; 495 /** 496 * @internal Reimplemenation of @ref Imp::mark(). 497 */ 498 virtual void mark(Imp *imp = 0L); 499 private: 500 Class cl; 501 Imp *val; 502 }; 503 504 /** 505 * @short Object class encapsulating an internal value. 506 */ 507 class Object : public KJSO { 508 public: 509 Object(Imp *d); 510 Object(Class c = UndefClass); 511 Object(Class c, const KJSO& v); 512 Object(Class c, const KJSO& v, const Object& p); 513 virtual ~Object(); 514 void setClass(Class c); 515 Class getClass() const; 516 void setInternalValue(const KJSO& v); 517 KJSO internalValue(); 518 static Object create(Class c); 519 static Object create(Class c, const KJSO& val); 520 static Object create(Class c, const KJSO& val, const Object &p); 521 static Object dynamicCast(const KJSO &obj); 522 }; 523 524 /** 525 * @short Implementation base class for Host Objects. 526 */ 527 class HostImp : public Imp { 528 public: 529 HostImp(); 530 virtual ~HostImp(); 531 virtual const TypeInfo* typeInfo() const { return &info; } 532 533 virtual Boolean toBoolean() const; 534 virtual String toString() const; 535 536 static const TypeInfo info; 537 }; 538 539 class KJScriptImp; 540 /** 541 * The Global object represents the global namespace. It holds the native 542 * objects like String and functions like eval(). 543 * 544 * It also serves as a container for variables created by the user, i.e. 545 * the statement 546 * <pre> 547 * var i = 2; 548 * </pre> 549 * will basically perform a Global::current().put("i", Number(2)); operation. 550 * 551 * @short Unique global object containing initial native properties. 552 */ 553 class Global : public Object { 554 friend class KJScriptImp; 555 public: 556 /** 557 * Constructs a Global object. This is done by the interpreter once and 558 * there should be no need to create an instance on your own. Usually, 559 * you'll just want to access the current instance. 560 * For example like this: 561 * <pre> 562 * Global global(Global::current()); 563 * KJSO proto = global.objectPrototype(); 564 * </pre> 565 */ 566 Global(); 567 /** 568 * Destruct the Global object. 569 */ 570 virtual ~Global(); 571 /** 572 * @return A reference to the Global object belonging to the current 573 * interpreter instance. 574 */ 575 static Global current(); 576 /** 577 * @return A handle to Object.prototype. 578 */ 579 KJSO objectPrototype() const; 580 /** 581 * @return A handle to Function.prototype. 582 */ 583 KJSO functionPrototype() const; 584 /** 585 * Set a filter object that will intercept all put() and get() calls 586 * to the global object. If this object returns Undefined on get() the 587 * request will be passed on the global object. 588 * @deprecated 589 */ 590 void setFilter(const KJSO &f); 591 /** 592 * Return a handle to the filter object (see @ref setFilter()). 593 * Null if no filter has been installed. 594 * @deprecated 595 */ 596 KJSO filter() const; 597 /** 598 * Returns the extra user data set for this global object. Null by default. 599 * Typical usage if you need to query any info related to the currently 600 * running interpreter: 601 * 602 * MyMainWindow *m = (MyMainWindow*)Global::current().extra(); 603 */ 604 void *extra() const; 605 /** 606 * Set the extra user data for this global object. It's not used by the 607 * interpreter itself and can therefore be used to bind arbitrary data 608 * to each interpreter instance. 609 */ 610 void setExtra(void *e); 611 private: 612 Global(void *); 613 void init(); 614 void clear(); 615 }; 580 enum ErrorType { GeneralError = 0, 581 EvalError = 1, 582 RangeError = 2, 583 ReferenceError = 3, 584 SyntaxError = 4, 585 TypeError = 5, 586 URIError = 6}; 616 587 617 588 /** … … 621 592 public: 622 593 /** 623 * Factory method for error objects. The error will be registered globally 624 * and the execution will continue as if a "throw" statement was 625 * encountered. 626 * @param e Type of error. 627 * @param m Optional error message. 628 * @param l Optional line number. 629 */ 630 static KJSO create(ErrorType e, const char *m = 0, int l = -1); 631 /** 632 * Same as above except the different return type (which is not casted 633 * here). 634 */ 635 static Object createObject(ErrorType e, const char *m = 0, int l = -1); 594 * Factory method for error objects. 595 * 596 * @param exec The current execution state 597 * @param errtype Type of error. 598 * @param message Optional error message. 599 * @param lineno Optional line number. 600 * @param lineno Optional source id. 601 */ 602 static Object create(ExecState *exec, ErrorType errtype = GeneralError, 603 const char *message = 0, int lineno = -1, 604 int sourceId = -1); 605 606 /** 607 * Array of error names corresponding to @ref ErrorType 608 */ 609 static const char * const * const errorNames; 636 610 }; 637 611 638 612 }; // namespace 639 613 640 #endif 614 #endif // _KJS_OBJECT_H_ -
trunk/JavaScriptCore/kjs/object_object.cpp
r6 r798 1 // -*- c-basic-offset: 2 -*- 1 2 /* 2 3 * This file is part of the KDE libraries … … 16 17 * License along with this library; if not, write to the Free Software 17 18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 * 20 * $Id$ 18 21 */ 19 22 20 #include "kjs.h" 23 #include "value.h" 24 #include "object.h" 25 #include "types.h" 26 #include "interpreter.h" 21 27 #include "operations.h" 22 28 #include "object_object.h" 23 #include " types.h"29 #include "function_object.h" 24 30 #include <stdio.h> 31 #include <assert.h> 25 32 26 33 using namespace KJS; 27 34 28 ObjectObject::ObjectObject(const Object &funcProto, const Object &objProto) 29 : ConstructorImp(funcProto, 1) 35 // ------------------------------ ObjectPrototypeImp -------------------------------- 36 37 ObjectPrototypeImp::ObjectPrototypeImp(ExecState *exec, 38 FunctionPrototypeImp *funcProto) 39 : ObjectImp() // [[Prototype]] is Null() 30 40 { 31 // ECMA 15.2.3.1 32 setPrototypeProperty(objProto); 41 Value protect(this); 42 put(exec,"toString", Object(new ObjectProtoFuncImp(exec,funcProto,ObjectProtoFuncImp::ToString, 0)), DontEnum); 43 put(exec,"valueOf", Object(new ObjectProtoFuncImp(exec,funcProto,ObjectProtoFuncImp::ValueOf, 0)), DontEnum); 33 44 } 34 45 35 Completion ObjectObject::execute(const List &args) 46 47 // ------------------------------ ObjectProtoFuncImp -------------------------------- 48 49 ObjectProtoFuncImp::ObjectProtoFuncImp(ExecState *exec, 50 FunctionPrototypeImp *funcProto, 51 int i, int len) 52 : InternalFunctionImp(funcProto), id(i) 36 53 { 37 KJSO result; 54 Value protect(this); 55 put(exec,"length",Number(len),DontDelete|ReadOnly|DontEnum); 56 } 38 57 39 List argList; 40 if (args.isEmpty()) { 41 result = construct(argList); 42 } else { 43 KJSO arg = args[0]; 44 if (arg.isA(NullType) || arg.isA(UndefinedType)) { 45 argList.append(arg); 46 result = construct(argList); 47 } else 48 result = arg.toObject(); 49 } 50 return Completion(ReturnValue, result); 58 59 bool ObjectProtoFuncImp::implementsCall() const 60 { 61 return true; 62 } 63 64 // ECMA 15.2.4.2 + 15.2.4.3 65 66 Value ObjectProtoFuncImp::call(ExecState */*exec*/, Object &thisObj, const List &/*args*/) 67 { 68 if (id == ValueOf) 69 return thisObj; 70 else /* ToString */ 71 return String("[object "+thisObj.className()+"]"); 72 } 73 74 // ------------------------------ ObjectObjectImp -------------------------------- 75 76 ObjectObjectImp::ObjectObjectImp(ExecState *exec, 77 ObjectPrototypeImp *objProto, 78 FunctionPrototypeImp *funcProto) 79 : InternalFunctionImp(funcProto) 80 { 81 Value protect(this); 82 // ECMA 15.2.3.1 83 put(exec,"prototype", Object(objProto), DontEnum|DontDelete|ReadOnly); 84 85 // no. of arguments for constructor 86 put(exec,"length", Number(1), ReadOnly|DontDelete|DontEnum); 87 } 88 89 90 bool ObjectObjectImp::implementsConstruct() const 91 { 92 return true; 51 93 } 52 94 53 95 // ECMA 15.2.2 54 Object ObjectObject ::construct(const List &args)96 Object ObjectObjectImp::construct(ExecState *exec, const List &args) 55 97 { 56 98 // if no arguments have been passed ... 57 if (args.isEmpty()) 58 return Object::create(ObjectClass); 99 if (args.isEmpty()) { 100 Object proto = exec->interpreter()->builtinObjectPrototype(); 101 Object result(new ObjectImp(proto)); 102 return result; 103 } 59 104 60 KJSO arg = *args.begin();105 Value arg = *(args.begin()); 61 106 Object obj = Object::dynamicCast(arg); 62 107 if (!obj.isNull()) { 63 /* TODO: handle host objects */64 108 return obj; 65 109 } … … 69 113 case BooleanType: 70 114 case NumberType: 71 return arg.toObject( );115 return arg.toObject(exec); 72 116 default: 73 117 assert(!"unhandled switch case in ObjectConstructor"); 74 118 case NullType: 75 119 case UndefinedType: 76 return Object::create(ObjectClass); 120 Object proto = exec->interpreter()->builtinObjectPrototype(); 121 return Object(new ObjectImp(proto)); 77 122 } 78 123 } 79 124 80 ObjectPrototype::ObjectPrototype() 81 : ObjectImp(ObjectClass) 125 bool ObjectObjectImp::implementsCall() const 82 126 { 83 // the spec says that [[Property]] should be `null'. 84 // Not sure if Null or C's NULL is needed. 127 return true; 85 128 } 86 129 87 bool ObjectPrototype::hasProperty(const UString &p, bool recursive) const 130 Value ObjectObjectImp::call(ExecState *exec, Object &/*thisObj*/, const List &args) 88 131 { 89 if ( p == "toString" || p == "valueOf" ) 90 return true; 91 return /*recursive &&*/ ObjectImp::hasProperty(p, recursive); 132 Value result; 133 134 List argList; 135 // Construct a new Object 136 if (args.isEmpty()) { 137 result = construct(exec,argList); 138 } else { 139 Value arg = args[0]; 140 if (arg.type() == NullType || arg.type() == UndefinedType) { 141 argList.append(arg); 142 result = construct(exec,argList); 143 } else 144 result = arg.toObject(exec); 145 } 146 return result; 92 147 } 93 148 94 KJSO ObjectPrototype::get(const UString &p) const95 {96 if (p == "toString")97 return Function(new ObjectProtoFunc(ToString));98 else if (p == "valueOf")99 return Function(new ObjectProtoFunc(ValueOf));100 else101 return Imp::get(p);102 }103 104 ObjectProtoFunc::ObjectProtoFunc(int i)105 : id(i)106 {107 }108 109 // ECMA 15.2.4.2 + 15.2.4.3110 Completion ObjectProtoFunc::execute(const List &)111 {112 Object thisObj = Object::dynamicCast(thisValue());113 114 /* TODO: what to do with non-objects. Is this possible at all ? */115 // Yes, this happens with Host Object at least (David)116 if (thisObj.isNull()) {117 UString str = "[object ";118 str += thisValue().isNull() ? "null" : thisValue().imp()->typeInfo()->name;119 str += "]";120 return Completion(ReturnValue, String(str));121 }122 123 // valueOf()124 if (id == ObjectPrototype::ValueOf)125 /* TODO: host objects*/126 return Completion(ReturnValue, thisObj);127 128 // toString()129 UString str;130 switch(thisObj.getClass()) {131 case StringClass:132 str = "[object String]";133 break;134 case BooleanClass:135 str = "[object Boolean]";136 break;137 case NumberClass:138 str = "[object Number]";139 break;140 case ObjectClass:141 {142 str = "[object ";143 str += thisValue().isNull() ? "Object" : thisValue().imp()->typeInfo()->name;144 str += "]";145 break;146 }147 default:148 str = "[undefined object]";149 }150 151 return Completion(ReturnValue, String(str));152 } -
trunk/JavaScriptCore/kjs/object_object.h
r6 r798 1 // -*- c-basic-offset: 2 -*- 1 2 /* 2 3 * This file is part of the KDE libraries … … 16 17 * License along with this library; if not, write to the Free Software 17 18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 * 20 * $Id$ 18 21 */ 19 22 … … 21 24 #define _OBJECT_OBJECT_H_ 22 25 23 #include "object.h" 24 #include "function.h" 26 #include "internal.h" 25 27 26 28 namespace KJS { 27 29 28 class ObjectObject : public ConstructorImp { 30 class FunctionPrototypeImp; 31 32 /** 33 * @internal 34 * 35 * The initial value of Object.prototype (and thus all objects created 36 * with the Object constructor 37 */ 38 class ObjectPrototypeImp : public ObjectImp { 29 39 public: 30 ObjectObject(const Object &funcProto, const Object &objProto); 31 Completion execute(const List &); 32 Object construct(const List &); 40 ObjectPrototypeImp(ExecState *exec, FunctionPrototypeImp *funcProto); 33 41 }; 34 42 35 class ObjectPrototype : public ObjectImp { 43 /** 44 * @internal 45 * 46 * Class to implement all methods that are properties of the 47 * Object.prototype object 48 */ 49 class ObjectProtoFuncImp : public InternalFunctionImp { 36 50 public: 37 ObjectPrototype(); 38 bool hasProperty(const UString &p, bool recursive) const; 39 KJSO get(const UString &p) const; 51 ObjectProtoFuncImp(ExecState *exec, FunctionPrototypeImp *funcProto, 52 int i, int len); 53 54 virtual bool implementsCall() const; 55 virtual Value call(ExecState *exec, Object &thisObj, const List &args); 56 40 57 enum { ToString, ValueOf }; 58 private: 59 int id; 41 60 }; 42 61 43 class ObjectProtoFunc : public InternalFunctionImp { 62 /** 63 * @internal 64 * 65 * The initial value of the the global variable's "Object" property 66 */ 67 class ObjectObjectImp : public InternalFunctionImp { 44 68 public: 45 ObjectProtoFunc(int i); 46 Completion execute(const List &); 47 private: 48 int id; 69 70 ObjectObjectImp(ExecState *exec, 71 ObjectPrototypeImp *objProto, 72 FunctionPrototypeImp *funcProto); 73 74 virtual bool implementsConstruct() const; 75 virtual Object construct(ExecState *exec, const List &args); 76 virtual bool implementsCall() const; 77 virtual Value call(ExecState *exec, Object &thisObj, const List &args); 49 78 }; 50 79 -
trunk/JavaScriptCore/kjs/operations.cpp
r6 r798 1 // -*- c-basic-offset: 2 -*- 1 2 /* 2 3 * This file is part of the KDE libraries … … 17 18 * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, 18 19 * Boston, MA 02111-1307, USA. 20 * 19 21 */ 20 22 … … 42 44 #endif 43 45 46 #include "operations.h" 44 47 #include "object.h" 45 #include "types.h"46 #include "operations.h"47 48 48 49 using namespace KJS; … … 72 73 } 73 74 75 bool KJS::isPosInf(double d) 76 { 77 #if defined(HAVE_FUNC_ISINF) 78 return (isinf(d) == 1); 79 #elif HAVE_FUNC_FINITE 80 return finite(d) == 0 && d == d; // ### can we distinguish between + and - ? 81 #elif HAVE_FUNC__FINITE 82 return _finite(d) == 0 && d == d; // ### 83 #else 84 return false; 85 #endif 86 } 87 88 bool KJS::isNegInf(double d) 89 { 90 #if defined(HAVE_FUNC_ISINF) 91 return (isinf(d) == -1); 92 #elif HAVE_FUNC_FINITE 93 return finite(d) == 0 && d == d; // ### 94 #elif HAVE_FUNC__FINITE 95 return _finite(d) == 0 && d == d; // ### 96 #else 97 return false; 98 #endif 99 } 100 74 101 // ECMA 11.9.3 75 bool KJS::equal( const KJSO& v1, const KJSO& v2)102 bool KJS::equal(ExecState *exec, const Value& v1, const Value& v2) 76 103 { 77 104 Type t1 = v1.type(); … … 82 109 return true; 83 110 if (t1 == NumberType) 84 return (v1.toNumber().value() == v2.toNumber().value()); /* TODO: NaN, -0 ? */ 111 { 112 double d1 = v1.toNumber(exec); 113 double d2 = v2.toNumber(exec); 114 if ( isNaN( d1 ) || isNaN( d2 ) ) 115 return false; 116 return ( d1 == d2 ); /* TODO: +0, -0 ? */ 117 } 85 118 if (t1 == StringType) 86 return (v1.toString( ).value() == v2.toString().value());119 return (v1.toString(exec) == v2.toString(exec)); 87 120 if (t1 == BooleanType) 88 return (v1.toBoolean().value() == v2.toBoolean().value()); 89 if (t1 == HostType) { 90 KJSO h1 = v1.get("[[==]]"); 91 KJSO h2 = v2.get("[[==]]"); 92 if (!h1.isA(UndefinedType) && !h2.isA(UndefinedType)) 93 return equal(h1, h2); 94 } 121 return (v1.toBoolean(exec) == v2.toBoolean(exec)); 122 123 // types are Object 95 124 return (v1.imp() == v2.imp()); 96 125 } … … 100 129 return true; 101 130 if (t1 == NumberType && t2 == StringType) { 102 Number n2 = v2.toNumber( );103 return equal( v1, n2);131 Number n2 = v2.toNumber(exec); 132 return equal(exec,v1, n2); 104 133 } 105 134 if ((t1 == StringType && t2 == NumberType) || t1 == BooleanType) { 106 Number n1 = v1.toNumber( );107 return equal( n1, v2);135 Number n1 = v1.toNumber(exec); 136 return equal(exec,n1, v2); 108 137 } 109 138 if (t2 == BooleanType) { 110 Number n2 = v2.toNumber( );111 return equal( v1, n2);139 Number n2 = v2.toNumber(exec); 140 return equal(exec,v1, n2); 112 141 } 113 142 if ((t1 == StringType || t1 == NumberType) && t2 >= ObjectType) { 114 KJSO p2 = v2.toPrimitive();115 return equal( v1, p2);143 Value p2 = v2.toPrimitive(exec); 144 return equal(exec,v1, p2); 116 145 } 117 146 if (t1 >= ObjectType && (t2 == StringType || t2 == NumberType)) { 118 KJSO p1 = v1.toPrimitive();119 return equal( p1, v2);120 } 121 122 return false; 123 } 124 125 bool KJS::strictEqual( const KJSO &v1, const KJSO&v2)147 Value p1 = v1.toPrimitive(exec); 148 return equal(exec,p1, v2); 149 } 150 151 return false; 152 } 153 154 bool KJS::strictEqual(ExecState *exec, const Value &v1, const Value &v2) 126 155 { 127 156 Type t1 = v1.type(); … … 133 162 return true; 134 163 if (t1 == NumberType) { 135 double n1 = v1.toNumber( ).value();136 double n2 = v2.toNumber( ).value();164 double n1 = v1.toNumber(exec); 165 double n2 = v2.toNumber(exec); 137 166 if (isNaN(n1) || isNaN(n2)) 138 167 return false; … … 142 171 return false; 143 172 } else if (t1 == StringType) { 144 return v1.toString( ).value() == v2.toString().value();173 return v1.toString(exec) == v2.toString(exec); 145 174 } else if (t2 == BooleanType) { 146 return v1.toBoolean( ).value() == v2.toBoolean().value();175 return v1.toBoolean(exec) == v2.toBoolean(exec); 147 176 } 148 177 if (v1.imp() == v2.imp()) … … 153 182 } 154 183 155 int KJS::relation(const KJSO& v1, const KJSO& v2) 156 { 157 KJSO p1 = v1.toPrimitive(NumberType); 158 KJSO p2 = v2.toPrimitive(NumberType); 159 160 if (p1.isA(StringType) && p2.isA(StringType)) 161 return p1.toString().value() < p2.toString().value() ? 1 : 0; 162 163 Number n1 = p1.toNumber(); 164 Number n2 = p2.toNumber(); 165 /* TODO: check for NaN */ 166 if (n1.value() == n2.value()) 184 int KJS::relation(ExecState *exec, const Value& v1, const Value& v2) 185 { 186 Value p1 = v1.toPrimitive(exec,NumberType); 187 Value p2 = v2.toPrimitive(exec,NumberType); 188 189 if (p1.type() == StringType && p2.type() == StringType) 190 return p1.toString(exec) < p2.toString(exec) ? 1 : 0; 191 192 double n1 = p1.toNumber(exec); 193 double n2 = p2.toNumber(exec); 194 if ( isNaN( n1 ) || isNaN( n2 ) ) 195 return -1; // means undefined 196 if (n1 == n2) 167 197 return 0; 168 /* TODO: +0, -0 and Infinity */ 169 return (n1.value() < n2.value()); 170 } 171 172 double KJS::max(double d1, double d2) 173 { 174 /* TODO: check for NaN */ 198 /* TODO: +0, -0 */ 199 if ( isPosInf( n1 ) ) 200 return 0; 201 if ( isPosInf( n2 ) ) 202 return 1; 203 if ( isNegInf( n2 ) ) 204 return 0; 205 if ( isNegInf( n1 ) ) 206 return 1; 207 return (n1 < n2) ? 1 : 0; 208 } 209 210 int KJS::maxInt(int d1, int d2) 211 { 175 212 return (d1 > d2) ? d1 : d2; 176 213 } 177 214 178 double KJS::min(double d1, double d2) 179 { 180 /* TODO: check for NaN */ 215 int KJS::minInt(int d1, int d2) 216 { 181 217 return (d1 < d2) ? d1 : d2; 182 218 } 183 219 184 220 // ECMA 11.6 185 KJSO KJS::add(const KJSO &v1, const KJSO &v2, char oper) 186 { 187 KJSO p1 = v1.toPrimitive(); 188 KJSO p2 = v2.toPrimitive(); 189 190 if ((p1.isA(StringType) || p2.isA(StringType)) && oper == '+') { 191 String s1 = p1.toString(); 192 String s2 = p2.toString(); 193 194 UString s = s1.value() + s2.value(); 195 196 return String(s); 197 } 198 199 Number n1 = p1.toNumber(); 200 Number n2 = p2.toNumber(); 221 Value KJS::add(ExecState *exec, const Value &v1, const Value &v2, char oper) 222 { 223 Value p1 = v1.toPrimitive(exec); 224 Value p2 = v2.toPrimitive(exec); 225 226 if ((p1.type() == StringType || p2.type() == StringType) && oper == '+') { 227 UString s1 = p1.toString(exec); 228 UString s2 = p2.toString(exec); 229 230 return String(s1 + s2); 231 } 232 233 double n1 = p1.toNumber(exec); 234 double n2 = p2.toNumber(exec); 201 235 202 236 if (oper == '+') 203 return Number(n1 .value() + n2.value());237 return Number(n1 + n2); 204 238 else 205 return Number(n1 .value() - n2.value());239 return Number(n1 - n2); 206 240 } 207 241 208 242 // ECMA 11.5 209 KJSO KJS::mult(const KJSO &v1, const KJSO&v2, char oper)210 { 211 Number n1 = v1.toNumber( );212 Number n2 = v2.toNumber( );243 Value KJS::mult(ExecState *exec, const Value &v1, const Value &v2, char oper) 244 { 245 Number n1 = v1.toNumber(exec); 246 Number n2 = v2.toNumber(exec); 213 247 214 248 double result; -
trunk/JavaScriptCore/kjs/operations.h
r6 r798 1 // -*- c-basic-offset: 2 -*- 1 2 /* 2 3 * This file is part of the KDE libraries … … 17 18 * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, 18 19 * Boston, MA 02111-1307, USA. 20 * 21 * $Id$ 19 22 */ 20 23 … … 22 25 #define _KJS_OPERATIONS_H_ 23 26 24 #include " object.h"27 #include "value.h" 25 28 26 29 namespace KJS { 30 31 class ExecState; 27 32 28 33 /** … … 34 39 */ 35 40 bool isInf(double d); 36 bool equal(const KJSO& v1, const KJSO& v2); 37 bool strictEqual(const KJSO &v1, const KJSO &v2); 41 bool isPosInf(double d); 42 bool isNegInf(double d); 43 bool equal(ExecState *exec, const Value& v1, const Value& v2); 44 bool strictEqual(ExecState *exec, const Value &v1, const Value &v2); 38 45 /** 39 46 * This operator performs an abstract relational comparision of the two … … 44 51 * equal". -1 if the result is undefined. 45 52 */ 46 int relation( const KJSO& v1, const KJSO& v2);47 double max(double d1, doubled2);48 double min(double d1, doubled2);53 int relation(ExecState *exec, const Value& v1, const Value& v2); 54 int maxInt(int d1, int d2); 55 int minInt(int d1, int d2); 49 56 /** 50 57 * Additive operator. Either performs an addition or substraction of v1 … … 53 60 * @return The result of the operation. 54 61 */ 55 KJSO add(const KJSO &v1, const KJSO&v2, char oper);62 Value add(ExecState *exec, const Value &v1, const Value &v2, char oper); 56 63 /** 57 64 * Multiplicative operator. Either multiplies/divides v1 and v2 or … … 61 68 * @return The result of the operation. 62 69 */ 63 KJSO mult(const KJSO &v1, const KJSO&v2, char oper);70 Value mult(ExecState *exec, const Value &v1, const Value &v2, char oper); 64 71 65 72 }; -
trunk/JavaScriptCore/kjs/regexp.cpp
r6 r798 1 // -*- c-basic-offset: 2 -*- 1 2 /* 2 3 * This file is part of the KDE libraries … … 16 17 * License along with this library; if not, write to the Free Software 17 18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 * 20 * $Id$ 18 21 */ 19 22 20 23 #include <stdio.h> 24 #include <stdlib.h> 25 #include <string.h> 21 26 22 #include "object.h"23 27 #include "regexp.h" 24 28 … … 26 30 27 31 RegExp::RegExp(const UString &p, int f) 28 : pattern(p), flags(f)32 : pattern(p), flags(f) 29 33 { 30 #ifdef REG_EXTENDED 31 regcomp(&preg, p.ascii(), REG_EXTENDED); 32 #else 33 regcomp(&preg, p.ascii(), 0); 34 #endif 35 /* TODO use flags, check for errors */ 34 35 #ifdef HAVE_PCREPOSIX 36 int pcreflags = 0; 37 const char *perrormsg; 38 int errorOffset; 39 40 if (flags & IgnoreCase) 41 pcreflags |= PCRE_CASELESS; 42 43 if (flags & Multiline) 44 pcreflags |= PCRE_MULTILINE; 45 46 pcregex = pcre_compile(p.ascii(), pcreflags, 47 &perrormsg, &errorOffset, NULL); 48 49 #ifdef PCRE_INFO_CAPTURECOUNT 50 // Get number of subpatterns that will be returned 51 int rc = pcre_fullinfo( pcregex, NULL, PCRE_INFO_CAPTURECOUNT, &nrSubPatterns); 52 if (rc != 0) 53 #endif 54 nrSubPatterns = 0; // fallback. We always need the first pair of offsets. 55 56 #else /* HAVE_PCREPOSIX */ 57 58 nrSubPatterns = 0; // not implemented with POSIX regex. 59 int regflags = 0; 60 #ifdef REG_EXTENDED 61 regflags |= REG_EXTENDED; 62 #endif 63 #ifdef REG_ICASE 64 if ( f & IgnoreCase ) 65 regflags |= REG_ICASE; 66 #endif 67 68 //NOTE: Multiline is not feasible with POSIX regex. 69 //if ( f & Multiline ) 70 // ; 71 // Note: the Global flag is already handled by RegExpProtoFunc::execute 72 73 regcomp(&preg, p.ascii(), regflags); 74 /* TODO check for errors */ 75 #endif 76 36 77 } 37 78 38 79 RegExp::~RegExp() 39 80 { 81 #ifdef HAVE_PCREPOSIX 82 pcre_free(pcregex); 83 84 #else 40 85 /* TODO: is this really okay after an error ? */ 41 86 regfree(&preg); 87 #endif 42 88 } 43 89 44 UString RegExp::match(const UString &s, int i, int *pos )90 UString RegExp::match(const UString &s, int i, int *pos, int **ovector) 45 91 { 92 93 #ifdef HAVE_PCREPOSIX 94 CString buffer(s.cstring()); 95 int ovecsize = (nrSubPatterns+1)*3; // see pcre docu 96 if (ovector) *ovector = new int[ovecsize]; 97 98 if (i < 0) 99 i = 0; 100 101 if (i > s.size() || s.isNull() || 102 pcre_exec(pcregex, NULL, buffer.c_str(), buffer.size(), i, 103 0, ovector ? *ovector : 0L, ovecsize) == PCRE_ERROR_NOMATCH) { 104 105 if (pos) 106 *pos = -1; 107 return UString::null; 108 } 109 110 if (!ovector) 111 return UString::null; // don't rely on the return value if you pass ovector==0 112 if (pos) 113 *pos = (*ovector)[0]; 114 return s.substr((*ovector)[0], (*ovector)[1] - (*ovector)[0]); 115 116 #else 46 117 regmatch_t rmatch[10]; 47 118 … … 49 120 i = 0; 50 121 122 char *str = strdup(s.ascii()); 51 123 if (i > s.size() || s.isNull() || 52 regexec(&preg, s .ascii()+ i, 10, rmatch, 0)) {124 regexec(&preg, str + i, 10, rmatch, 0)) { 53 125 if (pos) 54 *pos = -1;126 *pos = -1; 55 127 return UString::null; 56 128 } 129 free(str); 57 130 58 131 if (pos) 59 *pos = rmatch[0].rm_so + i; 132 *pos = rmatch[0].rm_so + i; 133 // TODO copy from rmatch to ovector 60 134 return s.substr(rmatch[0].rm_so + i, rmatch[0].rm_eo - rmatch[0].rm_so); 135 #endif 61 136 } 62 137 138 #if 0 // unused 63 139 bool RegExp::test(const UString &s, int) 64 140 { 65 int r = regexec(&preg, s.ascii(), 0, 0, 0); 141 #ifdef HAVE_PCREPOSIX 142 int ovector[300]; 143 CString buffer(s.cstring()); 144 145 if (s.isNull() || 146 pcre_exec(pcregex, NULL, buffer.c_str(), buffer.size(), 0, 147 0, ovector, 300) == PCRE_ERROR_NOMATCH) 148 return false; 149 else 150 return true; 151 152 #else 153 154 char *str = strdup(s.ascii()); 155 int r = regexec(&preg, str, 0, 0, 0); 156 free(str); 66 157 67 158 return r == 0; 159 #endif 68 160 } 161 #endif -
trunk/JavaScriptCore/kjs/regexp.h
r6 r798 1 // -*- c-basic-offset: 2 -*- 1 2 /* 2 3 * This file is part of the KDE libraries … … 16 17 * License along with this library; if not, write to the Free Software 17 18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 * 20 * $Id$ 18 21 */ 19 22 … … 27 30 #ifdef HAVE_PCREPOSIX 28 31 #include <pcreposix.h> 32 #include <pcre.h> 29 33 #else // POSIX regex - not so good... 30 34 extern "C" { // bug with some libc5 distributions … … 39 43 class RegExp { 40 44 public: 41 enum { None , Global, IgnoreCase, Multiline};45 enum { None = 0, Global = 1, IgnoreCase = 2, Multiline = 4 }; 42 46 RegExp(const UString &p, int f = None); 43 47 ~RegExp(); 44 UString match(const UString &s, int i = -1, int *pos = 0L); 45 bool test(const UString &s, int i = -1); 48 UString match(const UString &s, int i = -1, int *pos = 0L, int **ovector = 0L); 49 // test is unused. The JS spec says that RegExp.test should use 50 // RegExp.exec, so it has to store $1 etc. 51 // bool test(const UString &s, int i = -1); 52 uint subPatterns() const { return nrSubPatterns; } 46 53 private: 47 54 const UString &pattern; 48 55 int flags; 56 57 #ifndef HAVE_PCREPOSIX 49 58 regex_t preg; 59 #else 60 pcre *pcregex; 61 #endif 62 uint nrSubPatterns; 50 63 51 64 RegExp(); -
trunk/JavaScriptCore/kjs/regexp_object.cpp
r6 r798 1 // -*- c-basic-offset: 2 -*- 1 2 /* 2 3 * This file is part of the KDE libraries … … 16 17 * License along with this library; if not, write to the Free Software 17 18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 * 20 * $Id$ 18 21 */ 19 22 20 23 #include <stdio.h> 21 24 22 #include "kjs.h" 25 #include "value.h" 26 #include "object.h" 27 #include "types.h" 28 #include "interpreter.h" 23 29 #include "operations.h" 24 #include "types.h"25 30 #include "internal.h" 26 31 #include "regexp.h" 27 32 #include "regexp_object.h" 33 #include "error_object.h" 28 34 29 35 using namespace KJS; 30 36 31 RegExpObject::RegExpObject(const Object& funcProto, const Object ®Proto) 32 : ConstructorImp(funcProto, 2) 33 { 37 // ------------------------------ RegExpPrototypeImp --------------------------- 38 39 // ECMA 15.9.4 40 41 RegExpPrototypeImp::RegExpPrototypeImp(ExecState *exec, 42 ObjectPrototypeImp *objProto, 43 FunctionPrototypeImp *funcProto) 44 : ObjectImp(Object(objProto)) 45 { 46 Value protect(this); 47 setInternalValue(String("")); 48 49 // The constructor will be added later in RegExpObject's constructor (?) 50 51 put(exec, "exec", Object(new RegExpProtoFuncImp(exec,funcProto,RegExpProtoFuncImp::Exec, 0)), DontEnum); 52 put(exec, "test", Object(new RegExpProtoFuncImp(exec,funcProto,RegExpProtoFuncImp::Test, 0)), DontEnum); 53 put(exec, "toString", Object(new RegExpProtoFuncImp(exec,funcProto,RegExpProtoFuncImp::ToString, 0)), DontEnum); 54 } 55 56 // ------------------------------ RegExpProtoFuncImp --------------------------- 57 58 RegExpProtoFuncImp::RegExpProtoFuncImp(ExecState *exec, 59 FunctionPrototypeImp *funcProto, int i, int len) 60 : InternalFunctionImp(funcProto), id(i) 61 { 62 Value protect(this); 63 put(exec,"length",Number(len),DontDelete|ReadOnly|DontEnum); 64 } 65 66 bool RegExpProtoFuncImp::implementsCall() const 67 { 68 return true; 69 } 70 71 Value RegExpProtoFuncImp::call(ExecState *exec, Object &thisObj, const List &args) 72 { 73 if (!thisObj.inherits(&RegExpImp::info)) { 74 Object err = Error::create(exec,TypeError); 75 exec->setException(err); 76 return err; 77 } 78 79 RegExpImp *reimp = static_cast<RegExpImp*>(thisObj.imp()); 80 RegExp *re = reimp->regExp(); 81 String s; 82 UString str; 83 switch (id) { 84 case Exec: // 15.10.6.2 85 case Test: 86 { 87 s = args[0].toString(exec); 88 int length = s.value().size(); 89 Value lastIndex = thisObj.get(exec,"lastIndex"); 90 int i = lastIndex.isNull() ? 0 : lastIndex.toInt32(exec); 91 bool globalFlag = thisObj.get(exec,"global").toBoolean(exec); 92 if (!globalFlag) 93 i = 0; 94 if (i < 0 || i > length) { 95 thisObj.put(exec,"lastIndex", Number(0), DontDelete | DontEnum); 96 return Null(); 97 } 98 RegExpObjectImp* regExpObj = static_cast<RegExpObjectImp*>(exec->interpreter()->builtinRegExp().imp()); 99 int **ovector = regExpObj->registerRegexp( re, s.value() ); 100 101 str = re->match(s.value(), i, 0L, ovector); 102 103 if (id == Test) 104 return Boolean(!str.isNull()); 105 106 if (str.isNull()) // no match 107 { 108 if (globalFlag) 109 thisObj.put(exec,"lastIndex",Number(0), DontDelete | DontEnum); 110 return Null(); 111 } 112 else // success 113 { 114 if (globalFlag) 115 thisObj.put(exec,"lastIndex",Number( (*ovector)[1] ), DontDelete | DontEnum); 116 return regExpObj->arrayOfMatches(exec,str); 117 } 118 } 119 break; 120 case ToString: 121 s = thisObj.get(exec,"source").toString(exec); 122 str = "/"; 123 str += s.value(); 124 str += "/"; 125 // TODO append the flags 126 return String(str); 127 } 128 129 return Undefined(); 130 } 131 132 // ------------------------------ RegExpImp ------------------------------------ 133 134 const ClassInfo RegExpImp::info = {"RegExp", 0, 0, 0}; 135 136 RegExpImp::RegExpImp(RegExpPrototypeImp *regexpProto) 137 : ObjectImp(Object(regexpProto)), reg(0L) 138 { 139 } 140 141 RegExpImp::~RegExpImp() 142 { 143 delete reg; 144 } 145 146 // ------------------------------ RegExpObjectImp ------------------------------ 147 148 RegExpObjectImp::RegExpObjectImp(ExecState *exec, 149 RegExpPrototypeImp *regProto, 150 FunctionPrototypeImp *funcProto) 151 : InternalFunctionImp(funcProto), lastOvector(0L), lastNrSubPatterns(0) 152 { 153 Value protect(this); 34 154 // ECMA 15.10.5.1 RegExp.prototype 35 setPrototypeProperty(regProto); 36 } 37 38 // ECMA 15.9.2 39 Completion RegExpObject::execute(const List &) 40 { 41 return Completion(ReturnValue, Undefined()); 42 } 43 44 // ECMA 15.9.3 45 Object RegExpObject::construct(const List &args) 46 { 47 /* TODO: regexp arguments */ 48 String p = args[0].toString(); 49 String f = args[1].toString(); 155 put(exec,"prototype", Object(regProto), DontEnum|DontDelete|ReadOnly); 156 157 // no. of arguments for constructor 158 put(exec,"length", Number(2), ReadOnly|DontDelete|DontEnum); 159 } 160 161 RegExpObjectImp::~RegExpObjectImp() 162 { 163 if (lastOvector) 164 delete [] lastOvector; 165 } 166 167 int **RegExpObjectImp::registerRegexp( const RegExp* re, const UString& s ) 168 { 169 lastString = s; 170 if (lastOvector) 171 delete [] lastOvector; 172 lastOvector = 0; 173 lastNrSubPatterns = re->subPatterns(); 174 return &lastOvector; 175 } 176 177 Value RegExpObjectImp::arrayOfMatches(ExecState *exec, const UString &result) const 178 { 179 List list; 180 // The returned array contains 'result' as first item, followed by the list of matches 181 list.append(String(result)); 182 if ( lastOvector ) 183 for ( uint i = 1 ; i < lastNrSubPatterns + 1 ; ++i ) 184 { 185 UString substring = lastString.substr( lastOvector[2*i], lastOvector[2*i+1] - lastOvector[2*i] ); 186 list.append(String(substring)); 187 } 188 return exec->interpreter()->builtinArray().construct(exec, list); 189 } 190 191 Value RegExpObjectImp::get(ExecState *, const UString &p) const 192 { 193 if (p[0] == '$' && lastOvector) 194 { 195 bool ok; 196 unsigned long i = p.substr(1).toULong(&ok); 197 if (ok) 198 { 199 if (i < lastNrSubPatterns + 1) 200 { 201 UString substring = lastString.substr( lastOvector[2*i], lastOvector[2*i+1] - lastOvector[2*i] ); 202 return String(substring); 203 } 204 return String(""); 205 } 206 } 207 return Undefined(); 208 } 209 210 bool RegExpObjectImp::implementsConstruct() const 211 { 212 return true; 213 } 214 215 // ECMA 15.10.4 216 Object RegExpObjectImp::construct(ExecState *exec, const List &args) 217 { 218 String p = args[0].toString(exec); 219 String f = args[1].toString(exec); 50 220 UString flags = f.value(); 51 221 52 RegExpImp *dat = new RegExpImp(); 222 RegExpPrototypeImp *proto = static_cast<RegExpPrototypeImp*>(exec->interpreter()->builtinRegExpPrototype().imp()); 223 RegExpImp *dat = new RegExpImp(proto); 53 224 Object obj(dat); // protect from GC 54 225 … … 56 227 bool ignoreCase = (flags.find("i") >= 0); 57 228 bool multiline = (flags.find("m") >= 0); 58 /* TODO: throw an error on invalid flags */ 59 60 dat->put("global", Boolean(global)); 61 dat->put("ignoreCase", Boolean(ignoreCase)); 62 dat->put("multiline", Boolean(multiline)); 63 64 dat->put("source", String(p.value())); 65 dat->put("lastIndex", 0, DontDelete | DontEnum); 66 67 dat->setRegExp(new RegExp(p.value() /* TODO flags */)); 68 obj.setClass(RegExpClass); 69 obj.setPrototype(Global::current().get("[[RegExp.prototype]]")); 229 // TODO: throw a syntax error on invalid flags 230 231 dat->put(exec, "global", Boolean(global)); 232 dat->put(exec, "ignoreCase", Boolean(ignoreCase)); 233 dat->put(exec, "multiline", Boolean(multiline)); 234 235 dat->put(exec, "source", String(p.value())); 236 dat->put(exec, "lastIndex", Number(0), DontDelete | DontEnum); 237 238 int reflags = RegExp::None; 239 if (global) 240 reflags |= RegExp::Global; 241 if (ignoreCase) 242 reflags |= RegExp::IgnoreCase; 243 if (multiline) 244 reflags |= RegExp::Multiline; 245 dat->setRegExp(new RegExp(p.value(), reflags)); 70 246 71 247 return obj; 72 248 } 73 249 74 // ECMA 15.9.4 75 RegExpPrototype::RegExpPrototype(const Object& proto) 76 : ObjectImp(RegExpClass, String(""), proto) 77 { 78 // The constructor will be added later in RegExpObject's constructor 79 } 80 81 KJSO RegExpPrototype::get(const UString &p) const 82 { 83 int id = -1; 84 if (p == "exec") 85 id = RegExpProtoFunc::Exec; 86 else if (p == "test") 87 id = RegExpProtoFunc::Test; 88 else if (p == "toString") 89 id = RegExpProtoFunc::ToString; 90 91 if (id >= 0) 92 return Function(new RegExpProtoFunc(id)); 93 else 94 return Imp::get(p); 95 } 96 97 Completion RegExpProtoFunc::execute(const List &args) 98 { 99 KJSO result; 100 101 Object thisObj = Object::dynamicCast(thisValue()); 102 103 if (thisObj.getClass() != RegExpClass) { 104 result = Error::create(TypeError); 105 return Completion(ReturnValue, result); 106 } 107 108 RegExp *re = static_cast<RegExpImp*>(thisObj.imp())->regExp(); 109 String s; 110 KJSO lastIndex, tmp; 111 UString str; 112 int length, i; 113 switch (id) { 114 case Exec: 115 case Test: 116 s = args[0].toString(); 117 length = s.value().size(); 118 lastIndex = thisObj.get("lastIndex"); 119 i = lastIndex.toInt32(); 120 tmp = thisObj.get("global"); 121 if (tmp.toBoolean().value() == false) 122 i = 0; 123 if (i < 0 || i > length) { 124 thisObj.put("lastIndex", 0); 125 result = Null(); 126 break; 127 } 128 str = re->match(s.value(), i); 129 if (id == Test) { 130 result = Boolean(str.size() != 0); 131 break; 132 } 133 /* TODO complete */ 134 result = String(str); 135 break; 136 case ToString: 137 s = thisObj.get("source").toString(); 138 str = "/"; 139 str += s.value(); 140 str += "/"; 141 result = String(str); 142 break; 143 } 144 145 return Completion(ReturnValue, result); 146 } 250 bool RegExpObjectImp::implementsCall() const 251 { 252 return true; 253 } 254 255 // ECMA 15.10.3 256 Value RegExpObjectImp::call(ExecState */*exec*/, Object &/*thisObj*/, const List &/*args*/) 257 { 258 // TODO: implement constructor 259 return Undefined(); 260 } -
trunk/JavaScriptCore/kjs/regexp_object.h
r6 r798 1 // -*- c-basic-offset: 2 -*- 1 2 /* 2 3 * This file is part of the KDE libraries … … 16 17 * License along with this library; if not, write to the Free Software 17 18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 * 20 * $Id$ 18 21 */ 19 22 … … 21 24 #define _REGEXP_OBJECT_H_ 22 25 23 #include "object.h" 24 #include "function.h" 26 #include "internal.h" 27 #include "function_object.h" 28 #include "regexp.h" 25 29 26 30 namespace KJS { 27 28 class RegExp Object : public ConstructorImp {31 class ExecState; 32 class RegExpPrototypeImp : public ObjectImp { 29 33 public: 30 RegExp Object(const Object& funcProto, const Object ®Proto);31 Completion execute(const List &);32 Object construct(const List &);34 RegExpPrototypeImp(ExecState *exec, 35 ObjectPrototypeImp *objProto, 36 FunctionPrototypeImp *funcProto); 33 37 }; 34 38 35 class RegExpProto type : public ObjectImp {39 class RegExpProtoFuncImp : public InternalFunctionImp { 36 40 public: 37 RegExpPrototype(const Object& proto); 38 KJSO get(const UString &p) const; 39 }; 41 RegExpProtoFuncImp(ExecState *exec, 42 FunctionPrototypeImp *funcProto, int i, int len); 40 43 41 class RegExpProtoFunc : public InternalFunctionImp { 42 public: 43 RegExpProtoFunc(int i) : id(i) { } 44 Completion execute(const List &); 44 virtual bool implementsCall() const; 45 virtual Value call(ExecState *exec, Object &thisObj, const List &args); 46 45 47 enum { Exec, Test, ToString }; 46 48 private: … … 48 50 }; 49 51 52 class RegExpImp : public ObjectImp { 53 public: 54 RegExpImp(RegExpPrototypeImp *regexpProto); 55 ~RegExpImp(); 56 void setRegExp(RegExp *r) { reg = r; } 57 RegExp* regExp() const { return reg; } 58 59 virtual const ClassInfo *classInfo() const { return &info; } 60 static const ClassInfo info; 61 private: 62 RegExp *reg; 63 }; 64 65 class RegExpObjectImp : public InternalFunctionImp { 66 public: 67 RegExpObjectImp(ExecState *exec, 68 RegExpPrototypeImp *regProto, 69 FunctionPrototypeImp *funcProto); 70 virtual ~RegExpObjectImp(); 71 virtual bool implementsConstruct() const; 72 virtual Object construct(ExecState *exec, const List &args); 73 virtual bool implementsCall() const; 74 virtual Value call(ExecState *exec, Object &thisObj, const List &args); 75 76 Value get(ExecState *exec, const UString &p) const; 77 int ** registerRegexp( const RegExp* re, const UString& s ); 78 Value arrayOfMatches(ExecState *exec, const UString &result) const; 79 private: 80 UString lastString; 81 int *lastOvector; 82 uint lastNrSubPatterns; 83 }; 84 50 85 }; // namespace 51 86 -
trunk/JavaScriptCore/kjs/string_object.cpp
r6 r798 1 // -*- c-basic-offset: 2 -*- 1 2 /* 2 3 * This file is part of the KDE libraries … … 16 17 * License along with this library; if not, write to the Free Software 17 18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 * 18 20 */ 19 21 20 #include "kjs.h" 22 #include "value.h" 23 #include "object.h" 24 #include "types.h" 25 #include "interpreter.h" 21 26 #include "operations.h" 22 #include "types.h"23 27 #include "regexp.h" 28 #include "regexp_object.h" 24 29 #include "string_object.h" 30 #include "error_object.h" 25 31 #include <stdio.h> 32 #include "string_object.lut.h" 26 33 27 34 using namespace KJS; 28 35 29 StringObject::StringObject(const Object &funcProto, const Object &stringProto) 30 : ConstructorImp(funcProto, 1) 31 { 36 // ------------------------------ StringInstanceImp ---------------------------- 37 38 const ClassInfo StringInstanceImp::info = {"String", 0, 0, 0}; 39 40 StringInstanceImp::StringInstanceImp(const Object &proto) 41 : ObjectImp(proto) 42 { 43 setInternalValue(String("")); 44 } 45 46 // ------------------------------ StringPrototypeImp --------------------------- 47 const ClassInfo StringPrototypeImp::info = {"String", &StringInstanceImp::info, &stringTable, 0}; 48 /* Source for string_object.lut.h 49 @begin stringTable 26 50 toString StringProtoFuncImp::ToString DontEnum|Function 0 51 valueOf StringProtoFuncImp::ValueOf DontEnum|Function 0 52 charAt StringProtoFuncImp::CharAt DontEnum|Function 1 53 charCodeAt StringProtoFuncImp::CharCodeAt DontEnum|Function 1 54 concat StringProtoFuncImp::Concat DontEnum|Function 1 55 indexOf StringProtoFuncImp::IndexOf DontEnum|Function 2 56 lastIndexOf StringProtoFuncImp::LastIndexOf DontEnum|Function 2 57 match StringProtoFuncImp::Match DontEnum|Function 1 58 replace StringProtoFuncImp::Replace DontEnum|Function 2 59 search StringProtoFuncImp::Search DontEnum|Function 1 60 slice StringProtoFuncImp::Slice DontEnum|Function 0 61 split StringProtoFuncImp::Split DontEnum|Function 1 62 substr StringProtoFuncImp::Substr DontEnum|Function 2 63 substring StringProtoFuncImp::Substring DontEnum|Function 2 64 toLowerCase StringProtoFuncImp::ToLowerCase DontEnum|Function 0 65 toUpperCase StringProtoFuncImp::ToUpperCase DontEnum|Function 0 66 # 67 # Under here: html extension, should only exist if KJS_PURE_ECMA is not defined 68 # I guess we need to generate two hashtables in the .lut.h file, and use #ifdef 69 # to select the right one... TODO. ##### 70 big StringProtoFuncImp::Big DontEnum|Function 0 71 small StringProtoFuncImp::Small DontEnum|Function 0 72 blink StringProtoFuncImp::Blink DontEnum|Function 0 73 bold StringProtoFuncImp::Bold DontEnum|Function 0 74 fixed StringProtoFuncImp::Fixed DontEnum|Function 0 75 italics StringProtoFuncImp::Italics DontEnum|Function 0 76 strike StringProtoFuncImp::Strike DontEnum|Function 0 77 sub StringProtoFuncImp::Sub DontEnum|Function 0 78 sup StringProtoFuncImp::Sup DontEnum|Function 0 79 fontcolor StringProtoFuncImp::Fontcolor DontEnum|Function 1 80 fontsize StringProtoFuncImp::Fontsize DontEnum|Function 1 81 anchor StringProtoFuncImp::Anchor DontEnum|Function 1 82 link StringProtoFuncImp::Link DontEnum|Function 1 83 @end 84 */ 85 // ECMA 15.5.4 86 StringPrototypeImp::StringPrototypeImp(ExecState *exec, 87 ObjectPrototypeImp *objProto) 88 : StringInstanceImp(Object(objProto)) 89 { 90 Value protect(this); 91 // The constructor will be added later, after StringObjectImp has been built 92 put(exec,"length",Number(0),DontDelete|ReadOnly|DontEnum); 93 94 } 95 96 Value StringPrototypeImp::get(ExecState *exec, const UString &propertyName) const 97 { 98 return lookupGetFunction<StringProtoFuncImp, StringInstanceImp>( exec, propertyName, &stringTable, this ); 99 } 100 101 // ------------------------------ StringProtoFuncImp --------------------------- 102 103 StringProtoFuncImp::StringProtoFuncImp(ExecState *exec, int i, int len) 104 : InternalFunctionImp( 105 static_cast<FunctionPrototypeImp*>(exec->interpreter()->builtinFunctionPrototype().imp()) 106 ), id(i) 107 { 108 Value protect(this); 109 put(exec,"length",Number(len),DontDelete|ReadOnly|DontEnum); 110 } 111 112 bool StringProtoFuncImp::implementsCall() const 113 { 114 return true; 115 } 116 117 // ECMA 15.5.4.2 - 15.5.4.20 118 Value StringProtoFuncImp::call(ExecState *exec, Object &thisObj, const List &args) 119 { 120 Value result; 121 122 // toString and valueOf are no generic function. 123 if (id == ToString || id == ValueOf) { 124 if (thisObj.isNull() || !thisObj.inherits(&StringInstanceImp::info)) { 125 Object err = Error::create(exec,TypeError); 126 exec->setException(err); 127 return err; 128 } 129 130 return String(thisObj.internalValue().toString(exec)); 131 } 132 133 int n, m; 134 UString u, u2, u3; 135 int pos, p0, i; 136 double d = 0.0; 137 138 UString s = thisObj.toString(exec); 139 140 int len = s.size(); 141 Value a0 = args[0]; 142 Value a1 = args[1]; 143 144 switch (id) { 145 case ToString: 146 case ValueOf: 147 // handled above 148 break; 149 case CharAt: 150 pos = a0.toInteger(exec); 151 if (pos < 0 || pos >= len) 152 u = ""; 153 else 154 u = s.substr(pos, 1); 155 result = String(u); 156 break; 157 case CharCodeAt: 158 pos = a0.toInteger(exec); 159 if (pos < 0 || pos >= len) 160 d = NaN; 161 else { 162 UChar c = s[pos]; 163 d = (c.high() << 8) + c.low(); 164 } 165 result = Number(d); 166 break; 167 case Concat: { 168 ListIterator it = args.begin(); 169 for ( ; it != args.end() ; ++it) { 170 s += it->toString(exec); 171 } 172 result = String(s); 173 break; 174 } 175 case IndexOf: 176 u2 = a0.toString(exec); 177 if (a1.type() == UndefinedType) 178 pos = 0; 179 else 180 pos = a1.toInteger(exec); 181 d = s.find(u2, pos); 182 result = Number(d); 183 break; 184 case LastIndexOf: 185 u2 = a0.toString(exec); 186 d = a1.toNumber(exec); 187 if (a1.type() == UndefinedType || KJS::isNaN(d) || KJS::isPosInf(d)) 188 pos = len; 189 else 190 pos = a1.toInteger(exec); 191 if (pos < 0) 192 pos = 0; 193 d = s.rfind(u2, pos); 194 result = Number(d); 195 break; 196 case Match: 197 case Search: { 198 u = s; 199 RegExp* reg = 0; 200 if (a0.isA(ObjectType) && a0.toObject(exec).inherits(&RegExpImp::info)) 201 { 202 RegExpImp* imp = static_cast<RegExpImp *>( a0.toObject(exec).imp() ); 203 reg = imp->regExp(); 204 } 205 else if (a0.isA(StringType)) 206 { 207 reg = new RegExp(a0.toString(exec), RegExp::None); 208 } 209 else 210 { 211 #ifndef NDEBUG 212 printf("KJS: Match/Search. Argument is not a RegExp nor a String - returning Undefined\n"); 213 #endif 214 result = Undefined(); 215 break; 216 } 217 RegExpObjectImp* regExpObj = static_cast<RegExpObjectImp*>(exec->interpreter()->builtinRegExp().imp()); 218 int **ovector = regExpObj->registerRegexp( reg, u ); 219 UString mstr = reg->match(u, -1, &pos, ovector); 220 if (a0.isA(StringType)) 221 delete reg; 222 if (id == Search) { 223 result = Number(pos); 224 break; 225 } 226 if (mstr.isNull()) 227 result = Null(); 228 else 229 result = regExpObj->arrayOfMatches(exec,mstr); 230 } 231 break; 232 case Replace: 233 u = s; 234 if (a0.type() == ObjectType && a0.toObject(exec).inherits(&RegExpImp::info)) { 235 RegExpImp* imp = static_cast<RegExpImp *>( a0.toObject(exec).imp() ); 236 RegExp *reg = imp->regExp(); 237 bool global = false; 238 Value tmp = imp->get(exec,"global"); 239 if (tmp.type() != UndefinedType && tmp.toBoolean(exec) == true) 240 global = true; 241 242 RegExpObjectImp* regExpObj = static_cast<RegExpObjectImp*>(exec->interpreter()->builtinRegExp().imp()); 243 int **ovector = regExpObj->registerRegexp( reg, u ); 244 int lastIndex = 0; 245 u3 = a1.toString(exec); // replacement string 246 // This is either a loop (if global is set) or a one-way (if not). 247 do { 248 UString mstr = reg->match(u, lastIndex, &pos, ovector); 249 len = mstr.size(); 250 lastIndex = pos + u3.size(); 251 if ( pos != -1 ) 252 u = u.substr(0, pos) + u3 + u.substr(pos + len); 253 //fprintf(stderr,"pos=%d,len=%d,lastIndex=%d,u=%s\n",pos,len,lastIndex,u.ascii()); 254 } while ( global && pos != -1 ); 255 256 result = String(u); 257 } else { // First arg is a string 258 u2 = a0.toString(exec); 259 pos = u.find(u2); 260 len = u2.size(); 261 // Do the replacement 262 if (pos == -1) 263 result = String(s); 264 else { 265 u3 = u.substr(0, pos) + a1.toString(exec) + 266 u.substr(pos + len); 267 result = String(u3); 268 } 269 } 270 break; 271 case Slice: // http://developer.netscape.com/docs/manuals/js/client/jsref/string.htm#1194366 272 { 273 // The arg processing is very much like ArrayProtoFunc::Slice 274 // We return a new array 275 result = exec->interpreter()->builtinArray().construct(exec,List::empty()); 276 int begin = args[0].toUInt32(exec); 277 int end = len; 278 if (args[1].type() != UndefinedType) 279 { 280 end = args[1].toUInt32(exec); 281 if ( end < 0 ) 282 end += len; 283 } 284 // safety tests 285 if ( begin < 0 || end < 0 || begin >= end ) { 286 result = String(); 287 break; 288 } 289 //printf( "Slicing from %d to %d \n", begin, end ); 290 result = String(s.substr(begin, end-begin)); 291 break; 292 } 293 case Split: { 294 Object constructor = exec->interpreter()->builtinArray(); 295 Object res = Object::dynamicCast(constructor.construct(exec,List::empty())); 296 result = res; 297 u = s; 298 i = p0 = 0; 299 d = (a1.type() != UndefinedType) ? a1.toInteger(exec) : -1; // optional max number 300 if (a0.type() == ObjectType && Object::dynamicCast(a0).inherits(&RegExpImp::info)) { 301 Object obj0 = Object::dynamicCast(a0); 302 RegExp reg(obj0.get(exec,"source").toString(exec)); 303 if (u.isEmpty() && !reg.match(u, 0).isNull()) { 304 // empty string matched by regexp -> empty array 305 res.put(exec,"length", Number(0)); 306 break; 307 } 308 int *ovector; 309 int mpos; 310 pos = 0; 311 while (1) { 312 // TODO: back references 313 UString mstr = reg.match(u, pos, &mpos, &ovector); 314 if (mpos < 0) 315 break; 316 pos = mpos + (mstr.isEmpty() ? 1 : mstr.size()); 317 if (mpos != p0 || !mstr.isEmpty()) { 318 res.put(exec,UString::from(i), String(u.substr(p0, mpos-p0))); 319 p0 = mpos + mstr.size(); 320 i++; 321 } 322 } 323 delete ovector; 324 } else if (a0.type() != UndefinedType) { 325 u2 = a0.toString(exec); 326 if (u2.isEmpty()) { 327 if (u.isEmpty()) { 328 // empty separator matches empty string -> empty array 329 put(exec,"length", Number(0)); 330 break; 331 } else { 332 while (i != d && i < u.size()-1) 333 res.put(exec,UString::from(i++), String(u.substr(p0++, 1))); 334 } 335 } else { 336 while (i != d && (pos = u.find(u2, p0)) >= 0) { 337 res.put(exec,UString::from(i), String(u.substr(p0, pos-p0))); 338 p0 = pos + u2.size(); 339 i++; 340 } 341 } 342 } 343 // add remaining string, if any 344 if (i != d) 345 res.put(exec,UString::from(i++), String(u.substr(p0))); 346 res.put(exec,"length", Number(i)); 347 } 348 break; 349 case Substr: { 350 n = a0.toInteger(exec); 351 m = a1.toInteger(exec); 352 int d, d2; 353 if (n >= 0) 354 d = n; 355 else 356 d = maxInt(len + n, 0); 357 if (a1.type() == UndefinedType) 358 d2 = len - d; 359 else 360 d2 = minInt(maxInt(m, 0), len - d); 361 result = String(s.substr(d, d2)); 362 break; 363 } 364 case Substring: { 365 double start = a0.toNumber(exec); 366 double end = a1.toNumber(exec); 367 if (KJS::isNaN(start)) 368 start = 0; 369 if (KJS::isNaN(end)) 370 end = 0; 371 if (start < 0) 372 start = 0; 373 if (end < 0) 374 end = 0; 375 if (start > len) 376 start = len; 377 if (end > len) 378 end = len; 379 if (a1.type() == UndefinedType) 380 end = len; 381 if (start > end) { 382 double temp = end; 383 end = start; 384 start = temp; 385 } 386 result = String(s.substr((int)start, (int)end-(int)start)); 387 } 388 break; 389 case ToLowerCase: 390 u = s; 391 for (i = 0; i < len; i++) 392 u[i] = u[i].toLower(); 393 result = String(u); 394 break; 395 case ToUpperCase: 396 u = s; 397 for (i = 0; i < len; i++) 398 u[i] = u[i].toUpper(); 399 result = String(u); 400 break; 401 #ifndef KJS_PURE_ECMA 402 case Big: 403 result = String("<BIG>" + s + "</BIG>"); 404 break; 405 case Small: 406 result = String("<SMALL>" + s + "</SMALL>"); 407 break; 408 case Blink: 409 result = String("<BLINK>" + s + "</BLINK>"); 410 break; 411 case Bold: 412 result = String("<B>" + s + "</B>"); 413 break; 414 case Fixed: 415 result = String("<TT>" + s + "</TT>"); 416 break; 417 case Italics: 418 result = String("<I>" + s + "</I>"); 419 break; 420 case Strike: 421 result = String("<STRIKE>" + s + "</STRIKE>"); 422 break; 423 case Sub: 424 result = String("<SUB>" + s + "</SUB>"); 425 break; 426 case Sup: 427 result = String("<SUP>" + s + "</SUP>"); 428 break; 429 case Fontcolor: 430 result = String("<FONT COLOR=" + a0.toString(exec) + ">" 431 + s + "</FONT>"); 432 break; 433 case Fontsize: 434 result = String("<FONT SIZE=" + a0.toString(exec) + ">" 435 + s + "</FONT>"); 436 break; 437 case Anchor: 438 result = String("<a name=" + a0.toString(exec) + ">" 439 + s + "</a>"); 440 break; 441 case Link: 442 result = String("<a href=" + a0.toString(exec) + ">" 443 + s + "</a>"); 444 break; 445 #endif 446 } 447 448 return result; 449 } 450 451 // ------------------------------ StringObjectImp ------------------------------ 452 453 StringObjectImp::StringObjectImp(ExecState *exec, 454 FunctionPrototypeImp *funcProto, 455 StringPrototypeImp *stringProto) 456 : InternalFunctionImp(funcProto) 457 { 458 Value protect(this); 32 459 // ECMA 15.5.3.1 String.prototype 33 setPrototypeProperty(stringProto); 34 } 35 36 KJSO StringObject::get(const UString &p) const 37 { 38 if (p == "fromCharCode") 39 return Function(new StringObjectFunc()); 460 put(exec,"prototype", Object(stringProto), DontEnum|DontDelete|ReadOnly); 461 462 put(exec,"fromCharCode", Object(new StringObjectFuncImp(exec,funcProto)), DontEnum); 463 464 // no. of arguments for constructor 465 put(exec,"length", Number(1), ReadOnly|DontDelete|DontEnum); 466 } 467 468 469 bool StringObjectImp::implementsConstruct() const 470 { 471 return true; 472 } 473 474 // ECMA 15.5.2 475 Object StringObjectImp::construct(ExecState *exec, const List &args) 476 { 477 Object proto = exec->interpreter()->builtinStringPrototype(); 478 Object obj(new StringInstanceImp(proto )); 479 480 UString s; 481 if (args.size() > 0) 482 s = args.begin()->toString(exec); 40 483 else 41 return Imp::get(p); 484 s = UString(""); 485 486 obj.setInternalValue(String(s)); 487 obj.put(exec, "length", Number(s.size()), ReadOnly|DontEnum|DontDelete); 488 489 return obj; 490 } 491 492 bool StringObjectImp::implementsCall() const 493 { 494 return true; 42 495 } 43 496 44 497 // ECMA 15.5.1 45 Completion StringObject::execute(const List &args) 46 { 47 KJSO v; 48 String s; 49 498 Value StringObjectImp::call(ExecState *exec, Object &/*thisObj*/, const List &args) 499 { 50 500 if (args.isEmpty()) 51 s =String("");501 return String(""); 52 502 else { 53 v = args[0];54 s = v.toString();503 Value v = args[0]; 504 return String(v.toString(exec)); 55 505 } 56 57 return Completion(ReturnValue, s); 58 } 59 60 // ECMA 15.5.2 61 Object StringObject::construct(const List &args) 62 { 63 String s; 64 if (args.size() > 0) 65 s = args.begin()->toString(); 66 else 67 s = String(""); 68 69 return Object::create(StringClass, s); 70 } 506 } 507 508 // ------------------------------ StringObjectFuncImp -------------------------- 71 509 72 510 // ECMA 15.5.3.2 fromCharCode() 73 Completion StringObjectFunc::execute(const List &args) 511 StringObjectFuncImp::StringObjectFuncImp(ExecState *exec, FunctionPrototypeImp *funcProto) 512 : InternalFunctionImp(funcProto) 513 { 514 Value protect(this); 515 put(exec,"length",Number(1),DontDelete|ReadOnly|DontEnum); 516 } 517 518 bool StringObjectFuncImp::implementsCall() const 519 { 520 return true; 521 } 522 523 Value StringObjectFuncImp::call(ExecState *exec, Object &/*thisObj*/, const List &args) 74 524 { 75 525 UString s; … … 79 529 ListIterator it = args.begin(); 80 530 while (it != args.end()) { 81 unsigned short u = it->toUInt16( );531 unsigned short u = it->toUInt16(exec); 82 532 *p++ = UChar(u); 83 533 it++; … … 87 537 s = ""; 88 538 89 return Completion(ReturnValue, String(s)); 90 } 91 92 // ECMA 15.5.4 93 StringPrototype::StringPrototype(const Object& proto) 94 : ObjectImp(StringClass, String(""), proto) 95 { 96 // The constructor will be added later in StringObject's constructor 97 } 98 99 KJSO StringPrototype::get(const UString &p) const 100 { 101 int id; 102 103 if (p == "toString") 104 id = StringProtoFunc::ToString; 105 else if (p == "valueOf") 106 id = StringProtoFunc::ValueOf; 107 else if (p == "charAt") 108 id = StringProtoFunc::CharAt; 109 else if (p == "charCodeAt") 110 id = StringProtoFunc::CharCodeAt; 111 else if (p == "indexOf") 112 id = StringProtoFunc::IndexOf; 113 else if (p == "lastIndexOf") 114 id = StringProtoFunc::LastIndexOf; 115 else if (p == "match") 116 id = StringProtoFunc::Match; 117 else if (p == "replace") 118 id = StringProtoFunc::Replace; 119 else if (p == "search") 120 id = StringProtoFunc::Search; 121 else if (p == "split") 122 id = StringProtoFunc::Split; 123 else if (p == "substr") 124 id = StringProtoFunc::Substr; 125 else if (p == "substring") 126 id = StringProtoFunc::Substring; 127 else if (p == "toLowerCase") 128 id = StringProtoFunc::ToLowerCase; 129 else if (p == "toUpperCase") 130 id = StringProtoFunc::ToUpperCase; 131 #ifndef KJS_PURE_ECMA 132 else if (p == "big") 133 id = StringProtoFunc::Big; 134 else if (p == "small") 135 id = StringProtoFunc::Small; 136 else if (p == "blink") 137 id = StringProtoFunc::Blink; 138 else if (p == "bold") 139 id = StringProtoFunc::Bold; 140 else if (p == "fixed") 141 id = StringProtoFunc::Fixed; 142 else if (p == "italics") 143 id = StringProtoFunc::Italics; 144 else if (p == "strike") 145 id = StringProtoFunc::Strike; 146 else if (p == "sub") 147 id = StringProtoFunc::Sub; 148 else if (p == "sup") 149 id = StringProtoFunc::Sup; 150 else if (p == "fontcolor") 151 id = StringProtoFunc::Fontcolor; 152 else if (p == "fontsize") 153 id = StringProtoFunc::Fontsize; 154 else if (p == "anchor") 155 id = StringProtoFunc::Anchor; 156 else if (p == "link") 157 id = StringProtoFunc::Link; 158 #endif 159 else 160 return Imp::get(p); 161 162 return Function(new StringProtoFunc(id)); 163 } 164 165 StringProtoFunc::StringProtoFunc(int i) 166 : id(i) 167 { 168 } 169 170 // ECMA 15.5.4.2 - 15.5.4.20 171 Completion StringProtoFunc::execute(const List &args) 172 { 173 KJSO result; 174 175 Object thisObj = Object::dynamicCast(thisValue()); 176 177 // toString and valueOf are no generic function. 178 if (id == ToString || id == ValueOf) { 179 if (thisObj.isNull() || thisObj.getClass() != StringClass) { 180 result = Error::create(TypeError); 181 return Completion(ReturnValue, result); 182 } 183 } 184 185 String s2; 186 Number n, m; 187 UString u, u2, u3; 188 int pos, p0, i; 189 double d, d2; 190 KJSO v = thisObj.internalValue(); 191 String s = v.toString(); 192 int len = s.value().size(); 193 KJSO a0 = args[0]; 194 KJSO a1 = args[1]; 195 196 switch (id) { 197 case ToString: 198 case ValueOf: 199 result = v.toString(); 200 break; 201 case CharAt: 202 n = a0.toInteger(); 203 pos = (int) n.value(); 204 if (pos < 0 || pos >= len) 205 u = ""; 206 else 207 u = s.value().substr(pos, 1); 208 result = String(u); 209 break; 210 case CharCodeAt: 211 n = a0.toInteger(); 212 pos = (int) n.value(); 213 if (pos < 0 || pos >= len) 214 d = NaN; 215 else { 216 UChar c = s.value()[pos]; 217 d = (c.high() << 8) + c.low(); 218 } 219 result = Number(d); 220 break; 221 case IndexOf: 222 s2 = a0.toString(); 223 if (a1.isA(UndefinedType)) 224 pos = 0; 225 else 226 pos = a1.toInteger().intValue(); 227 d = s.value().find(s2.value(), pos); 228 result = Number(d); 229 break; 230 case LastIndexOf: 231 s2 = a0.toString(); 232 if (a1.isA(UndefinedType)) 233 pos = len; 234 else 235 pos = a1.toInteger().intValue(); 236 d = s.value().rfind(s2.value(), pos); 237 result = Number(d); 238 break; 239 case Match: 240 case Search: 241 u = s.value(); 242 if (a0.isA(ObjectType) && a0.toObject().getClass() == RegExpClass) { 243 s2 = a0.get("source").toString(); 244 RegExp reg(s2.value()); 245 UString mstr = reg.match(u, -1, &pos); 246 if (id == Search) { 247 result = Number(pos); 248 break; 249 } 250 if (mstr.isNull()) { 251 result = Null(); 252 break; 253 } 254 /* TODO return an array, with the matches, etc. */ 255 result = String(mstr); 256 } else 257 { 258 printf("Match/Search. Argument is not a RegExp - returning Undefined\n"); 259 result = Undefined(); // No idea what to do here 260 } 261 break; 262 case Replace: 263 /* TODO: this is just a hack to get the most common cases going */ 264 u = s.value(); 265 if (a0.isA(ObjectType) && a0.toObject().getClass() == RegExpClass) { 266 s2 = a0.get("source").toString(); 267 RegExp reg(s2.value()); 268 UString mstr = reg.match(u, -1, &pos); 269 len = mstr.size(); 270 } else { 271 s2 = a0.toString(); 272 u2 = s2.value(); 273 pos = u.find(u2); 274 len = u2.size(); 275 } 276 if (pos == -1) 277 result = s; 278 else { 279 u3 = u.substr(0, pos) + a1.toString().value() + 280 u.substr(pos + len); 281 result = String(u3); 282 } 283 break; 284 case Split: 285 result = Object::create(ArrayClass); 286 u = s.value(); 287 i = p0 = 0; 288 d = a1.isDefined() ? a1.toInteger().intValue() : -1; // optional max number 289 if (a0.isA(ObjectType) && Object(a0.imp()).getClass() == RegExpClass) { 290 RegExp reg(a0.get("source").toString().value()); 291 if (u.isEmpty() && !reg.match(u, 0).isNull()) { 292 // empty string matched by regexp -> empty array 293 result.put("length", 0); 294 break; 295 } 296 int mpos; 297 pos = 0; 298 while (1) { 299 /* TODO: back references */ 300 UString mstr = reg.match(u, pos, &mpos); 301 if (mpos < 0) 302 break; 303 pos = mpos + (mstr.isEmpty() ? 1 : mstr.size()); 304 if (mpos != p0 || !mstr.isEmpty()) { 305 result.put(UString::from(i), String(u.substr(p0, mpos-p0))); 306 p0 = mpos + mstr.size(); 307 i++; 308 } 309 } 310 } else if (a0.isDefined()) { 311 u2 = a0.toString().value(); 312 if (u2.isEmpty()) { 313 if (u.isEmpty()) { 314 // empty separator matches empty string -> empty array 315 put("length", 0); 316 break; 317 } else { 318 while (i != d && i < u.size()) 319 result.put(UString::from(i++), String(u.substr(p0++, 1))); 320 } 321 } else { 322 while (i != d && (pos = u.find(u2, p0)) >= 0) { 323 result.put(UString::from(i), String(u.substr(p0, pos-p0))); 324 p0 = pos + u2.size(); 325 i++; 326 } 327 } 328 } 329 // add remaining string, if any 330 if (i != d && (p0 < len || i == 0)) 331 result.put(UString::from(i++), String(u.substr(p0))); 332 result.put("length", i); 333 break; 334 case Substr: 335 n = a0.toInteger(); 336 m = a1.toInteger(); 337 if (n.value() >= 0) 338 d = n.value(); 339 else 340 d = max(len + n.value(), 0); 341 if (a1.isA(UndefinedType)) 342 d2 = len - d; 343 else 344 d2 = min(max(m.value(), 0), len - d); 345 result = String(s.value().substr((int)d, (int)d2)); 346 break; 347 case Substring: 348 n = a0.toInteger(); 349 m = a1.toInteger(); 350 d = min(max(n.value(), 0), len); 351 if (a1.isA(UndefinedType)) 352 d2 = len - d; 353 else { 354 d2 = min(max(m.value(), 0), len); 355 d2 = max(d2-d, 0); 356 } 357 result = String(s.value().substr((int)d, (int)d2)); 358 break; 359 case ToLowerCase: 360 u = UString(s.value()); 361 for (i = 0; i < len; i++) 362 u[i] = u[i].toLower(); 363 result = String(u); 364 break; 365 case ToUpperCase: 366 u = UString(s.value()); 367 for (i = 0; i < len; i++) 368 u[i] = u[i].toUpper(); 369 result = String(u); 370 break; 371 #ifndef KJS_PURE_ECMA 372 case Big: 373 result = String("<BIG>" + s.value() + "</BIG>"); 374 break; 375 case Small: 376 result = String("<SMALL>" + s.value() + "</SMALL>"); 377 break; 378 case Blink: 379 result = String("<BLINK>" + s.value() + "</BLINK>"); 380 break; 381 case Bold: 382 result = String("<B>" + s.value() + "</B>"); 383 break; 384 case Fixed: 385 result = String("<TT>" + s.value() + "</TT>"); 386 break; 387 case Italics: 388 result = String("<I>" + s.value() + "</I>"); 389 break; 390 case Strike: 391 result = String("<STRIKE>" + s.value() + "</STRIKE>"); 392 break; 393 case Sub: 394 result = String("<SUB>" + s.value() + "</SUB>"); 395 break; 396 case Sup: 397 result = String("<SUP>" + s.value() + "</SUP>"); 398 break; 399 case Fontcolor: 400 result = String("<FONT COLOR=" + a0.toString().value() + ">" 401 + s.value() + "</FONT>"); 402 break; 403 case Fontsize: 404 result = String("<FONT SIZE=" + a0.toString().value() + ">" 405 + s.value() + "</FONT>"); 406 break; 407 case Anchor: 408 result = String("<a name=" + a0.toString().value() + ">" 409 + s.value() + "</a>"); 410 break; 411 case Link: 412 result = String("<a href=" + a0.toString().value() + ">" 413 + s.value() + "</a>"); 414 break; 415 #endif 416 } 417 418 return Completion(ReturnValue, result); 419 } 539 return String(s); 540 } -
trunk/JavaScriptCore/kjs/string_object.h
r6 r798 1 // -*- c-basic-offset: 2 -*- 1 2 /* 2 3 * This file is part of the KDE libraries … … 16 17 * License along with this library; if not, write to the Free Software 17 18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 * 20 * $Id$ 18 21 */ 19 22 … … 21 24 #define _STRING_OBJECT_H_ 22 25 23 #include " object.h"24 #include "function .h"26 #include "internal.h" 27 #include "function_object.h" 25 28 26 29 namespace KJS { 27 30 28 class String Object : public ConstructorImp {31 class StringInstanceImp : public ObjectImp { 29 32 public: 30 String Object(const Object &funcProto, const Object &stringProto);31 KJSO get(const UString &p) const; 32 Completion execute(const List &);33 Object construct(const List &);33 StringInstanceImp(const Object &proto); 34 35 virtual const ClassInfo *classInfo() const { return &info; } 36 static const ClassInfo info; 34 37 }; 35 38 36 class StringObjectFunc : public InternalFunctionImp { 39 /** 40 * @internal 41 * 42 * The initial value of String.prototype (and thus all objects created 43 * with the String constructor 44 */ 45 class StringPrototypeImp : public StringInstanceImp { 37 46 public: 38 Completion execute(const List &); 47 StringPrototypeImp(ExecState *exec, 48 ObjectPrototypeImp *objProto); 49 Value get(ExecState *exec, const UString &p) const; 50 virtual const ClassInfo *classInfo() const { return &info; } 51 static const ClassInfo info; 39 52 }; 40 53 41 class StringPrototype : public ObjectImp { 54 /** 55 * @internal 56 * 57 * Class to implement all methods that are properties of the 58 * String.prototype object 59 */ 60 class StringProtoFuncImp : public InternalFunctionImp { 42 61 public: 43 StringPrototype(const Object& proto); 44 KJSO get(const UString &p) const; 45 }; 62 StringProtoFuncImp(ExecState *exec, int i, int len); 46 63 47 class StringProtoFunc : public InternalFunctionImp { 48 public: 49 StringProtoFunc(int i); 50 Completion execute(const List &); 64 virtual bool implementsCall() const; 65 virtual Value call(ExecState *exec, Object &thisObj, const List &args); 51 66 52 enum { ToString, ValueOf, CharAt, CharCodeAt, IndexOf, LastIndexOf,67 enum { ToString, ValueOf, CharAt, CharCodeAt, Concat, IndexOf, LastIndexOf, 53 68 Match, Replace, Search, Slice, Split, 54 69 Substr, Substring, FromCharCode, ToLowerCase, ToUpperCase … … 62 77 }; 63 78 79 /** 80 * @internal 81 * 82 * The initial value of the the global variable's "String" property 83 */ 84 class StringObjectImp : public InternalFunctionImp { 85 public: 86 StringObjectImp(ExecState *exec, 87 FunctionPrototypeImp *funcProto, 88 StringPrototypeImp *stringProto); 89 90 virtual bool implementsConstruct() const; 91 virtual Object construct(ExecState *exec, const List &args); 92 virtual bool implementsCall() const; 93 virtual Value call(ExecState *exec, Object &thisObj, const List &args); 94 }; 95 96 /** 97 * @internal 98 * 99 * Class to implement all methods that are properties of the 100 * String object 101 */ 102 class StringObjectFuncImp : public InternalFunctionImp { 103 public: 104 StringObjectFuncImp(ExecState *exec, FunctionPrototypeImp *funcProto); 105 virtual bool implementsCall() const; 106 virtual Value call(ExecState *exec, Object &thisObj, const List &args); 107 }; 108 64 109 }; // namespace 65 110 66 111 #endif 112 -
trunk/JavaScriptCore/kjs/testkjs.cpp
r6 r798 1 // -*- c-basic-offset: 2 -*- 1 2 /* 2 3 * This file is part of the KDE libraries … … 17 18 * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, 18 19 * Boston, MA 02111-1307, USA. 20 * 21 * $Id$ 19 22 */ 20 23 21 24 #include <stdio.h> 25 #include <iostream.h> 22 26 23 #include "kjs.h" 24 27 #include "value.h" 25 28 #include "object.h" 26 29 #include "types.h" 27 #include "internal.h" 30 #include "interpreter.h" 31 32 using namespace KJS; 33 34 class TestFunctionImp : public ObjectImp { 35 public: 36 TestFunctionImp() : ObjectImp() {} 37 virtual bool implementsCall() const { return true; } 38 virtual Value call(ExecState *exec, Object &thisObj, const List &args); 39 }; 40 41 Value TestFunctionImp::call(ExecState *exec, Object &/*thisObj*/, const List &args) 42 { 43 fprintf(stderr,"--> %s\n",args[0].toString(exec).ascii()); 44 return Undefined(); 45 } 46 47 class GlobalImp : public ObjectImp { 48 public: 49 virtual UString className() const { return "global"; } 50 }; 28 51 29 52 int main(int argc, char **argv) … … 35 58 } 36 59 37 // create interpreter 38 KJScript *kjs = new KJScript(); 60 bool ret = true; 61 { 62 Object global(new GlobalImp()); 39 63 40 // add debug() function 41 kjs->enableDebug(); 64 // create interpreter 65 Interpreter interp(global); 66 global.put(interp.globalExec(),"debug", Object(new TestFunctionImp())); 67 // add "print" for compatibility with the mozilla js shell 68 global.put(interp.globalExec(),"print", Object(new TestFunctionImp())); 42 69 43 const int BufferSize = 100000;44 char code[BufferSize];70 // add debug() function 71 // kjs->enableDebug(); 45 72 46 bool ret = true; 47 for (int i = 1; i < argc; i++) { 48 const char *file = argv[i]; 49 FILE *f = fopen(file, "r"); 50 if (!f) { 51 fprintf(stderr, "Error opening %s.\n", file); 52 return -1; 73 const int BufferSize = 200000; 74 char code[BufferSize]; 75 76 for (int i = 1; i < argc; i++) { 77 const char *file = argv[i]; 78 FILE *f = fopen(file, "r"); 79 if (!f) { 80 fprintf(stderr, "Error opening %s.\n", file); 81 return -1; 82 } 83 int num = fread(code, 1, BufferSize, f); 84 code[num] = '\0'; 85 if(num >= BufferSize) 86 fprintf(stderr, "Warning: File may have been too long.\n"); 87 88 // run 89 Completion comp(interp.evaluate(code)); 90 91 fclose(f); 92 93 if (comp.complType() == Throw) { 94 ExecState *exec = interp.globalExec(); 95 Value exVal = comp.value(); 96 char *msg = exVal.toString(exec).ascii(); 97 int lineno = -1; 98 if (exVal.type() == ObjectType) { 99 Value lineVal = Object::dynamicCast(exVal).get(exec,"line"); 100 if (lineVal.type() == NumberType) 101 lineno = int(lineVal.toNumber(exec)); 102 } 103 if (lineno != -1) 104 fprintf(stderr,"Exception, line %d: %s\n",lineno,msg); 105 else 106 fprintf(stderr,"Exception: %s\n",msg); 107 ret = false; 108 } 109 else if (comp.complType() == ReturnValue) { 110 char *msg = comp.value().toString(interp.globalExec()).ascii(); 111 fprintf(stderr,"Return value: %s\n",msg); 112 } 53 113 } 54 int num = fread(code, 1, BufferSize, f);55 code[num] = '\0';56 if(num >= BufferSize)57 fprintf(stderr, "Warning: File may have been too long.\n");58 114 59 // run 60 ret = ret && kjs->evaluate(code); 61 if (kjs->errorType() != 0) 62 printf("%s returned: %s\n", file, kjs->errorMsg()); 63 else if (kjs->returnValue()) 64 printf("returned a value\n"); 115 // delete kjs; 116 } // end block, so that Interpreter and global get deleted 65 117 66 fclose(f); 67 } 68 69 delete kjs; 118 if (ret) 119 fprintf(stderr, "OK.\n"); 70 120 71 121 #ifdef KJS_DEBUG_MEM 72 printf("List::count = %d\n", KJS::List::count); 73 assert(KJS::List::count == 0); 74 printf("Imp::count = %d\n", KJS::Imp::count); 75 assert(KJS::Imp::count == 0); 122 Interpreter::finalCheck(); 76 123 #endif 77 78 fprintf(stderr, "OK.\n");79 124 return ret; 80 125 } -
trunk/JavaScriptCore/kjs/types.cpp
r6 r798 1 // -*- c-basic-offset: 2 -*- 1 2 /* 2 3 * This file is part of the KDE libraries 3 * Copyright (C) 1999-2000 Harri Porten ([email protected]) 4 * Copyright (C) 1999-2001 Harri Porten ([email protected]) 5 * Copyright (C) 2001 Peter Kelly ([email protected]) 4 6 * 5 7 * This library is free software; you can redistribute it and/or … … 17 19 * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, 18 20 * Boston, MA 02111-1307, USA. 21 * 22 * $Id$ 19 23 */ 20 24 21 #include <stdio.h> 22 23 #include "kjs.h" 25 #include "value.h" 24 26 #include "object.h" 25 27 #include "types.h" 28 #include "interpreter.h" 29 30 #include <assert.h> 31 #include <math.h> 32 #include <stdio.h> 33 26 34 #include "internal.h" 35 #include "collector.h" 27 36 #include "operations.h" 37 #include "error_object.h" 28 38 #include "nodes.h" 29 39 30 40 using namespace KJS; 31 41 32 Undefined::Undefined() : KJSO(UndefinedImp::staticUndefined) { } 33 34 Undefined::~Undefined() { } 35 36 Null::Null() : KJSO(NullImp::staticNull) { } 37 38 Null::~Null() { } 39 40 Boolean::Boolean(bool b) 41 : KJSO(b ? BooleanImp::staticTrue : BooleanImp::staticFalse) 42 { 43 } 44 45 Boolean::Boolean(BooleanImp *i) : KJSO(i) { } 46 47 Boolean::~Boolean() { } 48 49 bool Boolean::value() const 50 { 51 assert(rep); 52 return ((BooleanImp*)rep)->value(); 53 } 54 55 Number::Number(int i) 56 : KJSO(new NumberImp(static_cast<double>(i))) { } 57 58 Number::Number(unsigned int u) 59 : KJSO(new NumberImp(static_cast<double>(u))) { } 60 61 Number::Number(double d) 62 : KJSO(new NumberImp(d)) { } 63 64 Number::Number(long int l) 65 : KJSO(new NumberImp(static_cast<double>(l))) { } 66 67 Number::Number(long unsigned int l) 68 : KJSO(new NumberImp(static_cast<double>(l))) { } 69 70 Number::Number(NumberImp *i) 71 : KJSO(i) { } 72 73 Number::~Number() { } 74 75 double Number::value() const 76 { 77 assert(rep); 78 return ((NumberImp*)rep)->value(); 79 } 80 81 int Number::intValue() const 82 { 83 assert(rep); 84 return (int)((NumberImp*)rep)->value(); 85 } 86 87 bool Number::isNaN() const 88 { 89 return KJS::isNaN(((NumberImp*)rep)->value()); 90 } 91 92 bool Number::isInf() const 93 { 94 return KJS::isInf(((NumberImp*)rep)->value()); 95 } 96 97 String::String(const UString &s) : KJSO(new StringImp(UString(s))) { } 98 99 String::String(StringImp *i) : KJSO(i) { } 100 101 String::~String() { } 102 103 UString String::value() const 104 { 105 assert(rep); 106 return ((StringImp*)rep)->value(); 107 } 108 109 Reference::Reference(const KJSO& b, const UString &p) 110 : KJSO(new ReferenceImp(b, p)) 42 // ------------------------------ Reference ------------------------------------ 43 44 Reference::Reference(const Object& b, const UString& p) 45 : Value(new ReferenceImp(b,p)) 46 { 47 } 48 49 Reference::Reference(const Null& b, const UString& p) 50 : Value(new ReferenceImp(b,p)) 51 { 52 } 53 54 Reference::Reference(ReferenceImp *v) : Value(v) 55 { 56 } 57 58 Reference::Reference(const Reference &v) : Value(v) 111 59 { 112 60 } … … 116 64 } 117 65 118 Completion::Completion(Imp *d) : KJSO(d) { } 119 120 Completion::Completion(Compl c) 121 : KJSO(new CompletionImp(c, KJSO(), UString::null)) 122 { 123 if (c == Throw) 124 KJScriptImp::setException(new UndefinedImp()); 125 } 126 127 Completion::Completion(Compl c, const KJSO& v, const UString &t) 128 : KJSO(new CompletionImp(c, v, t)) 129 { 130 if (c == Throw) 131 KJScriptImp::setException(v.imp()); 132 } 133 134 Completion::~Completion() { } 135 136 Compl Completion::complType() const 137 { 138 assert(rep); 139 return ((CompletionImp*)rep)->completion(); 66 Reference& Reference::operator=(const Reference &v) 67 { 68 Value::operator=(v); 69 return *this; 70 } 71 72 Reference Reference::dynamicCast(const Value &v) 73 { 74 if (v.isNull() || v.type() != ReferenceType) 75 return 0; 76 77 return static_cast<ReferenceImp*>(v.imp()); 78 } 79 80 // ------------------------------ ListIterator --------------------------------- 81 82 //d dont add ListIterator(); 83 84 ListIterator::ListIterator(ListNode *n) : node(n) 85 { 86 } 87 88 ListIterator::ListIterator(const List &l) 89 : node(static_cast<ListImp*>(l.imp())->hook->next) 90 { 91 } 92 93 ListIterator& ListIterator::operator=(const ListIterator &iterator) 94 { 95 node=iterator.node; 96 return *this; 97 } 98 99 ListIterator::ListIterator(const ListIterator &i) : node(i.node) 100 { 101 } 102 103 ListIterator::~ListIterator() 104 { 105 } 106 107 ValueImp* ListIterator::operator->() const 108 { 109 return node->member; 110 } 111 112 // operator Value* () const { return node->member; } 113 Value ListIterator::operator*() const 114 { 115 return Value(node->member); 116 } 117 118 // operator Value*() const { return node->member; } 119 Value ListIterator::operator++() 120 { 121 node = node->next; 122 return Value(node->member); 123 } 124 125 Value ListIterator::operator++(int) 126 { 127 const ListNode *n = node; 128 ++*this; 129 return Value(n->member); 130 } 131 132 Value ListIterator::operator--() 133 { 134 node = node->prev; 135 return Value(node->member); 136 } 137 138 Value ListIterator::operator--(int) 139 { 140 const ListNode *n = node; 141 --*this; 142 return Value(n->member); 143 } 144 145 bool ListIterator::operator==(const ListIterator &it) const 146 { 147 return (node==it.node); 148 } 149 150 bool ListIterator::operator!=(const ListIterator &it) const 151 { 152 return (node!=it.node); 153 } 154 155 // ------------------------------ List ----------------------------------------- 156 157 List::List() 158 : Value(new ListImp()) 159 { 160 //fprintf(stderr,"List::List() this=%p imp=%p refcount=%d\n",this,rep,rep->refcount); 161 } 162 163 List::List(ListImp *v) : Value(v) 164 { 165 //fprintf(stderr,"List::List(imp) this=%p imp=%p refcount=%d\n",this,v,v?v->refcount:0); 166 } 167 168 List::List(const List &v) : Value(v) 169 { 170 //fprintf(stderr,"List::List(List) this=%p imp=%p refcount=%d\n",this,rep,rep?rep->refcount:0); 171 } 172 173 List::~List() 174 { 175 //fprintf(stderr,"List::~List() this=%p imp=%p refcount=%d\n",this,rep,rep->refcount-1); 176 } 177 178 List& List::operator=(const List &v) 179 { 180 //fprintf(stderr,"List::operator=() this=%p\n",this); 181 Value::operator=(v); 182 return *this; 183 } 184 185 List List::dynamicCast(const Value &v) 186 { 187 if (v.isNull() || v.type() != ListType) 188 return 0; 189 190 return static_cast<ListImp*>(v.imp()); 191 } 192 193 void List::append(const Value& val) 194 { 195 static_cast<ListImp*>(rep)->append(val); 196 } 197 198 void List::prepend(const Value& val) 199 { 200 static_cast<ListImp*>(rep)->prepend(val); 201 } 202 203 void List::appendList(const List& lst) 204 { 205 static_cast<ListImp*>(rep)->appendList(lst); 206 } 207 208 void List::prependList(const List& lst) 209 { 210 static_cast<ListImp*>(rep)->prependList(lst); 211 } 212 213 void List::removeFirst() 214 { 215 static_cast<ListImp*>(rep)->removeFirst(); 216 } 217 218 void List::removeLast() 219 { 220 static_cast<ListImp*>(rep)->removeLast(); 221 } 222 223 void List::remove(const Value &val) 224 { 225 static_cast<ListImp*>(rep)->remove(val); 226 } 227 228 void List::clear() 229 { 230 static_cast<ListImp*>(rep)->clear(); 231 } 232 233 List List::copy() const 234 { 235 return static_cast<ListImp*>(rep)->copy(); 236 } 237 238 ListIterator List::begin() const 239 { 240 return static_cast<ListImp*>(rep)->begin(); 241 } 242 243 ListIterator List::end() const 244 { 245 return static_cast<ListImp*>(rep)->end(); 246 } 247 248 bool List::isEmpty() const 249 { 250 return static_cast<ListImp*>(rep)->isEmpty(); 251 } 252 253 int List::size() const 254 { 255 return static_cast<ListImp*>(rep)->size(); 256 } 257 258 Value List::at(int i) const 259 { 260 return static_cast<ListImp*>(rep)->at(i); 261 } 262 263 Value List::operator[](int i) const 264 { 265 return static_cast<ListImp*>(rep)->at(i); 266 } 267 268 const List List::empty() 269 { 270 return ListImp::empty(); 271 } 272 273 // ------------------------------ Completion ----------------------------------- 274 275 Completion::Completion(ComplType c, const Value& v, const UString &t) 276 : Value(new CompletionImp(c,v,t)) 277 { 278 } 279 280 Completion::Completion(CompletionImp *v) : Value(v) 281 { 282 } 283 284 Completion::Completion(const Completion &v) : Value(v) 285 { 286 } 287 288 Completion::~Completion() 289 { 290 } 291 292 Completion& Completion::operator=(const Completion &v) 293 { 294 Value::operator=(v); 295 return *this; 296 } 297 298 Completion Completion::dynamicCast(const Value &v) 299 { 300 if (v.isNull() || v.type() != CompletionType) 301 return 0; 302 303 return static_cast<CompletionImp*>(v.imp()); 304 } 305 306 ComplType Completion::complType() const 307 { 308 return static_cast<CompletionImp*>(rep)->complType(); 309 } 310 311 Value Completion::value() const 312 { 313 return static_cast<CompletionImp*>(rep)->value(); 314 } 315 316 UString Completion::target() const 317 { 318 return static_cast<CompletionImp*>(rep)->target(); 140 319 } 141 320 142 321 bool Completion::isValueCompletion() const 143 322 { 144 assert(rep); 145 return !((CompletionImp*)rep)->value().isNull(); 146 } 147 148 KJSO Completion::value() const 149 { 150 assert(isA(CompletionType)); 151 return ((CompletionImp*)rep)->value(); 152 } 153 154 UString Completion::target() const 155 { 156 assert(rep); 157 return ((CompletionImp*)rep)->target(); 158 } 159 160 ListIterator::ListIterator(const List &l) 161 : node(l.hook->next) 162 { 163 } 164 165 List::List() 166 { 167 #ifdef KJS_DEBUG_MEM 168 count++; 169 #endif 170 171 static KJSO *null = 0; 172 if (!null) 173 null = new KJSO(); 174 175 hook = new ListNode(*null, 0L, 0L); 176 hook->next = hook; 177 hook->prev = hook; 178 } 179 180 List::~List() 181 { 182 #ifdef KJS_DEBUG_MEM 183 count--; 184 #endif 185 186 clear(); 187 delete hook; 188 } 189 190 void List::append(const KJSO& obj) 191 { 192 ListNode *n = new ListNode(obj, hook->prev, hook); 193 hook->prev->next = n; 194 hook->prev = n; 195 } 196 197 void List::prepend(const KJSO& obj) 198 { 199 ListNode *n = new ListNode(obj, hook, hook->next); 200 hook->next->prev = n; 201 hook->next = n; 202 } 203 204 void List::removeFirst() 205 { 206 erase(hook->next); 207 } 208 209 void List::removeLast() 210 { 211 erase(hook->prev); 212 } 213 214 void List::remove(const KJSO &obj) 215 { 216 if (obj.isNull()) 217 return; 218 ListNode *n = hook->next; 219 while (n != hook) { 220 if (n->member.imp() == obj.imp()) { 221 erase(n); 222 return; 223 } 224 n = n->next; 225 } 226 } 227 228 void List::clear() 229 { 230 ListNode *n = hook->next; 231 while (n != hook) { 232 n = n->next; 233 delete n->prev; 234 } 235 236 hook->next = hook; 237 hook->prev = hook; 238 } 239 240 List *List::copy() const 241 { 242 List *newList = new List(); 243 ListIterator e = end(); 244 ListIterator it = begin(); 245 246 while(it != e) { 247 newList->append(*it); 248 ++it; 249 } 250 251 return newList; 252 } 253 254 void List::erase(ListNode *n) 255 { 256 if (n != hook) { 257 n->next->prev = n->prev; 258 n->prev->next = n->next; 259 delete n; 260 } 261 } 262 263 int List::size() const 264 { 265 int s = 0; 266 ListNode *node = hook; 267 while ((node = node->next) != hook) 268 s++; 269 270 return s; 271 } 272 273 KJSO List::at(int i) const 274 { 275 if (i < 0 || i >= size()) 276 return Undefined(); 277 278 ListIterator it = begin(); 279 int j = 0; 280 while ((j++ < i)) 281 it++; 282 283 return *it; 284 } 285 286 List *List::emptyList = 0L; 287 288 const List *List::empty() 289 { 290 if (!emptyList) 291 emptyList = new List; 292 #ifdef KJS_DEBUG_MEM 293 else 294 count++; 295 #endif 296 297 298 return emptyList; 299 } 323 return !value().isNull(); 324 } -
trunk/JavaScriptCore/kjs/types.h
r6 r798 1 // -*- c-basic-offset: 2 -*- 1 2 /* 2 3 * This file is part of the KDE libraries 3 * Copyright (C) 1999-2000 Harri Porten ([email protected]) 4 * Copyright (C) 1999-2001 Harri Porten ([email protected]) 5 * Copyright (C) 2001 Peter Kelly ([email protected]) 4 6 * 5 7 * This library is free software; you can redistribute it and/or … … 17 19 * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, 18 20 * Boston, MA 02111-1307, USA. 21 * 22 * $Id$ 19 23 */ 20 24 21 #ifndef _TYPES_H_ 22 #define _TYPES_H_ 23 24 #include "object.h" 25 #ifndef _KJS_TYPES_H_ 26 #define _KJS_TYPES_H_ 27 28 // internal data types 29 30 #include "value.h" 25 31 26 32 namespace KJS { 27 33 28 /** 29 * @short Handle for an Undefined type. 30 */ 31 class Undefined : public KJSO { 32 public: 33 Undefined(); 34 virtual ~Undefined(); 35 }; 36 37 /** 38 * @short Handle for a Null type. 39 */ 40 class Null : public KJSO { 41 public: 42 Null(); 43 virtual ~Null(); 44 }; 45 46 class BooleanImp; 47 class NumberImp; 48 class StringImp; 49 50 /** 51 * @short Handle for a Boolean type. 52 */ 53 class Boolean : public KJSO { 54 friend class BooleanImp; 55 public: 56 Boolean(bool b = false); 57 virtual ~Boolean(); 58 bool value() const; 59 private: 60 Boolean(BooleanImp *i); 61 }; 62 63 /** 64 * @short Handle for a Number type. 65 * 66 * Number is a handle for a number value. @ref KJSO::toPrimitive(), 67 * @ref KJSO::toBoolean(), @ref KJSO::toNumber(), @ref KJSO::toString() and 68 * @ref KJSO::toString() are re-implemented internally according to the 69 * specification. 70 * 71 * Example usage: 72 * <pre> 73 * Number a(2), b(3.0), c; // c defaults to 0.0 74 * 75 * c = a.value() * b.value(); // c will be 6.0 now 76 * 77 * String s = c.toString(); // s holds "6" 78 * </pre> 79 * 80 * Note the following implementation detail: Internally, the value is stored 81 * as a double and will be casted from and to other types when needed. 82 * This won't be noticable within a certain range of values but might produce 83 * unpredictable results when crossing these limits. In case this turns out 84 * to be a real problem for an application we might have to extend this class 85 * to behave more intelligently. 86 */ 87 class Number : public KJSO { 88 friend class NumberImp; 89 public: 90 /** 91 * Construct a Number type from an integer. 92 */ 93 Number(int i); 94 /** 95 * Construct a Number type from an unsigned integer. 96 */ 97 Number(unsigned int u); 98 /** 99 * Construct a Number type from a double. 100 */ 101 Number(double d = 0.0); 102 /** 103 * Construct a Number type from a long int. 104 */ 105 Number(long int l); 106 /** 107 * Construct a Number type from a long unsigned int. 108 */ 109 Number(long unsigned int l); 110 /** 111 * Destructor. 112 */ 113 virtual ~Number(); 114 /** 115 * @return The internally stored value. 116 */ 117 double value() const; 118 /** 119 * Convenience function. 120 * @return The internally stored value converted to an int. 121 */ 122 int intValue() const; 123 /** 124 * @return True is this is not a number (NaN). 125 */ 126 bool isNaN() const; 127 /** 128 * @return True if Number is either +Infinity or -Infinity. 129 */ 130 bool isInf() const; 131 private: 132 Number(NumberImp *i); 133 }; 134 135 /** 136 * @short Handle for a String type. 137 */ 138 class String : public KJSO { 139 friend class StringImp; 140 public: 141 String(const UString &s = ""); 142 virtual ~String(); 143 UString value() const; 144 private: 145 String(StringImp *i); 146 }; 147 148 /** 149 * Completion objects are used to convey the return status and value 150 * from functions. 151 * 152 * See @ref FunctionImp::execute() 153 * 154 * @see FunctionImp 155 * 156 * @short Handle for a Completion type. 157 */ 158 class Completion : public KJSO { 159 public: 160 Completion(Imp *d = 0L); 161 Completion(Compl c); 162 Completion(Compl c, const KJSO& v, const UString &t = UString::null); 163 virtual ~Completion(); 164 Compl complType() const; 165 bool isValueCompletion() const; 166 KJSO value() const; 167 UString target() const; 34 class Reference : public Value { 35 public: 36 Reference(const Object& b, const UString& p); 37 Reference(const Null& b, const UString& p); 38 Reference(ReferenceImp *v); 39 Reference(const Reference &v); 40 virtual ~Reference(); 41 42 Reference& operator=(const Reference &v); 43 44 /** 45 * Converts a Value into an Reference. If the value's type is not 46 * ReferenceType, a null object will be returned (i.e. one with it's 47 * internal pointer set to 0). If you do not know for sure whether the 48 * value is of type ReferenceType, you should check the @ref isNull() 49 * methods afterwards before calling any methods on the returned value. 50 * 51 * @return The value converted to an Reference 52 */ 53 static Reference dynamicCast(const Value &v); 168 54 }; 169 55 170 56 class List; 171 57 class ListIterator; 172 173 /** 174 * @internal 175 */ 176 class ListNode { 177 friend class List; 178 friend class ListIterator; 179 ListNode(KJSO obj, ListNode *p, ListNode *n) 180 : member(obj), prev(p), next(n) {}; 181 KJSO member; 182 ListNode *prev, *next; 183 }; 58 class ListNode; 184 59 185 60 /** … … 188 63 class ListIterator { 189 64 friend class List; 65 friend class ListImp; 190 66 ListIterator(); 191 ListIterator(ListNode *n) : node(n) { }67 ListIterator(ListNode *n); 192 68 public: 193 69 /** … … 195 71 * @param l The list the iterator will operate on. 196 72 */ 197 ListIterator(const List &l ist);73 ListIterator(const List &l); 198 74 /** 199 75 * Assignment constructor. 200 76 */ 201 ListIterator& operator=(const ListIterator &iterator) 202 { node=iterator.node; return *this; } 77 ListIterator& operator=(const ListIterator &iterator); 203 78 /** 204 79 * Copy constructor. 205 80 */ 206 ListIterator(const ListIterator &i) : node(i.node) { } 81 ListIterator(const ListIterator &i); 82 ~ListIterator(); 207 83 /** 208 84 * Dereference the iterator. 209 85 * @return A pointer to the element the iterator operates on. 210 86 */ 211 KJSO* operator->() const { return &node->member; }212 // operator KJSO* () const { return node->member; }213 KJSO operator*() const { return node->member; }214 /** 215 * Conversion to @ref KJS:: KJSO*87 ValueImp* operator->() const; 88 // operator Value* () const { return node->member; } 89 Value operator*() const; 90 /** 91 * Conversion to @ref KJS::Value* 216 92 * @return A pointer to the element the iterator operates on. 217 93 */ 218 // operator KJSO*() const { return node->member; }94 // operator Value*() const { return node->member; } 219 95 /** 220 96 * Postfix increment operator. 221 97 * @return The element after the increment. 222 98 */ 223 KJSO operator++() { node = node->next; return node->member; }99 Value operator++(); 224 100 /** 225 101 * Prefix increment operator. 226 102 */ 227 KJSO operator++(int) { const ListNode *n = node; ++*this; return n->member; }103 Value operator++(int); 228 104 /** 229 105 * Postfix decrement operator. 230 106 */ 231 KJSO operator--() { node = node->prev; return node->member; }107 Value operator--(); 232 108 /** 233 109 * Prefix decrement operator. 234 110 */ 235 KJSO operator--(int) { const ListNode *n = node; --*this; return n->member; }111 Value operator--(int); 236 112 /** 237 113 * Compare the iterator with another one. … … 239 115 * False otherwise. 240 116 */ 241 bool operator==(const ListIterator &it) const { return (node==it.node); }117 bool operator==(const ListIterator &it) const; 242 118 /** 243 119 * Check for inequality with another iterator. 244 120 * @return True if the two iterators operate on different list elements. 245 121 */ 246 bool operator!=(const ListIterator &it) const { return (node!=it.node); }122 bool operator!=(const ListIterator &it) const; 247 123 private: 248 124 ListNode *node; … … 259 135 * copy of the list the referenced objects are still shared. 260 136 */ 261 class List {137 class List : public Value { 262 138 friend class ListIterator; 263 139 public: 264 /**265 * Constructor.266 */267 140 List(); 268 /** 269 * Destructor. 270 */ 271 ~List(); 141 List(ListImp *v); 142 List(const List &v); 143 virtual ~List(); 144 145 List& operator=(const List &v); 146 147 /** 148 * Converts a Value into an List. If the value's type is not 149 * ListType, a null object will be returned (i.e. one with it's 150 * internal pointer set to 0). If you do not know for sure whether the 151 * value is of type List, you should check the @ref isNull() 152 * methods afterwards before calling any methods on the returned value. 153 * 154 * @return The value converted to an List 155 */ 156 static List dynamicCast(const Value &v); 272 157 /** 273 158 * Append an object to the end of the list. 274 159 * 275 * @param objPointer to object.276 */ 277 void append(const KJSO& obj);160 * @param val Pointer to object. 161 */ 162 void append(const Value& val); 278 163 /** 279 164 * Insert an object at the beginning of the list. 280 165 * 281 * @param obj Pointer to object. 282 */ 283 void prepend(const KJSO& obj); 166 * @param val Pointer to object. 167 */ 168 void prepend(const Value& val); 169 /** 170 * Appends the items of another list at the end of this one. 171 */ 172 void appendList(const List& lst); 173 /** 174 * Prepend the items of another list to this one. 175 * The first item of @p lst will become the first item of the list. 176 */ 177 void prependList(const List& lst); 284 178 /** 285 179 * Remove the element at the beginning of the list. … … 291 185 void removeLast(); 292 186 /* 293 * Remove objfrom list.294 */ 295 void remove(const KJSO &obj);187 * Remove val from list. 188 */ 189 void remove(const Value &val); 296 190 /** 297 191 * Remove all elements from the list. … … 302 196 * who is responsible for deleting the list then. 303 197 */ 304 List *copy() const;198 List copy() const; 305 199 /** 306 200 * @return A @ref KJS::ListIterator pointing to the first element. 307 201 */ 308 ListIterator begin() const { return ListIterator(hook->next); }202 ListIterator begin() const; 309 203 /** 310 204 * @return A @ref KJS::ListIterator pointing to the last element. 311 205 */ 312 ListIterator end() const { return ListIterator(hook); }206 ListIterator end() const; 313 207 /** 314 208 * @return true if the list is empty. false otherwise. 315 209 */ 316 bool isEmpty() const { return (hook->prev == hook); }210 bool isEmpty() const; 317 211 /** 318 212 * @return the current size of the list. … … 327 221 * index is out of range. 328 222 */ 329 KJSOat(int i) const;223 Value at(int i) const; 330 224 /** 331 225 * Equivalent to @ref at. 332 226 */ 333 KJSO operator[](int i) const { return at(i); }227 Value operator[](int i) const; 334 228 /** 335 229 * Returns a pointer to a static instance of an empty list. Useful if a 336 230 * function has a @ref KJS::List parameter. 337 231 */ 338 static const List *empty(); 339 340 #ifdef KJS_DEBUG_MEM 341 /** 342 * @internal 343 */ 344 static int count; 345 #endif 346 private: 347 void erase(ListNode *n); 348 ListNode *hook; 349 static List *emptyList; 232 static const List empty(); 233 }; 234 235 /** 236 * Completion types. 237 */ 238 enum ComplType { Normal, Break, Continue, ReturnValue, Throw }; 239 240 /** 241 * Completion objects are used to convey the return status and value 242 * from functions. 243 * 244 * See @ref FunctionImp::execute() 245 * 246 * @see FunctionImp 247 * 248 * @short Handle for a Completion type. 249 */ 250 class Completion : public Value { 251 public: 252 Completion(ComplType c = Normal, const Value& v = Value(), 253 const UString &t = UString::null); 254 Completion(CompletionImp *v); 255 Completion(const Completion &v); 256 virtual ~Completion(); 257 258 Completion& operator=(const Completion &v); 259 260 /** 261 * Converts a Value into an Completion. If the value's type is not 262 * CompletionType, a null object will be returned (i.e. one with it's 263 * internal pointer set to 0). If you do not know for sure whether the 264 * value is of type CompletionType, you should check the @ref isNull() 265 * methods afterwards before calling any methods on the returned value. 266 * 267 * @return The value converted to an Completion 268 */ 269 static Completion dynamicCast(const Value &v); 270 271 ComplType complType() const; 272 Value value() const; 273 UString target() const; 274 bool isValueCompletion() const; 350 275 }; 351 276 352 277 }; // namespace 353 278 354 355 #endif 279 #endif // _KJS_TYPES_H_ -
trunk/JavaScriptCore/kjs/ustring.cpp
r6 r798 1 // -*- c-basic-offset: 2 -*- 1 2 /* 2 3 * This file is part of the KDE libraries … … 17 18 * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, 18 19 * Boston, MA 02111-1307, USA. 20 * 21 * $Id$ 19 22 */ 20 23 … … 35 38 #include "ustring.h" 36 39 #include "operations.h" 40 #include <math.h> 37 41 38 42 namespace KJS { … … 122 126 123 127 UChar::UChar(const UCharReference &c) 124 #ifdef KJS_SWAPPED_CHAR 125 : lo(c.low()), hi(c.high()) 126 #else 127 : hi(c.high()), lo(c.low()) 128 #endif 128 : uc( c.unicode() ) 129 129 { 130 130 } … … 132 132 UChar UChar::toLower() const 133 133 { 134 if (islower(lo) && hi == 0) 134 // ### properly supprot unicode tolower 135 if (uc >= 256 || islower(uc)) 135 136 return *this; 136 137 137 return UChar( 0, tolower(lo));138 return UChar(tolower(uc)); 138 139 } 139 140 140 141 UChar UChar::toUpper() const 141 142 { 142 if ( isupper(lo) && hi == 0)143 if (uc >= 256 || isupper(uc)) 143 144 return *this; 144 145 145 return UChar( 0, toupper(lo));146 return UChar(toupper(uc)); 146 147 } 147 148 … … 237 238 { 238 239 char buf[40]; 239 sprintf(buf, "%.16g", d); // does the right thing 240 241 if (d == -0) 242 strcpy(buf,"0"); 243 else if (KJS::isNaN(d)) 244 strcpy(buf,"NaN"); 245 else if (KJS::isPosInf(d)) 246 strcpy(buf,"Infinity"); 247 else if (KJS::isNegInf(d)) 248 strcpy(buf,"-Infinity"); 249 else 250 sprintf(buf, "%.16g", d); // does the right thing 251 252 // ECMA 3rd ed. 9.8.1 9 e: "with no leading zeros" 253 int buflen = strlen(buf); 254 if (buflen >= 4 && buf[buflen-4] == 'e' && buf[buflen-2] == '0') { 255 buf[buflen-2] = buf[buflen-1]; 256 buf[buflen-1] = 0; 257 } 258 240 259 return UString(buf); 241 260 } … … 265 284 statBuffer = new char[size()+1]; 266 285 for(int i = 0; i < size(); i++) 267 statBuffer[i] = data()[i].lo ;286 statBuffer[i] = data()[i].low(); 268 287 statBuffer[size()] = '\0'; 269 288 … … 277 296 UChar *d = new UChar[l]; 278 297 for (int i = 0; i < l; i++) 279 d[i]. lo= c[i];298 d[i].uc = c[i]; 280 299 rep = Rep::create(d, l); 281 300 … … 287 306 str.rep->ref(); 288 307 release(); 289 rep = str.rep; 308 rep = str.rep; 290 309 291 310 return *this; … … 301 320 const UChar *u = data(); 302 321 for(int i = 0; i < size(); i++, u++) 303 if (u-> hi)322 if (u->uc > 0xFF) 304 323 return false; 305 324 … … 321 340 } 322 341 323 double UString::toDouble( ) const342 double UString::toDouble( bool tolerant ) const 324 343 { 325 344 double d; … … 355 374 char *end; 356 375 d = strtod(c, &end); 357 if ( d != 0.0 || end != c) {376 if ((d != 0.0 || end != c) && d != HUGE_VAL && d != -HUGE_VAL) { 358 377 c = end; 359 378 } else { … … 376 395 while (isspace(*c)) 377 396 c++; 378 if (*c != '\0') 397 // don't allow anything after - unless tolerant=true 398 if ( !tolerant && *c != '\0') 379 399 d = NaN; 380 400 … … 474 494 } 475 495 476 bool KJS::operator==(const UChar &c1, const UChar &c2)477 {478 return ((c1.lo == c2.lo) & (c1.hi == c2.hi));479 }480 481 496 bool KJS::operator==(const UString& s1, const UString& s2) 482 497 { … … 498 513 const UChar *u = s1.data(); 499 514 while (*s2) { 500 if (u-> lo != *s2 || u->hi != 0)515 if (u->uc != *s2 ) 501 516 return false; 502 517 s2++; … … 505 520 506 521 return true; 507 }508 509 bool KJS::operator==(const char *s1, const UString& s2)510 {511 return operator==(s2, s1);512 522 } 513 523 -
trunk/JavaScriptCore/kjs/ustring.h
r6 r798 1 // -*- c-basic-offset: 2 -*- 1 2 /* 2 3 * This file is part of the KDE libraries … … 17 18 * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, 18 19 * Boston, MA 02111-1307, USA. 20 * 21 * $Id$ 19 22 */ 20 23 21 #ifndef _KJS_ STRING_H_22 #define _KJS_ STRING_H_24 #ifndef _KJS_USTRING_H_ 25 #define _KJS_USTRING_H_ 23 26 24 27 #ifdef HAVE_CONFIG_H 25 28 #include <config.h> 29 #endif 30 31 #ifdef APPLE_CHANGES 32 #include <KWQDef.h> 26 33 #endif 27 34 … … 36 43 class QConstString; 37 44 38 #if defined(__GNUC__)39 #define KJS_PACKED __attribute__((__packed__))40 #else41 #define KJS_PACKED42 #endif43 44 45 namespace KJS { 45 46 … … 74 75 * @return The higher byte of the character. 75 76 */ 76 unsigned char high() const { return hi; }77 unsigned char high() const { return uc >> 8; } 77 78 /** 78 79 * @return The lower byte of the character. 79 80 */ 80 unsigned char low() const { return lo; }81 unsigned char low() const { return uc & 0xFF; } 81 82 /** 82 83 * @return the 16 bit Unicode value of the character 83 84 */ 84 unsigned short unicode() const { return hi << 8 | lo; }85 unsigned short unicode() const { return uc; } 85 86 public: 86 87 /** … … 102 103 friend bool operator==(const UString& s1, const char *s2); 103 104 friend bool operator<(const UString& s1, const UString& s2); 104 #ifdef KJS_SWAPPED_CHAR 105 unsigned char lo; 106 unsigned char hi; 107 #else 108 unsigned char hi; 109 unsigned char lo; 110 #endif 111 } KJS_PACKED; 112 113 114 #ifdef KJS_SWAPPED_CHAR // to avoid reorder warnings 115 inline UChar::UChar() : lo(0), hi(0) { } 116 inline UChar::UChar(unsigned char h , unsigned char l) : lo(l), hi(h) { } 117 inline UChar::UChar(unsigned short u) : lo(u & 0x00ff), hi(u >> 8) { } 118 #else 119 inline UChar::UChar() : hi(0), lo(0) { } 120 inline UChar::UChar(unsigned char h , unsigned char l) : hi(h), lo(l) { } 121 inline UChar::UChar(unsigned short u) : hi(u >> 8), lo(u & 0x00ff) { } 122 #endif 105 106 ushort uc; 107 }; 108 109 inline UChar::UChar() : uc(0) { } 110 inline UChar::UChar(unsigned char h , unsigned char l) : uc(h << 8 | l) { } 111 inline UChar::UChar(unsigned short u) : uc(u) { } 123 112 124 113 /** … … 155 144 * @return Lower byte. 156 145 */ 157 unsigned char & low() const { return ref().lo; }146 unsigned char low() const { return ref().uc & 0xFF; } 158 147 /** 159 148 * @return Higher byte. 160 149 */ 161 unsigned char & high() const { return ref().hi; }150 unsigned char high() const { return ref().uc >> 8; } 162 151 /** 163 152 * @return Character converted to lower case. … … 365 354 * indicated by a 0x or 0X prefix) and +/- Infinity. 366 355 * Returns NaN if the conversion failed. 367 */ 368 double toDouble() const; 356 * @param tolerant if true, toDouble can tolerate garbage after the number. 357 */ 358 double toDouble(bool tolerant=false) const; 369 359 /** 370 360 * Attempts an conversion to an unsigned long integer. ok will be set … … 398 388 }; 399 389 400 bool operator==(const UChar &c1, const UChar &c2); 390 inline bool operator==(const UChar &c1, const UChar &c2) { 391 return (c1.uc == c2.uc); 392 } 401 393 bool operator==(const UString& s1, const UString& s2); 402 394 inline bool operator!=(const UString& s1, const UString& s2) { … … 408 400 return !KJS::operator==(s1, s2); 409 401 } 410 bool operator==(const char *s1, const UString& s2); 402 inline bool operator==(const char *s1, const UString& s2) { 403 return operator==(s2, s1); 404 } 411 405 inline bool operator!=(const char *s1, const UString& s2) { 412 406 return !KJS::operator==(s1, s2);
Note:
See TracChangeset
for help on using the changeset viewer.