git.delta.rocks / jrsonnet / refs/commits / 433adfa9b8ae

difftreelog

style run rustfmt

Лач2020-07-16parent: #c07d38d.patch.diff
in: master

4 files changed

modifiedcmds/jrsonnet/src/main.rsdiffbeforeafterboth
--- a/cmds/jrsonnet/src/main.rs
+++ b/cmds/jrsonnet/src/main.rs
@@ -134,19 +134,30 @@
 
 fn main_real(opts: Opts) {
 	let evaluator = jrsonnet_evaluator::EvaluationState::default();
-	evaluator.set_max_trace(opts.max_trace);
-	evaluator.set_max_stack(opts.max_stack);
-	evaluator.set_import_resolver(Box::new(jrsonnet_evaluator::FileImportResolver {
-		library_paths: opts.jpath.clone(),
-	}));
+	{
+		let mut settings = evaluator.settings_mut();
+		settings.max_stack = opts.max_stack;
+		settings.max_trace = opts.max_trace;
+		settings.import_resolver = Box::new(jrsonnet_evaluator::FileImportResolver {
+			library_paths: opts.jpath.clone(),
+		});
+	}
 	if !opts.no_stdlib {
 		evaluator.with_stdlib();
 	}
 	for ExtStr { name, value } in opts.ext_str.iter().cloned() {
-		evaluator.add_ext_var(name.into(), Val::Str(value.into()));
+		evaluator
+			.settings_mut()
+			.ext_vars
+			.insert(name.into(), Val::Str(value.into()));
 	}
 	for ExtStr { name, value } in opts.ext_code.iter().cloned() {
-		evaluator.add_ext_var(name.into(), evaluator.parse_evaluate_raw(&value).unwrap());
+		evaluator.settings_mut().ext_vars.insert(
+			name.clone().into(),
+			evaluator
+				.parse_evaluate_raw(PathBuf::from(format!("ext_code {}", name)).into(), &value)
+				.unwrap(),
+		);
 	}
 
 	let resolver = PathResolver::Relative(std::env::current_dir().unwrap());
@@ -184,8 +195,11 @@
 							.unwrap(),
 						);
 					}
-					evaluator.add_global("__tmp__tlf__".into(), Val::Func(f));
 					evaluator
