git.delta.rocks / jrsonnet / refs/commits / a486673b143e

difftreelog

refactor unified ContextBuilder

lzpkwkksYaroslav Bolyukin2026-04-25parent: #edb8e7e.patch.diff
in: master

17 files changed

modifiedCargo.lockdiffbeforeafterboth
699 "bitmaps",699 "bitmaps",
700 "rand_core 0.6.4",700 "rand_core 0.6.4",
701 "rand_xoshiro",701 "rand_xoshiro",
702 "refpool",
702 "sized-chunks",703 "sized-chunks",
703 "typenum",704 "typenum",
704 "version_check",705 "version_check",
861862
862[[package]]863[[package]]
863name = "jrsonnet-gcmodule"864name = "jrsonnet-gcmodule"
864version = "0.4.3"865version = "0.4.4"
865source = "registry+https://github.com/rust-lang/crates.io-index"866source = "registry+https://github.com/rust-lang/crates.io-index"
866checksum = "8a6a63a6e55ba82764e483d7f8a181f25db95a8f25da8ae6520e95a5fe39c6a6"867checksum = "21dd97b40cbfb2043094219f95d96519858ba1aee4e8260eb048a1774832a517"
867dependencies = [868dependencies = [
868 "im-rc",869 "im-rc",
869 "jrsonnet-gcmodule-derive",870 "jrsonnet-gcmodule-derive",
870]871]
871872
872[[package]]873[[package]]
873name = "jrsonnet-gcmodule-derive"874name = "jrsonnet-gcmodule-derive"
874version = "0.4.3"875version = "0.4.4"
875source = "registry+https://github.com/rust-lang/crates.io-index"876source = "registry+https://github.com/rust-lang/crates.io-index"
876checksum = "095fe3c4c0acf32de80205a8a479ef63c216b9efb0024dec9eb7fe1c5ef1f1a1"877checksum = "ede3d0445c2a7d7adab0a3cc33bdb33df78ffebebc21a2848c221526cb1795d4"
877dependencies = [878dependencies = [
878 "proc-macro2",879 "proc-macro2",
879 "quote",880 "quote",
1419 "crossbeam-utils",1420 "crossbeam-utils",
1420]1421]
1422
1423[[package]]
1424name = "refpool"
1425version = "0.4.3"
1426source = "registry+https://github.com/rust-lang/crates.io-index"
1427checksum = "369e86b80fa7dc8c561dd9613a5bf25c59d2d3073cd66c47fd9e39802f0ecb58"
14211428
1422[[package]]1429[[package]]
1423name = "regex"1430name = "regex"
1633checksum = "16d69225bde7a69b235da73377861095455d298f2b970996eec25ddbb42b3d1e"1640checksum = "16d69225bde7a69b235da73377861095455d298f2b970996eec25ddbb42b3d1e"
1634dependencies = [1641dependencies = [
1635 "bitmaps",1642 "bitmaps",
1643 "refpool",
1636 "typenum",1644 "typenum",
1637]1645]
16381646
1738 "jrsonnet-evaluator",1746 "jrsonnet-evaluator",
1739 "jrsonnet-gcmodule",1747 "jrsonnet-gcmodule",
1740 "jrsonnet-stdlib",1748 "jrsonnet-stdlib",
1749 "mimallocator",
1741 "serde",1750 "serde",
1742 "serde_json",1751 "serde_json",
1743]1752]
modifiedCargo.tomldiffbeforeafterboth
22jrsonnet-cli = { path = "./crates/jrsonnet-cli", version = "0.5.0-pre98" }22jrsonnet-cli = { path = "./crates/jrsonnet-cli", version = "0.5.0-pre98" }
23jrsonnet-types = { path = "./crates/jrsonnet-types", version = "0.5.0-pre98" }23jrsonnet-types = { path = "./crates/jrsonnet-types", version = "0.5.0-pre98" }
24jrsonnet-formatter = { path = "./crates/jrsonnet-formatter", version = "0.5.0-pre98" }24jrsonnet-formatter = { path = "./crates/jrsonnet-formatter", version = "0.5.0-pre98" }
25jrsonnet-gcmodule = { version = "0.4.3", features = ["im-rc"] }25jrsonnet-gcmodule = { version = "0.4.4", features = ["im-rc"] }
26# Diagnostics.26# Diagnostics.
27# hi-doc is my library, which handles text formatting very well, but isn't polished enough yet27# hi-doc is my library, which handles text formatting very well, but isn't polished enough yet
28# Previous implementation was based on annotate-snippets, which I don't like for many reasons.28# Previous implementation was based on annotate-snippets, which I don't like for many reasons.
modifiedcmds/jrsonnet/src/main.rsdiffbeforeafterboth
200 val = s.evaluate_snippet_with(200 val = s.evaluate_snippet_with(
201 "<exp_apply>".to_owned(),201 "<exp_apply>".to_owned(),
202 &apply,202 &apply,
203 InitialUnderscore(Thunk::evaluated(val)),203 &InitialUnderscore(Thunk::evaluated(val)),
204 )?;204 )?;
205 }205 }
206206
modifiedcrates/jrsonnet-evaluator/Cargo.tomldiffbeforeafterboth
76 "Hash",76 "Hash",
77 "PartialEq",77 "PartialEq",
78] }78] }
79im-rc = "15.1.0"79im-rc = { version = "15.1.0", features = ["pool"] }
8080
81[build-dependencies]81[build-dependencies]
82rustversion = "1.0.22"82rustversion = "1.0.22"
modifiedcrates/jrsonnet-evaluator/src/ctx.rsdiffbeforeafterboth
3use educe::Educe;3use educe::Educe;
4use jrsonnet_gcmodule::{Cc, Trace};4use jrsonnet_gcmodule::{Cc, Trace};
5use jrsonnet_interner::IStr;5use jrsonnet_interner::IStr;
6use rustc_hash::FxHashMap;6use rustc_hash::{FxHashMap, FxHashSet};
77
8use crate::{8use crate::{
9 ObjValue, Pending, Result, SupThis, Thunk, Val, error::ErrorKind::*, gc::WithCapacityExt as _,9 ObjValue, Pending, Result, SupThis, Thunk, Val, bail, error::ErrorKind::*,
10 map::LayeredHashMap,10 gc::WithCapacityExt as _,
11};11};
12/// Context keeps information about current lexical code location12/// Context keeps information about current lexical code location
13///13///
20struct ContextInternal {20struct ContextInternal {
21 dollar: Option<ObjValue>,21 dollar: Option<ObjValue>,
22 sup_this: Option<SupThis>,22 sup_this: Option<SupThis>,
23 bindings: LayeredHashMap,23 bindings: FxHashMap<IStr, Thunk<Val>>,
24
25 branch_point: Option<Context>,
24}26}
25impl Context {27impl Context {
26 pub fn new_future() -> Pending<Self> {28 pub fn new_future() -> Pending<Self> {
71 return Ok(val);73 return Ok(val);
72 }74 }
75
76 if let Some(branch_point) = &self.0.branch_point {
77 return branch_point.binding(name);
78 }
7379
74 let mut heap = Vec::new();80 let mut heap = Vec::new();
75 self.0.bindings.clone().iter_keys(|k| {81 for k in self.0.bindings.keys() {
76 let conf = strsim::jaro_winkler(&k as &str, &name as &str);82 let conf = strsim::jaro_winkler(k as &str, &name as &str);
77 if conf < 0.8 {83 if conf < 0.8 {
78 return;84 continue;
79 }85 }
80 heap.push((conf, k));86 heap.push((conf, k.clone()));
81 });87 }
82 heap.sort_by(|a, b| b.0.partial_cmp(&a.0).unwrap_or(Ordering::Equal));88 heap.sort_by(|a, b| b.0.partial_cmp(&a.0).unwrap_or(Ordering::Equal));
8389
84 bail!(VariableIsNotDefined(90 bail!(VariableIsNotDefined(
97 ctx.unwrap()103 ctx.unwrap()
98 }104 }
99
100 #[must_use]
101 pub fn with_var(self, name: impl Into<IStr>, value: Val) -> Self {
102 let mut new_bindings = FxHashMap::with_capacity(1);
103 new_bindings.insert(name.into(), Thunk::evaluated(value));
104 self.extend_bindings(new_bindings)
105 }
106105
107 #[must_use]106 #[must_use]
108 pub fn extend_bindings_sup_this(107 pub fn branch_point(self) -> Self {
109 self,
110 new_bindings: FxHashMap<IStr, Thunk<Val>>,
111 sup_this: SupThis,
112 ) -> Self {
113 let ctx = &self;
114 let dollar = ctx
115 .0
116 .dollar
117 .clone()
118 .or_else(|| Some(sup_this.this().clone()));
119 let bindings = if new_bindings.is_empty() {108 if self.0.bindings.is_empty() {
120 ctx.0.bindings.clone()109 self
121 } else {110 } else {
122 ctx.0.bindings.clone().extend(new_bindings)111 ContextBuilder::extend(self).build()
123 };112 }
124 Self(Cc::new(ContextInternal {
125 dollar,
126 sup_this: Some(sup_this),
127 bindings,
128 }))
129 }113 }
130 #[must_use]
131 pub fn extend_bindings(self, new_bindings: FxHashMap<IStr, Thunk<Val>>) -> Self {
132 if new_bindings.is_empty() {
133 return self;
134 }
135 let ctx = &self;
136 let bindings = if new_bindings.is_empty() {
137 ctx.0.bindings.clone()
138 } else {
139 ctx.0.bindings.clone().extend(new_bindings)
140 };
141 Self(Cc::new(ContextInternal {
142 dollar: ctx.0.dollar.clone(),
143 sup_this: ctx.0.sup_this.clone(),
144 bindings,
145 }))
146 }
147}114}
148115
149#[derive(Default)]116#[derive(Clone)]
150pub struct ContextBuilder {117pub struct ContextBuilder {
118 dollar: Option<ObjValue>,
119 sup_this: Option<SupThis>,
151 bindings: FxHashMap<IStr, Thunk<Val>>,120 bindings: FxHashMap<IStr, Thunk<Val>>,
121 filled: FxHashSet<IStr>,
152 extend: Option<Context>,122 branch_point: Option<Context>,
153}123}
154124
155impl ContextBuilder {125impl ContextBuilder {
156 pub fn new() -> Self {126 pub fn new() -> Self {
157 Self::with_capacity(0)127 Self {
128 dollar: None,
129 sup_this: None,
130 bindings: FxHashMap::new(),
131 filled: FxHashSet::new(),
132 branch_point: None,
133 }
158 }134 }
159135
160 pub fn with_capacity(capacity: usize) -> Self {136 pub fn extend_fast(parent: Context) -> Self {
161 Self {137 Self {
138 dollar: parent.0.dollar.clone(),
139 sup_this: parent.0.sup_this.clone(),
162 bindings: FxHashMap::with_capacity(capacity),140 bindings: parent.0.bindings.clone(),
163 extend: None,141 filled: FxHashSet::new(),
142 branch_point: parent.0.branch_point.clone(),
164 }143 }
165 }144 }
166145
167 pub fn extend(parent: Context) -> Self {146 pub fn extend(parent: Context) -> Self {
168 Self {147 Self {
148 dollar: parent.0.dollar.clone(),
149 sup_this: parent.0.sup_this.clone(),
169 bindings: FxHashMap::new(),150 bindings: FxHashMap::new(),
151 filled: FxHashSet::new(),
170 extend: Some(parent),152 branch_point: Some(parent.clone()),
171 }153 }
172 }154 }
173155
174 /// # Panics
175 ///
176 /// If `name` is already bound. Makes no sense to bind same local multiple times,
177 /// unless it is separate context layers.
178 pub fn bind(&mut self, name: impl Into<IStr>, value: Thunk<Val>) -> &mut Self {156 pub fn bind(&mut self, name: impl Into<IStr>, value: Thunk<Val>) {
179 let old = self.bindings.insert(name.into(), value);157 let _ = self.bindings.insert(name.into(), value);
180 assert!(old.is_none(), "variable bound twice in single context call");
181 self
182 }158 }
159 /// After commit, binds would shadow the previous declarations
160 #[must_use]
161 pub fn commit(mut self) -> Self {
162 self.filled.clear();
163 self
164 }
183 pub fn binds(&mut self, bindings: FxHashMap<IStr, Thunk<Val>>) -> &mut Self {165 pub fn try_bind(&mut self, name: impl Into<IStr>, value: Thunk<Val>) -> Result<()> {
184 for (k, v) in bindings {166 let name = name.into();
167 if !self.filled.insert(name.clone()) {
168 bail!(DuplicateLocalVar(name))
169 }
185 self.bind(k, v);170 self.bind(name, value);
186 }171 Ok(())
187 self
188 }172 }
189 pub fn build(self) -> Context {173 pub fn build(self) -> Context {
190 if let Some(parent) = self.extend {
191 parent.extend_bindings(self.bindings)
192 } else {
193 Context(Cc::new(ContextInternal {174 Context(Cc::new(ContextInternal {
175 dollar: self.dollar,
176 sup_this: self.sup_this,
194 bindings: LayeredHashMap::new(self.bindings),177 bindings: self.bindings,
195 dollar: None,178 branch_point: self.branch_point,
196 sup_this: None,
197 }))179 }))
198 }
199 }180 }
181 pub fn build_sup_this(mut self, st: SupThis) -> Context {
182 if self.dollar.is_none() {
183 self.dollar = Some(st.this().clone());
184 }
185 self.sup_this = Some(st);
186 self.build()
187 }
200}188}
189
190impl Default for ContextBuilder {
191 fn default() -> Self {
192 Self::new()
193 }
194}
201195
modifiedcrates/jrsonnet-evaluator/src/error.rsdiffbeforeafterboth
250#[derive(Clone, Trace)]250#[derive(Clone, Trace)]
251pub struct Error(Box<(ErrorKind, StackTrace)>);251pub struct Error(Box<(ErrorKind, StackTrace)>);
252
253#[cfg(target_pointer_width = "64")]
254static_assertions::assert_eq_size!(Error, usize);
255
252impl Error {256impl Error {
253 pub fn new(e: ErrorKind) -> Self {257 pub fn new(e: ErrorKind) -> Self {
modifiedcrates/jrsonnet-evaluator/src/evaluate/destructure.rsdiffbeforeafterboth
1use std::{collections::HashMap, hash::BuildHasher};
2
3use jrsonnet_interner::IStr;
4use jrsonnet_ir::{BindSpec, Destruct};1use jrsonnet_ir::{BindSpec, Destruct};
52
6#[cfg(feature = "exp-preserve-order")]3#[cfg(feature = "exp-preserve-order")]
7use crate::evaluate;4use crate::evaluate;
8use crate::{5use crate::{
9 Context, Pending, Thunk, Val, bail,6 Context, ContextBuilder, Pending, Thunk, Val, error::Result, evaluate_method,
10 error::{ErrorKind::*, Result},
11 evaluate_method, evaluate_named_param,7 evaluate_named_param,
12};8};
139
14#[allow(clippy::too_many_lines)]10#[allow(clippy::too_many_lines)]
15#[allow(unused_variables)]11#[allow(unused_variables)]
16pub fn destruct<H: BuildHasher>(12pub fn destruct(
17 d: &Destruct,13 d: &Destruct,
18 parent: Thunk<Val>,14 parent: Thunk<Val>,
19 fctx: Pending<Context>,15 fctx: Pending<Context>,
20 new_bindings: &mut HashMap<IStr, Thunk<Val>, H>,16 new_bindings: &mut ContextBuilder,
21) -> Result<()> {17) -> Result<()> {
22 match d {18 match d {
23 Destruct::Full(v) => {19 Destruct::Full(v) => {
24 let old = new_bindings.insert(v.clone(), parent);20 new_bindings.try_bind(v.clone(), parent)?;
25 if old.is_some() {
26 bail!(DuplicateLocalVar(v.clone()))
27 }
28 }21 }
29 #[cfg(feature = "exp-destruct")]22 #[cfg(feature = "exp-destruct")]
30 Destruct::Skip => {}23 Destruct::Skip => {}
187 Ok(())180 Ok(())
188}181}
189182
190pub fn evaluate_dest<H: BuildHasher>(183pub fn evaluate_dest(
191 d: &BindSpec,184 d: &BindSpec,
192 fctx: Pending<Context>,185 fctx: Pending<Context>,
193 new_bindings: &mut HashMap<IStr, Thunk<Val>, H>,186 new_bindings: &mut ContextBuilder,
194) -> Result<()> {187) -> Result<()> {
195 match d {188 match d {
196 BindSpec::Field { into, value } => {189 BindSpec::Field { into, value } => {
210 let params = params.clone();203 let params = params.clone();
211 let name = name.clone();204 let name = name.clone();
212 let value = value.clone();205 let value = value.clone();
213 let old = new_bindings.insert(name.clone(), {206 new_bindings.try_bind(
214 let name = name.clone();207 name.clone(),
215 Thunk!(move || Ok(evaluate_method(fctx.unwrap(), name, params, value)))208 Thunk!(move || Ok(evaluate_method(fctx.unwrap(), name, params, value))),
216 });209 )?;
217 if old.is_some() {
218 bail!(DuplicateLocalVar(name))
219 }
220 }210 }
221 }211 }
222 Ok(())212 Ok(())
modifiedcrates/jrsonnet-evaluator/src/evaluate/mod.rsdiffbeforeafterboth
8 function::ParamName,8 function::ParamName,
9};9};
10use jrsonnet_types::ValType;10use jrsonnet_types::ValType;
11use rustc_hash::FxHashMap;
1211
13use self::destructure::destruct;12use self::destructure::destruct;
14use crate::{13use crate::{
15 Context, Error, ObjValue, ObjValueBuilder, ObjectAssertion, Pending, Result, ResultExt,14 Context, ContextBuilder, Error, ObjValue, ObjValueBuilder, ObjectAssertion, Pending, Result,
16 SupThis, Unbound, Val,15 ResultExt, SupThis, Unbound, Val,
17 arr::ArrValue,16 arr::ArrValue,
18 bail,17 bail,
19 destructure::evaluate_dest,18 destructure::evaluate_dest,
20 error::{ErrorKind::*, suggest_object_fields},19 error::{ErrorKind::*, suggest_object_fields},
21 evaluate::operator::{evaluate_binary_op_special, evaluate_unary_op},20 evaluate::operator::{evaluate_binary_op_special, evaluate_unary_op},
22 function::{CallLocation, FuncDesc, FuncVal, PreparedFuncVal},21 function::{CallLocation, FuncDesc, FuncVal, PreparedFuncVal},
23 gc::WithCapacityExt as _,
24 in_frame,22 in_frame,
25 typed::{FromUntyped, IntoUntyped as _, Typed},23 typed::{FromUntyped, IntoUntyped as _, Typed},
26 val::{CachedUnbound, IndexableVal, NumValue, StrValue, Thunk},24 val::{CachedUnbound, IndexableVal, NumValue, StrValue, Thunk},
130 guaranteed_reserve = guaranteed_reserve.max(1) * list.len();128 guaranteed_reserve = guaranteed_reserve.max(1) * list.len();
131 for (i, item) in list.iter_lazy().enumerate() {129 for (i, item) in list.iter_lazy().enumerate() {
132 let fctx = Pending::new();130 let fctx = Pending::new();
133 let mut new_bindings = FxHashMap::with_capacity(into.binds_len());131 let mut ctx = ContextBuilder::extend_fast(ctx.clone());
134 destruct(into, item, fctx.clone(), &mut new_bindings)?;132 destruct(into, item, fctx.clone(), &mut ctx)?;
135 let ctx = ctx.clone().extend_bindings(new_bindings).into_future(fctx);133 let ctx = ctx.build().into_future(fctx);
136134
137 let specs = &specs[1..];135 let specs = &specs[1..];
138 evaluate_comp(136 evaluate_comp(
179}177}
180178
181fn evaluate_arr_comp(ctx: Context, expr: &Rc<Expr>, comp_specs: &[CompSpec]) -> Result<ArrValue> {179fn evaluate_arr_comp(ctx: Context, expr: &Rc<Expr>, comp_specs: &[CompSpec]) -> Result<ArrValue> {
180 let ctx = ctx.branch_point();
182 'eager: {181 'eager: {
183 let mut out = Vec::new();182 let mut out = Vec::new();
184183
225224
226 fn bind(&self, sup_this: SupThis) -> Result<Context> {225 fn bind(&self, sup_this: SupThis) -> Result<Context> {
227 let fctx = Context::new_future();226 let fctx = Context::new_future();
228 let mut new_bindings =227 let ctx = self.fctx.clone();
229 FxHashMap::with_capacity(self.locals.iter().map(BindSpec::binds_len).sum());228 let mut ctx = ContextBuilder::extend(ctx);
230 for b in self.locals.iter() {229 for b in self.locals.iter() {
231 evaluate_dest(b, fctx.clone(), &mut new_bindings)?;230 evaluate_dest(b, fctx.clone(), &mut ctx)?;
232 }231 }
233
234 let ctx = self.fctx.clone();
235232
236 let ctx = ctx233 let ctx = ctx.build_sup_this(sup_this).into_future(fctx);
237 .extend_bindings_sup_this(new_bindings, sup_this)
238 .into_future(fctx);
239234
240 Ok(ctx)235 Ok(ctx)
332impl Unbound for DirectUnbound {327impl Unbound for DirectUnbound {
333 type Bound = Context;328 type Bound = Context;
334 fn bind(&self, sup_this: SupThis) -> Result<Context> {329 fn bind(&self, sup_this: SupThis) -> Result<Context> {
335 Ok(self330 Ok(ContextBuilder::extend(self.0.clone()).build_sup_this(sup_this))
336 .0
337 .clone()
338 .extend_bindings_sup_this(FxHashMap::new(), sup_this))
339 }331 }
340}332}
341333
409 }401 }
410 let locals = obj.locals.clone();402 let locals = obj.locals.clone();
411 evaluate_comp(ctx, &obj.compspecs, 0, &mut |ctx, reserve| {403 evaluate_comp(
404 ctx.branch_point(),
405 &obj.compspecs,
406 0,
407 &mut |ctx, reserve| {
412 let uctx = evaluate_object_locals(ctx.clone(), locals.clone());408 let uctx = evaluate_object_locals(ctx.clone(), locals.clone());
413 builder.reserve_fields(reserve);409 builder.reserve_fields(reserve);
414410
415 evaluate_field_member(&mut builder, ctx, uctx, &obj.field)411 evaluate_field_member(&mut builder, ctx, uctx, &obj.field)
416 })?;412 },
413 )?;
417414
418 builder.build()415 builder.build()
684 Ok(indexable)681 Ok(indexable)
685 })?,682 })?,
686 LocalExpr(bindings, returned) => {683 LocalExpr(bindings, returned) => {
687 let mut new_bindings: FxHashMap<IStr, Thunk<Val>> =
688 FxHashMap::with_capacity(bindings.iter().map(BindSpec::binds_len).sum());
689 let fctx = Context::new_future();684 let fctx = Context::new_future();
685 let mut ctx = ContextBuilder::extend(ctx);
690 for b in bindings {686 for b in bindings {
691 evaluate_dest(b, fctx.clone(), &mut new_bindings)?;687 evaluate_dest(b, fctx.clone(), &mut ctx)?;
692 }688 }
693 let ctx = ctx.extend_bindings(new_bindings).into_future(fctx);689 let ctx = ctx.build().into_future(fctx);
694 evaluate(ctx, returned)?690 evaluate(ctx, returned)?
695 }691 }
696 Arr(items) => {692 Arr(items) => {
modifiedcrates/jrsonnet-evaluator/src/function/parse.rsdiffbeforeafterboth
1use jrsonnet_ir::ExprParams;1use jrsonnet_ir::ExprParams;
2use rustc_hash::FxHashMap;
32
4use crate::{3use crate::{
5 Context, Thunk,4 Context, ContextBuilder, Thunk,
6 destructure::destruct,5 destructure::destruct,
7 error::{ErrorKind::*, Result},6 error::{ErrorKind::*, Result},
8 evaluate_named_param,7 evaluate_named_param,
9 gc::WithCapacityExt as _,
10};8};
119
12/// Creates Context, which has all argument default values applied10/// Creates Context, which has all argument default values applied
13/// and with unbound values causing error to be returned11/// and with unbound values causing error to be returned
14pub fn parse_default_function_call(body_ctx: Context, params: &ExprParams) -> Result<Context> {12pub fn parse_default_function_call(body_ctx: Context, params: &ExprParams) -> Result<Context> {
15 let fctx = Context::new_future();13 let fctx = Context::new_future();
1614
17 let mut bindings = FxHashMap::with_capacity(params.binds_len());15 let mut ctx = ContextBuilder::extend(body_ctx);
1816
19 for param in params.exprs.iter() {17 for param in params.exprs.iter() {
20 if let Some(v) = &param.default {18 if let Some(v) = &param.default {
27 Thunk!(move || evaluate_named_param(ctx.unwrap(), &value, name))25 Thunk!(move || evaluate_named_param(ctx.unwrap(), &value, name))
28 },26 },
29 fctx.clone(),27 fctx.clone(),
30 &mut bindings,28 &mut ctx,
31 )?;29 )?;
32 } else {30 } else {
33 destruct(31 destruct(
42 .into()))40 .into()))
43 },41 },
44 fctx.clone(),42 fctx.clone(),
45 &mut bindings,43 &mut ctx,
46 )?;44 )?;
47 }45 }
48 }46 }
4947
50 Ok(body_ctx.extend_bindings(bindings).into_future(fctx))48 Ok(ctx.build().into_future(fctx))
51}49}
5250
modifiedcrates/jrsonnet-evaluator/src/function/prepared.rsdiffbeforeafterboth
22
3use jrsonnet_gcmodule::{Acyclic, Trace};3use jrsonnet_gcmodule::{Acyclic, Trace};
4use jrsonnet_ir::{ExprParams, IStr, function::FunctionSignature};4use jrsonnet_ir::{ExprParams, IStr, function::FunctionSignature};
5use rustc_hash::{FxHashMap, FxHashSet};5use rustc_hash::FxHashSet;
66
7use super::{CallLocation, FuncVal};7use super::{CallLocation, FuncVal};
8use crate::{8use crate::{
9 Context, ContextBuilder, Pending, Result, Thunk, Val, bail, destructure::destruct,9 Context, ContextBuilder, Pending, Result, Thunk, Val, bail, destructure::destruct,
10 error::ErrorKind::*, evaluate_named_param, gc::WithCapacityExt,10 error::ErrorKind::*, evaluate_named_param,
11};11};
1212
13#[derive(Debug, Trace, Clone)]13#[derive(Debug, Trace, Clone)]
118 unnamed: &[Thunk<Val>],118 unnamed: &[Thunk<Val>],
119 named: &[Thunk<Val>],119 named: &[Thunk<Val>],
120) -> Result<Context> {120) -> Result<Context> {
121 let mut passed_args = FxHashMap::with_capacity(params.binds_len());121 let mut ctx = ContextBuilder::extend(body_ctx);
122122
123 let destruct_ctx = Pending::new();123 let destruct_ctx = Pending::new();
124124
127 &params.exprs[param_idx].destruct,127 &params.exprs[param_idx].destruct,
128 unnamed.clone(),128 unnamed.clone(),
129 destruct_ctx.clone(),129 destruct_ctx.clone(),
130 &mut passed_args,130 &mut ctx,
131 )?;131 )?;
132 }132 }
133133
136 &params.exprs[param_idx].destruct,136 &params.exprs[param_idx].destruct,
137 named[arg_idx].clone(),137 named[arg_idx].clone(),
138 destruct_ctx.clone(),138 destruct_ctx.clone(),
139 &mut passed_args,139 &mut ctx,
140 )?;140 )?;
141 }141 }
142142
143 if prepared.defaults.is_empty() {143 if prepared.defaults.is_empty() {
144 let body_ctx = body_ctx144 let body_ctx = ctx.build().into_future(destruct_ctx);
145 .extend_bindings(passed_args)
146 .into_future(destruct_ctx);
147 Ok(body_ctx)145 Ok(body_ctx)
148 } else {146 } else {
149 let fctx = Context::new_future();147 let fctx = Context::new_future();
150 let mut defaults = FxHashMap::with_capacity(params.binds_len() - passed_args.len());148 let mut ctx = ctx.commit();
151 for param_idx in prepared.defaults.iter().copied() {149 for param_idx in prepared.defaults.iter().copied() {
152 // let param = params.0.rc_idx(param_idx);150 // let param = params.0.rc_idx(param_idx);
153 destruct(151 destruct(
163 })161 })
164 },162 },
165 fctx.clone(),163 fctx.clone(),
166 &mut defaults,164 &mut ctx,
167 )?;165 )?;
168 }166 }
169167
170 let mut ctx = ContextBuilder::extend(body_ctx);
171 ctx.binds(passed_args);
172 ctx.binds(defaults);
173 Ok(ctx.build().into_future(fctx).into_future(destruct_ctx))168 Ok(ctx.build().into_future(fctx).into_future(destruct_ctx))
174 }169 }
175}170}
modifiedcrates/jrsonnet-evaluator/src/gc.rsdiffbeforeafterboth
3232
33pub fn assert_trace<T: Trace>(_v: &T) {}33pub fn assert_trace<T: Trace>(_v: &T) {}
34
35pub type ImHashMap<K, V> = im_rc::HashMap<K, V, FxBuildHasher>;
3436
modifiedcrates/jrsonnet-evaluator/src/lib.rsdiffbeforeafterboth
15mod import;15mod import;
16mod integrations;16mod integrations;
17pub mod manifest;17pub mod manifest;
18mod map;
19mod obj;18mod obj;
20pub mod stack;19pub mod stack;
21pub mod stdlib;20pub mod stdlib;
162161
163/// During import, this trait will be called to create initial context for file.162/// During import, this trait will be called to create initial context for file.
164/// It may initialize global variables, stdlib for example.163/// It may initialize global variables, stdlib for example.
165pub trait ContextInitializer: Trace {164pub trait ContextInitializer {
166 /// For which size the builder should be preallocated
167 fn reserve_vars(&self) -> usize {
168 0
169 }
170 /// Initialize default file context.
171 /// Has default implementation, which calls `populate`.
172 /// Prefer to always implement `populate` instead.
173 fn initialize(&self, for_file: Source) -> Context {
174 let mut builder = ContextBuilder::with_capacity(self.reserve_vars());
175 self.populate(for_file, &mut builder);
176 builder.build()
177 }
178 /// For composability: extend builder. May panic if this initialization is not supported,165 /// For composability: extend builder. May panic if this initialization is not supported,
179 /// and the context may only be created via `initialize`.166 /// and the context may only be created via `initialize`.
180 fn populate(&self, for_file: Source, builder: &mut ContextBuilder);167 fn populate(&self, for_file: Source, builder: &mut ContextBuilder);
181 /// Allows upcasting from abstract to concrete context initializer.168 /// Allows upcasting from abstract to concrete context initializer.
182 /// jrsonnet by itself doesn't use this method, it is allowed for it to panic.169 /// jrsonnet by itself doesn't use this method, it is allowed for it to panic.
183 fn as_any(&self) -> &dyn Any;170 fn as_any(&self) -> &dyn Any;
184}171}
172impl<T> ContextInitializer for &T
173where
174 T: ContextInitializer,
175{
176 fn populate(&self, for_file: Source, builder: &mut ContextBuilder) {
177 (*self).populate(for_file, builder);
178 }
179
180 fn as_any(&self) -> &dyn Any {
181 (*self).as_any()
182 }
183}
185184
186/// Context initializer which adds nothing.185/// Context initializer which adds nothing.
187impl ContextInitializer for () {186impl ContextInitializer for () {
193192
194impl<T> ContextInitializer for Option<T>193impl<T> ContextInitializer for Option<T>
195where194where
196 T: ContextInitializer,195 T: ContextInitializer + 'static,
197{196{
198 fn initialize(&self, for_file: Source) -> Context {
199 if let Some(ctx) = self {
200 ctx.initialize(for_file)
201 } else {
202 ().initialize(for_file)
203 }
204 }
205
206 fn populate(&self, for_file: Source, builder: &mut ContextBuilder) {197 fn populate(&self, for_file: Source, builder: &mut ContextBuilder) {
207 if let Some(ctx) = self {198 if let Some(ctx) = self {
218 ($($gen:ident)*) => {209 ($($gen:ident)*) => {
219 #[allow(non_snake_case)]210 #[allow(non_snake_case)]
220 impl<$($gen: ContextInitializer + Trace,)*> ContextInitializer for ($($gen,)*) {211 impl<$($gen: ContextInitializer + Trace,)*> ContextInitializer for ($($gen,)*) {
221 fn reserve_vars(&self) -> usize {
222 let mut out = 0;
223 let ($($gen,)*) = self;
224 $(out += $gen.reserve_vars();)*
225 out
226 }
227 fn populate(&self, for_file: Source, builder: &mut ContextBuilder) {212 fn populate(&self, for_file: Source, builder: &mut ContextBuilder) {
228 let ($($gen,)*) = self;213 let ($($gen,)*) = self;
229 $($gen.populate(for_file.clone(), builder);)*214 $($gen.populate(for_file.clone(), builder);)*
453438
454 /// Creates context with all passed global variables439 /// Creates context with all passed global variables
455 pub fn create_default_context(&self, source: Source) -> Context {440 pub fn create_default_context(&self, source: Source) -> Context {
456 self.context_initializer().initialize(source)441 self.create_default_context_with(source, &())
457 }442 }
458443
459 /// Creates context with all passed global variables, calling custom modifier444 /// Creates context with all passed global variables, calling custom modifier
460 pub fn create_default_context_with(445 pub fn create_default_context_with(
461 &self,446 &self,
462 source: Source,447 source: Source,
463 context_initializer: impl ContextInitializer,448 context_initializer: &dyn ContextInitializer,
464 ) -> Context {449 ) -> Context {
465 let default_initializer = self.context_initializer();450 let default_initializer = self.context_initializer();
466 let mut builder = ContextBuilder::with_capacity(451 let mut builder = ContextBuilder::new();
467 default_initializer.reserve_vars() + context_initializer.reserve_vars(),
468 );
469 default_initializer.populate(source.clone(), &mut builder);452 default_initializer.populate(source.clone(), &mut builder);
470 context_initializer.populate(source, &mut builder);453 context_initializer.populate(source, &mut builder);
516impl State {499impl State {
517 /// Parses and evaluates the given snippet500 /// Parses and evaluates the given snippet
518 pub fn evaluate_snippet(&self, name: impl Into<IStr>, code: impl Into<IStr>) -> Result<Val> {501 pub fn evaluate_snippet(&self, name: impl Into<IStr>, code: impl Into<IStr>) -> Result<Val> {
519 let code = code.into();
520 let source = Source::new_virtual(name.into(), code.clone());502 self.evaluate_snippet_with(name, code, &())
521 let parsed = parse_jsonnet(&code, source.clone()).map_err(|e| ImportSyntaxError {
522 path: source.clone(),
523 error: Box::new(e),
524 })?;
525 evaluate(self.create_default_context(source), &parsed)
526 }503 }
527 /// Parses and evaluates the given snippet with custom context modifier504 /// Parses and evaluates the given snippet with custom context modifier
528 pub fn evaluate_snippet_with(505 pub fn evaluate_snippet_with(
529 &self,506 &self,
530 name: impl Into<IStr>,507 name: impl Into<IStr>,
531 code: impl Into<IStr>,508 code: impl Into<IStr>,
532 context_initializer: impl ContextInitializer,509 context_initializer: &dyn ContextInitializer,
533 ) -> Result<Val> {510 ) -> Result<Val> {
534 let code = code.into();511 let code = code.into();
535 let source = Source::new_virtual(name.into(), code.clone());512 let source = Source::new_virtual(name.into(), code.clone());
587 }564 }
588 pub fn context_initializer(565 pub fn context_initializer(
589 &mut self,566 &mut self,
590 context_initializer: impl ContextInitializer,567 context_initializer: impl ContextInitializer + Trace,
591 ) -> &mut Self {568 ) -> &mut Self {
592 let _ = self569 let _ = self
593 .context_initializer570 .context_initializer
modifiedcrates/jrsonnet-evaluator/src/manifest.rsdiffbeforeafterboth
1use std::{borrow::Cow, fmt::Write, ptr};1use std::{borrow::Cow, fmt::Write, hint::black_box, ptr};
22
3use crate::{Result, ResultExt, Val, bail, in_description_frame};3use crate::{Result, ResultExt, Val, bail, in_description_frame};
44
44 }44 }
45}45}
46
47pub struct BlackBoxFormat;
48impl ManifestFormat for BlackBoxFormat {
49 #[allow(clippy::only_used_in_recursion)]
50 fn manifest_buf(&self, val: Val, buf: &mut String) -> Result<()> {
51 match val {
52 Val::Bool(v) => {
53 black_box(v);
54 }
55 val @ Val::Null => {
56 black_box(val);
57 }
58 Val::Str(str_value) => {
59 black_box(format!("{str_value}"));
60 }
61 Val::Num(num_value) => {
62 black_box(num_value);
63 }
64 Val::Arr(arr_value) => {
65 for ele in arr_value.iter() {
66 let ele = ele?;
67 self.manifest_buf(ele, buf)?;
68 }
69 }
70 Val::Obj(obj_value) => {
71 for (name, value) in obj_value.iter() {
72 black_box(name);
73 let value = value?;
74 self.manifest_buf(value, buf)?;
75 }
76 }
77 Val::Func(func_val) => {
78 black_box(func_val);
79 bail!("tried to manifest function")
80 }
81 }
82 Ok(())
83 }
84}
4685
47#[derive(PartialEq, Eq, Clone, Copy)]86#[derive(PartialEq, Eq, Clone, Copy)]
48enum JsonFormatting {87enum JsonFormatting {
66 preserve_order: bool,105 preserve_order: bool,
67 #[cfg(feature = "exp-bigint")]106 #[cfg(feature = "exp-bigint")]
68 preserve_bigints: bool,107 preserve_bigints: bool,
69 debug_truncate_strings: Option<usize>,
70}108}
71109
72impl<'s> JsonFormat<'s> {110impl<'s> JsonFormat<'s> {
81 preserve_order,119 preserve_order,
82 #[cfg(feature = "exp-bigint")]120 #[cfg(feature = "exp-bigint")]
83 preserve_bigints: false,121 preserve_bigints: false,
84 debug_truncate_strings: None,
85 }122 }
86 }123 }
87 /// Same format as std.toString, except does not keeps top-level string as-is124 /// Same format as std.toString, except does not keeps top-level string as-is
96 preserve_order: false,133 preserve_order: false,
97 #[cfg(feature = "exp-bigint")]134 #[cfg(feature = "exp-bigint")]
98 preserve_bigints: false,135 preserve_bigints: false,
99 debug_truncate_strings: None,
100 }136 }
101 }137 }
102 pub fn std_to_json(138 pub fn std_to_json(
114 preserve_order,150 preserve_order,
115 #[cfg(feature = "exp-bigint")]151 #[cfg(feature = "exp-bigint")]
116 preserve_bigints: false,152 preserve_bigints: false,
117 debug_truncate_strings: None,
118 }153 }
119 }154 }
120 // Same format as CLI manifestification155 // Same format as CLI manifestification
137 preserve_order,172 preserve_order,
138 #[cfg(feature = "exp-bigint")]173 #[cfg(feature = "exp-bigint")]
139 preserve_bigints: false,174 preserve_bigints: false,
140 debug_truncate_strings: None,
141 }175 }
142 }176 }
143 // Same format as CLI manifestification177 // Same format as CLI manifestification
151 preserve_order: true,185 preserve_order: true,
152 #[cfg(feature = "exp-bigint")]186 #[cfg(feature = "exp-bigint")]
153 preserve_bigints: true,187 preserve_bigints: true,
154 debug_truncate_strings: Some(256),
155 }188 }
156 }189 }
157}190}
166 preserve_order: false,199 preserve_order: false,
167 #[cfg(feature = "exp-bigint")]200 #[cfg(feature = "exp-bigint")]
168 preserve_bigints: false,201 preserve_bigints: false,
169 debug_truncate_strings: None,
170 }202 }
171 }203 }
172}204}
197 }229 }
198 Val::Null => buf.push_str("null"),230 Val::Null => buf.push_str("null"),
199 Val::Str(s) => {231 Val::Str(s) => {
200 let flat = s.clone().into_flat();232 buf.reserve(2 + s.len());
201 if let Some(truncate) = options.debug_truncate_strings {233 buf.push('"');
202 if flat.len() > truncate {
203 let (start, end) = flat.split_at(truncate / 2);
204 let (_, end) = end.split_at(end.len() - truncate / 2);
205 escape_string_json_buf(&format!("{start}..{end}"), buf);
206 } else {234 s.chunks(&mut |c| {
207 escape_string_json_buf(&flat, buf);235 escape_string_json_buf_raw(c, buf);
208 }236 });
209 } else {
210 escape_string_json_buf(&flat, buf);237 buf.push('"');
211 }
212 }238 }
213 Val::Num(n) => write!(buf, "{n}").unwrap(),239 Val::Num(n) => write!(buf, "{n}").unwrap(),
214 #[cfg(feature = "exp-bigint")]240 #[cfg(feature = "exp-bigint")]
475 __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // F501 __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // F
476];502];
503
504pub fn escape_string_json_buf(value: &str, buf: &mut String) {
505 buf.reserve_exact(value.len() + 2);
506 escape_string_json_buf_raw(value, buf);
507}
477508
478pub fn escape_string_json_buf(value: &str, buf: &mut String) {509fn escape_string_json_buf_raw(value: &str, buf: &mut String) {
479 // Safety: we only write correct utf-8 in this function510 // Safety: we only write correct utf-8 in this function
480 let buf: &mut Vec<u8> = unsafe { &mut *ptr::from_mut(buf).cast::<Vec<u8>>() };511 let buf: &mut Vec<u8> = unsafe { &mut *ptr::from_mut(buf).cast::<Vec<u8>>() };
481 let bytes = value.as_bytes();512 let bytes = value.as_bytes();
482
483 // Perfect for ascii strings, removes any reallocations
484 buf.reserve(value.len() + 2);
485
486 buf.push(b'"');
487513
488 let mut start = 0;514 let mut start = 0;
489515
519 }545 }
520546
521 if start == bytes.len() {547 if start == bytes.len() {
522 buf.push(b'"');
523 return;548 return;
524 }549 }
525550
526 buf.extend_from_slice(&bytes[start..]);551 buf.extend_from_slice(&bytes[start..]);
527 buf.push(b'"');
528}552}
529553
deletedcrates/jrsonnet-evaluator/src/map.rsdiffbeforeafterboth

