Changeset 798 in webkit for trunk/JavaScriptCore/kjs/function.cpp


Ignore:
Timestamp:
Mar 21, 2002, 4:31:57 PM (23 years ago)
Author:
mjs
Message:

Merged changes from LABYRINTH_KDE_3_MERGE branch.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/JavaScriptCore/kjs/function.cpp

    r6 r798  
     1// -*- c-basic-offset: 2 -*-
    12/*
    23 *  This file is part of the KDE libraries
    34 *  Copyright (C) 1999-2000 Harri Porten ([email protected])
     5 *  Copyright (C) 2001 Peter Kelly ([email protected])
    46 *
    57 *  This library is free software; you can redistribute it and/or
     
    1719 *  the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    1820 *  Boston, MA 02111-1307, USA.
     21 *
    1922 */
    2023
    2124#include "function.h"
    2225
    23 #include "kjs.h"
    24 #include "types.h"
    2526#include "internal.h"
     27#include "function_object.h"
     28#include "lexer.h"
     29#include "nodes.h"
    2630#include "operations.h"
    27 #include "nodes.h"
    28 #ifndef NDEBUG
     31#include "debugger.h"
     32
    2933#include <stdio.h>
    30 #endif
     34#include <assert.h>
     35#include <string.h>
    3136
    3237using namespace KJS;
    3338
    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
     41const ClassInfo FunctionImp::info = {"Function", &InternalFunctionImp::info, 0, 0};
    4142
    4243namespace KJS {
    43 
    4444  class Parameter {
    4545  public:
     
    4949    Parameter *next;
    5050  };
    51 
    5251};
    5352
    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 {
     53FunctionImp::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);
    6261}
    6362
    6463FunctionImp::~FunctionImp()
    6564{
     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());
    6669  delete param;
    6770}
    6871
    69 KJSO FunctionImp::thisValue() const
    70 {
    71   return KJSO(Context::current()->thisValue());
     72void FunctionImp::mark()
     73{
     74  InternalFunctionImp::mark();
     75  if (argStack && !argStack->marked())
     76    argStack->mark();
     77}
     78
     79bool FunctionImp::implementsCall() const
     80{
     81  return true;
     82}
     83
     84Value 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();
    72163}
    73164
     
    81172}
    82173
    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
     176void FunctionImp::processParameters(ExecState *exec, const List &args)
     177{
     178  Object variable = exec->context().imp()->variableObject();
    94179
    95180#ifdef KJS_VERBOSE
     
    100185
    101186  if (param) {
    102     ListIterator it = args->begin();
     187    ListIterator it = args.begin();
    103188    Parameter **p = &param;
    104189    while (*p) {
    105       if (it != args->end()) {
     190      if (it != args.end()) {
    106191#ifdef KJS_VERBOSE
    107192        fprintf(stderr, "setting parameter %s ", (*p)->name.ascii());
    108         printInfo("to", *it);
     193        printInfo(exec,"to", *it);
    109194#endif
    110         variable.put((*p)->name, *it);
     195        variable.put(exec,(*p)->name, *it);
    111196        it++;
    112197      } else
    113         variable.put((*p)->name, Undefined());
     198        variable.put(exec,(*p)->name, Undefined());
    114199      p = &(*p)->next;
    115200    }
     
    117202#ifdef KJS_VERBOSE
    118203  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]);
    121206  }
    122207#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
     210void FunctionImp::processVarDecls(ExecState */*exec*/)
     211{
     212}
     213
     214void FunctionImp::pushArgs(ExecState *exec, const Object &args)
     215{
     216  argStack->append(args);
     217  put(exec,"arguments",args,ReadOnly|DontDelete|DontEnum);
     218}
     219
     220void FunctionImp::popArgs(ExecState *exec)
     221{
     222  argStack->removeLast();
     223  if (argStack->isEmpty()) {
     224    put(exec,"arguments",Null(),ReadOnly|DontDelete|DontEnum);
     225  }
    189226  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?
     233const ClassInfo DeclaredFunctionImp::info = {"Function", &FunctionImp::info, 0, 0};
     234
     235DeclaredFunctionImp::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
     244DeclaredFunctionImp::~DeclaredFunctionImp()
     245{
     246  if ( body->deref() )
     247    delete body;
     248}
     249
     250bool DeclaredFunctionImp::implementsConstruct() const
     251{
     252  return true;
     253}
     254
     255// ECMA 13.2.2 [[Construct]]
     256Object 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()));
    201262  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);
    229271  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
     275Completion 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
     284void DeclaredFunctionImp::processVarDecls(ExecState *exec)
     285{
     286  body->processVarDecls(exec);
     287}
     288
     289// ------------------------------ ArgumentsImp ---------------------------------
     290
     291const ClassInfo ArgumentsImp::info = {"Arguments", 0, 0, 0};
     292
     293// ECMA 10.1.8
     294ArgumentsImp::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
     310const ClassInfo ActivationImp::info = {"Activation", 0, 0, 0};
     311
     312// ECMA 10.1.6
     313ActivationImp::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
     321ActivationImp::~ActivationImp()
     322{
     323  arguments->setGcAllowed();
     324}
     325
     326// ------------------------------ GlobalFunc -----------------------------------
     327
     328
     329GlobalFuncImp::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
     336CodeType GlobalFuncImp::codeType() const
     337{
     338  return id == Eval ? EvalCode : codeType();
     339}
     340
     341bool GlobalFuncImp::implementsCall() const
     342{
     343  return true;
     344}
     345
     346Value 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.