difftreelog
refactor(evaluator) use argument parsing macro
in: master
2 files changed
crates/jsonnet-evaluator/src/error.rsdiffbeforeafterboth--- a/crates/jsonnet-evaluator/src/error.rs
+++ b/crates/jsonnet-evaluator/src/error.rs
@@ -4,13 +4,16 @@
#[derive(Debug, Clone)]
pub enum Error {
+ IntristicNotFound(Rc<str>, Rc<str>),
+ IntristicArgumentReorderingIsNotSupportedYet,
+
VariableIsNotDefined(String),
TypeMismatch(&'static str, Vec<ValType>, ValType),
- IntristicArgumentReorderingIsNotSupportedYet,
NoSuchField(Rc<str>),
UnknownVariable(Rc<str>),
+ OnlyFunctionsCanBeCalledGot(ValType),
UnknownFunctionParameter(String),
BindingParameterASecondTime(Rc<str>),
TooManyArgsFunctionHas(usize),
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, escape_string_json, future_wrapper, lazy_val, manifest_json_ex,3 push, with_state, Context, ContextCreator, Error, FuncDesc, LazyBinding, LazyVal, ObjMember,3 parse_args, push, with_state, Context, ContextCreator, Error, FuncDesc, LazyBinding, LazyVal,4 ObjValue, Result, Val, ValType,4 ObjMember, ObjValue, Result, Val, ValType,5};5};6use closure::closure;6use closure::closure;7use jsonnet_parser::{7use jsonnet_parser::{502 match value {502 match value {503 Val::Intristic(ns, name) => match (&ns as &str, &name as &str) {503 Val::Intristic(ns, name) => match (&ns as &str, &name as &str) {504 // arr/string/function504 // arr/string/function505 ("std", "length") => {505 ("std", "length") => parse_args!(context, "std.length", args, 1, [506 assert_eq!(args.len(), 1);506 0, x: [Val::Str|Val::Arr|Val::Obj], vec![ValType::Str, ValType::Arr, ValType::Obj];507 let expr = &args.get(0).unwrap().1;507 ], {508 match evaluate(context, expr)? {508 match x {509 Val::Str(n) => Val::Num(n.chars().count() as f64),509 Val::Str(n) => Val::Num(n.chars().count() as f64),510 Val::Arr(i) => Val::Num(i.len() as f64),510 Val::Arr(i) => Val::Num(i.len() as f64),511 Val::Obj(o) => Val::Num(511 Val::Obj(o) => Val::Num(514 .filter(|(_k, v)| *v)514 .filter(|(_k, v)| *v)515 .count() as f64,515 .count() as f64,516 ),516 ),517 v => panic!("can't get length of {:?}", v),517 _ => unreachable!(),518 }518 }519 }519 }),520 // any520 // any521 ("std", "type") => {521 ("std", "type") => parse_args!(context, "std.type", args, 1, [522 assert_eq!(args.len(), 1);522 0, x, vec![];523 let expr = &args.get(0).unwrap().1;523 ], {524 Val::Str(evaluate(context, expr)?.value_type()?.name().into())524 Val::Str(x.value_type()?.name().into())525 }525 }),526 // length, idx=>any526 // length, idx=>any527 ("std", "makeArray") => {527 ("std", "makeArray") => parse_args!(context, "std.makeArray", args, 2, [528 assert_eq!(args.len(), 2);529 if let (Val::Num(v), Val::Func(d)) = (528 0, sz: [Val::Num]!!Val::Num, vec![ValType::Num];530 evaluate(context.clone(), &args[0].1)?,531 evaluate(context, &args[1].1)?,529 1, func: [Val::Func]!!Val::Func, vec![ValType::Func];532 ) {530 ], {533 assert!(v >= 0.0);531 assert!(sz >= 0.0);534 let mut out = Vec::with_capacity(v as usize);532 let mut out = Vec::with_capacity(sz as usize);535 for i in 0..v as usize {533 for i in 0..sz as usize {536 let call_ctx =534 out.push(func.evaluate_values(537 Context::new().with_var("v".into(), Val::Num(i as f64))?;538 out.push(d.evaluate(539 call_ctx,535 Context::new(),540 &ArgsDesc(vec![Arg(None, el!(Expr::Var("v".into())))]),541 true,536 &[Val::Num(i as f64)]542 )?)543 }544 Val::Arr(Rc::new(out))545 } else {546 panic!("bad makeArray call");537 )?)547 }538 }548 }539 Val::Arr(Rc::new(out))540 }),549 // string541 // string550 ("std", "codepoint") => {542 ("std", "codepoint") => parse_args!(context, "std.codepoint", args, 1, [551 assert_eq!(args.len(), 1);552 if let Val::Str(s) = evaluate(context, &args[0].1)? {543 0, str: [Val::Str]!!Val::Str, vec![ValType::Str];544 ], {553 assert!(545 assert!(554 s.chars().count() == 1,546 str.chars().count() == 1,555 "std.codepoint should receive single char string"547 "std.codepoint should receive single char string"556 );548 );557 Val::Num(s.chars().take(1).next().unwrap() as u32 as f64)549 Val::Num(str.chars().take(1).next().unwrap() as u32 as f64)558 } else {550 }),559 panic!("bad codepoint call");560 }561 }562 // object, includeHidden551 // object, includeHidden563 ("std", "objectFieldsEx") => {552 ("std", "objectFieldsEx") => {564 assert_eq!(args.len(), 2);553 parse_args!(context, "std.objectFieldsEx",args, 2, [565 if let (Val::Obj(body), Val::Bool(include_hidden)) = (554 0, obj: [Val::Obj]!!Val::Obj, vec![ValType::Obj];566 evaluate(context.clone(), &args[0].1)?,555 1, inc_hidden: [Val::Bool]!!Val::Bool, vec![ValType::Bool];567 evaluate(context, &args[1].1)?,568 ) {556 ], {569 Val::Arr(Rc::new(557 Val::Arr(Rc::new(570 body.fields_visibility()558 obj.fields_visibility()571 .into_iter()559 .into_iter()572 .filter(|(_k, v)| *v || include_hidden)560 .filter(|(_k, v)| *v || inc_hidden)573 .map(|(k, _v)| Val::Str(k))561 .map(|(k, _v)| Val::Str(k))574 .collect(),562 .collect(),575 ))563 ))576 } else {564 })577 panic!("bad objectFieldsEx call");578 }579 }565 }580 // object, field, includeHidden566 // object, field, includeHidden581 ("std", "objectHasEx") => {567 ("std", "objectHasEx") => parse_args!(context, "std.objectHasEx", args, 3, [582 assert_eq!(args.len(), 3);583 if let (Val::Obj(body), Val::Str(name), Val::Bool(include_hidden)) = (568 0, obj: [Val::Obj]!!Val::Obj, vec![ValType::Obj];584 evaluate(context.clone(), &args[0].1)?,569 1, f: [Val::Str]!!Val::Str, vec![ValType::Str];585 evaluate(context.clone(), &args[1].1)?,586 evaluate(context, &args[2].1)?,570 2, inc_hidden: [Val::Bool]!!Val::Bool, vec![ValType::Bool];587 ) {571 ], {588 Val::Bool(572 Val::Bool(589 body.fields_visibility()573 obj.fields_visibility()590 .into_iter()574 .into_iter()591 .filter(|(_k, v)| *v || include_hidden)575 .filter(|(_k, v)| *v || inc_hidden)592 .any(|(k, _v)| *k == *name),576 .any(|(k, _v)| *k == *f),593 )577 )594 } else {578 }),595 panic!("bad objectHasEx call");596 }597 }598 ("std", "primitiveEquals") => {579 ("std", "primitiveEquals") => {599 assert_eq!(args.len(), 2);580 parse_args!(context, "std.primitiveEquals", args, 2, [600 let (a, b) = (601 evaluate(context.clone(), &args[0].1)?,581 0, a, vec![];602 evaluate(context, &args[1].1)?,582 1, b, vec![];603 );583 ], {604 Val::Bool(a == b)584 Val::Bool(a == b)585 })605 }586 }606 ("std", "modulo") => {587 ("std", "modulo") => parse_args!(context, "std.modulo", args, 2, [607 assert_eq!(args.len(), 2);588 0, a: [Val::Num]!!Val::Num, vec![ValType::Num];608 if let (Val::Num(a), Val::Num(b)) = (589 1, b: [Val::Num]!!Val::Num, vec![ValType::Num];609 evaluate(context.clone(), &args[0].1)?,590 ], {610 evaluate(context, &args[1].1)?,591 Val::Num(a % b)611 ) {592 }),612 Val::Num(a % b)593 ("std", "floor") => parse_args!(context, "std.floor", args, 1, [613 } else {594 0, x: [Val::Num]!!Val::Num, vec![ValType::Num];614 panic!("bad modulo call");595 ], {615 }596 Val::Num(x.floor())616 }597 }),617 ("std", "floor") => {598 ("std", "trace") => parse_args!(context, "std.trace", args, 2, [618 assert_eq!(args.len(), 1);599 0, str: [Val::Str]!!Val::Str, vec![ValType::Str];619 if let Val::Num(a) = evaluate(context, &args[0].1)? {600 1, rest, vec![];620 Val::Num(a.floor())601 ], {621 } else {602 // TODO: Line numbers as in original jsonnet622 panic!("bad floor call");603 println!("TRACE: {}", str);623 }604 rest624 }605 }),625 ("std", "trace") => {606 ("std", "pow") => parse_args!(context, "std.modulo", args, 2, [626 assert_eq!(args.len(), 2);607 0, x: [Val::Num]!!Val::Num, vec![ValType::Num];627 if let (Val::Str(a), b) = (608 1, n: [Val::Num]!!Val::Num, vec![ValType::Num];628 evaluate(context.clone(), &args[0].1)?,609 ], {629 evaluate(context, &args[1].1)?,610 Val::Num(x.powf(n))630 ) {611 }),631 // TODO: Line numbers as in original jsonnet612 ("std", "extVar") => parse_args!(context, "std.extVar", args, 2, [632 println!("TRACE: {}", a);613 0, x: [Val::Str]!!Val::Str, vec![ValType::Str];633 b614 ], {634 } else {615 with_state(|s| s.0.ext_vars.borrow().get(&x).cloned()).ok_or_else(635 panic!("bad trace call");616 || {636 }617 create_error::<()>(crate::Error::UndefinedExternalVariable(x))637 }618 .err()638 ("std", "pow") => {619 .unwrap()639 assert_eq!(args.len(), 2);620 },640 if let (Val::Num(a), Val::Num(b)) = (621 )?641 evaluate(context.clone(), &args[0].1)?,622 }),642 evaluate(context, &args[1].1)?,623 ("std", "filter") => parse_args!(context, "std.filter", args, 2, [643 ) {624 0, func: [Val::Func]!!Val::Func, vec![ValType::Func];644 Val::Num(a.powf(b))625 1, arr: [Val::Arr]!!Val::Arr, vec![ValType::Arr];645 } else {626 ], {646 panic!("bad pow call");627 Val::Arr(Rc::new(647 }628 arr.iter()648 }629 .cloned()649 ("std", "extVar") => {630 .filter(|e| {650 assert_eq!(args.len(), 1);631 func651 if let Val::Str(a) = evaluate(context, &args[0].1)? {632 .evaluate_values(context.clone(), &[e.clone()])652 with_state(|s| s.0.ext_vars.borrow().get(&a).cloned()).ok_or_else(653 || {654 create_error::<()>(crate::Error::UndefinedExternalVariable(a))655 .err()656 .unwrap()633 .unwrap()657 },634 .try_cast_bool("filter predicate")658 )?659 } else {660 panic!("bad extVar call");661 }662 }663 ("std", "filter") => {664 assert_eq!(args.len(), 2);665 if let (Val::Func(predicate), Val::Arr(arr)) = (666 evaluate(context.clone(), &args[0].1)?,667 evaluate(context.clone(), &args[1].1)?,668 ) {669 Val::Arr(Rc::new(670 arr.iter()671 .cloned()672 .filter(|e| {673 predicate674 .evaluate_values(context.clone(), &[e.clone()])675 .unwrap()676 .try_cast_bool("filter predicate")677 .unwrap()635 .unwrap()678 })636 })679 .collect(),637 .collect(),680 ))638 ))681 } else {639 }),682 panic!("bad filter call");683 }640 ("std", "char") => parse_args!(context, "std.char", args, 1, [684 }685 ("std", "char") => {686 assert_eq!(args.len(), 1);687 let ch = evaluate(context, &args[0].1)?641 0, n: [Val::Num]!!Val::Num, vec![ValType::Num];688 .unwrap_if_lazy()?642 ], {689 .try_cast_num("std.char first argument")?;690 let mut out = String::new();643 let mut out = String::new();691 out.push(std::char::from_u32(ch as u32).unwrap());644 out.push(std::char::from_u32(n as u32).unwrap());692 Val::Str(out.into())645 Val::Str(out.into())693 }646 }),694 ("std", "encodeUTF8") => {647 ("std", "encodeUTF8") => parse_args!(context, "std.encodeUtf8", args, 1, [695 assert_eq!(args.len(), 1);696 let s = evaluate(context, &args[0].1)?648 0, str: [Val::Str]!!Val::Str, vec![ValType::Str];697 .unwrap_if_lazy()?649 ], {698 .try_cast_str("std.encodeUTF8 first argument")?;699 Val::Arr(Rc::new(s.bytes().map(|b| Val::Num(b as f64)).collect()))650 Val::Arr(Rc::new(str.bytes().map(|b| Val::Num(b as f64)).collect()))700 }651 }),701 ("std", "md5") => {652 ("std", "md5") => parse_args!(context, "std.md5", args, 1, [702 assert_eq!(args.len(), 1);703 let s = evaluate(context, &args[0].1)?653 0, str: [Val::Str]!!Val::Str, vec![ValType::Str];704 .unwrap_if_lazy()?654 ], {705 .try_cast_str("std.md5 first argument")?;706 Val::Str(format!("{:x}", md5::compute(s.as_bytes())).into())655 Val::Str(format!("{:x}", md5::compute(str.as_bytes())).into())707 }656 }),708 // faster657 // faster709 ("std", "join") => {658 ("std", "join") => parse_args!(context, "std.join", args, 2, [710 assert_eq!(args.len(), 2);711 let joiner = evaluate(context.clone(), &args[0].1)?;659 0, sep: [Val::Str|Val::Arr], vec![ValType::Str, ValType::Arr];712 let items = evaluate(context, &args[1].1)?;660 1, arr: [Val::Arr]!!Val::Arr, vec![ValType::Arr];713 match (joiner.unwrap_if_lazy()?, items.unwrap_if_lazy()?) {661 ], {662 match sep {714 (Val::Arr(joiner_items), Val::Arr(items)) => {663 Val::Arr(joiner_items) => {715 // TODO: Minimal size should be known716 let mut out = Vec::new();664 let mut out = Vec::new();717665718 let mut first = true;666 let mut first = true;719 for item in items.iter().cloned() {667 for item in arr.iter().cloned() {720 if let Val::Arr(items) = item.unwrap_if_lazy()? {668 if let Val::Arr(items) = item.unwrap_if_lazy()? {721 if !first {669 if !first {722 out.reserve(joiner_items.len());670 out.reserve(joiner_items.len());731 }679 }732680733 Val::Arr(Rc::new(out))681 Val::Arr(Rc::new(out))734 }682 },735 (Val::Str(joiner), Val::Arr(items)) => {683 Val::Str(sep) => {736 let mut out = String::new();684 let mut out = String::new();737685738 let mut first = true;686 let mut first = true;739 for item in items.iter().cloned() {687 for item in arr.iter().cloned() {740 if let Val::Str(item) = item.unwrap_if_lazy()? {688 if let Val::Str(item) = item.unwrap_if_lazy()? {741 if !first {689 if !first {742 out += &joiner;690 out += &sep;743 }691 }744 first = false;692 first = false;745 out += &item;693 out += &item;749 }697 }750698751 Val::Str(out.into())699 Val::Str(out.into())752 }700 },753 (joiner, items) => panic!("bad join call: {:?} {:?}", joiner, items),701 _ => unreachable!()754 }702 }755 }703 }),756 // Faster704 // Faster757 ("std", "escapeStringJson") => {705 ("std", "escapeStringJson") => {758 assert_eq!(args.len(), 1);706 parse_args!(context, "std.escapeStringJson", args, 1, [759 match evaluate(context, &args[0].1)?.unwrap_if_lazy()? {707 0, str_: [Val::Str]!!Val::Str, vec![ValType::Str];708 ], {760 Val::Str(s) => Val::Str(escape_string_json(&s).into()),709 Val::Str(escape_string_json(&str_).into())761 _ => panic!("bad escapeStringJson call"),710 })762 }763 }711 }764 // Faster712 // Faster765 ("std", "manifestJsonEx") => {713 ("std", "manifestJsonEx") => {766 assert_eq!(args.len(), 2);714 parse_args!(context, "std.manifestJsonEx", args, 2, [767 let value = evaluate(context.clone(), &args[0].1)?.unwrap_if_lazy()?;715 0, value, vec![];768 let ident = evaluate(context, &args[1].1)?.unwrap_if_lazy()?;716 1, indent: [Val::Str]!!Val::Str, vec![ValType::Str];769 match (value, ident) {717 ], {770 (o, Val::Str(s)) => Val::Str(manifest_json_ex(&o, &s)?.into()),718 Val::Str(manifest_json_ex(&value, &indent)?.into())771 _ => panic!("bad escapeStringJson call"),719 })772 }773 }720 }774 (ns, name) => panic!("Intristic not found: {}.{}", ns, name),721 (ns, name) => panic!("Intristic not found: {}.{}", ns, name),775 },722 },