git.delta.rocks / jrsonnet / refs/commits / 9411dba19aab

difftreelog

refactor(ir) explicit Rc wrapping

yvwlymvmYaroslav Bolyukin2026-03-19parent: #15dca76.patch.diff
in: master

51 files changed

modifiedCargo.lockdiffbeforeafterboth
717name = "jrsonnet-parser"717name = "jrsonnet-parser"
718version = "0.5.0-pre97"718version = "0.5.0-pre97"
719dependencies = [719dependencies = [
720 "insta",
720 "jrsonnet-gcmodule",721 "jrsonnet-gcmodule",
721 "jrsonnet-interner",722 "jrsonnet-interner",
722 "peg",723 "peg",
modifiedcrates/jrsonnet-evaluator/src/arr/mod.rsdiffbeforeafterboth
1use std::{1use std::{
2 any::Any,2 any::Any,
3 fmt::{self},3 fmt::{self},
4 num::NonZeroU32,4 num::NonZeroU32, rc::Rc,
5};5};
66
7use jrsonnet_gcmodule::{cc_dyn, Cc};7use jrsonnet_gcmodule::{cc_dyn, Cc};
8use jrsonnet_interner::IBytes;8use jrsonnet_interner::IBytes;
9use jrsonnet_parser::LocExpr;9use jrsonnet_parser::{Expr, Spanned};
1010
11use crate::{function::FuncVal, Context, Result, Thunk, Val};11use crate::{function::FuncVal, Context, Result, Thunk, Val};
1212
37 Self::new(RangeArray::empty())37 Self::new(RangeArray::empty())
38 }38 }
3939
40 pub fn expr(ctx: Context, exprs: impl IntoIterator<Item = LocExpr>) -> Self {40 pub fn expr(ctx: Context, exprs: Rc<Vec<Spanned<Expr>>>) -> Self {
41 Self::new(ExprArray::new(ctx, exprs))41 Self::new(ExprArray::new(ctx, exprs))
42 }42 }
4343
modifiedcrates/jrsonnet-evaluator/src/arr/spec.rsdiffbeforeafterboth
1use std::rc::Rc;
1use std::{any::Any, cell::RefCell, fmt::Debug, iter, mem::replace};2use std::{any::Any, cell::RefCell, fmt::Debug, mem::replace};
23
3use jrsonnet_gcmodule::{Cc, Trace};4use jrsonnet_gcmodule::{Cc, Trace};
4use jrsonnet_interner::{IBytes, IStr};5use jrsonnet_interner::{IBytes, IStr};
5use jrsonnet_parser::LocExpr;6use jrsonnet_parser::{Expr, Spanned};
67
7use super::ArrValue;8use super::ArrValue;
8use crate::{9use crate::{
103}104}
104105
105#[derive(Debug, Trace, Clone)]106#[derive(Debug, Trace, Clone)]
106enum ArrayThunk<T: 'static + Trace> {107enum ArrayThunk {
107 Computed(Val),108 Computed(Val),
108 Errored(Error),109 Errored(Error),
109 Waiting(T),110 Waiting,
110 Pending,111 Pending,
111}112}
112113
113#[derive(Debug, Trace, Clone)]114#[derive(Debug, Trace, Clone)]
114pub struct ExprArray {115pub struct ExprArray {
115 ctx: Context,116 ctx: Context,
117 src: Rc<Vec<Spanned<Expr>>>,
116 cached: Cc<RefCell<Vec<ArrayThunk<LocExpr>>>>,118 cached: Cc<RefCell<Vec<ArrayThunk>>>,
117}119}
118impl ExprArray {120impl ExprArray {
119 pub fn new(ctx: Context, items: impl IntoIterator<Item = LocExpr>) -> Self {121 pub fn new(ctx: Context, src: Rc<Vec<Spanned<Expr>>>) -> Self {
120 Self {122 Self {
121 ctx,123 ctx,
122 cached: Cc::new(RefCell::new(124 cached: Cc::new(RefCell::new(vec![ArrayThunk::Waiting; src.len()])),
123 items.into_iter().map(ArrayThunk::Waiting).collect(),125 src,
124 )),
125 }126 }
126 }127 }
137 ArrayThunk::Computed(c) => return Ok(Some(c.clone())),138 ArrayThunk::Computed(c) => return Ok(Some(c.clone())),
138 ArrayThunk::Errored(e) => return Err(e.clone()),139 ArrayThunk::Errored(e) => return Err(e.clone()),
139 ArrayThunk::Pending => return Err(InfiniteRecursionDetected.into()),140 ArrayThunk::Pending => return Err(InfiniteRecursionDetected.into()),
140 ArrayThunk::Waiting(..) => {}141 ArrayThunk::Waiting => {}
141 };142 };
142143
143 let ArrayThunk::Waiting(expr) =144 let ArrayThunk::Waiting =
144 replace(&mut self.cached.borrow_mut()[index], ArrayThunk::Pending)145 replace(&mut self.cached.borrow_mut()[index], ArrayThunk::Pending)
145 else {146 else {
146 unreachable!()147 unreachable!()
147 };148 };
148149
149 let new_value = match evaluate(self.ctx.clone(), &expr) {150 let new_value = match evaluate(self.ctx.clone(), &self.src[index]) {
150 Ok(v) => v,151 Ok(v) => v,
151 Err(e) => {152 Err(e) => {
152 self.cached.borrow_mut()[index] = ArrayThunk::Errored(e.clone());153 self.cached.borrow_mut()[index] = ArrayThunk::Errored(e.clone());
163 match &self.cached.borrow()[index] {164 match &self.cached.borrow()[index] {
164 ArrayThunk::Computed(c) => return Some(Thunk::evaluated(c.clone())),165 ArrayThunk::Computed(c) => return Some(Thunk::evaluated(c.clone())),
165 ArrayThunk::Errored(e) => return Some(Thunk::errored(e.clone())),166 ArrayThunk::Errored(e) => return Some(Thunk::errored(e.clone())),
166 ArrayThunk::Waiting(_) | ArrayThunk::Pending => {}167 ArrayThunk::Waiting | ArrayThunk::Pending => {}
167 };168 };
168169
169 #[derive(Trace)]170 #[derive(Trace)]
406#[derive(Trace, Debug, Clone)]407#[derive(Trace, Debug, Clone)]
407pub struct MappedArray<const WITH_INDEX: bool> {408pub struct MappedArray<const WITH_INDEX: bool> {
408 inner: ArrValue,409 inner: ArrValue,
409 cached: Cc<RefCell<Vec<ArrayThunk<()>>>>,410 cached: Cc<RefCell<Vec<ArrayThunk>>>,
410 mapper: FuncVal,411 mapper: FuncVal,
411}412}
412impl<const WITH_INDEX: bool> MappedArray<WITH_INDEX> {413impl<const WITH_INDEX: bool> MappedArray<WITH_INDEX> {
413 pub fn new(inner: ArrValue, mapper: FuncVal) -> Self {414 pub fn new(inner: ArrValue, mapper: FuncVal) -> Self {
414 let len = inner.len();415 let len = inner.len();
415 Self {416 Self {
416 inner,417 inner,
417 cached: Cc::new(RefCell::new(vec![ArrayThunk::Waiting(()); len])),418 cached: Cc::new(RefCell::new(vec![ArrayThunk::Waiting; len])),
418 mapper,419 mapper,
419 }420 }
420 }421 }
439 ArrayThunk::Computed(c) => return Ok(Some(c.clone())),440 ArrayThunk::Computed(c) => return Ok(Some(c.clone())),
440 ArrayThunk::Errored(e) => return Err(e.clone()),441 ArrayThunk::Errored(e) => return Err(e.clone()),
441 ArrayThunk::Pending => return Err(InfiniteRecursionDetected.into()),442 ArrayThunk::Pending => return Err(InfiniteRecursionDetected.into()),
442 ArrayThunk::Waiting(..) => {}443 ArrayThunk::Waiting => {}
443 };444 };
444445
445 let ArrayThunk::Waiting(()) =446 let ArrayThunk::Waiting =
446 replace(&mut self.cached.borrow_mut()[index], ArrayThunk::Pending)447 replace(&mut self.cached.borrow_mut()[index], ArrayThunk::Pending)
447 else {448 else {
448 unreachable!()449 unreachable!()
472 match &self.cached.borrow()[index] {473 match &self.cached.borrow()[index] {
473 ArrayThunk::Computed(c) => return Some(Thunk::evaluated(c.clone())),474 ArrayThunk::Computed(c) => return Some(Thunk::evaluated(c.clone())),
474 ArrayThunk::Errored(e) => return Some(Thunk::errored(e.clone())),475 ArrayThunk::Errored(e) => return Some(Thunk::errored(e.clone())),
475 ArrayThunk::Waiting(()) | ArrayThunk::Pending => {}476 ArrayThunk::Waiting | ArrayThunk::Pending => {}
476 };477 };
477478
478 #[derive(Trace)]479 #[derive(Trace)]
modifiedcrates/jrsonnet-evaluator/src/async_import.rsdiffbeforeafterboth
1use std::rc::Rc;
1use std::{any::Any, cell::RefCell, future::Future};2use std::{any::Any, cell::RefCell, future::Future};
23
3use jrsonnet_gcmodule::Acyclic;4use jrsonnet_gcmodule::Acyclic;
4use jrsonnet_parser::{5use jrsonnet_parser::{
5 ArgsDesc, AssertStmt, BindSpec, CompSpec, Destruct, Expr, FieldMember, FieldName, ForSpecData,6 ArgsDesc, AssertExpr, AssertStmt, BindSpec, CompSpec, Destruct, Expr, FieldMember, FieldName,
6 IfSpecData, LocExpr, Member, ObjBody, Param, ParamsDesc, ParserSettings, SliceDesc, Source,7 ForSpecData, IfElse, IfSpecData, ImportKind, Member, ObjBody, Param, ParamsDesc,
7 SourcePath,8 ParserSettings, Slice, SliceDesc, Source, SourcePath, Spanned,
8};9};
9use rustc_hash::FxHashMap;10use rustc_hash::FxHashMap;
1011
1920
20// Visits all nodes, trying to find import statements21// Visits all nodes, trying to find import statements
21#[allow(clippy::too_many_lines)]22#[allow(clippy::too_many_lines)]
22pub fn find_imports(expr: &LocExpr, out: &mut FoundImports) {23pub fn find_imports(expr: &Spanned<Expr>, out: &mut FoundImports) {
23 fn in_destruct(dest: &Destruct, #[allow(unused_variables)] out: &mut FoundImports) {24 fn in_destruct(dest: &Destruct, #[allow(unused_variables)] out: &mut FoundImports) {
24 match dest {25 match dest {
25 #[cfg(feature = "exp-destruct")]26 #[cfg(feature = "exp-destruct")]
120 find_imports(value, out);121 find_imports(value, out);
121 }122 }
122 Member::BindStmt(_) => todo!(),123 Member::BindStmt(_) => todo!(),
123 Member::AssertStmt(AssertStmt(expr, expr2)) => {124 Member::AssertStmt(assert) => {
124 find_imports(expr, out);125 find_imports(&assert.0, out);
125 if let Some(expr) = expr2 {126 if let Some(expr) = &assert.1 {
126 find_imports(expr, out);127 find_imports(expr, out);
127 }128 }
128 }129 }
132 ObjBody::ObjComp(_) => todo!(),133 ObjBody::ObjComp(_) => todo!(),
133 }134 }
134 }135 }
135 match &*expr.expr() {136 match &**expr {
136 Expr::Import(v) | Expr::ImportStr(v) | Expr::ImportBin(v) => {137 Expr::Import(_, v) => {
137 if let Expr::Str(s) = &*v.expr() {138 if let Expr::Str(s) = &***v {
138 out.0.push(Import {139 out.0.push(Import {
139 path: ResolvePathOwned::Str(s.to_string()),140 path: ResolvePathOwned::Str(s.to_string()),
140 expression: matches!(&*expr.expr(), Expr::Import(_)),141 expression: matches!(&**expr, Expr::Import(ImportKind::Normal, _)),
141 });142 });
142 }143 }
143 // Non-string import will fail in runtime144 // Non-string import will fail in runtime
146 Expr::Literal(_) | Expr::Str(_) | Expr::Num(_) | Expr::Var(_) => {}147 Expr::Literal(_) | Expr::Str(_) | Expr::Num(_) | Expr::Var(_) => {}
147148
148 Expr::Arr(arr) => {149 Expr::Arr(arr) => {
149 for expr in arr {150 for expr in &**arr {
150 find_imports(expr, out);151 find_imports(expr, out);
151 }152 }
152 }153 }
159 find_imports(expr, out);160 find_imports(expr, out);
160 in_obj(obj, out);161 in_obj(obj, out);
161 }162 }
162 Expr::BinaryOp(a, _, b) => {163 Expr::BinaryOp(binop) => {
163 find_imports(a, out);164 find_imports(&binop.lhs, out);
164 find_imports(b, out);165 find_imports(&binop.rhs, out);
165 }166 }
166 Expr::AssertExpr(AssertStmt(expr, expr2), then) => {167 Expr::AssertExpr(assert) => {
168 let AssertExpr {
169 assert: AssertStmt(expr, expr2),
170 rest,
171 } = &**assert;
167 find_imports(expr, out);172 find_imports(expr, out);
168 if let Some(expr) = expr2 {173 if let Some(expr) = expr2 {
169 find_imports(expr, out);174 find_imports(expr, out);
170 }175 }
171 find_imports(then, out);176 find_imports(rest, out);
172 }177 }
173 Expr::LocalExpr(specs, expr) => {178 Expr::LocalExpr(specs, expr) => {
174 in_bind(specs, out);179 in_bind(specs, out);
175 find_imports(expr, out);180 find_imports(expr, out);
188 in_params(params, out);193 in_params(params, out);
189 find_imports(expr, out);194 find_imports(expr, out);
190 }195 }
191 Expr::IfElse {196 Expr::IfElse(if_else) => {
197 let IfElse {
192 cond: IfSpecData(expr),198 cond: IfSpecData(expr),
193 cond_then,199 cond_then,
194 cond_else,200 cond_else,
195 } => {201 } = &**if_else;
196 find_imports(expr, out);202 find_imports(expr, out);
197 find_imports(cond_then, out);203 find_imports(cond_then, out);
198 if let Some(expr) = cond_else {204 if let Some(expr) = cond_else {
199 find_imports(expr, out);205 find_imports(expr, out);
200 }206 }
201 }207 }
202 Expr::Slice(expr, SliceDesc { start, end, step }) => {208 Expr::Slice(slice) => {
209 let Slice {
210 value,
211 slice: SliceDesc { start, end, step },
212 } = &**slice;
203 find_imports(expr, out);213 find_imports(value, out);
204 if let Some(expr) = start {214 if let Some(expr) = start {
205 find_imports(expr, out);215 find_imports(expr, out);
206 }216 }
210 if let Some(expr) = step {220 if let Some(expr) = step {
211 find_imports(expr, out);221 find_imports(expr, out);
212 }222 }
213 }223 }
214 Expr::UnaryOp(_, expr) | Expr::ErrorStmt(expr) => {224 Expr::UnaryOp(_, expr) | Expr::ErrorStmt(expr) => {
215 find_imports(expr, out);225 find_imports(expr, out);
216 }226 }
315 let source = Source::new(path.clone(), code.clone());325 let source = Source::new(path.clone(), code.clone());
316 // If failed - then skip import326 // If failed - then skip import
317 file.parsed =327 file.parsed = jrsonnet_parser::parse(&code, &ParserSettings { source })
328 .map(Rc::new)
318 jrsonnet_parser::parse(&code, &ParserSettings { source }).ok();329 .ok();
319 if let Some(parsed) = &file.parsed {330 if let Some(parsed) = &file.parsed {
320 let mut imports = FoundImports(vec![]);331 let mut imports = FoundImports(vec![]);
modifiedcrates/jrsonnet-evaluator/src/error.rsdiffbeforeafterboth
4 fmt::{Debug, Display},4 fmt::{Debug, Display},
5};5};
66
7use jrsonnet_gcmodule::Trace;7use jrsonnet_gcmodule::{Acyclic, Trace};
8use jrsonnet_interner::IStr;8use jrsonnet_interner::IStr;
9use jrsonnet_parser::{BinaryOpType, LocExpr, Source, SourcePath, Span, UnaryOpType};9use jrsonnet_parser::{BinaryOpType, Source, SourcePath, Span, Spanned, UnaryOpType};
10use jrsonnet_types::ValType;10use jrsonnet_types::ValType;
11use thiserror::Error;11use thiserror::Error;
1212
324pub trait ErrorSource {324pub trait ErrorSource {
325 fn to_location(self) -> Option<Span>;325 fn to_location(self) -> Option<Span>;
326}326}
327impl ErrorSource for &LocExpr {327impl<T: Acyclic> ErrorSource for &Spanned<T> {
328 fn to_location(self) -> Option<Span> {328 fn to_location(self) -> Option<Span> {
329 Some(self.span())329 Some(self.span())
330 }330 }
modifiedcrates/jrsonnet-evaluator/src/evaluate/mod.rsdiffbeforeafterboth
4use jrsonnet_interner::IStr;4use jrsonnet_interner::IStr;
5use jrsonnet_parser::{5use jrsonnet_parser::{
6 ArgsDesc, AssertStmt, BinaryOpType, BindSpec, CompSpec, Expr, FieldMember, FieldName,6 ArgsDesc, AssertStmt, BinaryOpType, BindSpec, CompSpec, Expr, FieldMember, FieldName,
7 ForSpecData, IfSpecData, LiteralType, LocExpr, Member, ObjBody, ParamsDesc,7 ForSpecData, IfSpecData, ImportKind, LiteralType, Member, ObjBody, ParamsDesc, Spanned,
8};8};
9use jrsonnet_types::ValType;9use jrsonnet_types::ValType;
10use rustc_hash::FxHashMap;10use rustc_hash::FxHashMap;
46 stacker::maybe_grow(RED_ZONE, STACK_PER_RECURSION, f)46 stacker::maybe_grow(RED_ZONE, STACK_PER_RECURSION, f)
47}47}
4848
49pub fn evaluate_trivial(expr: &LocExpr) -> Option<Val> {49pub fn evaluate_trivial(expr: &Spanned<Expr>) -> Option<Val> {
50 fn is_trivial(expr: &LocExpr) -> bool {50 fn is_trivial(expr: &Spanned<Expr>) -> bool {
51 match expr.expr() {51 match &**expr {
52 Expr::Str(_)52 Expr::Str(_)
53 | Expr::Num(_)53 | Expr::Num(_)
54 | Expr::Literal(LiteralType::False | LiteralType::True | LiteralType::Null) => true,54 | Expr::Literal(LiteralType::False | LiteralType::True | LiteralType::Null) => true,
55 Expr::Arr(a) => a.iter().all(is_trivial),55 Expr::Arr(a) => a.iter().all(is_trivial),
56 _ => false,56 _ => false,
57 }57 }
58 }58 }
59 Some(match expr.expr() {59 Some(match &**expr {
60 Expr::Str(s) => Val::string(s.clone()),60 Expr::Str(s) => Val::string(s.clone()),
61 Expr::Num(n) => {61 Expr::Num(n) => {
62 Val::Num(NumValue::new(*n).expect("parser will not allow non-finite values"))62 Val::Num(NumValue::new(*n).expect("parser will not allow non-finite values"))
79 })79 })
80}80}
8181
82pub fn evaluate_method(ctx: Context, name: IStr, params: ParamsDesc, body: LocExpr) -> Val {82pub fn evaluate_method(
83 ctx: Context,
84 name: IStr,
85 params: ParamsDesc,
86 body: Rc<Spanned<Expr>>,
87) -> Val {
83 Val::Func(FuncVal::Normal(Cc::new(FuncDesc {88 Val::Func(FuncVal::Normal(Cc::new(FuncDesc {
84 name,89 name,
215 #[derive(Trace)]220 #[derive(Trace)]
216 struct UnboundValue<B: Trace> {221 struct UnboundValue<B: Trace> {
217 uctx: B,222 uctx: B,
218 value: LocExpr,223 value: Rc<Spanned<Expr>>,
219 name: IStr,224 name: IStr,
220 }225 }
221 impl<B: Unbound<Bound = Context>> Unbound for UnboundValue<B> {226 impl<B: Unbound<Bound = Context>> Unbound for UnboundValue<B> {
245 #[derive(Trace)]250 #[derive(Trace)]
246 struct UnboundMethod<B: Trace> {251 struct UnboundMethod<B: Trace> {
247 uctx: B,252 uctx: B,
248 value: LocExpr,253 value: Rc<Spanned<Expr>>,
249 params: ParamsDesc,254 params: ParamsDesc,
250 name: IStr,255 name: IStr,
251 }256 }
301 #[derive(Trace)]306 #[derive(Trace)]
302 struct ObjectAssert<B: Trace> {307 struct ObjectAssert<B: Trace> {
303 uctx: B,308 uctx: B,
304 assert: AssertStmt,309 assert: Rc<AssertStmt>,
305 }310 }
306 impl<B: Unbound<Bound = Context>> ObjectAssertion for ObjectAssert<B> {311 impl<B: Unbound<Bound = Context>> ObjectAssertion for ObjectAssert<B> {
307 fn run(&self, sup_this: SupThis) -> Result<()> {312 fn run(&self, sup_this: SupThis) -> Result<()> {
347352
348pub fn evaluate_apply(353pub fn evaluate_apply(
349 ctx: Context,354 ctx: Context,
350 value: &LocExpr,355 value: &Spanned<Expr>,
351 args: &ArgsDesc,356 args: &ArgsDesc,
352 loc: CallLocation<'_>,357 loc: CallLocation<'_>,
353 tailstrict: bool,358 tailstrict: bool,
389 Ok(())394 Ok(())
390}395}
391396
392pub fn evaluate_named(ctx: Context, expr: &LocExpr, name: IStr) -> Result<Val> {397pub fn evaluate_named(ctx: Context, expr: &Spanned<Expr>, name: IStr) -> Result<Val> {
393 use Expr::*;398 use Expr::*;
394 Ok(match expr.expr() {399 Ok(match &**expr {
395 Function(params, body) => evaluate_method(ctx, name, params.clone(), body.clone()),400 Function(params, body) => evaluate_method(ctx, name, params.clone(), body.clone()),
396 _ => evaluate(ctx, expr)?,401 _ => evaluate(ctx, expr)?,
397 })402 })
398}403}
399404
400#[allow(clippy::too_many_lines)]405#[allow(clippy::too_many_lines)]
401pub fn evaluate(ctx: Context, expr: &LocExpr) -> Result<Val> {406pub fn evaluate(ctx: Context, expr: &Spanned<Expr>) -> Result<Val> {
402 use Expr::*;407 use Expr::*;
403408
404 if let Some(trivial) = evaluate_trivial(expr) {409 if let Some(trivial) = evaluate_trivial(expr) {
405 return Ok(trivial);410 return Ok(trivial);
406 }411 }
407 let loc = expr.span();412 let loc = expr.span();
408 Ok(match expr.expr() {413 Ok(match &**expr {
409 Literal(LiteralType::This) => Val::Obj(ctx.try_this()?),414 Literal(LiteralType::This) => Val::Obj(ctx.try_this()?),
410 Literal(LiteralType::Super) => Val::Obj(ctx.try_sup_this()?.standalone_super()?),415 Literal(LiteralType::Super) => Val::Obj(ctx.try_sup_this()?.standalone_super()?),
411 Literal(LiteralType::Dollar) => Val::Obj(ctx.try_dollar()?),416 Literal(LiteralType::Dollar) => Val::Obj(ctx.try_dollar()?),
420 // Note that other jsonnet implementations will fail on `if value in (super)` expression,425 // Note that other jsonnet implementations will fail on `if value in (super)` expression,
421 // because the standalone super literal is not supported, that is because in other426 // because the standalone super literal is not supported, that is because in other
422 // implementations `in super` treated differently from `in smth_else`.427 // implementations `in super` treated differently from `in smth_else`.
423 BinaryOp(field, BinaryOpType::In, e)428 BinaryOp(bin)
424 if matches!(e.expr(), Expr::Literal(LiteralType::Super)) =>429 if matches!(&*bin.rhs, Expr::Literal(LiteralType::Super))
430 && bin.op == BinaryOpType::In =>
425 {431 {
426 let sup_this = ctx.try_sup_this()?;432 let sup_this = ctx.try_sup_this()?;
427 // In jsonnet, "field" in e is eager, LHS expression is always executed regardless of super existence.433 // In jsonnet, "field" in e is eager, LHS expression is always executed regardless of super existence.
428 // In jrsonnet, however, this wasn't true, this was kept here for compatibility.434 // In jrsonnet, however, this wasn't true, this was kept here for compatibility.
429 if !sup_this.has_super() {435 if !sup_this.has_super() {
430 return Ok(Val::Bool(false));436 return Ok(Val::Bool(false));
431 }437 }
432 let field = evaluate(ctx, field)?;438 let field = evaluate(ctx, &bin.lhs)?;
433 Val::Bool(sup_this.field_in_super(field.to_string()?))439 Val::Bool(sup_this.field_in_super(field.to_string()?))
434 }440 }
435 BinaryOp(v1, o, v2) => evaluate_binary_op_special(ctx, v1, *o, v2)?,441 BinaryOp(bin) => evaluate_binary_op_special(ctx, &bin.lhs, bin.op, &bin.rhs)?,
436 UnaryOp(o, v) => evaluate_unary_op(*o, &evaluate(ctx, v)?)?,442 UnaryOp(o, v) => evaluate_unary_op(*o, &evaluate(ctx, v)?)?,
437 Var(name) => in_frame(443 Var(name) => in_frame(
438 CallLocation::new(&loc),444 CallLocation::new(&loc),
441 )?,447 )?,
442 Index { indexable, parts } => ensure_sufficient_stack(|| {448 Index { indexable, parts } => ensure_sufficient_stack(|| {
443 let mut parts = parts.iter();449 let mut parts = parts.iter();
444 let mut indexable = if matches!(indexable.expr(), Expr::Literal(LiteralType::Super)) {450 let mut indexable = if matches!(&***indexable, Expr::Literal(LiteralType::Super)) {
445 let part = parts.next().expect("at least part should exist");451 let part = parts.next().expect("at least part should exist");
446 // sup_this existence check might also be skipped here for null-coalesce...452 // sup_this existence check might also be skipped here for null-coalesce...
447 // But I believe this might cause errors.453 // But I believe this might cause errors.
574 Arr(items) => {580 Arr(items) => {
575 if items.is_empty() {581 if items.is_empty() {
576 Val::Arr(ArrValue::empty())582 Val::Arr(ArrValue::empty())
577 } else if items.len() == 1 {583 } else {
578 let item = items[0].clone();
579 Val::Arr(ArrValue::lazy(vec![Thunk!(move || evaluate(ctx, &item))]))
580 } else {
581 Val::Arr(ArrValue::expr(ctx, items.iter().cloned()))584 Val::Arr(ArrValue::expr(ctx, items.clone()))
582 }585 }
583 }586 }
584 ArrComp(expr, comp_specs) => {587 ArrComp(expr, comp_specs) => {
601 Function(params, body) => {604 Function(params, body) => {
602 evaluate_method(ctx, "anonymous".into(), params.clone(), body.clone())605 evaluate_method(ctx, "anonymous".into(), params.clone(), body.clone())
603 }606 }
604 AssertExpr(assert, returned) => {607 AssertExpr(assert) => {
605 evaluate_assert(ctx.clone(), assert)?;608 evaluate_assert(ctx.clone(), &assert.assert)?;
606 evaluate(ctx, returned)?609 evaluate(ctx, &assert.rest)?
607 }610 }
608 ErrorStmt(e) => in_frame(611 ErrorStmt(e) => in_frame(
609 CallLocation::new(&loc),612 CallLocation::new(&loc),
610 || "error statement".to_owned(),613 || "error statement".to_owned(),
611 || bail!(RuntimeError(evaluate(ctx, e)?.to_string()?,)),614 || bail!(RuntimeError(evaluate(ctx, e)?.to_string()?,)),
612 )?,615 )?,
613 IfElse {616 IfElse (if_else)
614 cond,617 // {
615 cond_then,618 // cond,
616 cond_else,619 // cond_then,
620 // cond_else,
621 // }
617 } => {622 => {
618 if in_frame(623 if in_frame(
619 CallLocation::new(&loc),624 CallLocation::new(&loc),
620 || "if condition".to_owned(),625 || "if condition".to_owned(),
621 || bool::from_untyped(evaluate(ctx.clone(), &cond.0)?),626 || bool::from_untyped(evaluate(ctx.clone(), &if_else.cond.0)?),
622 )? {627 )? {
623 evaluate(ctx, cond_then)?628 evaluate(ctx, &if_else.cond_then)?
624 } else {629 } else {
625 match cond_else {630 match &if_else.cond_else {
626 Some(v) => evaluate(ctx, v)?,631 Some(v) => evaluate(ctx, v)?,
627 None => Val::Null,632 None => Val::Null,
628 }633 }
629 }634 }
630 }635 }
631 Slice(value, desc) => {636 Slice(slice) => {
632 fn parse_idx<T: Typed>(637 fn parse_idx<T: Typed>(
633 loc: CallLocation<'_>,638 loc: CallLocation<'_>,
634 ctx: Context,639 ctx: Context,
635 expr: Option<&LocExpr>,640 expr: Option<&Spanned<Expr>>,
636 desc: &'static str,641 desc: &'static str,
637 ) -> Result<Option<T>> {642 ) -> Result<Option<T>> {
638 if let Some(value) = expr {643 if let Some(value) = expr {
646 }651 }
647 }652 }
648653
649 let indexable = evaluate(ctx.clone(), value)?;654 let indexable = evaluate(ctx.clone(), &slice.value)?;
650 let loc = CallLocation::new(&loc);655 let loc = CallLocation::new(&loc);
651656
652 let start = parse_idx(loc, ctx.clone(), desc.start.as_ref(), "start")?;657 let start = parse_idx(loc, ctx.clone(), slice.slice.start.as_ref(), "start")?;
653 let end = parse_idx(loc, ctx.clone(), desc.end.as_ref(), "end")?;658 let end = parse_idx(loc, ctx.clone(), slice.slice.end.as_ref(), "end")?;
654 let step = parse_idx(loc, ctx, desc.step.as_ref(), "step")?;659 let step = parse_idx(loc, ctx, slice.slice.step.as_ref(), "step")?;
655660
656 IndexableVal::into_untyped(indexable.into_indexable()?.slice(start, end, step)?)?661 IndexableVal::into_untyped(indexable.into_indexable()?.slice(start, end, step)?)?
657 }662 }
658 i @ (Import(path) | ImportStr(path) | ImportBin(path)) => {663 Import(kind, path) => {
659 let Expr::Str(path) = &path.expr() else {664 let Expr::Str(path) = &***path else {
660 bail!("computed imports are not supported")665 bail!("computed imports are not supported")
661 };666 };
662 let tmp = loc.clone().0;667 let tmp = loc.clone().0;
663 with_state(|s| {668 with_state(|s| {
664 let resolved_path = s.resolve_from(tmp.source_path(), path)?;669 let resolved_path = s.resolve_from(tmp.source_path(), path)?;
665 Ok(match i {670 Ok(match kind {
666 Import(_) => in_frame(671 ImportKind::Normal => in_frame(
667 CallLocation::new(&loc),672 CallLocation::new(&loc),
668 || format!("import {:?}", path.clone()),673 || format!("import {:?}", path.clone()),
669 || s.import_resolved(resolved_path),674 || s.import_resolved(resolved_path),
670 )?,675 )?,
671 ImportStr(_) => Val::string(s.import_resolved_str(resolved_path)?),676 ImportKind::Str => Val::string(s.import_resolved_str(resolved_path)?),
672 ImportBin(_) => {677 ImportKind::Bin => {
673 Val::Arr(ArrValue::bytes(s.import_resolved_bin(resolved_path)?))678 Val::Arr(ArrValue::bytes(s.import_resolved_bin(resolved_path)?))
674 }679 }
675 _ => unreachable!(),
676 }) as Result<Val>680 }) as Result<Val>
677 })?681 })?
678 }682 }
modifiedcrates/jrsonnet-evaluator/src/evaluate/operator.rsdiffbeforeafterboth
1use std::cmp::Ordering;1use std::cmp::Ordering;
22
3use jrsonnet_parser::{BinaryOpType, LocExpr, UnaryOpType};3use jrsonnet_parser::{BinaryOpType, Expr, Spanned, UnaryOpType};
44
5use crate::{5use crate::{
6 arr::ArrValue,6 arr::ArrValue,
147147
148pub fn evaluate_binary_op_special(148pub fn evaluate_binary_op_special(
149 ctx: Context,149 ctx: Context,
150 a: &LocExpr,150 a: &Spanned<Expr>,
151 op: BinaryOpType,151 op: BinaryOpType,
152 b: &LocExpr,152 b: &Spanned<Expr>,
153) -> Result<Val> {153) -> Result<Val> {
154 use BinaryOpType::*;154 use BinaryOpType::*;
155 use Val::*;155 use Val::*;
modifiedcrates/jrsonnet-evaluator/src/function/arglike.rsdiffbeforeafterboth
1use std::collections::HashMap;1use std::collections::HashMap;
2use std::rc::Rc;
23
3use jrsonnet_gcmodule::Trace;4use jrsonnet_gcmodule::Trace;
4use jrsonnet_interner::IStr;5use jrsonnet_interner::IStr;
5use jrsonnet_parser::{ArgsDesc, LocExpr, SourceFifo, SourcePath};6use jrsonnet_parser::{ArgsDesc, Expr, SourceFifo, SourcePath, Spanned};
67
7use crate::{evaluate, typed::Typed, with_state, Context, Result, Thunk, Val};8use crate::{evaluate, typed::Typed, with_state, Context, Result, Thunk, Val};
89
13 fn evaluate_arg(&self, ctx: Context, tailstrict: bool) -> Result<Thunk<Val>>;14 fn evaluate_arg(&self, ctx: Context, tailstrict: bool) -> Result<Thunk<Val>>;
14}15}
1516
16impl ArgLike for &LocExpr {17impl ArgLike for &Rc<Spanned<Expr>> {
17 fn evaluate_arg(&self, ctx: Context, tailstrict: bool) -> Result<Thunk<Val>> {18 fn evaluate_arg(&self, ctx: Context, tailstrict: bool) -> Result<Thunk<Val>> {
18 Ok(if tailstrict {19 Ok(if tailstrict {
19 Thunk::evaluated(evaluate(ctx, self)?)20 Thunk::evaluated(evaluate(ctx, self)?)
modifiedcrates/jrsonnet-evaluator/src/function/mod.rsdiffbeforeafterboth
1use std::fmt::Debug;1use std::{fmt::Debug, rc::Rc};
22
3pub use arglike::{ArgLike, ArgsLike, TlaArg};3pub use arglike::{ArgLike, ArgsLike, TlaArg};
4use jrsonnet_gcmodule::{Cc, Trace};4use jrsonnet_gcmodule::{Cc, Trace};
5use jrsonnet_interner::IStr;5use jrsonnet_interner::IStr;
6pub use jrsonnet_macros::builtin;6pub use jrsonnet_macros::builtin;
7use jrsonnet_parser::{Destruct, Expr, LocExpr, ParamsDesc, Span};7use jrsonnet_parser::{Destruct, Expr, ParamsDesc, Span, Spanned};
88
9use self::{9use self::{
10 arglike::OptionalContext,10 arglike::OptionalContext,
66 /// Function parameter definition66 /// Function parameter definition
67 pub params: ParamsDesc,67 pub params: ParamsDesc,
68 /// Function body68 /// Function body
69 pub body: LocExpr,69 pub body: Rc<Spanned<Expr>>,
70}70}
71impl FuncDesc {71impl FuncDesc {
72 /// Create body context, but fill arguments without defaults with lazy error72 /// Create body context, but fill arguments without defaults with lazy error
240 #[cfg(feature = "exp-destruct")]240 #[cfg(feature = "exp-destruct")]
241 _ => return false,241 _ => return false,
242 };242 };
243 desc.body.expr() == &Expr::Var(id.clone())243 **desc.body == Expr::Var(id.clone())
244 }244 }
245 _ => false,245 _ => false,
246 }246 }
modifiedcrates/jrsonnet-evaluator/src/lib.rsdiffbeforeafterboth
45#[doc(hidden)]45#[doc(hidden)]
46pub use jrsonnet_macros;46pub use jrsonnet_macros;
47pub use jrsonnet_parser as parser;47pub use jrsonnet_parser as parser;
48use jrsonnet_parser::{LocExpr, ParserSettings, Source, SourcePath};48use jrsonnet_parser::{Expr, ParserSettings, Source, SourcePath, Spanned};
49pub use obj::*;49pub use obj::*;
50pub use rustc_hash;50pub use rustc_hash;
51use rustc_hash::FxHashMap;51use rustc_hash::FxHashMap;
186struct FileData {186struct FileData {
187 string: Option<IStr>,187 string: Option<IStr>,
188 bytes: Option<IBytes>,188 bytes: Option<IBytes>,
189 parsed: Option<LocExpr>,189 parsed: Option<Rc<Spanned<Expr>>>,
190 evaluated: Option<Val>,190 evaluated: Option<Val>,
191191
192 evaluating: bool,192 evaluating: bool,
350 source: file_name.clone(),350 source: file_name.clone(),
351 },351 },
352 )352 )
353 .map(Rc::new)
353 .map_err(|e| ImportSyntaxError {354 .map_err(|e| ImportSyntaxError {
354 path: file_name.clone(),355 path: file_name.clone(),
355 error: Box::new(e),356 error: Box::new(e),
modifiedcrates/jrsonnet-parser/Cargo.tomldiffbeforeafterboth
2020
21peg.workspace = true21peg.workspace = true
22
23[dev-dependencies]
24insta.workspace = true
2225
modifiedcrates/jrsonnet-parser/src/expr.rsdiffbeforeafterboth
14 /// {fixed: 2}14 /// {fixed: 2}
15 Fixed(IStr),15 Fixed(IStr),
16 /// {["dyn"+"amic"]: 3}16 /// {["dyn"+"amic"]: 3}
17 Dyn(LocExpr),17 Dyn(Spanned<Expr>),
18}18}
1919
20#[derive(Debug, Clone, Copy, PartialEq, Eq, Acyclic)]20#[derive(Debug, Clone, Copy, PartialEq, Eq, Acyclic)]
34 }34 }
35}35}
3636
37#[derive(Clone, Debug, PartialEq, Acyclic)]37#[derive(Debug, PartialEq, Acyclic)]
38pub struct AssertStmt(pub LocExpr, pub Option<LocExpr>);38pub struct AssertStmt(pub Spanned<Expr>, pub Option<Spanned<Expr>>);
3939
40#[derive(Debug, PartialEq, Acyclic)]40#[derive(Debug, PartialEq, Acyclic)]
41pub struct FieldMember {41pub struct FieldMember {
42 pub name: FieldName,42 pub name: FieldName,
43 pub plus: bool,43 pub plus: bool,
44 pub params: Option<ParamsDesc>,44 pub params: Option<ParamsDesc>,
45 pub visibility: Visibility,45 pub visibility: Visibility,
46 pub value: LocExpr,46 pub value: Rc<Spanned<Expr>>,
47}47}
4848
49#[derive(Debug, PartialEq, Acyclic)]49#[derive(Debug, PartialEq, Acyclic)]
50pub enum Member {50pub enum Member {
51 Field(FieldMember),51 Field(FieldMember),
52 BindStmt(BindSpec),52 BindStmt(BindSpec),
53 AssertStmt(AssertStmt),53 AssertStmt(Rc<AssertStmt>),
54}54}
5555
56#[derive(Debug, Clone, Copy, PartialEq, Eq, Acyclic)]56#[derive(Debug, Clone, Copy, PartialEq, Eq, Acyclic)]
147147
148/// name, default value148/// name, default value
149#[derive(Debug, PartialEq, Acyclic)]149#[derive(Debug, PartialEq, Acyclic)]
150pub struct Param(pub Destruct, pub Option<LocExpr>);150pub struct Param(pub Destruct, pub Option<Rc<Spanned<Expr>>>);
151151
152/// Defined function parameters152/// Defined function parameters
153#[derive(Debug, Clone, PartialEq, Acyclic)]153#[derive(Debug, Clone, PartialEq, Acyclic)]
162162
163#[derive(Debug, PartialEq, Acyclic)]163#[derive(Debug, PartialEq, Acyclic)]
164pub struct ArgsDesc {164pub struct ArgsDesc {
165 pub unnamed: Vec<LocExpr>,165 pub unnamed: Vec<Rc<Spanned<Expr>>>,
166 pub named: Vec<(IStr, LocExpr)>,166 pub named: Vec<(IStr, Rc<Spanned<Expr>>)>,
167}167}
168impl ArgsDesc {168impl ArgsDesc {
169 pub fn new(unnamed: Vec<LocExpr>, named: Vec<(IStr, LocExpr)>) -> Self {169 pub fn new(unnamed: Vec<Rc<Spanned<Expr>>>, named: Vec<(IStr, Rc<Spanned<Expr>>)>) -> Self {
170 Self { unnamed, named }170 Self { unnamed, named }
171 }171 }
172}172}
192 },192 },
193 #[cfg(feature = "exp-destruct")]193 #[cfg(feature = "exp-destruct")]
194 Object {194 Object {
195 fields: Vec<(IStr, Option<Destruct>, Option<LocExpr>)>,195 fields: Vec<(IStr, Option<Destruct>, Option<Spanned<Expr>>)>,
196 rest: Option<DestructRest>,196 rest: Option<DestructRest>,
197 },197 },
198}198}
244pub enum BindSpec {244pub enum BindSpec {
245 Field {245 Field {
246 into: Destruct,246 into: Destruct,
247 value: LocExpr,247 value: Rc<Spanned<Expr>>,
248 },248 },
249 Function {249 Function {
250 name: IStr,250 name: IStr,
251 params: ParamsDesc,251 params: ParamsDesc,
252 value: LocExpr,252 value: Rc<Spanned<Expr>>,
253 },253 },
254}254}
255impl BindSpec {255impl BindSpec {
262}262}
263263
264#[derive(Debug, PartialEq, Acyclic)]264#[derive(Debug, PartialEq, Acyclic)]
265pub struct IfSpecData(pub LocExpr);265pub struct IfSpecData(pub Spanned<Expr>);
266266
267#[derive(Debug, PartialEq, Acyclic)]267#[derive(Debug, PartialEq, Acyclic)]
268pub struct ForSpecData(pub Destruct, pub LocExpr);268pub struct ForSpecData(pub Destruct, pub Spanned<Expr>);
269269
270#[derive(Debug, PartialEq, Acyclic)]270#[derive(Debug, PartialEq, Acyclic)]
271pub enum CompSpec {271pub enum CompSpec {
276#[derive(Debug, PartialEq, Acyclic)]276#[derive(Debug, PartialEq, Acyclic)]
277pub struct ObjComp {277pub struct ObjComp {
278 pub pre_locals: Vec<BindSpec>,278 pub pre_locals: Vec<BindSpec>,
279 pub field: FieldMember,279 pub field: Rc<FieldMember>,
280 pub post_locals: Vec<BindSpec>,280 pub post_locals: Vec<BindSpec>,
281 pub compspecs: Vec<CompSpec>,281 pub compspecs: Vec<CompSpec>,
282}282}
299299
300#[derive(Debug, PartialEq, Acyclic)]300#[derive(Debug, PartialEq, Acyclic)]
301pub struct SliceDesc {301pub struct SliceDesc {
302 pub start: Option<LocExpr>,302 pub start: Option<Spanned<Expr>>,
303 pub end: Option<LocExpr>,303 pub end: Option<Spanned<Expr>>,
304 pub step: Option<LocExpr>,304 pub step: Option<Spanned<Expr>>,
305}305}
306
307#[derive(Debug, PartialEq, Acyclic)]
308pub struct AssertExpr {
309 pub assert: AssertStmt,
310 pub rest: Spanned<Expr>,
311}
312
313#[derive(Debug, PartialEq, Acyclic)]
314pub struct BinaryOp {
315 pub lhs: Spanned<Expr>,
316 pub op: BinaryOpType,
317 pub rhs: Spanned<Expr>,
318}
319
320#[derive(Debug, PartialEq, Acyclic)]
321pub enum ImportKind {
322 Normal,
323 Str,
324 Bin,
325}
326
327#[derive(Debug, PartialEq, Acyclic)]
328pub struct IfElse {
329 pub cond: IfSpecData,
330 pub cond_then: Spanned<Expr>,
331 pub cond_else: Option<Spanned<Expr>>,
332}
333
334#[derive(Debug, PartialEq, Acyclic)]
335pub struct Slice {
336 pub value: Spanned<Expr>,
337 pub slice: SliceDesc,
338}
306339
307/// Syntax base340/// Syntax base
308#[derive(Debug, PartialEq, Acyclic)]341#[derive(Debug, PartialEq, Acyclic)]
317 Var(IStr),350 Var(IStr),
318351
319 /// Array of expressions: [1, 2, "Hello"]352 /// Array of expressions: [1, 2, "Hello"]
320 Arr(Vec<LocExpr>),353 Arr(Rc<Vec<Spanned<Expr>>>),
321 /// Array comprehension:354 /// Array comprehension:
322 /// ```jsonnet355 /// ```jsonnet
323 /// ingredients: [356 /// ingredients: [
329 /// ]362 /// ]
330 /// ],363 /// ],
331 /// ```364 /// ```
332 ArrComp(LocExpr, Vec<CompSpec>),365 ArrComp(Rc<Spanned<Expr>>, Vec<CompSpec>),
333366
334 /// Object: {a: 2}367 /// Object: {a: 2}
335 Obj(ObjBody),368 Obj(ObjBody),
336 /// Object extension: var1 {b: 2}369 /// Object extension: var1 {b: 2}
337 ObjExtend(LocExpr, ObjBody),370 ObjExtend(Rc<Spanned<Expr>>, ObjBody),
338371
339 /// -2372 /// -2
340 UnaryOp(UnaryOpType, LocExpr),373 UnaryOp(UnaryOpType, Box<Spanned<Expr>>),
341 /// 2 - 2374 /// 2 - 2
342 BinaryOp(LocExpr, BinaryOpType, LocExpr),375 BinaryOp(Box<BinaryOp>),
343 /// assert 2 == 2 : "Math is broken"376 /// assert 2 == 2 : "Math is broken"
344 AssertExpr(AssertStmt, LocExpr),377 AssertExpr(Rc<AssertExpr>),
345 /// local a = 2; { b: a }378 /// local a = 2; { b: a }
346 LocalExpr(Vec<BindSpec>, LocExpr),379 LocalExpr(Vec<BindSpec>, Box<Spanned<Expr>>),
347380
348 /// import "hello"381 /// import* "hello"
349 Import(LocExpr),382 Import(ImportKind, Box<Spanned<Expr>>),
350 /// importStr "file.txt"
351 ImportStr(LocExpr),
352 /// importBin "file.txt"
353 ImportBin(LocExpr),
354 /// error "I'm broken"383 /// error "I'm broken"
355 ErrorStmt(LocExpr),384 ErrorStmt(Box<Spanned<Expr>>),
356 /// a(b, c)385 /// a(b, c)
357 Apply(LocExpr, ArgsDesc, bool),386 Apply(Box<Spanned<Expr>>, ArgsDesc, bool),
358 /// a[b], a.b, a?.b387 /// a[b], a.b, a?.b
359 Index {388 Index {
360 indexable: LocExpr,389 indexable: Box<Spanned<Expr>>,
361 parts: Vec<IndexPart>,390 parts: Vec<IndexPart>,
362 },391 },
363 /// function(x) x392 /// function(x) x
364 Function(ParamsDesc, LocExpr),393 Function(ParamsDesc, Rc<Spanned<Expr>>),
365 /// if true == false then 1 else 2394 /// if true == false then 1 else 2
366 IfElse {395 IfElse(Box<IfElse>),
367 cond: IfSpecData,
368 cond_then: LocExpr,
369 cond_else: Option<LocExpr>,
370 },
371 Slice(LocExpr, SliceDesc),396 Slice(Box<Slice>),
372}397}
373398
374#[derive(Debug, PartialEq, Acyclic)]399#[derive(Debug, PartialEq, Acyclic)]
375pub struct IndexPart {400pub struct IndexPart {
376 pub value: LocExpr,401 pub value: Spanned<Expr>,
377 #[cfg(feature = "exp-null-coaelse")]402 #[cfg(feature = "exp-null-coaelse")]
378 pub null_coaelse: bool,403 pub null_coaelse: bool,
379}404}
396 }421 }
397}422}
398423
399/// Holds AST expression and its location in source file
400#[derive(Clone, PartialEq, Acyclic)]424#[derive(Clone, PartialEq, Acyclic)]
401pub struct LocExpr(Rc<(Expr, Span)>);425pub struct Spanned<T: Acyclic>(T, Span);
426impl<T: Acyclic> Deref for Spanned<T> {
427 type Target = T;
428 fn deref(&self) -> &Self::Target {
429 &self.0
430 }
431}
402impl LocExpr {432impl<T: Acyclic> Spanned<T> {
433 #[inline]
403 pub fn new(expr: Expr, span: Span) -> Self {434 pub fn new(v: T, s: Span) -> Self {
404 Self(Rc::new((expr, span)))435 Self(v, s)
405 }436 }
406 #[inline]437 #[inline]
407 pub fn span(&self) -> Span {438 pub fn span(&self) -> Span {
408 self.0 .1.clone()439 self.1.clone()
409 }440 }
410 #[inline]
411 pub fn expr(&self) -> &Expr {
412 &self.0 .0
413 }
414}441}
415
416static_assertions::assert_eq_size!(LocExpr, usize);
417442
418impl Debug for LocExpr {443impl<T: Debug + Acyclic> Debug for Spanned<T> {
419 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {444 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
420 let expr = self.expr();445 let expr = &**self;
421 if f.alternate() {446 if f.alternate() {
422 write!(f, "{:#?}", expr)?;447 write!(f, "{:#?}", expr)?;
423 } else {448 } else {
modifiedcrates/jrsonnet-parser/src/lib.rsdiffbeforeafterboth
2222
23macro_rules! expr_bin {23macro_rules! expr_bin {
24 ($a:ident $op:ident $b:ident) => {24 ($a:ident $op:ident $b:ident) => {
25 Expr::BinaryOp($a, $op, $b)25 Expr::BinaryOp(Box::new(BinaryOp {
26 lhs: $a,
27 op: $op,
28 rhs: $b,
29 }))
26 };30 };
27}31}
28macro_rules! expr_un {32macro_rules! expr_un {
29 ($op:ident $a:ident) => {33 ($op:ident $a:ident) => {
30 Expr::UnaryOp($op, $a)34 Expr::UnaryOp($op, Box::new($a))
31 };35 };
32}36}
3337
64 rule keyword(id: &'static str) -> ()68 rule keyword(id: &'static str) -> ()
65 = ##parse_string_literal(id) end_of_ident()69 = ##parse_string_literal(id) end_of_ident()
6670
67 pub rule param(s: &ParserSettings) -> expr::Param = name:destruct(s) expr:(_ "=" _ expr:expr(s){expr})? { expr::Param(name, expr) }71 pub rule param(s: &ParserSettings) -> expr::Param = name:destruct(s) expr:(_ "=" _ expr:expr(s){expr})? { expr::Param(name, expr.map(Rc::new)) }
68 pub rule params(s: &ParserSettings) -> expr::ParamsDesc72 pub rule params(s: &ParserSettings) -> expr::ParamsDesc
69 = params:param(s) ** comma() comma()? { expr::ParamsDesc(Rc::new(params)) }73 = params:param(s) ** comma() comma()? { expr::ParamsDesc(Rc::new(params)) }
70 / { expr::ParamsDesc(Rc::new(Vec::new())) }74 / { expr::ParamsDesc(Rc::new(Vec::new())) }
7175
72 pub rule arg(s: &ParserSettings) -> (Option<IStr>, LocExpr)76 pub rule arg(s: &ParserSettings) -> (Option<IStr>, Rc<Spanned<Expr>>)
73 = name:(quiet! { (s:id() _ "=" !['='] _ {s})? } / expected!("<argument name>")) expr:expr(s) {(name, expr)}77 = name:(quiet! { (s:id() _ "=" !['='] _ {s})? } / expected!("<argument name>")) expr:expr(s) {(name, Rc::new(expr))}
7478
75 pub rule args(s: &ParserSettings) -> expr::ArgsDesc79 pub rule args(s: &ParserSettings) -> expr::ArgsDesc
76 = args:arg(s)**comma() comma()? {?80 = args:arg(s)**comma() comma()? {?
135 / obj:destruct_object(s) {obj}139 / obj:destruct_object(s) {obj}
136140
137 pub rule bind(s: &ParserSettings) -> expr::BindSpec141 pub rule bind(s: &ParserSettings) -> expr::BindSpec
138 = into:destruct(s) _ "=" _ expr:expr(s) {expr::BindSpec::Field{into, value: expr}}142 = into:destruct(s) _ "=" _ expr:expr(s) {expr::BindSpec::Field{into, value: Rc::new(expr)}}
139 / name:id() _ "(" _ params:params(s) _ ")" _ "=" _ expr:expr(s) {expr::BindSpec::Function{name, params, value: expr}}143 / name:id() _ "(" _ params:params(s) _ ")" _ "=" _ expr:expr(s) {expr::BindSpec::Function{name, params, value: Rc::new(expr)}}
140144
141 pub rule assertion(s: &ParserSettings) -> expr::AssertStmt145 pub rule assertion(s: &ParserSettings) -> expr::AssertStmt
142 = keyword("assert") _ cond:expr(s) msg:(_ ":" _ e:expr(s) {e})? { expr::AssertStmt(cond, msg) }146 = keyword("assert") _ cond:expr(s) msg:(_ ":" _ e:expr(s) {e})? { expr::AssertStmt(cond, msg) }
190 plus: plus.is_some(),194 plus: plus.is_some(),
191 params: None,195 params: None,
192 visibility,196 visibility,
193 value,197 value: Rc::new(value),
194 }}198 }}
195 / name:field_name(s) _ "(" _ params:params(s) _ ")" _ visibility:visibility() _ value:expr(s) {expr::FieldMember{199 / name:field_name(s) _ "(" _ params:params(s) _ ")" _ visibility:visibility() _ value:expr(s) {expr::FieldMember{
196 name,200 name,
197 plus: false,201 plus: false,
198 params: Some(params),202 params: Some(params),
199 visibility,203 visibility,
200 value,204 value: Rc::new(value),
201 }}205 }}
202 pub rule obj_local(s: &ParserSettings) -> BindSpec206 pub rule obj_local(s: &ParserSettings) -> BindSpec
203 = keyword("local") _ bind:bind(s) {bind}207 = keyword("local") _ bind:bind(s) {bind}
204 pub rule member(s: &ParserSettings) -> expr::Member208 pub rule member(s: &ParserSettings) -> expr::Member
205 = bind:obj_local(s) {expr::Member::BindStmt(bind)}209 = bind:obj_local(s) {expr::Member::BindStmt(bind)}
206 / assertion:assertion(s) {expr::Member::AssertStmt(assertion)}210 / assertion:assertion(s) {expr::Member::AssertStmt(Rc::new(assertion))}
207 / field:field(s) {expr::Member::Field(field)}211 / field:field(s) {expr::Member::Field(field)}
208 pub rule objinside(s: &ParserSettings) -> expr::ObjBody212 pub rule objinside(s: &ParserSettings) -> expr::ObjBody
209 = pre_locals:(b: obj_local(s) comma() {b})* &"[" field:field(s) post_locals:(comma() b:obj_local(s) {b})* _ ("," _)? forspec:forspec(s) others:(_ rest:compspec(s) {rest})? {213 = pre_locals:(b: obj_local(s) comma() {b})* &"[" field:field(s) post_locals:(comma() b:obj_local(s) {b})* _ ("," _)? forspec:forspec(s) others:(_ rest:compspec(s) {rest})? {
210 let mut compspecs = vec![CompSpec::ForSpec(forspec)];214 let mut compspecs = vec![CompSpec::ForSpec(forspec)];
211 compspecs.extend(others.unwrap_or_default());215 compspecs.extend(others.unwrap_or_default());
212 expr::ObjBody::ObjComp(expr::ObjComp{216 expr::ObjBody::ObjComp(expr::ObjComp{
213 pre_locals,217 pre_locals,
214 field,218 field: Rc::new(field),
215 post_locals,219 post_locals,
216 compspecs,220 compspecs,
217 })221 })
224 pub rule compspec(s: &ParserSettings) -> Vec<expr::CompSpec>228 pub rule compspec(s: &ParserSettings) -> Vec<expr::CompSpec>
225 = s:(i:ifspec(s) { expr::CompSpec::IfSpec(i) } / f:forspec(s) {expr::CompSpec::ForSpec(f)} ) ** _ {s}229 = s:(i:ifspec(s) { expr::CompSpec::IfSpec(i) } / f:forspec(s) {expr::CompSpec::ForSpec(f)} ) ** _ {s}
226 pub rule local_expr(s: &ParserSettings) -> Expr230 pub rule local_expr(s: &ParserSettings) -> Expr
227 = keyword("local") _ binds:bind(s) ** comma() (_ ",")? _ ";" _ expr:expr(s) { Expr::LocalExpr(binds, expr) }231 = keyword("local") _ binds:bind(s) ** comma() (_ ",")? _ ";" _ expr:expr(s) { Expr::LocalExpr(binds, Box::new(expr)) }
228 pub rule string_expr(s: &ParserSettings) -> Expr232 pub rule string_expr(s: &ParserSettings) -> Expr
229 = s:string() {Expr::Str(s.into())}233 = s:string() {Expr::Str(s.into())}
230 pub rule obj_expr(s: &ParserSettings) -> Expr234 pub rule obj_expr(s: &ParserSettings) -> Expr
231 = "{" _ body:objinside(s) _ "}" {Expr::Obj(body)}235 = "{" _ body:objinside(s) _ "}" {Expr::Obj(body)}
232 pub rule array_expr(s: &ParserSettings) -> Expr236 pub rule array_expr(s: &ParserSettings) -> Expr
233 = "[" _ elems:(expr(s) ** comma()) _ comma()? "]" {Expr::Arr(elems)}237 = "[" _ elems:(expr(s) ** comma()) _ comma()? "]" {Expr::Arr(Rc::new(elems))}
234 pub rule array_comp_expr(s: &ParserSettings) -> Expr238 pub rule array_comp_expr(s: &ParserSettings) -> Expr
235 = "[" _ expr:expr(s) _ comma()? _ forspec:forspec(s) _ others:(others: compspec(s) _ {others})? "]" {239 = "[" _ expr:expr(s) _ comma()? _ forspec:forspec(s) _ others:(others: compspec(s) _ {others})? "]" {
236 let mut specs = vec![CompSpec::ForSpec(forspec)];240 let mut specs = vec![CompSpec::ForSpec(forspec)];
237 specs.extend(others.unwrap_or_default());241 specs.extend(others.unwrap_or_default());
238 Expr::ArrComp(expr, specs)242 Expr::ArrComp(Rc::new(expr), specs)
239 }243 }
240 pub rule number_expr(s: &ParserSettings) -> Expr244 pub rule number_expr(s: &ParserSettings) -> Expr
241 = n:number() {? if n.is_finite() {245 = n:number() {? if n.is_finite() {
245 }}249 }}
246 pub rule var_expr(s: &ParserSettings) -> Expr250 pub rule var_expr(s: &ParserSettings) -> Expr
247 = n:id() { expr::Expr::Var(n) }251 = n:id() { expr::Expr::Var(n) }
248 pub rule id_loc(s: &ParserSettings) -> LocExpr252 pub rule id_loc(s: &ParserSettings) -> Spanned<Expr>
249 = a:position!() n:id() b:position!() { LocExpr::new(expr::Expr::Str(n), Span(s.source.clone(), a as u32,b as u32)) }253 = a:position!() n:id() b:position!() { Spanned::new(expr::Expr::Str(n), Span(s.source.clone(), a as u32,b as u32)) }
250 pub rule if_then_else_expr(s: &ParserSettings) -> Expr254 pub rule if_then_else_expr(s: &ParserSettings) -> Expr
251 = cond:ifspec(s) _ keyword("then") _ cond_then:expr(s) cond_else:(_ keyword("else") _ e:expr(s) {e})? {Expr::IfElse{255 = cond:ifspec(s) _ keyword("then") _ cond_then:expr(s) cond_else:(_ keyword("else") _ e:expr(s) {e})? {Expr::IfElse(Box::new(IfElse{
252 cond,256 cond,
253 cond_then,257 cond_then,
254 cond_else,258 cond_else,
255 }}259 }))}
256260
257 pub rule literal(s: &ParserSettings) -> Expr261 pub rule literal(s: &ParserSettings) -> Expr
258 = v:(262 = v:(
264 / keyword("super") {LiteralType::Super}268 / keyword("super") {LiteralType::Super}
265 ) {Expr::Literal(v)}269 ) {Expr::Literal(v)}
270
271 rule import_kind() -> ImportKind
272 = keyword("importstr") { ImportKind::Str }
273 / keyword("importbin") { ImportKind::Bin }
274 / keyword("import") { ImportKind::Normal }
266275
267 pub rule expr_basic(s: &ParserSettings) -> Expr276 pub rule expr_basic(s: &ParserSettings) -> Expr
268 = literal(s)277 = literal(s)
273 / array_expr(s)282 / array_expr(s)
274 / array_comp_expr(s)283 / array_comp_expr(s)
275284
276 / keyword("importstr") _ path:expr(s) {Expr::ImportStr(path)}285 / kind:import_kind() _ path:expr(s) {Expr::Import(kind, Box::new(path))}
277 / keyword("importbin") _ path:expr(s) {Expr::ImportBin(path)}
278 / keyword("import") _ path:expr(s) {Expr::Import(path)}
279286
280 / var_expr(s)287 / var_expr(s)
281 / local_expr(s)288 / local_expr(s)
282 / if_then_else_expr(s)289 / if_then_else_expr(s)
283290
284 / keyword("function") _ "(" _ params:params(s) _ ")" _ expr:expr(s) {Expr::Function(params, expr)}291 / keyword("function") _ "(" _ params:params(s) _ ")" _ expr:expr(s) {Expr::Function(params, Rc::new(expr))}
285 / assertion:assertion(s) _ ";" _ expr:expr(s) { Expr::AssertExpr(assertion, expr) }292 / assert:assertion(s) _ ";" _ rest:expr(s) { Expr::AssertExpr(Rc::new(AssertExpr{
293 assert, rest
294 })) }
286295
287 / keyword("error") _ expr:expr(s) { Expr::ErrorStmt(expr) }296 / keyword("error") _ expr:expr(s) { Expr::ErrorStmt(Box::new(expr)) }
288297
289 rule slice_part(s: &ParserSettings) -> Option<LocExpr>298 rule slice_part(s: &ParserSettings) -> Option<Spanned<Expr>>
290 = _ e:(e:expr(s) _{e})? {e}299 = _ e:(e:expr(s) _{e})? {e}
291 pub rule slice_desc(s: &ParserSettings) -> SliceDesc300 pub rule slice_desc(s: &ParserSettings) -> SliceDesc
292 = start:slice_part(s) ":" pair:(end:slice_part(s) step:(":" e:slice_part(s){e})? {(end, step.flatten())})? {301 = start:slice_part(s) ":" pair:(end:slice_part(s) step:(":" e:slice_part(s){e})? {(end, step.flatten())})? {
311 }320 }
312 use BinaryOpType::*;321 use BinaryOpType::*;
313 use UnaryOpType::*;322 use UnaryOpType::*;
314 rule expr(s: &ParserSettings) -> LocExpr323 rule expr(s: &ParserSettings) -> Spanned<Expr>
315 = precedence! {324 = precedence! {
316 "(" _ e:expr(s) _ ")" {e}325 "(" _ e:expr(s) _ ")" {e}
317 start:position!() v:@ end:position!() { LocExpr::new(v, Span(s.source.clone(), start as u32, end as u32)) }326 start:position!() v:@ end:position!() { Spanned::new(v, Span(s.source.clone(), start as u32, end as u32)) }
318 --327 --
319 a:(@) _ binop(<"||">) _ b:@ {expr_bin!(a Or b)}328 a:(@) _ binop(<"||">) _ b:@ {expr_bin!(a Or b)}
320 a:(@) _ binop(<"??">) _ ensure_null_coaelse() b:@ {329 a:(@) _ binop(<"??">) _ ensure_null_coaelse() b:@ {
354 unaryop(<"!">) _ b:@ {expr_un!(Not b)}363 unaryop(<"!">) _ b:@ {expr_un!(Not b)}
355 unaryop(<"~">) _ b:@ {expr_un!(BitNot b)}364 unaryop(<"~">) _ b:@ {expr_un!(BitNot b)}
356 --365 --
357 a:(@) _ "[" _ e:slice_desc(s) _ "]" {Expr::Slice(a, e)}366 value:(@) _ "[" _ slice:slice_desc(s) _ "]" {Expr::Slice(Box::new(Slice{value, slice}))}
358 indexable:(@) _ parts:index_part(s)+ {Expr::Index{indexable, parts}}367 indexable:(@) _ parts:index_part(s)+ {Expr::Index{indexable: Box::new(indexable), parts}}
359 a:(@) _ "(" _ args:args(s) _ ")" ts:(_ keyword("tailstrict"))? {Expr::Apply(a, args, ts.is_some())}368 a:(@) _ "(" _ args:args(s) _ ")" ts:(_ keyword("tailstrict"))? {Expr::Apply(Box::new(a), args, ts.is_some())}
360 a:(@) _ "{" _ body:objinside(s) _ "}" {Expr::ObjExtend(a, body)}369 a:(@) _ "{" _ body:objinside(s) _ "}" {Expr::ObjExtend(Rc::new(a), body)}
361 --370 --
362 e:expr_basic(s) {e}371 e:expr_basic(s) {e}
363 }372 }
373 null_coaelse: n.is_some(),382 null_coaelse: n.is_some(),
374 }}383 }}
375384
376 pub rule jsonnet(s: &ParserSettings) -> LocExpr = _ e:expr(s) _ {e}385 pub rule jsonnet(s: &ParserSettings) -> Spanned<Expr> = _ e:expr(s) _ {e}
377 }386 }
378}387}
379388
380pub type ParseError = peg::error::ParseError<peg::str::LineCol>;389pub type ParseError = peg::error::ParseError<peg::str::LineCol>;
381pub fn parse(str: &str, settings: &ParserSettings) -> Result<LocExpr, ParseError> {390pub fn parse(str: &str, settings: &ParserSettings) -> Result<Spanned<Expr>, ParseError> {
382 jsonnet_parser::jsonnet(str, settings)391 jsonnet_parser::jsonnet(str, settings)
383}392}
384/// Used for importstr values393/// Used for importstr values
385pub fn string_to_expr(str: IStr, settings: &ParserSettings) -> LocExpr {394pub fn string_to_expr(str: IStr, settings: &ParserSettings) -> Spanned<Expr> {
386 let len = str.len();395 let len = str.len();
387 LocExpr::new(Expr::Str(str), Span(settings.source.clone(), 0, len as u32))396 Spanned::new(Expr::Str(str), Span(settings.source.clone(), 0, len as u32))
388}397}
389398
390#[cfg(test)]399#[cfg(test)]
391pub mod tests {400pub mod tests {
392 use jrsonnet_interner::IStr;401 use insta::assert_snapshot;
393 use BinaryOpType::*;402 use jrsonnet_interner::IStr;
394403
395 use super::{expr::*, parse};404 use super::parse;
396 use crate::{source::Source, ParserSettings};405 use crate::{source::Source, ParserSettings};
397406
398 macro_rules! parse {
399 ($s:expr) => {407 fn parsep(s: &str) -> String {
400 parse(408 let v = parse(
401 $s,409 s,
402 &ParserSettings {410 &ParserSettings {
403 source: Source::new_virtual("<test>".into(), IStr::empty()),411 source: Source::new_virtual("<test>".into(), IStr::empty()),
404 },412 },
405 )413 )
406 .unwrap()414 .unwrap();
415 format!("{v:#?}")
407 };416 }
408 }
409417
410 macro_rules! el {418 macro_rules! parse {
411 ($expr:expr, $from:expr, $to:expr$(,)?) => {419 ($s:expr) => {
412 LocExpr::new(420 assert_snapshot!(parsep($s));
413 $expr,
414 Span(
415 Source::new_virtual("<test>".into(), IStr::empty()),
416 $from,
417 $to,
418 ),
419 )
420 };421 };
421 }422 }
422423
423 #[test]424 #[test]
424 fn multiline_string() {425 fn multiline_string() {
425 assert_eq!(
426 parse!("|||\n Hello world!\n a\n|||"),426 parse!("|||\n Hello world!\n a\n|||");
427 el!(Expr::Str("Hello world!\n a\n".into()), 0, 31),
428 );
429 assert_eq!(
430 parse!("|||\n Hello world!\n a\n|||"),427 parse!("|||\n Hello world!\n a\n|||");
431 el!(Expr::Str("Hello world!\n a\n".into()), 0, 27),
432 );
433 assert_eq!(
434 parse!("|||\n\t\tHello world!\n\t\t\ta\n|||"),428 parse!("|||\n\t\tHello world!\n\t\t\ta\n|||");
435 el!(Expr::Str("Hello world!\n\ta\n".into()), 0, 27),
436 );
437 assert_eq!(
438 parse!("|||\n Hello world!\n a\n |||"),429 parse!("|||\n Hello world!\n a\n |||");
439 el!(Expr::Str("Hello world!\n a\n".into()), 0, 30),
440 );
441 }430 }
442431
443 #[test]432 #[test]
451440
452 #[test]441 #[test]
453 fn string_escaping() {442 fn string_escaping() {
454 assert_eq!(
455 parse!(r#""Hello, \"world\"!""#),443 parse!(r#""Hello, \"world\"!""#);
456 el!(Expr::Str(r#"Hello, "world"!"#.into()), 0, 19),
457 );
458 assert_eq!(
459 parse!(r#"'Hello \'world\'!'"#),444 parse!(r#"'Hello \'world\'!'"#);
460 el!(Expr::Str("Hello 'world'!".into()), 0, 18),
461 );
462 assert_eq!(parse!(r#"'\\\\'"#), el!(Expr::Str("\\\\".into()), 0, 6));445 parse!(r#"'\\\\'"#);
463 }446 }
464447
465 #[test]448 #[test]
466 fn string_unescaping() {449 fn string_unescaping() {
467 assert_eq!(
468 parse!(r#""Hello\nWorld""#),450 parse!(r#""Hello\nWorld""#);
469 el!(Expr::Str("Hello\nWorld".into()), 0, 14),
470 );
471 }451 }
472452
473 #[test]453 #[test]
474 fn string_verbantim() {454 fn string_verbantim() {
475 assert_eq!(
476 parse!(r#"@"Hello\n""World""""#),455 parse!(r#"@"Hello\n""World""""#);
477 el!(Expr::Str("Hello\\n\"World\"".into()), 0, 19),
478 );
479 }456 }
480457
481 #[test]458 #[test]
482 fn imports() {459 fn imports() {
483 assert_eq!(
484 parse!("import \"hello\""),460 parse!("import \"hello\"");
485 el!(Expr::Import(el!(Expr::Str("hello".into()), 7, 14)), 0, 14),
486 );
487 assert_eq!(
488 parse!("importstr \"garnish.txt\""),461 parse!("importstr \"garnish.txt\"");
489 el!(
490 Expr::ImportStr(el!(Expr::Str("garnish.txt".into()), 10, 23)),
491 0,
492 23
493 )
494 );
495 assert_eq!(
496 parse!("importbin \"garnish.bin\""),462 parse!("importbin \"garnish.bin\"");
497 el!(
498 Expr::ImportBin(el!(Expr::Str("garnish.bin".into()), 10, 23)),
499 0,
500 23
501 )
502 );
503 }463 }
504464
505 #[test]465 #[test]
506 fn empty_object() {466 fn empty_object() {
507 assert_eq!(
508 parse!("{}"),467 parse!("{}");
509 el!(Expr::Obj(ObjBody::MemberList(vec![])), 0, 2)
510 );
511 }468 }
512469
513 #[test]470 #[test]
514 fn basic_math() {471 fn basic_math() {
515 assert_eq!(472 parse!("2+2*2");
516 parse!("2+2*2"),
517 el!(
518 Expr::BinaryOp(
519 el!(Expr::Num(2.0), 0, 1),
520 Add,
521 el!(
522 Expr::BinaryOp(el!(Expr::Num(2.0), 2, 3), Mul, el!(Expr::Num(2.0), 4, 5)),
523 2,
524 5
525 )
526 ),
527 0,
528 5
529 )
530 );
531 }
532
533 #[test]
534 fn basic_math_with_indents() {
535 assert_eq!(
536 parse!("2 + 2 * 2 "),473 parse!("2 + 2 * 2 ");
537 el!(
538 Expr::BinaryOp(
539 el!(Expr::Num(2.0), 0, 1),
540 Add,
541 el!(
542 Expr::BinaryOp(el!(Expr::Num(2.0), 7, 8), Mul, el!(Expr::Num(2.0), 13, 14),),
543 7,
544 14
545 ),
546 ),
547 0,
548 14
549 )
550 );
551 }
552
553 #[test]
554 fn basic_math_parened() {
555 assert_eq!(
556 parse!("2+(2+2*2)"),474 parse!("2+(2+2*2)");
557 el!(
558 Expr::BinaryOp(
559 el!(Expr::Num(2.0), 0, 1),
560 Add,
561 el!(
562 Expr::BinaryOp(
563 el!(Expr::Num(2.0), 3, 4),
564 Add,
565 el!(
566 Expr::BinaryOp(
567 el!(Expr::Num(2.0), 5, 6),
568 Mul,
569 el!(Expr::Num(2.0), 7, 8),
570 ),
571 5,
572 8
573 ),
574 ),
575 3,
576 8
577 ),
578 ),
579 0,
580 9
581 )
582 );
583 }
584
585 /// Comments should not affect parsing
586 #[test]
587 fn comments() {
588 assert_eq!(
589 parse!("2//comment\n+//comment\n3/*test*/*/*test*/4"),475 parse!("2//comment\n+//comment\n3/*test*/*/*test*/4");
590 el!(476 }
591 Expr::BinaryOp(
592 el!(Expr::Num(2.0), 0, 1),
593 Add,
594 el!(
595 Expr::BinaryOp(
596 el!(Expr::Num(3.0), 22, 23),
597 Mul,
598 el!(Expr::Num(4.0), 40, 41)
599 ),
600 22,
601 41
602 )
603 ),
604 0,
605 41
606 )
607 );
608 }
609477
610 #[test]478 #[test]
611 fn suffix() {479 fn suffix() {
612 // assert_eq!(parse!("std.test"), el!(Expr::Num(2.2)));480 parse!("std.test");
613 // assert_eq!(parse!("std(2)"), el!(Expr::Num(2.2)));481 parse!("std(2)");
614 // assert_eq!(parse!("std.test(2)"), el!(Expr::Num(2.2)));482 parse!("std.test(2)");
615 // assert_eq!(parse!("a[b]"), el!(Expr::Num(2.2)))483 parse!("a[b]");
616 }484 }
617485
618 #[test]486 #[test]
619 fn array_comp() {487 fn array_comp() {
620 use Expr::*;
621 /*
622 `ArrComp(Apply(Index(Var("std") from "test.jsonnet":1-4, Var("deepJoin") from "test.jsonnet":5-13) from "test.jsonnet":1-13, ArgsDesc { unnamed: [Var("x") from "test.jsonnet":14-15], named: [] }, false) from "test.jsonnet":1-16, [ForSpec(ForSpecData("x", Var("arr") from "test.jsonnet":26-29))]) from "test.jsonnet":0-30`,
623 `ArrComp(Apply(Index(Var("std") from "test.jsonnet":1-4, Str("deepJoin") from "test.jsonnet":5-13) from "test.jsonnet":1-13, ArgsDesc { unnamed: [Var("x") from "test.jsonnet":14-15], named: [] }, false) from "test.jsonnet":1-16, [ForSpec(ForSpecData("x", Var("arr") from "test.jsonnet":26-29))]) from "test.jsonnet":0-30`
624 */
625 assert_eq!(
626 parse!("[std.deepJoin(x) for x in arr]"),488 parse!("[std.deepJoin(x) for x in arr]");
627 el!(
628 ArrComp(
629 el!(
630 Apply(
631 el!(
632 Index {
633 indexable: el!(Var("std".into()), 1, 4),
634 parts: vec![IndexPart {
635 value: el!(Str("deepJoin".into()), 5, 13),
636 #[cfg(feature = "exp-null-coaelse")]
637 null_coaelse: false,
638 }],
639 },
640 1,
641 13
642 ),
643 ArgsDesc::new(vec![el!(Var("x".into()), 14, 15)], vec![]),
644 false,
645 ),
646 1,
647 16
648 ),
649 vec![CompSpec::ForSpec(ForSpecData(
650 Destruct::Full("x".into()),
651 el!(Var("arr".into()), 26, 29)
652 ))]
653 ),
654 0,
655 30
656 ),
657 )
658 }489 }
659490
660 #[test]491 #[test]
661 fn reserved() {492 fn reserved() {
662 use Expr::*;
663 assert_eq!(parse!("null"), el!(Literal(LiteralType::Null), 0, 4));493 parse!("null");
664 assert_eq!(parse!("nulla"), el!(Var("nulla".into()), 0, 5));494 parse!("nulla");
665 }495 }
666496
667 #[test]497 #[test]
670 }500 }
671501
672 #[test]502 #[test]
673 fn infix_precedence() {503 fn infix_precedence() {
674 use Expr::*;
675 assert_eq!(
676 parse!("!a && !b"),
677 el!(
678 BinaryOp(
679 el!(UnaryOp(UnaryOpType::Not, el!(Var("a".into()), 1, 2)), 0, 2),
680 And,
681 el!(UnaryOp(UnaryOpType::Not, el!(Var("b".into()), 7, 8)), 6, 8)
682 ),
683 0,
684 8
685 )
686 );
687 }
688
689 #[test]
690 fn infix_precedence_division() {
691 use Expr::*;504 parse!("!a && !b");
692 assert_eq!(
693 parse!("!a / !b"),505 parse!("!a / !b");
694 el!(
695 BinaryOp(
696 el!(UnaryOp(UnaryOpType::Not, el!(Var("a".into()), 1, 2)), 0, 2),
697 Div,
698 el!(UnaryOp(UnaryOpType::Not, el!(Var("b".into()), 6, 7)), 5, 7)
699 ),
700 0,
701 7
702 )
703 );
704 }506 }
705507
706 #[test]508 #[test]
707 fn double_negation() {509 fn double_negation() {
708 use Expr::*;
709 assert_eq!(
710 parse!("!!a"),510 parse!("!!a");
711 el!(
712 UnaryOp(
713 UnaryOpType::Not,
714 el!(UnaryOp(UnaryOpType::Not, el!(Var("a".into()), 2, 3)), 1, 3)
715 ),
716 0,
717 3
718 )
719 )
720 }511 }
721512
722 #[test]513 #[test]
723 fn array_test_error() {514 fn array_test_error() {
724 parse!("[a for a in b if c for e in f]");515 parse!("[a for a in b if c for e in f]");
725 // ^^^^ failed code
726 }516 }
727517
728 #[test]518 #[test]
741531
742 #[test]532 #[test]
743 fn add_location_info_to_all_sub_expressions() {533 fn add_location_info_to_all_sub_expressions() {
744 use Expr::*;
745
746 let file_name = Source::new_virtual("<test>".into(), IStr::empty());
747 let expr = parse(534 parse!("{} { local x = 1, x: x } + {}");
748 "{} { local x = 1, x: x } + {}",
749 &ParserSettings { source: file_name },
750 )
751 .unwrap();
752 assert_eq!(
753 expr,
754 el!(
755 BinaryOp(
756 el!(
757 ObjExtend(
758 el!(Obj(ObjBody::MemberList(vec![])), 0, 2),
759 ObjBody::MemberList(vec![
760 Member::BindStmt(BindSpec::Field {
761 into: Destruct::Full("x".into()),
762 value: el!(Num(1.0), 15, 16)
763 }),
764 Member::Field(FieldMember {
765 name: FieldName::Fixed("x".into()),
766 plus: false,
767 params: None,
768 visibility: Visibility::Normal,
769 value: el!(Var("x".into()), 21, 22),
770 })
771 ])
772 ),
773 0,
774 24
775 ),
776 BinaryOpType::Add,
777 el!(Obj(ObjBody::MemberList(vec![])), 27, 29),
778 ),
779 0,
780 29
781 ),
782 );
783 }535 }
784}536}
785537
addedcrates/jrsonnet-parser/src/snapshots/jrsonnet_parser__tests__add_location_info_to_all_sub_expressions.snapdiffbeforeafterboth

no changes

addedcrates/jrsonnet-parser/src/snapshots/jrsonnet_parser__tests__array_comp.snapdiffbeforeafterboth

no changes

addedcrates/jrsonnet-parser/src/snapshots/jrsonnet_parser__tests__array_test_error.snapdiffbeforeafterboth

no changes

addedcrates/jrsonnet-parser/src/snapshots/jrsonnet_parser__tests__basic_math-2.snapdiffbeforeafterboth

no changes

addedcrates/jrsonnet-parser/src/snapshots/jrsonnet_parser__tests__basic_math-3.snapdiffbeforeafterboth

no changes

addedcrates/jrsonnet-parser/src/snapshots/jrsonnet_parser__tests__basic_math-4.snapdiffbeforeafterboth

no changes

addedcrates/jrsonnet-parser/src/snapshots/jrsonnet_parser__tests__basic_math.snapdiffbeforeafterboth

no changes

addedcrates/jrsonnet-parser/src/snapshots/jrsonnet_parser__tests__default_param_before_nondefault.snapdiffbeforeafterboth

no changes

addedcrates/jrsonnet-parser/src/snapshots/jrsonnet_parser__tests__double_negation.snapdiffbeforeafterboth

no changes

addedcrates/jrsonnet-parser/src/snapshots/jrsonnet_parser__tests__empty_object.snapdiffbeforeafterboth

no changes

addedcrates/jrsonnet-parser/src/snapshots/jrsonnet_parser__tests__imports-2.snapdiffbeforeafterboth

no changes

addedcrates/jrsonnet-parser/src/snapshots/jrsonnet_parser__tests__imports-3.snapdiffbeforeafterboth

no changes

addedcrates/jrsonnet-parser/src/snapshots/jrsonnet_parser__tests__imports.snapdiffbeforeafterboth

no changes

addedcrates/jrsonnet-parser/src/snapshots/jrsonnet_parser__tests__infix_precedence-2.snapdiffbeforeafterboth

no changes

addedcrates/jrsonnet-parser/src/snapshots/jrsonnet_parser__tests__infix_precedence.snapdiffbeforeafterboth

no changes

addedcrates/jrsonnet-parser/src/snapshots/jrsonnet_parser__tests__missing_newline_between_comment_and_eof.snapdiffbeforeafterboth

no changes

addedcrates/jrsonnet-parser/src/snapshots/jrsonnet_parser__tests__multiline_string-2.snapdiffbeforeafterboth

no changes

addedcrates/jrsonnet-parser/src/snapshots/jrsonnet_parser__tests__multiline_string-3.snapdiffbeforeafterboth

no changes

addedcrates/jrsonnet-parser/src/snapshots/jrsonnet_parser__tests__multiline_string-4.snapdiffbeforeafterboth

no changes

addedcrates/jrsonnet-parser/src/snapshots/jrsonnet_parser__tests__multiline_string.snapdiffbeforeafterboth

no changes

addedcrates/jrsonnet-parser/src/snapshots/jrsonnet_parser__tests__multiple_args_buf.snapdiffbeforeafterboth

no changes

addedcrates/jrsonnet-parser/src/snapshots/jrsonnet_parser__tests__reserved-2.snapdiffbeforeafterboth

no changes

addedcrates/jrsonnet-parser/src/snapshots/jrsonnet_parser__tests__reserved.snapdiffbeforeafterboth

no changes

addedcrates/jrsonnet-parser/src/snapshots/jrsonnet_parser__tests__slice-2.snapdiffbeforeafterboth

no changes

addedcrates/jrsonnet-parser/src/snapshots/jrsonnet_parser__tests__slice-3.snapdiffbeforeafterboth

no changes

addedcrates/jrsonnet-parser/src/snapshots/jrsonnet_parser__tests__slice-4.snapdiffbeforeafterboth

no changes

addedcrates/jrsonnet-parser/src/snapshots/jrsonnet_parser__tests__slice-5.snapdiffbeforeafterboth

no changes

addedcrates/jrsonnet-parser/src/snapshots/jrsonnet_parser__tests__slice.snapdiffbeforeafterboth

no changes

addedcrates/jrsonnet-parser/src/snapshots/jrsonnet_parser__tests__string_escaping-2.snapdiffbeforeafterboth

no changes

addedcrates/jrsonnet-parser/src/snapshots/jrsonnet_parser__tests__string_escaping-3.snapdiffbeforeafterboth

no changes

addedcrates/jrsonnet-parser/src/snapshots/jrsonnet_parser__tests__string_escaping.snapdiffbeforeafterboth

no changes

addedcrates/jrsonnet-parser/src/snapshots/jrsonnet_parser__tests__string_unescaping.snapdiffbeforeafterboth

no changes

addedcrates/jrsonnet-parser/src/snapshots/jrsonnet_parser__tests__string_verbantim.snapdiffbeforeafterboth

no changes

addedcrates/jrsonnet-parser/src/snapshots/jrsonnet_parser__tests__suffix-2.snapdiffbeforeafterboth

no changes

addedcrates/jrsonnet-parser/src/snapshots/jrsonnet_parser__tests__suffix-3.snapdiffbeforeafterboth

no changes

addedcrates/jrsonnet-parser/src/snapshots/jrsonnet_parser__tests__suffix-4.snapdiffbeforeafterboth

no changes

addedcrates/jrsonnet-parser/src/snapshots/jrsonnet_parser__tests__suffix.snapdiffbeforeafterboth

no changes

modifiedcrates/jrsonnet-parser/src/source.rsdiffbeforeafterboth
79/// search location is applicable79/// search location is applicable
80///80///
81/// Resolver may also return custom implementations of this trait, for example it may return http url in case of remotely loaded files81/// Resolver may also return custom implementations of this trait, for example it may return http url in case of remotely loaded files
82#[derive(Eq, Debug, Clone, Acyclic)]82#[derive(Eq, Clone, Acyclic)]
83pub struct SourcePath(Rc<dyn SourcePathT>);83pub struct SourcePath(Rc<dyn SourcePathT>);
84impl SourcePath {84impl SourcePath {
85 pub fn new(inner: impl SourcePathT) -> Self {85 pub fn new(inner: impl SourcePathT) -> Self {
111 write!(f, "{}", self.0)111 write!(f, "{}", self.0)
112 }112 }
113}113}
114impl Debug for SourcePath {
115 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
116 write!(f, "{:?}", self.0)
117 }
118}
114impl Default for SourcePath {119impl Default for SourcePath {
115 fn default() -> Self {120 fn default() -> Self {
116 Self(Rc::new(SourceDefault))121 Self(Rc::new(SourceDefault))
213///218///
214/// It is used for --ext-code=.../--tla-code=.../standard library source code by default,219/// It is used for --ext-code=.../--tla-code=.../standard library source code by default,
215/// and user can construct arbitrary values by hand, without asking import resolver220/// and user can construct arbitrary values by hand, without asking import resolver
216#[derive(Acyclic, Hash, PartialEq, Eq, Debug, Clone)]221#[derive(Acyclic, Hash, PartialEq, Eq, Clone)]
217pub struct SourceVirtual(pub IStr);222pub struct SourceVirtual(pub IStr);
218impl Display for SourceVirtual {223impl Display for SourceVirtual {
219 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {224 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
220 write!(f, "{}", self.0)225 write!(f, "virtual:{}", self.0)
221 }226 }
222}227}
228impl fmt::Debug for SourceVirtual {
229 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
230 write!(f, "virtual:{}", self.0)
231 }
232}
223impl SourcePathT for SourceVirtual {233impl SourcePathT for SourceVirtual {
224 fn is_default(&self) -> bool {234 fn is_default(&self) -> bool {
225 true235 true
263273
264/// Either real file, or virtual274/// Either real file, or virtual
265/// Hash of FileName always have same value as raw Path, to make it possible to use with raw_entry_mut275/// Hash of FileName always have same value as raw Path, to make it possible to use with raw_entry_mut
266#[derive(Clone, PartialEq, Eq, Debug, Acyclic)]276#[derive(Clone, PartialEq, Eq, Acyclic)]
267pub struct Source(pub Rc<(SourcePath, IStr)>);277pub struct Source(pub Rc<(SourcePath, IStr)>);
268278
269impl Source {279impl Source {
290 location_to_offset(&self.0 .1, line, column)300 location_to_offset(&self.0 .1, line, column)
291 }301 }
292}302}
303impl fmt::Debug for Source {
304 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
305 write!(f, "{:?}", self.0 .0)
306 }
307}
293308