git.delta.rocks / jrsonnet / refs/commits / 2e6febe0ffcd

difftreelog

fix(evaluator) indirect_self bug

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

4 files changed

modifiedCargo.lockdiffbeforeafterboth
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1,9 +1,16 @@
 # This file is automatically @generated by Cargo.
 # It is not intended for manual editing.
 [[package]]
+name = "closure"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d6173fd61b610d15a7566dd7b7620775627441c4ab9dac8906e17cb93a24b782"
+
+[[package]]
 name = "jsonnet-evaluator"
 version = "0.1.0"
 dependencies = [
+ "closure",
  "jsonnet-parser",
  "jsonnet-stdlib",
 ]
modifiedcrates/jsonnet-evaluator/src/ctx.rsdiffbeforeafterboth
--- a/crates/jsonnet-evaluator/src/ctx.rs
+++ b/crates/jsonnet-evaluator/src/ctx.rs
@@ -74,7 +74,6 @@
 		new_this: Option<ObjValue>,
 		new_super_obj: Option<ObjValue>,
 	) -> Context {
-		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());
modifiedcrates/jsonnet-evaluator/src/evaluate.rsdiffbeforeafterboth
--- a/crates/jsonnet-evaluator/src/evaluate.rs
+++ b/crates/jsonnet-evaluator/src/evaluate.rs
@@ -29,9 +29,8 @@
 	} else {
 		(
 			b.name.clone(),
-				binding!(move |this, super_obj| {
-					println!("Evaluating binding");
-					Val::Lazy(lazy_val!(
+			binding!(move |this, super_obj| {
+				Val::Lazy(lazy_val!(
 					closure!(clone context_creator, clone b, || evaluate(
 						context_creator.0(this.clone(), super_obj.clone()),
 						&b.value
@@ -137,12 +136,11 @@
 			let future_bindings = FutureNewBindings::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");
+				closure!(clone context, clone future_bindings, clone future_this, |this: Option<ObjValue>, super_obj: Option<ObjValue>| {
 					context.clone().extend(
 						future_bindings.clone().unwrap(),
 						context.clone().dollar().clone().or_else(||this.clone()),
-						this,
+						Some(future_this.clone().unwrap()),
 						super_obj
 					)
 				})
@@ -154,15 +152,12 @@
 					Member::BindStmt(b) => Some(b.clone()),
 					_ => None,
 				})
-				.map(|b| {
-					evaluate_binding(&b, context_creator.clone())
-				})
+				.map(|b| evaluate_binding(&b, context_creator.clone()))
 			{
 				bindings.insert(n, b);
 			}
 			future_bindings.fill(bindings);
 
-			println!("Bindings filled");
 			let mut new_members = BTreeMap::new();
 			for member in members.into_iter() {
 				match member {
@@ -180,8 +175,7 @@
 								add: plus,
 								visibility: visibility.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?
+									closure!(clone value, clone context_creator, |this, super_obj| {
 										// TODO: Assert
 										evaluate(
 											context_creator.0(this, super_obj),
@@ -205,8 +199,7 @@
 								add: false,
 								visibility: Visibility::Hidden,
 								invoke: binding!(
-									closure!(clone value, clone context_creator, clone future_this, |this, super_obj| {
-										// FIXME: I should take "this" instead of "future_this" there?
+									closure!(clone value, clone context_creator, |this, super_obj| {
 										// TODO: Assert
 										evaluate_method(
 											context_creator.0(this, super_obj),
@@ -231,15 +224,12 @@
 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::This) => Val::Obj(
+			context
+				.this()
+				.clone()
+				.unwrap_or_else(|| panic!("this not found")),
+		),
 		Literal(LiteralType::Super) => Val::Obj(
 			context
 				.super_obj()
modifiedcrates/jsonnet-evaluator/src/lib.rsdiffbeforeafterboth
before · crates/jsonnet-evaluator/src/lib.rs
1#![feature(box_syntax, box_patterns)]2#![feature(type_alias_impl_trait)]3#![feature(debug_non_exhaustive)]4#![allow(macro_expanded_macro_exports_accessed_by_absolute_paths)]5mod ctx;6mod dynamic;7mod evaluate;8mod obj;9mod val;1011pub use ctx::*;12pub use dynamic::*;13pub use evaluate::*;14use jsonnet_parser::*;15pub use obj::*;16pub use val::*;1718rc_fn_helper!(19	Binding,20	binding,21	dyn Fn(Option<ObjValue>, Option<ObjValue>) -> Val22);23rc_fn_helper!(FunctionRhs, function_rhs, dyn Fn(Context) -> Val);24rc_fn_helper!(25	FunctionDefault,26	function_default,27	dyn Fn(Context, Expr) -> Val28);2930#[cfg(test)]31pub mod tests {32	use super::{evaluate, Context, Val};33	use jsonnet_parser::*;3435	macro_rules! eval {36		($str: expr) => {37			evaluate(Context::new(), &parse($str).unwrap())38		};39	}4041	macro_rules! eval_stdlib {42		($str: expr) => {43			let std = "local std = ".to_owned() + jsonnet_stdlib::STDLIB_STR + ";";44			evaluate(Context::new(), &parse(&(std + $str)).unwrap())45		};46	}4748	macro_rules! assert_eval {49		($str: expr) => {50			assert_eq!(51				evaluate(Context::new(), &parse($str).unwrap()),52				Val::Literal(LiteralType::True)53				)54		};55	}56	macro_rules! assert_json {57		($str: expr, $out: expr) => {58			assert_eq!(59				format!("{}", evaluate(Context::new(), &parse($str).unwrap())),60				$out61				)62		};63	}64	macro_rules! assert_eval_neg {65		($str: expr) => {66			assert_eq!(67				evaluate(Context::new(), &parse($str).unwrap()),68				Val::Literal(LiteralType::False)69				)70		};71	}7273	/// Sanity checking, before trusting to another tests74	#[test]75	fn equality_operator() {76		assert_eval!("2 == 2");77		assert_eval_neg!("2 != 2");78		assert_eval!("2 != 3");79		assert_eval_neg!("2 == 3");80		assert_eval!("'Hello' == 'Hello'");81		assert_eval_neg!("'Hello' != 'Hello'");82		assert_eval!("'Hello' != 'World'");83		assert_eval_neg!("'Hello' == 'World'");84	}8586	#[test]87	fn math_evaluation() {88		assert_eval!("2 + 2 * 2 == 6");89		assert_eval!("3 + (2 + 2 * 2) == 9");90	}9192	#[test]93	fn string_concat() {94		assert_eval!("'Hello' + 'World' == 'HelloWorld'");95		assert_eval!("'Hello' * 3 == 'HelloHelloHello'");96		assert_eval!("'Hello' + 'World' * 3 == 'HelloWorldWorldWorld'");97	}9899	#[test]100	fn local() {101		assert_eval!("local a = 2; local b = 3; a + b == 5");102		assert_eval!("local a = 1, b = a + 1; a + b == 3");103		assert_eval!("local a = 1; local a = 2; a == 2");104	}105106	#[test]107	fn object_lazyness() {108		assert_json!("local a = {a:error 'test'}; {}", r#"{}"#);109	}110111	#[test]112	fn object_inheritance() {113		assert_json!("{a:self.b} + {b:3}", r#"{"a":3,"b":3}"#);114	}115116	#[test]117	fn test_object() {118		assert_json!("{a:2}", r#"{"a":2}"#);119		assert_json!("{a:2+2}", r#"{"a":4}"#);120		assert_json!("{a:2}+{b:2}", r#"{"a":2,"b":2}"#);121		assert_json!("{b:3}+{b:2}", r#"{"b":2}"#);122		assert_json!("{b:3}+{b+:2}", r#"{"b":5}"#);123		assert_json!("local test='a'; {[test]:2}", r#"{"a":2}"#);124		assert_json!(125			r#"126				{127					name: "Alice",128					welcome: "Hello " + self.name + "!",129				}130			"#,131			r#"{"name":"Alice","welcome":"Hello Alice!"}"#132		);133		assert_json!(134			r#"135				{136					name: "Alice",137					welcome: "Hello " + self.name + "!",138				} + {139					name: "Bob"140				}141			"#,142			r#"{"name":"Bob","welcome":"Hello Bob!"}"#143		);144	}145146	#[test]147	fn functions() {148		assert_json!(r#"local a = function(b, c = 2) b + c; a(2)"#, "4");149		assert_json!(150			r#"local a = function(b, c = "Dear") b + c + d, d = "World"; a("Hello")"#,151			r#""HelloDearWorld""#152		);153	}154155	#[test]156	fn local_methods() {157		assert_json!(r#"local a(b, c = 2) = b + c; a(2)"#, "4");158		assert_json!(159			r#"local a(b, c = "Dear") = b + c + d, d = "World"; a("Hello")"#,160			r#""HelloDearWorld""#161		);162	}163164	#[test]165	fn object_locals() {166		assert_json!(r#"{local a = 3, b: a}"#, r#"{"b":3}"#);167		assert_json!(r#"{local a = 3, local c = a, b: c}"#, r#"{"b":3}"#);168		assert_json!(169			r#"{local a = function (b) {[b]:4}, test: a("test")}"#,170			r#"{"test":{"test":4}}"#171		);172	}173174	#[test]175	fn direct_self() {176		println!(177			"{:#?}",178			eval!(179				r#"180					{181						local me = self,182						a: 3,183						b(): me.a,184					}185				"#186			)187		);188	}189190	#[test]191	fn indirect_self() {192		// `self` assigned to `me` was lost when being193		// referenced from field194		eval_stdlib!(195			r#"{196				local me = std.trace("test", self),197				b: me,198			}.b"#199		);200	}201202	// We can't trust other tests (And official jsonnet testsuite), if assert is not working correctly203	#[test]204	fn std_assert_ok() {205		eval_stdlib!("std.assertEqual(4.5 << 2, 16)");206	}207208	#[test]209	#[should_panic]210	fn std_assert_failure() {211		eval_stdlib!("std.assertEqual(4.5 << 2, 15)");212	}213214	#[test]215	fn base64_works() {216		eval_stdlib!(r#"std.base64("test")"#);217	}218}
after · crates/jsonnet-evaluator/src/lib.rs
1#![feature(box_syntax, box_patterns)]2#![feature(type_alias_impl_trait)]3#![feature(debug_non_exhaustive)]4#![allow(macro_expanded_macro_exports_accessed_by_absolute_paths)]5mod ctx;6mod dynamic;7mod evaluate;8mod obj;9mod val;1011pub use ctx::*;12pub use dynamic::*;13pub use evaluate::*;14use jsonnet_parser::*;15pub use obj::*;16pub use val::*;1718rc_fn_helper!(19	Binding,20	binding,21	dyn Fn(Option<ObjValue>, Option<ObjValue>) -> Val22);23rc_fn_helper!(FunctionRhs, function_rhs, dyn Fn(Context) -> Val);24rc_fn_helper!(25	FunctionDefault,26	function_default,27	dyn Fn(Context, Expr) -> Val28);2930#[cfg(test)]31pub mod tests {32	use super::{evaluate, Context, Val};33	use jsonnet_parser::*;3435	macro_rules! eval {36		($str: expr) => {37			evaluate(Context::new(), &parse($str).unwrap())38		};39	}4041	macro_rules! eval_stdlib {42		($str: expr) => {43			let std = "local std = ".to_owned() + jsonnet_stdlib::STDLIB_STR + ";";44			evaluate(Context::new(), &parse(&(std + $str)).unwrap())45		};46	}4748	macro_rules! assert_eval {49		($str: expr) => {50			assert_eq!(51				evaluate(Context::new(), &parse($str).unwrap()),52				Val::Literal(LiteralType::True)53				)54		};55	}56	macro_rules! assert_json {57		($str: expr, $out: expr) => {58			assert_eq!(59				format!("{}", evaluate(Context::new(), &parse($str).unwrap())),60				$out61				)62		};63	}64	macro_rules! assert_eval_neg {65		($str: expr) => {66			assert_eq!(67				evaluate(Context::new(), &parse($str).unwrap()),68				Val::Literal(LiteralType::False)69				)70		};71	}7273	/// Sanity checking, before trusting to another tests74	#[test]75	fn equality_operator() {76		assert_eval!("2 == 2");77		assert_eval_neg!("2 != 2");78		assert_eval!("2 != 3");79		assert_eval_neg!("2 == 3");80		assert_eval!("'Hello' == 'Hello'");81		assert_eval_neg!("'Hello' != 'Hello'");82		assert_eval!("'Hello' != 'World'");83		assert_eval_neg!("'Hello' == 'World'");84	}8586	#[test]87	fn math_evaluation() {88		assert_eval!("2 + 2 * 2 == 6");89		assert_eval!("3 + (2 + 2 * 2) == 9");90	}9192	#[test]93	fn string_concat() {94		assert_eval!("'Hello' + 'World' == 'HelloWorld'");95		assert_eval!("'Hello' * 3 == 'HelloHelloHello'");96		assert_eval!("'Hello' + 'World' * 3 == 'HelloWorldWorldWorld'");97	}9899	#[test]100	fn local() {101		assert_eval!("local a = 2; local b = 3; a + b == 5");102		assert_eval!("local a = 1, b = a + 1; a + b == 3");103		assert_eval!("local a = 1; local a = 2; a == 2");104	}105106	#[test]107	fn object_lazyness() {108		assert_json!("local a = {a:error 'test'}; {}", r#"{}"#);109	}110111	#[test]112	fn object_inheritance() {113		assert_json!("{a:self.b} + {b:3}", r#"{"a":3,"b":3}"#);114	}115116	#[test]117	fn test_object() {118		assert_json!("{a:2}", r#"{"a":2}"#);119		assert_json!("{a:2+2}", r#"{"a":4}"#);120		assert_json!("{a:2}+{b:2}", r#"{"a":2,"b":2}"#);121		assert_json!("{b:3}+{b:2}", r#"{"b":2}"#);122		assert_json!("{b:3}+{b+:2}", r#"{"b":5}"#);123		assert_json!("local test='a'; {[test]:2}", r#"{"a":2}"#);124		assert_json!(125			r#"126				{127					name: "Alice",128					welcome: "Hello " + self.name + "!",129				}130			"#,131			r#"{"name":"Alice","welcome":"Hello Alice!"}"#132		);133		assert_json!(134			r#"135				{136					name: "Alice",137					welcome: "Hello " + self.name + "!",138				} + {139					name: "Bob"140				}141			"#,142			r#"{"name":"Bob","welcome":"Hello Bob!"}"#143		);144	}145146	#[test]147	fn functions() {148		assert_json!(r#"local a = function(b, c = 2) b + c; a(2)"#, "4");149		assert_json!(150			r#"local a = function(b, c = "Dear") b + c + d, d = "World"; a("Hello")"#,151			r#""HelloDearWorld""#152		);153	}154155	#[test]156	fn local_methods() {157		assert_json!(r#"local a(b, c = 2) = b + c; a(2)"#, "4");158		assert_json!(159			r#"local a(b, c = "Dear") = b + c + d, d = "World"; a("Hello")"#,160			r#""HelloDearWorld""#161		);162	}163164	#[test]165	fn object_locals() {166		assert_json!(r#"{local a = 3, b: a}"#, r#"{"b":3}"#);167		assert_json!(r#"{local a = 3, local c = a, b: c}"#, r#"{"b":3}"#);168		assert_json!(169			r#"{local a = function (b) {[b]:4}, test: a("test")}"#,170			r#"{"test":{"test":4}}"#171		);172	}173174	#[test]175	fn direct_self() {176		println!(177			"{:#?}",178			eval!(179				r#"180					{181						local me = self,182						a: 3,183						b(): me.a,184					}185				"#186			)187		);188	}189190	#[test]191	fn indirect_self() {192		// `self` assigned to `me` was lost when being193		// referenced from field194		eval_stdlib!(195			r#"{196				local me = self,197				b: me,198			}.b"#199		);200	}201202	// We can't trust other tests (And official jsonnet testsuite), if assert is not working correctly203	#[test]204	fn std_assert_ok() {205		eval_stdlib!("std.assertEqual(4.5 << 2, 16)");206	}207208	#[test]209	#[should_panic]210	fn std_assert_failure() {211		eval_stdlib!("std.assertEqual(4.5 << 2, 15)");212	}213214	#[test]215	fn base64_works() {216		eval_stdlib!(r#"std.base64("test")"#);217	}218}