git.delta.rocks / jrsonnet / refs/commits / 76f0cfd3dd2f

difftreelog

feat --exp-apply argument

Yaroslav Bolyukin2023-07-26parent: #0f5ef44.patch.diff
in: master

3 files changed

modifiedcmds/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"]
modifiedcmds/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 {
modifiedcrates/jrsonnet-evaluator/src/lib.rsdiffbeforeafterboth
154 }154 }
155}155}
156
157macro_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 out
166 }
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 self
173 }
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 E
186}
156187
157/// Dynamically reconfigurable evaluation settings188/// Dynamically reconfigurable evaluation settings
158#[derive(Trace)]189#[derive(Trace)]
361 context_initializer.initialize(self.clone(), source)392 context_initializer.initialize(self.clone(), source)
362 }393 }
394
395 /// Creates context with all passed global variables, calling custom modifier
396 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);
408
409 builder.build()
410 }
363411
364 /// Executes code creating a new stack frame412 /// Executes code creating a new stack frame
365 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 inner
444 })490 });
445 }491 }
446 }
447 }492 }
448}493}
494
495#[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 }
501
502 fn as_any(&self) -> &dyn Any {
503 self
504 }
505}
449506
450/// Raw methods evaluate passed values but don't perform TLA execution507/// Raw methods evaluate passed values but don't perform TLA execution
451impl 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 modifier
526 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}
469550
470/// Settings utilities551/// Settings utilities