git.delta.rocks / jrsonnet / refs/commits / 5e6d5ee048e2

difftreelog

refactor unify throw & throw_runtime

Yaroslav Bolyukin2022-10-17parent: #b8bef13.patch.diff
in: master

13 files changed

modifiedcrates/jrsonnet-evaluator/src/error.rsdiffbeforeafterboth
--- a/crates/jrsonnet-evaluator/src/error.rs
+++ b/crates/jrsonnet-evaluator/src/error.rs
@@ -266,14 +266,13 @@
 
 #[macro_export]
 macro_rules! throw {
-	($e: expr) => {
-		return Err($e.into())
+	($w:ident$(::$i:ident)*$(($($tt:tt)*))?) => {
+		return Err($w$(::$i)*$(($($tt)*))?.into())
 	};
-}
-
-#[macro_export]
-macro_rules! throw_runtime {
-	($($tt:tt)*) => {
-		return Err($crate::error::Error::RuntimeError(format!($($tt)*).into()).into())
+	($l:literal) => {
+		return Err($crate::error::Error::RuntimeError($l.into()).into())
+	};
+	($l:literal, $($tt:tt)*) => {
+		return Err($crate::error::Error::RuntimeError(format!($l, $($tt)*).into()).into())
 	};
 }
modifiedcrates/jrsonnet-evaluator/src/evaluate/destructure.rsdiffbeforeafterboth
--- a/crates/jrsonnet-evaluator/src/evaluate/destructure.rs
+++ b/crates/jrsonnet-evaluator/src/evaluate/destructure.rs
@@ -32,7 +32,7 @@
 		Destruct::Array { start, rest, end } => {
 			use jrsonnet_parser::DestructRest;
 
-			use crate::{throw_runtime, val::ArrValue};
+			use crate::{throw, val::ArrValue};
 
 			#[derive(Trace)]
 			struct DataThunk {
@@ -47,14 +47,14 @@
 					let v = self.parent.evaluate(s)?;
 					let arr = match v {
 						Val::Arr(a) => a,
-						_ => throw_runtime!("expected array"),
+						_ => throw!("expected array"),
 					};
 					if !self.has_rest {
 						if arr.len() != self.min_len {
-							throw_runtime!("expected {} elements, got {}", self.min_len, arr.len())
+							throw!("expected {} elements, got {}", self.min_len, arr.len())
 						}
 					} else if arr.len() < self.min_len {
-						throw_runtime!(
+						throw!(
 							"expected at least {} elements, but array was only {}",
 							self.min_len,
 							arr.len()
@@ -163,7 +163,7 @@
 		}
 		#[cfg(feature = "exp-destruct")]
 		Destruct::Object { fields, rest } => {
-			use crate::{obj::ObjValue, throw_runtime};
+			use crate::{obj::ObjValue, throw};
 
 			#[derive(Trace)]
 			struct DataThunk {
@@ -178,17 +178,17 @@
 					let v = self.parent.evaluate(s)?;
 					let obj = match v {
 						Val::Obj(o) => o,
-						_ => throw_runtime!("expected object"),
+						_ => throw!("expected object"),
 					};
 					for field in &self.field_names {
 						if !obj.has_field_ex(field.clone(), true) {
-							throw_runtime!("missing field: {}", field);
+							throw!("missing field: {}", field);
 						}
 					}
 					if !self.has_rest {
 						let len = obj.len();
 						if len != self.field_names.len() {
-							throw_runtime!("too many fields, and rest not found");
+							throw!("too many fields, and rest not found");
 						}
 					}
 					Ok(obj)
modifiedcrates/jrsonnet-evaluator/src/evaluate/operator.rsdiffbeforeafterboth
--- a/crates/jrsonnet-evaluator/src/evaluate/operator.rs
+++ b/crates/jrsonnet-evaluator/src/evaluate/operator.rs
@@ -150,13 +150,13 @@
 		(Num(v1), BitXor, Num(v2)) => Num(f64::from((*v1 as i32) ^ (*v2 as i32))),
 		(Num(v1), Lhs, Num(v2)) => {
 			if *v2 < 0.0 {
-				throw!(RuntimeError("shift by negative exponent".into()))
+				throw!("shift by negative exponent")
 			}
 			Num(f64::from((*v1 as i32) << (*v2 as i32)))
 		}
 		(Num(v1), Rhs, Num(v2)) => {
 			if *v2 < 0.0 {
-				throw!(RuntimeError("shift by negative exponent".into()))
+				throw!("shift by negative exponent")
 			}
 			Num(f64::from((*v1 as i32) >> (*v2 as i32)))
 		}
modifiedcrates/jrsonnet-evaluator/src/integrations/serde.rsdiffbeforeafterboth
--- a/crates/jrsonnet-evaluator/src/integrations/serde.rs
+++ b/crates/jrsonnet-evaluator/src/integrations/serde.rs
@@ -72,7 +72,7 @@
 				}
 				Self::Object(out)
 			}
-			Val::Func(_) => throw!(RuntimeError("tried to manifest function".into())),
+			Val::Func(_) => throw!("tried to manifest function"),
 		})
 	}
 }
modifiedcrates/jrsonnet-evaluator/src/stdlib/format.rsdiffbeforeafterboth
--- a/crates/jrsonnet-evaluator/src/stdlib/format.rs
+++ b/crates/jrsonnet-evaluator/src/stdlib/format.rs
@@ -591,9 +591,7 @@
 			),
 			Val::Str(s) => {
 				if s.chars().count() != 1 {
-					throw!(RuntimeError(
-						format!("%c expected 1 char string, got {}", s.chars().count()).into(),
-					));
+					throw!("%c expected 1 char string, got {}", s.chars().count(),);
 				}
 				tmp_out.push_str(&s);
 			}
modifiedcrates/jrsonnet-evaluator/src/stdlib/manifest.rsdiffbeforeafterboth
before · crates/jrsonnet-evaluator/src/stdlib/manifest.rs
1use crate::{2	error::{Error::*, Result},3	throw, State, Val,4};56#[derive(PartialEq, Eq, Clone, Copy)]7pub enum ManifestType {8	// Applied in manifestification9	Manifest,10	/// Used for std.manifestJson11	/// Empty array/objects extends to "[\n\n]" instead of "[ ]" as in manifest12	Std,13	/// No line breaks, used in `obj+''`14	ToString,15	/// Minified json16	Minify,17}1819pub struct ManifestJsonOptions<'s> {20	pub padding: &'s str,21	pub mtype: ManifestType,22	pub newline: &'s str,23	pub key_val_sep: &'s str,24	#[cfg(feature = "exp-preserve-order")]25	pub preserve_order: bool,26}2728pub fn manifest_json_ex(s: State, val: &Val, options: &ManifestJsonOptions<'_>) -> Result<String> {29	let mut out = String::new();30	manifest_json_ex_buf(s, val, &mut out, &mut String::new(), options)?;31	Ok(out)32}33fn manifest_json_ex_buf(34	s: State,35	val: &Val,36	buf: &mut String,37	cur_padding: &mut String,38	options: &ManifestJsonOptions<'_>,39) -> Result<()> {40	use std::fmt::Write;41	let mtype = options.mtype;42	match val {43		Val::Bool(v) => {44			if *v {45				buf.push_str("true");46			} else {47				buf.push_str("false");48			}49		}50		Val::Null => buf.push_str("null"),51		Val::Str(s) => escape_string_json_buf(s, buf),52		Val::Num(n) => write!(buf, "{n}").unwrap(),53		Val::Arr(items) => {54			buf.push('[');55			if !items.is_empty() {56				if mtype != ManifestType::ToString && mtype != ManifestType::Minify {57					buf.push_str(options.newline);58				}5960				let old_len = cur_padding.len();61				cur_padding.push_str(options.padding);62				for (i, item) in items.iter(s.clone()).enumerate() {63					if i != 0 {64						buf.push(',');65						if mtype == ManifestType::ToString {66							buf.push(' ');67						} else if mtype != ManifestType::Minify {68							buf.push_str(options.newline);69						}70					}71					buf.push_str(cur_padding);72					manifest_json_ex_buf(s.clone(), &item?, buf, cur_padding, options)?;73				}74				cur_padding.truncate(old_len);7576				if mtype != ManifestType::ToString && mtype != ManifestType::Minify {77					buf.push_str(options.newline);78					buf.push_str(cur_padding);79				}80			} else if mtype == ManifestType::Std {81				buf.push_str("\n\n");82				buf.push_str(cur_padding);83			} else if mtype == ManifestType::ToString || mtype == ManifestType::Manifest {84				buf.push(' ');85			}86			buf.push(']');87		}88		Val::Obj(obj) => {89			obj.run_assertions(s.clone())?;90			buf.push('{');91			let fields = obj.fields(92				#[cfg(feature = "exp-preserve-order")]93				options.preserve_order,94			);95			if !fields.is_empty() {96				if mtype != ManifestType::ToString && mtype != ManifestType::Minify {97					buf.push_str(options.newline);98				}99100				let old_len = cur_padding.len();101				cur_padding.push_str(options.padding);102				for (i, field) in fields.into_iter().enumerate() {103					if i != 0 {104						buf.push(',');105						if mtype == ManifestType::ToString {106							buf.push(' ');107						} else if mtype != ManifestType::Minify {108							buf.push_str(options.newline);109						}110					}111					buf.push_str(cur_padding);112					escape_string_json_buf(&field, buf);113					buf.push_str(options.key_val_sep);114					s.push_description(115						|| format!("field <{}> manifestification", field.clone()),116						|| {117							let value = obj.get(s.clone(), field.clone())?.unwrap();118							manifest_json_ex_buf(s.clone(), &value, buf, cur_padding, options)?;119							Ok(())120						},121					)?;122				}123				cur_padding.truncate(old_len);124125				if mtype != ManifestType::ToString && mtype != ManifestType::Minify {126					buf.push_str(options.newline);127					buf.push_str(cur_padding);128				}129			} else if mtype == ManifestType::Std {130				buf.push_str("\n\n");131				buf.push_str(cur_padding);132			} else if mtype == ManifestType::ToString || mtype == ManifestType::Manifest {133				buf.push(' ');134			}135			buf.push('}');136		}137		Val::Func(_) => throw!(RuntimeError("tried to manifest function".into())),138	};139	Ok(())140}141142pub fn escape_string_json(s: &str) -> String {143	let mut buf = String::new();144	escape_string_json_buf(s, &mut buf);145	buf146}147148fn escape_string_json_buf(s: &str, buf: &mut String) {149	use std::fmt::Write;150	buf.push('"');151	for c in s.chars() {152		match c {153			'"' => buf.push_str("\\\""),154			'\\' => buf.push_str("\\\\"),155			'\u{0008}' => buf.push_str("\\b"),156			'\u{000c}' => buf.push_str("\\f"),157			'\n' => buf.push_str("\\n"),158			'\r' => buf.push_str("\\r"),159			'\t' => buf.push_str("\\t"),160			c if c < 32 as char || (c >= 127 as char && c <= 159 as char) => {161				write!(buf, "\\u{:04x}", c as u32).unwrap();162			}163			c => buf.push(c),164		}165	}166	buf.push('"');167}168169pub struct ManifestYamlOptions<'s> {170	/// Padding before fields, i.e171	/// ```yaml172	/// a:173	///   b:174	/// ## <- this175	/// ```176	pub padding: &'s str,177	/// Padding before array elements in objects178	/// ```yaml179	/// a:180	///   - 1181	/// ## <- this182	/// ```183	pub arr_element_padding: &'s str,184	/// Should yaml keys appear unescaped, when possible185	/// ```yaml186	/// "safe_key": 1187	/// # vs188	/// safe_key: 1189	/// ```190	pub quote_keys: bool,191	/// If true - then order of fields is preserved as written,192	/// instead of sorting alphabetically193	#[cfg(feature = "exp-preserve-order")]194	pub preserve_order: bool,195}196197/// From <https://github.com/chyh1990/yaml-rust/blob/da52a68615f2ecdd6b7e4567019f280c433c1521/src/emitter.rs#L289>198/// With added date check199fn yaml_needs_quotes(string: &str) -> bool {200	fn need_quotes_spaces(string: &str) -> bool {201		string.starts_with(' ') || string.ends_with(' ')202	}203204	string.is_empty()205		|| need_quotes_spaces(string)206		|| string.starts_with(|c| matches!(c, '&' | '*' | '?' | '|' | '-' | '<' | '>' | '=' | '!' | '%' | '@'))207		|| string.contains(|c| matches!(c, ':' | '{' | '}' | '[' | ']' | ',' | '#' | '`' | '\"' | '\'' | '\\' | '\0'..='\x06' | '\t' | '\n' | '\r' | '\x0e'..='\x1a' | '\x1c'..='\x1f'))208		|| [209			// http://yaml.org/type/bool.html210			// Note: 'y', 'Y', 'n', 'N', is not quoted deliberately, as in libyaml. PyYAML also parse211			// them as string, not booleans, although it is violating the YAML 1.1 specification.212			// See https://github.com/dtolnay/serde-yaml/pull/83#discussion_r152628088.213			"yes", "Yes", "YES", "no", "No", "NO", "True", "TRUE", "true", "False", "FALSE", "false",214			"on", "On", "ON", "off", "Off", "OFF", // http://yaml.org/type/null.html215			"null", "Null", "NULL", "~",216		].contains(&string)217		|| (string.chars().all(|c| matches!(c, '0'..='9' | '-'))218			&& string.chars().filter(|c| *c == '-').count() == 2)219		|| string.starts_with('.')220		|| string.starts_with("0x")221		|| string.parse::<i64>().is_ok()222		|| string.parse::<f64>().is_ok()223}224225pub fn manifest_yaml_ex(s: State, val: &Val, options: &ManifestYamlOptions<'_>) -> Result<String> {226	let mut out = String::new();227	manifest_yaml_ex_buf(s, val, &mut out, &mut String::new(), options)?;228	Ok(out)229}230231#[allow(clippy::too_many_lines)]232fn manifest_yaml_ex_buf(233	s: State,234	val: &Val,235	buf: &mut String,236	cur_padding: &mut String,237	options: &ManifestYamlOptions<'_>,238) -> Result<()> {239	use std::fmt::Write;240	match val {241		Val::Bool(v) => {242			if *v {243				buf.push_str("true");244			} else {245				buf.push_str("false");246			}247		}248		Val::Null => buf.push_str("null"),249		Val::Str(s) => {250			if s.is_empty() {251				buf.push_str("\"\"");252			} else if let Some(s) = s.strip_suffix('\n') {253				buf.push('|');254				for line in s.split('\n') {255					buf.push('\n');256					buf.push_str(cur_padding);257					buf.push_str(options.padding);258					buf.push_str(line);259				}260			} else if !options.quote_keys && !yaml_needs_quotes(s) {261				buf.push_str(s);262			} else {263				escape_string_json_buf(s, buf);264			}265		}266		Val::Num(n) => write!(buf, "{}", *n).unwrap(),267		Val::Arr(a) => {268			if a.is_empty() {269				buf.push_str("[]");270			} else {271				for (i, item) in a.iter(s.clone()).enumerate() {272					if i != 0 {273						buf.push('\n');274						buf.push_str(cur_padding);275					}276					let item = item?;277					buf.push('-');278					match &item {279						Val::Arr(a) if !a.is_empty() => {280							buf.push('\n');281							buf.push_str(cur_padding);282							buf.push_str(options.padding);283						}284						_ => buf.push(' '),285					}286					let extra_padding = match &item {287						Val::Arr(a) => !a.is_empty(),288						Val::Obj(o) => !o.is_empty(),289						_ => false,290					};291					let prev_len = cur_padding.len();292					if extra_padding {293						cur_padding.push_str(options.padding);294					}295					manifest_yaml_ex_buf(s.clone(), &item, buf, cur_padding, options)?;296					cur_padding.truncate(prev_len);297				}298			}299		}300		Val::Obj(o) => {301			if o.is_empty() {302				buf.push_str("{}");303			} else {304				for (i, key) in o305					.fields(306						#[cfg(feature = "exp-preserve-order")]307						options.preserve_order,308					)309					.iter()310					.enumerate()311				{312					if i != 0 {313						buf.push('\n');314						buf.push_str(cur_padding);315					}316					if !options.quote_keys && !yaml_needs_quotes(key) {317						buf.push_str(key);318					} else {319						escape_string_json_buf(key, buf);320					}321					buf.push(':');322					let prev_len = cur_padding.len();323					let item = o.get(s.clone(), key.clone())?.expect("field exists");324					match &item {325						Val::Arr(a) if !a.is_empty() => {326							buf.push('\n');327							buf.push_str(cur_padding);328							buf.push_str(options.arr_element_padding);329							cur_padding.push_str(options.arr_element_padding);330						}331						Val::Obj(o) if !o.is_empty() => {332							buf.push('\n');333							buf.push_str(cur_padding);334							buf.push_str(options.padding);335							cur_padding.push_str(options.padding);336						}337						_ => buf.push(' '),338					}339					manifest_yaml_ex_buf(s.clone(), &item, buf, cur_padding, options)?;340					cur_padding.truncate(prev_len);341				}342			}343		}344		Val::Func(_) => throw!(RuntimeError("tried to manifest function".into())),345	}346	Ok(())347}
after · crates/jrsonnet-evaluator/src/stdlib/manifest.rs
1use crate::{2	error::{Error::*, Result},3	throw, State, Val,4};56#[derive(PartialEq, Eq, Clone, Copy)]7pub enum ManifestType {8	// Applied in manifestification9	Manifest,10	/// Used for std.manifestJson11	/// Empty array/objects extends to "[\n\n]" instead of "[ ]" as in manifest12	Std,13	/// No line breaks, used in `obj+''`14	ToString,15	/// Minified json16	Minify,17}1819pub struct ManifestJsonOptions<'s> {20	pub padding: &'s str,21	pub mtype: ManifestType,22	pub newline: &'s str,23	pub key_val_sep: &'s str,24	#[cfg(feature = "exp-preserve-order")]25	pub preserve_order: bool,26}2728pub fn manifest_json_ex(s: State, val: &Val, options: &ManifestJsonOptions<'_>) -> Result<String> {29	let mut out = String::new();30	manifest_json_ex_buf(s, val, &mut out, &mut String::new(), options)?;31	Ok(out)32}33fn manifest_json_ex_buf(34	s: State,35	val: &Val,36	buf: &mut String,37	cur_padding: &mut String,38	options: &ManifestJsonOptions<'_>,39) -> Result<()> {40	use std::fmt::Write;41	let mtype = options.mtype;42	match val {43		Val::Bool(v) => {44			if *v {45				buf.push_str("true");46			} else {47				buf.push_str("false");48			}49		}50		Val::Null => buf.push_str("null"),51		Val::Str(s) => escape_string_json_buf(s, buf),52		Val::Num(n) => write!(buf, "{n}").unwrap(),53		Val::Arr(items) => {54			buf.push('[');55			if !items.is_empty() {56				if mtype != ManifestType::ToString && mtype != ManifestType::Minify {57					buf.push_str(options.newline);58				}5960				let old_len = cur_padding.len();61				cur_padding.push_str(options.padding);62				for (i, item) in items.iter(s.clone()).enumerate() {63					if i != 0 {64						buf.push(',');65						if mtype == ManifestType::ToString {66							buf.push(' ');67						} else if mtype != ManifestType::Minify {68							buf.push_str(options.newline);69						}70					}71					buf.push_str(cur_padding);72					manifest_json_ex_buf(s.clone(), &item?, buf, cur_padding, options)?;73				}74				cur_padding.truncate(old_len);7576				if mtype != ManifestType::ToString && mtype != ManifestType::Minify {77					buf.push_str(options.newline);78					buf.push_str(cur_padding);79				}80			} else if mtype == ManifestType::Std {81				buf.push_str("\n\n");82				buf.push_str(cur_padding);83			} else if mtype == ManifestType::ToString || mtype == ManifestType::Manifest {84				buf.push(' ');85			}86			buf.push(']');87		}88		Val::Obj(obj) => {89			obj.run_assertions(s.clone())?;90			buf.push('{');91			let fields = obj.fields(92				#[cfg(feature = "exp-preserve-order")]93				options.preserve_order,94			);95			if !fields.is_empty() {96				if mtype != ManifestType::ToString && mtype != ManifestType::Minify {97					buf.push_str(options.newline);98				}99100				let old_len = cur_padding.len();101				cur_padding.push_str(options.padding);102				for (i, field) in fields.into_iter().enumerate() {103					if i != 0 {104						buf.push(',');105						if mtype == ManifestType::ToString {106							buf.push(' ');107						} else if mtype != ManifestType::Minify {108							buf.push_str(options.newline);109						}110					}111					buf.push_str(cur_padding);112					escape_string_json_buf(&field, buf);113					buf.push_str(options.key_val_sep);114					s.push_description(115						|| format!("field <{}> manifestification", field.clone()),116						|| {117							let value = obj.get(s.clone(), field.clone())?.unwrap();118							manifest_json_ex_buf(s.clone(), &value, buf, cur_padding, options)?;119							Ok(())120						},121					)?;122				}123				cur_padding.truncate(old_len);124125				if mtype != ManifestType::ToString && mtype != ManifestType::Minify {126					buf.push_str(options.newline);127					buf.push_str(cur_padding);128				}129			} else if mtype == ManifestType::Std {130				buf.push_str("\n\n");131				buf.push_str(cur_padding);132			} else if mtype == ManifestType::ToString || mtype == ManifestType::Manifest {133				buf.push(' ');134			}135			buf.push('}');136		}137		Val::Func(_) => throw!(RuntimeError("tried to manifest function".into())),138	};139	Ok(())140}141142pub fn escape_string_json(s: &str) -> String {143	let mut buf = String::new();144	escape_string_json_buf(s, &mut buf);145	buf146}147148fn escape_string_json_buf(s: &str, buf: &mut String) {149	use std::fmt::Write;150	buf.push('"');151	for c in s.chars() {152		match c {153			'"' => buf.push_str("\\\""),154			'\\' => buf.push_str("\\\\"),155			'\u{0008}' => buf.push_str("\\b"),156			'\u{000c}' => buf.push_str("\\f"),157			'\n' => buf.push_str("\\n"),158			'\r' => buf.push_str("\\r"),159			'\t' => buf.push_str("\\t"),160			c if c < 32 as char || (c >= 127 as char && c <= 159 as char) => {161				write!(buf, "\\u{:04x}", c as u32).unwrap();162			}163			c => buf.push(c),164		}165	}166	buf.push('"');167}168169pub struct ManifestYamlOptions<'s> {170	/// Padding before fields, i.e171	/// ```yaml172	/// a:173	///   b:174	/// ## <- this175	/// ```176	pub padding: &'s str,177	/// Padding before array elements in objects178	/// ```yaml179	/// a:180	///   - 1181	/// ## <- this182	/// ```183	pub arr_element_padding: &'s str,184	/// Should yaml keys appear unescaped, when possible185	/// ```yaml186	/// "safe_key": 1187	/// # vs188	/// safe_key: 1189	/// ```190	pub quote_keys: bool,191	/// If true - then order of fields is preserved as written,192	/// instead of sorting alphabetically193	#[cfg(feature = "exp-preserve-order")]194	pub preserve_order: bool,195}196197/// From <https://github.com/chyh1990/yaml-rust/blob/da52a68615f2ecdd6b7e4567019f280c433c1521/src/emitter.rs#L289>198/// With added date check199fn yaml_needs_quotes(string: &str) -> bool {200	fn need_quotes_spaces(string: &str) -> bool {201		string.starts_with(' ') || string.ends_with(' ')202	}203204	string.is_empty()205		|| need_quotes_spaces(string)206		|| string.starts_with(|c| matches!(c, '&' | '*' | '?' | '|' | '-' | '<' | '>' | '=' | '!' | '%' | '@'))207		|| string.contains(|c| matches!(c, ':' | '{' | '}' | '[' | ']' | ',' | '#' | '`' | '\"' | '\'' | '\\' | '\0'..='\x06' | '\t' | '\n' | '\r' | '\x0e'..='\x1a' | '\x1c'..='\x1f'))208		|| [209			// http://yaml.org/type/bool.html210			// Note: 'y', 'Y', 'n', 'N', is not quoted deliberately, as in libyaml. PyYAML also parse211			// them as string, not booleans, although it is violating the YAML 1.1 specification.212			// See https://github.com/dtolnay/serde-yaml/pull/83#discussion_r152628088.213			"yes", "Yes", "YES", "no", "No", "NO", "True", "TRUE", "true", "False", "FALSE", "false",214			"on", "On", "ON", "off", "Off", "OFF", // http://yaml.org/type/null.html215			"null", "Null", "NULL", "~",216		].contains(&string)217		|| (string.chars().all(|c| matches!(c, '0'..='9' | '-'))218			&& string.chars().filter(|c| *c == '-').count() == 2)219		|| string.starts_with('.')220		|| string.starts_with("0x")221		|| string.parse::<i64>().is_ok()222		|| string.parse::<f64>().is_ok()223}224225pub fn manifest_yaml_ex(s: State, val: &Val, options: &ManifestYamlOptions<'_>) -> Result<String> {226	let mut out = String::new();227	manifest_yaml_ex_buf(s, val, &mut out, &mut String::new(), options)?;228	Ok(out)229}230231#[allow(clippy::too_many_lines)]232fn manifest_yaml_ex_buf(233	s: State,234	val: &Val,235	buf: &mut String,236	cur_padding: &mut String,237	options: &ManifestYamlOptions<'_>,238) -> Result<()> {239	use std::fmt::Write;240	match val {241		Val::Bool(v) => {242			if *v {243				buf.push_str("true");244			} else {245				buf.push_str("false");246			}247		}248		Val::Null => buf.push_str("null"),249		Val::Str(s) => {250			if s.is_empty() {251				buf.push_str("\"\"");252			} else if let Some(s) = s.strip_suffix('\n') {253				buf.push('|');254				for line in s.split('\n') {255					buf.push('\n');256					buf.push_str(cur_padding);257					buf.push_str(options.padding);258					buf.push_str(line);259				}260			} else if !options.quote_keys && !yaml_needs_quotes(s) {261				buf.push_str(s);262			} else {263				escape_string_json_buf(s, buf);264			}265		}266		Val::Num(n) => write!(buf, "{}", *n).unwrap(),267		Val::Arr(a) => {268			if a.is_empty() {269				buf.push_str("[]");270			} else {271				for (i, item) in a.iter(s.clone()).enumerate() {272					if i != 0 {273						buf.push('\n');274						buf.push_str(cur_padding);275					}276					let item = item?;277					buf.push('-');278					match &item {279						Val::Arr(a) if !a.is_empty() => {280							buf.push('\n');281							buf.push_str(cur_padding);282							buf.push_str(options.padding);283						}284						_ => buf.push(' '),285					}286					let extra_padding = match &item {287						Val::Arr(a) => !a.is_empty(),288						Val::Obj(o) => !o.is_empty(),289						_ => false,290					};291					let prev_len = cur_padding.len();292					if extra_padding {293						cur_padding.push_str(options.padding);294					}295					manifest_yaml_ex_buf(s.clone(), &item, buf, cur_padding, options)?;296					cur_padding.truncate(prev_len);297				}298			}299		}300		Val::Obj(o) => {301			if o.is_empty() {302				buf.push_str("{}");303			} else {304				for (i, key) in o305					.fields(306						#[cfg(feature = "exp-preserve-order")]307						options.preserve_order,308					)309					.iter()310					.enumerate()311				{312					if i != 0 {313						buf.push('\n');314						buf.push_str(cur_padding);315					}316					if !options.quote_keys && !yaml_needs_quotes(key) {317						buf.push_str(key);318					} else {319						escape_string_json_buf(key, buf);320					}321					buf.push(':');322					let prev_len = cur_padding.len();323					let item = o.get(s.clone(), key.clone())?.expect("field exists");324					match &item {325						Val::Arr(a) if !a.is_empty() => {326							buf.push('\n');327							buf.push_str(cur_padding);328							buf.push_str(options.arr_element_padding);329							cur_padding.push_str(options.arr_element_padding);330						}331						Val::Obj(o) if !o.is_empty() => {332							buf.push('\n');333							buf.push_str(cur_padding);334							buf.push_str(options.padding);335							cur_padding.push_str(options.padding);336						}337						_ => buf.push(' '),338					}339					manifest_yaml_ex_buf(s.clone(), &item, buf, cur_padding, options)?;340					cur_padding.truncate(prev_len);341				}342			}343		}344		Val::Func(_) => throw!("tried to manifest function"),345	}346	Ok(())347}
modifiedcrates/jrsonnet-evaluator/src/typed/conversions.rsdiffbeforeafterboth
--- a/crates/jrsonnet-evaluator/src/typed/conversions.rs
+++ b/crates/jrsonnet-evaluator/src/typed/conversions.rs
@@ -6,7 +6,7 @@
 use jrsonnet_types::{ComplexValType, ValType};
 
 use crate::{
-	error::{Error::*, Result},
+	error::Result,
 	function::{FuncDesc, FuncVal},
 	throw,
 	typed::CheckType,
@@ -41,13 +41,10 @@
 					Val::Num(n) => {
 						#[allow(clippy::float_cmp)]
 						if n.trunc() != n {
-							throw!(RuntimeError(
-								format!(
-									"cannot convert number with fractional part to {}",
-									stringify!($ty)
-								)
-								.into()
-							))
+							throw!(
+								"cannot convert number with fractional part to {}",
+								stringify!($ty)
+							)
 						}
 						Ok(n as Self)
 					}
@@ -99,13 +96,10 @@
 					Val::Num(n) => {
 						#[allow(clippy::float_cmp)]
 						if n.trunc() != n {
-							throw!(RuntimeError(
-								format!(
-									"cannot convert number with fractional part to {}",
-									stringify!($ty)
-								)
-								.into()
-							))
+							throw!(
+								"cannot convert number with fractional part to {}",
+								stringify!($ty)
+							)
 						}
 						Ok(Self(n as $ty))
 					}
@@ -167,7 +161,7 @@
 
 	fn into_untyped(value: Self, _: State) -> Result<Val> {
 		if value > u32::MAX as Self {
-			throw!(RuntimeError("number is too large".into()))
+			throw!("number is too large")
 		}
 		Ok(Val::Num(value as f64))
 	}
@@ -178,9 +172,7 @@
 			Val::Num(n) => {
 				#[allow(clippy::float_cmp)]
 				if n.trunc() != n {
-					throw!(RuntimeError(
-						"cannot convert number with fractional part to usize".into()
-					))
+					throw!("cannot convert number with fractional part to usize")
 				}
 				Ok(n as Self)
 			}
@@ -440,7 +432,7 @@
 		<Self as Typed>::TYPE.check(s, &value)?;
 		match value {
 			Val::Func(FuncVal::Normal(desc)) => Ok(desc),
-			Val::Func(_) => throw!(RuntimeError("expected normal function, not builtin".into())),
+			Val::Func(_) => throw!("expected normal function, not builtin"),
 			_ => unreachable!(),
 		}
 	}
modifiedcrates/jrsonnet-evaluator/src/val.rsdiffbeforeafterboth
--- a/crates/jrsonnet-evaluator/src/val.rs
+++ b/crates/jrsonnet-evaluator/src/val.rs
@@ -629,7 +629,7 @@
 		if num.is_finite() {
 			Ok(Self::Num(num))
 		} else {
-			throw!(RuntimeError("overflow".into()))
+			throw!("overflow")
 		}
 	}
 
