difftreelog
Merge pull request #29 from CertainLach/type-safety
in: master
Jsonnet type system
36 files changed
Cargo.lockdiffbeforeafterboth167 "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]181182[[package]]183name = "jrsonnet-interner"184version = "0.3.3"185dependencies = [186 "rustc-hash",187 "serde",188]180189181[[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]192200193[[package]]201[[package]]194name = "jrsonnet-stdlib"202name = "jrsonnet-stdlib"195version = "0.3.3"203version = "0.3.3"204205[[package]]206name = "jrsonnet-types"207version = "0.3.3"208dependencies = [209 "peg",210]196211197[[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]204220371source = "registry+https://github.com/rust-lang/crates.io-index"387source = "registry+https://github.com/rust-lang/crates.io-index"372checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"388checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"373374[[package]]375name = "structdump"376version = "0.1.2"377source = "registry+https://github.com/rust-lang/crates.io-index"378checksum = "2e16ec33a0342fdb67d13913b4ffae6527ebccfa04b5d7da174bdc7a31db29b8"379380[[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]390389391[[package]]390[[package]]392name = "syn"391name = "syn"Cargo.tomldiffbeforeafterboth1[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]101211[profile.test]13[profile.test]bindings/jsonnet/Cargo.tomldiffbeforeafterboth5edition = "2018"5edition = "2018"667[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" }1011bindings/jsonnet/src/import.rsdiffbeforeafterboth4 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,323333 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>> {757676 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)bindings/jsonnet/src/lib.rsdiffbeforeafterboth889use 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}163164164fn 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}239240240fn 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 {bindings/jsonnet/src/native.rsdiffbeforeafterboth353536 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())));bindings/jsonnet/src/val_extract.rsdiffbeforeafterboth9910#[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 127 }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 }bindings/jsonnet/src/val_make.rsdiffbeforeafterboth1//! Create values in VM1//! Create values in VM223use 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},383839#[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}434344#[no_mangle]44#[no_mangle]bindings/jsonnet/src/val_modify.rsdiffbeforeafterboth3//! In jrsonnet every value is immutable, and this code is probally broken3//! In jrsonnet every value is immutable, and this code is probally broken445use 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 }crates/jrsonnet-evaluator/Cargo.tomldiffbeforeafterboth12serialized-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 backwards14serde-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 time16codegenerated-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 calls19faster = []17faster = []24unstable = []22unstable = []252326[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"303031closure = "0.3.0"31closure = "0.3.0"57optional = true57optional = true585859[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"6564crates/jrsonnet-evaluator/build.rsdiffbeforeafterboth10 path::{Path, PathBuf},10 path::{Path, PathBuf},11 rc::Rc,11 rc::Rc,12};12};13use structdump::CodegenResult;141315fn 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 parsed54 };54 };55 {56 let mut codegen = CodegenResult::default();57 let code = codegen.codegen(&parsed);5859 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");crates/jrsonnet-evaluator/src/builtin/format.rsdiffbeforeafterboth1//! faster std.format impl1//! faster std.format impl2#![allow(clippy::too_many_arguments)]2#![allow(clippy::too_many_arguments)]334use 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;687#[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}242625impl From<FormatError> for LocError {27impl From<FormatError> for LocError {28 }30 }29}31}303231use std::rc::Rc;32use FormatError::*;33use FormatError::*;333434type 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 ref682 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);crates/jrsonnet-evaluator/src/builtin/manifest.rsdiffbeforeafterboth33) -> 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);6969118 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}crates/jrsonnet-evaluator/src/builtin/mod.rsdiffbeforeafterboth1use 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};111212pub mod stdlib;13pub mod stdlib;13pub use stdlib::*;14pub use stdlib::*;141516use self::manifest::{escape_string_json, manifest_json_ex, ManifestJsonOptions, ManifestType};1715pub mod format;18pub mod format;16pub mod manifest;19pub mod manifest;17pub mod sort;20pub mod sort;182119fn 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}323533#[allow(clippy::cognitive_complexity)]36type Builtin = fn(context: Context, loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val>;34pub fn call_builtin(3738type BuiltinsType = HashMap<Box<str>, Builtin>;3940thread_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}7980fn 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}9798fn 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}105106fn 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!(),12555 })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];13767 ], {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,15686 "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, includeHidden104 "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}116175117 // faster176// faster118 "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 // faster160 "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 func231 .evaluate_values(context.clone(), &[e.clone()])232 .unwrap()233 .try_cast_bool("filter predicate")234 .unwrap()235 })236 .collect(),237 )))238 })?,239 // faster240 "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 // faster252 "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 // faster264 #[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 // faster275 "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 // faster282 "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 // faster315 "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 // faster331 "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();338214339 let mut first = true;215// faster340 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}228229// faster230fn 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}238239fn 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}247248fn 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}260261fn 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}268269fn 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}276277fn 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}285286fn 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}293294fn 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}301302fn 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 func311 .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}319320fn 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}333334fn 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}347348#[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}364365// faster366fn 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}374375fn 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}390391fn 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}402403fn 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}414415fn 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}422423fn 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}439440fn 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}457458fn 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();466467 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: extend474 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: extend481 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 }353488354 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();358493359 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 }371507372 Val::Str(out.into())508 Val::Str(out.into())373 },509 },374 _ => unreachable!()510 _ => unreachable!()375 })511 })376 })?,377 // Faster378 "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 // Faster384 "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 // Faster394 "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}514515// faster516fn 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}527528// faster529fn 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}544545// faster546fn 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}553554fn 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}561562// faster563fn 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}587588pub 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}409599crates/jrsonnet-evaluator/src/builtin/sort.rsdiffbeforeafterboth46 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,crates/jrsonnet-evaluator/src/ctx.rsdiffbeforeafterboth2 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 }596060 pub fn binding(&self, name: Rc<str>) -> Result<LazyVal> {61 pub fn binding(&self, name: IStr) -> Result<LazyVal> {61 Ok(self62 Ok(self62 .063 .063 .bindings64 .bindings72 ctx.unwrap()73 ctx.unwrap()73 }74 }747575 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));818282 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>,crates/jrsonnet-evaluator/src/error.rsdiffbeforeafterboth1use 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;8109#[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,151732 ArrayBoundsError(usize, usize),34 ArrayBoundsError(usize, usize),333534 #[error("assert failed: {0}")]36 #[error("assert failed: {0}")]35 AssertionFailed(Rc<str>),37 AssertionFailed(IStr),363837 #[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),434544 #[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),545655 #[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),596160 #[error("field name should be string, got {0}")]62 #[error("field name should be string, got {0}")]61 FieldMustBeStringGot(ValType),63 FieldMustBeStringGot(ValType),626463 #[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 },919392 #[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")]117119118 #[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}128132129#[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).0146 }150 }151 pub fn error_mut(&mut self) -> &mut Error {152 &mut (self.0).0153 }147 pub const fn trace(&self) -> &StackTrace {154 pub const fn trace(&self) -> &StackTrace {148 &(self.0).1155 &(self.0).1149 }156 }crates/jrsonnet-evaluator/src/evaluate.rsdiffbeforeafterboth1use 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};141515pub 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}474848pub 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 None68 } else {68 } else {747475pub 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}848394 (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()),959496 (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}177177178 _ => 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}185185186future_wrapper!(HashMap<Rc<str>, LazyBinding>, FutureNewBindings);186future_wrapper!(HashMap<IStr, LazyBinding>, FutureNewBindings);187future_wrapper!(ObjValue, FutureObjValue);187future_wrapper!(ObjValue, FutureObjValue);188188189pub fn evaluate_comp<T>(189pub fn evaluate_comp<T>(200 None200 None201 }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}222219234 })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 members239 .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 obj343 .pre_locals340 .pre_locals344 .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 }381378388 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}408404409pub 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 context444 .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 )),476469477 (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 )),492483493 (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 )),505496506 (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();512503513 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 here542 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 )?crates/jrsonnet-evaluator/src/function.rsdiffbeforeafterboth1use 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};677const 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};150149 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 v173 } 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}183184#[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}207181crates/jrsonnet-evaluator/src/import.rsdiffbeforeafterboth3 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>>;161717 /// 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>;192020 /// # Safety21 /// # Safety21 ///22 ///32 throw!(ImportNotSupported(from.clone(), path.clone()))33 throw!(ImportNotSupported(from.clone(), path.clone()))33 }34 }343535 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 jsonnet37 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 resolver90pub 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 }103104104 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_cache106 .borrow_mut()107 .borrow_mut()107 .entry(resolved.clone())108 .entry(resolved.clone())crates/jrsonnet-evaluator/src/integrations/serde.rsdiffbeforeafterboth22 } 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());crates/jrsonnet-evaluator/src/lib.rsdiffbeforeafterboth14pub mod native;14pub mod native;15mod obj;15mod obj;16pub mod trace;16pub mod trace;17pub mod typed;17mod val;18mod val;181919pub 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 preserved63 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.native67 pub ext_natives: HashMap<Rc<str>, Rc<NativeCallback>>,69 pub ext_natives: HashMap<IStr, Rc<NativeCallback>>,68 /// TLA vars70 /// TLA vars69 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 context71 pub globals: HashMap<Rc<str>, Val>,73 pub globals: HashMap<IStr, Val>,72 /// Used to resolve file locations/contents74 /// Used to resolve file locations/contents73 pub import_resolver: Box<dyn ImportResolver>,75 pub import_resolver: Box<dyn ImportResolver>,74 /// Used in manifestification functions76 /// Used in manifestification functions101 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 stacktraces103 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}106108107pub 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}137138pub 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}139145140/// Maintains stack trace and import resolution146/// Maintains stack trace and import resolution141#[derive(Default, Clone)]147#[derive(Default, Clone)]142pub struct EvaluationState(Rc<EvaluationStateInternals>);148pub struct EvaluationState(Rc<EvaluationStateInternals>);143149144impl EvaluationState {150impl EvaluationState {145 /// Parses and adds file as loaded151 /// Parses and adds file as loaded146 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(182188183 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 variables257 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 frame270 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 out321 }327 }322328323 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 }332338333 /// If passed value is function then call with set TLA339 /// If passed value is function then call with set TLA334 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 snippet373 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 {390402391/// Settings utilities403/// Settings utilities392impl 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 }405417406 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 }425437430 self.settings_mut().import_resolver = resolver;442 self.settings_mut().import_resolver = resolver;431 }443 }432444433 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 }436448467pub 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};472485477 state.run_in_state(|| {490 state.run_in_state(|| {478 state491 state479 .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 }906933907 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 }912939913 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 }916943crates/jrsonnet-evaluator/src/map.rsdiffbeforeafterboth1use jrsonnet_interner::IStr;1use rustc_hash::FxHashMap;2use rustc_hash::FxHashMap;2use std::{borrow::Borrow, hash::Hash, rc::Rc};3use std::rc::Rc;344#[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}91010#[derive(Debug)]11#[derive(Debug)]11pub struct LayeredHashMap<K: Hash, V>(Rc<LayeredHashMapInternals<K, V>>);12pub struct LayeredHashMap<V>(Rc<LayeredHashMapInternals<V>>);121313impl<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 }262727 pub fn get<Q: ?Sized>(&self, key: &Q) -> Option<&V>28 pub fn get(&self, key: &IStr) -> Option<&V> {28 where29 K: Borrow<Q>,30 Q: Hash + Eq,31 {32 (self.0)29 (self.0)33 .current30 .current36 }33 }37}34}383539impl<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}444145impl<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,crates/jrsonnet-evaluator/src/native.rsdiffbeforeafterboth1#![allow(clippy::type_complexity)]21use 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;485pub 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 {crates/jrsonnet-evaluator/src/obj.rsdiffbeforeafterboth1use 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};5612}13}131414// Field => This15// Field => This15type 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}484949impl 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<_> = self96 .fields_visibility()97 .fields_visibility()97 .into_iter()98 .into_iter()101 visible_fields.sort();102 visible_fields.sort();102 visible_fields103 visible_fields103 }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);109111110 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.0138 .evaluate()?)140 .evaluate()?)139 }141 }142143 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 {crates/jrsonnet-evaluator/src/trace/location.rsdiffbeforeafterboth40 for (pos, ch) in file.chars().enumerate() {40 for (pos, ch) in file41 .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() {crates/jrsonnet-evaluator/src/trace/mod.rsdiffbeforeafterboth65 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.column71 )?;71 )?;118 .trace()118 .trace()119 .0119 .0120 .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 first124 let location = evaluation_state125 .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 first126 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_path133 })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_names134 .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 = align165 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]);170174176 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 }crates/jrsonnet-evaluator/src/typed.rsdiffbeforeafterbothno changes
crates/jrsonnet-evaluator/src/val.rsdiffbeforeafterboth9 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};191620enum LazyValInternals {17enum LazyValInternals {656266#[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 jsonnet77 Normal(FuncDesc),74 Normal(FuncDesc),78 /// Standard library function75 /// Standard library function79 Intrinsic(Rc<str>),76 Intrinsic(IStr),80 /// Library functions implemented in native77 /// Library functions implemented in native81 NativeExt(Rc<str>, Rc<NativeCallback>),78 NativeExt(IStr, Rc<NativeCallback>),82}79}838084impl 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 }134131135 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}168169#[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}198165199#[derive(Clone)]166#[derive(Clone)]200pub enum ManifestFormat {167pub enum ManifestFormat {205 String,172 String,206}173}174175#[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 }185186 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 }193194 pub fn is_empty(&self) -> bool {195 self.len() == 0196 }197198 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 }218219 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 }233234 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 }253254 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 }261262 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 }269270 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 }285286 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}294295impl From<Vec<LazyVal>> for ArrValue {296 fn from(v: Vec<LazyVal>) -> Self {297 Self::Lazy(Rc::new(v))298 }299}300301impl From<Vec<Val>> for ArrValue {302 fn from(v: Vec<Val>) -> Self {303 Self::Eager(Rc::new(v))304 }305}207306208#[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 }238336239 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 }284374285 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 }301391302 /// Expects value to be object, outputs (key, manifested value) pairs392 /// Expects value to be object, outputs (key, manifested value) pairs303 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 }319409320 /// Expects value to be array, outputs manifested values410 /// Expects value to be array, outputs manifested values321 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 }332422333 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 }368458369 /// For manifestification459 /// For manifestification370 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 = s425 .create_default_context()?515 .create_default_context()?456546457/// 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,476566477/// 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()?;481482 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 evaluated487 (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}513605crates/jrsonnet-interner/.gitignorediffbeforeafterbothno changes
crates/jrsonnet-interner/Cargo.tomldiffbeforeafterbothno changes
crates/jrsonnet-interner/src/lib.rsdiffbeforeafterbothno changes
crates/jrsonnet-parser/Cargo.tomldiffbeforeafterboth10default = []10default = []11serialize = ["serde"]11serialize = ["serde"]12deserialize = ["serde"]12deserialize = ["serde"]13# Adds ability to dump AST as source code for easy embedding14dump = ["structdump", "structdump-derive"]151316[dependencies]14[dependencies]15jrsonnet-interner = { path = "../jrsonnet-interner" }1617peg = "0.6.3"17peg = "0.6.3"18unescape = "0.1.0"18unescape = "0.1.0"191920serde = { 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 }232124[dev-dependencies]22[dev-dependencies]25jrsonnet-stdlib = { path = "../jrsonnet-stdlib", version = "0.3.3" }23jrsonnet-stdlib = { path = "../jrsonnet-stdlib", version = "0.3.3" }crates/jrsonnet-parser/src/expr.rsdiffbeforeafterboth1use 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")]1212use structdump_derive::Codegen;1314#[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}242225#[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}373438#[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>);433944#[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}555056#[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}655966#[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}918492#[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,999192 /// Implemented as intrinsic, put here for completeness100 Mod,93 Mod,10194102 Add,95 Add,146}139}147140148/// name, default value141/// name, default value149#[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>);154146155/// Defined function parameters147/// Defined function parameters156#[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}167158168#[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);173163174#[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}185174186#[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}195183196#[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);201188202#[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);207193208#[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}216201217#[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}228212229#[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}237220238#[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}257239258/// Syntax base240/// Syntax base259#[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),265246266 /// 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+20269 Num(f64),250 Num(f64),270 /// Variable name: test251 /// Variable name: test271 Var(Rc<str>),252 Var(IStr),272253273 /// 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) x316 Function(ParamsDesc, LocExpr),297 Function(ParamsDesc, LocExpr),317 /// std.primitiveEquals298 /// std.primitiveEquals318 Intrinsic(Rc<str>),299 Intrinsic(IStr),319 /// if true == false then 1 else 2300 /// if true == false then 1 else 2320 IfElse {301 IfElse {321 cond: IfSpecData,302 cond: IfSpecData,325}306}326307327/// file, begin offset, end offset308/// file, begin offset, end offset328#[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}338318339/// Holds AST expression and its location in source file319/// Holds AST expression and its location in source file340#[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)]crates/jrsonnet-types/Cargo.tomldiffbeforeafterbothno changes
crates/jrsonnet-types/src/lib.rsdiffbeforeafterbothno changes