+						.settings_mut()
+						.globals
+						.insert("__tmp__tlf__".into(), Val::Func(f));
+					evaluator
 						.evaluate_raw(el!(Expr::Apply(
 							el!(Expr::Var("__tmp__tlf__".into())),
 							ArgsDesc(desc_map.into_iter().map(|(k, v)| Arg(Some(k), v)).collect()),
modifiedcrates/jrsonnet-evaluator/src/function.rsdiffbeforeafterboth
--- a/crates/jrsonnet-evaluator/src/function.rs
+++ b/crates/jrsonnet-evaluator/src/function.rs
@@ -136,8 +136,8 @@
 
 #[test]
 fn test() -> Result<()> {
+	use crate::val::ValType;
 	use jrsonnet_parser::*;
-	use crate::val::ValType;
 	let state = crate::EvaluationState::default();
 	let evaluator = state.with_stdlib();
 	let ctx = evaluator.create_default_context()?;
modifiedcrates/jrsonnet-evaluator/src/lib.rsdiffbeforeafterboth
--- a/crates/jrsonnet-evaluator/src/lib.rs
+++ b/crates/jrsonnet-evaluator/src/lib.rs
@@ -7,6 +7,7 @@
 
 extern crate test;
 
+mod builtin;
 mod ctx;
 mod dynamic;
 mod error;
@@ -15,8 +16,8 @@
 mod import;
 mod map;
 mod obj;
-mod val;
 pub mod trace;
+mod val;
 
 pub use ctx::*;
 pub use dynamic::*;
@@ -26,9 +27,15 @@
 pub use import::*;
 use jrsonnet_parser::*;
 pub use obj::*;
-use std::{cell::{Ref, RefCell, RefMut}, collections::HashMap, fmt::Debug, path::PathBuf, rc::Rc};
+use std::{
+	cell::{Ref, RefCell, RefMut},
+	collections::HashMap,
+	fmt::Debug,
+	path::PathBuf,
+	rc::Rc,
+};
+use trace::{offset_to_location, CodeLocation};
 pub use val::*;
-use trace::{offset_to_location, CodeLocation};
 
 type BindableFn = dyn Fn(Option<ObjValue>, Option<ObjValue>) -> Result<LazyVal>;
 #[derive(Clone)]
@@ -319,7 +326,7 @@
 				drop(data);
 				return Err(self.error(Error::StackOverflow));
 			} else {
-				*stack_depth+=1;
+				*stack_depth += 1;
 			}
 		}
 		let result = f();
@@ -355,30 +362,28 @@
 #[cfg(test)]
 pub mod tests {
 	use super::Val;
-	use crate::{create_error, EvaluationState, primitive_equals};
+	use crate::{create_error, primitive_equals, EvaluationState};
 	use jrsonnet_parser::*;
 	use std::{path::PathBuf, rc::Rc};
 
 	#[test]
 	fn eval_state_stacktrace() {
 		let state = EvaluationState::default();
-		state.run_in_state(||{
+		state.run_in_state(|| {
 			state
-			.push(
-				&ExprLocation(Rc::new(PathBuf::from("test1.jsonnet")), 10, 20),
-				|| "outer".to_owned(),
-				|| {
-					state.push(
-						&ExprLocation(Rc::new(PathBuf::from("test2.jsonnet")), 30, 40),
-						|| "inner".to_owned(),
-						|| {
-							Err(create_error(crate::error::Error::RuntimeError("".into())))
-						},
-					)?;
-					Ok(())
-				},
-			)
-			.unwrap();
+				.push(
+					&ExprLocation(Rc::new(PathBuf::from("test1.jsonnet")), 10, 20),
+					|| "outer".to_owned(),
+					|| {
+						state.push(
+							&ExprLocation(Rc::new(PathBuf::from("test2.jsonnet")), 30, 40),
+							|| "inner".to_owned(),
+							|| Err(create_error(crate::error::Error::RuntimeError("".into()))),
+						)?;
+						Ok(())
+					},
+				)
+				.unwrap();
 		});
 	}
 
@@ -386,19 +391,23 @@
 	fn eval_state_standard() {
 		let state = EvaluationState::default();
 		state.with_stdlib();
-		assert!(
-			primitive_equals(
-				&state.parse_evaluate_raw(r#"std.assertEqual(std.base64("test"), "dGVzdA==")"#).unwrap(),
-				&Val::Bool(true),
-			).unwrap()
-		);
+		assert!(primitive_equals(
+			&state
+				.parse_evaluate_raw(
+					Rc::new(PathBuf::from("raw.jsonnet")),
+					r#"std.assertEqual(std.base64("test"), "dGVzdA==")"#
+				)
+				.unwrap(),
+			&Val::Bool(true),
+		)
+		.unwrap());
 	}
 
 	macro_rules! eval {
 		($str: expr) => {
 			EvaluationState::default()
 				.with_stdlib()
-				.parse_evaluate_raw($str)
+				.parse_evaluate_raw(Rc::new(PathBuf::from("raw.jsonnet")), $str)
 				.unwrap()
 		};
 	}
@@ -406,15 +415,15 @@
 		($str: expr) => {{
 			let evaluator = EvaluationState::default();
 			evaluator.with_stdlib();
-			evaluator.run_in_state(||{
+			evaluator.run_in_state(|| {
 				evaluator
-					.parse_evaluate_raw($str)
+					.parse_evaluate_raw(Rc::new(PathBuf::from("raw.jsonnet")), $str)
 					.unwrap()
 					.into_json(0)
 					.unwrap()
 					.replace("\n", "")
-			})
-		}}
+				})
+			}};
 	}
 
 	/// Asserts given code returns `true`
@@ -638,12 +647,11 @@
 
 	#[test]
 	fn string_is_string() {
-		assert!(
-			primitive_equals(
-				&eval!("local arr = 'hello'; (!std.isArray(arr)) && (!std.isString(arr))"),
-				&Val::Bool(false),
-			).unwrap()
-		);
+		assert!(primitive_equals(
+			&eval!("local arr = 'hello'; (!std.isArray(arr)) && (!std.isString(arr))"),
+			&Val::Bool(false),
+		)
+		.unwrap());
 	}
 
 	#[test]
@@ -746,8 +754,14 @@
 	}
 
 	#[test]
-	fn equality(){
-		println!("{:?}", jrsonnet_parser::parse("{ x: 1, y: 2 } == { x: 1, y: 2 }", &ParserSettings::default()));
+	fn equality() {
+		println!(
+			"{:?}",
+			jrsonnet_parser::parse(
+				"{ x: 1, y: 2 } == { x: 1, y: 2 }",
+				&ParserSettings::default()
+			)
+		);
 		assert_eval!("{ x: 1, y: 2 } == { x: 1, y: 2 }")
 	}
 }
modifiedcrates/jrsonnet-evaluator/src/val.rsdiffbeforeafterboth
after · crates/jrsonnet-evaluator/src/val.rs
1use crate::{2	create_error_result, evaluate,3	function::{parse_function_call, place_args},4	with_state, Context, Error, ObjValue, Result,5};6use jrsonnet_parser::{el, Arg, ArgsDesc, Expr, LocExpr, ParamsDesc};7use std::{8	cell::RefCell,9	fmt::{Debug, Display},10	rc::Rc,11};1213enum LazyValInternals {14	Computed(Val),15	Waiting(Box<dyn Fn() -> Result<Val>>),16}17#[derive(Clone)]18pub struct LazyVal(Rc<RefCell<LazyValInternals>>);19impl LazyVal {20	pub fn new(f: Box<dyn Fn() -> Result<Val>>) -> Self {21		LazyVal(Rc::new(RefCell::new(LazyValInternals::Waiting(f))))22	}23	pub fn new_resolved(val: Val) -> Self {24		LazyVal(Rc::new(RefCell::new(LazyValInternals::Computed(val))))25	}26	pub fn evaluate(&self) -> Result<Val> {27		let new_value = match &*self.0.borrow() {28			LazyValInternals::Computed(v) => return Ok(v.clone()),29			LazyValInternals::Waiting(f) => f()?,30		};31		*self.0.borrow_mut() = LazyValInternals::Computed(new_value.clone());32		Ok(new_value)33	}34}3536#[macro_export]37macro_rules! lazy_val {38	($f: expr) => {39		$crate::LazyVal::new(Box::new($f))40	};41}42#[macro_export]43macro_rules! resolved_lazy_val {44	($f: expr) => {45		$crate::LazyVal::new_resolved($f)46	};47}48impl Debug for LazyVal {49	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {50		write!(f, "Lazy")51	}52}53impl PartialEq for LazyVal {54	fn eq(&self, other: &Self) -> bool {55		Rc::ptr_eq(&self.0, &other.0)56	}57}5859#[derive(Debug, PartialEq)]60pub struct FuncDesc {61	pub name: Rc<str>,62	pub ctx: Context,63	pub params: ParamsDesc,64	pub body: LocExpr,65}66impl FuncDesc {67	/// This function is always inlined to make tailstrict work68	pub fn evaluate(&self, call_ctx: Context, args: &ArgsDesc, tailstrict: bool) -> Result<Val> {69		let ctx = parse_function_call(70			call_ctx,71			Some(self.ctx.clone()),72			&self.params,73			args,74			tailstrict,75		)?;76		evaluate(ctx, &self.body)77	}7879	pub fn evaluate_values(&self, call_ctx: Context, args: &[Val]) -> Result<Val> {80		let ctx = place_args(call_ctx, Some(self.ctx.clone()), &self.params, args)?;81		evaluate(ctx, &self.body)82	}83}8485#[derive(Debug, Clone, Copy, PartialEq)]86pub enum ValType {87	Bool,88	Null,89	Str,90	Num,91	Arr,92	Obj,93	Func,94}95impl ValType {96	pub fn name(&self) -> &'static str {97		use ValType::*;98		match self {99			Bool => "boolean",100			Null => "null",101			Str => "string",102			Num => "number",103			Arr => "array",104			Obj => "object",105			Func => "function",106		}107	}108}109impl Display for ValType {110	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {111		write!(f, "{}", self.name())112	}113}114115#[derive(Debug, Clone)]116pub enum Val {117	Bool(bool),118	Null,119	Str(Rc<str>),120	Num(f64),121	Lazy(LazyVal),122	Arr(Rc<Vec<Val>>),123	Obj(ObjValue),124	Func(Rc<FuncDesc>),125126	// Library functions implemented in native127	Intristic(Rc<str>, Rc<str>),128}129macro_rules! matches_unwrap {130	($e: expr, $p: pat, $r: expr) => {131		match $e {132			$p => $r,133			_ => panic!("no match"),134			}135	};136}137impl Val {138	/// Creates Val::Num after checking for overflow. As numbers are f64, we can just check for finity139	pub fn new_checked_num(num: f64) -> Result<Val> {140		if num.is_finite() {141			Ok(Val::Num(num))142		} else {143			create_error_result(Error::RuntimeError("overflow".into()))144		}145	}146147	pub fn assert_type(&self, context: &'static str, val_type: ValType) -> Result<()> {148		let this_type = self.value_type()?;149		if this_type != val_type {150			create_error_result(Error::TypeMismatch(context, vec![val_type], this_type))151		} else {152			Ok(())153		}154	}155	pub fn try_cast_bool(self, context: &'static str) -> Result<bool> {156		self.assert_type(context, ValType::Bool)?;157		Ok(matches_unwrap!(self.unwrap_if_lazy()?, Val::Bool(v), v))158	}159	pub fn try_cast_str(self, context: &'static str) -> Result<Rc<str>> {160		self.assert_type(context, ValType::Str)?;161		Ok(matches_unwrap!(self.unwrap_if_lazy()?, Val::Str(v), v))162	}163	pub fn try_cast_num(self, context: &'static str) -> Result<f64> {164		self.assert_type(context, ValType::Num)?;165		Ok(matches_unwrap!(self.unwrap_if_lazy()?, Val::Num(v), v))166	}167	pub fn unwrap_if_lazy(&self) -> Result<Self> {168		Ok(if let Val::Lazy(v) = self {169			v.evaluate()?.unwrap_if_lazy()?170		} else {171			self.clone()172		})173	}174	pub fn value_type(&self) -> Result<ValType> {175		Ok(match self {176			Val::Str(..) => ValType::Str,177			Val::Num(..) => ValType::Num,178			Val::Arr(..) => ValType::Arr,179			Val::Obj(..) => ValType::Obj,180			Val::Func(..) => ValType::Func,181			Val::Bool(_) => ValType::Bool,182			Val::Null => ValType::Null,183			Val::Intristic(_, _) => ValType::Func,184			Val::Lazy(_) => self.clone().unwrap_if_lazy()?.value_type()?,185		})186	}187	#[cfg(feature = "faster")]188	pub fn into_json(self, padding: usize) -> Result<Rc<str>> {189		manifest_json_ex(&self, &" ".repeat(padding)).map(|s| s.into())190	}191	#[cfg(not(feature = "faster"))]192	pub fn into_json(self, padding: usize) -> Result<Rc<str>> {193		with_state(|s| {194			let ctx = s195				.create_default_context()?196				.with_var("__tmp__to_json__".into(), self)?;197			Ok(evaluate(198				ctx,199				&el!(Expr::Apply(200					el!(Expr::Index(201						el!(Expr::Var("std".into())),202						el!(Expr::Str("manifestJsonEx".into()))203					)),204					ArgsDesc(vec![205						Arg(None, el!(Expr::Var("__tmp__to_json__".into()))),206						Arg(None, el!(Expr::Str(" ".repeat(padding).into())))207					]),208					false209				)),210			)?211			.try_cast_str("to json")?)212		})213	}214	pub fn into_yaml(self, padding: usize) -> Result<Rc<str>> {215		with_state(|s| {216			let ctx = s217				.create_default_context()?218				.with_var("__tmp__to_json__".into(), self)?;219			Ok(evaluate(220				ctx,221				&el!(Expr::Apply(222					el!(Expr::Index(223						el!(Expr::Var("std".into())),224						el!(Expr::Str("manifestYamlDoc".into()))225					)),226					ArgsDesc(vec![227						Arg(None, el!(Expr::Var("__tmp__to_json__".into()))),228						Arg(None, el!(Expr::Str(" ".repeat(padding).into())))229					]),230					false231				)),232			)?233			.try_cast_str("to json")?)234		})235	}236}237238fn is_function_like(val: &Val) -> bool {239	matches!(val, Val::Func(_) | Val::Intristic(_, _))240}241242/// Implements std.primitiveEquals builtin243pub fn primitive_equals(val_a: &Val, val_b: &Val) -> Result<bool> {244	Ok(match (val_a.unwrap_if_lazy()?, val_b.unwrap_if_lazy()?) {245		(Val::Bool(a), Val::Bool(b)) => a == b,246		(Val::Null, Val::Null) => true,247		(Val::Str(a), Val::Str(b)) => a == b,248		(Val::Num(a), Val::Num(b)) => (a - b).abs() <= f64::EPSILON,249		(Val::Arr(_), Val::Arr(_)) => create_error_result(Error::RuntimeError(250			"primitiveEquals operates on primitive types, got array".into(),251		))?,252		(Val::Obj(_), Val::Obj(_)) => create_error_result(Error::RuntimeError(253			"primitiveEquals operates on primitive types, got object".into(),254		))?,255		(a, b) if is_function_like(&a) && is_function_like(&b) => create_error_result(256			Error::RuntimeError("cannot test equality of functions".into()),257		)?,258		(_, _) => false,259	})260}261262/// Native implementation of std.equals263pub fn equals(val_a: &Val, val_b: &Val) -> Result<bool> {264	let val_a = val_a.unwrap_if_lazy()?;265	let val_b = val_b.unwrap_if_lazy()?;266267	if val_a.value_type()? != val_b.value_type()? {268		return Ok(false);269	}270	match (val_a, val_b) {271		// Cant test for ptr equality, because all fields needs to be evaluated272		(Val::Arr(a), Val::Arr(b)) => {273			if a.len() != b.len() {274				return Ok(false);275			}276			for (a, b) in a.iter().zip(b.iter()) {277				if !equals(&a.unwrap_if_lazy()?, &b.unwrap_if_lazy()?)? {278					return Ok(false);279				}280			}281			Ok(true)282		}283		(Val::Obj(a), Val::Obj(b)) => {284			let fields = a.visible_fields();285			if fields != b.visible_fields() {286				return Ok(false);287			}288			for field in fields {289				if !equals(&a.get(field.clone())?.unwrap(), &b.get(field)?.unwrap())? {290					return Ok(false);291				}292			}293			Ok(true)294		}295		(a, b) => Ok(primitive_equals(&a, &b)?),296	}297}298299pub fn manifest_json_ex(val: &Val, padding: &str) -> Result<String> {300	let mut out = String::new();301	manifest_json_ex_buf(val, &mut out, padding, &mut String::new())?;302	Ok(out)303}304fn manifest_json_ex_buf(305	val: &Val,306	buf: &mut String,307	padding: &str,308	cur_padding: &mut String,309) -> Result<()> {310	use std::fmt::Write;311	match val.unwrap_if_lazy()? {312		Val::Bool(v) => {313			if v {314				buf.push_str("true");315			} else {316				buf.push_str("false");317			}318		}319		Val::Null => buf.push_str("null"),320		Val::Str(s) => buf.push_str(&escape_string_json(&s)),321		Val::Num(n) => write!(buf, "{}", n).unwrap(),322		Val::Arr(items) => {323			buf.push_str("[\n");324			if !items.is_empty() {325				let old_len = cur_padding.len();326				cur_padding.push_str(padding);327				for (i, item) in items.iter().enumerate() {328					if i != 0 {329						buf.push_str(",\n")330					}331					buf.push_str(cur_padding);332					manifest_json_ex_buf(item, buf, padding, cur_padding)?;333				}334				cur_padding.truncate(old_len);335			}336			buf.push('\n');337			buf.push_str(cur_padding);338			buf.push(']');339		}340		Val::Obj(obj) => {341			buf.push_str("{\n");342			let fields = obj.visible_fields();343			if !fields.is_empty() {344				let old_len = cur_padding.len();345				cur_padding.push_str(padding);346				for (i, field) in fields.into_iter().enumerate() {347					if i != 0 {348						buf.push_str(",\n")349					}350					buf.push_str(cur_padding);351					buf.push_str(&escape_string_json(&field));352					buf.push_str(": ");353					manifest_json_ex_buf(&obj.get(field)?.unwrap(), buf, padding, cur_padding)?;354				}355				cur_padding.truncate(old_len);356			}357			buf.push('\n');358			buf.push_str(cur_padding);359			buf.push('}');360		}361		Val::Func(_) | Val::Intristic(_, _) => {362			create_error_result(Error::RuntimeError("tried to manifest function".into()))?363		}364		Val::Lazy(_) => unreachable!(),365	};366	Ok(())367}368pub fn escape_string_json(s: &str) -> String {369	use std::fmt::Write;370	let mut out = String::new();371	out.push('"');372	for c in s.chars() {373		match c {374			'"' => out.push_str("\\\""),375			'\\' => out.push_str("\\\\"),376			'\u{0008}' => out.push_str("\\b"),377			'\u{000c}' => out.push_str("\\f"),378			'\n' => out.push_str("\\n"),379			'\r' => out.push_str("\\r"),380			'\t' => out.push_str("\\t"),381			c if c < 32 as char || (c >= 127 as char && c <= 159 as char) => {382				write!(out, "\\u{:04x}", c as u32).unwrap()383			}384			c => out.push(c),385		}386	}387	out.push('"');388	out389}390391#[test]392fn json_test() {393	assert_eq!(escape_string_json("\u{001f}"), "\"\\u001f\"")394}