// 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; }
// 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; }
// 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; }
// 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; }
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(); }
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; }
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(); }