@@ -843,14 +843,14 @@
 		(Val::Null, Val::Null) => true,
 		(Val::Str(a), Val::Str(b)) => a == b,
 		(Val::Num(a), Val::Num(b)) => (a - b).abs() <= f64::EPSILON,
-		(Val::Arr(_), Val::Arr(_)) => throw!(RuntimeError(
-			"primitiveEquals operates on primitive types, got array".into(),
-		)),
-		(Val::Obj(_), Val::Obj(_)) => throw!(RuntimeError(
-			"primitiveEquals operates on primitive types, got object".into(),
-		)),
+		(Val::Arr(_), Val::Arr(_)) => {
+			throw!("primitiveEquals operates on primitive types, got array")
+		}
+		(Val::Obj(_), Val::Obj(_)) => {
+			throw!("primitiveEquals operates on primitive types, got object")
+		}
 		(a, b) if is_function_like(a) && is_function_like(b) => {
-			throw!(RuntimeError("cannot test equality of functions".into()))
+			throw!("cannot test equality of functions")
 		}
 		(_, _) => false,
 	})
modifiedcrates/jrsonnet-stdlib/src/arrays.rsdiffbeforeafterboth
--- a/crates/jrsonnet-stdlib/src/arrays.rs
+++ b/crates/jrsonnet-stdlib/src/arrays.rs
@@ -1,7 +1,7 @@
 use jrsonnet_evaluator::{
 	error::Result,
 	function::{builtin, FuncVal},
-	throw_runtime,
+	throw,
 	typed::{Any, BoundedUsize, Typed, VecVal},
 	val::{equals, ArrValue, IndexableVal},
 	IStr, State, Val,
@@ -43,7 +43,7 @@
 				match func.evaluate_simple(s.clone(), &(c.to_string(),))? {
 					Val::Str(o) => out.push_str(&o),
 					Val::Null => continue,
-					_ => throw_runtime!("in std.join all items should be strings"),
+					_ => throw!("in std.join all items should be strings"),
 				};
 			}
 			Ok(IndexableVal::Str(out.into()))
