git.delta.rocks / jrsonnet / refs/commits / 45caf79f1ab3

difftreelog

style fix clippy warnings

Yaroslav Bolyukin2021-01-25parent: #0d591aa.patch.diff
in: master

5 files changed

modifiedcrates/jrsonnet-evaluator/src/builtin/mod.rsdiffbeforeafterboth
before · crates/jrsonnet-evaluator/src/builtin/mod.rs
1use crate::{2	equals,3	error::{Error::*, Result},4	parse_args, primitive_equals, push, throw,5	with_state, ArrValue, Context, FuncVal, LazyVal, Val,6};7use format::{format_arr, format_obj};8use jrsonnet_interner::IStr;9use jrsonnet_parser::{ArgsDesc, BinaryOpType, ExprLocation};10use jrsonnet_types::ty;11use std::{collections::HashMap, path::PathBuf, rc::Rc};1213pub mod stdlib;14pub use stdlib::*;1516use self::manifest::{escape_string_json, manifest_json_ex, ManifestJsonOptions, ManifestType};1718pub mod format;19pub mod manifest;20pub mod sort;2122fn std_format(str: IStr, vals: Val) -> Result<Val> {23	push(24		Some(&ExprLocation(Rc::from(PathBuf::from("std.jsonnet")), 0, 0)),25		|| format!("std.format of {}", str),26		|| {27			Ok(match vals {28				Val::Arr(vals) => Val::Str(format_arr(&str, &vals.evaluated()?)?.into()),29				Val::Obj(obj) => Val::Str(format_obj(&str, &obj)?.into()),30				o => Val::Str(format_arr(&str, &[o])?.into()),31			})32		},33	)34}3536type Builtin = fn(context: Context, loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val>;3738type BuiltinsType = HashMap<Box<str>, Builtin>;3940thread_local! {41	static BUILTINS: BuiltinsType = {42		[43			("length".into(), builtin_length as Builtin),44			("type".into(), builtin_type),45			("makeArray".into(), builtin_make_array),46			("codepoint".into(), builtin_codepoint),47			("objectFieldsEx".into(), builtin_object_fields_ex),48			("objectHasEx".into(), builtin_object_has_ex),49			("slice".into(), builtin_slice),50			("primitiveEquals".into(), builtin_primitive_equals),51			("equals".into(), builtin_equals),52			("modulo".into(), builtin_modulo),53			("mod".into(), builtin_mod),54			("floor".into(), builtin_floor),55			("log".into(), builtin_log),56			("pow".into(), builtin_pow),57			("extVar".into(), builtin_ext_var),58			("native".into(), builtin_native),59			("filter".into(), builtin_filter),60			("foldl".into(), builtin_foldl),61			("foldr".into(), builtin_foldr),62			("sortImpl".into(), builtin_sort_impl),63			("format".into(), builtin_format),64			("range".into(), builtin_range),65			("char".into(), builtin_char),66			("encodeUTF8".into(), builtin_encode_utf8),67			("md5".into(), builtin_md5),68			("base64".into(), builtin_base64),69			("trace".into(), builtin_trace),70			("join".into(), builtin_join),71			("escapeStringJson".into(), builtin_escape_string_json),72			("manifestJsonEx".into(), builtin_manifest_json_ex),73			("reverse".into(), builtin_reverse),74			("id".into(), builtin_id),75			("strReplace".into(), builtin_str_replace),76		].iter().cloned().collect()77	};78}7980fn builtin_length(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val> {81	parse_args!(context, "length", args, 1, [82		0, x: ty!((string | object | array));83	], {84		Ok(match x {85			Val::Str(n) => Val::Num(n.chars().count() as f64),86			Val::Arr(a) => Val::Num(a.len() as f64),87			Val::Obj(o) => Val::Num(88				o.fields_visibility()89					.into_iter()90					.filter(|(_k, v)| *v)91					.count() as f64,92			),93			_ => unreachable!(),94		})95	})96}9798fn builtin_type(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val> {99	parse_args!(context, "type", args, 1, [100		0, x: ty!(any);101	], {102		Ok(Val::Str(x.value_type().name().into()))103	})104}105106fn builtin_make_array(107	context: Context,108	_loc: Option<&ExprLocation>,109	args: &ArgsDesc,110) -> Result<Val> {111	parse_args!(context, "makeArray", args, 2, [112		0, sz: ty!(BoundedNumber<(Some(0.0)), (None)>) => Val::Num;113		1, func: ty!(function) => Val::Func;114	], {115		let mut out = Vec::with_capacity(sz as usize);116		for i in 0..sz as usize {117			out.push(LazyVal::new_resolved(func.evaluate_values(118				Context::new(),119				&[Val::Num(i as f64)]120			)?))121		}122		Ok(Val::Arr(out.into()))123	})124}125126fn builtin_codepoint(127	context: Context,128	_loc: Option<&ExprLocation>,129	args: &ArgsDesc,130) -> Result<Val> {131	parse_args!(context, "codepoint", args, 1, [132		0, str: ty!(char) => Val::Str;133	], {134		Ok(Val::Num(str.chars().next().unwrap() as u32 as f64))135	})136}137138fn builtin_object_fields_ex(139	context: Context,140	_loc: Option<&ExprLocation>,141	args: &ArgsDesc,142) -> Result<Val> {143	parse_args!(context, "objectFieldsEx", args, 2, [144		0, obj: ty!(object) => Val::Obj;145		1, inc_hidden: ty!(boolean) => Val::Bool;146	], {147		let mut out = obj.fields_visibility()148			.into_iter()149			.filter(|(_k, v)| *v || inc_hidden)150			.map(|(k, _v)|k)151			.collect::<Vec<_>>();152		out.sort();153		Ok(Val::Arr(out.into_iter().map(Val::Str).collect::<Vec<_>>().into()))154	})155}156157fn builtin_object_has_ex(158	context: Context,159	_loc: Option<&ExprLocation>,160	args: &ArgsDesc,161) -> Result<Val> {162	parse_args!(context, "objectHasEx", args, 3, [163		0, obj: ty!(object) => Val::Obj;164		1, f: ty!(string) => Val::Str;165		2, inc_hidden: ty!(boolean) => Val::Bool;166	], {167		Ok(Val::Bool(168			obj.fields_visibility()169				.into_iter()170				.filter(|(_k, v)| *v || inc_hidden)171				.any(|(k, _v)| *k == *f),172		))173	})174}175176// faster177fn builtin_slice(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val> {178	parse_args!(context, "slice", args, 4, [179		0, indexable: ty!((string | array));180		1, index: ty!((number | null));181		2, end: ty!((number | null));182		3, step: ty!((number | null));183	], {184		let index = match index {185			Val::Num(v) => v as usize,186			Val::Null => 0,187			_ => unreachable!(),188		};189		let end = match end {190			Val::Num(v) => v as usize,191			Val::Null => match &indexable {192				Val::Str(s) => s.chars().count(),193				Val::Arr(v) => v.len(),194				_ => unreachable!()195			},196			_ => unreachable!()197		};198		let step = match step {199			Val::Num(v) => v as usize,200			Val::Null => 1,201			_ => unreachable!()202		};203		match &indexable {204			Val::Str(s) => {205				Ok(Val::Str((s.chars().skip(index).take(end-index).step_by(step).collect::<String>()).into()))206			}207			Val::Arr(arr) => {208				Ok(Val::Arr((arr.iter().skip(index).take(end-index).step_by(step).collect::<Result<Vec<Val>>>()?).into()))209			}210			_ => unreachable!()211		}212	})213}214215// faster216fn builtin_primitive_equals(217	context: Context,218	_loc: Option<&ExprLocation>,219	args: &ArgsDesc,220) -> Result<Val> {221	parse_args!(context, "primitiveEquals", args, 2, [222		0, a: ty!(any);223		1, b: ty!(any);224	], {225		Ok(Val::Bool(primitive_equals(&a, &b)?))226	})227}228229// faster230fn builtin_equals(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val> {231	parse_args!(context, "equals", args, 2, [232		0, a: ty!(any);233		1, b: ty!(any);234	], {235		Ok(Val::Bool(equals(&a, &b)?))236	})237}238239fn builtin_modulo(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val> {240	parse_args!(context, "modulo", args, 2, [241		0, a: ty!(number) => Val::Num;242		1, b: ty!(number) => Val::Num;243	], {244		Ok(Val::Num(a % b))245	})246}247248fn builtin_mod(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val> {249	parse_args!(context, "mod", args, 2, [250		0, a: ty!((number | string));251		1, b: ty!(any);252	], {253		match (a, b) {254			(Val::Num(a), Val::Num(b)) => Ok(Val::Num(a % b)),255			(Val::Str(str), vals) => std_format(str, vals),256			(a, b) => throw!(BinaryOperatorDoesNotOperateOnValues(BinaryOpType::Mod, a.value_type(), b.value_type()))257		}258	})259}260261fn builtin_floor(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val> {262	parse_args!(context, "floor", args, 1, [263		0, x: ty!(number) => Val::Num;264	], {265		Ok(Val::Num(x.floor()))266	})267}268269fn builtin_log(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val> {270	parse_args!(context, "log", args, 1, [271		0, n: ty!(number) => Val::Num;272	], {273		Ok(Val::Num(n.ln()))274	})275}276277fn builtin_pow(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val> {278	parse_args!(context, "pow", args, 2, [279		0, x: ty!(number) => Val::Num;280		1, n: ty!(number) => Val::Num;281	], {282		Ok(Val::Num(x.powf(n)))283	})284}285286fn builtin_ext_var(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val> {287	parse_args!(context, "extVar", args, 1, [288		0, x: ty!(string) => Val::Str;289	], {290		Ok(with_state(|s| s.settings().ext_vars.get(&x).cloned()).ok_or(UndefinedExternalVariable(x))?)291	})292}293294fn builtin_native(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val> {295	parse_args!(context, "native", args, 1, [296		0, x: ty!(string) => Val::Str;297	], {298		Ok(with_state(|s| s.settings().ext_natives.get(&x).cloned()).map(|v| Val::Func(Rc::new(FuncVal::NativeExt(x.clone(), v)))).ok_or(UndefinedExternalFunction(x))?)299	})300}301302fn builtin_filter(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val> {303	parse_args!(context, "filter", args, 2, [304		0, func: ty!(function) => Val::Func;305		1, arr: ty!(array) => Val::Arr;306	], {307		let mut out = Vec::new();308		for item in arr.iter() {309			let item = item?;310			if func311						.evaluate_values(context.clone(), &[item.clone()])?312						.try_cast_bool("filter predicate")? {313							out.push(item);314						}315		}316		Ok(Val::Arr(out.into()))317	})318}319320fn builtin_foldl(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val> {321	parse_args!(context, "foldl", args, 3, [322		0, func: ty!(function) => Val::Func;323		1, arr: ty!(array) => Val::Arr;324		2, init: ty!(any);325	], {326		let mut acc = init;327		for i in arr.iter() {328			acc = func.evaluate_values(context.clone(), &[acc, i?])?;329		}330		Ok(acc)331	})332}333334fn builtin_foldr(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val> {335	parse_args!(context, "foldr", args, 3, [336		0, func: ty!(function) => Val::Func;337		1, arr: ty!(array) => Val::Arr;338		2, init: ty!(any);339	], {340		let mut acc = init;341		for i in arr.iter().rev() {342			acc = func.evaluate_values(context.clone(), &[acc, i?])?;343		}344		Ok(acc)345	})346}347348#[allow(non_snake_case)]349fn builtin_sort_impl(350	context: Context,351	_loc: Option<&ExprLocation>,352	args: &ArgsDesc,353) -> Result<Val> {354	parse_args!(context, "sort", args, 2, [355		0, arr: ty!(array) => Val::Arr;356		1, keyF: ty!(function) => Val::Func;357	], {358		if arr.len() <= 1 {359			return Ok(Val::Arr(arr))360		}361		Ok(Val::Arr(ArrValue::Eager(sort::sort(context, arr.evaluated()?, &keyF)?)))362	})363}364365// faster366fn builtin_format(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val> {367	parse_args!(context, "format", args, 2, [368		0, str: ty!(string) => Val::Str;369		1, vals: ty!(any)370	], {371		std_format(str, vals)372	})373}374375fn builtin_range(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val> {376	parse_args!(context, "range", args, 2, [377		0, from: ty!(number) => Val::Num;378		1, to: ty!(number) => Val::Num;379	], {380		if to < from {381			return Ok(Val::Arr(ArrValue::new_eager()))382		}383		let mut out = Vec::with_capacity((1+to as usize-from as usize).max(0));384		for i in from as usize..=to as usize {385			out.push(Val::Num(i as f64));386		}387		Ok(Val::Arr(out.into()))388	})389}390391fn builtin_char(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val> {392	parse_args!(context, "char", args, 1, [393		0, n: ty!(number) => Val::Num;394	], {395		let mut out = String::new();396		out.push(std::char::from_u32(n as u32).ok_or_else(||397			InvalidUnicodeCodepointGot(n as u32)398		)?);399		Ok(Val::Str(out.into()))400	})401}402403fn builtin_encode_utf8(404	context: Context,405	_loc: Option<&ExprLocation>,406	args: &ArgsDesc,407) -> Result<Val> {408	parse_args!(context, "encodeUTF8", args, 1, [409		0, str: ty!(string) => Val::Str;410	], {411		Ok(Val::Arr((str.bytes().map(|b| Val::Num(b as f64)).collect::<Vec<Val>>()).into()))412	})413}414415fn builtin_md5(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val> {416	parse_args!(context, "md5", args, 1, [417		0, str: ty!(string) => Val::Str;418	], {419		Ok(Val::Str(format!("{:x}", md5::compute(&str.as_bytes())).into()))420	})421}422423fn builtin_trace(context: Context, loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val> {424	parse_args!(context, "trace", args, 2, [425		0, str: ty!(string) => Val::Str;426		1, rest: ty!(any);427	], {428		eprint!("TRACE:");429		if let Some(loc) = loc {430			with_state(|s|{431				let locs = s.map_source_locations(&loc.0, &[loc.1]);432				eprint!(" {}:{}", loc.0.file_name().unwrap().to_str().unwrap(), locs[0].line);433			});434		}435		eprintln!(" {}", str);436		Ok(rest)437	})438}439440fn builtin_base64(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val> {441	parse_args!(context, "base64", args, 1, [442		0, input: ty!((string | (Array<number>)));443	], {444		Ok(Val::Str(match input {445			Val::Str(s) => {446				base64::encode(s.bytes().collect::<Vec<_>>()).into()447			},448			Val::Arr(a) => {449				base64::encode(a.iter().map(|v| {450					Ok(v?.unwrap_num()? as u8)451				}).collect::<Result<Vec<_>>>()?).into()452			},453			_ => unreachable!()454		}))455	})456}457458fn builtin_join(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val> {459	parse_args!(context, "join", args, 2, [460		0, sep: ty!((string | array));461		1, arr: ty!(array) => Val::Arr;462	], {463		Ok(match sep {464			Val::Arr(joiner_items) => {465				let mut out = Vec::new();466467				let mut first = true;468				for item in arr.iter() {469					let item = item?.clone();470					if let Val::Arr(items) = item {471						if !first {472							out.reserve(joiner_items.len());473							// TODO: extend474							for item in joiner_items.iter() {475								out.push(item?);476							}477						}478						first = false;479						out.reserve(items.len());480						// TODO: extend481						for item in items.iter() {482							out.push(item?);483						}484					} else {485						throw!(RuntimeError("in std.join all items should be arrays".into()));486					}487				}488489				Val::Arr(out.into())490			},491			Val::Str(sep) => {492				let mut out = String::new();493494				let mut first = true;495				for item in arr.iter() {496					let item = item?.clone();497					if let Val::Str(item) = item {498						if !first {499							out += &sep;500						}501						first = false;502						out += &item;503					} else {504						throw!(RuntimeError("in std.join all items should be strings".into()));505					}506				}507508				Val::Str(out.into())509			},510			_ => unreachable!()511		})512	})513}514515// faster516fn builtin_escape_string_json(517	context: Context,518	_loc: Option<&ExprLocation>,519	args: &ArgsDesc,520) -> Result<Val> {521	parse_args!(context, "escapeStringJson", args, 1, [522		0, str_: ty!(string) => Val::Str;523	], {524		Ok(Val::Str(escape_string_json(&str_).into()))525	})526}527528// faster529fn builtin_manifest_json_ex(530	context: Context,531	_loc: Option<&ExprLocation>,532	args: &ArgsDesc,533) -> Result<Val> {534	parse_args!(context, "manifestJsonEx", args, 2, [535		0, value: ty!(any);536		1, indent: ty!(string) => Val::Str;537	], {538		Ok(Val::Str(manifest_json_ex(&value, &ManifestJsonOptions {539			padding: &indent,540			mtype: ManifestType::Std,541		})?.into()))542	})543}544545// faster546fn builtin_reverse(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val> {547	parse_args!(context, "reverse", args, 1, [548		0, value: ty!(array) => Val::Arr;549	], {550		Ok(Val::Arr(value.reversed()))551	})552}553554fn builtin_id(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val> {555	parse_args!(context, "id", args, 1, [556		0, v: ty!(any);557	], {558		Ok(v)559	})560}561562// faster563fn builtin_str_replace(564	context: Context,565	_loc: Option<&ExprLocation>,566	args: &ArgsDesc,567) -> Result<Val> {568	parse_args!(context, "strReplace", args, 3, [569		0, str: ty!(string) => Val::Str;570		1, from: ty!(string) => Val::Str;571		2, to: ty!(string) => Val::Str;572	], {573		let mut out = String::new();574		let mut last_idx = 0;575		while let Some(idx) = (&str[last_idx..]).find(&from as &str) {576			out.push_str(&str[last_idx..last_idx+idx]);577			out.push_str(&to);578			last_idx += idx + from.len();579		}580		if last_idx == 0 {581			return Ok(Val::Str(str))582		}583		out.push_str(&str[last_idx..]);584		Ok(Val::Str(out.into()))585	})586}587588pub fn call_builtin(589	context: Context,590	loc: Option<&ExprLocation>,591	name: &str,592	args: &ArgsDesc,593) -> Result<Val> {594	if let Some(f) = BUILTINS.with(|builtins| builtins.get(name).copied()) {595		return Ok(f(context, loc, args)?);596	}597	throw!(IntrinsicNotFound(name.into()))598}
after · crates/jrsonnet-evaluator/src/builtin/mod.rs
1use crate::{2	equals,3	error::{Error::*, Result},4	parse_args, primitive_equals, push, throw, with_state, ArrValue, Context, FuncVal, LazyVal,5	Val,6};7use format::{format_arr, format_obj};8use jrsonnet_interner::IStr;9use jrsonnet_parser::{ArgsDesc, BinaryOpType, ExprLocation};10use jrsonnet_types::ty;11use std::{collections::HashMap, path::PathBuf, rc::Rc};1213pub mod stdlib;14pub use stdlib::*;1516use self::manifest::{escape_string_json, manifest_json_ex, ManifestJsonOptions, ManifestType};1718pub mod format;19pub mod manifest;20pub mod sort;2122fn std_format(str: IStr, vals: Val) -> Result<Val> {23	push(24		Some(&ExprLocation(Rc::from(PathBuf::from("std.jsonnet")), 0, 0)),25		|| format!("std.format of {}", str),26		|| {27			Ok(match vals {28				Val::Arr(vals) => Val::Str(format_arr(&str, &vals.evaluated()?)?.into()),29				Val::Obj(obj) => Val::Str(format_obj(&str, &obj)?.into()),30				o => Val::Str(format_arr(&str, &[o])?.into()),31			})32		},33	)34}3536type Builtin = fn(context: Context, loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val>;3738type BuiltinsType = HashMap<Box<str>, Builtin>;3940thread_local! {41	static BUILTINS: BuiltinsType = {42		[43			("length".into(), builtin_length as Builtin),44			("type".into(), builtin_type),45			("makeArray".into(), builtin_make_array),46			("codepoint".into(), builtin_codepoint),47			("objectFieldsEx".into(), builtin_object_fields_ex),48			("objectHasEx".into(), builtin_object_has_ex),49			("slice".into(), builtin_slice),50			("primitiveEquals".into(), builtin_primitive_equals),51			("equals".into(), builtin_equals),52			("modulo".into(), builtin_modulo),53			("mod".into(), builtin_mod),54			("floor".into(), builtin_floor),55			("log".into(), builtin_log),56			("pow".into(), builtin_pow),57			("extVar".into(), builtin_ext_var),58			("native".into(), builtin_native),59			("filter".into(), builtin_filter),60			("foldl".into(), builtin_foldl),61			("foldr".into(), builtin_foldr),62			("sortImpl".into(), builtin_sort_impl),63			("format".into(), builtin_format),64			("range".into(), builtin_range),65			("char".into(), builtin_char),66			("encodeUTF8".into(), builtin_encode_utf8),67			("md5".into(), builtin_md5),68			("base64".into(), builtin_base64),69			("trace".into(), builtin_trace),70			("join".into(), builtin_join),71			("escapeStringJson".into(), builtin_escape_string_json),72			("manifestJsonEx".into(), builtin_manifest_json_ex),73			("reverse".into(), builtin_reverse),74			("id".into(), builtin_id),75			("strReplace".into(), builtin_str_replace),76		].iter().cloned().collect()77	};78}7980fn builtin_length(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val> {81	parse_args!(context, "length", args, 1, [82		0, x: ty!((string | object | array));83	], {84		Ok(match x {85			Val::Str(n) => Val::Num(n.chars().count() as f64),86			Val::Arr(a) => Val::Num(a.len() as f64),87			Val::Obj(o) => Val::Num(88				o.fields_visibility()89					.into_iter()90					.filter(|(_k, v)| *v)91					.count() as f64,92			),93			_ => unreachable!(),94		})95	})96}9798fn builtin_type(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val> {99	parse_args!(context, "type", args, 1, [100		0, x: ty!(any);101	], {102		Ok(Val::Str(x.value_type().name().into()))103	})104}105106fn builtin_make_array(107	context: Context,108	_loc: Option<&ExprLocation>,109	args: &ArgsDesc,110) -> Result<Val> {111	parse_args!(context, "makeArray", args, 2, [112		0, sz: ty!(BoundedNumber<(Some(0.0)), (None)>) => Val::Num;113		1, func: ty!(function) => Val::Func;114	], {115		let mut out = Vec::with_capacity(sz as usize);116		for i in 0..sz as usize {117			out.push(LazyVal::new_resolved(func.evaluate_values(118				Context::new(),119				&[Val::Num(i as f64)]120			)?))121		}122		Ok(Val::Arr(out.into()))123	})124}125126fn builtin_codepoint(127	context: Context,128	_loc: Option<&ExprLocation>,129	args: &ArgsDesc,130) -> Result<Val> {131	parse_args!(context, "codepoint", args, 1, [132		0, str: ty!(char) => Val::Str;133	], {134		Ok(Val::Num(str.chars().next().unwrap() as u32 as f64))135	})136}137138fn builtin_object_fields_ex(139	context: Context,140	_loc: Option<&ExprLocation>,141	args: &ArgsDesc,142) -> Result<Val> {143	parse_args!(context, "objectFieldsEx", args, 2, [144		0, obj: ty!(object) => Val::Obj;145		1, inc_hidden: ty!(boolean) => Val::Bool;146	], {147		let mut out = obj.fields_visibility()148			.into_iter()149			.filter(|(_k, v)| *v || inc_hidden)150			.map(|(k, _v)|k)151			.collect::<Vec<_>>();152		out.sort();153		Ok(Val::Arr(out.into_iter().map(Val::Str).collect::<Vec<_>>().into()))154	})155}156157fn builtin_object_has_ex(158	context: Context,159	_loc: Option<&ExprLocation>,160	args: &ArgsDesc,161) -> Result<Val> {162	parse_args!(context, "objectHasEx", args, 3, [163		0, obj: ty!(object) => Val::Obj;164		1, f: ty!(string) => Val::Str;165		2, inc_hidden: ty!(boolean) => Val::Bool;166	], {167		Ok(Val::Bool(168			obj.fields_visibility()169				.into_iter()170				.filter(|(_k, v)| *v || inc_hidden)171				.any(|(k, _v)| *k == *f),172		))173	})174}175176// faster177fn builtin_slice(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val> {178	parse_args!(context, "slice", args, 4, [179		0, indexable: ty!((string | array));180		1, index: ty!((number | null));181		2, end: ty!((number | null));182		3, step: ty!((number | null));183	], {184		let index = match index {185			Val::Num(v) => v as usize,186			Val::Null => 0,187			_ => unreachable!(),188		};189		let end = match end {190			Val::Num(v) => v as usize,191			Val::Null => match &indexable {192				Val::Str(s) => s.chars().count(),193				Val::Arr(v) => v.len(),194				_ => unreachable!()195			},196			_ => unreachable!()197		};198		let step = match step {199			Val::Num(v) => v as usize,200			Val::Null => 1,201			_ => unreachable!()202		};203		match &indexable {204			Val::Str(s) => {205				Ok(Val::Str((s.chars().skip(index).take(end-index).step_by(step).collect::<String>()).into()))206			}207			Val::Arr(arr) => {208				Ok(Val::Arr((arr.iter().skip(index).take(end-index).step_by(step).collect::<Result<Vec<Val>>>()?).into()))209			}210			_ => unreachable!()211		}212	})213}214215// faster216fn builtin_primitive_equals(217	context: Context,218	_loc: Option<&ExprLocation>,219	args: &ArgsDesc,220) -> Result<Val> {221	parse_args!(context, "primitiveEquals", args, 2, [222		0, a: ty!(any);223		1, b: ty!(any);224	], {225		Ok(Val::Bool(primitive_equals(&a, &b)?))226	})227}228229// faster230fn builtin_equals(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val> {231	parse_args!(context, "equals", args, 2, [232		0, a: ty!(any);233		1, b: ty!(any);234	], {235		Ok(Val::Bool(equals(&a, &b)?))236	})237}238239fn builtin_modulo(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val> {240	parse_args!(context, "modulo", args, 2, [241		0, a: ty!(number) => Val::Num;242		1, b: ty!(number) => Val::Num;243	], {244		Ok(Val::Num(a % b))245	})246}247248fn builtin_mod(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val> {249	parse_args!(context, "mod", args, 2, [250		0, a: ty!((number | string));251		1, b: ty!(any);252	], {253		match (a, b) {254			(Val::Num(a), Val::Num(b)) => Ok(Val::Num(a % b)),255			(Val::Str(str), vals) => std_format(str, vals),256			(a, b) => throw!(BinaryOperatorDoesNotOperateOnValues(BinaryOpType::Mod, a.value_type(), b.value_type()))257		}258	})259}260261fn builtin_floor(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val> {262	parse_args!(context, "floor", args, 1, [263		0, x: ty!(number) => Val::Num;264	], {265		Ok(Val::Num(x.floor()))266	})267}268269fn builtin_log(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val> {270	parse_args!(context, "log", args, 1, [271		0, n: ty!(number) => Val::Num;272	], {273		Ok(Val::Num(n.ln()))274	})275}276277fn builtin_pow(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val> {278	parse_args!(context, "pow", args, 2, [279		0, x: ty!(number) => Val::Num;280		1, n: ty!(number) => Val::Num;281	], {282		Ok(Val::Num(x.powf(n)))283	})284}285286fn builtin_ext_var(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val> {287	parse_args!(context, "extVar", args, 1, [288		0, x: ty!(string) => Val::Str;289	], {290		Ok(with_state(|s| s.settings().ext_vars.get(&x).cloned()).ok_or(UndefinedExternalVariable(x))?)291	})292}293294fn builtin_native(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val> {295	parse_args!(context, "native", args, 1, [296		0, x: ty!(string) => Val::Str;297	], {298		Ok(with_state(|s| s.settings().ext_natives.get(&x).cloned()).map(|v| Val::Func(Rc::new(FuncVal::NativeExt(x.clone(), v)))).ok_or(UndefinedExternalFunction(x))?)299	})300}301302fn builtin_filter(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val> {303	parse_args!(context, "filter", args, 2, [304		0, func: ty!(function) => Val::Func;305		1, arr: ty!(array) => Val::Arr;306	], {307		let mut out = Vec::new();308		for item in arr.iter() {309			let item = item?;310			if func311						.evaluate_values(context.clone(), &[item.clone()])?312						.try_cast_bool("filter predicate")? {313							out.push(item);314						}315		}316		Ok(Val::Arr(out.into()))317	})318}319320fn builtin_foldl(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val> {321	parse_args!(context, "foldl", args, 3, [322		0, func: ty!(function) => Val::Func;323		1, arr: ty!(array) => Val::Arr;324		2, init: ty!(any);325	], {326		let mut acc = init;327		for i in arr.iter() {328			acc = func.evaluate_values(context.clone(), &[acc, i?])?;329		}330		Ok(acc)331	})332}333334fn builtin_foldr(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val> {335	parse_args!(context, "foldr", args, 3, [336		0, func: ty!(function) => Val::Func;337		1, arr: ty!(array) => Val::Arr;338		2, init: ty!(any);339	], {340		let mut acc = init;341		for i in arr.iter().rev() {342			acc = func.evaluate_values(context.clone(), &[acc, i?])?;343		}344		Ok(acc)345	})346}347348#[allow(non_snake_case)]349fn builtin_sort_impl(350	context: Context,351	_loc: Option<&ExprLocation>,352	args: &ArgsDesc,353) -> Result<Val> {354	parse_args!(context, "sort", args, 2, [355		0, arr: ty!(array) => Val::Arr;356		1, keyF: ty!(function) => Val::Func;357	], {358		if arr.len() <= 1 {359			return Ok(Val::Arr(arr))360		}361		Ok(Val::Arr(ArrValue::Eager(sort::sort(context, arr.evaluated()?, &keyF)?)))362	})363}364365// faster366fn builtin_format(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val> {367	parse_args!(context, "format", args, 2, [368		0, str: ty!(string) => Val::Str;369		1, vals: ty!(any)370	], {371		std_format(str, vals)372	})373}374375fn builtin_range(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val> {376	parse_args!(context, "range", args, 2, [377		0, from: ty!(number) => Val::Num;378		1, to: ty!(number) => Val::Num;379	], {380		if to < from {381			return Ok(Val::Arr(ArrValue::new_eager()))382		}383		let mut out = Vec::with_capacity((1+to as usize-from as usize).max(0));384		for i in from as usize..=to as usize {385			out.push(Val::Num(i as f64));386		}387		Ok(Val::Arr(out.into()))388	})389}390391fn builtin_char(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val> {392	parse_args!(context, "char", args, 1, [393		0, n: ty!(number) => Val::Num;394	], {395		let mut out = String::new();396		out.push(std::char::from_u32(n as u32).ok_or_else(||397			InvalidUnicodeCodepointGot(n as u32)398		)?);399		Ok(Val::Str(out.into()))400	})401}402403fn builtin_encode_utf8(404	context: Context,405	_loc: Option<&ExprLocation>,406	args: &ArgsDesc,407) -> Result<Val> {408	parse_args!(context, "encodeUTF8", args, 1, [409		0, str: ty!(string) => Val::Str;410	], {411		Ok(Val::Arr((str.bytes().map(|b| Val::Num(b as f64)).collect::<Vec<Val>>()).into()))412	})413}414415fn builtin_md5(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val> {416	parse_args!(context, "md5", args, 1, [417		0, str: ty!(string) => Val::Str;418	], {419		Ok(Val::Str(format!("{:x}", md5::compute(&str.as_bytes())).into()))420	})421}422423fn builtin_trace(context: Context, loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val> {424	parse_args!(context, "trace", args, 2, [425		0, str: ty!(string) => Val::Str;426		1, rest: ty!(any);427	], {428		eprint!("TRACE:");429		if let Some(loc) = loc {430			with_state(|s|{431				let locs = s.map_source_locations(&loc.0, &[loc.1]);432				eprint!(" {}:{}", loc.0.file_name().unwrap().to_str().unwrap(), locs[0].line);433			});434		}435		eprintln!(" {}", str);436		Ok(rest)437	})438}439440fn builtin_base64(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val> {441	parse_args!(context, "base64", args, 1, [442		0, input: ty!((string | (Array<number>)));443	], {444		Ok(Val::Str(match input {445			Val::Str(s) => {446				base64::encode(s.bytes().collect::<Vec<_>>()).into()447			},448			Val::Arr(a) => {449				base64::encode(a.iter().map(|v| {450					Ok(v?.unwrap_num()? as u8)451				}).collect::<Result<Vec<_>>>()?).into()452			},453			_ => unreachable!()454		}))455	})456}457458fn builtin_join(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val> {459	parse_args!(context, "join", args, 2, [460		0, sep: ty!((string | array));461		1, arr: ty!(array) => Val::Arr;462	], {463		Ok(match sep {464			Val::Arr(joiner_items) => {465				let mut out = Vec::new();466467				let mut first = true;468				for item in arr.iter() {469					let item = item?.clone();470					if let Val::Arr(items) = item {471						if !first {472							out.reserve(joiner_items.len());473							// TODO: extend474							for item in joiner_items.iter() {475								out.push(item?);476							}477						}478						first = false;479						out.reserve(items.len());480						// TODO: extend481						for item in items.iter() {482							out.push(item?);483						}484					} else {485						throw!(RuntimeError("in std.join all items should be arrays".into()));486					}487				}488489				Val::Arr(out.into())490			},491			Val::Str(sep) => {492				let mut out = String::new();493494				let mut first = true;495				for item in arr.iter() {496					let item = item?.clone();497					if let Val::Str(item) = item {498						if !first {499							out += &sep;500						}501						first = false;502						out += &item;503					} else {504						throw!(RuntimeError("in std.join all items should be strings".into()));505					}506				}507508				Val::Str(out.into())509			},510			_ => unreachable!()511		})512	})513}514515// faster516fn builtin_escape_string_json(517	context: Context,518	_loc: Option<&ExprLocation>,519	args: &ArgsDesc,520) -> Result<Val> {521	parse_args!(context, "escapeStringJson", args, 1, [522		0, str_: ty!(string) => Val::Str;523	], {524		Ok(Val::Str(escape_string_json(&str_).into()))525	})526}527528// faster529fn builtin_manifest_json_ex(530	context: Context,531	_loc: Option<&ExprLocation>,532	args: &ArgsDesc,533) -> Result<Val> {534	parse_args!(context, "manifestJsonEx", args, 2, [535		0, value: ty!(any);536		1, indent: ty!(string) => Val::Str;537	], {538		Ok(Val::Str(manifest_json_ex(&value, &ManifestJsonOptions {539			padding: &indent,540			mtype: ManifestType::Std,541		})?.into()))542	})543}544545// faster546fn builtin_reverse(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val> {547	parse_args!(context, "reverse", args, 1, [548		0, value: ty!(array) => Val::Arr;549	], {550		Ok(Val::Arr(value.reversed()))551	})552}553554fn builtin_id(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val> {555	parse_args!(context, "id", args, 1, [556		0, v: ty!(any);557	], {558		Ok(v)559	})560}561562// faster563fn builtin_str_replace(564	context: Context,565	_loc: Option<&ExprLocation>,566	args: &ArgsDesc,567) -> Result<Val> {568	parse_args!(context, "strReplace", args, 3, [569		0, str: ty!(string) => Val::Str;570		1, from: ty!(string) => Val::Str;571		2, to: ty!(string) => Val::Str;572	], {573		let mut out = String::new();574		let mut last_idx = 0;575		while let Some(idx) = (&str[last_idx..]).find(&from as &str) {576			out.push_str(&str[last_idx..last_idx+idx]);577			out.push_str(&to);578			last_idx += idx + from.len();579		}580		if last_idx == 0 {581			return Ok(Val::Str(str))582		}583		out.push_str(&str[last_idx..]);584		Ok(Val::Str(out.into()))585	})586}587588pub fn call_builtin(589	context: Context,590	loc: Option<&ExprLocation>,591	name: &str,592	args: &ArgsDesc,593) -> Result<Val> {594	if let Some(f) = BUILTINS.with(|builtins| builtins.get(name).copied()) {595		return Ok(f(context, loc, args)?);596	}597	throw!(IntrinsicNotFound(name.into()))598}
modifiedcrates/jrsonnet-evaluator/src/lib.rsdiffbeforeafterboth
--- a/crates/jrsonnet-evaluator/src/lib.rs
+++ b/crates/jrsonnet-evaluator/src/lib.rs
@@ -139,7 +139,7 @@
 	e: Option<&ExprLocation>,
 	frame_desc: impl FnOnce() -> String,
 	f: impl FnOnce() -> Result<T>,
- ) -> Result<T> {
+) -> Result<T> {
 	push(e, frame_desc, f)
 }
 
@@ -340,11 +340,17 @@
 	pub fn with_tla(&self, val: Val) -> Result<Val> {
 		self.run_in_state(|| {
 			Ok(match val {
-				Val::Func(func) => push(None, || "during TLA call".to_owned(), || Ok(func.evaluate_map(
-					self.create_default_context()?,
-					&self.settings().tla_vars,
-					true,
-				)?))?,
+				Val::Func(func) => push(
+					None,
+					|| "during TLA call".to_owned(),
+					|| {
+						Ok(func.evaluate_map(
+							self.create_default_context()?,
+							&self.settings().tla_vars,
+							true,
+						)?)
+					},
+				)?,
 				v => v,
 			})
 		})
modifiedcrates/jrsonnet-evaluator/src/trace/location.rsdiffbeforeafterboth
--- a/crates/jrsonnet-evaluator/src/trace/location.rs
+++ b/crates/jrsonnet-evaluator/src/trace/location.rs
@@ -37,7 +37,11 @@
 	];
 	let mut with_no_known_line_ending = vec![];
 	let mut this_line_offset = 0;
-	for (pos, ch) in file.chars().enumerate().chain(std::iter::once((file.len(), ' '))) {
+	for (pos, ch) in file
+		.chars()
+		.enumerate()
+		.chain(std::iter::once((file.len(), ' ')))
+	{
 		column += 1;
 		match offset_map.last() {
 			Some(x) if x.0 == pos => {
modifiedcrates/jrsonnet-evaluator/src/trace/mod.rsdiffbeforeafterboth
--- a/crates/jrsonnet-evaluator/src/trace/mod.rs
+++ b/crates/jrsonnet-evaluator/src/trace/mod.rs
@@ -118,18 +118,24 @@
 			.trace()
 			.0
 			.iter()
-			.map(|el| el.location.as_ref().map(|l| {
-				use std::fmt::Write;
-				let mut resolved_path = self.resolver.resolve(&l.0);
-				// TODO: Process all trace elements first
-				let location = evaluation_state
-					.map_source_locations(&l.0, &[l.1, l.2]);
-				write!(resolved_path, ":").unwrap();
-				print_code_location(&mut resolved_path, &location[0], &location[1]).unwrap();
-				resolved_path
-			}))
+			.map(|el| {
+				el.location.as_ref().map(|l| {
+					use std::fmt::Write;
+					let mut resolved_path = self.resolver.resolve(&l.0);
+					// TODO: Process all trace elements first
+					let location = evaluation_state.map_source_locations(&l.0, &[l.1, l.2]);
+					write!(resolved_path, ":").unwrap();
+					print_code_location(&mut resolved_path, &location[0], &location[1]).unwrap();
+					resolved_path
+				})
+			})
 			.collect::<Vec<_>>();
-		let align = file_names.iter().flatten().map(|e| e.len()).max().unwrap_or(0);
+		let align = file_names
+			.iter()
+			.flatten()
+			.map(|e| e.len())
+			.max()
+			.unwrap_or(0);
 		for (i, (el, file)) in error.trace().0.iter().zip(file_names).enumerate() {
 			if i != 0 {
 				writeln!(out)?;
@@ -162,8 +168,9 @@
 				writeln!(out)?;
 			}
 			let desc = &item.desc;
-			if let Some (source) = &item.location {
-				let start_end = evaluation_state.map_source_locations(&source.0, &[source.1, source.2]);
+			if let Some(source) = &item.location {
+				let start_end =
+					evaluation_state.map_source_locations(&source.0, &[source.1, source.2]);
 
 				write!(
 					out,
@@ -174,11 +181,7 @@
 					start_end[0].column,
 				)?;
 			} else {
-				write!(
-					out,
-					"    at {}",
-					desc,
-				)?;
+				write!(out, "    at {}", desc,)?;
 			}
 		}
 		Ok(())
@@ -230,7 +233,8 @@
 		for item in trace.0.iter() {
 			let desc = &item.desc;
 			if let Some(source) = &item.location {
-				let start_end = evaluation_state.map_source_locations(&source.0, &[source.1, source.2]);
+				let start_end =
+					evaluation_state.map_source_locations(&source.0, &[source.1, source.2]);
 				self.print_snippet(
 					out,
 					&evaluation_state.get_source(&source.0).unwrap(),
modifiedcrates/jrsonnet-evaluator/src/typed.rsdiffbeforeafterboth
--- a/crates/jrsonnet-evaluator/src/typed.rs
+++ b/crates/jrsonnet-evaluator/src/typed.rs
@@ -16,8 +16,8 @@
 		match $value {
 			$match(v) => v,
 			_ => unreachable!(),
-		}
-	}}
+			}
+		}};
 }
 
 #[derive(Debug, Error, Clone)]