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

difftreelog

refactor Option<&ExprLocation> -> &Option<_>

Yaroslav Bolyukin2021-01-24parent: #a16a15d.patch.diff
in: master

6 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	evaluate, parse_args, primitive_equals, push, throw,5	typed::CheckType,6	with_state, ArrValue, Context, FuncVal, LazyVal, Val,7};8use format::{format_arr, format_obj};9use jrsonnet_interner::IStr;10use jrsonnet_parser::{ArgsDesc, BinaryOpType, ExprLocation};11use jrsonnet_types::ty;12use std::{collections::HashMap, path::PathBuf, rc::Rc};1314pub mod stdlib;15pub use stdlib::*;1617use self::manifest::{escape_string_json, manifest_json_ex, ManifestJsonOptions, ManifestType};1819pub mod format;20pub mod manifest;21pub mod sort;2223fn std_format(str: IStr, vals: Val) -> Result<Val> {24	push(25		&Some(ExprLocation(Rc::from(PathBuf::from("std.jsonnet")), 0, 0)),26		|| format!("std.format of {}", str),27		|| {28			Ok(match vals {29				Val::Arr(vals) => Val::Str(format_arr(&str, &vals.evaluated()?)?.into()),30				Val::Obj(obj) => Val::Str(format_obj(&str, &obj)?.into()),31				o => Val::Str(format_arr(&str, &[o])?.into()),32			})33		},34	)35}3637type Builtin = fn(context: Context, loc: &Option<ExprLocation>, args: &ArgsDesc) -> Result<Val>;3839type BuiltinsType = HashMap<Box<str>, Builtin>;4041thread_local! {42	static BUILTINS: BuiltinsType = {43		[44			("length".into(), builtin_length as Builtin),45			("type".into(), builtin_type),46			("makeArray".into(), builtin_make_array),47			("codepoint".into(), builtin_codepoint),48			("objectFieldsEx".into(), builtin_object_fields_ex),49			("objectHasEx".into(), builtin_object_has_ex),50			("slice".into(), builtin_slice),51			("primitiveEquals".into(), builtin_primitive_equals),52			("equals".into(), builtin_equals),53			("modulo".into(), builtin_modulo),54			("mod".into(), builtin_mod),55			("floor".into(), builtin_floor),56			("log".into(), builtin_log),57			("pow".into(), builtin_pow),58			("extVar".into(), builtin_ext_var),59			("native".into(), builtin_native),60			("filter".into(), builtin_filter),61			("foldl".into(), builtin_foldl),62			("foldr".into(), builtin_foldr),63			("sortImpl".into(), builtin_sort_impl),64			("format".into(), builtin_format),65			("range".into(), builtin_range),66			("char".into(), builtin_char),67			("encodeUTF8".into(), builtin_encode_utf8),68			("md5".into(), builtin_md5),69			("base64".into(), builtin_base64),70			("trace".into(), builtin_trace),71			("join".into(), builtin_join),72			("escapeStringJson".into(), builtin_escape_string_json),73			("manifestJsonEx".into(), builtin_manifest_json_ex),74			("reverse".into(), builtin_reverse),75			("id".into(), builtin_id),76			("strReplace".into(), builtin_str_replace),77		].iter().cloned().collect()78	};79}8081fn builtin_length(context: Context, _loc: &Option<ExprLocation>, args: &ArgsDesc) -> Result<Val> {82	parse_args!(context, "length", args, 1, [83		0, x: ty!((string | object | array));84	], {85		Ok(match x {86			Val::Str(n) => Val::Num(n.chars().count() as f64),87			Val::Arr(a) => Val::Num(a.len() as f64),88			Val::Obj(o) => Val::Num(89				o.fields_visibility()90					.into_iter()91					.filter(|(_k, v)| *v)92					.count() as f64,93			),94			_ => unreachable!(),95		})96	})97}9899fn builtin_type(context: Context, _loc: &Option<ExprLocation>, args: &ArgsDesc) -> Result<Val> {100	parse_args!(context, "type", args, 1, [101		0, x: ty!(any);102	], {103		Ok(Val::Str(x.value_type().name().into()))104	})105}106107fn builtin_make_array(108	context: Context,109	_loc: &Option<ExprLocation>,110	args: &ArgsDesc,111) -> Result<Val> {112	parse_args!(context, "makeArray", args, 2, [113		0, sz: ty!(BoundedNumber<(Some(0.0)), (None)>) => Val::Num;114		1, func: ty!(function) => Val::Func;115	], {116		let mut out = Vec::with_capacity(sz as usize);117		for i in 0..sz as usize {118			out.push(LazyVal::new_resolved(func.evaluate_values(119				Context::new(),120				&[Val::Num(i as f64)]121			)?))122		}123		Ok(Val::Arr(out.into()))124	})125}126127fn builtin_codepoint(128	context: Context,129	_loc: &Option<ExprLocation>,130	args: &ArgsDesc,131) -> Result<Val> {132	parse_args!(context, "codepoint", args, 1, [133		0, str: ty!(char) => Val::Str;134	], {135		Ok(Val::Num(str.chars().next().unwrap() as u32 as f64))136	})137}138139fn builtin_object_fields_ex(140	context: Context,141	_loc: &Option<ExprLocation>,142	args: &ArgsDesc,143) -> Result<Val> {144	parse_args!(context, "objectFieldsEx", args, 2, [145		0, obj: ty!(object) => Val::Obj;146		1, inc_hidden: ty!(boolean) => Val::Bool;147	], {148		let mut out = obj.fields_visibility()149			.into_iter()150			.filter(|(_k, v)| *v || inc_hidden)151			.map(|(k, _v)|k)152			.collect::<Vec<_>>();153		out.sort();154		Ok(Val::Arr(out.into_iter().map(Val::Str).collect::<Vec<_>>().into()))155	})156}157158fn builtin_object_has_ex(159	context: Context,160	_loc: &Option<ExprLocation>,161	args: &ArgsDesc,162) -> Result<Val> {163	parse_args!(context, "objectHasEx", args, 3, [164		0, obj: ty!(object) => Val::Obj;165		1, f: ty!(string) => Val::Str;166		2, inc_hidden: ty!(boolean) => Val::Bool;167	], {168		Ok(Val::Bool(169			obj.fields_visibility()170				.into_iter()171				.filter(|(_k, v)| *v || inc_hidden)172				.any(|(k, _v)| *k == *f),173		))174	})175}176177// faster178fn builtin_slice(context: Context, _loc: &Option<ExprLocation>, args: &ArgsDesc) -> Result<Val> {179	parse_args!(context, "slice", args, 4, [180		0, indexable: ty!((string | array));181		1, index: ty!((number | null));182		2, end: ty!((number | null));183		3, step: ty!((number | null));184	], {185		let index = match index {186			Val::Num(v) => v as usize,187			Val::Null => 0,188			_ => unreachable!(),189		};190		let end = match end {191			Val::Num(v) => v as usize,192			Val::Null => match &indexable {193				Val::Str(s) => s.chars().count(),194				Val::Arr(v) => v.len(),195				_ => unreachable!()196			},197			_ => unreachable!()198		};199		let step = match step {200			Val::Num(v) => v as usize,201			Val::Null => 1,202			_ => unreachable!()203		};204		match &indexable {205			Val::Str(s) => {206				Ok(Val::Str((s.chars().skip(index).take(end-index).step_by(step).collect::<String>()).into()))207			}208			Val::Arr(arr) => {209				Ok(Val::Arr((arr.iter().skip(index).take(end-index).step_by(step).collect::<Result<Vec<Val>>>()?).into()))210			}211			_ => unreachable!()212		}213	})214}215216// faster217fn builtin_primitive_equals(218	context: Context,219	_loc: &Option<ExprLocation>,220	args: &ArgsDesc,221) -> Result<Val> {222	parse_args!(context, "primitiveEquals", args, 2, [223		0, a: ty!(any);224		1, b: ty!(any);225	], {226		Ok(Val::Bool(primitive_equals(&a, &b)?))227	})228}229230// faster231fn builtin_equals(context: Context, _loc: &Option<ExprLocation>, args: &ArgsDesc) -> Result<Val> {232	parse_args!(context, "equals", args, 2, [233		0, a: ty!(any);234		1, b: ty!(any);235	], {236		Ok(Val::Bool(equals(&a, &b)?))237	})238}239240fn builtin_modulo(context: Context, _loc: &Option<ExprLocation>, args: &ArgsDesc) -> Result<Val> {241	parse_args!(context, "modulo", args, 2, [242		0, a: ty!(number) => Val::Num;243		1, b: ty!(number) => Val::Num;244	], {245		Ok(Val::Num(a % b))246	})247}248249fn builtin_mod(context: Context, _loc: &Option<ExprLocation>, args: &ArgsDesc) -> Result<Val> {250	parse_args!(context, "mod", args, 2, [251		0, a: ty!((number | string));252		1, b: ty!(any);253	], {254		match (a, b) {255			(Val::Num(a), Val::Num(b)) => Ok(Val::Num(a % b)),256			(Val::Str(str), vals) => std_format(str, vals),257			(a, b) => throw!(BinaryOperatorDoesNotOperateOnValues(BinaryOpType::Mod, a.value_type(), b.value_type()))258		}259	})260}261262fn builtin_floor(context: Context, _loc: &Option<ExprLocation>, args: &ArgsDesc) -> Result<Val> {263	parse_args!(context, "floor", args, 1, [264		0, x: ty!(number) => Val::Num;265	], {266		Ok(Val::Num(x.floor()))267	})268}269270fn builtin_log(context: Context, _loc: &Option<ExprLocation>, args: &ArgsDesc) -> Result<Val> {271	parse_args!(context, "log", args, 1, [272		0, n: ty!(number) => Val::Num;273	], {274		Ok(Val::Num(n.ln()))275	})276}277278fn builtin_pow(context: Context, _loc: &Option<ExprLocation>, args: &ArgsDesc) -> Result<Val> {279	parse_args!(context, "pow", args, 2, [280		0, x: ty!(number) => Val::Num;281		1, n: ty!(number) => Val::Num;282	], {283		Ok(Val::Num(x.powf(n)))284	})285}286287fn builtin_ext_var(context: Context, _loc: &Option<ExprLocation>, args: &ArgsDesc) -> Result<Val> {288	parse_args!(context, "extVar", args, 1, [289		0, x: ty!(string) => Val::Str;290	], {291		Ok(with_state(|s| s.settings().ext_vars.get(&x).cloned()).ok_or(UndefinedExternalVariable(x))?)292	})293}294295fn builtin_native(context: Context, _loc: &Option<ExprLocation>, args: &ArgsDesc) -> Result<Val> {296	parse_args!(context, "native", args, 1, [297		0, x: ty!(string) => Val::Str;298	], {299		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))?)300	})301}302303fn builtin_filter(context: Context, _loc: &Option<ExprLocation>, args: &ArgsDesc) -> Result<Val> {304	parse_args!(context, "filter", args, 2, [305		0, func: ty!(function) => Val::Func;306		1, arr: ty!(array) => Val::Arr;307	], {308		let mut out = Vec::new();309		for item in arr.iter() {310			let item = item?;311			if func312						.evaluate_values(context.clone(), &[item.clone()])?313						.try_cast_bool("filter predicate")? {314							out.push(item);315						}316		}317		Ok(Val::Arr(out.into()))318	})319}320321fn builtin_foldl(context: Context, _loc: &Option<ExprLocation>, args: &ArgsDesc) -> Result<Val> {322	parse_args!(context, "foldl", args, 3, [323		0, func: ty!(function) => Val::Func;324		1, arr: ty!(array) => Val::Arr;325		2, init: ty!(any);326	], {327		let mut acc = init;328		for i in arr.iter() {329			acc = func.evaluate_values(context.clone(), &[acc, i?])?;330		}331		Ok(acc)332	})333}334335fn builtin_foldr(context: Context, _loc: &Option<ExprLocation>, args: &ArgsDesc) -> Result<Val> {336	parse_args!(context, "foldr", args, 3, [337		0, func: ty!(function) => Val::Func;338		1, arr: ty!(array) => Val::Arr;339		2, init: ty!(any);340	], {341		let mut acc = init;342		for i in arr.iter().rev() {343			acc = func.evaluate_values(context.clone(), &[acc, i?])?;344		}345		Ok(acc)346	})347}348349#[allow(non_snake_case)]350fn builtin_sort_impl(351	context: Context,352	_loc: &Option<ExprLocation>,353	args: &ArgsDesc,354) -> Result<Val> {355	parse_args!(context, "sort", args, 2, [356		0, arr: ty!(array) => Val::Arr;357		1, keyF: ty!(function) => Val::Func;358	], {359		if arr.len() <= 1 {360			return Ok(Val::Arr(arr))361		}362		Ok(Val::Arr(ArrValue::Eager(sort::sort(context, arr.evaluated()?, &keyF)?)))363	})364}365366// faster367fn builtin_format(context: Context, _loc: &Option<ExprLocation>, args: &ArgsDesc) -> Result<Val> {368	parse_args!(context, "format", args, 2, [369		0, str: ty!(string) => Val::Str;370		1, vals: ty!(any)371	], {372		std_format(str, vals)373	})374}375376fn builtin_range(context: Context, _loc: &Option<ExprLocation>, args: &ArgsDesc) -> Result<Val> {377	parse_args!(context, "range", args, 2, [378		0, from: ty!(number) => Val::Num;379		1, to: ty!(number) => Val::Num;380	], {381		let mut out = Vec::with_capacity((1+to as usize-from as usize).max(0));382		for i in from as usize..=to as usize {383			out.push(Val::Num(i as f64));384		}385		Ok(Val::Arr(out.into()))386	})387}388389fn builtin_char(context: Context, _loc: &Option<ExprLocation>, args: &ArgsDesc) -> Result<Val> {390	parse_args!(context, "char", args, 1, [391		0, n: ty!(number) => Val::Num;392	], {393		let mut out = String::new();394		out.push(std::char::from_u32(n as u32).ok_or_else(||395			InvalidUnicodeCodepointGot(n as u32)396		)?);397		Ok(Val::Str(out.into()))398	})399}400401fn builtin_encode_utf8(402	context: Context,403	_loc: &Option<ExprLocation>,404	args: &ArgsDesc,405) -> Result<Val> {406	parse_args!(context, "encodeUTF8", args, 1, [407		0, str: ty!(string) => Val::Str;408	], {409		Ok(Val::Arr((str.bytes().map(|b| Val::Num(b as f64)).collect::<Vec<Val>>()).into()))410	})411}412413fn builtin_md5(context: Context, _loc: &Option<ExprLocation>, args: &ArgsDesc) -> Result<Val> {414	parse_args!(context, "md5", args, 1, [415		0, str: ty!(string) => Val::Str;416	], {417		Ok(Val::Str(format!("{:x}", md5::compute(&str.as_bytes())).into()))418	})419}420421fn builtin_trace(context: Context, loc: &Option<ExprLocation>, args: &ArgsDesc) -> Result<Val> {422	parse_args!(context, "trace", args, 2, [423		0, str: ty!(string) => Val::Str;424		1, rest: ty!(any);425	], {426		eprint!("TRACE:");427		if let Some(loc) = loc {428			with_state(|s|{429				let locs = s.map_source_locations(&loc.0, &[loc.1]);430				eprint!(" {}:{}", loc.0.file_name().unwrap().to_str().unwrap(), locs[0].line);431			});432		}433		eprintln!(" {}", str);434		Ok(rest)435	})436}437438fn builtin_base64(context: Context, _loc: &Option<ExprLocation>, args: &ArgsDesc) -> Result<Val> {439	parse_args!(context, "base64", args, 1, [440		0, input: ty!((string | (Array<number>)));441	], {442		Ok(Val::Str(match input {443			Val::Str(s) => {444				base64::encode(s.bytes().collect::<Vec<_>>()).into()445			},446			Val::Arr(a) => {447				base64::encode(a.iter().map(|v| {448					Ok(v?.clone().unwrap_num()? as u8)449				}).collect::<Result<Vec<_>>>()?).into()450			},451			_ => unreachable!()452		}))453	})454}455456fn builtin_join(context: Context, _loc: &Option<ExprLocation>, args: &ArgsDesc) -> Result<Val> {457	parse_args!(context, "join", args, 2, [458		0, sep: ty!((string | array));459		1, arr: ty!(array) => Val::Arr;460	], {461		Ok(match sep {462			Val::Arr(joiner_items) => {463				let mut out = Vec::new();464465				let mut first = true;466				for item in arr.iter() {467					let item = item?.clone();468					if let Val::Arr(items) = item {469						if !first {470							out.reserve(joiner_items.len());471							// TODO: extend472							for item in joiner_items.iter() {473								out.push(item?);474							}475						}476						first = false;477						out.reserve(items.len());478						// TODO: extend479						for item in items.iter() {480							out.push(item?);481						}482					} else {483						throw!(RuntimeError("in std.join all items should be arrays".into()));484					}485				}486487				Val::Arr(out.into())488			},489			Val::Str(sep) => {490				let mut out = String::new();491492				let mut first = true;493				for item in arr.iter() {494					let item = item?.clone();495					if let Val::Str(item) = item {496						if !first {497							out += &sep;498						}499						first = false;500						out += &item;501					} else {502						throw!(RuntimeError("in std.join all items should be strings".into()));503					}504				}505506				Val::Str(out.into())507			},508			_ => unreachable!()509		})510	})511}512513// faster514fn builtin_escape_string_json(515	context: Context,516	_loc: &Option<ExprLocation>,517	args: &ArgsDesc,518) -> Result<Val> {519	parse_args!(context, "escapeStringJson", args, 1, [520		0, str_: ty!(string) => Val::Str;521	], {522		Ok(Val::Str(escape_string_json(&str_).into()))523	})524}525526// faster527fn builtin_manifest_json_ex(528	context: Context,529	_loc: &Option<ExprLocation>,530	args: &ArgsDesc,531) -> Result<Val> {532	parse_args!(context, "manifestJsonEx", args, 2, [533		0, value: ty!(any);534		1, indent: ty!(string) => Val::Str;535	], {536		Ok(Val::Str(manifest_json_ex(&value, &ManifestJsonOptions {537			padding: &indent,538			mtype: ManifestType::Std,539		})?.into()))540	})541}542543// faster544fn builtin_reverse(context: Context, _loc: &Option<ExprLocation>, args: &ArgsDesc) -> Result<Val> {545	parse_args!(context, "reverse", args, 1, [546		0, value: ty!(array) => Val::Arr;547	], {548		Ok(Val::Arr(value.reversed()))549	})550}551552fn builtin_id(context: Context, _loc: &Option<ExprLocation>, args: &ArgsDesc) -> Result<Val> {553	parse_args!(context, "id", args, 1, [554		0, v: ty!(any);555	], {556		Ok(v)557	})558}559560// faster561fn builtin_str_replace(562	context: Context,563	_loc: &Option<ExprLocation>,564	args: &ArgsDesc,565) -> Result<Val> {566	parse_args!(context, "strReplace", args, 3, [567		0, str: ty!(string) => Val::Str;568		1, from: ty!(string) => Val::Str;569		2, to: ty!(string) => Val::Str;570	], {571		let mut out = String::new();572		let mut last_idx = 0;573		while let Some(idx) = (&str[last_idx..]).find(&from as &str) {574			out.push_str(&str[last_idx..last_idx+idx]);575			out.push_str(&to);576			last_idx += idx + from.len();577		}578		if last_idx == 0 {579			return Ok(Val::Str(str))580		}581		out.push_str(&str[last_idx..]);582		Ok(Val::Str(out.into()))583	})584}585586#[allow(clippy::cognitive_complexity)]587pub fn call_builtin(588	context: Context,589	loc: &Option<ExprLocation>,590	name: &str,591	args: &ArgsDesc,592) -> Result<Val> {593	if let Some(f) = BUILTINS.with(|builtins| builtins.get(name).map(|f| *f)) {594		return Ok(f(context, loc, args)?);595	}596	throw!(IntrinsicNotFound(name.into()))597}
after · crates/jrsonnet-evaluator/src/builtin/mod.rs
1use crate::{2	equals,3	error::{Error::*, Result},4	evaluate, parse_args, primitive_equals, push, throw,5	typed::CheckType,6	with_state, ArrValue, Context, FuncVal, LazyVal, Val,7};8use format::{format_arr, format_obj};9use jrsonnet_interner::IStr;10use jrsonnet_parser::{ArgsDesc, BinaryOpType, ExprLocation};11use jrsonnet_types::ty;12use std::{collections::HashMap, path::PathBuf, rc::Rc};1314pub mod stdlib;15pub use stdlib::*;1617use self::manifest::{escape_string_json, manifest_json_ex, ManifestJsonOptions, ManifestType};1819pub mod format;20pub mod manifest;21pub mod sort;2223fn std_format(str: IStr, vals: Val) -> Result<Val> {24	push(25		Some(&ExprLocation(Rc::from(PathBuf::from("std.jsonnet")), 0, 0)),26		|| format!("std.format of {}", str),27		|| {28			Ok(match vals {29				Val::Arr(vals) => Val::Str(format_arr(&str, &vals.evaluated()?)?.into()),30				Val::Obj(obj) => Val::Str(format_obj(&str, &obj)?.into()),31				o => Val::Str(format_arr(&str, &[o])?.into()),32			})33		},34	)35}3637type Builtin = fn(context: Context, loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val>;3839type BuiltinsType = HashMap<Box<str>, Builtin>;4041thread_local! {42	static BUILTINS: BuiltinsType = {43		[44			("length".into(), builtin_length as Builtin),45			("type".into(), builtin_type),46			("makeArray".into(), builtin_make_array),47			("codepoint".into(), builtin_codepoint),48			("objectFieldsEx".into(), builtin_object_fields_ex),49			("objectHasEx".into(), builtin_object_has_ex),50			("slice".into(), builtin_slice),51			("primitiveEquals".into(), builtin_primitive_equals),52			("equals".into(), builtin_equals),53			("modulo".into(), builtin_modulo),54			("mod".into(), builtin_mod),55			("floor".into(), builtin_floor),56			("log".into(), builtin_log),57			("pow".into(), builtin_pow),58			("extVar".into(), builtin_ext_var),59			("native".into(), builtin_native),60			("filter".into(), builtin_filter),61			("foldl".into(), builtin_foldl),62			("foldr".into(), builtin_foldr),63			("sortImpl".into(), builtin_sort_impl),64			("format".into(), builtin_format),65			("range".into(), builtin_range),66			("char".into(), builtin_char),67			("encodeUTF8".into(), builtin_encode_utf8),68			("md5".into(), builtin_md5),69			("base64".into(), builtin_base64),70			("trace".into(), builtin_trace),71			("join".into(), builtin_join),72			("escapeStringJson".into(), builtin_escape_string_json),73			("manifestJsonEx".into(), builtin_manifest_json_ex),74			("reverse".into(), builtin_reverse),75			("id".into(), builtin_id),76			("strReplace".into(), builtin_str_replace),77		].iter().cloned().collect()78	};79}8081fn builtin_length(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val> {82	parse_args!(context, "length", args, 1, [83		0, x: ty!((string | object | array));84	], {85		Ok(match x {86			Val::Str(n) => Val::Num(n.chars().count() as f64),87			Val::Arr(a) => Val::Num(a.len() as f64),88			Val::Obj(o) => Val::Num(89				o.fields_visibility()90					.into_iter()91					.filter(|(_k, v)| *v)92					.count() as f64,93			),94			_ => unreachable!(),95		})96	})97}9899fn builtin_type(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val> {100	parse_args!(context, "type", args, 1, [101		0, x: ty!(any);102	], {103		Ok(Val::Str(x.value_type().name().into()))104	})105}106107fn builtin_make_array(108	context: Context,109	_loc: Option<&ExprLocation>,110	args: &ArgsDesc,111) -> Result<Val> {112	parse_args!(context, "makeArray", args, 2, [113		0, sz: ty!(BoundedNumber<(Some(0.0)), (None)>) => Val::Num;114		1, func: ty!(function) => Val::Func;115	], {116		let mut out = Vec::with_capacity(sz as usize);117		for i in 0..sz as usize {118			out.push(LazyVal::new_resolved(func.evaluate_values(119				Context::new(),120				&[Val::Num(i as f64)]121			)?))122		}123		Ok(Val::Arr(out.into()))124	})125}126127fn builtin_codepoint(128	context: Context,129	_loc: Option<&ExprLocation>,130	args: &ArgsDesc,131) -> Result<Val> {132	parse_args!(context, "codepoint", args, 1, [133		0, str: ty!(char) => Val::Str;134	], {135		Ok(Val::Num(str.chars().next().unwrap() as u32 as f64))136	})137}138139fn builtin_object_fields_ex(140	context: Context,141	_loc: Option<&ExprLocation>,142	args: &ArgsDesc,143) -> Result<Val> {144	parse_args!(context, "objectFieldsEx", args, 2, [145		0, obj: ty!(object) => Val::Obj;146		1, inc_hidden: ty!(boolean) => Val::Bool;147	], {148		let mut out = obj.fields_visibility()149			.into_iter()150			.filter(|(_k, v)| *v || inc_hidden)151			.map(|(k, _v)|k)152			.collect::<Vec<_>>();153		out.sort();154		Ok(Val::Arr(out.into_iter().map(Val::Str).collect::<Vec<_>>().into()))155	})156}157158fn builtin_object_has_ex(159	context: Context,160	_loc: Option<&ExprLocation>,161	args: &ArgsDesc,162) -> Result<Val> {163	parse_args!(context, "objectHasEx", args, 3, [164		0, obj: ty!(object) => Val::Obj;165		1, f: ty!(string) => Val::Str;166		2, inc_hidden: ty!(boolean) => Val::Bool;167	], {168		Ok(Val::Bool(169			obj.fields_visibility()170				.into_iter()171				.filter(|(_k, v)| *v || inc_hidden)172				.any(|(k, _v)| *k == *f),173		))174	})175}176177// faster178fn builtin_slice(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val> {179	parse_args!(context, "slice", args, 4, [180		0, indexable: ty!((string | array));181		1, index: ty!((number | null));182		2, end: ty!((number | null));183		3, step: ty!((number | null));184	], {185		let index = match index {186			Val::Num(v) => v as usize,187			Val::Null => 0,188			_ => unreachable!(),189		};190		let end = match end {191			Val::Num(v) => v as usize,192			Val::Null => match &indexable {193				Val::Str(s) => s.chars().count(),194				Val::Arr(v) => v.len(),195				_ => unreachable!()196			},197			_ => unreachable!()198		};199		let step = match step {200			Val::Num(v) => v as usize,201			Val::Null => 1,202			_ => unreachable!()203		};204		match &indexable {205			Val::Str(s) => {206				Ok(Val::Str((s.chars().skip(index).take(end-index).step_by(step).collect::<String>()).into()))207			}208			Val::Arr(arr) => {209				Ok(Val::Arr((arr.iter().skip(index).take(end-index).step_by(step).collect::<Result<Vec<Val>>>()?).into()))210			}211			_ => unreachable!()212		}213	})214}215216// faster217fn builtin_primitive_equals(218	context: Context,219	_loc: Option<&ExprLocation>,220	args: &ArgsDesc,221) -> Result<Val> {222	parse_args!(context, "primitiveEquals", args, 2, [223		0, a: ty!(any);224		1, b: ty!(any);225	], {226		Ok(Val::Bool(primitive_equals(&a, &b)?))227	})228}229230// faster231fn builtin_equals(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val> {232	parse_args!(context, "equals", args, 2, [233		0, a: ty!(any);234		1, b: ty!(any);235	], {236		Ok(Val::Bool(equals(&a, &b)?))237	})238}239240fn builtin_modulo(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val> {241	parse_args!(context, "modulo", args, 2, [242		0, a: ty!(number) => Val::Num;243		1, b: ty!(number) => Val::Num;244	], {245		Ok(Val::Num(a % b))246	})247}248249fn builtin_mod(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val> {250	parse_args!(context, "mod", args, 2, [251		0, a: ty!((number | string));252		1, b: ty!(any);253	], {254		match (a, b) {255			(Val::Num(a), Val::Num(b)) => Ok(Val::Num(a % b)),256			(Val::Str(str), vals) => std_format(str, vals),257			(a, b) => throw!(BinaryOperatorDoesNotOperateOnValues(BinaryOpType::Mod, a.value_type(), b.value_type()))258		}259	})260}261262fn builtin_floor(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val> {263	parse_args!(context, "floor", args, 1, [264		0, x: ty!(number) => Val::Num;265	], {266		Ok(Val::Num(x.floor()))267	})268}269270fn builtin_log(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val> {271	parse_args!(context, "log", args, 1, [272		0, n: ty!(number) => Val::Num;273	], {274		Ok(Val::Num(n.ln()))275	})276}277278fn builtin_pow(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val> {279	parse_args!(context, "pow", args, 2, [280		0, x: ty!(number) => Val::Num;281		1, n: ty!(number) => Val::Num;282	], {283		Ok(Val::Num(x.powf(n)))284	})285}286287fn builtin_ext_var(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val> {288	parse_args!(context, "extVar", args, 1, [289		0, x: ty!(string) => Val::Str;290	], {291		Ok(with_state(|s| s.settings().ext_vars.get(&x).cloned()).ok_or(UndefinedExternalVariable(x))?)292	})293}294295fn builtin_native(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val> {296	parse_args!(context, "native", args, 1, [297		0, x: ty!(string) => Val::Str;298	], {299		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))?)300	})301}302303fn builtin_filter(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val> {304	parse_args!(context, "filter", args, 2, [305		0, func: ty!(function) => Val::Func;306		1, arr: ty!(array) => Val::Arr;307	], {308		let mut out = Vec::new();309		for item in arr.iter() {310			let item = item?;311			if func312						.evaluate_values(context.clone(), &[item.clone()])?313						.try_cast_bool("filter predicate")? {314							out.push(item);315						}316		}317		Ok(Val::Arr(out.into()))318	})319}320321fn builtin_foldl(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val> {322	parse_args!(context, "foldl", args, 3, [323		0, func: ty!(function) => Val::Func;324		1, arr: ty!(array) => Val::Arr;325		2, init: ty!(any);326	], {327		let mut acc = init;328		for i in arr.iter() {329			acc = func.evaluate_values(context.clone(), &[acc, i?])?;330		}331		Ok(acc)332	})333}334335fn builtin_foldr(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val> {336	parse_args!(context, "foldr", args, 3, [337		0, func: ty!(function) => Val::Func;338		1, arr: ty!(array) => Val::Arr;339		2, init: ty!(any);340	], {341		let mut acc = init;342		for i in arr.iter().rev() {343			acc = func.evaluate_values(context.clone(), &[acc, i?])?;344		}345		Ok(acc)346	})347}348349#[allow(non_snake_case)]350fn builtin_sort_impl(351	context: Context,352	_loc: Option<&ExprLocation>,353	args: &ArgsDesc,354) -> Result<Val> {355	parse_args!(context, "sort", args, 2, [356		0, arr: ty!(array) => Val::Arr;357		1, keyF: ty!(function) => Val::Func;358	], {359		if arr.len() <= 1 {360			return Ok(Val::Arr(arr))361		}362		Ok(Val::Arr(ArrValue::Eager(sort::sort(context, arr.evaluated()?, &keyF)?)))363	})364}365366// faster367fn builtin_format(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val> {368	parse_args!(context, "format", args, 2, [369		0, str: ty!(string) => Val::Str;370		1, vals: ty!(any)371	], {372		std_format(str, vals)373	})374}375376fn builtin_range(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val> {377	parse_args!(context, "range", args, 2, [378		0, from: ty!(number) => Val::Num;379		1, to: ty!(number) => Val::Num;380	], {381		let mut out = Vec::with_capacity((1+to as usize-from as usize).max(0));382		for i in from as usize..=to as usize {383			out.push(Val::Num(i as f64));384		}385		Ok(Val::Arr(out.into()))386	})387}388389fn builtin_char(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val> {390	parse_args!(context, "char", args, 1, [391		0, n: ty!(number) => Val::Num;392	], {393		let mut out = String::new();394		out.push(std::char::from_u32(n as u32).ok_or_else(||395			InvalidUnicodeCodepointGot(n as u32)396		)?);397		Ok(Val::Str(out.into()))398	})399}400401fn builtin_encode_utf8(402	context: Context,403	_loc: Option<&ExprLocation>,404	args: &ArgsDesc,405) -> Result<Val> {406	parse_args!(context, "encodeUTF8", args, 1, [407		0, str: ty!(string) => Val::Str;408	], {409		Ok(Val::Arr((str.bytes().map(|b| Val::Num(b as f64)).collect::<Vec<Val>>()).into()))410	})411}412413fn builtin_md5(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val> {414	parse_args!(context, "md5", args, 1, [415		0, str: ty!(string) => Val::Str;416	], {417		Ok(Val::Str(format!("{:x}", md5::compute(&str.as_bytes())).into()))418	})419}420421fn builtin_trace(context: Context, loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val> {422	parse_args!(context, "trace", args, 2, [423		0, str: ty!(string) => Val::Str;424		1, rest: ty!(any);425	], {426		eprint!("TRACE:");427		if let Some(loc) = loc {428			with_state(|s|{429				let locs = s.map_source_locations(&loc.0, &[loc.1]);430				eprint!(" {}:{}", loc.0.file_name().unwrap().to_str().unwrap(), locs[0].line);431			});432		}433		eprintln!(" {}", str);434		Ok(rest)435	})436}437438fn builtin_base64(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val> {439	parse_args!(context, "base64", args, 1, [440		0, input: ty!((string | (Array<number>)));441	], {442		Ok(Val::Str(match input {443			Val::Str(s) => {444				base64::encode(s.bytes().collect::<Vec<_>>()).into()445			},446			Val::Arr(a) => {447				base64::encode(a.iter().map(|v| {448					Ok(v?.clone().unwrap_num()? as u8)449				}).collect::<Result<Vec<_>>>()?).into()450			},451			_ => unreachable!()452		}))453	})454}455456fn builtin_join(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val> {457	parse_args!(context, "join", args, 2, [458		0, sep: ty!((string | array));459		1, arr: ty!(array) => Val::Arr;460	], {461		Ok(match sep {462			Val::Arr(joiner_items) => {463				let mut out = Vec::new();464465				let mut first = true;466				for item in arr.iter() {467					let item = item?.clone();468					if let Val::Arr(items) = item {469						if !first {470							out.reserve(joiner_items.len());471							// TODO: extend472							for item in joiner_items.iter() {473								out.push(item?);474							}475						}476						first = false;477						out.reserve(items.len());478						// TODO: extend479						for item in items.iter() {480							out.push(item?);481						}482					} else {483						throw!(RuntimeError("in std.join all items should be arrays".into()));484					}485				}486487				Val::Arr(out.into())488			},489			Val::Str(sep) => {490				let mut out = String::new();491492				let mut first = true;493				for item in arr.iter() {494					let item = item?.clone();495					if let Val::Str(item) = item {496						if !first {497							out += &sep;498						}499						first = false;500						out += &item;501					} else {502						throw!(RuntimeError("in std.join all items should be strings".into()));503					}504				}505506				Val::Str(out.into())507			},508			_ => unreachable!()509		})510	})511}512513// faster514fn builtin_escape_string_json(515	context: Context,516	_loc: Option<&ExprLocation>,517	args: &ArgsDesc,518) -> Result<Val> {519	parse_args!(context, "escapeStringJson", args, 1, [520		0, str_: ty!(string) => Val::Str;521	], {522		Ok(Val::Str(escape_string_json(&str_).into()))523	})524}525526// faster527fn builtin_manifest_json_ex(528	context: Context,529	_loc: Option<&ExprLocation>,530	args: &ArgsDesc,531) -> Result<Val> {532	parse_args!(context, "manifestJsonEx", args, 2, [533		0, value: ty!(any);534		1, indent: ty!(string) => Val::Str;535	], {536		Ok(Val::Str(manifest_json_ex(&value, &ManifestJsonOptions {537			padding: &indent,538			mtype: ManifestType::Std,539		})?.into()))540	})541}542543// faster544fn builtin_reverse(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val> {545	parse_args!(context, "reverse", args, 1, [546		0, value: ty!(array) => Val::Arr;547	], {548		Ok(Val::Arr(value.reversed()))549	})550}551552fn builtin_id(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val> {553	parse_args!(context, "id", args, 1, [554		0, v: ty!(any);555	], {556		Ok(v)557	})558}559560// faster561fn builtin_str_replace(562	context: Context,563	_loc: Option<&ExprLocation>,564	args: &ArgsDesc,565) -> Result<Val> {566	parse_args!(context, "strReplace", args, 3, [567		0, str: ty!(string) => Val::Str;568		1, from: ty!(string) => Val::Str;569		2, to: ty!(string) => Val::Str;570	], {571		let mut out = String::new();572		let mut last_idx = 0;573		while let Some(idx) = (&str[last_idx..]).find(&from as &str) {574			out.push_str(&str[last_idx..last_idx+idx]);575			out.push_str(&to);576			last_idx += idx + from.len();577		}578		if last_idx == 0 {579			return Ok(Val::Str(str))580		}581		out.push_str(&str[last_idx..]);582		Ok(Val::Str(out.into()))583	})584}585586pub fn call_builtin(587	context: Context,588	loc: Option<&ExprLocation>,589	name: &str,590	args: &ArgsDesc,591) -> Result<Val> {592	if let Some(f) = BUILTINS.with(|builtins| builtins.get(name).map(|f| *f)) {593		return Ok(f(context, loc, args)?);594	}595	throw!(IntrinsicNotFound(name.into()))596}
modifiedcrates/jrsonnet-evaluator/src/evaluate.rsdiffbeforeafterboth
--- a/crates/jrsonnet-evaluator/src/evaluate.rs
+++ b/crates/jrsonnet-evaluator/src/evaluate.rs
@@ -385,7 +385,7 @@
 	context: Context,
 	value: &LocExpr,
 	args: &ArgsDesc,
-	loc: &Option<ExprLocation>,
+	loc: Option<&ExprLocation>,
 	tailstrict: bool,
 ) -> Result<Val> {
 	let value = evaluate(context.clone(), value)?;
@@ -430,7 +430,7 @@
 		BinaryOp(v1, o, v2) => evaluate_binary_op_special(context, v1, *o, v2)?,
 		UnaryOp(o, v) => evaluate_unary_op(*o, &evaluate(context, v)?)?,
 		Var(name) => push(
-			loc,
+			loc.as_ref(),
 			|| format!("variable <{}>", name),
 			|| Ok(context.binding(name.clone())?.evaluate()?),
 		)?,
@@ -448,7 +448,7 @@
 				(Val::Obj(v), Val::Str(s)) => {
 					let sn = s.clone();
 					push(
-						loc,
+						loc.as_ref(),
 						|| format!("field <{}> access", sn),
 						|| {
 							if let Some(v) = v.get(s.clone())? {
@@ -540,14 +540,14 @@
 			&evaluate(context.clone(), s)?,
 			&Val::Obj(evaluate_object(context, t)?),
 		)?,
-		Apply(value, args, tailstrict) => evaluate_apply(context, value, args, loc, *tailstrict)?,
+		Apply(value, args, tailstrict) => evaluate_apply(context, value, args, loc.as_ref(), *tailstrict)?,
 		Function(params, body) => {
 			evaluate_method(context, "anonymous".into(), params.clone(), body.clone())
 		}
 		Intrinsic(name) => Val::Func(Rc::new(FuncVal::Intrinsic(name.clone()))),
 		AssertExpr(AssertStmt(value, msg), returned) => {
 			let assertion_result = push(
-				&value.1,
+				value.1.as_ref(),
 				|| "assertion condition".to_owned(),
 				|| {
 					evaluate(context.clone(), value)?
@@ -558,7 +558,7 @@
 				evaluate(context, returned)?
 			} else {
 				push(
-					&value.1,
+					value.1.as_ref(),
 					|| "assertion failure".to_owned(),
 					|| {
 						if let Some(msg) = msg {
@@ -571,7 +571,7 @@
 			}
 		}
 		ErrorStmt(e) => push(
-			loc,
+			loc.as_ref(),
 			|| "error statement".to_owned(),
 			|| {
 				throw!(RuntimeError(
@@ -585,7 +585,7 @@
 			cond_else,
 		} => {
 			if push(
-				loc,
+				loc.as_ref(),
 				|| "if condition".to_owned(),
 				|| evaluate(context.clone(), &cond.0)?.try_cast_bool("in if condition"),
 			)? {
@@ -605,7 +605,7 @@
 			let import_location = Rc::make_mut(&mut tmp);
 			import_location.pop();
 			push(
-				loc,
+				loc.as_ref(),
 				|| format!("import {:?}", path),
 				|| with_state(|s| s.import_file(import_location, path)),
 			)?
modifiedcrates/jrsonnet-evaluator/src/function.rsdiffbeforeafterboth
--- a/crates/jrsonnet-evaluator/src/function.rs
+++ b/crates/jrsonnet-evaluator/src/function.rs
@@ -160,7 +160,7 @@
 					throw!(IntrinsicArgumentReorderingIsNotSupportedYet);
 				}
 			}
-			let $name = push(&None, || format!("evaluating argument"), || {
+			let $name = push(None, || format!("evaluating argument"), || {
 				let value = evaluate($ctx.clone(), &$name.1)?;
 				$ty.check(&value)?;
 				Ok(value)
modifiedcrates/jrsonnet-evaluator/src/lib.rsdiffbeforeafterboth
--- a/crates/jrsonnet-evaluator/src/lib.rs
+++ b/crates/jrsonnet-evaluator/src/lib.rs
@@ -128,7 +128,7 @@
 	EVAL_STATE.with(|s| f(s.borrow().as_ref().unwrap()))
 }
 pub(crate) fn push<T>(
-	e: &Option<ExprLocation>,
+	e: Option<&ExprLocation>,
 	frame_desc: impl FnOnce() -> String,
 	f: impl FnOnce() -> Result<T>,
 ) -> Result<T> {
modifiedcrates/jrsonnet-evaluator/src/typed.rsdiffbeforeafterboth
--- a/crates/jrsonnet-evaluator/src/typed.rs
+++ b/crates/jrsonnet-evaluator/src/typed.rs
@@ -78,7 +78,7 @@
 }
 
 fn push_type(
-	location: &Option<ExprLocation>,
+	location: Option<&ExprLocation>,
 	error_reason: impl Fn() -> String,
 	path: impl Fn() -> ValuePathItem,
 	item: impl Fn() -> Result<()>,
@@ -162,7 +162,7 @@
 				Val::Arr(a) => {
 					for (i, item) in a.iter().enumerate() {
 						push_type(
-							&None,
+							None,
 							|| format!("array index {}", i),
 							|| ValuePathItem::Index(i as u64),
 							|| Ok(elem_type.check(&item.clone()?)?),
@@ -176,7 +176,7 @@
 				Val::Arr(a) => {
 					for (i, item) in a.iter().enumerate() {
 						push_type(
-							&None,
+							None,
 							|| format!("array index {}", i),
 							|| ValuePathItem::Index(i as u64),
 							|| Ok(elem_type.check(&item.clone()?)?),
@@ -191,7 +191,7 @@
 					for (k, v) in elems.iter() {
 						if let Some(got_v) = obj.get((*k).into())? {
 							push_type(
-								&None,
+								None,
 								|| format!("property {}", k),
 								|| ValuePathItem::Field((*k).into()),
 								|| v.check(&got_v),
modifiedcrates/jrsonnet-evaluator/src/val.rsdiffbeforeafterboth
--- a/crates/jrsonnet-evaluator/src/val.rs
+++ b/crates/jrsonnet-evaluator/src/val.rs
@@ -102,7 +102,7 @@
 	pub fn evaluate(
 		&self,
 		call_ctx: Context,
-		loc: &Option<ExprLocation>,
+		loc: Option<&ExprLocation>,
 		args: &ArgsDesc,
 		tailstrict: bool,
 	) -> Result<Val> {