@@ -59,7 +59,7 @@
 						}
 					}
 					Val::Null => continue,
-					_ => throw_runtime!("in std.join all items should be arrays"),
+					_ => throw!("in std.join all items should be arrays"),
 				};
 			}
 			Ok(IndexableVal::Arr(out.into()))
@@ -128,7 +128,7 @@
 				} else if matches!(item, Val::Null) {
 					continue;
 				} else {
-					throw_runtime!("in std.join all items should be arrays");
+					throw!("in std.join all items should be arrays");
 				}
 			}
 
@@ -149,7 +149,7 @@
 				} else if matches!(item, Val::Null) {
 					continue;
 				} else {
-					throw_runtime!("in std.join all items should be strings");
+					throw!("in std.join all items should be strings");
 				}
 			}
 
modifiedcrates/jrsonnet-stdlib/src/lib.rsdiffbeforeafterboth
--- a/crates/jrsonnet-stdlib/src/lib.rs
+++ b/crates/jrsonnet-stdlib/src/lib.rs
@@ -8,7 +8,7 @@
 	error::{Error::*, Result},
 	function::{builtin::Builtin, ArgLike, CallLocation, FuncVal, TlaArg},
 	gc::{GcHashMap, TraceBox},
-	tb, throw_runtime,
+	tb, throw,
 	trace::PathResolver,
 	typed::{Any, Either, Either2, Either4, VecVal, M1},
 	val::{equals, ArrValue},
