package goja

import (
	
	
	
	
	
	
)

func ( *Runtime) ( *Object) *regexpObject {
	 := &Object{runtime: }

	 := &regexpObject{}
	.class = classRegExp
	.val = 
	.extensible = true
	.self = 
	.prototype = 
	.init()
	return 
}

func ( *Runtime) ( *regexpPattern,  String,  *Object) *regexpObject {
	 := .newRegexpObject()

	.pattern = 
	.source = 

	return 
}

func decodeHex( string) (int, bool) {
	var  int
	for  := 0;  < len(); ++ {
		var  byte
		 := []
		switch {
		case '0' <=  &&  <= '9':
			 =  - '0'
		case 'a' <=  &&  <= 'f':
			 =  - 'a' + 10
		case 'A' <=  &&  <= 'F':
			 =  - 'A' + 10
		default:
			return 0, false
		}
		 = *16 + int()
	}
	return , true
}

func writeHex4( *strings.Builder,  int) {
	.WriteByte(hex[>>12])
	.WriteByte(hex[(>>8)&0xF])
	.WriteByte(hex[(>>4)&0xF])
	.WriteByte(hex[&0xF])
}

// Convert any valid surrogate pairs in the form of \uXXXX\uXXXX to unicode characters
func convertRegexpToUnicode( string) string {
	var  strings.Builder
	 := 0
	for  := 0;  < len()-11; {
		,  := utf8.DecodeRuneInString([:])
		if  == '\\' {
			++
			if [] == 'u' && [+5] == '\\' && [+6] == 'u' {
				if ,  := decodeHex([+1 : +5]);  {
					if isUTF16FirstSurrogate(uint16()) {
						if ,  := decodeHex([+7 : +11]);  {
							if isUTF16SecondSurrogate(uint16()) {
								 = utf16.DecodeRune(rune(), rune())
								.WriteString([ : -1])
								.WriteRune()
								 += 11
								 = 
								continue
							}
						}
					}
				}
			}
			++
		} else {
			 += 
		}
	}
	if  > 0 {
		.WriteString([:])
		return .String()
	}
	return 
}

// Convert any extended unicode characters to UTF-16 in the form of \uXXXX\uXXXX
func convertRegexpToUtf16( string) string {
	var  strings.Builder
	 := 0
	var  rune
	for  := 0;  < len(); {
		,  := utf8.DecodeRuneInString([:])
		if  > 0xFFFF {
			.WriteString([:])
			if  == '\\' {
				.WriteRune('\\')
			}
			,  := utf16.EncodeRune()
			.WriteString(`\u`)
			writeHex4(&, int())
			.WriteString(`\u`)
			writeHex4(&, int())
			 =  + 
		}
		 += 
		 = 
	}
	if  > 0 {
		.WriteString([:])
		return .String()
	}
	return 
}

// convert any broken UTF-16 surrogate pairs to \uXXXX
func escapeInvalidUtf16( String) string {
	if ,  := .(*importedString);  {
		return .s
	}
	if ,  := .(asciiString);  {
		return .String()
	}
	var  strings.Builder
	 := &lenientUtf16Decoder{utf16Reader: .utf16Reader()}
	 := 0
	 := 0
	var  [utf8.UTFMax]byte
	for {
		, ,  := .ReadRune()
		if  != nil {
			break
		}
		if utf16.IsSurrogate() {
			if .Len() == 0 {
				.Grow( + 7)
				 := .Reader()
				var  rune
				for  := 0;  < ; {
					var  int
					var  error
					, ,  = .ReadRune()
					if  != nil {
						// will not happen
						panic(fmt.Errorf("error while reading string head %q, pos: %d: %w", .String(), , ))
					}
					.WriteRune()
					 += 
				}
				if  == '\\' {
					.WriteRune()
				}
			}
			.WriteString(`\u`)
			writeHex4(&, int())
		} else {
			if .Len() > 0 {
				.WriteRune()
			} else {
				 += utf8.EncodeRune([:], )
				 += 
			}
		}
	}
	if .Len() > 0 {
		return .String()
	}
	return .String()
}

func compileRegexpFromValueString( String,  string) (*regexpPattern, error) {
	return compileRegexp(escapeInvalidUtf16(), )
}

