git.delta.rocks / jrsonnet / refs/commits / bcda254909e4

difftreelog

refactor(evaluator) use argument parsing macro

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

2 files changed

modifiedcrates/jsonnet-evaluator/src/error.rsdiffbeforeafterboth
44
5#[derive(Debug, Clone)]5#[derive(Debug, Clone)]
6pub enum Error {6pub enum Error {
7 IntristicNotFound(Rc<str>, Rc<str>),
8 IntristicArgumentReorderingIsNotSupportedYet,
9
7 VariableIsNotDefined(String),10 VariableIsNotDefined(String),
8 TypeMismatch(&'static str, Vec<ValType>, ValType),11 TypeMismatch(&'static str, Vec<ValType>, ValType),
9 IntristicArgumentReorderingIsNotSupportedYet,
10 NoSuchField(Rc<str>),12 NoSuchField(Rc<str>),
1113
12 UnknownVariable(Rc<str>),14 UnknownVariable(Rc<str>),
1315
16 OnlyFunctionsCanBeCalledGot(ValType),
14 UnknownFunctionParameter(String),17 UnknownFunctionParameter(String),
15 BindingParameterASecondTime(Rc<str>),18 BindingParameterASecondTime(Rc<str>),
16 TooManyArgsFunctionHas(usize),19 TooManyArgsFunctionHas(usize),
modifiedcrates/jsonnet-evaluator/src/evaluate.rsdiffbeforeafterboth
--- a/crates/jsonnet-evaluator/src/evaluate.rs
+++ b/crates/jsonnet-evaluator/src/evaluate.rs
@@ -1,7 +1,7 @@
 use crate::{
 	context_creator, create_error, escape_string_json, future_wrapper, lazy_val, manifest_json_ex,
-	push, with_state, Context, ContextCreator, Error, FuncDesc, LazyBinding, LazyVal, ObjMember,
-	ObjValue, Result, Val, ValType,
+	parse_args, push, with_state, Context, ContextCreator, Error, FuncDesc, LazyBinding, LazyVal,
+	ObjMember, ObjValue, Result, Val, ValType,
 };
 use closure::closure;
 use jsonnet_parser::{
@@ -502,10 +502,10 @@
 			match value {
 				Val::Intristic(ns, name) => match (&ns as &str, &name as &str) {
 					// arr/string/function
-					("std", "length") => {
-						assert_eq!(args.len(), 1);
-						let expr = &args.get(0).unwrap().1;
-						match evaluate(context, expr)? {
+					("std", "length") => parse_args!(context, "std.length", args, 1, [
+						0, x: [Val::Str|Val::Arr|Val::Obj], vec![ValType::Str, ValType::Arr, ValType::Obj];
+					], {
+						match x {
 							Val::Str(n) => Val::Num(n.chars().count() as f64),
 							Val::Arr(i) => Val::Num(i.len() as f64),
 							Val::Obj(o) => Val::Num(
@@ -514,209 +514,157 @@
 									.filter(|(_k, v)| *v)
 									.count() as f64,
 							),
-							v => panic!("can't get length of {:?}", v),
+							_ => unreachable!(),
 						}
-					}
+					}),
 					// any
-					("std", "type") => {
-						assert_eq!(args.len(), 1);
-						let expr = &args.get(0).unwrap().1;
-						Val::Str(evaluate(context, expr)?.value_type()?.name().into())
-					}
+					("std", "type") => parse_args!(context, "std.type", args, 1, [
+						0, x, vec![];
+					], {
+						Val::Str(x.value_type()?.name().into())
+					}),
 					// length, idx=>any
-					("std", "makeArray") => {
-						assert_eq!(args.len(), 2);
-						if let (Val::Num(v), Val::Func(d)) = (
-							evaluate(context.clone(), &args[0].1)?,
-							evaluate(context, &args[1].1)?,
-						) {
-							assert!(v >= 0.0);
-							let mut out = Vec::with_capacity(v as usize);
-							for i in 0..v as usize {
-								let call_ctx =
-									Context::new().with_var("v".into(), Val::Num(i as f64))?;
-								out.push(d.evaluate(
-									call_ctx,
-									&ArgsDesc(vec![Arg(None, el!(Expr::Var("v".into())))]),
-									true,
-								)?)
-							}
-							Val::Arr(Rc::new(out))
-						} else {
-							panic!("bad makeArray call");
+					("std", "makeArray") => parse_args!(context, "std.makeArray", args, 2, [
+						0, sz: [Val::Num]!!Val::Num, vec![ValType::Num];
+						1, func: [Val::Func]!!Val::Func, vec![ValType::Func];
+					], {
+						assert!(sz >= 0.0);
+						let mut out = Vec::with_capacity(sz as usize);
+						for i in 0..sz as usize {
+							out.push(func.evaluate_values(
+								Context::new(),
+								&[Val::Num(i as f64)]
+							)?)
 						}
-					}
+						Val::Arr(Rc::new(out))
+					}),
 					// string
-					("std", "codepoint") => {
-						assert_eq!(args.len(), 1);
-						if let Val::Str(s) = evaluate(context, &args[0].1)? {
-							assert!(
-								s.chars().count() == 1,
-								"std.codepoint should receive single char string"
-							);
-							Val::Num(s.chars().take(1).next().unwrap() as u32 as f64)
-						} else {
-							panic!("bad codepoint call");
-						}
-					}
+					("std", "codepoint") => parse_args!(context, "std.codepoint", args, 1, [
+						0, str: [Val::Str]!!Val::Str, vec![ValType::Str];
+					], {
+						assert!(
+							str.chars().count() == 1,
+							"std.codepoint should receive single char string"
+						);
+						Val::Num(str.chars().take(1).next().unwrap() as u32 as f64)
+					}),
 					// object, includeHidden
 					("std", "objectFieldsEx") => {
-						assert_eq!(args.len(), 2);
-						if let (Val::Obj(body), Val::Bool(include_hidden)) = (
-							evaluate(context.clone(), &args[0].1)?,
-							evaluate(context, &args[1].1)?,
-						) {
+						parse_args!(context, "std.objectFieldsEx",args, 2, [
+							0, obj: [Val::Obj]!!Val::Obj, vec![ValType::Obj];
+							1, inc_hidden: [Val::Bool]!!Val::Bool, vec![ValType::Bool];
+						], {
 							Val::Arr(Rc::new(
-								body.fields_visibility()
+								obj.fields_visibility()
 									.into_iter()
-									.filter(|(_k, v)| *v || include_hidden)
+									.filter(|(_k, v)| *v || inc_hidden)
 									.map(|(k, _v)| Val::Str(k))
 									.collect(),
 							))
-						} else {
-							panic!("bad objectFieldsEx call");
-						}
+						})
 					}
 					// object, field, includeHidden
-					("std", "objectHasEx") => {
-						assert_eq!(args.len(), 3);
-						if let (Val::Obj(body), Val::Str(name), Val::Bool(include_hidden)) = (
-							evaluate(context.clone(), &args[0].1)?,
-							evaluate(context.clone(), &args[1].1)?,
-							evaluate(context, &args[2].1)?,
-						) {
-							Val::Bool(
-								body.fields_visibility()
-									.into_iter()
-									.filter(|(_k, v)| *v || include_hidden)
-									.any(|(k, _v)| *k == *name),
-							)
-						} else {
-							panic!("bad objectHasEx call");
-						}
-					}
+					("std", "objectHasEx") => parse_args!(context, "std.objectHasEx", args, 3, [
+						0, obj: [Val::Obj]!!Val::Obj, vec![ValType::Obj];
+						1, f: [Val::Str]!!Val::Str, vec![ValType::Str];
+						2, inc_hidden: [Val::Bool]!!Val::Bool, vec![ValType::Bool];
+					], {
+						Val::Bool(
+							obj.fields_visibility()
+								.into_iter()
+								.filter(|(_k, v)| *v || inc_hidden)
+								.any(|(k, _v)| *k == *f),
+						)
+					}),
 					("std", "primitiveEquals") => {
-						assert_eq!(args.len(), 2);
-						let (a, b) = (
-							evaluate(context.clone(), &args[0].1)?,
-							evaluate(context, &args[1].1)?,
-						);
-						Val::Bool(a == b)
-					}
-					("std", "modulo") => {
-						assert_eq!(args.len(), 2);
-						if let (Val::Num(a), Val::Num(b)) = (
-							evaluate(context.clone(), &args[0].1)?,
-							evaluate(context, &args[1].1)?,
-						) {
-							Val::Num(a % b)
-						} else {
-							panic!("bad modulo call");
-						}
-					}
-					("std", "floor") => {
-						assert_eq!(args.len(), 1);
-						if let Val::Num(a) = evaluate(context, &args[0].1)? {
-							Val::Num(a.floor())
-						} else {
-							panic!("bad floor call");
-						}
-					}
-					("std", "trace") => {
-						assert_eq!(args.len(), 2);
-						if let (Val::Str(a), b) = (
-							evaluate(context.clone(), &args[0].1)?,
-							evaluate(context, &args[1].1)?,
-						) {
-							// TODO: Line numbers as in original jsonnet
-							println!("TRACE: {}", a);
-							b
-						} else {
-							panic!("bad trace call");
-						}
-					}
-					("std", "pow") => {
-						assert_eq!(args.len(), 2);
-						if let (Val::Num(a), Val::Num(b)) = (
-							evaluate(context.clone(), &args[0].1)?,
-							evaluate(context, &args[1].1)?,
-						) {
-							Val::Num(a.powf(b))
-						} else {
-							panic!("bad pow call");
-						}
+						parse_args!(context, "std.primitiveEquals", args, 2, [
+							0, a, vec![];
+							1, b, vec![];
+						], {
+							Val::Bool(a == b)
+						})
 					}
-					("std", "extVar") => {
-						assert_eq!(args.len(), 1);
-						if let Val::Str(a) = evaluate(context, &args[0].1)? {
-							with_state(|s| s.0.ext_vars.borrow().get(&a).cloned()).ok_or_else(
-								|| {
-									create_error::<()>(crate::Error::UndefinedExternalVariable(a))
-										.err()
+					("std", "modulo") => parse_args!(context, "std.modulo", args, 2, [
+						0, a: [Val::Num]!!Val::Num, vec![ValType::Num];
+						1, b: [Val::Num]!!Val::Num, vec![ValType::Num];
+					], {
+						Val::Num(a % b)
+					}),
+					("std", "floor") => parse_args!(context, "std.floor", args, 1, [
+						0, x: [Val::Num]!!Val::Num, vec![ValType::Num];
+					], {
+						Val::Num(x.floor())
+					}),
+					("std", "trace") => parse_args!(context, "std.trace", args, 2, [
+						0, str: [Val::Str]!!Val::Str, vec![ValType::Str];
+						1, rest, vec![];
+					], {
+						// TODO: Line numbers as in original jsonnet
+						println!("TRACE: {}", str);
+						rest
+					}),
+					("std", "pow") => parse_args!(context, "std.modulo", args, 2, [
+						0, x: [Val::Num]!!Val::Num, vec![ValType::Num];
+						1, n: [Val::Num]!!Val::Num, vec![ValType::Num];
+					], {
+						Val::Num(x.powf(n))
+					}),
+					("std", "extVar") => parse_args!(context, "std.extVar", args, 2, [
+						0, x: [Val::Str]!!Val::Str, vec![ValType::Str];
+					], {
+						with_state(|s| s.0.ext_vars.borrow().get(&x).cloned()).ok_or_else(
+							|| {
+								create_error::<()>(crate::Error::UndefinedExternalVariable(x))
+									.err()
+									.unwrap()
+							},
+						)?
+					}),
+					("std", "filter") => parse_args!(context, "std.filter", args, 2, [
+						0, func: [Val::Func]!!Val::Func, vec![ValType::Func];
+						1, arr: [Val::Arr]!!Val::Arr, vec![ValType::Arr];
+					], {
+						Val::Arr(Rc::new(
+							arr.iter()
+								.cloned()
+								.filter(|e| {
+									func
+										.evaluate_values(context.clone(), &[e.clone()])
 										.unwrap()
-								},
-							)?
-						} else {
-							panic!("bad extVar call");
-						}
-					}
-					("std", "filter") => {
-						assert_eq!(args.len(), 2);
-						if let (Val::Func(predicate), Val::Arr(arr)) = (
-							evaluate(context.clone(), &args[0].1)?,
-							evaluate(context.clone(), &args[1].1)?,
-						) {
-							Val::Arr(Rc::new(
-								arr.iter()
-									.cloned()
-									.filter(|e| {
-										predicate
-											.evaluate_values(context.clone(), &[e.clone()])
-											.unwrap()
-											.try_cast_bool("filter predicate")
-											.unwrap()
-									})
-									.collect(),
-							))
-						} else {
-							panic!("bad filter call");
-						}
-					}
-					("std", "char") => {
-						assert_eq!(args.len(), 1);
-						let ch = evaluate(context, &args[0].1)?
-							.unwrap_if_lazy()?
-							.try_cast_num("std.char first argument")?;
+										.try_cast_bool("filter predicate")
+										.unwrap()
+								})
+								.collect(),
+						))
+					}),
+					("std", "char") => parse_args!(context, "std.char", args, 1, [
+						0, n: [Val::Num]!!Val::Num, vec![ValType::Num];
+					], {
 						let mut out = String::new();
-						out.push(std::char::from_u32(ch as u32).unwrap());
+						out.push(std::char::from_u32(n as u32).unwrap());
 						Val::Str(out.into())
-					}
-					("std", "encodeUTF8") => {
-						assert_eq!(args.len(), 1);
-						let s = evaluate(context, &args[0].1)?
-							.unwrap_if_lazy()?
-							.try_cast_str("std.encodeUTF8 first argument")?;
-						Val::Arr(Rc::new(s.bytes().map(|b| Val::Num(b as f64)).collect()))
-					}
-					("std", "md5") => {
-						assert_eq!(args.len(), 1);
-						let s = evaluate(context, &args[0].1)?
-							.unwrap_if_lazy()?
-							.try_cast_str("std.md5 first argument")?;
-						Val::Str(format!("{:x}", md5::compute(s.as_bytes())).into())
-					}
+					}),
+					("std", "encodeUTF8") => parse_args!(context, "std.encodeUtf8", args, 1, [
+						0, str: [Val::Str]!!Val::Str, vec![ValType::Str];
+					], {
+						Val::Arr(Rc::new(str.bytes().map(|b| Val::Num(b as f64)).collect()))
+					}),
+					("std", "md5") => parse_args!(context, "std.md5", args, 1, [
+						0, str: [Val::Str]!!Val::Str, vec![ValType::Str];
+					], {
+						Val::Str(format!("{:x}", md5::compute(str.as_bytes())).into())
+					}),
 					// faster
-					("std", "join") => {
-						assert_eq!(args.len(), 2);
-						let joiner = evaluate(context.clone(), &args[0].1)?;
-						let items = evaluate(context, &args[1].1)?;
-						match (joiner.unwrap_if_lazy()?, items.unwrap_if_lazy()?) {
-							(Val::Arr(joiner_items), Val::Arr(items)) => {
-								// TODO: Minimal size should be known
+					("std", "join") => parse_args!(context, "std.join", args, 2, [
+						0, sep: [Val::Str|Val::Arr], vec![ValType::Str, ValType::Arr];
+						1, arr: [Val::Arr]!!Val::Arr, vec![ValType::Arr];
+					], {
+						match sep {
+							Val::Arr(joiner_items) => {
 								let mut out = Vec::new();
 
 								let mut first = true;
-								for item in items.iter().cloned() {
+								for item in arr.iter().cloned() {
 									if let Val::Arr(items) = item.unwrap_if_lazy()? {
 										if !first {
 											out.reserve(joiner_items.len());
@@ -731,15 +679,15 @@
 								}
 
 								Val::Arr(Rc::new(out))
-							}
-							(Val::Str(joiner), Val::Arr(items)) => {
+							},
+							Val::Str(sep) => {
 								let mut out = String::new();
 
 								let mut first = true;
-								for item in items.iter().cloned() {
+								for item in arr.iter().cloned() {
 									if let Val::Str(item) = item.unwrap_if_lazy()? {
 										if !first {
-											out += &joiner;
+											out += &sep;
 										}
 										first = false;
 										out += &item;
@@ -749,27 +697,26 @@
 								}
 
 								Val::Str(out.into())
-							}
-							(joiner, items) => panic!("bad join call: {:?} {:?}", joiner, items),
+							},
+							_ => unreachable!()
 						}
-					}
+					}),
 					// Faster
 					("std", "escapeStringJson") => {
-						assert_eq!(args.len(), 1);
-						match evaluate(context, &args[0].1)?.unwrap_if_lazy()? {
-							Val::Str(s) => Val::Str(escape_string_json(&s).into()),
-							_ => panic!("bad escapeStringJson call"),
-						}
+						parse_args!(context, "std.escapeStringJson", args, 1, [
+							0, str_: [Val::Str]!!Val::Str, vec![ValType::Str];
+						], {
+							Val::Str(escape_string_json(&str_).into())
+						})
 					}
 					// Faster
 					("std", "manifestJsonEx") => {
-						assert_eq!(args.len(), 2);
-						let value = evaluate(context.clone(), &args[0].1)?.unwrap_if_lazy()?;
-						let ident = evaluate(context, &args[1].1)?.unwrap_if_lazy()?;
-						match (value, ident) {
-							(o, Val::Str(s)) => Val::Str(manifest_json_ex(&o, &s)?.into()),
-							_ => panic!("bad escapeStringJson call"),
-						}
+						parse_args!(context, "std.manifestJsonEx", args, 2, [
+							0, value, vec![];
+							1, indent: [Val::Str]!!Val::Str, vec![ValType::Str];
+						], {
+							Val::Str(manifest_json_ex(&value, &indent)?.into())
+						})
 					}
 					(ns, name) => panic!("Intristic not found: {}.{}", ns, name),
 				},