@@ -500,7 +500,7 @@
 				true
 			}
 		}
-		_ => throw_runtime!("both arguments should be of the same type"),
+		_ => throw!("both arguments should be of the same type"),
 	})
 }
 
@@ -534,7 +534,7 @@
 				true
 			}
 		}
-		_ => throw_runtime!("both arguments should be of the same type"),
+		_ => throw!("both arguments should be of the same type"),
 	})
 }
 
modifiedcrates/jrsonnet-stdlib/src/sort.rsdiffbeforeafterboth
--- a/crates/jrsonnet-stdlib/src/sort.rs
+++ b/crates/jrsonnet-stdlib/src/sort.rs
@@ -1,7 +1,7 @@
 use jrsonnet_evaluator::{
 	error::Result,
 	function::{builtin, FuncVal},
-	throw_runtime,
+	throw,
 	typed::Any,
 	val::ArrValue,
 	State, Val,
@@ -41,9 +41,9 @@
 			(Val::Num(_), SortKeyType::Unknown) => sort_type = SortKeyType::Number,
 			(Val::Str(_), SortKeyType::String) | (Val::Num(_), SortKeyType::Number) => {}
 			(Val::Str(_) | Val::Num(_), _) => {
-				throw_runtime!("sort elements should have the same types")
+				throw!("sort elements should have the same types")
 			}
-			_ => throw_runtime!("sort key should either be a string or a number"),
+			_ => throw!("sort key should either be a string or a number"),
 		}
 	}
 	Ok(sort_type)
