--- a/bindings/jsonnet/src/import.rs +++ b/bindings/jsonnet/src/import.rs @@ -13,8 +13,9 @@ }; use jrsonnet_evaluator::{ + bail, error::{ErrorKind::*, Result}, - throw, FileImportResolver, ImportResolver, + FileImportResolver, ImportResolver, }; use jrsonnet_gcmodule::Trace; use jrsonnet_parser::{SourceDirectory, SourceFile, SourcePath}; @@ -80,7 +81,7 @@ assert!(success == 0 || success == 1); if success == 0 { let result = String::from_utf8(buf_intern).expect("error should be valid string"); - throw!(ImportCallbackError(result)); + bail!(ImportCallbackError(result)); } let found_here_raw = unsafe { CStr::from_ptr(found_here) }; --- a/bindings/jsonnet/src/lib.rs +++ b/bindings/jsonnet/src/lib.rs @@ -19,12 +19,12 @@ }; use jrsonnet_evaluator::{ - apply_tla, + apply_tla, bail, function::TlaArg, gc::GcHashMap, manifest::{JsonFormat, ManifestFormat, ToStringFormat}, stack::set_stack_depth_limit, - tb, throw, + tb, trace::{CompactFormat, PathResolver, TraceFormat}, FileImportResolver, IStr, Result, State, Val, }; @@ -249,7 +249,7 @@ fn val_to_multi(val: Val, format: &dyn ManifestFormat) -> Result> { let Val::Obj(val) = val else { - throw!("expected object as multi output") + bail!("expected object as multi output") }; let mut out = Vec::new(); for (k, v) in val.iter( @@ -336,7 +336,7 @@ fn val_to_stream(val: Val, format: &dyn ManifestFormat) -> Result> { let Val::Arr(val) = val else { - throw!("expected array as stream output") + bail!("expected array as stream output") }; let mut out = Vec::new(); for item in val.iter() { --- a/cmds/jrsonnet/src/main.rs +++ b/cmds/jrsonnet/src/main.rs @@ -7,9 +7,9 @@ use clap_complete::Shell; use jrsonnet_cli::{GcOpts, ManifestOpts, MiscOpts, OutputOpts, StdOpts, TlaOpts, TraceOpts}; use jrsonnet_evaluator::{ - apply_tla, + apply_tla, bail, error::{Error as JrError, ErrorKind}, - throw, ResultExt, State, Val, + ResultExt, State, Val, }; #[cfg(feature = "mimalloc")] @@ -208,7 +208,7 @@ create_dir_all(dir)?; } let Val::Obj(obj) = val else { - throw!( + bail!( "value should be object for --multi manifest, got {}", val.value_type() ) --- a/crates/jrsonnet-evaluator/src/ctx.rs +++ b/crates/jrsonnet-evaluator/src/ctx.rs @@ -54,7 +54,7 @@ pub fn binding(&self, name: IStr) -> Result> { use std::cmp::Ordering; - use crate::throw; + use crate::bail; if let Some(val) = self.0.bindings.get(&name).cloned() { return Ok(val); @@ -70,7 +70,7 @@ }); heap.sort_by(|a, b| b.0.partial_cmp(&a.0).unwrap_or(Ordering::Equal)); - throw!(VariableIsNotDefined( + bail!(VariableIsNotDefined( name, heap.into_iter().map(|(_, k)| k).collect() )) --- a/crates/jrsonnet-evaluator/src/dynamic.rs +++ b/crates/jrsonnet-evaluator/src/dynamic.rs @@ -2,7 +2,7 @@ use jrsonnet_gcmodule::{Cc, Trace}; -use crate::{error::ErrorKind::InfiniteRecursionDetected, throw, val::ThunkValue, Result, Thunk}; +use crate::{bail, error::ErrorKind::InfiniteRecursionDetected, val::ThunkValue, Result}; // TODO: Replace with OnceCell once in std #[derive(Clone, Trace)] @@ -41,7 +41,7 @@ fn get(self: Box) -> Result { let Some(value) = self.0.get() else { - throw!(InfiniteRecursionDetected); + bail!(InfiniteRecursionDetected); }; Ok(value.clone()) } --- a/crates/jrsonnet-evaluator/src/error.rs +++ b/crates/jrsonnet-evaluator/src/error.rs @@ -370,17 +370,21 @@ } #[macro_export] -macro_rules! throw { +macro_rules! bail { ($w:ident$(::$i:ident)*$(($($tt:tt)*))?) => { return Err($w$(::$i)*$(($($tt)*))?.into()) }; ($w:ident$(::$i:ident)*$({$($tt:tt)*})?) => { return Err($w$(::$i)*$({$($tt)*})?.into()) }; - ($l:literal) => { - return Err($crate::error::ErrorKind::RuntimeError($l.into()).into()) + ($l:literal$(, $($tt:tt)*)?) => { + return Err($crate::error::ErrorKind::RuntimeError(format!($l$(, $($tt)*)?).into()).into()) }; - ($l:literal, $($tt:tt)*) => { - return Err($crate::error::ErrorKind::RuntimeError(format!($l, $($tt)*).into()).into()) +} + +#[macro_export] +macro_rules! runtime_error { + ($l:literal$(, $($tt:tt)*)?) => { + $crate::error::Error::from($crate::error::ErrorKind::RuntimeError(format!($l$(, $($tt)*)?).into())) }; } --- a/crates/jrsonnet-evaluator/src/evaluate/destructure.rs +++ b/crates/jrsonnet-evaluator/src/evaluate/destructure.rs @@ -3,10 +3,10 @@ use jrsonnet_parser::{BindSpec, Destruct, LocExpr, ParamsDesc}; use crate::{ + bail, error::{ErrorKind::*, Result}, evaluate, evaluate_method, evaluate_named, gc::GcHashMap, - throw, val::ThunkValue, Context, Pending, Thunk, Val, }; @@ -23,7 +23,7 @@ Destruct::Full(v) => { let old = new_bindings.insert(v.clone(), parent); if old.is_some() { - throw!(DuplicateLocalVar(v.clone())) + bail!(DuplicateLocalVar(v.clone())) } } #[cfg(feature = "exp-destruct")] @@ -46,14 +46,14 @@ fn get(self: Box) -> Result { let v = self.parent.evaluate()?; let Val::Arr(arr) = v else { - throw!("expected array"); + bail!("expected array"); }; if !self.has_rest { if arr.len() != self.min_len { - throw!("expected {} elements, got {}", self.min_len, arr.len()) + bail!("expected {} elements, got {}", self.min_len, arr.len()) } } else if arr.len() < self.min_len { - throw!( + bail!( "expected at least {} elements, but array was only {}", self.min_len, arr.len() @@ -178,17 +178,17 @@ fn get(self: Box) -> Result { let v = self.parent.evaluate()?; let Val::Obj(obj) = v else { - throw!("expected object"); + bail!("expected object"); }; for field in &self.field_names { if !obj.has_field_ex(field.clone(), true) { - throw!("missing field: {}", field); + bail!("missing field: {field}"); } } if !self.has_rest { let len = obj.len(); if len != self.field_names.len() { - throw!("too many fields, and rest not found"); + bail!("too many fields, and rest not found"); } } Ok(obj) @@ -310,7 +310,7 @@ }), ); if old.is_some() { - throw!(DuplicateLocalVar(name.clone())) + bail!(DuplicateLocalVar(name.clone())) } } } --- a/crates/jrsonnet-evaluator/src/evaluate/mod.rs +++ b/crates/jrsonnet-evaluator/src/evaluate/mod.rs @@ -11,11 +11,11 @@ use self::destructure::destruct; use crate::{ arr::ArrValue, + bail, destructure::evaluate_dest, error::{suggest_object_fields, ErrorKind::*}, evaluate::operator::{evaluate_add_op, evaluate_binary_op_special, evaluate_unary_op}, function::{CallLocation, FuncDesc, FuncVal}, - throw, typed::Typed, val::{CachedUnbound, IndexableVal, StrValue, Thunk, ThunkValue}, Context, GcHashMap, ObjValue, ObjValueBuilder, ObjectAssertion, Pending, Result, ResultExt, @@ -150,7 +150,7 @@ evaluate_comp(ctx, &specs[1..], callback)?; } } - _ => throw!(InComprehensionCanOnlyIterateOverArray), + _ => bail!(InComprehensionCanOnlyIterateOverArray), }, } Ok(()) @@ -375,7 +375,7 @@ State::push(loc, || format!("function <{}> call", f.name()), body)? } } - v => throw!(OnlyFunctionsCanBeCalledGot(v.value_type())), + v => bail!(OnlyFunctionsCanBeCalledGot(v.value_type())), }) } @@ -393,9 +393,9 @@ || "assertion failure".to_owned(), || { if let Some(msg) = msg { - throw!(AssertionFailed(evaluate(ctx, msg)?.to_string()?)); + bail!(AssertionFailed(evaluate(ctx, msg)?.to_string()?)); } - throw!(AssertionFailed(Val::Null.to_string()?)); + bail!(AssertionFailed(Val::Null.to_string()?)); }, )?; } @@ -457,12 +457,12 @@ if part.null_coaelse { return Ok(Val::Null); } - throw!(NoSuperFound) + bail!(NoSuperFound) }; let name = evaluate(ctx.clone(), &part.value)?; let Val::Str(name) = name else { - throw!(ValueIndexMustBeTypeGot( + bail!(ValueIndexMustBeTypeGot( ValType::Obj, ValType::Str, name.value_type(), @@ -483,7 +483,7 @@ None => { let suggestions = suggest_object_fields(super_obj, name.clone()); - throw!(NoSuchField(name, suggestions)) + bail!(NoSuchField(name, suggestions)) } } } @@ -502,25 +502,25 @@ None => { let suggestions = suggest_object_fields(&v, key.clone().into_flat()); - throw!(NoSuchField(key.clone().into_flat(), suggestions)) + bail!(NoSuchField(key.clone().into_flat(), suggestions)) } }, - (Val::Obj(_), n) => throw!(ValueIndexMustBeTypeGot( + (Val::Obj(_), n) => bail!(ValueIndexMustBeTypeGot( ValType::Obj, ValType::Str, n.value_type(), )), (Val::Arr(v), Val::Num(n)) => { if n.fract() > f64::EPSILON { - throw!(FractionalIndex) + bail!(FractionalIndex) } v.get(n as usize)? .ok_or_else(|| ArrayBoundsError(n as usize, v.len()))? } (Val::Arr(_), Val::Str(n)) => { - throw!(AttemptedIndexAnArrayWithString(n.into_flat())) + bail!(AttemptedIndexAnArrayWithString(n.into_flat())) } - (Val::Arr(_), n) => throw!(ValueIndexMustBeTypeGot( + (Val::Arr(_), n) => bail!(ValueIndexMustBeTypeGot( ValType::Arr, ValType::Num, n.value_type(), @@ -537,18 +537,18 @@ .into(); if v.is_empty() { let size = s.into_flat().chars().count(); - throw!(StringBoundsError(n as usize, size)) + bail!(StringBoundsError(n as usize, size)) } StrValue::Flat(v) }), - (Val::Str(_), n) => throw!(ValueIndexMustBeTypeGot( + (Val::Str(_), n) => bail!(ValueIndexMustBeTypeGot( ValType::Str, ValType::Num, n.value_type(), )), #[cfg(feature = "exp-null-coaelse")] (Val::Null, _) if part.null_coaelse => return Ok(Val::Null), - (v, _) => throw!(CantIndexInto(v.value_type())), + (v, _) => bail!(CantIndexInto(v.value_type())), }; } indexable @@ -612,7 +612,7 @@ ErrorStmt(e) => State::push( CallLocation::new(loc), || "error statement".to_owned(), - || throw!(RuntimeError(evaluate(ctx, e)?.to_string()?,)), + || bail!(RuntimeError(evaluate(ctx, e)?.to_string()?,)), )?, IfElse { cond, @@ -661,7 +661,7 @@ } i @ (Import(path) | ImportStr(path) | ImportBin(path)) => { let Expr::Str(path) = &*path.0 else { - throw!("computed imports are not supported") + bail!("computed imports are not supported") }; let tmp = loc.clone().0; let s = ctx.state(); --- a/crates/jrsonnet-evaluator/src/evaluate/operator.rs +++ b/crates/jrsonnet-evaluator/src/evaluate/operator.rs @@ -4,10 +4,10 @@ use crate::{ arr::ArrValue, + bail, error::ErrorKind::*, evaluate, stdlib::std_format, - throw, typed::Typed, val::{equals, StrValue}, Context, Result, Val, @@ -21,7 +21,7 @@ (Minus, Num(n)) => Num(-*n), (Not, Bool(v)) => Bool(!v), (BitNot, Num(n)) => Num(!(*n as i64) as f64), - (op, o) => throw!(UnaryOperatorDoesNotOperateOnType(op, o.value_type())), + (op, o) => bail!(UnaryOperatorDoesNotOperateOnType(op, o.value_type())), }) } @@ -49,7 +49,7 @@ (Num(v1), Num(v2)) => Val::new_checked_num(v1 + v2)?, #[cfg(feature = "exp-bigint")] (BigInt(a), BigInt(b)) => BigInt(Box::new((&**a).clone() + (&**b).clone())), - _ => throw!(BinaryOperatorDoesNotOperateOnValues( + _ => bail!(BinaryOperatorDoesNotOperateOnValues( BinaryOpType::Add, a.value_type(), b.value_type(), @@ -62,14 +62,14 @@ match (a, b) { (Num(a), Num(b)) => { if *b == 0.0 { - throw!(DivisionByZero) + bail!(DivisionByZero) } Ok(Num(a % b)) } (Str(str), vals) => { String::into_untyped(std_format(&str.clone().into_flat(), vals.clone())?) } - (a, b) => throw!(BinaryOperatorDoesNotOperateOnValues( + (a, b) => bail!(BinaryOperatorDoesNotOperateOnValues( BinaryOpType::Mod, a.value_type(), b.value_type() @@ -124,7 +124,7 @@ } a.len().cmp(&b.len()) } - (_, _) => throw!(BinaryOperatorDoesNotOperateOnValues( + (_, _) => bail!(BinaryOperatorDoesNotOperateOnValues( op, a.value_type(), b.value_type() @@ -159,7 +159,7 @@ (Num(v1), Mul, Num(v2)) => Val::new_checked_num(v1 * v2)?, (Num(v1), Div, Num(v2)) => { if *v2 == 0.0 { - throw!(DivisionByZero) + bail!(DivisionByZero) } Val::new_checked_num(v1 / v2)? } @@ -171,14 +171,14 @@ (Num(v1), BitXor, Num(v2)) => Num((*v1 as i64 ^ *v2 as i64) as f64), (Num(v1), Lhs, Num(v2)) => { if *v2 < 0.0 { - throw!("shift by negative exponent") + bail!("shift by negative exponent") } let exp = ((*v2 as i64) & 63) as u32; Num((*v1 as i64).wrapping_shl(exp) as f64) } (Num(v1), Rhs, Num(v2)) => { if *v2 < 0.0 { - throw!("shift by negative exponent") + bail!("shift by negative exponent") } let exp = ((*v2 as i64) & 63) as u32; Num((*v1 as i64).wrapping_shr(exp) as f64) @@ -190,7 +190,7 @@ #[cfg(feature = "exp-bigint")] (BigInt(a), Sub, BigInt(b)) => BigInt(Box::new((&**a).clone() - (&**b).clone())), - _ => throw!(BinaryOperatorDoesNotOperateOnValues( + _ => bail!(BinaryOperatorDoesNotOperateOnValues( op, a.value_type(), b.value_type(), --- a/crates/jrsonnet-evaluator/src/function/arglike.rs +++ b/crates/jrsonnet-evaluator/src/function/arglike.rs @@ -3,14 +3,7 @@ use jrsonnet_interner::IStr; use jrsonnet_parser::{ArgsDesc, LocExpr}; -use crate::{ - error::Result, - evaluate, - gc::GcHashMap, - typed::Typed, - val::{StrValue, ThunkValue}, - Context, Thunk, Val, -}; +use crate::{evaluate, gc::GcHashMap, typed::Typed, val::ThunkValue, Context, Result, Thunk, Val}; /// Marker for arguments, which can be evaluated with context set to None pub trait OptionalContext {} --- a/crates/jrsonnet-evaluator/src/function/builtin.rs +++ b/crates/jrsonnet-evaluator/src/function/builtin.rs @@ -4,7 +4,7 @@ use jrsonnet_interner::IStr; use super::{arglike::ArgsLike, parse::parse_builtin_call, CallLocation}; -use crate::{error::Result, gc::TraceBox, tb, Context, Val}; +use crate::{gc::TraceBox, tb, Context, Result, Val}; /// Can't have str | IStr, because constant BuiltinParam causes /// E0492: constant functions cannot refer to interior mutable data --- a/crates/jrsonnet-evaluator/src/function/parse.rs +++ b/crates/jrsonnet-evaluator/src/function/parse.rs @@ -6,11 +6,11 @@ use super::{arglike::ArgsLike, builtin::BuiltinParam}; use crate::{ + bail, destructure::destruct, error::{ErrorKind::*, Result}, evaluate_named, gc::GcHashMap, - throw, val::ThunkValue, Context, Pending, Thunk, Val, }; @@ -47,7 +47,7 @@ let mut passed_args = GcHashMap::with_capacity(params.iter().map(|p| p.0.capacity_hint()).sum()); if args.unnamed_len() > params.len() { - throw!(TooManyArgsFunctionHas( + bail!(TooManyArgsFunctionHas( params.len(), params.iter().map(|p| (p.0.name(), p.1.is_some())).collect() )) @@ -71,10 +71,10 @@ args.named_iter(ctx, tailstrict, &mut |name, value| { // FIXME: O(n) for arg existence check if !params.iter().any(|p| p.0.name().as_ref() == Some(name)) { - throw!(UnknownFunctionParameter((name as &str).to_owned())); + bail!(UnknownFunctionParameter((name as &str).to_owned())); } if passed_args.insert(name.clone(), value).is_some() { - throw!(BindingParameterASecondTime(name.clone())); + bail!(BindingParameterASecondTime(name.clone())); } filled_named += 1; Ok(()) @@ -125,7 +125,7 @@ } }); if !found { - throw!(FunctionParameterNotBoundInCall( + bail!(FunctionParameterNotBoundInCall( param.0.clone().name(), params.iter().map(|p| (p.0.name(), p.1.is_some())).collect() )); @@ -159,7 +159,7 @@ ) -> Result>>> { let mut passed_args: Vec>> = vec![None; params.len()]; if args.unnamed_len() > params.len() { - throw!(TooManyArgsFunctionHas( + bail!(TooManyArgsFunctionHas( params.len(), params .iter() @@ -183,7 +183,7 @@ .position(|p| p.name() == name) .ok_or_else(|| UnknownFunctionParameter((name as &str).to_owned()))?; if replace(&mut passed_args[id], Some(arg)).is_some() { - throw!(BindingParameterASecondTime(name.clone())); + bail!(BindingParameterASecondTime(name.clone())); } filled_args += 1; Ok(()) @@ -207,7 +207,7 @@ } }); if !found { - throw!(FunctionParameterNotBoundInCall( + bail!(FunctionParameterNotBoundInCall( param.name().as_str().map(IStr::from), params .iter() --- a/crates/jrsonnet-evaluator/src/import.rs +++ b/crates/jrsonnet-evaluator/src/import.rs @@ -12,8 +12,8 @@ use jrsonnet_parser::{SourceDirectory, SourceFile, SourcePath}; use crate::{ + bail, error::{ErrorKind::*, Result}, - throw, }; /// Implements file resolution logic for `import` and `importStr` @@ -25,14 +25,14 @@ /// `from` should only be returned from [`ImportResolver::resolve`], or from other defined file, any other value /// may result in panic fn resolve_from(&self, from: &SourcePath, path: &str) -> Result { - throw!(ImportNotSupported(from.clone(), path.into())) + bail!(ImportNotSupported(from.clone(), path.into())) } fn resolve_from_default(&self, path: &str) -> Result { self.resolve_from(&SourcePath::default(), path) } /// Resolves absolute path, doesn't supports jpath and other fancy things fn resolve(&self, path: &Path) -> Result { - throw!(AbsoluteImportNotSupported(path.to_owned())) + bail!(AbsoluteImportNotSupported(path.to_owned())) } /// Load resolved file @@ -110,16 +110,16 @@ ))); } } - throw!(ImportFileNotFound(from.clone(), path.to_owned())) + bail!(ImportFileNotFound(from.clone(), path.to_owned())) } } fn resolve(&self, path: &Path) -> Result { let meta = match fs::metadata(path) { Ok(v) => v, Err(e) if e.kind() == ErrorKind::NotFound => { - throw!(AbsoluteImportFileNotFound(path.to_owned())) + bail!(AbsoluteImportFileNotFound(path.to_owned())) } - Err(e) => throw!(ImportIo(e.to_string())), + Err(e) => bail!(ImportIo(e.to_string())), }; if meta.is_file() { Ok(SourcePath::new(SourceFile::new( @@ -138,7 +138,7 @@ let path = if let Some(f) = id.downcast_ref::() { f.path() } else if id.downcast_ref::().is_some() || id.is_default() { - throw!(ImportIsADirectory(id.clone())) + bail!(ImportIsADirectory(id.clone())) } else { unreachable!("other types are not supported in resolve"); }; --- a/crates/jrsonnet-evaluator/src/integrations/serde.rs +++ b/crates/jrsonnet-evaluator/src/integrations/serde.rs @@ -620,6 +620,6 @@ where T: std::fmt::Display, { - JrError::new(ErrorKind::RuntimeError(format!("serde: {msg}").into())) + runtime_error!("serde: {msg}") } } --- a/crates/jrsonnet-evaluator/src/lib.rs +++ b/crates/jrsonnet-evaluator/src/lib.rs @@ -354,7 +354,7 @@ } let parsed = file.parsed.as_ref().expect("just set").clone(); if file.evaluating { - throw!(InfiniteRecursionDetected) + bail!(InfiniteRecursionDetected) } file.evaluating = true; // Dropping file cache guard here, as evaluation may use this map too --- a/crates/jrsonnet-evaluator/src/manifest.rs +++ b/crates/jrsonnet-evaluator/src/manifest.rs @@ -1,9 +1,6 @@ use std::{borrow::Cow, fmt::Write}; -use crate::{ - error::{ErrorKind::*, Result}, - throw, State, Val, -}; +use crate::{bail, Result, State, Val}; pub trait ManifestFormat { fn manifest_buf(&self, val: Val, buf: &mut String) -> Result<()>; @@ -268,7 +265,7 @@ } buf.push('}'); } - Val::Func(_) => throw!(RuntimeError("tried to manifest function".into())), + Val::Func(_) => bail!("tried to manifest function"), }; Ok(()) } @@ -292,7 +289,7 @@ impl ManifestFormat for StringFormat { fn manifest_buf(&self, val: Val, out: &mut String) -> Result<()> { let Val::Str(s) = val else { - throw!( + bail!( "output should be string for string manifest format, got {}", val.value_type() ) @@ -309,7 +306,7 @@ impl ManifestFormat for YamlStreamFormat { fn manifest_buf(&self, val: Val, out: &mut String) -> Result<()> { let Val::Arr(arr) = val else { - throw!( + bail!( "output should be array for yaml stream format, got {}", val.value_type() ) --- a/crates/jrsonnet-evaluator/src/obj.rs +++ b/crates/jrsonnet-evaluator/src/obj.rs @@ -13,11 +13,12 @@ use crate::{ arr::{PickObjectKeyValues, PickObjectValues}, + bail, error::{suggest_object_fields, Error, ErrorKind::*}, function::CallLocation, gc::{GcHashMap, GcHashSet, TraceBox}, operator::evaluate_add_op, - tb, throw, + tb, val::{ArrValue, ThunkValue}, MaybeUnbound, Result, State, Thunk, Unbound, Val, }; @@ -404,7 +405,7 @@ pub fn get_or_bail(&self, key: IStr) -> Result { let Some(value) = self.get(key.clone())? else { let suggestions = suggest_object_fields(self, key.clone()); - throw!(NoSuchField(key, suggestions)) + bail!(NoSuchField(key, suggestions)) }; Ok(value) } @@ -723,7 +724,7 @@ return Ok(match v { CacheValue::Cached(v) => Some(v.clone()), CacheValue::NotFound => None, - CacheValue::Pending => throw!(InfiniteRecursionDetected), + CacheValue::Pending => bail!(InfiniteRecursionDetected), CacheValue::Errored(e) => return Err(e.clone()), }); } @@ -953,7 +954,7 @@ State::push( CallLocation(location.as_ref()), || format!("field <{}> initializtion", name.clone()), - || throw!(DuplicateFieldName(name.clone())), + || bail!(DuplicateFieldName(name.clone())), )?; } Ok(()) --- a/crates/jrsonnet-evaluator/src/stdlib/format.rs +++ b/crates/jrsonnet-evaluator/src/stdlib/format.rs @@ -7,8 +7,8 @@ use thiserror::Error; use crate::{ + bail, error::{format_found, suggest_object_fields, ErrorKind::*}, - throw, typed::Typed, Error, ObjValue, Result, Val, }; @@ -611,12 +611,12 @@ Val::Str(s) => { let s = s.into_flat(); if s.chars().count() != 1 { - throw!("%c expected 1 char string, got {}", s.chars().count(),); + bail!("%c expected 1 char string, got {}", s.chars().count()); } tmp_out.push_str(&s); } _ => { - throw!(TypeMismatch( + bail!(TypeMismatch( "%c requires number/string", vec![ValType::Num, ValType::Str], value.value_type(), @@ -657,7 +657,7 @@ let width = match c.width { Width::Star => { if values.is_empty() { - throw!(NotEnoughValues); + bail!(NotEnoughValues); } let value = &values[0]; values = &values[1..]; @@ -668,7 +668,7 @@ let precision = match c.precision { Some(Width::Star) => { if values.is_empty() { - throw!(NotEnoughValues); + bail!(NotEnoughValues); } let value = &values[0]; values = &values[1..]; @@ -683,7 +683,7 @@ &Val::Null } else { if values.is_empty() { - throw!(NotEnoughValues); + bail!(NotEnoughValues); } let value = &values[0]; values = &values[1..]; @@ -696,7 +696,7 @@ } if !values.is_empty() { - throw!( + bail!( "too many values to format, expected {value_count}, got {}", value_count + values.len() ) @@ -717,7 +717,7 @@ let current = &field[name_offset..end_offset]; let full = &field[..name_offset]; let found = Box::new(suggest_object_fields(&obj, current.into())); - throw!(SubfieldNotFound { + bail!(SubfieldNotFound { current: current.into(), full: full.into(), found, @@ -726,7 +726,7 @@ } else { // No underflow may happen, initially we always start with an object let subfield = &field[..name_offset - 1]; - throw!(SubfieldDidntYieldAnObject( + bail!(SubfieldDidntYieldAnObject( subfield.into(), current.value_type() )); @@ -750,13 +750,13 @@ let f: IStr = c.mkey.into(); let width = match c.width { Width::Star => { - throw!(CannotUseStarWidthWithObject); + bail!(CannotUseStarWidthWithObject); } Width::Fixed(n) => n, }; let precision = match c.precision { Some(Width::Star) => { - throw!(CannotUseStarWidthWithObject); + bail!(CannotUseStarWidthWithObject); } Some(Width::Fixed(n)) => Some(n), None => None, @@ -766,7 +766,7 @@ Val::Null } else { if f.is_empty() { - throw!(MappingKeysRequired); + bail!(MappingKeysRequired); } if let Some(v) = values.get(f.clone())? { v --- a/crates/jrsonnet-evaluator/src/stdlib/mod.rs +++ b/crates/jrsonnet-evaluator/src/stdlib/mod.rs @@ -3,7 +3,7 @@ use format::{format_arr, format_obj}; -use crate::{error::Result, function::CallLocation, State, Val}; +use crate::{function::CallLocation, Result, State, Val}; pub mod format; --- a/crates/jrsonnet-evaluator/src/typed/conversions.rs +++ b/crates/jrsonnet-evaluator/src/typed/conversions.rs @@ -7,12 +7,11 @@ use crate::{ arr::{ArrValue, BytesArray}, - error::Result, + bail, function::{native::NativeDesc, FuncDesc, FuncVal}, - throw, typed::CheckType, - val::{IndexableVal, StrValue, ThunkMapper}, - ObjValue, ObjValueBuilder, Thunk, Val, + val::{IndexableVal, ThunkMapper}, + ObjValue, ObjValueBuilder, Result, Thunk, Val, }; #[derive(Trace)] @@ -134,7 +133,7 @@ Val::Num(n) => { #[allow(clippy::float_cmp)] if n.trunc() != n { - throw!( + bail!( "cannot convert number with fractional part to {}", stringify!($ty) ) @@ -189,7 +188,7 @@ Val::Num(n) => { #[allow(clippy::float_cmp)] if n.trunc() != n { - throw!( + bail!( "cannot convert number with fractional part to {}", stringify!($ty) ) @@ -253,7 +252,7 @@ fn into_untyped(value: Self) -> Result { if value > MAX_SAFE_INTEGER as Self { - throw!("number is too large") + bail!("number is too large") } Ok(Val::Num(value as f64)) } @@ -264,7 +263,7 @@ Val::Num(n) => { #[allow(clippy::float_cmp)] if n.trunc() != n { - throw!("cannot convert number with fractional part to usize") + bail!("cannot convert number with fractional part to usize") } Ok(n as Self) } @@ -354,7 +353,7 @@ let mut out = ObjValueBuilder::with_capacity(typed.len()); for (k, v) in typed { let Some(key) = K::into_untyped(k)?.as_str() else { - throw!("map key should serialize to string"); + bail!("map key should serialize to string"); }; let value = V::into_untyped(v)?; out.member(key).value_unchecked(value); @@ -567,7 +566,7 @@ ::TYPE.check(&value)?; match value { Val::Func(FuncVal::Normal(desc)) => Ok(desc), - Val::Func(_) => throw!("expected normal function, not builtin"), + Val::Func(_) => bail!("expected normal function, not builtin"), _ => unreachable!(), } } @@ -649,7 +648,7 @@ const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Func); fn into_untyped(_typed: Self) -> Result { - throw!("can only convert functions from jsonnet to native") + bail!("can only convert functions from jsonnet to native") } fn from_untyped(untyped: Val) -> Result { --- a/crates/jrsonnet-evaluator/src/val.rs +++ b/crates/jrsonnet-evaluator/src/val.rs @@ -11,11 +11,12 @@ pub use crate::arr::{ArrValue, ArrayLike}; use crate::{ + bail, error::{Error, ErrorKind::*}, function::FuncVal, gc::{GcHashMap, TraceBox}, manifest::{ManifestFormat, ToStringFormat}, - tb, throw, + tb, typed::BoundedUsize, ObjValue, Result, Unbound, WeakObjValue, }; @@ -456,7 +457,7 @@ if num.is_finite() { Ok(Self::Num(num)) } else { - throw!("overflow") + bail!("overflow") } } @@ -495,7 +496,7 @@ Ok(match self { Val::Str(s) => IndexableVal::Str(s.into_flat()), Val::Arr(arr) => IndexableVal::Arr(arr), - _ => throw!(ValueIsNotIndexable(self.value_type())), + _ => bail!(ValueIsNotIndexable(self.value_type())), }) } } @@ -514,13 +515,13 @@ #[cfg(feature = "exp-bigint")] (Val::BigInt(a), Val::BigInt(b)) => a == b, (Val::Arr(_), Val::Arr(_)) => { - throw!("primitiveEquals operates on primitive types, got array") + bail!("primitiveEquals operates on primitive types, got array") } (Val::Obj(_), Val::Obj(_)) => { - throw!("primitiveEquals operates on primitive types, got object") + bail!("primitiveEquals operates on primitive types, got object") } (a, b) if is_function_like(a) && is_function_like(b) => { - throw!("cannot test equality of functions") + bail!("cannot test equality of functions") } (_, _) => false, }) --- a/crates/jrsonnet-macros/src/lib.rs +++ b/crates/jrsonnet-macros/src/lib.rs @@ -356,7 +356,7 @@ use ::jrsonnet_evaluator::{ State, Val, function::{builtin::{Builtin, StaticBuiltin, BuiltinParam, ParamName}, CallLocation, ArgsLike, parse::parse_builtin_call}, - error::Result, Context, typed::Typed, + Result, Context, typed::Typed, parser::ExprLocation, }; const PARAMS: &'static [BuiltinParam] = &[ --- a/crates/jrsonnet-stdlib/src/arrays.rs +++ b/crates/jrsonnet-stdlib/src/arrays.rs @@ -1,19 +1,19 @@ #![allow(non_snake_case)] use jrsonnet_evaluator::{ - error::{ErrorKind::RuntimeError, Result}, + bail, function::{builtin, FuncVal}, - throw, + runtime_error, typed::{BoundedI32, BoundedUsize, Either2, NativeFn, Typed}, - val::{equals, ArrValue, IndexableVal, StrValue}, - Either, IStr, Thunk, Val, + val::{equals, ArrValue, IndexableVal}, + Either, IStr, Result, Thunk, Val, }; pub(crate) fn eval_on_empty(on_empty: Option>) -> Result { if let Some(on_empty) = on_empty { on_empty.evaluate() } else { - throw!("expected non-empty array") + bail!("expected non-empty array") } } @@ -39,7 +39,7 @@ Either2::A(s) => Val::Str(StrValue::Flat(s.repeat(count).into())), Either2::B(arr) => Val::Arr( ArrValue::repeated(arr, count) - .ok_or_else(|| RuntimeError("repeated length overflow".into()))?, + .ok_or_else(|| runtime_error!("repeated length overflow"))?, ), }) } @@ -73,7 +73,7 @@ match func(Either2::A(c.to_string()))? { Val::Str(o) => write!(out, "{o}").unwrap(), Val::Null => continue, - _ => throw!("in std.join all items should be strings"), + _ => bail!("in std.join all items should be strings"), }; } Ok(IndexableVal::Str(out.into())) @@ -89,7 +89,7 @@ } } Val::Null => continue, - _ => throw!("in std.join all items should be arrays"), + _ => bail!("in std.join all items should be arrays"), }; } Ok(IndexableVal::Arr(out.into())) @@ -154,7 +154,7 @@ } else if matches!(item, Val::Null) { continue; } else { - throw!("in std.join all items should be arrays"); + bail!("in std.join all items should be arrays"); } } @@ -175,7 +175,7 @@ } else if matches!(item, Val::Null) { continue; } else { - throw!("in std.join all items should be strings"); + bail!("in std.join all items should be strings"); } } --- a/crates/jrsonnet-stdlib/src/compat.rs +++ b/crates/jrsonnet-stdlib/src/compat.rs @@ -1,6 +1,6 @@ use std::cmp::Ordering; -use jrsonnet_evaluator::{error::Result, function::builtin, operator::evaluate_compare_op, Val}; +use jrsonnet_evaluator::{function::builtin, operator::evaluate_compare_op, Result, Val}; #[builtin] #[allow(non_snake_case)] --- a/crates/jrsonnet-stdlib/src/encoding.rs +++ b/crates/jrsonnet-stdlib/src/encoding.rs @@ -1,9 +1,9 @@ use base64::{engine::general_purpose::STANDARD, Engine}; use jrsonnet_evaluator::{ - error::{ErrorKind::RuntimeError, Result}, function::builtin, + runtime_error, typed::{Either, Either2}, - IBytes, IStr, + IBytes, IStr, Result, }; #[builtin] @@ -13,9 +13,7 @@ #[builtin] pub fn builtin_decode_utf8(arr: IBytes) -> Result { - Ok(arr - .cast_str() - .ok_or_else(|| RuntimeError("bad utf8".into()))?) + arr.cast_str().ok_or_else(|| runtime_error!("bad utf8")) } #[builtin] @@ -31,7 +29,7 @@ pub fn builtin_base64_decode_bytes(str: IStr) -> Result { Ok(STANDARD .decode(str.as_bytes()) - .map_err(|e| RuntimeError(format!("invalid base64: {e}").into()))? + .map_err(|e| runtime_error!("invalid base64: {e}"))? .as_slice() .into()) } @@ -40,6 +38,6 @@ pub fn builtin_base64_decode(str: IStr) -> Result { let bytes = STANDARD .decode(str.as_bytes()) - .map_err(|e| RuntimeError(format!("invalid base64: {e}").into()))?; - Ok(String::from_utf8(bytes).map_err(|_| RuntimeError("bad utf8".into()))?) + .map_err(|e| runtime_error!("invalid base64: {e}"))?; + Ok(String::from_utf8(bytes).map_err(|_| runtime_error!("bad utf8"))?) } --- a/crates/jrsonnet-stdlib/src/manifest/mod.rs +++ b/crates/jrsonnet-stdlib/src/manifest/mod.rs @@ -2,10 +2,9 @@ mod yaml; use jrsonnet_evaluator::{ - error::Result, function::builtin, manifest::{escape_string_json, JsonFormat}, - IStr, ObjValue, Val, + IStr, ObjValue, Result, Val, }; pub use toml::TomlFormat; pub use yaml::YamlFormat; --- a/crates/jrsonnet-stdlib/src/manifest/toml.rs +++ b/crates/jrsonnet-stdlib/src/manifest/toml.rs @@ -1,8 +1,8 @@ use std::borrow::Cow; use jrsonnet_evaluator::{ + bail, manifest::{escape_string_json_buf, ManifestFormat}, - throw, val::ArrValue, IStr, ObjValue, Result, Val, }; @@ -157,10 +157,10 @@ buf.push_str(" }"); } Val::Null => { - throw!("tried to manifest null") + bail!("tried to manifest null") } Val::Func(_) => { - throw!("tried to manifest function") + bail!("tried to manifest function") } } Ok(()) @@ -290,7 +290,7 @@ Val::Obj(obj) => { manifest_table_internal(&obj, &mut Vec::new(), buf, &mut String::new(), self) } - _ => throw!("toml body should be object"), + _ => bail!("toml body should be object"), } } } --- a/crates/jrsonnet-stdlib/src/manifest/yaml.rs +++ b/crates/jrsonnet-stdlib/src/manifest/yaml.rs @@ -1,8 +1,9 @@ use std::{borrow::Cow, fmt::Write}; use jrsonnet_evaluator::{ + bail, manifest::{escape_string_json_buf, ManifestFormat}, - throw, Result, Val, + Result, Val, }; pub struct YamlFormat<'s> { @@ -219,7 +220,7 @@ } } } - Val::Func(_) => throw!("tried to manifest function"), + Val::Func(_) => bail!("tried to manifest function"), } Ok(()) } --- a/crates/jrsonnet-stdlib/src/misc.rs +++ b/crates/jrsonnet-stdlib/src/misc.rs @@ -1,10 +1,10 @@ use std::{cell::RefCell, rc::Rc}; use jrsonnet_evaluator::{ + bail, error::{ErrorKind::*, Result}, function::{builtin, ArgLike, CallLocation, FuncVal}, manifest::JsonFormat, - throw, typed::{Either2, Either4}, val::{equals, ArrValue}, Context, Either, IStr, ObjValue, Thunk, Val, @@ -103,7 +103,7 @@ true } } - _ => throw!("both arguments should be of the same type"), + _ => bail!("both arguments should be of the same type"), }) } @@ -129,6 +129,6 @@ true } } - _ => throw!("both arguments should be of the same type"), + _ => bail!("both arguments should be of the same type"), }) } --- a/crates/jrsonnet-stdlib/src/operator.rs +++ b/crates/jrsonnet-stdlib/src/operator.rs @@ -2,13 +2,12 @@ //! However, in our case we instead implement them in native, and implement native functions on top of core for backwards compatibility use jrsonnet_evaluator::{ - error::Result, function::builtin, operator::evaluate_mod_op, stdlib::std_format, typed::{Either, Either2}, - val::{equals, primitive_equals, StrValue}, - IStr, Val, + val::{equals, primitive_equals}, + IStr, Result, Val, }; #[builtin] --- a/crates/jrsonnet-stdlib/src/parse.rs +++ b/crates/jrsonnet-stdlib/src/parse.rs @@ -1,14 +1,10 @@ -use jrsonnet_evaluator::{ - error::{ErrorKind::RuntimeError, Result}, - function::builtin, - IStr, Val, -}; +use jrsonnet_evaluator::{function::builtin, runtime_error, IStr, Result, Val}; use serde::Deserialize; #[builtin] pub fn builtin_parse_json(str: IStr) -> Result { - let value: Val = serde_json::from_str(&str) - .map_err(|e| RuntimeError(format!("failed to parse json: {e}").into()))?; + let value: Val = + serde_json::from_str(&str).map_err(|e| runtime_error!("failed to parse json: {e}"))?; Ok(value) } @@ -21,8 +17,8 @@ ); let mut out = vec![]; for item in value { - let val = Val::deserialize(item) - .map_err(|e| RuntimeError(format!("failed to parse yaml: {e}").into()))?; + let val = + Val::deserialize(item).map_err(|e| runtime_error!("failed to parse yaml: {e}"))?; out.push(val); } Ok(if out.is_empty() { --- a/crates/jrsonnet-stdlib/src/sort.rs +++ b/crates/jrsonnet-stdlib/src/sort.rs @@ -3,12 +3,11 @@ use std::cmp::Ordering; use jrsonnet_evaluator::{ - error::Result, + bail, function::{builtin, FuncVal}, operator::evaluate_compare_op, - throw, val::{equals, ArrValue}, - Thunk, Val, + Result, Thunk, Val, }; use jrsonnet_parser::BinaryOpType; @@ -44,7 +43,7 @@ (Val::Num(_), SortKeyType::Unknown) => sort_type = SortKeyType::Number, (Val::Str(_), SortKeyType::String) | (Val::Num(_), SortKeyType::Number) => {} (Val::Str(_) | Val::Num(_), _) => { - throw!("sort elements should have the same types") + bail!("sort elements should have the same types") } _ => {} } --- a/crates/jrsonnet-stdlib/src/strings.rs +++ b/crates/jrsonnet-stdlib/src/strings.rs @@ -1,7 +1,7 @@ use jrsonnet_evaluator::{ + bail, error::{ErrorKind::*, Result}, function::builtin, - throw, typed::{Either2, M1}, val::{ArrValue, StrValue}, Either, IStr, Val, @@ -91,13 +91,13 @@ pub fn builtin_parse_int(str: IStr) -> Result { if let Some(raw) = str.strip_prefix('-') { if raw.is_empty() { - throw!("integer only consists of a minus") + bail!("integer only consists of a minus") } parse_nat::<10>(raw).map(|value| -value) } else { if str.is_empty() { - throw!("empty integer") + bail!("empty integer") } parse_nat::<10>(str.as_str()) @@ -107,7 +107,7 @@ #[builtin] pub fn builtin_parse_octal(str: IStr) -> Result { if str.is_empty() { - throw!("empty octal integer"); + bail!("empty octal integer"); } parse_nat::<8>(str.as_str()) @@ -116,7 +116,7 @@ #[builtin] pub fn builtin_parse_hex(str: IStr) -> Result { if str.is_empty() { - throw!("empty hexadecimal integer"); + bail!("empty hexadecimal integer"); } parse_nat::<16>(str.as_str()) @@ -156,7 +156,7 @@ if digit < BASE { Ok(base * aggregate + digit as f64) } else { - throw!("{raw:?} is not a base {BASE} integer",); + bail!("{raw:?} is not a base {BASE} integer"); } }) } @@ -164,13 +164,14 @@ #[cfg(feature = "exp-bigint")] #[builtin] pub fn builtin_bigint(v: Either![f64, IStr]) -> Result { + use jrsonnet_evaluator::runtime_error; use Either2::*; Ok(match v { A(a) => Val::BigInt(Box::new((a as i64).into())), B(b) => Val::BigInt(Box::new( b.as_str() .parse() - .map_err(|e| RuntimeError(format!("bad bigint: {e}").into()))?, + .map_err(|e| runtime_error!("bad bigint: {e}"))?, )), }) } --- a/tests/tests/as_native.rs +++ b/tests/tests/as_native.rs @@ -1,4 +1,4 @@ -use jrsonnet_evaluator::{error::Result, State}; +use jrsonnet_evaluator::{Result, State}; use jrsonnet_stdlib::StateExt; mod common; --- a/tests/tests/builtin.rs +++ b/tests/tests/builtin.rs @@ -1,10 +1,9 @@ mod common; use jrsonnet_evaluator::{ - error::Result, function::{builtin, builtin::Builtin, CallLocation, FuncVal}, typed::Typed, - ContextBuilder, State, Thunk, Val, + ContextBuilder, Result, State, Thunk, Val, }; use jrsonnet_stdlib::StateExt; --- a/tests/tests/common.rs +++ b/tests/tests/common.rs @@ -1,7 +1,7 @@ use jrsonnet_evaluator::{ - error::Result, + bail, function::{builtin, FuncVal}, - throw, ObjValueBuilder, State, Thunk, Val, + ObjValueBuilder, Result, State, Thunk, Val, }; #[macro_export] @@ -10,7 +10,7 @@ let a = &$a; let b = &$b; if a != b { - ::jrsonnet_evaluator::throw!("assertion failed: a != b\na={:#?}\nb={:#?}", a, b) + ::jrsonnet_evaluator::bail!("assertion failed: a != b\na={a:#?}\nb={b:#?}") } }}; } @@ -19,7 +19,7 @@ macro_rules! ensure { ($v:expr $(,)?) => { if !$v { - ::jrsonnet_evaluator::throw!("assertion failed: {}", stringify!($v)) + ::jrsonnet_evaluator::bail!("assertion failed: {}", stringify!($v)) } }; } @@ -29,7 +29,7 @@ ($a:expr, $b:expr) => {{ if !::jrsonnet_evaluator::val::equals(&$a.clone(), &$b.clone())? { use ::jrsonnet_evaluator::manifest::JsonFormat; - ::jrsonnet_evaluator::throw!( + ::jrsonnet_evaluator::bail!( "assertion failed: a != b\na={:#?}\nb={:#?}", $a.manifest(JsonFormat::default())?, $b.manifest(JsonFormat::default())?, @@ -42,7 +42,7 @@ fn assert_throw(lazy: Thunk, message: String) -> Result { match lazy.evaluate() { Ok(_) => { - throw!("expected argument to throw on evaluation, but it returned instead") + bail!("expected argument to throw on evaluation, but it returned instead") } Err(e) => { let error = format!("{}", e.error()); --- a/tests/tests/sanity.rs +++ b/tests/tests/sanity.rs @@ -1,8 +1,7 @@ use jrsonnet_evaluator::{ - error::Result, - throw, + bail, trace::{CompactFormat, TraceFormat}, - State, Val, + Result, State, Val, }; use jrsonnet_stdlib::StateExt; @@ -29,14 +28,14 @@ { let Err(e) = s.evaluate_snippet("snip".to_owned(), "assert 1 == 2: 'fail'; null") else { - throw!("assertion should fail"); + bail!("assertion should fail"); }; let e = trace_format.format(&e).unwrap(); ensure!(e.starts_with("assert failed: fail\n")); } { let Err(e) = s.evaluate_snippet("snip".to_owned(), "std.assertEqual(1, 2)") else { - throw!("assertion should fail") + bail!("assertion should fail") }; let e = trace_format.format(&e).unwrap(); ensure!(e.starts_with("runtime error: Assertion failed. 1 != 2")) --- a/tests/tests/typed_obj.rs +++ b/tests/tests/typed_obj.rs @@ -2,7 +2,7 @@ use std::fmt::Debug; -use jrsonnet_evaluator::{error::Result, typed::Typed, State}; +use jrsonnet_evaluator::{typed::Typed, Result, State}; use jrsonnet_stdlib::StateExt; #[derive(Clone, Typed, PartialEq, Debug)]