Esempio n. 1
0
// ECMA 15.10.4
Object RegExpObjectImp::construct(ExecState *exec, const List &args)
{
  UString p;
  if (args.isEmpty()) {
      p = "";
  } else {
    Value a0 = args[0];
    if (a0.isA(ObjectType) && a0.toObject(exec).inherits(&RegExpImp::info)) {
      // It's a regexp. Check that no flags were passed.
      if (args.size() > 1 && args[1].type() != UndefinedType) {
          Object err = Error::create(exec,TypeError);
          exec->setException(err);
          return err;
      }
      RegExpImp *rimp = static_cast<RegExpImp*>(Object::dynamicCast(a0).imp());
      p = rimp->regExp()->pattern();
    } else {
      p = a0.toString(exec);
    }
  }

  RegExp* re = makeEngine(exec, p, args[1]);
  if (!re)
    return exec->exception().toObject(exec);

  RegExpPrototypeImp *proto = static_cast<RegExpPrototypeImp*>(exec->lexicalInterpreter()->builtinRegExpPrototype().imp());
  RegExpImp *dat = new RegExpImp(proto);
  Object obj(dat); // protect from GC
  dat->setRegExp(re);

  return obj;
}
Esempio n. 2
0
// ECMA 15.10.4
Object RegExpObjectImp::construct(ExecState *exec, const List &args)
{
  UString p = args.isEmpty() ? UString("") : args[0].toString(exec);
  UString flags = args[1].toString(exec);

  RegExpPrototypeImp *proto = static_cast<RegExpPrototypeImp*>(exec->interpreter()->builtinRegExpPrototype().imp());
  RegExpImp *dat = new RegExpImp(proto);
  Object obj(dat); // protect from GC

  bool global = (flags.find("g") >= 0);
  bool ignoreCase = (flags.find("i") >= 0);
  bool multiline = (flags.find("m") >= 0);
  // TODO: throw a syntax error on invalid flags

  dat->putDirect("global", global ? BooleanImp::staticTrue : BooleanImp::staticFalse);
  dat->putDirect("ignoreCase", ignoreCase ? BooleanImp::staticTrue : BooleanImp::staticFalse);
  dat->putDirect("multiline", multiline ? BooleanImp::staticTrue : BooleanImp::staticFalse);

  dat->putDirect("source", new StringImp(p));
  dat->putDirect("lastIndex", NumberImp::zero(), DontDelete | DontEnum);

  int reflags = RegExp::None;
  if (global)
      reflags |= RegExp::Global;
  if (ignoreCase)
      reflags |= RegExp::IgnoreCase;
  if (multiline)
      reflags |= RegExp::Multiline;
  dat->setRegExp(new RegExp(p, reflags));

  return obj;
}
Esempio n. 3
0
// ECMA 15.10.4
JSObject *RegExpObjectImp::construct(ExecState *exec, const List &args)
{
  JSObject *o = args[0]->getObject();
  if (o && o->inherits(&RegExpImp::info)) {
    if (!args[1]->isUndefined())
      return throwError(exec, TypeError);
    return o;
  }

  UString p = args[0]->isUndefined() ? UString("") : args[0]->toString(exec);

  RegExp* re = makeEngine(exec, p, args[1]);
  if (!re)
    return exec->exception()->toObject(exec);


  RegExpPrototype *proto = static_cast<RegExpPrototype*>(exec->lexicalInterpreter()->builtinRegExpPrototype());
  RegExpImp *dat = new RegExpImp(proto);

  dat->setRegExp(exec, re);

  return dat;
}
Esempio n. 4
0
// ECMA 15.10.4
JSObject *RegExpObjectImp::construct(ExecState *exec, const List &args)
{
  JSObject *o = args[0]->getObject();
  if (o && o->inherits(&RegExpImp::info)) {
    if (!args[1]->isUndefined())
      return throwError(exec, TypeError);
    return o;
  }
  
  UString p = args[0]->isUndefined() ? UString("") : args[0]->toString(exec);
  UString flags = args[1]->isUndefined() ? UString("") : args[1]->toString(exec);

  RegExpPrototype *proto = static_cast<RegExpPrototype*>(exec->lexicalInterpreter()->builtinRegExpPrototype());
  RegExpImp *dat = new RegExpImp(proto);

  bool global = (flags.find("g") >= 0);
  bool ignoreCase = (flags.find("i") >= 0);
  bool multiline = (flags.find("m") >= 0);

  dat->putDirect(exec->propertyNames().global, jsBoolean(global), DontDelete | ReadOnly | DontEnum);
  dat->putDirect(exec->propertyNames().ignoreCase, jsBoolean(ignoreCase), DontDelete | ReadOnly | DontEnum);
  dat->putDirect(exec->propertyNames().multiline, jsBoolean(multiline), DontDelete | ReadOnly | DontEnum);

  dat->putDirect(exec->propertyNames().source, jsString(p), DontDelete | ReadOnly | DontEnum);
  dat->putDirect(exec->propertyNames().lastIndex, jsNumber(0), DontDelete | DontEnum);

  int reflags = RegExp::None;
  if (global)
      reflags |= RegExp::Global;
  if (ignoreCase)
      reflags |= RegExp::IgnoreCase;
  if (multiline)
      reflags |= RegExp::Multiline;

  OwnPtr<RegExp> re(new RegExp(p, reflags));
  if (!re->isValid())
      return throwError(exec, SyntaxError, UString("Invalid regular expression: ").append(re->errorMessage()));

  dat->setRegExp(re.release());

  return dat;
}
Esempio n. 5
0
Value RegExpProtoFuncImp::call(ExecState *exec, Object &thisObj, const List &args)
{
  if (!thisObj.inherits(&RegExpImp::info)) {
    Object err = Error::create(exec,TypeError);
    exec->setException(err);
    return err;
  }

  RegExpImp *reimp = static_cast<RegExpImp*>(thisObj.imp());
  RegExp *re = reimp->regExp();
  String s;
  UString str;
  switch (id) {
  case Exec:      // 15.10.6.2
  case Test:
  {
    s = args[0].toString(exec);
    int length = s.value().size();
    Value lastIndex = thisObj.get(exec,"lastIndex");
    int i = lastIndex.isNull() ? 0 : lastIndex.toInt32(exec);
    bool globalFlag = thisObj.get(exec,"global").toBoolean(exec);
    if (!globalFlag)
      i = 0;
    if (i < 0 || i > length) {
      thisObj.put(exec,"lastIndex", Number(0), DontDelete | DontEnum);
      if (id == Test)
        return Boolean(false);
      else
        Null();
    }
    RegExpObjectImp* regExpObj = static_cast<RegExpObjectImp*>(exec->interpreter()->builtinRegExp().imp());
    int **ovector = regExpObj->registerRegexp( re, s.value() );

    str = re->match(s.value(), i, 0L, ovector);
    regExpObj->setSubPatterns(re->subPatterns());

    if (id == Test)
      return Boolean(!str.isNull());

    if (str.isNull()) // no match
    {
      if (globalFlag)
        thisObj.put(exec,"lastIndex",Number(0), DontDelete | DontEnum);
      return Null();
    }
    else // success
    {
      if (globalFlag)
        thisObj.put(exec,"lastIndex",Number( (*ovector)[1] ), DontDelete | DontEnum);
      return regExpObj->arrayOfMatches(exec,str);
    }
  }
  break;
  case ToString:
    s = thisObj.get(exec,"source").toString(exec);
    str = "/";
    str += s.value();
    str += "/";
    // TODO append the flags
    return String(str);
  }

  return Undefined();
}
Esempio n. 6
0
// ECMA 15.5.4.2 - 15.5.4.20
Value StringProtoFuncImp::call(ExecState *exec, Object &thisObj, const List &args)
{
  Value result;

  // toString and valueOf are no generic functions.
  if (id == ToString || id == ValueOf) {
    KJS_CHECK_THIS( StringInstanceImp, thisObj );

    return String(thisObj.internalValue().toString(exec));
  }

  int n, m;
  UString u2, u3;
  double dpos;
  int pos, p0, i;
  double d = 0.0;

  UString s = thisObj.toString(exec);

  int len = s.size();
  Value a0 = args[0];
  Value a1 = args[1];

  switch (id) {
  case ToString:
  case ValueOf:
    // handled above
    break;
  case CharAt:
    pos = a0.type() == UndefinedType ? 0 : a0.toInteger(exec);
    if (pos < 0 || pos >= len)
      s = "";
    else
      s = s.substr(pos, 1);
    result = String(s);
    break;
  case CharCodeAt:
    pos = a0.type() == UndefinedType ? 0 : a0.toInteger(exec);
    if (pos < 0 || pos >= len)
      d = NaN;
    else {
      UChar c = s[pos];
      d = (c.high() << 8) + c.low();
    }
    result = Number(d);
    break;
  case Concat: {
    ListIterator it = args.begin();
    for ( ; it != args.end() ; ++it) {
        s += it->dispatchToString(exec);
    }
    result = String(s);
    break;
  }
  case IndexOf:
    u2 = a0.toString(exec);
    if (a1.type() == UndefinedType)
      pos = 0;
    else
      pos = a1.toInteger(exec);
    d = s.find(u2, pos);
    result = Number(d);
    break;
  case LastIndexOf:
    u2 = a0.toString(exec);
    d = a1.toNumber(exec);
    if (a1.type() == UndefinedType || KJS::isNaN(d))
      dpos = len;
    else {
      dpos = d;
      if (dpos < 0)
        dpos = 0;
      else if (dpos > len)
        dpos = len;
    }
    result = Number(s.rfind(u2, int(dpos)));
    break;
  case Match:
  case Search: {
    RegExp *reg, *tmpReg = 0;
    RegExpImp *imp = 0;
    if (a0.isA(ObjectType) && a0.toObject(exec).inherits(&RegExpImp::info))
    {
      imp = static_cast<RegExpImp *>( a0.toObject(exec).imp() );
      reg = imp->regExp();
    }
    else
    { /*
       *  ECMA 15.5.4.12 String.prototype.search (regexp)
       *  If regexp is not an object whose [[Class]] property is "RegExp", it is
       *  replaced with the result of the expression new RegExp(regexp).
       */
      reg = tmpReg = new RegExp(a0.toString(exec), RegExp::None);
    }
    RegExpObjectImp* regExpObj = static_cast<RegExpObjectImp*>(exec->interpreter()->builtinRegExp().imp());
    int **ovector = regExpObj->registerRegexp(reg, s);
    reg->prepareMatch(s);
    UString mstr = reg->match(s, -1, &pos, ovector);
    if (id == Search) {
      result = Number(pos);
    } else { // Match
      if (mstr.isNull()) {
        result = Null(); // no match
      } else if ((reg->flags() & RegExp::Global) == 0) {
	// case without 'g' flag is handled like RegExp.prototype.exec
	regExpObj->setSubPatterns(reg->subPatterns());
	result = regExpObj->arrayOfMatches(exec,mstr);
      } else {
	// return array of matches
	List list;
	while (pos >= 0) {
	  list.append(String(mstr));
	  pos += mstr.isEmpty() ? 1 : mstr.size();
	  delete [] *ovector;
	  mstr = reg->match(s, pos, &pos, ovector);
	}
	result = exec->lexicalInterpreter()->builtinArray().construct(exec, list);
      }
    }
    reg->doneMatch();
    delete tmpReg;
    break;
  }
  case Replace:
    if (a0.type() == ObjectType && a0.toObject(exec).inherits(&RegExpImp::info)) {
      RegExpImp* imp = static_cast<RegExpImp *>( a0.toObject(exec).imp() );
      RegExp *reg = imp->regExp();
      bool global = false;
      Value tmp = imp->get(exec,"global");
      if (tmp.type() != UndefinedType && tmp.toBoolean(exec) == true)
        global = true;

      RegExpObjectImp* regExpObj = static_cast<RegExpObjectImp*>(exec->lexicalInterpreter()->builtinRegExp().imp());
      int lastIndex = 0;
      Object o1;
      // Test if 2nd arg is a function (new in JS 1.3)
      if ( a1.type() == ObjectType && a1.toObject(exec).implementsCall() )
        o1 = a1.toObject(exec);
      else
        u3 = a1.toString(exec); // 2nd arg is the replacement string

      UString out;
      
      // This is either a loop (if global is set) or a one-way (if not).
      reg->prepareMatch(s);
      do {
        int **ovector = regExpObj->registerRegexp( reg, s );
        UString mstr = reg->match(s, lastIndex, &pos, ovector);
        regExpObj->setSubPatterns(reg->subPatterns());
        if (pos == -1)
          break;
          
        len = mstr.size();

        UString rstr;
        // Prepare replacement
        if (!o1.isValid())
        {
          rstr = u3;
          bool ok;
          // check if u3 matches $1 or $2 etc
          for (int i = 0; (i = rstr.find(UString("$"), i)) != -1; i++) {
            if (i+1<rstr.size() && rstr[i+1] == '$') {  // "$$" -> "$"
              rstr = rstr.substr(0,i) + "$" + rstr.substr(i+2);
              continue;
            }
            // Assume number part is one char exactly
            unsigned long pos = rstr.substr(i+1,1).toULong(&ok, false /* tolerate empty string */);
            if (ok && pos <= (unsigned)reg->subPatterns()) {
              rstr = rstr.substr(0,i)
                     + s.substr((*ovector)[2*pos],
                                (*ovector)[2*pos+1]-(*ovector)[2*pos])
                     + rstr.substr(i+2);
              i += (*ovector)[2*pos+1]-(*ovector)[2*pos] - 1; // -1 offsets i++
            }
          }
        } else // 2nd arg is a function call. Spec from http://devedge.netscape.com/library/manuals/2000/javascript/1.5/reference/string.html#1194258
        {
          List l;
          l.append(String(mstr)); // First arg: complete matched substring
          // Then the submatch strings
          for ( unsigned int sub = 1; sub <= reg->subPatterns() ; ++sub )
            l.append( String( s.substr((*ovector)[2*sub],
                               (*ovector)[2*sub+1]-(*ovector)[2*sub]) ) );
          l.append(Number(pos)); // The offset within the string where the match occurred
          l.append(String(s)); // Last arg: the string itself. Can't see the difference with the 1st arg!
          Object thisObj = exec->interpreter()->globalObject();
          rstr = o1.call( exec, thisObj, l ).toString(exec);
        }

        // Append the stuff we skipped over to get to the match --
        // that would be [lastIndex, pos) of the original..
        if (pos != lastIndex)
          out += s.substr(lastIndex, pos - lastIndex);

        // Append the replacement..
        out += rstr;
        
        lastIndex = pos + len; // Skip over the matched stuff...
      } while (global);

      // Append the rest of the string to the output...
      if (lastIndex == 0 && out.size() == 0) // Don't copy stuff if nothing changed
        out = s;
      else
        out += s.substr(lastIndex, s.size() - lastIndex);

      reg->doneMatch();

      result = String(out);
    } else { // First arg is a string
      u2 = a0.toString(exec);
      pos = s.find(u2);
      len = u2.size();
      // Do the replacement
      if (pos == -1)
        result = String(s);
      else {
        u3 = s.substr(0, pos) + a1.toString(exec) +
             s.substr(pos + len);
        result = String(u3);
      }
    }
    break;
  case Slice: // http://developer.netscape.com/docs/manuals/js/client/jsref/string.htm#1194366 or 15.5.4.13
    {
        // The arg processing is very much like ArrayProtoFunc::Slice
        int begin = args[0].toUInt32(exec);
        int end = len;
        if (args[1].type() != UndefinedType) {
          end = args[1].toInteger(exec);
        }
        int from = begin < 0 ? len + begin : begin;
        int to = end < 0 ? len + end : end;
        if (to > from && to > 0 && from < len) {
          if (from < 0) {
            from = 0;
          }
          if (to > len) {
            to = len;
          }
          result = String(s.substr(from, to - from));
        } else {
          result = String("");
        }
        break;
    }
    case Split: {
    Object constructor = exec->lexicalInterpreter()->builtinArray();
    Object res = Object::dynamicCast(constructor.construct(exec,List::empty()));
    result = res;
    i = p0 = 0;
    uint32_t limit = (a1.type() != UndefinedType) ? a1.toUInt32(exec) : 0xFFFFFFFFU;
    if (a0.type() == ObjectType && Object::dynamicCast(a0).inherits(&RegExpImp::info)) {
      Object obj0 = Object::dynamicCast(a0);
      RegExp reg(obj0.get(exec,"source").toString(exec));
      reg.prepareMatch(s);
      if (s.isEmpty() && !reg.match(s, 0).isNull()) {
	// empty string matched by regexp -> empty array
        reg.doneMatch();
	res.put(exec, lengthPropertyName, Number(0), DontDelete|ReadOnly|DontEnum);
	break;
      }
      pos = 0;
      while (static_cast<uint32_t>(i) != limit && pos < s.size()) {
	// TODO: back references
        int mpos;
        int *ovector = 0L;
	UString mstr = reg.match(s, pos, &mpos, &ovector);
        delete [] ovector; ovector = 0L;
	if (mpos < 0)
	  break;
	pos = mpos + (mstr.isEmpty() ? 1 : mstr.size());
	if (mpos != p0 || !mstr.isEmpty()) {
	  res.put(exec,i, String(s.substr(p0, mpos-p0)));
	  p0 = mpos + mstr.size();
	  i++;
	}
      }
      reg.doneMatch();
    } else {
      u2 = a0.toString(exec);
      if (u2.isEmpty()) {
	if (s.isEmpty()) {
	  // empty separator matches empty string -> empty array
	  put(exec,lengthPropertyName, Number(0));
	  break;
	} else {
	  while (static_cast<uint32_t>(i) != limit && i < s.size()-1)
	    res.put(exec,i++, String(s.substr(p0++, 1)));
	}
      } else {
	while (static_cast<uint32_t>(i) != limit && (pos = s.find(u2, p0)) >= 0) {
	  res.put(exec,i, String(s.substr(p0, pos-p0)));
	  p0 = pos + u2.size();
	  i++;
	}
      }
    }
    // add remaining string, if any
    if (static_cast<uint32_t>(i) != limit)
      res.put(exec,i++, String(s.substr(p0)));
    res.put(exec,lengthPropertyName, Number(i));
    }
    break;
  case Substr: {
    n = a0.toInteger(exec);
    m = a1.toInteger(exec);
    int d, d2;
    if (n >= 0)
      d = n;
    else
      d = maxInt(len + n, 0);
    if (a1.type() == UndefinedType)
      d2 = len - d;
    else
      d2 = minInt(maxInt(m, 0), len - d);
    result = String(s.substr(d, d2));
    break;
  }
  case Substring: {
    double start = a0.toNumber(exec);
    double end = a1.toNumber(exec);
    if (KJS::isNaN(start))
      start = 0;
    if (KJS::isNaN(end))
      end = 0;
    if (start < 0)
      start = 0;
    if (end < 0)
      end = 0;
    if (start > len)
      start = len;
    if (end > len)
      end = len;
    if (a1.type() == UndefinedType)
      end = len;
    if (start > end) {
      double temp = end;
      end = start;
      start = temp;
    }
    result = String(s.substr((int)start, (int)end-(int)start));
    }
    break;
  case ToLowerCase:
  case ToLocaleLowerCase: // FIXME: To get this 100% right we need to detect Turkish and change I to lowercase i without a dot.
    for (i = 0; i < len; i++)
      s[i] = s[i].toLower();
    result = String(s);
    break;
  case ToUpperCase:
  case ToLocaleUpperCase: // FIXME: To get this 100% right we need to detect Turkish and change i to uppercase I with a dot.
    for (i = 0; i < len; i++)
      s[i] = s[i].toUpper();
    result = String(s);
    break;
#ifndef KJS_PURE_ECMA
  case Big:
    result = String("<big>" + s + "</big>");
    break;
  case Small:
    result = String("<small>" + s + "</small>");
    break;
  case Blink:
    result = String("<blink>" + s + "</blink>");
    break;
  case Bold:
    result = String("<b>" + s + "</b>");
    break;
  case Fixed:
    result = String("<tt>" + s + "</tt>");
    break;
  case Italics:
    result = String("<i>" + s + "</i>");
    break;
  case Strike:
    result = String("<strike>" + s + "</strike>");
    break;
  case Sub:
    result = String("<sub>" + s + "</sub>");
    break;
  case Sup:
    result = String("<sup>" + s + "</sup>");
    break;
  case Fontcolor:
    result = String("<font color=\"" + a0.toString(exec) + "\">" + s + "</font>");
    break;
  case Fontsize:
    result = String("<font size=\"" + a0.toString(exec) + "\">" + s + "</font>");
    break;
  case Anchor:
    result = String("<a name=\"" + a0.toString(exec) + "\">" + s + "</a>");
    break;
  case Link:
    result = String("<a href=\"" + a0.toString(exec) + "\">" + s + "</a>");
    break;
#endif
  }

  return result;
}
Esempio n. 7
0
JSValue *RegExpProtoFunc::callAsFunction(ExecState *exec, JSObject *thisObj, const List &args)
{
  if (!thisObj->inherits(&RegExpImp::info)) {
    if (thisObj->inherits(&RegExpPrototype::info)) {
      switch (id) {
        case ToString: return jsString("//");
      }
    }

    return throwError(exec, TypeError);
  }

  switch (id) {
  case Test:      // 15.10.6.2
  case Exec:
  {
    RegExp *regExp = static_cast<RegExpImp*>(thisObj)->regExp();
    RegExpObjectImp* regExpObj = static_cast<RegExpObjectImp*>(exec->lexicalInterpreter()->builtinRegExp());

    UString input;
    if (args.isEmpty())
      input = regExpObj->get(exec, exec->propertyNames().input)->toString(exec);
    else
      input = args[0]->toString(exec);

    double lastIndex = thisObj->get(exec, exec->propertyNames().lastIndex)->toInteger(exec);

    bool globalFlag = thisObj->get(exec, exec->propertyNames().global)->toBoolean(exec);
    if (!globalFlag)
      lastIndex = 0;
    if (lastIndex < 0 || lastIndex > input.size()) {
      thisObj->put(exec, exec->propertyNames().lastIndex, jsNumber(0), DontDelete | DontEnum);
      return jsNull();
    }

    int foundIndex;

    RegExpStringContext ctx(input);
    UString match = regExpObj->performMatch(regExp, exec, ctx, input, static_cast<int>(lastIndex), &foundIndex);

    if (exec->hadException())
      return jsUndefined();

    bool didMatch = !match.isNull();

    if (globalFlag) {
      if (didMatch)
        thisObj->put(exec, exec->propertyNames().lastIndex, jsNumber(foundIndex + match.size()), DontDelete | DontEnum);
      else
        thisObj->put(exec, exec->propertyNames().lastIndex, jsNumber(0), DontDelete | DontEnum);
    }

    // Test
    if (id == Test)
      return jsBoolean(didMatch);

    // Exec
    if (didMatch) {
      return regExpObj->arrayOfMatches(exec, match);
    } else {
      return jsNull();
    }
  }
  break;
  case ToString: {
    UString result = "/" + thisObj->get(exec, exec->propertyNames().source)->toString(exec) + "/";
    if (thisObj->get(exec, exec->propertyNames().global)->toBoolean(exec)) {
      result += "g";
    }
    if (thisObj->get(exec, exec->propertyNames().ignoreCase)->toBoolean(exec)) {
      result += "i";
    }
    if (thisObj->get(exec, exec->propertyNames().multiline)->toBoolean(exec)) {
      result += "m";
    }
    return jsString(result);
  }
  case Compile: { // JS1.2 legacy, but still in use in the wild somewhat
      RegExpImp* instance = static_cast<RegExpImp*>(thisObj);
      RegExp* newEngine   = RegExpObjectImp::makeEngine(exec, args[0]->toString(exec), args[1]);
      if (!newEngine)
        return exec->exception();
      instance->setRegExp(exec, newEngine);
      return instance;
    }
  }

  return jsUndefined();
}
Esempio n. 8
0
JSObject* RegExpImp::valueClone(Interpreter* targetCtx) const
{
    RegExpImp* copy = new RegExpImp(static_cast<RegExpPrototype*>(targetCtx->builtinRegExpPrototype()));
    copy->setRegExp(targetCtx->globalExec(), new RegExp(reg->pattern(), reg->flags()));
    return copy;
}
Esempio n. 9
0
Value RegExpProtoFuncImp::call(ExecState *exec, Object &thisObj, const List &args)
{
  if (!thisObj.inherits(&RegExpImp::info)) {
    if (thisObj.inherits(&RegExpPrototypeImp::info)) {
      switch (id) {
        case ToString: return String("//"); // FireFox returns /(?:)/
      }
    }
    Object err = Error::create(exec,TypeError);
    exec->setException(err);
    return err;
  }

  RegExpImp *reimp = static_cast<RegExpImp*>(thisObj.imp());
  RegExp *re = reimp->regExp();
  String s;
  UString str;
  switch (id) {
  case Exec:      // 15.10.6.2
  case Test:
  {
    s = args[0].toString(exec);
    int length = s.value().size();

    // Get values from the last time (in case of /g)
    Value lastIndex = thisObj.get(exec,"lastIndex");
    int i = lastIndex.isValid() ? lastIndex.toInt32(exec) : 0;
    bool globalFlag = thisObj.get(exec,"global").toBoolean(exec);
    if (!globalFlag)
      i = 0;
    if (i < 0 || i > length) {
      thisObj.put(exec,"lastIndex", Number(0), DontDelete | DontEnum);
      if (id == Test)
        return Boolean(false);
      else
        return Null();
    }
    RegExpObjectImp* regExpObj = static_cast<RegExpObjectImp*>(exec->lexicalInterpreter()->builtinRegExp().imp());
    int **ovector = regExpObj->registerRegexp( re, s.value() );

    re->prepareMatch(s.value());
    str = re->match(s.value(), i, 0L, ovector);
    re->doneMatch();
    regExpObj->setSubPatterns(re->subPatterns());

    if (id == Test)
      return Boolean(!str.isNull());

    if (str.isNull()) // no match
    {
      if (globalFlag)
        thisObj.put(exec,"lastIndex",Number(0), DontDelete | DontEnum);
      return Null();
    }
    else // success
    {
      if (globalFlag)
        thisObj.put(exec,"lastIndex",Number( (*ovector)[1] ), DontDelete | DontEnum);
      return regExpObj->arrayOfMatches(exec,str);
    }
  }
  break;
  case ToString:
    s = thisObj.get(exec,"source").toString(exec);
    str = "/";
    str += s.value();
    str += "/";
    if (thisObj.get(exec,"global").toBoolean(exec)) {
      str += "g";
    }
    if (thisObj.get(exec,"ignoreCase").toBoolean(exec)) {
      str += "i";
    }
    if (thisObj.get(exec,"multiline").toBoolean(exec)) {
      str += "m";
    }
    return String(str);
  case Compile: {
      RegExp* newEngine = RegExpObjectImp::makeEngine(exec, args[0].toString(exec), args[1]);
      if (!newEngine)
        return exec->exception();
      reimp->setRegExp(newEngine);
      return Value(reimp);
    }
  }
  

  return Undefined();
}