difftreelog
feat(evaluator) stacktrace preparation
in: master
3 files changed
crates/jsonnet-evaluator/src/evaluate.rsdiffbeforeafterboth676768pub 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}767577pub 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()),818082 (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),858386 (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)),888689 (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 }10189102 (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())),10391134 (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}238228239pub 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 context252 .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}crates/jsonnet-evaluator/src/lib.rsdiffbeforeafterboth13pub 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::*;171818rc_fn_helper!(19rc_fn_helper!(32 dyn Fn(Context, LocExpr) -> Val33 dyn Fn(Context, LocExpr) -> Val33);34);3536pub 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}4243pub 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 self55 .stack56 .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}347435#[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::*;8081 #[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 ));8990 state.print_stack_trace()91 }399240 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 }247338258 )349 )259 }350 }351352 #[test]353 fn json() {354 println!("{:?}", eval_stdlib!(r#"std.manifestJson({a:3, b:4, c:6})"#));355 }356357 #[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.k384 "#385 );386 }260}387}261388crates/jsonnet-parser/src/expr.rsdiffbeforeafterboth1use std::{1use std::{fmt::Debug, rc::Rc};2 fmt::{Debug, Display},3 rc::Rc,4};526#[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}150135151#[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}247232259macro_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 None267 },252 },