git.delta.rocks / jrsonnet / refs/commits / e614efaa7567

difftreelog

refactor(evaluator) use PathBuf for file paths

Лач2020-06-06parent: #30ce98e.patch.diff
in: master

4 files changed

modifiedcrates/jsonnet-evaluator/build.rsdiffbeforeafterboth
--- a/crates/jsonnet-evaluator/build.rs
+++ b/crates/jsonnet-evaluator/build.rs
@@ -1,13 +1,18 @@
 use bincode::serialize;
 use jsonnet_parser::{parse, ParserSettings};
 use jsonnet_stdlib::STDLIB_STR;
-use std::{env, fs::File, io::Write, path::Path};
+use std::{
+	env,
+	fs::File,
+	io::Write,
+	path::{Path, PathBuf},
+};
 
 fn main() {
 	let parsed = parse(
 		STDLIB_STR,
 		&ParserSettings {
-			file_name: "std.jsonnet".to_owned(),
+			file_name: PathBuf::from("std.jsonnet"),
 			loc_data: true,
 		},
 	)
modifiedcrates/jsonnet-evaluator/src/error.rsdiffbeforeafterboth
8 NoSuchField(String),8 NoSuchField(String),
99
10 RuntimeError(String),10 RuntimeError(String),
11 StackOverflow,
11}12}
1213
13#[derive(Clone, Debug)]14#[derive(Clone, Debug)]
modifiedcrates/jsonnet-evaluator/src/evaluate.rsdiffbeforeafterboth
--- a/crates/jsonnet-evaluator/src/evaluate.rs
+++ b/crates/jsonnet-evaluator/src/evaluate.rs
@@ -31,12 +31,14 @@
 		(
 			b.name.clone(),
 			lazy_binding!(move |this, super_obj| {
-				Ok(lazy_val!(
-					closure!(clone context_creator, clone b, || evaluate(
-						context_creator.0(this.clone(), super_obj.clone())?,
-						&b.value
-					))
-				))
+				Ok(lazy_val!(closure!(clone context_creator, clone b, ||
+					push(b.value.clone(), "thunk".to_owned(), ||{
+						evaluate(
+							context_creator.0(this.clone(), super_obj.clone())?,
+							&b.value
+						)
+					})
+				)))
 			}),
 		)
 	}
@@ -326,7 +328,9 @@
 		Num(v) => Val::Num(*v),
 		BinaryOp(v1, o, v2) => evaluate_binary_op_special(context, &v1, *o, &v2)?,
 		UnaryOp(o, v) => evaluate_unary_op(*o, &evaluate(context, v)?)?,
-		Var(name) => Val::Lazy(context.binding(&name)).unwrap_if_lazy()?,
+		Var(name) => push(locexpr, "var".to_owned(), || {
+			Val::Lazy(context.binding(&name)).unwrap_if_lazy()
+		})?,
 		Index(LocExpr(v, _), index) if matches!(&**v, Expr::Literal(LiteralType::Super)) => {
 			let name = evaluate(context.clone(), index)?.try_cast_str("object index")?;
 			context
@@ -412,6 +416,7 @@
 						match evaluate(context, expr)? {
 							Val::Str(n) => Val::Num(n.chars().count() as f64),
 							Val::Arr(i) => Val::Num(i.len() as f64),
+							Val::Obj(o) => Val::Num(o.fields().len() as f64),
 							v => panic!("can't get length of {:?}", v),
 						}
 					}
modifiedcrates/jsonnet-evaluator/src/lib.rsdiffbeforeafterboth
--- a/crates/jsonnet-evaluator/src/lib.rs
+++ b/crates/jsonnet-evaluator/src/lib.rs
@@ -16,7 +16,7 @@
 pub use evaluate::*;
 use jsonnet_parser::*;
 pub use obj::*;
-use std::{cell::RefCell, collections::HashMap, rc::Rc};
+use std::{cell::RefCell, collections::HashMap, path::PathBuf, rc::Rc};
 pub use val::*;
 
 rc_fn_helper!(
@@ -43,7 +43,7 @@
 	stack: RefCell<Vec<StackTraceElement>>,
 	/// Contains file source codes and evaluated results for imports and pretty
 	/// printing stacktraces
-	files: RefCell<HashMap<String, FileData>>,
+	files: RefCell<HashMap<PathBuf, FileData>>,
 	globals: RefCell<HashMap<String, Val>>,
 }
 
@@ -56,7 +56,7 @@
 pub(crate) fn create_error<T>(err: Error) -> Result<T> {
 	with_state(|s| s.error(err))
 }
