git.delta.rocks / jrsonnet / refs/commits / 1450eba56177

difftreelog

feat(evaluator) stacktrace preparation

Лач2020-06-01parent: #b25a25b.patch.diff
in: master

3 files changed

modifiedcrates/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())
+		),
 	}
 }
modifiedcrates/jsonnet-evaluator/src/lib.rsdiffbeforeafterboth
13pub use evaluate::*;13pub use evaluate::*;
14use jsonnet_parser::*;14use jsonnet_parser::*;
15pub use obj::*;15pub use obj::*;
16use std::{cell::RefCell, collections::HashMap, rc::Rc};
16pub use val::*;17pub use val::*;
1718
18rc_fn_helper!(19rc_fn_helper!(
32 dyn Fn(Context, LocExpr) -> Val33 dyn Fn(Context, LocExpr) -> Val
33);34);
35
36pub struct ExitGuard<'s>(&'s EvaluationState);
37impl<'s> Drop for ExitGuard<'s> {
38 fn drop(&mut self) {
39 self.0.stack.borrow_mut().pop();
40 }
41}
42
43pub struct EvaluationState {
44 pub stack: Rc<RefCell<Vec<LocExpr>>>,
45 pub files: Rc<RefCell<HashMap<String, String>>>,
46}
47impl EvaluationState {
48 #[must_use = "should keep exit guard before exit from function"]
49 pub fn push(&self, e: LocExpr) -> ExitGuard {
50 self.stack.borrow_mut().push(e);
51 ExitGuard(self)
52 }
53 pub fn print_stack_trace(&self) {
54 for e in self
55 .stack
56 .borrow()
57 .iter()
58 .rev()
59 .map(|e| e.1.clone())
60 .flatten()
61 {
62 println!("{:?}", e)
63 }
64 }
65}
66impl Default for EvaluationState {
67 fn default() -> Self {
68 EvaluationState {
69 stack: Rc::new(RefCell::new(Vec::new())),
70 files: Rc::new(RefCell::new(HashMap::new())),
71 }
72 }
73}
3474
35#[cfg(test)]75#[cfg(test)]
36pub mod tests {76pub mod tests {
37 use super::{evaluate, Context, Val};77 use super::{evaluate, Context, Val};
78 use crate::EvaluationState;
38 use jsonnet_parser::*;79 use jsonnet_parser::*;
80
81 #[test]
82 fn eval_state_stacktrace() {
83 let state = EvaluationState::default();
84 let _v = state.push(loc_expr!(
85 Expr::Num(0.0),
86 true,
87 ("test.jsonnet".to_owned(), 10, 20)
88 ));
89
90 state.print_stack_trace()
91 }
3992
40 macro_rules! eval {93 macro_rules! eval {
41 ($str: expr) => {94 ($str: expr) => {
42 evaluate(Context::new(), &parse($str, &ParserSettings {95 evaluate(
96 Context::new(),
97 &parse(
98 $str,
99 &ParserSettings {
43 loc_data: false,100 loc_data: true,
44 file_name: "test.jsonnet".to_owned(),101 file_name: "test.jsonnet".to_owned(),
45 }).unwrap())102 },
103 )
114 &parse(
115 &(std + $str),
116 &ParserSettings {
53 loc_data: false,117 loc_data: true,
54 file_name: "test.jsonnet".to_owned(),118 file_name: "test.jsonnet".to_owned(),
55 }).unwrap())119 },
120 )
131 &parse(
132 $str,
133 &ParserSettings {
63 loc_data: false,134 loc_data: true,
64 file_name: "test.jsonnet".to_owned(),135 file_name: "test.jsonnet".to_owned(),
65 }).unwrap()),136 }
137 )
138 .unwrap()
139 ),
66 Val::Literal(LiteralType::True)140 Val::Bool(true)
67 )141 )
68 };142 };
69 }143 }
70 macro_rules! assert_json {144 macro_rules! assert_json {
71 ($str: expr, $out: expr) => {145 ($str: expr, $out: expr) => {
72 assert_eq!(146 assert_eq!(
73 format!("{}", evaluate(Context::new(), &parse($str, &ParserSettings {147 format!(
148 "{}",
149 evaluate(
150 Context::new(),
151 &parse(
152 $str,
153 &ParserSettings {
74 loc_data: false,154 loc_data: true,
75 file_name: "test.jsonnet".to_owned(),155 file_name: "test.jsonnet".to_owned(),
76 }).unwrap())),156 }
157 )
175 &parse(
176 $str,
177 &ParserSettings {
90 loc_data: false,178 loc_data: true,
91 file_name: "test.jsonnet".to_owned(),179 file_name: "test.jsonnet".to_owned(),
92 }).unwrap()),180 }
181 )
182 .unwrap()
183 ),
93 Val::Literal(LiteralType::False)184 Val::Bool(false)
94 )185 )
95 };186 };
96 }187 }
241 fn string_is_string() {332 fn string_is_string() {
242 assert_eq!(333 assert_eq!(
243 eval_stdlib!("local arr = 'hello'; (!std.isArray(arr)) && (!std.isString(arr))"),334 eval_stdlib!("local arr = 'hello'; (!std.isArray(arr)) && (!std.isString(arr))"),
244 Val::Literal(LiteralType::False)335 Val::Bool(false)
245 );336 );
246 }337 }
247338
258 )349 )
259 }350 }
351
352 #[test]
353 fn json() {
354 println!("{:?}", eval_stdlib!(r#"std.manifestJson({a:3, b:4, c:6})"#));
355 }
356
357 #[test]
358 fn sjsonnet() {
359 eval!(
360 r#"
361 local x0 = {k: 1};
362 local x1 = {k: x0.k + x0.k};
363 local x2 = {k: x1.k + x1.k};
364 local x3 = {k: x2.k + x2.k};
365 local x4 = {k: x3.k + x3.k};
366 local x5 = {k: x4.k + x4.k};
367 local x6 = {k: x5.k + x5.k};
368 local x7 = {k: x6.k + x6.k};
369 local x8 = {k: x7.k + x7.k};
370 local x9 = {k: x8.k + x8.k};
371 local x10 = {k: x9.k + x9.k};
372 local x11 = {k: x10.k + x10.k};
373 local x12 = {k: x11.k + x11.k};
374 local x13 = {k: x12.k + x12.k};
375 local x14 = {k: x13.k + x13.k};
376 local x15 = {k: x14.k + x14.k};
377 local x16 = {k: x15.k + x15.k};
378 local x17 = {k: x16.k + x16.k};
379 local x18 = {k: x17.k + x17.k};
380 local x19 = {k: x18.k + x18.k};
381 local x20 = {k: x19.k + x19.k};
382 local x21 = {k: x20.k + x20.k};
383 x21.k
384 "#
385 );
386 }
260}387}
261388
modifiedcrates/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
-			},
-		)
+				},
+			)
 	};
 }