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

difftreelog

feat std.decodeUTF8 builtin

Yaroslav Bolyukin2021-07-12parent: #00fce89.patch.diff
in: master

3 files changed

modifiedcrates/jrsonnet-evaluator/src/builtin/mod.rsdiffbeforeafterboth
--- a/crates/jrsonnet-evaluator/src/builtin/mod.rs
+++ b/crates/jrsonnet-evaluator/src/builtin/mod.rs
@@ -112,6 +112,7 @@
 			("range".into(), builtin_range),
 			("char".into(), builtin_char),
 			("encodeUTF8".into(), builtin_encode_utf8),
+			("decodeUTF8".into(), builtin_decode_utf8),
 			("md5".into(), builtin_md5),
 			("base64".into(), builtin_base64),
 			("base64DecodeBytes".into(), builtin_base64_decode_bytes),
@@ -585,6 +586,23 @@
 	})
 }
 
+fn builtin_decode_utf8(
+	context: Context,
+	_loc: Option<&ExprLocation>,
+	args: &ArgsDesc,
+) -> Result<Val> {
+	parse_args!(context, "decodeUTF8", args, 1, [
+		0, arr: ty!((Array<ubyte>)) => Val::Arr;
+	], {
+		let data: Result<Vec<u8>> = arr.iter().map(|v| v.map(|v| match v{
+			Val::Num(n) => n as u8,
+			_ => unreachable!(),
+		})).collect();
+		let data = data?;
+		Ok(Val::Str(String::from_utf8(data).map_err(|_| RuntimeError("bad utf8".into()))?.into()))
+	})
+}
+
 fn builtin_md5(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val> {
 	parse_args!(context, "md5", args, 1, [
 		0, str: ty!(string) => Val::Str;
modifiedcrates/jrsonnet-stdlib/src/std.jsonnetdiffbeforeafterboth
--- a/crates/jrsonnet-stdlib/src/std.jsonnet
+++ b/crates/jrsonnet-stdlib/src/std.jsonnet
@@ -18,6 +18,7 @@
   filter:: $intrinsic(filter),
   char:: $intrinsic(char),
   encodeUTF8:: $intrinsic(encodeUTF8),
+  decodeUTF8:: $intrinsic(decodeUTF8),
   md5:: $intrinsic(md5),
   trace:: $intrinsic(trace),
   id:: $intrinsic(id),
modifiedcrates/jrsonnet-types/src/lib.rsdiffbeforeafterboth
before · crates/jrsonnet-types/src/lib.rs
1#![allow(clippy::redundant_closure_call)]23use jrsonnet_gc::Trace;4use std::fmt::Display;56#[macro_export]7macro_rules! ty {8	((Array<number>)) => {{9		$crate::ComplexValType::ArrayRef(&$crate::ComplexValType::Simple($crate::ValType::Num))10	}};11	(array) => {12		$crate::ComplexValType::Simple($crate::ValType::Arr)13	};14	(boolean) => {15		$crate::ComplexValType::Simple($crate::ValType::Bool)16	};17	(null) => {18		$crate::ComplexValType::Simple($crate::ValType::Null)19	};20	(string) => {21		$crate::ComplexValType::Simple($crate::ValType::Str)22	};23	(char) => {24		$crate::ComplexValType::Char25	};26	(number) => {27		$crate::ComplexValType::Simple($crate::ValType::Num)28	};29	(BoundedNumber<($min:expr), ($max:expr)>) => {{30		$crate::ComplexValType::BoundedNumber($min, $max)31	}};32	(object) => {33		$crate::ComplexValType::Simple($crate::ValType::Obj)34	};35	(any) => {36		$crate::ComplexValType::Any37	};38	(function) => {39		$crate::ComplexValType::Simple($crate::ValType::Func)40	};41	(($($a:tt) |+)) => {{42		static CONTENTS: &'static [$crate::ComplexValType] = &[43			$(ty!($a)),+44		];45		$crate::ComplexValType::UnionRef(CONTENTS)46	}};47	(($($a:tt) &+)) => {{48		static CONTENTS: &'static [$crate::ComplexValType] = &[49			$(ty!($a)),+50		];51		$crate::ComplexValType::SumRef(CONTENTS)52	}};53}5455#[test]56fn test() {57	assert_eq!(58		ty!((Array<number>)),59		ComplexValType::ArrayRef(&ComplexValType::Simple(ValType::Num))60	);61	assert_eq!(ty!(array), ComplexValType::Simple(ValType::Arr));62	assert_eq!(ty!(any), ComplexValType::Any);63	assert_eq!(64		ty!((string | number)),65		ComplexValType::UnionRef(&[66			ComplexValType::Simple(ValType::Str),67			ComplexValType::Simple(ValType::Num)68		])69	);70	assert_eq!(71		format!("{}", ty!(((string & number) | (object & null)))),72		"string & number | object & null"73	);74	assert_eq!(format!("{}", ty!((string | array))), "string | array");75	assert_eq!(76		format!("{}", ty!(((string & number) | array))),77		"string & number | array"78	);79}8081#[derive(Debug, Clone, Copy, PartialEq, Eq, Trace)]82#[trivially_drop]83pub enum ValType {84	Bool,85	Null,86	Str,87	Num,88	Arr,89	Obj,90	Func,91}9293impl ValType {94	pub const fn name(&self) -> &'static str {95		use ValType::*;96		match self {97			Bool => "boolean",98			Null => "null",99			Str => "string",100			Num => "number",101			Arr => "array",102			Obj => "object",103			Func => "function",104		}105	}106}107108impl Display for ValType {109	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {110		write!(f, "{}", self.name())111	}112}113114#[derive(Debug, Clone, PartialEq, Trace)]115#[trivially_drop]116pub enum ComplexValType {117	Any,118	Char,119	Simple(ValType),120	BoundedNumber(Option<f64>, Option<f64>),121	Array(Box<ComplexValType>),122	ArrayRef(&'static ComplexValType),123	ObjectRef(&'static [(&'static str, ComplexValType)]),124	Union(Vec<ComplexValType>),125	UnionRef(&'static [ComplexValType]),126	Sum(Vec<ComplexValType>),127	SumRef(&'static [ComplexValType]),128}129130impl From<ValType> for ComplexValType {131	fn from(s: ValType) -> Self {132		Self::Simple(s)133	}134}135136fn write_union(137	f: &mut std::fmt::Formatter<'_>,138	is_union: bool,139	union: &[ComplexValType],140) -> std::fmt::Result {141	for (i, v) in union.iter().enumerate() {142		let should_add_braces =143			matches!(v, ComplexValType::UnionRef(_) | ComplexValType::Union(_) if !is_union);144		if i != 0 {145			write!(f, " {} ", if is_union { '|' } else { '&' })?;146		}147		if should_add_braces {148			write!(f, "(")?;149		}150		write!(f, "{}", v)?;151		if should_add_braces {152			write!(f, ")")?;153		}154	}155	Ok(())156}157158fn print_array(a: &ComplexValType, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {159	if *a == ComplexValType::Any {160		write!(f, "array")?161	} else {162		write!(f, "Array<{}>", a)?163	}164	Ok(())165}166167impl Display for ComplexValType {168	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {169		match self {170			ComplexValType::Any => write!(f, "any")?,171			ComplexValType::Simple(s) => write!(f, "{}", s)?,172			ComplexValType::Char => write!(f, "char")?,173			ComplexValType::BoundedNumber(a, b) => write!(174				f,175				"BoundedNumber<{}, {}>",176				a.map(|e| e.to_string()).unwrap_or_else(|| "".into()),177				b.map(|e| e.to_string()).unwrap_or_else(|| "".into())178			)?,179			ComplexValType::ArrayRef(a) => print_array(a, f)?,180			ComplexValType::Array(a) => print_array(a, f)?,181			ComplexValType::ObjectRef(fields) => {182				write!(f, "{{")?;183				for (i, (k, v)) in fields.iter().enumerate() {184					if i != 0 {185						write!(f, ", ")?;186					}187					write!(f, "{}: {}", k, v)?;188				}189				write!(f, "}}")?;190			}191			ComplexValType::Union(v) => write_union(f, true, v)?,192			ComplexValType::UnionRef(v) => write_union(f, true, v)?,193			ComplexValType::Sum(v) => write_union(f, false, v)?,194			ComplexValType::SumRef(v) => write_union(f, false, v)?,195		};196		Ok(())197	}198}199200peg::parser! {201pub grammar parser() for str {202	rule number() -> f64203		= n:$(['0'..='9']+) { n.parse().unwrap() }204205	rule any_ty() -> ComplexValType = "any" { ComplexValType::Any }206	rule char_ty() -> ComplexValType = "character" { ComplexValType::Char }207	rule bool_ty() -> ComplexValType = "boolean" { ComplexValType::Simple(ValType::Bool) }208	rule null_ty() -> ComplexValType = "null" { ComplexValType::Simple(ValType::Null) }209	rule str_ty() -> ComplexValType = "string" { ComplexValType::Simple(ValType::Str) }210	rule num_ty() -> ComplexValType = "number" { ComplexValType::Simple(ValType::Num) }211	rule simple_array_ty() -> ComplexValType = "array" { ComplexValType::Simple(ValType::Arr) }212	rule simple_object_ty() -> ComplexValType = "object" { ComplexValType::Simple(ValType::Obj) }213	rule simple_function_ty() -> ComplexValType = "function" { ComplexValType::Simple(ValType::Func) }214215	rule array_ty() -> ComplexValType216		= "Array<" t:ty() ">" { ComplexValType::Array(Box::new(t)) }217218	rule bounded_number_ty() -> ComplexValType219		= "BoundedNumber<" a:number() ", " b:number() ">" { ComplexValType::BoundedNumber(Some(a), Some(b)) }220221	rule ty_basic() -> ComplexValType222		= any_ty()223		/ char_ty()224		/ bool_ty()225		/ null_ty()226		/ str_ty()227		/ num_ty()228		/ simple_array_ty()229		/ simple_object_ty()230		/ simple_function_ty()231		/ array_ty()232		/ bounded_number_ty()233234	pub rule ty() -> ComplexValType235		= precedence! {236			a:(@) " | " b:@ {237				match a {238					ComplexValType::Union(mut a) => {239						a.push(b);240						ComplexValType::Union(a)241					}242					_ => ComplexValType::Union(vec![a, b]),243				}244			}245			--246			a:(@) " & " b:@ {247				match a {248					ComplexValType::Sum(mut a) => {249						a.push(b);250						ComplexValType::Sum(a)251					}252					_ => ComplexValType::Sum(vec![a, b]),253				}254			}255			--256			"(" t:ty() ")" { t }257			t:ty_basic() { t }258		}259}260}261262#[cfg(test)]263pub mod tests {264	use super::parser;265266	#[test]267	fn precedence() {268		assert_eq!(269			parser::ty("(any & any) | (any | any) & any")270				.unwrap()271				.to_string(),272			"any & any | (any | any) & any"273		);274	}275276	#[test]277	fn array() {278		assert_eq!(parser::ty("Array<any>").unwrap().to_string(), "array");279		assert_eq!(280			parser::ty("Array<number>").unwrap().to_string(),281			"Array<number>"282		);283	}284	#[test]285	fn bounded_number() {286		assert_eq!(287			parser::ty("BoundedNumber<1, 2>").unwrap().to_string(),288			"BoundedNumber<1, 2>"289		);290	}291}
after · crates/jrsonnet-types/src/lib.rs
1#![allow(clippy::redundant_closure_call)]23use jrsonnet_gc::Trace;4use std::fmt::Display;56#[macro_export]7macro_rules! ty {8	((Array<number>)) => {{9		$crate::ComplexValType::ArrayRef(&$crate::ComplexValType::Simple($crate::ValType::Num))10	}};11	((Array<ubyte>)) => {{12		$crate::ComplexValType::ArrayRef(&$crate::ComplexValType::BoundedNumber(Some(0.0), Some(255.0)))13	}};14	(array) => {15		$crate::ComplexValType::Simple($crate::ValType::Arr)16	};17	(boolean) => {18		$crate::ComplexValType::Simple($crate::ValType::Bool)19	};20	(null) => {21		$crate::ComplexValType::Simple($crate::ValType::Null)22	};23	(string) => {24		$crate::ComplexValType::Simple($crate::ValType::Str)25	};26	(char) => {27		$crate::ComplexValType::Char28	};29	(number) => {30		$crate::ComplexValType::Simple($crate::ValType::Num)31	};32	(BoundedNumber<($min:expr), ($max:expr)>) => {{33		$crate::ComplexValType::BoundedNumber($min, $max)34	}};35	(object) => {36		$crate::ComplexValType::Simple($crate::ValType::Obj)37	};38	(any) => {39		$crate::ComplexValType::Any40	};41	(function) => {42		$crate::ComplexValType::Simple($crate::ValType::Func)43	};44	(($($a:tt) |+)) => {{45		static CONTENTS: &'static [$crate::ComplexValType] = &[46			$(ty!($a)),+47		];48		$crate::ComplexValType::UnionRef(CONTENTS)49	}};50	(($($a:tt) &+)) => {{51		static CONTENTS: &'static [$crate::ComplexValType] = &[52			$(ty!($a)),+53		];54		$crate::ComplexValType::SumRef(CONTENTS)55	}};56}5758#[test]59fn test() {60	assert_eq!(61		ty!((Array<number>)),62		ComplexValType::ArrayRef(&ComplexValType::Simple(ValType::Num))63	);64	assert_eq!(ty!(array), ComplexValType::Simple(ValType::Arr));65	assert_eq!(ty!(any), ComplexValType::Any);66	assert_eq!(67		ty!((string | number)),68		ComplexValType::UnionRef(&[69			ComplexValType::Simple(ValType::Str),70			ComplexValType::Simple(ValType::Num)71		])72	);73	assert_eq!(74		format!("{}", ty!(((string & number) | (object & null)))),75		"string & number | object & null"76	);77	assert_eq!(format!("{}", ty!((string | array))), "string | array");78	assert_eq!(79		format!("{}", ty!(((string & number) | array))),80		"string & number | array"81	);82}8384#[derive(Debug, Clone, Copy, PartialEq, Eq, Trace)]85#[trivially_drop]86pub enum ValType {87	Bool,88	Null,89	Str,90	Num,91	Arr,92	Obj,93	Func,94}9596impl ValType {97	pub const fn name(&self) -> &'static str {98		use ValType::*;99		match self {100			Bool => "boolean",101			Null => "null",102			Str => "string",103			Num => "number",104			Arr => "array",105			Obj => "object",106			Func => "function",107		}108	}109}110111impl Display for ValType {112	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {113		write!(f, "{}", self.name())114	}115}116117#[derive(Debug, Clone, PartialEq, Trace)]118#[trivially_drop]119pub enum ComplexValType {120	Any,121	Char,122	Simple(ValType),123	BoundedNumber(Option<f64>, Option<f64>),124	Array(Box<ComplexValType>),125	ArrayRef(&'static ComplexValType),126	ObjectRef(&'static [(&'static str, ComplexValType)]),127	Union(Vec<ComplexValType>),128	UnionRef(&'static [ComplexValType]),129	Sum(Vec<ComplexValType>),130	SumRef(&'static [ComplexValType]),131}132133impl From<ValType> for ComplexValType {134	fn from(s: ValType) -> Self {135		Self::Simple(s)136	}137}138139fn write_union(140	f: &mut std::fmt::Formatter<'_>,141	is_union: bool,142	union: &[ComplexValType],143) -> std::fmt::Result {144	for (i, v) in union.iter().enumerate() {145		let should_add_braces =146			matches!(v, ComplexValType::UnionRef(_) | ComplexValType::Union(_) if !is_union);147		if i != 0 {148			write!(f, " {} ", if is_union { '|' } else { '&' })?;149		}150		if should_add_braces {151			write!(f, "(")?;152		}153		write!(f, "{}", v)?;154		if should_add_braces {155			write!(f, ")")?;156		}157	}158	Ok(())159}160161fn print_array(a: &ComplexValType, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {162	if *a == ComplexValType::Any {163		write!(f, "array")?164	} else {165		write!(f, "Array<{}>", a)?166	}167	Ok(())168}169170impl Display for ComplexValType {171	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {172		match self {173			ComplexValType::Any => write!(f, "any")?,174			ComplexValType::Simple(s) => write!(f, "{}", s)?,175			ComplexValType::Char => write!(f, "char")?,176			ComplexValType::BoundedNumber(a, b) => write!(177				f,178				"BoundedNumber<{}, {}>",179				a.map(|e| e.to_string()).unwrap_or_else(|| "".into()),180				b.map(|e| e.to_string()).unwrap_or_else(|| "".into())181			)?,182			ComplexValType::ArrayRef(a) => print_array(a, f)?,183			ComplexValType::Array(a) => print_array(a, f)?,184			ComplexValType::ObjectRef(fields) => {185				write!(f, "{{")?;186				for (i, (k, v)) in fields.iter().enumerate() {187					if i != 0 {188						write!(f, ", ")?;189					}190					write!(f, "{}: {}", k, v)?;191				}192				write!(f, "}}")?;193			}194			ComplexValType::Union(v) => write_union(f, true, v)?,195			ComplexValType::UnionRef(v) => write_union(f, true, v)?,196			ComplexValType::Sum(v) => write_union(f, false, v)?,197			ComplexValType::SumRef(v) => write_union(f, false, v)?,198		};199		Ok(())200	}201}202203peg::parser! {204pub grammar parser() for str {205	rule number() -> f64206		= n:$(['0'..='9']+) { n.parse().unwrap() }207208	rule any_ty() -> ComplexValType = "any" { ComplexValType::Any }209	rule char_ty() -> ComplexValType = "character" { ComplexValType::Char }210	rule bool_ty() -> ComplexValType = "boolean" { ComplexValType::Simple(ValType::Bool) }211	rule null_ty() -> ComplexValType = "null" { ComplexValType::Simple(ValType::Null) }212	rule str_ty() -> ComplexValType = "string" { ComplexValType::Simple(ValType::Str) }213	rule num_ty() -> ComplexValType = "number" { ComplexValType::Simple(ValType::Num) }214	rule simple_array_ty() -> ComplexValType = "array" { ComplexValType::Simple(ValType::Arr) }215	rule simple_object_ty() -> ComplexValType = "object" { ComplexValType::Simple(ValType::Obj) }216	rule simple_function_ty() -> ComplexValType = "function" { ComplexValType::Simple(ValType::Func) }217218	rule array_ty() -> ComplexValType219		= "Array<" t:ty() ">" { ComplexValType::Array(Box::new(t)) }220221	rule bounded_number_ty() -> ComplexValType222		= "BoundedNumber<" a:number() ", " b:number() ">" { ComplexValType::BoundedNumber(Some(a), Some(b)) }223224	rule ty_basic() -> ComplexValType225		= any_ty()226		/ char_ty()227		/ bool_ty()228		/ null_ty()229		/ str_ty()230		/ num_ty()231		/ simple_array_ty()232		/ simple_object_ty()233		/ simple_function_ty()234		/ array_ty()235		/ bounded_number_ty()236237	pub rule ty() -> ComplexValType238		= precedence! {239			a:(@) " | " b:@ {240				match a {241					ComplexValType::Union(mut a) => {242						a.push(b);243						ComplexValType::Union(a)244					}245					_ => ComplexValType::Union(vec![a, b]),246				}247			}248			--249			a:(@) " & " b:@ {250				match a {251					ComplexValType::Sum(mut a) => {252						a.push(b);253						ComplexValType::Sum(a)254					}255					_ => ComplexValType::Sum(vec![a, b]),256				}257			}258			--259			"(" t:ty() ")" { t }260			t:ty_basic() { t }261		}262}263}264265#[cfg(test)]266pub mod tests {267	use super::parser;268269	#[test]270	fn precedence() {271		assert_eq!(272			parser::ty("(any & any) | (any | any) & any")273				.unwrap()274				.to_string(),275			"any & any | (any | any) & any"276		);277	}278279	#[test]280	fn array() {281		assert_eq!(parser::ty("Array<any>").unwrap().to_string(), "array");282		assert_eq!(283			parser::ty("Array<number>").unwrap().to_string(),284			"Array<number>"285		);286	}287	#[test]288	fn bounded_number() {289		assert_eq!(290			parser::ty("BoundedNumber<1, 2>").unwrap().to_string(),291			"BoundedNumber<1, 2>"292		);293	}294}