func compileRegexp(,  string) ( *regexpPattern,  error) {
	var , , , , ,  bool
	var  *regexpWrapper
	var  *regexp2Wrapper

	if  != "" {
		 := func() {
			 = fmt.Errorf("Invalid flags supplied to RegExp constructor '%s'", )
		}
		for ,  := range  {
			switch  {
			case 'g':
				if  {
					()
					return
				}
				 = true
			case 'm':
				if  {
					()
					return
				}
				 = true
			case 's':
				if  {
					()
					return
				}
				 = true
			case 'i':
				if  {
					()
					return
				}
				 = true
			case 'y':
				if  {
					()
					return
				}
				 = true
			case 'u':
				if  {
					()
				}
				 = true
			default:
				()
				return
			}
		}
	}

	if  {
		 = convertRegexpToUnicode()
	} else {
		 = convertRegexpToUtf16()
	}

	,  := parser.TransformRegExp(, , )
	if  == nil {
		 := ""
		if  {
			 += "m"
		}
		if  {
			 += "s"
		}
		if  {
			 += "i"
		}
		if len() > 0 {
			 = fmt.Sprintf("(?%s:%s)", , )
		}

		,  := regexp.Compile()
		if  != nil {
			 = fmt.Errorf("Invalid regular expression (re2): %s (%v)", , )
			return
		}
		 = (*regexpWrapper)()
	} else {
		if ,  := .(parser.RegexpErrorIncompatible); ! {
			 = 
			return
		}
		,  = compileRegexp2(, , , , )
		if  != nil {
			 = fmt.Errorf("Invalid regular expression (regexp2): %s (%v)", , )
			return
		}
	}

	 = &regexpPattern{
		src:            ,
		regexpWrapper:  ,
		regexp2Wrapper: ,
		global:         ,
		ignoreCase:     ,
		multiline:      ,
		dotAll:         ,
		sticky:         ,
		unicode:        ,
	}
	return
}

func ( *Runtime) ( String,  string,  *Object) *regexpObject {
	,  := compileRegexpFromValueString(, )
	if  != nil {
		panic(.newSyntaxError(.Error(), -1))
	}
	return .newRegExpp(, , )
}

func ( *Runtime) ( []Value,  *Object) *Object {
	var ,  Value
	if len() > 0 {
		 = [0]
	}
	if len() > 1 {
		 = [1]
	}
	return .newRegExp(, , ).val
}

func ( *Runtime) (,  Value,  *Object) *regexpObject {
	var  String
	var  string
	if isRegexp() { // this may have side effects so need to call it anyway
		if ,  := .(*Object);  {
			if ,  := .self.(*regexpObject);  {
				if  == nil ||  == _undefined {
					return .clone()
				} else {
					return ._newRegExp(.source, .toString().String(), )
				}
			} else {
				 = nilSafe(.self.getStr("source", nil)).toString()
				if  == nil ||  == _undefined {
					 = nilSafe(.self.getStr("flags", nil)).toString().String()
				} else {
					 = .toString().String()
				}
				goto 
			}
		}
	}

	if  != nil &&  != _undefined {
		 = .toString()
	}
	if  != nil &&  != _undefined {
		 = .toString().String()
	}

	if  == nil {
		 = stringEmpty
	}
:
	return ._newRegExp(, , )
}

func ( *Runtime) ( FunctionCall) Value {
	 := .Argument(0)
	 := isRegexp()
	 := .Argument(1)
	if  &&  == _undefined {
		if ,  := .Argument(0).(*Object);  {
			 := .self.getStr("constructor", nil)
			if  == .global.RegExp {
				return 
			}
		}
	}
	return .newRegExp(, , .getRegExpPrototype()).val
}

func ( *Runtime) ( FunctionCall) Value {
	if ,  := .toObject(.This).self.(*regexpObject);  {
		var (
			 *regexpPattern
			  String
			   string
			     error
		)
		 := .Argument(0)
		 := .Argument(1)
		if ,  := .(*Object);  {
			if ,  := .self.(*regexpObject);  {
				if  != _undefined {
					panic(.NewTypeError("Cannot supply flags when constructing one RegExp from another"))
				}
				.pattern = .pattern
				.source = .source
				goto 
			}
		}
		if  != _undefined {
			 = .toString()
		} else {
			 = stringEmpty
		}
		if  != _undefined {
			 = .toString().String()
		}
		,  = compileRegexpFromValueString(, )
		if  != nil {
			panic(.newSyntaxError(.Error(), -1))
		}
		.pattern = 
		.source = 
	:
		.setOwnStr("lastIndex", intToValue(0), true)
		return .This
	}

	panic(.NewTypeError("Method RegExp.prototype.compile called on incompatible receiver %s", .objectproto_toString(FunctionCall{This: .This})))
}

