difftreelog
Merge pull request #45 from CertainLach/gc-v2
in: master
Implement tracing Gc with rust-gc
35 files changed
Cargo.lockdiffbeforeafterboth99 "clap",99 "clap",100]100]101102[[package]]103name = "closure"104version = "0.3.0"105source = "registry+https://github.com/rust-lang/crates.io-index"106checksum = "d6173fd61b610d15a7566dd7b7620775627441c4ab9dac8906e17cb93a24b782"107101108[[package]]102[[package]]109name = "hashbrown"103name = "hashbrown"164dependencies = [158dependencies = [165 "clap",159 "clap",166 "jrsonnet-evaluator",160 "jrsonnet-evaluator",161 "jrsonnet-gc",167 "jrsonnet-parser",162 "jrsonnet-parser",168]163]169164175 "anyhow",170 "anyhow",176 "base64",171 "base64",177 "bincode",172 "bincode",178 "closure",173 "jrsonnet-gc",179 "jrsonnet-interner",174 "jrsonnet-interner",180 "jrsonnet-parser",175 "jrsonnet-parser",181 "jrsonnet-stdlib",176 "jrsonnet-stdlib",188 "thiserror",183 "thiserror",189]184]185186[[package]]187name = "jrsonnet-gc"188version = "0.4.2"189source = "registry+https://github.com/rust-lang/crates.io-index"190checksum = "68da8bc2f00117b1373bb8877af03b1d391e4c4800e6585d7279e5b99c919dde"191dependencies = [192 "jrsonnet-gc-derive",193]194195[[package]]196name = "jrsonnet-gc-derive"197version = "0.4.1"198source = "registry+https://github.com/rust-lang/crates.io-index"199checksum = "adcba9c387b64b054f06cc4d724905296e21edeeb7506847f3299117a2d92d12"200dependencies = [201 "proc-macro2",202 "quote",203 "syn",204 "synstructure",205]190206191[[package]]207[[package]]192name = "jrsonnet-interner"208name = "jrsonnet-interner"193version = "0.3.8"209version = "0.3.8"194dependencies = [210dependencies = [211 "jrsonnet-gc",195 "rustc-hash",212 "rustc-hash",196 "serde",213 "serde",197]214]200name = "jrsonnet-parser"217name = "jrsonnet-parser"201version = "0.3.8"218version = "0.3.8"202dependencies = [219dependencies = [220 "jrsonnet-gc",203 "jrsonnet-interner",221 "jrsonnet-interner",204 "jrsonnet-stdlib",222 "jrsonnet-stdlib",205 "peg",223 "peg",215name = "jrsonnet-types"233name = "jrsonnet-types"216version = "0.3.8"234version = "0.3.8"217dependencies = [235dependencies = [236 "jrsonnet-gc",218 "peg",237 "peg",219]238]220239223version = "0.3.8"242version = "0.3.8"224dependencies = [243dependencies = [225 "jrsonnet-evaluator",244 "jrsonnet-evaluator",245 "jrsonnet-gc",226 "jrsonnet-parser",246 "jrsonnet-parser",227]247]228248404 "unicode-xid",424 "unicode-xid",405]425]426427[[package]]428name = "synstructure"429version = "0.12.4"430source = "registry+https://github.com/rust-lang/crates.io-index"431checksum = "b834f2d66f734cb897113e34aaff2f1ab4719ca946f9a7358dba8f8064148701"432dependencies = [433 "proc-macro2",434 "quote",435 "syn",436 "unicode-xid",437]406438407[[package]]439[[package]]408name = "termcolor"440name = "termcolor"bindings/jsonnet/Cargo.tomldiffbeforeafterboth10[dependencies]10[dependencies]11jrsonnet-evaluator = { path = "../../crates/jrsonnet-evaluator", version = "0.3.8" }11jrsonnet-evaluator = { path = "../../crates/jrsonnet-evaluator", version = "0.3.8" }12jrsonnet-parser = { path = "../../crates/jrsonnet-parser", version = "0.3.8" }12jrsonnet-parser = { path = "../../crates/jrsonnet-parser", version = "0.3.8" }13jrsonnet-gc = { version = "0.4.2", features = ["derive"] }131414[lib]15[lib]15crate-type = ["cdylib"]16crate-type = ["cdylib"]bindings/jsonnet/src/native.rsdiffbeforeafterboth1use jrsonnet_evaluator::{error::Error, native::NativeCallback, EvaluationState, Val};1use jrsonnet_evaluator::{2 error::{Error, LocError},3 native::{NativeCallback, NativeCallbackHandler},4 EvaluationState, Val,5};6use jrsonnet_gc::{unsafe_empty_trace, Finalize, Gc, Trace};2use jrsonnet_parser::{Param, ParamsDesc};7use jrsonnet_parser::{Param, ParamsDesc};3use std::{8use std::{4 ffi::{c_void, CStr},9 ffi::{c_void, CStr},5 os::raw::{c_char, c_int},10 os::raw::{c_char, c_int},11 path::Path,6 rc::Rc,12 rc::Rc,7};13};81412 success: *mut c_int,18 success: *mut c_int,13) -> *mut Val;19) -> *mut Val;2021struct JsonnetNativeCallbackHandler {22 ctx: *const c_void,23 cb: JsonnetNativeCallback,24}25impl Finalize for JsonnetNativeCallbackHandler {}26unsafe impl Trace for JsonnetNativeCallbackHandler {27 unsafe_empty_trace!();28}29impl NativeCallbackHandler for JsonnetNativeCallbackHandler {30 fn call(&self, _from: Option<Rc<Path>>, args: &[Val]) -> Result<Val, LocError> {31 let mut n_args = Vec::new();32 for a in args {33 n_args.push(Some(Box::new(a.clone())));34 }35 n_args.push(None);36 let mut success = 1;37 let v = unsafe {38 (self.cb)(39 self.ctx,40 &n_args as *const _ as *const *const Val,41 &mut success,42 )43 };44 let v = unsafe { *Box::from_raw(v) };45 if success == 1 {46 Ok(v)47 } else {48 let e = v.try_cast_str("native error").expect("error msg");49 Err(Error::RuntimeError(e).into())50 }51 }52}145315/// # Safety54/// # Safety16#[no_mangle]55#[no_mangle]357436 vm.add_native(75 vm.add_native(37 name,76 name,38 Rc::new(NativeCallback::new(params, move |_caller, args| {77 Gc::new(NativeCallback::new(39 let mut n_args = Vec::new();78 params,40 for a in args {41 n_args.push(Some(Box::new(a.clone())));79 Box::new(JsonnetNativeCallbackHandler { ctx, cb }),42 }43 n_args.push(None);44 let mut success = 1;45 let v = cb(ctx, &n_args as *const _ as *const *const Val, &mut success);46 let v = *Box::from_raw(v);47 if success == 1 {48 Ok(v)49 } else {50 let e = v.try_cast_str("native error").expect("error msg");51 Err(Error::RuntimeError(e).into())52 }53 })),80 )),54 )81 )55}82}5683bindings/jsonnet/src/val_make.rsdiffbeforeafterboth1//! Create values in VM1//! Create values in VM223use jrsonnet_evaluator::{ArrValue, EvaluationState, ObjValue, Val};3use jrsonnet_evaluator::{ArrValue, EvaluationState, ObjValue, Val};4use jrsonnet_gc::Gc;4use std::{5use std::{5 ffi::CStr,6 ffi::CStr,6 os::raw::{c_char, c_double, c_int},7 os::raw::{c_char, c_double, c_int},7 rc::Rc,8};8};9910/// # Safety10/// # Safety383839#[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(ArrValue::Eager(Rc::new(Vec::new())))))41 Box::into_raw(Box::new(Val::Arr(ArrValue::Eager(Gc::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::{ArrValue, EvaluationState, LazyBinding, LazyVal, ObjMember, Val};5use jrsonnet_evaluator::{ArrValue, EvaluationState, LazyBinding, LazyVal, ObjMember, Val};6use jrsonnet_gc::Gc;6use jrsonnet_parser::Visibility;7use jrsonnet_parser::Visibility;7use std::{ffi::CStr, os::raw::c_char, rc::Rc};8use std::{ffi::CStr, os::raw::c_char};899/// # Safety10/// # Safety10///11///22 new.push(item);23 new.push(item);23 }24 }24 new.push(LazyVal::new_resolved(val.clone()));25 new.push(LazyVal::new_resolved(val.clone()));25 *arr = Val::Arr(ArrValue::Lazy(Rc::new(new)));26 *arr = Val::Arr(ArrValue::Lazy(Gc::new(new)));26 }27 }27 _ => panic!("should receive array"),28 _ => panic!("should receive array"),28 }29 }cmds/jrsonnet/Cargo.tomldiffbeforeafterboth8publish = false8publish = false9910[features]10[features]11default = []11default = ["mimalloc"]12# Use mimalloc as allocator12# Use mimalloc as allocator13mimalloc = []13mimalloc = ["mimallocator"]141415[dependencies]15[dependencies]16jrsonnet-evaluator = { path = "../../crates/jrsonnet-evaluator", version = "0.3.8" }16jrsonnet-evaluator = { path = "../../crates/jrsonnet-evaluator", version = "0.3.8" }17jrsonnet-parser = { path = "../../crates/jrsonnet-parser", version = "0.3.8" }17jrsonnet-parser = { path = "../../crates/jrsonnet-parser", version = "0.3.8" }18jrsonnet-cli = { path = "../../crates/jrsonnet-cli", version = "0.3.8" }18jrsonnet-cli = { path = "../../crates/jrsonnet-cli", version = "0.3.8" }19# TODO: Fix mimalloc compile errors, and use them20mimallocator = { version = "0.1.3", optional = true }19mimallocator = { version = "0.1.3", optional = true }21thiserror = "1.0"20thiserror = "1.0"2221cmds/jrsonnet/src/main.rsdiffbeforeafterboth1use clap::{AppSettings, Clap, IntoApp};1use clap::{AppSettings, Clap, IntoApp};2use jrsonnet_cli::{ConfigureState, GeneralOpts, InputOpts, ManifestOpts, OutputOpts};2use jrsonnet_cli::{ConfigureState, GcOpts, GeneralOpts, InputOpts, ManifestOpts, OutputOpts};3use jrsonnet_evaluator::{error::LocError, EvaluationState, ManifestFormat};3use jrsonnet_evaluator::{error::LocError, EvaluationState, ManifestFormat};4use std::{4use std::{5 fs::{create_dir_all, File},5 fs::{create_dir_all, File},61 output: OutputOpts,61 output: OutputOpts,62 #[clap(flatten)]62 #[clap(flatten)]63 debug: DebugOpts,63 debug: DebugOpts,64 #[clap(flatten)]65 gc: GcOpts,64}66}656766fn main() {68fn main() {114}116}115117116fn main_catch(opts: Opts) -> bool {118fn main_catch(opts: Opts) -> bool {119 let _printer = opts.gc.stats_printer();117 let state = EvaluationState::default();120 let state = EvaluationState::default();118 if let Err(e) = main_real(&state, opts) {121 if let Err(e) = main_real(&state, opts) {119 if let Error::Evaluation(e) = e {122 if let Error::Evaluation(e) = e {127}130}128131129fn main_real(state: &EvaluationState, opts: Opts) -> Result<(), Error> {132fn main_real(state: &EvaluationState, opts: Opts) -> Result<(), Error> {133 opts.gc.configure_global();130 opts.general.configure(&state)?;134 opts.general.configure(&state)?;131 opts.manifest.configure(&state)?;135 opts.manifest.configure(&state)?;132136crates/jrsonnet-cli/Cargo.tomldiffbeforeafterboth10[dependencies]10[dependencies]11jrsonnet-evaluator = { path = "../../crates/jrsonnet-evaluator", version = "0.3.6", features = ["explaining-traces"] }11jrsonnet-evaluator = { path = "../../crates/jrsonnet-evaluator", version = "0.3.6", features = ["explaining-traces"] }12jrsonnet-parser = { path = "../../crates/jrsonnet-parser", version = "0.3.6" }12jrsonnet-parser = { path = "../../crates/jrsonnet-parser", version = "0.3.6" }13jrsonnet-gc = { version = "0.4.2", features = ["derive", "unstable-config", "unstable-stats"] }131414[dependencies.clap]15[dependencies.clap]15git = "https://github.com/clap-rs/clap"16git = "https://github.com/clap-rs/clap"crates/jrsonnet-cli/src/lib.rsdiffbeforeafterboth96 }96 }97}97}9899#[derive(Clap)]100#[clap(help_heading = "GARBAGE COLLECTION")]101pub struct GcOpts {102 /// Min bytes allocated to start garbage collection103 #[clap(long, default_value = "20000000")]104 gc_initial_threshold: usize,105 /// How much heap should grow after unsuccessful garbage collection106 #[clap(long)]107 gc_used_space_ratio: Option<f64>,108 /// Do not skip gc on exit109 #[clap(long)]110 gc_collect_on_exit: bool,111 /// Print gc stats before exit112 #[clap(long)]113 gc_print_stats: bool,114 /// Force garbage collection before printing stats115 /// Useful for checking for memory leaks116 /// Does nothing useless --gc-print-stats is specified117 #[clap(long)]118 gc_collect_before_printing_stats: bool,119}120impl GcOpts {121 pub fn stats_printer(&self) -> Option<GcStatsPrinter> {122 self.gc_print_stats123 .then(|| GcStatsPrinter(self.gc_collect_before_printing_stats))124 }125 pub fn configure_global(&self) {126 jrsonnet_gc::configure(|config| {127 config.leak_on_drop = !self.gc_collect_on_exit;128 config.threshold = self.gc_initial_threshold;129 if let Some(used_space_ratio) = self.gc_used_space_ratio {130 config.used_space_ratio = used_space_ratio;131 }132 });133 }134}135pub struct GcStatsPrinter(bool);136impl Drop for GcStatsPrinter {137 fn drop(&mut self) {138 if self.0 {139 jrsonnet_gc::force_collect()140 }141 eprintln!("=== GC STATS ===");142 jrsonnet_gc::configure(|c| {143 eprintln!("Final threshold: {:?}", c.threshold);144 });145 let stats = jrsonnet_gc::stats();146 eprintln!("Collections performed: {}", stats.collections_performed);147 eprintln!("Bytes still allocated: {}", stats.bytes_allocated);148 }149}98150crates/jrsonnet-evaluator/Cargo.tomldiffbeforeafterboth30jrsonnet-types = { path = "../jrsonnet-types", version = "0.3.8" }30jrsonnet-types = { path = "../jrsonnet-types", version = "0.3.8" }31pathdiff = "0.2.0"31pathdiff = "0.2.0"3233closure = "0.3.0"343235md5 = "0.7.0"33md5 = "0.7.0"36base64 = "0.13.0"34base64 = "0.13.0"37rustc-hash = "1.1.0"35rustc-hash = "1.1.0"383639thiserror = "1.0"37thiserror = "1.0"38jrsonnet-gc = { version = "0.4.2", features = ["derive"] }403941[dependencies.anyhow]40[dependencies.anyhow]42version = "1.0"41version = "1.0"crates/jrsonnet-evaluator/README.mddiffbeforeafterboth667jsonnet stdlib is embedded into evaluator, but there is different modes for this:7jsonnet stdlib is embedded into evaluator, but there is different modes for this:889- `codegenerated-stdlib`10 - generates source code for reproducing stdlib AST ([Example](https://gist.githubusercontent.com/CertainLach/7b3149df556f3406f5e9368aaa9f32ec/raw/0c80d8ab9aa7b9288c6219a2779cb2ab37287669/a.rs))11 - fastest on interpretation, slowest on compilation (it takes more than 5 minutes to optimize them by llvm)12- `serialized-stdlib`9- `serialized-stdlib`13 - serializes standard library AST using serde10 - serializes standard library AST using serde14 - slower than `codegenerated-stdlib` at runtime, but have no compilation speed penality11 - slower than `codegenerated-stdlib` at runtime, but have no compilation speed penality23Can also be run via `cargo bench`20Can also be run via `cargo bench`242125```markdown22```markdown26# codegenerated-stdlib27test tests::bench_codegen ... bench: 401,696 ns/iter (+/- 38,521)28# serialized-stdlib23# serialized-stdlib29test tests::bench_serialize ... bench: 1,763,999 ns/iter (+/- 76,211)24test tests::bench_serialize ... bench: 1,763,999 ns/iter (+/- 76,211)30# none25# none34## Intrinsics29## Intrinsics353036Some functions from stdlib are implemented as intrinsics31Some functions from stdlib are implemented as intrinsics3738### Intrinsic handling3940If indexed jsonnet object has field '__intrinsic_namespace__' of type 'string', then any not found field/method is resolved as `Val::Intrinsic(__intrinsic_namespace__, name)`4132crates/jrsonnet-evaluator/src/builtin/format.rsdiffbeforeafterboth2#![allow(clippy::too_many_arguments)]2#![allow(clippy::too_many_arguments)]334use crate::{error::Error::*, throw, LocError, ObjValue, Result, Val};4use crate::{error::Error::*, throw, LocError, ObjValue, Result, Val};5use jrsonnet_gc::Trace;5use jrsonnet_interner::IStr;6use jrsonnet_interner::IStr;6use jrsonnet_types::ValType;7use jrsonnet_types::ValType;7use thiserror::Error;8use thiserror::Error;899#[derive(Debug, Clone, Error)]10#[derive(Debug, Clone, Error, Trace)]11#[trivially_drop]10pub enum FormatError {12pub enum FormatError {11 #[error("truncated format code")]13 #[error("truncated format code")]12 TruncatedFormatCode,14 TruncatedFormatCode,crates/jrsonnet-evaluator/src/builtin/manifest.rsdiffbeforeafterboth126 buf.push('}');126 buf.push('}');127 }127 }128 Val::Func(_) => throw!(RuntimeError("tried to manifest function".into())),128 Val::Func(_) => throw!(RuntimeError("tried to manifest function".into())),129 Val::DebugGcTraceValue(v) => manifest_json_ex_buf(&v.value, buf, cur_padding, options)?,129 };130 };130 Ok(())131 Ok(())131}132}crates/jrsonnet-evaluator/src/builtin/mod.rsdiffbeforeafterboth1use crate::{1use crate::{2 equals,2 equals,3 error::{Error::*, Result},3 error::{Error::*, Result},4 parse_args, primitive_equals, push, throw, with_state, ArrValue, Context, EvaluationState,4 parse_args, primitive_equals, push, throw, with_state, ArrValue, Context, DebugGcTraceValue,5 FuncVal, LazyVal, Val,5 EvaluationState, FuncVal, LazyVal, Val,6};6};7use format::{format_arr, format_obj};7use format::{format_arr, format_obj};8use jrsonnet_gc::Gc;8use jrsonnet_interner::IStr;9use jrsonnet_interner::IStr;9use jrsonnet_parser::{ArgsDesc, BinaryOpType, ExprLocation};10use jrsonnet_parser::{ArgsDesc, BinaryOpType, ExprLocation};10use jrsonnet_types::ty;11use jrsonnet_types::ty;68 ("md5".into(), builtin_md5),69 ("md5".into(), builtin_md5),69 ("base64".into(), builtin_base64),70 ("base64".into(), builtin_base64),70 ("trace".into(), builtin_trace),71 ("trace".into(), builtin_trace),72 ("gc".into(), builtin_gc),73 ("gcTrace".into(), builtin_gc_trace),71 ("join".into(), builtin_join),74 ("join".into(), builtin_join),72 ("escapeStringJson".into(), builtin_escape_string_json),75 ("escapeStringJson".into(), builtin_escape_string_json),73 ("manifestJsonEx".into(), builtin_manifest_json_ex),76 ("manifestJsonEx".into(), builtin_manifest_json_ex),301 parse_args!(context, "native", args, 1, [304 parse_args!(context, "native", args, 1, [302 0, x: ty!(string) => Val::Str;305 0, x: ty!(string) => Val::Str;303 ], {306 ], {304 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))?)307 Ok(with_state(|s| s.settings().ext_natives.get(&x).cloned()).map(|v| Val::Func(Gc::new(FuncVal::NativeExt(x.clone(), v)))).ok_or(UndefinedExternalFunction(x))?)305 })308 })306}309}307310446 })449 })447}450}451452fn builtin_gc(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val> {453 parse_args!(context, "gc", args, 1, [454 0, rest: ty!(any);455 ], {456 println!("GC start");457 jrsonnet_gc::force_collect();458 println!("GC done");459460 Ok(rest)461 })462}463464fn builtin_gc_trace(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val> {465 parse_args!(context, "gcTrace", args, 2, [466 0, name: ty!(string) => Val::Str;467 1, rest: ty!(any);468 ], {469 Ok(DebugGcTraceValue::create(name, rest))470 })471}448472449fn builtin_base64(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val> {473fn builtin_base64(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val> {450 parse_args!(context, "base64", args, 1, [474 parse_args!(context, "base64", args, 1, [crates/jrsonnet-evaluator/src/builtin/sort.rsdiffbeforeafterboth2 error::{Error, LocError, Result},2 error::{Error, LocError, Result},3 throw, Context, FuncVal, Val,3 throw, Context, FuncVal, Val,4};4};5use std::rc::Rc;5use jrsonnet_gc::{Finalize, Gc, Trace};667#[derive(Debug, Clone, thiserror::Error)]7#[derive(Debug, Clone, thiserror::Error, Trace, Finalize)]8pub enum SortError {8pub enum SortError {9 #[error("sort key should be string or number")]9 #[error("sort key should be string or number")]10 SortKeyShouldBeStringOrNumber,10 SortKeyShouldBeStringOrNumber,59 Ok(sort_type)59 Ok(sort_type)60}60}616162pub fn sort(ctx: Context, mut values: Rc<Vec<Val>>, key_getter: &FuncVal) -> Result<Rc<Vec<Val>>> {62pub fn sort(ctx: Context, values: Gc<Vec<Val>>, key_getter: &FuncVal) -> Result<Gc<Vec<Val>>> {63 if values.len() <= 1 {63 if values.len() <= 1 {64 return Ok(values);64 return Ok(values);65 }65 }66 if key_getter.is_ident() {66 if key_getter.is_ident() {67 let mvalues = Rc::make_mut(&mut values);67 let mut mvalues = (*values).clone();68 let sort_type = get_sort_type(mvalues, |k| k)?;68 let sort_type = get_sort_type(&mut mvalues, |k| k)?;69 match sort_type {69 match sort_type {70 SortKeyType::Number => mvalues.sort_by_key(|v| match v {70 SortKeyType::Number => mvalues.sort_by_key(|v| match v {71 Val::Num(n) => NonNaNf64(*n),71 Val::Num(n) => NonNaNf64(*n),77 }),77 }),78 SortKeyType::Unknown => unreachable!(),78 SortKeyType::Unknown => unreachable!(),79 };79 };80 Ok(values)80 Ok(Gc::new(mvalues))81 } else {81 } else {82 let mut vk = Vec::with_capacity(values.len());82 let mut vk = Vec::with_capacity(values.len());83 for value in values.iter() {83 for value in values.iter() {98 }),98 }),99 SortKeyType::Unknown => unreachable!(),99 SortKeyType::Unknown => unreachable!(),100 };100 };101 Ok(Rc::new(vk.into_iter().map(|v| v.0).collect()))101 Ok(Gc::new(vk.into_iter().map(|v| v.0).collect()))102 }102 }103}103}104104crates/jrsonnet-evaluator/src/ctx.rsdiffbeforeafterboth1use crate::{1use crate::{2 error::Error::*, map::LayeredHashMap, resolved_lazy_val, FutureWrapper, LazyBinding, LazyVal,2 error::Error::*, map::LayeredHashMap, FutureWrapper, LazyBinding, LazyVal, ObjValue, Result,3 ObjValue, Result, Val,3 Val,4};4};5use jrsonnet_gc::{Gc, Trace};5use jrsonnet_interner::IStr;6use jrsonnet_interner::IStr;6use rustc_hash::FxHashMap;7use rustc_hash::FxHashMap;7use std::hash::BuildHasherDefault;8use std::fmt::Debug;8use std::{fmt::Debug, rc::Rc};9use std::hash::BuildHasherDefault;91010#[derive(Clone)]11#[derive(Clone, Trace)]12#[trivially_drop]11pub struct ContextCreator(pub Context, pub FutureWrapper<FxHashMap<IStr, LazyBinding>>);13pub struct ContextCreator(pub Context, pub FutureWrapper<FxHashMap<IStr, LazyBinding>>);12impl ContextCreator {14impl ContextCreator {13 pub fn create(&self, this: Option<ObjValue>, super_obj: Option<ObjValue>) -> Result<Context> {15 pub fn create(&self, this: Option<ObjValue>, super_obj: Option<ObjValue>) -> Result<Context> {20 }22 }21}23}222425#[derive(Trace)]26#[trivially_drop]23struct ContextInternals {27struct ContextInternals {24 dollar: Option<ObjValue>,28 dollar: Option<ObjValue>,25 this: Option<ObjValue>,29 this: Option<ObjValue>,26 super_obj: Option<ObjValue>,30 super_obj: Option<ObjValue>,27 bindings: LayeredHashMap<LazyVal>,31 bindings: LayeredHashMap,28}32}29impl Debug for ContextInternals {33impl Debug for ContextInternals {30 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {34 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {31 f.debug_struct("Context")35 f.debug_struct("Context").finish()32 .field("this", &self.this.as_ref().map(|e| Rc::as_ptr(&e.0)))33 .field("bindings", &self.bindings)34 .finish()35 }36 }36}37}373838#[derive(Debug, Clone)]39#[derive(Debug, Clone, Trace)]40#[trivially_drop]39pub struct Context(Rc<ContextInternals>);41pub struct Context(Gc<ContextInternals>);40impl Context {42impl Context {41 pub fn new_future() -> FutureWrapper<Self> {43 pub fn new_future() -> FutureWrapper<Self> {42 FutureWrapper::new()44 FutureWrapper::new()55 }57 }565857 pub fn new() -> Self {59 pub fn new() -> Self {58 Self(Rc::new(ContextInternals {60 Self(Gc::new(ContextInternals {59 dollar: None,61 dollar: None,60 this: None,62 this: None,61 super_obj: None,63 super_obj: None,81 pub fn with_var(self, name: IStr, value: Val) -> Self {83 pub fn with_var(self, name: IStr, value: Val) -> Self {82 let mut new_bindings =84 let mut new_bindings =83 FxHashMap::with_capacity_and_hasher(1, BuildHasherDefault::default());85 FxHashMap::with_capacity_and_hasher(1, BuildHasherDefault::default());84 new_bindings.insert(name, resolved_lazy_val!(value));86 new_bindings.insert(name, LazyVal::new_resolved(value));85 self.extend(new_bindings, None, None, None)87 self.extend(new_bindings, None, None, None)86 }88 }878996 new_this: Option<ObjValue>,98 new_this: Option<ObjValue>,97 new_super_obj: Option<ObjValue>,99 new_super_obj: Option<ObjValue>,98 ) -> Self {100 ) -> Self {99 match Rc::try_unwrap(self.0) {100 Ok(mut ctx) => {101 // Extended context aren't used by anything else, we can freely mutate it without cloning102 if let Some(dollar) = new_dollar {101 let ctx = &self.0;103 ctx.dollar = Some(dollar);104 }105 if let Some(this) = new_this {106 ctx.this = Some(this);107 }108 if let Some(super_obj) = new_super_obj {109 ctx.super_obj = Some(super_obj);110 }111 if !new_bindings.is_empty() {112 ctx.bindings = ctx.bindings.extend(new_bindings);113 }114 Self(Rc::new(ctx))115 }116 Err(ctx) => {117 let dollar = new_dollar.or_else(|| ctx.dollar.clone());102 let dollar = new_dollar.or_else(|| ctx.dollar.clone());118 let this = new_this.or_else(|| ctx.this.clone());103 let this = new_this.or_else(|| ctx.this.clone());119 let super_obj = new_super_obj.or_else(|| ctx.super_obj.clone());104 let super_obj = new_super_obj.or_else(|| ctx.super_obj.clone());122 } else {107 } else {123 ctx.bindings.clone().extend(new_bindings)108 ctx.bindings.clone().extend(new_bindings)124 };109 };125 Self(Rc::new(ContextInternals {110 Self(Gc::new(ContextInternals {126 dollar,111 dollar,127 this,112 this,128 super_obj,113 super_obj,129 bindings,114 bindings,130 }))115 }))131 }132 }133 }116 }134 pub fn extend_bound(self, new_bindings: FxHashMap<IStr, LazyVal>) -> Self {117 pub fn extend_bound(self, new_bindings: FxHashMap<IStr, LazyVal>) -> Self {135 let new_this = self.0.this.clone();118 let new_this = self.0.this.clone();166149167impl PartialEq for Context {150impl PartialEq for Context {168 fn eq(&self, other: &Self) -> bool {151 fn eq(&self, other: &Self) -> bool {169 Rc::ptr_eq(&self.0, &other.0)152 Gc::ptr_eq(&self.0, &other.0)170 }153 }171}154}172173#[cfg(feature = "unstable")]174#[derive(Debug, Clone)]175pub struct WeakContext(std::rc::Weak<ContextInternals>);176#[cfg(feature = "unstable")]177impl WeakContext {178 pub fn upgrade(&self) -> Context {179 Context(self.0.upgrade().expect("context is removed"))180 }181}182#[cfg(feature = "unstable")]183impl PartialEq for WeakContext {184 fn eq(&self, other: &Self) -> bool {185 self.0.ptr_eq(&other.0)186 }187}188155crates/jrsonnet-evaluator/src/dynamic.rsdiffbeforeafterboth1use std::{cell::RefCell, rc::Rc};1use jrsonnet_gc::{Gc, GcCell, Trace};223#[derive(Clone)]3#[derive(Clone, Trace)]4#[trivially_drop]4pub struct FutureWrapper<V>(pub Rc<RefCell<Option<V>>>);5pub struct FutureWrapper<V: Trace + 'static>(pub Gc<GcCell<Option<V>>>);5impl<T> FutureWrapper<T> {6impl<T: Trace + 'static> FutureWrapper<T> {6 pub fn new() -> Self {7 pub fn new() -> Self {7 Self(Rc::new(RefCell::new(None)))8 Self(Gc::new(GcCell::new(None)))8 }9 }9 pub fn fill(self, value: T) {10 pub fn fill(self, value: T) {10 assert!(self.0.borrow().is_none(), "wrapper is filled already");11 assert!(self.0.borrow().is_none(), "wrapper is filled already");11 self.0.borrow_mut().replace(value);12 self.0.borrow_mut().replace(value);12 }13 }13}14}14impl<T: Clone> FutureWrapper<T> {15impl<T: Clone + Trace + 'static> FutureWrapper<T> {15 pub fn unwrap(&self) -> T {16 pub fn unwrap(&self) -> T {16 self.0.borrow().as_ref().cloned().unwrap()17 self.0.borrow().as_ref().cloned().unwrap()17 }18 }18}19}192020impl<T> Default for FutureWrapper<T> {21impl<T: Trace + 'static> Default for FutureWrapper<T> {21 fn default() -> Self {22 fn default() -> Self {22 Self::new()23 Self::new()23 }24 }crates/jrsonnet-evaluator/src/error.rsdiffbeforeafterboth2 builtin::{format::FormatError, sort::SortError},2 builtin::{format::FormatError, sort::SortError},3 typed::TypeLocError,3 typed::TypeLocError,4};4};5use jrsonnet_gc::Trace;5use jrsonnet_interner::IStr;6use jrsonnet_interner::IStr;6use jrsonnet_parser::{BinaryOpType, ExprLocation, UnaryOpType};7use jrsonnet_parser::{BinaryOpType, ExprLocation, UnaryOpType};7use jrsonnet_types::ValType;8use jrsonnet_types::ValType;11};12};12use thiserror::Error;13use thiserror::Error;131414#[derive(Error, Debug, Clone)]15#[derive(Error, Debug, Clone, Trace)]16#[trivially_drop]15pub enum Error {17pub enum Error {16 #[error("intrinsic not found: {0}")]18 #[error("intrinsic not found: {0}")]17 IntrinsicNotFound(IStr),19 IntrinsicNotFound(IStr),91 ImportSyntaxError {93 ImportSyntaxError {92 path: Rc<Path>,94 path: Rc<Path>,93 source_code: IStr,95 source_code: IStr,96 #[unsafe_ignore_trace]94 error: Box<jrsonnet_parser::ParseError>,97 error: Box<jrsonnet_parser::ParseError>,95 },98 },969997 #[error("runtime error: {0}")]100 #[error("runtime error: {0}")]98 RuntimeError(IStr),101 RuntimeError(IStr),99 #[error("stack overflow, try to reduce recursion, or set --max-stack to bigger value")]102 #[error("stack overflow, try to reduce recursion, or set --max-stack to bigger value")]100 StackOverflow,103 StackOverflow,104 #[error("infinite recursion detected")]105 RecursiveLazyValueEvaluation,101 #[error("tried to index by fractional value")]106 #[error("tried to index by fractional value")]102 FractionalIndex,107 FractionalIndex,103 #[error("attempted to divide by zero")]108 #[error("attempted to divide by zero")]145 }150 }146}151}147152148#[derive(Clone, Debug)]153#[derive(Clone, Debug, Trace)]154#[trivially_drop]149pub struct StackTraceElement {155pub struct StackTraceElement {150 pub location: Option<ExprLocation>,156 pub location: Option<ExprLocation>,151 pub desc: String,157 pub desc: String,152}158}153#[derive(Debug, Clone)]159#[derive(Debug, Clone, Trace)]160#[trivially_drop]154pub struct StackTrace(pub Vec<StackTraceElement>);161pub struct StackTrace(pub Vec<StackTraceElement>);155162156#[derive(Debug, Clone)]163#[derive(Debug, Clone, Trace)]164#[trivially_drop]157pub struct LocError(Box<(Error, StackTrace)>);165pub struct LocError(Box<(Error, StackTrace)>);158impl LocError {166impl LocError {159 pub fn new(e: Error) -> Self {167 pub fn new(e: Error) -> Self {crates/jrsonnet-evaluator/src/evaluate.rsdiffbeforeafterboth1use crate::{1use crate::{2 equals, error::Error::*, lazy_val, push, throw, with_state, ArrValue, Context, ContextCreator,2 equals, error::Error::*, push, throw, with_state, ArrValue, Bindable, Context, ContextCreator,3 FuncDesc, FuncVal, FutureWrapper, LazyBinding, LazyVal, ObjMember, ObjValue, Result, Val,3 FuncDesc, FuncVal, FutureWrapper, LazyBinding, LazyVal, LazyValValue, ObjMember, ObjValue,4 ObjectAssertion, Result, Val,4};5};5use closure::closure;6use jrsonnet_gc::{Gc, Trace};6use jrsonnet_interner::IStr;7use jrsonnet_interner::IStr;7use jrsonnet_parser::{8use jrsonnet_parser::{8 ArgsDesc, AssertStmt, BinaryOpType, BindSpec, CompSpec, Expr, ExprLocation, FieldMember,9 ArgsDesc, AssertStmt, BinaryOpType, BindSpec, CompSpec, Expr, ExprLocation, FieldMember,11};12};12use jrsonnet_types::ValType;13use jrsonnet_types::ValType;13use rustc_hash::{FxHashMap, FxHasher};14use rustc_hash::{FxHashMap, FxHasher};14use std::{collections::HashMap, hash::BuildHasherDefault, rc::Rc};15use std::{collections::HashMap, hash::BuildHasherDefault};151616pub fn evaluate_binding_in_future(17pub fn evaluate_binding_in_future(17 b: &BindSpec,18 b: &BindSpec,21 if let Some(params) = &b.params {22 if let Some(params) = &b.params {22 let params = params.clone();23 let params = params.clone();2425 #[derive(Trace)]26 #[trivially_drop]27 struct LazyMethodBinding {28 context_creator: FutureWrapper<Context>,29 name: IStr,30 params: ParamsDesc,31 value: LocExpr,32 }33 impl LazyValValue for LazyMethodBinding {34 fn get(self: Box<Self>) -> Result<Val> {35 Ok(evaluate_method(36 self.context_creator.unwrap(),37 self.name,38 self.params,39 self.value,40 ))41 }42 }4323 LazyVal::new(Box::new(move || {44 LazyVal::new(Box::new(LazyMethodBinding {24 Ok(evaluate_method(25 context_creator.unwrap(),45 context_creator,26 b.name.clone(),46 name: b.name.clone(),27 params.clone(),47 params,28 b.value.clone(),48 value: b.value.clone(),29 ))30 }))49 }))31 } else {50 } else {51 #[derive(Trace)]52 #[trivially_drop]53 struct LazyNamedBinding {54 context_creator: FutureWrapper<Context>,55 name: IStr,56 value: LocExpr,57 }58 impl LazyValValue for LazyNamedBinding {59 fn get(self: Box<Self>) -> Result<Val> {60 evaluate_named(self.context_creator.unwrap(), &self.value, self.name)61 }62 }32 LazyVal::new(Box::new(move || {63 LazyVal::new(Box::new(LazyNamedBinding {33 evaluate_named(context_creator.unwrap(), &b.value, b.name.clone())64 context_creator,65 name: b.name.clone(),66 value: b.value,34 }))67 }))35 }68 }36}69}40 if let Some(params) = &b.params {73 if let Some(params) = &b.params {41 let params = params.clone();74 let params = params.clone();7576 #[derive(Trace)]77 #[trivially_drop]78 struct BindableMethodLazyVal {79 this: Option<ObjValue>,80 super_obj: Option<ObjValue>,8182 context_creator: ContextCreator,83 name: IStr,84 params: ParamsDesc,85 value: LocExpr,86 }87 impl LazyValValue for BindableMethodLazyVal {88 fn get(self: Box<Self>) -> Result<Val> {89 Ok(evaluate_method(90 self.context_creator.create(self.this, self.super_obj)?,91 self.name,92 self.params,93 self.value,94 ))95 }96 }9798 #[derive(Trace)]99 #[trivially_drop]100 struct BindableMethod {101 context_creator: ContextCreator,102 name: IStr,103 params: ParamsDesc,104 value: LocExpr,105 }106 impl Bindable for BindableMethod {107 fn bind(&self, this: Option<ObjValue>, super_obj: Option<ObjValue>) -> Result<LazyVal> {108 Ok(LazyVal::new(Box::new(BindableMethodLazyVal {109 this,110 super_obj,111112 context_creator: self.context_creator.clone(),113 name: self.name.clone(),114 params: self.params.clone(),115 value: self.value.clone(),116 })))117 }118 }11942 (120 (43 b.name.clone(),121 b.name.clone(),44 LazyBinding::Bindable(Rc::new(move |this, super_obj| {122 LazyBinding::Bindable(Gc::new(Box::new(BindableMethod {45 Ok(lazy_val!(46 closure!(clone b, clone params, clone context_creator, || Ok(evaluate_method(123 context_creator,47 context_creator.create(this.clone(), super_obj.clone())?,48 b.name.clone(),124 name: b.name.clone(),49 params.clone(),125 params,50 b.value.clone(),126 value: b.value.clone(),51 )))52 ))127 }))),53 })),54 )128 )55 } else {129 } else {130 #[derive(Trace)]131 #[trivially_drop]132 struct BindableNamedLazyVal {133 this: Option<ObjValue>,134 super_obj: Option<ObjValue>,135136 context_creator: ContextCreator,137 name: IStr,138 value: LocExpr,139 }140 impl LazyValValue for BindableNamedLazyVal {141 fn get(self: Box<Self>) -> Result<Val> {142 evaluate_named(143 self.context_creator.create(self.this, self.super_obj)?,144 &self.value,145 self.name,146 )147 }148 }149150 #[derive(Trace)]151 #[trivially_drop]152 struct BindableNamed {153 context_creator: ContextCreator,154 name: IStr,155 value: LocExpr,156 }157 impl Bindable for BindableNamed {158 fn bind(&self, this: Option<ObjValue>, super_obj: Option<ObjValue>) -> Result<LazyVal> {159 Ok(LazyVal::new(Box::new(BindableNamedLazyVal {160 this,161 super_obj,162163 context_creator: self.context_creator.clone(),164 name: self.name.clone(),165 value: self.value.clone(),166 })))167 }168 }16956 (170 (57 b.name.clone(),171 b.name.clone(),58 LazyBinding::Bindable(Rc::new(move |this, super_obj| {172 LazyBinding::Bindable(Gc::new(Box::new(BindableNamed {59 Ok(lazy_val!(closure!(clone context_creator, clone b, ||173 context_creator,60 evaluate_named(61 context_creator.create(this.clone(), super_obj.clone())?,174 name: b.name.clone(),62 &b.value,175 value: b.value.clone(),63 b.name.clone()64 )65 )))176 }))),66 })),67 )177 )68 }178 }69}179}7018071pub fn evaluate_method(ctx: Context, name: IStr, params: ParamsDesc, body: LocExpr) -> Val {181pub fn evaluate_method(ctx: Context, name: IStr, params: ParamsDesc, body: LocExpr) -> Val {72 Val::Func(Rc::new(FuncVal::Normal(FuncDesc {182 Val::Func(Gc::new(FuncVal::Normal(FuncDesc {73 name,183 name,74 ctx,184 ctx,75 params,185 params,105215106pub fn evaluate_add_op(a: &Val, b: &Val) -> Result<Val> {216pub fn evaluate_add_op(a: &Val, b: &Val) -> Result<Val> {107 Ok(match (a, b) {217 Ok(match (a, b) {218 (Val::DebugGcTraceValue(v1), Val::DebugGcTraceValue(v2)) => {219 evaluate_add_op(&v1.value, &v2.value)?220 }108 (Val::Str(v1), Val::Str(v2)) => Val::Str(((**v1).to_owned() + v2).into()),221 (Val::Str(v1), Val::Str(v2)) => Val::Str(((**v1).to_owned() + v2).into()),109222110 // Can't use generic json serialization way, because it depends on number to string concatenation (std.jsonnet:890)223 // Can't use generic json serialization way, because it depends on number to string concatenation (std.jsonnet:890)257 }370 }258371259 let mut new_members = FxHashMap::default();372 let mut new_members = FxHashMap::default();260 let mut assertions = Vec::new();373 let mut assertions: Vec<Box<dyn ObjectAssertion>> = Vec::new();261 for member in members.iter() {374 for member in members.iter() {262 match member {375 match member {263 Member::Field(FieldMember {376 Member::Field(FieldMember {273 }386 }274 let name = name.unwrap();387 let name = name.unwrap();388389 #[derive(Trace)]390 #[trivially_drop]391 struct ObjMemberBinding {392 context_creator: ContextCreator,393 value: LocExpr,394 name: IStr,395 }396 impl Bindable for ObjMemberBinding {397 fn bind(398 &self,399 this: Option<ObjValue>,400 super_obj: Option<ObjValue>,401 ) -> Result<LazyVal> {402 Ok(LazyVal::new_resolved(evaluate_named(403 self.context_creator.create(this, super_obj)?,404 &self.value,405 self.name.clone(),406 )?))407 }408 }275 new_members.insert(409 new_members.insert(276 name.clone(),410 name.clone(),277 ObjMember {411 ObjMember {278 add: *plus,412 add: *plus,279 visibility: *visibility,413 visibility: *visibility,280 invoke: LazyBinding::Bindable(Rc::new(414 invoke: LazyBinding::Bindable(Gc::new(Box::new(ObjMemberBinding {281 closure!(clone name, clone value, clone context_creator, |this, super_obj| {415 context_creator: context_creator.clone(),282 Ok(LazyVal::new_resolved(evaluate_named(283 context_creator.create(this, super_obj)?,284 &value,416 value: value.clone(),285 name.clone(),417 name,286 )?))287 }),418 }))),288 )),289 location: value.1.clone(),419 location: value.1.clone(),290 },420 },301 continue;431 continue;302 }432 }303 let name = name.unwrap();433 let name = name.unwrap();434 #[derive(Trace)]435 #[trivially_drop]436 struct ObjMemberBinding {437 context_creator: ContextCreator,438 value: LocExpr,439 params: ParamsDesc,440 name: IStr,441 }442 impl Bindable for ObjMemberBinding {443 fn bind(444 &self,445 this: Option<ObjValue>,446 super_obj: Option<ObjValue>,447 ) -> Result<LazyVal> {448 Ok(LazyVal::new_resolved(evaluate_method(449 self.context_creator.create(this, super_obj)?,450 self.name.clone(),451 self.params.clone(),452 self.value.clone(),453 )))454 }455 }304 new_members.insert(456 new_members.insert(305 name.clone(),457 name.clone(),306 ObjMember {458 ObjMember {307 add: false,459 add: false,308 visibility: Visibility::Hidden,460 visibility: Visibility::Hidden,309 invoke: LazyBinding::Bindable(Rc::new(461 invoke: LazyBinding::Bindable(Gc::new(Box::new(ObjMemberBinding {310 closure!(clone value, clone context_creator, clone params, clone name, |this, super_obj| {462 context_creator: context_creator.clone(),311 // TODO: Assert312 Ok(LazyVal::new_resolved(evaluate_method(313 context_creator.create(this, super_obj)?,314 name.clone(),463 value: value.clone(),315 params.clone(),464 params: params.clone(),316 value.clone(),465 name,317 )))318 }),466 }))),319 )),320 location: value.1.clone(),467 location: value.1.clone(),321 },468 },322 );469 );323 }470 }324 Member::BindStmt(_) => {}471 Member::BindStmt(_) => {}325 Member::AssertStmt(stmt) => {472 Member::AssertStmt(stmt) => {473 #[derive(Trace)]474 #[trivially_drop]475 struct ObjectAssert {476 context_creator: ContextCreator,477 assert: AssertStmt,478 }479 impl ObjectAssertion for ObjectAssert {480 fn run(481 &self,482 this: Option<ObjValue>,483 super_obj: Option<ObjValue>,484 ) -> Result<()> {485 let ctx = self.context_creator.create(this, super_obj)?;486 evaluate_assert(ctx, &self.assert)487 }488 }326 assertions.push(stmt.clone());489 assertions.push(Box::new(ObjectAssert {490 context_creator: context_creator.clone(),491 assert: stmt.clone(),492 }));327 }493 }328 }494 }329 }495 }330 let this = ObjValue::new(context, None, Rc::new(new_members), Rc::new(assertions));496 let this = ObjValue::new(None, Gc::new(new_members), Gc::new(assertions));331 future_this.fill(this.clone());497 future_this.fill(this.clone());332 Ok(this)498 Ok(this)333}499}361 match key {527 match key {362 Val::Null => {}528 Val::Null => {}363 Val::Str(n) => {529 Val::Str(n) => {530 #[derive(Trace)]531 #[trivially_drop]532 struct ObjCompBinding {533 context: Context,534 value: LocExpr,535 }536 impl Bindable for ObjCompBinding {537 fn bind(538 &self,539 this: Option<ObjValue>,540 _super_obj: Option<ObjValue>,541 ) -> Result<LazyVal> {542 Ok(LazyVal::new_resolved(evaluate(543 self.context.clone().extend(544 FxHashMap::default(),545 None,546 this,547 None,548 ),549 &self.value,550 )?))551 }552 }364 new_members.insert(553 new_members.insert(365 n,554 n,366 ObjMember {555 ObjMember {367 add: false,556 add: false,368 visibility: Visibility::Normal,557 visibility: Visibility::Normal,369 invoke: LazyBinding::Bindable(Rc::new(558 invoke: LazyBinding::Bindable(Gc::new(Box::new(ObjCompBinding {370 closure!(clone ctx, clone obj.value, |this, _super_obj| {559 context: ctx,371 Ok(LazyVal::new_resolved(evaluate(ctx.clone().extend(FxHashMap::default(), None, this, None), &value)?))560 value: obj.value.clone(),372 }),561 }))),373 )),374 location: obj.value.1.clone(),562 location: obj.value.1.clone(),375 },563 },381 Ok(())569 Ok(())382 })?;570 })?;383571384 let this = ObjValue::new(context, None, Rc::new(new_members), Rc::new(Vec::new()));572 let this = ObjValue::new(None, Gc::new(new_members), Gc::new(Vec::new()));385 future_this.fill(this.clone());573 future_this.fill(this.clone());386 this574 this387 }575 }486 if let Some(v) = v.get(s.clone())? {674 if let Some(v) = v.get(s.clone())? {487 Ok(v)675 Ok(v)488 } else if v.get("__intrinsic_namespace__".into())?.is_some() {676 } else if v.get("__intrinsic_namespace__".into())?.is_some() {489 Ok(Val::Func(Rc::new(FuncVal::Intrinsic(s))))677 Ok(Val::Func(Gc::new(FuncVal::Intrinsic(s))))490 } else {678 } else {491 throw!(NoSuchField(s))679 throw!(NoSuchField(s))492 }680 }549 Arr(items) => {737 Arr(items) => {550 let mut out = Vec::with_capacity(items.len());738 let mut out = Vec::with_capacity(items.len());551 for item in items {739 for item in items {740 // TODO: Implement ArrValue::Lazy with same context for every element?741 #[derive(Trace)]742 #[trivially_drop]743 struct ArrayElement {744 context: Context,745 item: LocExpr,746 }747 impl LazyValValue for ArrayElement {748 fn get(self: Box<Self>) -> Result<Val> {749 evaluate(self.context, &self.item)750 }751 }552 out.push(LazyVal::new(Box::new(752 out.push(LazyVal::new(Box::new(ArrayElement {553 closure!(clone context, clone item, || {753 context: context.clone(),554 evaluate(context.clone(), &item)754 item: item.clone(),555 }),556 )));755 })));557 }756 }558 Val::Arr(out.into())757 Val::Arr(out.into())559 }758 }563 out.push(evaluate(ctx, expr)?);762 out.push(evaluate(ctx, expr)?);564 Ok(())763 Ok(())565 })?;764 })?;566 Val::Arr(ArrValue::Eager(Rc::new(out)))765 Val::Arr(ArrValue::Eager(Gc::new(out)))567 }766 }568 Obj(body) => Val::Obj(evaluate_object(context, body)?),767 Obj(body) => Val::Obj(evaluate_object(context, body)?),569 ObjExtend(s, t) => evaluate_add_op(768 ObjExtend(s, t) => evaluate_add_op(576 Function(params, body) => {775 Function(params, body) => {577 evaluate_method(context, "anonymous".into(), params.clone(), body.clone())776 evaluate_method(context, "anonymous".into(), params.clone(), body.clone())578 }777 }579 Intrinsic(name) => Val::Func(Rc::new(FuncVal::Intrinsic(name.clone()))),778 Intrinsic(name) => Val::Func(Gc::new(FuncVal::Intrinsic(name.clone()))),580 AssertExpr(assert, returned) => {779 AssertExpr(assert, returned) => {581 evaluate_assert(context.clone(), assert)?;780 evaluate_assert(context.clone(), assert)?;582 evaluate(context, returned)?781 evaluate(context, returned)?crates/jrsonnet-evaluator/src/function.rsdiffbeforeafterboth1use crate::{error::Error::*, evaluate, lazy_val, resolved_lazy_val, throw, Context, Result, Val};1use crate::{error::Error::*, evaluate, throw, Context, LazyVal, LazyValValue, Result, Val};2use closure::closure;2use jrsonnet_gc::Trace;3use jrsonnet_interner::IStr;3use jrsonnet_interner::IStr;4use jrsonnet_parser::{ArgsDesc, ParamsDesc};4use jrsonnet_parser::{ArgsDesc, LocExpr, ParamsDesc};5use rustc_hash::FxHashMap;5use rustc_hash::FxHashMap;6use std::{collections::HashMap, hash::BuildHasherDefault};6use std::{collections::HashMap, hash::BuildHasherDefault};7753 throw!(FunctionParameterNotBoundInCall(p.0.clone()));53 throw!(FunctionParameterNotBoundInCall(p.0.clone()));54 };54 };55 let val = if tailstrict {55 let val = if tailstrict {56 resolved_lazy_val!(evaluate(ctx, expr)?)56 LazyVal::new_resolved(evaluate(ctx, expr)?)57 } else {57 } else {58 #[derive(Trace)]59 #[trivially_drop]60 struct EvaluateLazyVal {61 context: Context,62 expr: LocExpr,63 }64 impl LazyValValue for EvaluateLazyVal {65 fn get(self: Box<Self>) -> Result<Val> {66 evaluate(self.context, &self.expr)67 }68 }6958 lazy_val!(closure!(clone ctx, clone expr, ||evaluate(ctx.clone(), &expr)))70 LazyVal::new(Box::new(EvaluateLazyVal {71 context: ctx.clone(),72 expr: expr.clone(),73 }))59 };74 };60 out.insert(p.0.clone(), val);75 out.insert(p.0.clone(), val);61 }76 }89 // Fill defaults104 // Fill defaults90 for (id, p) in params.iter().enumerate() {105 for (id, p) in params.iter().enumerate() {91 let val = if let Some(arg) = positioned_args[id].take() {106 let val = if let Some(arg) = positioned_args[id].take() {92 resolved_lazy_val!(arg)107 LazyVal::new_resolved(arg)93 } else if let Some(default) = &p.1 {108 } else if let Some(default) = &p.1 {94 if tailstrict {109 if tailstrict {95 resolved_lazy_val!(evaluate(110 LazyVal::new_resolved(evaluate(96 body_ctx.clone().expect(NO_DEFAULT_CONTEXT),111 body_ctx.clone().expect(NO_DEFAULT_CONTEXT),97 default112 default,98 )?)113 )?)99 } else {114 } else {100 let body_ctx = body_ctx.clone();115 let body_ctx = body_ctx.clone();101 let default = default.clone();116 let default = default.clone();117 #[derive(Trace)]118 #[trivially_drop]119 struct EvaluateLazyVal {120 body_ctx: Option<Context>,121 default: LocExpr,122 }123 impl LazyValValue for EvaluateLazyVal {102 lazy_val!(move || {124 fn get(self: Box<Self>) -> Result<Val> {103 evaluate(body_ctx.clone().expect(NO_DEFAULT_CONTEXT), &default)125 evaluate(126 self.body_ctx.clone().expect(NO_DEFAULT_CONTEXT),127 &self.default,128 )104 })129 }130 }131 LazyVal::new(Box::new(EvaluateLazyVal { body_ctx, default }))105 }132 }106 } else {133 } else {107 throw!(FunctionParameterNotBoundInCall(p.0.clone()));134 throw!(FunctionParameterNotBoundInCall(p.0.clone()));135 } else {162 } else {136 throw!(FunctionParameterNotBoundInCall(p.0.clone()));163 throw!(FunctionParameterNotBoundInCall(p.0.clone()));137 };164 };138 out.insert(p.0.clone(), resolved_lazy_val!(val));165 out.insert(p.0.clone(), LazyVal::new_resolved(val));139 }166 }140167141 Ok(body_ctx.unwrap_or(ctx).extend(out, None, None, None))168 Ok(body_ctx.unwrap_or(ctx).extend(out, None, None, None))crates/jrsonnet-evaluator/src/integrations/serde.rsdiffbeforeafterboth1use crate::{1use crate::{2 error::{Error::*, LocError, Result},2 error::{Error::*, LocError, Result},3 throw, Context, LazyBinding, LazyVal, ObjMember, ObjValue, Val,3 throw, LazyBinding, LazyVal, ObjMember, ObjValue, Val,4};4};5use jrsonnet_gc::Gc;5use jrsonnet_parser::Visibility;6use jrsonnet_parser::Visibility;6use rustc_hash::FxHasher;7use rustc_hash::FxHasher;7use serde_json::{Map, Number, Value};8use serde_json::{Map, Number, Value};8use std::{9use std::{9 collections::HashMap,10 collections::HashMap,10 convert::{TryFrom, TryInto},11 convert::{TryFrom, TryInto},11 hash::BuildHasherDefault,12 hash::BuildHasherDefault,12 rc::Rc,13};13};141415impl TryFrom<&Val> for Value {15impl TryFrom<&Val> for Value {42 Self::Object(out)42 Self::Object(out)43 }43 }44 Val::Func(_) => throw!(RuntimeError("tried to manifest function".into())),44 Val::Func(_) => throw!(RuntimeError("tried to manifest function".into())),45 Val::DebugGcTraceValue(v) => Self::try_from(&*v.value as &Val)?,45 })46 })46 }47 }47}48}76 },77 },77 );78 );78 }79 }79 Self::Obj(ObjValue::new(80 Self::Obj(ObjValue::new(None, Gc::new(entries), Gc::new(Vec::new())))80 Context::new(),81 None,82 Rc::new(entries),83 Rc::new(Vec::new()),84 ))85 }81 }86 }82 }crates/jrsonnet-evaluator/src/lib.rsdiffbeforeafterboth26pub use evaluate::*;26pub use evaluate::*;27pub use function::parse_function_call;27pub use function::parse_function_call;28pub use import::*;28pub use import::*;29use jrsonnet_gc::{Finalize, Gc, Trace};30pub use jrsonnet_interner::IStr;29use jrsonnet_parser::*;31use jrsonnet_parser::*;30use native::NativeCallback;32use native::NativeCallback;31pub use obj::*;33pub use obj::*;41use trace::{offset_to_location, CodeLocation, CompactFormat, TraceFormat};43use trace::{offset_to_location, CodeLocation, CompactFormat, TraceFormat};42pub use val::*;44pub use val::*;434544// Re-exports45pub use jrsonnet_interner::IStr;46pub trait Bindable: Trace {4647type BindableFn = dyn Fn(Option<ObjValue>, Option<ObjValue>) -> Result<LazyVal>;47 fn bind(&self, this: Option<ObjValue>, super_obj: Option<ObjValue>) -> Result<LazyVal>;48}48#[derive(Clone)]49#[derive(Trace, Finalize, Clone)]49pub enum LazyBinding {50pub enum LazyBinding {50 Bindable(Rc<BindableFn>),51 Bindable(Gc<Box<dyn Bindable>>),51 Bound(LazyVal),52 Bound(LazyVal),52}53}535459impl LazyBinding {60impl LazyBinding {60 pub fn evaluate(&self, this: Option<ObjValue>, super_obj: Option<ObjValue>) -> Result<LazyVal> {61 pub fn evaluate(&self, this: Option<ObjValue>, super_obj: Option<ObjValue>) -> Result<LazyVal> {61 match self {62 match self {62 Self::Bindable(v) => v(this, super_obj),63 Self::Bindable(v) => v.bind(this, super_obj),63 Self::Bound(v) => Ok(v.clone()),64 Self::Bound(v) => Ok(v.clone()),64 }65 }65 }66 }73 /// Used for s`td.extVar`74 /// Used for s`td.extVar`74 pub ext_vars: HashMap<IStr, Val>,75 pub ext_vars: HashMap<IStr, Val>,75 /// Used for ext.native76 /// Used for ext.native76 pub ext_natives: HashMap<IStr, Rc<NativeCallback>>,77 pub ext_natives: HashMap<IStr, Gc<NativeCallback>>,77 /// TLA vars78 /// TLA vars78 pub tla_vars: HashMap<IStr, Val>,79 pub tla_vars: HashMap<IStr, Val>,79 /// Global variables are inserted in default context80 /// Global variables are inserted in default context272 let mut new_bindings: FxHashMap<IStr, LazyVal> =273 let mut new_bindings: FxHashMap<IStr, LazyVal> =273 FxHashMap::with_capacity_and_hasher(globals.len(), BuildHasherDefault::default());274 FxHashMap::with_capacity_and_hasher(globals.len(), BuildHasherDefault::default());274 for (name, value) in globals.iter() {275 for (name, value) in globals.iter() {275 new_bindings.insert(name.clone(), resolved_lazy_val!(value.clone()));276 new_bindings.insert(name.clone(), LazyVal::new_resolved(value.clone()));276 }277 }277 Context::new().extend_bound(new_bindings)278 Context::new().extend_bound(new_bindings)278 }279 }451 self.settings_mut().import_resolver = resolver;452 self.settings_mut().import_resolver = resolver;452 }453 }453454454 pub fn add_native(&self, name: IStr, cb: Rc<NativeCallback>) {455 pub fn add_native(&self, name: IStr, cb: Gc<NativeCallback>) {455 self.settings_mut().ext_natives.insert(name, cb);456 self.settings_mut().ext_natives.insert(name, cb);456 }457 }457458488pub mod tests {489pub mod tests {489 use super::Val;490 use super::Val;490 use crate::{error::Error::*, primitive_equals, EvaluationState};491 use crate::{492 error::Error::*, native::NativeCallbackHandler, primitive_equals, EvaluationState,493 };494 use jrsonnet_gc::{Finalize, Gc, Trace};491 use jrsonnet_interner::IStr;495 use jrsonnet_interner::IStr;492 use jrsonnet_parser::*;496 use jrsonnet_parser::*;493 use std::{497 use std::{919 let evaluator = EvaluationState::default();923 let evaluator = EvaluationState::default();920924921 evaluator.with_stdlib();925 evaluator.with_stdlib();922 evaluator.settings_mut().ext_natives.insert(926923 "native_add".into(),927 #[derive(Trace, Finalize)]924 Rc::new(NativeCallback::new(928 struct NativeAdd;925 ParamsDesc(Rc::new(vec![929 impl NativeCallbackHandler for NativeAdd {926 Param("a".into(), None),927 Param("b".into(), None),928 ])),929 |caller, args| {930 fn call(&self, from: Option<Rc<Path>>, args: &[Val]) -> crate::error::Result<Val> {930 assert_eq!(931 assert_eq!(931 &caller.unwrap() as &Path,932 &from.unwrap() as &Path,932 &PathBuf::from("native_caller.jsonnet")933 &PathBuf::from("native_caller.jsonnet")933 );934 );934 match (&args[0], &args[1]) {935 match (&args[0], &args[1]) {935 (Val::Num(a), Val::Num(b)) => Ok(Val::Num(a + b)),936 (Val::Num(a), Val::Num(b)) => Ok(Val::Num(a + b)),936 (_, _) => unreachable!(),937 (_, _) => unreachable!(),937 }938 }938 },939 }939 )),940 }940 );941 evaluator.settings_mut().ext_natives.insert(942 "native_add".into(),943 Gc::new(NativeCallback::new(944 ParamsDesc(Rc::new(vec![945 Param("a".into(), None),946 Param("b".into(), None),947 ])),948 Box::new(NativeAdd),949 )),950 );941 evaluator.evaluate_snippet_raw(951 evaluator.evaluate_snippet_raw(942 PathBuf::from("native_caller.jsonnet").into(),952 PathBuf::from("native_caller.jsonnet").into(),943 "std.assertEqual(std.native(\"native_add\")(1, 2), 3)".into(),953 "std.assertEqual(std.native(\"native_add\")(1, 2), 3)".into(),crates/jrsonnet-evaluator/src/map.rsdiffbeforeafterboth1use jrsonnet_gc::{Gc, Trace};1use jrsonnet_interner::IStr;2use jrsonnet_interner::IStr;2use rustc_hash::FxHashMap;3use rustc_hash::FxHashMap;43use std::rc::Rc;5use crate::LazyVal;465#[derive(Default, Debug)]7#[derive(Trace)]8#[trivially_drop]6struct LayeredHashMapInternals<V> {9pub struct LayeredHashMapInternals {7 parent: Option<LayeredHashMap<V>>,10 parent: Option<LayeredHashMap>,8 current: FxHashMap<IStr, V>,11 current: FxHashMap<IStr, LazyVal>,9}12}101311#[derive(Debug)]14#[derive(Trace)]15#[trivially_drop]12pub struct LayeredHashMap<V>(Rc<LayeredHashMapInternals<V>>);16pub struct LayeredHashMap(Gc<LayeredHashMapInternals>);131714impl<V> LayeredHashMap<V> {18impl LayeredHashMap {15 pub fn extend(self, new_layer: FxHashMap<IStr, V>) -> Self {19 pub fn extend(self, new_layer: FxHashMap<IStr, LazyVal>) -> Self {16 match Rc::try_unwrap(self.0) {17 Ok(mut map) => {18 map.current.extend(new_layer);19 Self(Rc::new(map))20 }21 Err(this) => Self(Rc::new(LayeredHashMapInternals {20 Self(Gc::new(LayeredHashMapInternals {22 parent: Some(Self(this)),21 parent: Some(self),23 current: new_layer,22 current: new_layer,24 })),23 }))25 }26 }24 }272528 pub fn get(&self, key: &IStr) -> Option<&V> {26 pub fn get(&self, key: &IStr) -> Option<&LazyVal> {29 (self.0)27 (self.0)30 .current28 .current31 .get(key)29 .get(key)32 .or_else(|| self.0.parent.as_ref().and_then(|p| p.get(key)))30 .or_else(|| self.0.parent.as_ref().and_then(|p| p.get(key)))33 }31 }34}32}353336impl<V> Clone for LayeredHashMap<V> {34impl Clone for LayeredHashMap {37 fn clone(&self) -> Self {35 fn clone(&self) -> Self {38 Self(self.0.clone())36 Self(self.0.clone())39 }37 }40}38}413942impl<V> Default for LayeredHashMap<V> {40impl Default for LayeredHashMap {43 fn default() -> Self {41 fn default() -> Self {44 Self(Rc::new(LayeredHashMapInternals {42 Self(Gc::new(LayeredHashMapInternals {45 parent: None,43 parent: None,46 current: FxHashMap::default(),44 current: FxHashMap::default(),47 }))45 }))crates/jrsonnet-evaluator/src/native.rsdiffbeforeafterboth1#![allow(clippy::type_complexity)]1#![allow(clippy::type_complexity)]223use crate::{error::Result, Val};3use crate::{error::Result, Val};4use jrsonnet_gc::Trace;4use jrsonnet_parser::ParamsDesc;5use jrsonnet_parser::ParamsDesc;5use std::fmt::Debug;6use std::fmt::Debug;6use std::path::Path;7use std::path::Path;7use std::rc::Rc;8use std::rc::Rc;8910pub trait NativeCallbackHandler: Trace {11 fn call(&self, from: Option<Rc<Path>>, args: &[Val]) -> Result<Val>;12}1314#[derive(Trace)]15#[trivially_drop]9pub struct NativeCallback {16pub struct NativeCallback {10 pub params: ParamsDesc,17 pub params: ParamsDesc,11 handler: Box<dyn Fn(Option<Rc<Path>>, &[Val]) -> Result<Val>>,18 handler: Box<dyn NativeCallbackHandler>,12}19}13impl NativeCallback {20impl NativeCallback {14 pub fn new(21 pub fn new(params: ParamsDesc, handler: Box<dyn NativeCallbackHandler>) -> Self {15 params: ParamsDesc,16 handler: impl Fn(Option<Rc<Path>>, &[Val]) -> Result<Val> + 'static,17 ) -> Self {18 Self {22 Self { params, handler }19 params,20 handler: Box::new(handler),21 }22 }23 }23 pub fn call(&self, caller: Option<Rc<Path>>, args: &[Val]) -> Result<Val> {24 pub fn call(&self, caller: Option<Rc<Path>>, args: &[Val]) -> Result<Val> {24 (self.handler)(caller, args)25 self.handler.call(caller, args)25 }26 }26}27}27impl Debug for NativeCallback {28impl Debug for NativeCallback {crates/jrsonnet-evaluator/src/obj.rsdiffbeforeafterboth1use crate::{evaluate_add_op, evaluate_assert, Context, LazyBinding, Result, Val};1use crate::{evaluate_add_op, LazyBinding, Result, Val};2use jrsonnet_gc::{Gc, GcCell, Trace};2use jrsonnet_interner::IStr;3use jrsonnet_interner::IStr;3use jrsonnet_parser::{AssertStmt, ExprLocation, Visibility};4use jrsonnet_parser::{ExprLocation, Visibility};4use rustc_hash::{FxHashMap, FxHashSet};5use rustc_hash::{FxHashMap, FxHashSet};5use std::hash::{Hash, Hasher};6use std::hash::{Hash, Hasher};6use std::{cell::RefCell, fmt::Debug, hash::BuildHasherDefault, rc::Rc};7use std::{fmt::Debug, hash::BuildHasherDefault};788#[derive(Debug)]9#[derive(Debug, Trace)]10#[trivially_drop]9pub struct ObjMember {11pub struct ObjMember {10 pub add: bool,12 pub add: bool,11 pub visibility: Visibility,13 pub visibility: Visibility,12 pub invoke: LazyBinding,14 pub invoke: LazyBinding,13 pub location: Option<ExprLocation>,15 pub location: Option<ExprLocation>,14}16}1718pub trait ObjectAssertion: Trace {19 fn run(&self, this: Option<ObjValue>, super_obj: Option<ObjValue>) -> Result<()>;20}152116// Field => This22// Field => This17type CacheKey = (IStr, ObjValue);23type CacheKey = (IStr, ObjValue);18#[derive(Debug)]24#[derive(Trace)]25#[trivially_drop]19pub struct ObjValueInternals {26pub struct ObjValueInternals {20 context: Context,21 super_obj: Option<ObjValue>,27 super_obj: Option<ObjValue>,22 assertions: Rc<Vec<AssertStmt>>,28 assertions: Gc<Vec<Box<dyn ObjectAssertion>>>,23 assertions_ran: RefCell<FxHashSet<ObjValue>>,29 assertions_ran: GcCell<FxHashSet<ObjValue>>,24 this_obj: Option<ObjValue>,30 this_obj: Option<ObjValue>,25 this_entries: Rc<FxHashMap<IStr, ObjMember>>,31 this_entries: Gc<FxHashMap<IStr, ObjMember>>,26 value_cache: RefCell<FxHashMap<CacheKey, Option<Val>>>,32 value_cache: GcCell<FxHashMap<CacheKey, Option<Val>>>,27}33}283429#[derive(Clone)]35#[derive(Clone, Trace)]36#[trivially_drop]30pub struct ObjValue(pub(crate) Rc<ObjValueInternals>);37pub struct ObjValue(pub(crate) Gc<ObjValueInternals>);31impl Debug for ObjValue {38impl Debug for ObjValue {32 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {39 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {33 if let Some(super_obj) = self.0.super_obj.as_ref() {40 if let Some(super_obj) = self.0.super_obj.as_ref() {556256impl ObjValue {63impl ObjValue {57 pub fn new(64 pub fn new(58 context: Context,59 super_obj: Option<Self>,65 super_obj: Option<Self>,60 this_entries: Rc<FxHashMap<IStr, ObjMember>>,66 this_entries: Gc<FxHashMap<IStr, ObjMember>>,61 assertions: Rc<Vec<AssertStmt>>,67 assertions: Gc<Vec<Box<dyn ObjectAssertion>>>,62 ) -> Self {68 ) -> Self {63 Self(Rc::new(ObjValueInternals {69 Self(Gc::new(ObjValueInternals {64 context,65 super_obj,70 super_obj,66 assertions,71 assertions,67 assertions_ran: RefCell::new(FxHashSet::default()),72 assertions_ran: GcCell::new(FxHashSet::default()),68 this_obj: None,73 this_obj: None,69 this_entries,74 this_entries,70 value_cache: RefCell::new(FxHashMap::default()),75 value_cache: GcCell::new(FxHashMap::default()),71 }))76 }))72 }77 }73 pub fn new_empty() -> Self {78 pub fn new_empty() -> Self {74 Self::new(79 Self::new(None, Gc::new(FxHashMap::default()), Gc::new(Vec::new()))75 Context::new(),76 None,77 Rc::new(FxHashMap::default()),78 Rc::new(Vec::new()),79 )80 }80 }81 pub fn extend_from(&self, super_obj: Self) -> Self {81 pub fn extend_from(&self, super_obj: Self) -> Self {82 match &self.0.super_obj {82 match &self.0.super_obj {83 None => Self::new(83 None => Self::new(84 self.0.context.clone(),85 Some(super_obj),84 Some(super_obj),86 self.0.this_entries.clone(),85 self.0.this_entries.clone(),87 self.0.assertions.clone(),86 self.0.assertions.clone(),88 ),87 ),89 Some(v) => Self::new(88 Some(v) => Self::new(90 self.0.context.clone(),91 Some(v.extend_from(super_obj)),89 Some(v.extend_from(super_obj)),92 self.0.this_entries.clone(),90 self.0.this_entries.clone(),93 self.0.assertions.clone(),91 self.0.assertions.clone(),94 ),92 ),95 }93 }96 }94 }97 pub fn with_this(&self, this_obj: Self) -> Self {95 pub fn with_this(&self, this_obj: Self) -> Self {98 Self(Rc::new(ObjValueInternals {96 Self(Gc::new(ObjValueInternals {99 context: self.0.context.clone(),100 super_obj: self.0.super_obj.clone(),97 super_obj: self.0.super_obj.clone(),101 assertions: self.0.assertions.clone(),98 assertions: self.0.assertions.clone(),102 assertions_ran: RefCell::new(FxHashSet::default()),99 assertions_ran: GcCell::new(FxHashSet::default()),103 this_obj: Some(this_obj),100 this_obj: Some(this_obj),104 this_entries: self.0.this_entries.clone(),101 this_entries: self.0.this_entries.clone(),105 value_cache: RefCell::new(FxHashMap::default()),102 value_cache: GcCell::new(FxHashMap::default()),106 }))103 }))107 }104 }108105203 pub fn extend_with_field(self, key: IStr, value: ObjMember) -> Self {200 pub fn extend_with_field(self, key: IStr, value: ObjMember) -> Self {204 let mut new = FxHashMap::with_capacity_and_hasher(1, BuildHasherDefault::default());201 let mut new = FxHashMap::with_capacity_and_hasher(1, BuildHasherDefault::default());205 new.insert(key, value);202 new.insert(key, value);206 Self::new(203 Self::new(Some(self), Gc::new(new), Gc::new(Vec::new()))207 Context::new(),208 Some(self),209 Rc::new(new),210 Rc::new(Vec::new()),211 )212 }204 }213205249 fn run_assertions_raw(&self, real_this: &Self) -> Result<()> {241 fn run_assertions_raw(&self, real_this: &Self) -> Result<()> {250 if self.0.assertions_ran.borrow_mut().insert(real_this.clone()) {242 if self.0.assertions_ran.borrow_mut().insert(real_this.clone()) {251 for assertion in self.0.assertions.iter() {243 for assertion in self.0.assertions.iter() {252 if let Err(e) = evaluate_assert(244 if let Err(e) = assertion.run(Some(real_this.clone()), self.0.super_obj.clone()) {253 self.0254 .context255 .clone()256 .with_this_super(real_this.clone(), self.0.super_obj.clone()),257 assertion,258 ) {259 self.0.assertions_ran.borrow_mut().remove(real_this);245 self.0.assertions_ran.borrow_mut().remove(real_this);260 return Err(e);246 return Err(e);261 }247 }271 }257 }272258273 pub fn ptr_eq(a: &Self, b: &Self) -> bool {259 pub fn ptr_eq(a: &Self, b: &Self) -> bool {274 Rc::ptr_eq(&a.0, &b.0)260 Gc::ptr_eq(&a.0, &b.0)275 }261 }276}262}277263278impl PartialEq for ObjValue {264impl PartialEq for ObjValue {279 fn eq(&self, other: &Self) -> bool {265 fn eq(&self, other: &Self) -> bool {280 Rc::ptr_eq(&self.0, &other.0)266 Gc::ptr_eq(&self.0, &other.0)281 }267 }282}268}283269284impl Eq for ObjValue {}270impl Eq for ObjValue {}285impl Hash for ObjValue {271impl Hash for ObjValue {286 fn hash<H: Hasher>(&self, state: &mut H) {272 fn hash<H: Hasher>(&self, hasher: &mut H) {287 state.write_usize(Rc::as_ptr(&self.0) as usize)273 hasher.write_usize(&*self.0 as *const _ as usize)288 }274 }289}275}290276crates/jrsonnet-evaluator/src/typed.rsdiffbeforeafterboth4 error::{Error, LocError, Result},4 error::{Error, LocError, Result},5 push, Val,5 push, Val,6};6};7use jrsonnet_gc::Trace;7use jrsonnet_parser::ExprLocation;8use jrsonnet_parser::ExprLocation;8use jrsonnet_types::{ComplexValType, ValType};9use jrsonnet_types::{ComplexValType, ValType};9use thiserror::Error;10use thiserror::Error;20 }};21 }};21}22}222323#[derive(Debug, Error, Clone)]24#[derive(Debug, Error, Clone, Trace)]25#[trivially_drop]24pub enum TypeError {26pub enum TypeError {25 #[error("expected {0}, got {1}")]27 #[error("expected {0}, got {1}")]26 ExpectedGot(ComplexValType, ValType),28 ExpectedGot(ComplexValType, ValType),37 }39 }38}40}394140#[derive(Debug, Clone)]42#[derive(Debug, Clone, Trace)]43#[trivially_drop]41pub struct TypeLocError(Box<TypeError>, ValuePathStack);44pub struct TypeLocError(Box<TypeError>, ValuePathStack);42impl From<TypeError> for TypeLocError {45impl From<TypeError> for TypeLocError {43 fn from(e: TypeError) -> Self {46 fn from(e: TypeError) -> Self {59 }62 }60}63}616462#[derive(Debug, Clone)]65#[derive(Debug, Clone, Trace)]66#[trivially_drop]63pub struct TypeLocErrorList(Vec<TypeLocError>);67pub struct TypeLocErrorList(Vec<TypeLocError>);64impl Display for TypeLocErrorList {68impl Display for TypeLocErrorList {65 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {69 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {122 }126 }123}127}124128125#[derive(Clone, Debug)]129#[derive(Clone, Debug, Trace)]130#[trivially_drop]126enum ValuePathItem {131enum ValuePathItem {127 Field(Rc<str>),132 Field(Rc<str>),128 Index(u64),133 Index(u64),137 }142 }138}143}139144140#[derive(Clone, Debug)]145#[derive(Clone, Debug, Trace)]146#[trivially_drop]141struct ValuePathStack(Vec<ValuePathItem>);147struct ValuePathStack(Vec<ValuePathItem>);142impl Display for ValuePathStack {148impl Display for ValuePathStack {143 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {149 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {crates/jrsonnet-evaluator/src/val.rsdiffbeforeafterboth3 call_builtin,3 call_builtin,4 manifest::{manifest_json_ex, ManifestJsonOptions, ManifestType},4 manifest::{manifest_json_ex, ManifestJsonOptions, ManifestType},5 },5 },6 error::Error::*,6 error::{Error::*, LocError},7 evaluate,7 evaluate,8 function::{parse_function_call, parse_function_call_map, place_args},8 function::{parse_function_call, parse_function_call_map, place_args},9 native::NativeCallback,9 native::NativeCallback,10 throw, with_state, Context, ObjValue, Result,10 throw, with_state, Context, ObjValue, Result,11};11};12use jrsonnet_gc::{Finalize, Gc, GcCell, Trace};12use jrsonnet_interner::IStr;13use jrsonnet_interner::IStr;13use jrsonnet_parser::{el, Arg, ArgsDesc, Expr, ExprLocation, LiteralType, LocExpr, ParamsDesc};14use jrsonnet_parser::{el, Arg, ArgsDesc, Expr, ExprLocation, LiteralType, LocExpr, ParamsDesc};14use jrsonnet_types::ValType;15use jrsonnet_types::ValType;15use std::{cell::RefCell, collections::HashMap, fmt::Debug, rc::Rc};16use std::{collections::HashMap, fmt::Debug, rc::Rc};161718pub trait LazyValValue: Trace {19 fn get(self: Box<Self>) -> Result<Val>;20}2122#[derive(Trace)]23#[trivially_drop]17enum LazyValInternals {24enum LazyValInternals {18 Computed(Val),25 Computed(Val),26 Errored(LocError),19 Waiting(Box<dyn Fn() -> Result<Val>>),27 Waiting(Box<dyn LazyValValue>),28 Pending,20}29}3021#[derive(Clone)]31#[derive(Clone, Trace)]32#[trivially_drop]22pub struct LazyVal(Rc<RefCell<LazyValInternals>>);33pub struct LazyVal(Gc<GcCell<LazyValInternals>>);23impl LazyVal {34impl LazyVal {24 pub fn new(f: Box<dyn Fn() -> Result<Val>>) -> Self {35 pub fn new(f: Box<dyn LazyValValue>) -> Self {25 Self(Rc::new(RefCell::new(LazyValInternals::Waiting(f))))36 Self(Gc::new(GcCell::new(LazyValInternals::Waiting(f))))26 }37 }27 pub fn new_resolved(val: Val) -> Self {38 pub fn new_resolved(val: Val) -> Self {28 Self(Rc::new(RefCell::new(LazyValInternals::Computed(val))))39 Self(Gc::new(GcCell::new(LazyValInternals::Computed(val))))29 }40 }30 pub fn evaluate(&self) -> Result<Val> {41 pub fn evaluate(&self) -> Result<Val> {31 let new_value = match &*self.0.borrow() {42 match &*self.0.borrow() {32 LazyValInternals::Computed(v) => return Ok(v.clone()),43 LazyValInternals::Computed(v) => return Ok(v.clone()),33 LazyValInternals::Waiting(f) => f()?,44 LazyValInternals::Errored(e) => return Err(e.clone()),45 LazyValInternals::Pending => return Err(RecursiveLazyValueEvaluation.into()),46 _ => (),34 };47 };48 let value = if let LazyValInternals::Waiting(value) =49 std::mem::replace(&mut *self.0.borrow_mut(), LazyValInternals::Pending)50 {51 value52 } else {53 unreachable!()54 };55 let new_value = match value.get() {56 Ok(v) => v,57 Err(e) => {58 *self.0.borrow_mut() = LazyValInternals::Errored(e.clone());59 return Err(e);60 }61 };35 *self.0.borrow_mut() = LazyValInternals::Computed(new_value.clone());62 *self.0.borrow_mut() = LazyValInternals::Computed(new_value.clone());36 Ok(new_value)63 Ok(new_value)37 }64 }38}65}396640#[macro_export]41macro_rules! lazy_val {42 ($f: expr) => {43 $crate::LazyVal::new(Box::new($f))44 };45}46#[macro_export]47macro_rules! resolved_lazy_val {48 ($f: expr) => {49 $crate::LazyVal::new_resolved($f)50 };51}52impl Debug for LazyVal {67impl Debug for LazyVal {53 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {68 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {54 write!(f, "Lazy")69 write!(f, "Lazy")55 }70 }56}71}57impl PartialEq for LazyVal {72impl PartialEq for LazyVal {58 fn eq(&self, other: &Self) -> bool {73 fn eq(&self, other: &Self) -> bool {59 Rc::ptr_eq(&self.0, &other.0)74 Gc::ptr_eq(&self.0, &other.0)60 }75 }61}76}627763#[derive(Debug, PartialEq)]78#[derive(Debug, PartialEq, Trace)]79#[trivially_drop]64pub struct FuncDesc {80pub struct FuncDesc {65 pub name: IStr,81 pub name: IStr,66 pub ctx: Context,82 pub ctx: Context,67 pub params: ParamsDesc,83 pub params: ParamsDesc,68 pub body: LocExpr,84 pub body: LocExpr,69}85}708671#[derive(Debug)]87#[derive(Debug, Trace)]88#[trivially_drop]72pub enum FuncVal {89pub enum FuncVal {73 /// Plain function implemented in jsonnet90 /// Plain function implemented in jsonnet74 Normal(FuncDesc),91 Normal(FuncDesc),75 /// Standard library function92 /// Standard library function76 Intrinsic(IStr),93 Intrinsic(IStr),77 /// Library functions implemented in native94 /// Library functions implemented in native78 NativeExt(IStr, Rc<NativeCallback>),95 NativeExt(IStr, Gc<NativeCallback>),79}96}809781impl PartialEq for FuncVal {98impl PartialEq for FuncVal {172 String,189 String,173}190}174191175#[derive(Debug, Clone)]192#[derive(Debug, Clone, Trace)]193#[trivially_drop]176pub enum ArrValue {194pub enum ArrValue {177 Lazy(Rc<Vec<LazyVal>>),195 Lazy(Gc<Vec<LazyVal>>),178 Eager(Rc<Vec<Val>>),196 Eager(Gc<Vec<Val>>),179 Extended(Box<(Self, Self)>),197 Extended(Box<(Self, Self)>),180}198}181impl ArrValue {199impl ArrValue {182 pub fn new_eager() -> Self {200 pub fn new_eager() -> Self {183 Self::Eager(Rc::new(Vec::new()))201 Self::Eager(Gc::new(Vec::new()))184 }202 }185203186 pub fn len(&self) -> usize {204 pub fn len(&self) -> usize {231 }249 }232 }250 }233251234 pub fn evaluated(&self) -> Result<Rc<Vec<Val>>> {252 pub fn evaluated(&self) -> Result<Gc<Vec<Val>>> {235 Ok(match self {253 Ok(match self {236 Self::Lazy(vec) => {254 Self::Lazy(vec) => {237 let mut out = Vec::with_capacity(vec.len());255 let mut out = Vec::with_capacity(vec.len());238 for item in vec.iter() {256 for item in vec.iter() {239 out.push(item.evaluate()?);257 out.push(item.evaluate()?);240 }258 }241 Rc::new(out)259 Gc::new(out)242 }260 }243 Self::Eager(vec) => vec.clone(),261 Self::Eager(vec) => vec.clone(),244 Self::Extended(_v) => {262 Self::Extended(_v) => {245 let mut out = Vec::with_capacity(self.len());263 let mut out = Vec::with_capacity(self.len());246 for item in self.iter() {264 for item in self.iter() {247 out.push(item?);265 out.push(item?);248 }266 }249 Rc::new(out)267 Gc::new(out)250 }268 }251 })269 })252 }270 }272 Self::Lazy(vec) => {290 Self::Lazy(vec) => {273 let mut out = (&vec as &Vec<_>).clone();291 let mut out = (&vec as &Vec<_>).clone();274 out.reverse();292 out.reverse();275 Self::Lazy(Rc::new(out))293 Self::Lazy(Gc::new(out))276 }294 }277 Self::Eager(vec) => {295 Self::Eager(vec) => {278 let mut out = (&vec as &Vec<_>).clone();296 let mut out = (&vec as &Vec<_>).clone();279 out.reverse();297 out.reverse();280 Self::Eager(Rc::new(out))298 Self::Eager(Gc::new(out))281 }299 }282 Self::Extended(b) => Self::Extended(Box::new((b.1.reversed(), b.0.reversed()))),300 Self::Extended(b) => Self::Extended(Box::new((b.1.reversed(), b.0.reversed()))),283 }301 }290 out.push(mapper(value?)?);308 out.push(mapper(value?)?);291 }309 }292310293 Ok(Self::Eager(Rc::new(out)))311 Ok(Self::Eager(Gc::new(out)))294 }312 }295313296 pub fn filter(self, filter: impl Fn(&Val) -> Result<bool>) -> Result<Self> {314 pub fn filter(self, filter: impl Fn(&Val) -> Result<bool>) -> Result<Self> {303 }321 }304 }322 }305323306 Ok(Self::Eager(Rc::new(out)))324 Ok(Self::Eager(Gc::new(out)))307 }325 }308326309 pub fn ptr_eq(a: &Self, b: &Self) -> bool {327 pub fn ptr_eq(a: &Self, b: &Self) -> bool {310 match (a, b) {328 match (a, b) {311 (Self::Lazy(a), Self::Lazy(b)) => Rc::ptr_eq(a, b),329 (Self::Lazy(a), Self::Lazy(b)) => Gc::ptr_eq(a, b),312 (Self::Eager(a), Self::Eager(b)) => Rc::ptr_eq(a, b),330 (Self::Eager(a), Self::Eager(b)) => Gc::ptr_eq(a, b),313 _ => false,331 _ => false,314 }332 }315 }333 }316}334}317335318impl From<Vec<LazyVal>> for ArrValue {336impl From<Vec<LazyVal>> for ArrValue {319 fn from(v: Vec<LazyVal>) -> Self {337 fn from(v: Vec<LazyVal>) -> Self {320 Self::Lazy(Rc::new(v))338 Self::Lazy(Gc::new(v))321 }339 }322}340}323341324impl From<Vec<Val>> for ArrValue {342impl From<Vec<Val>> for ArrValue {325 fn from(v: Vec<Val>) -> Self {343 fn from(v: Vec<Val>) -> Self {326 Self::Eager(Rc::new(v))344 Self::Eager(Gc::new(v))327 }345 }328}346}347348#[derive(Debug)]349pub struct DebugGcTraceValue {350 name: IStr,351 pub value: Box<Val>,352}353impl DebugGcTraceValue {354 fn print(&self, action: &str) {355 println!("{} {}#{:?}", action, self.name, &*self.value as *const _)356 }357}358impl Finalize for DebugGcTraceValue {359 fn finalize(&self) {360 self.print("Garbage-collecting")361 }362}363impl Drop for DebugGcTraceValue {364 fn drop(&mut self) {365 self.print("Garbage-collected")366 }367}368unsafe impl Trace for DebugGcTraceValue {369 unsafe fn trace(&self) {370 self.print("Traced");371 self.value.trace()372 }373 unsafe fn root(&self) {374 self.print("Rooted");375 self.value.root()376 }377 unsafe fn unroot(&self) {378 self.print("Unrooted");379 self.value.unroot()380 }381 fn finalize_glue(&self) {382 Finalize::finalize(self)383 }384}385impl Clone for DebugGcTraceValue {386 fn clone(&self) -> Self {387 self.print("Cloned");388 let value = Self {389 name: self.name.clone(),390 value: self.value.clone(),391 };392 value.print("I'm clone");393 value394 }395}396impl DebugGcTraceValue {397 pub fn create(name: IStr, value: Val) -> Val {398 let value = Self {399 name,400 value: Box::new(value),401 };402 value.print("Constructed");403 Val::DebugGcTraceValue(value)404 }405}329406330#[derive(Debug, Clone)]407#[derive(Debug, Clone, Trace)]408#[trivially_drop]331pub enum Val {409pub enum Val {332 Bool(bool),410 Bool(bool),333 Null,411 Null,334 Str(IStr),412 Str(IStr),335 Num(f64),413 Num(f64),336 Arr(ArrValue),414 Arr(ArrValue),337 Obj(ObjValue),415 Obj(ObjValue),338 Func(Rc<FuncVal>),416 Func(Gc<FuncVal>),417 DebugGcTraceValue(DebugGcTraceValue),339}418}340419341macro_rules! matches_unwrap {420macro_rules! matches_unwrap {368 pub fn unwrap_num(self) -> Result<f64> {447 pub fn unwrap_num(self) -> Result<f64> {369 Ok(matches_unwrap!(self, Self::Num(v), v))448 Ok(matches_unwrap!(self, Self::Num(v), v))370 }449 }371 pub fn unwrap_func(self) -> Result<Rc<FuncVal>> {450 pub fn unwrap_func(self) -> Result<Gc<FuncVal>> {372 Ok(matches_unwrap!(self, Self::Func(v), v))451 Ok(matches_unwrap!(self, Self::Func(v), v))373 }452 }374 pub fn try_cast_bool(self, context: &'static str) -> Result<bool> {453 pub fn try_cast_bool(self, context: &'static str) -> Result<bool> {392 Self::Bool(_) => ValType::Bool,471 Self::Bool(_) => ValType::Bool,393 Self::Null => ValType::Null,472 Self::Null => ValType::Null,394 Self::Func(..) => ValType::Func,473 Self::Func(..) => ValType::Func,474 Self::DebugGcTraceValue(v) => v.value.value_type(),395 }475 }396 }476 }397477crates/jrsonnet-interner/Cargo.tomldiffbeforeafterboth9[dependencies]9[dependencies]10serde = { version = "1.0" }10serde = { version = "1.0" }11rustc-hash = "1.1.0"11rustc-hash = "1.1.0"12jrsonnet-gc = { version = "0.4.2", features = ["derive"] }1213crates/jrsonnet-interner/src/lib.rsdiffbeforeafterboth1use jrsonnet_gc::{unsafe_empty_trace, Finalize, Trace};1use rustc_hash::FxHashMap;2use rustc_hash::FxHashMap;2use serde::{Deserialize, Serialize};3use serde::{Deserialize, Serialize};3use std::{4use std::{101111#[derive(Clone, PartialOrd, Ord, Eq)]12#[derive(Clone, PartialOrd, Ord, Eq)]12pub struct IStr(Rc<str>);13pub struct IStr(Rc<str>);14impl Finalize for IStr {}15unsafe impl Trace for IStr {16 unsafe_empty_trace!();17}131814impl Deref for IStr {19impl Deref for IStr {15 type Target = str;20 type Target = str;crates/jrsonnet-parser/Cargo.tomldiffbeforeafterboth18unescape = "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 }21jrsonnet-gc = { version = "0.4.2", features = ["derive"] }212222[dev-dependencies]23[dev-dependencies]23jrsonnet-stdlib = { path = "../jrsonnet-stdlib", version = "0.3.8" }24jrsonnet-stdlib = { path = "../jrsonnet-stdlib", version = "0.3.8" }crates/jrsonnet-parser/src/expr.rsdiffbeforeafterboth1use jrsonnet_gc::{unsafe_empty_trace, Finalize, Trace};1use jrsonnet_interner::IStr;2use jrsonnet_interner::IStr;2#[cfg(feature = "deserialize")]3#[cfg(feature = "deserialize")]3use serde::Deserialize;4use serde::Deserialize;121313#[cfg_attr(feature = "serialize", derive(Serialize))]14#[cfg_attr(feature = "serialize", derive(Serialize))]14#[cfg_attr(feature = "deserialize", derive(Deserialize))]15#[cfg_attr(feature = "deserialize", derive(Deserialize))]15#[derive(Debug, PartialEq)]16#[derive(Debug, PartialEq, Trace)]17#[trivially_drop]16pub enum FieldName {18pub enum FieldName {17 /// {fixed: 2}19 /// {fixed: 2}18 Fixed(IStr),20 Fixed(IStr),222423#[cfg_attr(feature = "serialize", derive(Serialize))]25#[cfg_attr(feature = "serialize", derive(Serialize))]24#[cfg_attr(feature = "deserialize", derive(Deserialize))]26#[cfg_attr(feature = "deserialize", derive(Deserialize))]25#[derive(Debug, Clone, Copy, PartialEq)]27#[derive(Debug, Clone, Copy, PartialEq, Trace)]28#[trivially_drop]26pub enum Visibility {29pub enum Visibility {27 /// :30 /// :28 Normal,31 Normal,404341#[cfg_attr(feature = "serialize", derive(Serialize))]44#[cfg_attr(feature = "serialize", derive(Serialize))]42#[cfg_attr(feature = "deserialize", derive(Deserialize))]45#[cfg_attr(feature = "deserialize", derive(Deserialize))]43#[derive(Clone, Debug, PartialEq)]46#[derive(Clone, Debug, PartialEq, Trace)]47#[trivially_drop]44pub struct AssertStmt(pub LocExpr, pub Option<LocExpr>);48pub struct AssertStmt(pub LocExpr, pub Option<LocExpr>);454946#[cfg_attr(feature = "serialize", derive(Serialize))]50#[cfg_attr(feature = "serialize", derive(Serialize))]47#[cfg_attr(feature = "deserialize", derive(Deserialize))]51#[cfg_attr(feature = "deserialize", derive(Deserialize))]48#[derive(Debug, PartialEq)]52#[derive(Debug, PartialEq, Trace)]53#[trivially_drop]49pub struct FieldMember {54pub struct FieldMember {50 pub name: FieldName,55 pub name: FieldName,51 pub plus: bool,56 pub plus: bool,566157#[cfg_attr(feature = "serialize", derive(Serialize))]62#[cfg_attr(feature = "serialize", derive(Serialize))]58#[cfg_attr(feature = "deserialize", derive(Deserialize))]63#[cfg_attr(feature = "deserialize", derive(Deserialize))]59#[derive(Debug, PartialEq)]64#[derive(Debug, PartialEq, Trace)]65#[trivially_drop]60pub enum Member {66pub enum Member {61 Field(FieldMember),67 Field(FieldMember),62 BindStmt(BindSpec),68 BindStmt(BindSpec),657166#[cfg_attr(feature = "serialize", derive(Serialize))]72#[cfg_attr(feature = "serialize", derive(Serialize))]67#[cfg_attr(feature = "deserialize", derive(Deserialize))]73#[cfg_attr(feature = "deserialize", derive(Deserialize))]68#[derive(Debug, Clone, Copy, PartialEq)]74#[derive(Debug, Clone, Copy, PartialEq, Trace)]75#[trivially_drop]69pub enum UnaryOpType {76pub enum UnaryOpType {70 Plus,77 Plus,71 Minus,78 Minus,909891#[cfg_attr(feature = "serialize", derive(Serialize))]99#[cfg_attr(feature = "serialize", derive(Serialize))]92#[cfg_attr(feature = "deserialize", derive(Deserialize))]100#[cfg_attr(feature = "deserialize", derive(Deserialize))]93#[derive(Debug, Clone, Copy, PartialEq)]101#[derive(Debug, Clone, Copy, PartialEq, Trace)]102#[trivially_drop]94pub enum BinaryOpType {103pub enum BinaryOpType {95 Mul,104 Mul,96 Div,105 Div,152/// name, default value162/// name, default value153#[cfg_attr(feature = "serialize", derive(Serialize))]163#[cfg_attr(feature = "serialize", derive(Serialize))]154#[cfg_attr(feature = "deserialize", derive(Deserialize))]164#[cfg_attr(feature = "deserialize", derive(Deserialize))]155#[derive(Debug, PartialEq)]165#[derive(Debug, PartialEq, Trace)]166#[trivially_drop]156pub struct Param(pub IStr, pub Option<LocExpr>);167pub struct Param(pub IStr, pub Option<LocExpr>);157168158/// Defined function parameters169/// Defined function parameters161#[derive(Debug, Clone, PartialEq)]172#[derive(Debug, Clone, PartialEq)]162pub struct ParamsDesc(pub Rc<Vec<Param>>);173pub struct ParamsDesc(pub Rc<Vec<Param>>);174175/// Safety:176/// AST is acyclic, and there should be no gc pointers177unsafe impl Trace for ParamsDesc {178 unsafe_empty_trace!();179}180impl Finalize for ParamsDesc {}181163impl Deref for ParamsDesc {182impl Deref for ParamsDesc {164 type Target = Vec<Param>;183 type Target = Vec<Param>;169188170#[cfg_attr(feature = "serialize", derive(Serialize))]189#[cfg_attr(feature = "serialize", derive(Serialize))]171#[cfg_attr(feature = "deserialize", derive(Deserialize))]190#[cfg_attr(feature = "deserialize", derive(Deserialize))]172#[derive(Debug, PartialEq)]191#[derive(Debug, PartialEq, Trace)]192#[trivially_drop]173pub struct Arg(pub Option<String>, pub LocExpr);193pub struct Arg(pub Option<String>, pub LocExpr);174194175#[cfg_attr(feature = "serialize", derive(Serialize))]195#[cfg_attr(feature = "serialize", derive(Serialize))]176#[cfg_attr(feature = "deserialize", derive(Deserialize))]196#[cfg_attr(feature = "deserialize", derive(Deserialize))]177#[derive(Debug, PartialEq)]197#[derive(Debug, PartialEq, Trace)]198#[trivially_drop]178pub struct ArgsDesc(pub Vec<Arg>);199pub struct ArgsDesc(pub Vec<Arg>);200179impl Deref for ArgsDesc {201impl Deref for ArgsDesc {185207186#[cfg_attr(feature = "serialize", derive(Serialize))]208#[cfg_attr(feature = "serialize", derive(Serialize))]187#[cfg_attr(feature = "deserialize", derive(Deserialize))]209#[cfg_attr(feature = "deserialize", derive(Deserialize))]188#[derive(Debug, Clone, PartialEq)]210#[derive(Debug, Clone, PartialEq, Trace)]211#[trivially_drop]189pub struct BindSpec {212pub struct BindSpec {190 pub name: IStr,213 pub name: IStr,191 pub params: Option<ParamsDesc>,214 pub params: Option<ParamsDesc>,194217195#[cfg_attr(feature = "serialize", derive(Serialize))]218#[cfg_attr(feature = "serialize", derive(Serialize))]196#[cfg_attr(feature = "deserialize", derive(Deserialize))]219#[cfg_attr(feature = "deserialize", derive(Deserialize))]197#[derive(Debug, PartialEq)]220#[derive(Debug, PartialEq, Trace)]221#[trivially_drop]198pub struct IfSpecData(pub LocExpr);222pub struct IfSpecData(pub LocExpr);199223200#[cfg_attr(feature = "serialize", derive(Serialize))]224#[cfg_attr(feature = "serialize", derive(Serialize))]201#[cfg_attr(feature = "deserialize", derive(Deserialize))]225#[cfg_attr(feature = "deserialize", derive(Deserialize))]202#[derive(Debug, PartialEq)]226#[derive(Debug, PartialEq, Trace)]227#[trivially_drop]203pub struct ForSpecData(pub IStr, pub LocExpr);228pub struct ForSpecData(pub IStr, pub LocExpr);204229205#[cfg_attr(feature = "serialize", derive(Serialize))]230#[cfg_attr(feature = "serialize", derive(Serialize))]206#[cfg_attr(feature = "deserialize", derive(Deserialize))]231#[cfg_attr(feature = "deserialize", derive(Deserialize))]207#[derive(Debug, PartialEq)]232#[derive(Debug, PartialEq, Trace)]233#[trivially_drop]208pub enum CompSpec {234pub enum CompSpec {209 IfSpec(IfSpecData),235 IfSpec(IfSpecData),210 ForSpec(ForSpecData),236 ForSpec(ForSpecData),211}237}212238213#[cfg_attr(feature = "serialize", derive(Serialize))]239#[cfg_attr(feature = "serialize", derive(Serialize))]214#[cfg_attr(feature = "deserialize", derive(Deserialize))]240#[cfg_attr(feature = "deserialize", derive(Deserialize))]215#[derive(Debug, PartialEq)]241#[derive(Debug, PartialEq, Trace)]242#[trivially_drop]216pub struct ObjComp {243pub struct ObjComp {217 pub pre_locals: Vec<BindSpec>,244 pub pre_locals: Vec<BindSpec>,218 pub key: LocExpr,245 pub key: LocExpr,223250224#[cfg_attr(feature = "serialize", derive(Serialize))]251#[cfg_attr(feature = "serialize", derive(Serialize))]225#[cfg_attr(feature = "deserialize", derive(Deserialize))]252#[cfg_attr(feature = "deserialize", derive(Deserialize))]226#[derive(Debug, PartialEq)]253#[derive(Debug, PartialEq, Trace)]254#[trivially_drop]227pub enum ObjBody {255pub enum ObjBody {228 MemberList(Vec<Member>),256 MemberList(Vec<Member>),229 ObjComp(ObjComp),257 ObjComp(ObjComp),230}258}231259232#[cfg_attr(feature = "serialize", derive(Serialize))]260#[cfg_attr(feature = "serialize", derive(Serialize))]233#[cfg_attr(feature = "deserialize", derive(Deserialize))]261#[cfg_attr(feature = "deserialize", derive(Deserialize))]234#[derive(Debug, PartialEq, Clone, Copy)]262#[derive(Debug, PartialEq, Clone, Copy, Trace)]263#[trivially_drop]235pub enum LiteralType {264pub enum LiteralType {236 This,265 This,237 Super,266 Super,241 False,270 False,242}271}243272244#[derive(Debug, PartialEq)]273#[derive(Debug, PartialEq, Trace)]274#[trivially_drop]245pub struct SliceDesc {275pub struct SliceDesc {246 pub start: Option<LocExpr>,276 pub start: Option<LocExpr>,247 pub end: Option<LocExpr>,277 pub end: Option<LocExpr>,251/// Syntax base281/// Syntax base252#[cfg_attr(feature = "serialize", derive(Serialize))]282#[cfg_attr(feature = "serialize", derive(Serialize))]253#[cfg_attr(feature = "deserialize", derive(Deserialize))]283#[cfg_attr(feature = "deserialize", derive(Deserialize))]254#[derive(Debug, PartialEq)]284#[derive(Debug, PartialEq, Trace)]285#[trivially_drop]255pub enum Expr {286pub enum Expr {256 Literal(LiteralType),287 Literal(LiteralType),257288319/// file, begin offset, end offset350/// file, begin offset, end offset320#[cfg_attr(feature = "serialize", derive(Serialize))]351#[cfg_attr(feature = "serialize", derive(Serialize))]321#[cfg_attr(feature = "deserialize", derive(Deserialize))]352#[cfg_attr(feature = "deserialize", derive(Deserialize))]322#[derive(Clone, PartialEq)]353#[derive(Clone, PartialEq, Trace)]354#[trivially_drop]323pub struct ExprLocation(pub Rc<Path>, pub usize, pub usize);355pub struct ExprLocation(pub Rc<Path>, pub usize, pub usize);356324impl Debug for ExprLocation {357impl Debug for ExprLocation {332#[cfg_attr(feature = "deserialize", derive(Deserialize))]365#[cfg_attr(feature = "deserialize", derive(Deserialize))]333#[derive(Clone, PartialEq)]366#[derive(Clone, PartialEq)]334pub struct LocExpr(pub Rc<Expr>, pub Option<ExprLocation>);367pub struct LocExpr(pub Rc<Expr>, pub Option<ExprLocation>);368/// Safety:369/// AST is acyclic, and there should be no gc pointers370unsafe impl Trace for LocExpr {371 unsafe_empty_trace!();372}373impl Finalize for LocExpr {}374335impl Debug for LocExpr {375impl Debug for LocExpr {336 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {376 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {crates/jrsonnet-types/Cargo.tomldiffbeforeafterboth889[dependencies]9[dependencies]10peg = "0.7.0"10peg = "0.7.0"11jrsonnet-gc = { version = "0.4.2", features = ["derive"] }1112crates/jrsonnet-types/src/lib.rsdiffbeforeafterboth1#![allow(clippy::redundant_closure_call)]1#![allow(clippy::redundant_closure_call)]223use jrsonnet_gc::Trace;3use std::fmt::Display;4use std::fmt::Display;455#[macro_export]6#[macro_export]77 );78 );78}79}798080#[derive(Debug, Clone, Copy, PartialEq, Eq)]81#[derive(Debug, Clone, Copy, PartialEq, Eq, Trace)]82#[trivially_drop]81pub enum ValType {83pub enum ValType {82 Bool,84 Bool,83 Null,85 Null,109 }111 }110}112}111113112#[derive(Debug, Clone, PartialEq)]114#[derive(Debug, Clone, PartialEq, Trace)]115#[trivially_drop]113pub enum ComplexValType {116pub enum ComplexValType {114 Any,117 Any,115 Char,118 Char,flake.lockdiffbeforeafterboth2 "nodes": {2 "nodes": {3 "flake-utils": {3 "flake-utils": {4 "locked": {4 "locked": {5 "lastModified": 1614513358,5 "lastModified": 1623875721,6 "narHash": "sha256-LakhOx3S1dRjnh0b5Dg3mbZyH0ToC9I8Y2wKSkBaTzU=",6 "narHash": "sha256-A8BU7bjS5GirpAUv4QA+QnJ4CceLHkcXdRp4xITDB0s=",7 "owner": "numtide",7 "owner": "numtide",8 "repo": "flake-utils",8 "repo": "flake-utils",9 "rev": "5466c5bbece17adaab2d82fae80b46e807611bf3",9 "rev": "f7e004a55b120c02ecb6219596820fcd32ca8772",10 "type": "github"10 "type": "github"11 },11 },12 "original": {12 "original": {17 },17 },18 "nixpkgs": {18 "nixpkgs": {19 "locked": {19 "locked": {20 "lastModified": 1615532953,20 "lastModified": 1625281901,21 "narHash": "sha256-SWpaGjrp/INzorEqMz3HLi6Uuk9I0KAn4YS8B4n3q5g=",21 "narHash": "sha256-DkZDtTIPzhXATqIps2ifNFpnI+PTcfMYdcrx/oFm00Q=",22 "owner": "NixOS",22 "owner": "NixOS",23 "repo": "nixpkgs",23 "repo": "nixpkgs",24 "rev": "916ee862e87ac5ee2439f2fb7856386b4dc906ae",24 "rev": "09c38c29f2c719cd76ca17a596c2fdac9e186ceb",25 "type": "github"25 "type": "github"26 },26 },27 "original": {27 "original": {flake.nixdiffbeforeafterboth12 pname = "jrsonnet";12 pname = "jrsonnet";13 version = "0.1.0";13 version = "0.1.0";14 src = self;14 src = self;15 cargoSha256 = "sha256-6VhaQi3L2LWzR0cq7oRG81MDbrKJbzSNPcvYSoQ5ISo=";15 cargoSha256 = "sha256-cez8pJ/uwj+PHAPQwpSB4CKaxcP8Uvv8xguOrVXR2xE=";16 };16 };17 in { 17 in { 18 defaultPackage = jrsonnet;18 defaultPackage = jrsonnet;