git.delta.rocks / jrsonnet / refs/commits / 8f3ed48f89ef

difftreelog

refactor simplify and unify builtins

Yaroslav Bolyukin2021-12-27parent: #393dcbd.patch.diff
in: master

14 files changed

modifiedcmds/jrsonnet/src/main.rsdiffbeforeafterboth
83 std::process::exit(0);83 std::process::exit(0);
84 };84 };
8585
86 let success;86 let success = if let Some(size) = opts.debug.os_stack {
87 if let Some(size) = opts.debug.os_stack {
88 success = std::thread::Builder::new()87 std::thread::Builder::new()
89 .stack_size(size * 1024 * 1024)88 .stack_size(size * 1024 * 1024)
90 .spawn(|| main_catch(opts))89 .spawn(|| main_catch(opts))
91 .expect("new thread spawned")90 .expect("new thread spawned")
92 .join()91 .join()
93 .expect("thread finished successfully");92 .expect("thread finished successfully")
94 } else {93 } else {
95 success = main_catch(opts)94 main_catch(opts)
96 }95 };
97 if !success {96 if !success {
98 std::process::exit(1);97 std::process::exit(1);
99 }98 }
modifiedcrates/jrsonnet-evaluator/src/builtin/format.rsdiffbeforeafterboth
578 }578 }
579 ConvTypeV::Char => match value.clone() {579 ConvTypeV::Char => match value.clone() {
580 Val::Num(n) => tmp_out.push(580 Val::Num(n) => tmp_out
581 std::char::from_u32(n as u32)581 .push(std::char::from_u32(n as u32).ok_or(InvalidUnicodeCodepointGot(n as u32))?),
582 .ok_or_else(|| InvalidUnicodeCodepointGot(n as u32))?,
583 ),
584 Val::Str(s) => {582 Val::Str(s) => {
585 if s.chars().count() != 1 {583 if s.chars().count() != 1 {
modifiedcrates/jrsonnet-evaluator/src/builtin/mod.rsdiffbeforeafterboth
1use crate::function::StaticBuiltin;
1use crate::typed::{Any, Either, Null, PositiveF64, VecVal, M1};2use crate::typed::{Any, Either, Null, PositiveF64, VecVal, M1};
2use crate::{self as jrsonnet_evaluator, ObjValue};3use crate::{self as jrsonnet_evaluator, ObjValue};
3use crate::{4use crate::{
11use format::{format_arr, format_obj};11use format::{format_arr, format_obj};
12use gcmodule::Cc;12use gcmodule::Cc;
13use jrsonnet_interner::IStr;13use jrsonnet_interner::IStr;
14use jrsonnet_parser::{ArgsDesc, ExprLocation};14use jrsonnet_parser::ExprLocation;
15use serde::Deserialize;15use serde::Deserialize;
16use serde_yaml::DeserializingQuirks;16use serde_yaml::DeserializingQuirks;
17use std::collections::HashMap;
17use std::{18use std::convert::{TryFrom, TryInto};
18 collections::HashMap,
19 convert::{TryFrom, TryInto},
20 path::PathBuf,
21 rc::Rc,
22};
2319
24pub mod stdlib;20pub mod stdlib;
25pub use stdlib::*;21pub use stdlib::*;
3228
33pub fn std_format(str: IStr, vals: Val) -> Result<String> {29pub fn std_format(str: IStr, vals: Val) -> Result<String> {
34 push_frame(30 push_frame(
35 &ExprLocation(Rc::from(PathBuf::from("std.jsonnet")), 0, 0),31 None,
36 || format!("std.format of {}", str),32 || format!("std.format of {}", str),
37 || {33 || {
38 Ok(match vals {34 Ok(match vals {
76 }72 }
77}73}
78
79type Builtin = fn(context: Context, loc: &ExprLocation, args: &ArgsDesc) -> Result<Val>;
8074
81type BuiltinsType = HashMap<Box<str>, Builtin>;75type BuiltinsType = HashMap<IStr, &'static dyn StaticBuiltin>;
8276
83thread_local! {77thread_local! {
84 static BUILTINS: BuiltinsType = {78 pub static BUILTINS: BuiltinsType = {
85 [79 [
86 ("length".into(), builtin_length as Builtin),80 ("length".into(), builtin_length::INST),
87 ("type".into(), builtin_type),81 ("type".into(), builtin_type::INST),
88 ("makeArray".into(), builtin_make_array),82 ("makeArray".into(), builtin_make_array::INST),
89 ("codepoint".into(), builtin_codepoint),83 ("codepoint".into(), builtin_codepoint::INST),
90 ("objectFieldsEx".into(), builtin_object_fields_ex),84 ("objectFieldsEx".into(), builtin_object_fields_ex::INST),
91 ("objectHasEx".into(), builtin_object_has_ex),85 ("objectHasEx".into(), builtin_object_has_ex::INST),
92 ("slice".into(), builtin_slice),86 ("slice".into(), builtin_slice::INST),
93 ("substr".into(), builtin_substr),87 ("substr".into(), builtin_substr::INST),
94 ("primitiveEquals".into(), builtin_primitive_equals),88 ("primitiveEquals".into(), builtin_primitive_equals::INST),
95 ("equals".into(), builtin_equals),89 ("equals".into(), builtin_equals::INST),
96 ("modulo".into(), builtin_modulo),90 ("modulo".into(), builtin_modulo::INST),
97 ("mod".into(), builtin_mod),91 ("mod".into(), builtin_mod::INST),
98 ("floor".into(), builtin_floor),92 ("floor".into(), builtin_floor::INST),
99 ("ceil".into(), builtin_ceil),93 ("ceil".into(), builtin_ceil::INST),
100 ("log".into(), builtin_log),94 ("log".into(), builtin_log::INST),
101 ("pow".into(), builtin_pow),95 ("pow".into(), builtin_pow::INST),
102 ("sqrt".into(), builtin_sqrt),96 ("sqrt".into(), builtin_sqrt::INST),
103 ("sin".into(), builtin_sin),97 ("sin".into(), builtin_sin::INST),
104 ("cos".into(), builtin_cos),98 ("cos".into(), builtin_cos::INST),
105 ("tan".into(), builtin_tan),99 ("tan".into(), builtin_tan::INST),
106 ("asin".into(), builtin_asin),100 ("asin".into(), builtin_asin::INST),
107 ("acos".into(), builtin_acos),101 ("acos".into(), builtin_acos::INST),
108 ("atan".into(), builtin_atan),102 ("atan".into(), builtin_atan::INST),
109 ("exp".into(), builtin_exp),103 ("exp".into(), builtin_exp::INST),
110 ("mantissa".into(), builtin_mantissa),104 ("mantissa".into(), builtin_mantissa::INST),
111 ("exponent".into(), builtin_exponent),105 ("exponent".into(), builtin_exponent::INST),
112 ("extVar".into(), builtin_ext_var),106 ("extVar".into(), builtin_ext_var::INST),
113 ("native".into(), builtin_native),107 ("native".into(), builtin_native::INST),
114 ("filter".into(), builtin_filter),108 ("filter".into(), builtin_filter::INST),
115 ("map".into(), builtin_map),109 ("map".into(), builtin_map::INST),
116 ("flatMap".into(), builtin_flatmap),110 ("flatMap".into(), builtin_flatmap::INST),
117 ("foldl".into(), builtin_foldl),111 ("foldl".into(), builtin_foldl::INST),
118 ("foldr".into(), builtin_foldr),112 ("foldr".into(), builtin_foldr::INST),
119 ("sortImpl".into(), builtin_sort_impl),113 ("sort".into(), builtin_sort::INST),
120 ("format".into(), builtin_format),114 ("format".into(), builtin_format::INST),
121 ("range".into(), builtin_range),115 ("range".into(), builtin_range::INST),
122 ("char".into(), builtin_char),116 ("char".into(), builtin_char::INST),
123 ("encodeUTF8".into(), builtin_encode_utf8),117 ("encodeUTF8".into(), builtin_encode_utf8::INST),
124 ("decodeUTF8".into(), builtin_decode_utf8),118 ("decodeUTF8".into(), builtin_decode_utf8::INST),
125 ("md5".into(), builtin_md5),119 ("md5".into(), builtin_md5::INST),
126 ("base64".into(), builtin_base64),120 ("base64".into(), builtin_base64::INST),
127 ("base64DecodeBytes".into(), builtin_base64_decode_bytes),121 ("base64DecodeBytes".into(), builtin_base64_decode_bytes::INST),
128 ("base64Decode".into(), builtin_base64_decode),122 ("base64Decode".into(), builtin_base64_decode::INST),
129 ("trace".into(), builtin_trace),123 ("trace".into(), builtin_trace::INST),
130 ("join".into(), builtin_join),124 ("join".into(), builtin_join::INST),
131 ("escapeStringJson".into(), builtin_escape_string_json),125 ("escapeStringJson".into(), builtin_escape_string_json::INST),
132 ("manifestJsonEx".into(), builtin_manifest_json_ex),126 ("manifestJsonEx".into(), builtin_manifest_json_ex::INST),
133 ("manifestYamlDocImpl".into(), builtin_manifest_yaml_doc),127 ("manifestYamlDoc".into(), builtin_manifest_yaml_doc::INST),
134 ("reverse".into(), builtin_reverse),128 ("reverse".into(), builtin_reverse::INST),
135 ("id".into(), builtin_id),129 ("id".into(), builtin_id::INST),
136 ("strReplace".into(), builtin_str_replace),130 ("strReplace".into(), builtin_str_replace::INST),
137 ("splitLimit".into(), builtin_splitlimit),131 ("splitLimit".into(), builtin_splitlimit::INST),
138 ("parseJson".into(), builtin_parse_json),132 ("parseJson".into(), builtin_parse_json::INST),
139 ("parseYaml".into(), builtin_parse_yaml),133 ("parseYaml".into(), builtin_parse_yaml::INST),
140 ("asciiUpper".into(), builtin_ascii_upper),134 ("asciiUpper".into(), builtin_ascii_upper::INST),
141 ("asciiLower".into(), builtin_ascii_lower),135 ("asciiLower".into(), builtin_ascii_lower::INST),
142 ("member".into(), builtin_member),136 ("member".into(), builtin_member::INST),
143 ("count".into(), builtin_count),137 ("count".into(), builtin_count::INST),
144 ].iter().cloned().collect()138 ].iter().cloned().collect()
145 };139 };
146}140}
147141
148#[jrsonnet_macros::builtin]142#[jrsonnet_macros::builtin]
149fn builtin_length(x: Either<IStr, Either<VecVal, ObjValue>>) -> Result<usize> {143fn builtin_length(x: Either<IStr, Either<VecVal, Either<ObjValue, Cc<FuncVal>>>>) -> Result<usize> {
150 Ok(match x {144 Ok(match x {
151 Either::Left(x) => x.len(),145 Either::Left(x) => x.len(),
152 Either::Right(Either::Left(x)) => x.0.len(),146 Either::Right(Either::Left(x)) => x.0.len(),
153 Either::Right(Either::Right(x)) => x147 Either::Right(Either::Right(Either::Left(x))) => x
154 .fields_visibility()148 .fields_visibility()
155 .into_iter()149 .into_iter()
156 .filter(|(_k, v)| *v)150 .filter(|(_k, v)| *v)
157 .count(),151 .count(),
152 Either::Right(Either::Right(Either::Right(f))) => f.args_len(),
158 })153 })
159}154}
160155
167fn builtin_make_array(sz: usize, func: Cc<FuncVal>) -> Result<VecVal> {162fn builtin_make_array(sz: usize, func: Cc<FuncVal>) -> Result<VecVal> {
168 let mut out = Vec::with_capacity(sz);163 let mut out = Vec::with_capacity(sz);
169 for i in 0..sz {164 for i in 0..sz {
170 out.push(func.evaluate_values(&[Val::Num(i as f64)])?)165 out.push(func.evaluate_simple(&[i as f64].as_slice())?)
171 }166 }
172 Ok(VecVal(out))167 Ok(VecVal(out))
173}168}
354349
355#[jrsonnet_macros::builtin]350#[jrsonnet_macros::builtin]
356fn builtin_filter(func: Cc<FuncVal>, arr: ArrValue) -> Result<ArrValue> {351fn builtin_filter(func: Cc<FuncVal>, arr: ArrValue) -> Result<ArrValue> {
357 arr.filter(|val| bool::try_from(func.evaluate_values(&[val.clone()])?))352 arr.filter(|val| bool::try_from(func.evaluate_simple(&[Any(val.clone())].as_slice())?))
358}353}
359354
360#[jrsonnet_macros::builtin]355#[jrsonnet_macros::builtin]
361fn builtin_map(func: Cc<FuncVal>, arr: ArrValue) -> Result<ArrValue> {356fn builtin_map(func: Cc<FuncVal>, arr: ArrValue) -> Result<ArrValue> {
362 arr.map(|val| func.evaluate_values(&[val]))357 arr.map(|val| func.evaluate_simple(&[Any(val)].as_slice()))
363}358}
364359
365#[jrsonnet_macros::builtin]360#[jrsonnet_macros::builtin]
368 IndexableVal::Str(s) => {363 IndexableVal::Str(s) => {
369 let mut out = String::new();364 let mut out = String::new();
370 for c in s.chars() {365 for c in s.chars() {
371 match func.evaluate_values(&[Val::Str(c.to_string().into())])? {366 match func.evaluate_simple(&[c.to_string()].as_slice())? {
372 Val::Str(o) => out.push_str(&o),367 Val::Str(o) => out.push_str(&o),
373 _ => throw!(RuntimeError(368 _ => throw!(RuntimeError(
374 "in std.join all items should be strings".into()369 "in std.join all items should be strings".into()
381 let mut out = Vec::new();376 let mut out = Vec::new();
382 for el in a.iter() {377 for el in a.iter() {
383 let el = el?;378 let el = el?;
384 match func.evaluate_values(&[el])? {379 match func.evaluate_simple(&[Any(el)].as_slice())? {
385 Val::Arr(o) => {380 Val::Arr(o) => {
386 for oe in o.iter() {381 for oe in o.iter() {
387 out.push(oe?)382 out.push(oe?)
401fn builtin_foldl(func: Cc<FuncVal>, arr: ArrValue, init: Any) -> Result<Any> {396fn builtin_foldl(func: Cc<FuncVal>, arr: ArrValue, init: Any) -> Result<Any> {
402 let mut acc = init.0;397 let mut acc = init.0;
403 for i in arr.iter() {398 for i in arr.iter() {
404 acc = func.evaluate_values(&[acc, i?])?;399 acc = func.evaluate_simple(&[Any(acc), Any(i?)].as_slice())?;
405 }400 }
406 Ok(Any(acc))401 Ok(Any(acc))
407}402}
410fn builtin_foldr(func: Cc<FuncVal>, arr: ArrValue, init: Any) -> Result<Any> {405fn builtin_foldr(func: Cc<FuncVal>, arr: ArrValue, init: Any) -> Result<Any> {
411 let mut acc = init.0;406 let mut acc = init.0;
412 for i in arr.iter().rev() {407 for i in arr.iter().rev() {
413 acc = func.evaluate_values(&[i?, acc])?;408 acc = func.evaluate_simple(&[Any(i?), Any(acc)].as_slice())?;
414 }409 }
415 Ok(Any(acc))410 Ok(Any(acc))
416}411}
417412
418#[jrsonnet_macros::builtin]413#[jrsonnet_macros::builtin]
419#[allow(non_snake_case)]414#[allow(non_snake_case)]
420fn builtin_sort_impl(arr: ArrValue, keyF: Cc<FuncVal>) -> Result<ArrValue> {415fn builtin_sort(arr: ArrValue, keyF: Option<Cc<FuncVal>>) -> Result<ArrValue> {
421 if arr.len() <= 1 {416 if arr.len() <= 1 {
422 return Ok(arr);417 return Ok(arr);
423 }418 }
424 Ok(ArrValue::Eager(sort::sort(arr.evaluated()?, &keyF)?))419 Ok(ArrValue::Eager(sort::sort(
420 arr.evaluated()?,
421 keyF.as_deref(),
422 )?))
425}423}
426424
443441
444#[jrsonnet_macros::builtin]442#[jrsonnet_macros::builtin]
445fn builtin_char(n: u32) -> Result<char> {443fn builtin_char(n: u32) -> Result<char> {
446 Ok(std::char::from_u32(n as u32).ok_or_else(|| InvalidUnicodeCodepointGot(n as u32))?)444 Ok(std::char::from_u32(n as u32).ok_or(InvalidUnicodeCodepointGot(n as u32))?)
447}445}
448446
449#[jrsonnet_macros::builtin]447#[jrsonnet_macros::builtin]
466}464}
467465
468#[jrsonnet_macros::builtin]466#[jrsonnet_macros::builtin]
469fn builtin_trace(#[location] loc: &ExprLocation, str: IStr, rest: Any) -> Result<Any> {467fn builtin_trace(#[location] loc: Option<&ExprLocation>, str: IStr, rest: Any) -> Result<Any> {
470 eprint!("TRACE:");468 eprint!("TRACE:");
469 if let Some(loc) = loc {
471 with_state(|s| {470 with_state(|s| {
472 let locs = s.map_source_locations(&loc.0, &[loc.1]);471 let locs = s.map_source_locations(&loc.0, &[loc.1]);
473 eprint!(472 eprint!(
476 locs[0].line475 locs[0].line
477 );476 );
478 });477 });
478 }
479 eprintln!(" {}", str);479 eprintln!(" {}", str);
480 Ok(rest) as Result<Any>480 Ok(rest) as Result<Any>
481}481}
574#[jrsonnet_macros::builtin]574#[jrsonnet_macros::builtin]
575fn builtin_manifest_yaml_doc(575fn builtin_manifest_yaml_doc(
576 value: Any,576 value: Any,
577 indent_array_in_object: bool,577 indent_array_in_object: Option<bool>,
578 quote_keys: bool,578 quote_keys: Option<bool>,
579) -> Result<String> {579) -> Result<String> {
580 manifest_yaml_ex(580 manifest_yaml_ex(
581 &value.0,581 &value.0,
582 &ManifestYamlOptions {582 &ManifestYamlOptions {
583 padding: " ",583 padding: " ",
584 arr_element_padding: if indent_array_in_object { " " } else { "" },584 arr_element_padding: if indent_array_in_object.unwrap_or(false) {
585 " "
586 } else {
587 ""
588 },
585 quote_keys,589 quote_keys: quote_keys.unwrap_or(true),
586 },590 },
587 )591 )
588}592}
650 Ok(count)654 Ok(count)
651}655}
652
653pub fn call_builtin(
654 context: Context,
655 loc: &ExprLocation,
656 name: &str,
657 args: &ArgsDesc,
658) -> Result<Val> {
659 BUILTINS
660 .with(|builtins| builtins.get(name).copied())
661 .ok_or_else(|| IntrinsicNotFound(name.into()))?(context, loc, args)
662}
663656
modifiedcrates/jrsonnet-evaluator/src/builtin/sort.rsdiffbeforeafterboth
1use crate::{1use crate::{
2 error::{Error, LocError, Result},2 error::{Error, LocError, Result},
3 throw, FuncVal, Val,3 throw,
4 typed::Any,
5 FuncVal, Val,
4};6};
5use gcmodule::{Cc, Trace};7use gcmodule::{Cc, Trace};
59 Ok(sort_type)61 Ok(sort_type)
60}62}
6163
62pub fn sort(values: Cc<Vec<Val>>, key_getter: &FuncVal) -> Result<Cc<Vec<Val>>> {64pub fn sort(values: Cc<Vec<Val>>, key_getter: Option<&FuncVal>) -> Result<Cc<Vec<Val>>> {
63 if values.len() <= 1 {65 if values.len() <= 1 {
64 return Ok(values);66 return Ok(values);
65 }67 }
66 if key_getter.is_ident() {68 if let Some(key_getter) = key_getter {
69 // Slow path, user provided key getter
67 let mut mvalues = (*values).clone();70 let mut vk = Vec::with_capacity(values.len());
71 for value in values.iter() {
72 vk.push((
73 value.clone(),
74 key_getter.evaluate_simple(&[Any(value.clone())].as_slice())?,
75 ));
76 }
68 let sort_type = get_sort_type(&mut mvalues, |k| k)?;77 let sort_type = get_sort_type(&mut vk, |v| &mut v.1)?;
69 match sort_type {78 match sort_type {
70 SortKeyType::Number => mvalues.sort_by_key(|v| match v {79 SortKeyType::Number => vk.sort_by_key(|v| match v.1 {
71 Val::Num(n) => NonNaNf64(*n),80 Val::Num(n) => NonNaNf64(n),
72 _ => unreachable!(),81 _ => unreachable!(),
73 }),82 }),
74 SortKeyType::String => mvalues.sort_by_key(|v| match v {83 SortKeyType::String => vk.sort_by_key(|v| match &v.1 {
75 Val::Str(s) => s.clone(),84 Val::Str(s) => s.clone(),
76 _ => unreachable!(),85 _ => unreachable!(),
77 }),86 }),
78 SortKeyType::Unknown => unreachable!(),87 SortKeyType::Unknown => unreachable!(),
79 };88 };
80 Ok(Cc::new(mvalues))89 Ok(Cc::new(vk.into_iter().map(|v| v.0).collect()))
81 } else {90 } else {
91 // Fast path, identity key getter
82 let mut vk = Vec::with_capacity(values.len());92 let mut mvalues = (*values).clone();
83 for value in values.iter() {
84 vk.push((value.clone(), key_getter.evaluate_values(&[value.clone()])?));
85 }
86 let sort_type = get_sort_type(&mut vk, |v| &mut v.1)?;93 let sort_type = get_sort_type(&mut mvalues, |k| k)?;
87 match sort_type {94 match sort_type {
88 SortKeyType::Number => vk.sort_by_key(|v| match v.1 {95 SortKeyType::Number => mvalues.sort_unstable_by_key(|v| match v {
89 Val::Num(n) => NonNaNf64(n),96 Val::Num(n) => NonNaNf64(*n),
90 _ => unreachable!(),97 _ => unreachable!(),
91 }),98 }),
92 SortKeyType::String => vk.sort_by_key(|v| match &v.1 {99 SortKeyType::String => mvalues.sort_unstable_by_key(|v| match v {
93 Val::Str(s) => s.clone(),100 Val::Str(s) => s.clone(),
94 _ => unreachable!(),101 _ => unreachable!(),
95 }),102 }),
96 SortKeyType::Unknown => unreachable!(),103 SortKeyType::Unknown => unreachable!(),
97 };104 };
98 Ok(Cc::new(vk.into_iter().map(|v| v.0).collect()))105 Ok(Cc::new(mvalues))
99 }106 }
100}107}
101108
modifiedcrates/jrsonnet-evaluator/src/evaluate/mod.rsdiffbeforeafterboth
1use std::convert::TryFrom;1use std::convert::TryFrom;
22
3use crate::{3use crate::{
4 builtin::std_slice,4 builtin::{std_slice, BUILTINS},
5 error::Error::*,5 error::Error::*,
6 evaluate::operator::{evaluate_add_op, evaluate_binary_op_special, evaluate_unary_op},6 evaluate::operator::{evaluate_add_op, evaluate_binary_op_special, evaluate_unary_op},
7 gc::TraceBox,7 gc::TraceBox,
192 Ok(match field_name {192 Ok(match field_name {
193 jrsonnet_parser::FieldName::Fixed(n) => Some(n.clone()),193 jrsonnet_parser::FieldName::Fixed(n) => Some(n.clone()),
194 jrsonnet_parser::FieldName::Dyn(expr) => push_frame(194 jrsonnet_parser::FieldName::Dyn(expr) => push_frame(
195 &expr.1,195 Some(&expr.1),
196 || "evaluating field name".to_string(),196 || "evaluating field name".to_string(),
197 || {197 || {
198 let value = evaluate(context, expr)?;198 let value = evaluate(context, expr)?;
442 context: Context,442 context: Context,
443 value: &LocExpr,443 value: &LocExpr,
444 args: &ArgsDesc,444 args: &ArgsDesc,
445 loc: &ExprLocation,445 loc: Option<&ExprLocation>,
446 tailstrict: bool,446 tailstrict: bool,
447) -> Result<Val> {447) -> Result<Val> {
448 let value = evaluate(context.clone(), value)?;448 let value = evaluate(context.clone(), value)?;
463 let value = &assertion.0;463 let value = &assertion.0;
464 let msg = &assertion.1;464 let msg = &assertion.1;
465 let assertion_result = push_frame(465 let assertion_result = push_frame(
466 &value.1,466 Some(&value.1),
467 || "assertion condition".to_owned(),467 || "assertion condition".to_owned(),
468 || bool::try_from(evaluate(context.clone(), value)?),468 || bool::try_from(evaluate(context.clone(), value)?),
469 )?;469 )?;
470 if !assertion_result {470 if !assertion_result {
471 push_frame(471 push_frame(
472 &value.1,472 Some(&value.1),
473 || "assertion failure".to_owned(),473 || "assertion failure".to_owned(),
474 || {474 || {
475 if let Some(msg) = msg {475 if let Some(msg) = msg {
519 BinaryOp(v1, o, v2) => evaluate_binary_op_special(context, v1, *o, v2)?,519 BinaryOp(v1, o, v2) => evaluate_binary_op_special(context, v1, *o, v2)?,
520 UnaryOp(o, v) => evaluate_unary_op(*o, &evaluate(context, v)?)?,520 UnaryOp(o, v) => evaluate_unary_op(*o, &evaluate(context, v)?)?,
521 Var(name) => push_frame(521 Var(name) => push_frame(
522 loc,522 Some(loc),
523 || format!("variable <{}> access", name),523 || format!("variable <{}> access", name),
524 || context.binding(name.clone())?.evaluate(),524 || context.binding(name.clone())?.evaluate(),
525 )?,525 )?,
528 (Val::Obj(v), Val::Str(s)) => {528 (Val::Obj(v), Val::Str(s)) => {
529 let sn = s.clone();529 let sn = s.clone();
530 push_frame(530 push_frame(
531 loc,531 Some(loc),
532 || format!("field <{}> access", sn),532 || format!("field <{}> access", sn),
533 || {533 || {
534 if let Some(v) = v.get(s.clone())? {534 if let Some(v) = v.get(s.clone())? {
624 &evaluate(context.clone(), s)?,624 &evaluate(context.clone(), s)?,
625 &Val::Obj(evaluate_object(context, t)?),625 &Val::Obj(evaluate_object(context, t)?),
626 )?,626 )?,
627 Apply(value, args, tailstrict) => evaluate_apply(context, value, args, loc, *tailstrict)?,627 Apply(value, args, tailstrict) => {
628 evaluate_apply(context, value, args, Some(loc), *tailstrict)?
629 }
628 Function(params, body) => {630 Function(params, body) => {
629 evaluate_method(context, "anonymous".into(), params.clone(), body.clone())631 evaluate_method(context, "anonymous".into(), params.clone(), body.clone())
630 }632 }
631 Intrinsic(name) => Val::Func(Cc::new(FuncVal::Intrinsic(name.clone()))),633 Intrinsic(name) => Val::Func(Cc::new(FuncVal::StaticBuiltin(
634 BUILTINS
635 .with(|b| b.get(name).copied())
636 .ok_or_else(|| IntrinsicNotFound(name.clone()))?,
637 ))),
632 AssertExpr(assert, returned) => {638 AssertExpr(assert, returned) => {
633 evaluate_assert(context.clone(), assert)?;639 evaluate_assert(context.clone(), assert)?;
634 evaluate(context, returned)?640 evaluate(context, returned)?
635 }641 }
636 ErrorStmt(e) => push_frame(642 ErrorStmt(e) => push_frame(
637 loc,643 Some(loc),
638 || "error statement".to_owned(),644 || "error statement".to_owned(),
639 || throw!(RuntimeError(IStr::try_from(evaluate(context, e)?)?,)),645 || throw!(RuntimeError(IStr::try_from(evaluate(context, e)?)?,)),
640 )?,646 )?,
644 cond_else,650 cond_else,
645 } => {651 } => {
646 if push_frame(652 if push_frame(
647 loc,653 Some(loc),
648 || "if condition".to_owned(),654 || "if condition".to_owned(),
649 || bool::try_from(evaluate(context.clone(), &cond.0)?),655 || bool::try_from(evaluate(context.clone(), &cond.0)?),
650 )? {656 )? {
683 let mut import_location = tmp.to_path_buf();689 let mut import_location = tmp.to_path_buf();
684 import_location.pop();690 import_location.pop();
685 push_frame(691 push_frame(
686 loc,692 Some(loc),
687 || format!("import {:?}", path),693 || format!("import {:?}", path),
688 || with_state(|s| s.import_file(&import_location, path)),694 || with_state(|s| s.import_file(&import_location, path)),
689 )?695 )?
modifiedcrates/jrsonnet-evaluator/src/function.rsdiffbeforeafterboth
1use crate::{1use crate::{
2 error::Error::*, evaluate, evaluate_named, gc::TraceBox, throw, Context, FutureWrapper,2 error::{Error::*, LocError},
3 evaluate, evaluate_named,
4 gc::TraceBox,
5 throw,
6 typed::Typed,
3 GcHashMap, LazyVal, LazyValValue, Result, Val,7 Context, FutureWrapper, GcHashMap, LazyVal, LazyValValue, Result, Val,
4};8};
5use gcmodule::Trace;9use gcmodule::Trace;
6use jrsonnet_interner::IStr;10use jrsonnet_interner::IStr;
7use jrsonnet_parser::{ArgsDesc, LocExpr, ParamsDesc};11use jrsonnet_parser::{ArgsDesc, ExprLocation, LocExpr, ParamsDesc};
8use std::collections::HashMap;12use std::{borrow::Cow, collections::HashMap, convert::TryFrom};
913
10const NO_DEFAULT_CONTEXT: &str =
11 "no default context set for call with defined default parameter value";
12
13#[derive(Trace)]14#[derive(Trace)]
14struct EvaluateLazyVal {15struct EvaluateLazyVal {
15 context: Context,16 context: Context,
21 }22 }
22}23}
2324
25pub trait ArgLike {
26 fn evaluate_arg(&self, ctx: Context, tailstrict: bool) -> Result<LazyVal>;
27}
28impl ArgLike for &LocExpr {
29 fn evaluate_arg(&self, ctx: Context, tailstrict: bool) -> Result<LazyVal> {
30 Ok(if tailstrict {
31 LazyVal::new_resolved(evaluate(ctx, self)?)
32 } else {
33 LazyVal::new(TraceBox(Box::new(EvaluateLazyVal {
34 context: ctx,
35 expr: (*self).clone(),
36 })))
37 })
38 }
39}
40impl<T> ArgLike for T
41where
42 T: Typed + Clone,
43 Val: TryFrom<T, Error = LocError>,
44{
45 fn evaluate_arg(&self, _ctx: Context, _tailstrict: bool) -> Result<LazyVal> {
46 let val: Val = Val::try_from(self.clone())?;
47 Ok(LazyVal::new_resolved(val))
48 }
49}
50pub enum TlaArg {
51 String(IStr),
52 Code(LocExpr),
53 Val(Val),
54}
55impl ArgLike for TlaArg {
56 fn evaluate_arg(&self, ctx: Context, tailstrict: bool) -> Result<LazyVal> {
57 match self {
58 TlaArg::String(s) => Ok(LazyVal::new_resolved(Val::Str(s.clone()))),
59 TlaArg::Code(code) => Ok(if tailstrict {
60 LazyVal::new_resolved(evaluate(ctx, code)?)
61 } else {
62 LazyVal::new(TraceBox(Box::new(EvaluateLazyVal {
63 context: ctx,
64 expr: code.clone(),
65 })))
66 }),
67 TlaArg::Val(val) => Ok(LazyVal::new_resolved(val.clone())),
68 }
69 }
70}
71
72pub trait ArgsLike {
73 fn unnamed_len(&self) -> usize;
74 fn unnamed_iter(
75 &self,
76 ctx: Context,
77 tailstrict: bool,
78 handler: &mut dyn FnMut(usize, LazyVal) -> Result<()>,
79 ) -> Result<()>;
80 fn named_iter(
81 &self,
82 ctx: Context,
83 tailstrict: bool,
84 handler: &mut dyn FnMut(&IStr, LazyVal) -> Result<()>,
85 ) -> Result<()>;
86 fn named_names(&self, handler: &mut dyn FnMut(&IStr));
87}
88
89impl ArgsLike for ArgsDesc {
90 fn unnamed_len(&self) -> usize {
91 self.unnamed.len()
92 }
93
94 fn unnamed_iter(
95 &self,
96 ctx: Context,
97 tailstrict: bool,
98 handler: &mut dyn FnMut(usize, LazyVal) -> Result<()>,
99 ) -> Result<()> {
100 for (id, arg) in self.unnamed.iter().enumerate() {
101 handler(
102 id,
103 if tailstrict {
104 LazyVal::new_resolved(evaluate(ctx.clone(), arg)?)
105 } else {
106 LazyVal::new(TraceBox(Box::new(EvaluateLazyVal {
107 context: ctx.clone(),
108 expr: arg.clone(),
109 })))
110 },
111 )?;
112 }
113 Ok(())
114 }
115
116 fn named_iter(
117 &self,
118 ctx: Context,
119 tailstrict: bool,
120 handler: &mut dyn FnMut(&IStr, LazyVal) -> Result<()>,
121 ) -> Result<()> {
122 for (name, arg) in self.named.iter() {
123 handler(
124 name,
125 if tailstrict {
126 LazyVal::new_resolved(evaluate(ctx.clone(), arg)?)
127 } else {
128 LazyVal::new(TraceBox(Box::new(EvaluateLazyVal {
129 context: ctx.clone(),
130 expr: arg.clone(),
131 })))
132 },
133 )?;
134 }
135 Ok(())
136 }
137
138 fn named_names(&self, handler: &mut dyn FnMut(&IStr)) {
139 for (name, _) in self.named.iter() {
140 handler(name)
141 }
142 }
143}
144
145impl<A: ArgLike> ArgsLike for [(IStr, A)] {
146 fn unnamed_len(&self) -> usize {
147 0
148 }
149
150 fn unnamed_iter(
151 &self,
152 _ctx: Context,
153 _tailstrict: bool,
154 _handler: &mut dyn FnMut(usize, LazyVal) -> Result<()>,
155 ) -> Result<()> {
156 Ok(())
157 }
158
159 fn named_iter(
160 &self,
161 ctx: Context,
162 tailstrict: bool,
163 handler: &mut dyn FnMut(&IStr, LazyVal) -> Result<()>,
164 ) -> Result<()> {
165 for (name, val) in self.iter() {
166 handler(name, val.evaluate_arg(ctx.clone(), tailstrict)?)?;
167 }
168 Ok(())
169 }
170
171 fn named_names(&self, handler: &mut dyn FnMut(&IStr)) {
172 for (name, _) in self.iter() {
173 handler(name);
174 }
175 }
176}
177
178impl<A: ArgLike> ArgsLike for HashMap<IStr, A> {
179 fn unnamed_len(&self) -> usize {
180 0
181 }
182
183 fn unnamed_iter(
184 &self,
185 _ctx: Context,
186 _tailstrict: bool,
187 _handler: &mut dyn FnMut(usize, LazyVal) -> Result<()>,
188 ) -> Result<()> {
189 Ok(())
190 }
191
192 fn named_iter(
193 &self,
194 ctx: Context,
195 tailstrict: bool,
196 handler: &mut dyn FnMut(&IStr, LazyVal) -> Result<()>,
197 ) -> Result<()> {
198 for (name, value) in self.iter() {
199 handler(name, value.evaluate_arg(ctx.clone(), tailstrict)?)?;
200 }
201 Ok(())
202 }
203
204 fn named_names(&self, handler: &mut dyn FnMut(&IStr)) {
205 for (name, _) in self.iter() {
206 handler(name);
207 }
208 }
209}
210
211impl<A: ArgLike> ArgsLike for [A] {
212 fn unnamed_len(&self) -> usize {
213 self.len()
214 }
215
216 fn unnamed_iter(
217 &self,
218 ctx: Context,
219 tailstrict: bool,
220 handler: &mut dyn FnMut(usize, LazyVal) -> Result<()>,
221 ) -> Result<()> {
222 for (i, arg) in self.iter().enumerate() {
223 handler(i, arg.evaluate_arg(ctx.clone(), tailstrict)?)?;
224 }
225 Ok(())
226 }
227
228 fn named_iter(
229 &self,
230 _ctx: Context,
231 _tailstrict: bool,
232 _handler: &mut dyn FnMut(&IStr, LazyVal) -> Result<()>,
233 ) -> Result<()> {
234 Ok(())
235 }
236
237 fn named_names(&self, _handler: &mut dyn FnMut(&IStr)) {}
238}
239impl<A: ArgLike> ArgsLike for &[A] {
240 fn unnamed_len(&self) -> usize {
241 (*self).unnamed_len()
242 }
243
244 fn unnamed_iter(
245 &self,
246 ctx: Context,
247 tailstrict: bool,
248 handler: &mut dyn FnMut(usize, LazyVal) -> Result<()>,
249 ) -> Result<()> {
250 (*self).unnamed_iter(ctx, tailstrict, handler)
251 }
252
253 fn named_iter(
254 &self,
255 ctx: Context,
256 tailstrict: bool,
257 handler: &mut dyn FnMut(&IStr, LazyVal) -> Result<()>,
258 ) -> Result<()> {
259 (*self).named_iter(ctx, tailstrict, handler)
260 }
261
262 fn named_names(&self, handler: &mut dyn FnMut(&IStr)) {
263 (*self).named_names(handler)
264 }
265}
266
24/// Creates correct [context](Context) for function body evaluation returning error on invalid call.267/// Creates correct [context](Context) for function body evaluation returning error on invalid call.
25///268///
33 ctx: Context,276 ctx: Context,
34 body_ctx: Context,277 body_ctx: Context,
35 params: &ParamsDesc,278 params: &ParamsDesc,
36 args: &ArgsDesc,279 args: &dyn ArgsLike,
37 tailstrict: bool,280 tailstrict: bool,
38) -> Result<Context> {281) -> Result<Context> {
39 let mut passed_args = GcHashMap::with_capacity(params.len());282 let mut passed_args = GcHashMap::with_capacity(params.len());
40 if args.unnamed.len() > params.len() {283 if args.unnamed_len() > params.len() {
41 throw!(TooManyArgsFunctionHas(params.len()))284 throw!(TooManyArgsFunctionHas(params.len()))
42 }285 }
43286
44 let mut filled_args = 0;287 let mut filled_args = 0;
45288
46 for (id, arg) in args.unnamed.iter().enumerate() {289 args.unnamed_iter(ctx.clone(), tailstrict, &mut |id, arg| {
47 let name = params[id].0.clone();290 let name = params[id].0.clone();
48 passed_args.insert(291 passed_args.insert(name, arg);
49 name,
50 if tailstrict {
51 LazyVal::new_resolved(evaluate(ctx.clone(), arg)?)
52 } else {
53 LazyVal::new(TraceBox(Box::new(EvaluateLazyVal {
54 context: ctx.clone(),
55 expr: arg.clone(),
56 })))
57 },
58 );
59 filled_args += 1;292 filled_args += 1;
60 }293 Ok(())
294 })?;
61295
62 for (name, value) in args.named.iter() {296 args.named_iter(ctx, tailstrict, &mut |name, value| {
63 // FIXME: O(n) for arg existence check297 // FIXME: O(n) for arg existence check
64 if !params.iter().any(|p| &p.0 == name) {298 if !params.iter().any(|p| &p.0 == name) {
65 throw!(UnknownFunctionParameter((name as &str).to_owned()));299 throw!(UnknownFunctionParameter((name as &str).to_owned()));
66 }300 }
67 if passed_args301 if passed_args.insert(name.clone(), value).is_some() {
68 .insert(
69 name.clone(),
70 if tailstrict {
71 LazyVal::new_resolved(evaluate(ctx.clone(), value)?)
72 } else {
73 LazyVal::new(TraceBox(Box::new(EvaluateLazyVal {
74 context: ctx.clone(),
75 expr: value.clone(),
76 })))
77 },
78 )
79 .is_some()
80 {
81 throw!(BindingParameterASecondTime(name.clone()));302 throw!(BindingParameterASecondTime(name.clone()));
82 }303 }
83 filled_args += 1;304 filled_args += 1;
84 }305 Ok(())
306 })?;
85307
86 if filled_args < params.len() {308 if filled_args < params.len() {
87 // Some args are unset, but maybe we have defaults for them309 // Some args are unset, but maybe we have defaults for them
123345
124 // Some args still wasn't filled346 // Some args still wasn't filled
125 if filled_args != params.len() {347 if filled_args != params.len() {
126 for param in params.iter().skip(args.unnamed.len()) {348 for param in params.iter().skip(args.unnamed_len()) {
127 if !args.named.iter().any(|a| a.0 == param.0) {349 let mut found = false;
350 args.named_names(&mut |name| {
351 if name == &param.0 {
352 found = true;
353 }
354 });
355 if !found {
128 throw!(FunctionParameterNotBoundInCall(param.0.clone()));356 throw!(FunctionParameterNotBoundInCall(param.0.clone()));
129 }357 }
130 }358 }
141 }369 }
142}370}
143371
372type BuiltinParamName = Cow<'static, str>;
373
144#[derive(Clone, Copy)]374#[derive(Clone)]
145pub struct BuiltinParam {375pub struct BuiltinParam {
146 pub name: &'static str,376 pub name: BuiltinParamName,
147 pub has_default: bool,377 pub has_default: bool,
148}378}
149379
380pub trait Builtin: Trace {
381 fn name(&self) -> &str;
382 fn params(&self) -> &[BuiltinParam];
383 fn call(
384 &self,
385 context: Context,
386 loc: Option<&ExprLocation>,
387 args: &dyn ArgsLike,
388 ) -> Result<Val>;
389}
390
391pub trait StaticBuiltin: Builtin + Send + Sync
392where
393 Self: 'static,
394{
395 // In impl, to make it object safe:
396 // const INST: &'static Self;
397}
398
150/// You shouldn't probally use this function, use jrsonnet_macros::builtin instead399/// You shouldn't probally use this function, use jrsonnet_macros::builtin instead
151///400///
152/// ## Parameters401/// ## Parameters
153/// * `ctx`: used for passed argument expressions' execution and for body execution (if `body_ctx` is not set)402/// * `ctx`: used for passed argument expressions' execution and for body execution (if `body_ctx` is not set)
154/// * `params`: function parameters' definition403/// * `params`: function parameters' definition
155/// * `args`: passed function arguments404/// * `args`: passed function arguments
156/// * `tailstrict`: if set to `true` function arguments are eagerly executed, otherwise - lazily405/// * `tailstrict`: if set to `true` function arguments are eagerly executed, otherwise - lazily
157pub fn parse_builtin_call<'k>(406pub fn parse_builtin_call(
158 ctx: Context,407 ctx: Context,
159 params: &'static [BuiltinParam],408 params: &[BuiltinParam],
160 args: &'k ArgsDesc,409 args: &dyn ArgsLike,
161 tailstrict: bool,410 tailstrict: bool,
162) -> Result<GcHashMap<&'k str, LazyVal>> {411) -> Result<GcHashMap<BuiltinParamName, LazyVal>> {
163 let mut passed_args = GcHashMap::with_capacity(params.len());412 let mut passed_args = GcHashMap::with_capacity(params.len());
164 if args.unnamed.len() > params.len() {413 if args.unnamed_len() > params.len() {
165 throw!(TooManyArgsFunctionHas(params.len()))414 throw!(TooManyArgsFunctionHas(params.len()))
166 }415 }
167416
168 let mut filled_args = 0;417 let mut filled_args = 0;
169418
170 for (id, arg) in args.unnamed.iter().enumerate() {419 args.unnamed_iter(ctx.clone(), tailstrict, &mut |id, arg| {
171 let name = params[id].name;420 let name = params[id].name.clone();
172 passed_args.insert(421 passed_args.insert(name, arg);
173 name,
174 if tailstrict {
175 LazyVal::new_resolved(evaluate(ctx.clone(), arg)?)
176 } else {
177 LazyVal::new(TraceBox(Box::new(EvaluateLazyVal {
178 context: ctx.clone(),
179 expr: arg.clone(),
180 })))
181 },
182 );
183 filled_args += 1;422 filled_args += 1;
184 }423 Ok(())
424 })?;
185425
186 for (name, value) in args.named.iter() {426 args.named_iter(ctx, tailstrict, &mut |name, arg| {
187 // FIXME: O(n) for arg existence check427 // FIXME: O(n) for arg existence check
188 if !params.iter().any(|p| p.name == name as &str) {428 let p = params
429 .iter()
430 .find(|p| p.name == name as &str)
189 throw!(UnknownFunctionParameter((name as &str).to_owned()));431 .ok_or_else(|| UnknownFunctionParameter((name as &str).to_owned()))?;
190 }432 if passed_args.insert(p.name.clone(), arg).is_some() {
191 if passed_args
192 .insert(
193 name,
194 if tailstrict {
195 LazyVal::new_resolved(evaluate(ctx.clone(), value)?)
196 } else {
197 LazyVal::new(TraceBox(Box::new(EvaluateLazyVal {
198 context: ctx.clone(),
199 expr: value.clone(),
200 })))
201 },
202 )
203 .is_some()
204 {
205 throw!(BindingParameterASecondTime(name.clone()));433 throw!(BindingParameterASecondTime(name.clone()));
206 }434 }
207 filled_args += 1;435 filled_args += 1;
208 }436 Ok(())
437 })?;
209438
210 if filled_args < params.len() {439 if filled_args < params.len() {
211 for param in params.iter().filter(|p| p.has_default) {440 for param in params.iter().filter(|p| p.has_default) {
217446
218 // Some args still wasn't filled447 // Some args still wasn't filled
219 if filled_args != params.len() {448 if filled_args != params.len() {
220 for param in params.iter().skip(args.unnamed.len()) {449 for param in params.iter().skip(args.unnamed_len()) {
221 if !args.named.iter().any(|a| &a.0 as &str == param.name) {450 let mut found = false;
451 args.named_names(&mut |name| {
452 if name as &str == &param.name as &str {
453 found = true;
454 }
455 });
456 if !found {
222 throw!(FunctionParameterNotBoundInCall(param.name.into()));457 throw!(FunctionParameterNotBoundInCall(param.name.clone().into()));
223 }458 }
224 }459 }
225 unreachable!();460 unreachable!();
226 }461 }
227 }462 }
228 Ok(passed_args)463 Ok(passed_args)
229}
230
231pub fn parse_function_call_map(
232 ctx: Context,
233 body_ctx: Option<Context>,
234 params: &ParamsDesc,
235 args: &HashMap<IStr, Val>,
236 tailstrict: bool,
237) -> Result<Context> {
238 let mut out = GcHashMap::with_capacity(params.len());
239 let mut positioned_args = vec![None; params.0.len()];
240 for (name, val) in args.iter() {
241 let idx = params
242 .iter()
243 .position(|p| *p.0 == **name)
244 .ok_or_else(|| UnknownFunctionParameter((name as &str).to_owned()))?;
245
246 if idx >= params.len() {
247 throw!(TooManyArgsFunctionHas(params.len()));
248 }
249 if positioned_args[idx].is_some() {
250 throw!(BindingParameterASecondTime(params[idx].0.clone()));
251 }
252 positioned_args[idx] = Some(val.clone());
253 }
254 // Fill defaults
255 for (id, p) in params.iter().enumerate() {
256 let val = if let Some(arg) = positioned_args[id].take() {
257 LazyVal::new_resolved(arg)
258 } else if let Some(default) = &p.1 {
259 if tailstrict {
260 LazyVal::new_resolved(evaluate(
261 body_ctx.clone().expect(NO_DEFAULT_CONTEXT),
262 default,
263 )?)
264 } else {
265 let body_ctx = body_ctx.clone();
266 let default = default.clone();
267 #[derive(Trace)]
268 struct EvaluateLazyVal {
269 body_ctx: Option<Context>,
270 default: LocExpr,
271 }
272 impl LazyValValue for EvaluateLazyVal {
273 fn get(self: Box<Self>) -> Result<Val> {
274 evaluate(
275 self.body_ctx.clone().expect(NO_DEFAULT_CONTEXT),
276 &self.default,
277 )
278 }
279 }
280 LazyVal::new(TraceBox(Box::new(EvaluateLazyVal { body_ctx, default })))
281 }
282 } else {
283 throw!(FunctionParameterNotBoundInCall(p.0.clone()));
284 };
285 out.insert(p.0.clone(), val);
286 }
287
288 Ok(body_ctx.unwrap_or(ctx).extend(out, None, None, None))
289}
290
291pub fn place_args(body_ctx: Context, params: &ParamsDesc, args: &[Val]) -> Result<Context> {
292 let mut out = GcHashMap::with_capacity(params.len());
293 let mut positioned_args = vec![None; params.0.len()];
294 for (id, arg) in args.iter().enumerate() {
295 if id >= params.len() {
296 throw!(TooManyArgsFunctionHas(params.len()));
297 }
298 positioned_args[id] = Some(arg);
299 }
300 // Fill defaults
301 for (id, p) in params.iter().enumerate() {
302 let val = if let Some(arg) = &positioned_args[id] {
303 (*arg).clone()
304 } else if let Some(default) = &p.1 {
305 evaluate(body_ctx.clone(), default)?
306 } else {
307 throw!(FunctionParameterNotBoundInCall(p.0.clone()));
308 };
309 out.insert(p.0.clone(), LazyVal::new_resolved(val));
310 }
311
312 Ok(body_ctx.extend(out, None, None, None))
313}464}
314465
modifiedcrates/jrsonnet-evaluator/src/lib.rsdiffbeforeafterboth
25use error::{Error::*, LocError, Result, StackTraceElement};25use error::{Error::*, LocError, Result, StackTraceElement};
26pub use evaluate::*;26pub use evaluate::*;
27pub use function::parse_function_call;27pub use function::parse_function_call;
28use function::TlaArg;
28use gc::{GcHashMap, TraceBox};29use gc::{GcHashMap, TraceBox};
29use gcmodule::{Cc, Trace};30use gcmodule::{Cc, Trace};
30pub use import::*;31pub use import::*;
77 /// Used for ext.native78 /// Used for ext.native
78 pub ext_natives: HashMap<IStr, Cc<NativeCallback>>,79 pub ext_natives: HashMap<IStr, Cc<NativeCallback>>,
79 /// TLA vars80 /// TLA vars
80 pub tla_vars: HashMap<IStr, Val>,81 pub tla_vars: HashMap<IStr, TlaArg>,
81 /// Global variables are inserted in default context82 /// Global variables are inserted in default context
82 pub globals: HashMap<IStr, Val>,83 pub globals: HashMap<IStr, Val>,
83 /// Used to resolve file locations/contents84 /// Used to resolve file locations/contents
174 EVAL_STATE.with(|s| f(s.borrow().as_ref().unwrap()))175 EVAL_STATE.with(|s| f(s.borrow().as_ref().unwrap()))
175}176}
176pub(crate) fn push_frame<T>(177pub(crate) fn push_frame<T>(
177 e: &ExprLocation,178 e: Option<&ExprLocation>,
178 frame_desc: impl FnOnce() -> String,179 frame_desc: impl FnOnce() -> String,
179 f: impl FnOnce() -> Result<T>,180 f: impl FnOnce() -> Result<T>,
180) -> Result<T> {181) -> Result<T> {
203204
204impl EvaluationState {205impl EvaluationState {
205 /// Parses and adds file as loaded206 /// Parses and adds file as loaded
206 pub fn add_file(&self, path: Rc<Path>, source_code: IStr) -> Result<()> {207 pub fn add_file(&self, path: Rc<Path>, source_code: IStr) -> Result<LocExpr> {
207 self.add_parsed_file(
208 path.clone(),
209 source_code.clone(),
210 parse(208 let parsed = parse(
211 &source_code,209 &source_code,
212 &ParserSettings {210 &ParserSettings {
213 file_name: path.clone(),211 file_name: path.clone(),
216 .map_err(|error| ImportSyntaxError {214 .map_err(|error| ImportSyntaxError {
217 error: Box::new(error),215 error: Box::new(error),
218 path: path.to_owned(),216 path: path.to_owned(),
219 source_code,217 source_code: source_code.clone(),
220 })?,218 })?;
221 )?;219 self.add_parsed_file(path, source_code, parsed.clone())?;
222220
223 Ok(())221 Ok(parsed)
224 }222 }
225223
226 pub fn reset_evaluation_state(&self, name: &Path) {224 pub fn reset_evaluation_state(&self, name: &Path) {
341 /// Executes code creating a new stack frame339 /// Executes code creating a new stack frame
342 pub fn push<T>(340 pub fn push<T>(
343 &self,341 &self,
344 e: &ExprLocation,342 e: Option<&ExprLocation>,
345 frame_desc: impl FnOnce() -> String,343 frame_desc: impl FnOnce() -> String,
346 f: impl FnOnce() -> Result<T>,344 f: impl FnOnce() -> Result<T>,
347 ) -> Result<T> {345 ) -> Result<T> {
364 }362 }
365 if let Err(mut err) = result {363 if let Err(mut err) = result {
366 err.trace_mut().0.push(StackTraceElement {364 err.trace_mut().0.push(StackTraceElement {
367 location: Some(e.clone()),365 location: e.cloned(),
368 desc: frame_desc(),366 desc: frame_desc(),
369 });367 });
370 return Err(err);368 return Err(err);
506 Val::Func(func) => push_description_frame(504 Val::Func(func) => push_description_frame(
507 || "during TLA call".to_owned(),505 || "during TLA call".to_owned(),
508 || {506 || {
509 func.evaluate_map(507 func.evaluate(
510 self.create_default_context(),508 self.create_default_context(),
509 None,
511 &self.settings().tla_vars,510 &self.settings().tla_vars,
512 true,511 true,
513 )512 )
583 pub fn add_tla(&self, name: IStr, value: Val) {582 pub fn add_tla(&self, name: IStr, value: Val) {
584 self.settings_mut().tla_vars.insert(name, value);583 self.settings_mut()
584 .tla_vars
585 .insert(name, TlaArg::Val(value));
585 }586 }
586 pub fn add_tla_str(&self, name: IStr, value: IStr) {587 pub fn add_tla_str(&self, name: IStr, value: IStr) {
587 self.add_tla(name, Val::Str(value));588 self.settings_mut()
589 .tla_vars
590 .insert(name, TlaArg::String(value));
588 }591 }
589 pub fn add_tla_code(&self, name: IStr, code: IStr) -> Result<()> {592 pub fn add_tla_code(&self, name: IStr, code: IStr) -> Result<()> {
590 let value =593 let parsed = self.add_file(PathBuf::from(format!("tla_code {}", name)).into(), code)?;
591 self.evaluate_snippet_raw(PathBuf::from(format!("tla_code {}", name)).into(), code)?;
592 self.add_tla(name, value);594 self.settings_mut()
595 .tla_vars
596 .insert(name, TlaArg::Code(parsed));
593 Ok(())597 Ok(())
594 }598 }
595599
668 state.run_in_state(|| {672 state.run_in_state(|| {
669 state673 state
670 .push(674 .push(
671 &ExprLocation(PathBuf::from("test1.jsonnet").into(), 10, 20),675 Some(&ExprLocation(PathBuf::from("test1.jsonnet").into(), 10, 20)),
672 || "outer".to_owned(),676 || "outer".to_owned(),
673 || {677 || {
674 state.push(678 state.push(
675 &ExprLocation(PathBuf::from("test2.jsonnet").into(), 30, 40),679 Some(&ExprLocation(PathBuf::from("test2.jsonnet").into(), 30, 40)),
676 || "inner".to_owned(),680 || "inner".to_owned(),
677 || Err(RuntimeError("".into()).into()),681 || Err(RuntimeError("".into()).into()),
678 )?;682 )?;
977 r#"std.parseJson('{"a": -1,"b": 1,"c": 3.141,"d": []}')"#,981 r#"std.parseJson('{"a": -1,"b": 1,"c": 3.141,"d": []}')"#,
978 r#"{"a": -1,"b": 1,"c": 3.141,"d": []}"#982 r#"{"a": -1,"b": 1,"c": 3.141,"d": []}"#
979 );983 );
980 // TODO: this should in fact fail as is no proper JSON syntax
981 assert_json!(
982 r#"std.parseJson("{a:-1, b:1, c:3.141, d:[]}")"#,
983 r#"{"a": -1,"b": 1,"c": 3.141,"d": []}"#
984 );
985 // TODO: this is also no valid JSON
986 assert_json!(r#"std.parseJson('local x = 2; x * x')"#, r#"4"#);
987 }984 }
988985
989 #[test]986 #[test]
modifiedcrates/jrsonnet-evaluator/src/native.rsdiffbeforeafterboth
8use std::path::Path;8use std::path::Path;
9use std::rc::Rc;9use std::rc::Rc;
1010
11#[deprecated(note = "Use builtins instead")]
11pub trait NativeCallbackHandler: Trace {12pub trait NativeCallbackHandler: Trace {
12 fn call(&self, from: Rc<Path>, args: &[Val]) -> Result<Val>;13 fn call(&self, from: Rc<Path>, args: &[Val]) -> Result<Val>;
13}14}
modifiedcrates/jrsonnet-evaluator/src/typed/conversions.rsdiffbeforeafterboth
37 .into()37 .into()
38 ))38 ))
39 }39 }
40 Ok(n as $ty)40 Ok(n as Self)
41 }41 }
42 _ => unreachable!(),42 _ => unreachable!(),
43 }43 }
249249
250/// To be used in Vec<Any>250/// To be used in Vec<Any>
251/// Regular Val can't be used here, because it has wrong TryFrom::Error type251/// Regular Val can't be used here, because it has wrong TryFrom::Error type
252#[derive(Clone)]
252pub struct Any(pub Val);253pub struct Any(pub Val);
253254
254impl Typed for Any {255impl Typed for Any {
modifiedcrates/jrsonnet-evaluator/src/val.rsdiffbeforeafterboth
1use crate::{1use crate::{
2 builtin::{2 builtin::manifest::{
3 call_builtin,
4 manifest::{
5 manifest_json_ex, manifest_yaml_ex, ManifestJsonOptions, ManifestType,3 manifest_json_ex, manifest_yaml_ex, ManifestJsonOptions, ManifestType, ManifestYamlOptions,
6 ManifestYamlOptions,
7 },4 },
8 },
9 cc_ptr_eq,5 cc_ptr_eq,
10 error::{Error::*, LocError},6 error::{Error::*, LocError},
11 evaluate,7 evaluate,
12 function::{parse_function_call, parse_function_call_map, place_args},8 function::{parse_function_call, ArgsLike, Builtin, StaticBuiltin},
13 gc::TraceBox,9 gc::TraceBox,
14 native::NativeCallback,10 native::NativeCallback,
15 throw, Context, ObjValue, Result,11 throw, Context, ObjValue, Result,
16};12};
17use gcmodule::{Cc, Trace};13use gcmodule::{Cc, Trace};
18use jrsonnet_interner::IStr;14use jrsonnet_interner::IStr;
19use jrsonnet_parser::{ArgsDesc, ExprLocation, LocExpr, ParamsDesc};15use jrsonnet_parser::{ExprLocation, LocExpr, ParamsDesc};
20use jrsonnet_types::ValType;16use jrsonnet_types::ValType;
21use std::{cell::RefCell, collections::HashMap, fmt::Debug, rc::Rc};17use std::{cell::RefCell, fmt::Debug, rc::Rc};
2218
23pub trait LazyValValue: Trace {19pub trait LazyValValue: Trace {
24 fn get(self: Box<Self>) -> Result<Val>;20 fn get(self: Box<Self>) -> Result<Val>;
41 pub fn new_resolved(val: Val) -> Self {37 pub fn new_resolved(val: Val) -> Self {
42 Self(Cc::new(RefCell::new(LazyValInternals::Computed(val))))38 Self(Cc::new(RefCell::new(LazyValInternals::Computed(val))))
43 }39 }
40 pub fn force(&self) -> Result<()> {
41 self.evaluate()?;
42 Ok(())
43 }
44 pub fn evaluate(&self) -> Result<Val> {44 pub fn evaluate(&self) -> Result<Val> {
45 match &*self.0.borrow() {45 match &*self.0.borrow() {
46 LazyValInternals::Computed(v) => return Ok(v.clone()),46 LazyValInternals::Computed(v) => return Ok(v.clone()),
86 pub body: LocExpr,86 pub body: LocExpr,
87}87}
8888
89#[derive(Debug, Trace)]89#[derive(Trace)]
90pub enum FuncVal {90pub enum FuncVal {
91 /// Plain function implemented in jsonnet91 /// Plain function implemented in jsonnet
92 Normal(FuncDesc),92 Normal(FuncDesc),
93 /// Standard library function93 /// Standard library function
94 Intrinsic(IStr),94 StaticBuiltin(#[skip_trace] &'static dyn StaticBuiltin),
95
96 Builtin(TraceBox<dyn Builtin>),
95 /// Library functions implemented in native97 /// Library functions implemented in native
96 NativeExt(IStr, Cc<NativeCallback>),98 NativeExt(IStr, Cc<NativeCallback>),
97}99}
100
101impl Debug for FuncVal {
102 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
103 match self {
104 Self::Normal(arg0) => f.debug_tuple("Normal").field(arg0).finish(),
105 Self::StaticBuiltin(arg0) => f.debug_tuple("Intrinsic").field(&arg0.name()).finish(),
106 Self::Builtin(arg0) => f.debug_tuple("Intrinsic").field(&arg0.name()).finish(),
107 Self::NativeExt(arg0, arg1) => {
108 f.debug_tuple("NativeExt").field(arg0).field(arg1).finish()
109 }
110 }
111 }
112}
98113
99impl PartialEq for FuncVal {114impl PartialEq for FuncVal {
100 fn eq(&self, other: &Self) -> bool {115 fn eq(&self, other: &Self) -> bool {
101 match (self, other) {116 match (self, other) {
102 (Self::Normal(a), Self::Normal(b)) => a == b,117 (Self::Normal(a), Self::Normal(b)) => a == b,
103 (Self::Intrinsic(an), Self::Intrinsic(bn)) => an == bn,118 (Self::StaticBuiltin(an), Self::StaticBuiltin(bn)) => std::ptr::eq(*an, *bn),
104 (Self::NativeExt(an, _), Self::NativeExt(bn, _)) => an == bn,119 (Self::NativeExt(an, _), Self::NativeExt(bn, _)) => an == bn,
105 (..) => false,120 (..) => false,
106 }121 }
107 }122 }
108}123}
109impl FuncVal {124impl FuncVal {
110 pub fn is_ident(&self) -> bool {125 pub fn args_len(&self) -> usize {
111 matches!(&self, Self::Intrinsic(n) if n as &str == "id")126 match self {
127 Self::Normal(n) => n.params.iter().filter(|p| p.1.is_none()).count(),
128 Self::StaticBuiltin(i) => i.params().iter().filter(|p| !p.has_default).count(),
129 Self::Builtin(i) => i.params().iter().filter(|p| !p.has_default).count(),
130 Self::NativeExt(_, n) => n.params.iter().filter(|p| p.1.is_none()).count(),
131 }
112 }132 }
113 pub fn name(&self) -> IStr {133 pub fn name(&self) -> IStr {
114 match self {134 match self {
115 Self::Normal(normal) => normal.name.clone(),135 Self::Normal(normal) => normal.name.clone(),
116 Self::Intrinsic(name) => format!("std.{}", name).into(),136 Self::StaticBuiltin(builtin) => builtin.name().into(),
137 Self::Builtin(builtin) => builtin.name().into(),
117 Self::NativeExt(n, _) => format!("native.{}", n).into(),138 Self::NativeExt(n, _) => format!("native.{}", n).into(),
118 }139 }
119 }140 }
120 pub fn evaluate(141 pub fn evaluate(
121 &self,142 &self,
122 call_ctx: Context,143 call_ctx: Context,
123 loc: &ExprLocation,144 loc: Option<&ExprLocation>,
124 args: &ArgsDesc,145 args: &dyn ArgsLike,
125 tailstrict: bool,146 tailstrict: bool,
126 ) -> Result<Val> {147 ) -> Result<Val> {
127 match self {148 match self {
135 )?;156 )?;
136 evaluate(ctx, &func.body)157 evaluate(ctx, &func.body)
137 }158 }
138 Self::Intrinsic(name) => call_builtin(call_ctx, loc, name, args),159 Self::StaticBuiltin(name) => name.call(call_ctx, loc, args),
160 Self::Builtin(b) => b.call(call_ctx, loc, args),
139 Self::NativeExt(_name, handler) => {161 Self::NativeExt(_name, handler) => {
140 let args =162 let args =
141 parse_function_call(call_ctx, Context::new(), &handler.params, args, true)?;163 parse_function_call(call_ctx, Context::new(), &handler.params, args, true)?;
142 let mut out_args = Vec::with_capacity(handler.params.len());164 let mut out_args = Vec::with_capacity(handler.params.len());
143 for p in handler.params.0.iter() {165 for p in handler.params.0.iter() {
144 out_args.push(args.binding(p.0.clone())?.evaluate()?);166 out_args.push(args.binding(p.0.clone())?.evaluate()?);
145 }167 }
146 Ok(handler.call(loc.0.clone(), &out_args)?)168 Ok(handler.call(loc.expect("todo").0.clone(), &out_args)?)
147 }169 }
148 }170 }
149 }171 }
150
151 pub fn evaluate_map(172 pub fn evaluate_simple(&self, args: &dyn ArgsLike) -> Result<Val> {
152 &self,
153 call_ctx: Context,
154 args: &HashMap<IStr, Val>,
155 tailstrict: bool,
156 ) -> Result<Val> {
157 match self {173 self.evaluate(Context::default(), None, args, true)
158 Self::Normal(func) => {
159 let ctx = parse_function_call_map(
160 call_ctx,
161 Some(func.ctx.clone()),
162 &func.params,
163 args,
164 tailstrict,
165 )?;
166 evaluate(ctx, &func.body)
167 }
168 Self::Intrinsic(_) => todo!(),
169 Self::NativeExt(_, _) => todo!(),
170 }
171 }174 }
172
173 pub fn evaluate_values(&self, args: &[Val]) -> Result<Val> {
174 match self {
175 Self::Normal(func) => {
176 let ctx = place_args(func.ctx.clone(), &func.params, args)?;
177 evaluate(ctx, &func.body)
178 }
179 Self::Intrinsic(_) => todo!(),
180 Self::NativeExt(_, _) => todo!(),
181 }
182 }
183}175}
184176
185#[derive(Clone)]177#[derive(Clone)]
modifiedcrates/jrsonnet-interner/src/lib.rsdiffbeforeafterboth
2use rustc_hash::FxHashMap;2use rustc_hash::FxHashMap;
3use serde::{Deserialize, Serialize};3use serde::{Deserialize, Serialize};
4use std::{4use std::{
5 borrow::Cow,
5 cell::RefCell,6 cell::RefCell,
6 fmt::{self, Display},7 fmt::{self, Display},
7 hash::{BuildHasherDefault, Hash, Hasher},8 hash::{BuildHasherDefault, Hash, Hasher},
90 }91 }
91}92}
93
94impl<'i> From<Cow<'i, str>> for IStr {
95 fn from(c: Cow<'i, str>) -> Self {
96 (&c as &str).into()
97 }
98}
9299
93impl Serialize for IStr {100impl Serialize for IStr {
94 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>101 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
modifiedcrates/jrsonnet-macros/src/lib.rsdiffbeforeafterboth
1use proc_macro2::Span;
2use quote::quote;1use quote::quote;
3use syn::{parse_macro_input, FnArg, Ident, ItemFn, Pat, PatType};2use syn::{
3 parse_macro_input, FnArg, GenericArgument, ItemFn, Pat, PatType, Path, PathArguments, Type,
4};
45
5fn is_location_arg(t: &PatType) -> bool {6fn is_location_arg(t: &PatType) -> bool {
6 t.attrs.iter().any(|a| a.path.is_ident("location"))7 t.attrs.iter().any(|a| a.path.is_ident("location"))
7}8}
9
10trait RetainHad<T> {
11 fn retain_had(&mut self, h: impl FnMut(&T) -> bool) -> bool;
12}
13impl<T> RetainHad<T> for Vec<T> {
14 fn retain_had(&mut self, h: impl FnMut(&T) -> bool) -> bool {
15 let before = self.len();
16 self.retain(h);
17 let after = self.len();
18 before != after
19 }
20}
21
22fn extract_type_from_option(ty: &Type) -> Option<&Type> {
23 fn path_is_option(path: &Path) -> bool {
24 path.leading_colon.is_none()
25 && path.segments.len() == 1
26 && path.segments.iter().next().unwrap().ident == "Option"
27 }
28
29 match ty {
30 Type::Path(typepath) if typepath.qself.is_none() && path_is_option(&typepath.path) => {
31 // Get the first segment of the path (there is only one, in fact: "Option"):
32 let type_params = &typepath.path.segments.iter().next().unwrap().arguments;
33 // It should have only on angle-bracketed param ("<String>"):
34 let generic_arg = match type_params {
35 PathArguments::AngleBracketed(params) => params.args.iter().next().unwrap(),
36 _ => panic!("missing option generic"),
37 };
38 // This argument must be a type:
39 match generic_arg {
40 GenericArgument::Type(ty) => Some(ty),
41 _ => panic!("option generic should be a type"),
42 }
43 }
44 _ => None,
45 }
46}
847
9#[proc_macro_attribute]48#[proc_macro_attribute]
10pub fn builtin(49pub fn builtin(
33 Pat::Ident(i) => i.ident.to_string(),72 Pat::Ident(i) => i.ident.to_string(),
34 _ => panic!("only idents supported yet"),73 _ => panic!("only idents supported yet"),
35 };74 };
36 // TODO: Check if ty == Option<_>
37 let optional = false;75 let optional = extract_type_from_option(&t.ty).is_some();
38 quote! {76 quote! {
39 BuiltinParam {77 BuiltinParam {
40 name: #ident,78 name: std::borrow::Cow::Borrowed(#ident),
41 has_default: #optional,79 has_default: #optional,
42 }80 }
43 }81 }
53 FnArg::Typed(t) => t,91 FnArg::Typed(t) => t,
54 })92 })
55 .map(|t| {93 .map(|t| {
56 let count_before = t.attrs.len();94 let is_location = t.attrs.retain_had(|a| !a.path.is_ident("location"));
57 t.attrs.retain(|a| !a.path.is_ident("location"));
58 let count_after = t.attrs.len();
59 let is_location = count_before != count_after;
60 if is_location {95 if is_location {
61 quote! {{96 quote! {{
62 loc97 loc
67 _ => panic!("only idents supported yet"),102 _ => panic!("only idents supported yet"),
68 };103 };
69 let ty = &t.ty;104 let ty = &t.ty;
105 if let Some(opt_ty) = extract_type_from_option(&t.ty) {
106 quote! {{
107 if let Some(value) = parsed.get(#ident) {
108 Some(jrsonnet_evaluator::push_description_frame(
109 || format!("argument <{}> evaluation", #ident),
110 || <#opt_ty>::try_from(value.evaluate()?),
111 )?)
112 } else {
113 None
114 }
115 }}
116 } else {
70 quote! {{117 quote! {{
71 let value = parsed.get(#ident).unwrap();118 let value = parsed.get(#ident).unwrap();
72119
75 || <#ty>::try_from(value.evaluate()?),122 || <#ty>::try_from(value.evaluate()?),
76 )?123 )?
77 }}124 }}
125 }
78 }126 }
79 }).collect::<Vec<_>>();127 })
80 128 .collect::<Vec<_>>();
81 let inner_name = Ident::new("inner", Span::call_site());129
82 let mut inner_fun = fun.clone();
83 inner_fun.sig.ident = inner_name.clone();
84
85 let attrs = &fun.attrs;
86 let vis = &fun.vis;
87 let name = &fun.sig.ident;130 let name = &fun.sig.ident;
131 let vis = &fun.vis;
88 (quote! {132 (quote! {
89 #(#attrs)*133 #fun
134 #[doc(hidden)]
135 #[allow(non_camel_case_types)]
136 #[derive(Clone, Copy, gcmodule::Trace)]
90 #vis fn #name(context: Context, loc: &ExprLocation, args: &ArgsDesc) -> Result<Val> {137 #vis struct #name {}
91 #inner_fun138 const _: () = {
92 use jrsonnet_evaluator::function::BuiltinParam;139 use jrsonnet_evaluator::function::{Builtin, StaticBuiltin, BuiltinParam, ArgsLike};
93 const PARAMS: &'static [BuiltinParam] = &[140 const PARAMS: &'static [BuiltinParam] = &[
94 #(#params),*141 #(#params),*
95 ];142 ];
143
144 impl #name {
145 pub const INST: &'static dyn StaticBuiltin = &#name {};
146 }
147 impl StaticBuiltin for #name {}
148 impl Builtin for #name
149 where
150 Self: 'static
151 {
152 fn name(&self) -> &str {
153 stringify!(#name)
154 }
155 fn params(&self) -> &[BuiltinParam] {
156 PARAMS
157 }
158 fn call(&self, context: Context, loc: Option<&ExprLocation>, args: &dyn ArgsLike) -> Result<Val> {
96 let parsed = jrsonnet_evaluator::function::parse_builtin_call(context, &PARAMS, args, false)?;159 let parsed = jrsonnet_evaluator::function::parse_builtin_call(context, &PARAMS, args, false)?;
97160
98 let result: #result = #inner_name(#(#args),*);161 let result: #result = #name(#(#args),*);
99 let result = result?;162 let result = result?;
100 result.try_into()163 result.try_into()
164 }
165 }
101 }166 };
102 })167 })
103 .into()168 .into()
104}169}
modifiedcrates/jrsonnet-parser/src/lib.rsdiffbeforeafterboth
40 / "#" (!eol()[_])* eol()40 / "#" (!eol()[_])* eol()
4141
42 rule single_whitespace() = quiet!{([' ' | '\r' | '\n' | '\t'] / comment())} / expected!("<whitespace>")42 rule single_whitespace() = quiet!{([' ' | '\r' | '\n' | '\t'] / comment())} / expected!("<whitespace>")
43 rule _() = single_whitespace()*43 rule _() = quiet!{([' ' | '\r' | '\n' | '\t']+) / comment()}* / expected!("<whitespace>")
4444
45 /// For comma-delimited elements45 /// For comma-delimited elements
46 rule comma() = quiet!{_ "," _} / expected!("<comma>")46 rule comma() = quiet!{_ "," _} / expected!("<comma>")
305pub fn parse(str: &str, settings: &ParserSettings) -> Result<LocExpr, ParseError> {305pub fn parse(str: &str, settings: &ParserSettings) -> Result<LocExpr, ParseError> {
306 jsonnet_parser::jsonnet(str, settings)306 jsonnet_parser::jsonnet(str, settings)
307}307}
308/// Used for importstr values
309pub fn string_to_expr(str: IStr, settings: &ParserSettings) -> LocExpr {
310 let len = str.len();
311 LocExpr(
312 Rc::new(Expr::Str(str)),
313 ExprLocation(settings.file_name.clone(), 0, len),
314 )
315}
308316
309#[cfg(test)]317#[cfg(test)]
310pub mod tests {318pub mod tests {
modifiedcrates/jrsonnet-stdlib/src/std.jsonnetdiffbeforeafterboth
375375
376 manifestJsonEx:: $intrinsic(manifestJsonEx),376 manifestJsonEx:: $intrinsic(manifestJsonEx),
377377
378 manifestYamlDocImpl:: $intrinsic(manifestYamlDocImpl),378 manifestYamlDoc:: $intrinsic(manifestYamlDoc),
379379
380 manifestYamlDoc(value, indent_array_in_object=false, quote_keys=true):: std.manifestYamlDocImpl(value, indent_array_in_object, quote_keys),
381
382 manifestYamlStream(value, indent_array_in_object=false, c_document_end=true)::380 manifestYamlStream(value, indent_array_in_object=false, c_document_end=true)::
383 if !std.isArray(value) then381 if !std.isArray(value) then
384 error 'manifestYamlStream only takes arrays, got ' + std.type(value)382 error 'manifestYamlStream only takes arrays, got ' + std.type(value)
442 base64Decode:: $intrinsic(base64Decode),440 base64Decode:: $intrinsic(base64Decode),
443441
444 reverse:: $intrinsic(reverse),442 reverse:: $intrinsic(reverse),
445
446 sortImpl:: $intrinsic(sortImpl),
447443
448 sort(arr, keyF=id)::444 sort:: $intrinsic(sort),
449 std.sortImpl(arr, keyF),
450445
451 uniq(arr, keyF=id)::446 uniq(arr, keyF=id)::
452 local f(a, b) =447 local f(a, b) =