difftreelog
refactor remove implicit global state
in: master
31 files changed
bindings/jsonnet/src/import.rsdiffbeforeafterboth151516use jrsonnet_evaluator::{16use jrsonnet_evaluator::{17 error::{Error::*, Result},17 error::{Error::*, Result},18 throw, EvaluationState, ImportResolver,18 throw, ImportResolver, State,19};19};202021pub type JsonnetImportCallback = unsafe extern "C" fn(21pub type JsonnetImportCallback = unsafe extern "C" fn(87/// # Safety87/// # Safety88#[no_mangle]88#[no_mangle]89pub unsafe extern "C" fn jsonnet_import_callback(89pub unsafe extern "C" fn jsonnet_import_callback(90 vm: &EvaluationState,90 vm: &State,91 cb: JsonnetImportCallback,91 cb: JsonnetImportCallback,92 ctx: *mut c_void,92 ctx: *mut c_void,93) {93) {141///141///142/// This function is safe, if received v is a pointer to normal C string142/// This function is safe, if received v is a pointer to normal C string143#[no_mangle]143#[no_mangle]144pub unsafe extern "C" fn jsonnet_jpath_add(vm: &EvaluationState, v: *const c_char) {144pub unsafe extern "C" fn jsonnet_jpath_add(vm: &State, v: *const c_char) {145 let cstr = CStr::from_ptr(v);145 let cstr = CStr::from_ptr(v);146 let path = PathBuf::from(cstr.to_str().unwrap());146 let path = PathBuf::from(cstr.to_str().unwrap());147 let any_resolver = &vm.settings().import_resolver;147 let any_resolver = &vm.settings().import_resolver;bindings/jsonnet/src/interop.rsdiffbeforeafterboth5 os::raw::{c_char, c_int},5 os::raw::{c_char, c_int},6};6};778use jrsonnet_evaluator::{EvaluationState, Val};8use jrsonnet_evaluator::{State, Val};9910use crate::{import::jsonnet_import_callback, native::jsonnet_native_callback};10use crate::{import::jsonnet_import_callback, native::jsonnet_native_callback};1111282829/// # Safety29/// # Safety30#[no_mangle]30#[no_mangle]31pub unsafe extern "C" fn jrsonnet_apply_static_import_callback(31pub unsafe extern "C" fn jrsonnet_apply_static_import_callback(vm: &State, ctx: *mut c_void) {32 vm: &EvaluationState,33 ctx: *mut c_void,34) {35 jsonnet_import_callback(vm, _jrsonnet_static_import_callback, ctx)32 jsonnet_import_callback(vm, _jrsonnet_static_import_callback, ctx)38/// # Safety35/// # Safety39#[no_mangle]36#[no_mangle]40pub unsafe extern "C" fn jrsonnet_apply_static_native_callback(37pub unsafe extern "C" fn jrsonnet_apply_static_native_callback(41 vm: &EvaluationState,38 vm: &State,42 name: *const c_char,39 name: *const c_char,43 ctx: *mut c_void,40 ctx: *mut c_void,44 raw_params: *const *const c_char,41 raw_params: *const *const c_char,47}44}484549#[no_mangle]46#[no_mangle]50pub extern "C" fn jrsonnet_set_trace_format(vm: &EvaluationState, format: u8) {47pub extern "C" fn jrsonnet_set_trace_format(vm: &State, format: u8) {51 use jrsonnet_evaluator::trace::JsFormat;48 use jrsonnet_evaluator::trace::JsFormat;52 match format {49 match format {53 1 => vm.set_trace_format(Box::new(JsFormat)),50 1 => vm.set_trace_format(Box::new(JsFormat)),bindings/jsonnet/src/lib.rsdiffbeforeafterboth16};16};171718use import::NativeImportResolver;18use import::NativeImportResolver;19use jrsonnet_evaluator::{EvaluationState, IStr, ManifestFormat, Val};19use jrsonnet_evaluator::{IStr, ManifestFormat, State, Val};202021/// WASM stub21/// WASM stub22#[cfg(target_arch = "wasm32")]22#[cfg(target_arch = "wasm32")]29}29}303031#[no_mangle]31#[no_mangle]32pub extern "C" fn jsonnet_make() -> *mut EvaluationState {32pub extern "C" fn jsonnet_make() -> *mut State {33 let state = EvaluationState::default();33 let state = State::default();34 state.with_stdlib();34 state.with_stdlib();35 state.settings_mut().import_resolver = Box::new(NativeImportResolver::default());35 state.settings_mut().import_resolver = Box::new(NativeImportResolver::default());36 Box::into_raw(Box::new(state))36 Box::into_raw(Box::new(state))39/// # Safety39/// # Safety40#[no_mangle]40#[no_mangle]41#[allow(clippy::boxed_local)]41#[allow(clippy::boxed_local)]42pub unsafe extern "C" fn jsonnet_destroy(vm: *mut EvaluationState) {42pub unsafe extern "C" fn jsonnet_destroy(vm: *mut State) {43 Box::from_raw(vm);43 Box::from_raw(vm);44}44}454546#[no_mangle]46#[no_mangle]47pub extern "C" fn jsonnet_max_stack(vm: &EvaluationState, v: c_uint) {47pub extern "C" fn jsonnet_max_stack(vm: &State, v: c_uint) {48 vm.settings_mut().max_stack = v as usize;48 vm.settings_mut().max_stack = v as usize;49}49}505051// jrsonnet currently have no GC, so these functions is no-op51// jrsonnet currently have no GC, so these functions is no-op52#[no_mangle]52#[no_mangle]53pub extern "C" fn jsonnet_gc_min_objects(_vm: &EvaluationState, _v: c_uint) {}53pub extern "C" fn jsonnet_gc_min_objects(_vm: &State, _v: c_uint) {}54#[no_mangle]54#[no_mangle]55pub extern "C" fn jsonnet_gc_growth_trigger(_vm: &EvaluationState, _v: c_double) {}55pub extern "C" fn jsonnet_gc_growth_trigger(_vm: &State, _v: c_double) {}565657#[no_mangle]57#[no_mangle]58pub extern "C" fn jsonnet_string_output(vm: &EvaluationState, v: c_int) {58pub extern "C" fn jsonnet_string_output(vm: &State, v: c_int) {59 match v {59 match v {60 1 => vm.set_manifest_format(ManifestFormat::String),60 1 => vm.set_manifest_format(ManifestFormat::String),61 0 => vm.set_manifest_format(ManifestFormat::Json {61 0 => vm.set_manifest_format(ManifestFormat::Json {71///71///72/// This function is most definitely broken, but it works somehow, see TODO inside72/// This function is most definitely broken, but it works somehow, see TODO inside73#[no_mangle]73#[no_mangle]74pub unsafe extern "C" fn jsonnet_realloc(74pub unsafe extern "C" fn jsonnet_realloc(_vm: &State, buf: *mut u8, sz: usize) -> *mut u8 {75 _vm: &EvaluationState,76 buf: *mut u8,77 sz: usize,78) -> *mut u8 {95/// # Safety91/// # Safety96#[no_mangle]92#[no_mangle]97#[allow(clippy::boxed_local)]93#[allow(clippy::boxed_local)]98pub unsafe extern "C" fn jsonnet_json_destroy(_vm: &EvaluationState, v: *mut Val) {94pub unsafe extern "C" fn jsonnet_json_destroy(_vm: &State, v: *mut Val) {99 Box::from_raw(v);95 Box::from_raw(v);100}96}10197102#[no_mangle]98#[no_mangle]103pub extern "C" fn jsonnet_max_trace(vm: &EvaluationState, v: c_uint) {99pub extern "C" fn jsonnet_max_trace(vm: &State, v: c_uint) {104 vm.set_max_trace(v as usize)100 vm.set_max_trace(v as usize)105}101}106102109/// This function is safe, if received v is a pointer to normal C string105/// This function is safe, if received v is a pointer to normal C string110#[no_mangle]106#[no_mangle]111pub unsafe extern "C" fn jsonnet_evaluate_file(107pub unsafe extern "C" fn jsonnet_evaluate_file(112 vm: &EvaluationState,108 vm: &State,113 filename: *const c_char,109 filename: *const c_char,114 error: &mut c_int,110 error: &mut c_int,115) -> *const c_char {111) -> *const c_char {116 vm.run_in_state(|| {117 let filename = CStr::from_ptr(filename);112 let filename = CStr::from_ptr(filename);118 match vm113 match vm119 .evaluate_file_raw_nocwd(&PathBuf::from(filename.to_str().unwrap()))114 .evaluate_file_raw_nocwd(&PathBuf::from(filename.to_str().unwrap()))130 CString::new(&out as &str).unwrap().into_raw()125 CString::new(&out as &str).unwrap().into_raw()131 }126 }132 }127 }133 })134}128}135129136/// # Safety130/// # Safety137///131///138/// This function is safe, if received v is a pointer to normal C string132/// This function is safe, if received v is a pointer to normal C string139#[no_mangle]133#[no_mangle]140pub unsafe extern "C" fn jsonnet_evaluate_snippet(134pub unsafe extern "C" fn jsonnet_evaluate_snippet(141 vm: &EvaluationState,135 vm: &State,142 filename: *const c_char,136 filename: *const c_char,143 snippet: *const c_char,137 snippet: *const c_char,144 error: &mut c_int,138 error: &mut c_int,145) -> *const c_char {139) -> *const c_char {146 vm.run_in_state(|| {147 let filename = CStr::from_ptr(filename);140 let filename = CStr::from_ptr(filename);148 let snippet = CStr::from_ptr(snippet);141 let snippet = CStr::from_ptr(snippet);149 match vm142 match vm164 CString::new(&out as &str).unwrap().into_raw()157 CString::new(&out as &str).unwrap().into_raw()165 }158 }166 }159 }167 })168}160}169161170fn multi_to_raw(multi: Vec<(IStr, IStr)>) -> *const c_char {162fn multi_to_raw(multi: Vec<(IStr, IStr)>) -> *const c_char {187/// # Safety179/// # Safety188#[no_mangle]180#[no_mangle]189pub unsafe extern "C" fn jsonnet_evaluate_file_multi(181pub unsafe extern "C" fn jsonnet_evaluate_file_multi(190 vm: &EvaluationState,182 vm: &State,191 filename: *const c_char,183 filename: *const c_char,192 error: &mut c_int,184 error: &mut c_int,193) -> *const c_char {185) -> *const c_char {194 vm.run_in_state(|| {195 let filename = CStr::from_ptr(filename);186 let filename = CStr::from_ptr(filename);196 match vm187 match vm197 .evaluate_file_raw_nocwd(&PathBuf::from(filename.to_str().unwrap()))188 .evaluate_file_raw_nocwd(&PathBuf::from(filename.to_str().unwrap()))208 CString::new(&out as &str).unwrap().into_raw()199 CString::new(&out as &str).unwrap().into_raw()209 }200 }210 }201 }211 })212}202}213203214/// # Safety204/// # Safety215#[no_mangle]205#[no_mangle]216pub unsafe extern "C" fn jsonnet_evaluate_snippet_multi(206pub unsafe extern "C" fn jsonnet_evaluate_snippet_multi(217 vm: &EvaluationState,207 vm: &State,218 filename: *const c_char,208 filename: *const c_char,219 snippet: *const c_char,209 snippet: *const c_char,220 error: &mut c_int,210 error: &mut c_int,221) -> *const c_char {211) -> *const c_char {222 vm.run_in_state(|| {223 let filename = CStr::from_ptr(filename);212 let filename = CStr::from_ptr(filename);224 let snippet = CStr::from_ptr(snippet);213 let snippet = CStr::from_ptr(snippet);225 match vm214 match vm240 CString::new(&out as &str).unwrap().into_raw()229 CString::new(&out as &str).unwrap().into_raw()241 }230 }242 }231 }243 })244}232}245233246fn stream_to_raw(multi: Vec<IStr>) -> *const c_char {234fn stream_to_raw(multi: Vec<IStr>) -> *const c_char {261/// # Safety249/// # Safety262#[no_mangle]250#[no_mangle]263pub unsafe extern "C" fn jsonnet_evaluate_file_stream(251pub unsafe extern "C" fn jsonnet_evaluate_file_stream(264 vm: &EvaluationState,252 vm: &State,265 filename: *const c_char,253 filename: *const c_char,266 error: &mut c_int,254 error: &mut c_int,267) -> *const c_char {255) -> *const c_char {268 vm.run_in_state(|| {269 let filename = CStr::from_ptr(filename);256 let filename = CStr::from_ptr(filename);270 match vm257 match vm271 .evaluate_file_raw_nocwd(&PathBuf::from(filename.to_str().unwrap()))258 .evaluate_file_raw_nocwd(&PathBuf::from(filename.to_str().unwrap()))282 CString::new(&out as &str).unwrap().into_raw()269 CString::new(&out as &str).unwrap().into_raw()283 }270 }284 }271 }285 })286}272}287273288/// # Safety274/// # Safety289#[no_mangle]275#[no_mangle]290pub unsafe extern "C" fn jsonnet_evaluate_snippet_stream(276pub unsafe extern "C" fn jsonnet_evaluate_snippet_stream(291 vm: &EvaluationState,277 vm: &State,292 filename: *const c_char,278 filename: *const c_char,293 snippet: *const c_char,279 snippet: *const c_char,294 error: &mut c_int,280 error: &mut c_int,295) -> *const c_char {281) -> *const c_char {296 vm.run_in_state(|| {297 let filename = CStr::from_ptr(filename);282 let filename = CStr::from_ptr(filename);298 let snippet = CStr::from_ptr(snippet);283 let snippet = CStr::from_ptr(snippet);299 match vm284 match vm314 CString::new(&out as &str).unwrap().into_raw()299 CString::new(&out as &str).unwrap().into_raw()315 }300 }316 }301 }317 })318}302}319303bindings/jsonnet/src/native.rsdiffbeforeafterboth1use std::{1use std::{2 convert::TryFrom,3 ffi::{c_void, CStr},2 ffi::{c_void, CStr},4 os::raw::{c_char, c_int},3 os::raw::{c_char, c_int},5 path::Path,4 path::Path,12 function::BuiltinParam,11 function::BuiltinParam,13 gc::TraceBox,12 gc::TraceBox,14 native::{NativeCallback, NativeCallbackHandler},13 native::{NativeCallback, NativeCallbackHandler},15 EvaluationState, IStr, Val,14 typed::Typed,15 IStr, State, Val,16};16};171718type JsonnetNativeCallback = unsafe extern "C" fn(18type JsonnetNativeCallback = unsafe extern "C" fn(29 cb: JsonnetNativeCallback,29 cb: JsonnetNativeCallback,30}30}31impl NativeCallbackHandler for JsonnetNativeCallbackHandler {31impl NativeCallbackHandler for JsonnetNativeCallbackHandler {32 fn call(&self, _from: Option<Rc<Path>>, args: &[Val]) -> Result<Val, LocError> {32 fn call(&self, s: State, _from: Option<Rc<Path>>, args: &[Val]) -> Result<Val, LocError> {33 let mut n_args = Vec::new();33 let mut n_args = Vec::new();34 for a in args {34 for a in args {35 n_args.push(Some(Box::new(a.clone())));35 n_args.push(Some(Box::new(a.clone())));47 if success == 1 {47 if success == 1 {48 Ok(v)48 Ok(v)49 } else {49 } else {50 let e = IStr::try_from(v).expect("error msg");50 let e = IStr::from_untyped(v, s).expect("error msg");51 Err(Error::RuntimeError(e).into())51 Err(Error::RuntimeError(e).into())52 }52 }53 }53 }56/// # Safety56/// # Safety57#[no_mangle]57#[no_mangle]58pub unsafe extern "C" fn jsonnet_native_callback(58pub unsafe extern "C" fn jsonnet_native_callback(59 vm: &EvaluationState,59 vm: &State,60 name: *const c_char,60 name: *const c_char,61 cb: JsonnetNativeCallback,61 cb: JsonnetNativeCallback,62 ctx: *const c_void,62 ctx: *const c_void,bindings/jsonnet/src/val_extract.rsdiffbeforeafterboth5 os::raw::{c_char, c_double, c_int},5 os::raw::{c_char, c_double, c_int},6};6};778use jrsonnet_evaluator::{EvaluationState, Val};8use jrsonnet_evaluator::{State, Val};9910#[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: &State, v: &Val) -> *mut c_char {12 match v {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 }16}16}17#[no_mangle]17#[no_mangle]18pub extern "C" fn jsonnet_json_extract_number(18pub extern "C" fn jsonnet_json_extract_number(_vm: &State, v: &Val, out: &mut c_double) -> c_int {19 _vm: &EvaluationState,20 v: &Val,21 out: &mut c_double,22) -> c_int {29 }25 }30}26}31#[no_mangle]27#[no_mangle]32pub extern "C" fn jsonnet_json_extract_bool(_vm: &EvaluationState, v: &Val) -> c_int {28pub extern "C" fn jsonnet_json_extract_bool(_vm: &State, v: &Val) -> c_int {33 match v {29 match v {34 Val::Bool(false) => 0,30 Val::Bool(false) => 0,35 Val::Bool(true) => 1,31 Val::Bool(true) => 1,36 _ => 2,32 _ => 2,37 }33 }38}34}39#[no_mangle]35#[no_mangle]40pub extern "C" fn jsonnet_json_extract_null(_vm: &EvaluationState, v: &Val) -> c_int {36pub extern "C" fn jsonnet_json_extract_null(_vm: &State, v: &Val) -> c_int {41 match v {37 match v {42 Val::Null => 1,38 Val::Null => 1,43 _ => 0,39 _ => 0,bindings/jsonnet/src/val_make.rsdiffbeforeafterboth6};6};778use gcmodule::Cc;8use gcmodule::Cc;9use jrsonnet_evaluator::{val::ArrValue, EvaluationState, ObjValue, Val};9use jrsonnet_evaluator::{val::ArrValue, ObjValue, State, Val};101011/// # Safety11/// # Safety12///12///13/// This function is safe, if received v is a pointer to normal C string13/// This function is safe, if received v is a pointer to normal C string14#[no_mangle]14#[no_mangle]15pub unsafe extern "C" fn jsonnet_json_make_string(15pub unsafe extern "C" fn jsonnet_json_make_string(_vm: &State, v: *const c_char) -> *mut Val {16 _vm: &EvaluationState,17 v: *const c_char,18) -> *mut Val {19 let cstr = CStr::from_ptr(v);16 let cstr = CStr::from_ptr(v);22}19}232024#[no_mangle]21#[no_mangle]25pub extern "C" fn jsonnet_json_make_number(_vm: &EvaluationState, v: c_double) -> *mut Val {22pub extern "C" fn jsonnet_json_make_number(_vm: &State, v: c_double) -> *mut Val {26 Box::into_raw(Box::new(Val::Num(v)))23 Box::into_raw(Box::new(Val::Num(v)))27}24}282529#[no_mangle]26#[no_mangle]30pub extern "C" fn jsonnet_json_make_bool(_vm: &EvaluationState, v: c_int) -> *mut Val {27pub extern "C" fn jsonnet_json_make_bool(_vm: &State, v: c_int) -> *mut Val {31 assert!(v == 0 || v == 1);28 assert!(v == 0 || v == 1);32 Box::into_raw(Box::new(Val::Bool(v == 1)))29 Box::into_raw(Box::new(Val::Bool(v == 1)))33}30}343135#[no_mangle]32#[no_mangle]36pub extern "C" fn jsonnet_json_make_null(_vm: &EvaluationState) -> *mut Val {33pub extern "C" fn jsonnet_json_make_null(_vm: &State) -> *mut Val {37 Box::into_raw(Box::new(Val::Null))34 Box::into_raw(Box::new(Val::Null))38}35}393640#[no_mangle]37#[no_mangle]41pub extern "C" fn jsonnet_json_make_array(_vm: &EvaluationState) -> *mut Val {38pub extern "C" fn jsonnet_json_make_array(_vm: &State) -> *mut Val {42 Box::into_raw(Box::new(Val::Arr(ArrValue::Eager(Cc::new(Vec::new())))))39 Box::into_raw(Box::new(Val::Arr(ArrValue::Eager(Cc::new(Vec::new())))))43}40}444145#[no_mangle]42#[no_mangle]46pub extern "C" fn jsonnet_json_make_object(_vm: &EvaluationState) -> *mut Val {43pub extern "C" fn jsonnet_json_make_object(_vm: &State) -> *mut Val {47 Box::into_raw(Box::new(Val::Obj(ObjValue::new_empty())))44 Box::into_raw(Box::new(Val::Obj(ObjValue::new_empty())))48}45}4946bindings/jsonnet/src/val_modify.rsdiffbeforeafterboth5use std::{ffi::CStr, os::raw::c_char};5use std::{ffi::CStr, os::raw::c_char};667use gcmodule::Cc;7use gcmodule::Cc;8use jrsonnet_evaluator::{val::ArrValue, EvaluationState, LazyVal, Val};8use jrsonnet_evaluator::{val::ArrValue, LazyVal, State, Val};9910/// # Safety10/// # Safety11///11///12/// Received arr value should be correct pointer to array allocated by make_array12/// Received arr value should be correct pointer to array allocated by make_array13#[no_mangle]13#[no_mangle]14pub unsafe extern "C" fn jsonnet_json_array_append(14pub unsafe extern "C" fn jsonnet_json_array_append(_vm: &State, arr: &mut Val, val: &Val) {15 _vm: &EvaluationState,16 arr: &mut Val,17 val: &Val,18) {34/// This function is safe if passed name is ok30/// This function is safe if passed name is ok35#[no_mangle]31#[no_mangle]36pub unsafe extern "C" fn jsonnet_json_object_append(32pub unsafe extern "C" fn jsonnet_json_object_append(37 _vm: &EvaluationState,33 _vm: &State,38 obj: &mut Val,34 obj: &mut Val,39 name: *const c_char,35 name: *const c_char,40 val: &Val,36 val: &Val,bindings/jsonnet/src/vars_tlas.rsdiffbeforeafterboth223use std::{ffi::CStr, os::raw::c_char};3use std::{ffi::CStr, os::raw::c_char};445use jrsonnet_evaluator::EvaluationState;5use jrsonnet_evaluator::State;667/// # Safety7/// # Safety8#[no_mangle]8#[no_mangle]9pub unsafe extern "C" fn jsonnet_ext_var(9pub unsafe extern "C" fn jsonnet_ext_var(vm: &State, name: *const c_char, value: *const c_char) {10 vm: &EvaluationState,11 name: *const c_char,12 value: *const c_char,13) {211722/// # Safety18/// # Safety23#[no_mangle]19#[no_mangle]24pub unsafe extern "C" fn jsonnet_ext_code(20pub unsafe extern "C" fn jsonnet_ext_code(vm: &State, name: *const c_char, value: *const c_char) {25 vm: &EvaluationState,26 name: *const c_char,27 value: *const c_char,28) {36}28}37/// # Safety29/// # Safety38#[no_mangle]30#[no_mangle]39pub unsafe extern "C" fn jsonnet_tla_var(31pub unsafe extern "C" fn jsonnet_tla_var(vm: &State, name: *const c_char, value: *const c_char) {40 vm: &EvaluationState,41 name: *const c_char,42 value: *const c_char,43) {50}38}51/// # Safety39/// # Safety52#[no_mangle]40#[no_mangle]53pub unsafe extern "C" fn jsonnet_tla_code(41pub unsafe extern "C" fn jsonnet_tla_code(vm: &State, name: *const c_char, value: *const c_char) {54 vm: &EvaluationState,55 name: *const c_char,56 value: *const c_char,57) {cmds/jrsonnet/src/main.rsdiffbeforeafterboth7use clap::{AppSettings, IntoApp, Parser};7use clap::{AppSettings, IntoApp, Parser};8use clap_complete::Shell;8use clap_complete::Shell;9use jrsonnet_cli::{ConfigureState, GcOpts, GeneralOpts, InputOpts, ManifestOpts, OutputOpts};9use jrsonnet_cli::{ConfigureState, GcOpts, GeneralOpts, InputOpts, ManifestOpts, OutputOpts};10use jrsonnet_evaluator::{error::LocError, EvaluationState};10use jrsonnet_evaluator::{error::LocError, State};111112#[cfg(feature = "mimalloc")]12#[cfg(feature = "mimalloc")]13#[global_allocator]13#[global_allocator]102102103fn main_catch(opts: Opts) -> bool {103fn main_catch(opts: Opts) -> bool {104 let _printer = opts.gc.stats_printer();104 let _printer = opts.gc.stats_printer();105 let state = EvaluationState::default();105 let s = State::default();106 if let Err(e) = main_real(&state, opts) {106 if let Err(e) = main_real(&s, opts) {107 if let Error::Evaluation(e) = e {107 if let Error::Evaluation(e) = e {108 eprintln!("{}", state.stringify_err(&e));108 eprintln!("{}", s.stringify_err(&e));109 } else {109 } else {110 eprintln!("{}", e);110 eprintln!("{}", e);111 }111 }114 true114 true115}115}116116117fn main_real(state: &EvaluationState, opts: Opts) -> Result<(), Error> {117fn main_real(s: &State, opts: Opts) -> Result<(), Error> {118 opts.gc.configure_global();118 opts.gc.configure_global();119 opts.general.configure(state)?;119 opts.general.configure(s)?;120 opts.manifest.configure(state)?;120 opts.manifest.configure(s)?;121121122 let val = if opts.input.exec {122 let val = if opts.input.exec {123 state.evaluate_snippet_raw(123 s.evaluate_snippet_raw(124 PathBuf::from("<cmdline>").into(),124 PathBuf::from("<cmdline>").into(),125 (&opts.input.input as &str).into(),125 (&opts.input.input as &str).into(),126 )?126 )?127 } else if opts.input.input == "-" {127 } else if opts.input.input == "-" {128 let mut input = Vec::new();128 let mut input = Vec::new();129 std::io::stdin().read_to_end(&mut input)?;129 std::io::stdin().read_to_end(&mut input)?;130 let input_str = std::str::from_utf8(&input)?.into();130 let input_str = std::str::from_utf8(&input)?.into();131 state.evaluate_snippet_raw(PathBuf::from("<stdin>").into(), input_str)?131 s.evaluate_snippet_raw(PathBuf::from("<stdin>").into(), input_str)?132 } else {132 } else {133 state.evaluate_file_raw(&PathBuf::from(opts.input.input))?133 s.evaluate_file_raw(&PathBuf::from(opts.input.input))?134 };134 };135135136 let val = state.with_tla(val)?;136 let val = s.with_tla(val)?;137137138 if let Some(multi) = opts.output.multi {138 if let Some(multi) = opts.output.multi {139 if opts.output.create_output_dirs {139 if opts.output.create_output_dirs {140 let mut dir = multi.clone();140 let mut dir = multi.clone();141 dir.pop();141 dir.pop();142 create_dir_all(dir)?;142 create_dir_all(dir)?;143 }143 }144 for (file, data) in state.manifest_multi(val)?.iter() {144 for (file, data) in s.manifest_multi(val)?.iter() {145 let mut path = multi.clone();145 let mut path = multi.clone();146 path.push(file as &str);146 path.push(file as &str);147 if opts.output.create_output_dirs {147 if opts.output.create_output_dirs {160 create_dir_all(dir)?;160 create_dir_all(dir)?;161 }161 }162 let mut file = File::create(path)?;162 let mut file = File::create(path)?;163 writeln!(file, "{}", state.manifest(val)?)?;163 writeln!(file, "{}", s.manifest(val)?)?;164 } else {164 } else {165 let output = state.manifest(val)?;165 let output = s.manifest(val)?;166 if !output.is_empty() {166 if !output.is_empty() {167 println!("{}", output);167 println!("{}", output);168 }168 }crates/jrsonnet-cli/src/ext.rsdiffbeforeafterboth1use std::{fs::read_to_string, str::FromStr};1use std::{fs::read_to_string, str::FromStr};223use clap::Parser;3use clap::Parser;4use jrsonnet_evaluator::{error::Result, EvaluationState};4use jrsonnet_evaluator::{error::Result, State};556use crate::ConfigureState;6use crate::ConfigureState;77100 ext_code_file: Vec<ExtFile>,100 ext_code_file: Vec<ExtFile>,101}101}102impl ConfigureState for ExtVarOpts {102impl ConfigureState for ExtVarOpts {103 fn configure(&self, state: &EvaluationState) -> Result<()> {103 fn configure(&self, s: &State) -> Result<()> {104 for ext in self.ext_str.iter() {104 for ext in self.ext_str.iter() {105 state.add_ext_str((&ext.name as &str).into(), (&ext.value as &str).into());105 s.add_ext_str((&ext.name as &str).into(), (&ext.value as &str).into());106 }106 }107 for ext in self.ext_str_file.iter() {107 for ext in self.ext_str_file.iter() {108 state.add_ext_str((&ext.name as &str).into(), (&ext.value as &str).into());108 s.add_ext_str((&ext.name as &str).into(), (&ext.value as &str).into());109 }109 }110 for ext in self.ext_code.iter() {110 for ext in self.ext_code.iter() {111 state.add_ext_code((&ext.name as &str).into(), (&ext.value as &str).into())?;111 s.add_ext_code((&ext.name as &str).into(), (&ext.value as &str).into())?;112 }112 }113 for ext in self.ext_code_file.iter() {113 for ext in self.ext_code_file.iter() {114 state.add_ext_code((&ext.name as &str).into(), (&ext.value as &str).into())?;114 s.add_ext_code((&ext.name as &str).into(), (&ext.value as &str).into())?;115 }115 }116 Ok(())116 Ok(())117 }117 }crates/jrsonnet-cli/src/lib.rsdiffbeforeafterboth778use clap::Parser;8use clap::Parser;9pub use ext::*;9pub use ext::*;10use jrsonnet_evaluator::{error::Result, EvaluationState, FileImportResolver};10use jrsonnet_evaluator::{error::Result, FileImportResolver, State};11pub use manifest::*;11pub use manifest::*;12pub use tla::*;12pub use tla::*;13pub use trace::*;13pub use trace::*;141415pub trait ConfigureState {15pub trait ConfigureState {16 fn configure(&self, state: &EvaluationState) -> Result<()>;16 fn configure(&self, s: &State) -> Result<()>;17}17}181819#[derive(Parser)]19#[derive(Parser)]50 jpath: Vec<PathBuf>,50 jpath: Vec<PathBuf>,51}51}52impl ConfigureState for MiscOpts {52impl ConfigureState for MiscOpts {53 fn configure(&self, state: &EvaluationState) -> Result<()> {53 fn configure(&self, s: &State) -> Result<()> {54 if !self.no_stdlib {54 if !self.no_stdlib {55 state.with_stdlib();55 s.with_stdlib();56 }56 }575758 let mut library_paths = self.jpath.clone();58 let mut library_paths = self.jpath.clone();61 library_paths.extend(env::split_paths(path.as_os_str()));61 library_paths.extend(env::split_paths(path.as_os_str()));62 }62 }636364 state.set_import_resolver(Box::new(FileImportResolver { library_paths }));64 s.set_import_resolver(Box::new(FileImportResolver { library_paths }));656566 state.set_max_stack(self.max_stack);66 s.set_max_stack(self.max_stack);67 Ok(())67 Ok(())68 }68 }69}69}85}85}868687impl ConfigureState for GeneralOpts {87impl ConfigureState for GeneralOpts {88 fn configure(&self, state: &EvaluationState) -> Result<()> {88 fn configure(&self, s: &State) -> Result<()> {89 // Configure trace first, because tla-code/ext-code can throw89 // Configure trace first, because tla-code/ext-code can throw90 self.trace.configure(state)?;90 self.trace.configure(s)?;91 self.misc.configure(state)?;91 self.misc.configure(s)?;92 self.tla.configure(state)?;92 self.tla.configure(s)?;93 self.ext.configure(state)?;93 self.ext.configure(s)?;94 Ok(())94 Ok(())95 }95 }96}96}crates/jrsonnet-cli/src/manifest.rsdiffbeforeafterboth1use std::{path::PathBuf, str::FromStr};1use std::{path::PathBuf, str::FromStr};223use clap::Parser;3use clap::Parser;4use jrsonnet_evaluator::{error::Result, EvaluationState, ManifestFormat};4use jrsonnet_evaluator::{error::Result, ManifestFormat, State};556use crate::ConfigureState;6use crate::ConfigureState;7749 exp_preserve_order: bool,49 exp_preserve_order: bool,50}50}51impl ConfigureState for ManifestOpts {51impl ConfigureState for ManifestOpts {52 fn configure(&self, state: &EvaluationState) -> Result<()> {52 fn configure(&self, s: &State) -> Result<()> {53 if self.string {53 if self.string {54 state.set_manifest_format(ManifestFormat::String);54 s.set_manifest_format(ManifestFormat::String);55 } else {55 } else {56 #[cfg(feature = "exp-preserve-order")]56 #[cfg(feature = "exp-preserve-order")]57 let preserve_order = self.exp_preserve_order;57 let preserve_order = self.exp_preserve_order;58 match self.format {58 match self.format {59 ManifestFormatName::String => state.set_manifest_format(ManifestFormat::String),59 ManifestFormatName::String => s.set_manifest_format(ManifestFormat::String),60 ManifestFormatName::Json => state.set_manifest_format(ManifestFormat::Json {60 ManifestFormatName::Json => s.set_manifest_format(ManifestFormat::Json {61 padding: self.line_padding.unwrap_or(3),61 padding: self.line_padding.unwrap_or(3),62 #[cfg(feature = "exp-preserve-order")]62 #[cfg(feature = "exp-preserve-order")]63 preserve_order,63 preserve_order,64 }),64 }),65 ManifestFormatName::Yaml => state.set_manifest_format(ManifestFormat::Yaml {65 ManifestFormatName::Yaml => s.set_manifest_format(ManifestFormat::Yaml {66 padding: self.line_padding.unwrap_or(2),66 padding: self.line_padding.unwrap_or(2),67 #[cfg(feature = "exp-preserve-order")]67 #[cfg(feature = "exp-preserve-order")]68 preserve_order,68 preserve_order,69 }),69 }),70 }70 }71 }71 }72 if self.yaml_stream {72 if self.yaml_stream {73 state.set_manifest_format(ManifestFormat::YamlStream(Box::new(73 s.set_manifest_format(ManifestFormat::YamlStream(Box::new(s.manifest_format())))74 state.manifest_format(),75 )))76 }74 }77 Ok(())75 Ok(())crates/jrsonnet-cli/src/tla.rsdiffbeforeafterboth1use clap::Parser;1use clap::Parser;2use jrsonnet_evaluator::{error::Result, EvaluationState};2use jrsonnet_evaluator::{error::Result, State};334use crate::{ConfigureState, ExtFile, ExtStr};4use crate::{ConfigureState, ExtFile, ExtStr};5547 tla_code_file: Vec<ExtFile>,47 tla_code_file: Vec<ExtFile>,48}48}49impl ConfigureState for TLAOpts {49impl ConfigureState for TLAOpts {50 fn configure(&self, state: &EvaluationState) -> Result<()> {50 fn configure(&self, s: &State) -> Result<()> {51 for tla in self.tla_str.iter() {51 for tla in self.tla_str.iter() {52 state.add_tla_str((&tla.name as &str).into(), (&tla.value as &str).into());52 s.add_tla_str((&tla.name as &str).into(), (&tla.value as &str).into());53 }53 }54 for tla in self.tla_str_file.iter() {54 for tla in self.tla_str_file.iter() {55 state.add_tla_str((&tla.name as &str).into(), (&tla.value as &str).into())55 s.add_tla_str((&tla.name as &str).into(), (&tla.value as &str).into())56 }56 }57 for tla in self.tla_code.iter() {57 for tla in self.tla_code.iter() {58 state.add_tla_code((&tla.name as &str).into(), (&tla.value as &str).into())?;58 s.add_tla_code((&tla.name as &str).into(), (&tla.value as &str).into())?;59 }59 }60 for tla in self.tla_code_file.iter() {60 for tla in self.tla_code_file.iter() {61 state.add_tla_code((&tla.name as &str).into(), (&tla.value as &str).into())?;61 s.add_tla_code((&tla.name as &str).into(), (&tla.value as &str).into())?;62 }62 }63 Ok(())63 Ok(())64 }64 }crates/jrsonnet-cli/src/trace.rsdiffbeforeafterboth4use jrsonnet_evaluator::{4use jrsonnet_evaluator::{5 error::Result,5 error::Result,6 trace::{CompactFormat, ExplainingFormat, PathResolver},6 trace::{CompactFormat, ExplainingFormat, PathResolver},7 EvaluationState,7 State,8};8};9910use crate::ConfigureState;10use crate::ConfigureState;41 max_trace: usize,41 max_trace: usize,42}42}43impl ConfigureState for TraceOpts {43impl ConfigureState for TraceOpts {44 fn configure(&self, state: &EvaluationState) -> Result<()> {44 fn configure(&self, s: &State) -> Result<()> {45 let resolver = PathResolver::Absolute;45 let resolver = PathResolver::Absolute;46 match self46 match self47 .trace_format47 .trace_format48 .as_ref()48 .as_ref()49 .unwrap_or(&TraceFormatName::Compact)49 .unwrap_or(&TraceFormatName::Compact)50 {50 {51 TraceFormatName::Compact => state.set_trace_format(Box::new(CompactFormat {51 TraceFormatName::Compact => s.set_trace_format(Box::new(CompactFormat {52 resolver,52 resolver,53 padding: 4,53 padding: 4,54 })),54 })),55 TraceFormatName::Explaining => {55 TraceFormatName::Explaining => {56 state.set_trace_format(Box::new(ExplainingFormat { resolver }))56 s.set_trace_format(Box::new(ExplainingFormat { resolver }))57 }57 }58 }58 }59 state.set_max_trace(self.max_trace);59 s.set_max_trace(self.max_trace);60 Ok(())60 Ok(())61 }61 }62}62}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)]34use std::convert::TryFrom;536use gcmodule::Trace;4use gcmodule::Trace;7use jrsonnet_interner::IStr;5use jrsonnet_interner::IStr;8use jrsonnet_types::ValType;6use jrsonnet_types::ValType;9use thiserror::Error;7use thiserror::Error;10811use crate::{error::Error::*, throw, LocError, ObjValue, Result, Val};9use crate::{error::Error::*, throw, typed::Typed, LocError, ObjValue, Result, State, Val};121013#[derive(Debug, Clone, Error, Trace)]11#[derive(Debug, Clone, Error, Trace)]14pub enum FormatError {12pub enum FormatError {464}462}465463466pub fn format_code(464pub fn format_code(465 s: State,467 out: &mut String,466 out: &mut String,468 value: &Val,467 value: &Val,469 code: &Code,468 code: &Code,485 let mut tmp_out = String::new();484 let mut tmp_out = String::new();486485487 match code.convtype {486 match code.convtype {488 ConvTypeV::String => tmp_out.push_str(&value.clone().to_string()?),487 ConvTypeV::String => tmp_out.push_str(&value.clone().to_string(s)?),489 ConvTypeV::Decimal => {488 ConvTypeV::Decimal => {490 let value = f64::try_from(value.clone())?;489 let value = f64::from_untyped(value.clone(), s)?;491 render_decimal(490 render_decimal(492 &mut tmp_out,491 &mut tmp_out,493 value as i64,492 value as i64,498 );497 );499 }498 }500 ConvTypeV::Octal => {499 ConvTypeV::Octal => {501 let value = f64::try_from(value.clone())?;500 let value = f64::from_untyped(value.clone(), s)?;502 render_octal(501 render_octal(503 &mut tmp_out,502 &mut tmp_out,504 value as i64,503 value as i64,510 );509 );511 }510 }512 ConvTypeV::Hexadecimal => {511 ConvTypeV::Hexadecimal => {513 let value = f64::try_from(value.clone())?;512 let value = f64::from_untyped(value.clone(), s)?;514 render_hexadecimal(513 render_hexadecimal(515 &mut tmp_out,514 &mut tmp_out,516 value as i64,515 value as i64,523 );522 );524 }523 }525 ConvTypeV::Scientific => {524 ConvTypeV::Scientific => {526 let value = f64::try_from(value.clone())?;525 let value = f64::from_untyped(value.clone(), s)?;527 render_float_sci(526 render_float_sci(528 &mut tmp_out,527 &mut tmp_out,529 value,528 value,537 );536 );538 }537 }539 ConvTypeV::Float => {538 ConvTypeV::Float => {540 let value = f64::try_from(value.clone())?;539 let value = f64::from_untyped(value.clone(), s)?;541 render_float(540 render_float(542 &mut tmp_out,541 &mut tmp_out,543 value,542 value,550 );549 );551 }550 }552 ConvTypeV::Shorter => {551 ConvTypeV::Shorter => {553 let value = f64::try_from(value.clone())?;552 let value = f64::from_untyped(value.clone(), s)?;554 let exponent = value.log10().floor();553 let exponent = value.log10().floor();555 if exponent < -4.0 || exponent >= fpprec as f64 {554 if exponent < -4.0 || exponent >= fpprec as f64 {556 render_float_sci(555 render_float_sci(617 Ok(())616 Ok(())618}617}619618620pub fn format_arr(str: &str, mut values: &[Val]) -> Result<String> {619pub fn format_arr(s: State, str: &str, mut values: &[Val]) -> Result<String> {621 let codes = parse_codes(str)?;620 let codes = parse_codes(str)?;622 let mut out = String::new();621 let mut out = String::new();623622634 }633 }635 let value = &values[0];634 let value = &values[0];636 values = &values[1..];635 values = &values[1..];637 usize::try_from(value.clone())?636 usize::from_untyped(value.clone(), s.clone())?638 }637 }639 Width::Fixed(n) => n,638 Width::Fixed(n) => n,640 };639 };645 }644 }646 let value = &values[0];645 let value = &values[0];647 values = &values[1..];646 values = &values[1..];648 Some(usize::try_from(value.clone())?)647 Some(usize::from_untyped(value.clone(), s.clone())?)649 }648 }650 Some(Width::Fixed(n)) => Some(n),649 Some(Width::Fixed(n)) => Some(n),651 None => None,650 None => None,663 value662 value664 };663 };665664666 format_code(&mut out, value, &c, width, precision)?;665 format_code(s.clone(), &mut out, value, &c, width, precision)?;667 }666 }668 }667 }669 }668 }670669671 Ok(out)670 Ok(out)672}671}673672674pub fn format_obj(str: &str, values: &ObjValue) -> Result<String> {673pub fn format_obj(s: State, str: &str, values: &ObjValue) -> Result<String> {675 let codes = parse_codes(str)?;674 let codes = parse_codes(str)?;676 let mut out = String::new();675 let mut out = String::new();677676703 if f.is_empty() {702 if f.is_empty() {704 throw!(MappingKeysRequired);703 throw!(MappingKeysRequired);705 }704 }706 if let Some(v) = values.get(f.clone())? {705 if let Some(v) = values.get(s.clone(), f.clone())? {707 v706 v708 } else {707 } else {709 throw!(NoSuchFormatField(f));708 throw!(NoSuchFormatField(f));710 }709 }711 };710 };712711713 format_code(&mut out, &value, &c, width, precision)?;712 format_code(s.clone(), &mut out, &value, &c, width, precision)?;714 }713 }715 }714 }716 }715 }crates/jrsonnet-evaluator/src/builtin/manifest.rsdiffbeforeafterboth1use crate::{1use crate::{2 error::{Error::*, Result},2 error::{Error::*, Result},3 push_description_frame, throw, Val,3 throw, State, Val,4};4};556#[derive(PartialEq, Clone, Copy)]6#[derive(PartialEq, Clone, Copy)]25 pub preserve_order: bool,25 pub preserve_order: bool,26}26}272728pub fn manifest_json_ex(val: &Val, options: &ManifestJsonOptions<'_>) -> Result<String> {28pub fn manifest_json_ex(s: State, val: &Val, options: &ManifestJsonOptions<'_>) -> Result<String> {29 let mut out = String::new();29 let mut out = String::new();30 manifest_json_ex_buf(val, &mut out, &mut String::new(), options)?;30 manifest_json_ex_buf(s, val, &mut out, &mut String::new(), options)?;31 Ok(out)31 Ok(out)32}32}33fn manifest_json_ex_buf(33fn manifest_json_ex_buf(34 s: State,34 val: &Val,35 val: &Val,35 buf: &mut String,36 buf: &mut String,36 cur_padding: &mut String,37 cur_padding: &mut String,585959 let old_len = cur_padding.len();60 let old_len = cur_padding.len();60 cur_padding.push_str(options.padding);61 cur_padding.push_str(options.padding);61 for (i, item) in items.iter().enumerate() {62 for (i, item) in items.iter(s.clone()).enumerate() {62 if i != 0 {63 if i != 0 {63 buf.push(',');64 buf.push(',');64 if mtype == ManifestType::ToString {65 if mtype == ManifestType::ToString {68 }69 }69 }70 }70 buf.push_str(cur_padding);71 buf.push_str(cur_padding);71 manifest_json_ex_buf(&item?, buf, cur_padding, options)?;72 manifest_json_ex_buf(s.clone(), &item?, buf, cur_padding, options)?;72 }73 }73 cur_padding.truncate(old_len);74 cur_padding.truncate(old_len);747585 buf.push(']');86 buf.push(']');86 }87 }87 Val::Obj(obj) => {88 Val::Obj(obj) => {88 obj.run_assertions()?;89 obj.run_assertions(s.clone())?;89 buf.push('{');90 buf.push('{');90 let fields = obj.fields(91 let fields = obj.fields(91 #[cfg(feature = "exp-preserve-order")]92 #[cfg(feature = "exp-preserve-order")]110 buf.push_str(cur_padding);111 buf.push_str(cur_padding);111 escape_string_json_buf(&field, buf);112 escape_string_json_buf(&field, buf);112 buf.push_str(options.key_val_sep);113 buf.push_str(options.key_val_sep);113 push_description_frame(114 s.push_description(114 || format!("field <{}> manifestification", field.clone()),115 || format!("field <{}> manifestification", field.clone()),115 || {116 || {116 let value = obj.get(field.clone())?.unwrap();117 let value = obj.get(s.clone(), field.clone())?.unwrap();117 manifest_json_ex_buf(&value, buf, cur_padding, options)?;118 manifest_json_ex_buf(s.clone(), &value, buf, cur_padding, options)?;118 Ok(Val::Null)119 Ok(Val::Null)119 },120 },120 )?;121 )?;221 || string.parse::<f64>().is_ok()222 || string.parse::<f64>().is_ok()222}223}223224224pub fn manifest_yaml_ex(val: &Val, options: &ManifestYamlOptions<'_>) -> Result<String> {225pub fn manifest_yaml_ex(s: State, val: &Val, options: &ManifestYamlOptions<'_>) -> Result<String> {225 let mut out = String::new();226 let mut out = String::new();226 manifest_yaml_ex_buf(val, &mut out, &mut String::new(), options)?;227 manifest_yaml_ex_buf(s, val, &mut out, &mut String::new(), options)?;227 Ok(out)228 Ok(out)228}229}229fn manifest_yaml_ex_buf(230fn manifest_yaml_ex_buf(231 s: State,230 val: &Val,232 val: &Val,231 buf: &mut String,233 buf: &mut String,232 cur_padding: &mut String,234 cur_padding: &mut String,249 buf.push('|');251 buf.push('|');250 for line in s.split('\n') {252 for line in s.split('\n') {251 buf.push('\n');253 buf.push('\n');252 buf.push_str(&cur_padding);254 buf.push_str(cur_padding);253 buf.push_str(options.padding);255 buf.push_str(options.padding);254 buf.push_str(line);256 buf.push_str(line);255 }257 }264 if a.is_empty() {266 if a.is_empty() {265 buf.push_str("[]");267 buf.push_str("[]");266 } else {268 } else {267 for (i, item) in a.iter().enumerate() {269 for (i, item) in a.iter(s.clone()).enumerate() {268 if i != 0 {270 if i != 0 {269 buf.push('\n');271 buf.push('\n');270 buf.push_str(cur_padding);272 buf.push_str(cur_padding);288 if extra_padding {290 if extra_padding {289 cur_padding.push_str(options.padding);291 cur_padding.push_str(options.padding);290 }292 }291 manifest_yaml_ex_buf(&item, buf, cur_padding, options)?;293 manifest_yaml_ex_buf(s.clone(), &item, buf, cur_padding, options)?;292 cur_padding.truncate(prev_len);294 cur_padding.truncate(prev_len);293 }295 }294 }296 }316 }318 }317 buf.push(':');319 buf.push(':');318 let prev_len = cur_padding.len();320 let prev_len = cur_padding.len();319 let item = o.get(key.clone())?.expect("field exists");321 let item = o.get(s.clone(), key.clone())?.expect("field exists");320 match &item {322 match &item {321 Val::Arr(a) if !a.is_empty() => {323 Val::Arr(a) if !a.is_empty() => {322 buf.push('\n');324 buf.push('\n');332 }334 }333 _ => buf.push(' '),335 _ => buf.push(' '),334 }336 }335 manifest_yaml_ex_buf(&item, buf, cur_padding, options)?;337 manifest_yaml_ex_buf(s.clone(), &item, buf, cur_padding, options)?;336 cur_padding.truncate(prev_len);338 cur_padding.truncate(prev_len);337 }339 }338 }340 }crates/jrsonnet-evaluator/src/builtin/mod.rsdiffbeforeafterboth1use std::{1use std::collections::HashMap;2 collections::HashMap,3 convert::{TryFrom, TryInto},4};526use format::{format_arr, format_obj};3use format::{format_arr, format_obj};7use gcmodule::Cc;4use gcmodule::Cc;14 error::{Error::*, Result},11 error::{Error::*, Result},15 function::{CallLocation, StaticBuiltin},12 function::{CallLocation, StaticBuiltin},16 operator::evaluate_mod_op,13 operator::evaluate_mod_op,17 push_frame, throw,14 throw,18 typed::{Any, BoundedUsize, Bytes, Either2, Either4, PositiveF64, VecVal, M1},15 typed::{Any, BoundedUsize, Bytes, Either2, Either4, PositiveF64, Typed, VecVal, M1},19 val::{equals, primitive_equals, ArrValue, FuncVal, IndexableVal, Slice},16 val::{equals, primitive_equals, ArrValue, FuncVal, IndexableVal, Slice},20 with_state, Either, ObjValue, Val,17 Either, ObjValue, State, Val,21};18};221923pub mod stdlib;20pub mod stdlib;29pub mod manifest;26pub mod manifest;30pub mod sort;27pub mod sort;312832pub fn std_format(str: IStr, vals: Val) -> Result<String> {29pub fn std_format(s: State, str: IStr, vals: Val) -> Result<String> {33 push_frame(30 s.push(34 CallLocation::native(),31 CallLocation::native(),35 || format!("std.format of {}", str),32 || format!("std.format of {}", str),36 || {33 || {37 Ok(match vals {34 Ok(match vals {38 Val::Arr(vals) => format_arr(&str, &vals.evaluated()?)?,35 Val::Arr(vals) => format_arr(s.clone(), &str, &vals.evaluated(s.clone())?)?,39 Val::Obj(obj) => format_obj(&str, &obj)?,36 Val::Obj(obj) => format_obj(s.clone(), &str, &obj)?,40 o => format_arr(&str, &[o])?,37 o => format_arr(s.clone(), &str, &[o])?,41 })38 })42 },39 },43 )40 )173}170}174171175#[jrsonnet_macros::builtin]172#[jrsonnet_macros::builtin]176fn builtin_make_array(sz: usize, func: FuncVal) -> Result<VecVal> {173fn builtin_make_array(s: State, sz: usize, func: FuncVal) -> Result<VecVal> {177 let mut out = Vec::with_capacity(sz);174 let mut out = Vec::with_capacity(sz);178 for i in 0..sz {175 for i in 0..sz {179 out.push(func.evaluate_simple(&[i as f64].as_slice())?)176 out.push(func.evaluate_simple(s.clone(), &[i as f64].as_slice())?)180 }177 }181 Ok(VecVal(Cc::new(out)))178 Ok(VecVal(Cc::new(out)))182}179}210}207}211208212#[jrsonnet_macros::builtin]209#[jrsonnet_macros::builtin]213fn builtin_parse_json(s: IStr) -> Result<Any> {210fn builtin_parse_json(st: State, s: IStr) -> Result<Any> {211 use serde_json::Value;214 let value: serde_json::Value = serde_json::from_str(&s)212 let value: Value = serde_json::from_str(&s)215 .map_err(|e| RuntimeError(format!("failed to parse json: {}", e).into()))?;213 .map_err(|e| RuntimeError(format!("failed to parse json: {}", e).into()))?;216 Ok(Any(Val::try_from(&value)?))214 Ok(Any(Value::into_untyped(value, st)?))217}215}218216219#[jrsonnet_macros::builtin]217#[jrsonnet_macros::builtin]220fn builtin_parse_yaml(s: IStr) -> Result<Any> {218fn builtin_parse_yaml(st: State, s: IStr) -> Result<Any> {219 use serde_json::Value;221 let value = serde_yaml::Deserializer::from_str_with_quirks(220 let value = serde_yaml::Deserializer::from_str_with_quirks(222 &s,221 &s,223 DeserializingQuirks { old_octals: true },222 DeserializingQuirks { old_octals: true },224 );223 );225 let mut out = vec![];224 let mut out = vec![];226 for item in value {225 for item in value {227 let value = serde_json::Value::deserialize(item)226 let value = Value::deserialize(item)228 .map_err(|e| RuntimeError(format!("failed to parse yaml: {}", e).into()))?;227 .map_err(|e| RuntimeError(format!("failed to parse yaml: {}", e).into()))?;229 let val = Val::try_from(&value)?;228 let val = Value::into_untyped(value, st.clone())?;230 out.push(val);229 out.push(val);231 }230 }232 Ok(Any(if out.is_empty() {231 Ok(Any(if out.is_empty() {259}258}260259261#[jrsonnet_macros::builtin]260#[jrsonnet_macros::builtin]262fn builtin_equals(a: Any, b: Any) -> Result<bool> {261fn builtin_equals(s: State, a: Any, b: Any) -> Result<bool> {263 equals(&a.0, &b.0)262 equals(s, &a.0, &b.0)264}263}265264266#[jrsonnet_macros::builtin]265#[jrsonnet_macros::builtin]269}268}270269271#[jrsonnet_macros::builtin]270#[jrsonnet_macros::builtin]272fn builtin_mod(a: Either![f64, IStr], b: Any) -> Result<Any> {271fn builtin_mod(s: State, a: Either![f64, IStr], b: Any) -> Result<Any> {273 use Either2::*;272 use Either2::*;274 Ok(Any(evaluate_mod_op(273 Ok(Any(evaluate_mod_op(274 s,275 &match a {275 &match a {276 A(v) => Val::Num(v),276 A(v) => Val::Num(v),277 B(s) => Val::Str(s),277 B(s) => Val::Str(s),362}362}363363364#[jrsonnet_macros::builtin]364#[jrsonnet_macros::builtin]365fn builtin_ext_var(x: IStr) -> Result<Any> {365fn builtin_ext_var(s: State, x: IStr) -> Result<Any> {366 Ok(Any(with_state(|s| s.settings().ext_vars.get(&x).cloned())366 Ok(Any(s367 .settings()368 .ext_vars369 .get(&x)370 .cloned()367 .ok_or(UndefinedExternalVariable(x))?))371 .ok_or(UndefinedExternalVariable(x))?))368}372}369373370#[jrsonnet_macros::builtin]374#[jrsonnet_macros::builtin]371fn builtin_native(name: IStr) -> Result<FuncVal> {375fn builtin_native(s: State, name: IStr) -> Result<FuncVal> {372 Ok(with_state(|s| s.settings().ext_natives.get(&name).cloned())376 Ok(s.settings()377 .ext_natives378 .get(&name)379 .cloned()373 .map(|v| FuncVal::Builtin(v.clone()))380 .map(|v| FuncVal::Builtin(v.clone()))374 .ok_or(UndefinedExternalFunction(name))?)381 .ok_or(UndefinedExternalFunction(name))?)375}382}376383377#[jrsonnet_macros::builtin]384#[jrsonnet_macros::builtin]378fn builtin_filter(func: FuncVal, arr: ArrValue) -> Result<ArrValue> {385fn builtin_filter(s: State, func: FuncVal, arr: ArrValue) -> Result<ArrValue> {379 arr.filter(|val| bool::try_from(func.evaluate_simple(&[Any(val.clone())].as_slice())?))386 arr.filter(s.clone(), |val| {387 bool::from_untyped(388 func.evaluate_simple(s.clone(), &[Any(val.clone())].as_slice())?,389 s.clone(),390 )391 })380}392}381393382#[jrsonnet_macros::builtin]394#[jrsonnet_macros::builtin]383fn builtin_map(func: FuncVal, arr: ArrValue) -> Result<ArrValue> {395fn builtin_map(s: State, func: FuncVal, arr: ArrValue) -> Result<ArrValue> {384 arr.map(|val| func.evaluate_simple(&[Any(val)].as_slice()))396 arr.map(s.clone(), |val| {397 func.evaluate_simple(s.clone(), &[Any(val)].as_slice())398 })385}399}386400387#[jrsonnet_macros::builtin]401#[jrsonnet_macros::builtin]388fn builtin_flatmap(func: FuncVal, arr: IndexableVal) -> Result<IndexableVal> {402fn builtin_flatmap(s: State, func: FuncVal, arr: IndexableVal) -> Result<IndexableVal> {389 match arr {403 match arr {390 IndexableVal::Str(s) => {404 IndexableVal::Str(str) => {391 let mut out = String::new();405 let mut out = String::new();392 for c in s.chars() {406 for c in str.chars() {393 match func.evaluate_simple(&[c.to_string()].as_slice())? {407 match func.evaluate_simple(s.clone(), &[c.to_string()].as_slice())? {394 Val::Str(o) => out.push_str(&o),408 Val::Str(o) => out.push_str(&o),395 _ => throw!(RuntimeError(409 _ => throw!(RuntimeError(396 "in std.join all items should be strings".into()410 "in std.join all items should be strings".into()401 }415 }402 IndexableVal::Arr(a) => {416 IndexableVal::Arr(a) => {403 let mut out = Vec::new();417 let mut out = Vec::new();404 for el in a.iter() {418 for el in a.iter(s.clone()) {405 let el = el?;419 let el = el?;406 match func.evaluate_simple(&[Any(el)].as_slice())? {420 match func.evaluate_simple(s.clone(), &[Any(el)].as_slice())? {407 Val::Arr(o) => {421 Val::Arr(o) => {408 for oe in o.iter() {422 for oe in o.iter(s.clone()) {409 out.push(oe?)423 out.push(oe?)410 }424 }411 }425 }420}434}421435422#[jrsonnet_macros::builtin]436#[jrsonnet_macros::builtin]423fn builtin_foldl(func: FuncVal, arr: ArrValue, init: Any) -> Result<Any> {437fn builtin_foldl(s: State, func: FuncVal, arr: ArrValue, init: Any) -> Result<Any> {424 let mut acc = init.0;438 let mut acc = init.0;425 for i in arr.iter() {439 for i in arr.iter(s.clone()) {426 acc = func.evaluate_simple(&[Any(acc), Any(i?)].as_slice())?;440 acc = func.evaluate_simple(s.clone(), &[Any(acc), Any(i?)].as_slice())?;427 }441 }428 Ok(Any(acc))442 Ok(Any(acc))429}443}430444431#[jrsonnet_macros::builtin]445#[jrsonnet_macros::builtin]432fn builtin_foldr(func: FuncVal, arr: ArrValue, init: Any) -> Result<Any> {446fn builtin_foldr(s: State, func: FuncVal, arr: ArrValue, init: Any) -> Result<Any> {433 let mut acc = init.0;447 let mut acc = init.0;434 for i in arr.iter().rev() {448 for i in arr.iter(s.clone()).rev() {435 acc = func.evaluate_simple(&[Any(i?), Any(acc)].as_slice())?;449 acc = func.evaluate_simple(s.clone(), &[Any(i?), Any(acc)].as_slice())?;436 }450 }437 Ok(Any(acc))451 Ok(Any(acc))438}452}439453440#[jrsonnet_macros::builtin]454#[jrsonnet_macros::builtin]441#[allow(non_snake_case)]455#[allow(non_snake_case)]442fn builtin_sort(arr: ArrValue, keyF: Option<FuncVal>) -> Result<ArrValue> {456fn builtin_sort(s: State, arr: ArrValue, keyF: Option<FuncVal>) -> Result<ArrValue> {443 if arr.len() <= 1 {457 if arr.len() <= 1 {444 return Ok(arr);458 return Ok(arr);445 }459 }446 Ok(ArrValue::Eager(sort::sort(460 Ok(ArrValue::Eager(sort::sort(461 s.clone(),447 arr.evaluated()?,462 arr.evaluated(s)?,448 keyF.as_ref(),463 keyF.as_ref(),449 )?))464 )?))450}465}451466452#[jrsonnet_macros::builtin]467#[jrsonnet_macros::builtin]453fn builtin_format(str: IStr, vals: Any) -> Result<String> {468fn builtin_format(s: State, str: IStr, vals: Any) -> Result<String> {454 std_format(str, vals.0)469 std_format(s, str, vals.0)455}470}456471457#[jrsonnet_macros::builtin]472#[jrsonnet_macros::builtin]485}500}486501487#[jrsonnet_macros::builtin]502#[jrsonnet_macros::builtin]488fn builtin_trace(loc: CallLocation, str: IStr, rest: Any) -> Result<Any> {503fn builtin_trace(s: State, loc: CallLocation, str: IStr, rest: Any) -> Result<Any> {489 eprint!("TRACE:");504 eprint!("TRACE:");490 if let Some(loc) = loc.0 {505 if let Some(loc) = loc.0 {491 with_state(|s| {492 let locs = s.map_source_locations(&loc.0, &[loc.1]);506 let locs = s.map_source_locations(&loc.0, &[loc.1]);493 eprint!(507 eprint!(494 " {}:{}",508 " {}:{}",495 loc.0.file_name().unwrap().to_str().unwrap(),509 loc.0.file_name().unwrap().to_str().unwrap(),496 locs[0].line510 locs[0].line497 );511 );498 });499 }512 }500 eprintln!(" {}", str);513 eprintln!(" {}", str);501 Ok(rest) as Result<Any>514 Ok(rest) as Result<Any>526}539}527540528#[jrsonnet_macros::builtin]541#[jrsonnet_macros::builtin]529fn builtin_join(sep: IndexableVal, arr: ArrValue) -> Result<IndexableVal> {542fn builtin_join(s: State, sep: IndexableVal, arr: ArrValue) -> Result<IndexableVal> {530 Ok(match sep {543 Ok(match sep {531 IndexableVal::Arr(joiner_items) => {544 IndexableVal::Arr(joiner_items) => {532 let mut out = Vec::new();545 let mut out = Vec::new();533546534 let mut first = true;547 let mut first = true;535 for item in arr.iter() {548 for item in arr.iter(s.clone()) {536 let item = item?.clone();549 let item = item?.clone();537 if let Val::Arr(items) = item {550 if let Val::Arr(items) = item {538 if !first {551 if !first {539 out.reserve(joiner_items.len());552 out.reserve(joiner_items.len());540 // TODO: extend553 // TODO: extend541 for item in joiner_items.iter() {554 for item in joiner_items.iter(s.clone()) {542 out.push(item?);555 out.push(item?);543 }556 }544 }557 }545 first = false;558 first = false;546 out.reserve(items.len());559 out.reserve(items.len());547 // TODO: extend548 for item in items.iter() {560 for item in items.iter(s.clone()) {549 out.push(item?);561 out.push(item?);550 }562 }551 } else {563 } else {561 let mut out = String::new();573 let mut out = String::new();562574563 let mut first = true;575 let mut first = true;564 for item in arr.iter() {576 for item in arr.iter(s) {565 let item = item?.clone();577 let item = item?.clone();566 if let Val::Str(item) = item {578 if let Val::Str(item) = item {567 if !first {579 if !first {588600589#[jrsonnet_macros::builtin]601#[jrsonnet_macros::builtin]590fn builtin_manifest_json_ex(602fn builtin_manifest_json_ex(603 s: State,591 value: Any,604 value: Any,592 indent: IStr,605 indent: IStr,593 newline: Option<IStr>,606 newline: Option<IStr>,597 let newline = newline.as_deref().unwrap_or("\n");610 let newline = newline.as_deref().unwrap_or("\n");598 let key_val_sep = key_val_sep.as_deref().unwrap_or(": ");611 let key_val_sep = key_val_sep.as_deref().unwrap_or(": ");599 manifest_json_ex(612 manifest_json_ex(613 s,600 &value.0,614 &value.0,601 &ManifestJsonOptions {615 &ManifestJsonOptions {602 padding: &indent,616 padding: &indent,611625612#[jrsonnet_macros::builtin]626#[jrsonnet_macros::builtin]613fn builtin_manifest_yaml_doc(627fn builtin_manifest_yaml_doc(628 s: State,614 value: Any,629 value: Any,615 indent_array_in_object: Option<bool>,630 indent_array_in_object: Option<bool>,616 quote_keys: Option<bool>,631 quote_keys: Option<bool>,617 #[cfg(feature = "exp-preserve-order")] preserve_order: Option<bool>,632 #[cfg(feature = "exp-preserve-order")] preserve_order: Option<bool>,618) -> Result<String> {633) -> Result<String> {619 manifest_yaml_ex(634 manifest_yaml_ex(635 s,620 &value.0,636 &value.0,621 &ManifestYamlOptions {637 &ManifestYamlOptions {622 padding: " ",638 padding: " ",670}686}671687672#[jrsonnet_macros::builtin]688#[jrsonnet_macros::builtin]673fn builtin_member(arr: IndexableVal, x: Any) -> Result<bool> {689fn builtin_member(s: State, arr: IndexableVal, x: Any) -> Result<bool> {674 match arr {690 match arr {675 IndexableVal::Str(s) => {691 IndexableVal::Str(str) => {676 let x: IStr = IStr::try_from(x.0)?;692 let x: IStr = IStr::from_untyped(x.0, s)?;677 Ok(!x.is_empty() && s.contains(&*x))693 Ok(!x.is_empty() && str.contains(&*x))678 }694 }679 IndexableVal::Arr(a) => {695 IndexableVal::Arr(a) => {680 for item in a.iter() {696 for item in a.iter(s.clone()) {681 let item = item?;697 let item = item?;682 if equals(&item, &x.0)? {698 if equals(s.clone(), &item, &x.0)? {683 return Ok(true);699 return Ok(true);684 }700 }685 }701 }689}705}690706691#[jrsonnet_macros::builtin]707#[jrsonnet_macros::builtin]692fn builtin_count(arr: Vec<Any>, v: Any) -> Result<usize> {708fn builtin_count(s: State, arr: Vec<Any>, v: Any) -> Result<usize> {693 let mut count = 0;709 let mut count = 0;694 for item in arr.iter() {710 for item in arr.iter() {695 if equals(&item.0, &v.0)? {711 if equals(s.clone(), &item.0, &v.0)? {696 count += 1;712 count += 1;697 }713 }698 }714 }699 Ok(count)715 Ok(count)700}716}701717702#[jrsonnet_macros::builtin]718#[jrsonnet_macros::builtin]703fn builtin_any(arr: ArrValue) -> Result<bool> {719fn builtin_any(s: State, arr: ArrValue) -> Result<bool> {704 for v in arr.iter() {720 for v in arr.iter(s.clone()) {705 let v: bool = v?.try_into()?;721 let v = bool::from_untyped(v?, s.clone())?;706 if v {722 if v {707 return Ok(true);723 return Ok(true);708 }724 }711}727}712728713#[jrsonnet_macros::builtin]729#[jrsonnet_macros::builtin]714fn builtin_all(arr: ArrValue) -> Result<bool> {730fn builtin_all(s: State, arr: ArrValue) -> Result<bool> {715 for v in arr.iter() {731 for v in arr.iter(s.clone()) {716 let v: bool = v?.try_into()?;732 let v = bool::from_untyped(v?, s.clone())?;717 if !v {733 if !v {718 return Ok(false);734 return Ok(false);719 }735 }crates/jrsonnet-evaluator/src/builtin/sort.rsdiffbeforeafterboth5 throw,5 throw,6 typed::Any,6 typed::Any,7 val::FuncVal,7 val::FuncVal,8 Val,8 State, Val,9};9};101011#[derive(Debug, Clone, thiserror::Error, Trace)]11#[derive(Debug, Clone, thiserror::Error, Trace)]63 Ok(sort_type)63 Ok(sort_type)64}64}656566pub fn sort(values: Cc<Vec<Val>>, key_getter: Option<&FuncVal>) -> Result<Cc<Vec<Val>>> {66pub fn sort(s: State, values: Cc<Vec<Val>>, key_getter: Option<&FuncVal>) -> Result<Cc<Vec<Val>>> {67 if values.len() <= 1 {67 if values.len() <= 1 {68 return Ok(values);68 return Ok(values);69 }69 }73 for value in values.iter() {73 for value in values.iter() {74 vk.push((74 vk.push((75 value.clone(),75 value.clone(),76 key_getter.evaluate_simple(&[Any(value.clone())].as_slice())?,76 key_getter.evaluate_simple(s.clone(), &[Any(value.clone())].as_slice())?,77 ));77 ));78 }78 }79 let sort_type = get_sort_type(&mut vk, |v| &mut v.1)?;79 let sort_type = get_sort_type(&mut vk, |v| &mut v.1)?;crates/jrsonnet-evaluator/src/ctx.rsdiffbeforeafterboth556use crate::{6use crate::{7 cc_ptr_eq, error::Error::*, gc::GcHashMap, map::LayeredHashMap, FutureWrapper, LazyBinding,7 cc_ptr_eq, error::Error::*, gc::GcHashMap, map::LayeredHashMap, FutureWrapper, LazyBinding,8 LazyVal, ObjValue, Result, Val,8 LazyVal, ObjValue, Result, State, Val,9};9};101011#[derive(Clone, Trace)]11#[derive(Clone, Trace)]12pub struct ContextCreator(pub Context, pub FutureWrapper<GcHashMap<IStr, LazyBinding>>);12pub struct ContextCreator(pub Context, pub FutureWrapper<GcHashMap<IStr, LazyBinding>>);13impl ContextCreator {13impl ContextCreator {14 pub fn create(&self, this: Option<ObjValue>, super_obj: Option<ObjValue>) -> Result<Context> {14 pub fn create(15 &self,16 s: State,17 this: Option<ObjValue>,18 super_obj: Option<ObjValue>,19 ) -> Result<Context> {15 self.0.clone().extend_unbound(20 self.0.clone().extend_unbound(21 s,16 self.1.clone().unwrap(),22 self.1.clone().unwrap(),17 self.0.dollar().clone().or_else(|| this.clone()),23 self.0.dollar().clone().or_else(|| this.clone()),18 this,24 this,120 }126 }121 pub fn extend_unbound(127 pub fn extend_unbound(122 self,128 self,129 s: State,123 new_bindings: GcHashMap<IStr, LazyBinding>,130 new_bindings: GcHashMap<IStr, LazyBinding>,124 new_dollar: Option<ObjValue>,131 new_dollar: Option<ObjValue>,125 new_this: Option<ObjValue>,132 new_this: Option<ObjValue>,129 let super_obj = new_super_obj.or_else(|| self.0.super_obj.clone());136 let super_obj = new_super_obj.or_else(|| self.0.super_obj.clone());130 let mut new = GcHashMap::with_capacity(new_bindings.len());137 let mut new = GcHashMap::with_capacity(new_bindings.len());131 for (k, v) in new_bindings.0.into_iter() {138 for (k, v) in new_bindings.0.into_iter() {132 new.insert(k, v.evaluate(this.clone(), super_obj.clone())?);139 new.insert(k, v.evaluate(s.clone(), this.clone(), super_obj.clone())?);133 }140 }134 Ok(self.extend(new, new_dollar, this, super_obj))141 Ok(self.extend(new, new_dollar, this, super_obj))135 }142 }crates/jrsonnet-evaluator/src/evaluate/mod.rsdiffbeforeafterboth1use std::convert::TryFrom;23use gcmodule::{Cc, Trace};1use gcmodule::{Cc, Trace};4use jrsonnet_interner::IStr;2use jrsonnet_interner::IStr;14 evaluate::operator::{evaluate_add_op, evaluate_binary_op_special, evaluate_unary_op},12 evaluate::operator::{evaluate_add_op, evaluate_binary_op_special, evaluate_unary_op},15 function::CallLocation,13 function::CallLocation,16 gc::TraceBox,14 gc::TraceBox,17 push_frame, throw,15 throw,18 typed::BoundedUsize,16 typed::Typed,19 val::{ArrValue, FuncDesc, FuncVal, LazyValValue},17 val::{ArrValue, FuncDesc, FuncVal, LazyValValue},20 with_state, Bindable, Context, ContextCreator, FutureWrapper, GcHashMap, LazyBinding, LazyVal,18 Bindable, Context, ContextCreator, FutureWrapper, GcHashMap, LazyBinding, LazyVal, ObjValue,21 ObjValue, ObjValueBuilder, ObjectAssertion, Result, Val,19 ObjValueBuilder, ObjectAssertion, Result, State, Val,22};20};23pub mod operator;21pub mod operator;242225pub fn evaluate_binding_in_future(23pub fn evaluate_binding_in_future(b: &BindSpec, fctx: FutureWrapper<Context>) -> LazyVal {26 b: &BindSpec,27 context_creator: FutureWrapper<Context>,28) -> LazyVal {29 let b = b.clone();24 let b = b.clone();30 if let Some(params) = &b.params {25 if let Some(params) = &b.params {31 let params = params.clone();26 let params = params.clone();322733 #[derive(Trace)]28 #[derive(Trace)]34 struct LazyMethodBinding {29 struct LazyMethodBinding {35 context_creator: FutureWrapper<Context>,30 fctx: FutureWrapper<Context>,36 name: IStr,31 name: IStr,37 params: ParamsDesc,32 params: ParamsDesc,38 value: LocExpr,33 value: LocExpr,39 }34 }40 impl LazyValValue for LazyMethodBinding {35 impl LazyValValue for LazyMethodBinding {41 fn get(self: Box<Self>) -> Result<Val> {36 fn get(self: Box<Self>, _: State) -> Result<Val> {42 Ok(evaluate_method(37 Ok(evaluate_method(43 self.context_creator.unwrap(),38 self.fctx.unwrap(),44 self.name,39 self.name,45 self.params,40 self.params,46 self.value,41 self.value,49 }44 }504551 LazyVal::new(TraceBox(Box::new(LazyMethodBinding {46 LazyVal::new(TraceBox(Box::new(LazyMethodBinding {52 context_creator,47 fctx,53 name: b.name.clone(),48 name: b.name.clone(),54 params,49 params,55 value: b.value.clone(),50 value: b.value.clone(),56 })))51 })))57 } else {52 } else {58 #[derive(Trace)]53 #[derive(Trace)]59 struct LazyNamedBinding {54 struct LazyNamedBinding {60 context_creator: FutureWrapper<Context>,55 fctx: FutureWrapper<Context>,61 name: IStr,56 name: IStr,62 value: LocExpr,57 value: LocExpr,63 }58 }64 impl LazyValValue for LazyNamedBinding {59 impl LazyValValue for LazyNamedBinding {65 fn get(self: Box<Self>) -> Result<Val> {60 fn get(self: Box<Self>, s: State) -> Result<Val> {66 evaluate_named(self.context_creator.unwrap(), &self.value, self.name)61 evaluate_named(s, self.fctx.unwrap(), &self.value, self.name)67 }62 }68 }63 }69 LazyVal::new(TraceBox(Box::new(LazyNamedBinding {64 LazyVal::new(TraceBox(Box::new(LazyNamedBinding {70 context_creator,65 fctx,71 name: b.name.clone(),66 name: b.name.clone(),72 value: b.value,67 value: b.value,73 })))68 })))74 }69 }75}70}767177pub fn evaluate_binding(b: &BindSpec, context_creator: ContextCreator) -> (IStr, LazyBinding) {72pub fn evaluate_binding(b: &BindSpec, cctx: ContextCreator) -> (IStr, LazyBinding) {78 let b = b.clone();73 let b = b.clone();79 if let Some(params) = &b.params {74 if let Some(params) = &b.params {80 let params = params.clone();75 let params = params.clone();84 this: Option<ObjValue>,79 this: Option<ObjValue>,85 super_obj: Option<ObjValue>,80 super_obj: Option<ObjValue>,868187 context_creator: ContextCreator,82 cctx: ContextCreator,88 name: IStr,83 name: IStr,89 params: ParamsDesc,84 params: ParamsDesc,90 value: LocExpr,85 value: LocExpr,91 }86 }92 impl LazyValValue for BindableMethodLazyVal {87 impl LazyValValue for BindableMethodLazyVal {93 fn get(self: Box<Self>) -> Result<Val> {88 fn get(self: Box<Self>, s: State) -> Result<Val> {94 Ok(evaluate_method(89 Ok(evaluate_method(95 self.context_creator.create(self.this, self.super_obj)?,90 self.cctx.create(s, self.this, self.super_obj)?,96 self.name,91 self.name,97 self.params,92 self.params,98 self.value,93 self.value,10297103 #[derive(Trace)]98 #[derive(Trace)]104 struct BindableMethod {99 struct BindableMethod {105 context_creator: ContextCreator,100 cctx: ContextCreator,106 name: IStr,101 name: IStr,107 params: ParamsDesc,102 params: ParamsDesc,108 value: LocExpr,103 value: LocExpr,109 }104 }110 impl Bindable for BindableMethod {105 impl Bindable for BindableMethod {111 fn bind(&self, this: Option<ObjValue>, super_obj: Option<ObjValue>) -> Result<LazyVal> {106 fn bind(107 &self,108 _: State,109 this: Option<ObjValue>,110 super_obj: Option<ObjValue>,111 ) -> Result<LazyVal> {112 Ok(LazyVal::new(TraceBox(Box::new(BindableMethodLazyVal {112 Ok(LazyVal::new(TraceBox(Box::new(BindableMethodLazyVal {113 this,113 this,114 super_obj,114 super_obj,115115116 context_creator: self.context_creator.clone(),116 cctx: self.cctx.clone(),117 name: self.name.clone(),117 name: self.name.clone(),118 params: self.params.clone(),118 params: self.params.clone(),119 value: self.value.clone(),119 value: self.value.clone(),124 (124 (125 b.name.clone(),125 b.name.clone(),126 LazyBinding::Bindable(Cc::new(TraceBox(Box::new(BindableMethod {126 LazyBinding::Bindable(Cc::new(TraceBox(Box::new(BindableMethod {127 context_creator,127 cctx,128 name: b.name.clone(),128 name: b.name.clone(),129 params,129 params,130 value: b.value.clone(),130 value: b.value.clone(),136 this: Option<ObjValue>,136 this: Option<ObjValue>,137 super_obj: Option<ObjValue>,137 super_obj: Option<ObjValue>,138138139 context_creator: ContextCreator,139 cctx: ContextCreator,140 name: IStr,140 name: IStr,141 value: LocExpr,141 value: LocExpr,142 }142 }143 impl LazyValValue for BindableNamedLazyVal {143 impl LazyValValue for BindableNamedLazyVal {144 fn get(self: Box<Self>) -> Result<Val> {144 fn get(self: Box<Self>, s: State) -> Result<Val> {145 evaluate_named(145 evaluate_named(146 s.clone(),146 self.context_creator.create(self.this, self.super_obj)?,147 self.cctx.create(s, self.this, self.super_obj)?,147 &self.value,148 &self.value,148 self.name,149 self.name,149 )150 )152153153 #[derive(Trace)]154 #[derive(Trace)]154 struct BindableNamed {155 struct BindableNamed {155 context_creator: ContextCreator,156 cctx: ContextCreator,156 name: IStr,157 name: IStr,157 value: LocExpr,158 value: LocExpr,158 }159 }159 impl Bindable for BindableNamed {160 impl Bindable for BindableNamed {160 fn bind(&self, this: Option<ObjValue>, super_obj: Option<ObjValue>) -> Result<LazyVal> {161 fn bind(162 &self,163 _: State,164 this: Option<ObjValue>,165 super_obj: Option<ObjValue>,166 ) -> Result<LazyVal> {161 Ok(LazyVal::new(TraceBox(Box::new(BindableNamedLazyVal {167 Ok(LazyVal::new(TraceBox(Box::new(BindableNamedLazyVal {162 this,168 this,163 super_obj,169 super_obj,164170165 context_creator: self.context_creator.clone(),171 cctx: self.cctx.clone(),166 name: self.name.clone(),172 name: self.name.clone(),167 value: self.value.clone(),173 value: self.value.clone(),168 }))))174 }))))172 (178 (173 b.name.clone(),179 b.name.clone(),174 LazyBinding::Bindable(Cc::new(TraceBox(Box::new(BindableNamed {180 LazyBinding::Bindable(Cc::new(TraceBox(Box::new(BindableNamed {175 context_creator,181 cctx,176 name: b.name.clone(),182 name: b.name.clone(),177 value: b.value.clone(),183 value: b.value.clone(),178 })))),184 })))),190}196}191197192pub fn evaluate_field_name(198pub fn evaluate_field_name(199 s: State,193 context: Context,200 ctx: Context,194 field_name: &jrsonnet_parser::FieldName,201 field_name: &jrsonnet_parser::FieldName,195) -> Result<Option<IStr>> {202) -> Result<Option<IStr>> {196 Ok(match field_name {203 Ok(match field_name {197 jrsonnet_parser::FieldName::Fixed(n) => Some(n.clone()),204 jrsonnet_parser::FieldName::Fixed(n) => Some(n.clone()),198 jrsonnet_parser::FieldName::Dyn(expr) => push_frame(205 jrsonnet_parser::FieldName::Dyn(expr) => s.push(199 CallLocation::new(&expr.1),206 CallLocation::new(&expr.1),200 || "evaluating field name".to_string(),207 || "evaluating field name".to_string(),201 || {208 || {202 let value = evaluate(context, expr)?;209 let value = evaluate(s.clone(), ctx, expr)?;203 if matches!(value, Val::Null) {210 if matches!(value, Val::Null) {204 Ok(None)211 Ok(None)205 } else {212 } else {206 Ok(Some(IStr::try_from(value)?))213 Ok(Some(IStr::from_untyped(value, s.clone())?))207 }214 }208 },215 },209 )?,216 )?,210 })217 })211}218}212219213pub fn evaluate_comp(220pub fn evaluate_comp(221 s: State,214 context: Context,222 ctx: Context,215 specs: &[CompSpec],223 specs: &[CompSpec],216 callback: &mut impl FnMut(Context) -> Result<()>,224 callback: &mut impl FnMut(Context) -> Result<()>,217) -> Result<()> {225) -> Result<()> {218 match specs.get(0) {226 match specs.get(0) {219 None => callback(context)?,227 None => callback(ctx)?,220 Some(CompSpec::IfSpec(IfSpecData(cond))) => {228 Some(CompSpec::IfSpec(IfSpecData(cond))) => {221 if bool::try_from(evaluate(context.clone(), cond)?)? {229 if bool::from_untyped(evaluate(s.clone(), ctx.clone(), cond)?, s.clone())? {222 evaluate_comp(context, &specs[1..], callback)?230 evaluate_comp(s, ctx, &specs[1..], callback)?223 }231 }224 }232 }225 Some(CompSpec::ForSpec(ForSpecData(var, expr))) => match evaluate(context.clone(), expr)? {233 Some(CompSpec::ForSpec(ForSpecData(var, expr))) => {234 match evaluate(s.clone(), ctx.clone(), expr)? {226 Val::Arr(list) => {235 Val::Arr(list) => {227 for item in list.iter() {236 for item in list.iter(s.clone()) {228 evaluate_comp(237 evaluate_comp(238 s.clone(),229 context.clone().with_var(var.clone(), item?.clone()),239 ctx.clone().with_var(var.clone(), item?.clone()),230 &specs[1..],240 &specs[1..],231 callback,241 callback,232 )?242 )?233 }243 }234 }244 }235 _ => throw!(InComprehensionCanOnlyIterateOverArray),245 _ => throw!(InComprehensionCanOnlyIterateOverArray),236 },246 }247 }237 }248 }238 Ok(())249 Ok(())239}250}240251241pub fn evaluate_member_list_object(context: Context, members: &[Member]) -> Result<ObjValue> {252pub fn evaluate_member_list_object(s: State, ctx: Context, members: &[Member]) -> Result<ObjValue> {242 let new_bindings = FutureWrapper::new();253 let new_bindings = FutureWrapper::new();243 let future_this = FutureWrapper::new();254 let future_this = FutureWrapper::new();244 let context_creator = ContextCreator(context.clone(), new_bindings.clone());255 let cctx = ContextCreator(ctx.clone(), new_bindings.clone());245 {256 {246 let mut bindings: GcHashMap<IStr, LazyBinding> = GcHashMap::with_capacity(members.len());257 let mut bindings: GcHashMap<IStr, LazyBinding> = GcHashMap::with_capacity(members.len());247 for (n, b) in members258 for (n, b) in members250 Member::BindStmt(b) => Some(b.clone()),261 Member::BindStmt(b) => Some(b.clone()),251 _ => None,262 _ => None,252 })263 })253 .map(|b| evaluate_binding(&b, context_creator.clone()))264 .map(|b| evaluate_binding(&b, cctx.clone()))254 {265 {255 bindings.insert(n, b);266 bindings.insert(n, b);256 }267 }267 visibility,278 visibility,268 value,279 value,269 }) => {280 }) => {270 let name = evaluate_field_name(context.clone(), name)?;281 let name = evaluate_field_name(s.clone(), ctx.clone(), name)?;271 if name.is_none() {282 if name.is_none() {272 continue;283 continue;273 }284 }274 let name = name.unwrap();285 let name = name.unwrap();275286276 #[derive(Trace)]287 #[derive(Trace)]277 struct ObjMemberBinding {288 struct ObjMemberBinding {278 context_creator: ContextCreator,289 cctx: ContextCreator,279 value: LocExpr,290 value: LocExpr,280 name: IStr,291 name: IStr,281 }292 }282 impl Bindable for ObjMemberBinding {293 impl Bindable for ObjMemberBinding {283 fn bind(294 fn bind(284 &self,295 &self,296 s: State,285 this: Option<ObjValue>,297 this: Option<ObjValue>,286 super_obj: Option<ObjValue>,298 super_obj: Option<ObjValue>,287 ) -> Result<LazyVal> {299 ) -> Result<LazyVal> {288 Ok(LazyVal::new_resolved(evaluate_named(300 Ok(LazyVal::new_resolved(evaluate_named(301 s.clone(),289 self.context_creator.create(this, super_obj)?,302 self.cctx.create(s, this, super_obj)?,290 &self.value,303 &self.value,291 self.name.clone(),304 self.name.clone(),292 )?))305 )?))298 .with_visibility(*visibility)311 .with_visibility(*visibility)299 .with_location(value.1.clone())312 .with_location(value.1.clone())300 .bindable(TraceBox(Box::new(ObjMemberBinding {313 .bindable(314 s.clone(),315 TraceBox(Box::new(ObjMemberBinding {301 context_creator: context_creator.clone(),316 cctx: cctx.clone(),302 value: value.clone(),317 value: value.clone(),303 name,318 name,304 })))?;319 })),320 )?;305 }321 }306 Member::Field(FieldMember {322 Member::Field(FieldMember {309 value,325 value,310 ..326 ..311 }) => {327 }) => {312 let name = evaluate_field_name(context.clone(), name)?;328 let name = evaluate_field_name(s.clone(), ctx.clone(), name)?;313 if name.is_none() {329 if name.is_none() {314 continue;330 continue;315 }331 }316 let name = name.unwrap();332 let name = name.unwrap();317 #[derive(Trace)]333 #[derive(Trace)]318 struct ObjMemberBinding {334 struct ObjMemberBinding {319 context_creator: ContextCreator,335 cctx: ContextCreator,320 value: LocExpr,336 value: LocExpr,321 params: ParamsDesc,337 params: ParamsDesc,322 name: IStr,338 name: IStr,323 }339 }324 impl Bindable for ObjMemberBinding {340 impl Bindable for ObjMemberBinding {325 fn bind(341 fn bind(326 &self,342 &self,343 s: State,327 this: Option<ObjValue>,344 this: Option<ObjValue>,328 super_obj: Option<ObjValue>,345 super_obj: Option<ObjValue>,329 ) -> Result<LazyVal> {346 ) -> Result<LazyVal> {330 Ok(LazyVal::new_resolved(evaluate_method(347 Ok(LazyVal::new_resolved(evaluate_method(331 self.context_creator.create(this, super_obj)?,348 self.cctx.create(s, this, super_obj)?,332 self.name.clone(),349 self.name.clone(),333 self.params.clone(),350 self.params.clone(),334 self.value.clone(),351 self.value.clone(),340 .hide()357 .hide()341 .with_location(value.1.clone())358 .with_location(value.1.clone())342 .bindable(TraceBox(Box::new(ObjMemberBinding {359 .bindable(360 s.clone(),361 TraceBox(Box::new(ObjMemberBinding {343 context_creator: context_creator.clone(),362 cctx: cctx.clone(),344 value: value.clone(),363 value: value.clone(),345 params: params.clone(),364 params: params.clone(),346 name,365 name,347 })))?;366 })),367 )?;348 }368 }349 Member::BindStmt(_) => {}369 Member::BindStmt(_) => {}350 Member::AssertStmt(stmt) => {370 Member::AssertStmt(stmt) => {351 #[derive(Trace)]371 #[derive(Trace)]352 struct ObjectAssert {372 struct ObjectAssert {353 context_creator: ContextCreator,373 cctx: ContextCreator,354 assert: AssertStmt,374 assert: AssertStmt,355 }375 }356 impl ObjectAssertion for ObjectAssert {376 impl ObjectAssertion for ObjectAssert {357 fn run(377 fn run(358 &self,378 &self,379 s: State,359 this: Option<ObjValue>,380 this: Option<ObjValue>,360 super_obj: Option<ObjValue>,381 super_obj: Option<ObjValue>,361 ) -> Result<()> {382 ) -> Result<()> {362 let ctx = self.context_creator.create(this, super_obj)?;383 let ctx = self.cctx.create(s.clone(), this, super_obj)?;363 evaluate_assert(ctx, &self.assert)384 evaluate_assert(s, ctx, &self.assert)364 }385 }365 }386 }366 builder.assert(TraceBox(Box::new(ObjectAssert {387 builder.assert(TraceBox(Box::new(ObjectAssert {367 context_creator: context_creator.clone(),388 cctx: cctx.clone(),368 assert: stmt.clone(),389 assert: stmt.clone(),369 })));390 })));370 }391 }375 Ok(this)396 Ok(this)376}397}377398378pub fn evaluate_object(context: Context, object: &ObjBody) -> Result<ObjValue> {399pub fn evaluate_object(s: State, ctx: Context, object: &ObjBody) -> Result<ObjValue> {379 Ok(match object {400 Ok(match object {380 ObjBody::MemberList(members) => evaluate_member_list_object(context, members)?,401 ObjBody::MemberList(members) => evaluate_member_list_object(s, ctx, members)?,381 ObjBody::ObjComp(obj) => {402 ObjBody::ObjComp(obj) => {382 let future_this = FutureWrapper::new();403 let future_this = FutureWrapper::new();383 let mut builder = ObjValueBuilder::new();404 let mut builder = ObjValueBuilder::new();384 evaluate_comp(context.clone(), &obj.compspecs, &mut |ctx| {405 evaluate_comp(s.clone(), ctx, &obj.compspecs, &mut |ctx| {385 let new_bindings = FutureWrapper::new();406 let new_bindings = FutureWrapper::new();386 let context_creator = ContextCreator(context.clone(), new_bindings.clone());407 let cctx = ContextCreator(ctx.clone(), new_bindings.clone());387 let mut bindings: GcHashMap<IStr, LazyBinding> =408 let mut bindings: GcHashMap<IStr, LazyBinding> =388 GcHashMap::with_capacity(obj.pre_locals.len() + obj.post_locals.len());409 GcHashMap::with_capacity(obj.pre_locals.len() + obj.post_locals.len());389 for (n, b) in obj410 for (n, b) in obj390 .pre_locals411 .pre_locals391 .iter()412 .iter()392 .chain(obj.post_locals.iter())413 .chain(obj.post_locals.iter())393 .map(|b| evaluate_binding(b, context_creator.clone()))414 .map(|b| evaluate_binding(b, cctx.clone()))394 {415 {395 bindings.insert(n, b);416 bindings.insert(n, b);396 }417 }397 new_bindings.fill(bindings.clone());418 new_bindings.fill(bindings.clone());398 let ctx = ctx.extend_unbound(bindings, None, None, None)?;419 let ctx = ctx.extend_unbound(s.clone(), bindings, None, None, None)?;399 let key = evaluate(ctx.clone(), &obj.key)?;420 let key = evaluate(s.clone(), ctx.clone(), &obj.key)?;400421401 match key {422 match key {402 Val::Null => {}423 Val::Null => {}403 Val::Str(n) => {424 Val::Str(n) => {404 #[derive(Trace)]425 #[derive(Trace)]405 struct ObjCompBinding {426 struct ObjCompBinding {406 context: Context,427 ctx: Context,407 value: LocExpr,428 value: LocExpr,408 }429 }409 impl Bindable for ObjCompBinding {430 impl Bindable for ObjCompBinding {410 fn bind(431 fn bind(411 &self,432 &self,433 s: State,412 this: Option<ObjValue>,434 this: Option<ObjValue>,413 _super_obj: Option<ObjValue>,435 _super_obj: Option<ObjValue>,414 ) -> Result<LazyVal> {436 ) -> Result<LazyVal> {415 Ok(LazyVal::new_resolved(evaluate(437 Ok(LazyVal::new_resolved(evaluate(438 s,416 self.context439 self.ctx.clone().extend(GcHashMap::new(), None, this, None),417 .clone()418 .extend(GcHashMap::new(), None, this, None),419 &self.value,440 &self.value,425 .with_location(obj.value.1.clone())446 .with_location(obj.value.1.clone())426 .with_add(obj.plus)447 .with_add(obj.plus)427 .bindable(TraceBox(Box::new(ObjCompBinding {448 .bindable(449 s.clone(),450 TraceBox(Box::new(ObjCompBinding {428 context: ctx,451 ctx,429 value: obj.value.clone(),452 value: obj.value.clone(),430 })))?;453 })),454 )?;431 }455 }432 v => throw!(FieldMustBeStringGot(v.value_type())),456 v => throw!(FieldMustBeStringGot(v.value_type())),443}467}444468445pub fn evaluate_apply(469pub fn evaluate_apply(470 s: State,446 context: Context,471 ctx: Context,447 value: &LocExpr,472 value: &LocExpr,448 args: &ArgsDesc,473 args: &ArgsDesc,449 loc: CallLocation,474 loc: CallLocation,450 tailstrict: bool,475 tailstrict: bool,451) -> Result<Val> {476) -> Result<Val> {452 let value = evaluate(context.clone(), value)?;477 let value = evaluate(s.clone(), ctx.clone(), value)?;453 Ok(match value {478 Ok(match value {454 Val::Func(f) => {479 Val::Func(f) => {455 let body = || f.evaluate(context, loc, args, tailstrict);480 let body = || f.evaluate(s.clone(), ctx, loc, args, tailstrict);456 if tailstrict {481 if tailstrict {457 body()?482 body()?458 } else {483 } else {459 push_frame(loc, || format!("function <{}> call", f.name()), body)?484 s.push(loc, || format!("function <{}> call", f.name()), body)?460 }485 }461 }486 }462 v => throw!(OnlyFunctionsCanBeCalledGot(v.value_type())),487 v => throw!(OnlyFunctionsCanBeCalledGot(v.value_type())),463 })488 })464}489}465490466pub fn evaluate_assert(context: Context, assertion: &AssertStmt) -> Result<()> {491pub fn evaluate_assert(s: State, ctx: Context, assertion: &AssertStmt) -> Result<()> {467 let value = &assertion.0;492 let value = &assertion.0;468 let msg = &assertion.1;493 let msg = &assertion.1;469 let assertion_result = push_frame(494 let assertion_result = s.push(470 CallLocation::new(&value.1),495 CallLocation::new(&value.1),471 || "assertion condition".to_owned(),496 || "assertion condition".to_owned(),472 || bool::try_from(evaluate(context.clone(), value)?),497 || bool::from_untyped(evaluate(s.clone(), ctx.clone(), value)?, s.clone()),473 )?;498 )?;474 if !assertion_result {499 if !assertion_result {475 push_frame(500 s.push(476 CallLocation::new(&value.1),501 CallLocation::new(&value.1),477 || "assertion failure".to_owned(),502 || "assertion failure".to_owned(),478 || {503 || {479 if let Some(msg) = msg {504 if let Some(msg) = msg {480 throw!(AssertionFailed(evaluate(context, msg)?.to_string()?));505 throw!(AssertionFailed(506 evaluate(s.clone(), ctx, msg)?.to_string(s.clone())?507 ));481 } else {508 } else {482 throw!(AssertionFailed(Val::Null.to_string()?));509 throw!(AssertionFailed(Val::Null.to_string(s.clone())?));483 }510 }484 },511 },485 )?512 )?486 }513 }487 Ok(())514 Ok(())488}515}489516490pub fn evaluate_named(context: Context, lexpr: &LocExpr, name: IStr) -> Result<Val> {517pub fn evaluate_named(s: State, ctx: Context, lexpr: &LocExpr, name: IStr) -> Result<Val> {491 use Expr::*;518 use Expr::*;492 let LocExpr(expr, _loc) = lexpr;519 let LocExpr(expr, _loc) = lexpr;493 Ok(match &**expr {520 Ok(match &**expr {494 Function(params, body) => evaluate_method(context, name, params.clone(), body.clone()),521 Function(params, body) => evaluate_method(ctx, name, params.clone(), body.clone()),495 _ => evaluate(context, lexpr)?,522 _ => evaluate(s, ctx, lexpr)?,496 })523 })497}524}498525499pub fn evaluate(context: Context, expr: &LocExpr) -> Result<Val> {526pub fn evaluate(s: State, ctx: Context, expr: &LocExpr) -> Result<Val> {500 use Expr::*;527 use Expr::*;501 let LocExpr(expr, loc) = expr;528 let LocExpr(expr, loc) = expr;502 // let bp = with_state(|s| s.0.stop_at.borrow().clone());529 // let bp = with_state(|s| s.0.stop_at.borrow().clone());503 Ok(match &**expr {530 Ok(match &**expr {504 Literal(LiteralType::This) => {531 Literal(LiteralType::This) => {505 Val::Obj(context.this().clone().ok_or(CantUseSelfOutsideOfObject)?)532 Val::Obj(ctx.this().clone().ok_or(CantUseSelfOutsideOfObject)?)506 }533 }507 Literal(LiteralType::Super) => Val::Obj(534 Literal(LiteralType::Super) => Val::Obj(508 context509 .super_obj()535 ctx.super_obj()510 .clone()536 .clone()511 .ok_or(NoSuperFound)?537 .ok_or(NoSuperFound)?512 .with_this(context.this().clone().unwrap()),538 .with_this(ctx.this().clone().unwrap()),513 ),539 ),514 Literal(LiteralType::Dollar) => {540 Literal(LiteralType::Dollar) => {515 Val::Obj(context.dollar().clone().ok_or(NoTopLevelObjectFound)?)541 Val::Obj(ctx.dollar().clone().ok_or(NoTopLevelObjectFound)?)516 }542 }517 Literal(LiteralType::True) => Val::Bool(true),543 Literal(LiteralType::True) => Val::Bool(true),518 Literal(LiteralType::False) => Val::Bool(false),544 Literal(LiteralType::False) => Val::Bool(false),519 Literal(LiteralType::Null) => Val::Null,545 Literal(LiteralType::Null) => Val::Null,520 Parened(e) => evaluate(context, e)?,546 Parened(e) => evaluate(s, ctx, e)?,521 Str(v) => Val::Str(v.clone()),547 Str(v) => Val::Str(v.clone()),522 Num(v) => Val::new_checked_num(*v)?,548 Num(v) => Val::new_checked_num(*v)?,523 BinaryOp(v1, o, v2) => evaluate_binary_op_special(context, v1, *o, v2)?,549 BinaryOp(v1, o, v2) => evaluate_binary_op_special(s, ctx, v1, *o, v2)?,524 UnaryOp(o, v) => evaluate_unary_op(*o, &evaluate(context, v)?)?,550 UnaryOp(o, v) => evaluate_unary_op(*o, &evaluate(s, ctx, v)?)?,525 Var(name) => push_frame(551 Var(name) => s.push(526 CallLocation::new(loc),552 CallLocation::new(loc),527 || format!("variable <{}> access", name),553 || format!("variable <{}> access", name),528 || context.binding(name.clone())?.evaluate(),554 || ctx.binding(name.clone())?.evaluate(s.clone()),529 )?,555 )?,530 Index(value, index) => {556 Index(value, index) => {531 match (evaluate(context.clone(), value)?, evaluate(context, index)?) {557 match (558 evaluate(s.clone(), ctx.clone(), value)?,559 evaluate(s.clone(), ctx, index)?,560 ) {532 (Val::Obj(v), Val::Str(s)) => {561 (Val::Obj(v), Val::Str(key)) => s.push(533 let sn = s.clone();534 push_frame(535 CallLocation::new(loc),562 CallLocation::new(loc),536 || format!("field <{}> access", sn),563 || format!("field <{}> access", key),537 || {564 || {538 if let Some(v) = v.get(s.clone())? {565 if let Some(v) = v.get(s.clone(), key.clone())? {539 Ok(v)566 Ok(v)540 } else {567 } else {541 throw!(NoSuchField(s))568 throw!(NoSuchField(key.clone()))542 }569 }543 },570 },544 )?571 )?,545 }546 (Val::Obj(_), n) => throw!(ValueIndexMustBeTypeGot(572 (Val::Obj(_), n) => throw!(ValueIndexMustBeTypeGot(547 ValType::Obj,573 ValType::Obj,548 ValType::Str,574 ValType::Str,553 if n.fract() > f64::EPSILON {579 if n.fract() > f64::EPSILON {554 throw!(FractionalIndex)580 throw!(FractionalIndex)555 }581 }556 v.get(n as usize)?582 v.get(s, n as usize)?557 .ok_or_else(|| ArrayBoundsError(n as usize, v.len()))?583 .ok_or_else(|| ArrayBoundsError(n as usize, v.len()))?558 }584 }559 (Val::Arr(_), Val::Str(n)) => throw!(AttemptedIndexAnArrayWithString(n)),585 (Val::Arr(_), Val::Str(n)) => throw!(AttemptedIndexAnArrayWithString(n)),582 LocalExpr(bindings, returned) => {608 LocalExpr(bindings, returned) => {583 let mut new_bindings: GcHashMap<IStr, LazyVal> =609 let mut new_bindings: GcHashMap<IStr, LazyVal> =584 GcHashMap::with_capacity(bindings.len());610 GcHashMap::with_capacity(bindings.len());585 let future_context = Context::new_future();611 let fctx = Context::new_future();586 for b in bindings {612 for b in bindings {587 new_bindings.insert(613 new_bindings.insert(b.name.clone(), evaluate_binding_in_future(b, fctx.clone()));588 b.name.clone(),589 evaluate_binding_in_future(b, future_context.clone()),590 );591 }614 }592 let context = context615 let ctx = ctx.extend_bound(new_bindings).into_future(fctx);593 .extend_bound(new_bindings)594 .into_future(future_context);595 evaluate(context, &returned.clone())?616 evaluate(s, ctx, &returned.clone())?596 }617 }597 Arr(items) => {618 Arr(items) => {598 let mut out = Vec::with_capacity(items.len());619 let mut out = Vec::with_capacity(items.len());599 for item in items {620 for item in items {600 // TODO: Implement ArrValue::Lazy with same context for every element?621 // TODO: Implement ArrValue::Lazy with same context for every element?601 #[derive(Trace)]622 #[derive(Trace)]602 struct ArrayElement {623 struct ArrayElement {603 context: Context,624 ctx: Context,604 item: LocExpr,625 item: LocExpr,605 }626 }606 impl LazyValValue for ArrayElement {627 impl LazyValValue for ArrayElement {607 fn get(self: Box<Self>) -> Result<Val> {628 fn get(self: Box<Self>, s: State) -> Result<Val> {608 evaluate(self.context, &self.item)629 evaluate(s, self.ctx, &self.item)609 }630 }610 }631 }611 out.push(LazyVal::new(TraceBox(Box::new(ArrayElement {632 out.push(LazyVal::new(TraceBox(Box::new(ArrayElement {612 context: context.clone(),633 ctx: ctx.clone(),613 item: item.clone(),634 item: item.clone(),614 }))));635 }))));615 }636 }616 Val::Arr(out.into())637 Val::Arr(out.into())617 }638 }618 ArrComp(expr, comp_specs) => {639 ArrComp(expr, comp_specs) => {619 let mut out = Vec::new();640 let mut out = Vec::new();620 evaluate_comp(context, comp_specs, &mut |ctx| {641 evaluate_comp(s.clone(), ctx, comp_specs, &mut |ctx| {621 out.push(evaluate(ctx, expr)?);642 out.push(evaluate(s.clone(), ctx, expr)?);622 Ok(())643 Ok(())623 })?;644 })?;624 Val::Arr(ArrValue::Eager(Cc::new(out)))645 Val::Arr(ArrValue::Eager(Cc::new(out)))625 }646 }626 Obj(body) => Val::Obj(evaluate_object(context, body)?),647 Obj(body) => Val::Obj(evaluate_object(s, ctx, body)?),627 ObjExtend(s, t) => evaluate_add_op(648 ObjExtend(a, b) => evaluate_add_op(649 s.clone(),628 &evaluate(context.clone(), s)?,650 &evaluate(s.clone(), ctx.clone(), a)?,629 &Val::Obj(evaluate_object(context, t)?),651 &Val::Obj(evaluate_object(s, ctx, b)?),630 )?,652 )?,631 Apply(value, args, tailstrict) => {653 Apply(value, args, tailstrict) => {632 evaluate_apply(context, value, args, CallLocation::new(loc), *tailstrict)?654 evaluate_apply(s, ctx, value, args, CallLocation::new(loc), *tailstrict)?633 }655 }634 Function(params, body) => {656 Function(params, body) => {635 evaluate_method(context, "anonymous".into(), params.clone(), body.clone())657 evaluate_method(ctx, "anonymous".into(), params.clone(), body.clone())636 }658 }637 Intrinsic(name) => Val::Func(FuncVal::StaticBuiltin(659 Intrinsic(name) => Val::Func(FuncVal::StaticBuiltin(638 BUILTINS660 BUILTINS639 .with(|b| b.get(name).copied())661 .with(|b| b.get(name).copied())640 .ok_or_else(|| IntrinsicNotFound(name.clone()))?,662 .ok_or_else(|| IntrinsicNotFound(name.clone()))?,641 )),663 )),642 AssertExpr(assert, returned) => {664 AssertExpr(assert, returned) => {643 evaluate_assert(context.clone(), assert)?;665 evaluate_assert(s.clone(), ctx.clone(), assert)?;644 evaluate(context, returned)?666 evaluate(s, ctx, returned)?645 }667 }646 ErrorStmt(e) => push_frame(668 ErrorStmt(e) => s.push(647 CallLocation::new(loc),669 CallLocation::new(loc),648 || "error statement".to_owned(),670 || "error statement".to_owned(),649 || throw!(RuntimeError(evaluate(context, e)?.to_string()?,)),671 || {672 throw!(RuntimeError(673 evaluate(s.clone(), ctx, e)?.to_string(s.clone())?,674 ))675 },650 )?,676 )?,651 IfElse {677 IfElse {652 cond,678 cond,653 cond_then,679 cond_then,654 cond_else,680 cond_else,655 } => {681 } => {656 if push_frame(682 if s.push(657 CallLocation::new(loc),683 CallLocation::new(loc),658 || "if condition".to_owned(),684 || "if condition".to_owned(),659 || bool::try_from(evaluate(context.clone(), &cond.0)?),685 || bool::from_untyped(evaluate(s.clone(), ctx.clone(), &cond.0)?, s.clone()),660 )? {686 )? {661 evaluate(context, cond_then)?687 evaluate(s, ctx, cond_then)?662 } else {688 } else {663 match cond_else {689 match cond_else {664 Some(v) => evaluate(context, v)?,690 Some(v) => evaluate(s, ctx, v)?,665 None => Val::Null,691 None => Val::Null,666 }692 }667 }693 }668 }694 }669 Slice(value, desc) => {695 Slice(value, desc) => {670 let indexable = evaluate(context.clone(), value)?;696 let indexable = evaluate(s.clone(), ctx.clone(), value)?;671 let loc = CallLocation::new(loc);697 let loc = CallLocation::new(loc);672698673 fn parse_idx<const MIN: usize>(699 fn parse_idx<T: Typed>(674 loc: CallLocation,700 loc: CallLocation,701 s: State,675 context: &Context,702 ctx: &Context,676 expr: &Option<LocExpr>,703 expr: &Option<LocExpr>,677 desc: &'static str,704 desc: &'static str,678 ) -> Result<Option<BoundedUsize<MIN, { i32::MAX as usize }>>> {705 ) -> Result<Option<T>> {679 if let Some(value) = expr {706 if let Some(value) = expr {680 Ok(Some(push_frame(707 Ok(Some(s.push(681 loc,708 loc,682 || format!("slice {}", desc),709 || format!("slice {}", desc),683 || evaluate(context.clone(), value)?.try_into(),710 || T::from_untyped(evaluate(s.clone(), ctx.clone(), value)?, s.clone()),684 )?))711 )?))685 } else {712 } else {686 Ok(None)713 Ok(None)687 }714 }688 }715 }689716690 let start = parse_idx(loc, &context, &desc.start, "start")?;717 let start = parse_idx(loc, s.clone(), &ctx, &desc.start, "start")?;691 let end = parse_idx(loc, &context, &desc.end, "end")?;718 let end = parse_idx(loc, s.clone(), &ctx, &desc.end, "end")?;692 let step = parse_idx(loc, &context, &desc.step, "step")?;719 let step = parse_idx(loc, s, &ctx, &desc.step, "step")?;693720694 std_slice(indexable.into_indexable()?, start, end, step)?721 std_slice(indexable.into_indexable()?, start, end, step)?695 }722 }696 Import(path) => {723 Import(path) => {697 let tmp = loc.clone().0;724 let tmp = loc.clone().0;698 let mut import_location = tmp.to_path_buf();725 let mut import_location = tmp.to_path_buf();699 import_location.pop();726 import_location.pop();700 push_frame(727 s.push(701 CallLocation::new(loc),728 CallLocation::new(loc),702 || format!("import {:?}", path),729 || format!("import {:?}", path),703 || with_state(|s| s.import_file(&import_location, path)),730 || s.import_file(&import_location, path),704 )?731 )?705 }732 }706 ImportStr(path) => {733 ImportStr(path) => {707 let tmp = loc.clone().0;734 let tmp = loc.clone().0;708 let mut import_location = tmp.to_path_buf();735 let mut import_location = tmp.to_path_buf();709 import_location.pop();736 import_location.pop();710 Val::Str(with_state(|s| s.import_file_str(&import_location, path))?)737 Val::Str(s.import_file_str(&import_location, path)?)711 }738 }712 ImportBin(path) => {739 ImportBin(path) => {713 let tmp = loc.clone().0;740 let tmp = loc.clone().0;714 let mut import_location = tmp.to_path_buf();741 let mut import_location = tmp.to_path_buf();715 import_location.pop();742 import_location.pop();716 let bytes = with_state(|s| s.import_file_bin(&import_location, path))?;743 let bytes = s.import_file_bin(&import_location, path)?;717 Val::Arr(ArrValue::Bytes(bytes))744 Val::Arr(ArrValue::Bytes(bytes))718 }745 }719 })746 })crates/jrsonnet-evaluator/src/evaluate/operator.rsdiffbeforeafterboth1use std::convert::TryInto;23use jrsonnet_parser::{BinaryOpType, LocExpr, UnaryOpType};1use jrsonnet_parser::{BinaryOpType, LocExpr, UnaryOpType};425use crate::{3use crate::{6 builtin::std_format, error::Error::*, evaluate, throw, val::equals, Context, Result, Val,4 builtin::std_format, error::Error::*, evaluate, throw, typed::Typed, val::equals, Context,5 Result, State, Val,7};6};879pub fn evaluate_unary_op(op: UnaryOpType, b: &Val) -> Result<Val> {8pub fn evaluate_unary_op(op: UnaryOpType, b: &Val) -> Result<Val> {17 })16 })18}17}191820pub fn evaluate_add_op(a: &Val, b: &Val) -> Result<Val> {19pub fn evaluate_add_op(s: State, a: &Val, b: &Val) -> Result<Val> {21 use Val::*;20 use Val::*;22 Ok(match (a, b) {21 Ok(match (a, b) {23 (Str(v1), Str(v2)) => Str(((**v1).to_owned() + v2).into()),22 (Str(v1), Str(v2)) => Str(((**v1).to_owned() + v2).into()),26 (Num(n), Str(o)) => Str(format!("{}{}", n, o).into()),25 (Num(n), Str(o)) => Str(format!("{}{}", n, o).into()),27 (Str(o), Num(n)) => Str(format!("{}{}", o, n).into()),26 (Str(o), Num(n)) => Str(format!("{}{}", o, n).into()),282729 (Str(s), o) => Str(format!("{}{}", s, o.clone().to_string()?).into()),28 (Str(a), o) => Str(format!("{}{}", a, o.clone().to_string(s)?).into()),30 (o, Str(s)) => Str(format!("{}{}", o.clone().to_string()?, s).into()),29 (o, Str(a)) => Str(format!("{}{}", o.clone().to_string(s)?, a).into()),313032 (Obj(v1), Obj(v2)) => Obj(v2.extend_from(v1.clone())),31 (Obj(v1), Obj(v2)) => Obj(v2.extend_from(v1.clone())),33 (Arr(a), Arr(b)) => {32 (Arr(a), Arr(b)) => {45 })44 })46}45}474648pub fn evaluate_mod_op(a: &Val, b: &Val) -> Result<Val> {47pub fn evaluate_mod_op(s: State, a: &Val, b: &Val) -> Result<Val> {49 use Val::*;48 use Val::*;50 match (a, b) {49 match (a, b) {51 (Num(a), Num(b)) => Ok(Num(a % b)),50 (Num(a), Num(b)) => Ok(Num(a % b)),52 (Str(str), vals) => std_format(str.clone(), vals.clone())?.try_into(),51 (Str(str), vals) => {52 String::into_untyped(std_format(s.clone(), str.clone(), vals.clone())?, s)53 }53 (a, b) => throw!(BinaryOperatorDoesNotOperateOnValues(54 (a, b) => throw!(BinaryOperatorDoesNotOperateOnValues(54 BinaryOpType::Mod,55 BinaryOpType::Mod,55 a.value_type(),56 a.value_type(),59}60}606161pub fn evaluate_binary_op_special(62pub fn evaluate_binary_op_special(63 s: State,62 context: Context,64 ctx: Context,63 a: &LocExpr,65 a: &LocExpr,64 op: BinaryOpType,66 op: BinaryOpType,65 b: &LocExpr,67 b: &LocExpr,66) -> Result<Val> {68) -> Result<Val> {67 use BinaryOpType::*;69 use BinaryOpType::*;68 use Val::*;70 use Val::*;69 Ok(match (evaluate(context.clone(), a)?, op, b) {71 Ok(match (evaluate(s.clone(), ctx.clone(), a)?, op, b) {70 (Bool(true), Or, _o) => Val::Bool(true),72 (Bool(true), Or, _o) => Val::Bool(true),71 (Bool(false), And, _o) => Val::Bool(false),73 (Bool(false), And, _o) => Val::Bool(false),72 (a, op, eb) => evaluate_binary_op_normal(&a, op, &evaluate(context, eb)?)?,74 (a, op, eb) => evaluate_binary_op_normal(s.clone(), &a, op, &evaluate(s, ctx, eb)?)?,73 })75 })74}76}757776pub fn evaluate_binary_op_normal(a: &Val, op: BinaryOpType, b: &Val) -> Result<Val> {78pub fn evaluate_binary_op_normal(s: State, a: &Val, op: BinaryOpType, b: &Val) -> Result<Val> {77 use BinaryOpType::*;79 use BinaryOpType::*;78 use Val::*;80 use Val::*;79 Ok(match (a, op, b) {81 Ok(match (a, op, b) {80 (a, Add, b) => evaluate_add_op(a, b)?,82 (a, Add, b) => evaluate_add_op(s, a, b)?,818382 (a, Eq, b) => Bool(equals(a, b)?),84 (a, Eq, b) => Bool(equals(s, a, b)?),83 (a, Neq, b) => Bool(!equals(a, b)?),85 (a, Neq, b) => Bool(!equals(s, a, b)?),848685 (Str(a), In, Obj(obj)) => Bool(obj.has_field_ex(a.clone(), true)),87 (Str(a), In, Obj(obj)) => Bool(obj.has_field_ex(a.clone(), true)),86 (a, Mod, b) => evaluate_mod_op(a, b)?,88 (a, Mod, b) => evaluate_mod_op(s, a, b)?,878988 (Str(v1), Mul, Num(v2)) => Str(v1.repeat(*v2 as usize).into()),90 (Str(v1), Mul, Num(v2)) => Str(v1.repeat(*v2 as usize).into()),8991crates/jrsonnet-evaluator/src/function.rsdiffbeforeafterboth1use std::{borrow::Cow, collections::HashMap, convert::TryFrom};1use std::{borrow::Cow, collections::HashMap};223use gcmodule::Trace;3use gcmodule::Trace;4use jrsonnet_interner::IStr;4use jrsonnet_interner::IStr;5pub use jrsonnet_macros::builtin;5pub use jrsonnet_macros::builtin;6use jrsonnet_parser::{ArgsDesc, ExprLocation, LocExpr, ParamsDesc};6use jrsonnet_parser::{ArgsDesc, ExprLocation, LocExpr, ParamsDesc};778use crate::{8use crate::{9 error::{Error::*, LocError},9 error::Error::*, evaluate, evaluate_named, gc::TraceBox, throw, typed::Typed,10 evaluate, evaluate_named,11 gc::TraceBox,12 throw,13 typed::Typed,14 val::LazyValValue,10 val::LazyValValue, Context, FutureWrapper, GcHashMap, LazyVal, Result, State, Val,15 Context, FutureWrapper, GcHashMap, LazyVal, Result, Val,16};11};1712302531#[derive(Trace)]26#[derive(Trace)]32struct EvaluateLazyVal {27struct EvaluateLazyVal {33 context: Context,28 ctx: Context,34 expr: LocExpr,29 expr: LocExpr,35}30}36impl LazyValValue for EvaluateLazyVal {31impl LazyValValue for EvaluateLazyVal {37 fn get(self: Box<Self>) -> Result<Val> {32 fn get(self: Box<Self>, s: State) -> Result<Val> {38 evaluate(self.context, &self.expr)33 evaluate(s, self.ctx, &self.expr)39 }34 }40}35}413642#[derive(Trace)]37#[derive(Trace)]43struct EvaluateNamedLazyVal {38struct EvaluateNamedLazyVal {44 future_context: FutureWrapper<Context>,39 ctx: FutureWrapper<Context>,45 name: IStr,40 name: IStr,46 value: LocExpr,41 value: LocExpr,47}42}48impl LazyValValue for EvaluateNamedLazyVal {43impl LazyValValue for EvaluateNamedLazyVal {49 fn get(self: Box<Self>) -> Result<Val> {44 fn get(self: Box<Self>, s: State) -> Result<Val> {50 evaluate_named(self.future_context.unwrap(), &self.value, self.name)45 evaluate_named(s, self.ctx.unwrap(), &self.value, self.name)51 }46 }52}47}534854pub trait ArgLike {49pub trait ArgLike {55 fn evaluate_arg(&self, ctx: Context, tailstrict: bool) -> Result<LazyVal>;50 fn evaluate_arg(&self, s: State, ctx: Context, tailstrict: bool) -> Result<LazyVal>;56}51}57impl ArgLike for &LocExpr {52impl ArgLike for &LocExpr {58 fn evaluate_arg(&self, ctx: Context, tailstrict: bool) -> Result<LazyVal> {53 fn evaluate_arg(&self, s: State, ctx: Context, tailstrict: bool) -> Result<LazyVal> {59 Ok(if tailstrict {54 Ok(if tailstrict {60 LazyVal::new_resolved(evaluate(ctx, self)?)55 LazyVal::new_resolved(evaluate(s, ctx, self)?)61 } else {56 } else {62 LazyVal::new(TraceBox(Box::new(EvaluateLazyVal {57 LazyVal::new(TraceBox(Box::new(EvaluateLazyVal {63 context: ctx,58 ctx,64 expr: (*self).clone(),59 expr: (*self).clone(),65 })))60 })))66 })61 })69impl<T> ArgLike for T64impl<T> ArgLike for T70where65where71 T: Typed + Clone,66 T: Typed + Clone,72 Val: TryFrom<T, Error = LocError>,73{67{74 fn evaluate_arg(&self, _ctx: Context, _tailstrict: bool) -> Result<LazyVal> {68 fn evaluate_arg(&self, s: State, _ctx: Context, _tailstrict: bool) -> Result<LazyVal> {75 let val: Val = Val::try_from(self.clone())?;69 let val = T::into_untyped(self.clone(), s)?;76 Ok(LazyVal::new_resolved(val))70 Ok(LazyVal::new_resolved(val))77 }71 }78}72}82 Val(Val),76 Val(Val),83}77}84impl ArgLike for TlaArg {78impl ArgLike for TlaArg {85 fn evaluate_arg(&self, ctx: Context, tailstrict: bool) -> Result<LazyVal> {79 fn evaluate_arg(&self, s: State, ctx: Context, tailstrict: bool) -> Result<LazyVal> {86 match self {80 match self {87 TlaArg::String(s) => Ok(LazyVal::new_resolved(Val::Str(s.clone()))),81 TlaArg::String(s) => Ok(LazyVal::new_resolved(Val::Str(s.clone()))),88 TlaArg::Code(code) => Ok(if tailstrict {82 TlaArg::Code(code) => Ok(if tailstrict {89 LazyVal::new_resolved(evaluate(ctx, code)?)83 LazyVal::new_resolved(evaluate(s, ctx, code)?)90 } else {84 } else {91 LazyVal::new(TraceBox(Box::new(EvaluateLazyVal {85 LazyVal::new(TraceBox(Box::new(EvaluateLazyVal {92 context: ctx,86 ctx,93 expr: code.clone(),87 expr: code.clone(),94 })))88 })))95 }),89 }),102 fn unnamed_len(&self) -> usize;96 fn unnamed_len(&self) -> usize;103 fn unnamed_iter(97 fn unnamed_iter(104 &self,98 &self,99 s: State,105 ctx: Context,100 ctx: Context,106 tailstrict: bool,101 tailstrict: bool,107 handler: &mut dyn FnMut(usize, LazyVal) -> Result<()>,102 handler: &mut dyn FnMut(usize, LazyVal) -> Result<()>,108 ) -> Result<()>;103 ) -> Result<()>;109 fn named_iter(104 fn named_iter(110 &self,105 &self,106 s: State,111 ctx: Context,107 ctx: Context,112 tailstrict: bool,108 tailstrict: bool,113 handler: &mut dyn FnMut(&IStr, LazyVal) -> Result<()>,109 handler: &mut dyn FnMut(&IStr, LazyVal) -> Result<()>,122118123 fn unnamed_iter(119 fn unnamed_iter(124 &self,120 &self,121 s: State,125 ctx: Context,122 ctx: Context,126 tailstrict: bool,123 tailstrict: bool,127 handler: &mut dyn FnMut(usize, LazyVal) -> Result<()>,124 handler: &mut dyn FnMut(usize, LazyVal) -> Result<()>,130 handler(127 handler(131 id,128 id,132 if tailstrict {129 if tailstrict {133 LazyVal::new_resolved(evaluate(ctx.clone(), arg)?)130 LazyVal::new_resolved(evaluate(s.clone(), ctx.clone(), arg)?)134 } else {131 } else {135 LazyVal::new(TraceBox(Box::new(EvaluateLazyVal {132 LazyVal::new(TraceBox(Box::new(EvaluateLazyVal {136 context: ctx.clone(),133 ctx: ctx.clone(),137 expr: arg.clone(),134 expr: arg.clone(),138 })))135 })))139 },136 },144141145 fn named_iter(142 fn named_iter(146 &self,143 &self,144 s: State,147 ctx: Context,145 ctx: Context,148 tailstrict: bool,146 tailstrict: bool,149 handler: &mut dyn FnMut(&IStr, LazyVal) -> Result<()>,147 handler: &mut dyn FnMut(&IStr, LazyVal) -> Result<()>,152 handler(150 handler(153 name,151 name,154 if tailstrict {152 if tailstrict {155 LazyVal::new_resolved(evaluate(ctx.clone(), arg)?)153 LazyVal::new_resolved(evaluate(s.clone(), ctx.clone(), arg)?)156 } else {154 } else {157 LazyVal::new(TraceBox(Box::new(EvaluateLazyVal {155 LazyVal::new(TraceBox(Box::new(EvaluateLazyVal {158 context: ctx.clone(),156 ctx: ctx.clone(),159 expr: arg.clone(),157 expr: arg.clone(),160 })))158 })))161 },159 },178176179 fn unnamed_iter(177 fn unnamed_iter(180 &self,178 &self,179 _s: State,181 _ctx: Context,180 _ctx: Context,182 _tailstrict: bool,181 _tailstrict: bool,183 _handler: &mut dyn FnMut(usize, LazyVal) -> Result<()>,182 _handler: &mut dyn FnMut(usize, LazyVal) -> Result<()>,187186188 fn named_iter(187 fn named_iter(189 &self,188 &self,189 s: State,190 ctx: Context,190 ctx: Context,191 tailstrict: bool,191 tailstrict: bool,192 handler: &mut dyn FnMut(&IStr, LazyVal) -> Result<()>,192 handler: &mut dyn FnMut(&IStr, LazyVal) -> Result<()>,193 ) -> Result<()> {193 ) -> Result<()> {194 for (name, val) in self.iter() {194 for (name, val) in self.iter() {195 handler(name, val.evaluate_arg(ctx.clone(), tailstrict)?)?;195 handler(name, val.evaluate_arg(s.clone(), ctx.clone(), tailstrict)?)?;196 }196 }197 Ok(())197 Ok(())198 }198 }211211212 fn unnamed_iter(212 fn unnamed_iter(213 &self,213 &self,214 _s: State,214 _ctx: Context,215 _ctx: Context,215 _tailstrict: bool,216 _tailstrict: bool,216 _handler: &mut dyn FnMut(usize, LazyVal) -> Result<()>,217 _handler: &mut dyn FnMut(usize, LazyVal) -> Result<()>,220221221 fn named_iter(222 fn named_iter(222 &self,223 &self,224 s: State,223 ctx: Context,225 ctx: Context,224 tailstrict: bool,226 tailstrict: bool,225 handler: &mut dyn FnMut(&IStr, LazyVal) -> Result<()>,227 handler: &mut dyn FnMut(&IStr, LazyVal) -> Result<()>,226 ) -> Result<()> {228 ) -> Result<()> {227 for (name, value) in self.iter() {229 for (name, value) in self.iter() {228 handler(name, value.evaluate_arg(ctx.clone(), tailstrict)?)?;230 handler(231 name,232 value.evaluate_arg(s.clone(), ctx.clone(), tailstrict)?,233 )?;229 }234 }230 Ok(())235 Ok(())244249245 fn unnamed_iter(250 fn unnamed_iter(246 &self,251 &self,252 s: State,247 ctx: Context,253 ctx: Context,248 tailstrict: bool,254 tailstrict: bool,249 handler: &mut dyn FnMut(usize, LazyVal) -> Result<()>,255 handler: &mut dyn FnMut(usize, LazyVal) -> Result<()>,250 ) -> Result<()> {256 ) -> Result<()> {251 for (i, arg) in self.iter().enumerate() {257 for (i, arg) in self.iter().enumerate() {252 handler(i, arg.evaluate_arg(ctx.clone(), tailstrict)?)?;258 handler(i, arg.evaluate_arg(s.clone(), ctx.clone(), tailstrict)?)?;253 }259 }254 Ok(())260 Ok(())255 }261 }256262257 fn named_iter(263 fn named_iter(258 &self,264 &self,265 _s: State,259 _ctx: Context,266 _ctx: Context,260 _tailstrict: bool,267 _tailstrict: bool,261 _handler: &mut dyn FnMut(&IStr, LazyVal) -> Result<()>,268 _handler: &mut dyn FnMut(&IStr, LazyVal) -> Result<()>,272279273 fn unnamed_iter(280 fn unnamed_iter(274 &self,281 &self,282 s: State,275 ctx: Context,283 ctx: Context,276 tailstrict: bool,284 tailstrict: bool,277 handler: &mut dyn FnMut(usize, LazyVal) -> Result<()>,285 handler: &mut dyn FnMut(usize, LazyVal) -> Result<()>,278 ) -> Result<()> {286 ) -> Result<()> {279 (*self).unnamed_iter(ctx, tailstrict, handler)287 (*self).unnamed_iter(s, ctx, tailstrict, handler)280 }288 }281289282 fn named_iter(290 fn named_iter(283 &self,291 &self,292 s: State,284 ctx: Context,293 ctx: Context,285 tailstrict: bool,294 tailstrict: bool,286 handler: &mut dyn FnMut(&IStr, LazyVal) -> Result<()>,295 handler: &mut dyn FnMut(&IStr, LazyVal) -> Result<()>,287 ) -> Result<()> {296 ) -> Result<()> {288 (*self).named_iter(ctx, tailstrict, handler)297 (*self).named_iter(s, ctx, tailstrict, handler)289 }298 }290299291 fn named_names(&self, handler: &mut dyn FnMut(&IStr)) {300 fn named_names(&self, handler: &mut dyn FnMut(&IStr)) {302/// * `args`: passed function arguments311/// * `args`: passed function arguments303/// * `tailstrict`: if set to `true` function arguments are eagerly executed, otherwise - lazily312/// * `tailstrict`: if set to `true` function arguments are eagerly executed, otherwise - lazily304pub fn parse_function_call(313pub fn parse_function_call(314 s: State,305 ctx: Context,315 ctx: Context,306 body_ctx: Context,316 body_ctx: Context,307 params: &ParamsDesc,317 params: &ParamsDesc,315325316 let mut filled_args = 0;326 let mut filled_args = 0;317327318 args.unnamed_iter(ctx.clone(), tailstrict, &mut |id, arg| {328 args.unnamed_iter(s.clone(), ctx.clone(), tailstrict, &mut |id, arg| {319 let name = params[id].0.clone();329 let name = params[id].0.clone();320 passed_args.insert(name, arg);330 passed_args.insert(name, arg);321 filled_args += 1;331 filled_args += 1;322 Ok(())332 Ok(())323 })?;333 })?;324334325 args.named_iter(ctx, tailstrict, &mut |name, value| {335 args.named_iter(s, ctx, tailstrict, &mut |name, value| {326 // FIXME: O(n) for arg existence check336 // FIXME: O(n) for arg existence check327 if !params.iter().any(|p| &p.0 == name) {337 if !params.iter().any(|p| &p.0 == name) {328 throw!(UnknownFunctionParameter((name as &str).to_owned()));338 throw!(UnknownFunctionParameter((name as &str).to_owned()));337 if filled_args < params.len() {347 if filled_args < params.len() {338 // Some args are unset, but maybe we have defaults for them348 // Some args are unset, but maybe we have defaults for them339 // Default values should be created in newly created context349 // Default values should be created in newly created context340 let future_context = Context::new_future();350 let fctx = Context::new_future();341 let mut defaults = GcHashMap::with_capacity(params.len() - filled_args);351 let mut defaults = GcHashMap::with_capacity(params.len() - filled_args);342352343 for param in params.iter().filter(|p| p.1.is_some()) {353 for param in params.iter().filter(|p| p.1.is_some()) {344 if passed_args.contains_key(¶m.0.clone()) {354 if passed_args.contains_key(¶m.0.clone()) {345 continue;355 continue;346 }356 }347 LazyVal::new(TraceBox(Box::new(EvaluateNamedLazyVal {357 LazyVal::new(TraceBox(Box::new(EvaluateNamedLazyVal {348 future_context: future_context.clone(),358 ctx: fctx.clone(),349 name: param.0.clone(),359 name: param.0.clone(),350 value: param.1.clone().unwrap(),360 value: param.1.clone().unwrap(),351 })));361 })));352362353 defaults.insert(363 defaults.insert(354 param.0.clone(),364 param.0.clone(),355 LazyVal::new(TraceBox(Box::new(EvaluateNamedLazyVal {365 LazyVal::new(TraceBox(Box::new(EvaluateNamedLazyVal {356 future_context: future_context.clone(),366 ctx: fctx.clone(),357 name: param.0.clone(),367 name: param.0.clone(),358 value: param.1.clone().unwrap(),368 value: param.1.clone().unwrap(),359 }))),369 }))),380 Ok(body_ctx390 Ok(body_ctx381 .extend(passed_args, None, None, None)391 .extend(passed_args, None, None, None)382 .extend_bound(defaults)392 .extend_bound(defaults)383 .into_future(future_context))393 .into_future(fctx))384 } else {394 } else {385 let body_ctx = body_ctx.extend(passed_args, None, None, None);395 let body_ctx = body_ctx.extend(passed_args, None, None, None);386 Ok(body_ctx)396 Ok(body_ctx)399pub trait Builtin: Trace {409pub trait Builtin: Trace {400 fn name(&self) -> &str;410 fn name(&self) -> &str;401 fn params(&self) -> &[BuiltinParam];411 fn params(&self) -> &[BuiltinParam];402 fn call(&self, context: Context, loc: CallLocation, args: &dyn ArgsLike) -> Result<Val>;412 fn call(&self, s: State, ctx: Context, loc: CallLocation, args: &dyn ArgsLike) -> Result<Val>;403}413}404414405pub trait StaticBuiltin: Builtin + Send + Sync415pub trait StaticBuiltin: Builtin + Send + Sync418/// * `args`: passed function arguments428/// * `args`: passed function arguments419/// * `tailstrict`: if set to `true` function arguments are eagerly executed, otherwise - lazily429/// * `tailstrict`: if set to `true` function arguments are eagerly executed, otherwise - lazily420pub fn parse_builtin_call(430pub fn parse_builtin_call(431 s: State,421 ctx: Context,432 ctx: Context,422 params: &[BuiltinParam],433 params: &[BuiltinParam],423 args: &dyn ArgsLike,434 args: &dyn ArgsLike,430441431 let mut filled_args = 0;442 let mut filled_args = 0;432443433 args.unnamed_iter(ctx.clone(), tailstrict, &mut |id, arg| {444 args.unnamed_iter(s.clone(), ctx.clone(), tailstrict, &mut |id, arg| {434 let name = params[id].name.clone();445 let name = params[id].name.clone();435 passed_args.insert(name, arg);446 passed_args.insert(name, arg);436 filled_args += 1;447 filled_args += 1;437 Ok(())448 Ok(())438 })?;449 })?;439450440 args.named_iter(ctx, tailstrict, &mut |name, arg| {451 args.named_iter(s, ctx, tailstrict, &mut |name, arg| {441 // FIXME: O(n) for arg existence check452 // FIXME: O(n) for arg existence check442 let p = params453 let p = params443 .iter()454 .iter()480/// Creates Context, which has all argument default values applied491/// Creates Context, which has all argument default values applied481/// and with unbound values causing error to be returned492/// and with unbound values causing error to be returned482pub fn parse_default_function_call(body_ctx: Context, params: &ParamsDesc) -> Context {493pub fn parse_default_function_call(body_ctx: Context, params: &ParamsDesc) -> Context {483 let ctx = Context::new_future();494 let fctx = Context::new_future();484495485 let mut bindings = GcHashMap::new();496 let mut bindings = GcHashMap::new();486497487 #[derive(Trace)]498 #[derive(Trace)]488 struct DependsOnUnbound(IStr);499 struct DependsOnUnbound(IStr);489 impl LazyValValue for DependsOnUnbound {500 impl LazyValValue for DependsOnUnbound {490 fn get(self: Box<Self>) -> Result<Val> {501 fn get(self: Box<Self>, _: State) -> Result<Val> {491 Err(FunctionParameterNotBoundInCall(self.0.clone()).into())502 Err(FunctionParameterNotBoundInCall(self.0.clone()).into())492 }503 }493 }504 }497 bindings.insert(508 bindings.insert(498 param.0.clone(),509 param.0.clone(),499 LazyVal::new(TraceBox(Box::new(EvaluateNamedLazyVal {510 LazyVal::new(TraceBox(Box::new(EvaluateNamedLazyVal {500 future_context: ctx.clone(),511 ctx: fctx.clone(),501 name: param.0.clone(),512 name: param.0.clone(),502 value: v.clone(),513 value: v.clone(),503 }))),514 }))),510 }521 }511 }522 }512523513 body_ctx.extend(bindings, None, None, None).into_future(ctx)524 body_ctx525 .extend(bindings, None, None, None)526 .into_future(fctx)514}527}515528crates/jrsonnet-evaluator/src/integrations/serde.rsdiffbeforeafterboth1use std::convert::{TryFrom, TryInto};1use jrsonnet_types::ComplexValType;23use serde_json::{Map, Number, Value};2use serde_json::{Map, Number, Value};435use crate::{4use crate::{6 error::{Error::*, LocError, Result},5 error::{Error::*, Result},7 throw, ObjValueBuilder, Val,6 throw,7 typed::Typed,8 ObjValueBuilder, State, Val,8};9};91010impl TryFrom<&Val> for Value {11impl Typed for Value {12 const TYPE: &'static ComplexValType = &ComplexValType::Any;1314 fn into_untyped(value: Self, s: State) -> Result<Val> {15 Ok(match value {16 Value::Null => Val::Null,17 Value::Bool(v) => Val::Bool(v),18 Value::Number(n) => Val::Num(n.as_f64().ok_or_else(|| {19 RuntimeError(format!("json number can't be represented as jsonnet: {}", n).into())20 })?),21 Value::String(s) => Val::Str((&s as &str).into()),22 Value::Array(a) => {23 let mut out: Vec<Val> = Vec::with_capacity(a.len());24 for v in a {25 out.push(Self::into_untyped(v, s.clone())?);26 }27 Val::Arr(out.into())28 }29 Value::Object(o) => {11 type Error = LocError;30 let mut builder = ObjValueBuilder::with_capacity(o.len());31 for (k, v) in o {32 builder33 .member((&k as &str).into())34 .value(s.clone(), Self::into_untyped(v, s.clone())?)?;35 }36 Val::Obj(builder.build())37 }38 })39 }4012 fn try_from(v: &Val) -> Result<Self> {41 fn from_untyped(value: Val, s: State) -> Result<Self> {13 Ok(match v {42 Ok(match value {14 Val::Bool(b) => Self::Bool(*b),43 Val::Bool(b) => Self::Bool(b),15 Val::Null => Self::Null,44 Val::Null => Self::Null,16 Val::Str(s) => Self::String((s as &str).into()),45 Val::Str(s) => Self::String((&s as &str).into()),17 Val::Num(n) => Self::Number(if n.fract() <= f64::EPSILON {46 Val::Num(n) => Self::Number(if n.fract() <= f64::EPSILON {18 (*n as i64).into()47 (n as i64).into()19 } else {48 } else {20 Number::from_f64(*n).expect("jsonnet numbers can't be infinite or NaN")49 Number::from_f64(n).expect("jsonnet numbers can't be infinite or NaN")21 }),50 }),22 Val::Arr(a) => {51 Val::Arr(a) => {23 let mut out = Vec::with_capacity(a.len());52 let mut out = Vec::with_capacity(a.len());24 for item in a.iter() {53 for item in a.iter(s.clone()) {25 out.push(item?.try_into()?);54 out.push(Self::from_untyped(item?, s.clone())?);26 }55 }27 Self::Array(out)56 Self::Array(out)28 }57 }34 ) {63 ) {35 out.insert(64 out.insert(36 (&key as &str).into(),65 (&key as &str).into(),66 Self::from_untyped(37 o.get(key)?67 o.get(s.clone(), key)?38 .expect("key is present in fields, so value should exist")68 .expect("key is present in fields, so value should exist"),39 .try_into()?,69 s.clone(),70 )?,40 );71 );41 }72 }42 Self::Object(out)73 Self::Object(out)43 }74 }44 Val::Func(_) => throw!(RuntimeError("tried to manifest function".into())),75 Val::Func(_) => throw!(RuntimeError("tried to manifest function".into())),45 })76 })46 }77 }47}78}48impl TryFrom<Val> for Value {49 type Error = LocError;5051 fn try_from(value: Val) -> Result<Self, Self::Error> {52 <Self as TryFrom<&Val>>::try_from(&value)53 }54}5556impl TryFrom<&Value> for Val {57 type Error = LocError;58 fn try_from(v: &Value) -> Result<Self> {59 Ok(match v {60 Value::Null => Self::Null,61 Value::Bool(v) => Self::Bool(*v),62 Value::Number(n) => Self::Num(n.as_f64().ok_or_else(|| {63 RuntimeError(format!("json number can't be represented as jsonnet: {}", n).into())64 })?),65 Value::String(s) => Self::Str((s as &str).into()),66 Value::Array(a) => {67 let mut out: Vec<Self> = Vec::with_capacity(a.len());68 for v in a {69 out.push(v.try_into()?);70 }71 Self::Arr(out.into())72 }73 Value::Object(o) => {74 let mut builder = ObjValueBuilder::with_capacity(o.len());75 for (k, v) in o {76 builder.member((k as &str).into()).value(v.try_into()?)?;77 }78 Self::Obj(builder.build())79 }80 })81 }82}83impl TryFrom<Value> for Val {84 type Error = LocError;8586 fn try_from(value: Value) -> Result<Self, Self::Error> {87 <Self as TryFrom<&Value>>::try_from(&value)88 }89}9079crates/jrsonnet-evaluator/src/lib.rsdiffbeforeafterboth49pub trait Bindable: Trace + 'static {49pub trait Bindable: Trace + 'static {50 fn bind(&self, this: Option<ObjValue>, super_obj: Option<ObjValue>) -> Result<LazyVal>;50 fn bind(51 &self,52 s: State,53 this: Option<ObjValue>,54 super_obj: Option<ObjValue>,55 ) -> Result<LazyVal>;51}56}525764impl LazyBinding {69impl LazyBinding {65 pub fn evaluate(&self, this: Option<ObjValue>, super_obj: Option<ObjValue>) -> Result<LazyVal> {70 pub fn evaluate(71 &self,72 s: State,73 this: Option<ObjValue>,74 super_obj: Option<ObjValue>,75 ) -> Result<LazyVal> {66 match self {76 match self {67 Self::Bindable(v) => v.bind(this, super_obj),77 Self::Bindable(v) => v.bind(s, this, super_obj),68 Self::Bound(v) => Ok(v.clone()),78 Self::Bound(v) => Ok(v.clone()),69 }79 }70 }80 }173 settings: RefCell<EvaluationSettings>,183 settings: RefCell<EvaluationSettings>,174}184}175176thread_local! {177 /// Contains the state for a currently executed file.178 /// Global state is fine here.179 pub(crate) static EVAL_STATE: RefCell<Option<EvaluationState>> = RefCell::new(None)180}181182pub(crate) fn with_state<T>(f: impl FnOnce(&EvaluationState) -> T) -> T {183 EVAL_STATE.with(|s| {184 f(s.borrow().as_ref().expect(185 "missing evaluation state, some functions should be called inside of run_in_state call",186 ))187 })188}189pub fn push_frame<T>(190 e: CallLocation,191 frame_desc: impl FnOnce() -> String,192 f: impl FnOnce() -> Result<T>,193) -> Result<T> {194 with_state(|s| s.push(e, frame_desc, f))195}196197#[allow(dead_code)]198pub fn push_val_frame(199 e: &ExprLocation,200 frame_desc: impl FnOnce() -> String,201 f: impl FnOnce() -> Result<Val>,202) -> Result<Val> {203 with_state(|s| s.push_val(e, frame_desc, f))204}205#[allow(dead_code)]206pub fn push_description_frame<T>(207 frame_desc: impl FnOnce() -> String,208 f: impl FnOnce() -> Result<T>,209) -> Result<T> {210 with_state(|s| s.push_description(frame_desc, f))211}212185213/// Maintains stack trace and import resolution186/// Maintains stack trace and import resolution214#[derive(Default, Clone)]187#[derive(Default, Clone)]215pub struct EvaluationState(Rc<EvaluationStateInternals>);188pub struct State(Rc<EvaluationStateInternals>);216189217impl EvaluationState {190impl State {218 /// Parses and adds file as loaded191 /// Parses and adds file as loaded219 pub fn add_file(&self, path: Rc<Path>, source_code: IStr) -> Result<LocExpr> {192 pub fn add_file(&self, path: Rc<Path>, source_code: IStr) -> Result<LocExpr> {220 let parsed = parse(193 let parsed = parse(317 }290 }318 value.parsed.clone()291 value.parsed.clone()319 };292 };320 let value = evaluate(self.create_default_context(), &expr)?;293 let value = evaluate(self.clone(), self.create_default_context(), &expr)?;321 {294 {322 self.data_mut()295 self.data_mut()323 .files296 .files333 pub fn with_stdlib(&self) -> &Self {306 pub fn with_stdlib(&self) -> &Self {334 use jrsonnet_stdlib::STDLIB_STR;307 use jrsonnet_stdlib::STDLIB_STR;335 let std_path: Rc<Path> = PathBuf::from("std.jsonnet").into();308 let std_path: Rc<Path> = PathBuf::from("std.jsonnet").into();336 self.run_in_state(|| {309337 self.add_parsed_file(310 self.add_parsed_file(338 std_path.clone(),311 std_path.clone(),339 STDLIB_STR.to_owned().into(),312 STDLIB_STR.to_owned().into(),342 .unwrap();315 .unwrap();343 let val = self.evaluate_loaded_file_raw(&std_path).unwrap();316 let val = self.evaluate_loaded_file_raw(&std_path).unwrap();344 self.settings_mut().globals.insert("std".into(), val);317 self.settings_mut().globals.insert("std".into(), val);345 });346 self318 self347 }319 }348320459 result431 result460 }432 }461462 /// Runs passed function in state (required if function needs to modify stack trace)463 pub fn run_in_state<T>(&self, f: impl FnOnce() -> T) -> T {464 EVAL_STATE.with(|v| {465 let has_state = v.borrow().is_some();466 if !has_state {467 v.borrow_mut().replace(self.clone());468 }469 let result = f();470 if !has_state {471 v.borrow_mut().take();472 }473 result474 })475 }476 pub fn run_in_state_with_breakpoint(477 &self,478 bp: Rc<Breakpoint>,479 f: impl FnOnce() -> Result<()>,480 ) -> Result<()> {481 {482 let mut data = self.data_mut();483 data.breakpoints.0.push(bp);484 }485486 let result = self.run_in_state(f);487488 {489 let mut data = self.data_mut();490 data.breakpoints.0.pop();491 }492493 result494 }495433496 pub fn stringify_err(&self, e: &LocError) -> String {434 pub fn stringify_err(&self, e: &LocError) -> String {497 let mut out = String::new();435 let mut out = String::new();503 }441 }504442505 pub fn manifest(&self, val: Val) -> Result<IStr> {443 pub fn manifest(&self, val: Val) -> Result<IStr> {506 self.run_in_state(|| {444 self.push_description(507 push_description_frame(508 || "manifestification".to_string(),445 || "manifestification".to_string(),509 || val.manifest(&self.manifest_format()),446 || val.manifest(self.clone(), &self.manifest_format()),510 )511 })447 )512 }448 }513 pub fn manifest_multi(&self, val: Val) -> Result<Vec<(IStr, IStr)>> {449 pub fn manifest_multi(&self, val: Val) -> Result<Vec<(IStr, IStr)>> {514 self.run_in_state(|| val.manifest_multi(&self.manifest_format()))450 val.manifest_multi(self.clone(), &self.manifest_format())515 }451 }516 pub fn manifest_stream(&self, val: Val) -> Result<Vec<IStr>> {452 pub fn manifest_stream(&self, val: Val) -> Result<Vec<IStr>> {517 self.run_in_state(|| val.manifest_stream(&self.manifest_format()))453 val.manifest_stream(self.clone(), &self.manifest_format())518 }454 }519455520 /// If passed value is function then call with set TLA456 /// If passed value is function then call with set TLA521 pub fn with_tla(&self, val: Val) -> Result<Val> {457 pub fn with_tla(&self, val: Val) -> Result<Val> {522 self.run_in_state(|| {523 Ok(match val {458 Ok(match val {524 Val::Func(func) => push_description_frame(459 Val::Func(func) => self.push_description(525 || "during TLA call".to_owned(),460 || "during TLA call".to_owned(),526 || {461 || {527 func.evaluate(462 func.evaluate(463 self.clone(),528 self.create_default_context(),464 self.create_default_context(),529 CallLocation::native(),465 CallLocation::native(),530 &self.settings().tla_vars,466 &self.settings().tla_vars,534 )?,470 )?,535 v => v,471 v => v,536 })472 })537 })538 }473 }539}474}540475541/// Internals476/// Internals542impl EvaluationState {477impl State {543 fn data(&self) -> Ref<EvaluationData> {478 fn data(&self) -> Ref<EvaluationData> {544 self.0.data.borrow()479 self.0.data.borrow()545 }480 }555}490}556491557/// Raw methods evaluate passed values but don't perform TLA execution492/// Raw methods evaluate passed values but don't perform TLA execution558impl EvaluationState {493impl State {559 pub fn evaluate_file_raw(&self, name: &Path) -> Result<Val> {494 pub fn evaluate_file_raw(&self, name: &Path) -> Result<Val> {560 self.run_in_state(|| self.import_file(&std::env::current_dir().expect("cwd"), name))495 self.import_file(&std::env::current_dir().expect("cwd"), name)561 }496 }562 pub fn evaluate_file_raw_nocwd(&self, name: &Path) -> Result<Val> {497 pub fn evaluate_file_raw_nocwd(&self, name: &Path) -> Result<Val> {563 self.run_in_state(|| self.import_file(&PathBuf::from("."), name))498 self.import_file(&PathBuf::from("."), name)564 }499 }565 /// Parses and evaluates the given snippet500 /// Parses and evaluates the given snippet566 pub fn evaluate_snippet_raw(&self, source: Rc<Path>, code: IStr) -> Result<Val> {501 pub fn evaluate_snippet_raw(&self, source: Rc<Path>, code: IStr) -> Result<Val> {580 }515 }581 /// Evaluates the parsed expression516 /// Evaluates the parsed expression582 pub fn evaluate_expr_raw(&self, code: LocExpr) -> Result<Val> {517 pub fn evaluate_expr_raw(&self, code: LocExpr) -> Result<Val> {583 self.run_in_state(|| evaluate(self.create_default_context(), &code))518 evaluate(self.clone(), self.create_default_context(), &code)584 }519 }585}520}586521587/// Settings utilities522/// Settings utilities588impl EvaluationState {523impl State {589 pub fn add_ext_var(&self, name: IStr, value: Val) {524 pub fn add_ext_var(&self, name: IStr, value: Val) {590 self.settings_mut().ext_vars.insert(name, value);525 self.settings_mut().ext_vars.insert(name, value);591 }526 }712 gc::TraceBox,647 gc::TraceBox,713 native::NativeCallbackHandler,648 native::NativeCallbackHandler,714 val::primitive_equals,649 val::primitive_equals,715 EvaluationState,650 State,716 };651 };717652718 #[test]653 #[test]719 #[should_panic]654 #[should_panic]720 fn eval_state_stacktrace() {655 fn eval_state_stacktrace() {721 let state = EvaluationState::default();656 let state = State::default();722 state.run_in_state(|| {723 state657 state724 .push(658 .push(725 CallLocation::new(&ExprLocation(PathBuf::from("test1.jsonnet").into(), 10, 20)),659 CallLocation::new(&ExprLocation(PathBuf::from("test1.jsonnet").into(), 10, 20)),738 },672 },739 )673 )740 .unwrap();674 .unwrap();741 });742 }675 }743676744 #[test]677 #[test]745 fn eval_state_standard() {678 fn eval_state_standard() {746 let state = EvaluationState::default();679 let state = State::default();747 state.with_stdlib();680 state.with_stdlib();748 assert!(primitive_equals(681 assert!(primitive_equals(749 &state682 &state759692760 macro_rules! eval {693 macro_rules! eval {761 ($str: expr) => {{694 ($str: expr) => {{762 let evaluator = EvaluationState::default();695 let evaluator = State::default();763 evaluator.with_stdlib();696 evaluator.with_stdlib();764 evaluator.run_in_state(|| {697 evaluator765 evaluator766 .evaluate_snippet_raw(PathBuf::from("raw.jsonnet").into(), $str.into())698 .evaluate_snippet_raw(PathBuf::from("raw.jsonnet").into(), $str.into())767 .unwrap()699 .unwrap()768 })769 }};700 }};770 }701 }771 macro_rules! eval_json {702 macro_rules! eval_json {772 ($str: expr) => {{703 ($str: expr) => {{773 let evaluator = EvaluationState::default();704 let evaluator = State::default();774 evaluator.with_stdlib();705 evaluator.with_stdlib();775 evaluator.run_in_state(|| {706 evaluator776 evaluator777 .evaluate_snippet_raw(PathBuf::from("raw.jsonnet").into(), $str.into())707 .evaluate_snippet_raw(PathBuf::from("raw.jsonnet").into(), $str.into())778 .unwrap()708 .unwrap()779 .to_json(0)709 .to_json(0)780 .unwrap()710 .unwrap()781 .replace("\n", "")711 .replace("\n", "")782 })783 }};712 }};784 }713 }7857141143 #[test]1072 #[test]1144 fn native_ext() -> crate::error::Result<()> {1073 fn native_ext() -> crate::error::Result<()> {1145 use super::native::NativeCallback;1074 use super::native::NativeCallback;1146 let evaluator = EvaluationState::default();1075 let evaluator = State::default();114710761148 evaluator.with_stdlib();1077 evaluator.with_stdlib();114910781178 TraceBox(Box::new(NativeAdd)),1107 TraceBox(Box::new(NativeAdd)),1179 )))),1108 )))),1180 );1109 );1110 dbg!(evaluator.settings().ext_natives.keys().collect::<Vec<_>>());1181 evaluator.evaluate_snippet_raw(1111 evaluator.evaluate_snippet_raw(1182 PathBuf::from("native_caller.jsonnet").into(),1112 PathBuf::from("native_caller.jsonnet").into(),1183 "std.assertEqual(std.native(\"native_add\")(1, 2), 3)".into(),1113 "std.assertEqual(std.native(\"native_add\")(1, 2), 3)".into(),1184 )?;1114 )?;1115 dbg!(evaluator.settings().ext_natives.keys().collect::<Vec<_>>());1185 Ok(())1116 Ok(())1186 }1117 }11871118125011811251 #[test]1182 #[test]1252 fn issue_23() {1183 fn issue_23() {1253 let state = EvaluationState::default();1184 let state = State::default();1254 state.set_import_resolver(Box::new(TestImportResolver(r#"import "/test""#.into())));1185 state.set_import_resolver(Box::new(TestImportResolver(r#"import "/test""#.into())));1255 let _ = state.evaluate_file_raw(&PathBuf::from("/test"));1186 let _ = state.evaluate_file_raw(&PathBuf::from("/test"));1256 }1187 }125711881258 #[test]1189 #[test]1259 fn issue_40() {1190 fn issue_40() {1260 let state = EvaluationState::default();1191 let state = State::default();1261 state.with_stdlib();1192 state.with_stdlib();126211931263 let error = state1194 let error = state1306 mod derive_typed {1237 mod derive_typed {1307 use std::path::PathBuf;1238 use std::path::PathBuf;130812391309 use crate::{typed::Typed, EvaluationState};1240 use crate::{typed::Typed, State};131012411311 #[derive(PartialEq, Debug, Typed)]1242 #[derive(PartialEq, Debug, Typed)]1312 struct MyTyped {1243 struct MyTyped {131712481318 #[test]1249 #[test]1319 fn test() {1250 fn test() {1320 let es = EvaluationState::default();1251 let es = State::default();1321 let val = eval!("{a: 14, b: 'Hello, world!'}");1252 let val = eval!("{a: 14, b: 'Hello, world!'}");1322 let typed = es.run_in_state(|| MyTyped::try_from(val).unwrap());1253 let typed = MyTyped::try_from(val).unwrap();132312541324 assert_eq!(1255 assert_eq!(1325 typed,1256 typed,1331 es.settings_mut().globals.insert(1262 es.settings_mut()1263 .globals1332 "mytyped".into(),1264 .insert("mytyped".into(), typed.try_into().unwrap());1333 es.run_in_state(|| typed.try_into()).unwrap(),1334 );133512651336 let v = es1266 let v = escrates/jrsonnet-evaluator/src/native.rsdiffbeforeafterboth8 error::Result,8 error::Result,9 function::{parse_builtin_call, ArgsLike, Builtin, BuiltinParam, CallLocation},9 function::{parse_builtin_call, ArgsLike, Builtin, BuiltinParam, CallLocation},10 gc::TraceBox,10 gc::TraceBox,11 Context, Val,11 Context, State, Val,12};12};131314#[derive(Trace)]14#[derive(Trace)]34 &self.params34 &self.params35 }35 }363637 fn call(&self, context: Context, loc: CallLocation, args: &dyn ArgsLike) -> Result<Val> {37 fn call(&self, s: State, ctx: Context, loc: CallLocation, args: &dyn ArgsLike) -> Result<Val> {38 let args = parse_builtin_call(context, &self.params, args, true)?;38 let args = parse_builtin_call(s.clone(), ctx, &self.params, args, true)?;39 let mut out_args = Vec::with_capacity(self.params.len());39 let mut out_args = Vec::with_capacity(self.params.len());40 for p in self.params.iter() {40 for p in self.params.iter() {41 out_args.push(args[&p.name].evaluate()?);41 out_args.push(args[&p.name].evaluate(s.clone())?);42 }42 }43 self.handler.call(loc.0.map(|l| l.0.clone()), &out_args)43 self.handler.call(s, loc.0.map(|l| l.0.clone()), &out_args)44 }44 }45}45}464647pub trait NativeCallbackHandler: Trace {47pub trait NativeCallbackHandler: Trace {48 fn call(&self, from: Option<Rc<Path>>, args: &[Val]) -> Result<Val>;48 fn call(&self, s: State, from: Option<Rc<Path>>, args: &[Val]) -> Result<Val>;49}49}5050crates/jrsonnet-evaluator/src/obj.rsdiffbeforeafterboth15 function::CallLocation,15 function::CallLocation,16 gc::{GcHashMap, GcHashSet, TraceBox},16 gc::{GcHashMap, GcHashSet, TraceBox},17 operator::evaluate_add_op,17 operator::evaluate_add_op,18 push_frame, throw, weak_ptr_eq, weak_raw, Bindable, LazyBinding, LazyVal, Result, Val,18 throw, weak_ptr_eq, weak_raw, Bindable, LazyBinding, LazyVal, Result, State, Val,19};19};202021#[cfg(not(feature = "exp-preserve-order"))]21#[cfg(not(feature = "exp-preserve-order"))]99}99}100100101pub trait ObjectAssertion: Trace {101pub trait ObjectAssertion: Trace {102 fn run(&self, this: Option<ObjValue>, super_obj: Option<ObjValue>) -> Result<()>;102 fn run(&self, s: State, this: Option<ObjValue>, super_obj: Option<ObjValue>) -> Result<()>;103}103}104104105// Field => This105// Field => This360 .unwrap_or(false)360 .unwrap_or(false)361 }361 }362362363 pub fn get(&self, key: IStr) -> Result<Option<Val>> {363 pub fn get(&self, s: State, key: IStr) -> Result<Option<Val>> {364 self.run_assertions()?;364 self.run_assertions(s.clone())?;365 self.get_raw(key, self.0.this_obj.as_ref())365 self.get_raw(s, key, self.0.this_obj.as_ref())366 }366 }367367368 // pub fn extend_with(self, key: )368 // pub fn extend_with(self, key: )369369370 fn get_raw(&self, key: IStr, real_this: Option<&Self>) -> Result<Option<Val>> {370 fn get_raw(&self, s: State, key: IStr, real_this: Option<&Self>) -> Result<Option<Val>> {371 let real_this = real_this.unwrap_or(self);371 let real_this = real_this.unwrap_or(self);372 let cache_key = (key.clone(), WeakObjValue(real_this.0.downgrade()));372 let cache_key = (key.clone(), WeakObjValue(real_this.0.downgrade()));373373384 .borrow_mut()384 .borrow_mut()385 .insert(cache_key.clone(), CacheValue::Pending);385 .insert(cache_key.clone(), CacheValue::Pending);386 let value = match (self.0.this_entries.get(&key), &self.0.super_obj) {386 let value = match (self.0.this_entries.get(&key), &self.0.super_obj) {387 (Some(k), None) => Ok(Some(self.evaluate_this(k, real_this)?)),387 (Some(k), None) => Ok(Some(self.evaluate_this(s, k, real_this)?)),388 (Some(k), Some(s)) => {388 (Some(k), Some(super_obj)) => {389 let our = self.evaluate_this(k, real_this)?;389 let our = self.evaluate_this(s.clone(), k, real_this)?;390 if k.add {390 if k.add {391 super_obj391 s.get_raw(key, Some(real_this))?392 .get_raw(s.clone(), key, Some(real_this))?392 .map_or(Ok(Some(our.clone())), |v| {393 .map_or(Ok(Some(our.clone())), |v| {393 Ok(Some(evaluate_add_op(&v, &our)?))394 Ok(Some(evaluate_add_op(s.clone(), &v, &our)?))394 })395 })395 } else {396 } else {396 Ok(Some(our))397 Ok(Some(our))397 }398 }398 }399 }399 (None, Some(s)) => s.get_raw(key, Some(real_this)),400 (None, Some(super_obj)) => super_obj.get_raw(s, key, Some(real_this)),400 (None, None) => Ok(None),401 (None, None) => Ok(None),401 };402 };402 let value = match value {403 let value = match value {418 );419 );419 Ok(value)420 Ok(value)420 }421 }421 fn evaluate_this(&self, v: &ObjMember, real_this: &Self) -> Result<Val> {422 fn evaluate_this(&self, s: State, v: &ObjMember, real_this: &Self) -> Result<Val> {422 v.invoke423 v.invoke423 .evaluate(Some(real_this.clone()), self.0.super_obj.clone())?424 .evaluate(s.clone(), Some(real_this.clone()), self.0.super_obj.clone())?424 .evaluate()425 .evaluate(s)425 }426 }426427427 fn run_assertions_raw(&self, real_this: &Self) -> Result<()> {428 fn run_assertions_raw(&self, s: State, real_this: &Self) -> Result<()> {428 if self.0.assertions_ran.borrow_mut().insert(real_this.clone()) {429 if self.0.assertions_ran.borrow_mut().insert(real_this.clone()) {429 for assertion in self.0.assertions.iter() {430 for assertion in self.0.assertions.iter() {430 if let Err(e) = assertion.run(Some(real_this.clone()), self.0.super_obj.clone()) {431 if let Err(e) =432 assertion.run(s.clone(), Some(real_this.clone()), self.0.super_obj.clone())433 {431 self.0.assertions_ran.borrow_mut().remove(real_this);434 self.0.assertions_ran.borrow_mut().remove(real_this);432 return Err(e);435 return Err(e);433 }436 }434 }437 }435 if let Some(super_obj) = &self.0.super_obj {438 if let Some(super_obj) = &self.0.super_obj {436 super_obj.run_assertions_raw(real_this)?;439 super_obj.run_assertions_raw(s, real_this)?;437 }440 }438 }441 }439 Ok(())442 Ok(())440 }443 }441 pub fn run_assertions(&self) -> Result<()> {444 pub fn run_assertions(&self, s: State) -> Result<()> {442 self.run_assertions_raw(self)445 self.run_assertions_raw(s, self)443 }446 }444447445 pub fn ptr_eq(a: &Self, b: &Self) -> bool {448 pub fn ptr_eq(a: &Self, b: &Self) -> bool {565568566pub struct ValueBuilder<'v>(&'v mut ObjValueBuilder);569pub struct ValueBuilder<'v>(&'v mut ObjValueBuilder);567impl<'v> ObjMemberBuilder<ValueBuilder<'v>> {570impl<'v> ObjMemberBuilder<ValueBuilder<'v>> {568 pub fn value(self, value: Val) -> Result<()> {571 pub fn value(self, s: State, value: Val) -> Result<()> {569 self.binding(LazyBinding::Bound(LazyVal::new_resolved(value)))572 self.binding(s, LazyBinding::Bound(LazyVal::new_resolved(value)))570 }573 }571 pub fn bindable(self, bindable: TraceBox<dyn Bindable>) -> Result<()> {574 pub fn bindable(self, s: State, bindable: TraceBox<dyn Bindable>) -> Result<()> {572 self.binding(LazyBinding::Bindable(Cc::new(bindable)))575 self.binding(s, LazyBinding::Bindable(Cc::new(bindable)))573 }576 }574 pub fn binding(self, binding: LazyBinding) -> Result<()> {577 pub fn binding(self, s: State, binding: LazyBinding) -> Result<()> {575 let (receiver, name, member) = self.build_member(binding);578 let (receiver, name, member) = self.build_member(binding);576 let location = member.location.clone();579 let location = member.location.clone();577 let old = receiver.0.map.insert(name.clone(), member);580 let old = receiver.0.map.insert(name.clone(), member);578 if old.is_some() {581 if old.is_some() {579 push_frame(582 s.push(580 CallLocation(location.as_ref()),583 CallLocation(location.as_ref()),581 || format!("field <{}> initializtion", name.clone()),584 || format!("field <{}> initializtion", name.clone()),582 || throw!(DuplicateFieldName(name.clone())),585 || throw!(DuplicateFieldName(name.clone())),crates/jrsonnet-evaluator/src/trace/mod.rsdiffbeforeafterboth445pub use location::*;5pub use location::*;667use crate::{error::Error, EvaluationState, LocError};7use crate::{error::Error, LocError, State};889/// The way paths should be displayed9/// The way paths should be displayed10pub enum PathResolver {10pub enum PathResolver {39 fn write_trace(39 fn write_trace(40 &self,40 &self,41 out: &mut dyn std::fmt::Write,41 out: &mut dyn std::fmt::Write,42 evaluation_state: &EvaluationState,42 s: &State,43 error: &LocError,43 error: &LocError,44 ) -> Result<(), std::fmt::Error>;44 ) -> Result<(), std::fmt::Error>;45 // fn print_trace(46 // &self,47 // evaluation_state: &EvaluationState,48 // error: &LocError,49 // ) -> Result<(), std::fmt::Error> {50 // self.write_trace(&mut std::fmt::stdout(), evaluation_state, error)51 // }52}45}534654fn print_code_location(47fn print_code_location(85 fn write_trace(78 fn write_trace(86 &self,79 &self,87 out: &mut dyn std::fmt::Write,80 out: &mut dyn std::fmt::Write,88 evaluation_state: &EvaluationState,81 s: &State,89 error: &LocError,82 error: &LocError,90 ) -> Result<(), std::fmt::Error> {83 ) -> Result<(), std::fmt::Error> {91 write!(out, "{}", error.error())?;84 write!(out, "{}", error.error())?;128 if let Some(location) = location {121 if let Some(location) = location {129 let mut resolved_path = self.resolver.resolve(&location.0);122 let mut resolved_path = self.resolver.resolve(&location.0);130 // TODO: Process all trace elements first123 // TODO: Process all trace elements first131 let location = evaluation_state124 let location = s.map_source_locations(&location.0, &[location.1, location.2]);132 .map_source_locations(&location.0, &[location.1, location.2]);133 write!(resolved_path, ":").unwrap();125 write!(resolved_path, ":").unwrap();134 print_code_location(&mut resolved_path, &location[0], &location[1]).unwrap();126 print_code_location(&mut resolved_path, &location[0], &location[1]).unwrap();170 fn write_trace(162 fn write_trace(171 &self,163 &self,172 out: &mut dyn std::fmt::Write,164 out: &mut dyn std::fmt::Write,173 evaluation_state: &EvaluationState,165 s: &State,174 error: &LocError,166 error: &LocError,175 ) -> Result<(), std::fmt::Error> {167 ) -> Result<(), std::fmt::Error> {176 write!(out, "{}", error.error())?;168 write!(out, "{}", error.error())?;177 for item in error.trace().0.iter() {169 for item in error.trace().0.iter() {178 writeln!(out)?;170 writeln!(out)?;179 let desc = &item.desc;171 let desc = &item.desc;180 if let Some(source) = &item.location {172 if let Some(source) = &item.location {181 let start_end =173 let start_end = s.map_source_locations(&source.0, &[source.1, source.2]);182 evaluation_state.map_source_locations(&source.0, &[source.1, source.2]);183174184 write!(175 write!(185 out,176 out,207 fn write_trace(198 fn write_trace(208 &self,199 &self,209 out: &mut dyn std::fmt::Write,200 out: &mut dyn std::fmt::Write,210 evaluation_state: &EvaluationState,201 s: &State,211 error: &LocError,202 error: &LocError,212 ) -> Result<(), std::fmt::Error> {203 ) -> Result<(), std::fmt::Error> {213 write!(out, "{}", error.error())?;204 write!(out, "{}", error.error())?;240 writeln!(out)?;231 writeln!(out)?;241 let desc = &item.desc;232 let desc = &item.desc;242 if let Some(source) = &item.location {233 if let Some(source) = &item.location {243 let start_end =234 let start_end = s.map_source_locations(&source.0, &[source.1, source.2]);244 evaluation_state.map_source_locations(&source.0, &[source.1, source.2]);245 self.print_snippet(235 self.print_snippet(246 out,236 out,247 &evaluation_state.get_source(&source.0).unwrap(),237 &s.get_source(&source.0).unwrap(),248 &source.0,238 &source.0,249 &start_end[0],239 &start_end[0],250 &start_end[1],240 &start_end[1],crates/jrsonnet-evaluator/src/typed/conversions.rsdiffbeforeafterboth1use std::{1use std::{ops::Deref, rc::Rc};2 convert::{TryFrom, TryInto},3 ops::Deref,4 rc::Rc,5};627use gcmodule::Cc;3use gcmodule::Cc;10use jrsonnet_types::{ComplexValType, ValType};6use jrsonnet_types::{ComplexValType, ValType};11712use crate::{8use crate::{13 error::{Error::*, LocError, Result},9 error::{Error::*, Result},14 throw,10 throw,15 typed::CheckType,11 typed::CheckType,16 val::{ArrValue, FuncDesc, FuncVal, IndexableVal},12 val::{ArrValue, FuncDesc, FuncVal, IndexableVal},17 ObjValue, ObjValueBuilder, Val,13 ObjValue, ObjValueBuilder, State, Val,18};14};191520pub trait TypedObj: Typed {16pub trait TypedObj: Typed {27 }23 }28}24}292530pub trait Typed: TryFrom<Val, Error = LocError> + TryInto<Val, Error = LocError> {26pub trait Typed: Sized {31 const TYPE: &'static ComplexValType;27 const TYPE: &'static ComplexValType;28 fn into_untyped(typed: Self, s: State) -> Result<Val>;29 fn from_untyped(untyped: Val, s: State) -> Result<Self>;32}30}333134macro_rules! impl_int {32macro_rules! impl_int {35 ($($ty:ty)*) => {$(33 ($($ty:ty)*) => {$(36 impl Typed for $ty {34 impl Typed for $ty {37 const TYPE: &'static ComplexValType =35 const TYPE: &'static ComplexValType =38 &ComplexValType::BoundedNumber(Some(Self::MIN as f64), Some(Self::MAX as f64));36 &ComplexValType::BoundedNumber(Some(Self::MIN as f64), Some(Self::MAX as f64));39 }40 impl TryFrom<Val> for $ty {41 type Error = LocError;4243 fn try_from(value: Val) -> Result<Self> {37 fn from_untyped(value: Val, s: State) -> Result<Self> {44 <Self as Typed>::TYPE.check(&value)?;38 <Self as Typed>::TYPE.check(s, &value)?;45 match value {39 match value {46 Val::Num(n) => {40 Val::Num(n) => {47 if n.trunc() != n {41 if n.trunc() != n {58 _ => unreachable!(),52 _ => unreachable!(),59 }53 }60 }54 }61 }62 impl TryFrom<$ty> for Val {63 type Error = LocError;6465 fn try_from(value: $ty) -> Result<Self> {55 fn into_untyped(value: Self, _: State) -> Result<Val> {66 Ok(Self::Num(value as f64))56 Ok(Val::Num(value as f64))67 }57 }68 }58 }69 )*};59 )*};70}60}716194 }84 }95 }85 }968697 impl<const MIN: $ty, const MAX: $ty> Typed for $name<MIN, MAX> {87 impl<const MIN: $ty, const MAX: $ty> Typed for $name<MIN, MAX> {98 const TYPE: &'static ComplexValType =88 const TYPE: &'static ComplexValType =99 &ComplexValType::BoundedNumber(89 &ComplexValType::BoundedNumber(100 Some(MIN as f64),90 Some(MIN as f64),101 Some(MAX as f64),91 Some(MAX as f64),102 );92 );103 }104 impl<const MIN: $ty, const MAX: $ty> TryFrom<Val> for $name<MIN, MAX> {105 type Error = LocError;10693107 fn try_from(value: Val) -> Result<Self> {94 fn from_untyped(value: Val, s: State) -> Result<Self> {108 <Self as Typed>::TYPE.check(&value)?;95 <Self as Typed>::TYPE.check(s, &value)?;109 match value {96 match value {110 Val::Num(n) => {97 Val::Num(n) => {111 if n.trunc() != n {98 if n.trunc() != n {122 _ => unreachable!(),109 _ => unreachable!(),123 }110 }124 }111 }125 }126 impl<const MIN: $ty, const MAX: $ty> TryFrom<$name<MIN, MAX>> for Val {127 type Error = LocError;128112129 fn try_from(value: $name<MIN, MAX>) -> Result<Self> {113 fn into_untyped(value: Self, _: State) -> Result<Val> {130 Ok(Self::Num(value.0 as f64))114 Ok(Val::Num(value.0 as f64))131 }115 }132 }116 }133 )*};117 )*};134}118}135119141 BoundedUsize = usize125 BoundedUsize = usize142);126);143127144impl Typed for f64 {128impl Typed for f64 {145 const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Num);129 const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Num);146}130147impl TryFrom<Val> for f64 {131 fn into_untyped(value: Self, _: State) -> Result<Val> {148 type Error = LocError;132 Ok(Val::Num(value))133 }149134150 fn try_from(value: Val) -> Result<Self> {135 fn from_untyped(value: Val, s: State) -> Result<Self> {151 <Self as Typed>::TYPE.check(&value)?;136 <Self as Typed>::TYPE.check(s, &value)?;152 match value {137 match value {153 Val::Num(n) => Ok(n),138 Val::Num(n) => Ok(n),154 _ => unreachable!(),139 _ => unreachable!(),155 }140 }156 }141 }157}142}158impl TryFrom<f64> for Val {159 type Error = LocError;160161 fn try_from(value: f64) -> Result<Self> {162 Ok(Self::Num(value))163 }164}165143166pub struct PositiveF64(pub f64);144pub struct PositiveF64(pub f64);167impl Typed for PositiveF64 {145impl Typed for PositiveF64 {168 const TYPE: &'static ComplexValType = &ComplexValType::BoundedNumber(Some(0.0), None);146 const TYPE: &'static ComplexValType = &ComplexValType::BoundedNumber(Some(0.0), None);169}147170impl TryFrom<Val> for PositiveF64 {148 fn into_untyped(value: Self, _: State) -> Result<Val> {171 type Error = LocError;149 Ok(Val::Num(value.0))150 }172151173 fn try_from(value: Val) -> Result<Self> {152 fn from_untyped(value: Val, s: State) -> Result<Self> {174 <Self as Typed>::TYPE.check(&value)?;153 <Self as Typed>::TYPE.check(s, &value)?;175 match value {154 match value {176 Val::Num(n) => Ok(Self(n)),155 Val::Num(n) => Ok(Self(n)),177 _ => unreachable!(),156 _ => unreachable!(),178 }157 }179 }158 }180}159}181impl TryFrom<PositiveF64> for Val {160impl Typed for usize {182 type Error = LocError;183184 fn try_from(value: PositiveF64) -> Result<Self> {185 Ok(Self::Num(value.0))186 }187}188189impl Typed for usize {190 // It is possible to store 54 bits of precision in f64, but leaving u32::MAX here for compatibility161 // It is possible to store 54 bits of precision in f64, but leaving u32::MAX here for compatibility191 const TYPE: &'static ComplexValType =162 const TYPE: &'static ComplexValType =192 &ComplexValType::BoundedNumber(Some(0.0), Some(4294967295.0));163 &ComplexValType::BoundedNumber(Some(0.0), Some(4294967295.0));193}164194impl TryFrom<Val> for usize {165 fn into_untyped(value: Self, _: State) -> Result<Val> {195 type Error = LocError;166 if value > u32::MAX as Self {167 throw!(RuntimeError("number is too large".into()))168 }169 Ok(Val::Num(value as f64))170 }196171197 fn try_from(value: Val) -> Result<Self> {172 fn from_untyped(value: Val, s: State) -> Result<Self> {198 <Self as Typed>::TYPE.check(&value)?;173 <Self as Typed>::TYPE.check(s, &value)?;199 match value {174 match value {200 Val::Num(n) => {175 Val::Num(n) => {201 if n.trunc() != n {176 if n.trunc() != n {208 _ => unreachable!(),183 _ => unreachable!(),209 }184 }210 }185 }211}186}187212impl TryFrom<usize> for Val {188impl Typed for IStr {213 type Error = LocError;214215 fn try_from(value: usize) -> Result<Self> {216 if value > u32::MAX as usize {217 throw!(RuntimeError("number is too large".into()))218 }219 Ok(Self::Num(value as f64))220 }221}222223impl Typed for IStr {224 const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Str);189 const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Str);225}190226impl TryFrom<Val> for IStr {191 fn into_untyped(value: Self, _: State) -> Result<Val> {227 type Error = LocError;192 Ok(Val::Str(value))193 }228194229 fn try_from(value: Val) -> Result<Self> {195 fn from_untyped(value: Val, s: State) -> Result<Self> {230 <Self as Typed>::TYPE.check(&value)?;196 <Self as Typed>::TYPE.check(s, &value)?;231 match value {197 match value {232 Val::Str(s) => Ok(s),198 Val::Str(s) => Ok(s),233 _ => unreachable!(),199 _ => unreachable!(),234 }200 }235 }201 }236}202}203237impl TryFrom<IStr> for Val {204impl Typed for String {238 type Error = LocError;239240 fn try_from(value: IStr) -> Result<Self> {241 Ok(Self::Str(value))242 }243}244245impl Typed for String {246 const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Str);205 const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Str);247}206248impl TryFrom<Val> for String {207 fn into_untyped(value: Self, _: State) -> Result<Val> {249 type Error = LocError;208 Ok(Val::Str(value.into()))209 }250210251 fn try_from(value: Val) -> Result<Self> {211 fn from_untyped(value: Val, s: State) -> Result<Self> {252 <Self as Typed>::TYPE.check(&value)?;212 <Self as Typed>::TYPE.check(s, &value)?;253 match value {213 match value {254 Val::Str(s) => Ok(s.to_string()),214 Val::Str(s) => Ok(s.to_string()),255 _ => unreachable!(),215 _ => unreachable!(),256 }216 }257 }217 }258}218}219259impl TryFrom<String> for Val {220impl Typed for char {260 type Error = LocError;261262 fn try_from(value: String) -> Result<Self> {263 Ok(Self::Str(value.into()))264 }265}266267impl Typed for char {268 const TYPE: &'static ComplexValType = &ComplexValType::Char;221 const TYPE: &'static ComplexValType = &ComplexValType::Char;269}222270impl TryFrom<Val> for char {223 fn into_untyped(value: Self, _: State) -> Result<Val> {271 type Error = LocError;224 Ok(Val::Str(value.to_string().into()))225 }272226273 fn try_from(value: Val) -> Result<Self> {227 fn from_untyped(value: Val, s: State) -> Result<Self> {274 <Self as Typed>::TYPE.check(&value)?;228 <Self as Typed>::TYPE.check(s, &value)?;275 match value {229 match value {276 Val::Str(s) => Ok(s.chars().next().unwrap()),230 Val::Str(s) => Ok(s.chars().next().unwrap()),277 _ => unreachable!(),231 _ => unreachable!(),278 }232 }279 }233 }280}234}235281impl TryFrom<char> for Val {236impl<T> Typed for Vec<T>282 type Error = LocError;283284 fn try_from(value: char) -> Result<Self> {285 Ok(Self::Str(value.to_string().into()))286 }287}288289impl<T> Typed for Vec<T>290where237where291 T: Typed,238 T: Typed,292 T: TryFrom<Val, Error = LocError>,239{293 T: TryInto<Val, Error = LocError>,294{295 const TYPE: &'static ComplexValType = &ComplexValType::ArrayRef(T::TYPE);240 const TYPE: &'static ComplexValType = &ComplexValType::ArrayRef(T::TYPE);296}241297impl<T> TryFrom<Val> for Vec<T>298where299 T: Typed,242 fn into_untyped(value: Self, s: State) -> Result<Val> {300 T: TryFrom<Val, Error = LocError>,243 let mut o = Vec::with_capacity(value.len());244 for i in value {301 T: TryInto<Val, Error = LocError>,245 o.push(T::into_untyped(i, s.clone())?);302{246 }303 type Error = LocError;247 Ok(Val::Arr(o.into()))248 }304249305 fn try_from(value: Val) -> Result<Self> {250 fn from_untyped(value: Val, s: State) -> Result<Self> {306 <Self as Typed>::TYPE.check(&value)?;251 <Self as Typed>::TYPE.check(s.clone(), &value)?;307 match value {252 match value {308 Val::Arr(a) => {253 Val::Arr(a) => {309 let mut o = Self::with_capacity(a.len());254 let mut o = Self::with_capacity(a.len());310 for i in a.iter() {255 for i in a.iter(s.clone()) {311 o.push(T::try_from(i?)?);256 o.push(T::from_untyped(i?, s.clone())?);312 }257 }313 Ok(o)258 Ok(o)314 }259 }315 _ => unreachable!(),260 _ => unreachable!(),316 }261 }317 }262 }318}263}319impl<T> TryFrom<Vec<T>> for Val320where321 T: Typed,322 T: TryFrom<Self, Error = LocError>,323 T: TryInto<Self, Error = LocError>,324{325 type Error = LocError;326327 fn try_from(value: Vec<T>) -> Result<Self> {328 let mut o = Vec::with_capacity(value.len());329 for i in value {330 o.push(i.try_into()?);331 }332 Ok(Self::Arr(o.into()))333 }334}335264336/// To be used in Vec<Any>265/// To be used in Vec<Any>337/// Regular Val can't be used here, because it has wrong TryFrom::Error type266/// Regular Val can't be used here, because it has wrong TryFrom::Error type338#[derive(Clone)]267#[derive(Clone)]339pub struct Any(pub Val);268pub struct Any(pub Val);340269341impl Typed for Any {270impl Typed for Any {342 const TYPE: &'static ComplexValType = &ComplexValType::Any;271 const TYPE: &'static ComplexValType = &ComplexValType::Any;343}344impl TryFrom<Val> for Any {345 type Error = LocError;346272347 fn try_from(value: Val) -> Result<Self> {273 fn into_untyped(value: Self, _: State) -> Result<Val> {348 Ok(Self(value))274 Ok(value.0)349 }275 }350}351impl TryFrom<Any> for Val {352 type Error = LocError;353276354 fn try_from(value: Any) -> Result<Self> {277 fn from_untyped(value: Val, _: State) -> Result<Self> {355 Ok(value.0)278 Ok(Self(value))356 }279 }357}280}358281359/// Specialization, provides faster TryFrom<VecVal> for Val282/// Specialization, provides faster TryFrom<VecVal> for Val360pub struct VecVal(pub Cc<Vec<Val>>);283pub struct VecVal(pub Cc<Vec<Val>>);361284362impl Typed for VecVal {285impl Typed for VecVal {363 const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Arr);286 const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Arr);364}287365impl TryFrom<Val> for VecVal {288 fn into_untyped(value: Self, _: State) -> Result<Val> {366 type Error = LocError;289 Ok(Val::Arr(ArrValue::Eager(value.0)))290 }367291368 fn try_from(value: Val) -> Result<Self> {292 fn from_untyped(value: Val, s: State) -> Result<Self> {369 <Self as Typed>::TYPE.check(&value)?;293 <Self as Typed>::TYPE.check(s.clone(), &value)?;370 match value {294 match value {371 Val::Arr(a) => Ok(Self(a.evaluated()?)),295 Val::Arr(a) => Ok(Self(a.evaluated(s)?)),372 _ => unreachable!(),296 _ => unreachable!(),373 }297 }374 }298 }375}299}376impl TryFrom<VecVal> for Val {377 type Error = LocError;378379 fn try_from(value: VecVal) -> Result<Self> {380 Ok(Self::Arr(ArrValue::Eager(value.0)))381 }382}383300384/// Specialization301/// Specialization385pub struct Bytes(pub Rc<[u8]>);302pub struct Bytes(pub Rc<[u8]>);386303387impl Typed for Bytes {304impl Typed for Bytes {388 const TYPE: &'static ComplexValType =305 const TYPE: &'static ComplexValType =389 &ComplexValType::ArrayRef(&ComplexValType::BoundedNumber(Some(0.0), Some(255.0)));306 &ComplexValType::ArrayRef(&ComplexValType::BoundedNumber(Some(0.0), Some(255.0)));390}307391impl TryFrom<Val> for Bytes {308 fn into_untyped(value: Self, _: State) -> Result<Val> {392 type Error = LocError;309 Ok(Val::Arr(ArrValue::Bytes(value.0)))310 }393311394 fn try_from(value: Val) -> Result<Self> {312 fn from_untyped(value: Val, s: State) -> Result<Self> {395 match value {313 match value {396 Val::Arr(ArrValue::Bytes(bytes)) => Ok(Self(bytes)),314 Val::Arr(ArrValue::Bytes(bytes)) => Ok(Self(bytes)),397 _ => {315 _ => {398 <Self as Typed>::TYPE.check(&value)?;316 <Self as Typed>::TYPE.check(s.clone(), &value)?;399 match value {317 match value {400 Val::Arr(a) => {318 Val::Arr(a) => {401 let mut out = Vec::with_capacity(a.len());319 let mut out = Vec::with_capacity(a.len());402 for e in a.iter() {320 for e in a.iter(s.clone()) {403 let r = e?;321 let r = e?;404 out.push(u8::try_from(r)?);322 out.push(u8::from_untyped(r, s.clone())?);405 }323 }406 Ok(Self(out.into()))324 Ok(Self(out.into()))407 }325 }410 }328 }411 }329 }412 }330 }413}331}414impl TryFrom<Bytes> for Val {415 type Error = LocError;416417 fn try_from(value: Bytes) -> Result<Self> {418 Ok(Self::Arr(ArrValue::Bytes(value.0)))419 }420}421332422pub struct M1;333pub struct M1;423impl Typed for M1 {334impl Typed for M1 {424 const TYPE: &'static ComplexValType = &ComplexValType::BoundedNumber(Some(-1.0), Some(-1.0));335 const TYPE: &'static ComplexValType = &ComplexValType::BoundedNumber(Some(-1.0), Some(-1.0));425}336426impl TryFrom<Val> for M1 {337 fn into_untyped(_: Self, _: State) -> Result<Val> {427 type Error = LocError;338 Ok(Val::Num(-1.0))339 }428340429 fn try_from(value: Val) -> Result<Self> {341 fn from_untyped(value: Val, s: State) -> Result<Self> {430 <Self as Typed>::TYPE.check(&value)?;342 <Self as Typed>::TYPE.check(s, &value)?;431 Ok(Self)343 Ok(Self)432 }344 }433}345}434impl TryFrom<M1> for Val {435 type Error = LocError;436437 fn try_from(_: M1) -> Result<Self> {438 Ok(Self::Num(-1.0))439 }440}441346442macro_rules! decl_either {347macro_rules! decl_either {443 ($($name: ident, $($id: ident)*);*) => {$(348 ($($name: ident, $($id: ident)*);*) => {$(447 impl<$($id),*> Typed for $name<$($id),*>352 impl<$($id),*> Typed for $name<$($id),*>448 where353 where449 $($id: Typed,)*354 $($id: Typed,)*450 {355 {451 const TYPE: &'static ComplexValType = &ComplexValType::UnionRef(&[$($id::TYPE),*]);356 const TYPE: &'static ComplexValType = &ComplexValType::UnionRef(&[$($id::TYPE),*]);452 }357453 impl<$($id),*> TryFrom<Val> for $name<$($id),*>358 fn into_untyped(value: Self, s: State) -> Result<Val> {454 where455 $($id: Typed,)*359 match value {$(456 {360 $name::$id(v) => $id::into_untyped(v, s)457 type Error = LocError;361 ),*}362 }458363459 fn try_from(value: Val) -> Result<Self> {364 fn from_untyped(value: Val, s: State) -> Result<Self> {460 $(365 $(461 if $id::TYPE.check(&value).is_ok() {366 if $id::TYPE.check(s.clone(), &value).is_ok() {462 $id::try_from(value).map(Self::$id)367 $id::from_untyped(value, s.clone()).map(Self::$id)463 } else368 } else464 )* {369 )* {465 <Self as Typed>::TYPE.check(&value)?;370 <Self as Typed>::TYPE.check(s, &value)?;466 unreachable!()371 unreachable!()467 }372 }468 }373 }469 }374 }470 impl<$($id),*> TryFrom<$name<$($id),*>> for Val471 where472 $($id: Typed,)*473 {474 type Error = LocError;475 fn try_from(value: $name<$($id),*>) -> Result<Self> {476 match value {$(477 $name::$id(v) => v.try_into()478 ),*}479 }480 }481 )*}375 )*}482}376}483decl_either!(377decl_either!(502396503pub type MyType = Either![u32, f64, String];397pub type MyType = Either![u32, f64, String];504398505impl Typed for ArrValue {399impl Typed for ArrValue {506 const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Arr);400 const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Arr);507}401508impl TryFrom<Val> for ArrValue {402 fn into_untyped(value: Self, _: State) -> Result<Val> {509 type Error = LocError;403 Ok(Val::Arr(value))404 }510405511 fn try_from(value: Val) -> Result<Self> {406 fn from_untyped(value: Val, s: State) -> Result<Self> {512 <Self as Typed>::TYPE.check(&value)?;407 <Self as Typed>::TYPE.check(s, &value)?;513 match value {408 match value {514 Val::Arr(a) => Ok(a),409 Val::Arr(a) => Ok(a),515 _ => unreachable!(),410 _ => unreachable!(),516 }411 }517 }412 }518}413}414519impl TryFrom<ArrValue> for Val {415impl Typed for FuncVal {520 type Error = LocError;521522 fn try_from(value: ArrValue) -> Result<Self> {523 Ok(Self::Arr(value))524 }525}526527impl Typed for FuncVal {528 const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Func);416 const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Func);529}417530impl TryFrom<Val> for FuncVal {418 fn into_untyped(value: Self, _: State) -> Result<Val> {531 type Error = LocError;419 Ok(Val::Func(value))420 }532421533 fn try_from(value: Val) -> Result<Self> {422 fn from_untyped(value: Val, s: State) -> Result<Self> {534 <Self as Typed>::TYPE.check(&value)?;423 <Self as Typed>::TYPE.check(s, &value)?;535 match value {424 match value {536 Val::Func(a) => Ok(a),425 Val::Func(a) => Ok(a),537 _ => unreachable!(),426 _ => unreachable!(),538 }427 }539 }428 }540}429}430541impl TryFrom<FuncVal> for Val {431impl Typed for Cc<FuncDesc> {542 type Error = LocError;543544 fn try_from(value: FuncVal) -> Result<Self> {545 Ok(Self::Func(value))546 }547}548549impl Typed for Cc<FuncDesc> {550 const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Func);432 const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Func);551}433552impl TryFrom<Val> for Cc<FuncDesc> {434 fn into_untyped(value: Self, _: State) -> Result<Val> {553 type Error = LocError;435 Ok(Val::Func(FuncVal::Normal(value)))436 }554437555 fn try_from(value: Val) -> Result<Self, Self::Error> {438 fn from_untyped(value: Val, s: State) -> Result<Self> {556 <Self as Typed>::TYPE.check(&value)?;439 <Self as Typed>::TYPE.check(s, &value)?;557 match value {440 match value {558 Val::Func(FuncVal::Normal(desc)) => Ok(desc),441 Val::Func(FuncVal::Normal(desc)) => Ok(desc),559 Val::Func(_) => throw!(RuntimeError("expected normal function, not builtin".into())),442 Val::Func(_) => throw!(RuntimeError("expected normal function, not builtin".into())),560 _ => unreachable!(),443 _ => unreachable!(),561 }444 }562 }445 }563}446}447564impl TryFrom<Cc<FuncDesc>> for Val {448impl Typed for ObjValue {565 type Error = LocError;566567 fn try_from(value: Cc<FuncDesc>) -> Result<Self, Self::Error> {568 Ok(Self::Func(FuncVal::Normal(value)))569 }570}571572impl Typed for ObjValue {573 const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Obj);449 const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Obj);574}450575impl TryFrom<Val> for ObjValue {451 fn into_untyped(value: Self, _: State) -> Result<Val> {576 type Error = LocError;452 Ok(Val::Obj(value))453 }577454578 fn try_from(value: Val) -> Result<Self> {455 fn from_untyped(value: Val, s: State) -> Result<Self> {579 <Self as Typed>::TYPE.check(&value)?;456 <Self as Typed>::TYPE.check(s, &value)?;580 match value {457 match value {581 Val::Obj(a) => Ok(a),458 Val::Obj(a) => Ok(a),582 _ => unreachable!(),459 _ => unreachable!(),583 }460 }584 }461 }585}462}463586impl TryFrom<ObjValue> for Val {464impl Typed for bool {587 type Error = LocError;588589 fn try_from(value: ObjValue) -> Result<Self> {590 Ok(Self::Obj(value))591 }592}593594impl Typed for bool {595 const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Bool);465 const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Bool);596}466597impl TryFrom<Val> for bool {467 fn into_untyped(value: Self, _: State) -> Result<Val> {598 type Error = LocError;468 Ok(Val::Bool(value))469 }599470600 fn try_from(value: Val) -> Result<Self> {471 fn from_untyped(value: Val, s: State) -> Result<Self> {601 <Self as Typed>::TYPE.check(&value)?;472 <Self as Typed>::TYPE.check(s, &value)?;602 match value {473 match value {603 Val::Bool(a) => Ok(a),474 Val::Bool(a) => Ok(a),604 _ => unreachable!(),475 _ => unreachable!(),605 }476 }606 }477 }607}478}608impl TryFrom<bool> for Val {479impl Typed for IndexableVal {609 type Error = LocError;610611 fn try_from(value: bool) -> Result<Self> {612 Ok(Self::Bool(value))613 }614}615616impl Typed for IndexableVal {617 const TYPE: &'static ComplexValType = &ComplexValType::UnionRef(&[480 const TYPE: &'static ComplexValType = &ComplexValType::UnionRef(&[618 &ComplexValType::Simple(ValType::Arr),481 &ComplexValType::Simple(ValType::Arr),619 &ComplexValType::Simple(ValType::Str),482 &ComplexValType::Simple(ValType::Str),620 ]);483 ]);621}622impl TryFrom<Val> for IndexableVal {623 type Error = LocError;624625 fn try_from(value: Val) -> Result<Self> {626 <Self as Typed>::TYPE.check(&value)?;627 value.into_indexable()628 }629}630impl TryFrom<IndexableVal> for Val {631 type Error = LocError;632484633 fn try_from(value: IndexableVal) -> Result<Self> {485 fn into_untyped(value: Self, _: State) -> Result<Val> {634 match value {486 match value {635 IndexableVal::Str(s) => Ok(Self::Str(s)),487 IndexableVal::Str(s) => Ok(Val::Str(s)),636 IndexableVal::Arr(a) => Ok(Self::Arr(a)),488 IndexableVal::Arr(a) => Ok(Val::Arr(a)),637 }489 }638 }490 }639}491492 fn from_untyped(value: Val, s: State) -> Result<Self> {493 <Self as Typed>::TYPE.check(s, &value)?;494 value.into_indexable()495 }496}640497641pub struct Null;498pub struct Null;642impl Typed for Null {499impl Typed for Null {643 const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Null);500 const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Null);644}501645impl TryFrom<Val> for Null {502 fn into_untyped(_: Self, _: State) -> Result<Val> {646 type Error = LocError;503 Ok(Val::Null)504 }647505648 fn try_from(value: Val) -> Result<Self> {506 fn from_untyped(value: Val, s: State) -> Result<Self> {649 <Self as Typed>::TYPE.check(&value)?;507 <Self as Typed>::TYPE.check(s, &value)?;650 Ok(Self)508 Ok(Self)651 }509 }652}510}653impl TryFrom<Null> for Val {654 type Error = LocError;655656 fn try_from(_: Null) -> Result<Self> {657 Ok(Self::Null)658 }659}660511crates/jrsonnet-evaluator/src/typed/mod.rsdiffbeforeafterboth889use crate::{9use crate::{10 error::{Error, LocError, Result},10 error::{Error, LocError, Result},11 push_description_frame, Val,11 State, Val,12};12};131314#[derive(Debug, Error, Clone, Trace)]14#[derive(Debug, Error, Clone, Trace)]85}85}868687fn push_type_description(87fn push_type_description(88 s: State,88 error_reason: impl Fn() -> String,89 error_reason: impl Fn() -> String,89 path: impl Fn() -> ValuePathItem,90 path: impl Fn() -> ValuePathItem,90 item: impl Fn() -> Result<()>,91 item: impl Fn() -> Result<()>,91) -> Result<()> {92) -> Result<()> {92 push_description_frame(error_reason, || match item() {93 s.push_description(error_reason, || match item() {93 Ok(_) => Ok(()),94 Ok(_) => Ok(()),94 Err(mut e) => {95 Err(mut e) => {95 if let Error::TypeError(e) = &mut e.error_mut() {96 if let Error::TypeError(e) = &mut e.error_mut() {102103103// TODO: check_fast for fast path of union type checking104// TODO: check_fast for fast path of union type checking104pub trait CheckType {105pub trait CheckType {105 fn check(&self, value: &Val) -> Result<()>;106 fn check(&self, s: State, value: &Val) -> Result<()>;106}107}107108108impl CheckType for ValType {109impl CheckType for ValType {109 fn check(&self, value: &Val) -> Result<()> {110 fn check(&self, _: State, value: &Val) -> Result<()> {110 let got = value.value_type();111 let got = value.value_type();111 if got != *self {112 if got != *self {112 let loc_error: TypeLocError = TypeError::ExpectedGot((*self).into(), got).into();113 let loc_error: TypeLocError = TypeError::ExpectedGot((*self).into(), got).into();144}145}145146146impl CheckType for ComplexValType {147impl CheckType for ComplexValType {147 fn check(&self, value: &Val) -> Result<()> {148 fn check(&self, s: State, value: &Val) -> Result<()> {148 match self {149 match self {149 Self::Any => Ok(()),150 Self::Any => Ok(()),150 Self::Simple(s) => s.check(value),151 Self::Simple(t) => t.check(s, value),151 Self::Char => match value {152 Self::Char => match value {152 Val::Str(s) if s.len() == 1 || s.chars().count() == 1 => Ok(()),153 Val::Str(s) if s.len() == 1 || s.chars().count() == 1 => Ok(()),153 v => Err(TypeError::ExpectedGot(self.clone(), v.value_type()).into()),154 v => Err(TypeError::ExpectedGot(self.clone(), v.value_type()).into()),166 }167 }167 Self::Array(elem_type) => match value {168 Self::Array(elem_type) => match value {168 Val::Arr(a) => {169 Val::Arr(a) => {169 for (i, item) in a.iter().enumerate() {170 for (i, item) in a.iter(s.clone()).enumerate() {170 push_type_description(171 push_type_description(172 s.clone(),171 || format!("array index {}", i),173 || format!("array index {}", i),172 || ValuePathItem::Index(i as u64),174 || ValuePathItem::Index(i as u64),173 || elem_type.check(&item.clone()?),175 || elem_type.check(s.clone(), &item.clone()?),174 )?;176 )?;175 }177 }176 Ok(())178 Ok(())179 },181 },180 Self::ArrayRef(elem_type) => match value {182 Self::ArrayRef(elem_type) => match value {181 Val::Arr(a) => {183 Val::Arr(a) => {182 for (i, item) in a.iter().enumerate() {184 for (i, item) in a.iter(s.clone()).enumerate() {183 push_type_description(185 push_type_description(186 s.clone(),184 || format!("array index {}", i),187 || format!("array index {}", i),185 || ValuePathItem::Index(i as u64),188 || ValuePathItem::Index(i as u64),186 || elem_type.check(&item.clone()?),189 || elem_type.check(s.clone(), &item.clone()?),187 )?;190 )?;188 }191 }189 Ok(())192 Ok(())193 Self::ObjectRef(elems) => match value {196 Self::ObjectRef(elems) => match value {194 Val::Obj(obj) => {197 Val::Obj(obj) => {195 for (k, v) in elems.iter() {198 for (k, v) in elems.iter() {196 if let Some(got_v) = obj.get((*k).into())? {199 if let Some(got_v) = obj.get(s.clone(), (*k).into())? {197 push_type_description(200 push_type_description(201 s.clone(),198 || format!("property {}", k),202 || format!("property {}", k),199 || ValuePathItem::Field((*k).into()),203 || ValuePathItem::Field((*k).into()),200 || v.check(&got_v),204 || v.check(s.clone(), &got_v),201 )?205 )?202 } else {206 } else {203 return Err(207 return Err(212 Self::Union(types) => {216 Self::Union(types) => {213 let mut errors = Vec::new();217 let mut errors = Vec::new();214 for ty in types.iter() {218 for ty in types.iter() {215 match ty.check(value) {219 match ty.check(s.clone(), value) {216 Ok(()) => {220 Ok(()) => {217 return Ok(());221 return Ok(());218 }222 }227 Self::UnionRef(types) => {231 Self::UnionRef(types) => {228 let mut errors = Vec::new();232 let mut errors = Vec::new();229 for ty in types.iter() {233 for ty in types.iter() {230 match ty.check(value) {234 match ty.check(s.clone(), value) {231 Ok(()) => {235 Ok(()) => {232 return Ok(());236 return Ok(());233 }237 }241 }245 }242 Self::Sum(types) => {246 Self::Sum(types) => {243 for ty in types.iter() {247 for ty in types.iter() {244 ty.check(value)?248 ty.check(s.clone(), value)?245 }249 }246 Ok(())250 Ok(())247 }251 }248 Self::SumRef(types) => {252 Self::SumRef(types) => {249 for ty in types.iter() {253 for ty in types.iter() {250 ty.check(value)?254 ty.check(s.clone(), value)?251 }255 }252 Ok(())256 Ok(())253 }257 }crates/jrsonnet-evaluator/src/val.rsdiffbeforeafterboth17 StaticBuiltin,17 StaticBuiltin,18 },18 },19 gc::TraceBox,19 gc::TraceBox,20 throw, Context, ObjValue, Result,20 throw, Context, ObjValue, Result, State,21};21};222223pub trait LazyValValue: Trace {23pub trait LazyValValue: Trace {24 fn get(self: Box<Self>) -> Result<Val>;24 fn get(self: Box<Self>, s: State) -> Result<Val>;25}25}262627#[derive(Trace)]27#[derive(Trace)]41 pub fn new_resolved(val: Val) -> Self {41 pub fn new_resolved(val: Val) -> Self {42 Self(Cc::new(RefCell::new(LazyValInternals::Computed(val))))42 Self(Cc::new(RefCell::new(LazyValInternals::Computed(val))))43 }43 }44 pub fn force(&self) -> Result<()> {44 pub fn force(&self, s: State) -> Result<()> {45 self.evaluate()?;45 self.evaluate(s)?;46 Ok(())46 Ok(())47 }47 }48 pub fn evaluate(&self) -> Result<Val> {48 pub fn evaluate(&self, s: State) -> Result<Val> {49 match &*self.0.borrow() {49 match &*self.0.borrow() {50 LazyValInternals::Computed(v) => return Ok(v.clone()),50 LazyValInternals::Computed(v) => return Ok(v.clone()),51 LazyValInternals::Errored(e) => return Err(e.clone()),51 LazyValInternals::Errored(e) => return Err(e.clone()),59 } else {59 } else {60 unreachable!()60 unreachable!()61 };61 };62 let new_value = match value.0.get() {62 let new_value = match value.0.get(s) {63 Ok(v) => v,63 Ok(v) => v,64 Err(e) => {64 Err(e) => {65 *self.0.borrow_mut() = LazyValInternals::Errored(e.clone());65 *self.0.borrow_mut() = LazyValInternals::Errored(e.clone());98 /// Create context, with which body code will run98 /// Create context, with which body code will run99 pub fn call_body_context(99 pub fn call_body_context(100 &self,100 &self,101 s: State,101 call_ctx: Context,102 call_ctx: Context,102 args: &dyn ArgsLike,103 args: &dyn ArgsLike,103 tailstrict: bool,104 tailstrict: bool,104 ) -> Result<Context> {105 ) -> Result<Context> {105 parse_function_call(call_ctx, self.ctx.clone(), &self.params, args, tailstrict)106 parse_function_call(107 s,108 call_ctx,109 self.ctx.clone(),110 &self.params,111 args,112 tailstrict,113 )106 }114 }107}115}145 }153 }146 pub fn evaluate(154 pub fn evaluate(147 &self,155 &self,156 s: State,148 call_ctx: Context,157 call_ctx: Context,149 loc: CallLocation,158 loc: CallLocation,150 args: &dyn ArgsLike,159 args: &dyn ArgsLike,151 tailstrict: bool,160 tailstrict: bool,152 ) -> Result<Val> {161 ) -> Result<Val> {153 match self {162 match self {154 Self::Normal(func) => {163 Self::Normal(func) => {155 let body_ctx = func.call_body_context(call_ctx, args, tailstrict)?;164 let body_ctx = func.call_body_context(s.clone(), call_ctx, args, tailstrict)?;156 evaluate(body_ctx, &func.body)165 evaluate(s, body_ctx, &func.body)157 }166 }158 Self::StaticBuiltin(b) => b.call(call_ctx, loc, args),167 Self::StaticBuiltin(b) => b.call(s, call_ctx, loc, args),159 Self::Builtin(b) => b.call(call_ctx, loc, args),168 Self::Builtin(b) => b.call(s, call_ctx, loc, args),160 }169 }161 }170 }162 pub fn evaluate_simple(&self, args: &dyn ArgsLike) -> Result<Val> {171 pub fn evaluate_simple(&self, s: State, args: &dyn ArgsLike) -> Result<Val> {163 self.evaluate(Context::default(), CallLocation::native(), args, true)172 self.evaluate(s, Context::default(), CallLocation::native(), args, true)164 }173 }165}174}166175276 self.len() == 0285 self.len() == 0277 }286 }278287279 pub fn get(&self, index: usize) -> Result<Option<Val>> {288 pub fn get(&self, s: State, index: usize) -> Result<Option<Val>> {280 match self {289 match self {281 Self::Bytes(i) => i290 Self::Bytes(i) => i282 .get(index)291 .get(index)283 .map_or(Ok(None), |v| Ok(Some(Val::Num(*v as f64)))),292 .map_or(Ok(None), |v| Ok(Some(Val::Num(*v as f64)))),284 Self::Lazy(vec) => {293 Self::Lazy(vec) => {285 if let Some(v) = vec.get(index) {294 if let Some(v) = vec.get(index) {286 Ok(Some(v.evaluate()?))295 Ok(Some(v.evaluate(s)?))287 } else {296 } else {288 Ok(None)297 Ok(None)289 }298 }292 Self::Extended(v) => {301 Self::Extended(v) => {293 let a_len = v.0.len();302 let a_len = v.0.len();294 if a_len > index {303 if a_len > index {295 v.0.get(index)304 v.0.get(s, index)296 } else {305 } else {297 v.1.get(index - a_len)306 v.1.get(s, index - a_len)298 }307 }299 }308 }300 Self::Range(a, _) => {309 Self::Range(a, _) => {308 if index >= len {317 if index >= len {309 return Ok(None);318 return Ok(None);310 }319 }311 v.get(len - index - 1)320 v.get(s, len - index - 1)312 }321 }313 Self::Slice(s) => {322 Self::Slice(v) => {314 let index = s.from() + index * s.step();323 let index = v.from() + index * v.step();315 if index >= s.to() {324 if index >= v.to() {316 return Ok(None);325 return Ok(None);317 }326 }318 s.inner.get(index as usize)327 v.inner.get(s, index as usize)319 }328 }320 }329 }321 }330 }360 }369 }361 }370 }362371363 pub fn evaluated(&self) -> Result<Cc<Vec<Val>>> {372 pub fn evaluated(&self, s: State) -> Result<Cc<Vec<Val>>> {364 Ok(match self {373 Ok(match self {365 Self::Bytes(i) => {374 Self::Bytes(i) => {366 let mut out = Vec::with_capacity(i.len());375 let mut out = Vec::with_capacity(i.len());372 Self::Lazy(vec) => {381 Self::Lazy(vec) => {373 let mut out = Vec::with_capacity(vec.len());382 let mut out = Vec::with_capacity(vec.len());374 for item in vec.iter() {383 for item in vec.iter() {375 out.push(item.evaluate()?);384 out.push(item.evaluate(s.clone())?);376 }385 }377 Cc::new(out)386 Cc::new(out)378 }387 }379 Self::Eager(vec) => vec.clone(),388 Self::Eager(vec) => vec.clone(),380 Self::Extended(_v) => {389 Self::Extended(_v) => {381 let mut out = Vec::with_capacity(self.len());390 let mut out = Vec::with_capacity(self.len());382 for item in self.iter() {391 for item in self.iter(s) {383 out.push(item?);392 out.push(item?);384 }393 }385 Cc::new(out)394 Cc::new(out)392 Cc::new(out)401 Cc::new(out)393 }402 }394 Self::Reversed(r) => {403 Self::Reversed(r) => {395 let mut r = r.evaluated()?;404 let mut r = r.evaluated(s)?;396 Cc::update_with(&mut r, |v| v.reverse());405 Cc::update_with(&mut r, |v| v.reverse());397 r406 r398 }407 }405 .take(v.to() - v.from())414 .take(v.to() - v.from())406 .step_by(v.step())415 .step_by(v.step())407 {416 {408 out.push(v.evaluate()?)417 out.push(v.evaluate(s.clone())?)409 }418 }410 Cc::new(out)419 Cc::new(out)411 }420 }412 })421 })413 }422 }414423415 pub fn iter(&self) -> impl DoubleEndedIterator<Item = Result<Val>> + '_ {424 pub fn iter(&self, s: State) -> impl DoubleEndedIterator<Item = Result<Val>> + '_ {416 (0..self.len()).map(move |idx| match self {425 (0..self.len()).map(move |idx| match self {417 Self::Bytes(b) => Ok(Val::Num(b[idx] as f64)),426 Self::Bytes(b) => Ok(Val::Num(b[idx] as f64)),418 Self::Lazy(l) => l[idx].evaluate(),427 Self::Lazy(l) => l[idx].evaluate(s.clone()),419 Self::Eager(e) => Ok(e[idx].clone()),428 Self::Eager(e) => Ok(e[idx].clone()),420 Self::Extended(_) => self.get(idx).map(|e| e.unwrap()),429 Self::Extended(_) => self.get(s.clone(), idx).map(|e| e.unwrap()),421 Self::Range(..) => self.get(idx).map(|e| e.unwrap()),430 Self::Range(..) => self.get(s.clone(), idx).map(|e| e.unwrap()),422 Self::Reversed(..) => self.get(idx).map(|e| e.unwrap()),431 Self::Reversed(..) => self.get(s.clone(), idx).map(|e| e.unwrap()),423 Self::Slice(..) => self.get(idx).map(|e| e.unwrap()),432 Self::Slice(..) => self.get(s.clone(), idx).map(|e| e.unwrap()),424 })433 })425 }434 }426435440 Self::Reversed(Box::new(self))449 Self::Reversed(Box::new(self))441 }450 }442451443 pub fn map(self, mapper: impl Fn(Val) -> Result<Val>) -> Result<Self> {452 pub fn map(self, s: State, mapper: impl Fn(Val) -> Result<Val>) -> Result<Self> {444 let mut out = Vec::with_capacity(self.len());453 let mut out = Vec::with_capacity(self.len());445454446 for value in self.iter() {455 for value in self.iter(s) {447 out.push(mapper(value?)?);456 out.push(mapper(value?)?);448 }457 }449458450 Ok(Self::Eager(Cc::new(out)))459 Ok(Self::Eager(Cc::new(out)))451 }460 }452461453 pub fn filter(self, filter: impl Fn(&Val) -> Result<bool>) -> Result<Self> {462 pub fn filter(self, s: State, filter: impl Fn(&Val) -> Result<bool>) -> Result<Self> {454 let mut out = Vec::with_capacity(self.len());463 let mut out = Vec::with_capacity(self.len());455464456 for value in self.iter() {465 for value in self.iter(s) {457 let value = value?;466 let value = value?;458 if filter(&value)? {467 if filter(&value)? {459 out.push(value);468 out.push(value);566 }575 }567 }576 }568577569 pub fn to_string(&self) -> Result<IStr> {578 pub fn to_string(&self, s: State) -> Result<IStr> {570 Ok(match self {579 Ok(match self {571 Self::Bool(true) => "true".into(),580 Self::Bool(true) => "true".into(),572 Self::Bool(false) => "false".into(),581 Self::Bool(false) => "false".into(),573 Self::Null => "null".into(),582 Self::Null => "null".into(),574 Self::Str(s) => s.clone(),583 Self::Str(s) => s.clone(),575 v => manifest_json_ex(584 v => manifest_json_ex(585 s,576 v,586 v,577 &ManifestJsonOptions {587 &ManifestJsonOptions {578 padding: "",588 padding: "",588 }598 }589599590 /// Expects value to be object, outputs (key, manifested value) pairs600 /// Expects value to be object, outputs (key, manifested value) pairs591 pub fn manifest_multi(&self, ty: &ManifestFormat) -> Result<Vec<(IStr, IStr)>> {601 pub fn manifest_multi(&self, s: State, ty: &ManifestFormat) -> Result<Vec<(IStr, IStr)>> {592 let obj = match self {602 let obj = match self {593 Self::Obj(obj) => obj,603 Self::Obj(obj) => obj,594 _ => throw!(MultiManifestOutputIsNotAObject),604 _ => throw!(MultiManifestOutputIsNotAObject),600 let mut out = Vec::with_capacity(keys.len());610 let mut out = Vec::with_capacity(keys.len());601 for key in keys {611 for key in keys {602 let value = obj612 let value = obj603 .get(key.clone())?613 .get(s.clone(), key.clone())?604 .expect("item in object")614 .expect("item in object")605 .manifest(ty)?;615 .manifest(s.clone(), ty)?;606 out.push((key, value));616 out.push((key, value));607 }617 }608 Ok(out)618 Ok(out)609 }619 }610620611 /// Expects value to be array, outputs manifested values621 /// Expects value to be array, outputs manifested values612 pub fn manifest_stream(&self, ty: &ManifestFormat) -> Result<Vec<IStr>> {622 pub fn manifest_stream(&self, s: State, ty: &ManifestFormat) -> Result<Vec<IStr>> {613 let arr = match self {623 let arr = match self {614 Self::Arr(a) => a,624 Self::Arr(a) => a,615 _ => throw!(StreamManifestOutputIsNotAArray),625 _ => throw!(StreamManifestOutputIsNotAArray),616 };626 };617 let mut out = Vec::with_capacity(arr.len());627 let mut out = Vec::with_capacity(arr.len());618 for i in arr.iter() {628 for i in arr.iter(s.clone()) {619 out.push(i?.manifest(ty)?);629 out.push(i?.manifest(s.clone(), ty)?);620 }630 }621 Ok(out)631 Ok(out)622 }632 }623633624 pub fn manifest(&self, ty: &ManifestFormat) -> Result<IStr> {634 pub fn manifest(&self, s: State, ty: &ManifestFormat) -> Result<IStr> {625 Ok(match ty {635 Ok(match ty {626 ManifestFormat::YamlStream(format) => {636 ManifestFormat::YamlStream(format) => {627 let arr = match self {637 let arr = match self {637 };647 };638648639 if !arr.is_empty() {649 if !arr.is_empty() {640 for v in arr.iter() {650 for v in arr.iter(s.clone()) {641 out.push_str("---\n");651 out.push_str("---\n");642 out.push_str(&v?.manifest(format)?);652 out.push_str(&v?.manifest(s.clone(), format)?);643 out.push('\n');653 out.push('\n');644 }654 }645 out.push_str("...");655 out.push_str("...");652 #[cfg(feature = "exp-preserve-order")]662 #[cfg(feature = "exp-preserve-order")]653 preserve_order,663 preserve_order,654 } => self.to_yaml(664 } => self.to_yaml(665 s,655 *padding,666 *padding,656 #[cfg(feature = "exp-preserve-order")]667 #[cfg(feature = "exp-preserve-order")]657 *preserve_order,668 *preserve_order,661 #[cfg(feature = "exp-preserve-order")]672 #[cfg(feature = "exp-preserve-order")]662 preserve_order,673 preserve_order,663 } => self.to_json(674 } => self.to_json(675 s,664 *padding,676 *padding,665 #[cfg(feature = "exp-preserve-order")]677 #[cfg(feature = "exp-preserve-order")]666 *preserve_order,678 *preserve_order,667 )?,679 )?,668 ManifestFormat::ToString => self.to_string()?,680 ManifestFormat::ToString => self.to_string(s)?,669 ManifestFormat::String => match self {681 ManifestFormat::String => match self {670 Self::Str(s) => s.clone(),682 Self::Str(s) => s.clone(),671 _ => throw!(StringManifestOutputIsNotAString),683 _ => throw!(StringManifestOutputIsNotAString),676 /// For manifestification688 /// For manifestification677 pub fn to_json(689 pub fn to_json(678 &self,690 &self,691 s: State,679 padding: usize,692 padding: usize,680 #[cfg(feature = "exp-preserve-order")] preserve_order: bool,693 #[cfg(feature = "exp-preserve-order")] preserve_order: bool,681 ) -> Result<IStr> {694 ) -> Result<IStr> {682 manifest_json_ex(695 manifest_json_ex(696 s,683 self,697 self,684 &ManifestJsonOptions {698 &ManifestJsonOptions {685 padding: &" ".repeat(padding),699 padding: &" ".repeat(padding),700 /// Calls `std.manifestJson`714 /// Calls `std.manifestJson`701 pub fn to_std_json(715 pub fn to_std_json(702 &self,716 &self,717 s: State,703 padding: usize,718 padding: usize,704 #[cfg(feature = "exp-preserve-order")] preserve_order: bool,719 #[cfg(feature = "exp-preserve-order")] preserve_order: bool,705 ) -> Result<Rc<str>> {720 ) -> Result<Rc<str>> {706 manifest_json_ex(721 manifest_json_ex(722 s,707 self,723 self,708 &ManifestJsonOptions {724 &ManifestJsonOptions {709 padding: &" ".repeat(padding),725 padding: &" ".repeat(padding),719735720 pub fn to_yaml(736 pub fn to_yaml(721 &self,737 &self,738 s: State,722 padding: usize,739 padding: usize,723 #[cfg(feature = "exp-preserve-order")] preserve_order: bool,740 #[cfg(feature = "exp-preserve-order")] preserve_order: bool,724 ) -> Result<IStr> {741 ) -> Result<IStr> {725 let padding = &" ".repeat(padding);742 let padding = &" ".repeat(padding);726 manifest_yaml_ex(743 manifest_yaml_ex(744 s,727 self,745 self,728 &ManifestYamlOptions {746 &ManifestYamlOptions {729 padding,747 padding,769}787}770788771/// Native implementation of `std.equals`789/// Native implementation of `std.equals`772pub fn equals(val_a: &Val, val_b: &Val) -> Result<bool> {790pub fn equals(s: State, val_a: &Val, val_b: &Val) -> Result<bool> {773 if val_a.value_type() != val_b.value_type() {791 if val_a.value_type() != val_b.value_type() {774 return Ok(false);792 return Ok(false);775 }793 }781 if a.len() != b.len() {799 if a.len() != b.len() {782 return Ok(false);800 return Ok(false);783 }801 }784 for (a, b) in a.iter().zip(b.iter()) {802 for (a, b) in a.iter(s.clone()).zip(b.iter(s.clone())) {785 if !equals(&a?, &b?)? {803 if !equals(s.clone(), &a?, &b?)? {786 return Ok(false);804 return Ok(false);787 }805 }788 }806 }805 }823 }806 for field in fields {824 for field in fields {807 if !equals(&a.get(field.clone())?.unwrap(), &b.get(field)?.unwrap())? {825 if !equals(826 s.clone(),827 &a.get(s.clone(), field.clone())?.unwrap(),828 &b.get(s.clone(), field)?.unwrap(),829 )? {808 return Ok(false);830 return Ok(false);809 }831 }crates/jrsonnet-macros/src/lib.rsdiffbeforeafterboth129 is_option: bool,129 is_option: bool,130 name: String,130 name: String,131 },131 },132 State,132 Location,133 Location,133 This,134 This,134}135}144 _ => return Err(Error::new(arg.pat.span(), "arg should be plain identifier")),145 _ => return Err(Error::new(arg.pat.span(), "arg should be plain identifier")),145 };146 };146 let ty = &arg.ty;147 let ty = &arg.ty;148 if type_is_path(ty, "State").is_some() {149 return Ok(Self::State);147 if type_is_path(ty, "CallLocation").is_some() {150 } else if type_is_path(ty, "CallLocation").is_some() {148 return Ok(Self::Location);151 return Ok(Self::Location);149 } else if type_is_path(ty, "Self").is_some() {152 } else if type_is_path(ty, "Self").is_some() {150 return Ok(Self::This);153 return Ok(Self::This);208 }211 }209 ReturnType::Type(_, ref ty) => ty.clone(),212 ReturnType::Type(_, ref ty) => ty.clone(),210 };213 };214 let result_inner = if let Some(args) = type_is_path(&result, "Result") {215 let generic_arg = match args {216 PathArguments::AngleBracketed(params) => params.args.iter().next().unwrap(),217 _ => return Err(Error::new(args.span(), "missing result generic")),218 };219 // This argument must be a type:220 match generic_arg {221 GenericArgument::Type(ty) => ty,222 _ => {223 return Err(Error::new(224 generic_arg.span(),225 "option generic should be a type",226 ))227 }228 }229 } else {230 return Err(Error::new(result.span(), "return value should be result"));231 };211232212 let args = fun233 let args = fun213 .sig234 .sig235 has_default: #is_option,256 has_default: #is_option,236 },257 },237 }),258 }),259 ArgInfo::State => None,238 ArgInfo::Location => None,260 ArgInfo::Location => None,239 ArgInfo::This => None,261 ArgInfo::This => None,240 });262 });246 name,268 name,247 cfg_attrs,269 cfg_attrs,248 } => {270 } => {249 let eval = quote! {::jrsonnet_evaluator::push_description_frame(271 let eval = quote! {s.push_description(250 || format!("argument <{}> evaluation", #name),272 || format!("argument <{}> evaluation", #name),251 || <#ty>::try_from(value.evaluate()?),273 || <#ty>::from_untyped(value.evaluate(s.clone())?, s.clone()),252 )?};274 )?};253 let value = if *is_option {275 let value = if *is_option {254 quote! {if let Some(value) = parsed.get(#name) {276 quote! {if let Some(value) = parsed.get(#name) {280 }302 }281 }303 }282 }304 }305 ArgInfo::State => quote! {s.clone(),},283 ArgInfo::Location => quote! {location,},306 ArgInfo::Location => quote! {location,},284 ArgInfo::This => quote! {self,},307 ArgInfo::This => quote! {self,},285 });308 });320 }343 }321 const _: () = {344 const _: () = {322 use ::jrsonnet_evaluator::{345 use ::jrsonnet_evaluator::{346 State,323 function::{Builtin, CallLocation, StaticBuiltin, BuiltinParam, ArgsLike, parse_builtin_call},347 function::{Builtin, CallLocation, StaticBuiltin, BuiltinParam, ArgsLike, parse_builtin_call},324 error::Result, Context,348 error::Result, Context,325 parser::ExprLocation,349 parser::ExprLocation,339 fn params(&self) -> &[BuiltinParam] {363 fn params(&self) -> &[BuiltinParam] {340 PARAMS364 PARAMS341 }365 }342 fn call(&self, context: Context, location: CallLocation, args: &dyn ArgsLike) -> Result<Val> {366 fn call(&self, s: State, ctx: Context, location: CallLocation, args: &dyn ArgsLike) -> Result<Val> {343 let parsed = parse_builtin_call(context, &PARAMS, args, false)?;367 let parsed = parse_builtin_call(s.clone(), ctx, &PARAMS, args, false)?;344368345 let result: #result = #name(#(#pass)*);369 let result: #result = #name(#(#pass)*);346 let result = result?;370 let result = result?;347 result.try_into()371 <#result_inner>::into_untyped(result, s)348 }372 }349 }373 }350 };374 };540 impl Typed for #ident {564 impl Typed for #ident {541 const TYPE: &'static ComplexValType = &ComplexValType::ObjectRef(&ITEMS);565 const TYPE: &'static ComplexValType = &ComplexValType::ObjectRef(&ITEMS);566567 fn from_untyped(value: Val, s: State) -> Result<Self> {568 let obj = value.as_obj().expect("shape is correct");569 Self::parse(&obj)570 }571572 fn into_untyped(value: Self, s: State) -> Result<Val> {573 let mut out = ObjValueBuilder::new();574 value.serialize(&mut out)?;575 Ok(Val::Obj(out.build()))576 }577542 }578 }543 }579 }570 }606 }571 }607 }572573 impl TryFrom<Val> for #ident {574 type Error = LocError;575 fn try_from(value: Val) -> Result<Self, Self::Error> {576 let obj = value.as_obj().expect("shape is correct");577 Self::parse(&obj)578 }579 }580 impl TryInto<Val> for #ident {581 type Error = LocError;582 fn try_into(self) -> Result<Val, Self::Error> {583 let mut out = ObjValueBuilder::new();584 self.serialize(&mut out)?;585 Ok(Val::Obj(out.build()))586 }587 }588 ()589 };608 };590 })609 })591}610}