Skip to content

Commit

Permalink
lib,mito: add support for runtime error source location reporting
Browse files Browse the repository at this point in the history
  • Loading branch information
efd6 committed Jan 18, 2024
1 parent 19e4f58 commit ff31822
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 70 deletions.
18 changes: 9 additions & 9 deletions mito.go
Original file line number Diff line number Diff line change
Expand Up @@ -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})

Check failure on line 335 in mito.go

View workflow job for this annotation

GitHub Actions / test (1.19.x, ubuntu-latest)

undefined: lib.DecoratedError

Check failure on line 335 in mito.go

View workflow job for this annotation

GitHub Actions / test (1.20.x, ubuntu-latest)

undefined: lib.DecoratedError
}

v, err := out.ConvertToNative(reflect.TypeOf(&structpb.Value{}))
Expand Down
120 changes: 60 additions & 60 deletions mito_bench_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
},
},

Expand All @@ -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
},
},
}
Expand All @@ -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)
}
Expand Down
2 changes: 1 addition & 1 deletion testdata/serve_tls.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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: <input>: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
Expand Down

0 comments on commit ff31822

Please sign in to comment.