diff --git a/go.mod b/go.mod index 3ce6605..bcefcf5 100644 --- a/go.mod +++ b/go.mod @@ -1,14 +1,3 @@ module github.com/danielgtaylor/mexpr go 1.18 - -require ( - github.com/stretchr/testify v1.7.0 - golang.org/x/exp v0.0.0-20230108222341-4b8118a2686a -) - -require ( - github.com/davecgh/go-spew v1.1.0 // indirect - github.com/pmezard/go-difflib v1.0.0 // indirect - gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c // indirect -) diff --git a/go.sum b/go.sum index d522a88..e69de29 100644 --- a/go.sum +++ b/go.sum @@ -1,13 +0,0 @@ -github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= -github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -golang.org/x/exp v0.0.0-20230108222341-4b8118a2686a h1:tlXy25amD5A7gOfbXdqCGN5k8ESEed/Ee1E5RcrYnqU= -golang.org/x/exp v0.0.0-20230108222341-4b8118a2686a/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/interpreter.go b/interpreter.go index 03fc688..c26c5bc 100644 --- a/interpreter.go +++ b/interpreter.go @@ -3,8 +3,6 @@ package mexpr import ( "math" "strings" - - "golang.org/x/exp/maps" ) // InterpreterOption passes configuration settings when creating a new @@ -21,6 +19,16 @@ const ( UnquotedStrings ) +// mapValues returns the values of the map m. +// The values will be in an indeterminate order. +func mapValues[M ~map[K]V, K comparable, V any](m M) []V { + r := make([]V, 0, len(m)) + for _, v := range m { + r = append(r, v) + } + return r +} + // checkBounds returns an error if the index is out of bounds. func checkBounds(ast *Node, input any, idx int) Error { if v, ok := input.([]any); ok { @@ -437,7 +445,7 @@ func (i *interpreter) run(ast *Node, value any) (any, Error) { return nil, nil } if m, ok := resultLeft.(map[string]any); ok { - resultLeft = maps.Values(m) + resultLeft = mapValues(m) } if m, ok := resultLeft.(map[any]any); ok { values := make([]any, 0, len(m)) diff --git a/interpreter_test.go b/interpreter_test.go index 401646b..9d243bd 100644 --- a/interpreter_test.go +++ b/interpreter_test.go @@ -2,10 +2,9 @@ package mexpr import ( "encoding/json" + "reflect" "strings" "testing" - - "github.com/stretchr/testify/assert" ) func TestInterpreter(t *testing.T) { @@ -224,7 +223,9 @@ func TestInterpreter(t *testing.T) { if err != nil { t.Fatal(err.Pretty(tc.expr)) } - assert.Equal(t, tc.output, result) + if !reflect.DeepEqual(tc.output, result) { + t.Fatalf("expected %v but found %v", tc.output, result) + } } }) } @@ -283,7 +284,9 @@ func Benchmark(b *testing.B) { ast, _ := Parse(bm.mexpr, input) r, _ = Run(ast, input, StrictMode) } - assert.Equal(b, bm.result, r) + if !reflect.DeepEqual(bm.result, r) { + b.Fatalf("expected %v but found %v", bm.result, r) + } }) // b.Run(" expr-"+bm.name+"-slow", func(b *testing.B) { @@ -299,13 +302,17 @@ func Benchmark(b *testing.B) { b.Run("mexpr-"+bm.name+"-cached", func(b *testing.B) { b.ReportAllocs() ast, err := Parse(bm.mexpr, input) - assert.NoError(b, err) + if err != nil { + b.Fatal(err) + } i := NewInterpreter(ast) b.ResetTimer() for n := 0; n < b.N; n++ { r, _ = i.Run(input) } - assert.Equal(b, bm.result, r) + if !reflect.DeepEqual(bm.result, r) { + b.Fatalf("expected %v but found %v", bm.result, r) + } }) // b.Run(" expr-"+bm.name+"-cached", func(b *testing.B) { diff --git a/typecheck.go b/typecheck.go index a22782a..fe75a7a 100644 --- a/typecheck.go +++ b/typecheck.go @@ -4,8 +4,6 @@ import ( "fmt" "sort" "strings" - - "golang.org/x/exp/maps" ) type valueType string @@ -19,6 +17,16 @@ const ( typeObject valueType = "object" ) +// mapKeys returns the keys of the map m. +// The keys will be in an indeterminate order. +func mapKeys[M ~map[K]V, K comparable, V any](m M) []K { + r := make([]K, 0, len(m)) + for k := range m { + r = append(r, k) + } + return r +} + type schema struct { typeName valueType items *schema @@ -30,7 +38,7 @@ func (s *schema) String() string { return fmt.Sprintf("%s[%s]", s.typeName, s.items) } if s.isObject() { - return fmt.Sprintf("%s{%v}", s.typeName, maps.Keys(s.properties)) + return fmt.Sprintf("%s{%v}", s.typeName, mapKeys(s.properties)) } return string(s.typeName) } @@ -285,7 +293,7 @@ func (i *typeChecker) run(ast *Node, value any) (*schema, Error) { return nil, err } if leftType.isObject() { - keys := maps.Keys(leftType.properties) + keys := mapKeys(leftType.properties) sort.Strings(keys) if len(keys) > 0 { // Pick the first prop as the representative item type.