From 7eb32146c8afe2b3af1ac940bc176f7e725fd7a7 Mon Sep 17 00:00:00 2001 From: Лач Date: Sat, 27 Jun 2020 13:03:10 +0000 Subject: [PATCH] refactor(evaluator): error handling cleanup --- --- a/crates/jsonnet-evaluator/src/ctx.rs +++ b/crates/jsonnet-evaluator/src/ctx.rs @@ -54,11 +54,11 @@ } pub fn binding(&self, name: Rc) -> Result { - self.0.bindings.get(&name).cloned().ok_or_else(|| { - create_error::<()>(Error::UnknownVariable(name)) - .err() - .unwrap() - }) + self.0 + .bindings + .get(&name) + .cloned() + .ok_or_else(|| create_error(Error::UnknownVariable(name))) } pub fn into_future(self, ctx: FutureContext) -> Context { { --- a/crates/jsonnet-evaluator/src/evaluate.rs +++ b/crates/jsonnet-evaluator/src/evaluate.rs @@ -1,7 +1,7 @@ use crate::{ - context_creator, create_error, escape_string_json, future_wrapper, lazy_val, manifest_json_ex, - parse_args, push, with_state, Context, ContextCreator, Error, FuncDesc, LazyBinding, LazyVal, - ObjMember, ObjValue, Result, Val, ValType, + context_creator, create_error, create_error_result, escape_string_json, future_wrapper, + lazy_val, manifest_json_ex, parse_args, push, with_state, Context, ContextCreator, Error, + FuncDesc, LazyBinding, LazyVal, ObjMember, ObjValue, Result, Val, ValType, }; use closure::closure; use jsonnet_parser::{ @@ -74,7 +74,7 @@ (UnaryOpType::Not, Val::Bool(v)) => Val::Bool(!v), (UnaryOpType::Minus, Val::Num(n)) => Val::Num(-*n), (UnaryOpType::BitNot, Val::Num(n)) => Val::Num(!(*n as i32) as f64), - (op, o) => create_error(Error::UnaryOperatorDoesNotOperateOnType( + (op, o) => create_error_result(Error::UnaryOperatorDoesNotOperateOnType( op, o.value_type()?, ))?, @@ -95,7 +95,7 @@ (Val::Obj(v1), Val::Obj(v2)) => Val::Obj(v2.with_super(v1.clone())), (Val::Arr(a), Val::Arr(b)) => Val::Arr(Rc::new([&a[..], &b[..]].concat())), (Val::Num(v1), Val::Num(v2)) => Val::Num(v1 + v2), - _ => create_error(Error::BinaryOperatorDoesNotOperateOnValues( + _ => create_error_result(Error::BinaryOperatorDoesNotOperateOnValues( BinaryOpType::Add, a.value_type()?, b.value_type()?, @@ -140,7 +140,7 @@ (Val::Num(v1), BinaryOpType::Mul, Val::Num(v2)) => Val::Num(v1 * v2), (Val::Num(v1), BinaryOpType::Div, Val::Num(v2)) => { if *v2 <= f64::EPSILON { - create_error(crate::Error::DivisionByZero)? + create_error_result(crate::Error::DivisionByZero)? } Val::Num(v1 / v2) } @@ -168,7 +168,7 @@ Val::Num(((*v1 as i32) >> (*v2 as i32)) as f64) } - _ => create_error(Error::BinaryOperatorDoesNotOperateOnValues( + _ => create_error_result(Error::BinaryOperatorDoesNotOperateOnValues( op, a.value_type()?, b.value_type()?, @@ -367,7 +367,7 @@ }, ); } - v => create_error(Error::FieldMustBeStringGot(v.value_type()?))?, + v => create_error_result(Error::FieldMustBeStringGot(v.value_type()?))?, } } @@ -423,10 +423,10 @@ } else if let Some(Val::Str(n)) = v.get("__intristic_namespace__".into())? { Val::Intristic(n, s) } else { - create_error(crate::Error::NoSuchField(s))? + create_error_result(crate::Error::NoSuchField(s))? } } - (Val::Obj(_), n) => create_error(crate::Error::ValueIndexMustBeTypeGot( + (Val::Obj(_), n) => create_error_result(crate::Error::ValueIndexMustBeTypeGot( ValType::Obj, ValType::Str, n.value_type()?, @@ -434,17 +434,19 @@ (Val::Arr(v), Val::Num(n)) => { if n.fract() > f64::EPSILON { - create_error(crate::Error::FractionalIndex)? + create_error_result(crate::Error::FractionalIndex)? } v.get(n as usize) - .unwrap_or_else(|| panic!("out of bounds")) + .ok_or_else(|| { + create_error(crate::Error::ArrayBoundsError(n as usize, v.len())) + })? .clone() .unwrap_if_lazy()? } (Val::Arr(_), Val::Str(n)) => { - create_error(crate::Error::AttemptedIndexAnArrayWithString(n))? + create_error_result(crate::Error::AttemptedIndexAnArrayWithString(n))? } - (Val::Arr(_), n) => create_error(crate::Error::ValueIndexMustBeTypeGot( + (Val::Arr(_), n) => create_error_result(crate::Error::ValueIndexMustBeTypeGot( ValType::Arr, ValType::Num, n.value_type()?, @@ -457,13 +459,13 @@ .collect::() .into(), ), - (Val::Str(_), n) => create_error(crate::Error::ValueIndexMustBeTypeGot( + (Val::Str(_), n) => create_error_result(crate::Error::ValueIndexMustBeTypeGot( ValType::Str, ValType::Num, n.value_type()?, ))?, - (v, _) => create_error(crate::Error::CantIndexInto(v.value_type()?))?, + (v, _) => create_error_result(crate::Error::CantIndexInto(v.value_type()?))?, } } LocalExpr(bindings, returned) => { @@ -623,11 +625,7 @@ 0, x: [Val::Str]!!Val::Str, vec![ValType::Str]; ], { with_state(|s| s.0.ext_vars.borrow().get(&x).cloned()).ok_or_else( - || { - create_error::<()>(crate::Error::UndefinedExternalVariable(x)) - .err() - .unwrap() - }, + || create_error(crate::Error::UndefinedExternalVariable(x)), )? }), ("std", "filter") => parse_args!(context, "std.filter", args, 2, [ @@ -728,7 +726,7 @@ Val::Str(manifest_json_ex(&value, &indent)?.into()) }) } - (ns, name) => create_error(crate::error::Error::IntristicNotFound( + (ns, name) => create_error_result(crate::Error::IntristicNotFound( ns.into(), name.into(), ))?, @@ -741,7 +739,7 @@ push(loc, "function call", body)? } } - v => create_error(crate::error::Error::OnlyFunctionsCanBeCalledGot( + v => create_error_result(crate::Error::OnlyFunctionsCanBeCalledGot( v.value_type()?, ))?, } @@ -764,7 +762,7 @@ panic!("assertion failed ({:?}): no message", value); } } - Error(e) => create_error(crate::Error::RuntimeError( + Error(e) => create_error_result(crate::Error::RuntimeError( evaluate(context, e)?.try_cast_str("error text should be string")?, ))?, IfElse { @@ -801,6 +799,8 @@ import_location.pop(); Val::Str(with_state(|s| s.import_file_str(&import_location, path))?) } - Literal(LiteralType::Super) => return create_error(crate::error::Error::StandaloneSuper), + Literal(LiteralType::Super) => { + return create_error_result(crate::Error::StandaloneSuper) + } }) } --- a/crates/jsonnet-evaluator/src/function.rs +++ b/crates/jsonnet-evaluator/src/function.rs @@ -1,4 +1,7 @@ -use crate::{create_error, evaluate, lazy_val, resolved_lazy_val, Context, Error, Result, Val}; +use crate::{ + create_error, create_error_result, evaluate, lazy_val, resolved_lazy_val, Context, Error, + Result, Val, +}; use closure::closure; use jsonnet_parser::{ArgsDesc, ParamsDesc}; use std::collections::HashMap; @@ -21,20 +24,19 @@ let mut positioned_args = vec![None; params.0.len()]; for (id, arg) in args.iter().enumerate() { let idx = if let Some(name) = &arg.0 { - params.iter().position(|p| *p.0 == *name).ok_or_else(|| { - create_error::<()>(Error::UnknownFunctionParameter(name.clone())) - .err() - .unwrap() - })? + params + .iter() + .position(|p| *p.0 == *name) + .ok_or_else(|| create_error(Error::UnknownFunctionParameter(name.clone())))? } else { id }; if idx >= params.len() { - create_error(Error::TooManyArgsFunctionHas(params.len()))?; + create_error_result(Error::TooManyArgsFunctionHas(params.len()))?; } if positioned_args[idx].is_some() { - create_error(Error::BindingParameterASecondTime(params[idx].0.clone()))?; + create_error_result(Error::BindingParameterASecondTime(params[idx].0.clone()))?; } positioned_args[idx] = Some(arg.1.clone()); } @@ -50,7 +52,7 @@ default, ) } else { - create_error(Error::FunctionParameterNotBoundInCall(p.0.clone()))?; + create_error_result(Error::FunctionParameterNotBoundInCall(p.0.clone()))?; unreachable!() }; let val = if tailstrict { @@ -74,7 +76,7 @@ let mut positioned_args = vec![None; params.0.len()]; for (id, arg) in args.iter().enumerate() { if id >= params.len() { - create_error(Error::TooManyArgsFunctionHas(params.len()))?; + create_error_result(Error::TooManyArgsFunctionHas(params.len()))?; } positioned_args[id] = Some(arg); } @@ -85,7 +87,7 @@ } else if let Some(default) = &p.1 { evaluate(ctx.clone(), default)? } else { - create_error(Error::FunctionParameterNotBoundInCall(p.0.clone()))?; + create_error_result(Error::FunctionParameterNotBoundInCall(p.0.clone()))?; unreachable!() }; out.insert(p.0.clone(), resolved_lazy_val!(val)); @@ -99,31 +101,31 @@ ($ctx: expr, $fn_name: expr, $args: expr, $total_args: expr, [ $($id: expr, $name: ident $(: [$($p: path)|+] $(!! $a: path)?)?, $nt: expr);+ $(;)? ], $handler:block) => {{ - use crate::error::Error; + use crate::Error; let args = $args; if args.len() > $total_args { - create_error(Error::TooManyArgsFunctionHas($total_args))?; + create_error_result(Error::TooManyArgsFunctionHas($total_args))?; } $( if args.len() <= $id { - create_error(Error::FunctionParameterNotBoundInCall(stringify!($name).into()))?; + create_error_result(Error::FunctionParameterNotBoundInCall(stringify!($name).into()))?; } let $name = &args[$id]; if $name.0.is_some() { if $name.0.as_ref().unwrap() != stringify!($name) { - create_error(Error::IntristicArgumentReorderingIsNotSupportedYet)?; + create_error_result(Error::IntristicArgumentReorderingIsNotSupportedYet)?; } } let $name = evaluate($ctx.clone(), &$name.1)?; $( match $name { $($p(_))|+ => {}, - _ => create_error(Error::TypeMismatch(concat!($fn_name, " ", stringify!($id), "nd argument"), $nt, $name.value_type()?))?, + _ => create_error_result(Error::TypeMismatch(concat!($fn_name, " ", stringify!($id), "nd argument"), $nt, $name.value_type()?))?, }; $( let $name = match $name { $a(v) => v, - _ => create_error(Error::TypeMismatch(concat!($fn_name, " ", stringify!($id), "nd argument"), $nt, $name.value_type()?))?, + _ => create_error_result(Error::TypeMismatch(concat!($fn_name, " ", stringify!($id), "nd argument"), $nt, $name.value_type()?))?, }; )* )* --- a/crates/jsonnet-evaluator/src/import.rs +++ b/crates/jsonnet-evaluator/src/import.rs @@ -1,5 +1,8 @@ -use crate::create_error; -use crate::error::{Error, Result}; +use crate::create_error_result; +use crate::{ + create_error, + error::{Error, Result}, +}; use fs::File; use std::fs; use std::io::Read; @@ -13,7 +16,7 @@ pub struct DummyImportResolver; impl ImportResolver for DummyImportResolver { fn resolve_file(&self, from: &PathBuf, path: &PathBuf) -> Result> { - create_error(Error::ImportNotSupported(from.clone(), path.clone())) + create_error_result(Error::ImportNotSupported(from.clone(), path.clone())) } fn load_file_contents(&self, _resolved: &PathBuf) -> Result> { // Can be only caused by library direct consumer, not by supplied jsonnet @@ -43,21 +46,15 @@ return Ok(Rc::new(cloned)); } } - create_error(Error::ImportFileNotFound(from.clone(), path.clone())) + create_error_result(Error::ImportFileNotFound(from.clone(), path.clone())) } } fn load_file_contents(&self, id: &PathBuf) -> Result> { - let mut file = File::open(id).map_err(|_e| { - create_error::<()>(Error::ResolvedFileNotFound(id.clone())) - .err() - .unwrap() - })?; + let mut file = + File::open(id).map_err(|_e| create_error(Error::ResolvedFileNotFound(id.clone())))?; let mut out = String::new(); - file.read_to_string(&mut out).map_err(|_e| { - create_error::<()>(Error::ImportBadFileUtf8(id.clone())) - .err() - .unwrap() - })?; + file.read_to_string(&mut out) + .map_err(|_e| create_error(Error::ImportBadFileUtf8(id.clone())))?; Ok(out.into()) } } --- a/crates/jsonnet-evaluator/src/lib.rs +++ b/crates/jsonnet-evaluator/src/lib.rs @@ -87,9 +87,12 @@ pub(crate) fn with_state(f: impl FnOnce(&EvaluationState) -> T) -> T { EVAL_STATE.with(|s| f(s.borrow().as_ref().unwrap())) } -pub(crate) fn create_error(err: Error) -> Result { +pub(crate) fn create_error(err: Error) -> LocError { with_state(|s| s.error(err)) } +pub(crate) fn create_error_result(err: Error) -> Result { + Err(with_state(|s| s.error(err))) +} pub(crate) fn push( e: &Option, comment: &str, @@ -187,9 +190,7 @@ } let contents = self.0.import_resolver.load_file_contents(&file_path)?; self.add_file(file_path.clone(), contents).map_err(|e| { - create_error::<()>(Error::ImportSyntaxError(e)) - .err() - .unwrap() + create_error(Error::ImportSyntaxError(e)) })?; self.evaluate_file(&file_path) } @@ -292,7 +293,7 @@ let mut stack = self.0.stack.borrow_mut(); if stack.len() > self.0.settings.max_stack_frames { drop(stack); - return self.error(Error::StackOverflow); + return Err(self.error(Error::StackOverflow)); } else { stack.push(StackTraceElement(e, comment)); } @@ -318,8 +319,8 @@ .collect(), ) } - pub fn error(&self, err: Error) -> Result { - Err(LocError(err, self.stack_trace())) + pub fn error(&self, err: Error) -> LocError { + LocError(err, self.stack_trace()) } pub fn run_in_state(&self, f: impl FnOnce() -> T) -> T { --- a/crates/jsonnet-evaluator/src/val.rs +++ b/crates/jsonnet-evaluator/src/val.rs @@ -1,5 +1,5 @@ use crate::{ - create_error, evaluate, + create_error_result, evaluate, function::{parse_function_call, place_args}, Context, Error, ObjValue, Result, }; @@ -137,7 +137,7 @@ pub fn assert_type(&self, context: &'static str, val_type: ValType) -> Result<()> { let this_type = self.value_type()?; if this_type != val_type { - create_error(Error::TypeMismatch(context, vec![val_type], this_type)) + create_error_result(Error::TypeMismatch(context, vec![val_type], this_type)) } else { Ok(()) } -- gitstuff