difftreelog
feat --exp-apply argument
in: master
3 files changed
cmds/jrsonnet/Cargo.tomldiffbeforeafterboth1[package]2name = "jrsonnet"3description = "Rust jsonnet implementation"4version.workspace = true5repository.workspace = true6authors = ["Yaroslav Bolyukin <iam@lach.pw>"]7license = "MIT"8edition = "2021"910[features]11experimental = ["exp-preserve-order", "exp-destruct"]12# Use mimalloc as allocator13mimalloc = ["mimallocator"]14# Experimental feature, which allows to preserve order of object fields15exp-preserve-order = [16 "jrsonnet-evaluator/exp-preserve-order",17 "jrsonnet-cli/exp-preserve-order",18]19# Destructuring of locals20exp-destruct = ["jrsonnet-evaluator/exp-destruct"]21# Iteration over objects yields [key, value] elements22exp-object-iteration = ["jrsonnet-evaluator/exp-object-iteration"]23# Bigint type24exp-bigint = ["jrsonnet-evaluator/exp-bigint", "jrsonnet-cli/exp-bigint"]2526# std.thisFile support27legacy-this-file = ["jrsonnet-cli/legacy-this-file"]2829nightly = ["jrsonnet-evaluator/nightly"]3031[dependencies]32jrsonnet-evaluator.workspace = true33jrsonnet-parser.workspace = true34jrsonnet-cli.workspace = true35jrsonnet-gcmodule.workspace = true3637mimallocator = { version = "0.1.3", optional = true }38thiserror = "1.0"39clap = { version = "4.1", features = ["derive"] }40clap_complete = { version = "4.1" }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.rsdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/lib.rs
+++ b/crates/jrsonnet-evaluator/src/lib.rs
@@ -154,6 +154,37 @@
}
}
+macro_rules! impl_context_initializer {
+ ($($gen:ident)*) => {
+ #[allow(non_snake_case)]
+ impl<$($gen: ContextInitializer + Trace,)*> ContextInitializer for ($($gen,)*) {
+ fn reserve_vars(&self) -> usize {
+ let mut out = 0;
+ let ($($gen,)*) = self;
+ $(out += $gen.reserve_vars();)*
+ out
+ }
+ fn populate(&self, for_file: Source, builder: &mut ContextBuilder) {
+ let ($($gen,)*) = self;
+ $($gen.populate(for_file.clone(), builder);)*
+ }
+ fn as_any(&self) -> &dyn Any {
+ self
+ }
+ }
+ };
+ ($($cur:ident)* @ $c:ident $($rest:ident)*) => {
+ impl_context_initializer!($($cur)*);
+ impl_context_initializer!($($cur)* $c @ $($rest)*);
+ };
+ ($($cur:ident)* @) => {
+ impl_context_initializer!($($cur)*);
+ }
+}
+impl_context_initializer! {
+ A B @ C D E
+}
+
/// Dynamically reconfigurable evaluation settings
#[derive(Trace)]
pub struct EvaluationSettings {
@@ -361,6 +392,23 @@
context_initializer.initialize(self.clone(), source)
}
+ /// Creates context with all passed global variables, calling custom modifier
+ pub fn create_default_context_with(
+ &self,
+ source: Source,
+ context_initializer: impl ContextInitializer,
+ ) -> Context {
+ let default_initializer = &self.settings().context_initializer;
+ let mut builder = ContextBuilder::with_capacity(
+ self.clone(),
+ default_initializer.reserve_vars() + context_initializer.reserve_vars(),
+ );
+ default_initializer.populate(source.clone(), &mut builder);
+ context_initializer.populate(source, &mut builder);
+
+ builder.build()
+ }
+
/// Executes code creating a new stack frame
pub fn push<T>(
e: CallLocation<'_>,
@@ -428,25 +476,34 @@
}
let mut settings = self.settings_mut();
let initializer = &mut settings.context_initializer;
- match initializer.as_any().downcast_ref::<GlobalsCtx>() {
- Some(glob) => {
- glob.globals.borrow_mut().insert(name, value);
- }
- None => {
- let inner = std::mem::replace(&mut settings.context_initializer, tb!(()));
- settings.context_initializer = tb!(GlobalsCtx {
- globals: {
- let mut out = GcHashMap::with_capacity(1);
- out.insert(name, value);
- RefCell::new(out)
- },
- inner
- })
- }
+ if let Some(global) = initializer.as_any().downcast_ref::<GlobalsCtx>() {
+ global.globals.borrow_mut().insert(name, value);
+ } else {
+ let inner = std::mem::replace(&mut settings.context_initializer, tb!(()));
+ settings.context_initializer = tb!(GlobalsCtx {
+ globals: {
+ let mut out = GcHashMap::with_capacity(1);
+ out.insert(name, value);
+ RefCell::new(out)
+ },
+ inner
+ });
}
}
}
+#[derive(Trace)]
+pub struct InitialUnderscore(pub Thunk<Val>);
+impl ContextInitializer for InitialUnderscore {
+ fn populate(&self, _for_file: Source, builder: &mut ContextBuilder) {
+ builder.bind("_".into(), self.0.clone());
+ }
+
+ fn as_any(&self) -> &dyn Any {
+ self
+ }
+}
+
/// Raw methods evaluate passed values but don't perform TLA execution
impl State {
/// Parses and evaluates the given snippet
@@ -465,6 +522,30 @@
})?;
evaluate(self.create_default_context(source), &parsed)
}
+ /// Parses and evaluates the given snippet with custom context modifier
+ pub fn evaluate_snippet_with(
+ &self,
+ name: impl Into<IStr>,
+ code: impl Into<IStr>,
+ context_initializer: impl ContextInitializer,
+ ) -> Result<Val> {
+ let code = code.into();
+ let source = Source::new_virtual(name.into(), code.clone());
+ let parsed = jrsonnet_parser::parse(
+ &code,
+ &ParserSettings {
+ source: source.clone(),
+ },
+ )
+ .map_err(|e| ImportSyntaxError {
+ path: source.clone(),
+ error: Box::new(e),
+ })?;
+ evaluate(
+ self.create_default_context_with(source, context_initializer),
+ &parsed,
+ )
+ }
}
/// Settings utilities