difftreelog
feat(evaluator) stacktrace preparation
in: master
3 files changed
crates/jsonnet-evaluator/src/evaluate.rsdiffbeforeafterboth--- a/crates/jsonnet-evaluator/src/evaluate.rs
+++ b/crates/jsonnet-evaluator/src/evaluate.rs
@@ -67,37 +67,25 @@
pub fn evaluate_unary_op(op: UnaryOpType, b: &Val) -> Val {
match (op, b) {
- (o, Val::Lazy(l)) => evaluate_unary_op(o, &l.0()),
- (UnaryOpType::Not, Val::Literal(LiteralType::True)) => Val::Literal(LiteralType::False),
- (UnaryOpType::Not, Val::Literal(LiteralType::False)) => Val::Literal(LiteralType::True),
+ (o, Val::Lazy(l)) => evaluate_unary_op(o, &l.evaluate()),
+ (UnaryOpType::Not, Val::Bool(v)) => Val::Bool(!v),
(op, o) => panic!("unary op not implemented: {:?} {:?}", op, o),
}
}
pub fn evaluate_binary_op(a: &Val, op: BinaryOpType, b: &Val) -> Val {
match (a, op, b) {
- (Val::Lazy(a), o, b) => evaluate_binary_op(&a.0(), o, b),
- (a, o, Val::Lazy(b)) => evaluate_binary_op(a, o, &b.0()),
+ (Val::Lazy(a), o, b) => evaluate_binary_op(&a.evaluate(), o, b),
+ (a, o, Val::Lazy(b)) => evaluate_binary_op(a, o, &b.evaluate()),
(Val::Str(v1), BinaryOpType::Add, Val::Str(v2)) => Val::Str(v1.to_owned() + &v2),
- (Val::Str(v1), BinaryOpType::Eq, Val::Str(v2)) => bool_val(v1 == v2),
(Val::Str(v1), BinaryOpType::Ne, Val::Str(v2)) => bool_val(v1 != v2),
(Val::Str(v1), BinaryOpType::Add, Val::Num(v2)) => Val::Str(format!("{}{}", v1, v2)),
(Val::Str(v1), BinaryOpType::Mul, Val::Num(v2)) => Val::Str(v1.repeat(*v2 as usize)),
- (Val::Literal(LiteralType::False), BinaryOpType::And, Val::Literal(LiteralType::False)) => {
- bool_val(false)
- }
- (Val::Literal(LiteralType::False), BinaryOpType::And, Val::Literal(LiteralType::True)) => {
- bool_val(false)
- }
- (Val::Literal(LiteralType::True), BinaryOpType::And, Val::Literal(LiteralType::False)) => {
- bool_val(false)
- }
- (Val::Literal(LiteralType::True), BinaryOpType::And, Val::Literal(LiteralType::True)) => {
- bool_val(true)
- }
+ (Val::Bool(a), BinaryOpType::And, Val::Bool(b)) => Val::Bool(*a && *b),
+ (Val::Bool(a), BinaryOpType::Or, Val::Bool(b)) => Val::Bool(*a || *b),
(Val::Obj(v1), BinaryOpType::Add, Val::Obj(v2)) => Val::Obj(v2.with_super(v1.clone())),
@@ -134,6 +122,8 @@
(Val::Num(v1), BinaryOpType::BitXor, Val::Num(v2)) => {
Val::Num(((*v1 as i32) ^ (*v2 as i32)) as f64)
}
+ (a, BinaryOpType::Eq, b) => bool_val(a == b),
+ (a, BinaryOpType::Ne, b) => bool_val(a != b),
_ => panic!("no rules for binary operation: {:?} {:?} {:?}", a, op, b),
}
}
@@ -238,7 +228,7 @@
pub fn evaluate(context: Context, expr: &LocExpr) -> Val {
use Expr::*;
- let LocExpr(expr, _location) = expr;
+ let LocExpr(expr, loc) = expr;
match &**expr {
Literal(LiteralType::This) => Val::Obj(
context
@@ -252,7 +242,9 @@
.clone()
.unwrap_or_else(|| panic!("super not found")),
),
- Literal(t) => Val::Literal(t.clone()),
+ Literal(LiteralType::True) => Val::Bool(true),
+ Literal(LiteralType::False) => Val::Bool(false),
+ Literal(LiteralType::Null) => Val::Null,
Parened(e) => evaluate(context, e),
Str(v) => Val::Str(v.clone()),
Num(v) => Val::Num(*v),
@@ -383,13 +375,16 @@
cond_then,
cond_else,
} => match evaluate(context.clone(), &cond.0).unwrap_if_lazy() {
- Val::Literal(LiteralType::True) => evaluate(context, cond_then),
- Val::Literal(LiteralType::False) => match cond_else {
+ Val::Bool(true) => evaluate(context, cond_then),
+ Val::Bool(false) => match cond_else {
Some(v) => evaluate(context, v),
- None => Val::Literal(LiteralType::False),
+ None => Val::Bool(false),
},
v => panic!("if condition evaluated to {:?} (boolean needed instead)", v),
},
- _ => panic!("evaluation not implemented: {:?}", expr),
+ _ => panic!(
+ "evaluation not implemented: {:?}",
+ LocExpr(expr.clone(), loc.clone())
+ ),
}
}
crates/jsonnet-evaluator/src/lib.rsdiffbeforeafterboth1#![feature(box_syntax, box_patterns)]2#![feature(type_alias_impl_trait)]3#![feature(debug_non_exhaustive)]4#![allow(macro_expanded_macro_exports_accessed_by_absolute_paths)]5mod ctx;6mod dynamic;7mod evaluate;8mod obj;9mod val;1011pub use ctx::*;12pub use dynamic::*;13pub use evaluate::*;14use jsonnet_parser::*;15pub use obj::*;16pub use val::*;1718rc_fn_helper!(19 Binding,20 binding,21 dyn Fn(Option<ObjValue>, Option<ObjValue>) -> Val22);23rc_fn_helper!(24 LazyBinding,25 lazy_binding,26 dyn Fn(Option<ObjValue>, Option<ObjValue>) -> LazyVal27);28rc_fn_helper!(FunctionRhs, function_rhs, dyn Fn(Context) -> Val);29rc_fn_helper!(30 FunctionDefault,31 function_default,32 dyn Fn(Context, LocExpr) -> Val33);3435#[cfg(test)]36pub mod tests {37 use super::{evaluate, Context, Val};38 use jsonnet_parser::*;3940 macro_rules! eval {41 ($str: expr) => {42 evaluate(Context::new(), &parse($str, &ParserSettings {43 loc_data: false,44 file_name: "test.jsonnet".to_owned(),45 }).unwrap())46 };47 }4849 macro_rules! eval_stdlib {50 ($str: expr) => {{51 let std = "local std = ".to_owned() + jsonnet_stdlib::STDLIB_STR + ";";52 evaluate(Context::new(), &parse(&(std + $str), &ParserSettings {53 loc_data: false,54 file_name: "test.jsonnet".to_owned(),55 }).unwrap())56 }};57 }5859 macro_rules! assert_eval {60 ($str: expr) => {61 assert_eq!(62 evaluate(Context::new(), &parse($str, &ParserSettings {63 loc_data: false,64 file_name: "test.jsonnet".to_owned(),65 }).unwrap()),66 Val::Literal(LiteralType::True)67 )68 };69 }70 macro_rules! assert_json {71 ($str: expr, $out: expr) => {72 assert_eq!(73 format!("{}", evaluate(Context::new(), &parse($str, &ParserSettings {74 loc_data: false,75 file_name: "test.jsonnet".to_owned(),76 }).unwrap())),77 $out78 )79 };80 }81 macro_rules! assert_json_stdlib {82 ($str: expr, $out: expr) => {83 assert_eq!(format!("{}", eval_stdlib!($str)), $out)84 };85 }86 macro_rules! assert_eval_neg {87 ($str: expr) => {88 assert_eq!(89 evaluate(Context::new(), &parse($str, &ParserSettings {90 loc_data: false,91 file_name: "test.jsonnet".to_owned(),92 }).unwrap()),93 Val::Literal(LiteralType::False)94 )95 };96 }9798 /// Sanity checking, before trusting to another tests99 #[test]100 fn equality_operator() {101 assert_eval!("2 == 2");102 assert_eval_neg!("2 != 2");103 assert_eval!("2 != 3");104 assert_eval_neg!("2 == 3");105 assert_eval!("'Hello' == 'Hello'");106 assert_eval_neg!("'Hello' != 'Hello'");107 assert_eval!("'Hello' != 'World'");108 assert_eval_neg!("'Hello' == 'World'");109 }110111 #[test]112 fn math_evaluation() {113 assert_eval!("2 + 2 * 2 == 6");114 assert_eval!("3 + (2 + 2 * 2) == 9");115 }116117 #[test]118 fn string_concat() {119 assert_eval!("'Hello' + 'World' == 'HelloWorld'");120 assert_eval!("'Hello' * 3 == 'HelloHelloHello'");121 assert_eval!("'Hello' + 'World' * 3 == 'HelloWorldWorldWorld'");122 }123124 #[test]125 fn local() {126 assert_eval!("local a = 2; local b = 3; a + b == 5");127 assert_eval!("local a = 1, b = a + 1; a + b == 3");128 assert_eval!("local a = 1; local a = 2; a == 2");129 }130131 #[test]132 fn object_lazyness() {133 assert_json!("local a = {a:error 'test'}; {}", r#"{}"#);134 }135136 #[test]137 fn object_inheritance() {138 assert_json!("{a: self.b} + {b:3}", r#"{"a":3,"b":3}"#);139 }140141 #[test]142 fn test_object() {143 assert_json!("{a:2}", r#"{"a":2}"#);144 assert_json!("{a:2+2}", r#"{"a":4}"#);145 assert_json!("{a:2}+{b:2}", r#"{"a":2,"b":2}"#);146 assert_json!("{b:3}+{b:2}", r#"{"b":2}"#);147 assert_json!("{b:3}+{b+:2}", r#"{"b":5}"#);148 assert_json!("local test='a'; {[test]:2}", r#"{"a":2}"#);149 assert_json!(150 r#"151 {152 name: "Alice",153 welcome: "Hello " + self.name + "!",154 }155 "#,156 r#"{"name":"Alice","welcome":"Hello Alice!"}"#157 );158 assert_json!(159 r#"160 {161 name: "Alice",162 welcome: "Hello " + self.name + "!",163 } + {164 name: "Bob"165 }166 "#,167 r#"{"name":"Bob","welcome":"Hello Bob!"}"#168 );169 }170171 #[test]172 fn functions() {173 assert_json!(r#"local a = function(b, c = 2) b + c; a(2)"#, "4");174 assert_json!(175 r#"local a = function(b, c = "Dear") b + c + d, d = "World"; a("Hello")"#,176 r#""HelloDearWorld""#177 );178 }179180 #[test]181 fn local_methods() {182 assert_json!(r#"local a(b, c = 2) = b + c; a(2)"#, "4");183 assert_json!(184 r#"local a(b, c = "Dear") = b + c + d, d = "World"; a("Hello")"#,185 r#""HelloDearWorld""#186 );187 }188189 #[test]190 fn object_locals() {191 assert_json!(r#"{local a = 3, b: a}"#, r#"{"b":3}"#);192 assert_json!(r#"{local a = 3, local c = a, b: c}"#, r#"{"b":3}"#);193 assert_json!(194 r#"{local a = function (b) {[b]:4}, test: a("test")}"#,195 r#"{"test":{"test":4}}"#196 );197 }198199 #[test]200 fn direct_self() {201 println!(202 "{:#?}",203 eval!(204 r#"205 {206 local me = self,207 a: 3,208 b(): me.a,209 }210 "#211 )212 );213 }214215 #[test]216 fn indirect_self() {217 // `self` assigned to `me` was lost when being218 // referenced from field219 eval_stdlib!(220 r#"{221 local me = self,222 a: 3,223 b: me.a,224 }.b"#225 );226 }227228 // We can't trust other tests (And official jsonnet testsuite), if assert is not working correctly229 #[test]230 fn std_assert_ok() {231 eval_stdlib!("std.assertEqual(4.5 << 2, 16)");232 }233234 #[test]235 #[should_panic]236 fn std_assert_failure() {237 eval_stdlib!("std.assertEqual(4.5 << 2, 15)");238 }239240 #[test]241 fn string_is_string() {242 assert_eq!(243 eval_stdlib!("local arr = 'hello'; (!std.isArray(arr)) && (!std.isString(arr))"),244 Val::Literal(LiteralType::False)245 );246 }247248 #[test]249 fn base64_works() {250 assert_json_stdlib!(r#"std.base64("test")"#, r#""dGVzdA==""#);251 }252253 #[test]254 fn utf8_chars() {255 assert_json_stdlib!(256 r#"local c="😎";{c:std.codepoint(c),l:std.length(c)}"#,257 r#"{"c":128526,"l":1}"#258 )259 }260}crates/jsonnet-parser/src/expr.rsdiffbeforeafterboth--- a/crates/jsonnet-parser/src/expr.rs
+++ b/crates/jsonnet-parser/src/expr.rs
@@ -1,7 +1,4 @@
-use std::{
- fmt::{Debug, Display},
- rc::Rc,
-};
+use std::{fmt::Debug, rc::Rc};
#[derive(Debug, Clone, PartialEq)]
pub enum FieldName {
@@ -135,18 +132,6 @@
True,
False,
}
-impl Display for LiteralType {
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- use LiteralType::*;
- match self {
- This => write!(f, "this"),
- Null => write!(f, "null"),
- True => write!(f, "true"),
- False => write!(f, "false"),
- _ => panic!("non printable item"),
- }
- }
-}
#[derive(Debug, Clone, PartialEq)]
pub struct SliceDesc {
@@ -241,7 +226,7 @@
pub struct ExprLocation(pub String, pub usize, pub usize);
impl Debug for ExprLocation {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- write!(f, "{}:{:?}", self.0, self.1)
+ write!(f, "{}:{:?}-{:?}", self.0, self.1, self.2)
}
}
@@ -259,13 +244,13 @@
macro_rules! loc_expr {
($expr:expr, $need_loc:expr, ($name:expr, $start:expr, $end:expr)) => {
LocExpr(
- Rc::new($expr),
+ std::rc::Rc::new($expr),
if $need_loc {
- Some(Rc::new(ExprLocation($name.to_owned(), $start, $end)))
+ Some(std::rc::Rc::new(ExprLocation($name.to_owned(), $start, $end)))
} else {
None
- },
- )
+ },
+ )
};
}