difftreelog
refactor(evaluator) error handling cleanup
in: master
6 files changed
crates/jsonnet-evaluator/src/ctx.rsdiffbeforeafterboth54 }54 }555556 pub fn binding(&self, name: Rc<str>) -> Result<LazyVal> {56 pub fn binding(&self, name: Rc<str>) -> Result<LazyVal> {57 self.0.bindings.get(&name).cloned().ok_or_else(|| {57 self.058 .bindings59 .get(&name)60 .cloned()58 create_error::<()>(Error::UnknownVariable(name))61 .ok_or_else(|| create_error(Error::UnknownVariable(name)))59 .err()60 .unwrap()61 })62 }62 }63 pub fn into_future(self, ctx: FutureContext) -> Context {63 pub fn into_future(self, ctx: FutureContext) -> Context {64 {64 {crates/jsonnet-evaluator/src/evaluate.rsdiffbeforeafterboth1use crate::{1use crate::{2 context_creator, create_error, escape_string_json, future_wrapper, lazy_val, manifest_json_ex,2 context_creator, create_error, create_error_result, escape_string_json, future_wrapper,3 parse_args, push, with_state, Context, ContextCreator, Error, FuncDesc, LazyBinding, LazyVal,3 lazy_val, manifest_json_ex, parse_args, push, with_state, Context, ContextCreator, Error,4 ObjMember, ObjValue, Result, Val, ValType,4 FuncDesc, LazyBinding, LazyVal, ObjMember, ObjValue, Result, Val, ValType,5};5};74 (UnaryOpType::Not, Val::Bool(v)) => Val::Bool(!v),74 (UnaryOpType::Not, Val::Bool(v)) => Val::Bool(!v),75 (UnaryOpType::Minus, Val::Num(n)) => Val::Num(-*n),75 (UnaryOpType::Minus, Val::Num(n)) => Val::Num(-*n),76 (UnaryOpType::BitNot, Val::Num(n)) => Val::Num(!(*n as i32) as f64),76 (UnaryOpType::BitNot, Val::Num(n)) => Val::Num(!(*n as i32) as f64),77 (op, o) => create_error(Error::UnaryOperatorDoesNotOperateOnType(77 (op, o) => create_error_result(Error::UnaryOperatorDoesNotOperateOnType(78 op,78 op,79 o.value_type()?,79 o.value_type()?,80 ))?,80 ))?,95 (Val::Obj(v1), Val::Obj(v2)) => Val::Obj(v2.with_super(v1.clone())),95 (Val::Obj(v1), Val::Obj(v2)) => Val::Obj(v2.with_super(v1.clone())),96 (Val::Arr(a), Val::Arr(b)) => Val::Arr(Rc::new([&a[..], &b[..]].concat())),96 (Val::Arr(a), Val::Arr(b)) => Val::Arr(Rc::new([&a[..], &b[..]].concat())),97 (Val::Num(v1), Val::Num(v2)) => Val::Num(v1 + v2),97 (Val::Num(v1), Val::Num(v2)) => Val::Num(v1 + v2),98 _ => create_error(Error::BinaryOperatorDoesNotOperateOnValues(98 _ => create_error_result(Error::BinaryOperatorDoesNotOperateOnValues(99 BinaryOpType::Add,99 BinaryOpType::Add,100 a.value_type()?,100 a.value_type()?,101 b.value_type()?,101 b.value_type()?,140 (Val::Num(v1), BinaryOpType::Mul, Val::Num(v2)) => Val::Num(v1 * v2),140 (Val::Num(v1), BinaryOpType::Mul, Val::Num(v2)) => Val::Num(v1 * v2),141 (Val::Num(v1), BinaryOpType::Div, Val::Num(v2)) => {141 (Val::Num(v1), BinaryOpType::Div, Val::Num(v2)) => {142 if *v2 <= f64::EPSILON {142 if *v2 <= f64::EPSILON {143 create_error(crate::Error::DivisionByZero)?143 create_error_result(crate::Error::DivisionByZero)?144 }144 }145 Val::Num(v1 / v2)145 Val::Num(v1 / v2)146 }146 }168 Val::Num(((*v1 as i32) >> (*v2 as i32)) as f64)168 Val::Num(((*v1 as i32) >> (*v2 as i32)) as f64)169 }169 }170170171 _ => create_error(Error::BinaryOperatorDoesNotOperateOnValues(171 _ => create_error_result(Error::BinaryOperatorDoesNotOperateOnValues(172 op,172 op,173 a.value_type()?,173 a.value_type()?,174 b.value_type()?,174 b.value_type()?,367 },367 },368 );368 );369 }369 }370 v => create_error(Error::FieldMustBeStringGot(v.value_type()?))?,370 v => create_error_result(Error::FieldMustBeStringGot(v.value_type()?))?,371 }371 }372 }372 }373373423 } else if let Some(Val::Str(n)) = v.get("__intristic_namespace__".into())? {423 } else if let Some(Val::Str(n)) = v.get("__intristic_namespace__".into())? {424 Val::Intristic(n, s)424 Val::Intristic(n, s)425 } else {425 } else {426 create_error(crate::Error::NoSuchField(s))?426 create_error_result(crate::Error::NoSuchField(s))?427 }427 }428 }428 }429 (Val::Obj(_), n) => create_error(crate::Error::ValueIndexMustBeTypeGot(429 (Val::Obj(_), n) => create_error_result(crate::Error::ValueIndexMustBeTypeGot(430 ValType::Obj,430 ValType::Obj,431 ValType::Str,431 ValType::Str,432 n.value_type()?,432 n.value_type()?,433 ))?,433 ))?,434434435 (Val::Arr(v), Val::Num(n)) => {435 (Val::Arr(v), Val::Num(n)) => {436 if n.fract() > f64::EPSILON {436 if n.fract() > f64::EPSILON {437 create_error(crate::Error::FractionalIndex)?437 create_error_result(crate::Error::FractionalIndex)?438 }438 }439 v.get(n as usize)439 v.get(n as usize)440 .unwrap_or_else(|| panic!("out of bounds"))440 .ok_or_else(|| {441 create_error(crate::Error::ArrayBoundsError(n as usize, v.len()))442 })?441 .clone()443 .clone()442 .unwrap_if_lazy()?444 .unwrap_if_lazy()?443 }445 }444 (Val::Arr(_), Val::Str(n)) => {446 (Val::Arr(_), Val::Str(n)) => {445 create_error(crate::Error::AttemptedIndexAnArrayWithString(n))?447 create_error_result(crate::Error::AttemptedIndexAnArrayWithString(n))?446 }448 }447 (Val::Arr(_), n) => create_error(crate::Error::ValueIndexMustBeTypeGot(449 (Val::Arr(_), n) => create_error_result(crate::Error::ValueIndexMustBeTypeGot(448 ValType::Arr,450 ValType::Arr,449 ValType::Num,451 ValType::Num,450 n.value_type()?,452 n.value_type()?,457 .collect::<String>()459 .collect::<String>()458 .into(),460 .into(),459 ),461 ),460 (Val::Str(_), n) => create_error(crate::Error::ValueIndexMustBeTypeGot(462 (Val::Str(_), n) => create_error_result(crate::Error::ValueIndexMustBeTypeGot(461 ValType::Str,463 ValType::Str,462 ValType::Num,464 ValType::Num,463 n.value_type()?,465 n.value_type()?,464 ))?,466 ))?,465467466 (v, _) => create_error(crate::Error::CantIndexInto(v.value_type()?))?,468 (v, _) => create_error_result(crate::Error::CantIndexInto(v.value_type()?))?,467 }469 }468 }470 }469 LocalExpr(bindings, returned) => {471 LocalExpr(bindings, returned) => {623 0, x: [Val::Str]!!Val::Str, vec![ValType::Str];625 0, x: [Val::Str]!!Val::Str, vec![ValType::Str];624 ], {626 ], {625 with_state(|s| s.0.ext_vars.borrow().get(&x).cloned()).ok_or_else(627 with_state(|s| s.0.ext_vars.borrow().get(&x).cloned()).ok_or_else(626 || {628 || create_error(crate::Error::UndefinedExternalVariable(x)),627 create_error::<()>(crate::Error::UndefinedExternalVariable(x))628 .err()629 .unwrap()630 },631 )?629 )?632 }),630 }),633 ("std", "filter") => parse_args!(context, "std.filter", args, 2, [631 ("std", "filter") => parse_args!(context, "std.filter", args, 2, [728 Val::Str(manifest_json_ex(&value, &indent)?.into())726 Val::Str(manifest_json_ex(&value, &indent)?.into())729 })727 })730 }728 }731 (ns, name) => create_error(crate::error::Error::IntristicNotFound(729 (ns, name) => create_error_result(crate::Error::IntristicNotFound(732 ns.into(),730 ns.into(),733 name.into(),731 name.into(),734 ))?,732 ))?,741 push(loc, "function call", body)?739 push(loc, "function call", body)?742 }740 }743 }741 }744 v => create_error(crate::error::Error::OnlyFunctionsCanBeCalledGot(742 v => create_error_result(crate::Error::OnlyFunctionsCanBeCalledGot(745 v.value_type()?,743 v.value_type()?,746 ))?,744 ))?,747 }745 }764 panic!("assertion failed ({:?}): no message", value);762 panic!("assertion failed ({:?}): no message", value);765 }763 }766 }764 }767 Error(e) => create_error(crate::Error::RuntimeError(765 Error(e) => create_error_result(crate::Error::RuntimeError(768 evaluate(context, e)?.try_cast_str("error text should be string")?,766 evaluate(context, e)?.try_cast_str("error text should be string")?,769 ))?,767 ))?,770 IfElse {768 IfElse {801 import_location.pop();799 import_location.pop();802 Val::Str(with_state(|s| s.import_file_str(&import_location, path))?)800 Val::Str(with_state(|s| s.import_file_str(&import_location, path))?)803 }801 }804 Literal(LiteralType::Super) => return create_error(crate::error::Error::StandaloneSuper),802 Literal(LiteralType::Super) => {803 return create_error_result(crate::Error::StandaloneSuper)804 }805 })805 })806}806}807807crates/jsonnet-evaluator/src/function.rsdiffbeforeafterboth1use crate::{create_error, evaluate, lazy_val, resolved_lazy_val, Context, Error, Result, Val};1use crate::{2 create_error, create_error_result, evaluate, lazy_val, resolved_lazy_val, Context, Error,3 Result, Val,4};2use closure::closure;5use closure::closure;3use jsonnet_parser::{ArgsDesc, ParamsDesc};6use jsonnet_parser::{ArgsDesc, ParamsDesc};21 let mut positioned_args = vec![None; params.0.len()];24 let mut positioned_args = vec![None; params.0.len()];22 for (id, arg) in args.iter().enumerate() {25 for (id, arg) in args.iter().enumerate() {23 let idx = if let Some(name) = &arg.0 {26 let idx = if let Some(name) = &arg.0 {24 params.iter().position(|p| *p.0 == *name).ok_or_else(|| {27 params28 .iter()29 .position(|p| *p.0 == *name)25 create_error::<()>(Error::UnknownFunctionParameter(name.clone()))30 .ok_or_else(|| create_error(Error::UnknownFunctionParameter(name.clone())))?26 .err()27 .unwrap()28 })?29 } else {31 } else {30 id32 id31 };33 };323433 if idx >= params.len() {35 if idx >= params.len() {34 create_error(Error::TooManyArgsFunctionHas(params.len()))?;36 create_error_result(Error::TooManyArgsFunctionHas(params.len()))?;35 }37 }36 if positioned_args[idx].is_some() {38 if positioned_args[idx].is_some() {37 create_error(Error::BindingParameterASecondTime(params[idx].0.clone()))?;39 create_error_result(Error::BindingParameterASecondTime(params[idx].0.clone()))?;38 }40 }39 positioned_args[idx] = Some(arg.1.clone());41 positioned_args[idx] = Some(arg.1.clone());40 }42 }50 default,52 default,51 )53 )52 } else {54 } else {53 create_error(Error::FunctionParameterNotBoundInCall(p.0.clone()))?;55 create_error_result(Error::FunctionParameterNotBoundInCall(p.0.clone()))?;54 unreachable!()56 unreachable!()55 };57 };56 let val = if tailstrict {58 let val = if tailstrict {74 let mut positioned_args = vec![None; params.0.len()];76 let mut positioned_args = vec![None; params.0.len()];75 for (id, arg) in args.iter().enumerate() {77 for (id, arg) in args.iter().enumerate() {76 if id >= params.len() {78 if id >= params.len() {77 create_error(Error::TooManyArgsFunctionHas(params.len()))?;79 create_error_result(Error::TooManyArgsFunctionHas(params.len()))?;78 }80 }79 positioned_args[id] = Some(arg);81 positioned_args[id] = Some(arg);80 }82 }85 } else if let Some(default) = &p.1 {87 } else if let Some(default) = &p.1 {86 evaluate(ctx.clone(), default)?88 evaluate(ctx.clone(), default)?87 } else {89 } else {88 create_error(Error::FunctionParameterNotBoundInCall(p.0.clone()))?;90 create_error_result(Error::FunctionParameterNotBoundInCall(p.0.clone()))?;89 unreachable!()91 unreachable!()90 };92 };91 out.insert(p.0.clone(), resolved_lazy_val!(val));93 out.insert(p.0.clone(), resolved_lazy_val!(val));99 ($ctx: expr, $fn_name: expr, $args: expr, $total_args: expr, [101 ($ctx: expr, $fn_name: expr, $args: expr, $total_args: expr, [100 $($id: expr, $name: ident $(: [$($p: path)|+] $(!! $a: path)?)?, $nt: expr);+ $(;)?102 $($id: expr, $name: ident $(: [$($p: path)|+] $(!! $a: path)?)?, $nt: expr);+ $(;)?101 ], $handler:block) => {{103 ], $handler:block) => {{102 use crate::error::Error;104 use crate::Error;103 let args = $args;105 let args = $args;104 if args.len() > $total_args {106 if args.len() > $total_args {105 create_error(Error::TooManyArgsFunctionHas($total_args))?;107 create_error_result(Error::TooManyArgsFunctionHas($total_args))?;106 }108 }107 $(109 $(108 if args.len() <= $id {110 if args.len() <= $id {109 create_error(Error::FunctionParameterNotBoundInCall(stringify!($name).into()))?;111 create_error_result(Error::FunctionParameterNotBoundInCall(stringify!($name).into()))?;110 }112 }111 let $name = &args[$id];113 let $name = &args[$id];112 if $name.0.is_some() {114 if $name.0.is_some() {113 if $name.0.as_ref().unwrap() != stringify!($name) {115 if $name.0.as_ref().unwrap() != stringify!($name) {114 create_error(Error::IntristicArgumentReorderingIsNotSupportedYet)?;116 create_error_result(Error::IntristicArgumentReorderingIsNotSupportedYet)?;115 }117 }116 }118 }117 let $name = evaluate($ctx.clone(), &$name.1)?;119 let $name = evaluate($ctx.clone(), &$name.1)?;118 $(120 $(119 match $name {121 match $name {120 $($p(_))|+ => {},122 $($p(_))|+ => {},121 _ => create_error(Error::TypeMismatch(concat!($fn_name, " ", stringify!($id), "nd argument"), $nt, $name.value_type()?))?,123 _ => create_error_result(Error::TypeMismatch(concat!($fn_name, " ", stringify!($id), "nd argument"), $nt, $name.value_type()?))?,122 };124 };123 $(125 $(124 let $name = match $name {126 let $name = match $name {125 $a(v) => v,127 $a(v) => v,126 _ => create_error(Error::TypeMismatch(concat!($fn_name, " ", stringify!($id), "nd argument"), $nt, $name.value_type()?))?,128 _ => create_error_result(Error::TypeMismatch(concat!($fn_name, " ", stringify!($id), "nd argument"), $nt, $name.value_type()?))?,127 };129 };128 )*130 )*129 )*131 )*crates/jsonnet-evaluator/src/import.rsdiffbeforeafterboth1use crate::create_error;1use crate::create_error_result;2use crate::error::{Error, Result};2use crate::{3 create_error,4 error::{Error, Result},5};3use fs::File;6use fs::File;4use std::fs;7use std::fs;5use std::io::Read;8use std::io::Read;13pub struct DummyImportResolver;16pub struct DummyImportResolver;14impl ImportResolver for DummyImportResolver {17impl ImportResolver for DummyImportResolver {15 fn resolve_file(&self, from: &PathBuf, path: &PathBuf) -> Result<Rc<PathBuf>> {18 fn resolve_file(&self, from: &PathBuf, path: &PathBuf) -> Result<Rc<PathBuf>> {16 create_error(Error::ImportNotSupported(from.clone(), path.clone()))19 create_error_result(Error::ImportNotSupported(from.clone(), path.clone()))17 }20 }18 fn load_file_contents(&self, _resolved: &PathBuf) -> Result<Rc<str>> {21 fn load_file_contents(&self, _resolved: &PathBuf) -> Result<Rc<str>> {19 // Can be only caused by library direct consumer, not by supplied jsonnet22 // Can be only caused by library direct consumer, not by supplied jsonnet43 return Ok(Rc::new(cloned));46 return Ok(Rc::new(cloned));44 }47 }45 }48 }46 create_error(Error::ImportFileNotFound(from.clone(), path.clone()))49 create_error_result(Error::ImportFileNotFound(from.clone(), path.clone()))47 }50 }48 }51 }49 fn load_file_contents(&self, id: &PathBuf) -> Result<Rc<str>> {52 fn load_file_contents(&self, id: &PathBuf) -> Result<Rc<str>> {50 let mut file = File::open(id).map_err(|_e| {53 let mut file =51 create_error::<()>(Error::ResolvedFileNotFound(id.clone()))54 File::open(id).map_err(|_e| create_error(Error::ResolvedFileNotFound(id.clone())))?;52 .err()53 .unwrap()54 })?;55 let mut out = String::new();55 let mut out = String::new();56 file.read_to_string(&mut out).map_err(|_e| {56 file.read_to_string(&mut out)57 create_error::<()>(Error::ImportBadFileUtf8(id.clone()))57 .map_err(|_e| create_error(Error::ImportBadFileUtf8(id.clone())))?;58 .err()59 .unwrap()60 })?;61 Ok(out.into())58 Ok(out.into())62 }59 }63}60}crates/jsonnet-evaluator/src/lib.rsdiffbeforeafterboth87pub(crate) fn with_state<T>(f: impl FnOnce(&EvaluationState) -> T) -> T {87pub(crate) fn with_state<T>(f: impl FnOnce(&EvaluationState) -> T) -> T {88 EVAL_STATE.with(|s| f(s.borrow().as_ref().unwrap()))88 EVAL_STATE.with(|s| f(s.borrow().as_ref().unwrap()))89}89}90pub(crate) fn create_error<T>(err: Error) -> Result<T> {90pub(crate) fn create_error(err: Error) -> LocError {91 with_state(|s| s.error(err))92}93pub(crate) fn create_error_result<T>(err: Error) -> Result<T> {91 with_state(|s| s.error(err))94 Err(with_state(|s| s.error(err)))92}95}93pub(crate) fn push<T>(96pub(crate) fn push<T>(94 e: &Option<ExprLocation>,97 e: &Option<ExprLocation>,187 }190 }188 let contents = self.0.import_resolver.load_file_contents(&file_path)?;191 let contents = self.0.import_resolver.load_file_contents(&file_path)?;189 self.add_file(file_path.clone(), contents).map_err(|e| {192 self.add_file(file_path.clone(), contents).map_err(|e| {190 create_error::<()>(Error::ImportSyntaxError(e))193 create_error(Error::ImportSyntaxError(e))191 .err()192 .unwrap()193 })?;194 })?;194 self.evaluate_file(&file_path)195 self.evaluate_file(&file_path)195 }196 }292 let mut stack = self.0.stack.borrow_mut();293 let mut stack = self.0.stack.borrow_mut();293 if stack.len() > self.0.settings.max_stack_frames {294 if stack.len() > self.0.settings.max_stack_frames {294 drop(stack);295 drop(stack);295 return self.error(Error::StackOverflow);296 return Err(self.error(Error::StackOverflow));296 } else {297 } else {297 stack.push(StackTraceElement(e, comment));298 stack.push(StackTraceElement(e, comment));298 }299 }318 .collect(),319 .collect(),319 )320 )320 }321 }321 pub fn error<T>(&self, err: Error) -> Result<T> {322 pub fn error(&self, err: Error) -> LocError {322 Err(LocError(err, self.stack_trace()))323 LocError(err, self.stack_trace())323 }324 }324325325 pub fn run_in_state<T>(&self, f: impl FnOnce() -> T) -> T {326 pub fn run_in_state<T>(&self, f: impl FnOnce() -> T) -> T {crates/jsonnet-evaluator/src/val.rsdiffbeforeafterboth1use crate::{1use crate::{2 create_error, evaluate,2 create_error_result, evaluate,3 function::{parse_function_call, place_args},3 function::{parse_function_call, place_args},4 Context, Error, ObjValue, Result,4 Context, Error, ObjValue, Result,5};5};137 pub fn assert_type(&self, context: &'static str, val_type: ValType) -> Result<()> {137 pub fn assert_type(&self, context: &'static str, val_type: ValType) -> Result<()> {138 let this_type = self.value_type()?;138 let this_type = self.value_type()?;139 if this_type != val_type {139 if this_type != val_type {140 create_error(Error::TypeMismatch(context, vec![val_type], this_type))140 create_error_result(Error::TypeMismatch(context, vec![val_type], this_type))141 } else {141 } else {142 Ok(())142 Ok(())143 }143 }