git.delta.rocks / jrsonnet / refs/commits / 30d381bece76

difftreelog

refactor move state to context

Yaroslav Bolyukin2022-10-26parent: #78d45eb.patch.diff
in: master

46 files changed

modifiedCargo.lockdiffbeforeafterboth
240 "pathdiff",240 "pathdiff",
241 "rustc-hash",241 "rustc-hash",
242 "serde",242 "serde",
243 "serde_json",
244 "static_assertions",243 "static_assertions",
245 "strsim",244 "strsim",
246 "thiserror",245 "thiserror",
541source = "registry+https://github.com/rust-lang/crates.io-index"540source = "registry+https://github.com/rust-lang/crates.io-index"
542checksum = "82c2c1fdcd807d1098552c5b9a36e425e42e9fbd7c6a37a8425f390f781f7fa7"541checksum = "82c2c1fdcd807d1098552c5b9a36e425e42e9fbd7c6a37a8425f390f781f7fa7"
543dependencies = [542dependencies = [
544 "indexmap",
545 "itoa",543 "itoa",
546 "ryu",544 "ryu",
547 "serde",545 "serde",
modifiedbindings/jsonnet/src/import.rsdiffbeforeafterboth
15 error::{Error::*, Result},15 error::{Error::*, Result},
16 throw, FileImportResolver, ImportResolver, State,16 throw, FileImportResolver, ImportResolver, State,
17};17};
18use jrsonnet_gcmodule::Trace;
18use jrsonnet_parser::{SourceDirectory, SourceFile, SourcePath};19use jrsonnet_parser::{SourceDirectory, SourceFile, SourcePath};
1920
20pub type JsonnetImportCallback = unsafe extern "C" fn(21pub type JsonnetImportCallback = unsafe extern "C" fn(
26) -> *mut c_char;27) -> *mut c_char;
2728
28/// Resolves imports using callback29/// Resolves imports using callback
30#[derive(Trace)]
29pub struct CallbackImportResolver {31pub struct CallbackImportResolver {
32 #[trace(skip)]
30 cb: JsonnetImportCallback,33 cb: JsonnetImportCallback,
34 #[trace(skip)]
31 ctx: *mut c_void,35 ctx: *mut c_void,
32 out: RefCell<HashMap<SourcePath, Vec<u8>>>,36 out: RefCell<HashMap<SourcePath, Vec<u8>>>,
33}37}
modifiedbindings/jsonnet/src/lib.rsdiffbeforeafterboth
17};17};
1818
19use jrsonnet_evaluator::{19use jrsonnet_evaluator::{
20 trace::PathResolver, FileImportResolver, IStr, ManifestFormat, State, Val,20 tb, trace::PathResolver, FileImportResolver, IStr, ManifestFormat, State, Val,
21};21};
2222
23/// WASM stub23/// WASM stub
68#[allow(clippy::box_default)]68#[allow(clippy::box_default)]
69pub extern "C" fn jsonnet_make() -> *mut State {69pub extern "C" fn jsonnet_make() -> *mut State {
70 let state = State::default();70 let state = State::default();
71 state.settings_mut().import_resolver = Box::new(FileImportResolver::default());71 state.settings_mut().import_resolver = tb!(FileImportResolver::default());
72 state.settings_mut().context_initializer = Box::new(jrsonnet_stdlib::ContextInitializer::new(72 state.settings_mut().context_initializer = tb!(jrsonnet_stdlib::ContextInitializer::new(
73 state.clone(),73 state.clone(),
74 PathResolver::new_cwd_fallback(),74 PathResolver::new_cwd_fallback(),
75 ));75 ));
modifiedbindings/jsonnet/src/native.rsdiffbeforeafterboth
36 cb: JsonnetNativeCallback,36 cb: JsonnetNativeCallback,
37}37}
38impl NativeCallbackHandler for JsonnetNativeCallbackHandler {38impl NativeCallbackHandler for JsonnetNativeCallbackHandler {
39 fn call(&self, s: State, args: &[Val]) -> Result<Val, LocError> {39 fn call(&self, args: &[Val]) -> Result<Val, LocError> {
40 let mut n_args = Vec::new();40 let mut n_args = Vec::new();
41 for a in args {41 for a in args {
42 n_args.push(Some(Box::new(a.clone())));42 n_args.push(Some(Box::new(a.clone())));
54 if success == 1 {54 if success == 1 {
55 Ok(v)55 Ok(v)
56 } else {56 } else {
57 let e = IStr::from_untyped(v, s).expect("error msg should be a string");57 let e = IStr::from_untyped(v).expect("error msg should be a string");
58 Err(Error::RuntimeError(e).into())58 Err(Error::RuntimeError(e).into())
59 }59 }
60 }60 }
modifiedcrates/jrsonnet-cli/src/stdlib.rsdiffbeforeafterboth
1use std::{fs::read_to_string, str::FromStr};1use std::{fs::read_to_string, str::FromStr};
22
3use clap::Parser;3use clap::Parser;
4use jrsonnet_evaluator::{error::Result, trace::PathResolver, State};4use jrsonnet_evaluator::{error::Result, tb, trace::PathResolver, State};
55
6use crate::ConfigureState;6use crate::ConfigureState;
77
125 for ext in self.ext_code_file.iter() {125 for ext in self.ext_code_file.iter() {
126 ctx.add_ext_code(&ext.name as &str, &ext.value as &str)?;126 ctx.add_ext_code(&ext.name as &str, &ext.value as &str)?;
127 }127 }
128 s.settings_mut().context_initializer = Box::new(ctx);128 s.settings_mut().context_initializer = tb!(ctx);
129 Ok(())129 Ok(())
130 }130 }
131}131}
modifiedcrates/jrsonnet-cli/src/trace.rsdiffbeforeafterboth
49 .as_ref()49 .as_ref()
50 .unwrap_or(&TraceFormatName::Compact)50 .unwrap_or(&TraceFormatName::Compact)
51 {51 {
52 TraceFormatName::Compact => s.set_trace_format(Box::new(CompactFormat {52 TraceFormatName::Compact => s.set_trace_format(CompactFormat {
53 resolver,53 resolver,
54 padding: 4,54 padding: 4,
55 })),55 }),
56 TraceFormatName::Explaining => {56 TraceFormatName::Explaining => s.set_trace_format(ExplainingFormat { resolver }),
57 s.set_trace_format(Box::new(ExplainingFormat { resolver }))
58 }
59 }57 }
60 s.set_max_trace(self.max_trace);58 s.set_max_trace(self.max_trace);
61 Ok(())59 Ok(())
modifiedcrates/jrsonnet-evaluator/src/ctx.rsdiffbeforeafterboth
4use jrsonnet_interner::IStr;4use jrsonnet_interner::IStr;
55
6use crate::{6use crate::{
7 error::Error::*, gc::GcHashMap, map::LayeredHashMap, ObjValue, Pending, Result, Thunk, Val,7 error::Error::*, gc::GcHashMap, map::LayeredHashMap, ObjValue, Pending, Result, State, Thunk,
8 Val,
8};9};
910
10#[derive(Trace)]11#[derive(Trace)]
11struct ContextInternals {12struct ContextInternals {
13 state: Option<State>,
12 dollar: Option<ObjValue>,14 dollar: Option<ObjValue>,
13 sup: Option<ObjValue>,15 sup: Option<ObjValue>,
14 this: Option<ObjValue>,16 this: Option<ObjValue>,
30 Pending::new()32 Pending::new()
31 }33 }
34
35 pub fn state(&self) -> &State {
36 self.0
37 .state
38 .as_ref()
39 .expect("used state from dummy context")
40 }
3241
33 pub fn dollar(&self) -> &Option<ObjValue> {42 pub fn dollar(&self) -> &Option<ObjValue> {
34 &self.0.dollar43 &self.0.dollar
42 &self.0.sup51 &self.0.sup
43 }52 }
44
45 pub fn new() -> Self {
46 Self(Cc::new(ContextInternals {
47 dollar: None,
48 this: None,
49 sup: None,
50 bindings: LayeredHashMap::default(),
51 }))
52 }
5353
54 #[cfg(not(feature = "friendly-errors"))]54 #[cfg(not(feature = "friendly-errors"))]
55 pub fn binding(&self, name: IStr) -> Result<Thunk<Val>> {55 pub fn binding(&self, name: IStr) -> Result<Thunk<Val>> {
122 ctx.bindings.clone().extend(new_bindings)122 ctx.bindings.clone().extend(new_bindings)
123 };123 };
124 Self(Cc::new(ContextInternals {124 Self(Cc::new(ContextInternals {
125 state: ctx.state.clone(),
125 dollar,126 dollar,
126 sup,127 sup,
127 this,128 this,
130 }131 }
131}132}
132133
133impl Default for Context {134// impl Default for Context {
134 fn default() -> Self {135// fn default() -> Self {
135 Self::new()136// Self::new()
136 }137// }
137}138// }
138139
139impl PartialEq for Context {140impl PartialEq for Context {
140 fn eq(&self, other: &Self) -> bool {141 fn eq(&self, other: &Self) -> bool {
143}144}
144145
145pub struct ContextBuilder {146pub struct ContextBuilder {
147 state: Option<State>,
146 bindings: GcHashMap<IStr, Thunk<Val>>,148 bindings: GcHashMap<IStr, Thunk<Val>>,
147 extend: Option<Context>,149 extend: Option<Context>,
148}150}
149151
150impl ContextBuilder {152impl ContextBuilder {
153 /// # Panics
154 /// Panics aren't directly caused by this function, but if state from resulting context is used
155 pub fn dangerous_empty_state() -> Self {
156 Self {
157 state: None,
158 bindings: GcHashMap::new(),
159 extend: None,
160 }
161 }
151 pub fn new() -> Self {162 pub fn new(state: State) -> Self {
152 Self::with_capacity(0)163 Self::with_capacity(state, 0)
153 }164 }
154 pub fn with_capacity(capacity: usize) -> Self {165 pub fn with_capacity(state: State, capacity: usize) -> Self {
155 Self {166 Self {
167 state: Some(state),
156 bindings: GcHashMap::with_capacity(capacity),168 bindings: GcHashMap::with_capacity(capacity),
157 extend: None,169 extend: None,
158 }170 }
159 }171 }
160 pub fn extend(parent: Context) -> Self {172 pub fn extend(parent: Context) -> Self {
161 Self {173 Self {
174 state: parent.0.state.clone(),
162 bindings: GcHashMap::new(),175 bindings: GcHashMap::new(),
163 extend: Some(parent),176 extend: Some(parent),
164 }177 }
172 }185 }
173 pub fn build(self) -> Context {186 pub fn build(self) -> Context {
174 if let Some(parent) = self.extend {187 if let Some(parent) = self.extend {
188 // TODO: replace self.extend with Result<Context, State>, and remove `state` field
175 parent.extend(self.bindings, None, None, None)189 parent.extend(self.bindings, None, None, None)
176 } else {190 } else {
177 Context(Cc::new(ContextInternals {191 Context(Cc::new(ContextInternals {
192 state: self.state,
178 bindings: LayeredHashMap::new(self.bindings),193 bindings: LayeredHashMap::new(self.bindings),
179 dollar: None,194 dollar: None,
180 sup: None,195 sup: None,
184 }199 }
185}200}
186
187impl Default for ContextBuilder {
188 fn default() -> Self {
189 Self::new()
190 }
191}
192201
modifiedcrates/jrsonnet-evaluator/src/error.rsdiffbeforeafterboth
1use std::{fmt::Debug, path::PathBuf};1use std::{
2 fmt::{Debug, Display},
3 path::PathBuf,
4};
25
3use jrsonnet_gcmodule::Trace;6use jrsonnet_gcmodule::Trace;
252 &mut (self.0).1255 &mut (self.0).1
253 }256 }
254}257}
255impl Debug for LocError {258impl Display for LocError {
256 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {259 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
257 writeln!(f, "{}", self.0 .0)?;260 writeln!(f, "{}", self.0 .0)?;
258 for el in &self.0 .1 .0 {261 for el in &self.0 .1 .0 {
262 write!(f, "\t{}", el.desc)?;
263 if let Some(loc) = &el.location {
264 write!(f, "at {}", loc.0 .0 .0)?;
265 // loc.0
266 loc.0.map_source_locations(&[loc.1, loc.2]);
267 }
259 writeln!(f, "\t{el:?}")?;268 writeln!(f)?;
260 }269 }
261 Ok(())270 Ok(())
262 }271 }
263}272}
273impl Debug for LocError {
274 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
275 f.debug_tuple("LocError").field(&self.0).finish()
276 }
277}
264278
265pub trait ErrorSource {279pub trait ErrorSource {
266 fn to_location(self) -> Option<ExprLocation>;280 fn to_location(self) -> Option<ExprLocation>;
modifiedcrates/jrsonnet-evaluator/src/evaluate/destructure.rsdiffbeforeafterboth
8 gc::GcHashMap,8 gc::GcHashMap,
9 tb, throw,9 tb, throw,
10 val::ThunkValue,10 val::ThunkValue,
11 Context, Pending, State, Thunk, Val,11 Context, Pending, Thunk, Val,
12};12};
1313
14#[allow(clippy::too_many_lines)]14#[allow(clippy::too_many_lines)]
261 }261 }
262 impl ThunkValue for EvaluateThunkValue {262 impl ThunkValue for EvaluateThunkValue {
263 type Output = Val;263 type Output = Val;
264 fn get(self: Box<Self>, s: State) -> Result<Self::Output> {264 fn get(self: Box<Self>) -> Result<Self::Output> {
265 if let Some(name) = self.name {265 self.name.map_or_else(
266 evaluate_named(s, self.fctx.unwrap(), &self.expr, name)266 || evaluate(self.fctx.unwrap(), &self.expr),
267 } else {
268 evaluate(s, self.fctx.unwrap(), &self.expr)267 |name| evaluate_named(self.fctx.unwrap(), &self.expr, name),
269 }268 )
270 }269 }
271 }270 }
272 let data = Thunk::new(tb!(EvaluateThunkValue {271 let data = Thunk::new(tb!(EvaluateThunkValue {
291 impl ThunkValue for MethodThunk {290 impl ThunkValue for MethodThunk {
292 type Output = Val;291 type Output = Val;
293292
294 fn get(self: Box<Self>, _s: State) -> Result<Self::Output> {293 fn get(self: Box<Self>) -> Result<Self::Output> {
295 Ok(evaluate_method(294 Ok(evaluate_method(
296 self.fctx.unwrap(),295 self.fctx.unwrap(),
297 self.name,296 self.name,
modifiedcrates/jrsonnet-evaluator/src/evaluate/mod.rsdiffbeforeafterboth
31 })))31 })))
32}32}
3333
34pub fn evaluate_field_name(s: State, ctx: Context, field_name: &FieldName) -> Result<Option<IStr>> {34pub fn evaluate_field_name(ctx: Context, field_name: &FieldName) -> Result<Option<IStr>> {
35 Ok(match field_name {35 Ok(match field_name {
36 FieldName::Fixed(n) => Some(n.clone()),36 FieldName::Fixed(n) => Some(n.clone()),
37 FieldName::Dyn(expr) => State::push(37 FieldName::Dyn(expr) => State::push(
38 CallLocation::new(&expr.1),38 CallLocation::new(&expr.1),
39 || "evaluating field name".to_string(),39 || "evaluating field name".to_string(),
40 || {40 || {
41 let value = evaluate(s.clone(), ctx, expr)?;41 let value = evaluate(ctx, expr)?;
42 if matches!(value, Val::Null) {42 if matches!(value, Val::Null) {
43 Ok(None)43 Ok(None)
44 } else {44 } else {
45 Ok(Some(IStr::from_untyped(value, s.clone())?))45 Ok(Some(IStr::from_untyped(value)?))
46 }46 }
47 },47 },
48 )?,48 )?,
49 })49 })
50}50}
5151
52pub fn evaluate_comp(52pub fn evaluate_comp(
53 s: State,
54 ctx: Context,53 ctx: Context,
55 specs: &[CompSpec],54 specs: &[CompSpec],
56 callback: &mut impl FnMut(Context) -> Result<()>,55 callback: &mut impl FnMut(Context) -> Result<()>,
57) -> Result<()> {56) -> Result<()> {
58 match specs.get(0) {57 match specs.get(0) {
59 None => callback(ctx)?,58 None => callback(ctx)?,
60 Some(CompSpec::IfSpec(IfSpecData(cond))) => {59 Some(CompSpec::IfSpec(IfSpecData(cond))) => {
61 if bool::from_untyped(evaluate(s.clone(), ctx.clone(), cond)?, s.clone())? {60 if bool::from_untyped(evaluate(ctx.clone(), cond)?)? {
62 evaluate_comp(s, ctx, &specs[1..], callback)?;61 evaluate_comp(ctx, &specs[1..], callback)?;
63 }62 }
64 }63 }
65 Some(CompSpec::ForSpec(ForSpecData(var, expr))) => {64 Some(CompSpec::ForSpec(ForSpecData(var, expr))) => match evaluate(ctx.clone(), expr)? {
66 match evaluate(s.clone(), ctx.clone(), expr)? {
67 Val::Arr(list) => {65 Val::Arr(list) => {
68 for item in list.iter(s.clone()) {66 for item in list.iter() {
69 evaluate_comp(67 evaluate_comp(
70 s.clone(),
71 ctx.clone().with_var(var.clone(), item?.clone()),68 ctx.clone().with_var(var.clone(), item?.clone()),
72 &specs[1..],69 &specs[1..],
73 callback,70 callback,
74 )?;71 )?;
75 }72 }
76 }73 }
77 _ => throw!(InComprehensionCanOnlyIterateOverArray),74 _ => throw!(InComprehensionCanOnlyIterateOverArray),
78 }75 },
79 }
80 }76 }
81 Ok(())77 Ok(())
82}78}
9894
99 fn bind(95 fn bind(&self, sup: Option<ObjValue>, this: Option<ObjValue>) -> Result<Context> {
100 &self,
101 _s: State,
102 sup: Option<ObjValue>,
103 this: Option<ObjValue>,
104 ) -> Result<Context> {
105 let fctx = Context::new_future();96 let fctx = Context::new_future();
106 let mut new_bindings = GcHashMap::new();97 let mut new_bindings = GcHashMap::new();
123}114}
124115
125#[allow(clippy::too_many_lines)]116#[allow(clippy::too_many_lines)]
126pub fn evaluate_member_list_object(s: State, ctx: Context, members: &[Member]) -> Result<ObjValue> {117pub fn evaluate_member_list_object(ctx: Context, members: &[Member]) -> Result<ObjValue> {
127 let mut builder = ObjValueBuilder::new();118 let mut builder = ObjValueBuilder::new();
128 let locals = Rc::new(119 let locals = Rc::new(
129 members120 members
159 type Bound = Thunk<Val>;150 type Bound = Thunk<Val>;
160 fn bind(151 fn bind(
161 &self,152 &self,
162 s: State,
163 sup: Option<ObjValue>,153 sup: Option<ObjValue>,
164 this: Option<ObjValue>,154 this: Option<ObjValue>,
165 ) -> Result<Thunk<Val>> {155 ) -> Result<Thunk<Val>> {
166 Ok(Thunk::evaluated(evaluate_named(156 Ok(Thunk::evaluated(evaluate_named(
167 s.clone(),
168 self.uctx.bind(s, sup, this)?,157 self.uctx.bind(sup, this)?,
169 &self.value,158 &self.value,
170 self.name.clone(),159 self.name.clone(),
171 )?))160 )?))
172 }161 }
173 }162 }
174163
175 let name = evaluate_field_name(s.clone(), ctx.clone(), name)?;164 let name = evaluate_field_name(ctx.clone(), name)?;
176 let name = if let Some(name) = name {165 let name = if let Some(name) = name {
177 name166 name
178 } else {167 } else {
207 type Bound = Thunk<Val>;196 type Bound = Thunk<Val>;
208 fn bind(197 fn bind(
209 &self,198 &self,
210 s: State,
211 sup: Option<ObjValue>,199 sup: Option<ObjValue>,
212 this: Option<ObjValue>,200 this: Option<ObjValue>,
213 ) -> Result<Thunk<Val>> {201 ) -> Result<Thunk<Val>> {
214 Ok(Thunk::evaluated(evaluate_method(202 Ok(Thunk::evaluated(evaluate_method(
215 self.uctx.bind(s, sup, this)?,203 self.uctx.bind(sup, this)?,
216 self.name.clone(),204 self.name.clone(),
217 self.params.clone(),205 self.params.clone(),
218 self.value.clone(),206 self.value.clone(),
219 )))207 )))
220 }208 }
221 }209 }
222210
223 let name = if let Some(name) = evaluate_field_name(s.clone(), ctx.clone(), name)? {211 let name = if let Some(name) = evaluate_field_name(ctx.clone(), name)? {
224 name212 name
225 } else {213 } else {
226 continue;214 continue;
247 impl<B: Unbound<Bound = Context>> ObjectAssertion for ObjectAssert<B> {235 impl<B: Unbound<Bound = Context>> ObjectAssertion for ObjectAssert<B> {
248 fn run(236 fn run(&self, sup: Option<ObjValue>, this: Option<ObjValue>) -> Result<()> {
249 &self,
250 s: State,
251 sup: Option<ObjValue>,
252 this: Option<ObjValue>,
253 ) -> Result<()> {
254 let ctx = self.uctx.bind(s.clone(), sup, this)?;237 let ctx = self.uctx.bind(sup, this)?;
255 evaluate_assert(s, ctx, &self.assert)238 evaluate_assert(ctx, &self.assert)
256 }239 }
257 }240 }
258 builder.assert(tb!(ObjectAssert {241 builder.assert(tb!(ObjectAssert {
267 Ok(this)250 Ok(this)
268}251}
269252
270pub fn evaluate_object(s: State, ctx: Context, object: &ObjBody) -> Result<ObjValue> {253pub fn evaluate_object(ctx: Context, object: &ObjBody) -> Result<ObjValue> {
271 Ok(match object {254 Ok(match object {
272 ObjBody::MemberList(members) => evaluate_member_list_object(s, ctx, members)?,255 ObjBody::MemberList(members) => evaluate_member_list_object(ctx, members)?,
273 ObjBody::ObjComp(obj) => {256 ObjBody::ObjComp(obj) => {
274 let mut builder = ObjValueBuilder::new();257 let mut builder = ObjValueBuilder::new();
275 let locals = Rc::new(258 let locals = Rc::new(
280 .collect::<Vec<_>>(),263 .collect::<Vec<_>>(),
281 );264 );
282 let mut ctxs = vec![];265 let mut ctxs = vec![];
283 evaluate_comp(s.clone(), ctx, &obj.compspecs, &mut |ctx| {266 evaluate_comp(ctx, &obj.compspecs, &mut |ctx| {
284 let key = evaluate(s.clone(), ctx.clone(), &obj.key)?;267 let key = evaluate(ctx.clone(), &obj.key)?;
285 let fctx = Context::new_future();268 let fctx = Context::new_future();
286 ctxs.push((ctx, fctx.clone()));269 ctxs.push((ctx, fctx.clone()));
287 let uctx = evaluate_object_locals(fctx, locals.clone());270 let uctx = evaluate_object_locals(fctx, locals.clone());
298 type Bound = Thunk<Val>;281 type Bound = Thunk<Val>;
299 fn bind(282 fn bind(
300 &self,283 &self,
301 s: State,
302 sup: Option<ObjValue>,284 sup: Option<ObjValue>,
303 this: Option<ObjValue>,285 this: Option<ObjValue>,
304 ) -> Result<Thunk<Val>> {286 ) -> Result<Thunk<Val>> {
305 Ok(Thunk::evaluated(evaluate(287 Ok(Thunk::evaluated(evaluate(
306 s.clone(),
307 self.uctx.bind(s, sup, this.clone())?.extend(288 self.uctx.bind(sup, this.clone())?.extend(
308 GcHashMap::new(),289 GcHashMap::new(),
309 None,290 None,
310 None,291 None,
341}322}
342323
343pub fn evaluate_apply(324pub fn evaluate_apply(
344 s: State,
345 ctx: Context,325 ctx: Context,
346 value: &LocExpr,326 value: &LocExpr,
347 args: &ArgsDesc,327 args: &ArgsDesc,
348 loc: CallLocation<'_>,328 loc: CallLocation<'_>,
349 tailstrict: bool,329 tailstrict: bool,
350) -> Result<Val> {330) -> Result<Val> {
351 let value = evaluate(s.clone(), ctx.clone(), value)?;331 let value = evaluate(ctx.clone(), value)?;
352 Ok(match value {332 Ok(match value {
353 Val::Func(f) => {333 Val::Func(f) => {
354 let body = || f.evaluate(s.clone(), ctx, loc, args, tailstrict);334 let body = || f.evaluate(ctx, loc, args, tailstrict);
355 if tailstrict {335 if tailstrict {
356 body()?336 body()?
357 } else {337 } else {
362 })342 })
363}343}
364344
365pub fn evaluate_assert(s: State, ctx: Context, assertion: &AssertStmt) -> Result<()> {345pub fn evaluate_assert(ctx: Context, assertion: &AssertStmt) -> Result<()> {
366 let value = &assertion.0;346 let value = &assertion.0;
367 let msg = &assertion.1;347 let msg = &assertion.1;
368 let assertion_result = State::push(348 let assertion_result = State::push(
369 CallLocation::new(&value.1),349 CallLocation::new(&value.1),
370 || "assertion condition".to_owned(),350 || "assertion condition".to_owned(),
371 || bool::from_untyped(evaluate(s.clone(), ctx.clone(), value)?, s.clone()),351 || bool::from_untyped(evaluate(ctx.clone(), value)?),
372 )?;352 )?;
373 if !assertion_result {353 if !assertion_result {
374 State::push(354 State::push(
377 || {357 || {
378 if let Some(msg) = msg {358 if let Some(msg) = msg {
379 throw!(AssertionFailed(359 throw!(AssertionFailed(evaluate(ctx, msg)?.to_string()?));
380 evaluate(s.clone(), ctx, msg)?.to_string(s.clone())?
381 ));
382 }360 }
383 throw!(AssertionFailed(Val::Null.to_string(s.clone())?));361 throw!(AssertionFailed(Val::Null.to_string()?));
384 },362 },
385 )?;363 )?;
386 }364 }
387 Ok(())365 Ok(())
388}366}
389367
390pub fn evaluate_named(s: State, ctx: Context, expr: &LocExpr, name: IStr) -> Result<Val> {368pub fn evaluate_named(ctx: Context, expr: &LocExpr, name: IStr) -> Result<Val> {
391 use Expr::*;369 use Expr::*;
392 let LocExpr(raw_expr, _loc) = expr;370 let LocExpr(raw_expr, _loc) = expr;
393 Ok(match &**raw_expr {371 Ok(match &**raw_expr {
394 Function(params, body) => evaluate_method(ctx, name, params.clone(), body.clone()),372 Function(params, body) => evaluate_method(ctx, name, params.clone(), body.clone()),
395 _ => evaluate(s, ctx, expr)?,373 _ => evaluate(ctx, expr)?,
396 })374 })
397}375}
398376
399#[allow(clippy::too_many_lines)]377#[allow(clippy::too_many_lines)]
400pub fn evaluate(s: State, ctx: Context, expr: &LocExpr) -> Result<Val> {378pub fn evaluate(ctx: Context, expr: &LocExpr) -> Result<Val> {
401 use Expr::*;379 use Expr::*;
402 let LocExpr(expr, loc) = expr;380 let LocExpr(expr, loc) = expr;
403 // let bp = with_state(|s| s.0.stop_at.borrow().clone());381 // let bp = with_state(|s| s.0.stop_at.borrow().clone());
418 Literal(LiteralType::True) => Val::Bool(true),396 Literal(LiteralType::True) => Val::Bool(true),
419 Literal(LiteralType::False) => Val::Bool(false),397 Literal(LiteralType::False) => Val::Bool(false),
420 Literal(LiteralType::Null) => Val::Null,398 Literal(LiteralType::Null) => Val::Null,
421 Parened(e) => evaluate(s, ctx, e)?,399 Parened(e) => evaluate(ctx, e)?,
422 Str(v) => Val::Str(v.clone()),400 Str(v) => Val::Str(v.clone()),
423 Num(v) => Val::new_checked_num(*v)?,401 Num(v) => Val::new_checked_num(*v)?,
424 BinaryOp(v1, o, v2) => evaluate_binary_op_special(s, ctx, v1, *o, v2)?,402 BinaryOp(v1, o, v2) => evaluate_binary_op_special(ctx, v1, *o, v2)?,
425 UnaryOp(o, v) => evaluate_unary_op(*o, &evaluate(s, ctx, v)?)?,403 UnaryOp(o, v) => evaluate_unary_op(*o, &evaluate(ctx, v)?)?,
426 Var(name) => State::push(404 Var(name) => State::push(
427 CallLocation::new(loc),405 CallLocation::new(loc),
428 || format!("variable <{name}> access"),406 || format!("variable <{name}> access"),
429 || ctx.binding(name.clone())?.evaluate(s.clone()),407 || ctx.binding(name.clone())?.evaluate(),
430 )?,408 )?,
431 Index(value, index) => {409 Index(value, index) => match (evaluate(ctx.clone(), value)?, evaluate(ctx, index)?) {
432 match (
433 evaluate(s.clone(), ctx.clone(), value)?,
434 evaluate(s.clone(), ctx, index)?,
435 ) {
436 (Val::Obj(v), Val::Str(key)) => State::push(410 (Val::Obj(v), Val::Str(key)) => State::push(
437 CallLocation::new(loc),411 CallLocation::new(loc),
438 || format!("field <{key}> access"),412 || format!("field <{key}> access"),
439 || match v.get(s.clone(), key.clone()) {413 || match v.get(key.clone()) {
440 Ok(Some(v)) => Ok(v),414 Ok(Some(v)) => Ok(v),
441 #[cfg(not(feature = "friendly-errors"))]415 #[cfg(not(feature = "friendly-errors"))]
442 Ok(None) => throw!(NoSuchField(key.clone(), vec![])),416 Ok(None) => throw!(NoSuchField(key.clone(), vec![])),
474 if n.fract() > f64::EPSILON {448 if n.fract() > f64::EPSILON {
475 throw!(FractionalIndex)449 throw!(FractionalIndex)
476 }450 }
477 v.get(s, n as usize)?451 v.get(n as usize)?
478 .ok_or_else(|| ArrayBoundsError(n as usize, v.len()))?452 .ok_or_else(|| ArrayBoundsError(n as usize, v.len()))?
479 }453 }
480 (Val::Arr(_), Val::Str(n)) => throw!(AttemptedIndexAnArrayWithString(n)),454 (Val::Arr(_), Val::Str(n)) => throw!(AttemptedIndexAnArrayWithString(n)),
504 )),478 )),
505479
506 (v, _) => throw!(CantIndexInto(v.value_type())),480 (v, _) => throw!(CantIndexInto(v.value_type())),
507 }481 },
508 }
509 LocalExpr(bindings, returned) => {482 LocalExpr(bindings, returned) => {
510 let mut new_bindings: GcHashMap<IStr, Thunk<Val>> =483 let mut new_bindings: GcHashMap<IStr, Thunk<Val>> =
511 GcHashMap::with_capacity(bindings.len());484 GcHashMap::with_capacity(bindings.len());
514 evaluate_dest(b, fctx.clone(), &mut new_bindings)?;487 evaluate_dest(b, fctx.clone(), &mut new_bindings)?;
515 }488 }
516 let ctx = ctx.extend(new_bindings, None, None, None).into_future(fctx);489 let ctx = ctx.extend(new_bindings, None, None, None).into_future(fctx);
517 evaluate(s, ctx, &returned.clone())?490 evaluate(ctx, &returned.clone())?
518 }491 }
519 Arr(items) => {492 Arr(items) => {
520 let mut out = Vec::with_capacity(items.len());493 let mut out = Vec::with_capacity(items.len());
527 }500 }
528 impl ThunkValue for ArrayElement {501 impl ThunkValue for ArrayElement {
529 type Output = Val;502 type Output = Val;
530 fn get(self: Box<Self>, s: State) -> Result<Val> {503 fn get(self: Box<Self>) -> Result<Val> {
531 evaluate(s, self.ctx, &self.item)504 evaluate(self.ctx, &self.item)
532 }505 }
533 }506 }
534 out.push(Thunk::new(tb!(ArrayElement {507 out.push(Thunk::new(tb!(ArrayElement {
540 }513 }
541 ArrComp(expr, comp_specs) => {514 ArrComp(expr, comp_specs) => {
542 let mut out = Vec::new();515 let mut out = Vec::new();
543 evaluate_comp(s.clone(), ctx, comp_specs, &mut |ctx| {516 evaluate_comp(ctx, comp_specs, &mut |ctx| {
544 out.push(evaluate(s.clone(), ctx, expr)?);517 out.push(evaluate(ctx, expr)?);
545 Ok(())518 Ok(())
546 })?;519 })?;
547 Val::Arr(ArrValue::Eager(Cc::new(out)))520 Val::Arr(ArrValue::Eager(Cc::new(out)))
548 }521 }
549 Obj(body) => Val::Obj(evaluate_object(s, ctx, body)?),522 Obj(body) => Val::Obj(evaluate_object(ctx, body)?),
550 ObjExtend(a, b) => evaluate_add_op(523 ObjExtend(a, b) => evaluate_add_op(
551 s.clone(),
552 &evaluate(s.clone(), ctx.clone(), a)?,524 &evaluate(ctx.clone(), a)?,
553 &Val::Obj(evaluate_object(s, ctx, b)?),525 &Val::Obj(evaluate_object(ctx, b)?),
554 )?,526 )?,
555 Apply(value, args, tailstrict) => {527 Apply(value, args, tailstrict) => {
556 evaluate_apply(s, ctx, value, args, CallLocation::new(loc), *tailstrict)?528 evaluate_apply(ctx, value, args, CallLocation::new(loc), *tailstrict)?
557 }529 }
558 Function(params, body) => {530 Function(params, body) => {
559 evaluate_method(ctx, "anonymous".into(), params.clone(), body.clone())531 evaluate_method(ctx, "anonymous".into(), params.clone(), body.clone())
560 }532 }
561 AssertExpr(assert, returned) => {533 AssertExpr(assert, returned) => {
562 evaluate_assert(s.clone(), ctx.clone(), assert)?;534 evaluate_assert(ctx.clone(), assert)?;
563 evaluate(s, ctx, returned)?535 evaluate(ctx, returned)?
564 }536 }
565 ErrorStmt(e) => State::push(537 ErrorStmt(e) => State::push(
566 CallLocation::new(loc),538 CallLocation::new(loc),
567 || "error statement".to_owned(),539 || "error statement".to_owned(),
568 || {540 || throw!(RuntimeError(evaluate(ctx, e)?.to_string()?,)),
569 throw!(RuntimeError(
570 evaluate(s.clone(), ctx, e)?.to_string(s.clone())?,
571 ))
572 },
573 )?,541 )?,
574 IfElse {542 IfElse {
575 cond,543 cond,
579 if State::push(547 if State::push(
580 CallLocation::new(loc),548 CallLocation::new(loc),
581 || "if condition".to_owned(),549 || "if condition".to_owned(),
582 || bool::from_untyped(evaluate(s.clone(), ctx.clone(), &cond.0)?, s.clone()),550 || bool::from_untyped(evaluate(ctx.clone(), &cond.0)?),
583 )? {551 )? {
584 evaluate(s, ctx, cond_then)?552 evaluate(ctx, cond_then)?
585 } else {553 } else {
586 match cond_else {554 match cond_else {
587 Some(v) => evaluate(s, ctx, v)?,555 Some(v) => evaluate(ctx, v)?,
588 None => Val::Null,556 None => Val::Null,
589 }557 }
590 }558 }
591 }559 }
592 Slice(value, desc) => {560 Slice(value, desc) => {
593 fn parse_idx<T: Typed>(561 fn parse_idx<T: Typed>(
594 loc: CallLocation<'_>,562 loc: CallLocation<'_>,
595 s: State,
596 ctx: &Context,563 ctx: &Context,
597 expr: &Option<LocExpr>,564 expr: &Option<LocExpr>,
598 desc: &'static str,565 desc: &'static str,
601 Ok(Some(State::push(568 Ok(Some(State::push(
602 loc,569 loc,
603 || format!("slice {desc}"),570 || format!("slice {desc}"),
604 || T::from_untyped(evaluate(s.clone(), ctx.clone(), value)?, s.clone()),571 || T::from_untyped(evaluate(ctx.clone(), value)?),
605 )?))572 )?))
606 } else {573 } else {
607 Ok(None)574 Ok(None)
608 }575 }
609 }576 }
610577
611 let indexable = evaluate(s.clone(), ctx.clone(), value)?;578 let indexable = evaluate(ctx.clone(), value)?;
612 let loc = CallLocation::new(loc);579 let loc = CallLocation::new(loc);
613580
614 let start = parse_idx(loc, s.clone(), &ctx, &desc.start, "start")?;581 let start = parse_idx(loc, &ctx, &desc.start, "start")?;
615 let end = parse_idx(loc, s.clone(), &ctx, &desc.end, "end")?;582 let end = parse_idx(loc, &ctx, &desc.end, "end")?;
616 let step = parse_idx(loc, s.clone(), &ctx, &desc.step, "step")?;583 let step = parse_idx(loc, &ctx, &desc.step, "step")?;
617584
618 IndexableVal::into_untyped(indexable.into_indexable()?.slice(start, end, step)?, s)?585 IndexableVal::into_untyped(indexable.into_indexable()?.slice(start, end, step)?)?
619 }586 }
620 i @ (Import(path) | ImportStr(path) | ImportBin(path)) => {587 i @ (Import(path) | ImportStr(path) | ImportBin(path)) => {
621 let tmp = loc.clone().0;588 let tmp = loc.clone().0;
589 let s = ctx.state();
622 let resolved_path = s.resolve_from(tmp.source_path(), path as &str)?;590 let resolved_path = s.resolve_from(tmp.source_path(), path as &str)?;
623 match i {591 match i {
624 Import(_) => State::push(592 Import(_) => State::push(
modifiedcrates/jrsonnet-evaluator/src/evaluate/operator.rsdiffbeforeafterboth
44
5use crate::{5use crate::{
6 error::Error::*, evaluate, stdlib::std_format, throw, typed::Typed, val::equals, Context,6 error::Error::*, evaluate, stdlib::std_format, throw, typed::Typed, val::equals, Context,
7 Result, State, Val,7 Result, Val,
8};8};
99
10pub fn evaluate_unary_op(op: UnaryOpType, b: &Val) -> Result<Val> {10pub fn evaluate_unary_op(op: UnaryOpType, b: &Val) -> Result<Val> {
18 })18 })
19}19}
2020
21pub fn evaluate_add_op(s: State, a: &Val, b: &Val) -> Result<Val> {21pub fn evaluate_add_op(a: &Val, b: &Val) -> Result<Val> {
22 use Val::*;22 use Val::*;
23 Ok(match (a, b) {23 Ok(match (a, b) {
24 (Str(a), Str(b)) if a.is_empty() => Val::Str(b.clone()),24 (Str(a), Str(b)) if a.is_empty() => Val::Str(b.clone()),
29 (Num(a), Str(b)) => Str(format!("{a}{b}").into()),29 (Num(a), Str(b)) => Str(format!("{a}{b}").into()),
30 (Str(a), Num(b)) => Str(format!("{a}{b}").into()),30 (Str(a), Num(b)) => Str(format!("{a}{b}").into()),
3131
32 (Str(a), o) | (o, Str(a)) if a.is_empty() => Val::Str(o.clone().to_string(s)?),32 (Str(a), o) | (o, Str(a)) if a.is_empty() => Val::Str(o.clone().to_string()?),
33 (Str(a), o) => Str(format!("{a}{}", o.clone().to_string(s)?).into()),33 (Str(a), o) => Str(format!("{a}{}", o.clone().to_string()?).into()),
34 (o, Str(a)) => Str(format!("{}{a}", o.clone().to_string(s)?).into()),34 (o, Str(a)) => Str(format!("{}{a}", o.clone().to_string()?).into()),
3535
36 (Obj(v1), Obj(v2)) => Obj(v2.extend_from(v1.clone())),36 (Obj(v1), Obj(v2)) => Obj(v2.extend_from(v1.clone())),
37 (Arr(a), Arr(b)) => {37 (Arr(a), Arr(b)) => {
49 })49 })
50}50}
5151
52pub fn evaluate_mod_op(s: State, a: &Val, b: &Val) -> Result<Val> {52pub fn evaluate_mod_op(a: &Val, b: &Val) -> Result<Val> {
53 use Val::*;53 use Val::*;
54 match (a, b) {54 match (a, b) {
55 (Num(a), Num(b)) => {55 (Num(a), Num(b)) => {
58 }58 }
59 Ok(Num(a % b))59 Ok(Num(a % b))
60 }60 }
61 (Str(str), vals) => {61 (Str(str), vals) => String::into_untyped(std_format(str.clone(), vals.clone())?),
62 String::into_untyped(std_format(s.clone(), str.clone(), vals.clone())?, s)
63 }
64 (a, b) => throw!(BinaryOperatorDoesNotOperateOnValues(62 (a, b) => throw!(BinaryOperatorDoesNotOperateOnValues(
65 BinaryOpType::Mod,63 BinaryOpType::Mod,
66 a.value_type(),64 a.value_type(),
70}68}
7169
72pub fn evaluate_binary_op_special(70pub fn evaluate_binary_op_special(
73 s: State,
74 ctx: Context,71 ctx: Context,
75 a: &LocExpr,72 a: &LocExpr,
76 op: BinaryOpType,73 op: BinaryOpType,
77 b: &LocExpr,74 b: &LocExpr,
78) -> Result<Val> {75) -> Result<Val> {
79 use BinaryOpType::*;76 use BinaryOpType::*;
80 use Val::*;77 use Val::*;
81 Ok(match (evaluate(s.clone(), ctx.clone(), a)?, op, b) {78 Ok(match (evaluate(ctx.clone(), a)?, op, b) {
82 (Bool(true), Or, _o) => Val::Bool(true),79 (Bool(true), Or, _o) => Val::Bool(true),
83 (Bool(false), And, _o) => Val::Bool(false),80 (Bool(false), And, _o) => Val::Bool(false),
84 (a, op, eb) => evaluate_binary_op_normal(s.clone(), &a, op, &evaluate(s, ctx, eb)?)?,81 (a, op, eb) => evaluate_binary_op_normal(&a, op, &evaluate(ctx, eb)?)?,
85 })82 })
86}83}
8784
88pub fn evaluate_compare_op(s: State, a: &Val, op: BinaryOpType, b: &Val) -> Result<Ordering> {85pub fn evaluate_compare_op(a: &Val, op: BinaryOpType, b: &Val) -> Result<Ordering> {
89 use Val::*;86 use Val::*;
90 Ok(match (a, b) {87 Ok(match (a, b) {
91 (Str(a), Str(b)) => a.cmp(b),88 (Str(a), Str(b)) => a.cmp(b),
92 (Num(a), Num(b)) => a.partial_cmp(b).expect("jsonnet numbers are non NaN"),89 (Num(a), Num(b)) => a.partial_cmp(b).expect("jsonnet numbers are non NaN"),
93 (Arr(a), Arr(b)) => {90 (Arr(a), Arr(b)) => {
94 let ai = a.iter(s.clone());91 let ai = a.iter();
95 let bi = b.iter(s.clone());92 let bi = b.iter();
9693
97 for (a, b) in ai.zip(bi) {94 for (a, b) in ai.zip(bi) {
98 let ord = evaluate_compare_op(s.clone(), &a?, op, &b?)?;95 let ord = evaluate_compare_op(&a?, op, &b?)?;
99 if !ord.is_eq() {96 if !ord.is_eq() {
100 return Ok(ord);97 return Ok(ord);
101 }98 }
111 })108 })
112}109}
113110
114pub fn evaluate_binary_op_normal(s: State, a: &Val, op: BinaryOpType, b: &Val) -> Result<Val> {111pub fn evaluate_binary_op_normal(a: &Val, op: BinaryOpType, b: &Val) -> Result<Val> {
115 use BinaryOpType::*;112 use BinaryOpType::*;
116 use Val::*;113 use Val::*;
117 Ok(match (a, op, b) {114 Ok(match (a, op, b) {
118 (a, Add, b) => evaluate_add_op(s, a, b)?,115 (a, Add, b) => evaluate_add_op(a, b)?,
119116
120 (a, Eq, b) => Bool(equals(s, a, b)?),117 (a, Eq, b) => Bool(equals(a, b)?),
121 (a, Neq, b) => Bool(!equals(s, a, b)?),118 (a, Neq, b) => Bool(!equals(a, b)?),
122119
123 (a, Lt, b) => Bool(evaluate_compare_op(s, a, Lt, b)?.is_lt()),120 (a, Lt, b) => Bool(evaluate_compare_op(a, Lt, b)?.is_lt()),
124 (a, Gt, b) => Bool(evaluate_compare_op(s, a, Gt, b)?.is_gt()),121 (a, Gt, b) => Bool(evaluate_compare_op(a, Gt, b)?.is_gt()),
125 (a, Lte, b) => Bool(evaluate_compare_op(s, a, Lte, b)?.is_le()),122 (a, Lte, b) => Bool(evaluate_compare_op(a, Lte, b)?.is_le()),
126 (a, Gte, b) => Bool(evaluate_compare_op(s, a, Gte, b)?.is_ge()),123 (a, Gte, b) => Bool(evaluate_compare_op(a, Gte, b)?.is_ge()),
127124
128 (Str(a), In, Obj(obj)) => Bool(obj.has_field_ex(a.clone(), true)),125 (Str(a), In, Obj(obj)) => Bool(obj.has_field_ex(a.clone(), true)),
129 (a, Mod, b) => evaluate_mod_op(s, a, b)?,126 (a, Mod, b) => evaluate_mod_op(a, b)?,
130127
131 (Str(v1), Mul, Num(v2)) => Str(v1.repeat(*v2 as usize).into()),128 (Str(v1), Mul, Num(v2)) => Str(v1.repeat(*v2 as usize).into()),
132129
modifiedcrates/jrsonnet-evaluator/src/function/arglike.rsdiffbeforeafterboth
5use jrsonnet_parser::{ArgsDesc, LocExpr};5use jrsonnet_parser::{ArgsDesc, LocExpr};
66
7use crate::{7use crate::{error::Result, evaluate, tb, typed::Typed, val::ThunkValue, Context, Thunk, Val};
8 error::Result, evaluate, tb, typed::Typed, val::ThunkValue, Context, State, Thunk, Val,8
9};9/// Marker for arguments, which can be evaluated with context set to None
10pub trait OptionalContext {}
1011
11#[derive(Trace)]12#[derive(Trace)]
12struct EvaluateThunk {13struct EvaluateThunk {
15}16}
16impl ThunkValue for EvaluateThunk {17impl ThunkValue for EvaluateThunk {
17 type Output = Val;18 type Output = Val;
18 fn get(self: Box<Self>, s: State) -> Result<Val> {19 fn get(self: Box<Self>) -> Result<Val> {
19 evaluate(s, self.ctx, &self.expr)20 evaluate(self.ctx, &self.expr)
20 }21 }
21}22}
2223
23pub trait ArgLike {24pub trait ArgLike {
24 fn evaluate_arg(&self, s: State, ctx: Context, tailstrict: bool) -> Result<Thunk<Val>>;25 fn evaluate_arg(&self, ctx: Context, tailstrict: bool) -> Result<Thunk<Val>>;
25}26}
2627
27impl ArgLike for &LocExpr {28impl ArgLike for &LocExpr {
28 fn evaluate_arg(&self, s: State, ctx: Context, tailstrict: bool) -> Result<Thunk<Val>> {29 fn evaluate_arg(&self, ctx: Context, tailstrict: bool) -> Result<Thunk<Val>> {
29 Ok(if tailstrict {30 Ok(if tailstrict {
30 Thunk::evaluated(evaluate(s, ctx, self)?)31 Thunk::evaluated(evaluate(ctx, self)?)
31 } else {32 } else {
32 Thunk::new(tb!(EvaluateThunk {33 Thunk::new(tb!(EvaluateThunk {
33 ctx,34 ctx,
41where42where
42 T: Typed + Clone,43 T: Typed + Clone,
43{44{
44 fn evaluate_arg(&self, s: State, _ctx: Context, _tailstrict: bool) -> Result<Thunk<Val>> {45 fn evaluate_arg(&self, _ctx: Context, _tailstrict: bool) -> Result<Thunk<Val>> {
45 let val = T::into_untyped(self.clone(), s)?;46 let val = T::into_untyped(self.clone())?;
46 Ok(Thunk::evaluated(val))47 Ok(Thunk::evaluated(val))
47 }48 }
48}49}
50impl<T> OptionalContext for T where T: Typed + Clone {}
4951
50#[derive(Clone)]52#[derive(Clone, Trace)]
51pub enum TlaArg {53pub enum TlaArg {
52 String(IStr),54 String(IStr),
53 Code(LocExpr),55 Code(LocExpr),
54 Val(Val),56 Val(Val),
55}57}
56impl ArgLike for TlaArg {58impl ArgLike for TlaArg {
57 fn evaluate_arg(&self, s: State, ctx: Context, tailstrict: bool) -> Result<Thunk<Val>> {59 fn evaluate_arg(&self, ctx: Context, tailstrict: bool) -> Result<Thunk<Val>> {
58 match self {60 match self {
59 TlaArg::String(s) => Ok(Thunk::evaluated(Val::Str(s.clone()))),61 TlaArg::String(s) => Ok(Thunk::evaluated(Val::Str(s.clone()))),
60 TlaArg::Code(code) => Ok(if tailstrict {62 TlaArg::Code(code) => Ok(if tailstrict {
61 Thunk::evaluated(evaluate(s, ctx, code)?)63 Thunk::evaluated(evaluate(ctx, code)?)
62 } else {64 } else {
63 Thunk::new(tb!(EvaluateThunk {65 Thunk::new(tb!(EvaluateThunk {
64 ctx,66 ctx,
81 fn unnamed_len(&self) -> usize;83 fn unnamed_len(&self) -> usize;
82 fn unnamed_iter(84 fn unnamed_iter(
83 &self,85 &self,
84 s: State,
85 ctx: Context,86 ctx: Context,
86 tailstrict: bool,87 tailstrict: bool,
87 handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,88 handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,
88 ) -> Result<()>;89 ) -> Result<()>;
89 fn named_iter(90 fn named_iter(
90 &self,91 &self,
91 s: State,
92 ctx: Context,92 ctx: Context,
93 tailstrict: bool,93 tailstrict: bool,
94 handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,94 handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,
102 }102 }
103 fn unnamed_iter(103 fn unnamed_iter(
104 &self,104 &self,
105 _s: State,
106 _ctx: Context,105 _ctx: Context,
107 _tailstrict: bool,106 _tailstrict: bool,
108 handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,107 handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,
114 }113 }
115 fn named_iter(114 fn named_iter(
116 &self,115 &self,
117 _s: State,
118 _ctx: Context,116 _ctx: Context,
119 _tailstrict: bool,117 _tailstrict: bool,
120 _handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,118 _handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,
123 }121 }
124 fn named_names(&self, _handler: &mut dyn FnMut(&IStr)) {}122 fn named_names(&self, _handler: &mut dyn FnMut(&IStr)) {}
125}123}
124impl OptionalContext for Vec<Val> {}
126125
127impl ArgsLike for ArgsDesc {126impl ArgsLike for ArgsDesc {
128 fn unnamed_len(&self) -> usize {127 fn unnamed_len(&self) -> usize {
131130
132 fn unnamed_iter(131 fn unnamed_iter(
133 &self,132 &self,
134 s: State,
135 ctx: Context,133 ctx: Context,
136 tailstrict: bool,134 tailstrict: bool,
137 handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,135 handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,
140 handler(138 handler(
141 id,139 id,
142 if tailstrict {140 if tailstrict {
143 Thunk::evaluated(evaluate(s.clone(), ctx.clone(), arg)?)141 Thunk::evaluated(evaluate(ctx.clone(), arg)?)
144 } else {142 } else {
145 Thunk::new(tb!(EvaluateThunk {143 Thunk::new(tb!(EvaluateThunk {
146 ctx: ctx.clone(),144 ctx: ctx.clone(),
154152
155 fn named_iter(153 fn named_iter(
156 &self,154 &self,
157 s: State,
158 ctx: Context,155 ctx: Context,
159 tailstrict: bool,156 tailstrict: bool,
160 handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,157 handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,
163 handler(160 handler(
164 name,161 name,
165 if tailstrict {162 if tailstrict {
166 Thunk::evaluated(evaluate(s.clone(), ctx.clone(), arg)?)163 Thunk::evaluated(evaluate(ctx.clone(), arg)?)
167 } else {164 } else {
168 Thunk::new(tb!(EvaluateThunk {165 Thunk::new(tb!(EvaluateThunk {
169 ctx: ctx.clone(),166 ctx: ctx.clone(),
190187
191 fn unnamed_iter(188 fn unnamed_iter(
192 &self,189 &self,
193 _s: State,
194 _ctx: Context,190 _ctx: Context,
195 _tailstrict: bool,191 _tailstrict: bool,
196 _handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,192 _handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,
200196
201 fn named_iter(197 fn named_iter(
202 &self,198 &self,
203 s: State,
204 ctx: Context,199 ctx: Context,
205 tailstrict: bool,200 tailstrict: bool,
206 handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,201 handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,
207 ) -> Result<()> {202 ) -> Result<()> {
208 for (name, value) in self.iter() {203 for (name, value) in self.iter() {
209 handler(204 handler(name, value.evaluate_arg(ctx.clone(), tailstrict)?)?;
210 name,
211 value.evaluate_arg(s.clone(), ctx.clone(), tailstrict)?,
212 )?;
213 }205 }
214 Ok(())206 Ok(())
220 }212 }
221 }213 }
222}214}
215impl<A, S> OptionalContext for HashMap<IStr, A, S> where A: ArgLike + OptionalContext {}
223216
224macro_rules! impl_args_like {217macro_rules! impl_args_like {
225 ($count:expr; $($gen:ident)*) => {218 ($count:expr; $($gen:ident)*) => {
231 #[allow(non_snake_case, unused_assignments)]224 #[allow(non_snake_case, unused_assignments)]
232 fn unnamed_iter(225 fn unnamed_iter(
233 &self,226 &self,
234 s: State,
235 ctx: Context,227 ctx: Context,
236 tailstrict: bool,228 tailstrict: bool,
237 handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,229 handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,
238 ) -> Result<()> {230 ) -> Result<()> {
239 let mut i = 0usize;231 let mut i = 0usize;
240 let ($($gen,)*) = self;232 let ($($gen,)*) = self;
241 $(233 $(
242 handler(i, $gen.evaluate_arg(s.clone(), ctx.clone(), tailstrict)?)?;234 handler(i, $gen.evaluate_arg(ctx.clone(), tailstrict)?)?;
243 i+=1;235 i+=1;
244 )*236 )*
245 Ok(())237 Ok(())
246 }238 }
247 fn named_iter(239 fn named_iter(
248 &self,240 &self,
249 _s: State,
250 _ctx: Context,241 _ctx: Context,
251 _tailstrict: bool,242 _tailstrict: bool,
252 _handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,243 _handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,
255 }246 }
256 fn named_names(&self, _handler: &mut dyn FnMut(&IStr)) {}247 fn named_names(&self, _handler: &mut dyn FnMut(&IStr)) {}
257 }248 }
258 impl<$($gen: ArgLike,)*> sealed::Named for ($((IStr, $gen),)*) {}249 impl<$($gen: ArgLike,)*> OptionalContext for ($($gen,)*) where $($gen: OptionalContext),* {}
250
251 impl<$($gen: ArgLike,)*> sealed::Named for ($((IStr, $gen),)*) {}
259 impl<$($gen: ArgLike,)*> ArgsLike for ($((IStr, $gen),)*) {252 impl<$($gen: ArgLike,)*> ArgsLike for ($((IStr, $gen),)*) {
260 fn unnamed_len(&self) -> usize {253 fn unnamed_len(&self) -> usize {
261 0254 0
262 }255 }
263 fn unnamed_iter(256 fn unnamed_iter(
264 &self,257 &self,
265 _s: State,
266 _ctx: Context,258 _ctx: Context,
267 _tailstrict: bool,259 _tailstrict: bool,
268 _handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,260 _handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,
272 #[allow(non_snake_case)]264 #[allow(non_snake_case)]
273 fn named_iter(265 fn named_iter(
274 &self,266 &self,
275 s: State,
276 ctx: Context,267 ctx: Context,
277 tailstrict: bool,268 tailstrict: bool,
278 handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,269 handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,
279 ) -> Result<()> {270 ) -> Result<()> {
280 let ($($gen,)*) = self;271 let ($($gen,)*) = self;
281 $(272 $(
282 handler(&$gen.0, $gen.1.evaluate_arg(s.clone(), ctx.clone(), tailstrict)?)?;273 handler(&$gen.0, $gen.1.evaluate_arg(ctx.clone(), tailstrict)?)?;
283 )*274 )*
284 Ok(())275 Ok(())
285 }276 }
291 )*282 )*
292 }283 }
293 }284 }
285 impl<$($gen: ArgLike,)*> OptionalContext for ($((IStr, $gen),)*) where $($gen: OptionalContext),* {}
294 };286 };
295 ($count:expr; $($cur:ident)* @ $c:ident $($rest:ident)*) => {287 ($count:expr; $($cur:ident)* @ $c:ident $($rest:ident)*) => {
296 impl_args_like!($count; $($cur)*);288 impl_args_like!($count; $($cur)*);
312304
313 fn unnamed_iter(305 fn unnamed_iter(
314 &self,306 &self,
315 _s: State,
316 _ctx: Context,307 _ctx: Context,
317 _tailstrict: bool,308 _tailstrict: bool,
318 _handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,309 _handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,
322313
323 fn named_iter(314 fn named_iter(
324 &self,315 &self,
325 _s: State,
326 _ctx: Context,316 _ctx: Context,
327 _tailstrict: bool,317 _tailstrict: bool,
328 _handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,318 _handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,
332322
333 fn named_names(&self, _handler: &mut dyn FnMut(&IStr)) {}323 fn named_names(&self, _handler: &mut dyn FnMut(&IStr)) {}
334}324}
325impl OptionalContext for () {}
335326
modifiedcrates/jrsonnet-evaluator/src/function/builtin.rsdiffbeforeafterboth
3use jrsonnet_gcmodule::Trace;3use jrsonnet_gcmodule::Trace;
44
5use super::{arglike::ArgsLike, parse::parse_builtin_call, CallLocation};5use super::{arglike::ArgsLike, parse::parse_builtin_call, CallLocation};
6use crate::{error::Result, gc::TraceBox, Context, State, Val};6use crate::{error::Result, gc::TraceBox, Context, Val};
77
8pub type BuiltinParamName = Cow<'static, str>;8pub type BuiltinParamName = Cow<'static, str>;
99
26 /// Call the builtin26 /// Call the builtin
27 fn call(27 fn call(&self, ctx: Context, loc: CallLocation<'_>, args: &dyn ArgsLike) -> Result<Val>;
28 &self,
29 s: State,
30 ctx: Context,
31 loc: CallLocation<'_>,
32 args: &dyn ArgsLike,
33 ) -> Result<Val>;
34}28}
3529
7872
79 fn call(73 fn call(&self, ctx: Context, _loc: CallLocation<'_>, args: &dyn ArgsLike) -> Result<Val> {
80 &self,
81 s: State,
82 ctx: Context,
83 _loc: CallLocation<'_>,
84 args: &dyn ArgsLike,
85 ) -> Result<Val> {
86 let args = parse_builtin_call(s.clone(), ctx, &self.params, args, true)?;74 let args = parse_builtin_call(ctx, &self.params, args, true)?;
87 let args = args75 let args = args
88 .into_iter()76 .into_iter()
89 .map(|a| a.expect("legacy natives have no default params"))77 .map(|a| a.expect("legacy natives have no default params"))
90 .map(|a| a.evaluate(s.clone()))78 .map(|a| a.evaluate())
91 .collect::<Result<Vec<Val>>>()?;79 .collect::<Result<Vec<Val>>>()?;
92 self.handler.call(s, &args)80 self.handler.call(&args)
93 }81 }
94}82}
9583
96pub trait NativeCallbackHandler: Trace {84pub trait NativeCallbackHandler: Trace {
97 fn call(&self, s: State, args: &[Val]) -> Result<Val>;85 fn call(&self, args: &[Val]) -> Result<Val>;
98}86}
9987
modifiedcrates/jrsonnet-evaluator/src/function/mod.rsdiffbeforeafterboth
7use jrsonnet_parser::{Destruct, Expr, ExprLocation, LocExpr, ParamsDesc};7use jrsonnet_parser::{Destruct, Expr, ExprLocation, LocExpr, ParamsDesc};
88
9use self::{9use self::{
10 arglike::OptionalContext,
10 builtin::{Builtin, StaticBuiltin},11 builtin::{Builtin, StaticBuiltin},
11 native::NativeDesc,12 native::NativeDesc,
12 parse::{parse_default_function_call, parse_function_call},13 parse::{parse_default_function_call, parse_function_call},
13};14};
14use crate::{evaluate, gc::TraceBox, typed::Any, Context, Result, State, Val};15use crate::{evaluate, gc::TraceBox, typed::Any, Context, ContextBuilder, Result, Val};
1516
16pub mod arglike;17pub mod arglike;
17pub mod builtin;18pub mod builtin;
73 /// Create context, with which body code will run74 /// Create context, with which body code will run
74 pub fn call_body_context(75 pub fn call_body_context(
75 &self,76 &self,
76 s: State,
77 call_ctx: Context,77 call_ctx: Context,
78 args: &dyn ArgsLike,78 args: &dyn ArgsLike,
79 tailstrict: bool,79 tailstrict: bool,
80 ) -> Result<Context> {80 ) -> Result<Context> {
81 parse_function_call(81 parse_function_call(call_ctx, self.ctx.clone(), &self.params, args, tailstrict)
82 s,
83 call_ctx,
84 self.ctx.clone(),
85 &self.params,
86 args,
87 tailstrict,
88 )
89 }82 }
90}83}
140 /// If `tailstrict` is specified - then arguments will be evaluated before being passed to function body.133 /// If `tailstrict` is specified - then arguments will be evaluated before being passed to function body.
141 pub fn evaluate(134 pub fn evaluate(
142 &self,135 &self,
143 s: State,
144 call_ctx: Context,136 call_ctx: Context,
145 loc: CallLocation<'_>,137 loc: CallLocation<'_>,
146 args: &dyn ArgsLike,138 args: &dyn ArgsLike,
155 }147 }
156 static ID: &builtin_id = &builtin_id {};148 static ID: &builtin_id = &builtin_id {};
157149
158 ID.call(s, call_ctx, loc, args)150 ID.call(call_ctx, loc, args)
159 }151 }
160 Self::Normal(func) => {152 Self::Normal(func) => {
161 let body_ctx = func.call_body_context(s.clone(), call_ctx, args, tailstrict)?;153 let body_ctx = func.call_body_context(call_ctx, args, tailstrict)?;
162 evaluate(s, body_ctx, &func.body)154 evaluate(body_ctx, &func.body)
163 }155 }
164 Self::StaticBuiltin(b) => b.call(s, call_ctx, loc, args),156 Self::StaticBuiltin(b) => b.call(call_ctx, loc, args),
165 Self::Builtin(b) => b.call(s, call_ctx, loc, args),157 Self::Builtin(b) => b.call(call_ctx, loc, args),
166 }158 }
167 }159 }
168 /// Helper method, which calls [`Self::evaluate`] with sensible defaults for native code.
169 pub fn evaluate_simple(&self, s: State, args: &dyn ArgsLike) -> Result<Val> {160 pub fn evaluate_simple<A: ArgsLike + OptionalContext>(&self, args: &A) -> Result<Val> {
170 self.evaluate(s, Context::default(), CallLocation::native(), args, true)161 self.evaluate(
162 ContextBuilder::dangerous_empty_state().build(),
163 CallLocation::native(),
164 args,
165 true,
180 ///176 ///
181 /// This function should only be used for optimization, not for the conditional logic, i.e code should work with syntetic identity function too177 /// This function should only be used for optimization, not for the conditional logic, i.e code should work with syntetic identity function too
182 pub fn is_identity(&self) -> bool {178 pub fn is_identity(&self) -> bool {
183 if matches!(self, Self::Id) {
184 return true;
185 }
186
187 match self {179 match self {
188 Self::Id => true,180 Self::Id => true,
modifiedcrates/jrsonnet-evaluator/src/function/native.rsdiffbeforeafterboth
1use super::{arglike::ArgLike, CallLocation, FuncVal};1use super::{
2 arglike::{ArgLike, OptionalContext},
3 FuncVal,
4};
2use crate::{error::Result, typed::Typed, Context, State};5use crate::{error::Result, typed::Typed};
36
4pub trait NativeDesc {7pub trait NativeDesc {
5 type Value;8 type Value;
9 ($($gen:ident)*) => {12 ($($gen:ident)*) => {
10 impl<$($gen,)* O> NativeDesc for (($($gen,)*), O)13 impl<$($gen,)* O> NativeDesc for (($($gen,)*), O)
11 where14 where
12 $($gen: ArgLike,)*15 $($gen: ArgLike + OptionalContext,)*
13 O: Typed,16 O: Typed,
14 {17 {
15 type Value = Box<dyn Fn(State, $($gen,)*) -> Result<O>>;18 type Value = Box<dyn Fn($($gen,)*) -> Result<O>>;
1619
17 #[allow(non_snake_case)]20 #[allow(non_snake_case)]
18 fn into_native(val: FuncVal) -> Self::Value {21 fn into_native(val: FuncVal) -> Self::Value {
19 Box::new(move |s: State, $($gen),*| {22 Box::new(move |$($gen),*| {
20 let val = val.evaluate(23 let val = val.evaluate_simple(
21 s.clone(),
22 // This isn't intended to be used with ArgsDesc
23 Context::default(),
24 CallLocation::native(),
25 &($($gen,)*),24 &($($gen,)*),
26 true
27 )?;25 )?;
28 O::from_untyped(val, s.clone())26 O::from_untyped(val)
29 })27 })
30 }28 }
31 }29 }
modifiedcrates/jrsonnet-evaluator/src/function/parse.rsdiffbeforeafterboth
12 gc::GcHashMap,12 gc::GcHashMap,
13 tb, throw,13 tb, throw,
14 val::ThunkValue,14 val::ThunkValue,
15 Context, Pending, State, Thunk, Val,15 Context, Pending, Thunk, Val,
16};16};
1717
18#[derive(Trace)]18#[derive(Trace)]
2424
25impl ThunkValue for EvaluateNamedThunk {25impl ThunkValue for EvaluateNamedThunk {
26 type Output = Val;26 type Output = Val;
27 fn get(self: Box<Self>, s: State) -> Result<Val> {27 fn get(self: Box<Self>) -> Result<Val> {
28 evaluate_named(s, self.ctx.unwrap(), &self.value, self.name)28 evaluate_named(self.ctx.unwrap(), &self.value, self.name)
29 }29 }
30}30}
3131
38/// * `args`: passed function arguments38/// * `args`: passed function arguments
39/// * `tailstrict`: if set to `true` function arguments are eagerly executed, otherwise - lazily39/// * `tailstrict`: if set to `true` function arguments are eagerly executed, otherwise - lazily
40pub fn parse_function_call(40pub fn parse_function_call(
41 s: State,
42 ctx: Context,41 ctx: Context,
43 body_ctx: Context,42 body_ctx: Context,
44 params: &ParamsDesc,43 params: &ParamsDesc,
56 let mut filled_named = 0;55 let mut filled_named = 0;
57 let mut filled_positionals = 0;56 let mut filled_positionals = 0;
5857
59 args.unnamed_iter(s.clone(), ctx.clone(), tailstrict, &mut |id, arg| {58 args.unnamed_iter(ctx.clone(), tailstrict, &mut |id, arg| {
60 let name = params[id].0.clone();59 let name = params[id].0.clone();
61 destruct(60 destruct(
62 &name,61 &name,
68 Ok(())67 Ok(())
69 })?;68 })?;
7069
71 args.named_iter(s, ctx, tailstrict, &mut |name, value| {70 args.named_iter(ctx, tailstrict, &mut |name, value| {
72 // FIXME: O(n) for arg existence check71 // FIXME: O(n) for arg existence check
73 if !params.iter().any(|p| p.0.name().as_ref() == Some(name)) {72 if !params.iter().any(|p| p.0.name().as_ref() == Some(name)) {
74 throw!(UnknownFunctionParameter((name as &str).to_owned()));73 throw!(UnknownFunctionParameter((name as &str).to_owned()));
150/// * `args`: passed function arguments149/// * `args`: passed function arguments
151/// * `tailstrict`: if set to `true` function arguments are eagerly executed, otherwise - lazily150/// * `tailstrict`: if set to `true` function arguments are eagerly executed, otherwise - lazily
152pub fn parse_builtin_call(151pub fn parse_builtin_call(
153 s: State,
154 ctx: Context,152 ctx: Context,
155 params: &[BuiltinParam],153 params: &[BuiltinParam],
156 args: &dyn ArgsLike,154 args: &dyn ArgsLike,
169167
170 let mut filled_args = 0;168 let mut filled_args = 0;
171169
172 args.unnamed_iter(s.clone(), ctx.clone(), tailstrict, &mut |id, arg| {170 args.unnamed_iter(ctx.clone(), tailstrict, &mut |id, arg| {
173 passed_args[id] = Some(arg);171 passed_args[id] = Some(arg);
174 filled_args += 1;172 filled_args += 1;
175 Ok(())173 Ok(())
176 })?;174 })?;
177175
178 args.named_iter(s, ctx, tailstrict, &mut |name, arg| {176 args.named_iter(ctx, tailstrict, &mut |name, arg| {
179 // FIXME: O(n) for arg existence check177 // FIXME: O(n) for arg existence check
180 let id = params178 let id = params
181 .iter()179 .iter()
232 struct DependsOnUnbound(IStr, ParamsDesc);230 struct DependsOnUnbound(IStr, ParamsDesc);
233 impl ThunkValue for DependsOnUnbound {231 impl ThunkValue for DependsOnUnbound {
234 type Output = Val;232 type Output = Val;
235 fn get(self: Box<Self>, _: State) -> Result<Val> {233 fn get(self: Box<Self>) -> Result<Val> {
236 Err(FunctionParameterNotBoundInCall(234 Err(FunctionParameterNotBoundInCall(
237 Some(self.0.clone()),235 Some(self.0.clone()),
238 self.1.iter().map(|p| (p.0.name(), p.1.is_some())).collect(),236 self.1.iter().map(|p| (p.0.name(), p.1.is_some())).collect(),
modifiedcrates/jrsonnet-evaluator/src/import.rsdiffbeforeafterboth
8};8};
99
10use fs::File;10use fs::File;
11use jrsonnet_gcmodule::Trace;
11use jrsonnet_parser::{SourceDirectory, SourceFile, SourcePath};12use jrsonnet_parser::{SourceDirectory, SourceFile, SourcePath};
1213
13use crate::{14use crate::{
19};20};
2021
21/// Implements file resolution logic for `import` and `importStr`22/// Implements file resolution logic for `import` and `importStr`
22pub trait ImportResolver {23pub trait ImportResolver: Trace {
23 /// Resolves file path, e.g. `(/home/user/manifests, b.libjsonnet)` can correspond24 /// Resolves file path, e.g. `(/home/user/manifests, b.libjsonnet)` can correspond
24 /// both to `/home/user/manifests/b.libjsonnet` and to `/home/user/${vendor}/b.libjsonnet`25 /// both to `/home/user/manifests/b.libjsonnet` and to `/home/user/${vendor}/b.libjsonnet`
25 /// where `${vendor}` is a library path.26 /// where `${vendor}` is a library path.
47}48}
4849
49/// Dummy resolver, can't resolve/load any file50/// Dummy resolver, can't resolve/load any file
51#[derive(Trace)]
50pub struct DummyImportResolver;52pub struct DummyImportResolver;
51impl ImportResolver for DummyImportResolver {53impl ImportResolver for DummyImportResolver {
52 fn load_file_contents(&self, _resolved: &SourcePath) -> Result<Vec<u8>> {54 fn load_file_contents(&self, _resolved: &SourcePath) -> Result<Vec<u8>> {
65}67}
6668
67/// File resolver, can load file from both FS and library paths69/// File resolver, can load file from both FS and library paths
68#[derive(Default)]70#[derive(Default, Trace)]
69pub struct FileImportResolver {71pub struct FileImportResolver {
70 /// Library directories to search for file.72 /// Library directories to search for file.
71 /// Referred to as `jpath` in original jsonnet implementation.73 /// Referred to as `jpath` in original jsonnet implementation.
modifiedcrates/jrsonnet-evaluator/src/integrations/serde.rsdiffbeforeafterboth
3use jrsonnet_gcmodule::Cc;3use jrsonnet_gcmodule::Cc;
4use serde::{de::Visitor, ser::Error, Deserialize, Serialize};4use serde::{
5 de::Visitor,
6 ser::{Error, SerializeMap, SerializeSeq},
7 Deserialize, Serialize,
8};
59
6use crate::{error::Result, val::ArrValue, ObjValueBuilder, State, Val};10use crate::{error::Result, val::ArrValue, ObjValueBuilder, State, Val};
152 Val::Num(n) => serializer.serialize_f64(*n),156 Val::Num(n) => serializer.serialize_f64(*n),
153 Val::Arr(arr) => {157 Val::Arr(arr) => {
154 let mut seq = serializer.serialize_seq(Some(arr.len()))?;158 let mut seq = serializer.serialize_seq(Some(arr.len()))?;
155 for element in arr.iter(State::default()) {159 for (i, element) in arr.iter().enumerate() {
156 // seq.serialize_element()160 let mut serde_error = None;
161 // TODO: rewrite using try{} after stabilization
162 State::push_description(
163 || format!("array index [{i}]"),
164 || {
165 let e = element?;
166 if let Err(e) = seq.serialize_element(&e) {
167 serde_error = Some(e);
168 }
169 Ok(())
170 },
171 )
172 .map_err(|e| S::Error::custom(e.to_string()))?;
173 if let Some(e) = serde_error {
174 return Err(e);
157 }175 }
176 }
158 todo!()177 seq.end()
159 }178 }
160 Val::Obj(_) => todo!(),179 Val::Obj(obj) => {
180 let mut map = serializer.serialize_map(Some(obj.len()))?;
181 for (field, value) in obj.iter() {
182 let mut serde_error = None;
183 // TODO: rewrite using try{} after stabilization
184 State::push_description(
185 || format!("object field {field:?}"),
186 || {
187 let v = value?;
188 if let Err(e) = map.serialize_entry(field.as_str(), &v) {
189 serde_error = Some(e);
190 }
191 Ok(())
192 },
193 )
194 .map_err(|e| S::Error::custom(e.to_string()))?;
195 if let Some(e) = serde_error {
196 return Err(e);
197 }
198 }
199 map.end()
200 }
161 Val::Func(_) => Err(S::Error::custom("tried to manifest function")),201 Val::Func(_) => Err(S::Error::custom("tried to manifest function")),
162 }202 }
163 }203 }
modifiedcrates/jrsonnet-evaluator/src/lib.rsdiffbeforeafterboth
36 clippy::use_self,36 clippy::use_self,
37 // https://github.com/rust-lang/rust-clippy/issues/853937 // https://github.com/rust-lang/rust-clippy/issues/8539
38 clippy::iter_with_drain,38 clippy::iter_with_drain,
39 // ci is being run with nightly, but library should work on stable
40 clippy::missing_const_for_fn,
39)]41)]
4042
41// For jrsonnet-macros43// For jrsonnet-macros
63 collections::HashMap,65 collections::HashMap,
64 fmt::{self, Debug},66 fmt::{self, Debug},
65 path::Path,67 path::Path,
66 rc::Rc,
67};68};
6869
69pub use ctx::*;70pub use ctx::*;
89 /// Type of value after object context is bound90 /// Type of value after object context is bound
90 type Bound;91 type Bound;
91 /// Create value bound to specified object context92 /// Create value bound to specified object context
92 fn bind(&self, s: State, sup: Option<ObjValue>, this: Option<ObjValue>) -> Result<Self::Bound>;93 fn bind(&self, sup: Option<ObjValue>, this: Option<ObjValue>) -> Result<Self::Bound>;
93}94}
9495
95/// Object fields may, or may not depend on `this`/`super`, this enum allows cheaper reuse of object-independent fields for native code96/// Object fields may, or may not depend on `this`/`super`, this enum allows cheaper reuse of object-independent fields for native code
111 /// Attach object context to value, if required112 /// Attach object context to value, if required
112 pub fn evaluate(113 pub fn evaluate(&self, sup: Option<ObjValue>, this: Option<ObjValue>) -> Result<Thunk<Val>> {
113 &self,
114 s: State,
115 sup: Option<ObjValue>,
116 this: Option<ObjValue>,
117 ) -> Result<Thunk<Val>> {
118 match self {114 match self {
119 Self::Unbound(v) => v.bind(s, sup, this),115 Self::Unbound(v) => v.bind(sup, this),
120 Self::Bound(v) => Ok(v.clone()),116 Self::Bound(v) => Ok(v.clone()),
121 }117 }
122 }118 }
123}119}
124120
125/// During import, this trait will be called to create initial context for file.121/// During import, this trait will be called to create initial context for file.
126/// It may initialize global variables, stdlib for example.122/// It may initialize global variables, stdlib for example.
127pub trait ContextInitializer {123pub trait ContextInitializer: Trace {
128 /// Initialize default file context.124 /// Initialize default file context.
129 fn initialize(&self, state: State, for_file: Source) -> Context;125 fn initialize(&self, state: State, for_file: Source) -> Context;
130 /// Allows upcasting from abstract to concrete context initializer.126 /// Allows upcasting from abstract to concrete context initializer.
133}129}
134130
135/// Context initializer which adds nothing.131/// Context initializer which adds nothing.
132#[derive(Trace)]
136pub struct DummyContextInitializer;133pub struct DummyContextInitializer;
137impl ContextInitializer for DummyContextInitializer {134impl ContextInitializer for DummyContextInitializer {
138 fn initialize(&self, _state: State, _for_file: Source) -> Context {135 fn initialize(&self, state: State, _for_file: Source) -> Context {
139 Context::default()136 ContextBuilder::new(state).build()
140 }137 }
141 fn as_any(&self) -> &dyn Any {138 fn as_any(&self) -> &dyn Any {
142 self139 self
143 }140 }
144}141}
145142
146/// Dynamically reconfigurable evaluation settings143/// Dynamically reconfigurable evaluation settings
144#[derive(Trace)]
147pub struct EvaluationSettings {145pub struct EvaluationSettings {
148 /// Limits amount of stack trace items preserved146 /// Limits amount of stack trace items preserved
149 pub max_trace: usize,147 pub max_trace: usize,
150 /// TLA vars148 /// TLA vars
151 pub tla_vars: HashMap<IStr, TlaArg>,149 pub tla_vars: HashMap<IStr, TlaArg>,
152 /// Context initializer, which will be used for imports and everything150 /// Context initializer, which will be used for imports and everything
153 /// [`NoopContextInitializer`] is used by default, most likely you want to have `jrsonnet-stdlib`151 /// [`NoopContextInitializer`] is used by default, most likely you want to have `jrsonnet-stdlib`
154 pub context_initializer: Box<dyn ContextInitializer>,152 pub context_initializer: TraceBox<dyn ContextInitializer>,
155 /// Used to resolve file locations/contents153 /// Used to resolve file locations/contents
156 pub import_resolver: Box<dyn ImportResolver>,154 pub import_resolver: TraceBox<dyn ImportResolver>,
157 /// Used in manifestification functions155 /// Used in manifestification functions
158 pub manifest_format: ManifestFormat,156 pub manifest_format: ManifestFormat,
159 /// Used for bindings157 /// Used for bindings
160 pub trace_format: Box<dyn TraceFormat>,158 pub trace_format: TraceBox<dyn TraceFormat>,
161}159}
162impl Default for EvaluationSettings {160impl Default for EvaluationSettings {
163 fn default() -> Self {161 fn default() -> Self {
164 Self {162 Self {
165 max_trace: 20,163 max_trace: 20,
166 context_initializer: Box::new(DummyContextInitializer),164 context_initializer: tb!(DummyContextInitializer),
167 tla_vars: HashMap::default(),165 tla_vars: HashMap::default(),
168 import_resolver: Box::new(DummyImportResolver),166 import_resolver: tb!(DummyImportResolver),
169 manifest_format: ManifestFormat::Json {167 manifest_format: ManifestFormat::Json {
170 padding: 4,168 padding: 4,
171 #[cfg(feature = "exp-preserve-order")]169 #[cfg(feature = "exp-preserve-order")]
172 preserve_order: false,170 preserve_order: false,
173 },171 },
174 trace_format: Box::new(CompactFormat {172 trace_format: tb!(CompactFormat {
175 padding: 4,173 padding: 4,
176 resolver: trace::PathResolver::Absolute,174 resolver: trace::PathResolver::Absolute,
177 }),175 }),
178 }176 }
179 }177 }
180}178}
181179
180#[derive(Trace)]
182struct FileData {181struct FileData {
183 string: Option<IStr>,182 string: Option<IStr>,
184 bytes: Option<IBytes>,183 bytes: Option<IBytes>,
208 }207 }
209}208}
210209
211#[derive(Default)]210#[derive(Default, Trace)]
212pub struct EvaluationStateInternals {211pub struct EvaluationStateInternals {
213 /// Internal state212 /// Internal state
214 file_cache: RefCell<GcHashMap<SourcePath, FileData>>,213 file_cache: RefCell<GcHashMap<SourcePath, FileData>>,
217}216}
218217
219/// Maintains stack trace and import resolution218/// Maintains stack trace and import resolution
220#[derive(Default, Clone)]219#[derive(Default, Clone, Trace)]
221pub struct State(Rc<EvaluationStateInternals>);220pub struct State(Cc<EvaluationStateInternals>);
222221
223impl State {222impl State {
224 /// Should only be called with path retrieved from [`resolve_path`], may panic otherwise223 /// Should only be called with path retrieved from [`resolve_path`], may panic otherwise
341 // Dropping file cache guard here, as evaluation may use this map too340 // Dropping file cache guard here, as evaluation may use this map too
342 drop(file_cache);341 drop(file_cache);
343 let res = evaluate(342 let res = evaluate(self.create_default_context(file_name), &parsed);
344 self.clone(),
345 self.create_default_context(file_name),
346 &parsed,
347 );
348343
349 let mut file_cache = self.file_cache();344 let mut file_cache = self.file_cache();
425 pub fn manifest(&self, val: Val) -> Result<IStr> {420 pub fn manifest(&self, val: Val) -> Result<IStr> {
426 Self::push_description(421 Self::push_description(
427 || "manifestification".to_string(),422 || "manifestification".to_string(),
428 || val.manifest(self.clone(), &self.manifest_format()),423 || val.manifest(&self.manifest_format()),
429 )424 )
430 }425 }
431 pub fn manifest_multi(&self, val: Val) -> Result<Vec<(IStr, IStr)>> {426 pub fn manifest_multi(&self, val: Val) -> Result<Vec<(IStr, IStr)>> {
432 val.manifest_multi(self.clone(), &self.manifest_format())427 val.manifest_multi(&self.manifest_format())
433 }428 }
434 pub fn manifest_stream(&self, val: Val) -> Result<Vec<IStr>> {429 pub fn manifest_stream(&self, val: Val) -> Result<Vec<IStr>> {
435 val.manifest_stream(self.clone(), &self.manifest_format())430 val.manifest_stream(&self.manifest_format())
436 }431 }
437432
438 /// If passed value is function then call with set TLA433 /// If passed value is function then call with set TLA
442 || "during TLA call".to_owned(),437 || "during TLA call".to_owned(),
443 || {438 || {
444 func.evaluate(439 func.evaluate(
445 self.clone(),
446 self.create_default_context(Source::new_virtual(440 self.create_default_context(Source::new_virtual(
447 "<tla>".into(),441 "<tla>".into(),
448 IStr::empty(),442 IStr::empty(),
487 path: source.clone(),481 path: source.clone(),
488 error: Box::new(e),482 error: Box::new(e),
489 })?;483 })?;
490 evaluate(self.clone(), self.create_default_context(source), &parsed)484 evaluate(self.create_default_context(source), &parsed)
491 }485 }
492}486}
493487
537 Ref::map(self.settings(), |s| &*s.import_resolver)531 Ref::map(self.settings(), |s| &*s.import_resolver)
538 }532 }
539 pub fn set_import_resolver(&self, resolver: Box<dyn ImportResolver>) {533 pub fn set_import_resolver(&self, resolver: Box<dyn ImportResolver>) {
540 self.settings_mut().import_resolver = resolver;534 self.settings_mut().import_resolver = TraceBox(resolver);
541 }535 }
542 pub fn context_initializer(&self) -> Ref<'_, dyn ContextInitializer> {536 pub fn context_initializer(&self) -> Ref<'_, dyn ContextInitializer> {
543 Ref::map(self.settings(), |s| &*s.context_initializer)537 Ref::map(self.settings(), |s| &*s.context_initializer)
553 pub fn trace_format(&self) -> Ref<'_, dyn TraceFormat> {547 pub fn trace_format(&self) -> Ref<'_, dyn TraceFormat> {
554 Ref::map(self.settings(), |s| &*s.trace_format)548 Ref::map(self.settings(), |s| &*s.trace_format)
555 }549 }
556 pub fn set_trace_format(&self, format: Box<dyn TraceFormat>) {550 pub fn set_trace_format(&self, format: impl TraceFormat) {
557 self.settings_mut().trace_format = format;551 self.settings_mut().trace_format = tb!(format);
558 }552 }
559553
560 pub fn max_trace(&self) -> usize {554 pub fn max_trace(&self) -> usize {
modifiedcrates/jrsonnet-evaluator/src/obj.rsdiffbeforeafterboth
105}105}
106106
107pub trait ObjectAssertion: Trace {107pub trait ObjectAssertion: Trace {
108 fn run(&self, s: State, super_obj: Option<ObjValue>, this: Option<ObjValue>) -> Result<()>;108 fn run(&self, super_obj: Option<ObjValue>, this: Option<ObjValue>) -> Result<()>;
109}109}
110110
111// Field => This111// Field => This
368 .map_or(false, |v| v.is_visible())368 .map_or(false, |v| v.is_visible())
369 }369 }
370
371 pub fn iter(&self) -> impl Iterator<Item = (IStr, Result<Val>)> + '_ {
372 let fields = self.fields();
373 fields.into_iter().map(|field| {
374 (
375 field.clone(),
376 self.get(field)
377 .map(|opt| opt.expect("iterating over keys, field exists")),
378 )
379 })
380 }
370381
371 pub fn get(&self, s: State, key: IStr) -> Result<Option<Val>> {382 pub fn get(&self, key: IStr) -> Result<Option<Val>> {
372 self.run_assertions(s.clone())?;383 self.run_assertions()?;
373 if let Some(v) = self.0.value_cache.borrow().get(&key) {384 if let Some(v) = self.0.value_cache.borrow().get(&key) {
374 return Ok(match v {385 return Ok(match v {
375 CacheValue::Cached(v) => Some(v.clone()),386 CacheValue::Cached(v) => Some(v.clone()),
384 .insert(key.clone(), CacheValue::Pending);395 .insert(key.clone(), CacheValue::Pending);
385 let value = self396 let value = self
386 .get_raw(397 .get_raw(
387 s,
388 key.clone(),398 key.clone(),
389 self.0.this.clone().unwrap_or_else(|| self.clone()),399 self.0.this.clone().unwrap_or_else(|| self.clone()),
390 )400 )
404 Ok(value)414 Ok(value)
405 }415 }
406416
407 fn get_raw(&self, s: State, key: IStr, real_this: Self) -> Result<Option<Val>> {417 fn get_raw(&self, key: IStr, real_this: Self) -> Result<Option<Val>> {
408 match (self.0.this_entries.get(&key), &self.0.sup) {418 match (self.0.this_entries.get(&key), &self.0.sup) {
409 (Some(k), None) => Ok(Some(self.evaluate_this(s, k, real_this)?)),419 (Some(k), None) => Ok(Some(self.evaluate_this(k, real_this)?)),
410 (Some(k), Some(super_obj)) => {420 (Some(k), Some(super_obj)) => {
411 let our = self.evaluate_this(s.clone(), k, real_this.clone())?;421 let our = self.evaluate_this(k, real_this.clone())?;
412 if k.add {422 if k.add {
413 super_obj423 super_obj
414 .get_raw(s.clone(), key, real_this)?424 .get_raw(key, real_this)?
415 .map_or(Ok(Some(our.clone())), |v| {425 .map_or(Ok(Some(our.clone())), |v| {
416 Ok(Some(evaluate_add_op(s.clone(), &v, &our)?))426 Ok(Some(evaluate_add_op(&v, &our)?))
417 })427 })
418 } else {428 } else {
419 Ok(Some(our))429 Ok(Some(our))
420 }430 }
421 }431 }
422 (None, Some(super_obj)) => super_obj.get_raw(s, key, real_this),432 (None, Some(super_obj)) => super_obj.get_raw(key, real_this),
423 (None, None) => Ok(None),433 (None, None) => Ok(None),
424 }434 }
425 }435 }
426 fn evaluate_this(&self, s: State, v: &ObjMember, real_this: Self) -> Result<Val> {436 fn evaluate_this(&self, v: &ObjMember, real_this: Self) -> Result<Val> {
427 v.invoke437 v.invoke
428 .evaluate(s.clone(), self.0.sup.clone(), Some(real_this))?438 .evaluate(self.0.sup.clone(), Some(real_this))?
429 .evaluate(s)439 .evaluate()
430 }440 }
431441
432 fn run_assertions_raw(&self, s: State, real_this: &Self) -> Result<()> {442 fn run_assertions_raw(&self, real_this: &Self) -> Result<()> {
433 if self.0.assertions_ran.borrow_mut().insert(real_this.clone()) {443 if self.0.assertions_ran.borrow_mut().insert(real_this.clone()) {
434 for assertion in self.0.assertions.iter() {444 for assertion in self.0.assertions.iter() {
435 if let Err(e) =445 if let Err(e) = assertion.run(self.0.sup.clone(), Some(real_this.clone())) {
436 assertion.run(s.clone(), self.0.sup.clone(), Some(real_this.clone()))
437 {
438 self.0.assertions_ran.borrow_mut().remove(real_this);446 self.0.assertions_ran.borrow_mut().remove(real_this);
439 return Err(e);447 return Err(e);
440 }448 }
441 }449 }
442 if let Some(super_obj) = &self.0.sup {450 if let Some(super_obj) = &self.0.sup {
443 super_obj.run_assertions_raw(s, real_this)?;451 super_obj.run_assertions_raw(real_this)?;
444 }452 }
445 }453 }
446 Ok(())454 Ok(())
447 }455 }
448 pub fn run_assertions(&self, s: State) -> Result<()> {456 pub fn run_assertions(&self) -> Result<()> {
449 self.run_assertions_raw(s, self)457 self.run_assertions_raw(self)
450 }458 }
451459
452 pub fn ptr_eq(a: &Self, b: &Self) -> bool {460 pub fn ptr_eq(a: &Self, b: &Self) -> bool {
modifiedcrates/jrsonnet-evaluator/src/stdlib/format.rsdiffbeforeafterboth
6use jrsonnet_types::ValType;6use jrsonnet_types::ValType;
7use thiserror::Error;7use thiserror::Error;
88
9use crate::{error::Error::*, throw, typed::Typed, LocError, ObjValue, Result, State, Val};9use crate::{error::Error::*, throw, typed::Typed, LocError, ObjValue, Result, Val};
1010
11#[derive(Debug, Clone, Error, Trace)]11#[derive(Debug, Clone, Error, Trace)]
12pub enum FormatError {12pub enum FormatError {
472472
473#[allow(clippy::too_many_lines)]473#[allow(clippy::too_many_lines)]
474pub fn format_code(474pub fn format_code(
475 s: State,
476 out: &mut String,475 out: &mut String,
477 value: &Val,476 value: &Val,
478 code: &Code<'_>,477 code: &Code<'_>,
491 let mut tmp_out = String::new();490 let mut tmp_out = String::new();
492491
493 match code.convtype {492 match code.convtype {
494 ConvTypeV::String => tmp_out.push_str(&value.clone().to_string(s)?),493 ConvTypeV::String => tmp_out.push_str(&value.clone().to_string()?),
495 ConvTypeV::Decimal => {494 ConvTypeV::Decimal => {
496 let value = f64::from_untyped(value.clone(), s)?;495 let value = f64::from_untyped(value.clone())?;
497 render_decimal(496 render_decimal(
498 &mut tmp_out,497 &mut tmp_out,
499 value,498 value,
504 );503 );
505 }504 }
506 ConvTypeV::Octal => {505 ConvTypeV::Octal => {
507 let value = f64::from_untyped(value.clone(), s)?;506 let value = f64::from_untyped(value.clone())?;
508 render_octal(507 render_octal(
509 &mut tmp_out,508 &mut tmp_out,
510 value,509 value,
516 );515 );
517 }516 }
518 ConvTypeV::Hexadecimal => {517 ConvTypeV::Hexadecimal => {
519 let value = f64::from_untyped(value.clone(), s)?;518 let value = f64::from_untyped(value.clone())?;
520 render_hexadecimal(519 render_hexadecimal(
521 &mut tmp_out,520 &mut tmp_out,
522 value,521 value,
529 );528 );
530 }529 }
531 ConvTypeV::Scientific => {530 ConvTypeV::Scientific => {
532 let value = f64::from_untyped(value.clone(), s)?;531 let value = f64::from_untyped(value.clone())?;
533 render_float_sci(532 render_float_sci(
534 &mut tmp_out,533 &mut tmp_out,
535 value,534 value,
543 );542 );
544 }543 }
545 ConvTypeV::Float => {544 ConvTypeV::Float => {
546 let value = f64::from_untyped(value.clone(), s)?;545 let value = f64::from_untyped(value.clone())?;
547 render_float(546 render_float(
548 &mut tmp_out,547 &mut tmp_out,
549 value,548 value,
556 );555 );
557 }556 }
558 ConvTypeV::Shorter => {557 ConvTypeV::Shorter => {
559 let value = f64::from_untyped(value.clone(), s)?;558 let value = f64::from_untyped(value.clone())?;
560 let exponent = value.log10().floor();559 let exponent = value.log10().floor();
561 if exponent < -4.0 || exponent >= fpprec as f64 {560 if exponent < -4.0 || exponent >= fpprec as f64 {
562 render_float_sci(561 render_float_sci(
623 Ok(())622 Ok(())
624}623}
625624
626pub fn format_arr(s: State, str: &str, mut values: &[Val]) -> Result<String> {625pub fn format_arr(str: &str, mut values: &[Val]) -> Result<String> {
627 let codes = parse_codes(str)?;626 let codes = parse_codes(str)?;
628 let mut out = String::new();627 let mut out = String::new();
629628
640 }639 }
641 let value = &values[0];640 let value = &values[0];
642 values = &values[1..];641 values = &values[1..];
643 usize::from_untyped(value.clone(), s.clone())?642 usize::from_untyped(value.clone())?
644 }643 }
645 Width::Fixed(n) => n,644 Width::Fixed(n) => n,
646 };645 };
651 }650 }
652 let value = &values[0];651 let value = &values[0];
653 values = &values[1..];652 values = &values[1..];
654 Some(usize::from_untyped(value.clone(), s.clone())?)653 Some(usize::from_untyped(value.clone())?)
655 }654 }
656 Some(Width::Fixed(n)) => Some(n),655 Some(Width::Fixed(n)) => Some(n),
657 None => None,656 None => None,
669 value668 value
670 };669 };
671670
672 format_code(s.clone(), &mut out, value, &c, width, precision)?;671 format_code(&mut out, value, &c, width, precision)?;
673 }672 }
674 }673 }
675 }674 }
676675
677 Ok(out)676 Ok(out)
678}677}
679678
680pub fn format_obj(s: State, str: &str, values: &ObjValue) -> Result<String> {679pub fn format_obj(str: &str, values: &ObjValue) -> Result<String> {
681 let codes = parse_codes(str)?;680 let codes = parse_codes(str)?;
682 let mut out = String::new();681 let mut out = String::new();
683682
709 if f.is_empty() {708 if f.is_empty() {
710 throw!(MappingKeysRequired);709 throw!(MappingKeysRequired);
711 }710 }
712 if let Some(v) = values.get(s.clone(), f.clone())? {711 if let Some(v) = values.get(f.clone())? {
713 v712 v
714 } else {713 } else {
715 throw!(NoSuchFormatField(f));714 throw!(NoSuchFormatField(f));
716 }715 }
717 };716 };
718717
719 format_code(s.clone(), &mut out, &value, &c, width, precision)?;718 format_code(&mut out, &value, &c, width, precision)?;
720 }719 }
721 }720 }
722 }721 }
742741
743 #[test]742 #[test]
744 fn octals() {743 fn octals() {
745 let s = State::default();
746 assert_eq!(744 assert_eq!(format_arr("%#o", &[Val::Num(8.0)]).unwrap(), "010");
747 format_arr(s.clone(), "%#o", &[Val::Num(8.0)]).unwrap(),
748 "010"
749 );
750 assert_eq!(745 assert_eq!(format_arr("%#4o", &[Val::Num(8.0)]).unwrap(), " 010");
751 format_arr(s.clone(), "%#4o", &[Val::Num(8.0)]).unwrap(),
752 " 010"
753 );
754 assert_eq!(746 assert_eq!(format_arr("%4o", &[Val::Num(8.0)]).unwrap(), " 10");
755 format_arr(s.clone(), "%4o", &[Val::Num(8.0)]).unwrap(),
756 " 10"
757 );
758 assert_eq!(747 assert_eq!(format_arr("%04o", &[Val::Num(8.0)]).unwrap(), "0010");
759 format_arr(s.clone(), "%04o", &[Val::Num(8.0)]).unwrap(),
760 "0010"
761 );
762 assert_eq!(748 assert_eq!(format_arr("%+4o", &[Val::Num(8.0)]).unwrap(), " +10");
763 format_arr(s.clone(), "%+4o", &[Val::Num(8.0)]).unwrap(),
764 " +10"
765 );
766 assert_eq!(749 assert_eq!(format_arr("%+04o", &[Val::Num(8.0)]).unwrap(), "+010");
767 format_arr(s.clone(), "%+04o", &[Val::Num(8.0)]).unwrap(),
768 "+010"
769 );
770 assert_eq!(750 assert_eq!(format_arr("%-4o", &[Val::Num(8.0)]).unwrap(), "10 ");
771 format_arr(s.clone(), "%-4o", &[Val::Num(8.0)]).unwrap(),
772 "10 "
773 );
774 assert_eq!(751 assert_eq!(format_arr("%+-4o", &[Val::Num(8.0)]).unwrap(), "+10 ");
775 format_arr(s.clone(), "%+-4o", &[Val::Num(8.0)]).unwrap(),
776 "+10 "
777 );
778 assert_eq!(format_arr(s, "%+-04o", &[Val::Num(8.0)]).unwrap(), "+10 ");752 assert_eq!(format_arr("%+-04o", &[Val::Num(8.0)]).unwrap(), "+10 ");
779 }753 }
780754
781 #[test]755 #[test]
782 fn percent_doesnt_consumes_values() {756 fn percent_doesnt_consumes_values() {
783 let s = State::default();
784 assert_eq!(757 assert_eq!(
785 format_arr(758 format_arr(
786 s,
787 "How much error budget is left looking at our %.3f%% availability gurantees?",759 "How much error budget is left looking at our %.3f%% availability gurantees?",
788 &[Val::Num(4.0)]760 &[Val::Num(4.0)]
789 )761 )
modifiedcrates/jrsonnet-evaluator/src/stdlib/manifest.rsdiffbeforeafterboth
25 pub preserve_order: bool,25 pub preserve_order: bool,
26}26}
2727
28pub fn manifest_json_ex(s: State, val: &Val, options: &ManifestJsonOptions<'_>) -> Result<String> {28pub fn manifest_json_ex(val: &Val, options: &ManifestJsonOptions<'_>) -> Result<String> {
29 let mut out = String::new();29 let mut out = String::new();
30 manifest_json_ex_buf(s, val, &mut out, &mut String::new(), options)?;30 manifest_json_ex_buf(val, &mut out, &mut String::new(), options)?;
31 Ok(out)31 Ok(out)
32}32}
33fn manifest_json_ex_buf(33fn manifest_json_ex_buf(
34 s: State,
35 val: &Val,34 val: &Val,
36 buf: &mut String,35 buf: &mut String,
37 cur_padding: &mut String,36 cur_padding: &mut String,
5958
60 let old_len = cur_padding.len();59 let old_len = cur_padding.len();
61 cur_padding.push_str(options.padding);60 cur_padding.push_str(options.padding);
62 for (i, item) in items.iter(s.clone()).enumerate() {61 for (i, item) in items.iter().enumerate() {
63 if i != 0 {62 if i != 0 {
64 buf.push(',');63 buf.push(',');
65 if mtype == ManifestType::ToString {64 if mtype == ManifestType::ToString {
69 }68 }
70 }69 }
71 buf.push_str(cur_padding);70 buf.push_str(cur_padding);
72 manifest_json_ex_buf(s.clone(), &item?, buf, cur_padding, options)?;71 manifest_json_ex_buf(&item?, buf, cur_padding, options)?;
73 }72 }
74 cur_padding.truncate(old_len);73 cur_padding.truncate(old_len);
7574
86 buf.push(']');85 buf.push(']');
87 }86 }
88 Val::Obj(obj) => {87 Val::Obj(obj) => {
89 obj.run_assertions(s.clone())?;88 obj.run_assertions()?;
90 buf.push('{');89 buf.push('{');
91 let fields = obj.fields(90 let fields = obj.fields(
92 #[cfg(feature = "exp-preserve-order")]91 #[cfg(feature = "exp-preserve-order")]
114 State::push_description(113 State::push_description(
115 || format!("field <{}> manifestification", field.clone()),114 || format!("field <{}> manifestification", field.clone()),
116 || {115 || {
117 let value = obj.get(s.clone(), field.clone())?.unwrap();116 let value = obj.get(field.clone())?.unwrap();
118 manifest_json_ex_buf(s.clone(), &value, buf, cur_padding, options)?;117 manifest_json_ex_buf(&value, buf, cur_padding, options)?;
119 Ok(())118 Ok(())
120 },119 },
121 )?;120 )?;
222 || string.parse::<f64>().is_ok()221 || string.parse::<f64>().is_ok()
223}222}
224223
225pub fn manifest_yaml_ex(s: State, val: &Val, options: &ManifestYamlOptions<'_>) -> Result<String> {224pub fn manifest_yaml_ex(val: &Val, options: &ManifestYamlOptions<'_>) -> Result<String> {
226 let mut out = String::new();225 let mut out = String::new();
227 manifest_yaml_ex_buf(s, val, &mut out, &mut String::new(), options)?;226 manifest_yaml_ex_buf(val, &mut out, &mut String::new(), options)?;
228 Ok(out)227 Ok(out)
229}228}
230229
231#[allow(clippy::too_many_lines)]230#[allow(clippy::too_many_lines)]
232fn manifest_yaml_ex_buf(231fn manifest_yaml_ex_buf(
233 s: State,
234 val: &Val,232 val: &Val,
235 buf: &mut String,233 buf: &mut String,
236 cur_padding: &mut String,234 cur_padding: &mut String,
268 if a.is_empty() {266 if a.is_empty() {
269 buf.push_str("[]");267 buf.push_str("[]");
270 } else {268 } else {
271 for (i, item) in a.iter(s.clone()).enumerate() {269 for (i, item) in a.iter().enumerate() {
272 if i != 0 {270 if i != 0 {
273 buf.push('\n');271 buf.push('\n');
274 buf.push_str(cur_padding);272 buf.push_str(cur_padding);
292 if extra_padding {290 if extra_padding {
293 cur_padding.push_str(options.padding);291 cur_padding.push_str(options.padding);
294 }292 }
295 manifest_yaml_ex_buf(s.clone(), &item, buf, cur_padding, options)?;293 manifest_yaml_ex_buf(&item, buf, cur_padding, options)?;
296 cur_padding.truncate(prev_len);294 cur_padding.truncate(prev_len);
297 }295 }
298 }296 }
320 }318 }
321 buf.push(':');319 buf.push(':');
322 let prev_len = cur_padding.len();320 let prev_len = cur_padding.len();
323 let item = o.get(s.clone(), key.clone())?.expect("field exists");321 let item = o.get(key.clone())?.expect("field exists");
324 match &item {322 match &item {
325 Val::Arr(a) if !a.is_empty() => {323 Val::Arr(a) if !a.is_empty() => {
326 buf.push('\n');324 buf.push('\n');
336 }334 }
337 _ => buf.push(' '),335 _ => buf.push(' '),
338 }336 }
339 manifest_yaml_ex_buf(s.clone(), &item, buf, cur_padding, options)?;337 manifest_yaml_ex_buf(&item, buf, cur_padding, options)?;
340 cur_padding.truncate(prev_len);338 cur_padding.truncate(prev_len);
341 }339 }
342 }340 }
modifiedcrates/jrsonnet-evaluator/src/stdlib/mod.rsdiffbeforeafterboth
9pub mod format;9pub mod format;
10pub mod manifest;10pub mod manifest;
1111
12pub fn std_format(s: State, str: IStr, vals: Val) -> Result<String> {12pub fn std_format(str: IStr, vals: Val) -> Result<String> {
13 State::push(13 State::push(
14 CallLocation::native(),14 CallLocation::native(),
15 || format!("std.format of {str}"),15 || format!("std.format of {str}"),
16 || {16 || {
17 Ok(match vals {17 Ok(match vals {
18 Val::Arr(vals) => format_arr(s.clone(), &str, &vals.evaluated(s.clone())?)?,18 Val::Arr(vals) => format_arr(&str, &vals.evaluated()?)?,
19 Val::Obj(obj) => format_obj(s.clone(), &str, &obj)?,19 Val::Obj(obj) => format_obj(&str, &obj)?,
20 o => format_arr(s.clone(), &str, &[o])?,20 o => format_arr(&str, &[o])?,
21 })21 })
22 },22 },
23 )23 )
modifiedcrates/jrsonnet-evaluator/src/trace/mod.rsdiffbeforeafterboth
1use std::path::{Path, PathBuf};1use std::path::{Path, PathBuf};
22
3use jrsonnet_gcmodule::Trace;
3use jrsonnet_parser::{CodeLocation, Source};4use jrsonnet_parser::{CodeLocation, Source};
45
5use crate::{error::Error, LocError, State};6use crate::{error::Error, LocError, State};
67
7/// The way paths should be displayed8/// The way paths should be displayed
8#[derive(Clone)]9#[derive(Clone, Trace)]
9pub enum PathResolver {10pub enum PathResolver {
10 /// Only filename11 /// Only filename
11 FileName,12 FileName,
4344
44/// Implements pretty-printing of traces45/// Implements pretty-printing of traces
45#[allow(clippy::module_name_repetitions)]46#[allow(clippy::module_name_repetitions)]
46pub trait TraceFormat {47pub trait TraceFormat: Trace {
47 fn write_trace(48 fn write_trace(
48 &self,49 &self,
49 out: &mut dyn std::fmt::Write,50 out: &mut dyn std::fmt::Write,
77}78}
7879
79/// vanilla-like jsonnet formatting80/// vanilla-like jsonnet formatting
81#[derive(Trace)]
80pub struct CompactFormat {82pub struct CompactFormat {
81 pub resolver: PathResolver,83 pub resolver: PathResolver,
82 pub padding: usize,84 pub padding: usize,
168 }170 }
169}171}
170172
173#[derive(Trace)]
171pub struct JsFormat;174pub struct JsFormat;
172impl TraceFormat for JsFormat {175impl TraceFormat for JsFormat {
173 fn write_trace(176 fn write_trace(
202205
203/// rustc-like trace displaying206/// rustc-like trace displaying
204#[cfg(feature = "explaining-traces")]207#[cfg(feature = "explaining-traces")]
208#[derive(Trace)]
205pub struct ExplainingFormat {209pub struct ExplainingFormat {
206 pub resolver: PathResolver,210 pub resolver: PathResolver,
207}211}
222 .into_iter()226 .into_iter()
223 .next()227 .next()
224 .unwrap();228 .unwrap();
225 let mut end_location = location.clone();229 let mut end_location = location;
226 end_location.offset += 1;230 end_location.offset += 1;
227231
228 self.print_snippet(232 self.print_snippet(
modifiedcrates/jrsonnet-evaluator/src/typed/conversions.rsdiffbeforeafterboth
77
8use crate::{8use crate::{
9 error::Result,9 error::Result,
10 function::{FuncDesc, FuncVal},10 function::{native::NativeDesc, FuncDesc, FuncVal},
11 throw,11 throw,
12 typed::CheckType,12 typed::CheckType,
13 val::{ArrValue, IndexableVal},13 val::{ArrValue, IndexableVal},
14 ObjValue, ObjValueBuilder, State, Val,14 ObjValue, ObjValueBuilder, Val,
15};15};
1616
17pub trait TypedObj: Typed {17pub trait TypedObj: Typed {
18 fn serialize(self, s: State, out: &mut ObjValueBuilder) -> Result<()>;18 fn serialize(self, out: &mut ObjValueBuilder) -> Result<()>;
19 fn parse(obj: &ObjValue, s: State) -> Result<Self>;19 fn parse(obj: &ObjValue) -> Result<Self>;
20 fn into_object(self, s: State) -> Result<ObjValue> {20 fn into_object(self) -> Result<ObjValue> {
21 let mut builder = ObjValueBuilder::new();21 let mut builder = ObjValueBuilder::new();
22 self.serialize(s, &mut builder)?;22 self.serialize(&mut builder)?;
23 Ok(builder.build())23 Ok(builder.build())
24 }24 }
25}25}
2626
27pub trait Typed: Sized {27pub trait Typed: Sized {
28 const TYPE: &'static ComplexValType;28 const TYPE: &'static ComplexValType;
29 fn into_untyped(typed: Self, s: State) -> Result<Val>;29 fn into_untyped(typed: Self) -> Result<Val>;
30 fn from_untyped(untyped: Val, s: State) -> Result<Self>;30 fn from_untyped(untyped: Val) -> Result<Self>;
31}31}
3232
33macro_rules! impl_int {33macro_rules! impl_int {
34 ($($ty:ty)*) => {$(34 ($($ty:ty)*) => {$(
35 impl Typed for $ty {35 impl Typed for $ty {
36 const TYPE: &'static ComplexValType =36 const TYPE: &'static ComplexValType =
37 &ComplexValType::BoundedNumber(Some(Self::MIN as f64), Some(Self::MAX as f64));37 &ComplexValType::BoundedNumber(Some(Self::MIN as f64), Some(Self::MAX as f64));
38 fn from_untyped(value: Val, s: State) -> Result<Self> {38 fn from_untyped(value: Val) -> Result<Self> {
39 <Self as Typed>::TYPE.check(s, &value)?;39 <Self as Typed>::TYPE.check(&value)?;
40 match value {40 match value {
41 Val::Num(n) => {41 Val::Num(n) => {
42 #[allow(clippy::float_cmp)]42 #[allow(clippy::float_cmp)]
51 _ => unreachable!(),51 _ => unreachable!(),
52 }52 }
53 }53 }
54 fn into_untyped(value: Self, _: State) -> Result<Val> {54 fn into_untyped(value: Self) -> Result<Val> {
55 Ok(Val::Num(value as f64))55 Ok(Val::Num(value as f64))
56 }56 }
57 }57 }
90 Some(MAX as f64),90 Some(MAX as f64),
91 );91 );
9292
93 fn from_untyped(value: Val, s: State) -> Result<Self> {93 fn from_untyped(value: Val) -> Result<Self> {
94 <Self as Typed>::TYPE.check(s, &value)?;94 <Self as Typed>::TYPE.check(&value)?;
95 match value {95 match value {
96 Val::Num(n) => {96 Val::Num(n) => {
97 #[allow(clippy::float_cmp)]97 #[allow(clippy::float_cmp)]
107 }107 }
108 }108 }
109109
110 fn into_untyped(value: Self, _: State) -> Result<Val> {110 fn into_untyped(value: Self) -> Result<Val> {
111 Ok(Val::Num(value.0 as f64))111 Ok(Val::Num(value.0 as f64))
112 }112 }
113 }113 }
125impl Typed for f64 {125impl Typed for f64 {
126 const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Num);126 const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Num);
127127
128 fn into_untyped(value: Self, _: State) -> Result<Val> {128 fn into_untyped(value: Self) -> Result<Val> {
129 Ok(Val::Num(value))129 Ok(Val::Num(value))
130 }130 }
131131
132 fn from_untyped(value: Val, s: State) -> Result<Self> {132 fn from_untyped(value: Val) -> Result<Self> {
133 <Self as Typed>::TYPE.check(s, &value)?;133 <Self as Typed>::TYPE.check(&value)?;
134 match value {134 match value {
135 Val::Num(n) => Ok(n),135 Val::Num(n) => Ok(n),
136 _ => unreachable!(),136 _ => unreachable!(),
142impl Typed for PositiveF64 {142impl Typed for PositiveF64 {
143 const TYPE: &'static ComplexValType = &ComplexValType::BoundedNumber(Some(0.0), None);143 const TYPE: &'static ComplexValType = &ComplexValType::BoundedNumber(Some(0.0), None);
144144
145 fn into_untyped(value: Self, _: State) -> Result<Val> {145 fn into_untyped(value: Self) -> Result<Val> {
146 Ok(Val::Num(value.0))146 Ok(Val::Num(value.0))
147 }147 }
148148
149 fn from_untyped(value: Val, s: State) -> Result<Self> {149 fn from_untyped(value: Val) -> Result<Self> {
150 <Self as Typed>::TYPE.check(s, &value)?;150 <Self as Typed>::TYPE.check(&value)?;
151 match value {151 match value {
152 Val::Num(n) => Ok(Self(n)),152 Val::Num(n) => Ok(Self(n)),
153 _ => unreachable!(),153 _ => unreachable!(),
159 const TYPE: &'static ComplexValType =159 const TYPE: &'static ComplexValType =
160 &ComplexValType::BoundedNumber(Some(0.0), Some(u32::MAX as f64));160 &ComplexValType::BoundedNumber(Some(0.0), Some(u32::MAX as f64));
161161
162 fn into_untyped(value: Self, _: State) -> Result<Val> {162 fn into_untyped(value: Self) -> Result<Val> {
163 if value > u32::MAX as Self {163 if value > u32::MAX as Self {
164 throw!("number is too large")164 throw!("number is too large")
165 }165 }
166 Ok(Val::Num(value as f64))166 Ok(Val::Num(value as f64))
167 }167 }
168168
169 fn from_untyped(value: Val, s: State) -> Result<Self> {169 fn from_untyped(value: Val) -> Result<Self> {
170 <Self as Typed>::TYPE.check(s, &value)?;170 <Self as Typed>::TYPE.check(&value)?;
171 match value {171 match value {
172 Val::Num(n) => {172 Val::Num(n) => {
173 #[allow(clippy::float_cmp)]173 #[allow(clippy::float_cmp)]
184impl Typed for IStr {184impl Typed for IStr {
185 const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Str);185 const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Str);
186186
187 fn into_untyped(value: Self, _: State) -> Result<Val> {187 fn into_untyped(value: Self) -> Result<Val> {
188 Ok(Val::Str(value))188 Ok(Val::Str(value))
189 }189 }
190190
191 fn from_untyped(value: Val, s: State) -> Result<Self> {191 fn from_untyped(value: Val) -> Result<Self> {
192 <Self as Typed>::TYPE.check(s, &value)?;192 <Self as Typed>::TYPE.check(&value)?;
193 match value {193 match value {
194 Val::Str(s) => Ok(s),194 Val::Str(s) => Ok(s),
195 _ => unreachable!(),195 _ => unreachable!(),
200impl Typed for String {200impl Typed for String {
201 const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Str);201 const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Str);
202202
203 fn into_untyped(value: Self, _: State) -> Result<Val> {203 fn into_untyped(value: Self) -> Result<Val> {
204 Ok(Val::Str(value.into()))204 Ok(Val::Str(value.into()))
205 }205 }
206206
207 fn from_untyped(value: Val, s: State) -> Result<Self> {207 fn from_untyped(value: Val) -> Result<Self> {
208 <Self as Typed>::TYPE.check(s, &value)?;208 <Self as Typed>::TYPE.check(&value)?;
209 match value {209 match value {
210 Val::Str(s) => Ok(s.to_string()),210 Val::Str(s) => Ok(s.to_string()),
211 _ => unreachable!(),211 _ => unreachable!(),
216impl Typed for char {216impl Typed for char {
217 const TYPE: &'static ComplexValType = &ComplexValType::Char;217 const TYPE: &'static ComplexValType = &ComplexValType::Char;
218218
219 fn into_untyped(value: Self, _: State) -> Result<Val> {219 fn into_untyped(value: Self) -> Result<Val> {
220 Ok(Val::Str(value.to_string().into()))220 Ok(Val::Str(value.to_string().into()))
221 }221 }
222222
223 fn from_untyped(value: Val, s: State) -> Result<Self> {223 fn from_untyped(value: Val) -> Result<Self> {
224 <Self as Typed>::TYPE.check(s, &value)?;224 <Self as Typed>::TYPE.check(&value)?;
225 match value {225 match value {
226 Val::Str(s) => Ok(s.chars().next().unwrap()),226 Val::Str(s) => Ok(s.chars().next().unwrap()),
227 _ => unreachable!(),227 _ => unreachable!(),
235{235{
236 const TYPE: &'static ComplexValType = &ComplexValType::ArrayRef(T::TYPE);236 const TYPE: &'static ComplexValType = &ComplexValType::ArrayRef(T::TYPE);
237237
238 fn into_untyped(value: Self, s: State) -> Result<Val> {238 fn into_untyped(value: Self) -> Result<Val> {
239 let mut o = Vec::with_capacity(value.len());239 let mut o = Vec::with_capacity(value.len());
240 for i in value {240 for i in value {
241 o.push(T::into_untyped(i, s.clone())?);241 o.push(T::into_untyped(i)?);
242 }242 }
243 Ok(Val::Arr(o.into()))243 Ok(Val::Arr(o.into()))
244 }244 }
245245
246 fn from_untyped(value: Val, s: State) -> Result<Self> {246 fn from_untyped(value: Val) -> Result<Self> {
247 <Self as Typed>::TYPE.check(s.clone(), &value)?;247 <Self as Typed>::TYPE.check(&value)?;
248 match value {248 match value {
249 Val::Arr(a) => {249 Val::Arr(a) => {
250 let mut o = Self::with_capacity(a.len());250 let mut o = Self::with_capacity(a.len());
251 for i in a.iter(s.clone()) {251 for i in a.iter() {
252 o.push(T::from_untyped(i?, s.clone())?);252 o.push(T::from_untyped(i?)?);
253 }253 }
254 Ok(o)254 Ok(o)
255 }255 }
266impl Typed for Any {266impl Typed for Any {
267 const TYPE: &'static ComplexValType = &ComplexValType::Any;267 const TYPE: &'static ComplexValType = &ComplexValType::Any;
268268
269 fn into_untyped(value: Self, _: State) -> Result<Val> {269 fn into_untyped(value: Self) -> Result<Val> {
270 Ok(value.0)270 Ok(value.0)
271 }271 }
272272
273 fn from_untyped(value: Val, _: State) -> Result<Self> {273 fn from_untyped(value: Val) -> Result<Self> {
274 Ok(Self(value))274 Ok(Self(value))
275 }275 }
276}276}
281impl Typed for VecVal {281impl Typed for VecVal {
282 const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Arr);282 const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Arr);
283283
284 fn into_untyped(value: Self, _: State) -> Result<Val> {284 fn into_untyped(value: Self) -> Result<Val> {
285 Ok(Val::Arr(ArrValue::Eager(value.0)))285 Ok(Val::Arr(ArrValue::Eager(value.0)))
286 }286 }
287287
288 fn from_untyped(value: Val, s: State) -> Result<Self> {288 fn from_untyped(value: Val) -> Result<Self> {
289 <Self as Typed>::TYPE.check(s.clone(), &value)?;289 <Self as Typed>::TYPE.check(&value)?;
290 match value {290 match value {
291 Val::Arr(a) => Ok(Self(a.evaluated(s)?)),291 Val::Arr(a) => Ok(Self(a.evaluated()?)),
292 _ => unreachable!(),292 _ => unreachable!(),
293 }293 }
294 }294 }
299 const TYPE: &'static ComplexValType =299 const TYPE: &'static ComplexValType =
300 &ComplexValType::ArrayRef(&ComplexValType::BoundedNumber(Some(0.0), Some(255.0)));300 &ComplexValType::ArrayRef(&ComplexValType::BoundedNumber(Some(0.0), Some(255.0)));
301301
302 fn into_untyped(value: Self, _: State) -> Result<Val> {302 fn into_untyped(value: Self) -> Result<Val> {
303 Ok(Val::Arr(ArrValue::Bytes(value)))303 Ok(Val::Arr(ArrValue::Bytes(value)))
304 }304 }
305305
306 fn from_untyped(value: Val, s: State) -> Result<Self> {306 fn from_untyped(value: Val) -> Result<Self> {
307 if let Val::Arr(ArrValue::Bytes(bytes)) = value {307 if let Val::Arr(ArrValue::Bytes(bytes)) = value {
308 return Ok(bytes);308 return Ok(bytes);
309 }309 }
310 <Self as Typed>::TYPE.check(s.clone(), &value)?;310 <Self as Typed>::TYPE.check(&value)?;
311 match value {311 match value {
312 Val::Arr(a) => {312 Val::Arr(a) => {
313 let mut out = Vec::with_capacity(a.len());313 let mut out = Vec::with_capacity(a.len());
314 for e in a.iter(s.clone()) {314 for e in a.iter() {
315 let r = e?;315 let r = e?;
316 out.push(u8::from_untyped(r, s.clone())?);316 out.push(u8::from_untyped(r)?);
317 }317 }
318 Ok(out.as_slice().into())318 Ok(out.as_slice().into())
319 }319 }
326impl Typed for M1 {326impl Typed for M1 {
327 const TYPE: &'static ComplexValType = &ComplexValType::BoundedNumber(Some(-1.0), Some(-1.0));327 const TYPE: &'static ComplexValType = &ComplexValType::BoundedNumber(Some(-1.0), Some(-1.0));
328328
329 fn into_untyped(_: Self, _: State) -> Result<Val> {329 fn into_untyped(_: Self) -> Result<Val> {
330 Ok(Val::Num(-1.0))330 Ok(Val::Num(-1.0))
331 }331 }
332332
333 fn from_untyped(value: Val, s: State) -> Result<Self> {333 fn from_untyped(value: Val) -> Result<Self> {
334 <Self as Typed>::TYPE.check(s, &value)?;334 <Self as Typed>::TYPE.check(&value)?;
335 Ok(Self)335 Ok(Self)
336 }336 }
337}337}
338338
339macro_rules! decl_either {339macro_rules! decl_either {
340 ($($name: ident, $($id: ident)*);*) => {$(340 ($($name: ident, $($id: ident)*);*) => {$(
341 #[derive(Clone)]
341 pub enum $name<$($id),*> {342 pub enum $name<$($id),*> {
342 $($id($id)),*343 $($id($id)),*
343 }344 }
347 {348 {
348 const TYPE: &'static ComplexValType = &ComplexValType::UnionRef(&[$($id::TYPE),*]);349 const TYPE: &'static ComplexValType = &ComplexValType::UnionRef(&[$($id::TYPE),*]);
349350
350 fn into_untyped(value: Self, s: State) -> Result<Val> {351 fn into_untyped(value: Self) -> Result<Val> {
351 match value {$(352 match value {$(
352 $name::$id(v) => $id::into_untyped(v, s)353 $name::$id(v) => $id::into_untyped(v)
353 ),*}354 ),*}
354 }355 }
355356
356 fn from_untyped(value: Val, s: State) -> Result<Self> {357 fn from_untyped(value: Val) -> Result<Self> {
357 $(358 $(
358 if $id::TYPE.check(s.clone(), &value).is_ok() {359 if $id::TYPE.check(&value).is_ok() {
359 $id::from_untyped(value, s.clone()).map(Self::$id)360 $id::from_untyped(value).map(Self::$id)
360 } else361 } else
361 )* {362 )* {
362 <Self as Typed>::TYPE.check(s, &value)?;363 <Self as Typed>::TYPE.check(&value)?;
363 unreachable!()364 unreachable!()
364 }365 }
365 }366 }
392impl Typed for ArrValue {393impl Typed for ArrValue {
393 const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Arr);394 const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Arr);
394395
395 fn into_untyped(value: Self, _: State) -> Result<Val> {396 fn into_untyped(value: Self) -> Result<Val> {
396 Ok(Val::Arr(value))397 Ok(Val::Arr(value))
397 }398 }
398399
399 fn from_untyped(value: Val, s: State) -> Result<Self> {400 fn from_untyped(value: Val) -> Result<Self> {
400 <Self as Typed>::TYPE.check(s, &value)?;401 <Self as Typed>::TYPE.check(&value)?;
401 match value {402 match value {
402 Val::Arr(a) => Ok(a),403 Val::Arr(a) => Ok(a),
403 _ => unreachable!(),404 _ => unreachable!(),
408impl Typed for FuncVal {409impl Typed for FuncVal {
409 const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Func);410 const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Func);
410411
411 fn into_untyped(value: Self, _: State) -> Result<Val> {412 fn into_untyped(value: Self) -> Result<Val> {
412 Ok(Val::Func(value))413 Ok(Val::Func(value))
413 }414 }
414415
415 fn from_untyped(value: Val, s: State) -> Result<Self> {416 fn from_untyped(value: Val) -> Result<Self> {
416 <Self as Typed>::TYPE.check(s, &value)?;417 <Self as Typed>::TYPE.check(&value)?;
417 match value {418 match value {
418 Val::Func(a) => Ok(a),419 Val::Func(a) => Ok(a),
419 _ => unreachable!(),420 _ => unreachable!(),
424impl Typed for Cc<FuncDesc> {425impl Typed for Cc<FuncDesc> {
425 const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Func);426 const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Func);
426427
427 fn into_untyped(value: Self, _: State) -> Result<Val> {428 fn into_untyped(value: Self) -> Result<Val> {
428 Ok(Val::Func(FuncVal::Normal(value)))429 Ok(Val::Func(FuncVal::Normal(value)))
429 }430 }
430431
431 fn from_untyped(value: Val, s: State) -> Result<Self> {432 fn from_untyped(value: Val) -> Result<Self> {
432 <Self as Typed>::TYPE.check(s, &value)?;433 <Self as Typed>::TYPE.check(&value)?;
433 match value {434 match value {
434 Val::Func(FuncVal::Normal(desc)) => Ok(desc),435 Val::Func(FuncVal::Normal(desc)) => Ok(desc),
435 Val::Func(_) => throw!("expected normal function, not builtin"),436 Val::Func(_) => throw!("expected normal function, not builtin"),
441impl Typed for ObjValue {442impl Typed for ObjValue {
442 const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Obj);443 const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Obj);
443444
444 fn into_untyped(value: Self, _: State) -> Result<Val> {445 fn into_untyped(value: Self) -> Result<Val> {
445 Ok(Val::Obj(value))446 Ok(Val::Obj(value))
446 }447 }
447448
448 fn from_untyped(value: Val, s: State) -> Result<Self> {449 fn from_untyped(value: Val) -> Result<Self> {
449 <Self as Typed>::TYPE.check(s, &value)?;450 <Self as Typed>::TYPE.check(&value)?;
450 match value {451 match value {
451 Val::Obj(a) => Ok(a),452 Val::Obj(a) => Ok(a),
452 _ => unreachable!(),453 _ => unreachable!(),
457impl Typed for bool {458impl Typed for bool {
458 const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Bool);459 const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Bool);
459460
460 fn into_untyped(value: Self, _: State) -> Result<Val> {461 fn into_untyped(value: Self) -> Result<Val> {
461 Ok(Val::Bool(value))462 Ok(Val::Bool(value))
462 }463 }
463464
464 fn from_untyped(value: Val, s: State) -> Result<Self> {465 fn from_untyped(value: Val) -> Result<Self> {
465 <Self as Typed>::TYPE.check(s, &value)?;466 <Self as Typed>::TYPE.check(&value)?;
466 match value {467 match value {
467 Val::Bool(a) => Ok(a),468 Val::Bool(a) => Ok(a),
468 _ => unreachable!(),469 _ => unreachable!(),
475 &ComplexValType::Simple(ValType::Str),476 &ComplexValType::Simple(ValType::Str),
476 ]);477 ]);
477478
478 fn into_untyped(value: Self, _: State) -> Result<Val> {479 fn into_untyped(value: Self) -> Result<Val> {
479 match value {480 match value {
480 IndexableVal::Str(s) => Ok(Val::Str(s)),481 IndexableVal::Str(s) => Ok(Val::Str(s)),
481 IndexableVal::Arr(a) => Ok(Val::Arr(a)),482 IndexableVal::Arr(a) => Ok(Val::Arr(a)),
482 }483 }
483 }484 }
484485
485 fn from_untyped(value: Val, s: State) -> Result<Self> {486 fn from_untyped(value: Val) -> Result<Self> {
486 <Self as Typed>::TYPE.check(s, &value)?;487 <Self as Typed>::TYPE.check(&value)?;
487 value.into_indexable()488 value.into_indexable()
488 }489 }
489}490}
492impl Typed for Null {493impl Typed for Null {
493 const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Null);494 const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Null);
494495
495 fn into_untyped(_: Self, _: State) -> Result<Val> {496 fn into_untyped(_: Self) -> Result<Val> {
496 Ok(Val::Null)497 Ok(Val::Null)
497 }498 }
498499
499 fn from_untyped(value: Val, s: State) -> Result<Self> {500 fn from_untyped(value: Val) -> Result<Self> {
500 <Self as Typed>::TYPE.check(s, &value)?;501 <Self as Typed>::TYPE.check(&value)?;
501 Ok(Self)502 Ok(Self)
502 }503 }
503}504}
505
506pub struct NativeFn<D: NativeDesc>(D::Value);
507impl<D: NativeDesc> Deref for NativeFn<D> {
508 type Target = D::Value;
509
510 fn deref(&self) -> &Self::Target {
511 &self.0
512 }
513}
514impl<D: NativeDesc> Typed for NativeFn<D> {
515 const TYPE: &'static ComplexValType = &ComplexValType::Simple(ValType::Func);
516
517 fn into_untyped(_typed: Self) -> Result<Val> {
518 throw!("can only convert functions from jsonnet to native")
519 }
520
521 fn from_untyped(untyped: Val) -> Result<Self> {
522 Ok(Self(
523 untyped
524 .as_func()
525 .expect("shape is checked")
526 .into_native::<D>(),
527 ))
528 }
529}
504530
modifiedcrates/jrsonnet-evaluator/src/typed/mod.rsdiffbeforeafterboth
102102
103// TODO: check_fast for fast path of union type checking103// TODO: check_fast for fast path of union type checking
104pub trait CheckType {104pub trait CheckType {
105 fn check(&self, s: State, value: &Val) -> Result<()>;105 fn check(&self, value: &Val) -> Result<()>;
106}106}
107107
108impl CheckType for ValType {108impl CheckType for ValType {
109 fn check(&self, _: State, value: &Val) -> Result<()> {109 fn check(&self, value: &Val) -> Result<()> {
110 let got = value.value_type();110 let got = value.value_type();
111 if got != *self {111 if got != *self {
112 let loc_error: TypeLocError = TypeError::ExpectedGot((*self).into(), got).into();112 let loc_error: TypeLocError = TypeError::ExpectedGot((*self).into(), got).into();
145145
146impl CheckType for ComplexValType {146impl CheckType for ComplexValType {
147 #[allow(clippy::too_many_lines)]147 #[allow(clippy::too_many_lines)]
148 fn check(&self, s: State, value: &Val) -> Result<()> {148 fn check(&self, value: &Val) -> Result<()> {
149 match self {149 match self {
150 Self::Any => Ok(()),150 Self::Any => Ok(()),
151 Self::Simple(t) => t.check(s, value),151 Self::Simple(t) => t.check(value),
152 Self::Char => match value {152 Self::Char => match value {
153 Val::Str(s) if s.len() == 1 || s.chars().count() == 1 => Ok(()),153 Val::Str(s) if s.len() == 1 || s.chars().count() == 1 => Ok(()),
154 v => Err(TypeError::ExpectedGot(self.clone(), v.value_type()).into()),154 v => Err(TypeError::ExpectedGot(self.clone(), v.value_type()).into()),
167 }167 }
168 Self::Array(elem_type) => match value {168 Self::Array(elem_type) => match value {
169 Val::Arr(a) => {169 Val::Arr(a) => {
170 for (i, item) in a.iter(s.clone()).enumerate() {170 for (i, item) in a.iter().enumerate() {
171 push_type_description(171 push_type_description(
172 || format!("array index {i}"),172 || format!("array index {i}"),
173 || ValuePathItem::Index(i as u64),173 || ValuePathItem::Index(i as u64),
174 || elem_type.check(s.clone(), &item.clone()?),174 || elem_type.check(&item.clone()?),
175 )?;175 )?;
176 }176 }
177 Ok(())177 Ok(())
180 },180 },
181 Self::ArrayRef(elem_type) => match value {181 Self::ArrayRef(elem_type) => match value {
182 Val::Arr(a) => {182 Val::Arr(a) => {
183 for (i, item) in a.iter(s.clone()).enumerate() {183 for (i, item) in a.iter().enumerate() {
184 push_type_description(184 push_type_description(
185 || format!("array index {i}"),185 || format!("array index {i}"),
186 || ValuePathItem::Index(i as u64),186 || ValuePathItem::Index(i as u64),
187 || elem_type.check(s.clone(), &item.clone()?),187 || elem_type.check(&item.clone()?),
188 )?;188 )?;
189 }189 }
190 Ok(())190 Ok(())
194 Self::ObjectRef(elems) => match value {194 Self::ObjectRef(elems) => match value {
195 Val::Obj(obj) => {195 Val::Obj(obj) => {
196 for (k, v) in elems.iter() {196 for (k, v) in elems.iter() {
197 if let Some(got_v) = obj.get(s.clone(), (*k).into())? {197 if let Some(got_v) = obj.get((*k).into())? {
198 push_type_description(198 push_type_description(
199 || format!("property {k}"),199 || format!("property {k}"),
200 || ValuePathItem::Field((*k).into()),200 || ValuePathItem::Field((*k).into()),
201 || v.check(s.clone(), &got_v),201 || v.check(&got_v),
202 )?;202 )?;
203 } else {203 } else {
204 return Err(204 return Err(
213 Self::Union(types) => {213 Self::Union(types) => {
214 let mut errors = Vec::new();214 let mut errors = Vec::new();
215 for ty in types.iter() {215 for ty in types.iter() {
216 match ty.check(s.clone(), value) {216 match ty.check(value) {
217 Ok(()) => {217 Ok(()) => {
218 return Ok(());218 return Ok(());
219 }219 }
228 Self::UnionRef(types) => {228 Self::UnionRef(types) => {
229 let mut errors = Vec::new();229 let mut errors = Vec::new();
230 for ty in types.iter() {230 for ty in types.iter() {
231 match ty.check(s.clone(), value) {231 match ty.check(value) {
232 Ok(()) => {232 Ok(()) => {
233 return Ok(());233 return Ok(());
234 }234 }
242 }242 }
243 Self::Sum(types) => {243 Self::Sum(types) => {
244 for ty in types.iter() {244 for ty in types.iter() {
245 ty.check(s.clone(), value)?;245 ty.check(value)?;
246 }246 }
247 Ok(())247 Ok(())
248 }248 }
249 Self::SumRef(types) => {249 Self::SumRef(types) => {
250 for ty in types.iter() {250 for ty in types.iter() {
251 ty.check(s.clone(), value)?;251 ty.check(value)?;
252 }252 }
253 Ok(())253 Ok(())
254 }254 }
modifiedcrates/jrsonnet-evaluator/src/val.rsdiffbeforeafterboth
13 },13 },
14 throw,14 throw,
15 typed::BoundedUsize,15 typed::BoundedUsize,
16 ObjValue, Result, State, Unbound, WeakObjValue,16 ObjValue, Result, Unbound, WeakObjValue,
17};17};
1818
19pub trait ThunkValue: Trace {19pub trait ThunkValue: Trace {
20 type Output;20 type Output;
21 fn get(self: Box<Self>, s: State) -> Result<Self::Output>;21 fn get(self: Box<Self>) -> Result<Self::Output>;
22}22}
2323
24#[derive(Trace)]24#[derive(Trace)]
43 pub fn evaluated(val: T) -> Self {43 pub fn evaluated(val: T) -> Self {
44 Self(Cc::new(RefCell::new(ThunkInner::Computed(val))))44 Self(Cc::new(RefCell::new(ThunkInner::Computed(val))))
45 }45 }
46 pub fn force(&self, s: State) -> Result<()> {46 pub fn force(&self) -> Result<()> {
47 self.evaluate(s)?;47 self.evaluate()?;
48 Ok(())48 Ok(())
49 }49 }
50 pub fn evaluate(&self, s: State) -> Result<T> {50 pub fn evaluate(&self) -> Result<T> {
51 match &*self.0.borrow() {51 match &*self.0.borrow() {
52 ThunkInner::Computed(v) => return Ok(v.clone()),52 ThunkInner::Computed(v) => return Ok(v.clone()),
53 ThunkInner::Errored(e) => return Err(e.clone()),53 ThunkInner::Errored(e) => return Err(e.clone()),
61 } else {61 } else {
62 unreachable!()62 unreachable!()
63 };63 };
64 let new_value = match value.0.get(s) {64 let new_value = match value.0.get() {
65 Ok(v) => v,65 Ok(v) => v,
66 Err(e) => {66 Err(e) => {
67 *self.0.borrow_mut() = ThunkInner::Errored(e.clone());67 *self.0.borrow_mut() = ThunkInner::Errored(e.clone());
94}94}
95impl<I: Unbound<Bound = T>, T: Clone + Trace> Unbound for CachedUnbound<I, T> {95impl<I: Unbound<Bound = T>, T: Clone + Trace> Unbound for CachedUnbound<I, T> {
96 type Bound = T;96 type Bound = T;
97 fn bind(&self, s: State, sup: Option<ObjValue>, this: Option<ObjValue>) -> Result<T> {97 fn bind(&self, sup: Option<ObjValue>, this: Option<ObjValue>) -> Result<T> {
98 let cache_key = (98 let cache_key = (
99 sup.as_ref().map(|s| s.clone().downgrade()),99 sup.as_ref().map(|s| s.clone().downgrade()),
100 this.as_ref().map(|t| t.clone().downgrade()),100 this.as_ref().map(|t| t.clone().downgrade()),
104 return Ok(t.clone());104 return Ok(t.clone());
105 }105 }
106 }106 }
107 let bound = self.value.bind(s, sup, this)?;107 let bound = self.value.bind(sup, this)?;
108108
109 {109 {
110 let mut cache = self.cache.borrow_mut();110 let mut cache = self.cache.borrow_mut();
126 }126 }
127}127}
128128
129#[derive(Clone)]129#[derive(Clone, Trace)]
130pub enum ManifestFormat {130pub enum ManifestFormat {
131 YamlStream(Box<ManifestFormat>),131 YamlStream(Box<ManifestFormat>),
132 Yaml {132 Yaml {
268 /// Get array element by index, evaluating it, if it is lazy.268 /// Get array element by index, evaluating it, if it is lazy.
269 ///269 ///
270 /// Returns `None` on out-of-bounds condition.270 /// Returns `None` on out-of-bounds condition.
271 pub fn get(&self, s: State, index: usize) -> Result<Option<Val>> {271 pub fn get(&self, index: usize) -> Result<Option<Val>> {
272 match self {272 match self {
273 Self::Bytes(i) => i273 Self::Bytes(i) => i
274 .get(index)274 .get(index)
275 .map_or(Ok(None), |v| Ok(Some(Val::Num(f64::from(*v))))),275 .map_or(Ok(None), |v| Ok(Some(Val::Num(f64::from(*v))))),
276 Self::Lazy(vec) => {276 Self::Lazy(vec) => {
277 if let Some(v) = vec.get(index) {277 if let Some(v) = vec.get(index) {
278 Ok(Some(v.evaluate(s)?))278 Ok(Some(v.evaluate()?))
279 } else {279 } else {
280 Ok(None)280 Ok(None)
281 }281 }
284 Self::Extended(v) => {284 Self::Extended(v) => {
285 let a_len = v.0.len();285 let a_len = v.0.len();
286 if a_len > index {286 if a_len > index {
287 v.0.get(s, index)287 v.0.get(index)
288 } else {288 } else {
289 v.1.get(s, index - a_len)289 v.1.get(index - a_len)
290 }290 }
291 }291 }
292 Self::Range(a, _) => {292 Self::Range(a, _) => {
300 if index >= len {300 if index >= len {
301 return Ok(None);301 return Ok(None);
302 }302 }
303 v.get(s, len - index - 1)303 v.get(len - index - 1)
304 }304 }
305 Self::Slice(v) => {305 Self::Slice(v) => {
306 let index = v.from() + index * v.step();306 let index = v.from() + index * v.step();
307 if index >= v.to() {307 if index >= v.to() {
308 return Ok(None);308 return Ok(None);
309 }309 }
310 v.inner.get(s, index)310 v.inner.get(index)
311 }311 }
312 }312 }
313 }313 }
356 }356 }
357357
358 /// Evaluate all array elements, returning new array.358 /// Evaluate all array elements, returning new array.
359 pub fn evaluated(&self, s: State) -> Result<Cc<Vec<Val>>> {359 pub fn evaluated(&self) -> Result<Cc<Vec<Val>>> {
360 Ok(match self {360 Ok(match self {
361 Self::Bytes(i) => {361 Self::Bytes(i) => {
362 let mut out = Vec::with_capacity(i.len());362 let mut out = Vec::with_capacity(i.len());
368 Self::Lazy(vec) => {368 Self::Lazy(vec) => {
369 let mut out = Vec::with_capacity(vec.len());369 let mut out = Vec::with_capacity(vec.len());
370 for item in vec.iter() {370 for item in vec.iter() {
371 out.push(item.evaluate(s.clone())?);371 out.push(item.evaluate()?);
372 }372 }
373 Cc::new(out)373 Cc::new(out)
374 }374 }
375 Self::Eager(vec) => vec.clone(),375 Self::Eager(vec) => vec.clone(),
376 Self::Extended(_v) => {376 Self::Extended(_v) => {
377 let mut out = Vec::with_capacity(self.len());377 let mut out = Vec::with_capacity(self.len());
378 for item in self.iter(s) {378 for item in self.iter() {
379 out.push(item?);379 out.push(item?);
380 }380 }
381 Cc::new(out)381 Cc::new(out)
388 Cc::new(out)388 Cc::new(out)
389 }389 }
390 Self::Reversed(r) => {390 Self::Reversed(r) => {
391 let mut r = r.evaluated(s)?;391 let mut r = r.evaluated()?;
392 Cc::update_with(&mut r, |v| v.reverse());392 Cc::update_with(&mut r, |v| v.reverse());
393 r393 r
394 }394 }
401 .take(v.to() - v.from())401 .take(v.to() - v.from())
402 .step_by(v.step())402 .step_by(v.step())
403 {403 {
404 out.push(v.evaluate(s.clone())?);404 out.push(v.evaluate()?);
405 }405 }
406 Cc::new(out)406 Cc::new(out)
407 }407 }
408 })408 })
409 }409 }
410410
411 /// Iterate over elements, evaluating them.411 /// Iterate over elements, evaluating them.
412 pub fn iter(&self, s: State) -> impl DoubleEndedIterator<Item = Result<Val>> + '_ {412 pub fn iter(&self) -> impl DoubleEndedIterator<Item = Result<Val>> + '_ {
413 (0..self.len()).map(move |idx| match self {413 (0..self.len()).map(move |idx| match self {
414 Self::Bytes(b) => Ok(Val::Num(f64::from(b[idx]))),414 Self::Bytes(b) => Ok(Val::Num(f64::from(b[idx]))),
415 Self::Lazy(l) => l[idx].evaluate(s.clone()),415 Self::Lazy(l) => l[idx].evaluate(),
416 Self::Eager(e) => Ok(e[idx].clone()),416 Self::Eager(e) => Ok(e[idx].clone()),
417 Self::Extended(..) | Self::Range(..) | Self::Reversed(..) | Self::Slice(..) => {417 Self::Extended(..) | Self::Range(..) | Self::Reversed(..) | Self::Slice(..) => {
418 self.get(s.clone(), idx).map(|e| e.expect("idx < len"))418 self.get(idx).map(|e| e.expect("idx < len"))
419 }419 }
420 })420 })
421 }421 }
439 }439 }
440440
441 /// Return a new array, produced by passing every element of current array to specified callback function.441 /// Return a new array, produced by passing every element of current array to specified callback function.
442 pub fn map(self, s: State, mapper: impl Fn(Val) -> Result<Val>) -> Result<Self> {442 pub fn map(self, mapper: impl Fn(Val) -> Result<Val>) -> Result<Self> {
443 let mut out = Vec::with_capacity(self.len());443 let mut out = Vec::with_capacity(self.len());
444444
445 for value in self.iter(s) {445 for value in self.iter() {
446 out.push(mapper(value?)?);446 out.push(mapper(value?)?);
447 }447 }
448448
449 Ok(Self::Eager(Cc::new(out)))449 Ok(Self::Eager(Cc::new(out)))
450 }450 }
451451
452 /// Return a new array, produced from current array by removing every value, for which specified callback function returns false.452 /// Return a new array, produced from current array by removing every value, for which specified callback function returns false.
453 pub fn filter(self, s: State, filter: impl Fn(&Val) -> Result<bool>) -> Result<Self> {453 pub fn filter(self, filter: impl Fn(&Val) -> Result<bool>) -> Result<Self> {
454 let mut out = Vec::with_capacity(self.len());454 let mut out = Vec::with_capacity(self.len());
455455
456 for value in self.iter(s) {456 for value in self.iter() {
457 let value = value?;457 let value = value?;
458 if filter(&value)? {458 if filter(&value)? {
459 out.push(value);459 out.push(value);
645 }645 }
646 }646 }
647647
648 pub fn to_string(&self, s: State) -> Result<IStr> {648 pub fn to_string(&self) -> Result<IStr> {
649 Ok(match self {649 Ok(match self {
650 Self::Bool(true) => "true".into(),650 Self::Bool(true) => "true".into(),
651 Self::Bool(false) => "false".into(),651 Self::Bool(false) => "false".into(),
652 Self::Null => "null".into(),652 Self::Null => "null".into(),
653 Self::Str(s) => s.clone(),653 Self::Str(s) => s.clone(),
654 v => manifest_json_ex(654 v => manifest_json_ex(
655 s,
656 v,655 v,
657 &ManifestJsonOptions {656 &ManifestJsonOptions {
658 padding: "",657 padding: "",
668 }667 }
669668
670 /// Expects value to be object, outputs (key, manifested value) pairs669 /// Expects value to be object, outputs (key, manifested value) pairs
671 pub fn manifest_multi(&self, s: State, ty: &ManifestFormat) -> Result<Vec<(IStr, IStr)>> {670 pub fn manifest_multi(&self, ty: &ManifestFormat) -> Result<Vec<(IStr, IStr)>> {
672 let obj = match self {671 let obj = match self {
673 Self::Obj(obj) => obj,672 Self::Obj(obj) => obj,
674 _ => throw!(MultiManifestOutputIsNotAObject),673 _ => throw!(MultiManifestOutputIsNotAObject),
680 let mut out = Vec::with_capacity(keys.len());679 let mut out = Vec::with_capacity(keys.len());
681 for key in keys {680 for key in keys {
682 let value = obj681 let value = obj
683 .get(s.clone(), key.clone())?682 .get(key.clone())?
684 .expect("item in object")683 .expect("item in object")
685 .manifest(s.clone(), ty)?;684 .manifest(ty)?;
686 out.push((key, value));685 out.push((key, value));
687 }686 }
688 Ok(out)687 Ok(out)
689 }688 }
690689
691 /// Expects value to be array, outputs manifested values690 /// Expects value to be array, outputs manifested values
692 pub fn manifest_stream(&self, s: State, ty: &ManifestFormat) -> Result<Vec<IStr>> {691 pub fn manifest_stream(&self, ty: &ManifestFormat) -> Result<Vec<IStr>> {
693 let arr = match self {692 let arr = match self {
694 Self::Arr(a) => a,693 Self::Arr(a) => a,
695 _ => throw!(StreamManifestOutputIsNotAArray),694 _ => throw!(StreamManifestOutputIsNotAArray),
696 };695 };
697 let mut out = Vec::with_capacity(arr.len());696 let mut out = Vec::with_capacity(arr.len());
698 for i in arr.iter(s.clone()) {697 for i in arr.iter() {
699 out.push(i?.manifest(s.clone(), ty)?);698 out.push(i?.manifest(ty)?);
700 }699 }
701 Ok(out)700 Ok(out)
702 }701 }
703702
704 pub fn manifest(&self, s: State, ty: &ManifestFormat) -> Result<IStr> {703 pub fn manifest(&self, ty: &ManifestFormat) -> Result<IStr> {
705 Ok(match ty {704 Ok(match ty {
706 ManifestFormat::YamlStream(format) => {705 ManifestFormat::YamlStream(format) => {
707 let arr = match self {706 let arr = match self {
717 };716 };
718717
719 if !arr.is_empty() {718 if !arr.is_empty() {
720 for v in arr.iter(s.clone()) {719 for v in arr.iter() {
721 out.push_str("---\n");720 out.push_str("---\n");
722 out.push_str(&v?.manifest(s.clone(), format)?);721 out.push_str(&v?.manifest(format)?);
723 out.push('\n');722 out.push('\n');
724 }723 }
725 out.push_str("...");724 out.push_str("...");
732 #[cfg(feature = "exp-preserve-order")]731 #[cfg(feature = "exp-preserve-order")]
733 preserve_order,732 preserve_order,
734 } => self.to_yaml(733 } => self.to_yaml(
735 s,
736 *padding,734 *padding,
737 #[cfg(feature = "exp-preserve-order")]735 #[cfg(feature = "exp-preserve-order")]
738 *preserve_order,736 *preserve_order,
742 #[cfg(feature = "exp-preserve-order")]740 #[cfg(feature = "exp-preserve-order")]
743 preserve_order,741 preserve_order,
744 } => self.to_json(742 } => self.to_json(
745 s,
746 *padding,743 *padding,
747 #[cfg(feature = "exp-preserve-order")]744 #[cfg(feature = "exp-preserve-order")]
748 *preserve_order,745 *preserve_order,
749 )?,746 )?,
750 ManifestFormat::ToString => self.to_string(s)?,747 ManifestFormat::ToString => self.to_string()?,
751 ManifestFormat::String => match self {748 ManifestFormat::String => match self {
752 Self::Str(s) => s.clone(),749 Self::Str(s) => s.clone(),
753 _ => throw!(StringManifestOutputIsNotAString),750 _ => throw!(StringManifestOutputIsNotAString),
758 /// For manifestification755 /// For manifestification
759 pub fn to_json(756 pub fn to_json(
760 &self,757 &self,
761 s: State,
762 padding: usize,758 padding: usize,
763 #[cfg(feature = "exp-preserve-order")] preserve_order: bool,759 #[cfg(feature = "exp-preserve-order")] preserve_order: bool,
764 ) -> Result<IStr> {760 ) -> Result<IStr> {
765 manifest_json_ex(761 manifest_json_ex(
766 s,
767 self,762 self,
768 &ManifestJsonOptions {763 &ManifestJsonOptions {
769 padding: &" ".repeat(padding),764 padding: &" ".repeat(padding),
784 /// Calls `std.manifestJson`779 /// Calls `std.manifestJson`
785 pub fn to_std_json(780 pub fn to_std_json(
786 &self,781 &self,
787 s: State,
788 padding: usize,782 padding: usize,
789 #[cfg(feature = "exp-preserve-order")] preserve_order: bool,783 #[cfg(feature = "exp-preserve-order")] preserve_order: bool,
790 ) -> Result<Rc<str>> {784 ) -> Result<Rc<str>> {
791 manifest_json_ex(785 manifest_json_ex(
792 s,
793 self,786 self,
794 &ManifestJsonOptions {787 &ManifestJsonOptions {
795 padding: &" ".repeat(padding),788 padding: &" ".repeat(padding),
805798
806 pub fn to_yaml(799 pub fn to_yaml(
807 &self,800 &self,
808 s: State,
809 padding: usize,801 padding: usize,
810 #[cfg(feature = "exp-preserve-order")] preserve_order: bool,802 #[cfg(feature = "exp-preserve-order")] preserve_order: bool,
811 ) -> Result<IStr> {803 ) -> Result<IStr> {
812 let padding = &" ".repeat(padding);804 let padding = &" ".repeat(padding);
813 manifest_yaml_ex(805 manifest_yaml_ex(
814 s,
815 self,806 self,
816 &ManifestYamlOptions {807 &ManifestYamlOptions {
817 padding,808 padding,
857}848}
858849
859/// Native implementation of `std.equals`850/// Native implementation of `std.equals`
860pub fn equals(s: State, val_a: &Val, val_b: &Val) -> Result<bool> {851pub fn equals(val_a: &Val, val_b: &Val) -> Result<bool> {
861 if val_a.value_type() != val_b.value_type() {852 if val_a.value_type() != val_b.value_type() {
862 return Ok(false);853 return Ok(false);
863 }854 }
869 if a.len() != b.len() {860 if a.len() != b.len() {
870 return Ok(false);861 return Ok(false);
871 }862 }
872 for (a, b) in a.iter(s.clone()).zip(b.iter(s.clone())) {863 for (a, b) in a.iter().zip(b.iter()) {
873 if !equals(s.clone(), &a?, &b?)? {864 if !equals(&a?, &b?)? {
874 return Ok(false);865 return Ok(false);
875 }866 }
876 }867 }
893 }884 }
894 for field in fields {885 for field in fields {
895 if !equals(886 if !equals(
896 s.clone(),
897 &a.get(s.clone(), field.clone())?.expect("field exists"),887 &a.get(field.clone())?.expect("field exists"),
898 &b.get(s.clone(), field)?.expect("field exists"),888 &b.get(field)?.expect("field exists"),
899 )? {889 )? {
900 return Ok(false);890 return Ok(false);
901 }891 }
modifiedcrates/jrsonnet-interner/src/lib.rsdiffbeforeafterboth
4 clippy::undocumented_unsafe_blocks4 clippy::undocumented_unsafe_blocks
5)]5)]
6#![warn(clippy::pedantic, clippy::nursery)]6#![warn(clippy::pedantic, clippy::nursery)]
7#![allow(clippy::missing_const_for_fn)]
7use std::{8use std::{
8 borrow::Cow,9 borrow::Cow,
9 cell::RefCell,10 cell::RefCell,
modifiedcrates/jrsonnet-macros/src/lib.rsdiffbeforeafterboth
130 is_option: bool,130 is_option: bool,
131 name: Option<String>,131 name: Option<String>,
132 },132 },
133 State,133 Context,
134 Location,134 Location,
135 This,135 This,
136}136}
146 _ => None,146 _ => None,
147 };147 };
148 let ty = &arg.ty;148 let ty = &arg.ty;
149 if type_is_path(ty, "State").is_some() {149 if type_is_path(ty, "Context").is_some() {
150 return Ok(Self::State);150 return Ok(Self::Context);
151 } else if type_is_path(ty, "CallLocation").is_some() {151 } else if type_is_path(ty, "CallLocation").is_some() {
152 return Ok(Self::Location);152 return Ok(Self::Location);
153 } else if type_is_path(ty, "Thunk").is_some() {153 } else if type_is_path(ty, "Thunk").is_some() {
273 },273 },
274 })274 })
275 }275 }
276 ArgInfo::State => None,276 ArgInfo::Context => None,
277 ArgInfo::Location => None,277 ArgInfo::Location => None,
278 ArgInfo::This => None,278 ArgInfo::This => None,
279 });279 });
287 id += 1;287 id += 1;
288 (quote! {#cid}, a)288 (quote! {#cid}, a)
289 }289 }
290 ArgInfo::State | ArgInfo::Location | ArgInfo::This => {290 ArgInfo::Context | ArgInfo::Location | ArgInfo::This => {
291 (quote! {compile_error!("should not use id")}, a)291 (quote! {compile_error!("should not use id")}, a)
292 }292 }
293 })293 })
301 let name = name.as_ref().map(|v| v.as_str()).unwrap_or("<unnamed>");301 let name = name.as_ref().map(|v| v.as_str()).unwrap_or("<unnamed>");
302 let eval = quote! {jrsonnet_evaluator::State::push_description(302 let eval = quote! {jrsonnet_evaluator::State::push_description(
303 || format!("argument <{}> evaluation", #name),303 || format!("argument <{}> evaluation", #name),
304 || <#ty>::from_untyped(value.evaluate(s.clone())?, s.clone()),304 || <#ty>::from_untyped(value.evaluate()?),
305 )?};305 )?};
306 let value = if *is_option {306 let value = if *is_option {
307 quote! {if let Some(value) = &parsed[#id] {307 quote! {if let Some(value) = &parsed[#id] {
333 }333 }
334 }334 }
335 }335 }
336 ArgInfo::State => quote! {s.clone(),},336 ArgInfo::Context => quote! {ctx.clone(),},
337 ArgInfo::Location => quote! {location,},337 ArgInfo::Location => quote! {location,},
338 ArgInfo::This => quote! {self,},338 ArgInfo::This => quote! {self,},
339 });339 });
394 fn params(&self) -> &[BuiltinParam] {394 fn params(&self) -> &[BuiltinParam] {
395 PARAMS395 PARAMS
396 }396 }
397 fn call(&self, s: State, ctx: Context, location: CallLocation, args: &dyn ArgsLike) -> Result<Val> {397 fn call(&self, ctx: Context, location: CallLocation, args: &dyn ArgsLike) -> Result<Val> {
398 let parsed = parse_builtin_call(s.clone(), ctx, &PARAMS, args, false)?;398 let parsed = parse_builtin_call(ctx.clone(), &PARAMS, args, false)?;
399399
400 let result: #result = #name(#(#pass)*);400 let result: #result = #name(#(#pass)*);
401 let result = result?;401 let result = result?;
402 <#result_inner>::into_untyped(result, s)402 <#result_inner>::into_untyped(result)
403 }403 }
404 }404 }
405 };405 };
535 // optional flatten is handled in same way as serde535 // optional flatten is handled in same way as serde
536 return if self.is_option {536 return if self.is_option {
537 quote! {537 quote! {
538 #ident: <#ty>::parse(&obj, s.clone()).ok(),538 #ident: <#ty>::parse(&obj).ok(),
539 }539 }
540 } else {540 } else {
541 quote! {541 quote! {
542 #ident: <#ty>::parse(&obj, s.clone())?,542 #ident: <#ty>::parse(&obj)?,
543 }543 }
544 };544 };
545 };545 };
546546
547 let name = self.name().unwrap();547 let name = self.name().unwrap();
548 let value = if self.is_option {548 let value = if self.is_option {
549 quote! {549 quote! {
550 if let Some(value) = obj.get(s.clone(), #name.into())? {550 if let Some(value) = obj.get(#name.into())? {
551 Some(<#ty>::from_untyped(value, s.clone())?)551 Some(<#ty>::from_untyped(value)?)
552 } else {552 } else {
553 None553 None
554 }554 }
555 }555 }
556 } else {556 } else {
557 quote! {557 quote! {
558 <#ty>::from_untyped(obj.get(s.clone(), #name.into())?.ok_or_else(|| Error::NoSuchField(#name.into(), vec![]))?, s.clone())?558 <#ty>::from_untyped(obj.get(#name.into())?.ok_or_else(|| Error::NoSuchField(#name.into(), vec![]))?)?
559 }559 }
560 };560 };
561561
570 if self.is_option {570 if self.is_option {
571 quote! {571 quote! {
572 if let Some(value) = self.#ident {572 if let Some(value) = self.#ident {
573 out.member(#name.into()).value(s.clone(), <#ty>::into_untyped(value, s.clone())?)?;573 out.member(#name.into()).value(<#ty>::into_untyped(value)?)?;
574 }574 }
575 }575 }
576 } else {576 } else {
577 quote! {577 quote! {
578 out.member(#name.into()).value(s.clone(), <#ty>::into_untyped(self.#ident, s.clone())?)?;578 out.member(#name.into()).value(<#ty>::into_untyped(self.#ident)?)?;
579 }579 }
580 }580 }
581 } else if self.is_option {581 } else if self.is_option {
582 quote! {582 quote! {
583 if let Some(value) = self.#ident {583 if let Some(value) = self.#ident {
584 value.serialize(s.clone(), out)?;584 value.serialize(out)?;
585 }585 }
586 }586 }
587 } else {587 } else {
588 quote! {588 quote! {
589 self.#ident.serialize(s.clone(), out)?;589 self.#ident.serialize(out)?;
590 }590 }
591 })591 })
592 }592 }
628 impl Typed for #ident {628 impl Typed for #ident {
629 const TYPE: &'static ComplexValType = &ComplexValType::ObjectRef(&ITEMS);629 const TYPE: &'static ComplexValType = &ComplexValType::ObjectRef(&ITEMS);
630630
631 fn from_untyped(value: Val, s: State) -> Result<Self> {631 fn from_untyped(value: Val) -> Result<Self> {
632 let obj = value.as_obj().expect("shape is correct");632 let obj = value.as_obj().expect("shape is correct");
633 Self::parse(&obj, s)633 Self::parse(&obj)
634 }634 }
635635
636 fn into_untyped(value: Self, s: State) -> Result<Val> {636 fn into_untyped(value: Self) -> Result<Val> {
637 let mut out = ObjValueBuilder::new();637 let mut out = ObjValueBuilder::new();
638 value.serialize(s, &mut out)?;638 value.serialize(&mut out)?;
639 Ok(Val::Obj(out.build()))639 Ok(Val::Obj(out.build()))
640 }640 }
641641
661 #typed661 #typed
662662
663 impl TypedObj for #ident {663 impl TypedObj for #ident {
664 fn serialize(self, s: State, out: &mut ObjValueBuilder) -> Result<(), LocError> {664 fn serialize(self, out: &mut ObjValueBuilder) -> Result<(), LocError> {
665 #(#fields_serialize)*665 #(#fields_serialize)*
666666
667 Ok(())667 Ok(())
668 }668 }
669 fn parse(obj: &ObjValue, s: State) -> Result<Self, LocError> {669 fn parse(obj: &ObjValue) -> Result<Self, LocError> {
670 Ok(Self {670 Ok(Self {
671 #(#fields_parse)*671 #(#fields_parse)*
672 })672 })
modifiedcrates/jrsonnet-parser/src/location.rsdiffbeforeafterboth
1#[allow(clippy::module_name_repetitions)]1#[allow(clippy::module_name_repetitions)]
2#[derive(Clone, PartialEq, Eq, Debug)]2#[derive(Clone, Copy, PartialEq, Eq, Debug, Default)]
3pub struct CodeLocation {3pub struct CodeLocation {
4 pub offset: usize,4 pub offset: usize,
55
24}24}
2525
26#[allow(clippy::module_name_repetitions)]26#[allow(clippy::module_name_repetitions)]
27pub fn offset_to_location(file: &str, offsets: &[u32]) -> Vec<CodeLocation> {27pub fn offset_to_location<const S: usize>(file: &str, offsets: &[u32; S]) -> [CodeLocation; S] {
28 if offsets.is_empty() {28 if offsets.is_empty() {
29 return vec![];29 return [CodeLocation::default(); S];
30 }30 }
31 let mut line = 1;31 let mut line = 1;
32 let mut column = 1;32 let mut column = 1;
40 offset_map.sort_by_key(|v| v.0);40 offset_map.sort_by_key(|v| v.0);
41 offset_map.reverse();41 offset_map.reverse();
4242
43 let mut out = vec![43 let mut out = [CodeLocation::default(); S];
44 CodeLocation {
45 offset: 0,
46 column: 0,
47 line: 0,
48 line_start_offset: 0,
49 line_end_offset: 0
50 };
51 offsets.len()
52 ];
53 let mut with_no_known_line_ending = vec![];44 let mut with_no_known_line_ending = vec![];
54 let mut this_line_offset = 0;45 let mut this_line_offset = 0;
55 for (pos, ch) in file46 for (pos, ch) in file
103 "hello world\n_______________________________________________________",94 "hello world\n_______________________________________________________",
104 &[0, 14]95 &[0, 14]
105 ),96 ),
106 vec![97 [
107 CodeLocation {98 CodeLocation {
108 offset: 0,99 offset: 0,
109 line: 1,100 line: 1,
modifiedcrates/jrsonnet-parser/src/source.rsdiffbeforeafterboth
289 &self.0 .0289 &self.0 .0
290 }290 }
291291
292 pub fn map_source_locations(&self, locs: &[u32]) -> Vec<CodeLocation> {292 pub fn map_source_locations<const S: usize>(&self, locs: &[u32; S]) -> [CodeLocation; S] {
293 offset_to_location(&self.0 .1, locs)293 offset_to_location(&self.0 .1, locs)
294 }294 }
295 pub fn map_from_source_location(&self, line: usize, column: usize) -> Option<usize> {295 pub fn map_from_source_location(&self, line: usize, column: usize) -> Option<usize> {
modifiedcrates/jrsonnet-stdlib/src/arrays.rsdiffbeforeafterboth
2 error::Result,2 error::Result,
3 function::{builtin, FuncVal},3 function::{builtin, FuncVal},
4 throw,4 throw,
5 typed::{Any, BoundedUsize, Typed, VecVal},5 typed::{Any, BoundedUsize, Either2, NativeFn, Typed, VecVal},
6 val::{equals, ArrValue, IndexableVal},6 val::{equals, ArrValue, IndexableVal},
7 IStr, State, Val,7 Either, IStr, Val,
8};8};
9use jrsonnet_gcmodule::Cc;9use jrsonnet_gcmodule::Cc;
1010
11#[builtin]11#[builtin]
12pub fn builtin_make_array(s: State, sz: usize, func: FuncVal) -> Result<VecVal> {12pub fn builtin_make_array(sz: usize, func: NativeFn<((f64,), Any)>) -> Result<VecVal> {
13 let mut out = Vec::with_capacity(sz);13 let mut out = Vec::with_capacity(sz);
14 for i in 0..sz {14 for i in 0..sz {
15 out.push(func.evaluate_simple(s.clone(), &(i as f64,))?);15 out.push(func(i as f64)?.0);
16 }16 }
17 Ok(VecVal(Cc::new(out)))17 Ok(VecVal(Cc::new(out)))
18}18}
28}28}
2929
30#[builtin]30#[builtin]
31pub fn builtin_map(s: State, func: FuncVal, arr: ArrValue) -> Result<ArrValue> {31pub fn builtin_map(func: NativeFn<((Any,), Any)>, arr: ArrValue) -> Result<ArrValue> {
32 arr.map(s.clone(), |val| {32 arr.map(|val| Ok(func(Any(val))?.0))
33 func.evaluate_simple(s.clone(), &(Any(val),))
34 })
35}33}
3634
37#[builtin]35#[builtin]
38pub fn builtin_flatmap(s: State, func: FuncVal, arr: IndexableVal) -> Result<IndexableVal> {36pub fn builtin_flatmap(
37 func: NativeFn<((Either![String, Any],), Any)>,
38 arr: IndexableVal,
39) -> Result<IndexableVal> {
39 match arr {40 match arr {
40 IndexableVal::Str(str) => {41 IndexableVal::Str(str) => {
41 let mut out = String::new();42 let mut out = String::new();
42 for c in str.chars() {43 for c in str.chars() {
43 match func.evaluate_simple(s.clone(), &(c.to_string(),))? {44 match func(Either2::A(c.to_string()))?.0 {
44 Val::Str(o) => out.push_str(&o),45 Val::Str(o) => out.push_str(&o),
45 Val::Null => continue,46 Val::Null => continue,
46 _ => throw!("in std.join all items should be strings"),47 _ => throw!("in std.join all items should be strings"),
50 }51 }
51 IndexableVal::Arr(a) => {52 IndexableVal::Arr(a) => {
52 let mut out = Vec::new();53 let mut out = Vec::new();
53 for el in a.iter(s.clone()) {54 for el in a.iter() {
54 let el = el?;55 let el = el?;
55 match func.evaluate_simple(s.clone(), &(Any(el),))? {56 match func(Either2::B(Any(el)))?.0 {
56 Val::Arr(o) => {57 Val::Arr(o) => {
57 for oe in o.iter(s.clone()) {58 for oe in o.iter() {
58 out.push(oe?);59 out.push(oe?);
59 }60 }
60 }61 }
68}69}
6970
70#[builtin]71#[builtin]
71pub fn builtin_filter(s: State, func: FuncVal, arr: ArrValue) -> Result<ArrValue> {72pub fn builtin_filter(func: FuncVal, arr: ArrValue) -> Result<ArrValue> {
72 arr.filter(s.clone(), |val| {73 arr.filter(|val| bool::from_untyped(func.evaluate_simple(&(Any(val.clone()),))?))
73 bool::from_untyped(
74 func.evaluate_simple(s.clone(), &(Any(val.clone()),))?,
75 s.clone(),
76 )
77 })
78}74}
7975
80#[builtin]76#[builtin]
81pub fn builtin_foldl(s: State, func: FuncVal, arr: ArrValue, init: Any) -> Result<Any> {77pub fn builtin_foldl(func: FuncVal, arr: ArrValue, init: Any) -> Result<Any> {
82 let mut acc = init.0;78 let mut acc = init.0;
83 for i in arr.iter(s.clone()) {79 for i in arr.iter() {
84 acc = func.evaluate_simple(s.clone(), &(Any(acc), Any(i?)))?;80 acc = func.evaluate_simple(&(Any(acc), Any(i?)))?;
85 }81 }
86 Ok(Any(acc))82 Ok(Any(acc))
87}83}
8884
89#[builtin]85#[builtin]
90pub fn builtin_foldr(s: State, func: FuncVal, arr: ArrValue, init: Any) -> Result<Any> {86pub fn builtin_foldr(func: FuncVal, arr: ArrValue, init: Any) -> Result<Any> {
91 let mut acc = init.0;87 let mut acc = init.0;
92 for i in arr.iter(s.clone()).rev() {88 for i in arr.iter().rev() {
93 acc = func.evaluate_simple(s.clone(), &(Any(i?), Any(acc)))?;89 acc = func.evaluate_simple(&(Any(i?), Any(acc)))?;
94 }90 }
95 Ok(Any(acc))91 Ok(Any(acc))
96}92}
104}100}
105101
106#[builtin]102#[builtin]
107pub fn builtin_join(s: State, sep: IndexableVal, arr: ArrValue) -> Result<IndexableVal> {103pub fn builtin_join(sep: IndexableVal, arr: ArrValue) -> Result<IndexableVal> {
108 Ok(match sep {104 Ok(match sep {
109 IndexableVal::Arr(joiner_items) => {105 IndexableVal::Arr(joiner_items) => {
110 let mut out = Vec::new();106 let mut out = Vec::new();
111107
112 let mut first = true;108 let mut first = true;
113 for item in arr.iter(s.clone()) {109 for item in arr.iter() {
114 let item = item?.clone();110 let item = item?.clone();
115 if let Val::Arr(items) = item {111 if let Val::Arr(items) = item {
116 if !first {112 if !first {
117 out.reserve(joiner_items.len());113 out.reserve(joiner_items.len());
118 // TODO: extend114 // TODO: extend
119 for item in joiner_items.iter(s.clone()) {115 for item in joiner_items.iter() {
120 out.push(item?);116 out.push(item?);
121 }117 }
122 }118 }
123 first = false;119 first = false;
124 out.reserve(items.len());120 out.reserve(items.len());
125 for item in items.iter(s.clone()) {121 for item in items.iter() {
126 out.push(item?);122 out.push(item?);
127 }123 }
128 } else if matches!(item, Val::Null) {124 } else if matches!(item, Val::Null) {
138 let mut out = String::new();134 let mut out = String::new();
139135
140 let mut first = true;136 let mut first = true;
141 for item in arr.iter(s) {137 for item in arr.iter() {
142 let item = item?.clone();138 let item = item?.clone();
143 if let Val::Str(item) = item {139 if let Val::Str(item) = item {
144 if !first {140 if !first {
164}160}
165161
166#[builtin]162#[builtin]
167pub fn builtin_any(s: State, arr: ArrValue) -> Result<bool> {163pub fn builtin_any(arr: ArrValue) -> Result<bool> {
168 for v in arr.iter(s.clone()) {164 for v in arr.iter() {
169 let v = bool::from_untyped(v?, s.clone())?;165 let v = bool::from_untyped(v?)?;
170 if v {166 if v {
171 return Ok(true);167 return Ok(true);
172 }168 }
175}171}
176172
177#[builtin]173#[builtin]
178pub fn builtin_all(s: State, arr: ArrValue) -> Result<bool> {174pub fn builtin_all(arr: ArrValue) -> Result<bool> {
179 for v in arr.iter(s.clone()) {175 for v in arr.iter() {
180 let v = bool::from_untyped(v?, s.clone())?;176 let v = bool::from_untyped(v?)?;
181 if !v {177 if !v {
182 return Ok(false);178 return Ok(false);
183 }179 }
186}182}
187183
188#[builtin]184#[builtin]
189pub fn builtin_member(s: State, arr: IndexableVal, x: Any) -> Result<bool> {185pub fn builtin_member(arr: IndexableVal, x: Any) -> Result<bool> {
190 match arr {186 match arr {
191 IndexableVal::Str(str) => {187 IndexableVal::Str(str) => {
192 let x: IStr = IStr::from_untyped(x.0, s)?;188 let x: IStr = IStr::from_untyped(x.0)?;
193 Ok(!x.is_empty() && str.contains(&*x))189 Ok(!x.is_empty() && str.contains(&*x))
194 }190 }
195 IndexableVal::Arr(a) => {191 IndexableVal::Arr(a) => {
196 for item in a.iter(s.clone()) {192 for item in a.iter() {
197 let item = item?;193 let item = item?;
198 if equals(s.clone(), &item, &x.0)? {194 if equals(&item, &x.0)? {
199 return Ok(true);195 return Ok(true);
200 }196 }
201 }197 }
205}201}
206202
207#[builtin]203#[builtin]
208pub fn builtin_count(s: State, arr: Vec<Any>, v: Any) -> Result<usize> {204pub fn builtin_count(arr: Vec<Any>, v: Any) -> Result<usize> {
209 let mut count = 0;205 let mut count = 0;
210 for item in &arr {206 for item in &arr {
211 if equals(s.clone(), &item.0, &v.0)? {207 if equals(&item.0, &v.0)? {
212 count += 1;208 count += 1;
213 }209 }
214 }210 }
modifiedcrates/jrsonnet-stdlib/src/lib.rsdiffbeforeafterboth
12 trace::PathResolver,12 trace::PathResolver,
13 Context, ContextBuilder, IStr, ObjValue, ObjValueBuilder, State, Thunk, Val,13 Context, ContextBuilder, IStr, ObjValue, ObjValueBuilder, State, Thunk, Val,
14};14};
15use jrsonnet_gcmodule::Cc;15use jrsonnet_gcmodule::{Cc, Trace};
16use jrsonnet_parser::Source;16use jrsonnet_parser::Source;
1717
18mod expr;18mod expr;
41mod misc;41mod misc;
42pub use misc::*;42pub use misc::*;
4343
44pub fn stdlib_uncached(s: State, settings: Rc<RefCell<Settings>>) -> ObjValue {44pub fn stdlib_uncached(settings: Rc<RefCell<Settings>>) -> ObjValue {
45 let mut builder = ObjValueBuilder::new();45 let mut builder = ObjValueBuilder::new();
4646
47 let expr = expr::stdlib_expr();47 let expr = expr::stdlib_expr();
48 let eval = jrsonnet_evaluator::evaluate(s.clone(), Context::default(), &expr)48 let eval = jrsonnet_evaluator::evaluate(ContextBuilder::dangerous_empty_state().build(), &expr)
49 .expect("stdlib.jsonnet should have no errors")49 .expect("stdlib.jsonnet should have no errors")
50 .as_obj()50 .as_obj()
51 .expect("stdlib.jsonnet should evaluate to object");51 .expect("stdlib.jsonnet should evaluate to object");
173}173}
174174
175pub trait TracePrinter {175pub trait TracePrinter {
176 fn print_trace(&self, s: State, loc: CallLocation, value: IStr);176 fn print_trace(&self, loc: CallLocation, value: IStr);
177}177}
178178
179pub struct StdTracePrinter {179pub struct StdTracePrinter {
185 }185 }
186}186}
187impl TracePrinter for StdTracePrinter {187impl TracePrinter for StdTracePrinter {
188 fn print_trace(&self, _s: State, loc: CallLocation, value: IStr) {188 fn print_trace(&self, loc: CallLocation, value: IStr) {
189 eprint!("TRACE:");189 eprint!("TRACE:");
190 if let Some(loc) = loc.0 {190 if let Some(loc) = loc.0 {
191 let locs = loc.0.map_source_locations(&[loc.1]);191 let locs = loc.0.map_source_locations(&[loc.1]);
220 Source::new_virtual(source_name.into(), code.into())220 Source::new_virtual(source_name.into(), code.into())
221}221}
222222
223#[derive(Trace)]
223pub struct ContextInitializer {224pub struct ContextInitializer {
224 // When we don't need to support legacy-this-file, we can reuse same context for all files225 // When we don't need to support legacy-this-file, we can reuse same context for all files
225 #[cfg(not(feature = "legacy-this-file"))]226 #[cfg(not(feature = "legacy-this-file"))]
242 Self {243 Self {
243 #[cfg(not(feature = "legacy-this-file"))]244 #[cfg(not(feature = "legacy-this-file"))]
244 context: {245 context: {
245 let mut context = ContextBuilder::with_capacity(1);246 let mut context = ContextBuilder::with_capacity(s, 1);
246 context.bind(247 context.bind(
247 "std".into(),248 "std".into(),
248 Thunk::evaluated(Val::Obj(stdlib_uncached(s, settings.clone()))),249 Thunk::evaluated(Val::Obj(stdlib_uncached(settings.clone()))),
249 );250 );
250 context.build()251 context.build()
251 },252 },
349impl StateExt for State {350impl StateExt for State {
350 fn with_stdlib(&self) {351 fn with_stdlib(&self) {
351 let initializer = ContextInitializer::new(self.clone(), PathResolver::new_cwd_fallback());352 let initializer = ContextInitializer::new(self.clone(), PathResolver::new_cwd_fallback());
352 self.settings_mut().context_initializer = Box::new(initializer)353 self.settings_mut().context_initializer = tb!(initializer)
353 }354 }
354 fn add_global(&self, name: IStr, value: Thunk<Val>) {355 fn add_global(&self, name: IStr, value: Thunk<Val>) {
355 self.settings()356 self.settings()
modifiedcrates/jrsonnet-stdlib/src/manifest.rsdiffbeforeafterboth
6 ManifestYamlOptions,6 ManifestYamlOptions,
7 },7 },
8 typed::Any,8 typed::Any,
9 IStr, State,9 IStr,
10};10};
1111
12#[builtin]12#[builtin]
1616
17#[builtin]17#[builtin]
18pub fn builtin_manifest_json_ex(18pub fn builtin_manifest_json_ex(
19 s: State,
20 value: Any,19 value: Any,
21 indent: IStr,20 indent: IStr,
22 newline: Option<IStr>,21 newline: Option<IStr>,
26 let newline = newline.as_deref().unwrap_or("\n");25 let newline = newline.as_deref().unwrap_or("\n");
27 let key_val_sep = key_val_sep.as_deref().unwrap_or(": ");26 let key_val_sep = key_val_sep.as_deref().unwrap_or(": ");
28 manifest_json_ex(27 manifest_json_ex(
29 s,
30 &value.0,28 &value.0,
31 &ManifestJsonOptions {29 &ManifestJsonOptions {
32 padding: &indent,30 padding: &indent,
4139
42#[builtin]40#[builtin]
43pub fn builtin_manifest_yaml_doc(41pub fn builtin_manifest_yaml_doc(
44 s: State,
45 value: Any,42 value: Any,
46 indent_array_in_object: Option<bool>,43 indent_array_in_object: Option<bool>,
47 quote_keys: Option<bool>,44 quote_keys: Option<bool>,
48 #[cfg(feature = "exp-preserve-order")] preserve_order: Option<bool>,45 #[cfg(feature = "exp-preserve-order")] preserve_order: Option<bool>,
49) -> Result<String> {46) -> Result<String> {
50 manifest_yaml_ex(47 manifest_yaml_ex(
51 s,
52 &value.0,48 &value.0,
53 &ManifestYamlOptions {49 &ManifestYamlOptions {
54 padding: " ",50 padding: " ",
modifiedcrates/jrsonnet-stdlib/src/misc.rsdiffbeforeafterboth
6 throw,6 throw,
7 typed::{Any, Either2, Either4},7 typed::{Any, Either2, Either4},
8 val::{equals, ArrValue},8 val::{equals, ArrValue},
9 Either, IStr, ObjValue, State, Thunk, Val,9 Context, Either, IStr, ObjValue, Thunk, Val,
10};10};
1111
12use crate::{extvar_source, Settings};12use crate::{extvar_source, Settings};
25#[builtin(fields(25#[builtin(fields(
26 settings: Rc<RefCell<Settings>>,26 settings: Rc<RefCell<Settings>>,
27))]27))]
28pub fn builtin_ext_var(this: &builtin_ext_var, s: State, x: IStr) -> Result<Any> {28pub fn builtin_ext_var(this: &builtin_ext_var, ctx: Context, x: IStr) -> Result<Any> {
29 let ctx = s.create_default_context(extvar_source(&x, ""));29 let ctx = ctx.state().create_default_context(extvar_source(&x, ""));
30 Ok(Any(this30 Ok(Any(this
31 .settings31 .settings
32 .borrow()32 .borrow()
33 .ext_vars33 .ext_vars
34 .get(&x)34 .get(&x)
35 .cloned()35 .cloned()
36 .ok_or_else(|| UndefinedExternalVariable(x))?36 .ok_or_else(|| UndefinedExternalVariable(x))?
37 .evaluate_arg(s.clone(), ctx, true)?37 .evaluate_arg(ctx, true)?
38 .evaluate(s)?))38 .evaluate()?))
39}39}
4040
41#[builtin(fields(41#[builtin(fields(
58))]58))]
59pub fn builtin_trace(59pub fn builtin_trace(
60 this: &builtin_trace,60 this: &builtin_trace,
61 s: State,
62 loc: CallLocation,61 loc: CallLocation,
63 str: IStr,62 str: IStr,
64 rest: Thunk<Val>,63 rest: Thunk<Val>,
65) -> Result<Any> {64) -> Result<Any> {
66 this.settings65 this.settings.borrow().trace_printer.print_trace(loc, str);
67 .borrow()
68 .trace_printer
69 .print_trace(s.clone(), loc, str);
70 Ok(Any(rest.evaluate(s)?))66 Ok(Any(rest.evaluate()?))
71}67}
7268
73#[allow(clippy::comparison_chain)]69#[allow(clippy::comparison_chain)]
74#[builtin]70#[builtin]
75pub fn builtin_starts_with(71pub fn builtin_starts_with(a: Either![IStr, ArrValue], b: Either![IStr, ArrValue]) -> Result<bool> {
76 s: State,
77 a: Either![IStr, ArrValue],
78 b: Either![IStr, ArrValue],
79) -> Result<bool> {
80 Ok(match (a, b) {72 Ok(match (a, b) {
81 (Either2::A(a), Either2::A(b)) => a.starts_with(b.as_str()),73 (Either2::A(a), Either2::A(b)) => a.starts_with(b.as_str()),
82 (Either2::B(a), Either2::B(b)) => {74 (Either2::B(a), Either2::B(b)) => {
83 if b.len() > a.len() {75 if b.len() > a.len() {
84 return Ok(false);76 return Ok(false);
85 } else if b.len() == a.len() {77 } else if b.len() == a.len() {
86 return equals(s, &Val::Arr(a), &Val::Arr(b));78 return equals(&Val::Arr(a), &Val::Arr(b));
87 } else {79 } else {
88 for (a, b) in a80 for (a, b) in a.slice(None, Some(b.len()), None).iter().zip(b.iter()) {
89 .slice(None, Some(b.len()), None)
90 .iter(s.clone())
91 .zip(b.iter(s.clone()))
92 {
93 let a = a?;81 let a = a?;
94 let b = b?;82 let b = b?;
95 if !equals(s.clone(), &a, &b)? {83 if !equals(&a, &b)? {
96 return Ok(false);84 return Ok(false);
97 }85 }
98 }86 }
106#[allow(clippy::comparison_chain)]94#[allow(clippy::comparison_chain)]
107#[builtin]95#[builtin]
108pub fn builtin_ends_with(96pub fn builtin_ends_with(a: Either![IStr, ArrValue], b: Either![IStr, ArrValue]) -> Result<bool> {
109 s: State,
110 a: Either![IStr, ArrValue],
111 b: Either![IStr, ArrValue],
112) -> Result<bool> {
113 Ok(match (a, b) {97 Ok(match (a, b) {
114 (Either2::A(a), Either2::A(b)) => a.ends_with(b.as_str()),98 (Either2::A(a), Either2::A(b)) => a.ends_with(b.as_str()),
115 (Either2::B(a), Either2::B(b)) => {99 (Either2::B(a), Either2::B(b)) => {
116 if b.len() > a.len() {100 if b.len() > a.len() {
117 return Ok(false);101 return Ok(false);
118 } else if b.len() == a.len() {102 } else if b.len() == a.len() {
119 return equals(s, &Val::Arr(a), &Val::Arr(b));103 return equals(&Val::Arr(a), &Val::Arr(b));
120 } else {104 } else {
121 let a_len = a.len();105 let a_len = a.len();
122 for (a, b) in a106 for (a, b) in a
123 .slice(Some(a_len - b.len()), None, None)107 .slice(Some(a_len - b.len()), None, None)
124 .iter(s.clone())108 .iter()
125 .zip(b.iter(s.clone()))109 .zip(b.iter())
126 {110 {
127 let a = a?;111 let a = a?;
128 let b = b?;112 let b = b?;
129 if !equals(s.clone(), &a, &b)? {113 if !equals(&a, &b)? {
130 return Ok(false);114 return Ok(false);
131 }115 }
132 }116 }
modifiedcrates/jrsonnet-stdlib/src/operator.rsdiffbeforeafterboth
8 stdlib::std_format,8 stdlib::std_format,
9 typed::{Any, Either, Either2},9 typed::{Any, Either, Either2},
10 val::{equals, primitive_equals},10 val::{equals, primitive_equals},
11 IStr, State, Val,11 IStr, Val,
12};12};
1313
14#[builtin]14#[builtin]
15pub fn builtin_mod(s: State, a: Either![f64, IStr], b: Any) -> Result<Any> {15pub fn builtin_mod(a: Either![f64, IStr], b: Any) -> Result<Any> {
16 use Either2::*;16 use Either2::*;
17 Ok(Any(evaluate_mod_op(17 Ok(Any(evaluate_mod_op(
18 s,
19 &match a {18 &match a {
20 A(v) => Val::Num(v),19 A(v) => Val::Num(v),
21 B(s) => Val::Str(s),20 B(s) => Val::Str(s),
30}29}
3130
32#[builtin]31#[builtin]
33pub fn builtin_equals(s: State, a: Any, b: Any) -> Result<bool> {32pub fn builtin_equals(a: Any, b: Any) -> Result<bool> {
34 equals(s, &a.0, &b.0)33 equals(&a.0, &b.0)
35}34}
3635
37#[builtin]36#[builtin]
38pub fn builtin_format(s: State, str: IStr, vals: Any) -> Result<String> {37pub fn builtin_format(str: IStr, vals: Any) -> Result<String> {
39 std_format(s, str, vals.0)38 std_format(str, vals.0)
40}39}
4140
modifiedcrates/jrsonnet-stdlib/src/sort.rsdiffbeforeafterboth
1use jrsonnet_evaluator::{1use jrsonnet_evaluator::{
2 error::Result,2 error::Result,
3 function::{builtin, FuncVal},3 function::{builtin, CallLocation, FuncVal},
4 throw,4 throw,
5 typed::Any,5 typed::Any,
6 val::ArrValue,6 val::ArrValue,
7 State, Val,7 Context, Val,
8};8};
9use jrsonnet_gcmodule::Cc;9use jrsonnet_gcmodule::Cc;
1010
50}50}
5151
52/// * `key_getter` - None, if identity sort required52/// * `key_getter` - None, if identity sort required
53pub fn sort(s: State, values: Cc<Vec<Val>>, key_getter: FuncVal) -> Result<Cc<Vec<Val>>> {53pub fn sort(ctx: Context, values: Cc<Vec<Val>>, key_getter: FuncVal) -> Result<Cc<Vec<Val>>> {
54 if values.len() <= 1 {54 if values.len() <= 1 {
55 return Ok(values);55 return Ok(values);
56 }56 }
76 for value in values.iter() {76 for value in values.iter() {
77 vk.push((77 vk.push((
78 value.clone(),78 value.clone(),
79 key_getter.evaluate_simple(s.clone(), &(Any(value.clone()),))?,79 key_getter.evaluate(
80 ctx.clone(),
81 CallLocation::native(),
82 &(Any(value.clone()),),
83 true,
84 )?,
80 ));85 ));
81 }86 }
97102
98#[builtin]103#[builtin]
99#[allow(non_snake_case)]104#[allow(non_snake_case)]
100pub fn builtin_sort(s: State, arr: ArrValue, keyF: Option<FuncVal>) -> Result<ArrValue> {105pub fn builtin_sort(ctx: Context, arr: ArrValue, keyF: Option<FuncVal>) -> Result<ArrValue> {
101 if arr.len() <= 1 {106 if arr.len() <= 1 {
102 return Ok(arr);107 return Ok(arr);
103 }108 }
104 Ok(ArrValue::Eager(super::sort::sort(109 Ok(ArrValue::Eager(super::sort::sort(
105 s.clone(),110 ctx,
106 arr.evaluated(s)?,111 arr.evaluated()?,
107 keyF.unwrap_or_else(FuncVal::identity),112 keyF.unwrap_or_else(FuncVal::identity),
108 )?))113 )?))
109}114}
addedflake.lockdiffbeforeafterboth

no changes

modifiedflake.nixdiffbeforeafterboth
21 nativeBuildInputs = with pkgs;[21 nativeBuildInputs = with pkgs;[
22 rust22 rust
23 cargo-edit23 cargo-edit
24 hyperfine
25 go-jsonnet
24 ];26 ];
25 };27 };
26 }28 }
modifiedtests/tests/as_native.rsdiffbeforeafterboth
1313
14 let native = func.into_native::<((u32, u32), u32)>();14 let native = func.into_native::<((u32, u32), u32)>();
1515
16 ensure_eq!(native(s.clone(), 1, 2)?, 3);16 ensure_eq!(native(1, 2)?, 3);
17 ensure_eq!(native(s, 3, 4)?, 7);17 ensure_eq!(native(3, 4)?, 7);
1818
19 Ok(())19 Ok(())
20}20}
modifiedtests/tests/builtin.rsdiffbeforeafterboth
5 function::{builtin, builtin::Builtin, CallLocation, FuncVal},5 function::{builtin, builtin::Builtin, CallLocation, FuncVal},
6 tb,6 tb,
7 typed::Typed,7 typed::Typed,
8 Context, State, Thunk, Val,8 ContextBuilder, State, Thunk, Val,
9};9};
10use jrsonnet_gcmodule::Cc;10use jrsonnet_gcmodule::Cc;
11use jrsonnet_stdlib::StateExt;11use jrsonnet_stdlib::StateExt;
1717
18#[test]18#[test]
19fn basic_function() -> Result<()> {19fn basic_function() -> Result<()> {
20 let s = State::default();
21 let a: a = a {};20 let a: a = a {};
22 let v = u32::from_untyped(21 let v = u32::from_untyped(a.call(
23 a.call(s.clone(), Context::new(), CallLocation::native(), &())?,22 ContextBuilder::dangerous_empty_state().build(),
24 s,23 CallLocation::native(),
24 &(),
25 )?;25 )?)?;
2626
50 null50 null
51 ",51 ",
52 )?;52 )?;
53 ensure_val_eq!(s, v, Val::Null);53 ensure_val_eq!(v, Val::Null);
54 Ok(())54 Ok(())
55}55}
5656
89 null89 null
90 ",90 ",
91 )?;91 )?;
92 ensure_val_eq!(s, v, Val::Null);92 ensure_val_eq!(v, Val::Null);
93 Ok(())93 Ok(())
94}94}
9595
modifiedtests/tests/common.rsdiffbeforeafterboth
2727
28#[macro_export]28#[macro_export]
29macro_rules! ensure_val_eq {29macro_rules! ensure_val_eq {
30 ($s:expr, $a:expr, $b:expr) => {{30 ($a:expr, $b:expr) => {{
31 if !::jrsonnet_evaluator::val::equals($s.clone(), &$a.clone(), &$b.clone())? {31 if !::jrsonnet_evaluator::val::equals(&$a.clone(), &$b.clone())? {
32 ::jrsonnet_evaluator::throw!(32 ::jrsonnet_evaluator::throw!(
33 "assertion failed: a != b\na={:#?}\nb={:#?}",33 "assertion failed: a != b\na={:#?}\nb={:#?}",
34 $a.to_json(34 $a.to_json(
35 $s.clone(),
36 2,35 2,
37 #[cfg(feature = "exp-preserve-order")]36 #[cfg(feature = "exp-preserve-order")]
38 false37 false
39 )?,38 )?,
40 $b.to_json(39 $b.to_json(
41 $s.clone(),
42 2,40 2,
43 #[cfg(feature = "exp-preserve-order")]41 #[cfg(feature = "exp-preserve-order")]
44 false42 false
49}47}
5048
51#[builtin]49#[builtin]
52fn assert_throw(s: State, lazy: Thunk<Val>, message: String) -> Result<bool> {50fn assert_throw(lazy: Thunk<Val>, message: String) -> Result<bool> {
53 match lazy.evaluate(s) {51 match lazy.evaluate() {
54 Ok(_) => {52 Ok(_) => {
55 throw!("expected argument to throw on evaluation, but it returned instead")53 throw!("expected argument to throw on evaluation, but it returned instead")
56 }54 }
68 bobj.member("assertThrow".into())66 bobj.member("assertThrow".into())
69 .hide()67 .hide()
70 .value(68 .value(Val::Func(FuncVal::StaticBuiltin(assert_throw::INST)))
71 s.clone(),
72 Val::Func(FuncVal::StaticBuiltin(assert_throw::INST)),
73 )
74 .expect("no error");69 .expect("no error");
7570
modifiedtests/tests/golden.rsdiffbeforeafterboth
1313
14fn run(root: &Path, file: &Path) -> String {14fn run(root: &Path, file: &Path) -> String {
15 let s = State::default();15 let s = State::default();
16 s.set_trace_format(Box::new(CompactFormat {16 s.set_trace_format(CompactFormat {
17 resolver: PathResolver::Relative(root.to_owned()),17 resolver: PathResolver::Relative(root.to_owned()),
18 padding: 3,18 padding: 3,
19 }));19 });
20 s.with_stdlib();20 s.with_stdlib();
21 common::with_test(&s);21 common::with_test(&s);
22 s.set_import_resolver(Box::new(FileImportResolver::default()));22 s.set_import_resolver(Box::new(FileImportResolver::default()));
26 Err(e) => return s.stringify_err(&e),26 Err(e) => return s.stringify_err(&e),
27 };27 };
28 match v.to_json(28 match v.to_json(
29 s.clone(),
30 3,29 3,
31 #[cfg(feature = "exp-preserve-order")]30 #[cfg(feature = "exp-preserve-order")]
32 false,31 false,
modifiedtests/tests/sanity.rsdiffbeforeafterboth
9 s.with_stdlib();9 s.with_stdlib();
1010
11 let v = s.evaluate_snippet("snip".to_owned(), "assert 1 == 1: 'fail'; null")?;11 let v = s.evaluate_snippet("snip".to_owned(), "assert 1 == 1: 'fail'; null")?;
12 ensure_val_eq!(s, v, Val::Null);12 ensure_val_eq!(v, Val::Null);
13 let v = s.evaluate_snippet("snip".to_owned(), "std.assertEqual(1, 1)")?;13 let v = s.evaluate_snippet("snip".to_owned(), "std.assertEqual(1, 1)")?;
14 ensure_val_eq!(s, v, Val::Bool(true));14 ensure_val_eq!(v, Val::Bool(true));
1515
16 Ok(())16 Ok(())
17}17}
modifiedtests/tests/suite.rsdiffbeforeafterboth
1313
14fn run(root: &Path, file: &Path) {14fn run(root: &Path, file: &Path) {
15 let s = State::default();15 let s = State::default();
16 s.set_trace_format(Box::new(CompactFormat {16 s.set_trace_format(CompactFormat {
17 resolver: PathResolver::Relative(root.to_owned()),17 resolver: PathResolver::Relative(root.to_owned()),
18 padding: 3,18 padding: 3,
19 }));19 });
20 s.with_stdlib();20 s.with_stdlib();
21 common::with_test(&s);21 common::with_test(&s);
22 s.set_import_resolver(Box::new(FileImportResolver::default()));22 s.set_import_resolver(Box::new(FileImportResolver::default()));
modifiedtests/tests/typed_obj.rsdiffbeforeafterboth
11 b: u16,11 b: u16,
12}12}
1313
14fn test_roundtrip<T: Typed + PartialEq + Debug + Clone>(value: T, s: State) -> Result<()> {14fn test_roundtrip<T: Typed + PartialEq + Debug + Clone>(value: T) -> Result<()> {
15 let untyped = T::into_untyped(value.clone(), s.clone())?;15 let untyped = T::into_untyped(value.clone())?;
16 let value2 = T::from_untyped(untyped.clone(), s.clone())?;16 let value2 = T::from_untyped(untyped.clone())?;
17 ensure_eq!(value, value2);17 ensure_eq!(value, value2);
18 let untyped2 = T::into_untyped(value2, s.clone())?;18 let untyped2 = T::into_untyped(value2)?;
19 ensure_val_eq!(s, untyped, untyped2);19 ensure_val_eq!(untyped, untyped2);
2020
21 Ok(())21 Ok(())
22}22}
26 let s = State::default();26 let s = State::default();
27 s.with_stdlib();27 s.with_stdlib();
28 let a = A::from_untyped(28 let a = A::from_untyped(s.evaluate_snippet("snip".to_owned(), "{a: 1, b: 2}")?)?;
29 s.evaluate_snippet("snip".to_owned(), "{a: 1, b: 2}")?,
30 s.clone(),
31 )?;
32 ensure_eq!(a, A { a: 1, b: 2 });29 ensure_eq!(a, A { a: 1, b: 2 });
33 test_roundtrip(a, s)?;30 test_roundtrip(a)?;
34 Ok(())31 Ok(())
35}32}
3633
46 let s = State::default();43 let s = State::default();
47 s.with_stdlib();44 s.with_stdlib();
48 let b = B::from_untyped(45 let b = B::from_untyped(s.evaluate_snippet("snip".to_owned(), "{a: 1, c: 2}")?)?;
49 s.evaluate_snippet("snip".to_owned(), "{a: 1, c: 2}")?,
50 s.clone(),
51 )?;
52 ensure_eq!(b, B { a: 1, b: 2 });46 ensure_eq!(b, B { a: 1, b: 2 });
53 ensure_eq!(47 ensure_eq!(
54 &B::into_untyped(b.clone(), s.clone())?.to_string(s.clone())? as &str,48 &B::into_untyped(b.clone())?.to_string()? as &str,
55 r#"{"a": 1, "c": 2}"#,49 r#"{"a": 1, "c": 2}"#,
56 );50 );
57 test_roundtrip(b, s)?;51 test_roundtrip(b)?;
58 Ok(())52 Ok(())
59}53}
6054
79 s.with_stdlib();73 s.with_stdlib();
80 let obj = Object::from_untyped(74 let obj = Object::from_untyped(
81 s.evaluate_snippet("snip".to_owned(), "{apiVersion: 'ver', kind: 'kind', b: 2}")?,75 s.evaluate_snippet("snip".to_owned(), "{apiVersion: 'ver', kind: 'kind', b: 2}")?,
82 s.clone(),
83 )?;76 )?;
84 ensure_eq!(77 ensure_eq!(
85 obj,78 obj,
92 }85 }
93 );86 );
94 ensure_eq!(87 ensure_eq!(
95 &Object::into_untyped(obj.clone(), s.clone())?.to_string(s.clone())? as &str,88 &Object::into_untyped(obj.clone())?.to_string()? as &str,
96 r#"{"apiVersion": "ver", "b": 2, "kind": "kind"}"#,89 r#"{"apiVersion": "ver", "b": 2, "kind": "kind"}"#,
97 );90 );
98 test_roundtrip(obj, s)?;91 test_roundtrip(obj)?;
99 Ok(())92 Ok(())
100}93}
10194
110 let s = State::default();103 let s = State::default();
111 s.with_stdlib();104 s.with_stdlib();
112 let c = C::from_untyped(105 let c = C::from_untyped(s.evaluate_snippet("snip".to_owned(), "{a: 1, b: 2}")?)?;
113 s.evaluate_snippet("snip".to_owned(), "{a: 1, b: 2}")?,
114 s.clone(),
115 )?;
116 ensure_eq!(c, C { a: Some(1), b: 2 });106 ensure_eq!(c, C { a: Some(1), b: 2 });
117 ensure_eq!(107 ensure_eq!(
118 &C::into_untyped(c.clone(), s.clone())?.to_string(s.clone())? as &str,108 &C::into_untyped(c.clone())?.to_string()? as &str,
119 r#"{"a": 1, "b": 2}"#,109 r#"{"a": 1, "b": 2}"#,
120 );110 );
121 test_roundtrip(c, s)?;111 test_roundtrip(c)?;
122 Ok(())112 Ok(())
123}113}
124114
125#[test]115#[test]
126fn optional_field_none() -> Result<()> {116fn optional_field_none() -> Result<()> {
127 let s = State::default();117 let s = State::default();
128 s.with_stdlib();118 s.with_stdlib();
129 let c = C::from_untyped(s.evaluate_snippet("snip".to_owned(), "{b: 2}")?, s.clone())?;119 let c = C::from_untyped(s.evaluate_snippet("snip".to_owned(), "{b: 2}")?)?;
130 ensure_eq!(c, C { a: None, b: 2 });120 ensure_eq!(c, C { a: None, b: 2 });
131 ensure_eq!(121 ensure_eq!(
132 &C::into_untyped(c.clone(), s.clone())?.to_string(s.clone())? as &str,122 &C::into_untyped(c.clone())?.to_string()? as &str,
133 r#"{"b": 2}"#,123 r#"{"b": 2}"#,
134 );124 );
135 test_roundtrip(c, s)?;125 test_roundtrip(c)?;
136 Ok(())126 Ok(())
137}127}
138128
153 let s = State::default();143 let s = State::default();
154 s.with_stdlib();144 s.with_stdlib();
155 let d = D::from_untyped(145 let d = D::from_untyped(s.evaluate_snippet("snip".to_owned(), "{b: 2, v:1}")?)?;
156 s.evaluate_snippet("snip".to_owned(), "{b: 2, v:1}")?,
157 s.clone(),
158 )?;
159 ensure_eq!(146 ensure_eq!(
160 d,147 d,
164 }151 }
165 );152 );
166 ensure_eq!(153 ensure_eq!(
167 &D::into_untyped(d.clone(), s.clone())?.to_string(s.clone())? as &str,154 &D::into_untyped(d.clone())?.to_string()? as &str,
168 r#"{"b": 2, "v": 1}"#,155 r#"{"b": 2, "v": 1}"#,
169 );156 );
170 test_roundtrip(d, s)?;157 test_roundtrip(d)?;
171 Ok(())158 Ok(())
172}159}
173160
176 let s = State::default();163 let s = State::default();
177 s.with_stdlib();164 s.with_stdlib();
178 let d = D::from_untyped(165 let d = D::from_untyped(s.evaluate_snippet("snip".to_owned(), "{b: 2, v: '1'}")?)?;
179 s.evaluate_snippet("snip".to_owned(), "{b: 2, v: '1'}")?,
180 s.clone(),
181 )?;
182 ensure_eq!(d, D { e: None, b: 2 });166 ensure_eq!(d, D { e: None, b: 2 });
183 ensure_eq!(167 ensure_eq!(
184 &D::into_untyped(d.clone(), s.clone())?.to_string(s.clone())? as &str,168 &D::into_untyped(d.clone())?.to_string()? as &str,
185 r#"{"b": 2}"#,169 r#"{"b": 2}"#,
186 );170 );
187 test_roundtrip(d, s)?;171 test_roundtrip(d)?;
188 Ok(())172 Ok(())
189}173}
190174