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

difftreelog

feat std.parseYaml intrinsic

Yaroslav Bolyukin2021-11-27parent: #7c0b097.patch.diff
in: master

6 files changed

modifiedcrates/jrsonnet-evaluator/Cargo.tomldiffbeforeafterboth
--- a/crates/jrsonnet-evaluator/Cargo.toml
+++ b/crates/jrsonnet-evaluator/Cargo.toml
@@ -7,11 +7,9 @@
 edition = "2018"
 
 [features]
-default = ["serialized-stdlib", "explaining-traces", "serde-json"]
+default = ["serialized-stdlib", "explaining-traces"]
 # Serializes standard library AST instead of parsing them every run
-serialized-stdlib = ["serde", "bincode", "jrsonnet-parser/deserialize"]
-# Allow to convert Val into serde_json::Value and backwards
-serde-json = ["serde", "serde_json"]
+serialized-stdlib = ["bincode", "jrsonnet-parser/deserialize"]
 # Rustc-like trace visualization
 explaining-traces = ["annotate-snippets"]
 # Allows library authors to throw custom errors
@@ -34,21 +32,17 @@
 thiserror = "1.0"
 gcmodule = { git = "https://github.com/CertainLach/gcmodule", branch = "jrsonnet" }
 
+serde = "1.0"
+serde_json = "1.0"
+serde_yaml = { git = "https://github.com/CertainLach/serde-yaml", branch = "feature/old-octals-quirk" }
+
 [dependencies.anyhow]
 version = "1.0"
 optional = true
 
 # Serialized stdlib
-[dependencies.serde]
-version = "1.0"
-optional = true
 [dependencies.bincode]
 version = "1.3.1"
-optional = true
-
-# Serde json
-[dependencies.serde_json]
-version = "1.0"
 optional = true
 
 # Explaining traces
