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
before · crates/jsonnet-evaluator/src/evaluate.rs
1use crate::BoxedLazyVal;2use crate::{3	bool_val, ArgsBinding, BoxedBinding, BoxedContextCreator, ConstantContextCreator, Context,4	FuncDesc, FunctionDefault, FunctionRhs, NoArgsBinding, Val,5};6use crate::{7	future_wrapper, BoxedFunctionDefault, BoxedFunctionRhs, ContextCreator, ObjMember, ObjValue,8	PlainLazyVal,9};10use jsonnet_parser::{11	ArgsDesc, BinaryOpType, BindSpec, Expr, FieldMember, LiteralType, Member, ObjBody, ParamsDesc,12	Visibility,13};14use std::{15	cell::RefCell,16	collections::{BTreeMap, HashMap},17	rc::Rc,18};1920pub fn evaluate_binding<'t>(21	b: &BindSpec,22	context_creator: BoxedContextCreator,23) -> (String, BoxedBinding) {24	if let Some(args) = &b.params {25		(26			b.name.clone(),27			Rc::new(ArgsBinding {28				expr: *b.value.clone(),29				args: args.clone(),30				context_creator: context_creator.clone(),31			}),32		)33	} else {34		(35			b.name.clone(),36			Rc::new(NoArgsBinding {37				expr: *b.value.clone(),38				context_creator: context_creator.clone(),39			}) as BoxedBinding,40		)41	}42}4344#[derive(Debug)]45struct MethodRhs {46	rhs: Expr,47}48impl FunctionRhs for MethodRhs {49	fn evaluate(&self, ctx: Context) -> Val {50		evaluate(ctx, &self.rhs)51	}52}5354#[derive(Debug)]55struct MethodDefault {}56impl FunctionDefault for MethodDefault {57	fn default(&self, ctx: Context, expr: Expr) -> Val {58		evaluate(ctx, &expr)59	}60}6162pub fn evaluate_method(ctx: Context, expr: &Expr, arg_spec: ParamsDesc) -> Val {63	Val::Func(FuncDesc {64		ctx,65		params: arg_spec,66		eval_rhs: BoxedFunctionRhs(Rc::new(MethodRhs { rhs: expr.clone() })),67		eval_default: BoxedFunctionDefault(Rc::new(MethodDefault {})),68	})69}7071pub fn evaluate_field_name(context: Context, field_name: &jsonnet_parser::FieldName) -> String {72	match field_name {73		jsonnet_parser::FieldName::Fixed(n) => n.clone(),74		jsonnet_parser::FieldName::Dyn(expr) => {75			let name = evaluate(context, expr).unwrap_if_lazy();76			match name {77				Val::Str(n) => n.clone(),78				_ => panic!(79					"dynamic field name can be only evaluated to 'string', got: {:?}",80					name81				),82			}83		}84	}85}8687pub fn evaluate_binary_op(a: &Val, op: BinaryOpType, b: &Val) -> Val {88	match (a, op, b) {89		(Val::Lazy(l), o, r) => evaluate_binary_op(&l.evaluate(), o, r),90		(l, o, Val::Lazy(r)) => evaluate_binary_op(l, o, &r.evaluate()),9192		(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),94		(Val::Str(v1), BinaryOpType::Ne, Val::Str(v2)) => bool_val(v1 != v2),9596		(Val::Str(v1), BinaryOpType::Add, Val::Num(v2)) => Val::Str(format!("{}{}", v1, v2)),97		(Val::Str(v1), BinaryOpType::Mul, Val::Num(v2)) => Val::Str(v1.repeat(*v2 as usize)),9899		(Val::Obj(v1), BinaryOpType::Add, Val::Obj(v2)) => Val::Obj(v2.with_super(v1.clone())),100101		(Val::Arr(a), BinaryOpType::Add, Val::Arr(b)) => Val::Arr([&a[..], &b[..]].concat()),102103		(Val::Num(v1), BinaryOpType::Mul, Val::Num(v2)) => Val::Num(v1 * v2),104		(Val::Num(v1), BinaryOpType::Div, Val::Num(v2)) => Val::Num(v1 / v2),105		(Val::Num(v1), BinaryOpType::Mod, Val::Num(v2)) => Val::Num(v1 % v2),106107		(Val::Num(v1), BinaryOpType::Add, Val::Num(v2)) => Val::Num(v1 + v2),108		(Val::Num(v1), BinaryOpType::Sub, Val::Num(v2)) => Val::Num(v1 - v2),109110		(Val::Num(v1), BinaryOpType::Lhs, Val::Num(v2)) => {111			Val::Num(((*v1 as i32) << (*v2 as i32)) as f64)112		}113		(Val::Num(v1), BinaryOpType::Rhs, Val::Num(v2)) => {114			Val::Num(((*v1 as i32) >> (*v2 as i32)) as f64)115		}116117		(Val::Num(v1), BinaryOpType::Lt, Val::Num(v2)) => bool_val(v1 < v2),118		(Val::Num(v1), BinaryOpType::Gt, Val::Num(v2)) => bool_val(v1 > v2),119		(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),121122		(Val::Num(v1), BinaryOpType::Eq, Val::Num(v2)) => bool_val(v1 == v2),123		(Val::Num(v1), BinaryOpType::Ne, Val::Num(v2)) => bool_val(v1 != v2),124125		(Val::Num(v1), BinaryOpType::BitAnd, Val::Num(v2)) => {126			Val::Num(((*v1 as i32) & (*v2 as i32)) as f64)127		}128		(Val::Num(v1), BinaryOpType::BitOr, Val::Num(v2)) => {129			Val::Num(((*v1 as i32) | (*v2 as i32)) as f64)130		}131		(Val::Num(v1), BinaryOpType::BitXor, Val::Num(v2)) => {132			Val::Num(((*v1 as i32) ^ (*v2 as i32)) as f64)133		}134		_ => panic!("no rules for binary operation: {:?} {:?} {:?}", a, op, b),135	}136}137138future_wrapper!(HashMap<String, BoxedBinding>, FutureNewBindings);139140#[derive(Debug)]141pub struct ObjectContextCreator {142	original: Context,143	future_bindings: FutureNewBindings,144}145146impl ContextCreator for ObjectContextCreator {147	fn create_context(&self, this: &Option<ObjValue>, super_obj: &Option<ObjValue>) -> Context {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}156157// TODO: Asserts158pub fn evaluate_object(context: Context, object: ObjBody) -> ObjValue {159	match object {160		ObjBody::MemberList(members) => {161			let future_bindings = FutureNewBindings::new();162			let binding_context_creator = Rc::new(ObjectContextCreator {163				future_bindings: future_bindings.clone(),164				original: context.clone(),165			});166			let mut bindings: HashMap<String, BoxedBinding> = HashMap::new();167			for (n, b) in members168				.iter()169				.filter_map(|m| match m {170					Member::BindStmt(b) => Some(b.clone()),171					_ => None,172				})173				.map(|b| evaluate_binding(&b, binding_context_creator.clone()))174			{175				bindings.insert(n, b);176			}177			let bindings = future_bindings.fill(bindings);178			let mut new_members = BTreeMap::new();179			for member in members.iter() {180				match member {181					Member::Field(FieldMember {182						name,183						plus,184						params: None,185						visibility,186						value,187					}) => {188						let name = evaluate_field_name(context.clone(), name);189						new_members.insert(190							name,191							ObjMember {192								add: *plus,193								visibility: visibility.clone(),194								invoke: Rc::new(NoArgsBinding {195									context_creator: binding_context_creator.clone(),196									expr: value.clone(),197								}),198							},199						);200					}201					Member::Field(FieldMember {202						name,203						params: Some(params),204						value,205						..206					}) => {207						let name = evaluate_field_name(context.clone(), name);208						new_members.insert(209							name,210							ObjMember {211								add: false,212								visibility: Visibility::Hidden,213								invoke: Rc::new(ArgsBinding {214									expr: value.clone(),215									args: params.clone(),216									context_creator: binding_context_creator.clone(),217								}),218							},219						);220					}221					Member::BindStmt(_) => {}222					Member::AssertStmt(_) => {}223					_ => todo!(),224				}225			}226			ObjValue::new(None, Rc::new(new_members))227		}228		_ => todo!(),229	}230}231232pub fn evaluate(context: Context, expr: &Expr) -> Val {233	use Expr::*;234	match &*expr {235		Literal(t) => Val::Literal(t.clone()),236		Parened(e) => evaluate(context, e),237		Str(v) => Val::Str(v.clone()),238		Num(v) => Val::Num(*v),239		BinaryOp(v1, o, v2) => {240			evaluate_binary_op(&evaluate(context.clone(), v1), *o, &evaluate(context, v2))241		}242		Var(name) => {243			let variable = context.binding(&name);244			let val = variable.evaluate(None, None);245			val246		}247		Index(box value, box index) => {248			match (249				evaluate(context.clone(), value).unwrap_if_lazy(),250				evaluate(context.clone(), index),251			) {252				(Val::Literal(LiteralType::Super), _idx) => todo!(),253				(Val::Literal(LiteralType::This), idx) => match &idx.unwrap_if_lazy() {254					Val::Str(str) => context255						.this()256						.clone()257						.unwrap_or_else(|| panic!("'this' is not defined in current context"))258						.get_raw(str, None)259						.unwrap_or_else(|| {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					.get_raw(&s, None)270					.unwrap_or_else(|| panic!("{} not found in {:?}", s, v)),271				(v, i) => todo!("not implemented: {:?}[{:?}]", v, i.unwrap_if_lazy()),272			}273		}274		LocalExpr(bindings, returned) => {275			let mut new_bindings: HashMap<String, BoxedBinding> = HashMap::new();276			let future_context = Context::new_future();277278			let context_creator = Rc::new(ConstantContextCreator {279				context: future_context.clone(),280			});281			for (k, v) in bindings282				.iter()283				.map(move |b| evaluate_binding(b, context_creator.clone()))284			{285				new_bindings.insert(k, v);286			}287288			let context = context289				.extend(new_bindings, None, None, None)290				.into_future(future_context);291			evaluate(context, &*returned.clone())292		}293		Obj(body) => Val::Obj(evaluate_object(context, body.clone())),294		Apply(box value, ArgsDesc(args)) => {295			let value = evaluate(context.clone(), value).unwrap_if_lazy();296			match value {297				Val::Func(f) => f.evaluate(298					args.clone()299						.into_iter()300						.map(|a| {301							(302								a.0,303								Val::Lazy(BoxedLazyVal(Rc::new(PlainLazyVal {304									context: context.clone(),305									expr: *a.1,306								}))),307							)308						})309						.collect(),310				),311				_ => panic!("{:?} is not a function", value),312			}313		}314		Function(params, body) => evaluate_method(context, body, params.clone()),315		Error(e) => panic!("error: {}", evaluate(context, e)),316		IfElse {317			cond,318			cond_then,319			cond_else,320		} => match evaluate(context.clone(), &cond.0).unwrap_if_lazy() {321			Val::Literal(LiteralType::True) => evaluate(context.clone(), cond_then),322			Val::Literal(LiteralType::False) => match cond_else {323				Some(v) => evaluate(context.clone(), v),324				None => Val::Literal(LiteralType::False),325			},326			v => panic!("if condition evaluated to {:?} (boolean needed instead)", v),327		},328		_ => panic!("evaluation not implemented: {:?}", expr),329	}330}
after · crates/jsonnet-evaluator/src/evaluate.rs
1use crate::{2	binding, bool_val, context_creator, function_default, function_rhs, future_wrapper, lazy_val,3	Binding, Context, ContextCreator, FuncDesc, ObjMember, ObjValue, Val,4};5use closure::closure;6use jsonnet_parser::{7	ArgsDesc, BinaryOpType, BindSpec, Expr, FieldMember, LiteralType, Member, ObjBody, ParamsDesc,8	UnaryOpType, Visibility,9};10use std::{11	collections::{BTreeMap, HashMap},12	rc::Rc,13};1415pub fn evaluate_binding(b: &BindSpec, context_creator: ContextCreator) -> (String, Binding) {16	let b = b.clone();17	if let Some(args) = &b.params {18		let args = args.clone();19		(20			b.name.clone(),21			binding!(move |this, super_obj| Val::Lazy(lazy_val!(22				closure!(clone b, clone args, clone context_creator, || evaluate_method(23					context_creator.0(this.clone(), super_obj.clone()),24					&b.value,25					args.clone()26				))27			))),28		)29	} else {30		(31			b.name.clone(),32				binding!(move |this, super_obj| {33					println!("Evaluating binding");34					Val::Lazy(lazy_val!(35					closure!(clone context_creator, clone b, || evaluate(36						context_creator.0(this.clone(), super_obj.clone()),37						&b.value38					))39				))40			}),41		)42	}43}4445pub fn evaluate_method(ctx: Context, expr: &Expr, arg_spec: ParamsDesc) -> Val {46	Val::Func(FuncDesc {47		ctx,48		params: arg_spec,49		eval_rhs: function_rhs!(closure!(clone expr, |ctx| evaluate(ctx, &expr))),50		eval_default: function_default!(|ctx, default| evaluate(ctx, &default)),51	})52}5354pub fn evaluate_field_name(context: Context, field_name: &jsonnet_parser::FieldName) -> String {55	match field_name {56		jsonnet_parser::FieldName::Fixed(n) => n.clone(),57		jsonnet_parser::FieldName::Dyn(expr) => {58			let name = evaluate(context, expr).unwrap_if_lazy();59			match name {60				Val::Str(n) => n,61				_ => panic!(62					"dynamic field name can be only evaluated to 'string', got: {:?}",63					name64				),65			}66		}67	}68}6970pub fn evaluate_unary_op(op: UnaryOpType, b: &Val) -> Val {71	match (op, b) {72		(o, Val::Lazy(l)) => evaluate_unary_op(o, &l.0()),73		(UnaryOpType::Not, Val::Literal(LiteralType::True)) => Val::Literal(LiteralType::False),74		(UnaryOpType::Not, Val::Literal(LiteralType::False)) => Val::Literal(LiteralType::True),75		(op, o) => panic!("unary op not implemented: {:?} {:?}", op, o),76	}77}7879pub fn evaluate_binary_op(a: &Val, op: BinaryOpType, b: &Val) -> Val {80	match (a, op, b) {81		(Val::Lazy(a), o, b) => evaluate_binary_op(&a.0(), o, b),82		(a, o, Val::Lazy(b)) => evaluate_binary_op(a, o, &b.0()),8384		(Val::Str(v1), BinaryOpType::Add, Val::Str(v2)) => Val::Str(v1.to_owned() + &v2),85		(Val::Str(v1), BinaryOpType::Eq, Val::Str(v2)) => bool_val(v1 == v2),86		(Val::Str(v1), BinaryOpType::Ne, Val::Str(v2)) => bool_val(v1 != v2),8788		(Val::Str(v1), BinaryOpType::Add, Val::Num(v2)) => Val::Str(format!("{}{}", v1, v2)),89		(Val::Str(v1), BinaryOpType::Mul, Val::Num(v2)) => Val::Str(v1.repeat(*v2 as usize)),9091		(Val::Obj(v1), BinaryOpType::Add, Val::Obj(v2)) => Val::Obj(v2.with_super(v1.clone())),9293		(Val::Arr(a), BinaryOpType::Add, Val::Arr(b)) => Val::Arr([&a[..], &b[..]].concat()),9495		(Val::Num(v1), BinaryOpType::Mul, Val::Num(v2)) => Val::Num(v1 * v2),96		(Val::Num(v1), BinaryOpType::Div, Val::Num(v2)) => Val::Num(v1 / v2),97		(Val::Num(v1), BinaryOpType::Mod, Val::Num(v2)) => Val::Num(v1 % v2),9899		(Val::Num(v1), BinaryOpType::Add, Val::Num(v2)) => Val::Num(v1 + v2),100		(Val::Num(v1), BinaryOpType::Sub, Val::Num(v2)) => Val::Num(v1 - v2),101102		(Val::Num(v1), BinaryOpType::Lhs, Val::Num(v2)) => {103			Val::Num(((*v1 as i32) << (*v2 as i32)) as f64)104		}105		(Val::Num(v1), BinaryOpType::Rhs, Val::Num(v2)) => {106			Val::Num(((*v1 as i32) >> (*v2 as i32)) as f64)107		}108109		(Val::Num(v1), BinaryOpType::Lt, Val::Num(v2)) => bool_val(v1 < v2),110		(Val::Num(v1), BinaryOpType::Gt, Val::Num(v2)) => bool_val(v1 > v2),111		(Val::Num(v1), BinaryOpType::Lte, Val::Num(v2)) => bool_val(v1 <= v2),112		(Val::Num(v1), BinaryOpType::Gte, Val::Num(v2)) => bool_val(v1 >= v2),113114		(Val::Num(v1), BinaryOpType::Eq, Val::Num(v2)) => bool_val((v1 - v2).abs() < f64::EPSILON),115		(Val::Num(v1), BinaryOpType::Ne, Val::Num(v2)) => bool_val((v1 - v2).abs() > f64::EPSILON),116117		(Val::Num(v1), BinaryOpType::BitAnd, Val::Num(v2)) => {118			Val::Num(((*v1 as i32) & (*v2 as i32)) as f64)119		}120		(Val::Num(v1), BinaryOpType::BitOr, Val::Num(v2)) => {121			Val::Num(((*v1 as i32) | (*v2 as i32)) as f64)122		}123		(Val::Num(v1), BinaryOpType::BitXor, Val::Num(v2)) => {124			Val::Num(((*v1 as i32) ^ (*v2 as i32)) as f64)125		}126		_ => panic!("no rules for binary operation: {:?} {:?} {:?}", a, op, b),127	}128}129130future_wrapper!(HashMap<String, Binding>, FutureNewBindings);131future_wrapper!(ObjValue, FutureObjValue);132133// TODO: Asserts134pub fn evaluate_object(context: Context, object: ObjBody) -> ObjValue {135	match object {136		ObjBody::MemberList(members) => {137			let future_bindings = FutureNewBindings::new();138			let future_this = FutureObjValue::new();139			let context_creator = context_creator!(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(),144						context.clone().dollar().clone().or_else(||this.clone()),145						this,146						super_obj147					)148				})149			);150			let mut bindings: HashMap<String, Binding> = HashMap::new();151			for (n, b) in members152				.iter()153				.filter_map(|m| match m {154					Member::BindStmt(b) => Some(b.clone()),155					_ => None,156				})157				.map(|b| {158					evaluate_binding(&b, context_creator.clone())159				})160			{161				bindings.insert(n, b);162			}163			future_bindings.fill(bindings);164165			println!("Bindings filled");166			let mut new_members = BTreeMap::new();167			for member in members.into_iter() {168				match member {169					Member::Field(FieldMember {170						name,171						plus,172						params: None,173						visibility,174						value,175					}) => {176						let name = evaluate_field_name(context.clone(), &name);177						new_members.insert(178							name,179							ObjMember {180								add: plus,181								visibility: visibility.clone(),182								invoke: binding!(183									closure!(clone value, clone context_creator, clone future_this, |this, super_obj| {184										// FIXME: I should take "this" instead of "future_this" there?185										// TODO: Assert186										evaluate(187											context_creator.0(this, super_obj),188											&value,189										)190									})191								),192							},193						);194					}195					Member::Field(FieldMember {196						name,197						params: Some(params),198						value,199						..200					}) => {201						let name = evaluate_field_name(context.clone(), &name);202						new_members.insert(203							name,204							ObjMember {205								add: false,206								visibility: Visibility::Hidden,207								invoke: binding!(208									closure!(clone value, clone context_creator, clone future_this, |this, super_obj| {209										// FIXME: I should take "this" instead of "future_this" there?210										// TODO: Assert211										evaluate_method(212											context_creator.0(this, super_obj),213											&value.clone(),214											params.clone(),215										)216									})217								),218							},219						);220					}221					Member::BindStmt(_) => {}222					Member::AssertStmt(_) => {}223				}224			}225			future_this.fill(ObjValue::new(None, Rc::new(new_members)))226		}227		_ => todo!(),228	}229}230231pub fn evaluate(context: Context, expr: &Expr) -> Val {232	use Expr::*;233	match &*expr {234		Literal(LiteralType::This) => {235			println!("{:?}", context.this());236			Val::Obj(237				context238					.this()239					.clone()240					.unwrap_or_else(|| panic!("this not found")),241			)242		}243		Literal(LiteralType::Super) => Val::Obj(244			context245				.super_obj()246				.clone()247				.unwrap_or_else(|| panic!("super not found")),248		),249		Literal(t) => Val::Literal(t.clone()),250		Parened(e) => evaluate(context, e),251		Str(v) => Val::Str(v.clone()),252		Num(v) => Val::Num(*v),253		BinaryOp(v1, o, v2) => {254			evaluate_binary_op(&evaluate(context.clone(), v1), *o, &evaluate(context, v2))255		}256		UnaryOp(o, v) => evaluate_unary_op(*o, &evaluate(context, v)),257		Var(name) => {258			let variable = context.binding(&name);259			variable.0(None, None).unwrap_if_lazy()260		}261		Index(box value, box index) => {262			match (263				evaluate(context.clone(), value).unwrap_if_lazy(),264				evaluate(context, index),265			) {266				(Val::Obj(v), Val::Str(s)) => v267					.get(&s)268					.unwrap_or_else(|| panic!("{} not found in {:?}", s, v)),269				(Val::Arr(v), Val::Num(n)) => v270					.get(n as usize)271					.unwrap_or_else(|| panic!("out of bounds"))272					.clone(),273				(v, i) => todo!("not implemented: {:?}[{:?}]", v, i.unwrap_if_lazy()),274			}275		}276		LocalExpr(bindings, returned) => {277			let mut new_bindings: HashMap<String, Binding> = HashMap::new();278			let future_context = Context::new_future();279280			let context_creator = context_creator!(281				closure!(clone future_context, |_, _| future_context.clone().unwrap())282			);283284			for (k, v) in bindings285				.iter()286				.map(move |b| evaluate_binding(b, context_creator.clone()))287			{288				new_bindings.insert(k, v);289			}290291			let context = context292				.extend(new_bindings, None, None, None)293				.into_future(future_context);294			evaluate(context, &*returned.clone())295		}296		Obj(body) => Val::Obj(evaluate_object(context, body.clone())),297		Apply(box value, ArgsDesc(args)) => {298			let value = evaluate(context.clone(), value).unwrap_if_lazy();299			match value {300				Val::Func(f) => f.evaluate(301					args.clone()302						.into_iter()303						.map(|a| {304							(305								a.clone().0,306								Val::Lazy(lazy_val!(307									closure!(clone context, clone a, || evaluate(context.clone(), &a.clone().1))308								)),309							)310						})311						.collect(),312				),313				_ => panic!("{:?} is not a function", value),314			}315		}316		Function(params, body) => evaluate_method(context, body, params.clone()),317		Error(e) => panic!("error: {}", evaluate(context, e)),318		IfElse {319			cond,320			cond_then,321			cond_else,322		} => match evaluate(context.clone(), &cond.0).unwrap_if_lazy() {323			Val::Literal(LiteralType::True) => evaluate(context, cond_then),324			Val::Literal(LiteralType::False) => match cond_else {325				Some(v) => evaluate(context, v),326				None => Val::Literal(LiteralType::False),327			},328			v => panic!("if condition evaluated to {:?} (boolean needed instead)", v),329		},330		_ => panic!("evaluation not implemented: {:?}", expr),331	}332}
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,