func ( *Runtime) ( FunctionCall) Value {
	if ,  := .toObject(.This).self.(*regexpObject);  {
		return .exec(.Argument(0).toString())
	} else {
		.typeErrorResult(true, "Method RegExp.prototype.exec called on incompatible receiver %s", .objectproto_toString(FunctionCall{This: .This}))
		return nil
	}
}

func ( *Runtime) ( FunctionCall) Value {
	if ,  := .toObject(.This).self.(*regexpObject);  {
		if .test(.Argument(0).toString()) {
			return valueTrue
		} else {
			return valueFalse
		}
	} else {
		panic(.NewTypeError("Method RegExp.prototype.test called on incompatible receiver %s", .objectproto_toString(FunctionCall{This: .This})))
	}
}

func ( *Runtime) ( FunctionCall) Value {
	 := .toObject(.This)
	if  := .checkStdRegexp();  != nil {
		var  StringBuilder
		.WriteRune('/')
		if !.writeEscapedSource(&) {
			.WriteString(.source)
		}
		.WriteRune('/')
		if .pattern.global {
			.WriteRune('g')
		}
		if .pattern.ignoreCase {
			.WriteRune('i')
		}
		if .pattern.multiline {
			.WriteRune('m')
		}
		if .pattern.dotAll {
			.WriteRune('s')
		}
		if .pattern.unicode {
			.WriteRune('u')
		}
		if .pattern.sticky {
			.WriteRune('y')
		}
		return .String()
	}
	 := nilSafe(.self.getStr("source", nil)).toString()
	 := nilSafe(.self.getStr("flags", nil)).toString()
	var  StringBuilder
	.WriteRune('/')
	.WriteString()
	.WriteRune('/')
	.WriteString()
	return .String()
}

func ( *regexpObject) ( *StringBuilder) bool {
	if .source.Length() == 0 {
		.WriteString(asciiString("(?:)"))
		return true
	}
	 := 0
	 := 0
	 := &lenientUtf16Decoder{utf16Reader: .source.utf16Reader()}
:
	for {
		, ,  := .ReadRune()
		if  != nil {
			break
		}
		switch  {
		case '\\':
			++
			_, ,  = .ReadRune()
			if  != nil {
				break 
			}
		case '/', '\u000a', '\u000d', '\u2028', '\u2029':
			.WriteSubstring(.source, , )
			.WriteRune('\\')
			switch  {
			case '\u000a':
				.WriteRune('n')
			case '\u000d':
				.WriteRune('r')
			default:
				.WriteRune('u')
				.WriteRune(rune(hex[>>12]))
				.WriteRune(rune(hex[(>>8)&0xF]))
				.WriteRune(rune(hex[(>>4)&0xF]))
				.WriteRune(rune(hex[&0xF]))
			}
			 =  + 
		}
		 += 
	}
	if  > 0 {
		.WriteSubstring(.source, , .source.Length())
		return true
	}
	return false
}

func ( *Runtime) ( FunctionCall) Value {
	if ,  := .toObject(.This).self.(*regexpObject);  {
		var  StringBuilder
		if .writeEscapedSource(&) {
			return .String()
		}
		return .source
	} else if .This == .global.RegExpPrototype {
		return asciiString("(?:)")
	} else {
		panic(.NewTypeError("Method RegExp.prototype.source getter called on incompatible receiver"))
	}
}

func ( *Runtime) ( FunctionCall) Value {
	if ,  := .toObject(.This).self.(*regexpObject);  {
		if .pattern.global {
			return valueTrue
		} else {
			return valueFalse
		}
	} else if .This == .global.RegExpPrototype {
		return _undefined
	} else {
		panic(.NewTypeError("Method RegExp.prototype.global getter called on incompatible receiver %s", .objectproto_toString(FunctionCall{This: .This})))
	}
}

func ( *Runtime) ( FunctionCall) Value {
	if ,  := .toObject(.This).self.(*regexpObject);  {
		if .pattern.multiline {
			return valueTrue
		} else {
			return valueFalse
		}
	} else if .This == .global.RegExpPrototype {
		return _undefined
	} else {
		panic(.NewTypeError("Method RegExp.prototype.multiline getter called on incompatible receiver %s", .objectproto_toString(FunctionCall{This: .This})))
	}
}

