From ce2d8d503b4aa249b441db4055e295fa158616e7 Mon Sep 17 00:00:00 2001 From: Yaroslav Bulyukin Date: Tue, 20 Oct 2020 16:14:33 +0000 Subject: [PATCH] Merge pull request #19 from CertainLach/std-intrinsic Prevent changing meaning of std in desugared expressions --- --- a/crates/jrsonnet-evaluator/src/builtin/mod.rs +++ b/crates/jrsonnet-evaluator/src/builtin/mod.rs @@ -20,13 +20,12 @@ pub fn call_builtin( context: Context, loc: &Option, - ns: &str, name: &str, args: &ArgsDesc, ) -> Result { - Ok(match (ns, name as &str) { + Ok(match name as &str { // arr/string/function - ("std", "length") => parse_args!(context, "std.length", args, 1, [ + "length" => parse_args!(context, "std.length", args, 1, [ 0, x: [Val::Str|Val::Arr|Val::Obj], vec![ValType::Str, ValType::Arr, ValType::Obj]; ], { Ok(match x { @@ -42,13 +41,13 @@ }) })?, // any - ("std", "type") => parse_args!(context, "std.type", args, 1, [ + "type" => parse_args!(context, "std.type", args, 1, [ 0, x, vec![]; ], { Ok(Val::Str(x.value_type()?.name().into())) })?, // length, idx=>any - ("std", "makeArray") => parse_args!(context, "std.makeArray", args, 2, [ + "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]; ], { @@ -65,7 +64,7 @@ Ok(Val::Arr(Rc::new(out))) })?, // string - ("std", "codepoint") => parse_args!(context, "std.codepoint", args, 1, [ + "codepoint" => parse_args!(context, "std.codepoint", args, 1, [ 0, str: [Val::Str]!!Val::Str, vec![ValType::Str]; ], { assert!( @@ -75,7 +74,7 @@ Ok(Val::Num(str.chars().take(1).next().unwrap() as u32 as f64)) })?, // object, includeHidden - ("std", "objectFieldsEx") => parse_args!(context, "std.objectFieldsEx",args, 2, [ + "objectFieldsEx" => 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]; ], { @@ -88,7 +87,7 @@ Ok(Val::Arr(Rc::new(out.into_iter().map(Val::Str).collect()))) })?, // object, field, includeHidden - ("std", "objectHasEx") => parse_args!(context, "std.objectHasEx", args, 3, [ + "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]; @@ -100,36 +99,36 @@ .any(|(k, _v)| *k == *f), )) })?, - ("std", "primitiveEquals") => parse_args!(context, "std.primitiveEquals", args, 2, [ + "primitiveEquals" => parse_args!(context, "std.primitiveEquals", args, 2, [ 0, a, vec![]; 1, b, vec![]; ], { Ok(Val::Bool(primitive_equals(&a, &b)?)) })?, // faster - ("std", "equals") => parse_args!(context, "std.equals", args, 2, [ + "equals" => parse_args!(context, "std.equals", args, 2, [ 0, a, vec![]; 1, b, vec![]; ], { Ok(Val::Bool(equals(&a, &b)?)) })?, - ("std", "modulo") => parse_args!(context, "std.modulo", args, 2, [ + "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]; ], { Ok(Val::Num(a % b)) })?, - ("std", "floor") => parse_args!(context, "std.floor", args, 1, [ + "floor" => parse_args!(context, "std.floor", args, 1, [ 0, x: [Val::Num]!!Val::Num, vec![ValType::Num]; ], { Ok(Val::Num(x.floor())) })?, - ("std", "log") => parse_args!(context, "std.log", args, 2, [ + "log" => parse_args!(context, "std.log", args, 2, [ 0, n: [Val::Num]!!Val::Num, vec![ValType::Num]; ], { Ok(Val::Num(n.ln())) })?, - ("std", "trace") => parse_args!(context, "std.trace", args, 2, [ + "trace" => parse_args!(context, "std.trace", args, 2, [ 0, str: [Val::Str]!!Val::Str, vec![ValType::Str]; 1, rest, vec![]; ], { @@ -143,27 +142,27 @@ eprintln!(" {}", str); Ok(rest) })?, - ("std", "pow") => parse_args!(context, "std.modulo", args, 2, [ + "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]; ], { Ok(Val::Num(x.powf(n))) })?, - ("std", "extVar") => parse_args!(context, "std.extVar", args, 1, [ + "extVar" => parse_args!(context, "std.extVar", args, 1, [ 0, x: [Val::Str]!!Val::Str, vec![ValType::Str]; ], { Ok(with_state(|s| s.settings().ext_vars.get(&x).cloned()).ok_or_else( || UndefinedExternalVariable(x), )?) })?, - ("std", "native") => parse_args!(context, "std.native", args, 1, [ + "native" => parse_args!(context, "std.native", args, 1, [ 0, x: [Val::Str]!!Val::Str, vec![ValType::Str]; ], { Ok(with_state(|s| s.settings().ext_natives.get(&x).cloned()).map(|v| Val::Func(Rc::new(FuncVal::NativeExt(x.clone(), v)))).ok_or_else( || UndefinedExternalFunction(x), )?) })?, - ("std", "filter") => parse_args!(context, "std.filter", args, 2, [ + "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]; ], { @@ -181,7 +180,7 @@ ))) })?, // faster - ("std", "foldl") => parse_args!(context, "std.foldl", args, 3, [ + "foldl" => parse_args!(context, "std.foldl", args, 3, [ 0, func: [Val::Func]!!Val::Func, vec![ValType::Func]; 1, arr: [Val::Arr]!!Val::Arr, vec![ValType::Arr]; 2, init, vec![]; @@ -193,7 +192,7 @@ Ok(acc) })?, // faster - ("std", "foldr") => parse_args!(context, "std.foldr", args, 3, [ + "foldr" => parse_args!(context, "std.foldr", args, 3, [ 0, func: [Val::Func]!!Val::Func, vec![ValType::Func]; 1, arr: [Val::Arr]!!Val::Arr, vec![ValType::Arr]; 2, init, vec![]; @@ -206,7 +205,7 @@ })?, // faster #[allow(non_snake_case)] - ("std", "sortImpl") => parse_args!(context, "std.sort", args, 2, [ + "sortImpl" => parse_args!(context, "std.sort", args, 2, [ 0, arr: [Val::Arr]!!Val::Arr, vec![ValType::Arr]; 1, keyF: [Val::Func]!!Val::Func, vec![ValType::Func]; ], { @@ -216,7 +215,7 @@ Ok(Val::Arr(sort::sort(context, arr, &keyF)?)) })?, // faster - ("std", "format") => parse_args!(context, "std.format", args, 2, [ + "format" => parse_args!(context, "std.format", args, 2, [ 0, str: [Val::Str]!!Val::Str, vec![ValType::Str]; 1, vals, vec![] ], { @@ -229,7 +228,7 @@ }) })?, // faster - ("std", "range") => parse_args!(context, "std.range", args, 2, [ + "range" => parse_args!(context, "std.range", args, 2, [ 0, from: [Val::Num]!!Val::Num, vec![ValType::Num]; 1, to: [Val::Num]!!Val::Num, vec![ValType::Num]; ], { @@ -239,7 +238,7 @@ } Ok(Val::Arr(Rc::new(out))) })?, - ("std", "char") => parse_args!(context, "std.char", args, 1, [ + "char" => parse_args!(context, "std.char", args, 1, [ 0, n: [Val::Num]!!Val::Num, vec![ValType::Num]; ], { let mut out = String::new(); @@ -248,18 +247,18 @@ )?); Ok(Val::Str(out.into())) })?, - ("std", "encodeUTF8") => parse_args!(context, "std.encodeUtf8", args, 1, [ + "encodeUTF8" => parse_args!(context, "std.encodeUtf8", args, 1, [ 0, str: [Val::Str]!!Val::Str, vec![ValType::Str]; ], { Ok(Val::Arr(Rc::new(str.bytes().map(|b| Val::Num(b as f64)).collect()))) })?, - ("std", "md5") => parse_args!(context, "std.md5", args, 1, [ + "md5" => parse_args!(context, "std.md5", args, 1, [ 0, str: [Val::Str]!!Val::Str, vec![ValType::Str]; ], { Ok(Val::Str(format!("{:x}", md5::compute(&str.as_bytes())).into())) })?, // faster - ("std", "base64") => parse_args!(context, "std.base64", args, 1, [ + "base64" => parse_args!(context, "std.base64", args, 1, [ 0, input: [Val::Str | Val::Arr], vec![ValType::Arr, ValType::Str]; ], { Ok(Val::Str(match input { @@ -275,7 +274,7 @@ })) })?, // faster - ("std", "join") => parse_args!(context, "std.join", args, 2, [ + "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]; ], { @@ -322,13 +321,13 @@ }) })?, // Faster - ("std", "escapeStringJson") => parse_args!(context, "std.escapeStringJson", args, 1, [ + "escapeStringJson" => parse_args!(context, "std.escapeStringJson", args, 1, [ 0, str_: [Val::Str]!!Val::Str, vec![ValType::Str]; ], { Ok(Val::Str(escape_string_json(&str_).into())) })?, // Faster - ("std", "manifestJsonEx") => parse_args!(context, "std.manifestJsonEx", args, 2, [ + "manifestJsonEx" => parse_args!(context, "std.manifestJsonEx", args, 2, [ 0, value, vec![]; 1, indent: [Val::Str]!!Val::Str, vec![ValType::Str]; ], { @@ -338,18 +337,18 @@ })?.into())) })?, // Faster - ("std", "reverse") => parse_args!(context, "std.reverse", args, 1, [ + "reverse" => parse_args!(context, "std.reverse", args, 1, [ 0, arr: [Val::Arr]!!Val::Arr, vec![ValType::Arr]; ], { let mut marr = arr; Rc::make_mut(&mut marr).reverse(); Ok(Val::Arr(marr)) })?, - ("std", "id") => parse_args!(context, "std.id", args, 1, [ + "id" => parse_args!(context, "std.id", args, 1, [ 0, v, vec![]; ], { Ok(v) })?, - (ns, name) => throw!(IntrinsicNotFound(ns.into(), name.into())), + name => throw!(IntrinsicNotFound(name.into())), }) } --- a/crates/jrsonnet-evaluator/src/error.rs +++ b/crates/jrsonnet-evaluator/src/error.rs @@ -8,8 +8,8 @@ #[derive(Error, Debug, Clone)] pub enum Error { - #[error("intrinsic not found: {0}.{1}")] - IntrinsicNotFound(Rc, Rc), + #[error("intrinsic not found: {0}")] + IntrinsicNotFound(Rc), #[error("argument reordering in intrisics not supported yet")] IntrinsicArgumentReorderingIsNotSupportedYet, --- a/crates/jrsonnet-evaluator/src/evaluate.rs +++ b/crates/jrsonnet-evaluator/src/evaluate.rs @@ -466,10 +466,8 @@ || { if let Some(v) = v.get(s.clone())? { Ok(v.unwrap_if_lazy()?) - } else if let Some(Val::Str(n)) = - v.get("__intrinsic_namespace__".into())? - { - Ok(Val::Func(Rc::new(FuncVal::Intrinsic(n, s)))) + } else if v.get("__intrinsic_namespace__".into())?.is_some() { + Ok(Val::Func(Rc::new(FuncVal::Intrinsic(s)))) } else { throw!(NoSuchField(s)) } @@ -558,6 +556,7 @@ Function(params, body) => { evaluate_method(context, "anonymous".into(), params.clone(), body.clone()) } + Intrinsic(name) => Val::Func(Rc::new(FuncVal::Intrinsic(name.clone()))), AssertExpr(AssertStmt(value, msg), returned) => { let assertion_result = push( &value.1, --- a/crates/jrsonnet-evaluator/src/lib.rs +++ b/crates/jrsonnet-evaluator/src/lib.rs @@ -893,4 +893,12 @@ )?; Ok(()) } + + #[test] + fn constant_intrinsic() -> crate::error::Result<()> { + assert_eval!( + "local std2 = std; local std = std2 { primitiveEquals(a, b):: false }; 1 == 1" + ); + Ok(()) + } } --- a/crates/jrsonnet-evaluator/src/val.rs +++ b/crates/jrsonnet-evaluator/src/val.rs @@ -76,7 +76,7 @@ /// Plain function implemented in jsonnet Normal(FuncDesc), /// Standard library function - Intrinsic(Rc, Rc), + Intrinsic(Rc), /// Library functions implemented in native NativeExt(Rc, Rc), } @@ -85,7 +85,7 @@ fn eq(&self, other: &Self) -> bool { match (self, other) { (Self::Normal(a), Self::Normal(b)) => a == b, - (Self::Intrinsic(ans, an), Self::Intrinsic(bns, bn)) => ans == bns && an == bn, + (Self::Intrinsic(an), Self::Intrinsic(bn)) => an == bn, (Self::NativeExt(an, _), Self::NativeExt(bn, _)) => an == bn, (..) => false, } @@ -93,12 +93,12 @@ } impl FuncVal { pub fn is_ident(&self) -> bool { - matches!(&self, Self::Intrinsic(ns, n) if ns as &str == "std" && n as &str == "id") + matches!(&self, Self::Intrinsic(n) if n as &str == "id") } pub fn name(&self) -> Rc { match self { Self::Normal(normal) => normal.name.clone(), - Self::Intrinsic(ns, name) => format!("intrinsic.{}.{}", ns, name).into(), + Self::Intrinsic(name) => format!("std.{}", name).into(), Self::NativeExt(n, _) => format!("native.{}", n).into(), } } @@ -120,7 +120,7 @@ )?; evaluate(ctx, &func.body) } - Self::Intrinsic(ns, name) => call_builtin(call_ctx, loc, ns, name, args), + Self::Intrinsic(name) => call_builtin(call_ctx, loc, name, args), Self::NativeExt(_name, handler) => { let args = parse_function_call(call_ctx, None, &handler.params, args, true)?; let mut out_args = Vec::with_capacity(handler.params.len()); @@ -149,7 +149,7 @@ )?; evaluate(ctx, &func.body) } - Self::Intrinsic(_, _) => todo!(), + Self::Intrinsic(_) => todo!(), Self::NativeExt(_, _) => todo!(), } } @@ -160,7 +160,7 @@ let ctx = place_args(call_ctx, Some(func.ctx.clone()), &func.params, args)?; evaluate(ctx, &func.body) } - Self::Intrinsic(_, _) => todo!(), + Self::Intrinsic(_) => todo!(), Self::NativeExt(_, _) => todo!(), } } --- a/crates/jrsonnet-parser/src/expr.rs +++ b/crates/jrsonnet-parser/src/expr.rs @@ -311,6 +311,8 @@ Index(LocExpr, LocExpr), /// function(x) x Function(ParamsDesc, LocExpr), + /// std.primitiveEquals + Intrinsic(Rc), /// if true == false then 1 else 2 IfElse { cond: IfSpecData, --- a/crates/jrsonnet-parser/src/lib.rs +++ b/crates/jrsonnet-parser/src/lib.rs @@ -221,18 +221,12 @@ a:(@) _ "&" _ b:@ {loc_expr_todo!(Expr::BinaryOp(a, BinaryOpType::BitAnd, b))} -- a:(@) _ "==" _ b:@ {loc_expr_todo!(Expr::Apply( - el!(Expr::Index( - el!(Expr::Var("std".into())), - el!(Expr::Str("equals".into())) - )), + el!(Expr::Intrinsic("equals".into())), ArgsDesc(vec![Arg(None, a), Arg(None, b)]), true ))} a:(@) _ "!=" _ b:@ {loc_expr_todo!(Expr::UnaryOp(UnaryOpType::Not, el!(Expr::Apply( - el!(Expr::Index( - el!(Expr::Var("std".into())), - el!(Expr::Str("equals".into())) - )), + el!(Expr::Intrinsic("equals".into())), ArgsDesc(vec![Arg(None, a), Arg(None, b)]), true ))))} @@ -242,10 +236,7 @@ a:(@) _ "<=" _ b:@ {loc_expr_todo!(Expr::BinaryOp(a, BinaryOpType::Lte, b))} a:(@) _ ">=" _ b:@ {loc_expr_todo!(Expr::BinaryOp(a, BinaryOpType::Gte, b))} a:(@) _ keyword("in") _ b:@ {loc_expr_todo!(Expr::Apply( - el!(Expr::Index( - el!(Expr::Var("std".into())), - el!(Expr::Str("objectHasEx".into())) - )), ArgsDesc(vec![Arg(None, b), Arg(None, a), Arg(None, el!(Expr::Literal(LiteralType::True)))]), + el!(Expr::Intrinsic("objectHasEx".into())), ArgsDesc(vec![Arg(None, b), Arg(None, a), Arg(None, el!(Expr::Literal(LiteralType::True)))]), true ))} -- @@ -258,10 +249,7 @@ a:(@) _ "*" _ b:@ {loc_expr_todo!(Expr::BinaryOp(a, BinaryOpType::Mul, b))} a:(@) _ "/" _ b:@ {loc_expr_todo!(Expr::BinaryOp(a, BinaryOpType::Div, b))} a:(@) _ "%" _ b:@ {loc_expr_todo!(Expr::Apply( - el!(Expr::Index( - el!(Expr::Var("std".into())), - el!(Expr::Str("mod".into())) - )), ArgsDesc(vec![Arg(None, a), Arg(None, b)]), + el!(Expr::Intrinsic("mod".into())), ArgsDesc(vec![Arg(None, a), Arg(None, b)]), false ))} -- @@ -270,10 +258,7 @@ "~" _ b:@ { loc_expr_todo!(Expr::UnaryOp(UnaryOpType::BitNot, b)) } -- a:(@) _ "[" _ s:slice_desc(s) _ "]" {loc_expr_todo!(Expr::Apply( - el!(Expr::Index( - el!(Expr::Var("std".into())), - el!(Expr::Str("slice".into())), - )), + el!(Expr::Intrinsic("slice".into())), ArgsDesc(vec![ Arg(None, a), Arg(None, s.start.unwrap_or_else(||el!(Expr::Literal(LiteralType::Null)))), -- gitstuff