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 22, 2024
1 parent bfb6dc3 commit 9cf0032
Show file tree
Hide file tree
Showing 4 changed files with 125 additions and 70 deletions.
55 changes: 55 additions & 0 deletions lib/errors.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
// 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 "<nil>"
}
type nodeIDer interface {
NodeID() int64
}
nodeErr, ok := e.Err.(nodeIDer)
if !ok {
return e.Err.Error()
}
id := nodeErr.NodeID()
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()
}
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})
}

v, err := out.ConvertToNative(reflect.TypeOf(&structpb.Value{}))
Expand Down

0 comments on commit 9cf0032

Please sign in to comment.