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
6767
68pub fn evaluate_unary_op(op: UnaryOpType, b: &Val) -> Val {68pub fn evaluate_unary_op(op: UnaryOpType, b: &Val) -> Val {
69 match (op, b) {69 match (op, b) {
70 (o, Val::Lazy(l)) => evaluate_unary_op(o, &l.0()),70 (o, Val::Lazy(l)) => evaluate_unary_op(o, &l.evaluate()),
71 (UnaryOpType::Not, Val::Literal(LiteralType::True)) => Val::Literal(LiteralType::False),71 (UnaryOpType::Not, Val::Bool(v)) => Val::Bool(!v),
72 (UnaryOpType::Not, Val::Literal(LiteralType::False)) => Val::Literal(LiteralType::True),
73 (op, o) => panic!("unary op not implemented: {:?} {:?}", op, o),72 (op, o) => panic!("unary op not implemented: {:?} {:?}", op, o),
74 }73 }
75}74}
7675
77pub fn evaluate_binary_op(a: &Val, op: BinaryOpType, b: &Val) -> Val {76pub fn evaluate_binary_op(a: &Val, op: BinaryOpType, b: &Val) -> Val {
78 match (a, op, b) {77 match (a, op, b) {
79 (Val::Lazy(a), o, b) => evaluate_binary_op(&a.0(), o, b),78 (Val::Lazy(a), o, b) => evaluate_binary_op(&a.evaluate(), o, b),
80 (a, o, Val::Lazy(b)) => evaluate_binary_op(a, o, &b.0()),79 (a, o, Val::Lazy(b)) => evaluate_binary_op(a, o, &b.evaluate()),
8180
82 (Val::Str(v1), BinaryOpType::Add, Val::Str(v2)) => Val::Str(v1.to_owned() + &v2),81 (Val::Str(v1), BinaryOpType::Add, Val::Str(v2)) => Val::Str(v1.to_owned() + &v2),
83 (Val::Str(v1), BinaryOpType::Eq, Val::Str(v2)) => bool_val(v1 == v2),
84 (Val::Str(v1), BinaryOpType::Ne, Val::Str(v2)) => bool_val(v1 != v2),82 (Val::Str(v1), BinaryOpType::Ne, Val::Str(v2)) => bool_val(v1 != v2),
8583
86 (Val::Str(v1), BinaryOpType::Add, Val::Num(v2)) => Val::Str(format!("{}{}", v1, v2)),84 (Val::Str(v1), BinaryOpType::Add, Val::Num(v2)) => Val::Str(format!("{}{}", v1, v2)),
87 (Val::Str(v1), BinaryOpType::Mul, Val::Num(v2)) => Val::Str(v1.repeat(*v2 as usize)),85 (Val::Str(v1), BinaryOpType::Mul, Val::Num(v2)) => Val::Str(v1.repeat(*v2 as usize)),
8886
89 (Val::Literal(LiteralType::False), BinaryOpType::And, Val::Literal(LiteralType::False)) => {87 (Val::Bool(a), BinaryOpType::And, Val::Bool(b)) => Val::Bool(*a && *b),
90 bool_val(false)
91 }
92 (Val::Literal(LiteralType::False), BinaryOpType::And, Val::Literal(LiteralType::True)) => {
93 bool_val(false)
94 }
95 (Val::Literal(LiteralType::True), BinaryOpType::And, Val::Literal(LiteralType::False)) => {88 (Val::Bool(a), BinaryOpType::Or, Val::Bool(b)) => Val::Bool(*a || *b),
96 bool_val(false)
97 }
98 (Val::Literal(LiteralType::True), BinaryOpType::And, Val::Literal(LiteralType::True)) => {
99 bool_val(true)
100 }
10189
102 (Val::Obj(v1), BinaryOpType::Add, Val::Obj(v2)) => Val::Obj(v2.with_super(v1.clone())),90 (Val::Obj(v1), BinaryOpType::Add, Val::Obj(v2)) => Val::Obj(v2.with_super(v1.clone())),
10391
134 (Val::Num(v1), BinaryOpType::BitXor, Val::Num(v2)) => {122 (Val::Num(v1), BinaryOpType::BitXor, Val::Num(v2)) => {
135 Val::Num(((*v1 as i32) ^ (*v2 as i32)) as f64)123 Val::Num(((*v1 as i32) ^ (*v2 as i32)) as f64)
136 }124 }
125 (a, BinaryOpType::Eq, b) => bool_val(a == b),
126 (a, BinaryOpType::Ne, b) => bool_val(a != b),
137 _ => panic!("no rules for binary operation: {:?} {:?} {:?}", a, op, b),127 _ => panic!("no rules for binary operation: {:?} {:?} {:?}", a, op, b),
138 }128 }
139}129}
238228
239pub fn evaluate(context: Context, expr: &LocExpr) -> Val {229pub fn evaluate(context: Context, expr: &LocExpr) -> Val {
240 use Expr::*;230 use Expr::*;
241 let LocExpr(expr, _location) = expr;231 let LocExpr(expr, loc) = expr;
242 match &**expr {232 match &**expr {
243 Literal(LiteralType::This) => Val::Obj(233 Literal(LiteralType::This) => Val::Obj(
244 context234 context
252 .clone()242 .clone()
253 .unwrap_or_else(|| panic!("super not found")),243 .unwrap_or_else(|| panic!("super not found")),
254 ),244 ),
255 Literal(t) => Val::Literal(t.clone()),245 Literal(LiteralType::True) => Val::Bool(true),
246 Literal(LiteralType::False) => Val::Bool(false),
247 Literal(LiteralType::Null) => Val::Null,
256 Parened(e) => evaluate(context, e),248 Parened(e) => evaluate(context, e),
257 Str(v) => Val::Str(v.clone()),249 Str(v) => Val::Str(v.clone()),
258 Num(v) => Val::Num(*v),250 Num(v) => Val::Num(*v),
383 cond_then,375 cond_then,
384 cond_else,376 cond_else,
385 } => match evaluate(context.clone(), &cond.0).unwrap_if_lazy() {377 } => match evaluate(context.clone(), &cond.0).unwrap_if_lazy() {
386 Val::Literal(LiteralType::True) => evaluate(context, cond_then),378 Val::Bool(true) => evaluate(context, cond_then),
387 Val::Literal(LiteralType::False) => match cond_else {379 Val::Bool(false) => match cond_else {
388 Some(v) => evaluate(context, v),380 Some(v) => evaluate(context, v),
389 None => Val::Literal(LiteralType::False),381 None => Val::Bool(false),
390 },382 },
391 v => panic!("if condition evaluated to {:?} (boolean needed instead)", v),383 v => panic!("if condition evaluated to {:?} (boolean needed instead)", v),
392 },384 },
393 _ => panic!("evaluation not implemented: {:?}", expr),385 _ => panic!(
386 "evaluation not implemented: {:?}",
387 LocExpr(expr.clone(), loc.clone())
388 ),
394 }389 }
395}390}
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
1use std::{1use std::{fmt::Debug, rc::Rc};
2 fmt::{Debug, Display},
3 rc::Rc,
4};
52
6#[derive(Debug, Clone, PartialEq)]3#[derive(Debug, Clone, PartialEq)]
135 True,132 True,
136 False,133 False,
137}134}
138impl Display for LiteralType {
139 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
140 use LiteralType::*;
141 match self {
142 This => write!(f, "this"),
143 Null => write!(f, "null"),
144 True => write!(f, "true"),
145 False => write!(f, "false"),
146 _ => panic!("non printable item"),
147 }
148 }
149}
150135
151#[derive(Debug, Clone, PartialEq)]136#[derive(Debug, Clone, PartialEq)]
152pub struct SliceDesc {137pub struct SliceDesc {
241pub struct ExprLocation(pub String, pub usize, pub usize);226pub struct ExprLocation(pub String, pub usize, pub usize);
242impl Debug for ExprLocation {227impl Debug for ExprLocation {
243 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {228 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
244 write!(f, "{}:{:?}", self.0, self.1)229 write!(f, "{}:{:?}-{:?}", self.0, self.1, self.2)
245 }230 }
246}231}
247232
259macro_rules! loc_expr {244macro_rules! loc_expr {
260 ($expr:expr, $need_loc:expr, ($name:expr, $start:expr, $end:expr)) => {245 ($expr:expr, $need_loc:expr, ($name:expr, $start:expr, $end:expr)) => {
261 LocExpr(246 LocExpr(
262 Rc::new($expr),247 std::rc::Rc::new($expr),
263 if $need_loc {248 if $need_loc {
264 Some(Rc::new(ExprLocation($name.to_owned(), $start, $end)))249 Some(std::rc::Rc::new(ExprLocation($name.to_owned(), $start, $end)))
265 } else {250 } else {
266 None251 None
267 },252 },