func ( *Runtime) ( FunctionCall) Value {
	if ,  := .toObject(.This).self.(*regexpObject);  {
		if .pattern.dotAll {
			return valueTrue
		} else {
			return valueFalse
		}
	} else if .This == .global.RegExpPrototype {
		return _undefined
	} else {
		panic(.NewTypeError("Method RegExp.prototype.dotAll getter called on incompatible receiver %s", .objectproto_toString(FunctionCall{This: .This})))
	}
}

func ( *Runtime) ( FunctionCall) Value {
	if ,  := .toObject(.This).self.(*regexpObject);  {
		if .pattern.ignoreCase {
			return valueTrue
		} else {
			return valueFalse
		}
	} else if .This == .global.RegExpPrototype {
		return _undefined
	} else {
		panic(.NewTypeError("Method RegExp.prototype.ignoreCase getter called on incompatible receiver %s", .objectproto_toString(FunctionCall{This: .This})))
	}
}

func ( *Runtime) ( FunctionCall) Value {
	if ,  := .toObject(.This).self.(*regexpObject);  {
		if .pattern.unicode {
			return valueTrue
		} else {
			return valueFalse
		}
	} else if .This == .global.RegExpPrototype {
		return _undefined
	} else {
		panic(.NewTypeError("Method RegExp.prototype.unicode getter called on incompatible receiver %s", .objectproto_toString(FunctionCall{This: .This})))
	}
}

func ( *Runtime) ( FunctionCall) Value {
	if ,  := .toObject(.This).self.(*regexpObject);  {
		if .pattern.sticky {
			return valueTrue
		} else {
			return valueFalse
		}
	} else if .This == .global.RegExpPrototype {
		return _undefined
	} else {
		panic(.NewTypeError("Method RegExp.prototype.sticky getter called on incompatible receiver %s", .objectproto_toString(FunctionCall{This: .This})))
	}
}

func ( *Runtime) ( FunctionCall) Value {
	var , , , , ,  bool

	 := .toObject(.This)
	 := 0
	if  := .self.getStr("global", nil);  != nil {
		 = .ToBoolean()
		if  {
			++
		}
	}
	if  := .self.getStr("ignoreCase", nil);  != nil {
		 = .ToBoolean()
		if  {
			++
		}
	}
	if  := .self.getStr("multiline", nil);  != nil {
		 = .ToBoolean()
		if  {
			++
		}
	}
	if  := .self.getStr("dotAll", nil);  != nil {
		 = .ToBoolean()
		if  {
			++
		}
	}
	if  := .self.getStr("sticky", nil);  != nil {
		 = .ToBoolean()
		if  {
			++
		}
	}
	if  := .self.getStr("unicode", nil);  != nil {
		 = .ToBoolean()
		if  {
			++
		}
	}

	var  strings.Builder
	.Grow()
	if  {
		.WriteByte('g')
	}
	if  {
		.WriteByte('i')
	}
	if  {
		.WriteByte('m')
	}
	if  {
		.WriteByte('s')
	}
	if  {
		.WriteByte('u')
	}
	if  {
		.WriteByte('y')
	}

	return asciiString(.String())
}

func ( *Runtime) ( func(FunctionCall) Value,  *Object,  Value) Value {
	 := (FunctionCall{
		This:      ,
		Arguments: []Value{},
	})

	if  != _null {
		if ,  := .(*Object); ! {
			panic(.NewTypeError("RegExp exec method returned something other than an Object or null"))
		}
	}

	return 
}

func ( *Runtime) ( *Object,  String,  bool) []Value {
	.self.setOwnStr("lastIndex", intToValue(0), true)
	,  := .toObject(.self.getStr("exec", nil)).self.assertCallable()
	if ! {
		panic(.NewTypeError("exec is not a function"))
	}
	var  []Value
	for {
		 := .regExpExec(, , )
		if  == _null {
			break
		}
		 = append(, )
		 := nilSafe(.toObject().self.getIdx(valueInt(0), nil)).toString()
		if .Length() == 0 {
			 := toLength(.self.getStr("lastIndex", nil))
			.self.setOwnStr("lastIndex", valueInt(advanceStringIndex64(, , )), true)
		}
	}

	return 
}

