From 328e4838839d40eeedee121c50508034b47b051d Mon Sep 17 00:00:00 2001 From: Mihail Stoykov Date: Tue, 17 Feb 2026 19:10:59 +0200 Subject: [PATCH 1/2] Update tc39 test262 sha to latest and fix changes to Date --- .tc39_test262_checkout.sh | 2 +- builtin_date.go | 84 +++++++++++----------- tc39_test.go | 148 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 191 insertions(+), 43 deletions(-) diff --git a/.tc39_test262_checkout.sh b/.tc39_test262_checkout.sh index 1500daa97..ea7317829 100755 --- a/.tc39_test262_checkout.sh +++ b/.tc39_test262_checkout.sh @@ -1,6 +1,6 @@ #!/bin/sh -e # this is just the commit it was last tested with -sha=cb4a6c8074671c00df8cbc17a620c0f9462b312a +sha=3af36bec45bd4f72d4b57366653578e1e4dafef7 mkdir -p testdata/test262 cd testdata/test262 diff --git a/builtin_date.go b/builtin_date.go index 84a80ac02..16387f21e 100644 --- a/builtin_date.go +++ b/builtin_date.go @@ -684,24 +684,24 @@ func _dateSetMilliseconds(year, mon, day, hours, min, sec int64, t time.Time, ca func (r *Runtime) dateproto_setMilliseconds(call FunctionCall) Value { obj := r.toObject(call.This) if d, ok := obj.self.(*dateObject); ok { + tv := d.msec n := call.Argument(0).ToNumber() + if tv == timeUnset { + return _NaN + } if IsNaN(n) { d.unset() return _NaN } msec := n.ToInteger() - sec := d.msec / 1e3 + sec := tv / 1e3 var ok bool sec, msec, ok = _norm(sec, msec, 1e3) if !ok { d.unset() return _NaN } - if d.isSet() { - return d.setTimeMs(sec*1e3 + msec) - } else { - return _NaN - } + return d.setTimeMs(sec*1e3 + msec) } panic(r.NewTypeError("Method Date.prototype.setMilliseconds is called on incompatible receiver")) } @@ -709,24 +709,24 @@ func (r *Runtime) dateproto_setMilliseconds(call FunctionCall) Value { func (r *Runtime) dateproto_setUTCMilliseconds(call FunctionCall) Value { obj := r.toObject(call.This) if d, ok := obj.self.(*dateObject); ok { + tv := d.msec n := call.Argument(0).ToNumber() + if tv == timeUnset { + return _NaN + } if IsNaN(n) { d.unset() return _NaN } msec := n.ToInteger() - sec := d.msec / 1e3 + sec := tv / 1e3 var ok bool sec, msec, ok = _norm(sec, msec, 1e3) if !ok { d.unset() return _NaN } - if d.isSet() { - return d.setTimeMs(sec*1e3 + msec) - } else { - return _NaN - } + return d.setTimeMs(sec*1e3 + msec) } panic(r.NewTypeError("Method Date.prototype.setUTCMilliseconds is called on incompatible receiver")) } @@ -734,16 +734,16 @@ func (r *Runtime) dateproto_setUTCMilliseconds(call FunctionCall) Value { func (r *Runtime) dateproto_setSeconds(call FunctionCall) Value { obj := r.toObject(call.This) if d, ok := obj.self.(*dateObject); ok { + tv := d.msec t, ok := _dateSetFullYear(d.time(), call, -5, false) if !ok { d.unset() return _NaN } - if d.isSet() { - return d.setTimeMs(timeToMsec(t)) - } else { + if tv == timeUnset { return _NaN } + return d.setTimeMs(timeToMsec(t)) } panic(r.NewTypeError("Method Date.prototype.setSeconds is called on incompatible receiver")) } @@ -751,16 +751,16 @@ func (r *Runtime) dateproto_setSeconds(call FunctionCall) Value { func (r *Runtime) dateproto_setUTCSeconds(call FunctionCall) Value { obj := r.toObject(call.This) if d, ok := obj.self.(*dateObject); ok { + tv := d.msec t, ok := _dateSetFullYear(d.timeUTC(), call, -5, true) if !ok { d.unset() return _NaN } - if d.isSet() { - return d.setTimeMs(timeToMsec(t)) - } else { + if tv == timeUnset { return _NaN } + return d.setTimeMs(timeToMsec(t)) } panic(r.NewTypeError("Method Date.prototype.setUTCSeconds is called on incompatible receiver")) } @@ -768,16 +768,16 @@ func (r *Runtime) dateproto_setUTCSeconds(call FunctionCall) Value { func (r *Runtime) dateproto_setMinutes(call FunctionCall) Value { obj := r.toObject(call.This) if d, ok := obj.self.(*dateObject); ok { + tv := d.msec t, ok := _dateSetFullYear(d.time(), call, -4, false) if !ok { d.unset() return _NaN } - if d.isSet() { - return d.setTimeMs(timeToMsec(t)) - } else { + if tv == timeUnset { return _NaN } + return d.setTimeMs(timeToMsec(t)) } panic(r.NewTypeError("Method Date.prototype.setMinutes is called on incompatible receiver")) } @@ -785,16 +785,16 @@ func (r *Runtime) dateproto_setMinutes(call FunctionCall) Value { func (r *Runtime) dateproto_setUTCMinutes(call FunctionCall) Value { obj := r.toObject(call.This) if d, ok := obj.self.(*dateObject); ok { + tv := d.msec t, ok := _dateSetFullYear(d.timeUTC(), call, -4, true) if !ok { d.unset() return _NaN } - if d.isSet() { - return d.setTimeMs(timeToMsec(t)) - } else { + if tv == timeUnset { return _NaN } + return d.setTimeMs(timeToMsec(t)) } panic(r.NewTypeError("Method Date.prototype.setUTCMinutes is called on incompatible receiver")) } @@ -802,16 +802,16 @@ func (r *Runtime) dateproto_setUTCMinutes(call FunctionCall) Value { func (r *Runtime) dateproto_setHours(call FunctionCall) Value { obj := r.toObject(call.This) if d, ok := obj.self.(*dateObject); ok { + tv := d.msec t, ok := _dateSetFullYear(d.time(), call, -3, false) if !ok { d.unset() return _NaN } - if d.isSet() { - return d.setTimeMs(timeToMsec(t)) - } else { + if tv == timeUnset { return _NaN } + return d.setTimeMs(timeToMsec(t)) } panic(r.NewTypeError("Method Date.prototype.setHours is called on incompatible receiver")) } @@ -819,16 +819,16 @@ func (r *Runtime) dateproto_setHours(call FunctionCall) Value { func (r *Runtime) dateproto_setUTCHours(call FunctionCall) Value { obj := r.toObject(call.This) if d, ok := obj.self.(*dateObject); ok { + tv := d.msec t, ok := _dateSetFullYear(d.timeUTC(), call, -3, true) if !ok { d.unset() return _NaN } - if d.isSet() { - return d.setTimeMs(timeToMsec(t)) - } else { + if tv == timeUnset { return _NaN } + return d.setTimeMs(timeToMsec(t)) } panic(r.NewTypeError("Method Date.prototype.setUTCHours is called on incompatible receiver")) } @@ -836,16 +836,16 @@ func (r *Runtime) dateproto_setUTCHours(call FunctionCall) Value { func (r *Runtime) dateproto_setDate(call FunctionCall) Value { obj := r.toObject(call.This) if d, ok := obj.self.(*dateObject); ok { + tv := d.msec t, ok := _dateSetFullYear(d.time(), limitCallArgs(call, 1), -2, false) if !ok { d.unset() return _NaN } - if d.isSet() { - return d.setTimeMs(timeToMsec(t)) - } else { + if tv == timeUnset { return _NaN } + return d.setTimeMs(timeToMsec(t)) } panic(r.NewTypeError("Method Date.prototype.setDate is called on incompatible receiver")) } @@ -853,16 +853,16 @@ func (r *Runtime) dateproto_setDate(call FunctionCall) Value { func (r *Runtime) dateproto_setUTCDate(call FunctionCall) Value { obj := r.toObject(call.This) if d, ok := obj.self.(*dateObject); ok { + tv := d.msec t, ok := _dateSetFullYear(d.timeUTC(), limitCallArgs(call, 1), -2, true) if !ok { d.unset() return _NaN } - if d.isSet() { - return d.setTimeMs(timeToMsec(t)) - } else { + if tv == timeUnset { return _NaN } + return d.setTimeMs(timeToMsec(t)) } panic(r.NewTypeError("Method Date.prototype.setUTCDate is called on incompatible receiver")) } @@ -870,16 +870,16 @@ func (r *Runtime) dateproto_setUTCDate(call FunctionCall) Value { func (r *Runtime) dateproto_setMonth(call FunctionCall) Value { obj := r.toObject(call.This) if d, ok := obj.self.(*dateObject); ok { + tv := d.msec t, ok := _dateSetFullYear(d.time(), limitCallArgs(call, 2), -1, false) if !ok { d.unset() return _NaN } - if d.isSet() { - return d.setTimeMs(timeToMsec(t)) - } else { + if tv == timeUnset { return _NaN } + return d.setTimeMs(timeToMsec(t)) } panic(r.NewTypeError("Method Date.prototype.setMonth is called on incompatible receiver")) } @@ -887,16 +887,16 @@ func (r *Runtime) dateproto_setMonth(call FunctionCall) Value { func (r *Runtime) dateproto_setUTCMonth(call FunctionCall) Value { obj := r.toObject(call.This) if d, ok := obj.self.(*dateObject); ok { + tv := d.msec t, ok := _dateSetFullYear(d.timeUTC(), limitCallArgs(call, 2), -1, true) if !ok { d.unset() return _NaN } - if d.isSet() { - return d.setTimeMs(timeToMsec(t)) - } else { + if tv == timeUnset { return _NaN } + return d.setTimeMs(timeToMsec(t)) } panic(r.NewTypeError("Method Date.prototype.setUTCMonth is called on incompatible receiver")) } diff --git a/tc39_test.go b/tc39_test.go index 2f14ca567..13fccbf5f 100644 --- a/tc39_test.go +++ b/tc39_test.go @@ -192,6 +192,138 @@ var ( "test/built-ins/RegExp/nullable-quantifier.js": true, "test/built-ins/RegExp/lookahead-quantifier-match-groups.js": true, + + // Fixed in https://github.com/grafana/sobek/pull/115 + "test/built-ins/GeneratorPrototype/return/try-finally-set-property-within-try.js": true, + + // TypedArray internals + "test/built-ins/TypedArrayConstructors/internals/Set/key-is-valid-index-reflect-set.js": true, + "test/built-ins/TypedArrayConstructors/internals/Set/key-is-out-of-bounds-receiver-is-proto.js": true, + "test/built-ins/TypedArrayConstructors/internals/Set/key-is-out-of-bounds-receiver-is-not-object.js": true, + "test/built-ins/TypedArrayConstructors/internals/Set/key-is-canonical-invalid-index-prototype-chain-set.js": true, + "test/built-ins/TypedArrayConstructors/internals/Set/key-is-canonical-invalid-index-reflect-set.js": true, + "test/built-ins/TypedArrayConstructors/internals/Set/BigInt/key-is-valid-index-reflect-set.js": true, + "test/built-ins/TypedArrayConstructors/internals/Set/BigInt/key-is-canonical-invalid-index-prototype-chain-set.js": true, + "test/built-ins/TypedArrayConstructors/internals/Set/BigInt/key-is-canonical-invalid-index-reflect-set.js": true, + "test/built-ins/TypedArray/prototype/with/value-throw-completion.js": true, + "test/built-ins/TypedArray/prototype/slice/speciesctor-return-same-buffer-with-offset.js": true, + + // String prototype (cstm-* and regexp) + "test/built-ins/String/prototype/split/cstm-split-on-string-primitive.js": true, + "test/built-ins/String/prototype/split/cstm-split-on-number-primitive.js": true, + "test/built-ins/String/prototype/split/cstm-split-on-boolean-primitive.js": true, + "test/built-ins/String/prototype/split/cstm-split-on-bigint-primitive.js": true, + "test/built-ins/String/prototype/search/cstm-search-on-string-primitive.js": true, + "test/built-ins/String/prototype/search/cstm-search-on-number-primitive.js": true, + "test/built-ins/String/prototype/search/cstm-search-on-boolean-primitive.js": true, + "test/built-ins/String/prototype/search/cstm-search-on-bigint-primitive.js": true, + "test/built-ins/String/prototype/replaceAll/cstm-replaceall-on-number-primitive.js": true, + "test/built-ins/String/prototype/replaceAll/cstm-replaceall-on-bigint-primitive.js": true, + "test/built-ins/String/prototype/replace/cstm-replace-on-string-primitive.js": true, + "test/built-ins/String/prototype/replace/cstm-replace-on-number-primitive.js": true, + "test/built-ins/String/prototype/replaceAll/cstm-replaceall-on-string-primitive.js": true, + "test/built-ins/String/prototype/replace/cstm-replace-on-boolean-primitive.js": true, + "test/built-ins/String/prototype/replaceAll/cstm-replaceall-on-boolean-primitive.js": true, + "test/built-ins/String/prototype/replace/regexp-capture-by-index.js": true, + "test/built-ins/String/prototype/replace/cstm-replace-on-bigint-primitive.js": true, + "test/built-ins/String/prototype/match/cstm-matcher-on-number-primitive.js": true, + "test/built-ins/String/prototype/match/cstm-matcher-on-bigint-primitive.js": true, + "test/built-ins/String/prototype/match/cstm-matcher-on-boolean-primitive.js": true, + "test/built-ins/String/prototype/match/cstm-matcher-on-string-primitive.js": true, + "test/built-ins/String/prototype/matchAll/cstm-matchall-on-number-primitive.js": true, + "test/built-ins/String/prototype/matchAll/cstm-matchall-on-bigint-primitive.js": true, + "test/built-ins/String/prototype/matchAll/cstm-matchall-on-string-primitive.js": true, + + // RegExp CharacterClassEscapes + "test/built-ins/RegExp/CharacterClassEscapes/character-class-word-class-escape-positive-cases.js": true, + "test/built-ins/RegExp/CharacterClassEscapes/character-class-word-class-escape-negative-cases.js": true, + "test/built-ins/RegExp/CharacterClassEscapes/character-class-whitespace-class-escape-negative-cases.js": true, + "test/built-ins/RegExp/CharacterClassEscapes/character-class-whitespace-class-escape-positive-cases.js": true, + "test/built-ins/RegExp/CharacterClassEscapes/character-class-non-word-class-escape-positive-cases.js": true, + "test/built-ins/RegExp/CharacterClassEscapes/character-class-non-word-class-escape-negative-cases.js": true, + "test/built-ins/RegExp/CharacterClassEscapes/character-class-non-whitespace-class-escape-negative-cases.js": true, + "test/built-ins/RegExp/CharacterClassEscapes/character-class-non-digit-class-escape-positive-cases.js": true, + "test/built-ins/RegExp/CharacterClassEscapes/character-class-non-digit-class-escape-negative-cases.js": true, + "test/built-ins/RegExp/CharacterClassEscapes/character-class-digit-class-escape-positive-cases.js": true, + "test/built-ins/RegExp/CharacterClassEscapes/character-class-digit-class-escape-negative-cases.js": true, + "test/built-ins/RegExp/CharacterClassEscapes/character-class-non-whitespace-class-escape-positive-cases.js": true, + + // JSON (rawJSON, reviver) + "test/built-ins/JSON/isRawJSON/not-a-constructor.js": true, + "test/built-ins/JSON/isRawJSON/length.js": true, + "test/built-ins/JSON/isRawJSON/prop-desc.js": true, + "test/built-ins/JSON/isRawJSON/basic.js": true, + "test/built-ins/JSON/isRawJSON/name.js": true, + "test/built-ins/JSON/isRawJSON/builtin.js": true, + "test/built-ins/JSON/parse/reviver-forward-modifies-object.js": true, + "test/built-ins/JSON/parse/reviver-context-source-primitive-literal.js": true, + "test/built-ins/JSON/parse/reviver-context-source-object-literal.js": true, + "test/built-ins/JSON/parse/reviver-context-source-array-literal.js": true, + "test/built-ins/JSON/parse/reviver-call-args-after-forward-modification.js": true, + + // Error.isError + "test/built-ins/Error/isError/symbols.js": true, + "test/built-ins/Error/isError/primitives.js": true, + "test/built-ins/Error/isError/prop-desc.js": true, + "test/built-ins/Error/isError/name.js": true, + "test/built-ins/Error/isError/is-a-constructor.js": true, + "test/built-ins/Error/isError/fake-errors.js": true, + "test/built-ins/Error/isError/errors.js": true, + "test/built-ins/Error/isError/non-error-objects.js": true, + "test/built-ins/Error/isError/error-subclass.js": true, + "test/built-ins/Error/isError/bigints.js": true, + "test/built-ins/Error/error-message-tostring-symbol.js": true, + "test/built-ins/NativeErrors/nativeerror-tostring-message-throws-symbol.js": true, + + // Object, Array, AggregateError + "test/built-ins/Object/prototype/setPrototypeOf-with-non-circular-values.js": true, + "test/built-ins/Object/prototype/setPrototypeOf-with-non-circular-values-__proto__.js": true, + "test/built-ins/Array/prototype/flat/non-numeric-depth-should-not-throw.js": true, + "test/built-ins/AggregateError/errors-iterabletolist.js": true, + + // Language tests (class, with, module, expressions, identifiers) + "test/language/statements/class/subclass/private-class-field-on-nonextensible-return-override.js": true, + "test/language/statements/class/elements/syntax/valid/grammar-field-named-set-followed-by-generator-asi.js": true, + "test/language/statements/class/elements/syntax/valid/grammar-field-named-get-followed-by-generator-asi.js": true, + "test/language/statements/class/elements/private-class-field-on-nonextensible-objects.js": true, + "test/language/statements/with/set-mutable-binding-idref-compound-assign-with-proxy-env.js": true, + "test/language/statements/with/set-mutable-binding-binding-deleted-with-typed-array-in-proto-chain.js": true, + "test/language/statements/with/set-mutable-binding-idref-with-proxy-env.js": true, + "test/language/statements/with/get-binding-value-idref-with-proxy-env.js": true, + "test/language/statements/with/get-binding-value-call-with-proxy-env.js": true, + "test/language/statements/with/get-mutable-binding-binding-deleted-in-get-unscopables-strict-mode.js": true, + "test/language/module-code/ambiguous-export-bindings/namespace-unambiguous-if-export-star-as-from-and-import-star-as-and-export.js": true, + "test/language/module-code/ambiguous-export-bindings/namespace-unambiguous-if-import-star-as-and-export.js": true, + "test/language/module-code/top-level-await/pending-async-dep-from-cycle.js": true, + "test/language/module-code/top-level-await/module-graphs-does-not-hang.js": true, + "test/language/expressions/less-than-or-equal/S11.8.3_A4.12_T1.js": true, + "test/language/expressions/less-than/S11.8.1_A4.12_T1.js": true, + "test/language/expressions/greater-than-or-equal/S11.8.4_A4.12_T1.js": true, + "test/language/expressions/greater-than/S11.8.2_A4.12_T1.js": true, + "test/language/identifiers/part-unicode-17.0.0.js": true, + "test/language/identifiers/part-unicode-17.0.0-escaped.js": true, + "test/language/identifiers/part-unicode-17.0.0-class.js": true, + "test/language/identifiers/part-unicode-17.0.0-class-escaped.js": true, + "test/language/identifiers/part-unicode-16.0.0.js": true, + "test/language/identifiers/part-unicode-16.0.0-escaped.js": true, + "test/language/identifiers/part-unicode-16.0.0-class.js": true, + "test/language/identifiers/part-unicode-16.0.0-class-escaped.js": true, + "test/language/identifiers/part-unicode-15.1.0.js": true, + "test/language/identifiers/part-unicode-15.1.0-escaped.js": true, + "test/language/identifiers/part-unicode-15.1.0-class.js": true, + "test/language/identifiers/part-unicode-15.1.0-class-escaped.js": true, + "test/language/identifiers/start-unicode-17.0.0.js": true, + "test/language/identifiers/start-unicode-17.0.0-escaped.js": true, + "test/language/identifiers/start-unicode-17.0.0-class.js": true, + "test/language/identifiers/start-unicode-17.0.0-class-escaped.js": true, + "test/language/identifiers/start-unicode-16.0.0.js": true, + "test/language/identifiers/start-unicode-16.0.0-class.js": true, + "test/language/identifiers/start-unicode-15.1.0.js": true, + "test/language/identifiers/start-unicode-15.1.0-escaped.js": true, + "test/language/identifiers/start-unicode-15.1.0-class.js": true, + "test/language/identifiers/start-unicode-15.1.0-class-escaped.js": true, + "test/language/identifiers/start-unicode-16.0.0-class-escaped.js": true, + "test/language/identifiers/start-unicode-16.0.0-escaped.js": true, } featuresBlackList = []string{ @@ -220,6 +352,11 @@ var ( "ShadowRealm", "SharedArrayBuffer", "decorators", + "immutable-arraybuffer", + "joint-iteration", + "iterator-sequencing", + + "regexp-duplicate-named-groups", "regexp-v-flag", "iterator-helpers", "symbols-as-weakmap-keys", @@ -235,6 +372,10 @@ var ( "arraybuffer-transfer", "Array.fromAsync", "String.prototype.isWellFormed", + + "source-phase-imports", + "import-attributes", + "import-defer", } ) @@ -305,6 +446,13 @@ func init() { "test/language/export/", "test/language/import/", "test/language/module-code/", + + // Map getOrInsert* + "test/built-ins/WeakMap/prototype/getOrInsert", + "test/built-ins/Map/prototype/getOrInsert", + + // rawJSON isn not supported + "test/built-ins/JSON/rawJSON", ) } From 751fc25e264fc88d2f869e753bbb4f65439c1a2f Mon Sep 17 00:00:00 2001 From: Mihail Stoykov Date: Wed, 18 Feb 2026 14:10:35 +0200 Subject: [PATCH 2/2] Fix String.prototype issues with primitives --- builtin_string.go | 32 ++++++++++++++------------------ tc39_test.go | 27 ++------------------------- 2 files changed, 16 insertions(+), 43 deletions(-) diff --git a/builtin_string.go b/builtin_string.go index 76f8c57cf..7248ecac5 100644 --- a/builtin_string.go +++ b/builtin_string.go @@ -381,7 +381,7 @@ func (r *Runtime) stringproto_localeCompare(call FunctionCall) Value { func (r *Runtime) stringproto_match(call FunctionCall) Value { r.checkObjectCoercible(call.This) regexp := call.Argument(0) - if regexp != _undefined && regexp != _null { + if _, ok := regexp.(*Object); ok { if matcher := toMethod(r.getV(regexp, SymMatch)); matcher != nil { return matcher(FunctionCall{ This: regexp, @@ -412,14 +412,12 @@ func (r *Runtime) stringproto_match(call FunctionCall) Value { func (r *Runtime) stringproto_matchAll(call FunctionCall) Value { r.checkObjectCoercible(call.This) regexp := call.Argument(0) - if regexp != _undefined && regexp != _null { + if o, ok := regexp.(*Object); ok { if isRegexp(regexp) { - if o, ok := regexp.(*Object); ok { - flags := nilSafe(o.self.getStr("flags", nil)) - r.checkObjectCoercible(flags) - if !strings.Contains(flags.toString().String(), "g") { - panic(r.NewTypeError("RegExp doesn't have global flag set")) - } + flags := nilSafe(o.self.getStr("flags", nil)) + r.checkObjectCoercible(flags) + if !strings.Contains(flags.toString().String(), "g") { + panic(r.NewTypeError("RegExp doesn't have global flag set")) } } if matcher := toMethod(r.getV(regexp, SymMatchAll)); matcher != nil { @@ -664,7 +662,7 @@ func (r *Runtime) stringproto_replace(call FunctionCall) Value { r.checkObjectCoercible(call.This) searchValue := call.Argument(0) replaceValue := call.Argument(1) - if searchValue != _undefined && searchValue != _null { + if _, ok := searchValue.(*Object); ok { if replacer := toMethod(r.getV(searchValue, SymReplace)); replacer != nil { return replacer(FunctionCall{ This: searchValue, @@ -689,14 +687,12 @@ func (r *Runtime) stringproto_replaceAll(call FunctionCall) Value { r.checkObjectCoercible(call.This) searchValue := call.Argument(0) replaceValue := call.Argument(1) - if searchValue != _undefined && searchValue != _null { + if o, ok := searchValue.(*Object); ok { if isRegexp(searchValue) { - if o, ok := searchValue.(*Object); ok { - flags := nilSafe(o.self.getStr("flags", nil)) - r.checkObjectCoercible(flags) - if !strings.Contains(flags.toString().String(), "g") { - panic(r.NewTypeError("String.prototype.replaceAll called with a non-global RegExp argument")) - } + flags := nilSafe(o.self.getStr("flags", nil)) + r.checkObjectCoercible(flags) + if !strings.Contains(flags.toString().String(), "g") { + panic(r.NewTypeError("String.prototype.replaceAll called with a non-global RegExp argument")) } } if replacer := toMethod(r.getV(searchValue, SymReplace)); replacer != nil { @@ -726,7 +722,7 @@ func (r *Runtime) stringproto_replaceAll(call FunctionCall) Value { func (r *Runtime) stringproto_search(call FunctionCall) Value { r.checkObjectCoercible(call.This) regexp := call.Argument(0) - if regexp != _undefined && regexp != _null { + if _, ok := regexp.(*Object); ok { if searcher := toMethod(r.getV(regexp, SymSearch)); searcher != nil { return searcher(FunctionCall{ This: regexp, @@ -799,7 +795,7 @@ func (r *Runtime) stringproto_split(call FunctionCall) Value { r.checkObjectCoercible(call.This) separatorValue := call.Argument(0) limitValue := call.Argument(1) - if separatorValue != _undefined && separatorValue != _null { + if _, ok := separatorValue.(*Object); ok { if splitter := toMethod(r.getV(separatorValue, SymSplit)); splitter != nil { return splitter(FunctionCall{ This: separatorValue, diff --git a/tc39_test.go b/tc39_test.go index 13fccbf5f..25361234e 100644 --- a/tc39_test.go +++ b/tc39_test.go @@ -208,31 +208,8 @@ var ( "test/built-ins/TypedArray/prototype/with/value-throw-completion.js": true, "test/built-ins/TypedArray/prototype/slice/speciesctor-return-same-buffer-with-offset.js": true, - // String prototype (cstm-* and regexp) - "test/built-ins/String/prototype/split/cstm-split-on-string-primitive.js": true, - "test/built-ins/String/prototype/split/cstm-split-on-number-primitive.js": true, - "test/built-ins/String/prototype/split/cstm-split-on-boolean-primitive.js": true, - "test/built-ins/String/prototype/split/cstm-split-on-bigint-primitive.js": true, - "test/built-ins/String/prototype/search/cstm-search-on-string-primitive.js": true, - "test/built-ins/String/prototype/search/cstm-search-on-number-primitive.js": true, - "test/built-ins/String/prototype/search/cstm-search-on-boolean-primitive.js": true, - "test/built-ins/String/prototype/search/cstm-search-on-bigint-primitive.js": true, - "test/built-ins/String/prototype/replaceAll/cstm-replaceall-on-number-primitive.js": true, - "test/built-ins/String/prototype/replaceAll/cstm-replaceall-on-bigint-primitive.js": true, - "test/built-ins/String/prototype/replace/cstm-replace-on-string-primitive.js": true, - "test/built-ins/String/prototype/replace/cstm-replace-on-number-primitive.js": true, - "test/built-ins/String/prototype/replaceAll/cstm-replaceall-on-string-primitive.js": true, - "test/built-ins/String/prototype/replace/cstm-replace-on-boolean-primitive.js": true, - "test/built-ins/String/prototype/replaceAll/cstm-replaceall-on-boolean-primitive.js": true, - "test/built-ins/String/prototype/replace/regexp-capture-by-index.js": true, - "test/built-ins/String/prototype/replace/cstm-replace-on-bigint-primitive.js": true, - "test/built-ins/String/prototype/match/cstm-matcher-on-number-primitive.js": true, - "test/built-ins/String/prototype/match/cstm-matcher-on-bigint-primitive.js": true, - "test/built-ins/String/prototype/match/cstm-matcher-on-boolean-primitive.js": true, - "test/built-ins/String/prototype/match/cstm-matcher-on-string-primitive.js": true, - "test/built-ins/String/prototype/matchAll/cstm-matchall-on-number-primitive.js": true, - "test/built-ins/String/prototype/matchAll/cstm-matchall-on-bigint-primitive.js": true, - "test/built-ins/String/prototype/matchAll/cstm-matchall-on-string-primitive.js": true, + // String prototype regexp-capture-by-index (regexp named groups) + "test/built-ins/String/prototype/replace/regexp-capture-by-index.js": true, // RegExp CharacterClassEscapes "test/built-ins/RegExp/CharacterClassEscapes/character-class-word-class-escape-positive-cases.js": true,