00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include "function.h"
00025
00026 #include "internal.h"
00027 #include "function_object.h"
00028 #include "lexer.h"
00029 #include "nodes.h"
00030 #include "operations.h"
00031 #include "debugger.h"
00032
00033 #include <stdio.h>
00034 #include <stdlib.h>
00035 #include <assert.h>
00036 #include <string.h>
00037 #include <errno.h>
00038 #include <math.h>
00039 #include <ctype.h>
00040
00041 using namespace KJS;
00042
00043
00044
00045 const ClassInfo FunctionImp::info = {"Function", &InternalFunctionImp::info, 0, 0};
00046
00047 namespace KJS {
00048 class Parameter {
00049 public:
00050 Parameter(const UString &n) : name(n), next(0L) { }
00051 ~Parameter() { delete next; }
00052 UString name;
00053 Parameter *next;
00054 };
00055 }
00056
00057 FunctionImp::FunctionImp(ExecState *exec, const UString &n)
00058 : InternalFunctionImp(
00059 static_cast<FunctionPrototypeImp*>(exec->interpreter()->builtinFunctionPrototype().imp())
00060 ), param(0L), ident(n), argStack(0)
00061 {
00062 Value protect(this);
00063 argStack = new ListImp();
00064 Value protectArgStack( argStack );
00065
00066 put(exec,"arguments",Null(),ReadOnly|DontDelete|DontEnum);
00067 }
00068
00069 FunctionImp::~FunctionImp()
00070 {
00071
00072
00073
00074
00075
00076
00077 delete param;
00078 }
00079
00080 void FunctionImp::mark()
00081 {
00082 InternalFunctionImp::mark();
00083 if (argStack && !argStack->marked())
00084 argStack->mark();
00085 }
00086
00087 bool FunctionImp::implementsCall() const
00088 {
00089 return true;
00090 }
00091
00092 Value FunctionImp::call(ExecState *exec, Object &thisObj, const List &args)
00093 {
00094 Object globalObj = exec->interpreter()->globalObject();
00095
00096 Debugger *dbg = exec->interpreter()->imp()->debugger();
00097 int sid = -1;
00098 int lineno = -1;
00099 if (dbg) {
00100 if (inherits(&DeclaredFunctionImp::info)) {
00101 sid = static_cast<DeclaredFunctionImp*>(this)->body->sourceId();
00102 lineno = static_cast<DeclaredFunctionImp*>(this)->body->firstLine();
00103 }
00104
00105 Object func(this);
00106 bool cont = dbg->callEvent(exec,sid,lineno,func,args);
00107 if (!cont) {
00108 dbg->imp()->abort();
00109 return Undefined();
00110 }
00111 }
00112
00113
00114 ContextImp ctx(globalObj, exec, thisObj, codeType(),
00115 exec->context().imp(), this, args);
00116 ExecState newExec(exec->interpreter(), &ctx);
00117 newExec.setException(exec->exception());
00118
00119
00120
00121
00122
00123 if (codeType() == FunctionCode) {
00124 assert(ctx.activationObject().inherits(&ActivationImp::info));
00125 Object argsObj = static_cast<ActivationImp*>(ctx.activationObject().imp())->argumentsObject();
00126 put(&newExec, "arguments", argsObj, DontDelete|DontEnum|ReadOnly);
00127 pushArgs(&newExec, argsObj);
00128 }
00129
00130
00131 processParameters(&newExec, args);
00132
00133 processVarDecls(&newExec);
00134
00135 Completion comp = execute(&newExec);
00136
00137
00138 if (newExec.hadException())
00139 exec->setException(newExec.exception());
00140 if (codeType() == FunctionCode)
00141 popArgs(&newExec);
00142
00143 #ifdef KJS_VERBOSE
00144 CString n = ident.isEmpty() ? CString("(internal)") : ident.cstring();
00145 if (comp.complType() == Throw) {
00146 n += " throws";
00147 printInfo(exec, n.c_str(), comp.value());
00148 } else if (comp.complType() == ReturnValue) {
00149 n += " returns";
00150 printInfo(exec, n.c_str(), comp.value());
00151 } else
00152 fprintf(stderr, "%s returns: undefined\n", n.c_str());
00153 #endif
00154
00155 if (dbg) {
00156 Object func(this);
00157 int cont = dbg->returnEvent(exec,sid,lineno,func);
00158 if (!cont) {
00159 dbg->imp()->abort();
00160 return Undefined();
00161 }
00162 }
00163
00164 if (comp.complType() == Throw) {
00165 exec->setException(comp.value());
00166 return comp.value();
00167 }
00168 else if (comp.complType() == ReturnValue)
00169 return comp.value();
00170 else
00171 return Undefined();
00172 }
00173
00174 void FunctionImp::addParameter(const UString &n)
00175 {
00176 Parameter **p = ¶m;
00177 while (*p)
00178 p = &(*p)->next;
00179
00180 *p = new Parameter(n);
00181 }
00182
00183 UString FunctionImp::parameterString() const
00184 {
00185 UString s;
00186 const Parameter * const *p = ¶m;
00187 while (*p) {
00188 if (!s.isEmpty())
00189 s += ", ";
00190 s += (*p)->name;
00191 p = &(*p)->next;
00192 }
00193
00194 return s;
00195 }
00196
00197
00198
00199 void FunctionImp::processParameters(ExecState *exec, const List &args)
00200 {
00201 Object variable = exec->context().imp()->variableObject();
00202
00203 #ifdef KJS_VERBOSE
00204 fprintf(stderr, "---------------------------------------------------\n"
00205 "processing parameters for %s call\n",
00206 name().isEmpty() ? "(internal)" : name().ascii());
00207 #endif
00208
00209 if (param) {
00210 ListIterator it = args.begin();
00211 Parameter **p = ¶m;
00212 while (*p) {
00213 if (it != args.end()) {
00214 #ifdef KJS_VERBOSE
00215 fprintf(stderr, "setting parameter %s ", (*p)->name.ascii());
00216 printInfo(exec,"to", *it);
00217 #endif
00218 variable.put(exec,(*p)->name, *it);
00219 it++;
00220 } else
00221 variable.put(exec,(*p)->name, Undefined());
00222 p = &(*p)->next;
00223 }
00224 }
00225 #ifdef KJS_VERBOSE
00226 else {
00227 for (int i = 0; i < args.size(); i++)
00228 printInfo(exec,"setting argument", args[i]);
00229 }
00230 #endif
00231 }
00232
00233 void FunctionImp::processVarDecls(ExecState *)
00234 {
00235 }
00236
00237 void FunctionImp::pushArgs(ExecState *exec, const Object &args)
00238 {
00239 argStack->append(args);
00240 put(exec,"arguments",args,ReadOnly|DontDelete|DontEnum);
00241 }
00242
00243 void FunctionImp::popArgs(ExecState *exec)
00244 {
00245 argStack->removeLast();
00246 if (argStack->isEmpty()) {
00247 put(exec,"arguments",Null(),ReadOnly|DontDelete|DontEnum);
00248 }
00249 else
00250 put(exec,"arguments",argStack->at(argStack->size()-1),ReadOnly|DontDelete|DontEnum);
00251 }
00252
00253
00254
00255
00256 const ClassInfo DeclaredFunctionImp::info = {"Function", &FunctionImp::info, 0, 0};
00257
00258 DeclaredFunctionImp::DeclaredFunctionImp(ExecState *exec, const UString &n,
00259 FunctionBodyNode *b, const List &sc)
00260 : FunctionImp(exec,n), body(b)
00261 {
00262 Value protect(this);
00263 body->ref();
00264 setScope(sc.copy());
00265 }
00266
00267 DeclaredFunctionImp::~DeclaredFunctionImp()
00268 {
00269 if ( body->deref() )
00270 delete body;
00271 }
00272
00273 bool DeclaredFunctionImp::implementsConstruct() const
00274 {
00275 return true;
00276 }
00277
00278
00279 Object DeclaredFunctionImp::construct(ExecState *exec, const List &args)
00280 {
00281 Object proto;
00282 Value p = get(exec,"prototype");
00283 if (p.type() == ObjectType)
00284 proto = Object(static_cast<ObjectImp*>(p.imp()));
00285 else
00286 proto = exec->interpreter()->builtinObjectPrototype();
00287
00288 Object obj(new ObjectImp(proto));
00289
00290 Value res = call(exec,obj,args);
00291
00292 if (res.type() == ObjectType)
00293 return Object::dynamicCast(res);
00294 else
00295 return obj;
00296 }
00297
00298 Completion DeclaredFunctionImp::execute(ExecState *exec)
00299 {
00300 Completion result = body->execute(exec);
00301
00302 if (result.complType() == Throw || result.complType() == ReturnValue)
00303 return result;
00304 return Completion(Normal, Undefined());
00305 }
00306
00307 void DeclaredFunctionImp::processVarDecls(ExecState *exec)
00308 {
00309 body->processVarDecls(exec);
00310 }
00311
00312
00313
00314 const ClassInfo ArgumentsImp::info = {"Arguments", 0, 0, 0};
00315
00316
00317 ArgumentsImp::ArgumentsImp(ExecState *exec, FunctionImp *func, const List &args)
00318 : ObjectImp(exec->interpreter()->builtinObjectPrototype())
00319 {
00320 Value protect(this);
00321 put(exec,"callee", Object(func), DontEnum);
00322 put(exec,"length", Number(args.size()), DontEnum);
00323 if (!args.isEmpty()) {
00324 ListIterator arg = args.begin();
00325 for (int i = 0; arg != args.end(); arg++, i++) {
00326 put(exec,UString::from(i), *arg, DontEnum);
00327 }
00328 }
00329 }
00330
00331
00332
00333 const ClassInfo ActivationImp::info = {"Activation", 0, 0, 0};
00334
00335
00336 ActivationImp::ActivationImp(ExecState *exec, FunctionImp *f, const List &args)
00337 : ObjectImp()
00338 {
00339 Value protect(this);
00340 arguments = new ArgumentsImp(exec,f, args);
00341 put(exec, "arguments", Object(arguments), Internal|DontDelete);
00342 }
00343
00344 ActivationImp::~ActivationImp()
00345 {
00346 arguments->inlinedSetGcAllowed();
00347 }
00348
00349
00350
00351
00352 GlobalFuncImp::GlobalFuncImp(ExecState *exec, FunctionPrototypeImp *funcProto, int i, int len)
00353 : InternalFunctionImp(funcProto), id(i)
00354 {
00355 Value protect(this);
00356 put(exec,"length",Number(len),DontDelete|ReadOnly|DontEnum);
00357 }
00358
00359 CodeType GlobalFuncImp::codeType() const
00360 {
00361 return id == Eval ? EvalCode : codeType();
00362 }
00363
00364 bool GlobalFuncImp::implementsCall() const
00365 {
00366 return true;
00367 }
00368
00369 Value GlobalFuncImp::call(ExecState *exec, Object &thisObj, const List &args)
00370 {
00371 Value res;
00372
00373 static const char non_escape[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
00374 "abcdefghijklmnopqrstuvwxyz"
00375 "0123456789@*_+-./";
00376
00377 switch (id) {
00378 case Eval: {
00379 Value x = args[0];
00380 if (x.type() != StringType)
00381 return x;
00382 else {
00383 UString s = x.toString(exec);
00384
00385 int sid;
00386 int errLine;
00387 UString errMsg;
00388 #ifdef KJS_VERBOSE
00389 fprintf(stderr, "eval(): %s\n", s.ascii());
00390 #endif
00391 ProgramNode *progNode = Parser::parse(s.data(),s.size(),&sid,&errLine,&errMsg);
00392
00393
00394 if (!progNode) {
00395 Object err = Error::create(exec,SyntaxError,errMsg.ascii(),errLine);
00396 err.put(exec,"sid",Number(sid));
00397 exec->setException(err);
00398 return err;
00399 }
00400
00401 progNode->ref();
00402
00403
00404 Object glob(exec->interpreter()->globalObject());
00405 ContextImp ctx(glob, exec, thisObj, EvalCode, exec->context().imp());
00406 ExecState newExec(exec->interpreter(), &ctx);
00407 newExec.setException(exec->exception());
00408
00409
00410 Completion c = progNode->execute(&newExec);
00411
00412
00413 if (newExec.hadException())
00414 exec->setException(newExec.exception());
00415
00416 if ( progNode->deref() )
00417 delete progNode;
00418 if (c.complType() == ReturnValue)
00419 return c;
00420
00421 else if (c.complType() == Normal) {
00422 if (c.isValueCompletion())
00423 return c.value();
00424 else
00425 return Undefined();
00426 } else {
00427 return c;
00428 }
00429 }
00430 break;
00431 }
00432 case ParseInt: {
00433 CString cstr = args[0].toString(exec).cstring();
00434 const char* startptr = cstr.c_str();
00435 while ( *startptr && isspace( *startptr ) )
00436 ++startptr;
00437 char* endptr;
00438 errno = 0;
00439
00440 int base = 0;
00441
00442 if ( args.size() > 1 )
00443 base = args[ 1 ].toInt32( exec );
00444 if ( base == 0 ) {
00445
00446 if ( *startptr == '0' && toupper( *(startptr+1) ) == 'X' )
00447 base = 16;
00448 else
00449 base = 10;
00450 }
00451
00452 if ( base != 10 )
00453 {
00454
00455 long value = strtol(startptr, &endptr, base);
00456 if (errno || endptr == startptr)
00457 res = Number(NaN);
00458 else
00459 res = Number(value);
00460 } else {
00461
00462
00463
00464
00465
00466 bool foundSign = false;
00467 bool foundDot = false;
00468 bool ok = false;
00469 for ( const char* ptr = startptr; *ptr; ++ptr ) {
00470 if ( *ptr >= '0' && *ptr <= '9' )
00471 ok = true;
00472 else if ( !foundSign && ( *ptr == '-' || *ptr == '+' ) )
00473 foundSign = true;
00474 else if ( ok && !foundDot && *ptr == '.' )
00475 foundDot = true;
00476 else {
00477 *const_cast<char *>(ptr) = '\0';
00478 break;
00479 }
00480 }
00481
00482 double value = strtod(startptr, &endptr);
00483 if (!ok || errno || endptr == startptr)
00484 res = Number(NaN);
00485 else
00486 res = Number(floor(value));
00487 }
00488 break;
00489 }
00490 case ParseFloat:
00491 res = Number(args[0].toString(exec).toDouble( true ));
00492 break;
00493 case IsNaN:
00494 res = Boolean(isNaN(args[0].toNumber(exec)));
00495 break;
00496 case IsFinite: {
00497 double n = args[0].toNumber(exec);
00498 res = Boolean(!isNaN(n) && !isInf(n));
00499 break;
00500 }
00501 case Escape: {
00502 UString r = "", s, str = args[0].toString(exec);
00503 const UChar *c = str.data();
00504 for (int k = 0; k < str.size(); k++, c++) {
00505 int u = c->unicode();
00506 if (u > 255) {
00507 char tmp[7];
00508 sprintf(tmp, "%%u%04X", u);
00509 s = UString(tmp);
00510 } else if (strchr(non_escape, (char)u)) {
00511 s = UString(c, 1);
00512 } else {
00513 char tmp[4];
00514 sprintf(tmp, "%%%02X", u);
00515 s = UString(tmp);
00516 }
00517 r += s;
00518 }
00519 res = String(r);
00520 break;
00521 }
00522 case UnEscape: {
00523 UString s, str = args[0].toString(exec);
00524 int k = 0, len = str.size();
00525 while (k < len) {
00526 const UChar *c = str.data() + k;
00527 UChar u;
00528 if (*c == UChar('%') && k <= len - 6 && *(c+1) == UChar('u')) {
00529 u = Lexer::convertUnicode((c+2)->unicode(), (c+3)->unicode(),
00530 (c+4)->unicode(), (c+5)->unicode());
00531 c = &u;
00532 k += 5;
00533 } else if (*c == UChar('%') && k <= len - 3) {
00534 u = UChar(Lexer::convertHex((c+1)->unicode(), (c+2)->unicode()));
00535 c = &u;
00536 k += 2;
00537 }
00538 k++;
00539 s += UString(c, 1);
00540 }
00541 res = String(s);
00542 break;
00543 }
00544 }
00545
00546 return res;
00547 }