difftreelog
feat --exp-apply argument
in: master
3 files changed
cmds/jrsonnet/Cargo.tomldiffbeforeafterboth--- a/cmds/jrsonnet/Cargo.toml
+++ b/cmds/jrsonnet/Cargo.toml
@@ -8,7 +8,7 @@
edition = "2021"
[features]
-experimental = ["exp-preserve-order", "exp-destruct"]
+experimental = ["exp-preserve-order", "exp-destruct", "exp-null-coaelse", "exp-object-iteration", "exp-bigint", "exp-apply"]
# Use mimalloc as allocator
mimalloc = ["mimallocator"]
# Experimental feature, which allows to preserve order of object fields
@@ -22,6 +22,10 @@
exp-object-iteration = ["jrsonnet-evaluator/exp-object-iteration"]
# Bigint type
exp-bigint = ["jrsonnet-evaluator/exp-bigint", "jrsonnet-cli/exp-bigint"]
+# obj?.field, obj?.['field']
+exp-null-coaelse = ["jrsonnet-evaluator/exp-null-coaelse", "jrsonnet-parser/exp-null-coaelse"]
+# --exp-apply
+exp-apply = []
# std.thisFile support
legacy-this-file = ["jrsonnet-cli/legacy-this-file"]
cmds/jrsonnet/src/main.rsdiffbeforeafterboth--- a/cmds/jrsonnet/src/main.rs
+++ b/cmds/jrsonnet/src/main.rs
@@ -43,6 +43,12 @@
/// Path to the file to be compiled if `--evaluate` is unset, otherwise code itself
pub input: Option<String>,
+
+ /// After executing input, apply specified code.
+ /// Output of the initial input will be accessible using `$`
+ #[cfg(feature = "exp-apply")]
+ #[clap(long)]
+ pub exp_apply: Vec<String>,
}
/// Jsonnet commandline interpreter (Rust implementation)
@@ -181,7 +187,18 @@
};
let tla = opts.tla.tla_opts()?;
- let val = apply_tla(s.clone(), &tla, val)?;
+ #[allow(unused_mut)]
+ let mut val = apply_tla(s.clone(), &tla, val)?;
+
+ #[cfg(feature = "exp-apply")]
+ for apply in opts.input.exp_apply {
+ use jrsonnet_evaluator::{InitialUnderscore, Thunk};
+ val = s.evaluate_snippet_with(
+ "<exp_apply>".to_owned(),
+ &apply,
+ InitialUnderscore(Thunk::evaluated(val)),
+ )?;
+ }
let manifest_format = opts.manifest.manifest_format();
if let Some(multi) = opts.output.multi {
crates/jrsonnet-evaluator/src/lib.rsdiffbeforeafterboth154 }154 }155}155}156157macro_rules! impl_context_initializer {158 ($($gen:ident)*) => {159 #[allow(non_snake_case)]160 impl<$($gen: ContextInitializer + Trace,)*> ContextInitializer for ($($gen,)*) {161 fn reserve_vars(&self) -> usize {162 let mut out = 0;163 let ($($gen,)*) = self;164 $(out += $gen.reserve_vars();)*165 out166 }167 fn populate(&self, for_file: Source, builder: &mut ContextBuilder) {168 let ($($gen,)*) = self;169 $($gen.populate(for_file.clone(), builder);)*170 }171 fn as_any(&self) -> &dyn Any {172 self173 }174 }175 };176 ($($cur:ident)* @ $c:ident $($rest:ident)*) => {177 impl_context_initializer!($($cur)*);178 impl_context_initializer!($($cur)* $c @ $($rest)*);179 };180 ($($cur:ident)* @) => {181 impl_context_initializer!($($cur)*);182 }183}184impl_context_initializer! {185 A B @ C D E186}156187157/// Dynamically reconfigurable evaluation settings188/// Dynamically reconfigurable evaluation settings158#[derive(Trace)]189#[derive(Trace)]361 context_initializer.initialize(self.clone(), source)392 context_initializer.initialize(self.clone(), source)362 }393 }394395 /// Creates context with all passed global variables, calling custom modifier396 pub fn create_default_context_with(397 &self,398 source: Source,399 context_initializer: impl ContextInitializer,400 ) -> Context {401 let default_initializer = &self.settings().context_initializer;402 let mut builder = ContextBuilder::with_capacity(403 self.clone(),404 default_initializer.reserve_vars() + context_initializer.reserve_vars(),405 );406 default_initializer.populate(source.clone(), &mut builder);407 context_initializer.populate(source, &mut builder);408409 builder.build()410 }363411364 /// Executes code creating a new stack frame412 /// Executes code creating a new stack frame365 pub fn push<T>(413 pub fn push<T>(428 }476 }429 let mut settings = self.settings_mut();477 let mut settings = self.settings_mut();430 let initializer = &mut settings.context_initializer;478 let initializer = &mut settings.context_initializer;431 match initializer.as_any().downcast_ref::<GlobalsCtx>() {479 if let Some(global) = initializer.as_any().downcast_ref::<GlobalsCtx>() {432 Some(glob) => {480 global.globals.borrow_mut().insert(name, value);433 glob.globals.borrow_mut().insert(name, value);434 }481 } else {435 None => {436 let inner = std::mem::replace(&mut settings.context_initializer, tb!(()));482 let inner = std::mem::replace(&mut settings.context_initializer, tb!(()));437 settings.context_initializer = tb!(GlobalsCtx {483 settings.context_initializer = tb!(GlobalsCtx {438 globals: {484 globals: {441 RefCell::new(out)487 RefCell::new(out)442 },488 },443 inner489 inner444 })490 });445 }491 }446 }447 }492 }448}493}494495#[derive(Trace)]496pub struct InitialUnderscore(pub Thunk<Val>);497impl ContextInitializer for InitialUnderscore {498 fn populate(&self, _for_file: Source, builder: &mut ContextBuilder) {499 builder.bind("_".into(), self.0.clone());500 }501502 fn as_any(&self) -> &dyn Any {503 self504 }505}449506450/// Raw methods evaluate passed values but don't perform TLA execution507/// Raw methods evaluate passed values but don't perform TLA execution451impl State {508impl State {465 })?;522 })?;466 evaluate(self.create_default_context(source), &parsed)523 evaluate(self.create_default_context(source), &parsed)467 }524 }525 /// Parses and evaluates the given snippet with custom context modifier526 pub fn evaluate_snippet_with(527 &self,528 name: impl Into<IStr>,529 code: impl Into<IStr>,530 context_initializer: impl ContextInitializer,531 ) -> Result<Val> {532 let code = code.into();533 let source = Source::new_virtual(name.into(), code.clone());534 let parsed = jrsonnet_parser::parse(535 &code,536 &ParserSettings {537 source: source.clone(),538 },539 )540 .map_err(|e| ImportSyntaxError {541 path: source.clone(),542 error: Box::new(e),543 })?;544 evaluate(545 self.create_default_context_with(source, context_initializer),546 &parsed,547 )548 }468}549}469550470/// Settings utilities551/// Settings utilities