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
before · crates/jsonnet-evaluator/src/binding.rs
1use crate::{2	ArgsBindingLazyVal, BoxedContextCreator, BoxedLazyVal, NoArgsBindingLazyVal, ObjValue, Val,3};4use jsonnet_parser::{Expr, ParamsDesc};5use std::{fmt::Debug, rc::Rc};67pub trait Binding: Debug {8	fn evaluate(&self, this: Option<ObjValue>, super_obj: Option<ObjValue>) -> Val;9}10pub type BoxedBinding = Rc<dyn Binding>;1112#[derive(Debug)]13pub struct NoArgsBinding {14	pub expr: Expr,15	pub context_creator: BoxedContextCreator,16}17impl Binding for NoArgsBinding {18	fn evaluate(&self, this: Option<ObjValue>, super_obj: Option<ObjValue>) -> Val {19		Val::Lazy(BoxedLazyVal(Rc::new(NoArgsBindingLazyVal {20			context_creator: self.context_creator.clone(),21			expr: self.expr.clone(),22			this,23			super_obj,24		})))25	}26}27#[derive(Debug)]28pub struct ArgsBinding {29	pub expr: Expr,30	pub args: ParamsDesc,31	pub context_creator: BoxedContextCreator,32}33impl Binding for ArgsBinding {34	fn evaluate(&self, this: Option<ObjValue>, super_obj: Option<ObjValue>) -> Val {35		Val::Lazy(BoxedLazyVal(Rc::new(ArgsBindingLazyVal {36			context_creator: self.context_creator.clone(),37			expr: self.expr.clone(),38			args: self.args.clone(),39			this,40			super_obj,41		})))42	}43}
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
--- a/crates/jsonnet-evaluator/src/evaluate.rs
+++ b/crates/jsonnet-evaluator/src/evaluate.rs
@@ -1,70 +1,53 @@
-use crate::BoxedLazyVal;
 use crate::{
-	bool_val, ArgsBinding, BoxedBinding, BoxedContextCreator, ConstantContextCreator, Context,
-	FuncDesc, FunctionDefault, FunctionRhs, NoArgsBinding, Val,
-};
-use crate::{
-	future_wrapper, BoxedFunctionDefault, BoxedFunctionRhs, ContextCreator, ObjMember, ObjValue,
-	PlainLazyVal,
+	binding, bool_val, context_creator, function_default, function_rhs, future_wrapper, lazy_val,
+	Binding, Context, ContextCreator, FuncDesc, ObjMember, ObjValue, Val,
 };
+use closure::closure;
 use jsonnet_parser::{
 	ArgsDesc, BinaryOpType, BindSpec, Expr, FieldMember, LiteralType, Member, ObjBody, ParamsDesc,
-	Visibility,
+	UnaryOpType, Visibility,
 };
 use std::{
-	cell::RefCell,
 	collections::{BTreeMap, HashMap},
 	rc::Rc,
 };
 