func ( *Runtime) ( *Object,  String) Value {
	 := .self
	 := nilSafe(.getStr("flags", nil)).String()
	 := strings.ContainsRune(, 'g')
	if  {
		 := .getGlobalRegexpMatches(, , strings.ContainsRune(, 'u'))
		if len() == 0 {
			return _null
		}
		 := make([]Value, 0, len())
		for ,  := range  {
			 := .toObject()
			 := nilSafe(.self.getIdx(valueInt(0), nil)).ToString()
			 = append(, )
		}
		return .newArrayValues()
	}

	,  := .toObject(.getStr("exec", nil)).self.assertCallable()
	if ! {
		panic(.NewTypeError("exec is not a function"))
	}

	return .regExpExec(, , )
}

func ( *Runtime) ( *Object) *regexpObject {
	if deoptimiseRegexp {
		return nil
	}

	,  := .self.(*regexpObject)
	if ! {
		return nil
	}

	if !.standard || .prototype == nil || .prototype.self != .global.stdRegexpProto {
		return nil
	}

	return 
}

func ( *Runtime) ( FunctionCall) Value {
	 := .toObject(.This)
	 := .Argument(0).toString()
	 := .checkStdRegexp()
	if  == nil {
		return .regexpproto_stdMatcherGeneric(, )
	}
	if .pattern.global {
		 := .pattern.findAllSubmatchIndex(, 0, -1, .pattern.sticky)
		if len() == 0 {
			.setOwnStr("lastIndex", intToValue(0), true)
			return _null
		}
		 := make([]Value, 0, len())
		for ,  := range  {
			 = append(, .Substring([0], [1]))
		}
		.setOwnStr("lastIndex", intToValue(int64([len()-1][1])), true)
		return .newArrayValues()
	} else {
		return .exec()
	}
}

func ( *Runtime) ( *Object,  String) Value {
	 := .self
	 := nilSafe(.getStr("lastIndex", nil))
	 := intToValue(0)
	if !.SameAs() {
		.setOwnStr("lastIndex", , true)
	}
	,  := .toObject(.getStr("exec", nil)).self.assertCallable()
	if ! {
		panic(.NewTypeError("exec is not a function"))
	}

	 := .regExpExec(, , )
	 := nilSafe(.getStr("lastIndex", nil))
	if !.SameAs() {
		.setOwnStr("lastIndex", , true)
	}

	if  == _null {
		return intToValue(-1)
	}

	return .toObject().self.getStr("index", nil)
}

func ( *Runtime) ( FunctionCall) Value {
	 := .toObject(.This)
	 := .Argument(0).toString()
	 := nilSafe(.self.getStr("flags", nil)).toString()
	 := .speciesConstructorObj(.This.(*Object), .getRegExp())
	 := .toConstructor()([]Value{.This, }, nil)
	.self.setOwnStr("lastIndex", valueInt(toLength(.self.getStr("lastIndex", nil))), true)
	 := .String()
	 := strings.Contains(, "g")
	 := strings.Contains(, "u")
	return .createRegExpStringIterator(, , , )
}

func ( *Runtime) ( *Object,  String, ,  bool) Value {
	 := &Object{runtime: }

	 := &regExpStringIterObject{
		matcher:     ,
		s:           ,
		global:      ,
		fullUnicode: ,
	}
	.class = classObject
	.val = 
	.extensible = true
	.self = 
	.prototype = .getRegExpStringIteratorPrototype()
	.init()

	return 
}

type regExpStringIterObject struct {
	baseObject
	matcher                   *Object
	s                         String
	global, fullUnicode, done bool
}

// RegExpExec as defined in 21.2.5.2.1
func regExpExec( *Object,  String) Value {
	 := .self.getStr("exec", nil)
	if ,  := .(*Object);  {
		if ,  := .self.assertCallable();  {
			return .runtime.regExpExec(, , )
		}
	}
	if ,  := .self.(*regexpObject);  {
		return .exec()
	}
	panic(.runtime.NewTypeError("no RegExpMatcher internal slot"))
}

func ( *regExpStringIterObject) () ( Value) {
	if .done {
		return .val.runtime.createIterResultObject(_undefined, true)
	}

	 := regExpExec(.matcher, .s)
	if IsNull() {
		.done = true
		return .val.runtime.createIterResultObject(_undefined, true)
	}
	if !.global {
		.done = true
		return .val.runtime.createIterResultObject(, false)
	}

	 := nilSafe(.val.runtime.toObject().self.getIdx(valueInt(0), nil)).toString()
	if .Length() == 0 {
		 := toLength(.matcher.self.getStr("lastIndex", nil))
		.matcher.self.setOwnStr("lastIndex", valueInt(advanceStringIndex64(.s, , .fullUnicode)), true)
	}
	return .val.runtime.createIterResultObject(, false)
}

