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
--- a/crates/jsonnet-evaluator/Cargo.toml
+++ b/crates/jsonnet-evaluator/Cargo.toml
@@ -8,6 +8,7 @@
 
 [dependencies]
 jsonnet-parser = { path = "../jsonnet-parser" }
+closure = "0.3.0"
 
 [dev-dependencies]
 jsonnet-stdlib = { version = "0.1.0", path = "../jsonnet-stdlib" }
deletedcrates/jsonnet-evaluator/src/binding.rsdiffbeforeafterboth
--- a/crates/jsonnet-evaluator/src/binding.rs
+++ /dev/null
@@ -1,43 +0,0 @@
-use crate::{
-	ArgsBindingLazyVal, BoxedContextCreator, BoxedLazyVal, NoArgsBindingLazyVal, ObjValue, Val,
-};
-use jsonnet_parser::{Expr, ParamsDesc};
-use std::{fmt::Debug, rc::Rc};
-
-pub trait Binding: Debug {
-	fn evaluate(&self, this: Option<ObjValue>, super_obj: Option<ObjValue>) -> Val;
-}
-pub type BoxedBinding = Rc<dyn Binding>;
-
-#[derive(Debug)]
-pub struct NoArgsBinding {
-	pub expr: Expr,
-	pub context_creator: BoxedContextCreator,
-}
-impl Binding for NoArgsBinding {
-	fn evaluate(&self, this: Option<ObjValue>, super_obj: Option<ObjValue>) -> Val {
-		Val::Lazy(BoxedLazyVal(Rc::new(NoArgsBindingLazyVal {
-			context_creator: self.context_creator.clone(),
-			expr: self.expr.clone(),
-			this,
-			super_obj,
-		})))
-	}
-}
-#[derive(Debug)]
-pub struct ArgsBinding {
-	pub expr: Expr,
-	pub args: ParamsDesc,
-	pub context_creator: BoxedContextCreator,
-}
-impl Binding for ArgsBinding {
-	fn evaluate(&self, this: Option<ObjValue>, super_obj: Option<ObjValue>) -> Val {
-		Val::Lazy(BoxedLazyVal(Rc::new(ArgsBindingLazyVal {
-			context_creator: self.context_creator.clone(),
-			expr: self.expr.clone(),
-			args: self.args.clone(),
-			this,
-			super_obj,
-		})))
-	}
-}
modifiedcrates/jsonnet-evaluator/src/ctx.rsdiffbeforeafterboth
--- a/crates/jsonnet-evaluator/src/ctx.rs
+++ b/crates/jsonnet-evaluator/src/ctx.rs
@@ -1,20 +1,11 @@
-use crate::{dummy_debug, future_wrapper, BoxedBinding, ObjValue};
+use crate::{future_wrapper, rc_fn_helper, Binding, ObjValue};
 use std::{cell::RefCell, collections::HashMap, fmt::Debug, rc::Rc};
-
-pub trait ContextCreator: Debug {
-	fn create_context(&self, this: &Option<ObjValue>, super_obj: &Option<ObjValue>) -> Context;
-}
-pub type BoxedContextCreator = Rc<dyn ContextCreator>;
 
-#[derive(Debug)]
-pub struct ConstantContextCreator {
-	pub context: FutureContext,
-}
-impl ContextCreator for ConstantContextCreator {
-	fn create_context(&self, _this: &Option<ObjValue>, _super_obj: &Option<ObjValue>) -> Context {
-		self.context.clone().unwrap()
-	}
-}
+rc_fn_helper!(
+	ContextCreator,
+	context_creator,
+	dyn Fn(Option<ObjValue>, Option<ObjValue>) -> Context
+);
 
 future_wrapper!(Context, FutureContext);
 
@@ -23,10 +14,16 @@
 	dollar: Option<ObjValue>,
 	this: Option<ObjValue>,
 	super_obj: Option<ObjValue>,
-	bindings: Rc<RefCell<HashMap<String, BoxedBinding>>>,
+	bindings: Rc<RefCell<HashMap<String, Binding>>>,
 }
 pub struct Context(Rc<ContextInternals>);
