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

difftreelog

Merge pull request #29 from CertainLach/type-safety

Yaroslav Bolyukin2021-01-25parents: #847c11f #c93dcb4.patch.diff
in: master
Jsonnet type system

36 files changed

modifiedCargo.lockdiffbeforeafterboth
167 "bincode",167 "bincode",
168 "closure",168 "closure",
169 "indexmap",169 "indexmap",
170 "jrsonnet-interner",
170 "jrsonnet-parser",171 "jrsonnet-parser",
171 "jrsonnet-stdlib",172 "jrsonnet-stdlib",
173 "jrsonnet-types",
172 "md5",174 "md5",
173 "pathdiff",175 "pathdiff",
174 "rustc-hash",176 "rustc-hash",
175 "serde",177 "serde",
176 "serde_json",178 "serde_json",
177 "structdump",
178 "thiserror",179 "thiserror",
179]180]
181
182[[package]]
183name = "jrsonnet-interner"
184version = "0.3.3"
185dependencies = [
186 "rustc-hash",
187 "serde",
188]
180189
181[[package]]190[[package]]
182name = "jrsonnet-parser"191name = "jrsonnet-parser"
183version = "0.3.3"192version = "0.3.3"
184dependencies = [193dependencies = [
194 "jrsonnet-interner",
185 "jrsonnet-stdlib",195 "jrsonnet-stdlib",
186 "peg",196 "peg",
187 "serde",197 "serde",
188 "structdump",
189 "structdump-derive",
190 "unescape",198 "unescape",
191]199]
192200
193[[package]]201[[package]]
194name = "jrsonnet-stdlib"202name = "jrsonnet-stdlib"
195version = "0.3.3"203version = "0.3.3"
204
205[[package]]
206name = "jrsonnet-types"
207version = "0.3.3"
208dependencies = [
209 "peg",
210]
196211
197[[package]]212[[package]]
198name = "jsonnet"213name = "jsonnet"
199version = "0.3.3"214version = "0.3.3"
200dependencies = [215dependencies = [
201 "jrsonnet-evaluator",216 "jrsonnet-evaluator",
217 "jrsonnet-interner",
202 "jrsonnet-parser",218 "jrsonnet-parser",
203]219]
204220
371source = "registry+https://github.com/rust-lang/crates.io-index"387source = "registry+https://github.com/rust-lang/crates.io-index"
372checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"388checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
373
374[[package]]
375name = "structdump"
376version = "0.1.2"
377source = "registry+https://github.com/rust-lang/crates.io-index"
378checksum = "2e16ec33a0342fdb67d13913b4ffae6527ebccfa04b5d7da174bdc7a31db29b8"
379
380[[package]]
381name = "structdump-derive"
382version = "0.1.2"
383source = "registry+https://github.com/rust-lang/crates.io-index"
384checksum = "06c337fdc077e02ccbfcc62af0090564a4af342975c3b7be09705efab90c1888"
385dependencies = [
386 "proc-macro2",
387 "quote",
388 "syn",
389]
390389
391[[package]]390[[package]]
392name = "syn"391name = "syn"
modifiedCargo.tomldiffbeforeafterboth
1[workspace]1[workspace]
2members = [2members = [
3 "crates/jrsonnet-interner",
3 "crates/jrsonnet-parser",4 "crates/jrsonnet-parser",
4 "crates/jrsonnet-evaluator",5 "crates/jrsonnet-evaluator",
5 "crates/jrsonnet-stdlib",6 "crates/jrsonnet-stdlib",
6 "crates/jrsonnet-cli",7 "crates/jrsonnet-cli",
8 "crates/jrsonnet-types",
7 "bindings/jsonnet",9 "bindings/jsonnet",
8 "cmds/jrsonnet"10 "cmds/jrsonnet",
9]11]
1012
11[profile.test]13[profile.test]
modifiedbindings/jsonnet/Cargo.tomldiffbeforeafterboth
5edition = "2018"5edition = "2018"
66
7[dependencies]7[dependencies]
8jrsonnet-interner = { path = "../../crates/jrsonnet-interner", version = "0.3.3" }
8jrsonnet-evaluator = { path = "../../crates/jrsonnet-evaluator", version = "0.3.3" }9jrsonnet-evaluator = { path = "../../crates/jrsonnet-evaluator", version = "0.3.3" }
9jrsonnet-parser = { path = "../../crates/jrsonnet-parser", version = "0.3.3" }10jrsonnet-parser = { path = "../../crates/jrsonnet-parser", version = "0.3.3" }
1011
modifiedbindings/jsonnet/src/import.rsdiffbeforeafterboth
4 error::{Error::*, Result},4 error::{Error::*, Result},
5 throw, EvaluationState, ImportResolver,5 throw, EvaluationState, ImportResolver,
6};6};
7use jrsonnet_interner::IStr;
7use std::{8use std::{
8 any::Any,9 any::Any,
9 cell::RefCell,10 cell::RefCell,
30 cb: JsonnetImportCallback,31 cb: JsonnetImportCallback,
31 ctx: *mut c_void,32 ctx: *mut c_void,
3233
33 out: RefCell<HashMap<PathBuf, Rc<str>>>,34 out: RefCell<HashMap<PathBuf, IStr>>,
34}35}
35impl ImportResolver for CallbackImportResolver {36impl ImportResolver for CallbackImportResolver {
36 fn resolve_file(&self, from: &PathBuf, path: &PathBuf) -> Result<Rc<PathBuf>> {37 fn resolve_file(&self, from: &PathBuf, path: &PathBuf) -> Result<Rc<PathBuf>> {
7576
76 Ok(Rc::new(found_here_buf))77 Ok(Rc::new(found_here_buf))
77 }78 }
78 fn load_file_contents(&self, resolved: &PathBuf) -> Result<Rc<str>> {79 fn load_file_contents(&self, resolved: &PathBuf) -> Result<IStr> {
79 Ok(self.out.borrow().get(resolved).unwrap().clone())80 Ok(self.out.borrow().get(resolved).unwrap().clone())
80 }81 }
81 unsafe fn as_any(&self) -> &dyn Any {82 unsafe fn as_any(&self) -> &dyn Any {
124 throw!(ImportFileNotFound(from.clone(), path.clone()))125 throw!(ImportFileNotFound(from.clone(), path.clone()))
125 }126 }
126 }127 }
127 fn load_file_contents(&self, id: &PathBuf) -> Result<Rc<str>> {128 fn load_file_contents(&self, id: &PathBuf) -> Result<IStr> {
128 let mut file = File::open(id).map_err(|_e| ResolvedFileNotFound(id.clone()))?;129 let mut file = File::open(id).map_err(|_e| ResolvedFileNotFound(id.clone()))?;
129 let mut out = String::new();130 let mut out = String::new();
130 file.read_to_string(&mut out)131 file.read_to_string(&mut out)
modifiedbindings/jsonnet/src/lib.rsdiffbeforeafterboth
88
9use import::NativeImportResolver;9use import::NativeImportResolver;
10use jrsonnet_evaluator::{EvaluationState, ManifestFormat, Val};10use jrsonnet_evaluator::{EvaluationState, ManifestFormat, Val};
11use jrsonnet_interner::IStr;
11use std::{12use std::{
12 alloc::Layout,13 alloc::Layout,
13 ffi::{CStr, CString},14 ffi::{CStr, CString},
161 })162 })
162}163}
163164
164fn multi_to_raw(multi: Vec<(Rc<str>, Rc<str>)>) -> *const c_char {165fn multi_to_raw(multi: Vec<(IStr, IStr)>) -> *const c_char {
165 let mut out = Vec::new();166 let mut out = Vec::new();
166 for (i, (k, v)) in multi.iter().enumerate() {167 for (i, (k, v)) in multi.iter().enumerate() {
167 if i != 0 {168 if i != 0 {
237 })238 })
238}239}
239240
240fn stream_to_raw(multi: Vec<Rc<str>>) -> *const c_char {241fn stream_to_raw(multi: Vec<IStr>) -> *const c_char {
241 let mut out = Vec::new();242 let mut out = Vec::new();
242 for (i, v) in multi.iter().enumerate() {243 for (i, v) in multi.iter().enumerate() {
243 if i != 0 {244 if i != 0 {
modifiedbindings/jsonnet/src/native.rsdiffbeforeafterboth
3535
36 vm.add_native(36 vm.add_native(
37 name,37 name,
38 Rc::new(NativeCallback::new(params, move |args| {38 Rc::new(NativeCallback::new(params, move |_caller, args| {
39 let mut n_args = Vec::new();39 let mut n_args = Vec::new();
40 for a in args {40 for a in args {
41 n_args.push(Some(Box::new(a.clone())));41 n_args.push(Some(Box::new(a.clone())));
modifiedbindings/jsonnet/src/val_extract.rsdiffbeforeafterboth
99
10#[no_mangle]10#[no_mangle]
11pub extern "C" fn jsonnet_json_extract_string(_vm: &EvaluationState, v: &Val) -> *mut c_char {11pub extern "C" fn jsonnet_json_extract_string(_vm: &EvaluationState, v: &Val) -> *mut c_char {
12 match v.unwrap_if_lazy().unwrap() {12 match v {
13 Val::Str(s) => CString::new(&*s as &str).unwrap().into_raw(),13 Val::Str(s) => CString::new(&*s as &str).unwrap().into_raw(),
14 _ => std::ptr::null_mut(),14 _ => std::ptr::null_mut(),
15 }15 }
20 v: &Val,20 v: &Val,
21 out: &mut c_double,21 out: &mut c_double,
22) -> c_int {22) -> c_int {
23 match v.unwrap_if_lazy().unwrap() {23 match v {
24 Val::Num(n) => {24 Val::Num(n) => {
25 *out = n;25 *out = *n;
26 126 1
27 }27 }
28 _ => 0,28 _ => 0,
29 }29 }
30}30}
31#[no_mangle]31#[no_mangle]
32pub extern "C" fn jsonnet_json_extract_bool(_vm: &EvaluationState, v: &Val) -> c_int {32pub extern "C" fn jsonnet_json_extract_bool(_vm: &EvaluationState, v: &Val) -> c_int {
33 match v.unwrap_if_lazy().unwrap() {33 match v {
34 Val::Bool(false) => 0,34 Val::Bool(false) => 0,
35 Val::Bool(true) => 1,35 Val::Bool(true) => 1,
36 _ => 2,36 _ => 2,
37 }37 }
38}38}
39#[no_mangle]39#[no_mangle]
40pub extern "C" fn jsonnet_json_extract_null(_vm: &EvaluationState, v: &Val) -> c_int {40pub extern "C" fn jsonnet_json_extract_null(_vm: &EvaluationState, v: &Val) -> c_int {
41 match v.unwrap_if_lazy().unwrap() {41 match v {
42 Val::Null => 1,42 Val::Null => 1,
43 _ => 0,43 _ => 0,
44 }44 }
modifiedbindings/jsonnet/src/val_make.rsdiffbeforeafterboth
1//! Create values in VM1//! Create values in VM
22
3use jrsonnet_evaluator::{EvaluationState, ObjValue, Val};3use jrsonnet_evaluator::{ArrValue, EvaluationState, ObjValue, Val};
4use std::{4use std::{
5 ffi::CStr,5 ffi::CStr,
6 os::raw::{c_char, c_double, c_int},6 os::raw::{c_char, c_double, c_int},
3838
39#[no_mangle]39#[no_mangle]
40pub extern "C" fn jsonnet_json_make_array(_vm: &EvaluationState) -> *mut Val {40pub extern "C" fn jsonnet_json_make_array(_vm: &EvaluationState) -> *mut Val {
41 Box::into_raw(Box::new(Val::Arr(Rc::new(Vec::new()))))41 Box::into_raw(Box::new(Val::Arr(ArrValue::Eager(Rc::new(Vec::new())))))
42}42}
4343
44#[no_mangle]44#[no_mangle]
modifiedbindings/jsonnet/src/val_modify.rsdiffbeforeafterboth
3//! In jrsonnet every value is immutable, and this code is probally broken3//! In jrsonnet every value is immutable, and this code is probally broken
44
5use jrsonnet_evaluator::{EvaluationState, LazyBinding, LazyVal, ObjMember, ObjValue, Val};5use jrsonnet_evaluator::{
6 ArrValue, EvaluationState, LazyBinding, LazyVal, ObjMember, ObjValue, Val,
7};
6use jrsonnet_parser::Visibility;8use jrsonnet_parser::Visibility;
7use std::{collections::HashMap, ffi::CStr, os::raw::c_char, rc::Rc};9use std::{collections::HashMap, ffi::CStr, os::raw::c_char, rc::Rc};
12#[no_mangle]14#[no_mangle]
13pub unsafe extern "C" fn jsonnet_json_array_append(15pub unsafe extern "C" fn jsonnet_json_array_append(
14 _vm: &EvaluationState,16 _vm: &EvaluationState,
15 arr: *mut Val,17 arr: &mut Val,
16 val: &Val,18 val: &Val,
17) {19) {
18 match *Box::from_raw(arr) {20 match arr {
19 Val::Arr(old) => {21 Val::Arr(old) => {
20 let mut new = Rc::try_unwrap(old).expect("arr with no refs");22 let mut new = Vec::new();
23 for item in old.iter_lazy() {
24 new.push(item);
25 }
21 new.push(val.clone());26 new.push(LazyVal::new_resolved(val.clone()));
22 *arr = Val::Arr(Rc::new(new));27 *arr = Val::Arr(ArrValue::Lazy(Rc::new(new)));
23 }28 }
24 _ => panic!("should receive array"),29 _ => panic!("should receive array"),
25 }30 }
modifiedcrates/jrsonnet-evaluator/Cargo.tomldiffbeforeafterboth
12serialized-stdlib = ["serde", "bincode", "jrsonnet-parser/deserialize"]12serialized-stdlib = ["serde", "bincode", "jrsonnet-parser/deserialize"]
13# Allow to convert Val into serde_json::Value and backwards13# Allow to convert Val into serde_json::Value and backwards
14serde-json = ["serde", "serde_json"]14serde-json = ["serde", "serde_json"]
15# Same as above, but with generated code instead of serde. Reduces memory usage, but increases binary size and compilation time
16codegenerated-stdlib = []
17# Replace some standard library functions with faster implementations (I.e manifestJsonEx)15# Replace some standard library functions with faster implementations (I.e manifestJsonEx)
18# Library works fine without this feature, but requires more memory and time for std function calls16# Library works fine without this feature, but requires more memory and time for std function calls
19faster = []17faster = []
24unstable = []22unstable = []
2523
26[dependencies]24[dependencies]
25jrsonnet-interner = { path = "../jrsonnet-interner" }
27jrsonnet-parser = { path = "../jrsonnet-parser", version = "0.3.3" }26jrsonnet-parser = { path = "../jrsonnet-parser", version = "0.3.3" }
28jrsonnet-stdlib = { path = "../jrsonnet-stdlib", version = "0.3.3" }27jrsonnet-stdlib = { path = "../jrsonnet-stdlib", version = "0.3.3" }
28jrsonnet-types = { path = "../jrsonnet-types", version = "0.3.3" }
29pathdiff = "0.2.0"29pathdiff = "0.2.0"
3030
31closure = "0.3.0"31closure = "0.3.0"
57optional = true57optional = true
5858
59[build-dependencies]59[build-dependencies]
60jrsonnet-parser = { path = "../jrsonnet-parser", features = ["dump", "serialize", "deserialize"], version = "0.3.3" }60jrsonnet-parser = { path = "../jrsonnet-parser", features = ["serialize", "deserialize"], version = "0.3.3" }
61jrsonnet-stdlib = { path = "../jrsonnet-stdlib", version = "0.3.3" }61jrsonnet-stdlib = { path = "../jrsonnet-stdlib", version = "0.3.3" }
62structdump = "0.1.2"
63serde = "1.0"62serde = "1.0"
64bincode = "1.3.1"63bincode = "1.3.1"
6564
modifiedcrates/jrsonnet-evaluator/build.rsdiffbeforeafterboth
10 path::{Path, PathBuf},10 path::{Path, PathBuf},
11 rc::Rc,11 rc::Rc,
12};12};
13use structdump::CodegenResult;
1413
15fn main() {14fn main() {
16 let parsed = parse(15 let parsed = parse(
36 name: FieldName::Fixed(name),35 name: FieldName::Fixed(name),
37 ..36 ..
38 })37 })
39 if **name == *"join" || **name == *"manifestJsonEx" ||38 if name == "join" || name == "manifestJsonEx" ||
40 **name == *"escapeStringJson" || **name == *"equals" ||39 name == "escapeStringJson" || name == "equals" ||
41 **name == *"base64" || **name == *"foldl" || **name == *"foldr" ||40 name == "base64" || name == "foldl" || name == "foldr" ||
42 **name == *"sortImpl" || **name == *"format" || **name == *"range" ||41 name == "sortImpl" || name == "format" || name == "range" ||
43 **name == *"reverse" || **name == *"slice" || **name == *"mod"42 name == "reverse" || name == "slice" || name == "mod" ||
43 name == "strReplace"
44 )44 )
45 })45 })
46 .collect(),46 .collect(),
52 } else {52 } else {
53 parsed53 parsed
54 };54 };
55 {
56 let mut codegen = CodegenResult::default();
57 let code = codegen.codegen(&parsed);
58
59 let out_dir = env::var("OUT_DIR").unwrap();
60 let dest_path = Path::new(&out_dir).join("stdlib.rs");
61 let mut f = File::create(&dest_path).unwrap();
62 f.write_all(&code.as_bytes()).unwrap();
63 }
64 {55 {
65 let out_dir = env::var("OUT_DIR").unwrap();56 let out_dir = env::var("OUT_DIR").unwrap();
66 let dest_path = Path::new(&out_dir).join("stdlib.bincode");57 let dest_path = Path::new(&out_dir).join("stdlib.bincode");
modifiedcrates/jrsonnet-evaluator/src/builtin/format.rsdiffbeforeafterboth
1//! faster std.format impl1//! faster std.format impl
2#![allow(clippy::too_many_arguments)]2#![allow(clippy::too_many_arguments)]
33
4use crate::{error::Error::*, throw, LocError, ObjValue, Result, Val, ValType};4use crate::{error::Error::*, throw, LocError, ObjValue, Result, Val};
5use jrsonnet_interner::IStr;
6use jrsonnet_types::ValType;
5use thiserror::Error;7use thiserror::Error;
68
7#[derive(Debug, Clone, Error)]9#[derive(Debug, Clone, Error)]
19 #[error("mapping keys required")]21 #[error("mapping keys required")]
20 MappingKeysRequired,22 MappingKeysRequired,
21 #[error("no such format field: {0}")]23 #[error("no such format field: {0}")]
22 NoSuchFormatField(Rc<str>),24 NoSuchFormatField(IStr),
23}25}
2426
25impl From<FormatError> for LocError {27impl From<FormatError> for LocError {
28 }30 }
29}31}
3032
31use std::rc::Rc;
32use FormatError::*;33use FormatError::*;
3334
34type ParseResult<'t, T> = std::result::Result<(T, &'t str), FormatError>;35type ParseResult<'t, T> = std::result::Result<(T, &'t str), FormatError>;
573 );574 );
574 }575 }
575 }576 }
576 ConvTypeV::Char => match value.clone().unwrap_if_lazy()? {577 ConvTypeV::Char => match value.clone() {
577 Val::Num(n) => tmp_out.push(578 Val::Num(n) => tmp_out.push(
578 std::char::from_u32(n as u32)579 std::char::from_u32(n as u32)
579 .ok_or_else(|| InvalidUnicodeCodepointGot(n as u32))?,580 .ok_or_else(|| InvalidUnicodeCodepointGot(n as u32))?,
590 throw!(TypeMismatch(591 throw!(TypeMismatch(
591 "%c requires number/string",592 "%c requires number/string",
592 vec![ValType::Num, ValType::Str],593 vec![ValType::Num, ValType::Str],
593 value.value_type()?,594 value.value_type(),
594 ));595 ));
595 }596 }
596 },597 },
679 }680 }
680 Element::Code(c) => {681 Element::Code(c) => {
681 // TODO: Operate on ref682 // TODO: Operate on ref
682 let f: Rc<str> = c.mkey.into();683 let f: IStr = c.mkey.into();
683 let width = match c.width {684 let width = match c.width {
684 Width::Star => {685 Width::Star => {
685 throw!(CannotUseStarWidthWithObject);686 throw!(CannotUseStarWidthWithObject);
modifiedcrates/jrsonnet-evaluator/src/builtin/manifest.rsdiffbeforeafterboth
33) -> Result<()> {33) -> Result<()> {
34 use std::fmt::Write;34 use std::fmt::Write;
35 let mtype = options.mtype;35 let mtype = options.mtype;
36 match val.unwrap_if_lazy()? {36 match val {
37 Val::Bool(v) => {37 Val::Bool(v) => {
38 if v {38 if *v {
39 buf.push_str("true");39 buf.push_str("true");
40 } else {40 } else {
41 buf.push_str("false");41 buf.push_str("false");
42 }42 }
43 }43 }
44 Val::Null => buf.push_str("null"),44 Val::Null => buf.push_str("null"),
45 Val::Str(s) => buf.push_str(&escape_string_json(&s)),45 Val::Str(s) => buf.push_str(&escape_string_json(s)),
46 Val::Num(n) => write!(buf, "{}", n).unwrap(),46 Val::Num(n) => write!(buf, "{}", n).unwrap(),
47 Val::Arr(items) => {47 Val::Arr(items) => {
48 buf.push('[');48 buf.push('[');
63 }63 }
64 }64 }
65 buf.push_str(cur_padding);65 buf.push_str(cur_padding);
66 manifest_json_ex_buf(item, buf, cur_padding, options)?;66 manifest_json_ex_buf(&item?, buf, cur_padding, options)?;
67 }67 }
68 cur_padding.truncate(old_len);68 cur_padding.truncate(old_len);
6969
118 buf.push('}');118 buf.push('}');
119 }119 }
120 Val::Func(_) => throw!(RuntimeError("tried to manifest function".into())),120 Val::Func(_) => throw!(RuntimeError("tried to manifest function".into())),
121 Val::Lazy(_) => unreachable!(),
122 };121 };
123 Ok(())122 Ok(())
124}123}
modifiedcrates/jrsonnet-evaluator/src/builtin/mod.rsdiffbeforeafterboth
1use crate::{1use crate::{
2 equals,2 equals,
3 error::{Error::*, Result},3 error::{Error::*, Result},
4 evaluate, parse_args, primitive_equals, push, throw, with_state, Context, FuncVal, Val,4 parse_args, primitive_equals, push, throw, with_state, ArrValue, Context, FuncVal, LazyVal,
5 ValType,5 Val,
6};6};
7use format::{format_arr, format_obj};7use format::{format_arr, format_obj};
8use jrsonnet_parser::{ArgsDesc, ExprLocation};8use jrsonnet_interner::IStr;
9use jrsonnet_parser::{ArgsDesc, BinaryOpType, ExprLocation};
9use manifest::{escape_string_json, manifest_json_ex, ManifestJsonOptions, ManifestType};10use jrsonnet_types::ty;
10use std::{path::PathBuf, rc::Rc};11use std::{collections::HashMap, path::PathBuf, rc::Rc};
1112
12pub mod stdlib;13pub mod stdlib;
13pub use stdlib::*;14pub use stdlib::*;
1415
16use self::manifest::{escape_string_json, manifest_json_ex, ManifestJsonOptions, ManifestType};
17
15pub mod format;18pub mod format;
16pub mod manifest;19pub mod manifest;
17pub mod sort;20pub mod sort;
1821
19fn std_format(str: Rc<str>, vals: Val) -> Result<Val> {22fn std_format(str: IStr, vals: Val) -> Result<Val> {
20 push(23 push(
21 &Some(ExprLocation(Rc::from(PathBuf::from("std.jsonnet")), 0, 0)),24 Some(&ExprLocation(Rc::from(PathBuf::from("std.jsonnet")), 0, 0)),
22 || format!("std.format of {}", str),25 || format!("std.format of {}", str),
23 || {26 || {
24 Ok(match vals {27 Ok(match vals {
25 Val::Arr(vals) => Val::Str(format_arr(&str, &vals)?.into()),28 Val::Arr(vals) => Val::Str(format_arr(&str, &vals.evaluated()?)?.into()),
26 Val::Obj(obj) => Val::Str(format_obj(&str, &obj)?.into()),29 Val::Obj(obj) => Val::Str(format_obj(&str, &obj)?.into()),
27 o => Val::Str(format_arr(&str, &[o])?.into()),30 o => Val::Str(format_arr(&str, &[o])?.into()),
28 })31 })
29 },32 },
30 )33 )
31}34}
3235
33#[allow(clippy::cognitive_complexity)]36type Builtin = fn(context: Context, loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val>;
34pub fn call_builtin(37
38type BuiltinsType = HashMap<Box<str>, Builtin>;
39
40thread_local! {
41 static BUILTINS: BuiltinsType = {
42 [
43 ("length".into(), builtin_length as Builtin),
44 ("type".into(), builtin_type),
45 ("makeArray".into(), builtin_make_array),
46 ("codepoint".into(), builtin_codepoint),
47 ("objectFieldsEx".into(), builtin_object_fields_ex),
48 ("objectHasEx".into(), builtin_object_has_ex),
49 ("slice".into(), builtin_slice),
50 ("primitiveEquals".into(), builtin_primitive_equals),
51 ("equals".into(), builtin_equals),
52 ("modulo".into(), builtin_modulo),
53 ("mod".into(), builtin_mod),
54 ("floor".into(), builtin_floor),
55 ("log".into(), builtin_log),
56 ("pow".into(), builtin_pow),
57 ("extVar".into(), builtin_ext_var),
58 ("native".into(), builtin_native),
59 ("filter".into(), builtin_filter),
60 ("foldl".into(), builtin_foldl),
61 ("foldr".into(), builtin_foldr),
62 ("sortImpl".into(), builtin_sort_impl),
63 ("format".into(), builtin_format),
64 ("range".into(), builtin_range),
65 ("char".into(), builtin_char),
66 ("encodeUTF8".into(), builtin_encode_utf8),
67 ("md5".into(), builtin_md5),
68 ("base64".into(), builtin_base64),
69 ("trace".into(), builtin_trace),
70 ("join".into(), builtin_join),
71 ("escapeStringJson".into(), builtin_escape_string_json),
72 ("manifestJsonEx".into(), builtin_manifest_json_ex),
73 ("reverse".into(), builtin_reverse),
74 ("id".into(), builtin_id),
75 ("strReplace".into(), builtin_str_replace),
76 ].iter().cloned().collect()
77 };
78}
79
80fn builtin_length(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val> {
81 parse_args!(context, "length", args, 1, [
82 0, x: ty!((string | object | array));
83 ], {
84 Ok(match x {
85 Val::Str(n) => Val::Num(n.chars().count() as f64),
86 Val::Arr(a) => Val::Num(a.len() as f64),
87 Val::Obj(o) => Val::Num(
88 o.fields_visibility()
89 .into_iter()
90 .filter(|(_k, v)| *v)
91 .count() as f64,
92 ),
93 _ => unreachable!(),
94 })
95 })
96}
97
98fn builtin_type(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val> {
99 parse_args!(context, "type", args, 1, [
100 0, x: ty!(any);
101 ], {
102 Ok(Val::Str(x.value_type().name().into()))
103 })
104}
105
106fn builtin_make_array(
35 context: Context,107 context: Context,
36 loc: &Option<ExprLocation>,108 _loc: Option<&ExprLocation>,
37 name: &str,
38 args: &ArgsDesc,109 args: &ArgsDesc,
39) -> Result<Val> {110) -> Result<Val> {
40 Ok(match name as &str {111 parse_args!(context, "makeArray", args, 2, [
41 // arr/string/function112 0, sz: ty!(BoundedNumber<(Some(0.0)), (None)>) => Val::Num;
42 "length" => parse_args!(context, "std.length", args, 1, [113 1, func: ty!(function) => Val::Func;
43 0, x: [Val::Str|Val::Arr|Val::Obj], vec![ValType::Str, ValType::Arr, ValType::Obj];114 ], {
44 ], {115 let mut out = Vec::with_capacity(sz as usize);
45 Ok(match x {116 for i in 0..sz as usize {
46 Val::Str(n) => Val::Num(n.chars().count() as f64),117 out.push(LazyVal::new_resolved(func.evaluate_values(
47 Val::Arr(i) => Val::Num(i.len() as f64),118 Context::new(),
48 Val::Obj(o) => Val::Num(119 &[Val::Num(i as f64)]
49 o.fields_visibility()120 )?))
50 .into_iter()121 }
51 .filter(|(_k, v)| *v)122 Ok(Val::Arr(out.into()))
52 .count() as f64,123 })
53 ),124}
54 _ => unreachable!(),125
55 })126fn builtin_codepoint(
56 })?,127 context: Context,
57 // any128 _loc: Option<&ExprLocation>,
58 "type" => parse_args!(context, "std.type", args, 1, [129 args: &ArgsDesc,
59 0, x, vec![];130) -> Result<Val> {
60 ], {131 parse_args!(context, "codepoint", args, 1, [
61 Ok(Val::Str(x.value_type()?.name().into()))132 0, str: ty!(char) => Val::Str;
62 })?,133 ], {
63 // length, idx=>any134 Ok(Val::Num(str.chars().next().unwrap() as u32 as f64))
64 "makeArray" => parse_args!(context, "std.makeArray", args, 2, [135 })
65 0, sz: [Val::Num]!!Val::Num, vec![ValType::Num];136}
66 1, func: [Val::Func]!!Val::Func, vec![ValType::Func];137
67 ], {138fn builtin_object_fields_ex(
68 if sz < 0.0 {139 context: Context,
69 throw!(RuntimeError(format!("makeArray requires size >= 0, got {}", sz).into()));140 _loc: Option<&ExprLocation>,
70 }141 args: &ArgsDesc,
71 let mut out = Vec::with_capacity(sz as usize);142) -> Result<Val> {
72 for i in 0..sz as usize {143 parse_args!(context, "objectFieldsEx", args, 2, [
73 out.push(func.evaluate_values(144 0, obj: ty!(object) => Val::Obj;
74 Context::new(),145 1, inc_hidden: ty!(boolean) => Val::Bool;
75 &[Val::Num(i as f64)]146 ], {
76 )?)147 let mut out = obj.fields_visibility()
77 }148 .into_iter()
78 Ok(Val::Arr(Rc::new(out)))149 .filter(|(_k, v)| *v || inc_hidden)
79 })?,150 .map(|(k, _v)|k)
80 // string151 .collect::<Vec<_>>();
81 "codepoint" => parse_args!(context, "std.codepoint", args, 1, [152 out.sort();
82 0, str: [Val::Str]!!Val::Str, vec![ValType::Str];153 Ok(Val::Arr(out.into_iter().map(Val::Str).collect::<Vec<_>>().into()))
83 ], {154 })
84 assert!(155}
85 str.chars().count() == 1,156
86 "std.codepoint should receive single char string"157fn builtin_object_has_ex(
87 );158 context: Context,
88 Ok(Val::Num(str.chars().take(1).next().unwrap() as u32 as f64))159 _loc: Option<&ExprLocation>,
89 })?,160 args: &ArgsDesc,
90 // object, includeHidden161) -> Result<Val> {
91 "objectFieldsEx" => parse_args!(context, "std.objectFieldsEx",args, 2, [162 parse_args!(context, "objectHasEx", args, 3, [
92 0, obj: [Val::Obj]!!Val::Obj, vec![ValType::Obj];163 0, obj: ty!(object) => Val::Obj;
93 1, inc_hidden: [Val::Bool]!!Val::Bool, vec![ValType::Bool];164 1, f: ty!(string) => Val::Str;
94 ], {165 2, inc_hidden: ty!(boolean) => Val::Bool;
95 let mut out = obj.fields_visibility()166 ], {
167 Ok(Val::Bool(
168 obj.fields_visibility()
96 .into_iter()169 .into_iter()
97 .filter(|(_k, v)| *v || inc_hidden)170 .filter(|(_k, v)| *v || inc_hidden)
98 .map(|(k, _v)|k)171 .any(|(k, _v)| *k == *f),
99 .collect::<Vec<_>>();
100 out.sort();
101 Ok(Val::Arr(Rc::new(out.into_iter().map(Val::Str).collect())))
102 })?,
103 // object, field, includeHidden
104 "objectHasEx" => parse_args!(context, "std.objectHasEx", args, 3, [
105 0, obj: [Val::Obj]!!Val::Obj, vec![ValType::Obj];
106 1, f: [Val::Str]!!Val::Str, vec![ValType::Str];
107 2, inc_hidden: [Val::Bool]!!Val::Bool, vec![ValType::Bool];
108 ], {
109 Ok(Val::Bool(
110 obj.fields_visibility()
111 .into_iter()
112 .filter(|(_k, v)| *v || inc_hidden)
113 .any(|(k, _v)| *k == *f),
114 ))172 ))
115 })?,173 })
174}
116175
117 // faster176// faster
118 "slice" => parse_args!(context, "slice", args, 4, [177fn builtin_slice(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val> {
178 parse_args!(context, "slice", args, 4, [
119 0, indexable: [Val::Str | Val::Arr], vec![ValType::Str, ValType::Arr];179 0, indexable: ty!((string | array));
120 1, index, vec![ValType::Num, ValType::Null];180 1, index: ty!((number | null));
121 2, end, vec![ValType::Num, ValType::Null];181 2, end: ty!((number | null));
122 3, step, vec![ValType::Num, ValType::Null];182 3, step: ty!((number | null));
123 ], {183 ], {
124 let index = match index {184 let index = match index {
125 Val::Num(v) => v as usize,185 Val::Num(v) => v as usize,
126 Val::Null => 0,186 Val::Null => 0,
127 _ => unreachable!(),187 _ => unreachable!(),
128 };188 };
129 let end = match end {189 let end = match end {
130 Val::Num(v) => v as usize,190 Val::Num(v) => v as usize,
131 Val::Null => match &indexable {191 Val::Null => match &indexable {
132 Val::Str(s) => s.chars().count(),192 Val::Str(s) => s.chars().count(),
133 Val::Arr(v) => v.len(),193 Val::Arr(v) => v.len(),
134 _ => unreachable!()
135 },
136 _ => unreachable!()194 _ => unreachable!()
137 };195 },
138 let step = match step {196 _ => unreachable!()
197 };
198 let step = match step {
139 Val::Num(v) => v as usize,199 Val::Num(v) => v as usize,
140 Val::Null => 1,200 Val::Null => 1,
141 _ => unreachable!()201 _ => unreachable!()
142 };202 };
143 match &indexable {203 match &indexable {
144 Val::Str(s) => {204 Val::Str(s) => {
145 Ok(Val::Str((s.chars().skip(index).take(end-index).step_by(step).collect::<String>()).into()))205 Ok(Val::Str((s.chars().skip(index).take(end-index).step_by(step).collect::<String>()).into()))
146 }
147 Val::Arr(arr) => {
148 Ok(Val::Arr((arr.iter().skip(index).take(end-index).step_by(step).cloned().collect::<Vec<Val>>()).into()))
149 }
150 _ => unreachable!()
151 }206 }
152 })?,207 Val::Arr(arr) => {
153 "primitiveEquals" => parse_args!(context, "std.primitiveEquals", args, 2, [
154 0, a, vec![];
155 1, b, vec![];
156 ], {
157 Ok(Val::Bool(primitive_equals(&a, &b)?))
158 })?,
159 // faster
160 "equals" => parse_args!(context, "std.equals", args, 2, [
161 0, a, vec![];
162 1, b, vec![];
163 ], {
164 Ok(Val::Bool(equals(&a, &b)?))208 Ok(Val::Arr((arr.iter().skip(index).take(end-index).step_by(step).collect::<Result<Vec<Val>>>()?).into()))
165 })?,
166 "mod" => parse_args!(context, "std.mod", args, 2, [
167 0, a: [Val::Num | Val::Str], vec![ValType::Num, ValType::Str];
168 1, b, vec![];
169 ], {
170 match (a, b) {
171 (Val::Num(a), Val::Num(b)) => Ok(Val::Num(a % b)),
172 (Val::Str(str), vals) => std_format(str, vals),
173 (a, b) => throw!(BinaryOperatorDoesNotOperateOnValues(jrsonnet_parser::BinaryOpType::Mod, a.value_type()?, b.value_type()?))
174 }209 }
175 })?,210 _ => unreachable!()
176 "modulo" => parse_args!(context, "std.modulo", args, 2, [211 }
177 0, a: [Val::Num]!!Val::Num, vec![ValType::Num];212 })
178 1, b: [Val::Num]!!Val::Num, vec![ValType::Num];213}
179 ], {
180 Ok(Val::Num(a % b))
181 })?,
182 "floor" => parse_args!(context, "std.floor", args, 1, [
183 0, x: [Val::Num]!!Val::Num, vec![ValType::Num];
184 ], {
185 Ok(Val::Num(x.floor()))
186 })?,
187 "log" => parse_args!(context, "std.log", args, 2, [
188 0, n: [Val::Num]!!Val::Num, vec![ValType::Num];
189 ], {
190 Ok(Val::Num(n.ln()))
191 })?,
192 "trace" => parse_args!(context, "std.trace", args, 2, [
193 0, str: [Val::Str]!!Val::Str, vec![ValType::Str];
194 1, rest, vec![];
195 ], {
196 eprint!("TRACE:");
197 if let Some(loc) = loc {
198 with_state(|s|{
199 let locs = s.map_source_locations(&loc.0, &[loc.1]);
200 eprint!(" {}:{}", loc.0.file_name().unwrap().to_str().unwrap(), locs[0].line);
201 });
202 }
203 eprintln!(" {}", str);
204 Ok(rest)
205 })?,
206 "pow" => parse_args!(context, "std.modulo", args, 2, [
207 0, x: [Val::Num]!!Val::Num, vec![ValType::Num];
208 1, n: [Val::Num]!!Val::Num, vec![ValType::Num];
209 ], {
210 Ok(Val::Num(x.powf(n)))
211 })?,
212 "extVar" => parse_args!(context, "std.extVar", args, 1, [
213 0, x: [Val::Str]!!Val::Str, vec![ValType::Str];
214 ], {
215 Ok(with_state(|s| s.settings().ext_vars.get(&x).cloned()).ok_or(UndefinedExternalVariable(x))?)
216 })?,
217 "native" => parse_args!(context, "std.native", args, 1, [
218 0, x: [Val::Str]!!Val::Str, vec![ValType::Str];
219 ], {
220 Ok(with_state(|s| s.settings().ext_natives.get(&x).cloned()).map(|v| Val::Func(Rc::new(FuncVal::NativeExt(x.clone(), v)))).ok_or(UndefinedExternalFunction(x))?)
221 })?,
222 "filter" => parse_args!(context, "std.filter", args, 2, [
223 0, func: [Val::Func]!!Val::Func, vec![ValType::Func];
224 1, arr: [Val::Arr]!!Val::Arr, vec![ValType::Arr];
225 ], {
226 Ok(Val::Arr(Rc::new(
227 arr.iter()
228 .cloned()
229 .filter(|e| {
230 func
231 .evaluate_values(context.clone(), &[e.clone()])
232 .unwrap()
233 .try_cast_bool("filter predicate")
234 .unwrap()
235 })
236 .collect(),
237 )))
238 })?,
239 // faster
240 "foldl" => parse_args!(context, "std.foldl", args, 3, [
241 0, func: [Val::Func]!!Val::Func, vec![ValType::Func];
242 1, arr: [Val::Arr]!!Val::Arr, vec![ValType::Arr];
243 2, init, vec![];
244 ], {
245 let mut acc = init;
246 for i in arr.iter().cloned() {
247 acc = func.evaluate_values(context.clone(), &[acc, i])?;
248 }
249 Ok(acc)
250 })?,
251 // faster
252 "foldr" => parse_args!(context, "std.foldr", args, 3, [
253 0, func: [Val::Func]!!Val::Func, vec![ValType::Func];
254 1, arr: [Val::Arr]!!Val::Arr, vec![ValType::Arr];
255 2, init, vec![];
256 ], {
257 let mut acc = init;
258 for i in arr.iter().rev().cloned() {
259 acc = func.evaluate_values(context.clone(), &[acc, i])?;
260 }
261 Ok(acc)
262 })?,
263 // faster
264 #[allow(non_snake_case)]
265 "sortImpl" => parse_args!(context, "std.sort", args, 2, [
266 0, arr: [Val::Arr]!!Val::Arr, vec![ValType::Arr];
267 1, keyF: [Val::Func]!!Val::Func, vec![ValType::Func];
268 ], {
269 if arr.len() <= 1 {
270 return Ok(Val::Arr(arr))
271 }
272 Ok(Val::Arr(sort::sort(context, arr, &keyF)?))
273 })?,
274 // faster
275 "format" => parse_args!(context, "std.format", args, 2, [
276 0, str: [Val::Str]!!Val::Str, vec![ValType::Str];
277 1, vals, vec![]
278 ], {
279 std_format(str, vals)
280 })?,
281 // faster
282 "range" => parse_args!(context, "std.range", args, 2, [
283 0, from: [Val::Num]!!Val::Num, vec![ValType::Num];
284 1, to: [Val::Num]!!Val::Num, vec![ValType::Num];
285 ], {
286 if to < from {
287 return Ok(Val::Arr(Rc::new(Vec::new())))
288 }
289 let mut out = Vec::with_capacity((1+to as usize-from as usize).max(0));
290 for i in from as usize..=to as usize {
291 out.push(Val::Num(i as f64));
292 }
293 Ok(Val::Arr(Rc::new(out)))
294 })?,
295 "char" => parse_args!(context, "std.char", args, 1, [
296 0, n: [Val::Num]!!Val::Num, vec![ValType::Num];
297 ], {
298 let mut out = String::new();
299 out.push(std::char::from_u32(n as u32).ok_or_else(||
300 InvalidUnicodeCodepointGot(n as u32)
301 )?);
302 Ok(Val::Str(out.into()))
303 })?,
304 "encodeUTF8" => parse_args!(context, "std.encodeUtf8", args, 1, [
305 0, str: [Val::Str]!!Val::Str, vec![ValType::Str];
306 ], {
307 Ok(Val::Arr(Rc::new(str.bytes().map(|b| Val::Num(b as f64)).collect())))
308 })?,
309 "md5" => parse_args!(context, "std.md5", args, 1, [
310 0, str: [Val::Str]!!Val::Str, vec![ValType::Str];
311 ], {
312 Ok(Val::Str(format!("{:x}", md5::compute(&str.as_bytes())).into()))
313 })?,
314 // faster
315 "base64" => parse_args!(context, "std.base64", args, 1, [
316 0, input: [Val::Str | Val::Arr], vec![ValType::Arr, ValType::Str];
317 ], {
318 Ok(Val::Str(match input {
319 Val::Str(s) => {
320 base64::encode(s.bytes().collect::<Vec<_>>()).into()
321 },
322 Val::Arr(a) => {
323 base64::encode(a.iter().map(|v| {
324 Ok(v.clone().try_cast_num("base64 array")? as u8)
325 }).collect::<Result<Vec<_>>>()?).into()
326 },
327 _ => unreachable!()
328 }))
329 })?,
330 // faster
331 "join" => parse_args!(context, "std.join", args, 2, [
332 0, sep: [Val::Str|Val::Arr], vec![ValType::Str, ValType::Arr];
333 1, arr: [Val::Arr]!!Val::Arr, vec![ValType::Arr];
334 ], {
335 Ok(match sep {
336 Val::Arr(joiner_items) => {
337 let mut out = Vec::new();
338214
339 let mut first = true;215// faster
340 for item in arr.iter().cloned() {216fn builtin_primitive_equals(
341 if let Val::Arr(items) = item.unwrap_if_lazy()? {217 context: Context,
342 if !first {218 _loc: Option<&ExprLocation>,
343 out.reserve(joiner_items.len());219 args: &ArgsDesc,
344 out.extend(joiner_items.iter().cloned());220) -> Result<Val> {
221 parse_args!(context, "primitiveEquals", args, 2, [
222 0, a: ty!(any);
223 1, b: ty!(any);
224 ], {
225 Ok(Val::Bool(primitive_equals(&a, &b)?))
226 })
227}
228
229// faster
230fn builtin_equals(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val> {
231 parse_args!(context, "equals", args, 2, [
232 0, a: ty!(any);
233 1, b: ty!(any);
234 ], {
235 Ok(Val::Bool(equals(&a, &b)?))
236 })
237}
238
239fn builtin_modulo(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val> {
240 parse_args!(context, "modulo", args, 2, [
241 0, a: ty!(number) => Val::Num;
242 1, b: ty!(number) => Val::Num;
243 ], {
244 Ok(Val::Num(a % b))
245 })
246}
247
248fn builtin_mod(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val> {
249 parse_args!(context, "mod", args, 2, [
250 0, a: ty!((number | string));
251 1, b: ty!(any);
252 ], {
253 match (a, b) {
254 (Val::Num(a), Val::Num(b)) => Ok(Val::Num(a % b)),
255 (Val::Str(str), vals) => std_format(str, vals),
256 (a, b) => throw!(BinaryOperatorDoesNotOperateOnValues(BinaryOpType::Mod, a.value_type(), b.value_type()))
257 }
258 })
259}
260
261fn builtin_floor(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val> {
262 parse_args!(context, "floor", args, 1, [
263 0, x: ty!(number) => Val::Num;
264 ], {
265 Ok(Val::Num(x.floor()))
266 })
267}
268
269fn builtin_log(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val> {
270 parse_args!(context, "log", args, 1, [
271 0, n: ty!(number) => Val::Num;
272 ], {
273 Ok(Val::Num(n.ln()))
274 })
275}
276
277fn builtin_pow(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val> {
278 parse_args!(context, "pow", args, 2, [
279 0, x: ty!(number) => Val::Num;
280 1, n: ty!(number) => Val::Num;
281 ], {
282 Ok(Val::Num(x.powf(n)))
283 })
284}
285
286fn builtin_ext_var(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val> {
287 parse_args!(context, "extVar", args, 1, [
288 0, x: ty!(string) => Val::Str;
289 ], {
290 Ok(with_state(|s| s.settings().ext_vars.get(&x).cloned()).ok_or(UndefinedExternalVariable(x))?)
291 })
292}
293
294fn builtin_native(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val> {
295 parse_args!(context, "native", args, 1, [
296 0, x: ty!(string) => Val::Str;
297 ], {
298 Ok(with_state(|s| s.settings().ext_natives.get(&x).cloned()).map(|v| Val::Func(Rc::new(FuncVal::NativeExt(x.clone(), v)))).ok_or(UndefinedExternalFunction(x))?)
299 })
300}
301
302fn builtin_filter(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val> {
303 parse_args!(context, "filter", args, 2, [
304 0, func: ty!(function) => Val::Func;
305 1, arr: ty!(array) => Val::Arr;
306 ], {
307 let mut out = Vec::new();
308 for item in arr.iter() {
309 let item = item?;
310 if func
311 .evaluate_values(context.clone(), &[item.clone()])?
312 .try_cast_bool("filter predicate")? {
313 out.push(item);
314 }
315 }
316 Ok(Val::Arr(out.into()))
317 })
318}
319
320fn builtin_foldl(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val> {
321 parse_args!(context, "foldl", args, 3, [
322 0, func: ty!(function) => Val::Func;
323 1, arr: ty!(array) => Val::Arr;
324 2, init: ty!(any);
325 ], {
326 let mut acc = init;
327 for i in arr.iter() {
328 acc = func.evaluate_values(context.clone(), &[acc, i?])?;
329 }
330 Ok(acc)
331 })
332}
333
334fn builtin_foldr(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val> {
335 parse_args!(context, "foldr", args, 3, [
336 0, func: ty!(function) => Val::Func;
337 1, arr: ty!(array) => Val::Arr;
338 2, init: ty!(any);
339 ], {
340 let mut acc = init;
341 for i in arr.iter().rev() {
342 acc = func.evaluate_values(context.clone(), &[acc, i?])?;
343 }
344 Ok(acc)
345 })
346}
347
348#[allow(non_snake_case)]
349fn builtin_sort_impl(
350 context: Context,
351 _loc: Option<&ExprLocation>,
352 args: &ArgsDesc,
353) -> Result<Val> {
354 parse_args!(context, "sort", args, 2, [
355 0, arr: ty!(array) => Val::Arr;
356 1, keyF: ty!(function) => Val::Func;
357 ], {
358 if arr.len() <= 1 {
359 return Ok(Val::Arr(arr))
360 }
361 Ok(Val::Arr(ArrValue::Eager(sort::sort(context, arr.evaluated()?, &keyF)?)))
362 })
363}
364
365// faster
366fn builtin_format(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val> {
367 parse_args!(context, "format", args, 2, [
368 0, str: ty!(string) => Val::Str;
369 1, vals: ty!(any)
370 ], {
371 std_format(str, vals)
372 })
373}
374
375fn builtin_range(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val> {
376 parse_args!(context, "range", args, 2, [
377 0, from: ty!(number) => Val::Num;
378 1, to: ty!(number) => Val::Num;
379 ], {
380 if to < from {
381 return Ok(Val::Arr(ArrValue::new_eager()))
382 }
383 let mut out = Vec::with_capacity((1+to as usize-from as usize).max(0));
384 for i in from as usize..=to as usize {
385 out.push(Val::Num(i as f64));
386 }
387 Ok(Val::Arr(out.into()))
388 })
389}
390
391fn builtin_char(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val> {
392 parse_args!(context, "char", args, 1, [
393 0, n: ty!(number) => Val::Num;
394 ], {
395 let mut out = String::new();
396 out.push(std::char::from_u32(n as u32).ok_or_else(||
397 InvalidUnicodeCodepointGot(n as u32)
398 )?);
399 Ok(Val::Str(out.into()))
400 })
401}
402
403fn builtin_encode_utf8(
404 context: Context,
405 _loc: Option<&ExprLocation>,
406 args: &ArgsDesc,
407) -> Result<Val> {
408 parse_args!(context, "encodeUTF8", args, 1, [
409 0, str: ty!(string) => Val::Str;
410 ], {
411 Ok(Val::Arr((str.bytes().map(|b| Val::Num(b as f64)).collect::<Vec<Val>>()).into()))
412 })
413}
414
415fn builtin_md5(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val> {
416 parse_args!(context, "md5", args, 1, [
417 0, str: ty!(string) => Val::Str;
418 ], {
419 Ok(Val::Str(format!("{:x}", md5::compute(&str.as_bytes())).into()))
420 })
421}
422
423fn builtin_trace(context: Context, loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val> {
424 parse_args!(context, "trace", args, 2, [
425 0, str: ty!(string) => Val::Str;
426 1, rest: ty!(any);
427 ], {
428 eprint!("TRACE:");
429 if let Some(loc) = loc {
430 with_state(|s|{
431 let locs = s.map_source_locations(&loc.0, &[loc.1]);
432 eprint!(" {}:{}", loc.0.file_name().unwrap().to_str().unwrap(), locs[0].line);
433 });
434 }
435 eprintln!(" {}", str);
436 Ok(rest)
437 })
438}
439
440fn builtin_base64(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val> {
441 parse_args!(context, "base64", args, 1, [
442 0, input: ty!((string | (Array<number>)));
443 ], {
444 Ok(Val::Str(match input {
445 Val::Str(s) => {
446 base64::encode(s.bytes().collect::<Vec<_>>()).into()
447 },
448 Val::Arr(a) => {
449 base64::encode(a.iter().map(|v| {
450 Ok(v?.unwrap_num()? as u8)
451 }).collect::<Result<Vec<_>>>()?).into()
452 },
453 _ => unreachable!()
454 }))
455 })
456}
457
458fn builtin_join(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val> {
459 parse_args!(context, "join", args, 2, [
460 0, sep: ty!((string | array));
461 1, arr: ty!(array) => Val::Arr;
462 ], {
463 Ok(match sep {
464 Val::Arr(joiner_items) => {
465 let mut out = Vec::new();
466
467 let mut first = true;
468 for item in arr.iter() {
469 let item = item?.clone();
470 if let Val::Arr(items) = item {
471 if !first {
472 out.reserve(joiner_items.len());
473 // TODO: extend
474 for item in joiner_items.iter() {
475 out.push(item?);
345 }476 }
346 first = false;
347 out.reserve(items.len());
348 out.extend(items.iter().cloned());
349 } else {
350 throw!(RuntimeError("in std.join all items should be arrays".into()));
351 }477 }
478 first = false;
479 out.reserve(items.len());
480 // TODO: extend
481 for item in items.iter() {
482 out.push(item?);
483 }
484 } else {
485 throw!(RuntimeError("in std.join all items should be arrays".into()));
352 }486 }
487 }
353488
354 Val::Arr(Rc::new(out))489 Val::Arr(out.into())
355 },490 },
356 Val::Str(sep) => {491 Val::Str(sep) => {
357 let mut out = String::new();492 let mut out = String::new();
358493
359 let mut first = true;494 let mut first = true;
360 for item in arr.iter().cloned() {495 for item in arr.iter() {
361 if let Val::Str(item) = item.unwrap_if_lazy()? {496 let item = item?.clone();
497 if let Val::Str(item) = item {
362 if !first {498 if !first {
363 out += &sep;499 out += &sep;
364 }
365 first = false;
366 out += &item;
367 } else {
368 throw!(RuntimeError("in std.join all items should be strings".into()));
369 }500 }
501 first = false;
502 out += &item;
503 } else {
504 throw!(RuntimeError("in std.join all items should be strings".into()));
370 }505 }
506 }
371507
372 Val::Str(out.into())508 Val::Str(out.into())
373 },509 },
374 _ => unreachable!()510 _ => unreachable!()
375 })511 })
376 })?,
377 // Faster
378 "escapeStringJson" => parse_args!(context, "std.escapeStringJson", args, 1, [
379 0, str_: [Val::Str]!!Val::Str, vec![ValType::Str];
380 ], {
381 Ok(Val::Str(escape_string_json(&str_).into()))
382 })?,
383 // Faster
384 "manifestJsonEx" => parse_args!(context, "std.manifestJsonEx", args, 2, [
385 0, value, vec![];
386 1, indent: [Val::Str]!!Val::Str, vec![ValType::Str];
387 ], {
388 Ok(Val::Str(manifest_json_ex(&value, &ManifestJsonOptions {
389 padding: &indent,
390 mtype: ManifestType::Std,
391 })?.into()))
392 })?,
393 // Faster
394 "reverse" => parse_args!(context, "std.reverse", args, 1, [
395 0, arr: [Val::Arr]!!Val::Arr, vec![ValType::Arr];
396 ], {
397 let mut marr = arr;
398 Rc::make_mut(&mut marr).reverse();
399 Ok(Val::Arr(marr))
400 })?,
401 "id" => parse_args!(context, "std.id", args, 1, [
402 0, v, vec![];
403 ], {
404 Ok(v)
405 })?,
406 name => throw!(IntrinsicNotFound(name.into())),
407 })512 })
513}
514
515// faster
516fn builtin_escape_string_json(
517 context: Context,
518 _loc: Option<&ExprLocation>,
519 args: &ArgsDesc,
520) -> Result<Val> {
521 parse_args!(context, "escapeStringJson", args, 1, [
522 0, str_: ty!(string) => Val::Str;
523 ], {
524 Ok(Val::Str(escape_string_json(&str_).into()))
525 })
526}
527
528// faster
529fn builtin_manifest_json_ex(
530 context: Context,
531 _loc: Option<&ExprLocation>,
532 args: &ArgsDesc,
533) -> Result<Val> {
534 parse_args!(context, "manifestJsonEx", args, 2, [
535 0, value: ty!(any);
536 1, indent: ty!(string) => Val::Str;
537 ], {
538 Ok(Val::Str(manifest_json_ex(&value, &ManifestJsonOptions {
539 padding: &indent,
540 mtype: ManifestType::Std,
541 })?.into()))
542 })
543}
544
545// faster
546fn builtin_reverse(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val> {
547 parse_args!(context, "reverse", args, 1, [
548 0, value: ty!(array) => Val::Arr;
549 ], {
550 Ok(Val::Arr(value.reversed()))
551 })
552}
553
554fn builtin_id(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val> {
555 parse_args!(context, "id", args, 1, [
556 0, v: ty!(any);
557 ], {
558 Ok(v)
559 })
560}
561
562// faster
563fn builtin_str_replace(
564 context: Context,
565 _loc: Option<&ExprLocation>,
566 args: &ArgsDesc,
567) -> Result<Val> {
568 parse_args!(context, "strReplace", args, 3, [
569 0, str: ty!(string) => Val::Str;
570 1, from: ty!(string) => Val::Str;
571 2, to: ty!(string) => Val::Str;
572 ], {
573 let mut out = String::new();
574 let mut last_idx = 0;
575 while let Some(idx) = (&str[last_idx..]).find(&from as &str) {
576 out.push_str(&str[last_idx..last_idx+idx]);
577 out.push_str(&to);
578 last_idx += idx + from.len();
579 }
580 if last_idx == 0 {
581 return Ok(Val::Str(str))
582 }
583 out.push_str(&str[last_idx..]);
584 Ok(Val::Str(out.into()))
585 })
586}
587
588pub fn call_builtin(
589 context: Context,
590 loc: Option<&ExprLocation>,
591 name: &str,
592 args: &ArgsDesc,
593) -> Result<Val> {
594 if let Some(f) = BUILTINS.with(|builtins| builtins.get(name).copied()) {
595 return Ok(f(context, loc, args)?);
596 }
597 throw!(IntrinsicNotFound(name.into()))
408}598}
409599
modifiedcrates/jrsonnet-evaluator/src/builtin/sort.rsdiffbeforeafterboth
46 let mut sort_type = SortKeyType::Unknown;46 let mut sort_type = SortKeyType::Unknown;
47 for i in values.iter_mut() {47 for i in values.iter_mut() {
48 let i = key_getter(i);48 let i = key_getter(i);
49 i.inplace_unwrap()?;
50 match (i, sort_type) {49 match (i, sort_type) {
51 (Val::Str(_), SortKeyType::Unknown) => sort_type = SortKeyType::String,50 (Val::Str(_), SortKeyType::Unknown) => sort_type = SortKeyType::String,
52 (Val::Num(_), SortKeyType::Unknown) => sort_type = SortKeyType::Number,51 (Val::Num(_), SortKeyType::Unknown) => sort_type = SortKeyType::Number,
modifiedcrates/jrsonnet-evaluator/src/ctx.rsdiffbeforeafterboth
2 error::Error::*, future_wrapper, map::LayeredHashMap, rc_fn_helper, resolved_lazy_val,2 error::Error::*, future_wrapper, map::LayeredHashMap, rc_fn_helper, resolved_lazy_val,
3 LazyBinding, LazyVal, ObjValue, Result, Val,3 LazyBinding, LazyVal, ObjValue, Result, Val,
4};4};
5use jrsonnet_interner::IStr;
5use rustc_hash::FxHashMap;6use rustc_hash::FxHashMap;
6use std::hash::BuildHasherDefault;7use std::hash::BuildHasherDefault;
7use std::{cell::RefCell, collections::HashMap, fmt::Debug, rc::Rc};8use std::{cell::RefCell, collections::HashMap, fmt::Debug, rc::Rc};
18 dollar: Option<ObjValue>,19 dollar: Option<ObjValue>,
19 this: Option<ObjValue>,20 this: Option<ObjValue>,
20 super_obj: Option<ObjValue>,21 super_obj: Option<ObjValue>,
21 bindings: LayeredHashMap<Rc<str>, LazyVal>,22 bindings: LayeredHashMap<LazyVal>,
22}23}
23impl Debug for ContextInternals {24impl Debug for ContextInternals {
24 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {25 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
57 }))58 }))
58 }59 }
5960
60 pub fn binding(&self, name: Rc<str>) -> Result<LazyVal> {61 pub fn binding(&self, name: IStr) -> Result<LazyVal> {
61 Ok(self62 Ok(self
62 .063 .0
63 .bindings64 .bindings
72 ctx.unwrap()73 ctx.unwrap()
73 }74 }
7475
75 pub fn with_var(self, name: Rc<str>, value: Val) -> Self {76 pub fn with_var(self, name: IStr, value: Val) -> Self {
76 let mut new_bindings =77 let mut new_bindings =
77 FxHashMap::with_capacity_and_hasher(1, BuildHasherDefault::default());78 FxHashMap::with_capacity_and_hasher(1, BuildHasherDefault::default());
78 new_bindings.insert(name, resolved_lazy_val!(value));79 new_bindings.insert(name, resolved_lazy_val!(value));
8182
82 pub fn extend(83 pub fn extend(
83 self,84 self,
84 new_bindings: FxHashMap<Rc<str>, LazyVal>,85 new_bindings: FxHashMap<IStr, LazyVal>,
85 new_dollar: Option<ObjValue>,86 new_dollar: Option<ObjValue>,
86 new_this: Option<ObjValue>,87 new_this: Option<ObjValue>,
87 new_super_obj: Option<ObjValue>,88 new_super_obj: Option<ObjValue>,
123 }124 }
124 pub fn extend_unbound(125 pub fn extend_unbound(
125 self,126 self,
126 new_bindings: HashMap<Rc<str>, LazyBinding>,127 new_bindings: HashMap<IStr, LazyBinding>,
127 new_dollar: Option<ObjValue>,128 new_dollar: Option<ObjValue>,
128 new_this: Option<ObjValue>,129 new_this: Option<ObjValue>,
129 new_super_obj: Option<ObjValue>,130 new_super_obj: Option<ObjValue>,
modifiedcrates/jrsonnet-evaluator/src/error.rsdiffbeforeafterboth
1use crate::{1use crate::{
2 builtin::{format::FormatError, sort::SortError},2 builtin::{format::FormatError, sort::SortError},
3 ValType,3 typed::TypeLocError,
4};4};
5use jrsonnet_interner::IStr;
5use jrsonnet_parser::{BinaryOpType, ExprLocation, UnaryOpType};6use jrsonnet_parser::{BinaryOpType, ExprLocation, UnaryOpType};
7use jrsonnet_types::ValType;
6use std::{path::PathBuf, rc::Rc};8use std::{path::PathBuf, rc::Rc};
7use thiserror::Error;9use thiserror::Error;
810
9#[derive(Error, Debug, Clone)]11#[derive(Error, Debug, Clone)]
10pub enum Error {12pub enum Error {
11 #[error("intrinsic not found: {0}")]13 #[error("intrinsic not found: {0}")]
12 IntrinsicNotFound(Rc<str>),14 IntrinsicNotFound(IStr),
13 #[error("argument reordering in intrisics not supported yet")]15 #[error("argument reordering in intrisics not supported yet")]
14 IntrinsicArgumentReorderingIsNotSupportedYet,16 IntrinsicArgumentReorderingIsNotSupportedYet,
1517
32 ArrayBoundsError(usize, usize),34 ArrayBoundsError(usize, usize),
3335
34 #[error("assert failed: {0}")]36 #[error("assert failed: {0}")]
35 AssertionFailed(Rc<str>),37 AssertionFailed(IStr),
3638
37 #[error("variable is not defined: {0}")]39 #[error("variable is not defined: {0}")]
38 VariableIsNotDefined(Rc<str>),40 VariableIsNotDefined(IStr),
39 #[error("type mismatch: expected {}, got {2} {0}", .1.iter().map(|e| format!("{}", e)).collect::<Vec<_>>().join(", "))]41 #[error("type mismatch: expected {}, got {2} {0}", .1.iter().map(|e| format!("{}", e)).collect::<Vec<_>>().join(", "))]
40 TypeMismatch(&'static str, Vec<ValType>, ValType),42 TypeMismatch(&'static str, Vec<ValType>, ValType),
41 #[error("no such field: {0}")]43 #[error("no such field: {0}")]
42 NoSuchField(Rc<str>),44 NoSuchField(IStr),
4345
44 #[error("only functions can be called, got {0}")]46 #[error("only functions can be called, got {0}")]
45 OnlyFunctionsCanBeCalledGot(ValType),47 OnlyFunctionsCanBeCalledGot(ValType),
46 #[error("parameter {0} is not defined")]48 #[error("parameter {0} is not defined")]
47 UnknownFunctionParameter(String),49 UnknownFunctionParameter(String),
48 #[error("argument {0} is already bound")]50 #[error("argument {0} is already bound")]
49 BindingParameterASecondTime(Rc<str>),51 BindingParameterASecondTime(IStr),
50 #[error("too many args, function has {0}")]52 #[error("too many args, function has {0}")]
51 TooManyArgsFunctionHas(usize),53 TooManyArgsFunctionHas(usize),
52 #[error("founction argument is not passed: {0}")]54 #[error("founction argument is not passed: {0}")]
53 FunctionParameterNotBoundInCall(Rc<str>),55 FunctionParameterNotBoundInCall(IStr),
5456
55 #[error("external variable is not defined: {0}")]57 #[error("external variable is not defined: {0}")]
56 UndefinedExternalVariable(Rc<str>),58 UndefinedExternalVariable(IStr),
57 #[error("native is not defined: {0}")]59 #[error("native is not defined: {0}")]
58 UndefinedExternalFunction(Rc<str>),60 UndefinedExternalFunction(IStr),
5961
60 #[error("field name should be string, got {0}")]62 #[error("field name should be string, got {0}")]
61 FieldMustBeStringGot(ValType),63 FieldMustBeStringGot(ValType),
6264
63 #[error("attempted to index array with string {0}")]65 #[error("attempted to index array with string {0}")]
64 AttemptedIndexAnArrayWithString(Rc<str>),66 AttemptedIndexAnArrayWithString(IStr),
65 #[error("{0} index type should be {1}, got {2}")]67 #[error("{0} index type should be {1}, got {2}")]
66 ValueIndexMustBeTypeGot(ValType, ValType, ValType),68 ValueIndexMustBeTypeGot(ValType, ValType, ValType),
67 #[error("cant index into {0}")]69 #[error("cant index into {0}")]
85 )]87 )]
86 ImportSyntaxError {88 ImportSyntaxError {
87 path: Rc<PathBuf>,89 path: Rc<PathBuf>,
88 source_code: Rc<str>,90 source_code: IStr,
89 error: Box<jrsonnet_parser::ParseError>,91 error: Box<jrsonnet_parser::ParseError>,
90 },92 },
9193
92 #[error("runtime error: {0}")]94 #[error("runtime error: {0}")]
93 RuntimeError(Rc<str>),95 RuntimeError(IStr),
94 #[error("stack overflow, try to reduce recursion, or set --max-stack to bigger value")]96 #[error("stack overflow, try to reduce recursion, or set --max-stack to bigger value")]
95 StackOverflow,97 StackOverflow,
96 #[error("tried to index by fractional value")]98 #[error("tried to index by fractional value")]
117119
118 #[error("format error: {0}")]120 #[error("format error: {0}")]
119 Format(#[from] FormatError),121 Format(#[from] FormatError),
122 #[error("type error: {0}")]
123 TypeError(TypeLocError),
120 #[error("sort error: {0}")]124 #[error("sort error: {0}")]
121 Sort(#[from] SortError),125 Sort(#[from] SortError),
122}126}
128132
129#[derive(Clone, Debug)]133#[derive(Clone, Debug)]
130pub struct StackTraceElement {134pub struct StackTraceElement {
131 pub location: ExprLocation,135 pub location: Option<ExprLocation>,
132 pub desc: String,136 pub desc: String,
133}137}
134#[derive(Debug, Clone)]138#[derive(Debug, Clone)]
144 pub const fn error(&self) -> &Error {148 pub const fn error(&self) -> &Error {
145 &(self.0).0149 &(self.0).0
146 }150 }
151 pub fn error_mut(&mut self) -> &mut Error {
152 &mut (self.0).0
153 }
147 pub const fn trace(&self) -> &StackTrace {154 pub const fn trace(&self) -> &StackTrace {
148 &(self.0).1155 &(self.0).1
149 }156 }
modifiedcrates/jrsonnet-evaluator/src/evaluate.rsdiffbeforeafterboth
1use crate::{1use crate::{
2 context_creator, error::Error::*, future_wrapper, lazy_val, push, throw, with_state, Context,2 context_creator, error::Error::*, future_wrapper, lazy_val, push, throw, with_state, Context,
3 ContextCreator, FuncDesc, FuncVal, LazyBinding, LazyVal, ObjMember, ObjValue, Result, Val,3 ContextCreator, FuncDesc, FuncVal, LazyBinding, LazyVal, ObjMember, ObjValue, Result, Val,
4 ValType,
5};4};
6use closure::closure;5use closure::closure;
6use jrsonnet_interner::IStr;
7use jrsonnet_parser::{7use jrsonnet_parser::{
8 ArgsDesc, AssertStmt, BinaryOpType, BindSpec, CompSpec, Expr, ExprLocation, FieldMember,8 ArgsDesc, AssertStmt, BinaryOpType, BindSpec, CompSpec, Expr, ExprLocation, FieldMember,
9 ForSpecData, IfSpecData, LiteralType, LocExpr, Member, ObjBody, ParamsDesc, UnaryOpType,9 ForSpecData, IfSpecData, LiteralType, LocExpr, Member, ObjBody, ParamsDesc, UnaryOpType,
10 Visibility,10 Visibility,
11};11};
12use jrsonnet_types::ValType;
12use rustc_hash::FxHashMap;13use rustc_hash::FxHashMap;
13use std::{collections::HashMap, rc::Rc};14use std::{collections::HashMap, rc::Rc};
1415
15pub fn evaluate_binding(b: &BindSpec, context_creator: ContextCreator) -> (Rc<str>, LazyBinding) {16pub fn evaluate_binding(b: &BindSpec, context_creator: ContextCreator) -> (IStr, LazyBinding) {
16 let b = b.clone();17 let b = b.clone();
17 if let Some(params) = &b.params {18 if let Some(params) = &b.params {
18 let params = params.clone();19 let params = params.clone();
45 }46 }
46}47}
4748
48pub fn evaluate_method(ctx: Context, name: Rc<str>, params: ParamsDesc, body: LocExpr) -> Val {49pub fn evaluate_method(ctx: Context, name: IStr, params: ParamsDesc, body: LocExpr) -> Val {
49 Val::Func(Rc::new(FuncVal::Normal(FuncDesc {50 Val::Func(Rc::new(FuncVal::Normal(FuncDesc {
50 name,51 name,
51 ctx,52 ctx,
57pub fn evaluate_field_name(58pub fn evaluate_field_name(
58 context: Context,59 context: Context,
59 field_name: &jrsonnet_parser::FieldName,60 field_name: &jrsonnet_parser::FieldName,
60) -> Result<Option<Rc<str>>> {61) -> Result<Option<IStr>> {
61 Ok(match field_name {62 Ok(match field_name {
62 jrsonnet_parser::FieldName::Fixed(n) => Some(n.clone()),63 jrsonnet_parser::FieldName::Fixed(n) => Some(n.clone()),
63 jrsonnet_parser::FieldName::Dyn(expr) => {64 jrsonnet_parser::FieldName::Dyn(expr) => {
64 let lazy = evaluate(context, expr)?;65 let value = evaluate(context, expr)?;
65 let value = lazy.unwrap_if_lazy()?;
66 if matches!(value, Val::Null) {66 if matches!(value, Val::Null) {
67 None67 None
68 } else {68 } else {
7474
75pub fn evaluate_unary_op(op: UnaryOpType, b: &Val) -> Result<Val> {75pub fn evaluate_unary_op(op: UnaryOpType, b: &Val) -> Result<Val> {
76 Ok(match (op, b) {76 Ok(match (op, b) {
77 (o, Val::Lazy(l)) => evaluate_unary_op(o, &l.evaluate()?)?,
78 (UnaryOpType::Not, Val::Bool(v)) => Val::Bool(!v),77 (UnaryOpType::Not, Val::Bool(v)) => Val::Bool(!v),
79 (UnaryOpType::Minus, Val::Num(n)) => Val::Num(-*n),78 (UnaryOpType::Minus, Val::Num(n)) => Val::Num(-*n),
80 (UnaryOpType::BitNot, Val::Num(n)) => Val::Num(!(*n as i32) as f64),79 (UnaryOpType::BitNot, Val::Num(n)) => Val::Num(!(*n as i32) as f64),
81 (op, o) => throw!(UnaryOperatorDoesNotOperateOnType(op, o.value_type()?)),80 (op, o) => throw!(UnaryOperatorDoesNotOperateOnType(op, o.value_type())),
82 })81 })
83}82}
8483
94 (o, Val::Str(s)) => Val::Str(format!("{}{}", o.clone().to_string()?, s).into()),93 (o, Val::Str(s)) => Val::Str(format!("{}{}", o.clone().to_string()?, s).into()),
9594
96 (Val::Obj(v1), Val::Obj(v2)) => Val::Obj(v2.with_super(v1.clone())),95 (Val::Obj(v1), Val::Obj(v2)) => Val::Obj(v2.with_super(v1.clone())),
97 (Val::Arr(a), Val::Arr(b)) => Val::Arr(Rc::new([&a[..], &b[..]].concat())),96 (Val::Arr(a), Val::Arr(b)) => {
97 let mut out = Vec::with_capacity(a.len() + b.len());
98 out.extend(a.iter_lazy());
99 out.extend(b.iter_lazy());
100 Val::Arr(out.into())
101 }
98 (Val::Num(v1), Val::Num(v2)) => Val::new_checked_num(v1 + v2)?,102 (Val::Num(v1), Val::Num(v2)) => Val::new_checked_num(v1 + v2)?,
99 _ => throw!(BinaryOperatorDoesNotOperateOnValues(103 _ => throw!(BinaryOperatorDoesNotOperateOnValues(
100 BinaryOpType::Add,104 BinaryOpType::Add,
101 a.value_type()?,105 a.value_type(),
102 b.value_type()?,106 b.value_type(),
103 )),107 )),
104 })108 })
105}109}
111 b: &LocExpr,115 b: &LocExpr,
112) -> Result<Val> {116) -> Result<Val> {
113 Ok(117 Ok(match (evaluate(context.clone(), a)?, op, b) {
114 match (evaluate(context.clone(), a)?.unwrap_if_lazy()?, op, b) {
115 (Val::Bool(true), BinaryOpType::Or, _o) => Val::Bool(true),118 (Val::Bool(true), BinaryOpType::Or, _o) => Val::Bool(true),
116 (Val::Bool(false), BinaryOpType::And, _o) => Val::Bool(false),119 (Val::Bool(false), BinaryOpType::And, _o) => Val::Bool(false),
117 (a, op, eb) => {120 (a, op, eb) => evaluate_binary_op_normal(&a, op, &evaluate(context, eb)?)?,
118 evaluate_binary_op_normal(&a, op, &evaluate(context, eb)?.unwrap_if_lazy()?)?
119 }
120 },121 })
121 )
122}122}
177177
178 _ => throw!(BinaryOperatorDoesNotOperateOnValues(178 _ => throw!(BinaryOperatorDoesNotOperateOnValues(
179 op,179 op,
180 a.value_type()?,180 a.value_type(),
181 b.value_type()?,181 b.value_type(),
182 )),182 )),
183 })183 })
184}184}
185185
186future_wrapper!(HashMap<Rc<str>, LazyBinding>, FutureNewBindings);186future_wrapper!(HashMap<IStr, LazyBinding>, FutureNewBindings);
187future_wrapper!(ObjValue, FutureObjValue);187future_wrapper!(ObjValue, FutureObjValue);
188188
189pub fn evaluate_comp<T>(189pub fn evaluate_comp<T>(
200 None200 None
201 }201 }
202 }202 }
203 Some(CompSpec::ForSpec(ForSpecData(var, expr))) => {203 Some(CompSpec::ForSpec(ForSpecData(var, expr))) => match evaluate(context.clone(), expr)? {
204 match evaluate(context.clone(), expr)?.unwrap_if_lazy()? {
205 Val::Arr(list) => {204 Val::Arr(list) => {
206 let mut out = Vec::new();205 let mut out = Vec::new();
207 for item in list.iter() {206 for item in list.iter() {
208 let item = item.unwrap_if_lazy()?;
209 out.push(evaluate_comp(207 out.push(evaluate_comp(
210 context.clone().with_var(var.clone(), item.clone()),208 context.clone().with_var(var.clone(), item?.clone()),
211 value,209 value,
212 &specs[1..],210 &specs[1..],
213 )?);211 )?);
214 }212 }
215 Some(out.into_iter().flatten().flatten().collect())213 Some(out.into_iter().flatten().flatten().collect())
216 }214 }
217 _ => throw!(InComprehensionCanOnlyIterateOverArray),215 _ => throw!(InComprehensionCanOnlyIterateOverArray),
218 }216 },
219 }
220 })217 })
221}218}
222219
234 })231 })
235 );232 );
236 {233 {
237 let mut bindings: HashMap<Rc<str>, LazyBinding> = HashMap::new();234 let mut bindings: HashMap<IStr, LazyBinding> = HashMap::new();
238 for (n, b) in members235 for (n, b) in members
239 .iter()236 .iter()
240 .filter_map(|m| match m {237 .filter_map(|m| match m {
338 )?)335 )?)
339 })336 })
340 );337 );
341 let mut bindings: HashMap<Rc<str>, LazyBinding> = HashMap::new();338 let mut bindings: HashMap<IStr, LazyBinding> = HashMap::new();
342 for (n, b) in obj339 for (n, b) in obj
343 .pre_locals340 .pre_locals
344 .iter()341 .iter()
375 },372 },
376 );373 );
377 }374 }
378 v => throw!(FieldMustBeStringGot(v.value_type()?)),375 v => throw!(FieldMustBeStringGot(v.value_type())),
379 }376 }
380 }377 }
381378
388 context: Context,385 context: Context,
389 value: &LocExpr,386 value: &LocExpr,
390 args: &ArgsDesc,387 args: &ArgsDesc,
391 loc: &Option<ExprLocation>,388 loc: Option<&ExprLocation>,
392 tailstrict: bool,389 tailstrict: bool,
393) -> Result<Val> {390) -> Result<Val> {
394 let lazy = evaluate(context.clone(), value)?;391 let value = evaluate(context.clone(), value)?;
395 let value = lazy.unwrap_if_lazy()?;
396 Ok(match value {392 Ok(match value {
397 Val::Func(f) => {393 Val::Func(f) => {
398 let body = || f.evaluate(context, loc, args, tailstrict);394 let body = || f.evaluate(context, loc, args, tailstrict);
402 push(loc, || format!("function <{}> call", f.name()), body)?398 push(loc, || format!("function <{}> call", f.name()), body)?
403 }399 }
404 }400 }
405 v => throw!(OnlyFunctionsCanBeCalledGot(v.value_type()?)),401 v => throw!(OnlyFunctionsCanBeCalledGot(v.value_type())),
406 })402 })
407}403}
408404
409pub fn evaluate_named(context: Context, lexpr: &LocExpr, name: Rc<str>) -> Result<Val> {405pub fn evaluate_named(context: Context, lexpr: &LocExpr, name: IStr) -> Result<Val> {
410 use Expr::*;406 use Expr::*;
411 let LocExpr(expr, _loc) = lexpr;407 let LocExpr(expr, _loc) = lexpr;
412 Ok(match &**expr {408 Ok(match &**expr {
434 BinaryOp(v1, o, v2) => evaluate_binary_op_special(context, v1, *o, v2)?,430 BinaryOp(v1, o, v2) => evaluate_binary_op_special(context, v1, *o, v2)?,
435 UnaryOp(o, v) => evaluate_unary_op(*o, &evaluate(context, v)?)?,431 UnaryOp(o, v) => evaluate_unary_op(*o, &evaluate(context, v)?)?,
436 Var(name) => push(432 Var(name) => push(
437 loc,433 loc.as_ref(),
438 || format!("variable <{}>", name),434 || format!("variable <{}>", name),
439 || Ok(Val::Lazy(context.binding(name.clone())?).unwrap_if_lazy()?),435 || Ok(context.binding(name.clone())?.evaluate()?),
440 )?,436 )?,
441 Index(LocExpr(v, _), index) if matches!(&**v, Expr::Literal(LiteralType::Super)) => {437 Index(LocExpr(v, _), index) if matches!(&**v, Expr::Literal(LiteralType::Super)) => {
442 let name = evaluate(context.clone(), index)?.try_cast_str("object index")?;438 let name = evaluate(context.clone(), index)?.try_cast_str("object index")?;
443 context439 context
444 .super_obj()440 .super_obj()
445 .clone()441 .clone()
446 .expect("no super found")442 .expect("no super found")
447 .get_raw(name, &context.this().clone().expect("no this found"))?443 .get_raw(name, Some(&context.this().clone().expect("no this found")))?
448 .expect("value not found")444 .expect("value not found")
449 }445 }
450 Index(value, index) => {446 Index(value, index) => {
451 match (447 match (evaluate(context.clone(), value)?, evaluate(context, index)?) {
452 evaluate(context.clone(), value)?.unwrap_if_lazy()?,
453 evaluate(context, index)?,
454 ) {
455 (Val::Obj(v), Val::Str(s)) => {448 (Val::Obj(v), Val::Str(s)) => {
456 let sn = s.clone();449 let sn = s.clone();
457 push(450 push(
458 loc,451 loc.as_ref(),
459 || format!("field <{}> access", sn),452 || format!("field <{}> access", sn),
460 || {453 || {
461 if let Some(v) = v.get(s.clone())? {454 if let Some(v) = v.get(s.clone())? {
462 Ok(v.unwrap_if_lazy()?)455 Ok(v)
463 } else if v.get("__intrinsic_namespace__".into())?.is_some() {456 } else if v.get("__intrinsic_namespace__".into())?.is_some() {
464 Ok(Val::Func(Rc::new(FuncVal::Intrinsic(s))))457 Ok(Val::Func(Rc::new(FuncVal::Intrinsic(s))))
465 } else {458 } else {
471 (Val::Obj(_), n) => throw!(ValueIndexMustBeTypeGot(464 (Val::Obj(_), n) => throw!(ValueIndexMustBeTypeGot(
472 ValType::Obj,465 ValType::Obj,
473 ValType::Str,466 ValType::Str,
474 n.value_type()?,467 n.value_type(),
475 )),468 )),
476469
477 (Val::Arr(v), Val::Num(n)) => {470 (Val::Arr(v), Val::Num(n)) => {
478 if n.fract() > f64::EPSILON {471 if n.fract() > f64::EPSILON {
479 throw!(FractionalIndex)472 throw!(FractionalIndex)
480 }473 }
481 v.get(n as usize)474 v.get(n as usize)?
482 .ok_or_else(|| ArrayBoundsError(n as usize, v.len()))?475 .ok_or_else(|| ArrayBoundsError(n as usize, v.len()))?
483 .clone()
484 .unwrap_if_lazy()?
485 }476 }
486 (Val::Arr(_), Val::Str(n)) => throw!(AttemptedIndexAnArrayWithString(n)),477 (Val::Arr(_), Val::Str(n)) => throw!(AttemptedIndexAnArrayWithString(n)),
487 (Val::Arr(_), n) => throw!(ValueIndexMustBeTypeGot(478 (Val::Arr(_), n) => throw!(ValueIndexMustBeTypeGot(
488 ValType::Arr,479 ValType::Arr,
489 ValType::Num,480 ValType::Num,
490 n.value_type()?,481 n.value_type(),
491 )),482 )),
492483
493 (Val::Str(s), Val::Num(n)) => Val::Str(484 (Val::Str(s), Val::Num(n)) => Val::Str(
500 (Val::Str(_), n) => throw!(ValueIndexMustBeTypeGot(491 (Val::Str(_), n) => throw!(ValueIndexMustBeTypeGot(
501 ValType::Str,492 ValType::Str,
502 ValType::Num,493 ValType::Num,
503 n.value_type()?,494 n.value_type(),
504 )),495 )),
505496
506 (v, _) => throw!(CantIndexInto(v.value_type()?)),497 (v, _) => throw!(CantIndexInto(v.value_type())),
507 }498 }
508 }499 }
509 LocalExpr(bindings, returned) => {500 LocalExpr(bindings, returned) => {
510 let mut new_bindings: HashMap<Rc<str>, LazyBinding> = HashMap::new();501 let mut new_bindings: HashMap<IStr, LazyBinding> = HashMap::new();
511 let future_context = Context::new_future();502 let future_context = Context::new_future();
512503
513 let context_creator = context_creator!(504 let context_creator = context_creator!(
529 Arr(items) => {520 Arr(items) => {
530 let mut out = Vec::with_capacity(items.len());521 let mut out = Vec::with_capacity(items.len());
531 for item in items {522 for item in items {
532 out.push(Val::Lazy(lazy_val!(523 out.push(LazyVal::new(Box::new(
533 closure!(clone context, clone item, || {524 closure!(clone context, clone item, || {
534 evaluate(context.clone(), &item)525 evaluate(context.clone(), &item)
535 })526 }),
536 )));527 )));
537 }528 }
538 Val::Arr(Rc::new(out))529 Val::Arr(out.into())
539 }530 }
540 ArrComp(expr, comp_specs) => Val::Arr(531 ArrComp(expr, comp_specs) => Val::Arr(
541 // First comp_spec should be for_spec, so no "None" possible here532 // First comp_spec should be for_spec, so no "None" possible here
542 Rc::new(evaluate_comp(context, &|ctx| evaluate(ctx, expr), comp_specs)?.unwrap()),533 evaluate_comp(context, &|ctx| evaluate(ctx, expr), comp_specs)?
534 .unwrap()
535 .into(),
543 ),536 ),
544 Obj(body) => Val::Obj(evaluate_object(context, body)?),537 Obj(body) => Val::Obj(evaluate_object(context, body)?),
545 ObjExtend(s, t) => evaluate_add_op(538 ObjExtend(s, t) => evaluate_add_op(
546 &evaluate(context.clone(), s)?,539 &evaluate(context.clone(), s)?,
547 &Val::Obj(evaluate_object(context, t)?),540 &Val::Obj(evaluate_object(context, t)?),
548 )?,541 )?,
549 Apply(value, args, tailstrict) => evaluate_apply(context, value, args, loc, *tailstrict)?,542 Apply(value, args, tailstrict) => {
543 evaluate_apply(context, value, args, loc.as_ref(), *tailstrict)?
544 }
550 Function(params, body) => {545 Function(params, body) => {
551 evaluate_method(context, "anonymous".into(), params.clone(), body.clone())546 evaluate_method(context, "anonymous".into(), params.clone(), body.clone())
552 }547 }
553 Intrinsic(name) => Val::Func(Rc::new(FuncVal::Intrinsic(name.clone()))),548 Intrinsic(name) => Val::Func(Rc::new(FuncVal::Intrinsic(name.clone()))),
554 AssertExpr(AssertStmt(value, msg), returned) => {549 AssertExpr(AssertStmt(value, msg), returned) => {
555 let assertion_result = push(550 let assertion_result = push(
556 &value.1,551 value.1.as_ref(),
557 || "assertion condition".to_owned(),552 || "assertion condition".to_owned(),
558 || {553 || {
559 evaluate(context.clone(), value)?554 evaluate(context.clone(), value)?
562 )?;557 )?;
563 if assertion_result {558 if assertion_result {
564 evaluate(context, returned)?559 evaluate(context, returned)?
565 } else if let Some(msg) = msg {560 } else {
561 push(
562 value.1.as_ref(),
563 || "assertion failure".to_owned(),
564 || {
565 if let Some(msg) = msg {
566 throw!(AssertionFailed(evaluate(context, msg)?.to_string()?));566 throw!(AssertionFailed(evaluate(context, msg)?.to_string()?));
567 } else {567 } else {
568 throw!(AssertionFailed(Val::Null.to_string()?));568 throw!(AssertionFailed(Val::Null.to_string()?));
569 }569 }
570 },
571 )?
572 }
570 }573 }
571 ErrorStmt(e) => push(574 ErrorStmt(e) => push(
572 loc,575 loc.as_ref(),
573 || "error statement".to_owned(),576 || "error statement".to_owned(),
574 || {577 || {
575 throw!(RuntimeError(578 throw!(RuntimeError(
583 cond_else,586 cond_else,
584 } => {587 } => {
585 if push(588 if push(
586 loc,589 loc.as_ref(),
587 || "if condition".to_owned(),590 || "if condition".to_owned(),
588 || evaluate(context.clone(), &cond.0)?.try_cast_bool("in if condition"),591 || evaluate(context.clone(), &cond.0)?.try_cast_bool("in if condition"),
589 )? {592 )? {
603 let import_location = Rc::make_mut(&mut tmp);606 let import_location = Rc::make_mut(&mut tmp);
604 import_location.pop();607 import_location.pop();
605 push(608 push(
606 loc,609 loc.as_ref(),
607 || format!("import {:?}", path),610 || format!("import {:?}", path),
608 || with_state(|s| s.import_file(import_location, path)),611 || with_state(|s| s.import_file(import_location, path)),
609 )?612 )?
modifiedcrates/jrsonnet-evaluator/src/function.rsdiffbeforeafterboth
1use crate::{error::Error::*, evaluate, lazy_val, resolved_lazy_val, throw, Context, Result, Val};1use crate::{error::Error::*, evaluate, lazy_val, resolved_lazy_val, throw, Context, Result, Val};
2use closure::closure;2use closure::closure;
3use jrsonnet_interner::IStr;
3use jrsonnet_parser::{ArgsDesc, ParamsDesc};4use jrsonnet_parser::{ArgsDesc, ParamsDesc};
4use rustc_hash::FxHashMap;5use rustc_hash::FxHashMap;
5use std::{collections::HashMap, hash::BuildHasherDefault, rc::Rc};6use std::{collections::HashMap, hash::BuildHasherDefault};
67
7const NO_DEFAULT_CONTEXT: &str =8const NO_DEFAULT_CONTEXT: &str =
8 "no default context set for call with defined default parameter value";9 "no default context set for call with defined default parameter value";
66 ctx: Context,67 ctx: Context,
67 body_ctx: Option<Context>,68 body_ctx: Option<Context>,
68 params: &ParamsDesc,69 params: &ParamsDesc,
69 args: &HashMap<Rc<str>, Val>,70 args: &HashMap<IStr, Val>,
70 tailstrict: bool,71 tailstrict: bool,
71) -> Result<Context> {72) -> Result<Context> {
72 let mut out = FxHashMap::with_capacity_and_hasher(params.len(), BuildHasherDefault::default());73 let mut out = FxHashMap::with_capacity_and_hasher(params.len(), BuildHasherDefault::default());
143#[macro_export]144#[macro_export]
144macro_rules! parse_args {145macro_rules! parse_args {
145 ($ctx: expr, $fn_name: expr, $args: expr, $total_args: expr, [146 ($ctx: expr, $fn_name: expr, $args: expr, $total_args: expr, [
146 $($id: expr, $name: ident $(: [$($p: path)|+] $(!! $a: path)?)?, $nt: expr);+ $(;)?147 $($id: expr, $name: ident: $ty: expr $(=>$match: path)?);+ $(;)?
147 ], $handler:block) => {{148 ], $handler:block) => {{
148 use crate::{throw, error::Error::*};149 use $crate::{error::Error::*, throw, evaluate, push_stack_frame, typed::CheckType};
150
149 let args = $args;151 let args = $args;
150 if args.len() > $total_args {152 if args.len() > $total_args {
160 throw!(IntrinsicArgumentReorderingIsNotSupportedYet);162 throw!(IntrinsicArgumentReorderingIsNotSupportedYet);
161 }163 }
162 }164 }
163 let $name = evaluate($ctx.clone(), &$name.1)?;165 let $name = push_stack_frame(None, || format!("evaluating argument"), || {
164 $(166 let value = evaluate($ctx.clone(), &$name.1)?;
165 match $name {
166 $($p(_))|+ => {},167 $ty.check(&value)?;
167 _ => throw!(TypeMismatch(
168 concat!($fn_name, " ", stringify!($id), "nd (", stringify!($name), ") argument"),
169 $nt, $name.value_type()?168 Ok(value)
170 )),
171 };169 })?;
172 $(170 $(
173 let $name = match $name {171 let $name = if let $match(v) = $name {
174 $a(v) => v,172 v
173 } else {
175 _ =>throw!(TypeMismatch(concat!($fn_name, " ", stringify!($id), "nd (", stringify!($name), ") argument"), $nt, $name.value_type()?)),174 unreachable!();
176 };175 };
177 )*176 )?
178 )*
179 )+177 )+
180 ($handler as crate::Result<_>)178 ($handler as crate::Result<_>)
181 }};179 }};
182}180}
183
184#[test]
185fn test() -> Result<()> {
186 use crate::val::ValType;
187 use jrsonnet_parser::*;
188 let state = crate::EvaluationState::default();
189 let evaluator = state.with_stdlib();
190 let ctx = evaluator.create_default_context()?;
191 evaluator.run_in_state(|| {
192 parse_args!(ctx, "test", ArgsDesc(vec![
193 Arg(None, el!(Expr::Num(2.0))),
194 Arg(Some("b".into()), el!(Expr::Num(1.0))),
195 ]), 2, [
196 0, a: [Val::Num]!!Val::Num, vec![ValType::Num];
197 1, b: [Val::Num]!!Val::Num, vec![ValType::Num];
198 ], {
199 assert!((a - 2.0).abs() <= f64::EPSILON);
200 assert!((b - 1.0).abs() <= f64::EPSILON);
201 Ok(())
202 })
203 .unwrap();
204 Ok(())
205 })
206}
207181
modifiedcrates/jrsonnet-evaluator/src/import.rsdiffbeforeafterboth
3 throw,3 throw,
4};4};
5use fs::File;5use fs::File;
6use jrsonnet_interner::IStr;
6use std::fs;7use std::fs;
7use std::io::Read;8use std::io::Read;
8use std::{any::Any, cell::RefCell, collections::HashMap, path::PathBuf, rc::Rc};9use std::{any::Any, cell::RefCell, collections::HashMap, path::PathBuf, rc::Rc};
15 fn resolve_file(&self, from: &PathBuf, path: &PathBuf) -> Result<Rc<PathBuf>>;16 fn resolve_file(&self, from: &PathBuf, path: &PathBuf) -> Result<Rc<PathBuf>>;
1617
17 /// Reads file from filesystem, should be used only with path received from `resolve_file`18 /// Reads file from filesystem, should be used only with path received from `resolve_file`
18 fn load_file_contents(&self, resolved: &PathBuf) -> Result<Rc<str>>;19 fn load_file_contents(&self, resolved: &PathBuf) -> Result<IStr>;
1920
20 /// # Safety21 /// # Safety
21 ///22 ///
32 throw!(ImportNotSupported(from.clone(), path.clone()))33 throw!(ImportNotSupported(from.clone(), path.clone()))
33 }34 }
3435
35 fn load_file_contents(&self, _resolved: &PathBuf) -> Result<Rc<str>> {36 fn load_file_contents(&self, _resolved: &PathBuf) -> Result<IStr> {
36 // Can be only caused by library direct consumer, not by supplied jsonnet37 // Can be only caused by library direct consumer, not by supplied jsonnet
37 panic!("dummy resolver can't load any file")38 panic!("dummy resolver can't load any file")
38 }39 }
72 throw!(ImportFileNotFound(from.clone(), path.clone()))73 throw!(ImportFileNotFound(from.clone(), path.clone()))
73 }74 }
74 }75 }
75 fn load_file_contents(&self, id: &PathBuf) -> Result<Rc<str>> {76 fn load_file_contents(&self, id: &PathBuf) -> Result<IStr> {
76 let mut file = File::open(id).map_err(|_e| ResolvedFileNotFound(id.clone()))?;77 let mut file = File::open(id).map_err(|_e| ResolvedFileNotFound(id.clone()))?;
77 let mut out = String::new();78 let mut out = String::new();
78 file.read_to_string(&mut out)79 file.read_to_string(&mut out)
89/// Caches results of the underlying resolver90/// Caches results of the underlying resolver
90pub struct CachingImportResolver {91pub struct CachingImportResolver {
91 resolution_cache: RefCell<HashMap<ResolutionData, Result<Rc<PathBuf>>>>,92 resolution_cache: RefCell<HashMap<ResolutionData, Result<Rc<PathBuf>>>>,
92 loading_cache: RefCell<HashMap<PathBuf, Result<Rc<str>>>>,93 loading_cache: RefCell<HashMap<PathBuf, Result<IStr>>>,
93 inner: Box<dyn ImportResolver>,94 inner: Box<dyn ImportResolver>,
94}95}
95impl ImportResolver for CachingImportResolver {96impl ImportResolver for CachingImportResolver {
101 .clone()102 .clone()
102 }103 }
103104
104 fn load_file_contents(&self, resolved: &PathBuf) -> Result<Rc<str>> {105 fn load_file_contents(&self, resolved: &PathBuf) -> Result<IStr> {
105 self.loading_cache106 self.loading_cache
106 .borrow_mut()107 .borrow_mut()
107 .entry(resolved.clone())108 .entry(resolved.clone())
modifiedcrates/jrsonnet-evaluator/src/integrations/serde.rsdiffbeforeafterboth
22 } else {22 } else {
23 Number::from_f64(*n).expect("to json number")23 Number::from_f64(*n).expect("to json number")
24 }),24 }),
25 Val::Lazy(v) => (&v.evaluate()?).try_into()?,
26 Val::Arr(a) => {25 Val::Arr(a) => {
27 let mut out = Vec::with_capacity(a.len());26 let mut out = Vec::with_capacity(a.len());
28 for item in a.iter() {27 for item in a.iter() {
29 out.push(item.try_into()?);28 out.push((&item?).try_into()?);
30 }29 }
31 Self::Array(out)30 Self::Array(out)
32 }31 }
55 Value::Array(a) => {54 Value::Array(a) => {
56 let mut out = Vec::with_capacity(a.len());55 let mut out = Vec::with_capacity(a.len());
57 for v in a {56 for v in a {
58 out.push(v.into());57 out.push(LazyVal::new_resolved(v.into()));
59 }58 }
60 Self::Arr(Rc::new(out))59 Self::Arr(out.into())
61 }60 }
62 Value::Object(o) => {61 Value::Object(o) => {
63 let mut entries = HashMap::with_capacity(o.len());62 let mut entries = HashMap::with_capacity(o.len());
modifiedcrates/jrsonnet-evaluator/src/lib.rsdiffbeforeafterboth
14pub mod native;14pub mod native;
15mod obj;15mod obj;
16pub mod trace;16pub mod trace;
17pub mod typed;
17mod val;18mod val;
1819
19pub use ctx::*;20pub use ctx::*;
22pub use evaluate::*;23pub use evaluate::*;
23pub use function::parse_function_call;24pub use function::parse_function_call;
24pub use import::*;25pub use import::*;
26use jrsonnet_interner::IStr;
25use jrsonnet_parser::*;27use jrsonnet_parser::*;
26use native::NativeCallback;28use native::NativeCallback;
27pub use obj::*;29pub use obj::*;
62 /// Limits amount of stack trace items preserved64 /// Limits amount of stack trace items preserved
63 pub max_trace: usize,65 pub max_trace: usize,
64 /// Used for s`td.extVar`66 /// Used for s`td.extVar`
65 pub ext_vars: HashMap<Rc<str>, Val>,67 pub ext_vars: HashMap<IStr, Val>,
66 /// Used for ext.native68 /// Used for ext.native
67 pub ext_natives: HashMap<Rc<str>, Rc<NativeCallback>>,69 pub ext_natives: HashMap<IStr, Rc<NativeCallback>>,
68 /// TLA vars70 /// TLA vars
69 pub tla_vars: HashMap<Rc<str>, Val>,71 pub tla_vars: HashMap<IStr, Val>,
70 /// Global variables are inserted in default context72 /// Global variables are inserted in default context
71 pub globals: HashMap<Rc<str>, Val>,73 pub globals: HashMap<IStr, Val>,
72 /// Used to resolve file locations/contents74 /// Used to resolve file locations/contents
73 pub import_resolver: Box<dyn ImportResolver>,75 pub import_resolver: Box<dyn ImportResolver>,
74 /// Used in manifestification functions76 /// Used in manifestification functions
101 stack_depth: usize,103 stack_depth: usize,
102 /// Contains file source codes and evaluation results for imports and pretty-printed stacktraces104 /// Contains file source codes and evaluation results for imports and pretty-printed stacktraces
103 files: HashMap<Rc<PathBuf>, FileData>,105 files: HashMap<Rc<PathBuf>, FileData>,
104 str_files: HashMap<Rc<PathBuf>, Rc<str>>,106 str_files: HashMap<Rc<PathBuf>, IStr>,
105}107}
106108
107pub struct FileData {109pub struct FileData {
108 source_code: Rc<str>,110 source_code: IStr,
109 parsed: LocExpr,111 parsed: LocExpr,
110 evaluated: Option<Val>,112 evaluated: Option<Val>,
111}113}
126 EVAL_STATE.with(|s| f(s.borrow().as_ref().unwrap()))128 EVAL_STATE.with(|s| f(s.borrow().as_ref().unwrap()))
127}129}
128pub(crate) fn push<T>(130pub(crate) fn push<T>(
129 e: &Option<ExprLocation>,131 e: Option<&ExprLocation>,
130 frame_desc: impl FnOnce() -> String,132 frame_desc: impl FnOnce() -> String,
131 f: impl FnOnce() -> Result<T>,133 f: impl FnOnce() -> Result<T>,
132) -> Result<T> {134) -> Result<T> {
133 if let Some(v) = e {
134 with_state(|s| s.push(v, frame_desc, f))135 with_state(|s| s.push(e, frame_desc, f))
135 } else {
136 f()
137 }
138}136}
137
138pub fn push_stack_frame<T>(
139 e: Option<&ExprLocation>,
140 frame_desc: impl FnOnce() -> String,
141 f: impl FnOnce() -> Result<T>,
142) -> Result<T> {
143 push(e, frame_desc, f)
144}
139145
140/// Maintains stack trace and import resolution146/// Maintains stack trace and import resolution
141#[derive(Default, Clone)]147#[derive(Default, Clone)]
142pub struct EvaluationState(Rc<EvaluationStateInternals>);148pub struct EvaluationState(Rc<EvaluationStateInternals>);
143149
144impl EvaluationState {150impl EvaluationState {
145 /// Parses and adds file as loaded151 /// Parses and adds file as loaded
146 pub fn add_file(&self, path: Rc<PathBuf>, source_code: Rc<str>) -> Result<()> {152 pub fn add_file(&self, path: Rc<PathBuf>, source_code: IStr) -> Result<()> {
147 self.add_parsed_file(153 self.add_parsed_file(
148 path.clone(),154 path.clone(),
149 source_code.clone(),155 source_code.clone(),
168 pub fn add_parsed_file(174 pub fn add_parsed_file(
169 &self,175 &self,
170 name: Rc<PathBuf>,176 name: Rc<PathBuf>,
171 source_code: Rc<str>,177 source_code: IStr,
172 parsed: LocExpr,178 parsed: LocExpr,
173 ) -> Result<()> {179 ) -> Result<()> {
174 self.data_mut().files.insert(180 self.data_mut().files.insert(
182188
183 Ok(())189 Ok(())
184 }190 }
185 pub fn get_source(&self, name: &PathBuf) -> Option<Rc<str>> {191 pub fn get_source(&self, name: &PathBuf) -> Option<IStr> {
186 let ro_map = &self.data().files;192 let ro_map = &self.data().files;
187 ro_map.get(name).map(|value| value.source_code.clone())193 ro_map.get(name).map(|value| value.source_code.clone())
188 }194 }
204 self.add_file(file_path.clone(), contents)?;210 self.add_file(file_path.clone(), contents)?;
205 self.evaluate_loaded_file_raw(&file_path)211 self.evaluate_loaded_file_raw(&file_path)
206 }212 }
207 pub(crate) fn import_file_str(&self, from: &PathBuf, path: &PathBuf) -> Result<Rc<str>> {213 pub(crate) fn import_file_str(&self, from: &PathBuf, path: &PathBuf) -> Result<IStr> {
208 let path = self.resolve_file(from, path)?;214 let path = self.resolve_file(from, path)?;
209 if !self.data().str_files.contains_key(&path) {215 if !self.data().str_files.contains_key(&path) {
210 let file_str = self.load_file_contents(&path)?;216 let file_str = self.load_file_contents(&path)?;
256 /// Creates context with all passed global variables262 /// Creates context with all passed global variables
257 pub fn create_default_context(&self) -> Result<Context> {263 pub fn create_default_context(&self) -> Result<Context> {
258 let globals = &self.settings().globals;264 let globals = &self.settings().globals;
259 let mut new_bindings: HashMap<Rc<str>, LazyBinding> = HashMap::new();265 let mut new_bindings: HashMap<IStr, LazyBinding> = HashMap::new();
260 for (name, value) in globals.iter() {266 for (name, value) in globals.iter() {
261 new_bindings.insert(267 new_bindings.insert(
262 name.clone(),268 name.clone(),
269 /// Executes code creating a new stack frame275 /// Executes code creating a new stack frame
270 pub fn push<T>(276 pub fn push<T>(
271 &self,277 &self,
272 e: &ExprLocation,278 e: Option<&ExprLocation>,
273 frame_desc: impl FnOnce() -> String,279 frame_desc: impl FnOnce() -> String,
274 f: impl FnOnce() -> Result<T>,280 f: impl FnOnce() -> Result<T>,
275 ) -> Result<T> {281 ) -> Result<T> {
288 self.data_mut().stack_depth -= 1;294 self.data_mut().stack_depth -= 1;
289 if let Err(mut err) = result {295 if let Err(mut err) = result {
290 err.trace_mut().0.push(StackTraceElement {296 err.trace_mut().0.push(StackTraceElement {
291 location: e.clone(),297 location: e.cloned(),
292 desc: frame_desc(),298 desc: frame_desc(),
293 });299 });
294 return Err(err);300 return Err(err);
320 out326 out
321 }327 }
322328
323 pub fn manifest(&self, val: Val) -> Result<Rc<str>> {329 pub fn manifest(&self, val: Val) -> Result<IStr> {
324 self.run_in_state(|| val.manifest(&self.manifest_format()))330 self.run_in_state(|| val.manifest(&self.manifest_format()))
325 }331 }
326 pub fn manifest_multi(&self, val: Val) -> Result<Vec<(Rc<str>, Rc<str>)>> {332 pub fn manifest_multi(&self, val: Val) -> Result<Vec<(IStr, IStr)>> {
327 self.run_in_state(|| val.manifest_multi(&self.manifest_format()))333 self.run_in_state(|| val.manifest_multi(&self.manifest_format()))
328 }334 }
329 pub fn manifest_stream(&self, val: Val) -> Result<Vec<Rc<str>>> {335 pub fn manifest_stream(&self, val: Val) -> Result<Vec<IStr>> {
330 self.run_in_state(|| val.manifest_stream(&self.manifest_format()))336 self.run_in_state(|| val.manifest_stream(&self.manifest_format()))
331 }337 }
332338
333 /// If passed value is function then call with set TLA339 /// If passed value is function then call with set TLA
334 pub fn with_tla(&self, val: Val) -> Result<Val> {340 pub fn with_tla(&self, val: Val) -> Result<Val> {
335 self.run_in_state(|| {341 self.run_in_state(|| {
336 Ok(match val {342 Ok(match val {
337 Val::Func(func) => func.evaluate_map(343 Val::Func(func) => push(
344 None,
345 || "during TLA call".to_owned(),
346 || {
347 Ok(func.evaluate_map(
338 self.create_default_context()?,348 self.create_default_context()?,
339 &self.settings().tla_vars,349 &self.settings().tla_vars,
340 true,350 true,
341 )?,351 )?)
352 },
353 )?,
342 v => v,354 v => v,
343 })355 })
344 })356 })
370 self.run_in_state(|| self.import_file(&PathBuf::from("."), name))382 self.run_in_state(|| self.import_file(&PathBuf::from("."), name))
371 }383 }
372 /// Parses and evaluates the given snippet384 /// Parses and evaluates the given snippet
373 pub fn evaluate_snippet_raw(&self, source: Rc<PathBuf>, code: Rc<str>) -> Result<Val> {385 pub fn evaluate_snippet_raw(&self, source: Rc<PathBuf>, code: IStr) -> Result<Val> {
374 let parsed = parse(386 let parsed = parse(
375 &code,387 &code,
376 &ParserSettings {388 &ParserSettings {
390402
391/// Settings utilities403/// Settings utilities
392impl EvaluationState {404impl EvaluationState {
393 pub fn add_ext_var(&self, name: Rc<str>, value: Val) {405 pub fn add_ext_var(&self, name: IStr, value: Val) {
394 self.settings_mut().ext_vars.insert(name, value);406 self.settings_mut().ext_vars.insert(name, value);
395 }407 }
396 pub fn add_ext_str(&self, name: Rc<str>, value: Rc<str>) {408 pub fn add_ext_str(&self, name: IStr, value: IStr) {
397 self.add_ext_var(name, Val::Str(value));409 self.add_ext_var(name, Val::Str(value));
398 }410 }
399 pub fn add_ext_code(&self, name: Rc<str>, code: Rc<str>) -> Result<()> {411 pub fn add_ext_code(&self, name: IStr, code: IStr) -> Result<()> {
400 let value =412 let value =
401 self.evaluate_snippet_raw(Rc::new(PathBuf::from(format!("ext_code {}", name))), code)?;413 self.evaluate_snippet_raw(Rc::new(PathBuf::from(format!("ext_code {}", name))), code)?;
402 self.add_ext_var(name, value);414 self.add_ext_var(name, value);
403 Ok(())415 Ok(())
404 }416 }
405417
406 pub fn add_tla(&self, name: Rc<str>, value: Val) {418 pub fn add_tla(&self, name: IStr, value: Val) {
407 self.settings_mut().tla_vars.insert(name, value);419 self.settings_mut().tla_vars.insert(name, value);
408 }420 }
409 pub fn add_tla_str(&self, name: Rc<str>, value: Rc<str>) {421 pub fn add_tla_str(&self, name: IStr, value: IStr) {
410 self.add_tla(name, Val::Str(value));422 self.add_tla(name, Val::Str(value));
411 }423 }
412 pub fn add_tla_code(&self, name: Rc<str>, code: Rc<str>) -> Result<()> {424 pub fn add_tla_code(&self, name: IStr, code: IStr) -> Result<()> {
413 let value =425 let value =
414 self.evaluate_snippet_raw(Rc::new(PathBuf::from(format!("tla_code {}", name))), code)?;426 self.evaluate_snippet_raw(Rc::new(PathBuf::from(format!("tla_code {}", name))), code)?;
415 self.add_tla(name, value);427 self.add_tla(name, value);
419 pub fn resolve_file(&self, from: &PathBuf, path: &PathBuf) -> Result<Rc<PathBuf>> {431 pub fn resolve_file(&self, from: &PathBuf, path: &PathBuf) -> Result<Rc<PathBuf>> {
420 Ok(self.settings().import_resolver.resolve_file(from, path)?)432 Ok(self.settings().import_resolver.resolve_file(from, path)?)
421 }433 }
422 pub fn load_file_contents(&self, path: &PathBuf) -> Result<Rc<str>> {434 pub fn load_file_contents(&self, path: &PathBuf) -> Result<IStr> {
423 Ok(self.settings().import_resolver.load_file_contents(path)?)435 Ok(self.settings().import_resolver.load_file_contents(path)?)
424 }436 }
425437
430 self.settings_mut().import_resolver = resolver;442 self.settings_mut().import_resolver = resolver;
431 }443 }
432444
433 pub fn add_native(&self, name: Rc<str>, cb: Rc<NativeCallback>) {445 pub fn add_native(&self, name: IStr, cb: Rc<NativeCallback>) {
434 self.settings_mut().ext_natives.insert(name, cb);446 self.settings_mut().ext_natives.insert(name, cb);
435 }447 }
436448
467pub mod tests {479pub mod tests {
468 use super::Val;480 use super::Val;
469 use crate::{error::Error::*, primitive_equals, EvaluationState};481 use crate::{error::Error::*, primitive_equals, EvaluationState};
482 use jrsonnet_interner::IStr;
470 use jrsonnet_parser::*;483 use jrsonnet_parser::*;
471 use std::{path::PathBuf, rc::Rc};484 use std::{path::PathBuf, rc::Rc};
472485
477 state.run_in_state(|| {490 state.run_in_state(|| {
478 state491 state
479 .push(492 .push(
480 &ExprLocation(Rc::new(PathBuf::from("test1.jsonnet")), 10, 20),493 Some(&ExprLocation(
494 Rc::new(PathBuf::from("test1.jsonnet")),
495 10,
496 20,
497 )),
481 || "outer".to_owned(),498 || "outer".to_owned(),
482 || {499 || {
483 state.push(500 state.push(
484 &ExprLocation(Rc::new(PathBuf::from("test2.jsonnet")), 30, 40),501 Some(&ExprLocation(
502 Rc::new(PathBuf::from("test2.jsonnet")),
503 30,
504 40,
505 )),
485 || "inner".to_owned(),506 || "inner".to_owned(),
486 || Err(RuntimeError("".into()).into()),507 || Err(RuntimeError("".into()).into()),
487 )?;508 )?;
883 Param("a".into(), None),904 Param("a".into(), None),
884 Param("b".into(), None),905 Param("b".into(), None),
885 ])),906 ])),
886 |args| match (&args[0], &args[1]) {907 |caller, args| {
908 assert_eq!(
909 caller.unwrap(),
910 Rc::new(PathBuf::from("native_caller.jsonnet"))
911 );
912 match (&args[0], &args[1]) {
887 (Val::Num(a), Val::Num(b)) => Ok(Val::Num(a + b)),913 (Val::Num(a), Val::Num(b)) => Ok(Val::Num(a + b)),
888 (_, _) => todo!(),914 (_, _) => unreachable!(),
889 },915 }
916 },
890 )),917 )),
891 );918 );
892 evaluator.evaluate_snippet_raw(919 evaluator.evaluate_snippet_raw(
893 Rc::new(PathBuf::from("test.jsonnet")),920 Rc::new(PathBuf::from("native_caller.jsonnet")),
894 "std.assertEqual(std.native(\"native_add\")(1, 2), 3)".into(),921 "std.assertEqual(std.native(\"native_add\")(1, 2), 3)".into(),
895 )?;922 )?;
896 Ok(())923 Ok(())
904 Ok(())931 Ok(())
905 }932 }
906933
907 struct TestImportResolver(Rc<str>);934 struct TestImportResolver(IStr);
908 impl crate::import::ImportResolver for TestImportResolver {935 impl crate::import::ImportResolver for TestImportResolver {
909 fn resolve_file(&self, _: &PathBuf, _: &PathBuf) -> crate::error::Result<Rc<PathBuf>> {936 fn resolve_file(&self, _: &PathBuf, _: &PathBuf) -> crate::error::Result<Rc<PathBuf>> {
910 Ok(Rc::new(PathBuf::from("/test")))937 Ok(Rc::new(PathBuf::from("/test")))
911 }938 }
912939
913 fn load_file_contents(&self, _: &PathBuf) -> crate::error::Result<Rc<str>> {940 fn load_file_contents(&self, _: &PathBuf) -> crate::error::Result<IStr> {
914 Ok(self.0.clone())941 Ok(self.0.clone())
915 }942 }
916943
modifiedcrates/jrsonnet-evaluator/src/map.rsdiffbeforeafterboth
1use jrsonnet_interner::IStr;
1use rustc_hash::FxHashMap;2use rustc_hash::FxHashMap;
2use std::{borrow::Borrow, hash::Hash, rc::Rc};3use std::rc::Rc;
34
4#[derive(Default, Debug)]5#[derive(Default, Debug)]
5struct LayeredHashMapInternals<K: Hash, V> {6struct LayeredHashMapInternals<V> {
6 parent: Option<LayeredHashMap<K, V>>,7 parent: Option<LayeredHashMap<V>>,
7 current: FxHashMap<K, V>,8 current: FxHashMap<IStr, V>,
8}9}
910
10#[derive(Debug)]11#[derive(Debug)]
11pub struct LayeredHashMap<K: Hash, V>(Rc<LayeredHashMapInternals<K, V>>);12pub struct LayeredHashMap<V>(Rc<LayeredHashMapInternals<V>>);
1213
13impl<K: Hash + Eq, V> LayeredHashMap<K, V> {14impl<V> LayeredHashMap<V> {
14 pub fn extend(self, new_layer: FxHashMap<K, V>) -> Self {15 pub fn extend(self, new_layer: FxHashMap<IStr, V>) -> Self {
15 match Rc::try_unwrap(self.0) {16 match Rc::try_unwrap(self.0) {
16 Ok(mut map) => {17 Ok(mut map) => {
17 map.current.extend(new_layer);18 map.current.extend(new_layer);
24 }25 }
25 }26 }
2627
27 pub fn get<Q: ?Sized>(&self, key: &Q) -> Option<&V>28 pub fn get(&self, key: &IStr) -> Option<&V> {
28 where
29 K: Borrow<Q>,
30 Q: Hash + Eq,
31 {
32 (self.0)29 (self.0)
33 .current30 .current
36 }33 }
37}34}
3835
39impl<K: Hash, V> Clone for LayeredHashMap<K, V> {36impl<V> Clone for LayeredHashMap<V> {
40 fn clone(&self) -> Self {37 fn clone(&self) -> Self {
41 Self(self.0.clone())38 Self(self.0.clone())
42 }39 }
43}40}
4441
45impl<K: Hash + Eq, V> Default for LayeredHashMap<K, V> {42impl<V> Default for LayeredHashMap<V> {
46 fn default() -> Self {43 fn default() -> Self {
47 Self(Rc::new(LayeredHashMapInternals {44 Self(Rc::new(LayeredHashMapInternals {
48 parent: None,45 parent: None,
modifiedcrates/jrsonnet-evaluator/src/native.rsdiffbeforeafterboth
1#![allow(clippy::type_complexity)]
2
1use crate::{error::Result, Val};3use crate::{error::Result, Val};
2use jrsonnet_parser::ParamsDesc;4use jrsonnet_parser::ParamsDesc;
3use std::fmt::Debug;5use std::fmt::Debug;
6use std::path::PathBuf;
7use std::rc::Rc;
48
5pub struct NativeCallback {9pub struct NativeCallback {
6 pub params: ParamsDesc,10 pub params: ParamsDesc,
7 handler: Box<dyn Fn(&[Val]) -> Result<Val>>,11 handler: Box<dyn Fn(Option<Rc<PathBuf>>, &[Val]) -> Result<Val>>,
8}12}
9impl NativeCallback {13impl NativeCallback {
10 pub fn new(params: ParamsDesc, handler: impl Fn(&[Val]) -> Result<Val> + 'static) -> Self {14 pub fn new(
15 params: ParamsDesc,
16 handler: impl Fn(Option<Rc<PathBuf>>, &[Val]) -> Result<Val> + 'static,
17 ) -> Self {
11 Self {18 Self {
12 params,19 params,
13 handler: Box::new(handler),20 handler: Box::new(handler),
14 }21 }
15 }22 }
16 pub fn call(&self, args: &[Val]) -> Result<Val> {23 pub fn call(&self, caller: Option<Rc<PathBuf>>, args: &[Val]) -> Result<Val> {
17 (self.handler)(args)24 (self.handler)(caller, args)
18 }25 }
19}26}
20impl Debug for NativeCallback {27impl Debug for NativeCallback {
modifiedcrates/jrsonnet-evaluator/src/obj.rsdiffbeforeafterboth
1use crate::{evaluate_add_op, LazyBinding, Result, Val};1use crate::{evaluate_add_op, LazyBinding, Result, Val};
2use indexmap::IndexMap;2use indexmap::IndexMap;
3use jrsonnet_interner::IStr;
3use jrsonnet_parser::{ExprLocation, Visibility};4use jrsonnet_parser::{ExprLocation, Visibility};
4use std::{cell::RefCell, collections::HashMap, fmt::Debug, rc::Rc};5use std::{cell::RefCell, collections::HashMap, fmt::Debug, rc::Rc};
56
12}13}
1314
14// Field => This15// Field => This
15type CacheKey = (Rc<str>, usize);16type CacheKey = (IStr, usize);
16#[derive(Debug)]17#[derive(Debug)]
17pub struct ObjValueInternals {18pub struct ObjValueInternals {
18 super_obj: Option<ObjValue>,19 super_obj: Option<ObjValue>,
19 this_entries: Rc<HashMap<Rc<str>, ObjMember>>,20 this_entries: Rc<HashMap<IStr, ObjMember>>,
20 value_cache: RefCell<HashMap<CacheKey, Option<Val>>>,21 value_cache: RefCell<HashMap<CacheKey, Option<Val>>>,
21}22}
22#[derive(Clone)]23#[derive(Clone)]
47}48}
4849
49impl ObjValue {50impl ObjValue {
50 pub fn new(super_obj: Option<Self>, this_entries: Rc<HashMap<Rc<str>, ObjMember>>) -> Self {51 pub fn new(super_obj: Option<Self>, this_entries: Rc<HashMap<IStr, ObjMember>>) -> Self {
51 Self(Rc::new(ObjValueInternals {52 Self(Rc::new(ObjValueInternals {
52 super_obj,53 super_obj,
53 this_entries,54 this_entries,
63 Some(v) => Self::new(Some(v.with_super(super_obj)), self.0.this_entries.clone()),64 Some(v) => Self::new(Some(v.with_super(super_obj)), self.0.this_entries.clone()),
64 }65 }
65 }66 }
66 pub fn enum_fields(&self, handler: &impl Fn(&Rc<str>, &Visibility)) {67 pub fn enum_fields(&self, handler: &impl Fn(&IStr, &Visibility)) {
67 if let Some(s) = &self.0.super_obj {68 if let Some(s) = &self.0.super_obj {
68 s.enum_fields(handler);69 s.enum_fields(handler);
69 }70 }
70 for (name, member) in self.0.this_entries.iter() {71 for (name, member) in self.0.this_entries.iter() {
71 handler(name, &member.visibility);72 handler(name, &member.visibility);
72 }73 }
73 }74 }
74 pub fn fields_visibility(&self) -> IndexMap<Rc<str>, bool> {75 pub fn fields_visibility(&self) -> IndexMap<IStr, bool> {
75 let out = Rc::new(RefCell::new(IndexMap::new()));76 let out = Rc::new(RefCell::new(IndexMap::new()));
76 self.enum_fields(&|name, visibility| {77 self.enum_fields(&|name, visibility| {
77 let mut out = out.borrow_mut();78 let mut out = out.borrow_mut();
91 });92 });
92 Rc::try_unwrap(out).unwrap().into_inner()93 Rc::try_unwrap(out).unwrap().into_inner()
93 }94 }
94 pub fn visible_fields(&self) -> Vec<Rc<str>> {95 pub fn visible_fields(&self) -> Vec<IStr> {
95 let mut visible_fields: Vec<_> = self96 let mut visible_fields: Vec<_> = self
96 .fields_visibility()97 .fields_visibility()
97 .into_iter()98 .into_iter()
101 visible_fields.sort();102 visible_fields.sort();
102 visible_fields103 visible_fields
103 }104 }
104 pub fn get(&self, key: Rc<str>) -> Result<Option<Val>> {105 pub fn get(&self, key: IStr) -> Result<Option<Val>> {
105 Ok(self.get_raw(key, self)?)106 Ok(self.get_raw(key, None)?)
106 }107 }
107 pub(crate) fn get_raw(&self, key: Rc<str>, real_this: &Self) -> Result<Option<Val>> {108 pub(crate) fn get_raw(&self, key: IStr, real_this: Option<&Self>) -> Result<Option<Val>> {
109 let real_this = real_this.unwrap_or(self);
108 let cache_key = (key.clone(), Rc::as_ptr(&real_this.0) as usize);110 let cache_key = (key.clone(), Rc::as_ptr(&real_this.0) as usize);
109111
110 if let Some(v) = self.0.value_cache.borrow().get(&cache_key) {112 if let Some(v) = self.0.value_cache.borrow().get(&cache_key) {
115 (Some(k), Some(s)) => {117 (Some(k), Some(s)) => {
116 let our = self.evaluate_this(k, real_this)?;118 let our = self.evaluate_this(k, real_this)?;
117 if k.add {119 if k.add {
118 s.get_raw(key, real_this)?120 s.get_raw(key, Some(real_this))?
119 .map_or(Ok(Some(our.clone())), |v| {121 .map_or(Ok(Some(our.clone())), |v| {
120 Ok(Some(evaluate_add_op(&v, &our)?))122 Ok(Some(evaluate_add_op(&v, &our)?))
121 })123 })
122 } else {124 } else {
123 Ok(Some(our))125 Ok(Some(our))
124 }126 }
125 }127 }
126 (None, Some(s)) => s.get_raw(key, real_this),128 (None, Some(s)) => s.get_raw(key, Some(real_this)),
127 (None, None) => Ok(None),129 (None, None) => Ok(None),
128 }?;130 }?;
129 self.0131 self.0
138 .evaluate()?)140 .evaluate()?)
139 }141 }
142
143 pub fn ptr_eq(a: &Self, b: &Self) -> bool {
144 Rc::ptr_eq(&a.0, &b.0)
145 }
140}146}
141impl PartialEq for ObjValue {147impl PartialEq for ObjValue {
142 fn eq(&self, other: &Self) -> bool {148 fn eq(&self, other: &Self) -> bool {
modifiedcrates/jrsonnet-evaluator/src/trace/location.rsdiffbeforeafterboth
40 for (pos, ch) in file.chars().enumerate() {40 for (pos, ch) in file
41 .chars()
42 .enumerate()
43 .chain(std::iter::once((file.len(), ' ')))
44 {
41 column += 1;45 column += 1;
42 match offset_map.last() {46 match offset_map.last() {
modifiedcrates/jrsonnet-evaluator/src/trace/mod.rsdiffbeforeafterboth
65 out,65 out,
66 "{}:{}-{}:{}",66 "{}:{}-{}:{}",
67 start.line,67 start.line,
68 end.column - 1,68 end.column.saturating_sub(1),
69 start.line,69 start.line,
70 end.column70 end.column
71 )?;71 )?;
118 .trace()118 .trace()
119 .0119 .0
120 .iter()120 .iter()
121 .map(|el| {121 .map(|el| {
122 let resolved_path = self.resolver.resolve(&el.location.0);
123 // TODO: Process all trace elements first
124 let location = evaluation_state
125 .map_source_locations(&el.location.0, &[el.location.1, el.location.2]);
126 (resolved_path, location)
127 })
128 .map(|(mut n, location)| {122 el.location.as_ref().map(|l| {
129 use std::fmt::Write;123 use std::fmt::Write;
124 let mut resolved_path = self.resolver.resolve(&l.0);
125 // TODO: Process all trace elements first
126 let location = evaluation_state.map_source_locations(&l.0, &[l.1, l.2]);
130 write!(n, ":").unwrap();127 write!(resolved_path, ":").unwrap();
131 print_code_location(&mut n, &location[0], &location[1]).unwrap();128 print_code_location(&mut resolved_path, &location[0], &location[1]).unwrap();
132 n129 resolved_path
133 })130 })
131 })
134 .collect::<Vec<_>>();132 .collect::<Vec<_>>();
135 let align = file_names.iter().map(|e| e.len()).max().unwrap_or(0);133 let align = file_names
134 .iter()
135 .flatten()
136 .map(|e| e.len())
137 .max()
138 .unwrap_or(0);
141 out,144 out,
142 "{:<p$}{:<w$}: {}",145 "{:<p$}{:<w$}: {}",
143 "",146 "",
144 file,147 file.unwrap_or_else(|| "".to_owned()),
145 el.desc,148 el.desc,
146 p = self.padding,149 p = self.padding,
147 w = align150 w = align
165 writeln!(out)?;168 writeln!(out)?;
166 }169 }
167 let desc = &item.desc;170 let desc = &item.desc;
168 let source = item.location.clone();171 if let Some(source) = &item.location {
169 let start_end = evaluation_state.map_source_locations(&source.0, &[source.1, source.2]);172 let start_end =
173 evaluation_state.map_source_locations(&source.0, &[source.1, source.2]);
170174
176 start_end[0].line,180 start_end[0].line,
177 start_end[0].column,181 start_end[0].column,
178 )?;182 )?;
183 } else {
184 write!(out, " at {}", desc,)?;
185 }
179 }186 }
180 Ok(())187 Ok(())
181 }188 }
225 let trace = &error.trace();232 let trace = &error.trace();
226 for item in trace.0.iter() {233 for item in trace.0.iter() {
227 let desc = &item.desc;234 let desc = &item.desc;
228 let source = item.location.clone();235 if let Some(source) = &item.location {
229 let start_end = evaluation_state.map_source_locations(&source.0, &[source.1, source.2]);236 let start_end =
230237 evaluation_state.map_source_locations(&source.0, &[source.1, source.2]);
231 self.print_snippet(238 self.print_snippet(
236 &start_end[1],243 &start_end[1],
237 desc,244 desc,
238 )?;245 )?;
246 } else {
247 write!(out, "{}", desc)?;
248 }
239 }249 }
240 Ok(())250 Ok(())
241 }251 }
addedcrates/jrsonnet-evaluator/src/typed.rsdiffbeforeafterboth

no changes

modifiedcrates/jrsonnet-evaluator/src/val.rsdiffbeforeafterboth
9 native::NativeCallback,9 native::NativeCallback,
10 throw, with_state, Context, ObjValue, Result,10 throw, with_state, Context, ObjValue, Result,
11};11};
12use jrsonnet_interner::IStr;
12use jrsonnet_parser::{el, Arg, ArgsDesc, Expr, ExprLocation, LiteralType, LocExpr, ParamsDesc};13use jrsonnet_parser::{el, Arg, ArgsDesc, Expr, ExprLocation, LiteralType, LocExpr, ParamsDesc};
14use jrsonnet_types::ValType;
13use std::{15use std::{cell::RefCell, collections::HashMap, fmt::Debug, rc::Rc};
14 cell::RefCell,
15 collections::HashMap,
16 fmt::{Debug, Display},
17 rc::Rc,
18};
1916
20enum LazyValInternals {17enum LazyValInternals {
6562
66#[derive(Debug, PartialEq)]63#[derive(Debug, PartialEq)]
67pub struct FuncDesc {64pub struct FuncDesc {
68 pub name: Rc<str>,65 pub name: IStr,
69 pub ctx: Context,66 pub ctx: Context,
70 pub params: ParamsDesc,67 pub params: ParamsDesc,
71 pub body: LocExpr,68 pub body: LocExpr,
76 /// Plain function implemented in jsonnet73 /// Plain function implemented in jsonnet
77 Normal(FuncDesc),74 Normal(FuncDesc),
78 /// Standard library function75 /// Standard library function
79 Intrinsic(Rc<str>),76 Intrinsic(IStr),
80 /// Library functions implemented in native77 /// Library functions implemented in native
81 NativeExt(Rc<str>, Rc<NativeCallback>),78 NativeExt(IStr, Rc<NativeCallback>),
82}79}
8380
84impl PartialEq for FuncVal {81impl PartialEq for FuncVal {
95 pub fn is_ident(&self) -> bool {92 pub fn is_ident(&self) -> bool {
96 matches!(&self, Self::Intrinsic(n) if n as &str == "id")93 matches!(&self, Self::Intrinsic(n) if n as &str == "id")
97 }94 }
98 pub fn name(&self) -> Rc<str> {95 pub fn name(&self) -> IStr {
99 match self {96 match self {
100 Self::Normal(normal) => normal.name.clone(),97 Self::Normal(normal) => normal.name.clone(),
101 Self::Intrinsic(name) => format!("std.{}", name).into(),98 Self::Intrinsic(name) => format!("std.{}", name).into(),
105 pub fn evaluate(102 pub fn evaluate(
106 &self,103 &self,
107 call_ctx: Context,104 call_ctx: Context,
108 loc: &Option<ExprLocation>,105 loc: Option<&ExprLocation>,
109 args: &ArgsDesc,106 args: &ArgsDesc,
110 tailstrict: bool,107 tailstrict: bool,
111 ) -> Result<Val> {108 ) -> Result<Val> {
127 for p in handler.params.0.iter() {124 for p in handler.params.0.iter() {
128 out_args.push(args.binding(p.0.clone())?.evaluate()?);125 out_args.push(args.binding(p.0.clone())?.evaluate()?);
129 }126 }
130 Ok(handler.call(&out_args)?)127 Ok(handler.call(loc.clone().map(|l| l.0.clone()), &out_args)?)
131 }128 }
132 }129 }
133 }130 }
134131
135 pub fn evaluate_map(132 pub fn evaluate_map(
136 &self,133 &self,
137 call_ctx: Context,134 call_ctx: Context,
138 args: &HashMap<Rc<str>, Val>,135 args: &HashMap<IStr, Val>,
139 tailstrict: bool,136 tailstrict: bool,
140 ) -> Result<Val> {137 ) -> Result<Val> {
141 match self {138 match self {
166 }163 }
167}164}
168
169#[derive(Debug, Clone, Copy, PartialEq)]
170pub enum ValType {
171 Bool,
172 Null,
173 Str,
174 Num,
175 Arr,
176 Obj,
177 Func,
178}
179impl ValType {
180 pub const fn name(&self) -> &'static str {
181 use ValType::*;
182 match self {
183 Bool => "boolean",
184 Null => "null",
185 Str => "string",
186 Num => "number",
187 Arr => "array",
188 Obj => "object",
189 Func => "function",
190 }
191 }
192}
193impl Display for ValType {
194 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
195 write!(f, "{}", self.name())
196 }
197}
198165
199#[derive(Clone)]166#[derive(Clone)]
200pub enum ManifestFormat {167pub enum ManifestFormat {
205 String,172 String,
206}173}
174
175#[derive(Debug, Clone)]
176pub enum ArrValue {
177 Lazy(Rc<Vec<LazyVal>>),
178 Eager(Rc<Vec<Val>>),
179 Extended(Box<(Self, Self)>),
180}
181impl ArrValue {
182 pub fn new_eager() -> Self {
183 Self::Eager(Rc::new(Vec::new()))
184 }
185
186 pub fn len(&self) -> usize {
187 match self {
188 Self::Lazy(l) => l.len(),
189 Self::Eager(e) => e.len(),
190 Self::Extended(v) => v.0.len() + v.1.len(),
191 }
192 }
193
194 pub fn is_empty(&self) -> bool {
195 self.len() == 0
196 }
197
198 pub fn get(&self, index: usize) -> Result<Option<Val>> {
199 match self {
200 Self::Lazy(vec) => {
201 if let Some(v) = vec.get(index) {
202 Ok(Some(v.evaluate()?))
203 } else {
204 Ok(None)
205 }
206 }
207 Self::Eager(vec) => Ok(vec.get(index).cloned()),
208 Self::Extended(v) => {
209 let a_len = v.0.len();
210 if a_len > index {
211 v.0.get(index)
212 } else {
213 v.1.get(index - a_len)
214 }
215 }
216 }
217 }
218
219 pub fn get_lazy(&self, index: usize) -> Option<LazyVal> {
220 match self {
221 Self::Lazy(vec) => vec.get(index).cloned(),
222 Self::Eager(vec) => vec.get(index).cloned().map(LazyVal::new_resolved),
223 Self::Extended(v) => {
224 let a_len = v.0.len();
225 if a_len > index {
226 v.0.get_lazy(index)
227 } else {
228 v.1.get_lazy(index - a_len)
229 }
230 }
231 }
232 }
233
234 pub fn evaluated(&self) -> Result<Rc<Vec<Val>>> {
235 Ok(match self {
236 Self::Lazy(vec) => {
237 let mut out = Vec::with_capacity(vec.len());
238 for item in vec.iter() {
239 out.push(item.evaluate()?);
240 }
241 Rc::new(out)
242 }
243 Self::Eager(vec) => vec.clone(),
244 Self::Extended(_v) => {
245 let mut out = Vec::with_capacity(self.len());
246 for item in self.iter() {
247 out.push(item?);
248 }
249 Rc::new(out)
250 }
251 })
252 }
253
254 pub fn iter(&self) -> impl DoubleEndedIterator<Item = Result<Val>> + '_ {
255 (0..self.len()).map(move |idx| match self {
256 Self::Lazy(l) => l[idx].evaluate(),
257 Self::Eager(e) => Ok(e[idx].clone()),
258 Self::Extended(_) => self.get(idx).map(|e| e.unwrap()),
259 })
260 }
261
262 pub fn iter_lazy(&self) -> impl DoubleEndedIterator<Item = LazyVal> + '_ {
263 (0..self.len()).map(move |idx| match self {
264 Self::Lazy(l) => l[idx].clone(),
265 Self::Eager(e) => LazyVal::new_resolved(e[idx].clone()),
266 Self::Extended(_) => self.get_lazy(idx).unwrap(),
267 })
268 }
269
270 pub fn reversed(self) -> Self {
271 match self {
272 Self::Lazy(vec) => {
273 let mut out = (&vec as &Vec<_>).clone();
274 out.reverse();
275 Self::Lazy(Rc::new(out))
276 }
277 Self::Eager(vec) => {
278 let mut out = (&vec as &Vec<_>).clone();
279 out.reverse();
280 Self::Eager(Rc::new(out))
281 }
282 Self::Extended(b) => Self::Extended(Box::new((b.1.reversed(), b.0.reversed()))),
283 }
284 }
285
286 pub fn ptr_eq(a: &Self, b: &Self) -> bool {
287 match (a, b) {
288 (Self::Lazy(a), Self::Lazy(b)) => Rc::ptr_eq(a, b),
289 (Self::Eager(a), Self::Eager(b)) => Rc::ptr_eq(a, b),
290 _ => false,
291 }
292 }
293}
294
295impl From<Vec<LazyVal>> for ArrValue {
296 fn from(v: Vec<LazyVal>) -> Self {
297 Self::Lazy(Rc::new(v))
298 }
299}
300
301impl From<Vec<Val>> for ArrValue {
302 fn from(v: Vec<Val>) -> Self {
303 Self::Eager(Rc::new(v))
304 }
305}
207306
208#[derive(Debug, Clone)]307#[derive(Debug, Clone)]
209pub enum Val {308pub enum Val {
210 Bool(bool),309 Bool(bool),
211 Null,310 Null,
212 Str(Rc<str>),311 Str(IStr),
213 Num(f64),312 Num(f64),
214 Lazy(LazyVal),
215 Arr(Rc<Vec<Val>>),313 Arr(ArrValue),
216 Obj(ObjValue),314 Obj(ObjValue),
217 Func(Rc<FuncVal>),315 Func(Rc<FuncVal>),
218}316}
237 }335 }
238336
239 pub fn assert_type(&self, context: &'static str, val_type: ValType) -> Result<()> {337 pub fn assert_type(&self, context: &'static str, val_type: ValType) -> Result<()> {
240 let this_type = self.value_type()?;338 let this_type = self.value_type();
241 if this_type != val_type {339 if this_type != val_type {
242 throw!(TypeMismatch(context, vec![val_type], this_type))340 throw!(TypeMismatch(context, vec![val_type], this_type))
243 } else {341 } else {
244 Ok(())342 Ok(())
245 }343 }
246 }344 }
345 pub fn unwrap_num(self) -> Result<f64> {
346 Ok(matches_unwrap!(self, Self::Num(v), v))
347 }
348 pub fn unwrap_func(self) -> Result<Rc<FuncVal>> {
349 Ok(matches_unwrap!(self, Self::Func(v), v))
350 }
247 pub fn try_cast_bool(self, context: &'static str) -> Result<bool> {351 pub fn try_cast_bool(self, context: &'static str) -> Result<bool> {
248 self.assert_type(context, ValType::Bool)?;352 self.assert_type(context, ValType::Bool)?;
249 Ok(matches_unwrap!(self.unwrap_if_lazy()?, Self::Bool(v), v))353 Ok(matches_unwrap!(self, Self::Bool(v), v))
250 }354 }
251 pub fn try_cast_str(self, context: &'static str) -> Result<Rc<str>> {355 pub fn try_cast_str(self, context: &'static str) -> Result<IStr> {
252 self.assert_type(context, ValType::Str)?;356 self.assert_type(context, ValType::Str)?;
253 Ok(matches_unwrap!(self.unwrap_if_lazy()?, Self::Str(v), v))357 Ok(matches_unwrap!(self, Self::Str(v), v))
254 }358 }
255 pub fn try_cast_num(self, context: &'static str) -> Result<f64> {359 pub fn try_cast_num(self, context: &'static str) -> Result<f64> {
256 self.assert_type(context, ValType::Num)?;360 self.assert_type(context, ValType::Num)?;
257 Ok(matches_unwrap!(self.unwrap_if_lazy()?, Self::Num(v), v))361 self.unwrap_num()
258 }362 }
259 pub fn inplace_unwrap(&mut self) -> Result<()> {
260 while let Self::Lazy(lazy) = self {
261 *self = lazy.evaluate()?;
262 }
263 Ok(())
264 }
265 pub fn unwrap_if_lazy(&self) -> Result<Self> {
266 Ok(if let Self::Lazy(v) = self {
267 v.evaluate()?.unwrap_if_lazy()?
268 } else {
269 self.clone()
270 })
271 }
272 pub fn value_type(&self) -> Result<ValType> {363 pub const fn value_type(&self) -> ValType {
273 Ok(match self {364 match self {
274 Self::Str(..) => ValType::Str,365 Self::Str(..) => ValType::Str,
275 Self::Num(..) => ValType::Num,366 Self::Num(..) => ValType::Num,
276 Self::Arr(..) => ValType::Arr,367 Self::Arr(..) => ValType::Arr,
277 Self::Obj(..) => ValType::Obj,368 Self::Obj(..) => ValType::Obj,
278 Self::Bool(_) => ValType::Bool,369 Self::Bool(_) => ValType::Bool,
279 Self::Null => ValType::Null,370 Self::Null => ValType::Null,
280 Self::Func(..) => ValType::Func,371 Self::Func(..) => ValType::Func,
281 Self::Lazy(_) => self.clone().unwrap_if_lazy()?.value_type()?,
282 })372 }
283 }373 }
284374
285 pub fn to_string(&self) -> Result<Rc<str>> {375 pub fn to_string(&self) -> Result<IStr> {
286 Ok(match self.unwrap_if_lazy()? {376 Ok(match self {
287 Self::Bool(true) => "true".into(),377 Self::Bool(true) => "true".into(),
288 Self::Bool(false) => "false".into(),378 Self::Bool(false) => "false".into(),
289 Self::Null => "null".into(),379 Self::Null => "null".into(),
290 Self::Str(s) => s,380 Self::Str(s) => s.clone(),
291 v => manifest_json_ex(381 v => manifest_json_ex(
292 &v,382 v,
293 &ManifestJsonOptions {383 &ManifestJsonOptions {
294 padding: "",384 padding: "",
295 mtype: ManifestType::ToString,385 mtype: ManifestType::ToString,
300 }390 }
301391
302 /// Expects value to be object, outputs (key, manifested value) pairs392 /// Expects value to be object, outputs (key, manifested value) pairs
303 pub fn manifest_multi(&self, ty: &ManifestFormat) -> Result<Vec<(Rc<str>, Rc<str>)>> {393 pub fn manifest_multi(&self, ty: &ManifestFormat) -> Result<Vec<(IStr, IStr)>> {
304 let obj = match self {394 let obj = match self {
305 Self::Obj(obj) => obj,395 Self::Obj(obj) => obj,
306 _ => throw!(MultiManifestOutputIsNotAObject),396 _ => throw!(MultiManifestOutputIsNotAObject),
318 }408 }
319409
320 /// Expects value to be array, outputs manifested values410 /// Expects value to be array, outputs manifested values
321 pub fn manifest_stream(&self, ty: &ManifestFormat) -> Result<Vec<Rc<str>>> {411 pub fn manifest_stream(&self, ty: &ManifestFormat) -> Result<Vec<IStr>> {
322 let arr = match self {412 let arr = match self {
323 Self::Arr(a) => a,413 Self::Arr(a) => a,
324 _ => throw!(StreamManifestOutputIsNotAArray),414 _ => throw!(StreamManifestOutputIsNotAArray),
325 };415 };
326 let mut out = Vec::with_capacity(arr.len());416 let mut out = Vec::with_capacity(arr.len());
327 for i in arr.iter() {417 for i in arr.iter() {
328 out.push(i.manifest(ty)?);418 out.push(i?.manifest(ty)?);
329 }419 }
330 Ok(out)420 Ok(out)
331 }421 }
332422
333 pub fn manifest(&self, ty: &ManifestFormat) -> Result<Rc<str>> {423 pub fn manifest(&self, ty: &ManifestFormat) -> Result<IStr> {
334 Ok(match ty {424 Ok(match ty {
335 ManifestFormat::YamlStream(format) => {425 ManifestFormat::YamlStream(format) => {
336 let arr = match self {426 let arr = match self {
348 if !arr.is_empty() {438 if !arr.is_empty() {
349 for v in arr.iter() {439 for v in arr.iter() {
350 out.push_str("---\n");440 out.push_str("---\n");
351 out.push_str(&v.manifest(format)?);441 out.push_str(&v?.manifest(format)?);
352 out.push('\n');442 out.push('\n');
353 }443 }
354 out.push_str("...");444 out.push_str("...");
367 }457 }
368458
369 /// For manifestification459 /// For manifestification
370 pub fn to_json(&self, padding: usize) -> Result<Rc<str>> {460 pub fn to_json(&self, padding: usize) -> Result<IStr> {
371 manifest_json_ex(461 manifest_json_ex(
372 self,462 self,
373 &ManifestJsonOptions {463 &ManifestJsonOptions {
419 .try_cast_str("to json")?)509 .try_cast_str("to json")?)
420 })510 })
421 }511 }
422 pub fn to_yaml(&self, padding: usize) -> Result<Rc<str>> {512 pub fn to_yaml(&self, padding: usize) -> Result<IStr> {
423 with_state(|s| {513 with_state(|s| {
424 let ctx = s514 let ctx = s
425 .create_default_context()?515 .create_default_context()?
456546
457/// Native implementation of `std.primitiveEquals`547/// Native implementation of `std.primitiveEquals`
458pub fn primitive_equals(val_a: &Val, val_b: &Val) -> Result<bool> {548pub fn primitive_equals(val_a: &Val, val_b: &Val) -> Result<bool> {
459 Ok(match (val_a.unwrap_if_lazy()?, val_b.unwrap_if_lazy()?) {549 Ok(match (val_a, val_b) {
460 (Val::Bool(a), Val::Bool(b)) => a == b,550 (Val::Bool(a), Val::Bool(b)) => a == b,
461 (Val::Null, Val::Null) => true,551 (Val::Null, Val::Null) => true,
462 (Val::Str(a), Val::Str(b)) => a == b,552 (Val::Str(a), Val::Str(b)) => a == b,
467 (Val::Obj(_), Val::Obj(_)) => throw!(RuntimeError(557 (Val::Obj(_), Val::Obj(_)) => throw!(RuntimeError(
468 "primitiveEquals operates on primitive types, got object".into(),558 "primitiveEquals operates on primitive types, got object".into(),
469 )),559 )),
470 (a, b) if is_function_like(&a) && is_function_like(&b) => {560 (a, b) if is_function_like(a) && is_function_like(b) => {
471 throw!(RuntimeError("cannot test equality of functions".into()))561 throw!(RuntimeError("cannot test equality of functions".into()))
472 }562 }
473 (_, _) => false,563 (_, _) => false,
476566
477/// Native implementation of `std.equals`567/// Native implementation of `std.equals`
478pub fn equals(val_a: &Val, val_b: &Val) -> Result<bool> {568pub fn equals(val_a: &Val, val_b: &Val) -> Result<bool> {
479 let val_a = val_a.unwrap_if_lazy()?;
480 let val_b = val_b.unwrap_if_lazy()?;
481
482 if val_a.value_type()? != val_b.value_type()? {569 if val_a.value_type() != val_b.value_type() {
483 return Ok(false);570 return Ok(false);
484 }571 }
485 match (val_a, val_b) {572 match (val_a, val_b) {
486 // Cant test for ptr equality, because all fields needs to be evaluated
487 (Val::Arr(a), Val::Arr(b)) => {573 (Val::Arr(a), Val::Arr(b)) => {
574 if ArrValue::ptr_eq(a, b) {
575 return Ok(true);
576 }
488 if a.len() != b.len() {577 if a.len() != b.len() {
489 return Ok(false);578 return Ok(false);
490 }579 }
491 for (a, b) in a.iter().zip(b.iter()) {580 for (a, b) in a.iter().zip(b.iter()) {
492 if !equals(&a.unwrap_if_lazy()?, &b.unwrap_if_lazy()?)? {581 if !equals(&a?, &b?)? {
493 return Ok(false);582 return Ok(false);
494 }583 }
495 }584 }
496 Ok(true)585 Ok(true)
497 }586 }
498 (Val::Obj(a), Val::Obj(b)) => {587 (Val::Obj(a), Val::Obj(b)) => {
588 if ObjValue::ptr_eq(a, b) {
589 return Ok(true);
590 }
499 let fields = a.visible_fields();591 let fields = a.visible_fields();
500 if fields != b.visible_fields() {592 if fields != b.visible_fields() {
501 return Ok(false);593 return Ok(false);
507 }599 }
508 Ok(true)600 Ok(true)
509 }601 }
510 (a, b) => Ok(primitive_equals(&a, &b)?),602 (a, b) => Ok(primitive_equals(a, b)?),
511 }603 }
512}604}
513605
addedcrates/jrsonnet-interner/.gitignorediffbeforeafterboth

no changes

addedcrates/jrsonnet-interner/Cargo.tomldiffbeforeafterboth

no changes

addedcrates/jrsonnet-interner/src/lib.rsdiffbeforeafterboth

no changes

modifiedcrates/jrsonnet-parser/Cargo.tomldiffbeforeafterboth
10default = []10default = []
11serialize = ["serde"]11serialize = ["serde"]
12deserialize = ["serde"]12deserialize = ["serde"]
13# Adds ability to dump AST as source code for easy embedding
14dump = ["structdump", "structdump-derive"]
1513
16[dependencies]14[dependencies]
15jrsonnet-interner = { path = "../jrsonnet-interner" }
16
17peg = "0.6.3"17peg = "0.6.3"
18unescape = "0.1.0"18unescape = "0.1.0"
1919
20serde = { version = "1.0", features = ["derive", "rc"], optional = true }20serde = { version = "1.0", features = ["derive", "rc"], optional = true }
21structdump = { version = "0.1.2", optional = true }
22structdump-derive = { version = "0.1.2", optional = true }
2321
24[dev-dependencies]22[dev-dependencies]
25jrsonnet-stdlib = { path = "../jrsonnet-stdlib", version = "0.3.3" }23jrsonnet-stdlib = { path = "../jrsonnet-stdlib", version = "0.3.3" }
modifiedcrates/jrsonnet-parser/src/expr.rsdiffbeforeafterboth
1use jrsonnet_interner::IStr;
1#[cfg(feature = "deserialize")]2#[cfg(feature = "deserialize")]
2use serde::Deserialize;3use serde::Deserialize;
3#[cfg(feature = "serialize")]4#[cfg(feature = "serialize")]
8 path::PathBuf,9 path::PathBuf,
9 rc::Rc,10 rc::Rc,
10};11};
11#[cfg(feature = "dump")]12
12use structdump_derive::Codegen;
13
14#[cfg_attr(feature = "dump", derive(Codegen))]
15#[cfg_attr(feature = "serialize", derive(Serialize))]13#[cfg_attr(feature = "serialize", derive(Serialize))]
16#[cfg_attr(feature = "deserialize", derive(Deserialize))]14#[cfg_attr(feature = "deserialize", derive(Deserialize))]
17#[derive(Debug, PartialEq)]15#[derive(Debug, PartialEq)]
18pub enum FieldName {16pub enum FieldName {
19 /// {fixed: 2}17 /// {fixed: 2}
20 Fixed(Rc<str>),18 Fixed(IStr),
21 /// {["dyn"+"amic"]: 3}19 /// {["dyn"+"amic"]: 3}
22 Dyn(LocExpr),20 Dyn(LocExpr),
23}21}
2422
25#[cfg_attr(feature = "dump", derive(Codegen))]
26#[cfg_attr(feature = "serialize", derive(Serialize))]23#[cfg_attr(feature = "serialize", derive(Serialize))]
27#[cfg_attr(feature = "deserialize", derive(Deserialize))]24#[cfg_attr(feature = "deserialize", derive(Deserialize))]
28#[derive(Debug, Clone, Copy, PartialEq)]25#[derive(Debug, Clone, Copy, PartialEq)]
35 Unhide,32 Unhide,
36}33}
3734
38#[cfg_attr(feature = "dump", derive(Codegen))]
39#[cfg_attr(feature = "serialize", derive(Serialize))]35#[cfg_attr(feature = "serialize", derive(Serialize))]
40#[cfg_attr(feature = "deserialize", derive(Deserialize))]36#[cfg_attr(feature = "deserialize", derive(Deserialize))]
41#[derive(Debug, PartialEq)]37#[derive(Debug, PartialEq)]
42pub struct AssertStmt(pub LocExpr, pub Option<LocExpr>);38pub struct AssertStmt(pub LocExpr, pub Option<LocExpr>);
4339
44#[cfg_attr(feature = "dump", derive(Codegen))]
45#[cfg_attr(feature = "serialize", derive(Serialize))]40#[cfg_attr(feature = "serialize", derive(Serialize))]
46#[cfg_attr(feature = "deserialize", derive(Deserialize))]41#[cfg_attr(feature = "deserialize", derive(Deserialize))]
47#[derive(Debug, PartialEq)]42#[derive(Debug, PartialEq)]
53 pub value: LocExpr,48 pub value: LocExpr,
54}49}
5550
56#[cfg_attr(feature = "dump", derive(Codegen))]
57#[cfg_attr(feature = "serialize", derive(Serialize))]51#[cfg_attr(feature = "serialize", derive(Serialize))]
58#[cfg_attr(feature = "deserialize", derive(Deserialize))]52#[cfg_attr(feature = "deserialize", derive(Deserialize))]
59#[derive(Debug, PartialEq)]53#[derive(Debug, PartialEq)]
63 AssertStmt(AssertStmt),57 AssertStmt(AssertStmt),
64}58}
6559
66#[cfg_attr(feature = "dump", derive(Codegen))]
67#[cfg_attr(feature = "serialize", derive(Serialize))]60#[cfg_attr(feature = "serialize", derive(Serialize))]
68#[cfg_attr(feature = "deserialize", derive(Deserialize))]61#[cfg_attr(feature = "deserialize", derive(Deserialize))]
69#[derive(Debug, Clone, Copy, PartialEq)]62#[derive(Debug, Clone, Copy, PartialEq)]
89 }82 }
90}83}
9184
92#[cfg_attr(feature = "dump", derive(Codegen))]
93#[cfg_attr(feature = "serialize", derive(Serialize))]85#[cfg_attr(feature = "serialize", derive(Serialize))]
94#[cfg_attr(feature = "deserialize", derive(Deserialize))]86#[cfg_attr(feature = "deserialize", derive(Deserialize))]
95#[derive(Debug, Clone, Copy, PartialEq)]87#[derive(Debug, Clone, Copy, PartialEq)]
96pub enum BinaryOpType {88pub enum BinaryOpType {
97 Mul,89 Mul,
98 Div,90 Div,
9991
92 /// Implemented as intrinsic, put here for completeness
100 Mod,93 Mod,
10194
102 Add,95 Add,
146}139}
147140
148/// name, default value141/// name, default value
149#[cfg_attr(feature = "dump", derive(Codegen))]
150#[cfg_attr(feature = "serialize", derive(Serialize))]142#[cfg_attr(feature = "serialize", derive(Serialize))]
151#[cfg_attr(feature = "deserialize", derive(Deserialize))]143#[cfg_attr(feature = "deserialize", derive(Deserialize))]
152#[derive(Debug, PartialEq)]144#[derive(Debug, PartialEq)]
153pub struct Param(pub Rc<str>, pub Option<LocExpr>);145pub struct Param(pub IStr, pub Option<LocExpr>);
154146
155/// Defined function parameters147/// Defined function parameters
156#[cfg_attr(feature = "dump", derive(Codegen))]
157#[cfg_attr(feature = "serialize", derive(Serialize))]148#[cfg_attr(feature = "serialize", derive(Serialize))]
158#[cfg_attr(feature = "deserialize", derive(Deserialize))]149#[cfg_attr(feature = "deserialize", derive(Deserialize))]
159#[derive(Debug, Clone, PartialEq)]150#[derive(Debug, Clone, PartialEq)]
165 }156 }
166}157}
167158
168#[cfg_attr(feature = "dump", derive(Codegen))]
169#[cfg_attr(feature = "serialize", derive(Serialize))]159#[cfg_attr(feature = "serialize", derive(Serialize))]
170#[cfg_attr(feature = "deserialize", derive(Deserialize))]160#[cfg_attr(feature = "deserialize", derive(Deserialize))]
171#[derive(Debug, PartialEq)]161#[derive(Debug, PartialEq)]
172pub struct Arg(pub Option<String>, pub LocExpr);162pub struct Arg(pub Option<String>, pub LocExpr);
173163
174#[cfg_attr(feature = "dump", derive(Codegen))]
175#[cfg_attr(feature = "serialize", derive(Serialize))]164#[cfg_attr(feature = "serialize", derive(Serialize))]
176#[cfg_attr(feature = "deserialize", derive(Deserialize))]165#[cfg_attr(feature = "deserialize", derive(Deserialize))]
177#[derive(Debug, PartialEq)]166#[derive(Debug, PartialEq)]
183 }172 }
184}173}
185174
186#[cfg_attr(feature = "dump", derive(Codegen))]
187#[cfg_attr(feature = "serialize", derive(Serialize))]175#[cfg_attr(feature = "serialize", derive(Serialize))]
188#[cfg_attr(feature = "deserialize", derive(Deserialize))]176#[cfg_attr(feature = "deserialize", derive(Deserialize))]
189#[derive(Debug, Clone, PartialEq)]177#[derive(Debug, Clone, PartialEq)]
190pub struct BindSpec {178pub struct BindSpec {
191 pub name: Rc<str>,179 pub name: IStr,
192 pub params: Option<ParamsDesc>,180 pub params: Option<ParamsDesc>,
193 pub value: LocExpr,181 pub value: LocExpr,
194}182}
195183
196#[cfg_attr(feature = "dump", derive(Codegen))]
197#[cfg_attr(feature = "serialize", derive(Serialize))]184#[cfg_attr(feature = "serialize", derive(Serialize))]
198#[cfg_attr(feature = "deserialize", derive(Deserialize))]185#[cfg_attr(feature = "deserialize", derive(Deserialize))]
199#[derive(Debug, PartialEq)]186#[derive(Debug, PartialEq)]
200pub struct IfSpecData(pub LocExpr);187pub struct IfSpecData(pub LocExpr);
201188
202#[cfg_attr(feature = "dump", derive(Codegen))]
203#[cfg_attr(feature = "serialize", derive(Serialize))]189#[cfg_attr(feature = "serialize", derive(Serialize))]
204#[cfg_attr(feature = "deserialize", derive(Deserialize))]190#[cfg_attr(feature = "deserialize", derive(Deserialize))]
205#[derive(Debug, PartialEq)]191#[derive(Debug, PartialEq)]
206pub struct ForSpecData(pub Rc<str>, pub LocExpr);192pub struct ForSpecData(pub IStr, pub LocExpr);
207193
208#[cfg_attr(feature = "dump", derive(Codegen))]
209#[cfg_attr(feature = "serialize", derive(Serialize))]194#[cfg_attr(feature = "serialize", derive(Serialize))]
210#[cfg_attr(feature = "deserialize", derive(Deserialize))]195#[cfg_attr(feature = "deserialize", derive(Deserialize))]
211#[derive(Debug, PartialEq)]196#[derive(Debug, PartialEq)]
214 ForSpec(ForSpecData),199 ForSpec(ForSpecData),
215}200}
216201
217#[cfg_attr(feature = "dump", derive(Codegen))]
218#[cfg_attr(feature = "serialize", derive(Serialize))]202#[cfg_attr(feature = "serialize", derive(Serialize))]
219#[cfg_attr(feature = "deserialize", derive(Deserialize))]203#[cfg_attr(feature = "deserialize", derive(Deserialize))]
220#[derive(Debug, PartialEq)]204#[derive(Debug, PartialEq)]
226 pub compspecs: Vec<CompSpec>,210 pub compspecs: Vec<CompSpec>,
227}211}
228212
229#[cfg_attr(feature = "dump", derive(Codegen))]
230#[cfg_attr(feature = "serialize", derive(Serialize))]213#[cfg_attr(feature = "serialize", derive(Serialize))]
231#[cfg_attr(feature = "deserialize", derive(Deserialize))]214#[cfg_attr(feature = "deserialize", derive(Deserialize))]
232#[derive(Debug, PartialEq)]215#[derive(Debug, PartialEq)]
235 ObjComp(ObjComp),218 ObjComp(ObjComp),
236}219}
237220
238#[cfg_attr(feature = "dump", derive(Codegen))]
239#[cfg_attr(feature = "serialize", derive(Serialize))]221#[cfg_attr(feature = "serialize", derive(Serialize))]
240#[cfg_attr(feature = "deserialize", derive(Deserialize))]222#[cfg_attr(feature = "deserialize", derive(Deserialize))]
241#[derive(Debug, PartialEq, Clone, Copy)]223#[derive(Debug, PartialEq, Clone, Copy)]
256}238}
257239
258/// Syntax base240/// Syntax base
259#[cfg_attr(feature = "dump", derive(Codegen))]
260#[cfg_attr(feature = "serialize", derive(Serialize))]241#[cfg_attr(feature = "serialize", derive(Serialize))]
261#[cfg_attr(feature = "deserialize", derive(Deserialize))]242#[cfg_attr(feature = "deserialize", derive(Deserialize))]
262#[derive(Debug, PartialEq)]243#[derive(Debug, PartialEq)]
263pub enum Expr {244pub enum Expr {
264 Literal(LiteralType),245 Literal(LiteralType),
265246
266 /// String value: "hello"247 /// String value: "hello"
267 Str(Rc<str>),248 Str(IStr),
268 /// Number: 1, 2.0, 2e+20249 /// Number: 1, 2.0, 2e+20
269 Num(f64),250 Num(f64),
270 /// Variable name: test251 /// Variable name: test
271 Var(Rc<str>),252 Var(IStr),
272253
273 /// Array of expressions: [1, 2, "Hello"]254 /// Array of expressions: [1, 2, "Hello"]
274 Arr(Vec<LocExpr>),255 Arr(Vec<LocExpr>),
315 /// function(x) x296 /// function(x) x
316 Function(ParamsDesc, LocExpr),297 Function(ParamsDesc, LocExpr),
317 /// std.primitiveEquals298 /// std.primitiveEquals
318 Intrinsic(Rc<str>),299 Intrinsic(IStr),
319 /// if true == false then 1 else 2300 /// if true == false then 1 else 2
320 IfElse {301 IfElse {
321 cond: IfSpecData,302 cond: IfSpecData,
325}306}
326307
327/// file, begin offset, end offset308/// file, begin offset, end offset
328#[cfg_attr(feature = "dump", derive(Codegen))]
329#[cfg_attr(feature = "serialize", derive(Serialize))]309#[cfg_attr(feature = "serialize", derive(Serialize))]
330#[cfg_attr(feature = "deserialize", derive(Deserialize))]310#[cfg_attr(feature = "deserialize", derive(Deserialize))]
331#[derive(Clone, PartialEq)]311#[derive(Clone, PartialEq)]
337}317}
338318
339/// Holds AST expression and its location in source file319/// Holds AST expression and its location in source file
340#[cfg_attr(feature = "dump", derive(Codegen))]
341#[cfg_attr(feature = "serialize", derive(Serialize))]320#[cfg_attr(feature = "serialize", derive(Serialize))]
342#[cfg_attr(feature = "deserialize", derive(Deserialize))]321#[cfg_attr(feature = "deserialize", derive(Deserialize))]
343#[derive(Clone, PartialEq)]322#[derive(Clone, PartialEq)]
addedcrates/jrsonnet-types/Cargo.tomldiffbeforeafterboth

no changes

addedcrates/jrsonnet-types/src/lib.rsdiffbeforeafterboth

no changes