-pub fn evaluate_binding<'t>(
-	b: &BindSpec,
-	context_creator: BoxedContextCreator,
-) -> (String, BoxedBinding) {
+pub fn evaluate_binding(b: &BindSpec, context_creator: ContextCreator) -> (String, Binding) {
+	let b = b.clone();
 	if let Some(args) = &b.params {
+		let args = args.clone();
 		(
 			b.name.clone(),
-			Rc::new(ArgsBinding {
-				expr: *b.value.clone(),
-				args: args.clone(),
-				context_creator: context_creator.clone(),
-			}),
+			binding!(move |this, super_obj| Val::Lazy(lazy_val!(
+				closure!(clone b, clone args, clone context_creator, || evaluate_method(
+					context_creator.0(this.clone(), super_obj.clone()),
+					&b.value,
+					args.clone()
+				))
+			))),
 		)
 	} else {
 		(
 			b.name.clone(),
-			Rc::new(NoArgsBinding {
-				expr: *b.value.clone(),
-				context_creator: context_creator.clone(),
-			}) as BoxedBinding,
+				binding!(move |this, super_obj| {
+					println!("Evaluating binding");
+					Val::Lazy(lazy_val!(
+					closure!(clone context_creator, clone b, || evaluate(
+						context_creator.0(this.clone(), super_obj.clone()),
+						&b.value
+					))
+				))
+			}),
 		)
 	}
 }
 
-#[derive(Debug)]
-struct MethodRhs {
-	rhs: Expr,
-}
-impl FunctionRhs for MethodRhs {
-	fn evaluate(&self, ctx: Context) -> Val {
-		evaluate(ctx, &self.rhs)
-	}
-}
-
-#[derive(Debug)]
-struct MethodDefault {}
-impl FunctionDefault for MethodDefault {
-	fn default(&self, ctx: Context, expr: Expr) -> Val {
-		evaluate(ctx, &expr)
-	}
-}
-
 pub fn evaluate_method(ctx: Context, expr: &Expr, arg_spec: ParamsDesc) -> Val {
 	Val::Func(FuncDesc {
 		ctx,
 		params: arg_spec,
-		eval_rhs: BoxedFunctionRhs(Rc::new(MethodRhs { rhs: expr.clone() })),
-		eval_default: BoxedFunctionDefault(Rc::new(MethodDefault {})),
+		eval_rhs: function_rhs!(closure!(clone expr, |ctx| evaluate(ctx, &expr))),
+		eval_default: function_default!(|ctx, default| evaluate(ctx, &default)),
 	})
 }
 
@@ -74,7 +57,7 @@
 		jsonnet_parser::FieldName::Dyn(expr) => {
 			let name = evaluate(context, expr).unwrap_if_lazy();
 			match name {
-				Val::Str(n) => n.clone(),
+				Val::Str(n) => n,
 				_ => panic!(
 					"dynamic field name can be only evaluated to 'string', got: {:?}",
 					name
@@ -84,10 +67,19 @@
 	}
 }
 
+pub fn evaluate_unary_op(op: UnaryOpType, b: &Val) -> Val {
+	match (op, b) {
+		(o, Val::Lazy(l)) => evaluate_unary_op(o, &l.0()),
+		(UnaryOpType::Not, Val::Literal(LiteralType::True)) => Val::Literal(LiteralType::False),
+		(UnaryOpType::Not, Val::Literal(LiteralType::False)) => Val::Literal(LiteralType::True),
+		(op, o) => panic!("unary op not implemented: {:?} {:?}", op, o),
+	}
+}
+
 pub fn evaluate_binary_op(a: &Val, op: BinaryOpType, b: &Val) -> Val {
 	match (a, op, b) {
-		(Val::Lazy(l), o, r) => evaluate_binary_op(&l.evaluate(), o, r),
-		(l, o, Val::Lazy(r)) => evaluate_binary_op(l, o, &r.evaluate()),
+		(Val::Lazy(a), o, b) => evaluate_binary_op(&a.0(), o, b),
+		(a, o, Val::Lazy(b)) => evaluate_binary_op(a, o, &b.0()),
 
 		(Val::Str(v1), BinaryOpType::Add, Val::Str(v2)) => Val::Str(v1.to_owned() + &v2),
 		(Val::Str(v1), BinaryOpType::Eq, Val::Str(v2)) => bool_val(v1 == v2),
@@ -119,8 +111,8 @@
 		(Val::Num(v1), BinaryOpType::Lte, Val::Num(v2)) => bool_val(v1 <= v2),
 		(Val::Num(v1), BinaryOpType::Gte, Val::Num(v2)) => bool_val(v1 >= v2),
 
-		(Val::Num(v1), BinaryOpType::Eq, Val::Num(v2)) => bool_val(v1 == v2),
-		(Val::Num(v1), BinaryOpType::Ne, Val::Num(v2)) => bool_val(v1 != v2),
+		(Val::Num(v1), BinaryOpType::Eq, Val::Num(v2)) => bool_val((v1 - v2).abs() < f64::EPSILON),
+		(Val::Num(v1), BinaryOpType::Ne, Val::Num(v2)) => bool_val((v1 - v2).abs() > f64::EPSILON),
 
 		(Val::Num(v1), BinaryOpType::BitAnd, Val::Num(v2)) => {
 			Val::Num(((*v1 as i32) & (*v2 as i32)) as f64)
@@ -135,48 +127,44 @@
 	}
 }
 
-future_wrapper!(HashMap<String, BoxedBinding>, FutureNewBindings);
-
-#[derive(Debug)]
-pub struct ObjectContextCreator {
-	original: Context,
-	future_bindings: FutureNewBindings,
-}
-
-impl ContextCreator for ObjectContextCreator {
-	fn create_context(&self, this: &Option<ObjValue>, super_obj: &Option<ObjValue>) -> Context {
-		self.original.extend(
-			self.future_bindings.clone().unwrap(),
-			self.original.dollar().clone().or_else(|| this.clone()),
-			this.clone(),
-			super_obj.clone(),
-		)
-	}
-}
+future_wrapper!(HashMap<String, Binding>, FutureNewBindings);
+future_wrapper!(ObjValue, FutureObjValue);
 
 // TODO: Asserts
 pub fn evaluate_object(context: Context, object: ObjBody) -> ObjValue {
 	match object {
 		ObjBody::MemberList(members) => {
 			let future_bindings = FutureNewBindings::new();
-			let binding_context_creator = Rc::new(ObjectContextCreator {
-				future_bindings: future_bindings.clone(),
-				original: context.clone(),
-			});
-			let mut bindings: HashMap<String, BoxedBinding> = HashMap::new();
+			let future_this = FutureObjValue::new();
+			let context_creator = context_creator!(
+				closure!(clone context, clone future_bindings, |this: Option<ObjValue>, super_obj: Option<ObjValue>| {
+					println!("Context created");
+					context.clone().extend(
+						future_bindings.clone().unwrap(),
+						context.clone().dollar().clone().or_else(||this.clone()),
+						this,
+						super_obj
+					)
+				})
+			);
+			let mut bindings: HashMap<String, Binding> = HashMap::new();
 			for (n, b) in members
 				.iter()
 				.filter_map(|m| match m {
 					Member::BindStmt(b) => Some(b.clone()),
 					_ => None,
 				})
-				.map(|b| evaluate_binding(&b, binding_context_creator.clone()))
+				.map(|b| {
+					evaluate_binding(&b, context_creator.clone())
+				})
 			{
 				bindings.insert(n, b);
 			}
-			let bindings = future_bindings.fill(bindings);
+			future_bindings.fill(bindings);
+
+			println!("Bindings filled");
 			let mut new_members = BTreeMap::new();
-			for member in members.iter() {
+			for member in members.into_iter() {
 				match member {
 					Member::Field(FieldMember {
 						name,
@@ -185,16 +173,22 @@
 						visibility,
 						value,
 					}) => {
-						let name = evaluate_field_name(context.clone(), name);
+						let name = evaluate_field_name(context.clone(), &name);
 						new_members.insert(
 							name,
 							ObjMember {
-								add: *plus,
+								add: plus,
 								visibility: visibility.clone(),
-								invoke: Rc::new(NoArgsBinding {
-									context_creator: binding_context_creator.clone(),
-									expr: value.clone(),
-								}),
+								invoke: binding!(
+									closure!(clone value, clone context_creator, clone future_this, |this, super_obj| {
+										// FIXME: I should take "this" instead of "future_this" there?
+										// TODO: Assert
+										evaluate(
+											context_creator.0(this, super_obj),
+											&value,
+										)
+									})
+								),
 							},
 						);
 					}
@@ -204,26 +198,31 @@
 						value,
 						..
 					}) => {
-						let name = evaluate_field_name(context.clone(), name);
+						let name = evaluate_field_name(context.clone(), &name);
 						new_members.insert(
 							name,
 							ObjMember {
 								add: false,
 								visibility: Visibility::Hidden,
-								invoke: Rc::new(ArgsBinding {
-									expr: value.clone(),
-									args: params.clone(),
-									context_creator: binding_context_creator.clone(),
-								}),
+								invoke: binding!(
+									closure!(clone value, clone context_creator, clone future_this, |this, super_obj| {
+										// FIXME: I should take "this" instead of "future_this" there?
+										// TODO: Assert
+										evaluate_method(
+											context_creator.0(this, super_obj),
+											&value.clone(),
+											params.clone(),
+										)
+									})
+								),
 							},
 						);
 					}
 					Member::BindStmt(_) => {}
 					Member::AssertStmt(_) => {}
-					_ => todo!(),
 				}
 			}
-			ObjValue::new(None, Rc::new(new_members))
+			future_this.fill(ObjValue::new(None, Rc::new(new_members)))
 		}
 		_ => todo!(),
 	}
@@ -232,6 +231,21 @@
 pub fn evaluate(context: Context, expr: &Expr) -> Val {
 	use Expr::*;
 	match &*expr {
+		Literal(LiteralType::This) => {
+			println!("{:?}", context.this());
+			Val::Obj(
+				context
+					.this()
+					.clone()
+					.unwrap_or_else(|| panic!("this not found")),
+			)
+		}
+		Literal(LiteralType::Super) => Val::Obj(
+			context
+				.super_obj()
+				.clone()
+				.unwrap_or_else(|| panic!("super not found")),
+		),
 		Literal(t) => Val::Literal(t.clone()),
 		Parened(e) => evaluate(context, e),
 		Str(v) => Val::Str(v.clone()),
@@ -239,45 +253,34 @@
 		BinaryOp(v1, o, v2) => {
 			evaluate_binary_op(&evaluate(context.clone(), v1), *o, &evaluate(context, v2))
 		}
+		UnaryOp(o, v) => evaluate_unary_op(*o, &evaluate(context, v)),
 		Var(name) => {
 			let variable = context.binding(&name);
-			let val = variable.evaluate(None, None);
-			val
+			variable.0(None, None).unwrap_if_lazy()
 		}
 		Index(box value, box index) => {
 			match (
 				evaluate(context.clone(), value).unwrap_if_lazy(),
-				evaluate(context.clone(), index),
+				evaluate(context, index),
 			) {
-				(Val::Literal(LiteralType::Super), _idx) => todo!(),
-				(Val::Literal(LiteralType::This), idx) => match &idx.unwrap_if_lazy() {
-					Val::Str(str) => context
-						.this()
-						.clone()
-						.unwrap_or_else(|| panic!("'this' is not defined in current context"))
-						.get_raw(str, None)
-						.unwrap_or_else(|| {
-							panic!(
-								"key {} not found in current context 'this' ({:?})",
-								str,
-								context.this()
-							)
-						}),
-					_ => panic!("bad index"),
-				},
 				(Val::Obj(v), Val::Str(s)) => v
-					.get_raw(&s, None)
+					.get(&s)
 					.unwrap_or_else(|| panic!("{} not found in {:?}", s, v)),
+				(Val::Arr(v), Val::Num(n)) => v
+					.get(n as usize)
+					.unwrap_or_else(|| panic!("out of bounds"))
+					.clone(),
 				(v, i) => todo!("not implemented: {:?}[{:?}]", v, i.unwrap_if_lazy()),
 			}
 		}
 		LocalExpr(bindings, returned) => {
-			let mut new_bindings: HashMap<String, BoxedBinding> = HashMap::new();
+			let mut new_bindings: HashMap<String, Binding> = HashMap::new();
 			let future_context = Context::new_future();
 
-			let context_creator = Rc::new(ConstantContextCreator {
-				context: future_context.clone(),
-			});
+			let context_creator = context_creator!(
+				closure!(clone future_context, |_, _| future_context.clone().unwrap())
+			);
+
 			for (k, v) in bindings
 				.iter()
 				.map(move |b| evaluate_binding(b, context_creator.clone()))
@@ -299,11 +302,10 @@
 						.into_iter()
 						.map(|a| {
 							(
-								a.0,
-								Val::Lazy(BoxedLazyVal(Rc::new(PlainLazyVal {
-									context: context.clone(),
-									expr: *a.1,
-								}))),
+								a.clone().0,
+								Val::Lazy(lazy_val!(
+									closure!(clone context, clone a, || evaluate(context.clone(), &a.clone().1))
+								)),
 							)
 						})
 						.collect(),
@@ -318,9 +320,9 @@
 			cond_then,
 			cond_else,
 		} => match evaluate(context.clone(), &cond.0).unwrap_if_lazy() {
-			Val::Literal(LiteralType::True) => evaluate(context.clone(), cond_then),
+			Val::Literal(LiteralType::True) => evaluate(context, cond_then),
 			Val::Literal(LiteralType::False) => match cond_else {
-				Some(v) => evaluate(context.clone(), v),
+				Some(v) => evaluate(context, v),
 				None => Val::Literal(LiteralType::False),
 			},
 			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,