func ( *Runtime) ( FunctionCall) Value {
	 := .toObject(.This)
	 := .Argument(0).toString()
	 := .checkStdRegexp()
	if  == nil {
		return .regexpproto_stdSearchGeneric(, )
	}

	 := .getStr("lastIndex", nil)
	.setOwnStr("lastIndex", intToValue(0), true)

	,  := .execRegexp()
	.setOwnStr("lastIndex", , true)

	if ! {
		return intToValue(-1)
	}
	return intToValue(int64([0]))
}

func ( *Runtime) ( *Object,  String,  Value,  bool) Value {
	var  []Value
	var  int64
	if  == nil ||  == _undefined {
		 = maxInt - 1
	} else {
		 = toLength()
	}
	if  == 0 {
		return .newArrayValues()
	}
	 := .Length()
	 := 0
	 := toMethod(.ToObject().self.getStr("exec", nil)) // must be non-nil

	if  == 0 {
		if .regExpExec(, , ) == _null {
			 = append(, )
		}
		return .newArrayValues()
	}

	 := 
	for  <  {
		.self.setOwnStr("lastIndex", intToValue(int64()), true)
		 := .regExpExec(, , )
		if  == _null {
			 = advanceStringIndex(, , )
		} else {
			 := .toObject()
			 := toLength(.self.getStr("lastIndex", nil))
			if  == int64() {
				 = advanceStringIndex(, , )
			} else {
				 = append(, .Substring(, ))
				if int64(len()) ==  {
					return .newArrayValues()
				}
				if  > int64() {
					 = 
				} else {
					 = int()
				}
				 := max(toLength(.self.getStr("length", nil))-1, 0)
				for  := int64(1);  <= ; ++ {
					 = append(, nilSafe(.self.getIdx(valueInt(), nil)))
					if int64(len()) ==  {
						return .newArrayValues()
					}
				}
				 = 
			}
		}
	}
	 = append(, .Substring(, ))
	return .newArrayValues()
}

func advanceStringIndex( String,  int,  bool) int {
	 :=  + 1
	if ! {
		return 
	}
	 := .Length()
	if  >=  {
		return 
	}
	if !isUTF16FirstSurrogate(.CharAt()) {
		return 
	}
	if !isUTF16SecondSurrogate(.CharAt()) {
		return 
	}
	return  + 1
}

func advanceStringIndex64( String,  int64,  bool) int64 {
	 :=  + 1
	if ! {
		return 
	}
	 := int64(.Length())
	if  >=  {
		return 
	}
	if !isUTF16FirstSurrogate(.CharAt(int())) {
		return 
	}
	if !isUTF16SecondSurrogate(.CharAt(int())) {
		return 
	}
	return  + 1
}

func ( *Runtime) ( FunctionCall) Value {
	 := .toObject(.This)
	 := .Argument(0).toString()
	 := .Argument(1)
	var  *Object
	 := .checkStdRegexp()
	 := .speciesConstructorObj(, .getRegExp())
	if  == nil ||  != .global.RegExp {
		 := nilSafe(.self.getStr("flags", nil)).toString()
		 := .String()

		// Add 'y' flag if missing
		if !strings.Contains(, "y") {
			 = .Concat(asciiString("y"))
		}
		 = .toConstructor()([]Value{, }, nil)
		 = .checkStdRegexp()
		if  == nil {
			return .regexpproto_stdSplitterGeneric(, , , strings.Contains(, "u"))
		}
	}

	 := .pattern // toUint32() may recompile the pattern, but we still need to use the original
	 := -1
	if  != _undefined {
		 = int(toUint32())
	}

	if  == 0 {
		return .newArrayValues(nil)
	}

	 := .Length()
	var  []Value
	 := 0
	 := 0

	 := .findAllSubmatchIndex(, 0, -1, false)
	if  == 0 {
		if  == nil {
			 = append(, )
		}
		goto 
	}

	for ,  := range  {
		if [0] == [1] {
			// FIXME Ugh, this is a hack
			if [0] == 0 || [0] ==  {
				continue
			}
		}

		if  != [0] {
			 = append(, .Substring(, [0]))
			++
		} else if  == [0] {
			if  != -1 {
				 = append(, stringEmpty)
				++
			}
		}

		 = [1]
		if  ==  {
			goto 
		}

		 := len() / 2
		for  := 1;  < ; ++ {
			 :=  * 2
			var  Value
			if [] != -1 {
				 = .Substring([], [+1])
			} else {
				 = _undefined
			}
			 = append(, )
			++
			if  ==  {
				goto 
			}
		}
	}

	if  !=  {
		if  !=  {
			 = append(, .Substring(, ))
		} else {
			 = append(, stringEmpty)
		}
	}

:
	return .newArrayValues()
}

