difftreelog
refactor(evaluator) use closures where possible
in: master
9 files changed
crates/jsonnet-evaluator/Cargo.tomldiffbeforeafterboth889[dependencies]9[dependencies]10jsonnet-parser = { path = "../jsonnet-parser" }10jsonnet-parser = { path = "../jsonnet-parser" }11closure = "0.3.0"111212[dev-dependencies]13[dev-dependencies]13jsonnet-stdlib = { version = "0.1.0", path = "../jsonnet-stdlib" }14jsonnet-stdlib = { version = "0.1.0", path = "../jsonnet-stdlib" }crates/jsonnet-evaluator/src/binding.rsdiffbeforeafterbothno changes
crates/jsonnet-evaluator/src/ctx.rsdiffbeforeafterboth1use crate::{dummy_debug, future_wrapper, BoxedBinding, ObjValue};1use crate::{future_wrapper, rc_fn_helper, Binding, ObjValue};2use std::{cell::RefCell, collections::HashMap, fmt::Debug, rc::Rc};2use std::{cell::RefCell, collections::HashMap, fmt::Debug, rc::Rc};334rc_fn_helper!(4pub trait ContextCreator: Debug {5 ContextCreator,6 context_creator,5 fn create_context(&self, this: &Option<ObjValue>, super_obj: &Option<ObjValue>) -> Context;7 dyn Fn(Option<ObjValue>, Option<ObjValue>) -> Context6}8);7pub type BoxedContextCreator = Rc<dyn ContextCreator>;89#[derive(Debug)]10pub struct ConstantContextCreator {11 pub context: FutureContext,12}13impl ContextCreator for ConstantContextCreator {14 fn create_context(&self, _this: &Option<ObjValue>, _super_obj: &Option<ObjValue>) -> Context {15 self.context.clone().unwrap()16 }17}18919future_wrapper!(Context, FutureContext);10future_wrapper!(Context, FutureContext);201123 dollar: Option<ObjValue>,14 dollar: Option<ObjValue>,24 this: Option<ObjValue>,15 this: Option<ObjValue>,25 super_obj: Option<ObjValue>,16 super_obj: Option<ObjValue>,26 bindings: Rc<RefCell<HashMap<String, BoxedBinding>>>,17 bindings: Rc<RefCell<HashMap<String, Binding>>>,27}18}28pub struct Context(Rc<ContextInternals>);19pub struct Context(Rc<ContextInternals>);20impl Debug for Context {29dummy_debug!(Context);21 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {22 f.debug_struct("Context")23 .field("this", &self.0.this.clone().map(|e| Rc::as_ptr(&e.0)))24 .finish()25 }26}30impl Context {27impl Context {31 pub fn new_future() -> FutureContext {28 pub fn new_future() -> FutureContext {32 FutureContext(Rc::new(RefCell::new(None)))29 FutureContext(Rc::new(RefCell::new(None)))53 }))50 }))54 }51 }555256 pub fn binding(&self, name: &str) -> BoxedBinding {53 pub fn binding(&self, name: &str) -> Binding {57 self.054 self.058 .bindings55 .bindings59 .borrow()56 .borrow()60 .get(name)57 .get(name)61 .map(|e| e.clone())58 .cloned()62 .unwrap_or_else(|| {59 .unwrap_or_else(|| {63 panic!("can't find {} in {:?}", name, self);60 panic!("can't find {} in {:?}", name, self);64 })61 })726973 pub fn extend(70 pub fn extend(74 &self,71 &self,75 new_bindings: HashMap<String, BoxedBinding>,72 new_bindings: HashMap<String, Binding>,76 new_dollar: Option<ObjValue>,73 new_dollar: Option<ObjValue>,77 new_this: Option<ObjValue>,74 new_this: Option<ObjValue>,78 new_super_obj: Option<ObjValue>,75 new_super_obj: Option<ObjValue>,79 ) -> Context {76 ) -> Context {77 println!("Extend with {:?} {:?}", new_dollar, new_this);80 let dollar = new_dollar.or(self.0.dollar.clone());78 let dollar = new_dollar.or_else(|| self.0.dollar.clone());81 let this = new_this.or(self.0.this.clone());79 let this = new_this.or_else(|| self.0.this.clone());82 let super_obj = new_super_obj.or(self.0.super_obj.clone());80 let super_obj = new_super_obj.or_else(|| self.0.super_obj.clone());83 let bindings = if new_bindings.is_empty() {81 let bindings = if new_bindings.is_empty() {84 self.0.bindings.clone()82 self.0.bindings.clone()85 } else {83 } else {98 }96 }99}97}9899impl Default for Context {100 fn default() -> Self {101 Self::new()102 }103}104100impl PartialEq for Context {105impl PartialEq for Context {101 fn eq(&self, other: &Self) -> bool {106 fn eq(&self, other: &Self) -> bool {crates/jsonnet-evaluator/src/dynamic.rsdiffbeforeafterboth1#[macro_export]2macro_rules! dynamic_wrapper {3 ($orig: ident, $wrapper: ident) => {4 #[derive(Debug, Clone)]5 pub struct $wrapper(pub std::rc::Rc<dyn $orig>);6 impl std::ops::Deref for $wrapper {7 type Target = dyn $orig;8 fn deref(&self) -> &Self::Target {9 &*self.010 }11 }12 impl std::cmp::PartialEq for $wrapper {13 fn eq(&self, other: &Self) -> bool {14 Rc::ptr_eq(&self.0, &other.0)15 }16 }17 };18}1920#[macro_export]1#[macro_export]21macro_rules! future_wrapper {2macro_rules! future_wrapper {39 self.unwrap()20 self.unwrap()40 }21 }41 }22 }23 impl Default for $wrapper {24 fn default() -> Self {25 Self::new()26 }27 }42 };28 };43}29}443045#[macro_export]31#[macro_export]46macro_rules! dummy_debug {32macro_rules! rc_fn_helper {47 ($struct: ident) => {33 ($name: ident, $macro_name: ident, $fn: ty) => {34 #[derive(Clone)]35 #[doc = "Function wrapper"]36 pub struct $name(pub std::rc::Rc<$fn>);48 impl std::fmt::Debug for $struct {37 impl std::fmt::Debug for $name {49 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {38 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {50 f.debug_struct(std::stringify!($struct))39 f.debug_struct(std::stringify!($name)).finish()51 .finish_non_exhaustive()52 }40 }53 }41 }42 impl std::cmp::PartialEq for $name {43 fn eq(&self, other: &$name) -> bool {44 std::ptr::eq(&self.0, &other.0)45 }46 }47 #[doc = "Macro to ease wrapper creation"]48 #[macro_export]49 macro_rules! $macro_name {50 ($val: expr) => {51 $crate::$name(std::rc::Rc::new($val))52 };53 }54 };54 };55}55}5656crates/jsonnet-evaluator/src/evaluate.rsdiffbeforeafterboth1use crate::BoxedLazyVal;2use crate::{1use crate::{3 bool_val, ArgsBinding, BoxedBinding, BoxedContextCreator, ConstantContextCreator, Context,2 binding, bool_val, context_creator, function_default, function_rhs, future_wrapper, lazy_val,4 FuncDesc, FunctionDefault, FunctionRhs, NoArgsBinding, Val,3 Binding, Context, ContextCreator, FuncDesc, ObjMember, ObjValue, Val,5};4};6use crate::{5use closure::closure;7 future_wrapper, BoxedFunctionDefault, BoxedFunctionRhs, ContextCreator, ObjMember, ObjValue,8 PlainLazyVal,9};10use jsonnet_parser::{6use jsonnet_parser::{11 ArgsDesc, BinaryOpType, BindSpec, Expr, FieldMember, LiteralType, Member, ObjBody, ParamsDesc,7 ArgsDesc, BinaryOpType, BindSpec, Expr, FieldMember, LiteralType, Member, ObjBody, ParamsDesc,12 Visibility,8 UnaryOpType, Visibility,13};9};14use std::{10use std::{15 cell::RefCell,16 collections::{BTreeMap, HashMap},11 collections::{BTreeMap, HashMap},17 rc::Rc,12 rc::Rc,18};13};191420pub fn evaluate_binding<'t>(15pub fn evaluate_binding(b: &BindSpec, context_creator: ContextCreator) -> (String, Binding) {21 b: &BindSpec,16 let b = b.clone();22 context_creator: BoxedContextCreator,23) -> (String, BoxedBinding) {24 if let Some(args) = &b.params {17 if let Some(args) = &b.params {18 let args = args.clone();25 (19 (26 b.name.clone(),20 b.name.clone(),27 Rc::new(ArgsBinding {21 binding!(move |this, super_obj| Val::Lazy(lazy_val!(28 expr: *b.value.clone(),22 closure!(clone b, clone args, clone context_creator, || evaluate_method(29 args: args.clone(),23 context_creator.0(this.clone(), super_obj.clone()),24 &b.value,30 context_creator: context_creator.clone(),25 args.clone()26 ))31 }),27 ))),32 )28 )33 } else {29 } else {34 (30 (35 b.name.clone(),31 b.name.clone(),32 binding!(move |this, super_obj| {33 println!("Evaluating binding");36 Rc::new(NoArgsBinding {34 Val::Lazy(lazy_val!(37 expr: *b.value.clone(),35 closure!(clone context_creator, clone b, || evaluate(38 context_creator: context_creator.clone(),36 context_creator.0(this.clone(), super_obj.clone()),37 &b.value38 ))39 }) as BoxedBinding,39 ))40 }),40 )41 )41 }42 }42}43}4344#[derive(Debug)]45struct MethodRhs {46 rhs: Expr,47}48impl FunctionRhs for MethodRhs {49 fn evaluate(&self, ctx: Context) -> Val {50 evaluate(ctx, &self.rhs)51 }52}5354#[derive(Debug)]55struct MethodDefault {}56impl FunctionDefault for MethodDefault {57 fn default(&self, ctx: Context, expr: Expr) -> Val {58 evaluate(ctx, &expr)59 }60}614462pub fn evaluate_method(ctx: Context, expr: &Expr, arg_spec: ParamsDesc) -> Val {45pub fn evaluate_method(ctx: Context, expr: &Expr, arg_spec: ParamsDesc) -> Val {63 Val::Func(FuncDesc {46 Val::Func(FuncDesc {64 ctx,47 ctx,65 params: arg_spec,48 params: arg_spec,66 eval_rhs: BoxedFunctionRhs(Rc::new(MethodRhs { rhs: expr.clone() })),49 eval_rhs: function_rhs!(closure!(clone expr, |ctx| evaluate(ctx, &expr))),67 eval_default: BoxedFunctionDefault(Rc::new(MethodDefault {})),50 eval_default: function_default!(|ctx, default| evaluate(ctx, &default)),68 })51 })69}52}705374 jsonnet_parser::FieldName::Dyn(expr) => {57 jsonnet_parser::FieldName::Dyn(expr) => {75 let name = evaluate(context, expr).unwrap_if_lazy();58 let name = evaluate(context, expr).unwrap_if_lazy();76 match name {59 match name {77 Val::Str(n) => n.clone(),60 Val::Str(n) => n,78 _ => panic!(61 _ => panic!(79 "dynamic field name can be only evaluated to 'string', got: {:?}",62 "dynamic field name can be only evaluated to 'string', got: {:?}",80 name63 name84 }67 }85}68}6970pub fn evaluate_unary_op(op: UnaryOpType, b: &Val) -> Val {71 match (op, b) {72 (o, Val::Lazy(l)) => evaluate_unary_op(o, &l.0()),73 (UnaryOpType::Not, Val::Literal(LiteralType::True)) => Val::Literal(LiteralType::False),74 (UnaryOpType::Not, Val::Literal(LiteralType::False)) => Val::Literal(LiteralType::True),75 (op, o) => panic!("unary op not implemented: {:?} {:?}", op, o),76 }77}867887pub fn evaluate_binary_op(a: &Val, op: BinaryOpType, b: &Val) -> Val {79pub fn evaluate_binary_op(a: &Val, op: BinaryOpType, b: &Val) -> Val {88 match (a, op, b) {80 match (a, op, b) {89 (Val::Lazy(l), o, r) => evaluate_binary_op(&l.evaluate(), o, r),81 (Val::Lazy(a), o, b) => evaluate_binary_op(&a.0(), o, b),90 (l, o, Val::Lazy(r)) => evaluate_binary_op(l, o, &r.evaluate()),82 (a, o, Val::Lazy(b)) => evaluate_binary_op(a, o, &b.0()),918392 (Val::Str(v1), BinaryOpType::Add, Val::Str(v2)) => Val::Str(v1.to_owned() + &v2),84 (Val::Str(v1), BinaryOpType::Add, Val::Str(v2)) => Val::Str(v1.to_owned() + &v2),93 (Val::Str(v1), BinaryOpType::Eq, Val::Str(v2)) => bool_val(v1 == v2),85 (Val::Str(v1), BinaryOpType::Eq, Val::Str(v2)) => bool_val(v1 == v2),119 (Val::Num(v1), BinaryOpType::Lte, Val::Num(v2)) => bool_val(v1 <= v2),111 (Val::Num(v1), BinaryOpType::Lte, Val::Num(v2)) => bool_val(v1 <= v2),120 (Val::Num(v1), BinaryOpType::Gte, Val::Num(v2)) => bool_val(v1 >= v2),112 (Val::Num(v1), BinaryOpType::Gte, Val::Num(v2)) => bool_val(v1 >= v2),121113122 (Val::Num(v1), BinaryOpType::Eq, Val::Num(v2)) => bool_val(v1 == v2),114 (Val::Num(v1), BinaryOpType::Eq, Val::Num(v2)) => bool_val((v1 - v2).abs() < f64::EPSILON),123 (Val::Num(v1), BinaryOpType::Ne, Val::Num(v2)) => bool_val(v1 != v2),115 (Val::Num(v1), BinaryOpType::Ne, Val::Num(v2)) => bool_val((v1 - v2).abs() > f64::EPSILON),124116125 (Val::Num(v1), BinaryOpType::BitAnd, Val::Num(v2)) => {117 (Val::Num(v1), BinaryOpType::BitAnd, Val::Num(v2)) => {126 Val::Num(((*v1 as i32) & (*v2 as i32)) as f64)118 Val::Num(((*v1 as i32) & (*v2 as i32)) as f64)135 }127 }136}128}137129138future_wrapper!(HashMap<String, BoxedBinding>, FutureNewBindings);130future_wrapper!(HashMap<String, Binding>, FutureNewBindings);139140#[derive(Debug)]141pub struct ObjectContextCreator {142 original: Context,143 future_bindings: FutureNewBindings,144}145146impl ContextCreator for ObjectContextCreator {147 fn create_context(&self, this: &Option<ObjValue>, super_obj: &Option<ObjValue>) -> Context {131future_wrapper!(ObjValue, FutureObjValue);148 self.original.extend(149 self.future_bindings.clone().unwrap(),150 self.original.dollar().clone().or_else(|| this.clone()),151 this.clone(),152 super_obj.clone(),153 )154 }155}156132157// TODO: Asserts133// TODO: Asserts158pub fn evaluate_object(context: Context, object: ObjBody) -> ObjValue {134pub fn evaluate_object(context: Context, object: ObjBody) -> ObjValue {159 match object {135 match object {160 ObjBody::MemberList(members) => {136 ObjBody::MemberList(members) => {161 let future_bindings = FutureNewBindings::new();137 let future_bindings = FutureNewBindings::new();138 let future_this = FutureObjValue::new();162 let binding_context_creator = Rc::new(ObjectContextCreator {139 let context_creator = context_creator!(163 future_bindings: future_bindings.clone(),140 closure!(clone context, clone future_bindings, |this: Option<ObjValue>, super_obj: Option<ObjValue>| {141 println!("Context created");142 context.clone().extend(143 future_bindings.clone().unwrap(),164 original: context.clone(),144 context.clone().dollar().clone().or_else(||this.clone()),145 this,146 super_obj147 )148 })165 });149 );166 let mut bindings: HashMap<String, BoxedBinding> = HashMap::new();150 let mut bindings: HashMap<String, Binding> = HashMap::new();167 for (n, b) in members151 for (n, b) in members168 .iter()152 .iter()169 .filter_map(|m| match m {153 .filter_map(|m| match m {170 Member::BindStmt(b) => Some(b.clone()),154 Member::BindStmt(b) => Some(b.clone()),171 _ => None,155 _ => None,172 })156 })173 .map(|b| evaluate_binding(&b, binding_context_creator.clone()))157 .map(|b| {158 evaluate_binding(&b, context_creator.clone())159 })174 {160 {175 bindings.insert(n, b);161 bindings.insert(n, b);176 }162 }177 let bindings = future_bindings.fill(bindings);163 future_bindings.fill(bindings);164165 println!("Bindings filled");178 let mut new_members = BTreeMap::new();166 let mut new_members = BTreeMap::new();179 for member in members.iter() {167 for member in members.into_iter() {180 match member {168 match member {181 Member::Field(FieldMember {169 Member::Field(FieldMember {182 name,170 name,185 visibility,173 visibility,186 value,174 value,187 }) => {175 }) => {188 let name = evaluate_field_name(context.clone(), name);176 let name = evaluate_field_name(context.clone(), &name);189 new_members.insert(177 new_members.insert(190 name,178 name,191 ObjMember {179 ObjMember {192 add: *plus,180 add: plus,193 visibility: visibility.clone(),181 visibility: visibility.clone(),194 invoke: Rc::new(NoArgsBinding {182 invoke: binding!(183 closure!(clone value, clone context_creator, clone future_this, |this, super_obj| {184 // FIXME: I should take "this" instead of "future_this" there?185 // TODO: Assert186 evaluate(195 context_creator: binding_context_creator.clone(),187 context_creator.0(this, super_obj),196 expr: value.clone(),188 &value,189 )197 }),190 })191 ),198 },192 },199 );193 );204 value,198 value,205 ..199 ..206 }) => {200 }) => {207 let name = evaluate_field_name(context.clone(), name);201 let name = evaluate_field_name(context.clone(), &name);208 new_members.insert(202 new_members.insert(209 name,203 name,210 ObjMember {204 ObjMember {211 add: false,205 add: false,212 visibility: Visibility::Hidden,206 visibility: Visibility::Hidden,213 invoke: Rc::new(ArgsBinding {207 invoke: binding!(214 expr: value.clone(),208 closure!(clone value, clone context_creator, clone future_this, |this, super_obj| {209 // FIXME: I should take "this" instead of "future_this" there?210 // TODO: Assert211 evaluate_method(212 context_creator.0(this, super_obj),215 args: params.clone(),213 &value.clone(),216 context_creator: binding_context_creator.clone(),214 params.clone(),215 )216 })217 }),217 ),218 },218 },219 );219 );220 }220 }221 Member::BindStmt(_) => {}221 Member::BindStmt(_) => {}222 Member::AssertStmt(_) => {}222 Member::AssertStmt(_) => {}223 _ => todo!(),224 }223 }225 }224 }226 ObjValue::new(None, Rc::new(new_members))225 future_this.fill(ObjValue::new(None, Rc::new(new_members)))227 }226 }228 _ => todo!(),227 _ => todo!(),229 }228 }232pub fn evaluate(context: Context, expr: &Expr) -> Val {231pub fn evaluate(context: Context, expr: &Expr) -> Val {233 use Expr::*;232 use Expr::*;234 match &*expr {233 match &*expr {234 Literal(LiteralType::This) => {235 println!("{:?}", context.this());236 Val::Obj(237 context238 .this()239 .clone()240 .unwrap_or_else(|| panic!("this not found")),241 )242 }243 Literal(LiteralType::Super) => Val::Obj(244 context245 .super_obj()246 .clone()247 .unwrap_or_else(|| panic!("super not found")),248 ),235 Literal(t) => Val::Literal(t.clone()),249 Literal(t) => Val::Literal(t.clone()),236 Parened(e) => evaluate(context, e),250 Parened(e) => evaluate(context, e),237 Str(v) => Val::Str(v.clone()),251 Str(v) => Val::Str(v.clone()),238 Num(v) => Val::Num(*v),252 Num(v) => Val::Num(*v),239 BinaryOp(v1, o, v2) => {253 BinaryOp(v1, o, v2) => {240 evaluate_binary_op(&evaluate(context.clone(), v1), *o, &evaluate(context, v2))254 evaluate_binary_op(&evaluate(context.clone(), v1), *o, &evaluate(context, v2))241 }255 }256 UnaryOp(o, v) => evaluate_unary_op(*o, &evaluate(context, v)),242 Var(name) => {257 Var(name) => {243 let variable = context.binding(&name);258 let variable = context.binding(&name);244 let val = variable.evaluate(None, None);259 variable.0(None, None).unwrap_if_lazy()245 val246 }260 }247 Index(box value, box index) => {261 Index(box value, box index) => {248 match (262 match (249 evaluate(context.clone(), value).unwrap_if_lazy(),263 evaluate(context.clone(), value).unwrap_if_lazy(),250 evaluate(context.clone(), index),264 evaluate(context, index),251 ) {265 ) {252 (Val::Literal(LiteralType::Super), _idx) => todo!(),253 (Val::Literal(LiteralType::This), idx) => match &idx.unwrap_if_lazy() {266 (Val::Obj(v), Val::Str(s)) => v254 Val::Str(str) => context255 .this()267 .get(&s)256 .clone()257 .unwrap_or_else(|| panic!("'this' is not defined in current context"))258 .get_raw(str, None)259 .unwrap_or_else(|| {268 .unwrap_or_else(|| panic!("{} not found in {:?}", s, v)),260 panic!(261 "key {} not found in current context 'this' ({:?})",262 str,263 context.this()264 )265 }),266 _ => panic!("bad index"),267 },268 (Val::Obj(v), Val::Str(s)) => v269 (Val::Arr(v), Val::Num(n)) => v270 .get(n as usize)269 .get_raw(&s, None)271 .unwrap_or_else(|| panic!("out of bounds"))270 .unwrap_or_else(|| panic!("{} not found in {:?}", s, v)),272 .clone(),271 (v, i) => todo!("not implemented: {:?}[{:?}]", v, i.unwrap_if_lazy()),273 (v, i) => todo!("not implemented: {:?}[{:?}]", v, i.unwrap_if_lazy()),272 }274 }273 }275 }274 LocalExpr(bindings, returned) => {276 LocalExpr(bindings, returned) => {275 let mut new_bindings: HashMap<String, BoxedBinding> = HashMap::new();277 let mut new_bindings: HashMap<String, Binding> = HashMap::new();276 let future_context = Context::new_future();278 let future_context = Context::new_future();277279278 let context_creator = Rc::new(ConstantContextCreator {280 let context_creator = context_creator!(279 context: future_context.clone(),281 closure!(clone future_context, |_, _| future_context.clone().unwrap())280 });282 );283281 for (k, v) in bindings284 for (k, v) in bindings282 .iter()285 .iter()299 .into_iter()302 .into_iter()300 .map(|a| {303 .map(|a| {301 (304 (302 a.0,305 a.clone().0,303 Val::Lazy(BoxedLazyVal(Rc::new(PlainLazyVal {306 Val::Lazy(lazy_val!(304 context: context.clone(),307 closure!(clone context, clone a, || evaluate(context.clone(), &a.clone().1))305 expr: *a.1,306 }))),308 )),307 )309 )308 })310 })309 .collect(),311 .collect(),318 cond_then,320 cond_then,319 cond_else,321 cond_else,320 } => match evaluate(context.clone(), &cond.0).unwrap_if_lazy() {322 } => match evaluate(context.clone(), &cond.0).unwrap_if_lazy() {321 Val::Literal(LiteralType::True) => evaluate(context.clone(), cond_then),323 Val::Literal(LiteralType::True) => evaluate(context, cond_then),322 Val::Literal(LiteralType::False) => match cond_else {324 Val::Literal(LiteralType::False) => match cond_else {323 Some(v) => evaluate(context.clone(), v),325 Some(v) => evaluate(context, v),324 None => Val::Literal(LiteralType::False),326 None => Val::Literal(LiteralType::False),325 },327 },326 v => panic!("if condition evaluated to {:?} (boolean needed instead)", v),328 v => panic!("if condition evaluated to {:?} (boolean needed instead)", v),crates/jsonnet-evaluator/src/lib.rsdiffbeforeafterboth1#![feature(box_syntax, box_patterns)]1#![feature(box_syntax, box_patterns)]2#![feature(type_alias_impl_trait)]2#![feature(type_alias_impl_trait)]3#![feature(debug_non_exhaustive)]3#![feature(debug_non_exhaustive)]44#![allow(macro_expanded_macro_exports_accessed_by_absolute_paths)]5mod binding;6mod ctx;5mod ctx;7mod dynamic;6mod dynamic;8mod evaluate;7mod evaluate;9mod obj;8mod obj;10mod val;9mod val;111012pub use binding::*;13pub use ctx::*;11pub use ctx::*;14pub use dynamic::*;12pub use dynamic::*;15pub use evaluate::*;13pub use evaluate::*;16use jsonnet_parser::*;14use jsonnet_parser::*;17pub use obj::*;15pub use obj::*;18use std::fmt::Debug;19use std::rc::Rc;20pub use val::*;16pub use val::*;211722pub trait FunctionRhs: Debug {18rc_fn_helper!(19 Binding,20 binding,23 fn evaluate(&self, ctx: Context) -> Val;21 dyn Fn(Option<ObjValue>, Option<ObjValue>) -> Val24}22);25dynamic_wrapper!(FunctionRhs, BoxedFunctionRhs);23rc_fn_helper!(FunctionRhs, function_rhs, dyn Fn(Context) -> Val);2624rc_fn_helper!(27pub trait FunctionDefault: Debug {25 FunctionDefault,26 function_default,28 fn default(&self, ctx: Context, expr: Expr) -> Val;27 dyn Fn(Context, Expr) -> Val29}28);30dynamic_wrapper!(FunctionDefault, BoxedFunctionDefault);312932#[cfg(test)]30#[cfg(test)]33pub mod tests {31pub mod tests {34 use super::{evaluate, Context, Val};32 use super::{evaluate, Context, Val};35 use jsonnet_parser::*;33 use jsonnet_parser::*;363437 // macro_rules! eval {35 macro_rules! eval {38 // ($str: expr) => {36 ($str: expr) => {39 // evaluate(Context::new(), &parse($str).unwrap())37 evaluate(Context::new(), &parse($str).unwrap())40 // };38 };41 // }39 }4041 macro_rules! eval_stdlib {42 ($str: expr) => {43 let std = "local std = ".to_owned() + jsonnet_stdlib::STDLIB_STR + ";";44 evaluate(Context::new(), &parse(&(std + $str)).unwrap())45 };46 }4742 macro_rules! assert_eval {48 macro_rules! assert_eval {43 ($str: expr) => {49 ($str: expr) => {165 );171 );166 }172 }167173168 // We can't trust other tests (And official jsonnet testsuite), if assert is not working correctly169 #[test]174 #[test]170 fn std_assert_ok() {175 fn direct_self() {176 println!(177 "{:#?}",178 eval!(179 r#"180 {181 local me = self,182 a: 3,183 b(): me.a,184 }185 "#186 )187 );188 }189190 #[test]171 let std = "local std = ".to_owned() + jsonnet_stdlib::STDLIB_STR + ";";191 fn indirect_self() {172 evaluate(192 // `self` assigned to `me` was lost when being193 // referenced from field194 eval_stdlib!(195 r#"{196 local me = std.trace("test", self),197 b: me,198 }.b"#199 );200 }201202 // We can't trust other tests (And official jsonnet testsuite), if assert is not working correctly203 #[test]173 Context::new(),204 fn std_assert_ok() {174 &parse(&(std + "std.assertEqual(4.5 << 2, 16,)")).unwrap(),205 eval_stdlib!("std.assertEqual(4.5 << 2, 16)");175 );206 }176 }177207178 #[test]208 #[test]179 #[should_panic]209 #[should_panic]180 fn std_assert_failure() {210 fn std_assert_failure() {181 let std = "local std = ".to_owned() + jsonnet_stdlib::STDLIB_STR + ";";211 eval_stdlib!("std.assertEqual(4.5 << 2, 15)");182 evaluate(212 }213214 #[test]183 Context::new(),215 fn base64_works() {184 &parse(&(std + "std.assertEqual(4.5 << 2, 15,)")).unwrap(),216 eval_stdlib!(r#"std.base64("test")"#);185 );217 }186 }187}218}188219crates/jsonnet-evaluator/src/obj.rsdiffbeforeafterboth1use crate::{dummy_debug, evaluate_binary_op, BoxedBinding, Val};1use crate::{evaluate_binary_op, Binding, Val};2use jsonnet_parser::{BinaryOpType, Visibility};2use jsonnet_parser::{BinaryOpType, Visibility};3use std::{3use std::{4 collections::{BTreeMap, BTreeSet},4 collections::{BTreeMap, BTreeSet},5 fmt::Debug,5 rc::Rc,6 rc::Rc,6};7};788#[derive(Debug)]9#[derive(Debug)]9pub struct ObjMember {10pub struct ObjMember {10 pub add: bool,11 pub add: bool,11 pub visibility: Visibility,12 pub visibility: Visibility,12 pub invoke: BoxedBinding,13 pub invoke: Binding,13}14}141515#[derive(Debug)]16#[derive(Debug)]16pub struct ObjValueInternals {17pub struct ObjValueInternals {17 super_obj: Option<ObjValue>,18 super_obj: Option<ObjValue>,18 this_entries: Rc<BTreeMap<String, ObjMember>>,19 this_entries: Rc<BTreeMap<String, ObjMember>>,19}20}20pub struct ObjValue(Rc<ObjValueInternals>);21pub struct ObjValue(pub(crate) Rc<ObjValueInternals>);22impl Debug for ObjValue {23 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {24 if let Some(super_obj) = self.0.super_obj.as_ref() {25 if f.alternate() {26 write!(f, "{:#?}", super_obj)?;27 } else {28 write!(f, "{:?}", super_obj)?;29 }21dummy_debug!(ObjValue);30 write!(f, " + ")?;31 }32 let mut debug = f.debug_struct("ObjValue");33 debug.field("$ptr", &Rc::as_ptr(&self.0));34 for (name, member) in self.0.this_entries.iter() {35 debug.field(name, member);36 }37 debug.finish_non_exhaustive()38 // .field("fields", &self.fields())39 // .finish_non_exhaustive()40 }41}4222impl ObjValue {43impl ObjValue {23 pub fn new(44 pub fn new(47 }68 }48 fields69 fields49 }70 }50 pub fn get_raw(&self, key: &str, real_this: Option<ObjValue>) -> Option<Val> {71 pub fn get(&self, key: &str) -> Option<Val> {72 // TODO: Cache get_raw result73 self.get_raw(key, Some(self))74 }75 fn get_raw(&self, key: &str, real_this: Option<&ObjValue>) -> Option<Val> {51 match (self.0.this_entries.get(key), &self.0.super_obj) {76 match (self.0.this_entries.get(key), &self.0.super_obj) {52 (Some(k), None) => Some(k.invoke.evaluate(77 (Some(k), None) => Some(k.invoke.0(53 real_this.or_else(|| Some(self.clone())),78 real_this.as_ref().map(|e| (*e).clone()),54 self.0.super_obj.clone().map(|e| e.clone()),79 self.0.super_obj.clone(),55 )),80 )),56 (Some(k), Some(s)) => {81 (Some(k), Some(s)) => {57 let our = k82 let our = k.invoke.0(58 .invoke59 .evaluate(Some(self.clone()), self.0.super_obj.clone());83 real_this.as_ref().map(|e| (*e).clone()),84 self.0.super_obj.clone(),85 );60 if k.add {86 if k.add {61 s.get_raw(key, Some(self.clone()))87 s.get_raw(key, real_this).map_or(Some(our.clone()), |v| {62 .map_or(Some(our.clone()), |v| {63 Some(evaluate_binary_op(&v, BinaryOpType::Add, &our))88 Some(evaluate_binary_op(&v, BinaryOpType::Add, &our))64 })89 })65 } else {90 } else {66 Some(our)91 Some(our)67 }92 }68 }93 }69 (None, Some(s)) => s.get_raw(key, Some(self.clone())),94 (None, Some(s)) => s.get_raw(key, real_this),70 (None, None) => None,95 (None, None) => None,71 }96 }72 }97 }crates/jsonnet-evaluator/src/val.rsdiffbeforeafterboth1use crate::{1use crate::{binding, rc_fn_helper, Binding, Context, FunctionDefault, FunctionRhs, ObjValue};2 dynamic_wrapper, evaluate, evaluate_method, BoxedContextCreator, Context, FunctionDefault,3 FunctionRhs, ObjValue,4};5use crate::{Binding, BoxedBinding, BoxedFunctionDefault, BoxedFunctionRhs, FutureContext};2use closure::closure;6use jsonnet_parser::{ArgsDesc, Expr, LiteralType, Param, ParamsDesc};3use jsonnet_parser::{LiteralType, ParamsDesc};7use std::{4use std::{8 collections::HashMap,5 collections::HashMap,9 fmt::{Debug, Display},6 fmt::{Debug, Display},10 ops::Deref,11 rc::Rc,12};7};13814pub trait LazyVal: Debug {15 fn evaluate(&self) -> Val;16}17dynamic_wrapper!(LazyVal, BoxedLazyVal);9rc_fn_helper!(LazyVal, lazy_val, dyn Fn() -> Val);1819#[derive(Debug)]20pub struct PlainLazyVal {21 pub expr: Expr,22 pub context: Context,23}24impl LazyVal for PlainLazyVal {25 fn evaluate(&self) -> Val {26 evaluate(self.context.clone(), &self.expr)27 }28}2930#[derive(Debug)]31pub struct NoArgsBindingLazyVal {32 pub expr: Expr,33 pub context_creator: BoxedContextCreator,3435 pub this: Option<ObjValue>,36 pub super_obj: Option<ObjValue>,37}38impl LazyVal for NoArgsBindingLazyVal {39 fn evaluate(&self) -> Val {40 evaluate(41 self.context_creator42 .create_context(&self.this, &self.super_obj),43 &self.expr,44 )45 }46}4748#[derive(Debug)]49pub struct ArgsBindingLazyVal {50 pub expr: Expr,51 pub args: ParamsDesc,52 pub context_creator: BoxedContextCreator,5354 pub this: Option<ObjValue>,55 pub super_obj: Option<ObjValue>,56}57impl LazyVal for ArgsBindingLazyVal {58 fn evaluate(&self) -> Val {59 evaluate_method(60 self.context_creator61 .create_context(&self.this, &self.super_obj),62 &self.expr,63 self.args.clone(),64 )65 }66}6768#[derive(Debug)]69pub struct FunctionDefaultBinding {70 eval: BoxedFunctionDefault,71 default: Expr,72 ctx: FutureContext,73}74impl Binding for FunctionDefaultBinding {75 fn evaluate(&self, _this: Option<ObjValue>, _super_obj: Option<ObjValue>) -> Val {76 self.eval77 .default(self.ctx.clone().unwrap(), self.default.clone())78 }79}8081#[derive(Debug)]82pub struct ValBinding {83 val: Val,84}85impl Binding for ValBinding {86 fn evaluate(&self, this: Option<ObjValue>, super_obj: Option<ObjValue>) -> Val {87 self.val.clone()88 }89}901091#[derive(Debug, PartialEq, Clone)]11#[derive(Debug, PartialEq, Clone)]92pub struct FuncDesc {12pub struct FuncDesc {93 pub ctx: Context,13 pub ctx: Context,94 pub params: ParamsDesc,14 pub params: ParamsDesc,95 pub eval_rhs: BoxedFunctionRhs,15 pub eval_rhs: FunctionRhs,96 pub eval_default: BoxedFunctionDefault,16 pub eval_default: FunctionDefault,97}17}98impl FuncDesc {18impl FuncDesc {99 // TODO: Check for unset variables19 // TODO: Check for unset variables100 pub fn evaluate(&self, args: Vec<(Option<String>, Val)>) -> Val {20 pub fn evaluate(&self, args: Vec<(Option<String>, Val)>) -> Val {101 let mut new_bindings: HashMap<String, BoxedBinding> = HashMap::new();21 let mut new_bindings: HashMap<String, Binding> = HashMap::new();102 let future_ctx = Context::new_future();22 let future_ctx = Context::new_future();10323104 self.params24 // self.params105 .with_defaults()25 // .with_defaults()106 .into_iter()26 // .into_iter()107 .for_each(|Param(name, default)| {27 // .for_each(|Param(name, default)| {108 new_bindings.insert(28 // let default = Rc::new(*default.unwrap());109 name,29 // new_bindings.insert(110 Rc::new(FunctionDefaultBinding {30 // name,111 eval: self.eval_default.clone(),31 // binding!(move |_, _| Val::Lazy(lazy_val!(|| self112 default: *default.unwrap().clone(),32 // .eval_default113 ctx: future_ctx.clone(),33 // .0114 }),34 // .default(future_ctx.unwrap(), *default.clone())))),115 );35 // );116 });36 // });117 for (name, val) in args.iter().filter(|e| e.0.is_some()) {37 for (name, val) in args.clone().into_iter().filter(|e| e.0.is_some()) {118 new_bindings.insert(38 new_bindings.insert(119 name.as_ref().unwrap().clone(),39 name.as_ref().unwrap().clone(),40 binding!(120 Rc::new(ValBinding { val: val.clone() }),41 closure!(clone val, |_, _| Val::Lazy(lazy_val!(closure!(clone val, || val.clone()))))42 ),121 );43 );122 }44 }123 for (i, param) in self.params.0.iter().enumerate() {45 for (i, param) in self.params.0.iter().enumerate() {124 if let Some((None, val)) = args.get(i) {46 if let Some((None, val)) = args.get(i) {125 new_bindings.insert(param.0.clone(), Rc::new(ValBinding { val: val.clone() }));47 new_bindings.insert(48 param.0.clone(),49 binding!(50 closure!(clone val, |_, _| Val::Lazy(lazy_val!(closure!(clone val, || val.clone()))))51 ),52 );126 }53 }127 }54 }128 let ctx = self55 let ctx = self129 .ctx56 .ctx130 .extend(new_bindings, None, None, None)57 .extend(new_bindings, None, None, None)131 .into_future(future_ctx);58 .into_future(future_ctx);132 self.eval_rhs.evaluate(ctx)59 self.eval_rhs.0(ctx)133 }60 }134}61}13562138 Literal(LiteralType),65 Literal(LiteralType),139 Str(String),66 Str(String),140 Num(f64),67 Num(f64),141 Lazy(BoxedLazyVal),68 Lazy(LazyVal),142 Arr(Vec<Val>),69 Arr(Vec<Val>),143 Obj(ObjValue),70 Obj(ObjValue),144 Func(FuncDesc),71 Func(FuncDesc),7273 // Library functions implemented in native74 Intristic(String, String),145}75}146impl Val {76impl Val {147 pub fn unwrap_if_lazy(self) -> Self {77 pub fn unwrap_if_lazy(self) -> Self {148 if let Val::Lazy(v) = self {78 if let Val::Lazy(v) = self {149 v.evaluate().unwrap_if_lazy()79 v.0().unwrap_if_lazy()150 } else {80 } else {151 self81 self152 }82 }191 write!(f, ",")?;121 write!(f, ",")?;192 }122 }193 write!(f, "\"{}\":", field)?;123 write!(f, "\"{}\":", field)?;194 write!(f, "{}", value.get_raw(&field, None).unwrap())?;124 write!(f, "{}", value.get(&field).unwrap())?;195 }125 }196 write!(f, "}}")?;126 write!(f, "}}")?;197 }127 }198 Val::Lazy(lazy) => {128 Val::Lazy(lazy) => {199 write!(f, "{}", lazy.evaluate())?;129 write!(f, "{}", lazy.0())?;200 }130 }201 Val::Func(_) => {131 Val::Func(_) => {202 write!(f, "<<FUNC>>")?;132 write!(f, "<<FUNC>>")?;crates/jsonnet-parser/src/expr.rsdiffbeforeafterboth37 AssertStmt(AssertStmt),37 AssertStmt(AssertStmt),38}38}393940#[derive(Debug, Clone, PartialEq)]40#[derive(Debug, Clone, Copy, PartialEq)]41pub enum UnaryOpType {41pub enum UnaryOpType {42 Plus,42 Plus,43 Minus,43 Minus,