modifiedcrates/jrsonnet-evaluator/src/builtin/mod.rsdiffbeforeafterboth
before · crates/jrsonnet-evaluator/src/builtin/mod.rs
1use crate::{2	builtin::manifest::{manifest_yaml_ex, ManifestYamlOptions},3	equals,4	error::{Error::*, Result},5	operator::evaluate_mod_op,6	parse_args, primitive_equals, push_frame, throw, with_state, ArrValue, Context,7	EvaluationState, FuncVal, IndexableVal, LazyVal, Val,8};9use format::{format_arr, format_obj};10use gcmodule::Cc;11use jrsonnet_interner::IStr;12use jrsonnet_parser::{ArgsDesc, ExprLocation};13use jrsonnet_types::ty;14use std::{collections::HashMap, path::PathBuf, rc::Rc};1516pub mod stdlib;17pub use stdlib::*;1819use self::manifest::{escape_string_json, manifest_json_ex, ManifestJsonOptions, ManifestType};2021pub mod format;22pub mod manifest;23pub mod sort;2425pub fn std_format(str: IStr, vals: Val) -> Result<Val> {26	push_frame(27		&ExprLocation(Rc::from(PathBuf::from("std.jsonnet")), 0, 0),28		|| format!("std.format of {}", str),29		|| {30			Ok(match vals {31				Val::Arr(vals) => Val::Str(format_arr(&str, &vals.evaluated()?)?.into()),32				Val::Obj(obj) => Val::Str(format_obj(&str, &obj)?.into()),33				o => Val::Str(format_arr(&str, &[o])?.into()),34			})35		},36	)37}3839pub fn std_slice(40	indexable: IndexableVal,41	index: Option<usize>,42	end: Option<usize>,43	step: Option<usize>,44) -> Result<Val> {45	let index = index.unwrap_or(0);46	let end = end.unwrap_or_else(|| match &indexable {47		IndexableVal::Str(_) => usize::MAX,48		IndexableVal::Arr(v) => v.len(),49	});50	let step = step.unwrap_or(1);51	match &indexable {52		IndexableVal::Str(s) => Ok(Val::Str(53			(s.chars()54				.skip(index)55				.take(end - index)56				.step_by(step)57				.collect::<String>())58			.into(),59		)),60		IndexableVal::Arr(arr) => Ok(Val::Arr(61			(arr.iter()62				.skip(index)63				.take(end - index)64				.step_by(step)65				.collect::<Result<Vec<Val>>>()?)66			.into(),67		)),68	}69}7071type Builtin = fn(context: Context, loc: &ExprLocation, args: &ArgsDesc) -> Result<Val>;7273type BuiltinsType = HashMap<Box<str>, Builtin>;7475thread_local! {76	static BUILTINS: BuiltinsType = {77		[78			("length".into(), builtin_length as Builtin),79			("type".into(), builtin_type),80			("makeArray".into(), builtin_make_array),81			("codepoint".into(), builtin_codepoint),82			("objectFieldsEx".into(), builtin_object_fields_ex),83			("objectHasEx".into(), builtin_object_has_ex),84			("slice".into(), builtin_slice),85			("substr".into(), builtin_substr),86			("primitiveEquals".into(), builtin_primitive_equals),87			("equals".into(), builtin_equals),88			("modulo".into(), builtin_modulo),89			("mod".into(), builtin_mod),90			("floor".into(), builtin_floor),91			("ceil".into(), builtin_ceil),92			("log".into(), builtin_log),93			("pow".into(), builtin_pow),94			("sqrt".into(), builtin_sqrt),95			("sin".into(), builtin_sin),96			("cos".into(), builtin_cos),97			("tan".into(), builtin_tan),98			("asin".into(), builtin_asin),99			("acos".into(), builtin_acos),100			("atan".into(), builtin_atan),101			("exp".into(), builtin_exp),102			("mantissa".into(), builtin_mantissa),103			("exponent".into(), builtin_exponent),104			("extVar".into(), builtin_ext_var),105			("native".into(), builtin_native),106			("filter".into(), builtin_filter),107			("map".into(), builtin_map),108			("flatMap".into(), builtin_flatmap),109			("foldl".into(), builtin_foldl),110			("foldr".into(), builtin_foldr),111			("sortImpl".into(), builtin_sort_impl),112			("format".into(), builtin_format),113			("range".into(), builtin_range),114			("char".into(), builtin_char),115			("encodeUTF8".into(), builtin_encode_utf8),116			("decodeUTF8".into(), builtin_decode_utf8),117			("md5".into(), builtin_md5),118			("base64".into(), builtin_base64),119			("base64DecodeBytes".into(), builtin_base64_decode_bytes),120			("base64Decode".into(), builtin_base64_decode),121			("trace".into(), builtin_trace),122			("join".into(), builtin_join),123			("escapeStringJson".into(), builtin_escape_string_json),124			("manifestJsonEx".into(), builtin_manifest_json_ex),125			("manifestYamlDocImpl".into(), builtin_manifest_yaml_doc),126			("reverse".into(), builtin_reverse),127			("id".into(), builtin_id),128			("strReplace".into(), builtin_str_replace),129			("splitLimit".into(), builtin_splitlimit),130			("parseJson".into(), builtin_parse_json),131			("asciiUpper".into(), builtin_ascii_upper),132			("asciiLower".into(), builtin_ascii_lower),133			("member".into(), builtin_member),134			("count".into(), builtin_count),135		].iter().cloned().collect()136	};137}138139fn builtin_length(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result<Val> {140	parse_args!(context, "length", args, 1, [141		0, x: ty!((string | object | array));142	], {143		Ok(match x {144			Val::Str(n) => Val::Num(n.chars().count() as f64),145			Val::Arr(a) => Val::Num(a.len() as f64),146			Val::Obj(o) => Val::Num(147				o.fields_visibility()148					.into_iter()149					.filter(|(_k, v)| *v)150					.count() as f64,151			),152			_ => unreachable!(),153		})154	})155}156157fn builtin_type(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result<Val> {158	parse_args!(context, "type", args, 1, [159		0, x: ty!(any);160	], {161		Ok(Val::Str(x.value_type().name().into()))162	})163}164165fn builtin_make_array(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result<Val> {166	parse_args!(context, "makeArray", args, 2, [167		0, sz: ty!(BoundedNumber<(Some(0.0)), (None)>) => Val::Num;168		1, func: ty!(function) => Val::Func;169	], {170		let mut out = Vec::with_capacity(sz as usize);171		for i in 0..sz as usize {172			out.push(LazyVal::new_resolved(func.evaluate_values(173				context.clone(),174				&[Val::Num(i as f64)]175			)?))176		}177		Ok(Val::Arr(out.into()))178	})179}180181fn builtin_codepoint(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result<Val> {182	parse_args!(context, "codepoint", args, 1, [183		0, str: ty!(char) => Val::Str;184	], {185		Ok(Val::Num(str.chars().next().unwrap() as u32 as f64))186	})187}188189fn builtin_object_fields_ex(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result<Val> {190	parse_args!(context, "objectFieldsEx", args, 2, [191		0, obj: ty!(object) => Val::Obj;192		1, inc_hidden: ty!(boolean) => Val::Bool;193	], {194		let out = obj.fields_ex(inc_hidden);195		Ok(Val::Arr(out.into_iter().map(Val::Str).collect::<Vec<_>>().into()))196	})197}198199fn builtin_object_has_ex(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result<Val> {200	parse_args!(context, "objectHasEx", args, 3, [201		0, obj: ty!(object) => Val::Obj;202		1, f: ty!(string) => Val::Str;203		2, inc_hidden: ty!(boolean) => Val::Bool;204	], {205		Ok(Val::Bool(obj.has_field_ex(f, inc_hidden)))206	})207}208209fn builtin_parse_json(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result<Val> {210	parse_args!(context, "parseJson", args, 1, [211		0, s: ty!(string) => Val::Str;212	], {213		let state = EvaluationState::default();214		let path = PathBuf::from("std.parseJson").into();215		state.evaluate_snippet_raw(path ,s)216	})217}218219fn builtin_slice(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result<Val> {220	parse_args!(context, "slice", args, 4, [221		0, indexable: ty!((string | array));222		1, index: ty!((number | null));223		2, end: ty!((number | null));224		3, step: ty!((number | null));225	], {226		std_slice(227			indexable.into_indexable()?,228			index.try_cast_nullable_num("index")?.map(|v| v as usize),229			end.try_cast_nullable_num("end")?.map(|v| v as usize),230			step.try_cast_nullable_num("step")?.map(|v| v as usize),231		)232	})233}234235fn builtin_substr(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result<Val> {236	parse_args!(context, "substr", args, 3, [237		0, str: ty!(string) => Val::Str;238		1, from: ty!(BoundedNumber<(Some(0.0)), (None)>) => Val::Num;239		2, len: ty!(BoundedNumber<(Some(0.0)), (None)>) => Val::Num;240	], {241		let out: String = str.chars().skip(from as usize).take(len as usize).collect();242		Ok(Val::Str(out.into()))243	})244}245246fn builtin_primitive_equals(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result<Val> {247	parse_args!(context, "primitiveEquals", args, 2, [248		0, a: ty!(any);249		1, b: ty!(any);250	], {251		Ok(Val::Bool(primitive_equals(&a, &b)?))252	})253}254255fn builtin_equals(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result<Val> {256	parse_args!(context, "equals", args, 2, [257		0, a: ty!(any);258		1, b: ty!(any);259	], {260		Ok(Val::Bool(equals(&a, &b)?))261	})262}263264fn builtin_modulo(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result<Val> {265	parse_args!(context, "modulo", args, 2, [266		0, a: ty!(number) => Val::Num;267		1, b: ty!(number) => Val::Num;268	], {269		Ok(Val::Num(a % b))270	})271}272273fn builtin_mod(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result<Val> {274	parse_args!(context, "mod", args, 2, [275		0, a: ty!((number | string));276		1, b: ty!(any);277	], {278		evaluate_mod_op(&a, &b)279	})280}281282fn builtin_floor(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result<Val> {283	parse_args!(context, "floor", args, 1, [284		0, x: ty!(number) => Val::Num;285	], {286		Ok(Val::Num(x.floor()))287	})288}289290fn builtin_ceil(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result<Val> {291	parse_args!(context, "ceil", args, 1, [292		0, x: ty!(number) => Val::Num;293	], {294		Ok(Val::Num(x.ceil()))295	})296}297298fn builtin_log(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result<Val> {299	parse_args!(context, "log", args, 1, [300		0, n: ty!(number) => Val::Num;301	], {302		Ok(Val::Num(n.ln()))303	})304}305306fn builtin_pow(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result<Val> {307	parse_args!(context, "pow", args, 2, [308		0, x: ty!(number) => Val::Num;309		1, n: ty!(number) => Val::Num;310	], {311		Ok(Val::Num(x.powf(n)))312	})313}314315fn builtin_sqrt(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result<Val> {316	parse_args!(context, "sqrt", args, 1, [317		0, x: ty!(BoundedNumber<(Some(0.0)), (None)>) => Val::Num;318	], {319		Ok(Val::Num(x.sqrt()))320	})321}322323fn builtin_sin(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result<Val> {324	parse_args!(context, "sin", args, 1, [325		0, x: ty!(number) => Val::Num;326	], {327		Ok(Val::Num(x.sin()))328	})329}330331fn builtin_cos(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result<Val> {332	parse_args!(context, "cos", args, 1, [333		0, x: ty!(number) => Val::Num;334	], {335		Ok(Val::Num(x.cos()))336	})337}338339fn builtin_tan(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result<Val> {340	parse_args!(context, "tan", args, 1, [341		0, x: ty!(number) => Val::Num;342	], {343		Ok(Val::Num(x.tan()))344	})345}346347fn builtin_asin(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result<Val> {348	parse_args!(context, "asin", args, 1, [349		0, x: ty!(number) => Val::Num;350	], {351		Ok(Val::Num(x.asin()))352	})353}354355fn builtin_acos(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result<Val> {356	parse_args!(context, "acos", args, 1, [357		0, x: ty!(number) => Val::Num;358	], {359		Ok(Val::Num(x.acos()))360	})361}362363fn builtin_atan(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result<Val> {364	parse_args!(context, "atan", args, 1, [365		0, x: ty!(number) => Val::Num;366	], {367		Ok(Val::Num(x.atan()))368	})369}370371fn builtin_exp(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result<Val> {372	parse_args!(context, "exp", args, 1, [373		0, x: ty!(number) => Val::Num;374	], {375		Ok(Val::Num(x.exp()))376	})377}378379fn frexp(s: f64) -> (f64, i16) {380	if 0.0 == s {381		(s, 0)382	} else {383		let lg = s.abs().log2();384		let x = (lg - lg.floor() - 1.0).exp2();385		let exp = lg.floor() + 1.0;386		(s.signum() * x, exp as i16)387	}388}389390fn builtin_mantissa(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result<Val> {391	parse_args!(context, "mantissa", args, 1, [392		0, x: ty!(number) => Val::Num;393	], {394		Ok(Val::Num(frexp(x).0))395	})396}397398fn builtin_exponent(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result<Val> {399	parse_args!(context, "exponent", args, 1, [400		0, x: ty!(number) => Val::Num;401	], {402		Ok(Val::Num(frexp(x).1.into()))403	})404}405406fn builtin_ext_var(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result<Val> {407	parse_args!(context, "extVar", args, 1, [408		0, x: ty!(string) => Val::Str;409	], {410		Ok(with_state(|s| s.settings().ext_vars.get(&x).cloned()).ok_or(UndefinedExternalVariable(x))?)411	})412}413414fn builtin_native(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result<Val> {415	parse_args!(context, "native", args, 1, [416		0, x: ty!(string) => Val::Str;417	], {418		Ok(with_state(|s| s.settings().ext_natives.get(&x).cloned()).map(|v| Val::Func(Cc::new(FuncVal::NativeExt(x.clone(), v)))).ok_or(UndefinedExternalFunction(x))?)419	})420}421422fn builtin_filter(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result<Val> {423	parse_args!(context, "filter", args, 2, [424		0, func: ty!(function) => Val::Func;425		1, arr: ty!(array) => Val::Arr;426	], {427		Ok(Val::Arr(arr.filter(|val| func428			.evaluate_values(context.clone(), &[val.clone()])?429			.try_cast_bool("filter predicate"))?))430	})431}432433fn builtin_map(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result<Val> {434	parse_args!(context, "map", args, 2, [435		0, func: ty!(function) => Val::Func;436		1, arr: ty!(array) => Val::Arr;437	], {438		Ok(Val::Arr(arr.map(|val| func439			.evaluate_values(context.clone(), &[val]))?))440	})441}442443fn builtin_flatmap(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result<Val> {444	parse_args!(context, "flatMap", args, 2, [445		0, func: ty!(function) => Val::Func;446		1, arr: ty!((array | string));447	], {448		match arr {449			Val::Str(s) => {450				let mut out = String::new();451				for c in s.chars() {452					match func.evaluate_values(context.clone(), &[Val::Str(c.to_string().into())])? {453						Val::Str(o) => out.push_str(&o),454						_ => throw!(RuntimeError("in std.join all items should be strings".into())),455					};456				}457				Ok(Val::Str(out.into()))458			},459			Val::Arr(a) => {460				let mut out = Vec::new();461				for el in a.iter() {462					let el = el?;463					match func.evaluate_values(context.clone(), &[el])? {464						Val::Arr(o) => for oe in o.iter() {465							out.push(oe?)466						},467						_ => throw!(RuntimeError("in std.join all items should be arrays".into())),468					};469				}470				Ok(Val::Arr(out.into()))471			},472			_ => unreachable!(),473		}474	})475}476477fn builtin_foldl(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result<Val> {478	parse_args!(context, "foldl", args, 3, [479		0, func: ty!(function) => Val::Func;480		1, arr: ty!(array) => Val::Arr;481		2, init: ty!(any);482	], {483		let mut acc = init;484		for i in arr.iter() {485			acc = func.evaluate_values(context.clone(), &[acc, i?])?;486		}487		Ok(acc)488	})489}490491fn builtin_foldr(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result<Val> {492	parse_args!(context, "foldr", args, 3, [493		0, func: ty!(function) => Val::Func;494		1, arr: ty!(array) => Val::Arr;495		2, init: ty!(any);496	], {497		let mut acc = init;498		for i in arr.iter().rev() {499			acc = func.evaluate_values(context.clone(), &[i?, acc])?;500		}501		Ok(acc)502	})503}504505#[allow(non_snake_case)]506fn builtin_sort_impl(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result<Val> {507	parse_args!(context, "sort", args, 2, [508		0, arr: ty!(array) => Val::Arr;509		1, keyF: ty!(function) => Val::Func;510	], {511		if arr.len() <= 1 {512			return Ok(Val::Arr(arr))513		}514		Ok(Val::Arr(ArrValue::Eager(sort::sort(context, arr.evaluated()?, &keyF)?)))515	})516}517518fn builtin_format(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result<Val> {519	parse_args!(context, "format", args, 2, [520		0, str: ty!(string) => Val::Str;521		1, vals: ty!(any)522	], {523		std_format(str, vals)524	})525}526527fn builtin_range(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result<Val> {528	parse_args!(context, "range", args, 2, [529		0, from: ty!(number) => Val::Num;530		1, to: ty!(number) => Val::Num;531	], {532		if to < from {533			return Ok(Val::Arr(ArrValue::new_eager()))534		}535		let mut out = Vec::with_capacity((1+to as usize-from as usize).max(0));536		for i in from as usize..=to as usize {537			out.push(Val::Num(i as f64));538		}539		Ok(Val::Arr(out.into()))540	})541}542543fn builtin_char(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result<Val> {544	parse_args!(context, "char", args, 1, [545		0, n: ty!(number) => Val::Num;546	], {547		let mut out = String::new();548		out.push(std::char::from_u32(n as u32).ok_or_else(||549			InvalidUnicodeCodepointGot(n as u32)550		)?);551		Ok(Val::Str(out.into()))552	})553}554555fn builtin_encode_utf8(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result<Val> {556	parse_args!(context, "encodeUTF8", args, 1, [557		0, str: ty!(string) => Val::Str;558	], {559		Ok(Val::Arr((str.bytes().map(|b| Val::Num(b as f64)).collect::<Vec<Val>>()).into()))560	})561}562563fn builtin_decode_utf8(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result<Val> {564	parse_args!(context, "decodeUTF8", args, 1, [565		0, arr: ty!((Array<ubyte>)) => Val::Arr;566	], {567		let data: Result<Vec<u8>> = arr.iter().map(|v| v.map(|v| match v{568			Val::Num(n) => n as u8,569			_ => unreachable!(),570		})).collect();571		let data = data?;572		Ok(Val::Str(String::from_utf8(data).map_err(|_| RuntimeError("bad utf8".into()))?.into()))573	})574}575576fn builtin_md5(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result<Val> {577	parse_args!(context, "md5", args, 1, [578		0, str: ty!(string) => Val::Str;579	], {580		Ok(Val::Str(format!("{:x}", md5::compute(&str.as_bytes())).into()))581	})582}583584fn builtin_trace(context: Context, loc: &ExprLocation, args: &ArgsDesc) -> Result<Val> {585	parse_args!(context, "trace", args, 2, [586		0, str: ty!(string) => Val::Str;587		1, rest: ty!(any);588	], {589		eprint!("TRACE:");590			with_state(|s|{591				let locs = s.map_source_locations(&loc.0, &[loc.1]);592				eprint!(" {}:{}", loc.0.file_name().unwrap().to_str().unwrap(), locs[0].line);593			});594		eprintln!(" {}", str);595		Ok(rest)596	})597}598599fn builtin_base64(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result<Val> {600	parse_args!(context, "base64", args, 1, [601		0, input: ty!((string | (Array<number>)));602	], {603		Ok(Val::Str(match input {604			Val::Str(s) => {605				base64::encode(s.bytes().collect::<Vec<_>>()).into()606			},607			Val::Arr(a) => {608				base64::encode(a.iter().map(|v| {609					Ok(v?.unwrap_num()? as u8)610				}).collect::<Result<Vec<_>>>()?).into()611			},612			_ => unreachable!()613		}))614	})615}616617fn builtin_base64_decode_bytes(618	context: Context,619	_loc: &ExprLocation,620	args: &ArgsDesc,621) -> Result<Val> {622	parse_args!(context, "base64DecodeBytes", args, 1, [623		0, input: ty!(string) => Val::Str;624	], {625		Ok(Val::Arr(626			base64::decode(&input.as_bytes())627				.map_err(|_| RuntimeError("bad base64".into()))?628				.iter()629				.map(|v| Val::Num(*v as f64)).collect::<Vec<_>>().into()630		))631	})632}633634fn builtin_base64_decode(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result<Val> {635	parse_args!(context, "base64Decode", args, 1, [636		0, input: ty!(string) => Val::Str;637	], {638		Ok(Val::Str(639			String::from_utf8(base64::decode(&input.as_bytes())640				.map_err(|_| RuntimeError("bad base64".into()))?)641				.map_err(|_| RuntimeError("bad utf8".into()))?.into()642		))643	})644}645646fn builtin_join(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result<Val> {647	parse_args!(context, "join", args, 2, [648		0, sep: ty!((string | array));649		1, arr: ty!(array) => Val::Arr;650	], {651		Ok(match sep {652			Val::Arr(joiner_items) => {653				let mut out = Vec::new();654655				let mut first = true;656				for item in arr.iter() {657					let item = item?.clone();658					if let Val::Arr(items) = item {659						if !first {660							out.reserve(joiner_items.len());661							// TODO: extend662							for item in joiner_items.iter() {663								out.push(item?);664							}665						}666						first = false;667						out.reserve(items.len());668						// TODO: extend669						for item in items.iter() {670							out.push(item?);671						}672					} else {673						throw!(RuntimeError("in std.join all items should be arrays".into()));674					}675				}676677				Val::Arr(out.into())678			},679			Val::Str(sep) => {680				let mut out = String::new();681682				let mut first = true;683				for item in arr.iter() {684					let item = item?.clone();685					if let Val::Str(item) = item {686						if !first {687							out += &sep;688						}689						first = false;690						out += &item;691					} else {692						throw!(RuntimeError("in std.join all items should be strings".into()));693					}694				}695696				Val::Str(out.into())697			},698			_ => unreachable!()699		})700	})701}702703fn builtin_escape_string_json(704	context: Context,705	_loc: &ExprLocation,706	args: &ArgsDesc,707) -> Result<Val> {708	parse_args!(context, "escapeStringJson", args, 1, [709		0, str_: ty!(string) => Val::Str;710	], {711		Ok(Val::Str(escape_string_json(&str_).into()))712	})713}714715fn builtin_manifest_json_ex(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result<Val> {716	parse_args!(context, "manifestJsonEx", args, 2, [717		0, value: ty!(any);718		1, indent: ty!(string) => Val::Str;719	], {720		Ok(Val::Str(manifest_json_ex(&value, &ManifestJsonOptions {721			padding: &indent,722			mtype: ManifestType::Std,723		})?.into()))724	})725}726727fn builtin_manifest_yaml_doc(728	context: Context,729	_loc: &ExprLocation,730	args: &ArgsDesc,731) -> Result<Val> {732	parse_args!(context, "manifestYamlDoc", args, 2, [733		0, value: ty!(any);734		1, indent_array_in_object: ty!(boolean) => Val::Bool;735	], {736		Ok(Val::Str(manifest_yaml_ex(&value, &ManifestYamlOptions {737			padding: "  ",738			arr_element_padding: if indent_array_in_object { "  " } else { "" },739		})?.into()))740	})741}742743fn builtin_reverse(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result<Val> {744	parse_args!(context, "reverse", args, 1, [745		0, value: ty!(array) => Val::Arr;746	], {747		Ok(Val::Arr(value.reversed()))748	})749}750751fn builtin_id(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result<Val> {752	parse_args!(context, "id", args, 1, [753		0, v: ty!(any);754	], {755		Ok(v)756	})757}758759fn builtin_str_replace(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result<Val> {760	parse_args!(context, "strReplace", args, 3, [761		0, str: ty!(string) => Val::Str;762		1, from: ty!(string) => Val::Str;763		2, to: ty!(string) => Val::Str;764	], {765		Ok(Val::Str(str.replace(&from as &str, &to as &str).into()))766	})767}768769fn builtin_splitlimit(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result<Val> {770	parse_args!(context, "splitLimit", args, 3, [771		0, str: ty!(string) => Val::Str;772		1, c: ty!(char) => Val::Str;773		2, maxsplits: ty!(number) => Val::Num;774	], {775		let maxsplits = maxsplits as isize;776		let c = c.chars().next().unwrap();777778		let out: Vec<Val> = if maxsplits == -1 {779			str.split(c).map(|s| Val::Str(s.into())).collect()780		} else {781			str.splitn(maxsplits as usize + 1, c).map(|s| Val::Str(s.into())).collect()782		};783784		Ok(Val::Arr(out.into()))785	})786}787788fn builtin_ascii_upper(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result<Val> {789	parse_args!(context, "asciiUpper", args, 1, [790		0, str: ty!(string) => Val::Str;791	], {792		Ok(Val::Str(str.to_ascii_uppercase().into()))793	})794}795796fn builtin_ascii_lower(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result<Val> {797	parse_args!(context, "asciiLower", args, 1, [798		0, str: ty!(string) => Val::Str;799	], {800		Ok(Val::Str(str.to_ascii_lowercase().into()))801	})802}803804fn builtin_member(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result<Val> {805	parse_args!(context, "member", args, 2, [806		0, arr: ty!((array | string));807		1, x: ty!(any);808	], {809		match arr {810			Val::Str(s) => {811				let x = x.try_cast_str("x should be string")?;812				Ok(Val::Bool(!x.is_empty() && s.contains(&*x)))813			}814			Val::Arr(a) => {815				for item in a.iter() {816					let item = item?;817					if equals(&item, &x)? {818						return Ok(Val::Bool(true));819					}820				}821				Ok(Val::Bool(false))822			}823			_ => unreachable!(),824		}825	})826}827828fn builtin_count(context: Context, _loc: &ExprLocation, args: &ArgsDesc) -> Result<Val> {829	parse_args!(context, "count", args, 2, [830		0, arr: ty!(array) => Val::Arr;831		1, x: ty!(any);832	], {833		let mut count = 0;834		for item in arr.iter() {835			let item = item?;836			if equals(&item, &x)? {837				count += 1;838			}839		}840		Ok(Val::Num(count as f64))841	})842}843844pub fn call_builtin(845	context: Context,846	loc: &ExprLocation,847	name: &str,848	args: &ArgsDesc,849) -> Result<Val> {850	BUILTINS851		.with(|builtins| builtins.get(name).copied())852		.ok_or_else(|| IntrinsicNotFound(name.into()))?(context, loc, args)853}
modifiedcrates/jrsonnet-evaluator/src/integrations/mod.rsdiffbeforeafterboth
--- a/crates/jrsonnet-evaluator/src/integrations/mod.rs
+++ b/crates/jrsonnet-evaluator/src/integrations/mod.rs
@@ -1,2 +1 @@
-#[cfg(feature = "serde-json")]
 pub mod serde;
modifiedcrates/jrsonnet-evaluator/src/integrations/serde.rsdiffbeforeafterboth
--- a/crates/jrsonnet-evaluator/src/integrations/serde.rs
+++ b/crates/jrsonnet-evaluator/src/integrations/serde.rs
@@ -15,7 +15,7 @@
 			Val::Num(n) => Self::Number(if n.fract() <= f64::EPSILON {
 				(*n as i64).into()
 			} else {
-				Number::from_f64(*n).expect("to json number")
+				Number::from_f64(*n).expect("jsonnet numbers can't be infinite or NaN")
 			}),
 			Val::Arr(a) => {
 				let mut out = Vec::with_capacity(a.len());
@@ -29,7 +29,9 @@
 				for key in o.fields() {
 					out.insert(
 						(&key as &str).into(),
-						(&o.get(key)?.expect("field exists")).try_into()?,
+						(&o.get(key)?
+							.expect("key is present in fields, so value should exist"))
+							.try_into()?,
 					);
 				}
 				Self::Object(out)
@@ -39,27 +41,30 @@
 	}
 }
 
-impl From<&Value> for Val {
-	fn from(v: &Value) -> Self {
-		match v {
+impl TryFrom<&Value> for Val {
+	type Error = LocError;
+	fn try_from(v: &Value) -> Result<Self> {
+		Ok(match v {
 			Value::Null => Self::Null,
 			Value::Bool(v) => Self::Bool(*v),
-			Value::Number(n) => Self::Num(n.as_f64().expect("as f64")),
+			Value::Number(n) => Self::Num(n.as_f64().ok_or_else(|| {
+				RuntimeError(format!("json number can't be represented as jsonnet: {}", n).into())
+			})?),
 			Value::String(s) => Self::Str((s as &str).into()),
 			Value::Array(a) => {
 				let mut out: Vec<Self> = Vec::with_capacity(a.len());
 				for v in a {
-					out.push(v.into());
+					out.push(v.try_into()?);
 				}
 				Self::Arr(out.into())
 			}
 			Value::Object(o) => {
 				let mut builder = ObjValueBuilder::with_capacity(o.len());
 				for (k, v) in o {
-					builder.member((k as &str).into()).value(v.into());
+					builder.member((k as &str).into()).value(v.try_into()?);
 				}
 				Self::Obj(builder.build())
 			}
-		}
+		})
 	}
 }
modifiedcrates/jrsonnet-evaluator/src/trace/mod.rsdiffbeforeafterboth
--- a/crates/jrsonnet-evaluator/src/trace/mod.rs
+++ b/crates/jrsonnet-evaluator/src/trace/mod.rs
@@ -98,7 +98,7 @@
 			let mut n = self.resolver.resolve(path);
 			let mut offset = error.location.offset;
 			let is_eof = if offset >= source_code.len() {
-				offset = source_code.len() - 1;
+				offset = source_code.len().saturating_sub(1);
 				true
 			} else {
 				false
modifiedcrates/jrsonnet-stdlib/src/std.jsonnetdiffbeforeafterboth
--- a/crates/jrsonnet-stdlib/src/std.jsonnet
+++ b/crates/jrsonnet-stdlib/src/std.jsonnet
@@ -23,6 +23,7 @@
   trace:: $intrinsic(trace),
   id:: $intrinsic(id),
   parseJson:: $intrinsic(parseJson),
+  parseYaml:: $intrinsic(parseYaml),
 
   log:: $intrinsic(log),
   pow:: $intrinsic(pow),