-pub(crate) fn push<T>(e: LocExpr, comment: String, f: impl FnOnce() -> T) -> T {
+pub(crate) fn push<T>(e: LocExpr, comment: String, f: impl FnOnce() -> Result<T>) -> Result<T> {
 	with_state(|s| s.push(e, comment, f))
 }
 
@@ -65,7 +65,7 @@
 impl EvaluationState {
 	pub fn add_file(
 		&self,
-		name: String,
+		name: PathBuf,
 		code: String,
 	) -> std::result::Result<(), Box<dyn std::error::Error>> {
 		self.0.files.borrow_mut().insert(
@@ -87,7 +87,7 @@
 	}
 	pub fn add_parsed_file(
 		&self,
-		name: String,
+		name: PathBuf,
 		code: String,
 		parsed: LocExpr,
 	) -> std::result::Result<(), Box<dyn std::error::Error>> {
@@ -98,14 +98,13 @@
 
 		Ok(())
 	}
-	pub fn get_source(&self, name: &str) -> String {
+	pub fn get_source(&self, name: &PathBuf) -> Option<String> {
 		let ro_map = self.0.files.borrow();
-		let value = ro_map
+		ro_map
 			.get(name)
-			.unwrap_or_else(|| panic!("file not added: {:?}", name));
-		value.0.clone()
+			.map(|value|value.0.clone())
 	}
-	pub fn evaluate_file(&self, name: &str) -> Result<Val> {
+	pub fn evaluate_file(&self, name: &PathBuf) -> Result<Val> {
 		self.begin_state();
 		let expr: LocExpr = {
 			let ro_map = self.0.files.borrow();
@@ -135,7 +134,7 @@
 		let parsed = parse(
 			&code,
 			&ParserSettings {
-				file_name: "raw.jsonnet".to_owned(),
+				file_name: PathBuf::from("raw.jsonnet"),
 				loc_data: true,
 			},
 		);
@@ -154,17 +153,17 @@
 		use jsonnet_stdlib::STDLIB_STR;
 		if cfg!(feature = "serialized-stdlib") {
 			self.add_parsed_file(
-				"std.jsonnet".to_owned(),
+				PathBuf::from("std.jsonnet"),
 				STDLIB_STR.to_owned(),
 				bincode::deserialize(include_bytes!(concat!(env!("OUT_DIR"), "/stdlib.bincode")))
 					.expect("deserialize stdlib"),
 			)
 			.unwrap();
 		} else {
-			self.add_file("std.jsonnet".to_owned(), STDLIB_STR.to_owned())
+			self.add_file(PathBuf::from("std.jsonnet"), STDLIB_STR.to_owned())
 				.unwrap();
 		}
-		let val = self.evaluate_file("std.jsonnet").unwrap();
+		let val = self.evaluate_file(&PathBuf::from("std.jsonnet")).unwrap();
 		self.add_global("std".to_owned(), val);
 		self.end_state();
 	}
@@ -183,11 +182,16 @@
 		Context::new().extend(new_bindings, None, None, None)
 	}
 
-	pub fn push<T>(&self, e: LocExpr, comment: String, f: impl FnOnce() -> T) -> T {
-		self.0
-			.stack
-			.borrow_mut()
-			.push(StackTraceElement(e, comment));
+	pub fn push<T>(&self, e: LocExpr, comment: String, f: impl FnOnce() -> Result<T>) -> Result<T> {
+		{
+			let mut stack = self.0.stack.borrow_mut();
+			if stack.len() > 5000 {
+				drop(stack);
+				return self.error(Error::StackOverflow);
+			} else {
+				stack.push(StackTraceElement(e, comment));
+			}
+		}
 		let result = f();
 		self.0.stack.borrow_mut().pop();
 		result
@@ -217,21 +221,36 @@
 	use super::Val;
 	use crate::EvaluationState;
 	use jsonnet_parser::*;
+	use std::path::PathBuf;
 
 	#[test]
 	fn eval_state_stacktrace() {
 		let state = EvaluationState::default();
-		state.push(
-			loc_expr!(Expr::Num(0.0), true, ("test1.jsonnet".to_owned(), 10, 20)),
-			"outer".to_owned(),
-			|| {
-				state.push(
-					loc_expr!(Expr::Num(0.0), true, ("test2.jsonnet".to_owned(), 30, 40)),
-					"inner".to_owned(),
-					|| state.print_stack_trace(),
-				);
-			},
-		);
+		state
+			.push(
+				loc_expr!(
+					Expr::Num(0.0),
+					true,
+					(PathBuf::from("test1.jsonnet"), 10, 20)
+				),
+				"outer".to_owned(),
+				|| {
+					state.push(
+						loc_expr!(
+							Expr::Num(0.0),
+							true,
+							(PathBuf::from("test2.jsonnet"), 30, 40)
+						),
+						"inner".to_owned(),
+						|| {
+							state.print_stack_trace();
+							Ok(())
+						},
+					)?;
+					Ok(())
+				},
+			)
+			.unwrap();
 	}
 
 	#[test]
@@ -240,7 +259,7 @@
 		state.add_stdlib();
 		assert_eq!(
 			state
-				.parse_evaluate_raw(r#"std.assertEqual(std.base64("test"), "dGVzdA==w")"#)
+				.parse_evaluate_raw(r#"std.assertEqual(std.base64("test"), "dGVzdA==")"#)
 				.unwrap(),
 			Val::Bool(true)
 		);