diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index 619c1c0..9b050fd 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -10,7 +10,7 @@ jobs: test: strategy: matrix: - go-version: [1.19.x, 1.20.x] + go-version: [1.19.x, 1.20.x, 1.21.x] os: [ubuntu-latest] runs-on: ${{ matrix.os }} diff --git a/go.mod b/go.mod index f779058..4cb48eb 100644 --- a/go.mod +++ b/go.mod @@ -6,7 +6,7 @@ require ( aqwari.net/xml v0.0.0-20210331023308-d9421b293817 github.com/goccy/go-yaml v1.9.5 github.com/golang/protobuf v1.5.2 - github.com/google/cel-go v0.17.7 + github.com/google/cel-go v0.19.0 github.com/google/go-cmp v0.5.8 github.com/google/uuid v1.3.0 github.com/rogpeppe/go-internal v1.8.1 @@ -18,13 +18,14 @@ require ( require ( cloud.google.com/go/compute/metadata v0.2.0 // indirect - github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20230305170008-8188dc5388df // indirect + github.com/antlr4-go/antlr/v4 v4.13.0 // indirect github.com/fatih/color v1.10.0 // indirect github.com/mattn/go-colorable v0.1.8 // indirect github.com/mattn/go-isatty v0.0.12 // indirect github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e // indirect github.com/stoewer/go-strcase v1.2.0 // indirect - golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e // indirect + github.com/stretchr/testify v1.7.0 // indirect + golang.org/x/exp v0.0.0-20230515195305-f3d0a9c9a5cc // indirect golang.org/x/net v0.9.0 // indirect golang.org/x/sys v0.7.0 // indirect golang.org/x/text v0.9.0 // indirect diff --git a/go.sum b/go.sum index 8b9b695..3f4ffd9 100644 --- a/go.sum +++ b/go.sum @@ -2,8 +2,8 @@ aqwari.net/xml v0.0.0-20210331023308-d9421b293817 h1:+3Rh5EaTzNLnzWx3/uy/mAaH/dG aqwari.net/xml v0.0.0-20210331023308-d9421b293817/go.mod h1:c7kkWzc7HS/t8Q2DcVY8P2d1dyWNEhEVT5pL0ZHO11c= cloud.google.com/go/compute/metadata v0.2.0 h1:nBbNSZyDpkNlo3DepaaLKVuO7ClyifSAmNloSCZrHnQ= cloud.google.com/go/compute/metadata v0.2.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k= -github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20230305170008-8188dc5388df h1:7RFfzj4SSt6nnvCPbCqijJi1nWCd+TqAT3bYCStRC18= -github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20230305170008-8188dc5388df/go.mod h1:pSwJ0fSY5KhvocuWSx4fz3BA8OrA1bQn+K1Eli3BRwM= +github.com/antlr4-go/antlr/v4 v4.13.0 h1:lxCg3LAv+EUK6t1i0y1V6/SLeUi0eKEKdhQAlS8TVTI= +github.com/antlr4-go/antlr/v4 v4.13.0/go.mod h1:pfChB/xh/Unjila75QW7+VU4TSnWnnk9UTnmpPaOR2g= 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/fatih/color v1.10.0 h1:s36xzo75JdqLaaWoiEHk767eHiwo0598uUxyfiPkDsg= @@ -21,14 +21,8 @@ github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5y github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/google/cel-go v0.17.0 h1:o8fqHUcM+0g5prwg4pHZR+EMdef2RBumnEYefCXAyPQ= -github.com/google/cel-go v0.17.0/go.mod h1:HXZKzB0LXqer5lHHgfWAnlYwJaQBDKMjxjulNQzhwhY= -github.com/google/cel-go v0.17.1 h1:s2151PDGy/eqpCI80/8dl4VL3xTkqI/YubXLXCFw0mw= -github.com/google/cel-go v0.17.1/go.mod h1:HXZKzB0LXqer5lHHgfWAnlYwJaQBDKMjxjulNQzhwhY= -github.com/google/cel-go v0.17.7 h1:6ebJFzu1xO2n7TLtN+UBqShGBhlD85bhvglh5DpcfqQ= -github.com/google/cel-go v0.17.7/go.mod h1:HXZKzB0LXqer5lHHgfWAnlYwJaQBDKMjxjulNQzhwhY= -github.com/google/cel-go v0.18.1 h1:V/lAXKq4C3BYLDy/ARzMtpkEEYfHQpZzVyzy69nEUjs= -github.com/google/cel-go v0.18.1/go.mod h1:PVAybmSnWkNMUZR/tEWFUiJ1Np4Hz0MHsZJcgC4zln4= +github.com/google/cel-go v0.19.0 h1:vVgaZoHPBDd1lXCYGQOh5A06L4EtuIfmqQ/qnSXSKiU= +github.com/google/cel-go v0.19.0/go.mod h1:kWcIzTsPX0zmQ+H3TirHstLLf9ep5QTsZBN9u4dOYLg= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg= github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= @@ -55,15 +49,16 @@ github.com/stoewer/go-strcase v1.2.0 h1:Z2iHWqGXH00XYgqDmNgQbIBxf3wrNq0F3feEy0ai github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e h1:+WEEuIdZHnUeJJmEUjyYC2gfUMj69yZXw17EnHg/otA= -golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e/go.mod h1:Kr81I6Kryrl9sr8s2FK3vxD90NdsKWRuOIl2O4CvYbA= +golang.org/x/exp v0.0.0-20230515195305-f3d0a9c9a5cc h1:mCRnTeVUjcrhlRmO0VK8a6k6Rrf6TF9htwo2pJVSjIU= +golang.org/x/exp v0.0.0-20230515195305-f3d0a9c9a5cc/go.mod h1:V1LtkGg67GoY2N1AnLN78QLrzxkLyJw7RJb1gzOOz9w= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= @@ -110,5 +105,6 @@ gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33 gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/errgo.v2 v2.1.0 h1:0vLT13EuvQ0hNvakwLuFZ/jYrLp5F3kcWHXdRggjCE8= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= -gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +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/lib/collections.go b/lib/collections.go index cffdd7c..8fea491 100644 --- a/lib/collections.go +++ b/lib/collections.go @@ -24,6 +24,7 @@ import ( "github.com/google/cel-go/cel" "github.com/google/cel-go/checker/decls" "github.com/google/cel-go/common" + "github.com/google/cel-go/common/ast" "github.com/google/cel-go/common/operators" "github.com/google/cel-go/common/types" "github.com/google/cel-go/common/types/ref" @@ -948,21 +949,21 @@ func zipLists(arg0, arg1 ref.Val) ref.Val { return types.NewRefValMap(types.DefaultTypeAdapter, m) } -func makeAs(eh parser.ExprHelper, target *expr.Expr, args []*expr.Expr) (*expr.Expr, *common.Error) { +func makeAs(eh parser.ExprHelper, target ast.Expr, args []ast.Expr) (ast.Expr, *common.Error) { ident := args[0] - if _, ok := ident.ExprKind.(*expr.Expr_IdentExpr); !ok { + if ident.Kind() != ast.IdentKind { return nil, &common.Error{Message: "argument is not an identifier"} } - label := ident.GetIdentExpr().GetName() + label := ident.AsIdent() fn := args[1] target = eh.NewList(target) // Fold is a list comprehension, so fake this. - accuExpr := eh.Ident(parser.AccumulatorName) + accuExpr := eh.NewAccuIdent() init := eh.NewList() // Also for the result. - condition := eh.LiteralBool(true) - step := eh.GlobalCall(operators.Add, accuExpr, eh.NewList(fn)) - fold := eh.Fold(label, target, parser.AccumulatorName, init, condition, step, accuExpr) - return eh.GlobalCall(operators.Index, fold, eh.LiteralInt(0)), nil + condition := eh.NewLiteral(types.True) + step := eh.NewCall(operators.Add, accuExpr, eh.NewList(fn)) + fold := eh.NewComprehension(target, label, parser.AccumulatorName, init, condition, step, accuExpr) + return eh.NewCall(operators.Index, fold, eh.NewLiteral(types.IntZero)), nil } // pathSepIndex returns the offset to a non-escaped dot path separator and diff --git a/lib/errors.go b/lib/errors.go new file mode 100644 index 0000000..15ef1b8 --- /dev/null +++ b/lib/errors.go @@ -0,0 +1,84 @@ +// Licensed to Elasticsearch B.V. under one or more contributor +// license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright +// ownership. Elasticsearch B.V. licenses this file to you under +// the Apache License, Version 2.0 (the "License"); you may +// not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package lib + +import ( + "fmt" + + "github.com/google/cel-go/cel" + "github.com/google/cel-go/common" +) + +// DecoratedError implements error source location rendering. +type DecoratedError struct { + AST *cel.Ast + Err error +} + +func (e DecoratedError) Error() string { + if e.Err == nil { + return "" + } + + id, ok := nodeID(e.Err) + if !ok { + return e.Err.Error() + } + if id == 0 { + return fmt.Sprintf("%v: unset node id", e.Err) + } + if e.AST == nil { + return fmt.Sprintf("%v: node %d", e.Err, id) + } + loc := e.AST.NativeRep().SourceInfo().GetStartLocation(id) + errs := common.NewErrors(e.AST.Source()) + errs.ReportErrorAtID(id, loc, e.Err.Error()) + return errs.ToDisplayString() +} + +func nodeID(err error) (id int64, ok bool) { + if err == nil { + return 0, false + } + + type nodeIDer interface { + NodeID() int64 + } + + for { + if node, ok := err.(nodeIDer); ok { + return node.NodeID(), true + } + switch x := err.(type) { + case interface{ Unwrap() error }: + err = x.Unwrap() + if err == nil { + return 0, false + } + case interface{ Unwrap() []error }: + for _, err := range x.Unwrap() { + if node, ok := err.(nodeIDer); ok { + return node.NodeID(), true + } + } + return 0, false + default: + return 0, false + } + } +} diff --git a/mito.go b/mito.go index 0607964..d31ce3b 100644 --- a/mito.go +++ b/mito.go @@ -298,41 +298,41 @@ func debug(tag string, value any) { } func eval(src, root string, input interface{}, libs ...cel.EnvOption) (string, any, error) { - prg, err := compile(src, root, libs...) + prg, ast, err := compile(src, root, libs...) if err != nil { return "", nil, fmt.Errorf("failed program instantiation: %v", err) } - return run(prg, false, input) + return run(prg, ast, false, input) } -func compile(src, root string, libs ...cel.EnvOption) (cel.Program, error) { +func compile(src, root string, libs ...cel.EnvOption) (cel.Program, *cel.Ast, error) { opts := append([]cel.EnvOption{ cel.Declarations(decls.NewVar(root, decls.Dyn)), }, libs...) env, err := cel.NewEnv(opts...) if err != nil { - return nil, fmt.Errorf("failed to create env: %v", err) + return nil, nil, fmt.Errorf("failed to create env: %v", err) } ast, iss := env.Compile(src) if iss.Err() != nil { - return nil, fmt.Errorf("failed compilation: %v", iss.Err()) + return nil, nil, fmt.Errorf("failed compilation: %v", iss.Err()) } prg, err := env.Program(ast) if err != nil { - return nil, fmt.Errorf("failed program instantiation: %v", err) + return nil, nil, fmt.Errorf("failed program instantiation: %v", err) } - return prg, nil + return prg, ast, nil } -func run(prg cel.Program, fast bool, input interface{}) (string, any, error) { +func run(prg cel.Program, ast *cel.Ast, fast bool, input interface{}) (string, any, error) { if input == nil { input = interpreter.EmptyActivation() } out, _, err := prg.Eval(input) if err != nil { - return "", nil, fmt.Errorf("failed eval: %v", err) + return "", nil, fmt.Errorf("failed eval: %v", lib.DecoratedError{AST: ast, Err: err}) } v, err := out.ConvertToNative(reflect.TypeOf(&structpb.Value{})) diff --git a/mito_bench_test.go b/mito_bench_test.go index eaae673..846e8dc 100644 --- a/mito_bench_test.go +++ b/mito_bench_test.go @@ -36,99 +36,99 @@ var ( var benchmarks = []struct { name string - setup func(*testing.B) (prg cel.Program, state any, err error) + setup func(*testing.B) (prg cel.Program, ast *cel.Ast, state any, err error) }{ // Self-contained. { name: "hello_world_static", - setup: func(b *testing.B) (cel.Program, any, error) { - prg, err := compile( + setup: func(b *testing.B) (cel.Program, *cel.Ast, any, error) { + prg, ast, err := compile( `"hello world"`, root, ) - return prg, nil, err + return prg, ast, nil, err }, }, { name: "hello_world_object_static", - setup: func(b *testing.B) (cel.Program, any, error) { - prg, err := compile( + setup: func(b *testing.B) (cel.Program, *cel.Ast, any, error) { + prg, ast, err := compile( `{"greeting":"hello world"}`, root, ) - return prg, nil, err + return prg, ast, nil, err }, }, { name: "nested_static", - setup: func(b *testing.B) (cel.Program, any, error) { - prg, err := compile( + setup: func(b *testing.B) (cel.Program, *cel.Ast, any, error) { + prg, ast, err := compile( `{"a":{"b":{"c":{"d":{"e":"f"}}}}}`, root, ) - return prg, nil, err + return prg, ast, nil, err }, }, { name: "encode_json_static", - setup: func(b *testing.B) (cel.Program, any, error) { - prg, err := compile( + setup: func(b *testing.B) (cel.Program, *cel.Ast, any, error) { + prg, ast, err := compile( `{"a":{"b":{"c":{"d":{"e":"f"}}}}}.encode_json()`, root, lib.JSON(nil), ) - return prg, nil, err + return prg, ast, nil, err }, }, { name: "nested_collate_static", - setup: func(b *testing.B) (cel.Program, any, error) { - prg, err := compile( + setup: func(b *testing.B) (cel.Program, *cel.Ast, any, error) { + prg, ast, err := compile( `{"a":{"b":{"c":{"d":{"e":"f"}}}}}.collate("a.b.c.d.e")`, root, lib.Collections(), ) - return prg, nil, err + return prg, ast, nil, err }, }, // From state. { name: "hello_world_state", - setup: func(b *testing.B) (cel.Program, any, error) { - prg, err := compile(root, root) + setup: func(b *testing.B) (cel.Program, *cel.Ast, any, error) { + prg, ast, err := compile(root, root) state := map[string]any{root: "hello world"} - return prg, state, err + return prg, ast, state, err }, }, { name: "hello_world_object_state", - setup: func(b *testing.B) (cel.Program, any, error) { - prg, err := compile( + setup: func(b *testing.B) (cel.Program, *cel.Ast, any, error) { + prg, ast, err := compile( `{"greeting":state.greeting}`, root, ) state := map[string]any{root: mustParseJSON(`{"greeting": "hello world}"}`)} - return prg, state, err + return prg, ast, state, err }, }, { name: "nested_state", - setup: func(b *testing.B) (cel.Program, any, error) { - prg, err := compile(root, root) + setup: func(b *testing.B) (cel.Program, *cel.Ast, any, error) { + prg, ast, err := compile(root, root) state := map[string]any{root: mustParseJSON(`{"a":{"b":{"c":{"d":{"e":"f"}}}}}`)} - return prg, state, err + return prg, ast, state, err }, }, { name: "encode_json_state", - setup: func(b *testing.B) (cel.Program, any, error) { - prg, err := compile(`state.encode_json()`, + setup: func(b *testing.B) (cel.Program, *cel.Ast, any, error) { + prg, ast, err := compile(`state.encode_json()`, root, lib.JSON(nil), ) state := map[string]any{root: mustParseJSON(`{"a":{"b":{"c":{"d":{"e":"f"}}}}}`)} - return prg, state, err + return prg, ast, state, err }, }, // These two have additional complexity due to a wart that requires @@ -140,24 +140,24 @@ var benchmarks = []struct { // Similar in the net versions below. { name: "nested_collate_list_state", - setup: func(b *testing.B) (cel.Program, any, error) { - prg, err := compile(`[state].collate("a.b.c.d.e")`, + setup: func(b *testing.B) (cel.Program, *cel.Ast, any, error) { + prg, ast, err := compile(`[state].collate("a.b.c.d.e")`, root, lib.Collections(), ) state := map[string]any{root: mustParseJSON(`{"a":{"b":{"c":{"d":{"e":"f"}}}}}`)} - return prg, state, err + return prg, ast, state, err }, }, { name: "nested_collate_map_state", - setup: func(b *testing.B) (cel.Program, any, error) { - prg, err := compile(`{"state": state}.collate("state.a.b.c.d.e")`, + setup: func(b *testing.B) (cel.Program, *cel.Ast, any, error) { + prg, ast, err := compile(`{"state": state}.collate("state.a.b.c.d.e")`, root, lib.Collections(), ) state := map[string]any{root: mustParseJSON(`{"a":{"b":{"c":{"d":{"e":"f"}}}}}`)} - return prg, state, err + return prg, ast, state, err }, }, @@ -167,132 +167,132 @@ var benchmarks = []struct { // This is to get an idea of how much of the bench work is coming from // the test server. name: "null_net", - setup: func(b *testing.B) (cel.Program, any, error) { + setup: func(b *testing.B) (cel.Program, *cel.Ast, any, error) { srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { w.WriteHeader(http.StatusOK) })) b.Cleanup(func() { srv.Close() }) - prg, err := compile( + prg, ast, err := compile( fmt.Sprintf(`get(%q).size()`, srv.URL), root, lib.HTTP(srv.Client(), nil, nil), ) - return prg, nil, err + return prg, ast, nil, err }, }, { name: "hello_world_net", - setup: func(b *testing.B) (cel.Program, any, error) { + setup: func(b *testing.B) (cel.Program, *cel.Ast, any, error) { srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { w.Write([]byte("hello world")) })) b.Cleanup(func() { srv.Close() }) - prg, err := compile( + prg, ast, err := compile( fmt.Sprintf(`string(get(%q).Body)`, srv.URL), root, lib.HTTP(srv.Client(), nil, nil), ) - return prg, nil, err + return prg, ast, nil, err }, }, { name: "hello_world_object_net", - setup: func(b *testing.B) (cel.Program, any, error) { + setup: func(b *testing.B) (cel.Program, *cel.Ast, any, error) { srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { w.Write([]byte(`{"greeting":"hello world"}`)) })) b.Cleanup(func() { srv.Close() }) - prg, err := compile( + prg, ast, err := compile( fmt.Sprintf(`{"greeting":bytes(get(%q).Body).decode_json().greeting}`, srv.URL), root, lib.HTTP(srv.Client(), nil, nil), lib.JSON(nil), ) - return prg, nil, err + return prg, ast, nil, err }, }, { name: "nested_net", - setup: func(b *testing.B) (cel.Program, any, error) { + setup: func(b *testing.B) (cel.Program, *cel.Ast, any, error) { srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { w.Write([]byte(`{"a":{"b":{"c":{"d":{"e":"f"}}}}}`)) })) b.Cleanup(func() { srv.Close() }) - prg, err := compile( + prg, ast, err := compile( fmt.Sprintf(`bytes(get(%q).Body).decode_json()`, srv.URL), root, lib.HTTP(srv.Client(), nil, nil), lib.JSON(nil), ) - return prg, nil, err + return prg, ast, nil, err }, }, { name: "encode_json_null_net", - setup: func(b *testing.B) (cel.Program, any, error) { + setup: func(b *testing.B) (cel.Program, *cel.Ast, any, error) { srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { w.Write([]byte(`{"a":{"b":{"c":{"d":{"e":"f"}}}}}`)) })) b.Cleanup(func() { srv.Close() }) - prg, err := compile( + prg, ast, err := compile( fmt.Sprintf(`get(%q).Body`, srv.URL), root, lib.HTTP(srv.Client(), nil, nil), lib.JSON(nil), ) - return prg, nil, err + return prg, ast, nil, err }, }, { // encode_json_net should bead assessed with reference to encode_json_null_net // which performs the same request but does not round-trip the object. name: "encode_json_net", - setup: func(b *testing.B) (cel.Program, any, error) { + setup: func(b *testing.B) (cel.Program, *cel.Ast, any, error) { srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { w.Write([]byte(`{"a":{"b":{"c":{"d":{"e":"f"}}}}}`)) })) b.Cleanup(func() { srv.Close() }) - prg, err := compile( + prg, ast, err := compile( fmt.Sprintf(`bytes(get(%q).Body).decode_json().encode_json()`, srv.URL), root, lib.HTTP(srv.Client(), nil, nil), lib.JSON(nil), ) - return prg, nil, err + return prg, ast, nil, err }, }, { name: "nested_collate_list_net", - setup: func(b *testing.B) (cel.Program, any, error) { + setup: func(b *testing.B) (cel.Program, *cel.Ast, any, error) { srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { w.Write([]byte(`{"a":{"b":{"c":{"d":{"e":"f"}}}}}`)) })) b.Cleanup(func() { srv.Close() }) - prg, err := compile( + prg, ast, err := compile( fmt.Sprintf(`[bytes(get(%q).Body).decode_json()].collate("a.b.c.d.e")`, srv.URL), root, lib.HTTP(srv.Client(), nil, nil), lib.JSON(nil), lib.Collections(), ) - return prg, nil, err + return prg, ast, nil, err }, }, { name: "nested_collate_map_net", - setup: func(b *testing.B) (cel.Program, any, error) { + setup: func(b *testing.B) (cel.Program, *cel.Ast, any, error) { srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { w.Write([]byte(`{"a":{"b":{"c":{"d":{"e":"f"}}}}}`)) })) b.Cleanup(func() { srv.Close() }) - prg, err := compile( + prg, ast, err := compile( fmt.Sprintf(`{"body": bytes(get(%q).Body).decode_json()}.collate("body.a.b.c.d.e")`, srv.URL), root, lib.HTTP(srv.Client(), nil, nil), lib.JSON(nil), lib.Collections(), ) - return prg, nil, err + return prg, ast, nil, err }, }, } @@ -302,14 +302,14 @@ func BenchmarkMito(b *testing.B) { sampled := false b.Run(bench.name, func(b *testing.B) { b.StopTimer() - prg, state, err := bench.setup(b) + prg, ast, state, err := bench.setup(b) if err != nil { b.Fatalf("failed setup: %v", err) } b.StartTimer() for i := 0; i < b.N; i++ { - v, _, err := run(prg, *fastMarshal, state) + v, _, err := run(prg, ast, *fastMarshal, state) if err != nil { b.Fatalf("failed operation: %v", err) } diff --git a/testdata/serve_tls.txt b/testdata/serve_tls.txt index 3469b53..34e7cdb 100644 --- a/testdata/serve_tls.txt +++ b/testdata/serve_tls.txt @@ -4,7 +4,7 @@ cmpenv src.cel src_var.cel ! mito -use http src.cel ! stdout . -stderr 'failed eval: Get "https://127.0.0.1:[0-9]{1,5}": (?:tls: failed to verify certificate: )?x509: (?:certificate signed by unknown authority|.*certificate is not trusted)' +stderr 'failed eval: ERROR: :2:62: Get "https://127.0.0.1:[0-9]{1,5}": (?:tls: failed to verify certificate: )?x509: (?:certificate signed by unknown authority|.*certificate is not trusted)' mito -use http -insecure src.cel cmp stdout want_insecure.txt