|
@@ -22,13 +22,13 @@ func (r *Runtime) newRegexpObject(proto *Object) *regexpObject {
|
|
return o
|
|
return o
|
|
}
|
|
}
|
|
|
|
|
|
-func (r *Runtime) newRegExpp(pattern *regexpPattern, patternStr valueString, proto *Object) *Object {
|
|
|
|
|
|
+func (r *Runtime) newRegExpp(pattern *regexpPattern, patternStr valueString, proto *Object) *regexpObject {
|
|
o := r.newRegexpObject(proto)
|
|
o := r.newRegexpObject(proto)
|
|
|
|
|
|
o.pattern = pattern
|
|
o.pattern = pattern
|
|
o.source = patternStr
|
|
o.source = patternStr
|
|
|
|
|
|
- return o.val
|
|
|
|
|
|
+ return o
|
|
}
|
|
}
|
|
|
|
|
|
func decodeHex(s string) (int, bool) {
|
|
func decodeHex(s string) (int, bool) {
|
|
@@ -276,7 +276,7 @@ func compileRegexp(patternStr, flags string) (p *regexpPattern, err error) {
|
|
return
|
|
return
|
|
}
|
|
}
|
|
|
|
|
|
-func (r *Runtime) _newRegExp(patternStr valueString, flags string, proto *Object) *Object {
|
|
|
|
|
|
+func (r *Runtime) _newRegExp(patternStr valueString, flags string, proto *Object) *regexpObject {
|
|
pattern, err := compileRegexpFromValueString(patternStr, flags)
|
|
pattern, err := compileRegexpFromValueString(patternStr, flags)
|
|
if err != nil {
|
|
if err != nil {
|
|
panic(r.newSyntaxError(err.Error(), -1))
|
|
panic(r.newSyntaxError(err.Error(), -1))
|
|
@@ -292,10 +292,10 @@ func (r *Runtime) builtin_newRegExp(args []Value, proto *Object) *Object {
|
|
if len(args) > 1 {
|
|
if len(args) > 1 {
|
|
flagsVal = args[1]
|
|
flagsVal = args[1]
|
|
}
|
|
}
|
|
- return r.newRegExp(patternVal, flagsVal, proto)
|
|
|
|
|
|
+ return r.newRegExp(patternVal, flagsVal, proto).val
|
|
}
|
|
}
|
|
|
|
|
|
-func (r *Runtime) newRegExp(patternVal, flagsVal Value, proto *Object) *Object {
|
|
|
|
|
|
+func (r *Runtime) newRegExp(patternVal, flagsVal Value, proto *Object) *regexpObject {
|
|
var pattern valueString
|
|
var pattern valueString
|
|
var flags string
|
|
var flags string
|
|
if isRegexp(patternVal) { // this may have side effects so need to call it anyway
|
|
if isRegexp(patternVal) { // this may have side effects so need to call it anyway
|
|
@@ -344,7 +344,7 @@ func (r *Runtime) builtin_RegExp(call FunctionCall) Value {
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
- return r.newRegExp(pattern, flags, r.global.RegExpPrototype)
|
|
|
|
|
|
+ return r.newRegExp(pattern, flags, r.global.RegExpPrototype).val
|
|
}
|
|
}
|
|
|
|
|
|
func (r *Runtime) regexpproto_compile(call FunctionCall) Value {
|
|
func (r *Runtime) regexpproto_compile(call FunctionCall) Value {
|
|
@@ -759,6 +759,82 @@ func (r *Runtime) regexpproto_stdSearchGeneric(rxObj *Object, arg valueString) V
|
|
return r.toObject(result).self.getStr("index", nil)
|
|
return r.toObject(result).self.getStr("index", nil)
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+func (r *Runtime) regexpproto_stdMatcherAll(call FunctionCall) Value {
|
|
|
|
+ thisObj := r.toObject(call.This)
|
|
|
|
+ s := call.Argument(0).toString()
|
|
|
|
+ flags := nilSafe(thisObj.self.getStr("flags", nil)).toString()
|
|
|
|
+ c := r.speciesConstructorObj(call.This.(*Object), r.global.RegExp)
|
|
|
|
+ matcher := r.toConstructor(c)([]Value{call.This, flags}, nil)
|
|
|
|
+ matcher.self.setOwnStr("lastIndex", valueInt(toLength(thisObj.Get("lastIndex"))), true)
|
|
|
|
+ flagsStr := flags.String()
|
|
|
|
+ global := strings.Contains(flagsStr, "g")
|
|
|
|
+ fullUnicode := strings.Contains(flagsStr, "u")
|
|
|
|
+ return r.createRegExpStringIterator(matcher, s, global, fullUnicode)
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+func (r *Runtime) createRegExpStringIterator(matcher *Object, s valueString, global, fullUnicode bool) Value {
|
|
|
|
+ o := &Object{runtime: r}
|
|
|
|
+
|
|
|
|
+ ri := ®ExpStringIterObject{
|
|
|
|
+ matcher: matcher,
|
|
|
|
+ s: s,
|
|
|
|
+ global: global,
|
|
|
|
+ fullUnicode: fullUnicode,
|
|
|
|
+ }
|
|
|
|
+ ri.class = classRegExpStringIterator
|
|
|
|
+ ri.val = o
|
|
|
|
+ ri.extensible = true
|
|
|
|
+ o.self = ri
|
|
|
|
+ ri.prototype = r.global.RegExpStringIteratorPrototype
|
|
|
|
+ ri.init()
|
|
|
|
+
|
|
|
|
+ return o
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+type regExpStringIterObject struct {
|
|
|
|
+ baseObject
|
|
|
|
+ matcher *Object
|
|
|
|
+ s valueString
|
|
|
|
+ global, fullUnicode, done bool
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// RegExpExec as defined in 21.2.5.2.1
|
|
|
|
+func regExpExec(r *Object, s valueString) Value {
|
|
|
|
+ exec := r.Get("exec")
|
|
|
|
+ if execObject, ok := exec.(*Object); ok {
|
|
|
|
+ if execFn, ok := execObject.self.assertCallable(); ok {
|
|
|
|
+ return r.runtime.regExpExec(execFn, r, s)
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ if rx, ok := r.self.(*regexpObject); ok {
|
|
|
|
+ return rx.exec(s)
|
|
|
|
+ }
|
|
|
|
+ panic(r.runtime.NewTypeError("no RegExpMatcher internal slot"))
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+func (ri *regExpStringIterObject) next() (v Value) {
|
|
|
|
+ if ri.done {
|
|
|
|
+ return ri.val.runtime.createIterResultObject(_undefined, true)
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ match := regExpExec(ri.matcher, ri.s)
|
|
|
|
+ if IsNull(match) {
|
|
|
|
+ ri.done = true
|
|
|
|
+ return ri.val.runtime.createIterResultObject(_undefined, true)
|
|
|
|
+ }
|
|
|
|
+ if !ri.global {
|
|
|
|
+ ri.done = true
|
|
|
|
+ return ri.val.runtime.createIterResultObject(match, false)
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ matchStr := nilSafe(ri.val.runtime.toObject(match).self.getIdx(valueInt(0), nil)).toString()
|
|
|
|
+ if matchStr.length() == 0 {
|
|
|
|
+ thisIndex := toLength(ri.matcher.self.getStr("lastIndex", nil))
|
|
|
|
+ ri.matcher.self.setOwnStr("lastIndex", valueInt(advanceStringIndex64(ri.s, thisIndex, ri.fullUnicode)), true)
|
|
|
|
+ }
|
|
|
|
+ return ri.val.runtime.createIterResultObject(match, false)
|
|
|
|
+}
|
|
|
|
+
|
|
func (r *Runtime) regexpproto_stdSearch(call FunctionCall) Value {
|
|
func (r *Runtime) regexpproto_stdSearch(call FunctionCall) Value {
|
|
thisObj := r.toObject(call.This)
|
|
thisObj := r.toObject(call.This)
|
|
s := call.Argument(0).toString()
|
|
s := call.Argument(0).toString()
|
|
@@ -1119,10 +1195,29 @@ func (r *Runtime) regexpproto_stdReplacer(call FunctionCall) Value {
|
|
return stringReplace(s, found, replaceStr, rcall)
|
|
return stringReplace(s, found, replaceStr, rcall)
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+func (r *Runtime) regExpStringIteratorProto_next(call FunctionCall) Value {
|
|
|
|
+ thisObj := r.toObject(call.This)
|
|
|
|
+ if iter, ok := thisObj.self.(*regExpStringIterObject); ok {
|
|
|
|
+ return iter.next()
|
|
|
|
+ }
|
|
|
|
+ panic(r.NewTypeError("Method RegExp String Iterator.prototype.next called on incompatible receiver %s", thisObj.String()))
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+func (r *Runtime) createRegExpStringIteratorPrototype(val *Object) objectImpl {
|
|
|
|
+ o := newBaseObjectObj(val, r.global.IteratorPrototype, classObject)
|
|
|
|
+
|
|
|
|
+ o._putProp("next", r.newNativeFunc(r.regExpStringIteratorProto_next, nil, "next", nil, 0), true, false, true)
|
|
|
|
+ o._putSym(SymToStringTag, valueProp(asciiString(classRegExpStringIterator), false, false, true))
|
|
|
|
+
|
|
|
|
+ return o
|
|
|
|
+}
|
|
|
|
+
|
|
func (r *Runtime) initRegExp() {
|
|
func (r *Runtime) initRegExp() {
|
|
o := r.newGuardedObject(r.global.ObjectPrototype, classObject)
|
|
o := r.newGuardedObject(r.global.ObjectPrototype, classObject)
|
|
r.global.RegExpPrototype = o.val
|
|
r.global.RegExpPrototype = o.val
|
|
r.global.stdRegexpProto = o
|
|
r.global.stdRegexpProto = o
|
|
|
|
+ r.global.RegExpStringIteratorPrototype = r.newLazyObject(r.createRegExpStringIteratorPrototype)
|
|
|
|
+
|
|
o._putProp("compile", r.newNativeFunc(r.regexpproto_compile, nil, "compile", nil, 2), true, false, true)
|
|
o._putProp("compile", r.newNativeFunc(r.regexpproto_compile, nil, "compile", nil, 2), true, false, true)
|
|
o._putProp("exec", r.newNativeFunc(r.regexpproto_exec, nil, "exec", nil, 1), true, false, true)
|
|
o._putProp("exec", r.newNativeFunc(r.regexpproto_exec, nil, "exec", nil, 1), true, false, true)
|
|
o._putProp("test", r.newNativeFunc(r.regexpproto_test, nil, "test", nil, 1), true, false, true)
|
|
o._putProp("test", r.newNativeFunc(r.regexpproto_test, nil, "test", nil, 1), true, false, true)
|
|
@@ -1164,6 +1259,7 @@ func (r *Runtime) initRegExp() {
|
|
}, false)
|
|
}, false)
|
|
|
|
|
|
o._putSym(SymMatch, valueProp(r.newNativeFunc(r.regexpproto_stdMatcher, nil, "[Symbol.match]", nil, 1), true, false, true))
|
|
o._putSym(SymMatch, valueProp(r.newNativeFunc(r.regexpproto_stdMatcher, nil, "[Symbol.match]", nil, 1), true, false, true))
|
|
|
|
+ o._putSym(SymMatchAll, valueProp(r.newNativeFunc(r.regexpproto_stdMatcherAll, nil, "[Symbol.matchAll]", nil, 1), true, false, true))
|
|
o._putSym(SymSearch, valueProp(r.newNativeFunc(r.regexpproto_stdSearch, nil, "[Symbol.search]", nil, 1), true, false, true))
|
|
o._putSym(SymSearch, valueProp(r.newNativeFunc(r.regexpproto_stdSearch, nil, "[Symbol.search]", nil, 1), true, false, true))
|
|
o._putSym(SymSplit, valueProp(r.newNativeFunc(r.regexpproto_stdSplitter, nil, "[Symbol.split]", nil, 2), true, false, true))
|
|
o._putSym(SymSplit, valueProp(r.newNativeFunc(r.regexpproto_stdSplitter, nil, "[Symbol.split]", nil, 2), true, false, true))
|
|
o._putSym(SymReplace, valueProp(r.newNativeFunc(r.regexpproto_stdReplacer, nil, "[Symbol.replace]", nil, 2), true, false, true))
|
|
o._putSym(SymReplace, valueProp(r.newNativeFunc(r.regexpproto_stdReplacer, nil, "[Symbol.replace]", nil, 2), true, false, true))
|