modifiedtests/tests/common.rsdiffbeforeafterboth
--- a/tests/tests/common.rs
+++ b/tests/tests/common.rs
@@ -1,7 +1,7 @@
 use jrsonnet_evaluator::{
 	error::Result,
 	function::{builtin, FuncVal},
-	throw_runtime, ObjValueBuilder, State, Thunk, Val,
+	throw, ObjValueBuilder, State, Thunk, Val,
 };
 use jrsonnet_stdlib::StateExt;
 
@@ -11,7 +11,7 @@
 		let a = &$a;
 		let b = &$b;
 		if a != b {
-			::jrsonnet_evaluator::throw_runtime!("assertion failed: a != b\na={:#?}\nb={:#?}", a, b)
+			::jrsonnet_evaluator::throw!("assertion failed: a != b\na={:#?}\nb={:#?}", a, b)
 		}
 	}};
 }
@@ -20,7 +20,7 @@
 macro_rules! ensure {
 	($v:expr $(,)?) => {
 		if !$v {
-			::jrsonnet_evaluator::throw_runtime!("assertion failed: {}", stringify!($v))
+			::jrsonnet_evaluator::throw!("assertion failed: {}", stringify!($v))
 		}
 	};
 }
@@ -29,7 +29,7 @@
 macro_rules! ensure_val_eq {
 	($s:expr, $a:expr, $b:expr) => {{
 		if !::jrsonnet_evaluator::val::equals($s.clone(), &$a.clone(), &$b.clone())? {
-			::jrsonnet_evaluator::throw_runtime!(
+			::jrsonnet_evaluator::throw!(
 				"assertion failed: a != b\na={:#?}\nb={:#?}",
 				$a.to_json(
 					$s.clone(),
@@ -52,7 +52,7 @@
 fn assert_throw(s: State, lazy: Thunk<Val>, message: String) -> Result<bool> {
 	match lazy.evaluate(s) {
 		Ok(_) => {
-			throw_runtime!("expected argument to throw on evaluation, but it returned instead")
+			throw!("expected argument to throw on evaluation, but it returned instead")
 		}
 		Err(e) => {
 			let error = format!("{}", e.error());
modifiedtests/tests/sanity.rsdiffbeforeafterboth
--- a/tests/tests/sanity.rs
+++ b/tests/tests/sanity.rs
@@ -1,4 +1,4 @@
-use jrsonnet_evaluator::{error::Result, throw_runtime, State, Val};
+use jrsonnet_evaluator::{error::Result, throw, State, Val};
 use jrsonnet_stdlib::StateExt;
 
 mod common;
@@ -23,7 +23,7 @@
 
 	{
 		let e = match s.evaluate_snippet("snip".to_owned(), "assert 1 == 2: 'fail'; null") {
-			Ok(_) => throw_runtime!("assertion should fail"),
+			Ok(_) => throw!("assertion should fail"),
 			Err(e) => e,
 		};
 		let e = s.stringify_err(&e);
@@ -31,7 +31,7 @@
 	}
 	{
 		let e = match s.evaluate_snippet("snip".to_owned(), "std.assertEqual(1, 2)") {
-			Ok(_) => throw_runtime!("assertion should fail"),
+			Ok(_) => throw!("assertion should fail"),
 			Err(e) => e,
 		};
 		let e = s.stringify_err(&e);