From f9925f61b61650f0f2c79ae88ca0f05e54883add Mon Sep 17 00:00:00 2001 From: Лач Date: Thu, 04 Jun 2020 17:41:31 +0000 Subject: [PATCH] fix(parser): desugar == to std.equals --- --- a/crates/jsonnet-evaluator/src/evaluate.rs +++ b/crates/jsonnet-evaluator/src/evaluate.rs @@ -5,9 +5,8 @@ }; use closure::closure; use jsonnet_parser::{ - el, Arg, ArgsDesc, AssertStmt, BinaryOpType, BindSpec, CompSpec, Expr, FieldMember, - ForSpecData, IfSpecData, LiteralType, LocExpr, Member, ObjBody, ParamsDesc, UnaryOpType, - Visibility, + ArgsDesc, AssertStmt, BinaryOpType, BindSpec, CompSpec, Expr, FieldMember, ForSpecData, + IfSpecData, LiteralType, LocExpr, Member, ObjBody, ParamsDesc, UnaryOpType, Visibility, }; use std::{ collections::{BTreeMap, HashMap}, @@ -102,55 +101,20 @@ match (evaluate(context.clone(), &a)?.unwrap_if_lazy()?, op, b) { (Val::Bool(true), BinaryOpType::Or, _o) => Val::Bool(true), (Val::Bool(false), BinaryOpType::And, _o) => Val::Bool(false), - (a, op, eb) => evaluate_binary_op_normal( - context.clone(), - &a, - op, - &evaluate(context, eb)?.unwrap_if_lazy()?, - )?, + (a, op, eb) => { + evaluate_binary_op_normal(&a, op, &evaluate(context, eb)?.unwrap_if_lazy()?)? + } }, ) } -pub fn evaluate_binary_op_normal( - context: Context, - a: &Val, - op: BinaryOpType, - b: &Val, -) -> Result { +pub fn evaluate_binary_op_normal(a: &Val, op: BinaryOpType, b: &Val) -> Result { Ok(match (a, op, b) { (a, BinaryOpType::Add, b) => evaluate_add_op(a, b)?, - - (Val::Str(v1), BinaryOpType::Eq, Val::Str(v2)) => Val::Bool(v1 == v2), - (Val::Str(v1), BinaryOpType::Ne, Val::Str(v2)) => Val::Bool(v1 != v2), (Val::Str(v1), BinaryOpType::Mul, Val::Num(v2)) => Val::Str(v1.repeat(*v2 as usize)), - (Val::Str(format), BinaryOpType::Mod, args) => evaluate( - context - .with_var("__tmp__format__".to_owned(), Val::Str(format.to_owned()))? - .with_var( - "__tmp__args__".to_owned(), - match args { - Val::Arr(v) => Val::Arr(v.clone()), - v => Val::Arr(vec![v.clone()]), - }, - )?, - &el!(Expr::Apply( - el!(Expr::Index( - el!(Expr::Var("std".to_owned())), - el!(Expr::Str("format".to_owned())) - )), - ArgsDesc(vec![ - Arg(None, el!(Expr::Var("__tmp__format__".to_owned()))), - Arg(None, el!(Expr::Var("__tmp__args__".to_owned()))) - ]) - )), - )?, // Bool X Bool - (Val::Bool(a), BinaryOpType::Eq, Val::Bool(b)) => Val::Bool(a == b), - (Val::Bool(a), BinaryOpType::Ne, Val::Bool(b)) => Val::Bool(a != b), - (Val::Bool(a), BinaryOpType::And, Val::Bool(b)) => Val::Bool(*a && *b), (Val::Bool(a), BinaryOpType::Or, Val::Bool(b)) => Val::Bool(*a || *b), @@ -163,7 +127,6 @@ // Num X Num (Val::Num(v1), BinaryOpType::Mul, Val::Num(v2)) => Val::Num(v1 * v2), (Val::Num(v1), BinaryOpType::Div, Val::Num(v2)) => Val::Num(v1 / v2), - (Val::Num(v1), BinaryOpType::Mod, Val::Num(v2)) => Val::Num(v1 % v2), (Val::Num(v1), BinaryOpType::Sub, Val::Num(v2)) => Val::Num(v1 - v2), @@ -171,9 +134,6 @@ (Val::Num(v1), BinaryOpType::Gt, Val::Num(v2)) => Val::Bool(v1 > v2), (Val::Num(v1), BinaryOpType::Lte, Val::Num(v2)) => Val::Bool(v1 <= v2), (Val::Num(v1), BinaryOpType::Gte, Val::Num(v2)) => Val::Bool(v1 >= v2), - - (Val::Num(v1), BinaryOpType::Eq, Val::Num(v2)) => Val::Bool((v1 - v2).abs() < f64::EPSILON), - (Val::Num(v1), BinaryOpType::Ne, Val::Num(v2)) => Val::Bool((v1 - v2).abs() > f64::EPSILON), (Val::Num(v1), BinaryOpType::BitAnd, Val::Num(v2)) => { Val::Num(((*v1 as i32) & (*v2 as i32)) as f64) @@ -191,28 +151,6 @@ Val::Num(((*v1 as i32) >> (*v2 as i32)) as f64) } - // Arr X Arr - (Val::Arr(a), BinaryOpType::Eq, Val::Arr(b)) => { - if a.len() != b.len() { - Val::Bool(false) - } else { - for i in 0..a.len() { - if let Val::Bool(v) = evaluate_binary_op_normal( - context.clone(), - &a[i].clone().unwrap_if_lazy()?, - op, - &b[i].clone().unwrap_if_lazy()?, - )? { - if !v { - return Ok(Val::Bool(false)); - } - } else { - unreachable!() - } - } - return Ok(Val::Bool(true)); - } - } _ => panic!("no rules for binary operation: {:?} {:?} {:?}", a, op, b), }) } @@ -385,7 +323,7 @@ Index(value, index) => { match ( evaluate(context.clone(), value)?.unwrap_if_lazy()?, - evaluate(context.clone(), index)?, + evaluate(context, index)?, ) { (Val::Obj(v), Val::Str(s)) => { if let Some(v) = v.get(&s)? { @@ -506,9 +444,17 @@ panic!("bad objectFieldsEx call"); } } + ("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) + } (ns, name) => panic!("Intristic not found: {}.{}", ns, name), }, - Val::Func(f) => push(locexpr.clone(), "function call".to_owned(), || { + Val::Func(f) => push(locexpr, "function call".to_owned(), || { f.evaluate( args.clone() .into_iter() @@ -528,10 +474,11 @@ } Function(params, body) => evaluate_method(context, body, params.clone()), AssertExpr(AssertStmt(value, msg), returned) => { - if push(value.clone(), "assertion condition".to_owned(), || { + let assertion_result = push(value.clone(), "assertion condition".to_owned(), || { evaluate(context.clone(), &value)? .try_cast_bool("assertion condition should be boolean") - })? { + })?; + if assertion_result { push( returned.clone(), "assert 'return' branch".to_owned(), @@ -555,9 +502,10 @@ cond_then, cond_else, } => { - if push(cond.0.clone(), "if condition".to_owned(), || { + let condition_result = push(cond.0.clone(), "if condition".to_owned(), || { evaluate(context.clone(), &cond.0)?.try_cast_bool("if condition should be boolean") - })? { + })?; + if condition_result { push( cond_then.clone(), "if condition 'then' branch".to_owned(), --- a/crates/jsonnet-parser/Cargo.toml +++ b/crates/jsonnet-parser/Cargo.toml @@ -7,7 +7,7 @@ [features] default = [] # Trace peg token parsing -trace = ["peg/trace"] +# trace = ["peg/trace"] # TODO: # serialize = ["serde"] --- a/crates/jsonnet-parser/src/expr.rs +++ b/crates/jsonnet-parser/src/expr.rs @@ -50,7 +50,7 @@ pub enum BinaryOpType { Mul, Div, - // Mod is desugared to stdlib + // Mod is desugared to std.mod // Mod, Add, Sub, @@ -65,8 +65,9 @@ In, - Eq, - Ne, + // Eq/Ne is desugared to std.equals + // Eq, + // Ne, BitAnd, BitOr, --- a/crates/jsonnet-parser/src/lib.rs +++ b/crates/jsonnet-parser/src/lib.rs @@ -230,8 +230,18 @@ -- a:(@) _ "&" _ b:@ {loc_expr_todo!(Expr::BinaryOp(a, BinaryOpType::BitAnd, b))} -- - a:(@) _ "==" _ b:@ {loc_expr_todo!(Expr::BinaryOp(a, BinaryOpType::Eq, b))} - a:(@) _ "!=" _ b:@ {loc_expr_todo!(Expr::BinaryOp(a, BinaryOpType::Ne, b))} + a:(@) _ "==" _ b:@ {loc_expr_todo!(Expr::Apply( + el!(Expr::Index( + el!(Expr::Var("std".to_owned())), + el!(Expr::Str("equals".to_owned())) + )), ArgsDesc(vec![Arg(None, a), Arg(None, b)]) + ))} + a:(@) _ "!=" _ b:@ {loc_expr_todo!(Expr::UnaryOp(UnaryOpType::Not, el!(Expr::Apply( + el!(Expr::Index( + el!(Expr::Var("std".to_owned())), + el!(Expr::Str("equals".to_owned())) + )), ArgsDesc(vec![Arg(None, a), Arg(None, b)]) + ))))} -- a:(@) _ "<" _ b:@ {loc_expr_todo!(Expr::BinaryOp(a, BinaryOpType::Lt, b))} a:(@) _ ">" _ b:@ {loc_expr_todo!(Expr::BinaryOp(a, BinaryOpType::Gt, b))} @@ -385,25 +395,6 @@ el!(Expr::Num(2.0)), BinaryOpType::Sub, el!(Expr::Num(22.0)) - )) - ); - } - - #[test] - fn suffix_comparsion() { - use Expr::*; - assert_eq!( - parse!("std.type(a) == \"string\""), - el!(BinaryOp( - el!(Apply( - el!(Index( - el!(Var("std".to_owned())), - el!(Str("type".to_owned())) - )), - ArgsDesc(vec![Arg(None, el!(Var("a".to_owned())))]) - )), - BinaryOpType::Eq, - el!(Str("string".to_owned())) )) ); } @@ -427,37 +418,6 @@ ))] )), ) - } - - #[test] - fn array_comp_with_ifs() { - use Expr::*; - assert_eq!( - parse!("[k for k in std.objectFields(patch) if patch[k] == null]"), - el!(ArrComp( - el!(Var("k".to_owned())), - vec![ - CompSpec::ForSpec(ForSpecData( - "k".to_owned(), - el!(Apply( - el!(Index( - el!(Var("std".to_owned())), - el!(Str("objectFields".to_owned())) - )), - ArgsDesc(vec![Arg(None, el!(Var("patch".to_owned())))]) - )) - )), - CompSpec::IfSpec(IfSpecData(el!(BinaryOp( - el!(Index( - el!(Var("patch".to_owned())), - el!(Var("k".to_owned())) - )), - BinaryOpType::Eq, - el!(Literal(LiteralType::Null)) - )))) - ] - )) - ); } #[test] -- gitstuff