git.delta.rocks / jrsonnet / refs/commits / 11818aa7b735

difftreelog

feat(evaluator) use LocExpr

Лач2020-06-01parent: #c4387b3.patch.diff
in: master

2 files changed

modifiedcrates/jsonnet-evaluator/src/evaluate.rsdiffbeforeafterboth
--- a/crates/jsonnet-evaluator/src/evaluate.rs
+++ b/crates/jsonnet-evaluator/src/evaluate.rs
@@ -5,8 +5,8 @@
 };
 use closure::closure;
 use jsonnet_parser::{
-	ArgsDesc, BinaryOpType, BindSpec, Expr, FieldMember, LiteralType, Member, ObjBody, ParamsDesc,
-	UnaryOpType, Visibility,
+	ArgsDesc, BinaryOpType, BindSpec, Expr, FieldMember, LiteralType, LocExpr, Member, ObjBody,
+	ParamsDesc, UnaryOpType, Visibility,
 };
 use std::{
 	collections::{BTreeMap, HashMap},
@@ -40,7 +40,7 @@
 	}
 }
 
-pub fn evaluate_method(ctx: Context, expr: &Expr, arg_spec: ParamsDesc) -> Val {
+pub fn evaluate_method(ctx: Context, expr: &LocExpr, arg_spec: ParamsDesc) -> Val {
 	Val::Func(FuncDesc {
 		ctx,
 		params: arg_spec,
@@ -236,9 +236,10 @@
 	}
 }
 
-pub fn evaluate(context: Context, expr: &Expr) -> Val {
+pub fn evaluate(context: Context, expr: &LocExpr) -> Val {
 	use Expr::*;
-	match &*expr {
+	let LocExpr(expr, _location) = expr;
+	match &**expr {
 		Literal(LiteralType::This) => Val::Obj(
 			context
 				.this()
@@ -260,7 +261,7 @@
 		}
 		UnaryOp(o, v) => evaluate_unary_op(*o, &evaluate(context, v)),
 		Var(name) => Val::Lazy(context.binding(&name)).unwrap_if_lazy(),
-		Index(box value, box index) => {
+		Index(value, index) => {
 			match (
 				evaluate(context.clone(), value).unwrap_if_lazy(),
 				evaluate(context.clone(), index),
@@ -284,7 +285,7 @@
 					.unwrap_or_else(|| panic!("out of bounds"))
 					.clone(),
 				(Val::Str(s), Val::Num(n)) => {
-					Val::Str(s.chars().skip(n as usize - 1).take(1).collect())
+					Val::Str(s.chars().skip(n as usize).take(1).collect())
 				}
 				(v, i) => todo!("not implemented: {:?}[{:?}]", v, i.unwrap_if_lazy()),
 			}
@@ -307,10 +308,10 @@
 			let context = context
 				.extend(new_bindings, None, None, None)
 				.into_future(future_context);
-			evaluate(context, &*returned.clone())
+			evaluate(context, &returned.clone())
 		}
 		Obj(body) => Val::Obj(evaluate_object(context, body.clone())),
-		Apply(box value, ArgsDesc(args)) => {
+		Apply(value, ArgsDesc(args)) => {
 			let value = evaluate(context.clone(), value).unwrap_if_lazy();
 			match value {
 				// TODO: Capture context of application
modifiedcrates/jsonnet-evaluator/src/lib.rsdiffbeforeafterboth
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!(24	LazyBinding,25	lazy_binding,26	dyn Fn(Option<ObjValue>, Option<ObjValue>) -> LazyVal27);28rc_fn_helper!(FunctionRhs, function_rhs, dyn Fn(Context) -> Val);29rc_fn_helper!(30	FunctionDefault,31	function_default,32	dyn Fn(Context, LocExpr) -> Val33);3435#[cfg(test)]36pub mod tests {37	use super::{evaluate, Context, Val};38	use jsonnet_parser::*;3940	macro_rules! eval {41		($str: expr) => {42			evaluate(Context::new(), &parse($str, &ParserSettings {43				loc_data: false,44				file_name: "test.jsonnet".to_owned(),45			}).unwrap())46		};47	}4849	macro_rules! eval_stdlib {50		($str: expr) => {{51			let std = "local std = ".to_owned() + jsonnet_stdlib::STDLIB_STR + ";";52			evaluate(Context::new(), &parse(&(std + $str), &ParserSettings {53				loc_data: false,54				file_name: "test.jsonnet".to_owned(),55			}).unwrap())56			}};57	}5859	macro_rules! assert_eval {60		($str: expr) => {61			assert_eq!(62				evaluate(Context::new(), &parse($str, &ParserSettings {63					loc_data: false,64					file_name: "test.jsonnet".to_owned(),65				}).unwrap()),66				Val::Literal(LiteralType::True)67				)68		};69	}70	macro_rules! assert_json {71		($str: expr, $out: expr) => {72			assert_eq!(73				format!("{}", evaluate(Context::new(), &parse($str, &ParserSettings {74					loc_data: false,75					file_name: "test.jsonnet".to_owned(),76				}).unwrap())),77				$out78				)79		};80	}81	macro_rules! assert_json_stdlib {82		($str: expr, $out: expr) => {83			assert_eq!(format!("{}", eval_stdlib!($str)), $out)84		};85	}86	macro_rules! assert_eval_neg {87		($str: expr) => {88			assert_eq!(89				evaluate(Context::new(), &parse($str, &ParserSettings {90					loc_data: false,91					file_name: "test.jsonnet".to_owned(),92				}).unwrap()),93				Val::Literal(LiteralType::False)94				)95		};96	}9798	/// Sanity checking, before trusting to another tests99	#[test]100	fn equality_operator() {101		assert_eval!("2 == 2");102		assert_eval_neg!("2 != 2");103		assert_eval!("2 != 3");104		assert_eval_neg!("2 == 3");105		assert_eval!("'Hello' == 'Hello'");106		assert_eval_neg!("'Hello' != 'Hello'");107		assert_eval!("'Hello' != 'World'");108		assert_eval_neg!("'Hello' == 'World'");109	}110111	#[test]112	fn math_evaluation() {113		assert_eval!("2 + 2 * 2 == 6");114		assert_eval!("3 + (2 + 2 * 2) == 9");115	}116117	#[test]118	fn string_concat() {119		assert_eval!("'Hello' + 'World' == 'HelloWorld'");120		assert_eval!("'Hello' * 3 == 'HelloHelloHello'");121		assert_eval!("'Hello' + 'World' * 3 == 'HelloWorldWorldWorld'");122	}123124	#[test]125	fn local() {126		assert_eval!("local a = 2; local b = 3; a + b == 5");127		assert_eval!("local a = 1, b = a + 1; a + b == 3");128		assert_eval!("local a = 1; local a = 2; a == 2");129	}130131	#[test]132	fn object_lazyness() {133		assert_json!("local a = {a:error 'test'}; {}", r#"{}"#);134	}135136	#[test]137	fn object_inheritance() {138		assert_json!("{a: self.b} + {b:3}", r#"{"a":3,"b":3}"#);139	}140141	#[test]142	fn test_object() {143		assert_json!("{a:2}", r#"{"a":2}"#);144		assert_json!("{a:2+2}", r#"{"a":4}"#);145		assert_json!("{a:2}+{b:2}", r#"{"a":2,"b":2}"#);146		assert_json!("{b:3}+{b:2}", r#"{"b":2}"#);147		assert_json!("{b:3}+{b+:2}", r#"{"b":5}"#);148		assert_json!("local test='a'; {[test]:2}", r#"{"a":2}"#);149		assert_json!(150			r#"151				{152					name: "Alice",153					welcome: "Hello " + self.name + "!",154				}155			"#,156			r#"{"name":"Alice","welcome":"Hello Alice!"}"#157		);158		assert_json!(159			r#"160				{161					name: "Alice",162					welcome: "Hello " + self.name + "!",163				} + {164					name: "Bob"165				}166			"#,167			r#"{"name":"Bob","welcome":"Hello Bob!"}"#168		);169	}170171	#[test]172	fn functions() {173		assert_json!(r#"local a = function(b, c = 2) b + c; a(2)"#, "4");174		assert_json!(175			r#"local a = function(b, c = "Dear") b + c + d, d = "World"; a("Hello")"#,176			r#""HelloDearWorld""#177		);178	}179180	#[test]181	fn local_methods() {182		assert_json!(r#"local a(b, c = 2) = b + c; a(2)"#, "4");183		assert_json!(184			r#"local a(b, c = "Dear") = b + c + d, d = "World"; a("Hello")"#,185			r#""HelloDearWorld""#186		);187	}188189	#[test]190	fn object_locals() {191		assert_json!(r#"{local a = 3, b: a}"#, r#"{"b":3}"#);192		assert_json!(r#"{local a = 3, local c = a, b: c}"#, r#"{"b":3}"#);193		assert_json!(194			r#"{local a = function (b) {[b]:4}, test: a("test")}"#,195			r#"{"test":{"test":4}}"#196		);197	}198199	#[test]200	fn direct_self() {201		println!(202			"{:#?}",203			eval!(204				r#"205					{206						local me = self,207						a: 3,208						b(): me.a,209					}210				"#211			)212		);213	}214215	#[test]216	fn indirect_self() {217		// `self` assigned to `me` was lost when being218		// referenced from field219		eval_stdlib!(220			r#"{221				local me = self,222				a: 3,223				b: me.a,224			}.b"#225		);226	}227228	// We can't trust other tests (And official jsonnet testsuite), if assert is not working correctly229	#[test]230	fn std_assert_ok() {231		eval_stdlib!("std.assertEqual(4.5 << 2, 16)");232	}233234	#[test]235	#[should_panic]236	fn std_assert_failure() {237		eval_stdlib!("std.assertEqual(4.5 << 2, 15)");238	}239240	#[test]241	fn string_is_string() {242		assert_eq!(243			eval_stdlib!("local arr = 'hello'; (!std.isArray(arr)) && (!std.isString(arr))"),244			Val::Literal(LiteralType::False)245		);246	}247248	#[test]249	fn base64_works() {250		assert_json_stdlib!(r#"std.base64("test")"#, r#""dGVzdA==""#);251	}252253	#[test]254	fn utf8_chars() {255		assert_json_stdlib!(256			r#"local c="😎";{c:std.codepoint(c),l:std.length(c)}"#,257			r#"{"c":128526,"l":1}"#258		)259	}260}