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

difftreelog

Merge remote-tracking branch 'origin/master' into gcmodule

Yaroslav Bolyukin2022-01-04parents: #fa16ccf #e1fb5e1.patch.diff
in: master

7 files changed

modifiedcrates/jrsonnet-evaluator/src/builtin/manifest.rsdiffbeforeafterboth
--- a/crates/jrsonnet-evaluator/src/builtin/manifest.rs
+++ b/crates/jrsonnet-evaluator/src/builtin/manifest.rs
@@ -19,6 +19,8 @@
 pub struct ManifestJsonOptions<'s> {
 	pub padding: &'s str,
 	pub mtype: ManifestType,
+	pub newline: &'s str,
+	pub key_val_sep: &'s str,
 }
 
 pub fn manifest_json_ex(val: &Val, options: &ManifestJsonOptions<'_>) -> Result<String> {
@@ -49,7 +51,7 @@
 			buf.push('[');
 			if !items.is_empty() {
 				if mtype != ManifestType::ToString && mtype != ManifestType::Minify {
-					buf.push('\n');
+					buf.push_str(options.newline);
 				}
 
 				let old_len = cur_padding.len();
@@ -60,7 +62,7 @@
 						if mtype == ManifestType::ToString {
 							buf.push(' ');
 						} else if mtype != ManifestType::Minify {
-							buf.push('\n');
+							buf.push_str(options.newline);
 						}
 					}
 					buf.push_str(cur_padding);
@@ -69,7 +71,7 @@
 				cur_padding.truncate(old_len);
 
 				if mtype != ManifestType::ToString && mtype != ManifestType::Minify {
-					buf.push('\n');
+					buf.push_str(options.newline);
 					buf.push_str(cur_padding);
 				}
 			} else if mtype == ManifestType::Std {
@@ -86,7 +88,7 @@
 			let fields = obj.fields();
 			if !fields.is_empty() {
 				if mtype != ManifestType::ToString && mtype != ManifestType::Minify {
-					buf.push('\n');
+					buf.push_str(options.newline);
 				}
 
 				let old_len = cur_padding.len();
@@ -97,12 +99,12 @@
 						if mtype == ManifestType::ToString {
 							buf.push(' ');
 						} else if mtype != ManifestType::Minify {
-							buf.push('\n');
+							buf.push_str(options.newline);
 						}
 					}
 					buf.push_str(cur_padding);
 					escape_string_json_buf(&field, buf);
-					buf.push_str(": ");
+					buf.push_str(options.key_val_sep);
 					push_description_frame(
 						|| format!("field <{}> manifestification", field.clone()),
 						|| {
@@ -115,7 +117,7 @@
 				cur_padding.truncate(old_len);
 
 				if mtype != ManifestType::ToString && mtype != ManifestType::Minify {
-					buf.push('\n');
+					buf.push_str(options.newline);
 					buf.push_str(cur_padding);
 				}
 			} else if mtype == ManifestType::Std {
modifiedcrates/jrsonnet-evaluator/src/builtin/mod.rsdiffbeforeafterboth
--- a/crates/jrsonnet-evaluator/src/builtin/mod.rs
+++ b/crates/jrsonnet-evaluator/src/builtin/mod.rs
@@ -1,6 +1,5 @@
 use crate::function::StaticBuiltin;
-use crate::typed::{Any, Null, PositiveF64, VecVal, M1};
-use crate::{self as jrsonnet_evaluator, Either, ObjValue};
+use crate::typed::{Any, PositiveF64, VecVal, M1};
 use crate::{
 	builtin::manifest::{manifest_yaml_ex, ManifestYamlOptions},
 	equals,
@@ -10,6 +9,7 @@
 	typed::{Either2, Either4},
 	with_state, ArrValue, Context, FuncVal, IndexableVal, Val,
 };
+use crate::{Either, ObjValue};
 use format::{format_arr, format_obj};
 use gcmodule::Cc;
 use jrsonnet_interner::IStr;
@@ -145,7 +145,7 @@
 fn builtin_length(x: Either![IStr, VecVal, ObjValue, Cc<FuncVal>]) -> Result<usize> {
 	use Either4::*;
 	Ok(match x {
-		A(x) => x.len(),
+		A(x) => x.chars().count(),
 		B(x) => x.0.len(),
 		C(x) => x
 			.fields_visibility()
@@ -566,12 +566,21 @@
 }
 
 #[jrsonnet_macros::builtin]
-fn builtin_manifest_json_ex(value: Any, indent: IStr) -> Result<String> {
+fn builtin_manifest_json_ex(
+	value: Any,
+	indent: IStr,
+	newline: Option<IStr>,
+	key_val_sep: Option<IStr>,
+) -> Result<String> {
+	let newline = newline.as_deref().unwrap_or("\n");
+	let key_val_sep = key_val_sep.as_deref().unwrap_or(": ");
 	manifest_json_ex(
 		&value.0,
 		&ManifestJsonOptions {
 			padding: &indent,
 			mtype: ManifestType::Std,
+			newline,
+			key_val_sep,
 		},
 	)
 }
modifiedcrates/jrsonnet-evaluator/src/lib.rsdiffbeforeafterboth
--- a/crates/jrsonnet-evaluator/src/lib.rs
+++ b/crates/jrsonnet-evaluator/src/lib.rs
@@ -5,6 +5,9 @@
 	clippy::ptr_arg
 )]
 
+// For jrsonnet-macros
+extern crate self as jrsonnet_evaluator;
+
 mod builtin;
 mod ctx;
 mod dynamic;
@@ -976,6 +979,14 @@
 	}
 
 	#[test]
+	fn json_minified() {
+		assert_json!(
+			r#"std.manifestJsonMinified({a:3, b:4, c:6})"#,
+			r#""{\"a\":3,\"b\":4,\"c\":6}""#
+		);
+	}
+
+	#[test]
 	fn parse_json() {
 		assert_json!(
 			r#"std.parseJson('{"a": -1,"b": 1,"c": 3.141,"d": []}')"#,
modifiedcrates/jrsonnet-evaluator/src/typed/conversions.rsdiffbeforeafterboth
--- a/crates/jrsonnet-evaluator/src/typed/conversions.rs
+++ b/crates/jrsonnet-evaluator/src/typed/conversions.rs
@@ -19,7 +19,7 @@
 	($($ty:ty)*) => {$(
 		impl Typed for $ty {
 			const TYPE: &'static ComplexValType =
-				&ComplexValType::BoundedNumber(Some(<$ty>::MIN as f64), Some(<$ty>::MAX as f64));
+				&ComplexValType::BoundedNumber(Some(Self::MIN as f64), Some(Self::MAX as f64));
 		}
 		impl TryFrom<Val> for $ty {
 			type Error = LocError;
modifiedcrates/jrsonnet-evaluator/src/val.rsdiffbeforeafterboth
--- a/crates/jrsonnet-evaluator/src/val.rs
+++ b/crates/jrsonnet-evaluator/src/val.rs
@@ -400,6 +400,8 @@
 				&ManifestJsonOptions {
 					padding: "",
 					mtype: ManifestType::ToString,
+					newline: "\n",
+					key_val_sep: ": ",
 				},
 			)?
 			.into(),
@@ -484,6 +486,8 @@
 				} else {
 					ManifestType::Manifest
 				},
+				newline: "\n",
+				key_val_sep: ": ",
 			},
 		)
 		.map(|s| s.into())
@@ -496,6 +500,8 @@
 			&ManifestJsonOptions {
 				padding: &" ".repeat(padding),
 				mtype: ManifestType::Std,
+				newline: "\n",
+				key_val_sep: ": ",
 			},
 		)
 		.map(|s| s.into())
modifiedcrates/jrsonnet-macros/src/lib.rsdiffbeforeafterboth
before · crates/jrsonnet-macros/src/lib.rs
1use quote::quote;2use syn::{3	parse_macro_input, FnArg, GenericArgument, ItemFn, Pat, PatType, Path, PathArguments, Type,4};56fn is_location_arg(t: &PatType) -> bool {7	t.attrs.iter().any(|a| a.path.is_ident("location"))8}910trait RetainHad<T> {11	fn retain_had(&mut self, h: impl FnMut(&T) -> bool) -> bool;12}13impl<T> RetainHad<T> for Vec<T> {14	fn retain_had(&mut self, h: impl FnMut(&T) -> bool) -> bool {15		let before = self.len();16		self.retain(h);17		let after = self.len();18		before != after19	}20}2122fn extract_type_from_option(ty: &Type) -> Option<&Type> {23	fn path_is_option(path: &Path) -> bool {24		path.leading_colon.is_none()25			&& path.segments.len() == 126			&& path.segments.iter().next().unwrap().ident == "Option"27	}2829	match ty {30		Type::Path(typepath) if typepath.qself.is_none() && path_is_option(&typepath.path) => {31			// Get the first segment of the path (there is only one, in fact: "Option"):32			let type_params = &typepath.path.segments.iter().next().unwrap().arguments;33			// It should have only on angle-bracketed param ("<String>"):34			let generic_arg = match type_params {35				PathArguments::AngleBracketed(params) => params.args.iter().next().unwrap(),36				_ => panic!("missing option generic"),37			};38			// This argument must be a type:39			match generic_arg {40				GenericArgument::Type(ty) => Some(ty),41				_ => panic!("option generic should be a type"),42			}43		}44		_ => None,45	}46}4748#[proc_macro_attribute]49pub fn builtin(50	_attr: proc_macro::TokenStream,51	item: proc_macro::TokenStream,52) -> proc_macro::TokenStream {53	// syn::ItemFn::parse(input)54	let mut fun: ItemFn = parse_macro_input!(item);5556	let result = match fun.sig.output {57		syn::ReturnType::Default => panic!("builtin should return something"),58		syn::ReturnType::Type(_, ref ty) => ty.clone(),59	};6061	let params = fun62		.sig63		.inputs64		.iter()65		.map(|i| match i {66			FnArg::Receiver(_) => unreachable!(),67			FnArg::Typed(t) => t,68		})69		.filter(|a| !is_location_arg(a))70		.map(|t| {71			let ident = match &t.pat as &Pat {72				Pat::Ident(i) => i.ident.to_string(),73				_ => panic!("only idents supported yet"),74			};75			let optional = extract_type_from_option(&t.ty).is_some();76			quote! {77				BuiltinParam {78					name: std::borrow::Cow::Borrowed(#ident),79					has_default: #optional,80				}81			}82		})83		.collect::<Vec<_>>();8485	let args = fun86		.sig87		.inputs88		.iter_mut()89		.map(|i| match i {90			FnArg::Receiver(_) => unreachable!(),91			FnArg::Typed(t) => t,92		})93		.map(|t| {94			let is_location = t.attrs.retain_had(|a| !a.path.is_ident("location"));95			if is_location {96				quote! {{97					loc98				}}99			} else {100				let ident = match &t.pat as &Pat {101					Pat::Ident(i) => i.ident.to_string(),102					_ => panic!("only idents supported yet"),103				};104				let ty = &t.ty;105				if let Some(opt_ty) = extract_type_from_option(&t.ty) {106					quote! {{107						if let Some(value) = parsed.get(#ident) {108							Some(jrsonnet_evaluator::push_description_frame(109								|| format!("argument <{}> evaluation", #ident),110								|| <#opt_ty>::try_from(value.evaluate()?),111							)?)112						} else {113							None114						}115					}}116				} else {117					quote! {{118						let value = parsed.get(#ident).unwrap();119120						jrsonnet_evaluator::push_description_frame(121							|| format!("argument <{}> evaluation", #ident),122							|| <#ty>::try_from(value.evaluate()?),123						)?124					}}125				}126			}127		})128		.collect::<Vec<_>>();129130	let name = &fun.sig.ident;131	let vis = &fun.vis;132	(quote! {133		#fun134		#[doc(hidden)]135		#[allow(non_camel_case_types)]136		#[derive(Clone, Copy, gcmodule::Trace)]137		#vis struct #name {}138		const _: () = {139			use jrsonnet_evaluator::function::{Builtin, StaticBuiltin, BuiltinParam, ArgsLike};140			const PARAMS: &'static [BuiltinParam] = &[141				#(#params),*142			];143144			impl #name {145				pub const INST: &'static dyn StaticBuiltin = &#name {};146			}147			impl StaticBuiltin for #name {}148			impl Builtin for #name149			where150				Self: 'static151			{152				fn name(&self) -> &str {153					stringify!(#name)154				}155				fn params(&self) -> &[BuiltinParam] {156					PARAMS157				}158				fn call(&self, context: Context, loc: Option<&ExprLocation>, args: &dyn ArgsLike) -> Result<Val> {159					let parsed = jrsonnet_evaluator::function::parse_builtin_call(context, &PARAMS, args, false)?;160161					let result: #result = #name(#(#args),*);162					let result = result?;163					result.try_into()164				}165			}166		};167	})168	.into()169}
after · crates/jrsonnet-macros/src/lib.rs
1use quote::quote;2use syn::{3	parse_macro_input, FnArg, GenericArgument, ItemFn, Pat, PatType, Path, PathArguments, Type,4};56fn is_location_arg(t: &PatType) -> bool {7	t.attrs.iter().any(|a| a.path.is_ident("location"))8}910trait RetainHad<T> {11	fn retain_had(&mut self, h: impl FnMut(&T) -> bool) -> bool;12}13impl<T> RetainHad<T> for Vec<T> {14	fn retain_had(&mut self, h: impl FnMut(&T) -> bool) -> bool {15		let before = self.len();16		self.retain(h);17		let after = self.len();18		before != after19	}20}2122fn extract_type_from_option(ty: &Type) -> Option<&Type> {23	fn path_is_option(path: &Path) -> bool {24		path.leading_colon.is_none()25			&& path.segments.len() == 126			&& path.segments.iter().next().unwrap().ident == "Option"27	}2829	match ty {30		Type::Path(typepath) if typepath.qself.is_none() && path_is_option(&typepath.path) => {31			// Get the first segment of the path (there is only one, in fact: "Option"):32			let type_params = &typepath.path.segments.iter().next().unwrap().arguments;33			// It should have only on angle-bracketed param ("<String>"):34			let generic_arg = match type_params {35				PathArguments::AngleBracketed(params) => params.args.iter().next().unwrap(),36				_ => panic!("missing option generic"),37			};38			// This argument must be a type:39			match generic_arg {40				GenericArgument::Type(ty) => Some(ty),41				_ => panic!("option generic should be a type"),42			}43		}44		_ => None,45	}46}4748#[proc_macro_attribute]49pub fn builtin(50	_attr: proc_macro::TokenStream,51	item: proc_macro::TokenStream,52) -> proc_macro::TokenStream {53	// syn::ItemFn::parse(input)54	let mut fun: ItemFn = parse_macro_input!(item);5556	let result = match fun.sig.output {57		syn::ReturnType::Default => panic!("builtin should return something"),58		syn::ReturnType::Type(_, ref ty) => ty.clone(),59	};6061	let params = fun62		.sig63		.inputs64		.iter()65		.map(|i| match i {66			FnArg::Receiver(_) => unreachable!(),67			FnArg::Typed(t) => t,68		})69		.filter(|a| !is_location_arg(a))70		.map(|t| {71			let ident = match &t.pat as &Pat {72				Pat::Ident(i) => i.ident.to_string(),73				_ => panic!("only idents supported yet"),74			};75			let optional = extract_type_from_option(&t.ty).is_some();76			quote! {77				BuiltinParam {78					name: std::borrow::Cow::Borrowed(#ident),79					has_default: #optional,80				}81			}82		})83		.collect::<Vec<_>>();8485	let args = fun86		.sig87		.inputs88		.iter_mut()89		.map(|i| match i {90			FnArg::Receiver(_) => unreachable!(),91			FnArg::Typed(t) => t,92		})93		.map(|t| {94			let is_location = t.attrs.retain_had(|a| !a.path.is_ident("location"));95			if is_location {96				quote! {{97					loc98				}}99			} else {100				let ident = match &t.pat as &Pat {101					Pat::Ident(i) => i.ident.to_string(),102					_ => panic!("only idents supported yet"),103				};104				let ty = &t.ty;105				if let Some(opt_ty) = extract_type_from_option(&t.ty) {106					quote! {{107						if let Some(value) = parsed.get(#ident) {108							Some(::jrsonnet_evaluator::push_description_frame(109								|| format!("argument <{}> evaluation", #ident),110								|| <#opt_ty>::try_from(value.evaluate()?),111							)?)112						} else {113							None114						}115					}}116				} else {117					quote! {{118						let value = parsed.get(#ident).unwrap();119120						::jrsonnet_evaluator::push_description_frame(121							|| format!("argument <{}> evaluation", #ident),122							|| <#ty>::try_from(value.evaluate()?),123						)?124					}}125				}126			}127		})128		.collect::<Vec<_>>();129130	let name = &fun.sig.ident;131	let vis = &fun.vis;132	(quote! {133		#fun134		#[doc(hidden)]135		#[allow(non_camel_case_types)]136		#[derive(Clone, Copy, gcmodule::Trace)]137		#vis struct #name {}138		const _: () = {139			use ::jrsonnet_evaluator::function::{Builtin, StaticBuiltin, BuiltinParam, ArgsLike};140			const PARAMS: &'static [BuiltinParam] = &[141				#(#params),*142			];143144			impl #name {145				pub const INST: &'static dyn StaticBuiltin = &#name {};146			}147			impl StaticBuiltin for #name {}148			impl Builtin for #name149			where150				Self: 'static151			{152				fn name(&self) -> &str {153					stringify!(#name)154				}155				fn params(&self) -> &[BuiltinParam] {156					PARAMS157				}158				fn call(&self, context: Context, loc: Option<&ExprLocation>, args: &dyn ArgsLike) -> Result<Val> {159					let parsed = ::jrsonnet_evaluator::function::parse_builtin_call(context, &PARAMS, args, false)?;160161					let result: #result = #name(#(#args),*);162					let result = result?;163					result.try_into()164				}165			}166		};167	})168	.into()169}
modifiedcrates/jrsonnet-stdlib/src/std.jsonnetdiffbeforeafterboth
--- a/crates/jrsonnet-stdlib/src/std.jsonnet
+++ b/crates/jrsonnet-stdlib/src/std.jsonnet
@@ -373,6 +373,8 @@
 
   manifestJson(value):: std.manifestJsonEx(value, '    ') tailstrict,
 
+  manifestJsonMinified(value):: std.manifestJsonEx(value, '', '', ':'),
+
   manifestJsonEx:: $intrinsic(manifestJsonEx),
 
   manifestYamlDoc:: $intrinsic(manifestYamlDoc),
@@ -530,6 +532,9 @@
     else
       patch,
 
+  get(o, f, default = null, inc_hidden = true)::
+    if std.objectHasEx(o, f, inc_hidden) then o[f] else default,
+
   objectFields(o)::
     std.objectFieldsEx(o, false),