func ( *Runtime) ( *Object, ,  String,  func(FunctionCall) Value) Value {
	var  []Value
	 := nilSafe(.self.getStr("flags", nil)).String()
	 := strings.ContainsRune(, 'g')
	 := strings.ContainsRune(, 'u')
	if  {
		 = .getGlobalRegexpMatches(, , )
	} else {
		 := toMethod(.self.getStr("exec", nil)) // must be non-nil
		 := .regExpExec(, , )
		if  != _null {
			 = append(, )
		}
	}
	 := .Length()
	 := 0
	var  StringBuilder
	for ,  := range  {
		 := .toObject()
		 := max(toLength(.self.getStr("length", nil))-1, 0)
		 := nilSafe(.self.getIdx(valueInt(0), nil)).toString()
		 := .Length()
		 := toIntStrict(max(min(nilSafe(.self.getStr("index", nil)).ToInteger(), int64()), 0))
		var  []Value
		if  != nil {
			 = make([]Value, 0, +3)
		} else {
			 = make([]Value, 0, +1)
		}
		 = append(, )
		for  := int64(1);  <= ; ++ {
			 := nilSafe(.self.getIdx(valueInt(), nil))
			if  != _undefined {
				 = .ToString()
			}
			 = append(, )
		}
		var  String
		if  != nil {
			 = append(, intToValue(int64()), )
			 = (FunctionCall{
				This:      _undefined,
				Arguments: ,
			}).toString()
			if  >=  {
				.WriteString(.Substring(, ))
				.WriteString()
				 =  + 
			}
		} else {
			if  >=  {
				.WriteString(.Substring(, ))
				writeSubstitution(, , len(), func( int) String {
					 := []
					if  != _undefined {
						return .toString()
					}
					return stringEmpty
				}, , &)
				 =  + 
			}
		}
	}
	if  <  {
		.WriteString(.Substring(, ))
	}
	return .String()
}

func writeSubstitution( String,  int,  int,  func(int) String,  String,  *StringBuilder) {
	 := .Length()
	 := .Length()
	 := (0)
	 :=  + .Length()

	for  := 0;  < ; ++ {
		 := .CharAt()
		if  == '$' &&  < -1 {
			 := .CharAt( + 1)
			switch  {
			case '$':
				.WriteRune('$')
			case '`':
				.WriteString(.Substring(0, ))
			case '\'':
				if  <  {
					.WriteString(.Substring(, ))
				}
			case '&':
				.WriteString()
			default:
				 := 0
				 :=  + 1
				for  <  {
					 := .CharAt()
					if  >= '0' &&  <= '9' {
						 := *10 + int(-'0')
						if  >=  {
							break
						}
						 = 
						++
					} else {
						break
					}
				}
				if  > 0 {
					.WriteString(())
					 =  - 1
					continue
				} else {
					.WriteRune('$')
					.WriteRune(rune())
				}
			}
			++
		} else {
			.WriteRune(rune())
		}
	}
}

func ( *Runtime) ( FunctionCall) Value {
	 := .toObject(.This)
	 := .Argument(0).toString()
	,  := getReplaceValue(.Argument(1))

	 := .checkStdRegexp()
	if  == nil {
		return .regexpproto_stdReplacerGeneric(, , , )
	}

	var  int64
	 := 1
	if .pattern.global {
		 = -1
		.setOwnStr("lastIndex", intToValue(0), true)
	} else {
		 = .getLastIndex()
	}
	 := .pattern.findAllSubmatchIndex(, toIntStrict(), , .pattern.sticky)
	if len() > 0 {
		if !.updateLastIndex(, [0], [len()-1]) {
			 = nil
		}
	} else {
		.updateLastIndex(, nil, nil)
	}

	return stringReplace(, , , )
}

func ( *Runtime) ( FunctionCall) Value {
	 := .toObject(.This)
	if ,  := .self.(*regExpStringIterObject);  {
		return .next()
	}
	panic(.NewTypeError("Method RegExp String Iterator.prototype.next called on incompatible receiver %s", .objectproto_toString(FunctionCall{This: })))
}