no changes

modifiedcrates/jrsonnet-evaluator/src/val.rsdiffbeforeafterboth
355 Self::Tree(Rc::new((a, b, len)))355 Self::Tree(Rc::new((a, b, len)))
356 }356 }
357 }357 }
358 pub fn chunks(&self, c: &mut impl FnMut(&IStr)) {
359 fn write_buf(s: &StrValue, c: &mut impl FnMut(&IStr)) {
360 match s {
361 StrValue::Flat(f) => c(f),
362 StrValue::Tree(t) => {
363 write_buf(&t.0, c);
364 write_buf(&t.1, c);
365 }
366 }
367 }
368 write_buf(self, c);
369 }
358 pub fn into_flat(&self) -> IStr {370 pub fn into_flat(&self) -> IStr {
359 #[cold]
360 fn write_buf(s: &StrValue, out: &mut String) {371 fn write_buf(s: &StrValue, out: &mut String) {
361 match s {372 match s {
362 StrValue::Flat(f) => out.push_str(f),373 StrValue::Flat(f) => out.push_str(f),
modifiedcrates/jrsonnet-stdlib/src/lib.rsdiffbeforeafterboth
545 }545 }
546}546}
547impl jrsonnet_evaluator::ContextInitializer for ContextInitializer {547impl jrsonnet_evaluator::ContextInitializer for ContextInitializer {
548 fn reserve_vars(&self) -> usize {
549 1
550 }
551 fn populate(&self, source: Source, builder: &mut ContextBuilder) {548 fn populate(&self, source: Source, builder: &mut ContextBuilder) {
552 let mut std = ObjValueBuilder::new();549 let mut std = ObjValueBuilder::new();
553 std.with_super(self.stdlib_obj.clone());550 std.with_super(self.stdlib_obj.clone());
modifiedtests/Cargo.tomldiffbeforeafterboth
18jrsonnet-evaluator.workspace = true18jrsonnet-evaluator.workspace = true
19jrsonnet-gcmodule.workspace = true19jrsonnet-gcmodule.workspace = true
20jrsonnet-stdlib.workspace = true20jrsonnet-stdlib.workspace = true
21mimallocator.workspace = true
21serde.workspace = true22serde.workspace = true
22serde_json.workspace = true23serde_json.workspace = true
2324