difftreelog
refactor unified ContextBuilder
in: master
17 files changed
Cargo.lockdiffbeforeafterboth699 "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",861862862[[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]871872872[[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]14221423[[package]]1424name = "refpool"1425version = "0.4.3"1426source = "registry+https://github.com/rust-lang/crates.io-index"1427checksum = "369e86b80fa7dc8c561dd9613a5bf25c59d2d3073cd66c47fd9e39802f0ecb58"142114281422[[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]163816461738 "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]Cargo.tomldiffbeforeafterboth22jrsonnet-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 yet28# 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.cmds/jrsonnet/src/main.rsdiffbeforeafterboth200 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 }206206crates/jrsonnet-evaluator/Cargo.tomldiffbeforeafterboth76 "Hash",76 "Hash",77 "PartialEq",77 "PartialEq",78] }78] }79im-rc = "15.1.0"79im-rc = { version = "15.1.0", features = ["pool"] }808081[build-dependencies]81[build-dependencies]82rustversion = "1.0.22"82rustversion = "1.0.22"crates/jrsonnet-evaluator/src/ctx.rsdiffbeforeafterboth3use 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};778use 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 location13///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>>,2425 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 }7576 if let Some(branch_point) = &self.0.branch_point {77 return branch_point.binding(name);78 }737974 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));838984 bail!(VariableIsNotDefined(90 bail!(VariableIsNotDefined(97 ctx.unwrap()103 ctx.unwrap()98 }104 }99100 #[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 }106105107 #[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 = ctx115 .0116 .dollar117 .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 self121 } 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}148115149#[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}154124155impl 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 }159135160 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 }166145167 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 }173155174 /// # Panics175 ///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 self182 }158 }159 /// After commit, binds would shadow the previous declarations160 #[must_use]161 pub fn commit(mut self) -> Self {162 self.filled.clear();163 self164 }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 self188 }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}189190impl Default for ContextBuilder {191 fn default() -> Self {192 Self::new()193 }194}201195crates/jrsonnet-evaluator/src/error.rsdiffbeforeafterboth250#[derive(Clone, Trace)]250#[derive(Clone, Trace)]251pub struct Error(Box<(ErrorKind, StackTrace)>);251pub struct Error(Box<(ErrorKind, StackTrace)>);252253#[cfg(target_pointer_width = "64")]254static_assertions::assert_eq_size!(Error, usize);255252impl Error {256impl Error {253 pub fn new(e: ErrorKind) -> Self {257 pub fn new(e: ErrorKind) -> Self {crates/jrsonnet-evaluator/src/evaluate/destructure.rsdiffbeforeafterboth1use std::{collections::HashMap, hash::BuildHasher};23use jrsonnet_interner::IStr;4use jrsonnet_ir::{BindSpec, Destruct};1use jrsonnet_ir::{BindSpec, Destruct};526#[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};13914#[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}189182190pub 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(())crates/jrsonnet-evaluator/src/evaluate/mod.rsdiffbeforeafterboth8 function::ParamName,8 function::ParamName,9};9};10use jrsonnet_types::ValType;10use jrsonnet_types::ValType;11use rustc_hash::FxHashMap;121113use 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);136134137 let specs = &specs[1..];135 let specs = &specs[1..];138 evaluate_comp(136 evaluate_comp(179}177}180178181fn 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();184183225224226 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 }233234 let ctx = self.fctx.clone();235232236 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);239234240 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 .0337 .clone()338 .extend_bindings_sup_this(FxHashMap::new(), sup_this))339 }331 }340}332}341333409 }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);414410415 evaluate_field_member(&mut builder, ctx, uctx, &obj.field)411 evaluate_field_member(&mut builder, ctx, uctx, &obj.field)416 })?;412 },413 )?;417414418 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) => {crates/jrsonnet-evaluator/src/function/parse.rsdiffbeforeafterboth1use jrsonnet_ir::ExprParams;1use jrsonnet_ir::ExprParams;2use rustc_hash::FxHashMap;324use 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};11912/// Creates Context, which has all argument default values applied10/// Creates Context, which has all argument default values applied13/// and with unbound values causing error to be returned11/// and with unbound values causing error to be returned14pub 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();161417 let mut bindings = FxHashMap::with_capacity(params.binds_len());15 let mut ctx = ContextBuilder::extend(body_ctx);181619 for param in params.exprs.iter() {17 for param in params.exprs.iter() {20 if let Some(v) = ¶m.default {18 if let Some(v) = ¶m.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 }494750 Ok(body_ctx.extend_bindings(bindings).into_future(fctx))48 Ok(ctx.build().into_future(fctx))51}49}5250crates/jrsonnet-evaluator/src/function/prepared.rsdiffbeforeafterboth223use 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;667use 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};121213#[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);122122123 let destruct_ctx = Pending::new();123 let destruct_ctx = Pending::new();124124127 ¶ms.exprs[param_idx].destruct,127 ¶ms.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 }133133136 ¶ms.exprs[param_idx].destruct,136 ¶ms.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 }142142143 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 }169167170 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}crates/jrsonnet-evaluator/src/gc.rsdiffbeforeafterboth323233pub fn assert_trace<T: Trace>(_v: &T) {}33pub fn assert_trace<T: Trace>(_v: &T) {}3435pub type ImHashMap<K, V> = im_rc::HashMap<K, V, FxBuildHasher>;3436crates/jrsonnet-evaluator/src/lib.rsdiffbeforeafterboth15mod 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;162161163/// 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 preallocated167 fn reserve_vars(&self) -> usize {168 0169 }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 &T173where174 T: ContextInitializer,175{176 fn populate(&self, for_file: Source, builder: &mut ContextBuilder) {177 (*self).populate(for_file, builder);178 }179180 fn as_any(&self) -> &dyn Any {181 (*self).as_any()182 }183}185184186/// Context initializer which adds nothing.185/// Context initializer which adds nothing.187impl ContextInitializer for () {186impl ContextInitializer for () {193192194impl<T> ContextInitializer for Option<T>193impl<T> ContextInitializer for Option<T>195where194where196 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 }205206 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 out226 }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);)*453438454 /// Creates context with all passed global variables439 /// Creates context with all passed global variables455 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 }458443459 /// Creates context with all passed global variables, calling custom modifier444 /// Creates context with all passed global variables, calling custom modifier460 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 snippet518 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 modifier528 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 _ = self593 .context_initializer570 .context_initializercrates/jrsonnet-evaluator/src/manifest.rsdiffbeforeafterboth1use std::{borrow::Cow, fmt::Write, ptr};1use std::{borrow::Cow, fmt::Write, hint::black_box, ptr};223use crate::{Result, ResultExt, Val, bail, in_description_frame};3use crate::{Result, ResultExt, Val, bail, in_description_frame};4444 }44 }45}45}4647pub 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}468547#[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}7110972impl<'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-is96 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 manifestification137 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 manifestification151 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 __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // F476];502];503504pub 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}477508478pub 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 function480 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();482483 // Perfect for ascii strings, removes any reallocations484 buf.reserve(value.len() + 2);485486 buf.push(b'"');487513488 let mut start = 0;514 let mut start = 0;489515519 }545 }520546521 if start == bytes.len() {547 if start == bytes.len() {522 buf.push(b'"');523 return;548 return;524 }549 }525550526 buf.extend_from_slice(&bytes[start..]);551 buf.extend_from_slice(&bytes[start..]);527 buf.push(b'"');528}552}529553crates/jrsonnet-evaluator/src/map.rsdiffbeforeafterbothno changes
crates/jrsonnet-evaluator/src/val.rsdiffbeforeafterboth355 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),crates/jrsonnet-stdlib/src/lib.rsdiffbeforeafterboth545 }545 }546}546}547impl jrsonnet_evaluator::ContextInitializer for ContextInitializer {547impl jrsonnet_evaluator::ContextInitializer for ContextInitializer {548 fn reserve_vars(&self) -> usize {549 1550 }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());tests/Cargo.tomldiffbeforeafterboth18jrsonnet-evaluator.workspace = true18jrsonnet-evaluator.workspace = true19jrsonnet-gcmodule.workspace = true19jrsonnet-gcmodule.workspace = true20jrsonnet-stdlib.workspace = true20jrsonnet-stdlib.workspace = true21mimallocator.workspace = true21serde.workspace = true22serde.workspace = true22serde_json.workspace = true23serde_json.workspace = true2324