-dummy_debug!(Context);
+impl Debug for Context {
+	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+		f.debug_struct("Context")
+			.field("this", &self.0.this.clone().map(|e| Rc::as_ptr(&e.0)))
+			.finish()
+	}
+}
 impl Context {
 	pub fn new_future() -> FutureContext {
 		FutureContext(Rc::new(RefCell::new(None)))
@@ -53,12 +50,12 @@
 		}))
 	}
 
-	pub fn binding(&self, name: &str) -> BoxedBinding {
+	pub fn binding(&self, name: &str) -> Binding {
 		self.0
 			.bindings
 			.borrow()
 			.get(name)
-			.map(|e| e.clone())
+			.cloned()
 			.unwrap_or_else(|| {
 				panic!("can't find {} in {:?}", name, self);
 			})
@@ -72,14 +69,15 @@
 
 	pub fn extend(
 		&self,
-		new_bindings: HashMap<String, BoxedBinding>,
+		new_bindings: HashMap<String, Binding>,
 		new_dollar: Option<ObjValue>,
 		new_this: Option<ObjValue>,
 		new_super_obj: Option<ObjValue>,
 	) -> Context {
-		let dollar = new_dollar.or(self.0.dollar.clone());
-		let this = new_this.or(self.0.this.clone());
-		let super_obj = new_super_obj.or(self.0.super_obj.clone());
+		println!("Extend with {:?} {:?}", new_dollar, new_this);
+		let dollar = new_dollar.or_else(|| self.0.dollar.clone());
+		let this = new_this.or_else(|| self.0.this.clone());
+		let super_obj = new_super_obj.or_else(|| self.0.super_obj.clone());
 		let bindings = if new_bindings.is_empty() {
 			self.0.bindings.clone()
 		} else {
@@ -97,6 +95,13 @@
 		}))
 	}
 }
+
+impl Default for Context {
+	fn default() -> Self {
+		Self::new()
+	}
+}
+
 impl PartialEq for Context {
 	fn eq(&self, other: &Self) -> bool {
 		Rc::ptr_eq(&self.0, &other.0)
modifiedcrates/jsonnet-evaluator/src/dynamic.rsdiffbeforeafterboth
--- a/crates/jsonnet-evaluator/src/dynamic.rs
+++ b/crates/jsonnet-evaluator/src/dynamic.rs
@@ -1,23 +1,4 @@
 #[macro_export]
-macro_rules! dynamic_wrapper {
-	($orig: ident, $wrapper: ident) => {
-		#[derive(Debug, Clone)]
-		pub struct $wrapper(pub std::rc::Rc<dyn $orig>);
-		impl std::ops::Deref for $wrapper {
-			type Target = dyn $orig;
-			fn deref(&self) -> &Self::Target {
-				&*self.0
-			}
-		}
-		impl std::cmp::PartialEq for $wrapper {
-			fn eq(&self, other: &Self) -> bool {
-				Rc::ptr_eq(&self.0, &other.0)
-			}
-		}
-	};
-}
-
-#[macro_export]
 macro_rules! future_wrapper {
 	($orig: ty, $wrapper: ident) => {
 		#[derive(Debug, Clone)]
@@ -39,17 +20,36 @@
 				self.unwrap()
 			}
 		}
+		impl Default for $wrapper {
+			fn default() -> Self {
+				Self::new()
+			}
+		}
 	};
 }
 
 #[macro_export]