func ( *Runtime) ( *Object) objectImpl {
	 := newBaseObjectObj(, .getIteratorPrototype(), classObject)

	._putProp("next", .newNativeFunc(.regExpStringIteratorProto_next, "next", 0), true, false, true)
	._putSym(SymToStringTag, valueProp(asciiString(classRegExpStringIterator), false, false, true))

	return 
}

func ( *Runtime) () *Object {
	var  *Object
	if  = .global.RegExpStringIteratorPrototype;  == nil {
		 = &Object{runtime: }
		.global.RegExpStringIteratorPrototype = 
		.self = .createRegExpStringIteratorPrototype()
	}
	return 
}

func ( *Runtime) () *Object {
	 := .global.RegExp
	if  == nil {
		 = &Object{runtime: }
		.global.RegExp = 
		 := .getRegExpPrototype()
		.newNativeFuncAndConstruct(, .builtin_RegExp,
			.wrapNativeConstruct(.builtin_newRegExp, , ), , "RegExp", intToValue(2))
		 := .self
		.putSpeciesReturnThis()
	}
	return 
}

func ( *Runtime) () *Object {
	 := .global.RegExpPrototype
	if  == nil {
		 := .newGuardedObject(.global.ObjectPrototype, classObject)
		 = .val
		.global.RegExpPrototype = 
		.global.stdRegexpProto = 

		._putProp("constructor", .getRegExp(), true, false, true)
		._putProp("compile", .newNativeFunc(.regexpproto_compile, "compile", 2), true, false, true)
		._putProp("exec", .newNativeFunc(.regexpproto_exec, "exec", 1), true, false, true)
		._putProp("test", .newNativeFunc(.regexpproto_test, "test", 1), true, false, true)
		._putProp("toString", .newNativeFunc(.regexpproto_toString, "toString", 0), true, false, true)
		.setOwnStr("source", &valueProperty{
			configurable: true,
			getterFunc:   .newNativeFunc(.regexpproto_getSource, "get source", 0),
			accessor:     true,
		}, false)
		.setOwnStr("global", &valueProperty{
			configurable: true,
			getterFunc:   .newNativeFunc(.regexpproto_getGlobal, "get global", 0),
			accessor:     true,
		}, false)
		.setOwnStr("multiline", &valueProperty{
			configurable: true,
			getterFunc:   .newNativeFunc(.regexpproto_getMultiline, "get multiline", 0),
			accessor:     true,
		}, false)
		.setOwnStr("dotAll", &valueProperty{
			configurable: true,
			getterFunc:   .newNativeFunc(.regexpproto_getDotAll, "get dotAll", 0),
			accessor:     true,
		}, false)
		.setOwnStr("ignoreCase", &valueProperty{
			configurable: true,
			getterFunc:   .newNativeFunc(.regexpproto_getIgnoreCase, "get ignoreCase", 0),
			accessor:     true,
		}, false)
		.setOwnStr("unicode", &valueProperty{
			configurable: true,
			getterFunc:   .newNativeFunc(.regexpproto_getUnicode, "get unicode", 0),
			accessor:     true,
		}, false)
		.setOwnStr("sticky", &valueProperty{
			configurable: true,
			getterFunc:   .newNativeFunc(.regexpproto_getSticky, "get sticky", 0),
			accessor:     true,
		}, false)
		.setOwnStr("flags", &valueProperty{
			configurable: true,
			getterFunc:   .newNativeFunc(.regexpproto_getFlags, "get flags", 0),
			accessor:     true,
		}, false)

		._putSym(SymMatch, valueProp(.newNativeFunc(.regexpproto_stdMatcher, "[Symbol.match]", 1), true, false, true))
		._putSym(SymMatchAll, valueProp(.newNativeFunc(.regexpproto_stdMatcherAll, "[Symbol.matchAll]", 1), true, false, true))
		._putSym(SymSearch, valueProp(.newNativeFunc(.regexpproto_stdSearch, "[Symbol.search]", 1), true, false, true))
		._putSym(SymSplit, valueProp(.newNativeFunc(.regexpproto_stdSplitter, "[Symbol.split]", 2), true, false, true))
		._putSym(SymReplace, valueProp(.newNativeFunc(.regexpproto_stdReplacer, "[Symbol.replace]", 2), true, false, true))
		.guard("exec", "global", "multiline", "ignoreCase", "unicode", "sticky")
	}
	return 
}