diff --git a/lib/collections.go b/lib/collections.go index 0672836..10073a7 100644 --- a/lib/collections.go +++ b/lib/collections.go @@ -291,25 +291,25 @@ func (collectionsLib) CompileOptions() []cel.EnvOption { "list_collate_string", []*cel.Type{listDyn, cel.StringType}, listDyn, - cel.BinaryBinding(collateFields), + cel.BinaryBinding(catch(collateFields)), ), cel.MemberOverload( "list_collate_list_string", []*cel.Type{listDyn, listString}, listDyn, - cel.BinaryBinding(collateFields), + cel.BinaryBinding(catch(collateFields)), ), cel.MemberOverload( "map_collate_string", []*cel.Type{mapStringDyn, cel.StringType}, listDyn, - cel.BinaryBinding(collateFields), + cel.BinaryBinding(catch(collateFields)), ), cel.MemberOverload( "map_collate_list_string", []*cel.Type{mapStringDyn, listString}, listDyn, - cel.BinaryBinding(collateFields), + cel.BinaryBinding(catch(collateFields)), ), ), @@ -318,25 +318,25 @@ func (collectionsLib) CompileOptions() []cel.EnvOption { "list_drop_string", []*cel.Type{listV, cel.StringType}, listV, - cel.BinaryBinding(dropFields), + cel.BinaryBinding(catch(dropFields)), ), cel.MemberOverload( "list_drop_list_string", []*cel.Type{listV, listString}, listV, - cel.BinaryBinding(dropFields), + cel.BinaryBinding(catch(dropFields)), ), cel.MemberOverload( "map_drop_string", []*cel.Type{mapKV, cel.StringType}, mapKV, - cel.BinaryBinding(dropFields), + cel.BinaryBinding(catch(dropFields)), ), cel.MemberOverload( "map_drop_list_string", []*cel.Type{mapKV, listString}, mapKV, - cel.BinaryBinding(dropFields), + cel.BinaryBinding(catch(dropFields)), ), ), @@ -345,13 +345,13 @@ func (collectionsLib) CompileOptions() []cel.EnvOption { "list_drop_empty", []*cel.Type{listV}, listV, - cel.UnaryBinding(dropEmpty), + cel.UnaryBinding(catch(dropEmpty)), ), cel.MemberOverload( "map_drop_empty", []*cel.Type{mapKV}, mapKV, - cel.UnaryBinding(dropEmpty), + cel.UnaryBinding(catch(dropEmpty)), ), ), @@ -360,7 +360,7 @@ func (collectionsLib) CompileOptions() []cel.EnvOption { "list_flatten", []*cel.Type{listV}, listV, - cel.UnaryBinding(flatten), + cel.UnaryBinding(catch(flatten)), ), ), @@ -369,13 +369,13 @@ func (collectionsLib) CompileOptions() []cel.EnvOption { "map_keys", []*cel.Type{mapKV}, listK, - cel.UnaryBinding(mapKeys), + cel.UnaryBinding(catch(mapKeys)), ), cel.Overload( "keys_map", []*cel.Type{mapKV}, listK, - cel.UnaryBinding(mapKeys), + cel.UnaryBinding(catch(mapKeys)), ), ), @@ -384,13 +384,13 @@ func (collectionsLib) CompileOptions() []cel.EnvOption { "list_max", []*cel.Type{listV}, typeV, - cel.UnaryBinding(max), + cel.UnaryBinding(catch(max)), ), cel.Overload( "max_list", []*cel.Type{listV}, typeV, - cel.UnaryBinding(max), + cel.UnaryBinding(catch(max)), ), ), @@ -399,13 +399,13 @@ func (collectionsLib) CompileOptions() []cel.EnvOption { "list_min", []*cel.Type{listV}, typeV, - cel.UnaryBinding(min), + cel.UnaryBinding(catch(min)), ), cel.Overload( "min_list", []*cel.Type{listV}, typeV, - cel.UnaryBinding(min), + cel.UnaryBinding(catch(min)), ), ), @@ -414,7 +414,7 @@ func (collectionsLib) CompileOptions() []cel.EnvOption { "tail_list", []*cel.Type{listV}, listV, - cel.UnaryBinding(tail), + cel.UnaryBinding(catch(tail)), ), ), @@ -423,13 +423,13 @@ func (collectionsLib) CompileOptions() []cel.EnvOption { "map_values", []*cel.Type{mapKV}, listK, - cel.UnaryBinding(mapValues), + cel.UnaryBinding(catch(mapValues)), ), cel.Overload( "values_map", []*cel.Type{mapKV}, listK, - cel.UnaryBinding(mapValues), + cel.UnaryBinding(catch(mapValues)), ), ), @@ -438,7 +438,7 @@ func (collectionsLib) CompileOptions() []cel.EnvOption { "map_with_map", []*cel.Type{mapKV, mapKV}, mapKV, - cel.BinaryBinding(withAll), + cel.BinaryBinding(catch(withAll)), ), ), @@ -447,7 +447,7 @@ func (collectionsLib) CompileOptions() []cel.EnvOption { "map_with_update_map", []*cel.Type{mapKV, mapKV}, mapKV, - cel.BinaryBinding(withUpdate), + cel.BinaryBinding(catch(withUpdate)), ), ), @@ -456,7 +456,7 @@ func (collectionsLib) CompileOptions() []cel.EnvOption { "map_with_replace_map", []*cel.Type{mapKV, mapKV}, mapKV, - cel.BinaryBinding(withReplace), + cel.BinaryBinding(catch(withReplace)), ), ), @@ -465,13 +465,13 @@ func (collectionsLib) CompileOptions() []cel.EnvOption { "list_zip", []*cel.Type{listK, listV}, mapKV, - cel.BinaryBinding(zipLists), + cel.BinaryBinding(catch(zipLists)), ), cel.Overload( "zip_list", []*cel.Type{listK, listV}, mapKV, - cel.BinaryBinding(zipLists), + cel.BinaryBinding(catch(zipLists)), ), ), } diff --git a/lib/debug.go b/lib/debug.go index 93be4ab..81fbf9b 100644 --- a/lib/debug.go +++ b/lib/debug.go @@ -58,7 +58,7 @@ func (l debug) CompileOptions() []cel.EnvOption { "debug_string_dyn", []*cel.Type{cel.StringType, cel.DynType}, cel.DynType, - cel.BinaryBinding(l.logDebug), + cel.BinaryBinding(catch(l.logDebug)), cel.OverloadIsNonStrict(), ), ), diff --git a/lib/errors.go b/lib/errors.go index 3f34e30..0d6fe19 100644 --- a/lib/errors.go +++ b/lib/errors.go @@ -19,9 +19,14 @@ package lib import ( "fmt" + "path" + "runtime" + "strings" "github.com/google/cel-go/cel" "github.com/google/cel-go/common" + "github.com/google/cel-go/common/types" + "github.com/google/cel-go/common/types/ref" ) // DecoratedError implements error source location rendering. @@ -82,3 +87,62 @@ func nodeID(err error) (id int64, ok bool) { } } } + +type ( + unop = func(value ref.Val) ref.Val + binop = func(lhs ref.Val, rhs ref.Val) ref.Val + varop = func(values ...ref.Val) ref.Val + + bindings interface { + unop | binop | varop + } +) + +func catch[B bindings](binding B) B { + switch binding := any(binding).(type) { + case unop: + return any(func(arg ref.Val) (ret ref.Val) { + defer handlePanic(&ret) + return binding(arg) + }).(B) + case binop: + return any(func(arg0, arg1 ref.Val) (ret ref.Val) { + defer handlePanic(&ret) + return binding(arg0, arg1) + }).(B) + case varop: + return any(func(args ...ref.Val) (ret ref.Val) { + defer handlePanic(&ret) + return binding(args...) + }).(B) + default: + panic("unreachable") + } +} + +func handlePanic(ret *ref.Val) { + switch r := recover().(type) { + case nil: + return + default: + // We'll only try 64 stack frames deep. There are a few recursive + // functions in extensions, but panic in those functions are unlikely + // or are already explicitly recovered as part of normal operation. + pc := make([]uintptr, 64) + n := runtime.Callers(2, pc) + cf := runtime.CallersFrames(pc[:n]) + for { + f, more := cf.Next() + if !more { + break + } + file := f.File + if strings.Contains(file, "mito/lib") { + _, file, _ := strings.Cut(file, "mito/") + *ret = types.NewErr("%s: %s %s:%d", r, path.Base(f.Function), file, f.Line) + return + } + } + *ret = types.NewErr("%s", r) + } +} diff --git a/lib/file.go b/lib/file.go index 64cd594..c13513b 100644 --- a/lib/file.go +++ b/lib/file.go @@ -114,7 +114,7 @@ func (l fileLib) CompileOptions() []cel.EnvOption { "dir_string", []*cel.Type{cel.StringType}, cel.ListType(mapStringDyn), - cel.UnaryBinding(readDir), + cel.UnaryBinding(catch(readDir)), ), ), cel.Function("file", @@ -122,13 +122,13 @@ func (l fileLib) CompileOptions() []cel.EnvOption { "file_string", []*cel.Type{cel.StringType}, cel.BytesType, - cel.UnaryBinding(readFile), + cel.UnaryBinding(catch(readFile)), ), cel.Overload( "file_string_string", []*cel.Type{cel.StringType, cel.StringType}, cel.DynType, - cel.BinaryBinding(l.readMIMEFile), + cel.BinaryBinding(catch(l.readMIMEFile)), ), ), } diff --git a/lib/http.go b/lib/http.go index d31b2c1..ecbc0aa 100644 --- a/lib/http.go +++ b/lib/http.go @@ -316,7 +316,7 @@ func (l httpLib) CompileOptions() []cel.EnvOption { "head_string", []*cel.Type{cel.StringType}, mapStringDyn, - cel.UnaryBinding(l.doHead), + cel.UnaryBinding(catch(l.doHead)), ), ), @@ -325,7 +325,7 @@ func (l httpLib) CompileOptions() []cel.EnvOption { "get_string", []*cel.Type{cel.StringType}, mapStringDyn, - cel.UnaryBinding(l.doGet), + cel.UnaryBinding(catch(l.doGet)), ), ), cel.Function("get_request", @@ -333,7 +333,7 @@ func (l httpLib) CompileOptions() []cel.EnvOption { "get_request_string", []*cel.Type{cel.StringType}, mapStringDyn, - cel.UnaryBinding(newGetRequest), + cel.UnaryBinding(catch(newGetRequest)), ), ), @@ -342,13 +342,13 @@ func (l httpLib) CompileOptions() []cel.EnvOption { "post_string_string_bytes", []*cel.Type{cel.StringType, cel.StringType, cel.BytesType}, mapStringDyn, - cel.FunctionBinding(l.doPost), + cel.FunctionBinding(catch(l.doPost)), ), cel.Overload( "post_string_string_string", []*cel.Type{cel.StringType, cel.StringType, cel.StringType}, mapStringDyn, - cel.FunctionBinding(l.doPost), + cel.FunctionBinding(catch(l.doPost)), ), ), cel.Function("post_request", @@ -356,13 +356,13 @@ func (l httpLib) CompileOptions() []cel.EnvOption { "post_request_string_string_bytes", []*cel.Type{cel.StringType, cel.StringType, cel.BytesType}, mapStringDyn, - cel.FunctionBinding(newPostRequest), + cel.FunctionBinding(catch(newPostRequest)), ), cel.Overload( "post_request_string_string_string", []*cel.Type{cel.StringType, cel.StringType, cel.StringType}, mapStringDyn, - cel.FunctionBinding(newPostRequest), + cel.FunctionBinding(catch(newPostRequest)), ), ), @@ -371,19 +371,19 @@ func (l httpLib) CompileOptions() []cel.EnvOption { "request_string_string", []*cel.Type{cel.StringType, cel.StringType}, mapStringDyn, - cel.BinaryBinding(newRequest), + cel.BinaryBinding(catch(newRequest)), ), cel.Overload( "request_string_string_bytes", []*cel.Type{cel.StringType, cel.StringType, cel.BytesType}, mapStringDyn, - cel.FunctionBinding(newRequestBody), + cel.FunctionBinding(catch(newRequestBody)), ), cel.Overload( "request_string_string_string", []*cel.Type{cel.StringType, cel.StringType, cel.StringType}, mapStringDyn, - cel.FunctionBinding(newRequestBody), + cel.FunctionBinding(catch(newRequestBody)), ), ), @@ -392,7 +392,7 @@ func (l httpLib) CompileOptions() []cel.EnvOption { "map_do_request", []*cel.Type{mapStringDyn}, mapStringDyn, - cel.UnaryBinding(l.doRequest), + cel.UnaryBinding(catch(l.doRequest)), ), ), @@ -401,7 +401,7 @@ func (l httpLib) CompileOptions() []cel.EnvOption { "map_basic_authentication_string_string", []*cel.Type{mapStringDyn, cel.StringType, cel.StringType}, mapStringDyn, - cel.FunctionBinding(l.basicAuthentication), + cel.FunctionBinding(catch(l.basicAuthentication)), ), ), @@ -410,7 +410,7 @@ func (l httpLib) CompileOptions() []cel.EnvOption { "string_parse_url", []*cel.Type{cel.StringType}, mapStringDyn, - cel.UnaryBinding(parseURL), + cel.UnaryBinding(catch(parseURL)), ), ), cel.Function("format_url", @@ -418,7 +418,7 @@ func (l httpLib) CompileOptions() []cel.EnvOption { "map_format_url", []*cel.Type{mapStringDyn}, cel.StringType, - cel.UnaryBinding(formatURL), + cel.UnaryBinding(catch(formatURL)), ), ), @@ -427,7 +427,7 @@ func (l httpLib) CompileOptions() []cel.EnvOption { "string_parse_query", []*cel.Type{cel.StringType}, mapStringDyn, - cel.UnaryBinding(parseQuery), + cel.UnaryBinding(catch(parseQuery)), ), ), cel.Function("format_query", @@ -435,7 +435,7 @@ func (l httpLib) CompileOptions() []cel.EnvOption { "map_format_query", []*cel.Type{mapStringDyn}, cel.StringType, - cel.UnaryBinding(formatQuery), + cel.UnaryBinding(catch(formatQuery)), ), ), } diff --git a/lib/json.go b/lib/json.go index 46609b6..b8e6232 100644 --- a/lib/json.go +++ b/lib/json.go @@ -94,13 +94,13 @@ func (l jsonLib) CompileOptions() []cel.EnvOption { "dyn_encode_json", []*cel.Type{cel.DynType}, cel.StringType, - cel.UnaryBinding(encodeJSON), + cel.UnaryBinding(catch(encodeJSON)), ), cel.Overload( "encode_json_dyn", []*cel.Type{cel.DynType}, cel.StringType, - cel.UnaryBinding(encodeJSON), + cel.UnaryBinding(catch(encodeJSON)), ), ), @@ -109,25 +109,25 @@ func (l jsonLib) CompileOptions() []cel.EnvOption { "string_decode_json", []*cel.Type{cel.StringType}, cel.DynType, - cel.UnaryBinding(l.decodeJSON), + cel.UnaryBinding(catch(l.decodeJSON)), ), cel.Overload( "decode_json_string", []*cel.Type{cel.StringType}, cel.DynType, - cel.UnaryBinding(l.decodeJSON), + cel.UnaryBinding(catch(l.decodeJSON)), ), cel.MemberOverload( "bytes_decode_json", []*cel.Type{cel.BytesType}, cel.DynType, - cel.UnaryBinding(l.decodeJSON), + cel.UnaryBinding(catch(l.decodeJSON)), ), cel.Overload( "decode_json_bytes", []*cel.Type{cel.BytesType}, cel.DynType, - cel.UnaryBinding(l.decodeJSON), + cel.UnaryBinding(catch(l.decodeJSON)), ), ), @@ -136,25 +136,25 @@ func (l jsonLib) CompileOptions() []cel.EnvOption { "string_decode_json_stream", []*cel.Type{cel.StringType}, cel.DynType, - cel.UnaryBinding(l.decodeJSONStream), + cel.UnaryBinding(catch(l.decodeJSONStream)), ), cel.Overload( "decode_json_stream_string", []*cel.Type{cel.StringType}, cel.DynType, - cel.UnaryBinding(l.decodeJSONStream), + cel.UnaryBinding(catch(l.decodeJSONStream)), ), cel.MemberOverload( "bytes_decode_json_stream", []*cel.Type{cel.BytesType}, cel.DynType, - cel.UnaryBinding(l.decodeJSONStream), + cel.UnaryBinding(catch(l.decodeJSONStream)), ), cel.Overload( "decode_json_stream_bytes", []*cel.Type{cel.BytesType}, cel.DynType, - cel.UnaryBinding(l.decodeJSONStream), + cel.UnaryBinding(catch(l.decodeJSONStream)), ), ), } diff --git a/lib/limit.go b/lib/limit.go index add6f3c..ccdd648 100644 --- a/lib/limit.go +++ b/lib/limit.go @@ -97,13 +97,13 @@ func (l limitLib) CompileOptions() []cel.EnvOption { "map_dyn_rate_limit_string_duration", []*cel.Type{mapStringDyn, cel.StringType, cel.DurationType}, mapStringDyn, - cel.FunctionBinding(l.translatePolicy), + cel.FunctionBinding(catch(l.translatePolicy)), ), cel.Overload( "map_dyn_rate_limit_string_bool_bool_duration_int", []*cel.Type{mapStringDyn, cel.StringType, cel.BoolType, cel.BoolType, cel.DurationType, cel.IntType}, mapStringDyn, - cel.FunctionBinding(translatePolicy), + cel.FunctionBinding(catch(translatePolicy)), ), ), } diff --git a/lib/mime.go b/lib/mime.go index 6ffa53f..fa067cc 100644 --- a/lib/mime.go +++ b/lib/mime.go @@ -66,7 +66,7 @@ func (l mimeLib) CompileOptions() []cel.EnvOption { "bytes_mime_string", []*cel.Type{cel.BytesType, cel.StringType}, cel.DynType, - cel.BinaryBinding(l.transformMIME), + cel.BinaryBinding(catch(l.transformMIME)), ), ), } diff --git a/lib/regexp.go b/lib/regexp.go index 99793d4..68780a4 100644 --- a/lib/regexp.go +++ b/lib/regexp.go @@ -124,7 +124,7 @@ func (l regexpLib) CompileOptions() []cel.EnvOption { "typeV_re_match_string", []*cel.Type{cel.DynType, cel.StringType}, cel.BoolType, - cel.BinaryBinding(l.match), + cel.BinaryBinding(catch(l.match)), ), ), cel.Function("re_find", @@ -132,7 +132,7 @@ func (l regexpLib) CompileOptions() []cel.EnvOption { "typeV_re_find_string", []*cel.Type{typeV, cel.StringType}, typeV, - cel.BinaryBinding(l.find), + cel.BinaryBinding(catch(l.find)), ), ), cel.Function("re_find_all", @@ -140,7 +140,7 @@ func (l regexpLib) CompileOptions() []cel.EnvOption { "typeV_re_find_all_string", []*cel.Type{typeV, cel.StringType}, listV, - cel.BinaryBinding(l.findAll), + cel.BinaryBinding(catch(l.findAll)), ), ), cel.Function("re_find_submatch", @@ -148,7 +148,7 @@ func (l regexpLib) CompileOptions() []cel.EnvOption { "typeV_re_find_submatch_string", []*cel.Type{typeV, cel.StringType}, typeV, - cel.BinaryBinding(l.findSubmatch), + cel.BinaryBinding(catch(l.findSubmatch)), ), ), cel.Function("re_find_all_submatch", @@ -156,7 +156,7 @@ func (l regexpLib) CompileOptions() []cel.EnvOption { "typeV_re_find_all_submatch_string", []*cel.Type{typeV, cel.StringType}, listV, - cel.BinaryBinding(l.findAllSubmatch), + cel.BinaryBinding(catch(l.findAllSubmatch)), ), ), cel.Function("re_replace_all", @@ -164,7 +164,7 @@ func (l regexpLib) CompileOptions() []cel.EnvOption { "typeV_re_replace_all_string_dyn", []*cel.Type{typeV, cel.StringType, typeV}, typeV, - cel.FunctionBinding(l.replaceAll), + cel.FunctionBinding(catch(l.replaceAll)), ), ), } diff --git a/lib/xml.go b/lib/xml.go index dd56120..e0db916 100644 --- a/lib/xml.go +++ b/lib/xml.go @@ -87,25 +87,25 @@ func (l xmlLib) CompileOptions() []cel.EnvOption { "string_decode_xml", []*cel.Type{cel.StringType}, cel.DynType, - cel.UnaryBinding(l.decodeXML), + cel.UnaryBinding(catch(l.decodeXML)), ), cel.Overload( "decode_xml_string", []*cel.Type{cel.StringType}, cel.DynType, - cel.UnaryBinding(l.decodeXML), + cel.UnaryBinding(catch(l.decodeXML)), ), cel.MemberOverload( "bytes_decode_xml", []*cel.Type{cel.BytesType}, cel.DynType, - cel.UnaryBinding(l.decodeXML), + cel.UnaryBinding(catch(l.decodeXML)), ), cel.Overload( "decode_xml_bytes", []*cel.Type{cel.BytesType}, cel.DynType, - cel.UnaryBinding(l.decodeXML), + cel.UnaryBinding(catch(l.decodeXML)), ), // With type information. @@ -113,25 +113,25 @@ func (l xmlLib) CompileOptions() []cel.EnvOption { "string_decode_xml_string", []*cel.Type{cel.StringType, cel.StringType}, cel.DynType, - cel.BinaryBinding(l.decodeXMLWithXSD), + cel.BinaryBinding(catch(l.decodeXMLWithXSD)), ), cel.Overload( "decode_xml_string_string", []*cel.Type{cel.StringType, cel.StringType}, cel.DynType, - cel.BinaryBinding(l.decodeXMLWithXSD), + cel.BinaryBinding(catch(l.decodeXMLWithXSD)), ), cel.MemberOverload( "bytes_decode_xml_string", []*cel.Type{cel.BytesType, cel.StringType}, cel.DynType, - cel.BinaryBinding(l.decodeXMLWithXSD), + cel.BinaryBinding(catch(l.decodeXMLWithXSD)), ), cel.Overload( "decode_xml_bytes_string", []*cel.Type{cel.BytesType, cel.StringType}, cel.DynType, - cel.BinaryBinding(l.decodeXMLWithXSD), + cel.BinaryBinding(catch(l.decodeXMLWithXSD)), ), ), }