-macro_rules! dummy_debug {
-	($struct: ident) => {
-		impl std::fmt::Debug for $struct {
+macro_rules! rc_fn_helper {
+	($name: ident, $macro_name: ident, $fn: ty) => {
+		#[derive(Clone)]
+		#[doc = "Function wrapper"]
+		pub struct $name(pub std::rc::Rc<$fn>);
+		impl std::fmt::Debug for $name {
 			fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
-				f.debug_struct(std::stringify!($struct))
-					.finish_non_exhaustive()
+				f.debug_struct(std::stringify!($name)).finish()
+			}
+		}
+		impl std::cmp::PartialEq for $name {
+			fn eq(&self, other: &$name) -> bool {
+				std::ptr::eq(&self.0, &other.0)
 			}
 		}
+		#[doc = "Macro to ease wrapper creation"]
+		#[macro_export]
+		macro_rules! $macro_name {
+			($val: expr) => {
+				$crate::$name(std::rc::Rc::new($val))
+			};
+		}
 	};
 }
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
--- a/crates/jsonnet-evaluator/src/lib.rs
+++ b/crates/jsonnet-evaluator/src/lib.rs
@@ -1,44 +1,50 @@
 #![feature(box_syntax, box_patterns)]
 #![feature(type_alias_impl_trait)]
 #![feature(debug_non_exhaustive)]
-
-mod binding;
+#![allow(macro_expanded_macro_exports_accessed_by_absolute_paths)]
 mod ctx;
 mod dynamic;
 mod evaluate;
 mod obj;
 mod val;
 
-pub use binding::*;
 pub use ctx::*;
 pub use dynamic::*;
 pub use evaluate::*;
 use jsonnet_parser::*;
 pub use obj::*;
-use std::fmt::Debug;
-use std::rc::Rc;
 pub use val::*;
 
-pub trait FunctionRhs: Debug {
-	fn evaluate(&self, ctx: Context) -> Val;
-}
-dynamic_wrapper!(FunctionRhs, BoxedFunctionRhs);
-
-pub trait FunctionDefault: Debug {
-	fn default(&self, ctx: Context, expr: Expr) -> Val;
-}
-dynamic_wrapper!(FunctionDefault, BoxedFunctionDefault);
+rc_fn_helper!(
+	Binding,
+	binding,
+	dyn Fn(Option<ObjValue>, Option<ObjValue>) -> Val
+);
+rc_fn_helper!(FunctionRhs, function_rhs, dyn Fn(Context) -> Val);
+rc_fn_helper!(
+	FunctionDefault,
+	function_default,
+	dyn Fn(Context, Expr) -> Val
+);
 
 #[cfg(test)]
 pub mod tests {
 	use super::{evaluate, Context, Val};
 	use jsonnet_parser::*;
 
-	// macro_rules! eval {
-	// 	($str: expr) => {
-	// 		evaluate(Context::new(), &parse($str).unwrap())
-	// 	};
-	// }
+	macro_rules! eval {
+		($str: expr) => {
+			evaluate(Context::new(), &parse($str).unwrap())
+		};
+	}
+
+	macro_rules! eval_stdlib {
+		($str: expr) => {
+			let std = "local std = ".to_owned() + jsonnet_stdlib::STDLIB_STR + ";";
+			evaluate(Context::new(), &parse(&(std + $str)).unwrap())
+		};
+	}
+
 	macro_rules! assert_eval {
 		($str: expr) => {
 			assert_eq!(
@@ -165,23 +171,48 @@
 		);
 	}
 
+	#[test]
+	fn direct_self() {
+		println!(
+			"{:#?}",
+			eval!(
+				r#"
+					{
+						local me = self,
+						a: 3,
+						b(): me.a,
+					}
+				"#
+			)
+		);
+	}
+
+	#[test]
+	fn indirect_self() {
+		// `self` assigned to `me` was lost when being
+		// referenced from field
+		eval_stdlib!(
+			r#"{
+				local me = std.trace("test", self),
+				b: me,
+			}.b"#
+		);
+	}
+
 	// We can't trust other tests (And official jsonnet testsuite), if assert is not working correctly
 	#[test]
 	fn std_assert_ok() {
-		let std = "local std = ".to_owned() + jsonnet_stdlib::STDLIB_STR + ";";
-		evaluate(
-			Context::new(),
-			&parse(&(std + "std.assertEqual(4.5 << 2, 16,)")).unwrap(),
-		);
+		eval_stdlib!("std.assertEqual(4.5 << 2, 16)");
 	}
 
 	#[test]
 	#[should_panic]
 	fn std_assert_failure() {
-		let std = "local std = ".to_owned() + jsonnet_stdlib::STDLIB_STR + ";";
-		evaluate(
-			Context::new(),
-			&parse(&(std + "std.assertEqual(4.5 << 2, 15,)")).unwrap(),
-		);
+		eval_stdlib!("std.assertEqual(4.5 << 2, 15)");
+	}
+
+	#[test]
+	fn base64_works() {
+		eval_stdlib!(r#"std.base64("test")"#);
 	}
 }
modifiedcrates/jsonnet-evaluator/src/obj.rsdiffbeforeafterboth
--- a/crates/jsonnet-evaluator/src/obj.rs
+++ b/crates/jsonnet-evaluator/src/obj.rs
@@ -1,7 +1,8 @@
-use crate::{dummy_debug, evaluate_binary_op, BoxedBinding, Val};
+use crate::{evaluate_binary_op, Binding, Val};
 use jsonnet_parser::{BinaryOpType, Visibility};
 use std::{
 	collections::{BTreeMap, BTreeSet},
+	fmt::Debug,
 	rc::Rc,
 };
 
@@ -9,7 +10,7 @@
 pub struct ObjMember {
 	pub add: bool,
 	pub visibility: Visibility,
-	pub invoke: BoxedBinding,
+	pub invoke: Binding,
 }
 
 #[derive(Debug)]
@@ -17,8 +18,28 @@
 	super_obj: Option<ObjValue>,
 	this_entries: Rc<BTreeMap<String, ObjMember>>,
 }
-pub struct ObjValue(Rc<ObjValueInternals>);
-dummy_debug!(ObjValue);
+pub struct ObjValue(pub(crate) Rc<ObjValueInternals>);
+impl Debug for ObjValue {
+	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+		if let Some(super_obj) = self.0.super_obj.as_ref() {
+			if f.alternate() {
+				write!(f, "{:#?}", super_obj)?;
+			} else {
+				write!(f, "{:?}", super_obj)?;
+			}
+			write!(f, " + ")?;
+		}
+		let mut debug = f.debug_struct("ObjValue");
+		debug.field("$ptr", &Rc::as_ptr(&self.0));
+		for (name, member) in self.0.this_entries.iter() {
+			debug.field(name, member);
+		}
+		debug.finish_non_exhaustive()
+		// .field("fields", &self.fields())
+		// .finish_non_exhaustive()
+	}
+}
+
 impl ObjValue {
 	pub fn new(
 		super_obj: Option<ObjValue>,
@@ -47,26 +68,30 @@
 		}
 		fields
 	}
-	pub fn get_raw(&self, key: &str, real_this: Option<ObjValue>) -> Option<Val> {
+	pub fn get(&self, key: &str) -> Option<Val> {
+		// TODO: Cache get_raw result
+		self.get_raw(key, Some(self))
+	}
+	fn get_raw(&self, key: &str, real_this: Option<&ObjValue>) -> Option<Val> {
 		match (self.0.this_entries.get(key), &self.0.super_obj) {
-			(Some(k), None) => Some(k.invoke.evaluate(
-				real_this.or_else(|| Some(self.clone())),
-				self.0.super_obj.clone().map(|e| e.clone()),
+			(Some(k), None) => Some(k.invoke.0(
+				real_this.as_ref().map(|e| (*e).clone()),
+				self.0.super_obj.clone(),
 			)),
 			(Some(k), Some(s)) => {
-				let our = k
-					.invoke
-					.evaluate(Some(self.clone()), self.0.super_obj.clone());
+				let our = k.invoke.0(
+					real_this.as_ref().map(|e| (*e).clone()),
+					self.0.super_obj.clone(),
+				);
 				if k.add {
-					s.get_raw(key, Some(self.clone()))
-						.map_or(Some(our.clone()), |v| {
-							Some(evaluate_binary_op(&v, BinaryOpType::Add, &our))
-						})
+					s.get_raw(key, real_this).map_or(Some(our.clone()), |v| {
+						Some(evaluate_binary_op(&v, BinaryOpType::Add, &our))
+					})
 				} else {
 					Some(our)
 				}
 			}
-			(None, Some(s)) => s.get_raw(key, Some(self.clone())),
+			(None, Some(s)) => s.get_raw(key, real_this),
 			(None, None) => None,
 		}
 	}
modifiedcrates/jsonnet-evaluator/src/val.rsdiffbeforeafterboth
--- a/crates/jsonnet-evaluator/src/val.rs
+++ b/crates/jsonnet-evaluator/src/val.rs
@@ -1,135 +1,62 @@
-use crate::{
-	dynamic_wrapper, evaluate, evaluate_method, BoxedContextCreator, Context, FunctionDefault,
-	FunctionRhs, ObjValue,
-};
-use crate::{Binding, BoxedBinding, BoxedFunctionDefault, BoxedFunctionRhs, FutureContext};
-use jsonnet_parser::{ArgsDesc, Expr, LiteralType, Param, ParamsDesc};
+use crate::{binding, rc_fn_helper, Binding, Context, FunctionDefault, FunctionRhs, ObjValue};
+use closure::closure;
+use jsonnet_parser::{LiteralType, ParamsDesc};
 use std::{
 	collections::HashMap,
 	fmt::{Debug, Display},
-	ops::Deref,
-	rc::Rc,
 };
 
-pub trait LazyVal: Debug {
-	fn evaluate(&self) -> Val;
-}
-dynamic_wrapper!(LazyVal, BoxedLazyVal);
-
-#[derive(Debug)]
-pub struct PlainLazyVal {
-	pub expr: Expr,
-	pub context: Context,
-}
-impl LazyVal for PlainLazyVal {
-	fn evaluate(&self) -> Val {
-		evaluate(self.context.clone(), &self.expr)
-	}
-}
-
-#[derive(Debug)]
-pub struct NoArgsBindingLazyVal {
-	pub expr: Expr,
-	pub context_creator: BoxedContextCreator,
-
-	pub this: Option<ObjValue>,
-	pub super_obj: Option<ObjValue>,
-}
-impl LazyVal for NoArgsBindingLazyVal {
-	fn evaluate(&self) -> Val {
-		evaluate(
-			self.context_creator
-				.create_context(&self.this, &self.super_obj),
-			&self.expr,
-		)
-	}
-}
-
-#[derive(Debug)]
-pub struct ArgsBindingLazyVal {
-	pub expr: Expr,
-	pub args: ParamsDesc,
-	pub context_creator: BoxedContextCreator,
-
-	pub this: Option<ObjValue>,
-	pub super_obj: Option<ObjValue>,
-}
-impl LazyVal for ArgsBindingLazyVal {
-	fn evaluate(&self) -> Val {
-		evaluate_method(
-			self.context_creator
-				.create_context(&self.this, &self.super_obj),
-			&self.expr,
-			self.args.clone(),
-		)
-	}
-}
-
-#[derive(Debug)]
-pub struct FunctionDefaultBinding {
-	eval: BoxedFunctionDefault,
-	default: Expr,
-	ctx: FutureContext,
-}
-impl Binding for FunctionDefaultBinding {
-	fn evaluate(&self, _this: Option<ObjValue>, _super_obj: Option<ObjValue>) -> Val {
-		self.eval
-			.default(self.ctx.clone().unwrap(), self.default.clone())
-	}
-}
+rc_fn_helper!(LazyVal, lazy_val, dyn Fn() -> Val);
 
-#[derive(Debug)]
-pub struct ValBinding {
-	val: Val,
-}
-impl Binding for ValBinding {
-	fn evaluate(&self, this: Option<ObjValue>, super_obj: Option<ObjValue>) -> Val {
-		self.val.clone()
-	}
-}
-
 #[derive(Debug, PartialEq, Clone)]
 pub struct FuncDesc {
 	pub ctx: Context,
 	pub params: ParamsDesc,
-	pub eval_rhs: BoxedFunctionRhs,
-	pub eval_default: BoxedFunctionDefault,
+	pub eval_rhs: FunctionRhs,
+	pub eval_default: FunctionDefault,
 }
 impl FuncDesc {
 	// TODO: Check for unset variables
 	pub fn evaluate(&self, args: Vec<(Option<String>, Val)>) -> Val {
-		let mut new_bindings: HashMap<String, BoxedBinding> = HashMap::new();
+		let mut new_bindings: HashMap<String, Binding> = HashMap::new();
 		let future_ctx = Context::new_future();
 
-		self.params
-			.with_defaults()
-			.into_iter()
-			.for_each(|Param(name, default)| {
-				new_bindings.insert(
-					name,
-					Rc::new(FunctionDefaultBinding {
-						eval: self.eval_default.clone(),
-						default: *default.unwrap().clone(),
-						ctx: future_ctx.clone(),
-					}),
-				);
-			});
-		for (name, val) in args.iter().filter(|e| e.0.is_some()) {
+		// self.params
+		// 	.with_defaults()
+		// 	.into_iter()
+		// 	.for_each(|Param(name, default)| {
+		// 		let default = Rc::new(*default.unwrap());
+		// 		new_bindings.insert(
+		// 			name,
+		// 			binding!(move |_, _| Val::Lazy(lazy_val!(|| self
+		// 				.eval_default
+		// 				.0
+		// 				.default(future_ctx.unwrap(), *default.clone())))),
+		// 		);
+		// 	});
+		for (name, val) in args.clone().into_iter().filter(|e| e.0.is_some()) {
 			new_bindings.insert(
 				name.as_ref().unwrap().clone(),
-				Rc::new(ValBinding { val: val.clone() }),
+				binding!(
+					closure!(clone val, |_, _| Val::Lazy(lazy_val!(closure!(clone val, || val.clone()))))
+				),
 			);
 		}
 		for (i, param) in self.params.0.iter().enumerate() {
 			if let Some((None, val)) = args.get(i) {
-				new_bindings.insert(param.0.clone(), Rc::new(ValBinding { val: val.clone() }));
+				new_bindings.insert(
+					param.0.clone(),
+					binding!(
+						closure!(clone val, |_, _| Val::Lazy(lazy_val!(closure!(clone val, || val.clone()))))
+					),
+				);
 			}
 		}
 		let ctx = self
 			.ctx
 			.extend(new_bindings, None, None, None)
 			.into_future(future_ctx);
-		self.eval_rhs.evaluate(ctx)
+		self.eval_rhs.0(ctx)
 	}
 }
 
@@ -138,15 +65,18 @@
 	Literal(LiteralType),
 	Str(String),
 	Num(f64),
-	Lazy(BoxedLazyVal),
+	Lazy(LazyVal),
 	Arr(Vec<Val>),
 	Obj(ObjValue),
 	Func(FuncDesc),
+
+	// Library functions implemented in native
+	Intristic(String, String),
 }
 impl Val {
 	pub fn unwrap_if_lazy(self) -> Self {
 		if let Val::Lazy(v) = self {
-			v.evaluate().unwrap_if_lazy()
+			v.0().unwrap_if_lazy()
 		} else {
 			self
 		}
@@ -191,12 +121,12 @@
 						write!(f, ",")?;
 					}
 					write!(f, "\"{}\":", field)?;
-					write!(f, "{}", value.get_raw(&field, None).unwrap())?;
+					write!(f, "{}", value.get(&field).unwrap())?;
 				}
 				write!(f, "}}")?;
 			}
 			Val::Lazy(lazy) => {
-				write!(f, "{}", lazy.evaluate())?;
+				write!(f, "{}", lazy.0())?;
 			}
 			Val::Func(_) => {
 				write!(f, "<<FUNC>>")?;
modifiedcrates/jsonnet-parser/src/expr.rsdiffbeforeafterboth
--- a/crates/jsonnet-parser/src/expr.rs
+++ b/crates/jsonnet-parser/src/expr.rs
@@ -37,7 +37,7 @@
 	AssertStmt(AssertStmt),
 }
 
-#[derive(Debug, Clone, PartialEq)]
+#[derive(Debug, Clone, Copy, PartialEq)]
 pub enum UnaryOpType {
 	Plus,
 	Minus,