From 5356e2f40cfef84d383b1b6842c8eb0415b3bed5 Mon Sep 17 00:00:00 2001 From: Mihail Stoykov Date: Fri, 16 Aug 2024 12:24:02 +0300 Subject: [PATCH] Update sobek --- go.mod | 4 +- go.sum | 8 +- vendor/github.com/dlclark/regexp2/README.md | 9 +- vendor/github.com/dlclark/regexp2/match.go | 14 +- vendor/github.com/dlclark/regexp2/regexp.go | 28 ++- vendor/github.com/dlclark/regexp2/runner.go | 4 + .../dlclark/regexp2/syntax/parser.go | 19 +- .../github.com/grafana/sobek/builtin_array.go | 178 ++++++++++++++++++ .../github.com/grafana/sobek/builtin_error.go | 27 ++- .../grafana/sobek/builtin_regexp.go | 49 ++++- .../grafana/sobek/builtin_typedarrays.go | 92 +++++++++ .../grafana/sobek/object_gomap_reflect.go | 35 +++- .../github.com/grafana/sobek/parser/regexp.go | 9 +- vendor/github.com/grafana/sobek/regexp.go | 10 +- vendor/github.com/grafana/sobek/runtime.go | 4 +- vendor/modules.txt | 4 +- 16 files changed, 459 insertions(+), 35 deletions(-) diff --git a/go.mod b/go.mod index 90b48afd158..c4a6c6c7ce8 100644 --- a/go.mod +++ b/go.mod @@ -69,13 +69,13 @@ require ( github.com/chromedp/sysutil v1.0.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect - github.com/dlclark/regexp2 v1.9.0 // indirect + github.com/dlclark/regexp2 v1.11.4 // indirect github.com/fsnotify/fsnotify v1.5.4 // indirect github.com/go-logr/logr v1.4.2 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/google/pprof v0.0.0-20230728192033-2ba5b33183c6 // indirect github.com/google/uuid v1.6.0 // indirect - github.com/grafana/sobek v0.0.0-20240808084414-f7ac208544fe + github.com/grafana/sobek v0.0.0-20240816075701-fd55381ddfc3 github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.1 // indirect github.com/inconshreveable/mousetrap v1.0.0 // indirect github.com/josharian/intern v1.0.0 // indirect diff --git a/go.sum b/go.sum index ad8618840ff..e475609b775 100644 --- a/go.sum +++ b/go.sum @@ -40,8 +40,8 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= -github.com/dlclark/regexp2 v1.9.0 h1:pTK/l/3qYIKaRXuHnEnIf7Y5NxfRPfpb7dis6/gdlVI= -github.com/dlclark/regexp2 v1.9.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= +github.com/dlclark/regexp2 v1.11.4 h1:rPYF9/LECdNymJufQKmri9gV604RvvABwgOA8un7yAo= +github.com/dlclark/regexp2 v1.11.4/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= github.com/dop251/goja v0.0.0-20240610225006-393f6d42497b h1:fMKDnOAKCGXSZBphY/ilLtu7cmwMnjqE+xJxUkfkpCY= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= @@ -82,8 +82,8 @@ github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY= github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY= -github.com/grafana/sobek v0.0.0-20240808084414-f7ac208544fe h1:adA30lZ417BTZBJfuoBCjuHhM6SrcWQNbThi8g+c2Hs= -github.com/grafana/sobek v0.0.0-20240808084414-f7ac208544fe/go.mod h1:tUEHKWaMrxFGrMgjeAH85OEceCGQiSl6a/6Wckj/Vf4= +github.com/grafana/sobek v0.0.0-20240816075701-fd55381ddfc3 h1:mJ1DN6EDA5MlRtcspUjVTsfINUVJMd4Yw70RdFoKN8E= +github.com/grafana/sobek v0.0.0-20240816075701-fd55381ddfc3/go.mod h1:14YTHWUwjApKs5kzRn+4akwbvPMRsXEmjfozc5OmT0I= github.com/grafana/xk6-browser v1.7.0 h1:Rip0st43EmzV37DFO2Gt7sXO4TTRM4g9wGMwBvVb67c= github.com/grafana/xk6-browser v1.7.0/go.mod h1:TNngUsbmV3I5NDVklGxjpAR2znEjYEsBtHQirGw8nAI= github.com/grafana/xk6-dashboard v0.7.5 h1:TcILyffT/Ea/XD7xG1jMA5lwtusOPRbEQsQDHmO30Mk= diff --git a/vendor/github.com/dlclark/regexp2/README.md b/vendor/github.com/dlclark/regexp2/README.md index f3d1bd92b63..9cbc1d8d0aa 100644 --- a/vendor/github.com/dlclark/regexp2/README.md +++ b/vendor/github.com/dlclark/regexp2/README.md @@ -4,10 +4,17 @@ Regexp2 is a feature-rich RegExp engine for Go. It doesn't have constant time g ## Basis of the engine The engine is ported from the .NET framework's System.Text.RegularExpressions.Regex engine. That engine was open sourced in 2015 under the MIT license. There are some fundamental differences between .NET strings and Go strings that required a bit of borrowing from the Go framework regex engine as well. I cleaned up a couple of the dirtier bits during the port (regexcharclass.cs was terrible), but the parse tree, code emmitted, and therefore patterns matched should be identical. +## New Code Generation +For extra performance use `regexp2` with [`regexp2cg`](https://github.com/dlclark/regexp2cg). It is a code generation utility for `regexp2` and you can likely improve your regexp runtime performance by 3-10x in hot code paths. As always you should benchmark your specifics to confirm the results. Give it a try! + ## Installing This is a go-gettable library, so install is easy: - go get github.com/dlclark/regexp2/... + go get github.com/dlclark/regexp2 + +To use the new Code Generation (while it's in beta) you'll need to use the `code_gen` branch: + + go get github.com/dlclark/regexp2@code_gen ## Usage Usage is similar to the Go `regexp` package. Just like in `regexp`, you start by converting a regex into a state machine via the `Compile` or `MustCompile` methods. They ultimately do the same thing, but `MustCompile` will panic if the regex is invalid. You can then use the provided `Regexp` struct to find matches repeatedly. A `Regexp` struct is safe to use across goroutines. diff --git a/vendor/github.com/dlclark/regexp2/match.go b/vendor/github.com/dlclark/regexp2/match.go index 1871cffe303..759cf8ccf48 100644 --- a/vendor/github.com/dlclark/regexp2/match.go +++ b/vendor/github.com/dlclark/regexp2/match.go @@ -6,8 +6,9 @@ import ( ) // Match is a single regex result match that contains groups and repeated captures -// -Groups -// -Capture +// +// -Groups +// -Capture type Match struct { Group //embeded group 0 @@ -43,10 +44,10 @@ type Group struct { type Capture struct { // the original string text []rune - // the position in the original string where the first character of - // captured substring was found. + // Index is the position in the underlying rune slice where the first character of + // captured substring was found. Even if you pass in a string this will be in Runes. Index int - // the length of the captured substring. + // Length is the number of runes in the captured substring. Length int } @@ -187,7 +188,8 @@ func (m *Match) addMatch(c, start, l int) { } // Nonpublic builder: Add a capture to balance the specified group. This is used by the -// balanced match construct. (?...) +// +// balanced match construct. (?...) // // If there were no such thing as backtracking, this would be as simple as calling RemoveMatch(c). // However, since we have backtracking, we need to keep track of everything. diff --git a/vendor/github.com/dlclark/regexp2/regexp.go b/vendor/github.com/dlclark/regexp2/regexp.go index c8f9e6b0001..a7ddbaf3587 100644 --- a/vendor/github.com/dlclark/regexp2/regexp.go +++ b/vendor/github.com/dlclark/regexp2/regexp.go @@ -18,8 +18,12 @@ import ( "github.com/dlclark/regexp2/syntax" ) -// Default timeout used when running regexp matches -- "forever" -var DefaultMatchTimeout = time.Duration(math.MaxInt64) +var ( + // DefaultMatchTimeout used when running regexp matches -- "forever" + DefaultMatchTimeout = time.Duration(math.MaxInt64) + // DefaultUnmarshalOptions used when unmarshaling a regex from text + DefaultUnmarshalOptions = None +) // Regexp is the representation of a compiled regular expression. // A Regexp is safe for concurrent use by multiple goroutines. @@ -43,7 +47,7 @@ type Regexp struct { code *syntax.Code // compiled program // cache of machines for running regexp - muRun sync.Mutex + muRun *sync.Mutex runner []*runner } @@ -72,6 +76,7 @@ func Compile(expr string, opt RegexOptions) (*Regexp, error) { capsize: code.Capsize, code: code, MatchTimeout: DefaultMatchTimeout, + muRun: &sync.Mutex{}, }, nil } @@ -371,3 +376,20 @@ func (re *Regexp) GroupNumberFromName(name string) int { return -1 } + +// MarshalText implements [encoding.TextMarshaler]. The output +// matches that of calling the [Regexp.String] method. +func (re *Regexp) MarshalText() ([]byte, error) { + return []byte(re.String()), nil +} + +// UnmarshalText implements [encoding.TextUnmarshaler] by calling +// [Compile] on the encoded value. +func (re *Regexp) UnmarshalText(text []byte) error { + newRE, err := Compile(string(text), DefaultUnmarshalOptions) + if err != nil { + return err + } + *re = *newRE + return nil +} diff --git a/vendor/github.com/dlclark/regexp2/runner.go b/vendor/github.com/dlclark/regexp2/runner.go index 494dcef9f38..56759f1474e 100644 --- a/vendor/github.com/dlclark/regexp2/runner.go +++ b/vendor/github.com/dlclark/regexp2/runner.go @@ -1604,6 +1604,10 @@ func (re *Regexp) getRunner() *runner { // run using re. (The cache empties when re gets garbage collected.) func (re *Regexp) putRunner(r *runner) { re.muRun.Lock() + r.runtext = nil + if r.runmatch != nil { + r.runmatch.text = nil + } re.runner = append(re.runner, r) re.muRun.Unlock() } diff --git a/vendor/github.com/dlclark/regexp2/syntax/parser.go b/vendor/github.com/dlclark/regexp2/syntax/parser.go index 9dc6e313023..4ff0aaa8363 100644 --- a/vendor/github.com/dlclark/regexp2/syntax/parser.go +++ b/vendor/github.com/dlclark/regexp2/syntax/parser.go @@ -553,10 +553,10 @@ func (p *parser) scanRegex() (*regexNode, error) { } case '.': - if p.useOptionE() { - p.addUnitSet(ECMAAnyClass()) - } else if p.useOptionS() { + if p.useOptionS() { p.addUnitSet(AnyClass()) + } else if p.useOptionE() { + p.addUnitSet(ECMAAnyClass()) } else { p.addUnitNotone('\n') } @@ -1311,6 +1311,17 @@ func (p *parser) scanBasicBackslash(scanOnly bool) (*regexNode, error) { // Scans X for \p{X} or \P{X} func (p *parser) parseProperty() (string, error) { + // RE2 and PCRE supports \pX syntax (no {} and only 1 letter unicode cats supported) + // since this is purely additive syntax it's not behind a flag + if p.charsRight() >= 1 && p.rightChar(0) != '{' { + ch := string(p.moveRightGetChar()) + // check if it's a valid cat + if !isValidUnicodeCat(ch) { + return "", p.getErr(ErrUnknownSlashP, ch) + } + return ch, nil + } + if p.charsRight() < 3 { return "", p.getErr(ErrIncompleteSlashP) } @@ -1427,7 +1438,7 @@ func (p *parser) scanCapname() string { return string(p.pattern[startpos:p.textpos()]) } -//Scans contents of [] (not including []'s), and converts to a set. +// Scans contents of [] (not including []'s), and converts to a set. func (p *parser) scanCharSet(caseInsensitive, scanOnly bool) (*CharSet, error) { ch := '\x00' chPrev := '\x00' diff --git a/vendor/github.com/grafana/sobek/builtin_array.go b/vendor/github.com/grafana/sobek/builtin_array.go index 7121bfa7c4a..d421637330a 100644 --- a/vendor/github.com/grafana/sobek/builtin_array.go +++ b/vendor/github.com/grafana/sobek/builtin_array.go @@ -1224,6 +1224,177 @@ func (r *Runtime) arrayproto_flatMap(call FunctionCall) Value { return a } +func (r *Runtime) arrayproto_with(call FunctionCall) Value { + o := call.This.ToObject(r) + relativeIndex := call.Argument(0).ToInteger() + value := call.Argument(1) + length := toLength(o.self.getStr("length", nil)) + + actualIndex := int64(0) + if relativeIndex >= 0 { + actualIndex = relativeIndex + } else { + actualIndex = length + relativeIndex + } + if actualIndex >= length || actualIndex < 0 { + panic(r.newError(r.getRangeError(), "Invalid index %s", call.Argument(0).String())) + } + + if src := r.checkStdArrayObj(o); src != nil { + a := make([]Value, 0, length) + for k := int64(0); k < length; k++ { + pk := valueInt(k) + var fromValue Value + if k == actualIndex { + fromValue = value + } else { + fromValue = src.values[pk] + } + a = append(a, fromValue) + } + return r.newArrayValues(a) + } else { + a := r.newArrayLength(length) + for k := int64(0); k < length; k++ { + pk := valueInt(k) + var fromValue Value + if k == actualIndex { + fromValue = value + } else { + fromValue = o.self.getIdx(pk, nil) + } + createDataPropertyOrThrow(a, pk, fromValue) + } + return a + } +} + +func (r *Runtime) arrayproto_toReversed(call FunctionCall) Value { + o := call.This.ToObject(r) + length := toLength(o.self.getStr("length", nil)) + + if src := r.checkStdArrayObj(o); src != nil { + a := make([]Value, 0, length) + for k := int64(0); k < length; k++ { + from := valueInt(length - k - 1) + fromValue := src.values[from] + a = append(a, fromValue) + } + return r.newArrayValues(a) + } else { + a := r.newArrayLength(length) + for k := int64(0); k < length; k++ { + pk := valueInt(k) + from := valueInt(length - k - 1) + fromValue := o.self.getIdx(from, nil) + createDataPropertyOrThrow(a, pk, fromValue) + } + return a + } +} + +func (r *Runtime) arrayproto_toSorted(call FunctionCall) Value { + var compareFn func(FunctionCall) Value + arg := call.Argument(0) + if arg != _undefined { + if arg, ok := arg.(*Object); ok { + compareFn, _ = arg.self.assertCallable() + } + if compareFn == nil { + panic(r.NewTypeError("The comparison function must be either a function or undefined")) + } + } + + o := call.This.ToObject(r) + length := toLength(o.self.getStr("length", nil)) + if length >= math.MaxUint32 { + panic(r.newError(r.getRangeError(), "Invalid array length")) + } + var a []Value + + if src := r.checkStdArrayObj(o); src != nil { + a = make([]Value, length) + copy(a, src.values) + } else { + a = make([]Value, 0, length) + for i := int64(0); i < length; i++ { + idx := valueInt(i) + a = append(a, nilSafe(o.self.getIdx(idx, nil))) + } + } + + ar := r.newArrayValues(a) + ctx := arraySortCtx{ + obj: ar.self, + compare: compareFn, + } + + sort.Stable(&ctx) + return ar +} + +func (r *Runtime) arrayproto_toSpliced(call FunctionCall) Value { + o := call.This.ToObject(r) + length := toLength(o.self.getStr("length", nil)) + actualStart := relToIdx(call.Argument(0).ToInteger(), length) + var actualSkipCount int64 + if len(call.Arguments) == 1 { + actualSkipCount = length - actualStart + } else if len(call.Arguments) > 1 { + actualSkipCount = min(max(call.Argument(1).ToInteger(), 0), length-actualStart) + } + itemCount := max(int64(len(call.Arguments)-2), 0) + newLength := length - actualSkipCount + itemCount + if newLength >= maxInt { + panic(r.NewTypeError("Invalid array length")) + } + + if src := r.checkStdArrayObj(o); src != nil { + var values []Value + if itemCount == actualSkipCount { + values = make([]Value, len(src.values)) + copy(values, src.values) + } else { + values = make([]Value, newLength) + copy(values, src.values[:actualStart]) + copy(values[actualStart+itemCount:], src.values[actualStart+actualSkipCount:]) + } + if itemCount > 0 { + copy(values[actualStart:], call.Arguments[2:]) + } + return r.newArrayValues(values) + } else { + a := r.newArrayLength(newLength) + var i int64 + rl := actualStart + actualSkipCount + + for i < actualStart { + pi := valueInt(i) + iValue := nilSafe(o.self.getIdx(pi, nil)) + createDataPropertyOrThrow(a, pi, iValue) + i++ + } + + if itemCount > 0 { + for _, item := range call.Arguments[2:] { + createDataPropertyOrThrow(a, valueInt(i), nilSafe(item)) + i++ + } + } + + for i < newLength { + pi := valueInt(i) + from := valueInt(rl) + fromValue := nilSafe(o.self.getIdx(from, nil)) + createDataPropertyOrThrow(a, pi, fromValue) + i++ + rl++ + } + + return a + } +} + func (r *Runtime) checkStdArrayObj(obj *Object) *arrayObject { if arr, ok := obj.self.(*arrayObject); ok && arr.propValueCount == 0 && @@ -1442,6 +1613,10 @@ func createArrayProtoTemplate() *objectTemplate { t.putStr("toLocaleString", func(r *Runtime) Value { return r.methodProp(r.arrayproto_toLocaleString, "toLocaleString", 0) }) t.putStr("toString", func(r *Runtime) Value { return valueProp(r.getArrayToString(), true, false, true) }) t.putStr("unshift", func(r *Runtime) Value { return r.methodProp(r.arrayproto_unshift, "unshift", 1) }) + t.putStr("with", func(r *Runtime) Value { return r.methodProp(r.arrayproto_with, "with", 2) }) + t.putStr("toReversed", func(r *Runtime) Value { return r.methodProp(r.arrayproto_toReversed, "toReversed", 0) }) + t.putStr("toSorted", func(r *Runtime) Value { return r.methodProp(r.arrayproto_toSorted, "toSorted", 1) }) + t.putStr("toSpliced", func(r *Runtime) Value { return r.methodProp(r.arrayproto_toSpliced, "toSpliced", 2) }) t.putStr("values", func(r *Runtime) Value { return valueProp(r.getArrayValues(), true, false, true) }) t.putSym(SymIterator, func(r *Runtime) Value { return valueProp(r.getArrayValues(), true, false, true) }) @@ -1461,6 +1636,9 @@ func createArrayProtoTemplate() *objectTemplate { bl.setOwnStr("values", valueTrue, true) bl.setOwnStr("groupBy", valueTrue, true) bl.setOwnStr("groupByToMap", valueTrue, true) + bl.setOwnStr("toReversed", valueTrue, true) + bl.setOwnStr("toSorted", valueTrue, true) + bl.setOwnStr("toSpliced", valueTrue, true) return valueProp(bl.val, false, false, true) }) diff --git a/vendor/github.com/grafana/sobek/builtin_error.go b/vendor/github.com/grafana/sobek/builtin_error.go index 99532542cae..132fae6d28b 100644 --- a/vendor/github.com/grafana/sobek/builtin_error.go +++ b/vendor/github.com/grafana/sobek/builtin_error.go @@ -122,7 +122,19 @@ func (r *Runtime) newErrorObject(proto *Object, class string) *errorObject { func (r *Runtime) builtin_Error(args []Value, proto *Object) *Object { obj := r.newErrorObject(proto, classError) if len(args) > 0 && args[0] != _undefined { - obj._putProp("message", args[0], true, false, true) + obj._putProp("message", args[0].ToString(), true, false, true) + } + if len(args) > 1 && args[1] != _undefined { + if options, ok := args[1].(*Object); ok { + if options.hasProperty(asciiString("cause")) { + obj.defineOwnPropertyStr("cause", PropertyDescriptor{ + Writable: FLAG_TRUE, + Enumerable: FLAG_FALSE, + Configurable: FLAG_TRUE, + Value: options.Get("cause"), + }, true) + } + } } return obj.val } @@ -138,6 +150,19 @@ func (r *Runtime) builtin_AggregateError(args []Value, proto *Object) *Object { } obj._putProp("errors", r.newArrayValues(errors), true, false, true) + if len(args) > 2 && args[2] != _undefined { + if options, ok := args[2].(*Object); ok { + if options.hasProperty(asciiString("cause")) { + obj.defineOwnPropertyStr("cause", PropertyDescriptor{ + Writable: FLAG_TRUE, + Enumerable: FLAG_FALSE, + Configurable: FLAG_TRUE, + Value: options.Get("cause"), + }, true) + } + } + } + return obj.val } diff --git a/vendor/github.com/grafana/sobek/builtin_regexp.go b/vendor/github.com/grafana/sobek/builtin_regexp.go index a606da0ce0e..5b4ce71cfde 100644 --- a/vendor/github.com/grafana/sobek/builtin_regexp.go +++ b/vendor/github.com/grafana/sobek/builtin_regexp.go @@ -183,7 +183,7 @@ func compileRegexpFromValueString(patternStr String, flags string) (*regexpPatte } func compileRegexp(patternStr, flags string) (p *regexpPattern, err error) { - var global, ignoreCase, multiline, sticky, unicode bool + var global, ignoreCase, multiline, dotAll, sticky, unicode bool var wrapper *regexpWrapper var wrapper2 *regexp2Wrapper @@ -205,6 +205,12 @@ func compileRegexp(patternStr, flags string) (p *regexpPattern, err error) { return } multiline = true + case 's': + if dotAll { + invalidFlags() + return + } + dotAll = true case 'i': if ignoreCase { invalidFlags() @@ -235,12 +241,15 @@ func compileRegexp(patternStr, flags string) (p *regexpPattern, err error) { patternStr = convertRegexpToUtf16(patternStr) } - re2Str, err1 := parser.TransformRegExp(patternStr) + re2Str, err1 := parser.TransformRegExp(patternStr, dotAll) if err1 == nil { re2flags := "" if multiline { re2flags += "m" } + if dotAll { + re2flags += "s" + } if ignoreCase { re2flags += "i" } @@ -259,7 +268,7 @@ func compileRegexp(patternStr, flags string) (p *regexpPattern, err error) { err = err1 return } - wrapper2, err = compileRegexp2(patternStr, multiline, ignoreCase) + wrapper2, err = compileRegexp2(patternStr, multiline, dotAll, ignoreCase) if err != nil { err = fmt.Errorf("Invalid regular expression (regexp2): %s (%v)", patternStr, err) return @@ -273,6 +282,7 @@ func compileRegexp(patternStr, flags string) (p *regexpPattern, err error) { global: global, ignoreCase: ignoreCase, multiline: multiline, + dotAll: dotAll, sticky: sticky, unicode: unicode, } @@ -431,6 +441,9 @@ func (r *Runtime) regexpproto_toString(call FunctionCall) Value { if this.pattern.multiline { sb.WriteRune('m') } + if this.pattern.dotAll { + sb.WriteRune('s') + } if this.pattern.unicode { sb.WriteRune('u') } @@ -538,6 +551,20 @@ func (r *Runtime) regexpproto_getMultiline(call FunctionCall) Value { } } +func (r *Runtime) regexpproto_getDotAll(call FunctionCall) Value { + if this, ok := r.toObject(call.This).self.(*regexpObject); ok { + if this.pattern.dotAll { + return valueTrue + } else { + return valueFalse + } + } else if call.This == r.global.RegExpPrototype { + return _undefined + } else { + panic(r.NewTypeError("Method RegExp.prototype.dotAll getter called on incompatible receiver %s", r.objectproto_toString(FunctionCall{This: call.This}))) + } +} + func (r *Runtime) regexpproto_getIgnoreCase(call FunctionCall) Value { if this, ok := r.toObject(call.This).self.(*regexpObject); ok { if this.pattern.ignoreCase { @@ -581,7 +608,7 @@ func (r *Runtime) regexpproto_getSticky(call FunctionCall) Value { } func (r *Runtime) regexpproto_getFlags(call FunctionCall) Value { - var global, ignoreCase, multiline, sticky, unicode bool + var global, ignoreCase, multiline, dotAll, sticky, unicode bool thisObj := r.toObject(call.This) size := 0 @@ -603,6 +630,12 @@ func (r *Runtime) regexpproto_getFlags(call FunctionCall) Value { size++ } } + if v := thisObj.self.getStr("dotAll", nil); v != nil { + dotAll = v.ToBoolean() + if dotAll { + size++ + } + } if v := thisObj.self.getStr("sticky", nil); v != nil { sticky = v.ToBoolean() if sticky { @@ -627,6 +660,9 @@ func (r *Runtime) regexpproto_getFlags(call FunctionCall) Value { if multiline { sb.WriteByte('m') } + if dotAll { + sb.WriteByte('s') + } if unicode { sb.WriteByte('u') } @@ -1272,6 +1308,11 @@ func (r *Runtime) getRegExpPrototype() *Object { getterFunc: r.newNativeFunc(r.regexpproto_getMultiline, "get multiline", 0), accessor: true, }, false) + o.setOwnStr("dotAll", &valueProperty{ + configurable: true, + getterFunc: r.newNativeFunc(r.regexpproto_getDotAll, "get dotAll", 0), + accessor: true, + }, false) o.setOwnStr("ignoreCase", &valueProperty{ configurable: true, getterFunc: r.newNativeFunc(r.regexpproto_getIgnoreCase, "get ignoreCase", 0), diff --git a/vendor/github.com/grafana/sobek/builtin_typedarrays.go b/vendor/github.com/grafana/sobek/builtin_typedarrays.go index 7ad737fceb0..1cdb838c0e8 100644 --- a/vendor/github.com/grafana/sobek/builtin_typedarrays.go +++ b/vendor/github.com/grafana/sobek/builtin_typedarrays.go @@ -1153,6 +1153,95 @@ func (r *Runtime) typedArrayProto_toStringTag(call FunctionCall) Value { return _undefined } +func (r *Runtime) typedArrayProto_with(call FunctionCall) Value { + o := call.This.ToObject(r) + ta, ok := o.self.(*typedArrayObject) + if !ok { + panic(r.NewTypeError("%s is not a valid TypedArray", r.objectproto_toString(FunctionCall{This: call.This}))) + } + length := ta.length + relativeIndex := call.Argument(0).ToInteger() + var actualIndex int + + if relativeIndex >= 0 { + actualIndex = toIntStrict(relativeIndex) + } else { + actualIndex = toIntStrict(int64(length) + relativeIndex) + } + if !ta.isValidIntegerIndex(actualIndex) { + panic(r.newError(r.getRangeError(), "Invalid typed array index")) + } + + // TODO BigInt + // 7. If O.[[ContentType]] is BIGINT, let numericValue be ? ToBigInt(value). + // 8. Else, let numericValue be ? ToNumber(value). + numericValue := call.Argument(1).ToNumber() + + a := r.typedArrayCreate(ta.defaultCtor, intToValue(int64(length))) + for k := 0; k < length; k++ { + var fromValue Value + if k == actualIndex { + fromValue = numericValue + } else { + fromValue = ta.typedArray.get(ta.offset + k) + } + a.typedArray.set(ta.offset+k, fromValue) + } + return a.val +} + +func (r *Runtime) typedArrayProto_toReversed(call FunctionCall) Value { + o := call.This.ToObject(r) + ta, ok := o.self.(*typedArrayObject) + if !ok { + panic(r.NewTypeError("%s is not a valid TypedArray", r.objectproto_toString(FunctionCall{This: call.This}))) + } + length := ta.length + + a := r.typedArrayCreate(ta.defaultCtor, intToValue(int64(length))) + + for k := 0; k < length; k++ { + from := length - k - 1 + fromValue := ta.typedArray.get(ta.offset + from) + a.typedArray.set(ta.offset+k, fromValue) + } + + return a.val +} + +func (r *Runtime) typedArrayProto_toSorted(call FunctionCall) Value { + o := call.This.ToObject(r) + ta, ok := o.self.(*typedArrayObject) + if !ok { + panic(r.NewTypeError("%s is not a valid TypedArray", r.objectproto_toString(FunctionCall{This: call.This}))) + } + + var compareFn func(FunctionCall) Value + arg := call.Argument(0) + if arg != _undefined { + if arg, ok := arg.(*Object); ok { + compareFn, _ = arg.self.assertCallable() + } + if compareFn == nil { + panic(r.NewTypeError("The comparison function must be either a function or undefined")) + } + } + + length := ta.length + + a := r.typedArrayCreate(ta.defaultCtor, intToValue(int64(length))) + copy(a.viewedArrayBuf.data, ta.viewedArrayBuf.data) + + ctx := typedArraySortCtx{ + ta: a, + compare: compareFn, + } + + sort.Stable(&ctx) + + return a.val +} + func (r *Runtime) newTypedArray([]Value, *Object) *Object { panic(r.NewTypeError("Abstract class TypedArray not directly constructable")) } @@ -1543,6 +1632,9 @@ func createTypedArrayProtoTemplate() *objectTemplate { t.putStr("sort", func(r *Runtime) Value { return r.methodProp(r.typedArrayProto_sort, "sort", 1) }) t.putStr("subarray", func(r *Runtime) Value { return r.methodProp(r.typedArrayProto_subarray, "subarray", 2) }) t.putStr("toLocaleString", func(r *Runtime) Value { return r.methodProp(r.typedArrayProto_toLocaleString, "toLocaleString", 0) }) + t.putStr("with", func(r *Runtime) Value { return r.methodProp(r.typedArrayProto_with, "with", 2) }) + t.putStr("toReversed", func(r *Runtime) Value { return r.methodProp(r.typedArrayProto_toReversed, "toReversed", 0) }) + t.putStr("toSorted", func(r *Runtime) Value { return r.methodProp(r.typedArrayProto_toSorted, "toSorted", 1) }) t.putStr("toString", func(r *Runtime) Value { return valueProp(r.getArrayToString(), true, false, true) }) t.putStr("values", func(r *Runtime) Value { return valueProp(r.getTypedArrayValues(), true, false, true) }) diff --git a/vendor/github.com/grafana/sobek/object_gomap_reflect.go b/vendor/github.com/grafana/sobek/object_gomap_reflect.go index bf8b41a6bf2..555023417a6 100644 --- a/vendor/github.com/grafana/sobek/object_gomap_reflect.go +++ b/vendor/github.com/grafana/sobek/object_gomap_reflect.go @@ -1,6 +1,7 @@ package sobek import ( + "fmt" "reflect" "github.com/grafana/sobek/unistring" @@ -114,7 +115,7 @@ func (o *objectGoMapReflect) _put(key reflect.Value, val Value, throw bool) bool } o.fieldsValue.SetMapIndex(key, v) } else { - o.val.runtime.typeErrorResult(throw, "Cannot set property %s, object is not extensible", key.String()) + o.val.runtime.typeErrorResult(throw, "Cannot set property %v, object is not extensible", key) return false } return true @@ -241,7 +242,7 @@ func (i *gomapReflectPropIter) next() (propIterItem, iterNextFunc) { v := i.o.fieldsValue.MapIndex(key) i.idx++ if v.IsValid() { - return propIterItem{name: newStringValue(key.String()), enumerable: _ENUM_TRUE}, i.next + return propIterItem{name: i.o.keyToString(key), enumerable: _ENUM_TRUE}, i.next } } @@ -258,8 +259,36 @@ func (o *objectGoMapReflect) iterateStringKeys() iterNextFunc { func (o *objectGoMapReflect) stringKeys(_ bool, accum []Value) []Value { // all own keys are enumerable for _, key := range o.fieldsValue.MapKeys() { - accum = append(accum, newStringValue(key.String())) + accum = append(accum, o.keyToString(key)) } return accum } + +func (*objectGoMapReflect) keyToString(key reflect.Value) String { + kind := key.Kind() + + if kind == reflect.String { + return newStringValue(key.String()) + } + + str := fmt.Sprintf("%v", key) + + switch kind { + case reflect.Int, + reflect.Int8, + reflect.Int16, + reflect.Int32, + reflect.Int64, + reflect.Uint, + reflect.Uint8, + reflect.Uint16, + reflect.Uint32, + reflect.Uint64, + reflect.Float32, + reflect.Float64: + return asciiString(str) + default: + return newStringValue(str) + } +} diff --git a/vendor/github.com/grafana/sobek/parser/regexp.go b/vendor/github.com/grafana/sobek/parser/regexp.go index 2dbd0e1912d..72bb3c7fecb 100644 --- a/vendor/github.com/grafana/sobek/parser/regexp.go +++ b/vendor/github.com/grafana/sobek/parser/regexp.go @@ -40,6 +40,8 @@ type _RegExp_parser struct { goRegexp strings.Builder passOffset int + + dotAll bool // Enable dotAll mode } // TransformRegExp transforms a JavaScript pattern into a Go "regexp" pattern. @@ -55,7 +57,7 @@ type _RegExp_parser struct { // // If the pattern is invalid (not valid even in JavaScript), then this function // returns an empty string and a generic error. -func TransformRegExp(pattern string) (transformed string, err error) { +func TransformRegExp(pattern string, dotAll bool) (transformed string, err error) { if pattern == "" { return "", nil @@ -64,6 +66,7 @@ func TransformRegExp(pattern string) (transformed string, err error) { parser := _RegExp_parser{ str: pattern, length: len(pattern), + dotAll: dotAll, } err = parser.parse() if err != nil { @@ -147,6 +150,10 @@ func (self *_RegExp_parser) scan() { self.error(true, "Unmatched ')'") return case '.': + if self.dotAll { + self.pass() + break + } self.writeString(Re2Dot) self.read() default: diff --git a/vendor/github.com/grafana/sobek/regexp.go b/vendor/github.com/grafana/sobek/regexp.go index bdc15a1cb97..3da1fc4add7 100644 --- a/vendor/github.com/grafana/sobek/regexp.go +++ b/vendor/github.com/grafana/sobek/regexp.go @@ -61,17 +61,20 @@ func (rd *arrayRuneReader) ReadRune() (r rune, size int, err error) { type regexpPattern struct { src string - global, ignoreCase, multiline, sticky, unicode bool + global, ignoreCase, multiline, dotAll, sticky, unicode bool regexpWrapper *regexpWrapper regexp2Wrapper *regexp2Wrapper } -func compileRegexp2(src string, multiline, ignoreCase bool) (*regexp2Wrapper, error) { +func compileRegexp2(src string, multiline, dotAll, ignoreCase bool) (*regexp2Wrapper, error) { var opts regexp2.RegexOptions = regexp2.ECMAScript if multiline { opts |= regexp2.Multiline } + if dotAll { + opts |= regexp2.Singleline + } if ignoreCase { opts |= regexp2.IgnoreCase } @@ -87,7 +90,7 @@ func (p *regexpPattern) createRegexp2() { if p.regexp2Wrapper != nil { return } - rx, err := compileRegexp2(p.src, p.multiline, p.ignoreCase) + rx, err := compileRegexp2(p.src, p.multiline, p.dotAll, p.ignoreCase) if err != nil { // At this point the regexp should have been successfully converted to re2, if it fails now, it's a bug. panic(err) @@ -175,6 +178,7 @@ func (p *regexpPattern) clone() *regexpPattern { global: p.global, ignoreCase: p.ignoreCase, multiline: p.multiline, + dotAll: p.dotAll, sticky: p.sticky, unicode: p.unicode, } diff --git a/vendor/github.com/grafana/sobek/runtime.go b/vendor/github.com/grafana/sobek/runtime.go index 7866eedde6e..a4506ed30cd 100644 --- a/vendor/github.com/grafana/sobek/runtime.go +++ b/vendor/github.com/grafana/sobek/runtime.go @@ -1729,7 +1729,9 @@ Note that Value.Export() for a `Date` value returns time.Time in local timezone. # Maps -Maps with string or integer key type are converted into host objects that largely behave like a JavaScript Object. +Maps with string, integer, or float key types are converted into host objects that largely behave like a JavaScript Object. +One noticeable difference is that the key order is not stable, as with maps in Go. +Keys are converted to strings following the fmt.Sprintf("%v") convention. # Maps with methods diff --git a/vendor/modules.txt b/vendor/modules.txt index f5dfa1b6a68..b0f54a0bf47 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -101,7 +101,7 @@ github.com/davecgh/go-spew/spew # github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f ## explicit github.com/dgryski/go-rendezvous -# github.com/dlclark/regexp2 v1.9.0 +# github.com/dlclark/regexp2 v1.11.4 ## explicit; go 1.13 github.com/dlclark/regexp2 github.com/dlclark/regexp2/syntax @@ -163,7 +163,7 @@ github.com/google/uuid # github.com/gorilla/websocket v1.5.1 ## explicit; go 1.20 github.com/gorilla/websocket -# github.com/grafana/sobek v0.0.0-20240808084414-f7ac208544fe +# github.com/grafana/sobek v0.0.0-20240816075701-fd55381ddfc3 ## explicit; go 1.20 github.com/grafana/sobek github.com/grafana/sobek/ast