git.delta.rocks / jrsonnet / refs/commits / 7e00c7d820e8

difftreelog

source

crates/jrsonnet-evaluator/src/builtin/mod.rs10.6 KiBsourcehistory
1use crate::{2	equals,3	error::{Error::*, Result},4	evaluate, parse_args, primitive_equals, push, throw, with_state, Context, FuncVal, Val,5	ValType,6};7use format::{format_arr, format_obj};8use jrsonnet_parser::{ArgsDesc, ExprLocation};9use manifest::{escape_string_json, manifest_json_ex, ManifestJsonOptions, ManifestType};10use std::{path::PathBuf, rc::Rc};1112pub mod stdlib;13pub use stdlib::*;1415pub mod format;16pub mod manifest;17pub mod sort;1819#[allow(clippy::cognitive_complexity)]20pub fn call_builtin(21	context: Context,22	loc: &Option<ExprLocation>,23	ns: &str,24	name: &str,25	args: &ArgsDesc,26) -> Result<Val> {27	Ok(match (ns, name as &str) {28		// arr/string/function29		("std", "length") => parse_args!(context, "std.length", args, 1, [30			0, x: [Val::Str|Val::Arr|Val::Obj], vec![ValType::Str, ValType::Arr, ValType::Obj];31		], {32			Ok(match x {33				Val::Str(n) => Val::Num(n.chars().count() as f64),34				Val::Arr(i) => Val::Num(i.len() as f64),35				Val::Obj(o) => Val::Num(36					o.fields_visibility()37						.into_iter()38						.filter(|(_k, v)| *v)39						.count() as f64,40				),41				_ => unreachable!(),42			})43		})?,44		// any45		("std", "type") => parse_args!(context, "std.type", args, 1, [46			0, x, vec![];47		], {48			Ok(Val::Str(x.value_type()?.name().into()))49		})?,50		// length, idx=>any51		("std", "makeArray") => parse_args!(context, "std.makeArray", args, 2, [52			0, sz: [Val::Num]!!Val::Num, vec![ValType::Num];53			1, func: [Val::Func]!!Val::Func, vec![ValType::Func];54		], {55			if sz < 0.0 {56				throw!(RuntimeError(format!("makeArray requires size >= 0, got {}", sz).into()));57			}58			let mut out = Vec::with_capacity(sz as usize);59			for i in 0..sz as usize {60				out.push(func.evaluate_values(61					Context::new(),62					&[Val::Num(i as f64)]63				)?)64			}65			Ok(Val::Arr(Rc::new(out)))66		})?,67		// string68		("std", "codepoint") => parse_args!(context, "std.codepoint", args, 1, [69			0, str: [Val::Str]!!Val::Str, vec![ValType::Str];70		], {71			assert!(72				str.chars().count() == 1,73				"std.codepoint should receive single char string"74			);75			Ok(Val::Num(str.chars().take(1).next().unwrap() as u32 as f64))76		})?,77		// object, includeHidden78		("std", "objectFieldsEx") => parse_args!(context, "std.objectFieldsEx",args, 2, [79			0, obj: [Val::Obj]!!Val::Obj, vec![ValType::Obj];80			1, inc_hidden: [Val::Bool]!!Val::Bool, vec![ValType::Bool];81		], {82			let mut out = obj.fields_visibility()83				.into_iter()84				.filter(|(_k, v)| *v || inc_hidden)85				.map(|(k, _v)|k)86				.collect::<Vec<_>>();87			out.sort();88			Ok(Val::Arr(Rc::new(out.into_iter().map(Val::Str).collect())))89		})?,90		// object, field, includeHidden91		("std", "objectHasEx") => parse_args!(context, "std.objectHasEx", args, 3, [92			0, obj: [Val::Obj]!!Val::Obj, vec![ValType::Obj];93			1, f: [Val::Str]!!Val::Str, vec![ValType::Str];94			2, inc_hidden: [Val::Bool]!!Val::Bool, vec![ValType::Bool];95		], {96			Ok(Val::Bool(97				obj.fields_visibility()98					.into_iter()99					.filter(|(_k, v)| *v || inc_hidden)100					.any(|(k, _v)| *k == *f),101			))102		})?,103		("std", "primitiveEquals") => parse_args!(context, "std.primitiveEquals", args, 2, [104			0, a, vec![];105			1, b, vec![];106		], {107			Ok(Val::Bool(primitive_equals(&a, &b)?))108		})?,109		// faster110		("std", "equals") => parse_args!(context, "std.equals", args, 2, [111			0, a, vec![];112			1, b, vec![];113		], {114			Ok(Val::Bool(equals(&a, &b)?))115		})?,116		("std", "modulo") => parse_args!(context, "std.modulo", args, 2, [117			0, a: [Val::Num]!!Val::Num, vec![ValType::Num];118			1, b: [Val::Num]!!Val::Num, vec![ValType::Num];119		], {120			Ok(Val::Num(a % b))121		})?,122		("std", "floor") => parse_args!(context, "std.floor", args, 1, [123			0, x: [Val::Num]!!Val::Num, vec![ValType::Num];124		], {125			Ok(Val::Num(x.floor()))126		})?,127		("std", "log") => parse_args!(context, "std.log", args, 2, [128			0, n: [Val::Num]!!Val::Num, vec![ValType::Num];129		], {130			Ok(Val::Num(n.ln()))131		})?,132		("std", "trace") => parse_args!(context, "std.trace", args, 2, [133			0, str: [Val::Str]!!Val::Str, vec![ValType::Str];134			1, rest, vec![];135		], {136			eprint!("TRACE:");137			if let Some(loc) = loc {138				with_state(|s|{139					let locs = s.map_source_locations(&loc.0, &[loc.1]);140					eprint!(" {}:{}", loc.0.file_name().unwrap().to_str().unwrap(), locs[0].line);141				});142			}143			eprintln!(" {}", str);144			Ok(rest)145		})?,146		("std", "pow") => parse_args!(context, "std.modulo", args, 2, [147			0, x: [Val::Num]!!Val::Num, vec![ValType::Num];148			1, n: [Val::Num]!!Val::Num, vec![ValType::Num];149		], {150			Ok(Val::Num(x.powf(n)))151		})?,152		("std", "extVar") => parse_args!(context, "std.extVar", args, 1, [153			0, x: [Val::Str]!!Val::Str, vec![ValType::Str];154		], {155			Ok(with_state(|s| s.settings().ext_vars.get(&x).cloned()).ok_or_else(156				|| UndefinedExternalVariable(x),157			)?)158		})?,159		("std", "native") => parse_args!(context, "std.native", args, 1, [160			0, x: [Val::Str]!!Val::Str, vec![ValType::Str];161		], {162			Ok(with_state(|s| s.settings().ext_natives.get(&x).cloned()).map(|v| Val::Func(Rc::new(FuncVal::NativeExt(x.clone(), v)))).ok_or_else(163				|| UndefinedExternalFunction(x),164			)?)165		})?,166		("std", "filter") => parse_args!(context, "std.filter", args, 2, [167			0, func: [Val::Func]!!Val::Func, vec![ValType::Func];168			1, arr: [Val::Arr]!!Val::Arr, vec![ValType::Arr];169		], {170			Ok(Val::Arr(Rc::new(171				arr.iter()172					.cloned()173					.filter(|e| {174						func175							.evaluate_values(context.clone(), &[e.clone()])176							.unwrap()177							.try_cast_bool("filter predicate")178							.unwrap()179					})180					.collect(),181			)))182		})?,183		// faster184		("std", "foldl") => parse_args!(context, "std.foldl", args, 3, [185			0, func: [Val::Func]!!Val::Func, vec![ValType::Func];186			1, arr: [Val::Arr]!!Val::Arr, vec![ValType::Arr];187			2, init, vec![];188		], {189			let mut acc = init;190			for i in arr.iter().cloned() {191				acc = func.evaluate_values(context.clone(), &[acc, i])?;192			}193			Ok(acc)194		})?,195		// faster196		("std", "foldr") => parse_args!(context, "std.foldr", args, 3, [197			0, func: [Val::Func]!!Val::Func, vec![ValType::Func];198			1, arr: [Val::Arr]!!Val::Arr, vec![ValType::Arr];199			2, init, vec![];200		], {201			let mut acc = init;202			for i in arr.iter().rev().cloned() {203				acc = func.evaluate_values(context.clone(), &[acc, i])?;204			}205			Ok(acc)206		})?,207		// faster208		#[allow(non_snake_case)]209		("std", "sortImpl") => parse_args!(context, "std.sort", args, 2, [210			0, arr: [Val::Arr]!!Val::Arr, vec![ValType::Arr];211			1, keyF: [Val::Func]!!Val::Func, vec![ValType::Func];212		], {213			if arr.len() <= 1 {214				return Ok(Val::Arr(arr))215			}216			Ok(Val::Arr(sort::sort(context, arr, &keyF)?))217		})?,218		// faster219		("std", "format") => parse_args!(context, "std.format", args, 2, [220			0, str: [Val::Str]!!Val::Str, vec![ValType::Str];221			1, vals, vec![]222		], {223			push(&Some(ExprLocation(Rc::from(PathBuf::from("std.jsonnet")), 0, 0)), ||format!("std.format of {}", str), ||{224				Ok(match vals {225					Val::Arr(vals) => Val::Str(format_arr(&str, &vals)?.into()),226					Val::Obj(obj) => Val::Str(format_obj(&str, &obj)?.into()),227					o => Val::Str(format_arr(&str, &[o])?.into()),228				})229			})230		})?,231		// faster232		("std", "range") => parse_args!(context, "std.range", args, 2, [233			0, from: [Val::Num]!!Val::Num, vec![ValType::Num];234			1, to: [Val::Num]!!Val::Num, vec![ValType::Num];235		], {236			let mut out = Vec::with_capacity((1+to as usize-from as usize).max(0));237			for i in from as usize..=to as usize {238				out.push(Val::Num(i as f64));239			}240			Ok(Val::Arr(Rc::new(out)))241		})?,242		("std", "char") => parse_args!(context, "std.char", args, 1, [243			0, n: [Val::Num]!!Val::Num, vec![ValType::Num];244		], {245			let mut out = String::new();246			out.push(std::char::from_u32(n as u32).ok_or_else(||247				InvalidUnicodeCodepointGot(n as u32)248			)?);249			Ok(Val::Str(out.into()))250		})?,251		("std", "encodeUTF8") => parse_args!(context, "std.encodeUtf8", args, 1, [252			0, str: [Val::Str]!!Val::Str, vec![ValType::Str];253		], {254			Ok(Val::Arr(Rc::new(str.bytes().map(|b| Val::Num(b as f64)).collect())))255		})?,256		("std", "md5") => parse_args!(context, "std.md5", args, 1, [257			0, str: [Val::Str]!!Val::Str, vec![ValType::Str];258		], {259			Ok(Val::Str(format!("{:x}", md5::compute(&str.as_bytes())).into()))260		})?,261		// faster262		("std", "base64") => parse_args!(context, "std.base64", args, 1, [263			0, input: [Val::Str | Val::Arr], vec![ValType::Arr, ValType::Str];264		], {265			Ok(Val::Str(match input {266				Val::Str(s) => {267					base64::encode(s.bytes().collect::<Vec<_>>()).into()268				},269				Val::Arr(a) => {270					base64::encode(a.iter().map(|v| {271						Ok(v.clone().try_cast_num("base64 array")? as u8)272					}).collect::<Result<Vec<_>>>()?).into()273				},274				_ => unreachable!()275			}))276		})?,277		// faster278		("std", "join") => parse_args!(context, "std.join", args, 2, [279			0, sep: [Val::Str|Val::Arr], vec![ValType::Str, ValType::Arr];280			1, arr: [Val::Arr]!!Val::Arr, vec![ValType::Arr];281		], {282			Ok(match sep {283				Val::Arr(joiner_items) => {284					let mut out = Vec::new();285286					let mut first = true;287					for item in arr.iter().cloned() {288						if let Val::Arr(items) = item.unwrap_if_lazy()? {289							if !first {290								out.reserve(joiner_items.len());291								out.extend(joiner_items.iter().cloned());292							}293							first = false;294							out.reserve(items.len());295							out.extend(items.iter().cloned());296						} else {297							throw!(RuntimeError("in std.join all items should be arrays".into()));298						}299					}300301					Val::Arr(Rc::new(out))302				},303				Val::Str(sep) => {304					let mut out = String::new();305306					let mut first = true;307					for item in arr.iter().cloned() {308						if let Val::Str(item) = item.unwrap_if_lazy()? {309							if !first {310								out += &sep;311							}312							first = false;313							out += &item;314						} else {315							throw!(RuntimeError("in std.join all items should be strings".into()));316						}317					}318319					Val::Str(out.into())320				},321				_ => unreachable!()322			})323		})?,324		// Faster325		("std", "escapeStringJson") => parse_args!(context, "std.escapeStringJson", args, 1, [326			0, str_: [Val::Str]!!Val::Str, vec![ValType::Str];327		], {328			Ok(Val::Str(escape_string_json(&str_).into()))329		})?,330		// Faster331		("std", "manifestJsonEx") => parse_args!(context, "std.manifestJsonEx", args, 2, [332			0, value, vec![];333			1, indent: [Val::Str]!!Val::Str, vec![ValType::Str];334		], {335			Ok(Val::Str(manifest_json_ex(&value, &ManifestJsonOptions {336				padding: &indent,337				mtype: ManifestType::Std,338			})?.into()))339		})?,340		// Faster341		("std", "reverse") => parse_args!(context, "std.reverse", args, 1, [342			0, arr: [Val::Arr]!!Val::Arr, vec![ValType::Arr];343		], {344			let mut marr = arr;345			Rc::make_mut(&mut marr).reverse();346			Ok(Val::Arr(marr))347		})?,348		("std", "id") => parse_args!(context, "std.id", args, 1, [349			0, v, vec![];350		], {351			Ok(v)352		})?,353		(ns, name) => throw!(IntrinsicNotFound(ns.into(), name.into())),354	})355}