Changeset 798 in webkit for trunk/JavaScriptCore/kjs/function.cpp
- Timestamp:
- Mar 21, 2002, 4:31:57 PM (23 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
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 }
Note:
See TracChangeset
for help on using the changeset viewer.