git.delta.rocks / jrsonnet / refs/commits / abae2f2e28fb

difftreelog

refactor(evaluator) use closures where possible

Лач2020-05-30parent: #0787247.patch.diff
in: master

9 files changed

modifiedcrates/jsonnet-evaluator/Cargo.tomldiffbeforeafterboth
88
9[dependencies]9[dependencies]
10jsonnet-parser = { path = "../jsonnet-parser" }10jsonnet-parser = { path = "../jsonnet-parser" }
11closure = "0.3.0"
1112
12[dev-dependencies]13[dev-dependencies]
13jsonnet-stdlib = { version = "0.1.0", path = "../jsonnet-stdlib" }14jsonnet-stdlib = { version = "0.1.0", path = "../jsonnet-stdlib" }
deletedcrates/jsonnet-evaluator/src/binding.rsdiffbeforeafterboth

no changes

modifiedcrates/jsonnet-evaluator/src/ctx.rsdiffbeforeafterboth
1use 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};
33
4rc_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>) -> Context
6}8);
7pub type BoxedContextCreator = Rc<dyn ContextCreator>;
8
9#[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}
189
19future_wrapper!(Context, FutureContext);10future_wrapper!(Context, FutureContext);
2011
23 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 }
5552
56 pub fn binding(&self, name: &str) -> BoxedBinding {53 pub fn binding(&self, name: &str) -> Binding {
57 self.054 self.0
58 .bindings55 .bindings
59 .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 })
7269
73 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}
98
99impl Default for Context {
100 fn default() -> Self {
101 Self::new()
102 }
103}
104
100impl PartialEq for Context {105impl PartialEq for Context {
101 fn eq(&self, other: &Self) -> bool {106 fn eq(&self, other: &Self) -> bool {
modifiedcrates/jsonnet-evaluator/src/dynamic.rsdiffbeforeafterboth
1#[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.0
10 }
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}
19
20#[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}
4430
45#[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}
5656
modifiedcrates/jsonnet-evaluator/src/evaluate.rsdiffbeforeafterboth
1use 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};
1914
20pub 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.value
38 ))
39 }) as BoxedBinding,39 ))
40 }),
40 )41 )
41 }42 }
42}43}
43
44#[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}
53
54#[derive(Debug)]
55struct MethodDefault {}
56impl FunctionDefault for MethodDefault {
57 fn default(&self, ctx: Context, expr: Expr) -> Val {
58 evaluate(ctx, &expr)
59 }
60}
6144
62pub 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}
7053
74 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 name
84 }67 }
85}68}
69
70pub 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}
8678
87pub 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()),
9183
92 (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),
121113
122 (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),
124116
125 (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}
137129
138future_wrapper!(HashMap<String, BoxedBinding>, FutureNewBindings);130future_wrapper!(HashMap<String, Binding>, FutureNewBindings);
139
140#[derive(Debug)]
141pub struct ObjectContextCreator {
142 original: Context,
143 future_bindings: FutureNewBindings,
144}
145
146impl 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}
156132
157// TODO: Asserts133// TODO: Asserts
158pub 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_obj
147 )
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 members
168 .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);
164
165 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: Assert
186 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: Assert
211 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 context
238 .this()
239 .clone()
240 .unwrap_or_else(|| panic!("this not found")),
241 )
242 }
243 Literal(LiteralType::Super) => Val::Obj(
244 context
245 .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 val
246 }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)) => v
254 Val::Str(str) => context
255 .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)) => v
270 .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();
277279
278 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 );
283
281 for (k, v) in bindings284 for (k, v) in bindings
282 .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),
modifiedcrates/jsonnet-evaluator/src/lib.rsdiffbeforeafterboth
1#![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;
1110
12pub 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::*;
2117
22pub trait FunctionRhs: Debug {18rc_fn_helper!(
19 Binding,
20 binding,
23 fn evaluate(&self, ctx: Context) -> Val;21 dyn Fn(Option<ObjValue>, Option<ObjValue>) -> Val
24}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) -> Val
29}28);
30dynamic_wrapper!(FunctionDefault, BoxedFunctionDefault);
3129
32#[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::*;
3634
37 // 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 }
40
41 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 }
47
42 macro_rules! assert_eval {48 macro_rules! assert_eval {
43 ($str: expr) => {49 ($str: expr) => {
165 );171 );
166 }172 }
167173
168 // We can't trust other tests (And official jsonnet testsuite), if assert is not working correctly
169 #[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 }
189
190 #[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 being
193 // referenced from field
194 eval_stdlib!(
195 r#"{
196 local me = std.trace("test", self),
197 b: me,
198 }.b"#
199 );
200 }
201
202 // We can't trust other tests (And official jsonnet testsuite), if assert is not working correctly
203 #[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 }
177207
178 #[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 }
213
214 #[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}
188219
modifiedcrates/jsonnet-evaluator/src/obj.rsdiffbeforeafterboth
1use 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};
78
8#[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}
1415
15#[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}
42
22impl ObjValue {43impl ObjValue {
23 pub fn new(44 pub fn new(
47 }68 }
48 fields69 fields
49 }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 result
73 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 .invoke
59 .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 }
modifiedcrates/jsonnet-evaluator/src/val.rsdiffbeforeafterboth
1use 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};
138
14pub trait LazyVal: Debug {
15 fn evaluate(&self) -> Val;
16}
17dynamic_wrapper!(LazyVal, BoxedLazyVal);9rc_fn_helper!(LazyVal, lazy_val, dyn Fn() -> Val);
18
19#[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}
29
30#[derive(Debug)]
31pub struct NoArgsBindingLazyVal {
32 pub expr: Expr,
33 pub context_creator: BoxedContextCreator,
34
35 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_creator
42 .create_context(&self.this, &self.super_obj),
43 &self.expr,
44 )
45 }
46}
47
48#[derive(Debug)]
49pub struct ArgsBindingLazyVal {
50 pub expr: Expr,
51 pub args: ParamsDesc,
52 pub context_creator: BoxedContextCreator,
53
54 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_creator
61 .create_context(&self.this, &self.super_obj),
62 &self.expr,
63 self.args.clone(),
64 )
65 }
66}
67
68#[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.eval
77 .default(self.ctx.clone().unwrap(), self.default.clone())
78 }
79}
80
81#[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}
9010
91#[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 variables
100 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();
10323
104 self.params24 // self.params
105 .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!(|| self
112 default: *default.unwrap().clone(),32 // .eval_default
113 ctx: future_ctx.clone(),33 // .0
114 }),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 = self
129 .ctx56 .ctx
130 .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}
13562
138 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),
72
73 // Library functions implemented in native
74 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 self
152 }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>>")?;
modifiedcrates/jsonnet-parser/src/expr.rsdiffbeforeafterboth
37 AssertStmt(AssertStmt),37 AssertStmt(AssertStmt),
38}38}
3939
40#[derive(Debug, Clone, PartialEq)]40#[derive(Debug, Clone, Copy, PartialEq)]
41pub enum UnaryOpType {41pub enum UnaryOpType {
42 Plus,42 Plus,
43 Minus,43 Minus,