git.delta.rocks / jrsonnet / refs/commits / 6435abec6b9f

difftreelog

feat(evaluator) argument parsing macro

Лач2020-06-27parent: #cfd7ffe.patch.diff
in: master

2 files changed

modifiedcrates/jsonnet-evaluator/src/error.rsdiffbeforeafterboth
6pub enum Error {6pub enum Error {
7 VariableIsNotDefined(String),7 VariableIsNotDefined(String),
8 TypeMismatch(&'static str, Vec<ValType>, ValType),8 TypeMismatch(&'static str, Vec<ValType>, ValType),
9 IntristicArgumentReorderingIsNotSupportedYet,
9 NoSuchField(Rc<str>),10 NoSuchField(Rc<str>),
1011
11 UnknownVariable(Rc<str>),12 UnknownVariable(Rc<str>),
modifiedcrates/jsonnet-evaluator/src/function.rsdiffbeforeafterboth
--- a/crates/jsonnet-evaluator/src/function.rs
+++ b/crates/jsonnet-evaluator/src/function.rs
@@ -93,3 +93,63 @@
 
 	Ok(body_ctx.unwrap_or(ctx).extend(out, None, None, None)?)
 }
+
+#[macro_export]
+macro_rules! parse_args {
+	($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;
+		let args = $args;
+		if args.len() > $total_args {
+			create_error(Error::TooManyArgsFunctionHas($total_args))?;
+		}
+		$(
+			if args.len() <= $id {
+				create_error(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)?;
+				}
+			}
+			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()?))?,
+				};
+				$(
+					let $name = match $name {
+						$a(v) => v,
+						_ => create_error(Error::TypeMismatch(concat!($fn_name, " ", stringify!($id), "nd argument"), $nt, $name.value_type()?))?,
+					};
+				)*
+			)*
+		)+
+		$handler
+	}};
+}
+
+#[test]
+fn test() -> Result<()> {
+	use jsonnet_parser::*;
+	use crate::val::ValType;
+	let state = crate::EvaluationState::default();
+	let evaluator = state.with_stdlib();
+	let ctx = evaluator.create_default_context()?;
+	evaluator.run_in_state(|| {
+		parse_args!(ctx, "test", ArgsDesc(vec![
+			Arg(None, el!(Expr::Num(2.0))),
+			Arg(Some("b".into()), el!(Expr::Num(1.0))),
+		]), 2, [
+			0, a: [Val::Num]!!Val::Num, vec![ValType::Num];
+			1, b: [Val::Num]!!Val::Num, vec![ValType::Num];
+		], {
+			assert!((a - 2.0).abs() <= f64::EPSILON);
+			assert!((b - 1.0).abs() <= f64::EPSILON);
+		});
+		Ok(())
+	})
+}