difftreelog
refactor better rebinding handling
in: master
15 files changed
crates/jrsonnet-evaluator/src/ctx.rsdiffbeforeafterboth4use jrsonnet_interner::IStr;4use jrsonnet_interner::IStr;556use crate::{6use crate::{7 cc_ptr_eq, error::Error::*, gc::GcHashMap, map::LayeredHashMap, LazyBinding, ObjValue, Pending,7 cc_ptr_eq, error::Error::*, gc::GcHashMap, map::LayeredHashMap, ObjValue, Pending, Result,8 Result, State, Thunk, Val,8 Thunk, Val,9};9};1011#[derive(Clone, Trace)]12pub struct ContextCreator(pub Context, pub Pending<GcHashMap<IStr, LazyBinding>>);13impl ContextCreator {14 pub fn create(15 &self,16 s: State,17 this: Option<ObjValue>,18 super_obj: Option<ObjValue>,19 ) -> Result<Context> {20 self.0.clone().extend_unbound(21 s,22 self.1.clone().unwrap(),23 self.0.dollar().clone().or_else(|| this.clone()),24 this,25 super_obj,26 )27 }28}291030#[derive(Trace)]11#[derive(Trace)]31struct ContextInternals {12struct ContextInternals {32 dollar: Option<ObjValue>,13 dollar: Option<ObjValue>,33 this: Option<ObjValue>,14 sup: Option<ObjValue>,34 super_obj: Option<ObjValue>,15 this: Option<ObjValue>,35 bindings: LayeredHashMap,16 bindings: LayeredHashMap,36}17}37impl Debug for ContextInternals {18impl Debug for ContextInternals {56 }37 }573858 pub fn super_obj(&self) -> &Option<ObjValue> {39 pub fn super_obj(&self) -> &Option<ObjValue> {59 &self.0.super_obj40 &self.0.sup60 }41 }614262 pub fn new() -> Self {43 pub fn new() -> Self {63 Self(Cc::new(ContextInternals {44 Self(Cc::new(ContextInternals {64 dollar: None,45 dollar: None,65 this: None,46 this: None,66 super_obj: None,47 sup: None,67 bindings: LayeredHashMap::default(),48 bindings: LayeredHashMap::default(),68 }))49 }))69 }50 }94 self.extend(new_bindings, None, None, None)75 self.extend(new_bindings, None, None, None)95 }76 }9697 #[must_use]98 pub fn with_this_super(self, new_this: ObjValue, new_super_obj: Option<ObjValue>) -> Self {99 self.extend(GcHashMap::new(), None, Some(new_this), new_super_obj)100 }10177102 #[must_use]78 #[must_use]103 pub fn extend(79 pub fn extend(104 self,80 self,105 new_bindings: GcHashMap<IStr, Thunk<Val>>,81 new_bindings: GcHashMap<IStr, Thunk<Val>>,106 new_dollar: Option<ObjValue>,82 new_dollar: Option<ObjValue>,107 new_this: Option<ObjValue>,83 new_sup: Option<ObjValue>,108 new_super_obj: Option<ObjValue>,84 new_this: Option<ObjValue>,109 ) -> Self {85 ) -> Self {110 let ctx = &self.0;86 let ctx = &self.0;111 let dollar = new_dollar.or_else(|| ctx.dollar.clone());87 let dollar = new_dollar.or_else(|| ctx.dollar.clone());112 let this = new_this.or_else(|| ctx.this.clone());88 let this = new_this.or_else(|| ctx.this.clone());113 let super_obj = new_super_obj.or_else(|| ctx.super_obj.clone());89 let sup = new_sup.or_else(|| ctx.sup.clone());114 let bindings = if new_bindings.is_empty() {90 let bindings = if new_bindings.is_empty() {115 ctx.bindings.clone()91 ctx.bindings.clone()116 } else {92 } else {117 ctx.bindings.clone().extend(new_bindings)93 ctx.bindings.clone().extend(new_bindings)118 };94 };119 Self(Cc::new(ContextInternals {95 Self(Cc::new(ContextInternals {120 dollar,96 dollar,97 sup,121 this,98 this,122 super_obj,123 bindings,99 bindings,124 }))100 }))125 }101 }126 #[must_use]127 pub fn extend_bound(self, new_bindings: GcHashMap<IStr, Thunk<Val>>) -> Self {128 let new_this = self.0.this.clone();129 let new_super_obj = self.0.super_obj.clone();130 self.extend(new_bindings, None, new_this, new_super_obj)131 }132 pub fn extend_unbound(133 self,134 s: State,135 new_bindings: GcHashMap<IStr, LazyBinding>,136 new_dollar: Option<ObjValue>,137 new_this: Option<ObjValue>,138 new_super_obj: Option<ObjValue>,139 ) -> Result<Self> {140 let this = new_this.or_else(|| self.0.this.clone());141 let super_obj = new_super_obj.or_else(|| self.0.super_obj.clone());142 let mut new = GcHashMap::with_capacity(new_bindings.len());143 for (k, v) in new_bindings.0 {144 new.insert(k, v.evaluate(s.clone(), this.clone(), super_obj.clone())?);145 }146 Ok(self.extend(new, new_dollar, this, super_obj))147 }148}102}149103150impl Default for Context {104impl Default for Context {crates/jrsonnet-evaluator/src/evaluate/destructure.rsdiffbeforeafterboth11 Context, Pending, State, Thunk, Val,11 Context, Pending, State, Thunk, Val,12};12};131314#[allow(clippy::too_many_lines)]14fn destruct(15fn destruct(15 d: &Destruct,16 d: &Destruct,16 parent: Thunk<Val>,17 parent: Thunk<Val>,17 new_bindings: &mut GcHashMap<IStr, Thunk<Val>>,18 new_bindings: &mut GcHashMap<IStr, Thunk<Val>>,18) -> Result<()> {19) -> Result<()> {19 Ok(match d {20 match d {20 Destruct::Full(v) => {21 Destruct::Full(v) => {21 let old = new_bindings.insert(v.clone(), parent);22 let old = new_bindings.insert(v.clone(), parent);22 if old.is_some() {23 if old.is_some() {157 }158 }158 #[cfg(feature = "exp-destruct")]159 #[cfg(feature = "exp-destruct")]159 Destruct::Object { fields, rest } => {160 Destruct::Object { fields, rest } => {160 use jrsonnet_parser::DestructRest;161162 use crate::{obj::ObjValue, throw_runtime};161 use crate::{obj::ObjValue, throw_runtime};163162223 }222 }224 }223 }225 }224 }226 })225 }226 Ok(())227}227}228228229pub fn evaluate_dest(229pub fn evaluate_dest(crates/jrsonnet-evaluator/src/evaluate/mod.rsdiffbeforeafterboth1use std::rc::Rc;21use gcmodule::{Cc, Trace};3use gcmodule::{Cc, Trace};2use jrsonnet_interner::IStr;4use jrsonnet_interner::IStr;3use jrsonnet_parser::{5use jrsonnet_parser::{4 ArgsDesc, AssertStmt, BindSpec, CompSpec, Destruct, Expr, FieldMember, ForSpecData, IfSpecData,6 ArgsDesc, AssertStmt, BindSpec, CompSpec, Expr, FieldMember, ForSpecData, IfSpecData,5 LiteralType, LocExpr, Member, ObjBody, ParamsDesc,7 LiteralType, LocExpr, Member, ObjBody, ParamsDesc,6};8};7use jrsonnet_types::ValType;9use jrsonnet_types::ValType;14 stdlib::{std_slice, BUILTINS},16 stdlib::{std_slice, BUILTINS},15 tb, throw,17 tb, throw,16 typed::Typed,18 typed::Typed,17 val::{ArrValue, Thunk, ThunkValue},19 val::{ArrValue, CachedBindable, Thunk, ThunkValue},18 Bindable, Context, ContextCreator, GcHashMap, LazyBinding, ObjValue, ObjValueBuilder,20 Bindable, Context, GcHashMap, ObjValue, ObjValueBuilder, ObjectAssertion, Pending, Result,19 ObjectAssertion, Pending, Result, State, Val,21 State, Val,20};22};21pub mod destructure;23pub mod destructure;22pub mod operator;24pub mod operator;2324#[allow(clippy::too_many_lines)]25pub fn evaluate_binding(b: BindSpec, cctx: ContextCreator) -> Result<(IStr, LazyBinding)> {26 match b {27 BindSpec::Field {28 into: Destruct::Full(name),29 value,30 } => {31 #[derive(Trace)]32 struct BindableNamedThunk {33 this: Option<ObjValue>,34 super_obj: Option<ObjValue>,3536 cctx: ContextCreator,37 name: IStr,38 value: LocExpr,39 }40 impl ThunkValue for BindableNamedThunk {41 type Output = Val;42 fn get(self: Box<Self>, s: State) -> Result<Val> {43 evaluate_named(44 s.clone(),45 self.cctx.create(s, self.this, self.super_obj)?,46 &self.value,47 self.name,48 )49 }50 }5152 #[derive(Trace)]53 struct BindableNamed {54 cctx: ContextCreator,55 name: IStr,56 value: LocExpr,57 }58 impl Bindable for BindableNamed {59 fn bind(60 &self,61 _: State,62 this: Option<ObjValue>,63 super_obj: Option<ObjValue>,64 ) -> Result<Thunk<Val>> {65 Ok(Thunk::new(tb!(BindableNamedThunk {66 this,67 super_obj,6869 cctx: self.cctx.clone(),70 name: self.name.clone(),71 value: self.value.clone(),72 })))73 }74 }7576 Ok((77 name.clone(),78 LazyBinding::Bindable(Cc::new(tb!(BindableNamed {79 cctx,80 name: name.clone(),81 value: value.clone(),82 }))),83 ))84 }85 #[cfg(feature = "exp-destruct")]86 BindSpec::Field { into: _, .. } => {87 use crate::throw_runtime;88 throw_runtime!("destructuring is not yet supported here")89 }90 BindSpec::Function {91 name,92 params,93 value,94 } => {95 #[derive(Trace)]96 struct BindableMethodThunk {97 this: Option<ObjValue>,98 super_obj: Option<ObjValue>,99100 cctx: ContextCreator,101 name: IStr,102 params: ParamsDesc,103 value: LocExpr,104 }105 impl ThunkValue for BindableMethodThunk {106 type Output = Val;107 fn get(self: Box<Self>, s: State) -> Result<Val> {108 Ok(evaluate_method(109 self.cctx.create(s, self.this, self.super_obj)?,110 self.name,111 self.params,112 self.value,113 ))114 }115 }116117 #[derive(Trace)]118 struct BindableMethod {119 cctx: ContextCreator,120 name: IStr,121 params: ParamsDesc,122 value: LocExpr,123 }124 impl Bindable for BindableMethod {125 fn bind(126 &self,127 _: State,128 this: Option<ObjValue>,129 super_obj: Option<ObjValue>,130 ) -> Result<Thunk<Val>> {131 Ok(Thunk::<Val>::new(tb!(BindableMethodThunk {132 this,133 super_obj,134135 cctx: self.cctx.clone(),136 name: self.name.clone(),137 params: self.params.clone(),138 value: self.value.clone(),139 })))140 }141 }142143 let params = params.clone();144145 Ok((146 name.clone(),147 LazyBinding::Bindable(Cc::new(tb!(BindableMethod {148 cctx,149 name: name.clone(),150 params,151 value,152 }))),153 ))154 }155 }156}15725158pub fn evaluate_method(ctx: Context, name: IStr, params: ParamsDesc, body: LocExpr) -> Val {26pub fn evaluate_method(ctx: Context, name: IStr, params: ParamsDesc, body: LocExpr) -> Val {159 Val::Func(FuncVal::Normal(Cc::new(FuncDesc {27 Val::Func(FuncVal::Normal(Cc::new(FuncDesc {218 Ok(())86 Ok(())219}87}8889trait CloneableBindable<T>: Bindable<Bound = T> + Clone {}9091fn evaluate_object_locals(92 fctx: Pending<Context>,93 locals: Rc<Vec<BindSpec>>,94) -> impl CloneableBindable<Context> {95 #[derive(Trace, Clone)]96 struct WithObjectLocals {97 fctx: Pending<Context>,98 locals: Rc<Vec<BindSpec>>,99 }100 impl CloneableBindable<Context> for WithObjectLocals {}101 impl Bindable for WithObjectLocals {102 type Bound = Context;103104 fn bind(105 &self,106 _s: State,107 sup: Option<ObjValue>,108 this: Option<ObjValue>,109 ) -> Result<Context> {110 let fctx = Context::new_future();111 let mut new_bindings = GcHashMap::new();112 for b in self.locals.iter() {113 evaluate_dest(b, fctx.clone(), &mut new_bindings)?;114 }115116 let ctx = self.fctx.unwrap();117 let new_dollar = ctx.dollar().clone().or_else(|| this.clone());118119 let ctx = ctx120 .extend(new_bindings, new_dollar, sup, this)121 .into_future(fctx);122123 Ok(ctx)124 }125 }126127 WithObjectLocals { fctx, locals }128}220129221#[allow(clippy::too_many_lines)]130#[allow(clippy::too_many_lines)]222pub fn evaluate_member_list_object(s: State, ctx: Context, members: &[Member]) -> Result<ObjValue> {131pub fn evaluate_member_list_object(s: State, ctx: Context, members: &[Member]) -> Result<ObjValue> {223 let new_bindings = Pending::new();132 let mut builder = ObjValueBuilder::new();224 let future_this = Pending::new();225 let cctx = ContextCreator(ctx.clone(), new_bindings.clone());226 {227 let mut bindings: GcHashMap<IStr, LazyBinding> = GcHashMap::with_capacity(members.len());133 let locals = Rc::new(228 for r in members134 members229 .iter()135 .iter()230 .filter_map(|m| match m {136 .filter_map(|m| match m {231 Member::BindStmt(b) => Some(b.clone()),137 Member::BindStmt(bind) => Some(bind.clone()),232 _ => None,138 _ => None,233 })139 })234 .map(|b| evaluate_binding(b.clone(), cctx.clone()))140 .collect::<Vec<_>>(),235 {141 );236 let (n, b) = r?;142237 bindings.insert(n, b);238 }239 new_bindings.fill(bindings);143 let fctx = Context::new_future();240 }144241145 // We have single context for all fields, so we can cache binds242 let mut builder = ObjValueBuilder::new();146 let uctx = CachedBindable::new(evaluate_object_locals(fctx.clone(), locals));147243 for member in members.iter() {148 for member in members.iter() {244 match member {149 match member {250 value,155 value,251 }) => {156 }) => {252 #[derive(Trace)]157 #[derive(Trace)]253 struct ObjMemberBinding {158 struct ObjMemberBinding<B> {254 cctx: ContextCreator,159 uctx: B,255 value: LocExpr,160 value: LocExpr,256 name: IStr,161 name: IStr,257 }162 }258 impl Bindable for ObjMemberBinding {163 impl<B: Bindable<Bound = Context>> Bindable for ObjMemberBinding<B> {164 type Bound = Thunk<Val>;259 fn bind(165 fn bind(260 &self,166 &self,261 s: State,167 s: State,262 this: Option<ObjValue>,168 sup: Option<ObjValue>,263 super_obj: Option<ObjValue>,169 this: Option<ObjValue>,264 ) -> Result<Thunk<Val>> {170 ) -> Result<Thunk<Val>> {265 Ok(Thunk::evaluated(evaluate_named(171 Ok(Thunk::evaluated(evaluate_named(266 s.clone(),172 s.clone(),267 self.cctx.create(s, this, super_obj)?,173 self.uctx.bind(s, sup, this)?,268 &self.value,174 &self.value,269 self.name.clone(),175 self.name.clone(),270 )?))176 )?))286 .bindable(192 .bindable(287 s.clone(),193 s.clone(),288 tb!(ObjMemberBinding {194 tb!(ObjMemberBinding {289 cctx: cctx.clone(),195 uctx: uctx.clone(),290 value: value.clone(),196 value: value.clone(),291 name,197 name: name.clone()292 }),198 }),293 )?;199 )?;294 }200 }299 ..205 ..300 }) => {206 }) => {301 #[derive(Trace)]207 #[derive(Trace)]302 struct ObjMemberBinding {208 struct ObjMemberBinding<B> {303 cctx: ContextCreator,209 uctx: B,304 value: LocExpr,210 value: LocExpr,305 params: ParamsDesc,211 params: ParamsDesc,306 name: IStr,212 name: IStr,307 }213 }308 impl Bindable for ObjMemberBinding {214 impl<B: Bindable<Bound = Context>> Bindable for ObjMemberBinding<B> {215 type Bound = Thunk<Val>;309 fn bind(216 fn bind(310 &self,217 &self,311 s: State,218 s: State,312 this: Option<ObjValue>,219 sup: Option<ObjValue>,313 super_obj: Option<ObjValue>,220 this: Option<ObjValue>,314 ) -> Result<Thunk<Val>> {221 ) -> Result<Thunk<Val>> {315 Ok(Thunk::evaluated(evaluate_method(222 Ok(Thunk::evaluated(evaluate_method(316 self.cctx.create(s, this, super_obj)?,223 self.uctx.bind(s, sup, this)?,317 self.name.clone(),224 self.name.clone(),318 self.params.clone(),225 self.params.clone(),319 self.value.clone(),226 self.value.clone(),334 .bindable(241 .bindable(335 s.clone(),242 s.clone(),336 tb!(ObjMemberBinding {243 tb!(ObjMemberBinding {337 cctx: cctx.clone(),244 uctx: uctx.clone(),338 value: value.clone(),245 value: value.clone(),339 params: params.clone(),246 params: params.clone(),340 name,247 name: name.clone()341 }),248 }),342 )?;249 )?;343 }250 }344 Member::BindStmt(_) => {}251 Member::BindStmt(_) => {}345 Member::AssertStmt(stmt) => {252 Member::AssertStmt(stmt) => {346 #[derive(Trace)]253 #[derive(Trace)]347 struct ObjectAssert {254 struct ObjectAssert<B> {348 cctx: ContextCreator,255 uctx: B,349 assert: AssertStmt,256 assert: AssertStmt,350 }257 }351 impl ObjectAssertion for ObjectAssert {258 impl<B: Bindable<Bound = Context>> ObjectAssertion for ObjectAssert<B> {352 fn run(259 fn run(353 &self,260 &self,354 s: State,261 s: State,355 this: Option<ObjValue>,262 sup: Option<ObjValue>,356 super_obj: Option<ObjValue>,263 this: Option<ObjValue>,357 ) -> Result<()> {264 ) -> Result<()> {358 let ctx = self.cctx.create(s.clone(), this, super_obj)?;265 let ctx = self.uctx.bind(s.clone(), sup, this)?;359 evaluate_assert(s, ctx, &self.assert)266 evaluate_assert(s, ctx, &self.assert)360 }267 }361 }268 }362 builder.assert(tb!(ObjectAssert {269 builder.assert(tb!(ObjectAssert {363 cctx: cctx.clone(),270 uctx: uctx.clone(),364 assert: stmt.clone(),271 assert: stmt.clone(),365 }));272 }));366 }273 }367 }274 }368 }275 }369 let this = builder.build();276 let this = builder.build();277 let _ctx = ctx370 future_this.fill(this.clone());278 .extend(GcHashMap::new(), None, None, Some(this.clone()))279 .into_future(fctx);371 Ok(this)280 Ok(this)372}281}373282374pub fn evaluate_object(s: State, ctx: Context, object: &ObjBody) -> Result<ObjValue> {283pub fn evaluate_object(s: State, ctx: Context, object: &ObjBody) -> Result<ObjValue> {375 Ok(match object {284 Ok(match object {376 ObjBody::MemberList(members) => evaluate_member_list_object(s, ctx, members)?,285 ObjBody::MemberList(members) => evaluate_member_list_object(s, ctx, members)?,377 ObjBody::ObjComp(obj) => {286 ObjBody::ObjComp(obj) => {378 let future_this = Pending::new();287 let mut builder = ObjValueBuilder::new();379 let mut builder = ObjValueBuilder::new();288 let locals = Rc::new(289 obj.pre_locals290 .iter()291 .chain(obj.post_locals.iter())292 .cloned()293 .collect::<Vec<_>>(),294 );295 let mut ctxs = vec![];380 evaluate_comp(s.clone(), ctx, &obj.compspecs, &mut |ctx| {296 evaluate_comp(s.clone(), ctx, &obj.compspecs, &mut |ctx| {381 let new_bindings = Pending::new();382 let cctx = ContextCreator(ctx.clone(), new_bindings.clone());297 let key = evaluate(s.clone(), ctx.clone(), &obj.key)?;383 let mut bindings: GcHashMap<IStr, LazyBinding> =298 let fctx = Context::new_future();384 GcHashMap::with_capacity(obj.pre_locals.len() + obj.post_locals.len());385 for r in obj386 .pre_locals387 .iter()388 .chain(obj.post_locals.iter())389 .map(|b| evaluate_binding(b.clone(), cctx.clone()))299 ctxs.push((ctx, fctx.clone()));390 {391 let (n, b) = r?;392 bindings.insert(n, b);393 }394 new_bindings.fill(bindings.clone());395 let ctx = ctx.extend_unbound(s.clone(), bindings, None, None, None)?;396 let key = evaluate(s.clone(), ctx.clone(), &obj.key)?;300 let uctx = evaluate_object_locals(fctx, locals.clone());397301398 match key {302 match key {399 Val::Null => {}303 Val::Null => {}400 Val::Str(n) => {304 Val::Str(n) => {401 #[derive(Trace)]305 #[derive(Trace)]402 struct ObjCompBinding {306 struct ObjCompBinding<B> {403 ctx: Context,307 uctx: B,404 value: LocExpr,308 value: LocExpr,405 }309 }406 impl Bindable for ObjCompBinding {310 impl<B: Bindable<Bound = Context>> Bindable for ObjCompBinding<B> {311 type Bound = Thunk<Val>;407 fn bind(312 fn bind(408 &self,313 &self,409 s: State,314 s: State,410 this: Option<ObjValue>,315 sup: Option<ObjValue>,411 _super_obj: Option<ObjValue>,316 this: Option<ObjValue>,412 ) -> Result<Thunk<Val>> {317 ) -> Result<Thunk<Val>> {413 Ok(Thunk::evaluated(evaluate(318 Ok(Thunk::evaluated(evaluate(414 s,319 s.clone(),415 self.ctx.clone().extend(GcHashMap::new(), None, this, None),320 self.uctx.bind(s, sup, this.clone())?.extend(321 GcHashMap::new(),322 None,323 None,324 this,325 ),416 &self.value,326 &self.value,424 .bindable(334 .bindable(425 s.clone(),335 s.clone(),426 tb!(ObjCompBinding {336 tb!(ObjCompBinding {427 ctx,337 uctx,428 value: obj.value.clone(),338 value: obj.value.clone(),429 }),339 }),430 )?;340 )?;436 })?;346 })?;437347438 let this = builder.build();348 let this = builder.build();349 for (ctx, fctx) in ctxs {350 let _ctx = ctx439 future_this.fill(this.clone());351 .extend(GcHashMap::new(), None, None, Some(this.clone()))352 .into_future(fctx);353 }440 this354 this441 }355 }442 })356 })596 for b in bindings {510 for b in bindings {597 evaluate_dest(b, fctx.clone(), &mut new_bindings)?;511 evaluate_dest(b, fctx.clone(), &mut new_bindings)?;598 }512 }599 let ctx = ctx.extend_bound(new_bindings).into_future(fctx);513 let ctx = ctx.extend(new_bindings, None, None, None).into_future(fctx);600 evaluate(s, ctx, &returned.clone())?514 evaluate(s, ctx, &returned.clone())?601 }515 }602 Arr(items) => {516 Arr(items) => {crates/jrsonnet-evaluator/src/function/mod.rsdiffbeforeafterboth139 ) -> Result<Val> {139 ) -> Result<Val> {140 match self {140 match self {141 Self::Id => {141 Self::Id => {142 #[allow(clippy::unnecessary_wraps)]142 #[builtin]143 #[builtin]143 fn builtin_id(v: Any) -> Result<Any> {144 const fn builtin_id(v: Any) -> Result<Any> {144 Ok(v)145 Ok(v)145 }146 }146 static ID: &'static builtin_id = &builtin_id {};147 static ID: &builtin_id = &builtin_id {};147148148 ID.call(s, call_ctx, loc, args)149 ID.call(s, call_ctx, loc, args)149 }150 }159 self.evaluate(s, Context::default(), CallLocation::native(), args, true)160 self.evaluate(s, Context::default(), CallLocation::native(), args, true)160 }161 }161162162 pub fn is_identity(&self) -> bool {163 pub const fn is_identity(&self) -> bool {163 matches!(self, Self::Id)164 matches!(self, Self::Id)164 }165 }165 pub fn identity() -> Self {166 pub const fn identity() -> Self {166 Self::Id167 Self::Id167 }168 }168}169}crates/jrsonnet-evaluator/src/function/parse.rsdiffbeforeafterboth111111112 Ok(body_ctx112 Ok(body_ctx113 .extend(passed_args, None, None, None)113 .extend(passed_args, None, None, None)114 .extend_bound(defaults)114 .extend(defaults, None, None, None)115 .into_future(fctx))115 .into_future(fctx))116 } else {116 } else {117 let body_ctx = body_ctx.extend(passed_args, None, None, None);117 let body_ctx = body_ctx.extend(passed_args, None, None, None);crates/jrsonnet-evaluator/src/gc.rsdiffbeforeafterboth10use rustc_hash::{FxHashMap, FxHashSet};10use rustc_hash::{FxHashMap, FxHashSet};111112/// Replacement for box, which assumes that the underlying type is [`Trace`]12/// Replacement for box, which assumes that the underlying type is [`Trace`]13/// Used in places, where Cc<dyn Trait> should be used instead, but it can't, because CoerceUnsiced is not stable13/// Used in places, where `Cc<dyn Trait>` should be used instead, but it can't, because `CoerceUnsiced` is not stable14#[derive(Debug, Clone)]14#[derive(Debug, Clone)]15pub struct TraceBox<T: ?Sized>(pub Box<T>);15pub struct TraceBox<T: ?Sized>(pub Box<T>);16#[macro_export]16#[macro_export]crates/jrsonnet-evaluator/src/lib.rsdiffbeforeafterboth61pub use val::{ManifestFormat, Thunk, Val};61pub use val::{ManifestFormat, Thunk, Val};626263pub trait Bindable: Trace + 'static {63pub trait Bindable: Trace + 'static {64 type Bound;64 fn bind(65 fn bind(&self, s: State, sup: Option<ObjValue>, this: Option<ObjValue>) -> Result<Self::Bound>;65 &self,66 s: State,67 this: Option<ObjValue>,68 super_obj: Option<ObjValue>,69 ) -> Result<Thunk<Val>>;70}66}716772#[derive(Clone, Trace)]68#[derive(Clone, Trace)]73pub enum LazyBinding {69pub enum LazyBinding {74 Bindable(Cc<TraceBox<dyn Bindable>>),70 Bindable(Cc<TraceBox<dyn Bindable<Bound = Thunk<Val>>>>),75 Bound(Thunk<Val>),71 Bound(Thunk<Val>),76}72}777384 pub fn evaluate(80 pub fn evaluate(85 &self,81 &self,86 s: State,82 s: State,87 this: Option<ObjValue>,83 sup: Option<ObjValue>,88 super_obj: Option<ObjValue>,84 this: Option<ObjValue>,89 ) -> Result<Thunk<Val>> {85 ) -> Result<Thunk<Val>> {90 match self {86 match self {91 Self::Bindable(v) => v.bind(s, this, super_obj),87 Self::Bindable(v) => v.bind(s, sup, this),92 Self::Bound(v) => Ok(v.clone()),88 Self::Bound(v) => Ok(v.clone()),93 }89 }94 }90 }345 for (name, value) in globals.iter() {341 for (name, value) in globals.iter() {346 new_bindings.insert(name.clone(), Thunk::evaluated(value.clone()));342 new_bindings.insert(name.clone(), Thunk::evaluated(value.clone()));347 }343 }348 Context::new().extend_bound(new_bindings)344 Context::new().extend(new_bindings, None, None, None)349 }345 }350346351 /// Executes code creating a new stack frame347 /// Executes code creating a new stack framecrates/jrsonnet-evaluator/src/obj.rsdiffbeforeafterboth106}106}107107108pub trait ObjectAssertion: Trace {108pub trait ObjectAssertion: Trace {109 fn run(&self, s: State, this: Option<ObjValue>, super_obj: Option<ObjValue>) -> Result<()>;109 fn run(&self, s: State, super_obj: Option<ObjValue>, this: Option<ObjValue>) -> Result<()>;110}110}111111112// Field => This112// Field => This124#[derive(Trace)]124#[derive(Trace)]125#[force_tracking]125#[force_tracking]126pub struct ObjValueInternals {126pub struct ObjValueInternals {127 super_obj: Option<ObjValue>,127 sup: Option<ObjValue>,128 this: Option<ObjValue>,129128 assertions: Cc<Vec<TraceBox<dyn ObjectAssertion>>>,130 assertions: Cc<Vec<TraceBox<dyn ObjectAssertion>>>,129 assertions_ran: RefCell<GcHashSet<ObjValue>>,131 assertions_ran: RefCell<GcHashSet<ObjValue>>,130 this_obj: Option<ObjValue>,131 this_entries: Cc<GcHashMap<IStr, ObjMember>>,132 this_entries: Cc<GcHashMap<IStr, ObjMember>>,132 value_cache: RefCell<GcHashMap<CacheKey, CacheValue>>,133 value_cache: RefCell<GcHashMap<CacheKey, CacheValue>>,133}134}153pub struct ObjValue(pub(crate) Cc<ObjValueInternals>);154pub struct ObjValue(pub(crate) Cc<ObjValueInternals>);154impl Debug for ObjValue {155impl Debug for ObjValue {155 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {156 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {156 if let Some(super_obj) = self.0.super_obj.as_ref() {157 if let Some(super_obj) = self.0.sup.as_ref() {157 if f.alternate() {158 if f.alternate() {158 write!(f, "{:#?}", super_obj)?;159 write!(f, "{:#?}", super_obj)?;159 } else {160 } else {171172172impl ObjValue {173impl ObjValue {173 pub fn new(174 pub fn new(174 super_obj: Option<Self>,175 sup: Option<Self>,175 this_entries: Cc<GcHashMap<IStr, ObjMember>>,176 this_entries: Cc<GcHashMap<IStr, ObjMember>>,176 assertions: Cc<Vec<TraceBox<dyn ObjectAssertion>>>,177 assertions: Cc<Vec<TraceBox<dyn ObjectAssertion>>>,177 ) -> Self {178 ) -> Self {178 Self(Cc::new(ObjValueInternals {179 Self(Cc::new(ObjValueInternals {179 super_obj,180 sup,181 this: None,180 assertions,182 assertions,181 assertions_ran: RefCell::new(GcHashSet::new()),183 assertions_ran: RefCell::new(GcHashSet::new()),182 this_obj: None,183 this_entries,184 this_entries,184 value_cache: RefCell::new(GcHashMap::new()),185 value_cache: RefCell::new(GcHashMap::new()),185 }))186 }))188 Self::new(None, Cc::new(GcHashMap::new()), Cc::new(Vec::new()))189 Self::new(None, Cc::new(GcHashMap::new()), Cc::new(Vec::new()))189 }190 }190 #[must_use]191 #[must_use]191 pub fn extend_from(&self, super_obj: Self) -> Self {192 pub fn extend_from(&self, sup: Self) -> Self {192 match &self.0.super_obj {193 match &self.0.sup {193 None => Self::new(194 None => Self::new(194 Some(super_obj),195 Some(sup),195 self.0.this_entries.clone(),196 self.0.this_entries.clone(),196 self.0.assertions.clone(),197 self.0.assertions.clone(),197 ),198 ),198 Some(v) => Self::new(199 Some(v) => Self::new(199 Some(v.extend_from(super_obj)),200 Some(v.extend_from(sup)),200 self.0.this_entries.clone(),201 self.0.this_entries.clone(),201 self.0.assertions.clone(),202 self.0.assertions.clone(),202 ),203 ),212 }213 }213214214 #[must_use]215 #[must_use]215 pub fn with_this(&self, this_obj: Self) -> Self {216 pub fn with_this(&self, this: Self) -> Self {216 Self(Cc::new(ObjValueInternals {217 Self(Cc::new(ObjValueInternals {217 super_obj: self.0.super_obj.clone(),218 sup: self.0.sup.clone(),218 assertions: self.0.assertions.clone(),219 assertions: self.0.assertions.clone(),219 assertions_ran: RefCell::new(GcHashSet::new()),220 assertions_ran: RefCell::new(GcHashSet::new()),220 this_obj: Some(this_obj),221 this: Some(this),221 this_entries: self.0.this_entries.clone(),222 this_entries: self.0.this_entries.clone(),222 value_cache: RefCell::new(GcHashMap::new()),223 value_cache: RefCell::new(GcHashMap::new()),223 }))224 }))234 if !self.0.this_entries.is_empty() {235 if !self.0.this_entries.is_empty() {235 return false;236 return false;236 }237 }237 self.0.super_obj.as_ref().map_or(true, Self::is_empty)238 self.0.sup.as_ref().map_or(true, Self::is_empty)238 }239 }239240240 /// Run callback for every field found in object241 /// Run callback for every field found in object243 depth: SuperDepth,244 depth: SuperDepth,244 handler: &mut impl FnMut(SuperDepth, &IStr, &ObjMember) -> bool,245 handler: &mut impl FnMut(SuperDepth, &IStr, &ObjMember) -> bool,245 ) -> bool {246 ) -> bool {246 if let Some(s) = &self.0.super_obj {247 if let Some(s) = &self.0.sup {247 if s.enum_fields(depth.deeper(), handler) {248 if s.enum_fields(depth.deeper(), handler) {248 return true;249 return true;249 }250 }332 Some(match &m.visibility {333 Some(match &m.visibility {333 Visibility::Normal => self334 Visibility::Normal => self334 .0335 .0335 .super_obj336 .sup336 .as_ref()337 .as_ref()337 .and_then(|super_obj| super_obj.field_visibility(name))338 .and_then(|super_obj| super_obj.field_visibility(name))338 .unwrap_or(Visibility::Normal),339 .unwrap_or(Visibility::Normal),339 v => *v,340 v => *v,340 })341 })341 } else if let Some(super_obj) = &self.0.super_obj {342 } else if let Some(super_obj) = &self.0.sup {342 super_obj.field_visibility(name)343 super_obj.field_visibility(name)343 } else {344 } else {344 None345 None348 fn has_field_include_hidden(&self, name: IStr) -> bool {349 fn has_field_include_hidden(&self, name: IStr) -> bool {349 if self.0.this_entries.contains_key(&name) {350 if self.0.this_entries.contains_key(&name) {350 true351 true351 } else if let Some(super_obj) = &self.0.super_obj {352 } else if let Some(super_obj) = &self.0.sup {352 super_obj.has_field_include_hidden(name)353 super_obj.has_field_include_hidden(name)353 } else {354 } else {354 false355 false369370370 pub fn get(&self, s: State, key: IStr) -> Result<Option<Val>> {371 pub fn get(&self, s: State, key: IStr) -> Result<Option<Val>> {371 self.run_assertions(s.clone())?;372 self.run_assertions(s.clone())?;372 self.get_raw(s, key, self.0.this_obj.as_ref())373 self.get_raw(s, key, self.0.this.clone().unwrap_or_else(|| self.clone()))373 }374 }374375375 // pub fn extend_with(self, key: )376 // pub fn extend_with(self, key: )376377377 fn get_raw(&self, s: State, key: IStr, real_this: Option<&Self>) -> Result<Option<Val>> {378 fn get_raw(&self, s: State, key: IStr, real_this: Self) -> Result<Option<Val>> {378 let real_this = real_this.unwrap_or(self);379 let cache_key = (key.clone(), WeakObjValue(real_this.0.downgrade()));379 let cache_key = (key.clone(), WeakObjValue(real_this.0.downgrade()));380380381 if let Some(v) = self.0.value_cache.borrow().get(&cache_key) {381 if let Some(v) = self.0.value_cache.borrow().get(&cache_key) {397 .insert(cache_key.clone(), CacheValue::Errored(e.clone()));397 .insert(cache_key.clone(), CacheValue::Errored(e.clone()));398 e398 e399 };399 };400 let value = match (self.0.this_entries.get(&key), &self.0.super_obj) {400 let value = match (self.0.this_entries.get(&key), &self.0.sup) {401 (Some(k), None) => Ok(Some(401 (Some(k), None) => Ok(Some(402 self.evaluate_this(s, k, real_this).map_err(fill_error)?,402 self.evaluate_this(s, k, real_this).map_err(fill_error)?,403 )),403 )),404 (Some(k), Some(super_obj)) => {404 (Some(k), Some(super_obj)) => {405 let our = self405 let our = self406 .evaluate_this(s.clone(), k, real_this)406 .evaluate_this(s.clone(), k, real_this.clone())407 .map_err(fill_error)?;407 .map_err(fill_error)?;408 if k.add {408 if k.add {409 super_obj409 super_obj410 .get_raw(s.clone(), key, Some(real_this))410 .get_raw(s.clone(), key, real_this)411 .map_err(fill_error)?411 .map_err(fill_error)?412 .map_or(Ok(Some(our.clone())), |v| {412 .map_or(Ok(Some(our.clone())), |v| {413 Ok(Some(evaluate_add_op(s.clone(), &v, &our)?))413 Ok(Some(evaluate_add_op(s.clone(), &v, &our)?))416 Ok(Some(our))416 Ok(Some(our))417 }417 }418 }418 }419 (None, Some(super_obj)) => super_obj.get_raw(s, key, Some(real_this)),419 (None, Some(super_obj)) => super_obj.get_raw(s, key, real_this),420 (None, None) => Ok(None),420 (None, None) => Ok(None),421 }421 }422 .map_err(fill_error)?;422 .map_err(fill_error)?;429 );429 );430 Ok(value)430 Ok(value)431 }431 }432 fn evaluate_this(&self, s: State, v: &ObjMember, real_this: &Self) -> Result<Val> {432 fn evaluate_this(&self, s: State, v: &ObjMember, real_this: Self) -> Result<Val> {433 v.invoke433 v.invoke434 .evaluate(s.clone(), Some(real_this.clone()), self.0.super_obj.clone())?434 .evaluate(s.clone(), self.0.sup.clone(), Some(real_this))?435 .evaluate(s)435 .evaluate(s)436 }436 }437437438 fn run_assertions_raw(&self, s: State, real_this: &Self) -> Result<()> {438 fn run_assertions_raw(&self, s: State, real_this: &Self) -> Result<()> {439 if self.0.assertions_ran.borrow_mut().insert(real_this.clone()) {439 if self.0.assertions_ran.borrow_mut().insert(real_this.clone()) {440 for assertion in self.0.assertions.iter() {440 for assertion in self.0.assertions.iter() {441 if let Err(e) =441 if let Err(e) =442 assertion.run(s.clone(), Some(real_this.clone()), self.0.super_obj.clone())442 assertion.run(s.clone(), self.0.sup.clone(), Some(real_this.clone()))443 {443 {444 self.0.assertions_ran.borrow_mut().remove(real_this);444 self.0.assertions_ran.borrow_mut().remove(real_this);445 return Err(e);445 return Err(e);446 }446 }447 }447 }448 if let Some(super_obj) = &self.0.super_obj {448 if let Some(super_obj) = &self.0.sup {449 super_obj.run_assertions_raw(s, real_this)?;449 super_obj.run_assertions_raw(s, real_this)?;450 }450 }451 }451 }458 pub fn ptr_eq(a: &Self, b: &Self) -> bool {458 pub fn ptr_eq(a: &Self, b: &Self) -> bool {459 cc_ptr_eq(&a.0, &b.0)459 cc_ptr_eq(&a.0, &b.0)460 }460 }461 pub fn downgrade(self) -> WeakObjValue {462 WeakObjValue(self.0.downgrade())463 }461}464}462465463impl PartialEq for ObjValue {466impl PartialEq for ObjValue {475478476#[allow(clippy::module_name_repetitions)]479#[allow(clippy::module_name_repetitions)]477pub struct ObjValueBuilder {480pub struct ObjValueBuilder {478 super_obj: Option<ObjValue>,481 sup: Option<ObjValue>,479 map: GcHashMap<IStr, ObjMember>,482 map: GcHashMap<IStr, ObjMember>,480 assertions: Vec<TraceBox<dyn ObjectAssertion>>,483 assertions: Vec<TraceBox<dyn ObjectAssertion>>,481 next_field_index: FieldIndex,484 next_field_index: FieldIndex,486 }489 }487 pub fn with_capacity(capacity: usize) -> Self {490 pub fn with_capacity(capacity: usize) -> Self {488 Self {491 Self {489 super_obj: None,492 sup: None,490 map: GcHashMap::with_capacity(capacity),493 map: GcHashMap::with_capacity(capacity),491 assertions: Vec::new(),494 assertions: Vec::new(),492 next_field_index: FieldIndex::default(),495 next_field_index: FieldIndex::default(),497 self500 self498 }501 }499 pub fn with_super(&mut self, super_obj: ObjValue) -> &mut Self {502 pub fn with_super(&mut self, super_obj: ObjValue) -> &mut Self {500 self.super_obj = Some(super_obj);503 self.sup = Some(super_obj);501 self504 self502 }505 }503506512 }515 }513516514 pub fn build(self) -> ObjValue {517 pub fn build(self) -> ObjValue {515 ObjValue::new(self.super_obj, Cc::new(self.map), Cc::new(self.assertions))518 ObjValue::new(self.sup, Cc::new(self.map), Cc::new(self.assertions))516 }519 }517}520}518impl Default for ObjValueBuilder {521impl Default for ObjValueBuilder {586 pub fn bindable(self, s: State, bindable: TraceBox<dyn Bindable>) -> Result<()> {589 pub fn bindable(590 self,591 s: State,592 bindable: TraceBox<dyn Bindable<Bound = Thunk<Val>>>,593 ) -> Result<()> {587 self.binding(s, LazyBinding::Bindable(Cc::new(bindable)))594 self.binding(s, LazyBinding::Bindable(Cc::new(bindable)))588 }595 }606 pub fn value(self, value: Val) {613 pub fn value(self, value: Val) {607 self.binding(LazyBinding::Bound(Thunk::evaluated(value)));614 self.binding(LazyBinding::Bound(Thunk::evaluated(value)));608 }615 }609 pub fn bindable(self, bindable: TraceBox<dyn Bindable>) {616 pub fn bindable(self, bindable: TraceBox<dyn Bindable<Bound = Thunk<Val>>>) {610 self.binding(LazyBinding::Bindable(Cc::new(bindable)));617 self.binding(LazyBinding::Bindable(Cc::new(bindable)));611 }618 }612 pub fn binding(self, binding: LazyBinding) {619 pub fn binding(self, binding: LazyBinding) {crates/jrsonnet-evaluator/src/stdlib/mod.rsdiffbeforeafterboth466 Ok(ArrValue::Eager(sort::sort(466 Ok(ArrValue::Eager(sort::sort(467 s.clone(),467 s.clone(),468 arr.evaluated(s)?,468 arr.evaluated(s)?,469 keyF.unwrap_or(FuncVal::identity()),469 keyF.unwrap_or_else(FuncVal::identity),470 )?))470 )?))471}471}472472crates/jrsonnet-evaluator/src/stdlib/sort.rsdiffbeforeafterboth68 if values.len() <= 1 {68 if values.len() <= 1 {69 return Ok(values);69 return Ok(values);70 }70 }71 if !key_getter.is_identity() {71 if key_getter.is_identity() {72 // Slow path, user provided key getter72 // Fast path, identity key getter73 let mut vk = Vec::with_capacity(values.len());73 let mut values = (*values).clone();74 for value in values.iter() {75 vk.push((76 value.clone(),77 key_getter.evaluate_simple(s.clone(), &(Any(value.clone()),))?,78 ));79 }80 let sort_type = get_sort_type(&mut vk, |v| &mut v.1)?;74 let sort_type = get_sort_type(&mut values, |k| k)?;81 match sort_type {75 match sort_type {82 SortKeyType::Number => vk.sort_by_key(|v| match v.1 {76 SortKeyType::Number => values.sort_unstable_by_key(|v| match v {83 Val::Num(n) => NonNaNf64(n),77 Val::Num(n) => NonNaNf64(*n),84 _ => unreachable!(),78 _ => unreachable!(),85 }),79 }),86 SortKeyType::String => vk.sort_by_key(|v| match &v.1 {80 SortKeyType::String => values.sort_unstable_by_key(|v| match v {87 Val::Str(s) => s.clone(),81 Val::Str(s) => s.clone(),88 _ => unreachable!(),82 _ => unreachable!(),89 }),83 }),90 SortKeyType::Unknown => unreachable!(),84 SortKeyType::Unknown => unreachable!(),91 };85 };92 Ok(Cc::new(vk.into_iter().map(|v| v.0).collect()))86 Ok(Cc::new(values))93 } else {87 } else {94 // Fast path, identity key getter88 // Slow path, user provided key getter95 let mut values = (*values).clone();89 let mut vk = Vec::with_capacity(values.len());90 for value in values.iter() {91 vk.push((92 value.clone(),93 key_getter.evaluate_simple(s.clone(), &(Any(value.clone()),))?,94 ));95 }96 let sort_type = get_sort_type(&mut values, |k| k)?;96 let sort_type = get_sort_type(&mut vk, |v| &mut v.1)?;97 match sort_type {97 match sort_type {98 SortKeyType::Number => values.sort_unstable_by_key(|v| match v {98 SortKeyType::Number => vk.sort_by_key(|v| match v.1 {99 Val::Num(n) => NonNaNf64(*n),99 Val::Num(n) => NonNaNf64(n),100 _ => unreachable!(),100 _ => unreachable!(),101 }),101 }),102 SortKeyType::String => values.sort_unstable_by_key(|v| match v {102 SortKeyType::String => vk.sort_by_key(|v| match &v.1 {103 Val::Str(s) => s.clone(),103 Val::Str(s) => s.clone(),104 _ => unreachable!(),104 _ => unreachable!(),105 }),105 }),106 SortKeyType::Unknown => unreachable!(),106 SortKeyType::Unknown => unreachable!(),107 };107 };108 Ok(Cc::new(values))108 Ok(Cc::new(vk.into_iter().map(|v| v.0).collect()))109 }109 }110}110}111111crates/jrsonnet-evaluator/src/val.rsdiffbeforeafterboth8 cc_ptr_eq,8 cc_ptr_eq,9 error::{Error::*, LocError},9 error::{Error::*, LocError},10 function::FuncVal,10 function::FuncVal,11 gc::TraceBox,11 gc::{GcHashMap, TraceBox},12 stdlib::manifest::{12 stdlib::manifest::{13 manifest_json_ex, manifest_yaml_ex, ManifestJsonOptions, ManifestType, ManifestYamlOptions,13 manifest_json_ex, manifest_yaml_ex, ManifestJsonOptions, ManifestType, ManifestYamlOptions,14 },14 },15 throw, ObjValue, Result, State,15 throw, Bindable, ObjValue, Result, State, WeakObjValue,16};16};171718pub trait ThunkValue: Trace {18pub trait ThunkValue: Trace {71 }71 }72}72}7374type CacheKey = (Option<WeakObjValue>, Option<WeakObjValue>);7576#[derive(Trace, Clone)]77pub struct CachedBindable<I, T>78where79 I: Bindable<Bound = T>,80{81 cache: Cc<RefCell<GcHashMap<CacheKey, T>>>,82 value: I,83}84impl<I: Bindable<Bound = T>, T: Trace> CachedBindable<I, T> {85 pub fn new(value: I) -> Self {86 Self {87 cache: Cc::new(RefCell::new(GcHashMap::new())),88 value,89 }90 }91}92impl<I: Bindable<Bound = T>, T: Clone + Trace> Bindable for CachedBindable<I, T> {93 type Bound = T;94 fn bind(&self, s: State, sup: Option<ObjValue>, this: Option<ObjValue>) -> Result<T> {95 let cache_key = (96 sup.as_ref().map(|s| s.clone().downgrade()),97 this.as_ref().map(|t| t.clone().downgrade()),98 );99 {100 if let Some(t) = self.cache.borrow().get(&cache_key) {101 return Ok(t.clone());102 }103 }104 let bound = self.value.bind(s, sup, this)?;105106 {107 let mut cache = self.cache.borrow_mut();108 cache.insert(cache_key, bound.clone());109 }110111 Ok(bound)112 }113}7311474impl<T: Debug> Debug for Thunk<T> {115impl<T: Debug> Debug for Thunk<T> {75 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {116 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {crates/jrsonnet-evaluator/tests/builtin.rsdiffbeforeafterboth6use jrsonnet_evaluator::{6use jrsonnet_evaluator::{7 error::Result,7 error::Result,8 function::{builtin, builtin::Builtin, CallLocation, FuncVal},8 function::{builtin, builtin::Builtin, CallLocation, FuncVal},9 gc::TraceBox,10 tb,9 tb,11 typed::Typed,10 typed::Typed,12 State, Val,11 State, Val,crates/jrsonnet-evaluator/tests/common.rsdiffbeforeafterboth32 "assertion failed: a != b\na={:#?}\nb={:#?}",32 "assertion failed: a != b\na={:#?}\nb={:#?}",33 $a.to_json($s.clone(), 2)?,33 $a.to_json(34 $s.clone(),35 2,36 #[cfg(feature = "exp-preserve-order")]37 false38 )?,34 $b.to_json($s.clone(), 2)?,39 $b.to_json(40 $s.clone(),41 2,42 #[cfg(feature = "exp-preserve-order")]43 false44 )?,35 )45 )36 }46 }crates/jrsonnet-evaluator/tests/golden.rsdiffbeforeafterboth26 };26 };27 match v.to_json(s.clone(), 3) {27 match v.to_json(28 s.clone(),29 3,30 #[cfg(feature = "exp-preserve-order")]31 false,32 ) {28 Ok(v) => v.to_string(),33 Ok(v) => v.to_string(),29 Err(e) => s.stringify_err(&e),34 Err(e) => s.stringify_err(&e),crates/jrsonnet-parser/src/lib.rsdiffbeforeafterboth165 / string_block() } / expected!("<string>")165 / string_block() } / expected!("<string>")166166167 pub rule field_name(s: &ParserSettings) -> expr::FieldName167 pub rule field_name(s: &ParserSettings) -> expr::FieldName168 = name:id() {expr::FieldName::Fixed(name.into())}168 = name:id() {expr::FieldName::Fixed(name)}169 / name:string() {expr::FieldName::Fixed(name.into())}169 / name:string() {expr::FieldName::Fixed(name.into())}170 / "[" _ expr:expr(s) _ "]" {expr::FieldName::Dyn(expr)}170 / "[" _ expr:expr(s) _ "]" {expr::FieldName::Dyn(expr)}171 pub rule visibility() -> expr::Visibility171 pub rule visibility() -> expr::Visibility