difftreelog
refactor split literals and trivials
in: master
39 files changed
crates/jrsonnet-ir-parser/src/lib.rsdiffbeforeafterboth--- a/crates/jrsonnet-ir-parser/src/lib.rs
+++ b/crates/jrsonnet-ir-parser/src/lib.rs
@@ -1,9 +1,9 @@
use jrsonnet_gcmodule::Acyclic;
use jrsonnet_ir::{
ArgsDesc, AssertExpr, AssertStmt, BinaryOp, BinaryOpType, BindSpec, CompSpec, Destruct, Expr,
- ExprParam, ExprParams, FieldMember, FieldName, ForSpecData, IStr, IfElse, IfSpecData,
- ImportKind, IndexPart, LiteralType, Member, NumValue, ObjBody, ObjComp, ObjMembers, Slice,
- SliceDesc, Source, Span, Spanned, UnaryOpType, Visibility, unescape,
+ ExprParam, ExprParams, FieldMember, FieldName, ForSpecData, IStr, IdentityKind, IfElse,
+ IfSpecData, ImportKind, IndexPart, Member, NumValue, ObjBody, ObjComp, ObjMembers, Slice,
+ SliceDesc, Source, Span, Spanned, TrivialVal, UnaryOpType, Visibility, unescape,
};
use jrsonnet_lexer::{Lexeme, Lexer, Span as LexSpan, SyntaxKind, T, collect_lexed_str_block};
@@ -247,19 +247,6 @@
Ok(IStr::from(text))
}
-fn literal(p: &mut Parser<'_>) -> Option<(Span, LiteralType)> {
- let t = match p.peek() {
- T![self] => LiteralType::This,
- T![super] => LiteralType::Super,
- T!['$'] => LiteralType::Dollar,
- T![null] => LiteralType::Null,
- T![true] => LiteralType::True,
- T![false] => LiteralType::False,
- _ => return None,
- };
- Some((p.eat_any_spanned(), t))
-}
-
fn assert_stmt(p: &mut Parser<'_>) -> Result<AssertStmt> {
p.eat(T![assert])?;
let assertion = spanned(p, expr)?;
@@ -688,18 +675,30 @@
#[allow(clippy::too_many_lines)]
fn expr_basic(p: &mut Parser<'_>) -> Result<Expr> {
- if let Some((span, lit)) = literal(p) {
- return Ok(Expr::Literal(span, lit));
- }
+ match p.peek() {
+ T![self] => Ok(Expr::Identity(p.eat_any_spanned(), IdentityKind::This)),
+ T![super] => Ok(Expr::Identity(p.eat_any_spanned(), IdentityKind::Super)),
+ T!['$'] => Ok(Expr::Identity(p.eat_any_spanned(), IdentityKind::Dollar)),
+ T![null] => {
+ p.eat_any();
+ Ok(Expr::Trivial(TrivialVal::Null))
+ }
+ T![true] => {
+ p.eat_any();
+ Ok(Expr::Trivial(TrivialVal::Bool(true)))
+ }
+ T![false] => {
+ p.eat_any();
+ Ok(Expr::Trivial(TrivialVal::Bool(false)))
+ }
- match p.peek() {
SyntaxKind::STRING_DOUBLE
| SyntaxKind::STRING_SINGLE
| SyntaxKind::STRING_DOUBLE_VERBATIM
| SyntaxKind::STRING_SINGLE_VERBATIM
- | SyntaxKind::STRING_BLOCK => Ok(Expr::Str(parse_string_content(p)?)),
+ | SyntaxKind::STRING_BLOCK => Ok(Expr::Trivial(TrivialVal::Str(parse_string_content(p)?))),
- SyntaxKind::FLOAT => Ok(Expr::Num(parse_number(p)?)),
+ SyntaxKind::FLOAT => Ok(Expr::Trivial(TrivialVal::Num(parse_number(p)?))),
T!['('] => {
p.eat(T!['('])?;
@@ -832,7 +831,7 @@
if parts.is_empty() {
return;
}
- let old = std::mem::replace(e, Expr::Str(IStr::empty()));
+ let old = std::mem::replace(e, Expr::Trivial(TrivialVal::Null));
*e = Expr::Index {
indexable: Box::new(old),
parts: std::mem::take(parts),
@@ -863,7 +862,7 @@
});
} else {
// ?.field
- let id_spanned = spanned(p, |p| Ok(Expr::Str(ident(p)?)))?;
+ let id_spanned = spanned(p, |p| Ok(Expr::Trivial(TrivialVal::Str(ident(p)?))))?;
parts.push(IndexPart {
span: id_spanned.span,
value: id_spanned.value,
@@ -878,7 +877,7 @@
if p.at(T![.]) {
p.eat(T![.])?;
- let id_spanned = spanned(p, |p| Ok(Expr::Str(ident(p)?)))?;
+ let id_spanned = spanned(p, |p| Ok(Expr::Trivial(TrivialVal::Str(ident(p)?))))?;
parts.push(IndexPart {
span: id_spanned.span,
value: id_spanned.value,
@@ -1058,7 +1057,10 @@
pub fn string_to_expr(s: IStr, settings: &ParserSettings) -> Spanned<Expr> {
let len = u32::try_from(s.len()).expect("code size is limited by 4gb");
- Spanned::new(Expr::Str(s), Span(settings.source.clone(), 0, len))
+ Spanned::new(
+ Expr::Trivial(TrivialVal::Str(s)),
+ Span(settings.source.clone(), 0, len),
+ )
}
#[cfg(test)]
crates/jrsonnet-ir-parser/src/snapshots/jrsonnet_ir_parser__tests__basic_math.snapdiffbeforeafterboth--- a/crates/jrsonnet-ir-parser/src/snapshots/jrsonnet_ir_parser__tests__basic_math.snap
+++ b/crates/jrsonnet-ir-parser/src/snapshots/jrsonnet_ir_parser__tests__basic_math.snap
@@ -1,21 +1,28 @@
---
source: crates/jrsonnet-ir-parser/src/lib.rs
+assertion_line: 1094
expression: "format!(\"{v:#?}\")"
---
BinaryOp(
BinaryOp {
- lhs: Num(
- 2.0,
+ lhs: Trivial(
+ Num(
+ 2.0,
+ ),
),
op: Add,
rhs: BinaryOp(
BinaryOp {
- lhs: Num(
- 2.0,
+ lhs: Trivial(
+ Num(
+ 2.0,
+ ),
),
op: Mul,
- rhs: Num(
- 2.0,
+ rhs: Trivial(
+ Num(
+ 2.0,
+ ),
),
},
),
crates/jrsonnet-ir-parser/src/snapshots/jrsonnet_ir_parser__tests__basic_test.snapdiffbeforeafterboth--- a/crates/jrsonnet-ir-parser/src/snapshots/jrsonnet_ir_parser__tests__basic_test.snap
+++ b/crates/jrsonnet-ir-parser/src/snapshots/jrsonnet_ir_parser__tests__basic_test.snap
@@ -1,35 +1,40 @@
---
source: crates/jrsonnet-ir-parser/src/lib.rs
+assertion_line: 1082
expression: "format!(\"{v:#?}\")"
---
AssertExpr(
AssertExpr {
assert: AssertStmt {
assertion: Index {
- indexable: Literal(
- virtual:<test>:7-11,
- True,
+ indexable: Trivial(
+ Bool(
+ true,
+ ),
),
parts: [
IndexPart {
span: virtual:<test>:12-17,
- value: Literal(
- virtual:<test>:12-17,
- False,
+ value: Trivial(
+ Bool(
+ false,
+ ),
),
},
],
} from virtual:<test>:7-18,
message: Some(
- Literal(
- virtual:<test>:21-26,
- False,
+ Trivial(
+ Bool(
+ false,
+ ),
),
),
},
- rest: Literal(
- virtual:<test>:29-33,
- True,
+ rest: Trivial(
+ Bool(
+ true,
+ ),
),
},
)
crates/jrsonnet-ir-parser/src/snapshots/jrsonnet_ir_parser__tests__error_expr.snapdiffbeforeafterboth--- a/crates/jrsonnet-ir-parser/src/snapshots/jrsonnet_ir_parser__tests__error_expr.snap
+++ b/crates/jrsonnet-ir-parser/src/snapshots/jrsonnet_ir_parser__tests__error_expr.snap
@@ -1,10 +1,13 @@
---
source: crates/jrsonnet-ir-parser/src/lib.rs
+assertion_line: 1161
expression: "format!(\"{v:#?}\")"
---
ErrorStmt(
virtual:<test>:0-5,
- Str(
- "bad",
+ Trivial(
+ Str(
+ "bad",
+ ),
),
)
crates/jrsonnet-ir-parser/src/snapshots/jrsonnet_ir_parser__tests__function_and_call.snapdiffbeforeafterboth--- a/crates/jrsonnet-ir-parser/src/snapshots/jrsonnet_ir_parser__tests__function_and_call.snap
+++ b/crates/jrsonnet-ir-parser/src/snapshots/jrsonnet_ir_parser__tests__function_and_call.snap
@@ -1,5 +1,6 @@
---
source: crates/jrsonnet-ir-parser/src/lib.rs
+assertion_line: 1118
expression: "format!(\"{v:#?}\")"
---
LocalExpr(
@@ -19,8 +20,10 @@
"y" from virtual:<test>:11-12,
),
default: Some(
- Num(
- 1.0,
+ Trivial(
+ Num(
+ 1.0,
+ ),
),
),
},
@@ -62,16 +65,20 @@
),
ArgsDesc {
unnamed: [
- Num(
- 2.0,
+ Trivial(
+ Num(
+ 2.0,
+ ),
),
],
names: [
"y",
],
values: [
- Num(
- 3.0,
+ Trivial(
+ Num(
+ 3.0,
+ ),
),
],
} from virtual:<test>:26-34,
crates/jrsonnet-ir-parser/src/snapshots/jrsonnet_ir_parser__tests__if_then_else.snapdiffbeforeafterboth--- a/crates/jrsonnet-ir-parser/src/snapshots/jrsonnet_ir_parser__tests__if_then_else.snap
+++ b/crates/jrsonnet-ir-parser/src/snapshots/jrsonnet_ir_parser__tests__if_then_else.snap
@@ -1,22 +1,28 @@
---
source: crates/jrsonnet-ir-parser/src/lib.rs
+assertion_line: 1124
expression: "format!(\"{v:#?}\")"
---
IfElse(
IfElse {
cond: IfSpecData {
span: virtual:<test>:0-2,
- cond: Literal(
- virtual:<test>:3-7,
- True,
+ cond: Trivial(
+ Bool(
+ true,
+ ),
),
},
- cond_then: Num(
- 1.0,
+ cond_then: Trivial(
+ Num(
+ 1.0,
+ ),
),
cond_else: Some(
- Num(
- 2.0,
+ Trivial(
+ Num(
+ 2.0,
+ ),
),
),
},
crates/jrsonnet-ir-parser/src/snapshots/jrsonnet_ir_parser__tests__imports.snapdiffbeforeafterboth--- a/crates/jrsonnet-ir-parser/src/snapshots/jrsonnet_ir_parser__tests__imports.snap
+++ b/crates/jrsonnet-ir-parser/src/snapshots/jrsonnet_ir_parser__tests__imports.snap
@@ -1,25 +1,32 @@
---
source: crates/jrsonnet-ir-parser/src/lib.rs
+assertion_line: 1130
expression: "format!(\"{v:#?}\")"
---
Arr(
[
Import(
Normal from virtual:<test>:1-7,
- Str(
- "a",
+ Trivial(
+ Str(
+ "a",
+ ),
),
),
Import(
Str from virtual:<test>:13-22,
- Str(
- "b",
+ Trivial(
+ Str(
+ "b",
+ ),
),
),
Import(
Bin from virtual:<test>:28-37,
- Str(
- "c",
+ Trivial(
+ Str(
+ "c",
+ ),
),
),
],
crates/jrsonnet-ir-parser/src/snapshots/jrsonnet_ir_parser__tests__index_and_suffix.snapdiffbeforeafterboth--- a/crates/jrsonnet-ir-parser/src/snapshots/jrsonnet_ir_parser__tests__index_and_suffix.snap
+++ b/crates/jrsonnet-ir-parser/src/snapshots/jrsonnet_ir_parser__tests__index_and_suffix.snap
@@ -1,5 +1,6 @@
---
source: crates/jrsonnet-ir-parser/src/lib.rs
+assertion_line: 1143
expression: "format!(\"{v:#?}\")"
---
Index {
@@ -11,16 +12,20 @@
parts: [
IndexPart {
span: virtual:<test>:4-8,
- value: Str(
- "test",
+ value: Trivial(
+ Str(
+ "test",
+ ),
),
},
],
},
ArgsDesc {
unnamed: [
- Num(
- 2.0,
+ Trivial(
+ Num(
+ 2.0,
+ ),
),
],
names: [],
@@ -31,14 +36,18 @@
parts: [
IndexPart {
span: virtual:<test>:12-17,
- value: Str(
- "field",
+ value: Trivial(
+ Str(
+ "field",
+ ),
),
},
IndexPart {
span: virtual:<test>:18-19,
- value: Num(
- 0.0,
+ value: Trivial(
+ Num(
+ 0.0,
+ ),
),
},
],
crates/jrsonnet-ir-parser/src/snapshots/jrsonnet_ir_parser__tests__literals.snapdiffbeforeafterboth--- a/crates/jrsonnet-ir-parser/src/snapshots/jrsonnet_ir_parser__tests__literals.snap
+++ b/crates/jrsonnet-ir-parser/src/snapshots/jrsonnet_ir_parser__tests__literals.snap
@@ -1,30 +1,32 @@
---
source: crates/jrsonnet-ir-parser/src/lib.rs
+assertion_line: 1088
expression: "format!(\"{v:#?}\")"
---
Arr(
[
- Literal(
- virtual:<test>:1-5,
+ Trivial(
Null,
),
- Literal(
- virtual:<test>:7-11,
- True,
+ Trivial(
+ Bool(
+ true,
+ ),
),
- Literal(
- virtual:<test>:13-18,
- False,
+ Trivial(
+ Bool(
+ false,
+ ),
),
- Literal(
+ Identity(
virtual:<test>:20-24,
This,
),
- Literal(
+ Identity(
virtual:<test>:26-31,
Super,
),
- Literal(
+ Identity(
virtual:<test>:33-34,
Dollar,
),
crates/jrsonnet-ir-parser/src/snapshots/jrsonnet_ir_parser__tests__obj_extend.snapdiffbeforeafterboth--- a/crates/jrsonnet-ir-parser/src/snapshots/jrsonnet_ir_parser__tests__obj_extend.snap
+++ b/crates/jrsonnet-ir-parser/src/snapshots/jrsonnet_ir_parser__tests__obj_extend.snap
@@ -1,5 +1,6 @@
---
source: crates/jrsonnet-ir-parser/src/lib.rs
+assertion_line: 1149
expression: "format!(\"{v:#?}\")"
---
ObjExtend(
@@ -24,8 +25,10 @@
plus: false,
params: None,
visibility: Normal,
- value: Num(
- 1.0,
+ value: Trivial(
+ Num(
+ 1.0,
+ ),
),
},
],
crates/jrsonnet-ir-parser/src/snapshots/jrsonnet_ir_parser__tests__object.snapdiffbeforeafterboth--- a/crates/jrsonnet-ir-parser/src/snapshots/jrsonnet_ir_parser__tests__object.snap
+++ b/crates/jrsonnet-ir-parser/src/snapshots/jrsonnet_ir_parser__tests__object.snap
@@ -1,5 +1,6 @@
---
source: crates/jrsonnet-ir-parser/src/lib.rs
+assertion_line: 1112
expression: "format!(\"{v:#?}\")"
---
Obj(
@@ -15,8 +16,10 @@
plus: false,
params: None,
visibility: Normal,
- value: Num(
- 1.0,
+ value: Trivial(
+ Num(
+ 1.0,
+ ),
),
},
FieldMember {
@@ -26,8 +29,10 @@
plus: false,
params: None,
visibility: Hidden,
- value: Num(
- 2.0,
+ value: Trivial(
+ Num(
+ 2.0,
+ ),
),
},
FieldMember {
@@ -37,8 +42,10 @@
plus: false,
params: None,
visibility: Unhide,
- value: Num(
- 3.0,
+ value: Trivial(
+ Num(
+ 3.0,
+ ),
),
},
],
crates/jrsonnet-ir-parser/src/snapshots/jrsonnet_ir_parser__tests__peg_snapshots@array_comp.jsonnet.snapdiffbeforeafterboth--- a/crates/jrsonnet-ir-parser/src/snapshots/jrsonnet_ir_parser__tests__peg_snapshots@array_comp.jsonnet.snap
+++ b/crates/jrsonnet-ir-parser/src/snapshots/jrsonnet_ir_parser__tests__peg_snapshots@array_comp.jsonnet.snap
@@ -1,5 +1,6 @@
---
source: crates/jrsonnet-ir-parser/src/lib.rs
+assertion_line: 1184
expression: v
input_file: crates/jrsonnet-peg-parser/src/tests/array_comp.jsonnet
---
@@ -14,8 +15,10 @@
parts: [
IndexPart {
span: virtual:<test>:7-15,
- value: Str(
- "deepJoin",
+ value: Trivial(
+ Str(
+ "deepJoin",
+ ),
),
},
],
crates/jrsonnet-ir-parser/src/snapshots/jrsonnet_ir_parser__tests__peg_snapshots@basic_math.jsonnet.snapdiffbeforeafterboth--- a/crates/jrsonnet-ir-parser/src/snapshots/jrsonnet_ir_parser__tests__peg_snapshots@basic_math.jsonnet.snap
+++ b/crates/jrsonnet-ir-parser/src/snapshots/jrsonnet_ir_parser__tests__peg_snapshots@basic_math.jsonnet.snap
@@ -1,5 +1,6 @@
---
source: crates/jrsonnet-ir-parser/src/lib.rs
+assertion_line: 1184
expression: v
input_file: crates/jrsonnet-peg-parser/src/tests/basic_math.jsonnet
---
@@ -7,18 +8,24 @@
[
BinaryOp(
BinaryOp {
- lhs: Num(
- 2.0,
+ lhs: Trivial(
+ Num(
+ 2.0,
+ ),
),
op: Add,
rhs: BinaryOp(
BinaryOp {
- lhs: Num(
- 2.0,
+ lhs: Trivial(
+ Num(
+ 2.0,
+ ),
),
op: Mul,
- rhs: Num(
- 2.0,
+ rhs: Trivial(
+ Num(
+ 2.0,
+ ),
),
},
),
@@ -26,18 +33,24 @@
),
BinaryOp(
BinaryOp {
- lhs: Num(
- 2.0,
+ lhs: Trivial(
+ Num(
+ 2.0,
+ ),
),
op: Add,
rhs: BinaryOp(
BinaryOp {
- lhs: Num(
- 2.0,
+ lhs: Trivial(
+ Num(
+ 2.0,
+ ),
),
op: Mul,
- rhs: Num(
- 2.0,
+ rhs: Trivial(
+ Num(
+ 2.0,
+ ),
),
},
),
@@ -47,24 +60,32 @@
BinaryOp {
lhs: BinaryOp(
BinaryOp {
- lhs: Num(
- 2.0,
+ lhs: Trivial(
+ Num(
+ 2.0,
+ ),
),
op: Add,
- rhs: Num(
- 2.0,
+ rhs: Trivial(
+ Num(
+ 2.0,
+ ),
),
},
),
op: Add,
rhs: BinaryOp(
BinaryOp {
- lhs: Num(
- 2.0,
+ lhs: Trivial(
+ Num(
+ 2.0,
+ ),
),
op: Mul,
- rhs: Num(
- 2.0,
+ rhs: Trivial(
+ Num(
+ 2.0,
+ ),
),
},
),
@@ -72,24 +93,32 @@
),
BinaryOp(
BinaryOp {
- lhs: Num(
- 2.0,
+ lhs: Trivial(
+ Num(
+ 2.0,
+ ),
),
op: Add,
rhs: BinaryOp(
BinaryOp {
- lhs: Num(
- 2.0,
+ lhs: Trivial(
+ Num(
+ 2.0,
+ ),
),
op: Add,
rhs: BinaryOp(
BinaryOp {
- lhs: Num(
- 2.0,
+ lhs: Trivial(
+ Num(
+ 2.0,
+ ),
),
op: Mul,
- rhs: Num(
- 2.0,
+ rhs: Trivial(
+ Num(
+ 2.0,
+ ),
),
},
),
@@ -99,18 +128,24 @@
),
BinaryOp(
BinaryOp {
- lhs: Num(
- 2.0,
+ lhs: Trivial(
+ Num(
+ 2.0,
+ ),
),
op: Add,
rhs: BinaryOp(
BinaryOp {
- lhs: Num(
- 3.0,
+ lhs: Trivial(
+ Num(
+ 3.0,
+ ),
),
op: Mul,
- rhs: Num(
- 4.0,
+ rhs: Trivial(
+ Num(
+ 4.0,
+ ),
),
},
),
crates/jrsonnet-ir-parser/src/snapshots/jrsonnet_ir_parser__tests__peg_snapshots@comment_eof.jsonnet.snapdiffbeforeafterboth--- a/crates/jrsonnet-ir-parser/src/snapshots/jrsonnet_ir_parser__tests__peg_snapshots@comment_eof.jsonnet.snap
+++ b/crates/jrsonnet-ir-parser/src/snapshots/jrsonnet_ir_parser__tests__peg_snapshots@comment_eof.jsonnet.snap
@@ -1,5 +1,6 @@
---
source: crates/jrsonnet-ir-parser/src/lib.rs
+assertion_line: 1184
expression: v
input_file: crates/jrsonnet-peg-parser/src/tests/comment_eof.jsonnet
---
@@ -16,8 +17,10 @@
plus: false,
params: None,
visibility: Normal,
- value: Num(
- 1.0,
+ value: Trivial(
+ Num(
+ 1.0,
+ ),
),
},
],
crates/jrsonnet-ir-parser/src/snapshots/jrsonnet_ir_parser__tests__peg_snapshots@default_nondefault.jsonnet.snapdiffbeforeafterboth--- a/crates/jrsonnet-ir-parser/src/snapshots/jrsonnet_ir_parser__tests__peg_snapshots@default_nondefault.jsonnet.snap
+++ b/crates/jrsonnet-ir-parser/src/snapshots/jrsonnet_ir_parser__tests__peg_snapshots@default_nondefault.jsonnet.snap
@@ -1,5 +1,6 @@
---
source: crates/jrsonnet-ir-parser/src/lib.rs
+assertion_line: 1184
expression: v
input_file: crates/jrsonnet-peg-parser/src/tests/default_nondefault.jsonnet
---
@@ -14,8 +15,10 @@
"foo" from virtual:<test>:8-11,
),
default: Some(
- Str(
- "foo",
+ Trivial(
+ Str(
+ "foo",
+ ),
),
),
},
@@ -44,14 +47,12 @@
),
binds_len: 2,
},
- value: Literal(
- virtual:<test>:28-32,
+ value: Trivial(
Null,
),
},
],
- Literal(
- virtual:<test>:34-38,
+ Trivial(
Null,
),
)
crates/jrsonnet-ir-parser/src/snapshots/jrsonnet_ir_parser__tests__peg_snapshots@imports.jsonnet.snapdiffbeforeafterboth--- a/crates/jrsonnet-ir-parser/src/snapshots/jrsonnet_ir_parser__tests__peg_snapshots@imports.jsonnet.snap
+++ b/crates/jrsonnet-ir-parser/src/snapshots/jrsonnet_ir_parser__tests__peg_snapshots@imports.jsonnet.snap
@@ -1,5 +1,6 @@
---
source: crates/jrsonnet-ir-parser/src/lib.rs
+assertion_line: 1184
expression: v
input_file: crates/jrsonnet-peg-parser/src/tests/imports.jsonnet
---
@@ -7,20 +8,26 @@
[
Import(
Normal from virtual:<test>:2-8,
- Str(
- "hello",
+ Trivial(
+ Str(
+ "hello",
+ ),
),
),
Import(
Str from virtual:<test>:18-27,
- Str(
- "garnish.txt",
+ Trivial(
+ Str(
+ "garnish.txt",
+ ),
),
),
Import(
Bin from virtual:<test>:43-52,
- Str(
- "garnish.bin",
+ Trivial(
+ Str(
+ "garnish.bin",
+ ),
),
),
],
crates/jrsonnet-ir-parser/src/snapshots/jrsonnet_ir_parser__tests__peg_snapshots@multiline.jsonnet.snapdiffbeforeafterboth--- a/crates/jrsonnet-ir-parser/src/snapshots/jrsonnet_ir_parser__tests__peg_snapshots@multiline.jsonnet.snap
+++ b/crates/jrsonnet-ir-parser/src/snapshots/jrsonnet_ir_parser__tests__peg_snapshots@multiline.jsonnet.snap
@@ -1,21 +1,30 @@
---
source: crates/jrsonnet-ir-parser/src/lib.rs
+assertion_line: 1184
expression: v
input_file: crates/jrsonnet-peg-parser/src/tests/multiline.jsonnet
---
Arr(
[
- Str(
- "Hello world!\na\n",
+ Trivial(
+ Str(
+ "Hello world!\na\n",
+ ),
),
- Str(
- "Hello world!\na\n",
+ Trivial(
+ Str(
+ "Hello world!\na\n",
+ ),
),
- Str(
- "Hello world!\n\ta\n",
+ Trivial(
+ Str(
+ "Hello world!\n\ta\n",
+ ),
),
- Str(
- "Hello world!\n a\n",
+ Trivial(
+ Str(
+ "Hello world!\n a\n",
+ ),
),
],
)
crates/jrsonnet-ir-parser/src/snapshots/jrsonnet_ir_parser__tests__peg_snapshots@reserved.jsonnet.snapdiffbeforeafterboth--- a/crates/jrsonnet-ir-parser/src/snapshots/jrsonnet_ir_parser__tests__peg_snapshots@reserved.jsonnet.snap
+++ b/crates/jrsonnet-ir-parser/src/snapshots/jrsonnet_ir_parser__tests__peg_snapshots@reserved.jsonnet.snap
@@ -1,12 +1,12 @@
---
source: crates/jrsonnet-ir-parser/src/lib.rs
+assertion_line: 1184
expression: v
input_file: crates/jrsonnet-peg-parser/src/tests/reserved.jsonnet
---
Arr(
[
- Literal(
- virtual:<test>:2-6,
+ Trivial(
Null,
),
Var(
crates/jrsonnet-ir-parser/src/snapshots/jrsonnet_ir_parser__tests__peg_snapshots@slice.jsonnet.snapdiffbeforeafterboth--- a/crates/jrsonnet-ir-parser/src/snapshots/jrsonnet_ir_parser__tests__peg_snapshots@slice.jsonnet.snap
+++ b/crates/jrsonnet-ir-parser/src/snapshots/jrsonnet_ir_parser__tests__peg_snapshots@slice.jsonnet.snap
@@ -1,5 +1,6 @@
---
source: crates/jrsonnet-ir-parser/src/lib.rs
+assertion_line: 1184
expression: v
input_file: crates/jrsonnet-peg-parser/src/tests/slice.jsonnet
---
@@ -12,8 +13,10 @@
),
slice: SliceDesc {
start: Some(
- Num(
- 1.0,
+ Trivial(
+ Num(
+ 1.0,
+ ),
) from virtual:<test>:4-5,
),
end: None,
@@ -28,8 +31,10 @@
),
slice: SliceDesc {
start: Some(
- Num(
- 1.0,
+ Trivial(
+ Num(
+ 1.0,
+ ),
) from virtual:<test>:11-12,
),
end: None,
@@ -45,8 +50,10 @@
slice: SliceDesc {
start: None,
end: Some(
- Num(
- 1.0,
+ Trivial(
+ Num(
+ 1.0,
+ ),
) from virtual:<test>:20-21,
),
step: None,
@@ -62,8 +69,10 @@
start: None,
end: None,
step: Some(
- Num(
- 1.0,
+ Trivial(
+ Num(
+ 1.0,
+ ),
) from virtual:<test>:29-30,
),
},
@@ -83,8 +92,10 @@
"len" from virtual:<test>:38-41,
),
op: Sub,
- rhs: Num(
- 1.0,
+ rhs: Trivial(
+ Num(
+ 1.0,
+ ),
),
},
) from virtual:<test>:38-45,
crates/jrsonnet-ir-parser/src/snapshots/jrsonnet_ir_parser__tests__peg_snapshots@string_escaping.jsonnet.snapdiffbeforeafterboth--- a/crates/jrsonnet-ir-parser/src/snapshots/jrsonnet_ir_parser__tests__peg_snapshots@string_escaping.jsonnet.snap
+++ b/crates/jrsonnet-ir-parser/src/snapshots/jrsonnet_ir_parser__tests__peg_snapshots@string_escaping.jsonnet.snap
@@ -1,24 +1,35 @@
---
source: crates/jrsonnet-ir-parser/src/lib.rs
+assertion_line: 1184
expression: v
input_file: crates/jrsonnet-peg-parser/src/tests/string_escaping.jsonnet
---
Arr(
[
- Str(
- "Hello, \"world\"!",
+ Trivial(
+ Str(
+ "Hello, \"world\"!",
+ ),
),
- Str(
- "Hello 'world'!",
+ Trivial(
+ Str(
+ "Hello 'world'!",
+ ),
),
- Str(
- "\\\\",
+ Trivial(
+ Str(
+ "\\\\",
+ ),
),
- Str(
- "Hello\nWorld",
+ Trivial(
+ Str(
+ "Hello\nWorld",
+ ),
),
- Str(
- "Hello\\n\"World\"",
+ Trivial(
+ Str(
+ "Hello\\n\"World\"",
+ ),
),
],
)
crates/jrsonnet-ir-parser/src/snapshots/jrsonnet_ir_parser__tests__peg_snapshots@subexp.jsonnet.snapdiffbeforeafterboth--- a/crates/jrsonnet-ir-parser/src/snapshots/jrsonnet_ir_parser__tests__peg_snapshots@subexp.jsonnet.snap
+++ b/crates/jrsonnet-ir-parser/src/snapshots/jrsonnet_ir_parser__tests__peg_snapshots@subexp.jsonnet.snap
@@ -1,5 +1,6 @@
---
source: crates/jrsonnet-ir-parser/src/lib.rs
+assertion_line: 1184
expression: v
input_file: crates/jrsonnet-peg-parser/src/tests/subexp.jsonnet
---
@@ -22,8 +23,10 @@
into: Full(
"x" from virtual:<test>:11-12,
),
- value: Num(
- 1.0,
+ value: Trivial(
+ Num(
+ 1.0,
+ ),
),
},
],
crates/jrsonnet-ir-parser/src/snapshots/jrsonnet_ir_parser__tests__peg_snapshots@suffix.jsonnet.snapdiffbeforeafterboth--- a/crates/jrsonnet-ir-parser/src/snapshots/jrsonnet_ir_parser__tests__peg_snapshots@suffix.jsonnet.snap
+++ b/crates/jrsonnet-ir-parser/src/snapshots/jrsonnet_ir_parser__tests__peg_snapshots@suffix.jsonnet.snap
@@ -1,5 +1,6 @@
---
source: crates/jrsonnet-ir-parser/src/lib.rs
+assertion_line: 1184
expression: v
input_file: crates/jrsonnet-peg-parser/src/tests/suffix.jsonnet
---
@@ -12,8 +13,10 @@
parts: [
IndexPart {
span: virtual:<test>:6-10,
- value: Str(
- "test",
+ value: Trivial(
+ Str(
+ "test",
+ ),
),
},
],
@@ -24,8 +27,10 @@
),
ArgsDesc {
unnamed: [
- Num(
- 2.0,
+ Trivial(
+ Num(
+ 2.0,
+ ),
),
],
names: [],
@@ -41,16 +46,20 @@
parts: [
IndexPart {
span: virtual:<test>:24-28,
- value: Str(
- "test",
+ value: Trivial(
+ Str(
+ "test",
+ ),
),
},
],
},
ArgsDesc {
unnamed: [
- Num(
- 2.0,
+ Trivial(
+ Num(
+ 2.0,
+ ),
),
],
names: [],
crates/jrsonnet-ir-parser/src/snapshots/jrsonnet_ir_parser__tests__slice.snapdiffbeforeafterboth--- a/crates/jrsonnet-ir-parser/src/snapshots/jrsonnet_ir_parser__tests__slice.snap
+++ b/crates/jrsonnet-ir-parser/src/snapshots/jrsonnet_ir_parser__tests__slice.snap
@@ -1,5 +1,6 @@
---
source: crates/jrsonnet-ir-parser/src/lib.rs
+assertion_line: 1167
expression: "format!(\"{v:#?}\")"
---
Arr(
@@ -11,8 +12,10 @@
),
slice: SliceDesc {
start: Some(
- Num(
- 1.0,
+ Trivial(
+ Num(
+ 1.0,
+ ),
) from virtual:<test>:3-4,
),
end: None,
@@ -27,8 +30,10 @@
),
slice: SliceDesc {
start: Some(
- Num(
- 1.0,
+ Trivial(
+ Num(
+ 1.0,
+ ),
) from virtual:<test>:10-11,
),
end: None,
@@ -44,8 +49,10 @@
slice: SliceDesc {
start: None,
end: Some(
- Num(
- 1.0,
+ Trivial(
+ Num(
+ 1.0,
+ ),
) from virtual:<test>:19-20,
),
step: None,
@@ -61,8 +68,10 @@
start: None,
end: None,
step: Some(
- Num(
- 1.0,
+ Trivial(
+ Num(
+ 1.0,
+ ),
) from virtual:<test>:28-29,
),
},
crates/jrsonnet-ir-parser/src/snapshots/jrsonnet_ir_parser__tests__strings.snapdiffbeforeafterboth--- a/crates/jrsonnet-ir-parser/src/snapshots/jrsonnet_ir_parser__tests__strings.snap
+++ b/crates/jrsonnet-ir-parser/src/snapshots/jrsonnet_ir_parser__tests__strings.snap
@@ -1,20 +1,29 @@
---
source: crates/jrsonnet-ir-parser/src/lib.rs
+assertion_line: 1106
expression: "format!(\"{v:#?}\")"
---
Arr(
[
- Str(
- "hello",
+ Trivial(
+ Str(
+ "hello",
+ ),
),
- Str(
- "world",
+ Trivial(
+ Str(
+ "world",
+ ),
),
- Str(
- "raw\"str",
+ Trivial(
+ Str(
+ "raw\"str",
+ ),
),
- Str(
- "raw'str",
+ Trivial(
+ Str(
+ "raw'str",
+ ),
),
],
)
crates/jrsonnet-ir-parser/src/snapshots/jrsonnet_ir_parser__tests__underscore_numbers.snapdiffbeforeafterboth--- a/crates/jrsonnet-ir-parser/src/snapshots/jrsonnet_ir_parser__tests__underscore_numbers.snap
+++ b/crates/jrsonnet-ir-parser/src/snapshots/jrsonnet_ir_parser__tests__underscore_numbers.snap
@@ -1,17 +1,24 @@
---
source: crates/jrsonnet-ir-parser/src/lib.rs
+assertion_line: 1100
expression: "format!(\"{v:#?}\")"
---
Arr(
[
- Num(
- 1000.0,
+ Trivial(
+ Num(
+ 1000.0,
+ ),
),
- Num(
- 1000.0001,
+ Trivial(
+ Num(
+ 1000.0001,
+ ),
),
- Num(
- 100000000000.0,
+ Trivial(
+ Num(
+ 100000000000.0,
+ ),
),
],
)
crates/jrsonnet-ir/src/expr.rsdiffbeforeafterboth--- a/crates/jrsonnet-ir/src/expr.rs
+++ b/crates/jrsonnet-ir/src/expr.rs
@@ -31,6 +31,14 @@
Unhide,
}
+#[derive(Debug, Clone, PartialEq, Acyclic)]
+pub enum TrivialVal {
+ Null,
+ Bool(bool),
+ Num(NumValue),
+ Str(IStr),
+}
+
impl Visibility {
pub fn is_visible(&self) -> bool {
matches!(self, Self::Normal | Self::Unhide)
@@ -351,14 +359,12 @@
ObjComp(ObjComp),
}
-#[derive(Debug, PartialEq, Eq, Clone, Copy, Acyclic)]
-pub enum LiteralType {
+/// Object identity reference: `self`, `super`, or `$`.#[derive(Debug, PartialEq, Eq, Clone, Copy, Acyclic)]
+#[derive(Debug, PartialEq, Acyclic)]
+pub enum IdentityKind {
This,
Super,
Dollar,
- Null,
- True,
- False,
}
#[derive(Debug, PartialEq, Acyclic)]
@@ -404,12 +410,12 @@
/// Syntax base
#[derive(Debug, PartialEq, Acyclic)]
pub enum Expr {
- Literal(Span, LiteralType),
+ /// Object-identity reference: `self`, `super`, `$`.
+ Identity(Span, IdentityKind),
+
+ /// Trivial value literal
+ Trivial(TrivialVal),
- /// String value: "hello"
- Str(IStr),
- /// Number: 1, 2.0, 2e+20
- Num(NumValue),
/// Variable name: test
Var(Spanned<IStr>),
crates/jrsonnet-ir/src/visit.rsdiffbeforeafterboth--- a/crates/jrsonnet-ir/src/visit.rs
+++ b/crates/jrsonnet-ir/src/visit.rs
@@ -5,7 +5,7 @@
use crate::{
ArgsDesc, AssertExpr, AssertStmt, BinaryOp, BindSpec, CompSpec, Destruct, Expr, ExprParam,
ExprParams, FieldMember, FieldName, ForSpecData, IfElse, IfSpecData, ImportKind, IndexPart,
- ObjBody, ObjComp, ObjMembers, Slice, SliceDesc,
+ ObjBody, ObjComp, ObjMembers, Slice, SliceDesc, TrivialVal,
};
pub trait Visitor: Sized {
@@ -178,9 +178,8 @@
}
pub fn visit_expr<V: Visitor>(v: &mut V, e: &Expr) {
match e {
- Expr::Literal(_span, _literal_type) => {}
- Expr::Str(_istr) => {}
- Expr::Num(_num) => {}
+ Expr::Identity(_span, _identity_kind) => {}
+ Expr::Trivial(_) => {}
Expr::Var(_spanned) => {}
Expr::Arr(exprs) => {
for e in &**exprs {
@@ -220,7 +219,7 @@
Expr::Import(kind, expr) => {
v.visit_expr(expr);
- if let Expr::Str(expr) = &**expr {
+ if let Expr::Trivial(TrivialVal::Str(expr)) = &**expr {
v.visit_import(matches!(**kind, ImportKind::Normal), expr.clone());
}
}
crates/jrsonnet-peg-parser/src/lib.rsdiffbeforeafterboth1use jrsonnet_gcmodule::Acyclic;2use jrsonnet_ir::{3 ArgsDesc, AssertExpr, AssertStmt, BinaryOp, BindSpec, CompSpec, Destruct, DestructRest, Expr,4 ExprParam, ExprParams, FieldMember, FieldName, ForSpecData, IStr, IfElse, IfSpecData,5 ImportKind, IndexPart, LiteralType, Member, NumValue, ObjBody, ObjComp, ObjMembers, Slice,6 SliceDesc, Source, Span, Spanned, Visibility, unescape,7};8use peg::parser;910pub struct ParserSettings {11 pub source: Source,12}1314macro_rules! expr_bin {15 ($a:ident $op:ident $b:ident) => {16 Expr::BinaryOp(Box::new(BinaryOp {17 lhs: $a,18 op: $op,19 rhs: $b,20 }))21 };22}23macro_rules! expr_un {24 ($op:ident $a:ident) => {25 Expr::UnaryOp($op, Box::new($a))26 };27}2829parser! {30 pub grammar jsonnet_parser() for str {31 use peg::ParseLiteral;3233 rule eof() = quiet!{![_]} / expected!("<eof>")34 rule eol() = "\n" / eof()3536 /// Standard C-like comments37 rule comment()38 = "//" (!eol()[_])* eol()39 / "/*" (!("*/")[_])* "*/"40 / "#" (!eol()[_])* eol()4142 rule single_whitespace() = quiet!{([' ' | '\r' | '\n' | '\t'] / comment())} / expected!("<whitespace>")43 rule _() = quiet!{([' ' | '\r' | '\n' | '\t']+) / comment()}* / expected!("<whitespace>")4445 /// For comma-delimited elements46 rule comma() = quiet!{_ "," _} / expected!("<comma>")47 rule alpha() -> char = c:$(['_' | 'a'..='z' | 'A'..='Z']) {c.chars().next().unwrap()}48 rule digit() -> char = d:$(['0'..='9']) {d.chars().next().unwrap()}49 rule end_of_ident() = !['0'..='9' | '_' | 'a'..='z' | 'A'..='Z']50 /// Sequence of digits51 rule uint_str() -> &'input str = a:$(digit()+ ("_" digit()+)*) { a }52 /// Number in scientific notation format53 rule number() -> f64 = quiet!{a:$(uint_str() ("." uint_str())? (['e'|'E'] (s:['+'|'-'])? uint_str())?) {? a.replace('_',"").parse().map_err(|_| "<number>") }} / expected!("<number>")5455 /// Reserved word followed by any non-alphanumberic56 rule reserved() = ("assert" / "else" / "error" / "false" / "for" / "function" / "if" / "import" / "importstr" / "importbin" / "in" / "local" / "null" / "tailstrict" / "then" / "self" / "super" / "true") end_of_ident()57 rule id() -> IStr = v:$(quiet!{ !reserved() alpha() (alpha() / digit())*} / expected!("<identifier>")) { v.into() }5859 rule keyword(id: &'static str) -> ()60 = #{|input, pos| input.parse_string_literal(pos, id)} end_of_ident()6162 pub rule param(s: &ParserSettings) -> ExprParam = destruct:destruct(s) default:(_ "=" _ default:expr(s){default})? { ExprParam { destruct, default } }63 pub rule params(s: &ParserSettings) -> ExprParams64 = params:param(s) ** comma() comma()? { ExprParams::new(params) }65 / { ExprParams::new(Vec::new()) }6667 pub rule arg(s: &ParserSettings) -> (Option<IStr>, Expr)68 = name:(quiet! { (s:id() _ "=" !['='] _ {s})? } / expected!("<argument name>")) expr:expr(s) {(name, expr)}6970 pub rule args(s: &ParserSettings) -> ArgsDesc71 = args:arg(s)**comma() comma()? {?72 let unnamed_count = args.iter().take_while(|(n, _)| n.is_none()).count();73 let mut unnamed = Vec::with_capacity(unnamed_count);74 let mut names = Vec::with_capacity(args.len() - unnamed_count);75 let mut values = Vec::with_capacity(args.len() - unnamed_count);76 let mut named_started = false;77 for (name, value) in args {78 if let Some(name) = name {79 named_started = true;80 names.push(name);81 values.push(value);82 } else {83 if named_started {84 return Err("<named argument>")85 }86 unnamed.push(value);87 }88 }89 Ok(ArgsDesc{unnamed, names, values})90 }9192 pub rule destruct_rest() -> DestructRest93 = "..." into:(_ into:id() {into})? {into.map_or_else(|| DestructRest::Drop, DestructRest::Keep)}94 pub rule destruct_array(s: &ParserSettings) -> Destruct95 = "[" _ start:destruct(s)**comma() rest:(96 comma() _ rest:destruct_rest()? end:(97 comma() end:destruct(s)**comma() (_ comma())? {end}98 / comma()? {Vec::new()}99 ) {(rest, end)}100 / comma()? {(None, Vec::new())}101 ) _ "]" {?102 #[cfg(feature = "exp-destruct")] return Ok(Destruct::Array {103 start,104 rest: rest.0,105 end: rest.1,106 });107 #[cfg(not(feature = "exp-destruct"))] Err("!!!experimental destructuring was not enabled")108 }109 pub rule destruct_object(s: &ParserSettings) -> Destruct110 = "{" _111 fields:(name:id() into:(_ ":" _ into:destruct(s) {into})? default:(_ "=" _ v:spanned(<expr(s)>, s) {v})? {(name, into, default)})**comma()112 rest:(113 comma() rest:destruct_rest()? {rest}114 / comma()? {None}115 )116 _ "}" {?117 #[cfg(feature = "exp-destruct")] return Ok(Destruct::Object {118 fields,119 rest,120 });121 #[cfg(not(feature = "exp-destruct"))] Err("!!!experimental destructuring was not enabled")122 }123 pub rule destruct(s: &ParserSettings) -> Destruct124 = v:spanned(<id()>, s) {Destruct::Full(v)}125 / "?" {?126 #[cfg(feature = "exp-destruct")] return Ok(Destruct::Skip);127 #[cfg(not(feature = "exp-destruct"))] Err("!!!experimental destructuring was not enabled")128 }129 / arr:destruct_array(s) {arr}130 / obj:destruct_object(s) {obj}131132 pub rule bind(s: &ParserSettings) -> BindSpec133 = into:destruct(s) _ "=" _ value:expr(s) {BindSpec::Field{into, value}}134 / name:spanned(<id()>, s) _ "(" _ params:params(s) _ ")" _ "=" _ value:expr(s) {BindSpec::Function{name, params, value}}135136 pub rule assertion(s: &ParserSettings) -> AssertStmt137 = keyword("assert") _ assertion:spanned(<expr(s)>, s) message:(_ ":" _ e:expr(s) {e})? { AssertStmt{assertion, message} }138139 pub rule whole_line() -> &'input str140 = str:$((!['\n'][_])* "\n") {str}141 pub rule string_block() -> String142 = "|||" chomped:"-"? (!['\n']single_whitespace())* "\n"143 empty_lines:$(['\n']*)144 prefix:[' ' | '\t']+ first_line:whole_line()145 lines:("\n" {"\n"} / [' ' | '\t']*<{prefix.len()}> s:whole_line() {s})*146 [' ' | '\t']*<, {prefix.len() - 1}> "|||"147 {148 let mut l = empty_lines.to_owned();149 l.push_str(first_line);150 l.extend(lines);151 if chomped.is_some() {152 debug_assert!(l.ends_with('\n'));153 l.truncate(l.len() - 1);154 }155 l156 }157158 rule hex_char()159 = quiet! { ['0'..='9' | 'a'..='f' | 'A'..='F'] } / expected!("<hex char>")160161 rule string_char(c: rule<()>)162 = (!['\\']!c()[_])+163 / "\\\\"164 / "\\u" hex_char() hex_char() hex_char() hex_char()165 / "\\x" hex_char() hex_char()166 / ['\\'] (quiet! { ['b' | 'f' | 'n' | 'r' | 't' | '"' | '\''] } / expected!("<escape character>"))167 pub rule string() -> String168 = ['"'] str:$(string_char(<"\"">)*) ['"'] {? unescape::unescape(str).ok_or("<escaped string>")}169 / ['\''] str:$(string_char(<"\'">)*) ['\''] {? unescape::unescape(str).ok_or("<escaped string>")}170 / quiet!{ "@'" str:$(("''" / (!['\''][_]))*) "'" {str.replace("''", "'")}171 / "@\"" str:$(("\"\"" / (!['"'][_]))*) "\"" {str.replace("\"\"", "\"")}172 / string_block() } / expected!("<string>")173174 pub rule field_name(s: &ParserSettings) -> FieldName175 = name:id() {FieldName::Fixed(name)}176 / name:string() {FieldName::Fixed(name.into())}177 / "[" _ expr:expr(s) _ "]" {FieldName::Dyn(expr)}178 pub rule visibility() -> Visibility179 = ":::" {Visibility::Unhide}180 / "::" {Visibility::Hidden}181 / ":" {Visibility::Normal}182 pub rule field(s: &ParserSettings) -> FieldMember183 = name:spanned(<field_name(s)>, s) _ plus:"+"? _ visibility:visibility() _ value:expr(s) {FieldMember{184 name,185 plus: plus.is_some(),186 params: None,187 visibility,188 value,189 }}190 / name:spanned(<field_name(s)>, s) _ "(" _ params:params(s) _ ")" _ visibility:visibility() _ value:expr(s) {FieldMember{191 name,192 plus: false,193 params: Some(params),194 visibility,195 value,196 }}197 pub rule obj_local(s: &ParserSettings) -> BindSpec198 = keyword("local") _ bind:bind(s) {bind}199 pub rule member(s: &ParserSettings) -> Member200 = bind:obj_local(s) {Member::BindStmt(bind)}201 / assertion:assertion(s) {Member::AssertStmt(assertion)}202 / field:field(s) {Member::Field(field)}203 pub rule objinside(s: &ParserSettings) -> ObjBody204 = members:(member(s) ** comma()) comma()? _ compspecs:compspecs(s)? {?205 Ok(if let Some(compspecs) = compspecs {206 let mut locals = Vec::new();207 let mut field = None;208 for member in members {209 match member {210 Member::Field(field_member) => if field.replace(field_member).is_some() {211 return Err("<object comprehension can only contain one field>")212 },213 Member::BindStmt(bind_spec) => locals.push(bind_spec),214 Member::AssertStmt(assert_stmt) => return Err("<asserts are unsupported in object comprehension>"),215 }216 }217 ObjBody::ObjComp(ObjComp {218 locals,219 field: Box::new(field.ok_or("<missing object comprehension field>")?),220 compspecs221 })222 } else {223 let mut locals = Vec::new();224 let mut asserts = Vec::new();225 let mut fields = Vec::new();226 for member in members {227 match member {228 Member::Field(field_member) => fields.push(field_member),229 Member::BindStmt(bind_spec) => locals.push(bind_spec),230 Member::AssertStmt(assert_stmt) => asserts.push(assert_stmt),231 }232 }233 ObjBody::MemberList(ObjMembers {234 locals,235 asserts,236 fields237 })238 })239 }240 pub rule ifspec(s: &ParserSettings) -> IfSpecData241 = i:spanned(<keyword("if")>, s) _ cond:expr(s) {IfSpecData { span: i.span, cond }}242 pub rule forspec(s: &ParserSettings) -> ForSpecData243 = keyword("for") _ destruct:destruct(s) _ keyword("in") _ over:expr(s) { ForSpecData { destruct, over } }244 rule ensure_object_iteration()245 = "" {?246 #[cfg(not(feature = "exp-object-iteration"))] return Err("!!!experimental object iteration was not enabled");247 #[cfg(feature = "exp-object-iteration")] Ok(())248 }249 pub rule forobjspec(s: &ParserSettings) -> CompSpec250 = ensure_object_iteration() keyword("for") _ "[" _ key:id() _ "]" _ vis:visibility() _ value:destruct(s) _ keyword("in") _ over:expr(s) {251 #[cfg(feature = "exp-object-iteration")] return CompSpec::ForObjSpec(jrsonnet_ir::ForObjSpecData { key, visibility: vis, value, over });252 #[cfg(not(feature = "exp-object-iteration"))] unreachable!("ensure_object_iteration will fail if feature is not enabled")253 }254 rule compspec(s: &ParserSettings) -> CompSpec255 = i:ifspec(s) { CompSpec::IfSpec(i) } / f:forobjspec(s) { f } / f:forspec(s) {CompSpec::ForSpec(f)}256 pub rule compspecs(s: &ParserSettings) -> Vec<CompSpec>257 = specs:compspec(s) ++ _ {?258 if matches!(specs[0], CompSpec::IfSpec(_)) {259 return Err("<first compspec should be for>")260 }261 Ok(specs)262 }263 pub rule local_expr(s: &ParserSettings) -> Expr264 = keyword("local") _ binds:bind(s) ** comma() (_ ",")? _ ";" _ expr:expr(s) { Expr::LocalExpr(binds, Box::new(expr)) }265 pub rule string_expr(s: &ParserSettings) -> Expr266 = s:string() {Expr::Str(s.into())}267 pub rule obj_expr(s: &ParserSettings) -> Expr268 = "{" _ body:objinside(s) _ "}" {Expr::Obj(body)}269 pub rule array_expr(s: &ParserSettings) -> Expr270 = "[" _ elems:(expr(s) ** comma()) _ comma()? "]" {Expr::Arr(elems)}271 pub rule array_comp_expr(s: &ParserSettings) -> Expr272 = "[" _ expr:expr(s) _ comma()? _ specs:(r: compspecs(s) _ {r}) "]" {273 Expr::ArrComp(Box::new(expr), specs)274 }275 pub rule number_expr(s: &ParserSettings) -> Expr276 = n:number() {? NumValue::new(n).map_or_else(|| Err("!!!numbers are finite"), |n| Ok(Expr::Num(n)))}277278 rule spanned<T: Acyclic>(x: rule<T>, s: &ParserSettings) -> Spanned<T>279 = a:position!() n:x() b:position!() { Spanned::new(n, Span(s.source.clone(), codeidx(a), codeidx(b))) }280281 pub rule var_expr(s: &ParserSettings) -> Expr282 = n:spanned(<id()>, s) { Expr::Var(n) }283 pub rule id_loc(s: &ParserSettings) -> Spanned<Expr>284 = a:position!() n:id() b:position!() { Spanned::new(Expr::Str(n), Span(s.source.clone(), codeidx(a), codeidx(b))) }285 pub rule if_then_else_expr(s: &ParserSettings) -> Expr286 = cond:ifspec(s) _ keyword("then") _ cond_then:expr(s) cond_else:(_ keyword("else") _ e:expr(s) {e})? {Expr::IfElse(Box::new(IfElse{287 cond,288 cond_then,289 cond_else,290 }))}291292 pub rule literal(s: &ParserSettings) -> Expr293 = a:position!() v:(294 keyword("null") {LiteralType::Null}295 / keyword("true") {LiteralType::True}296 / keyword("false") {LiteralType::False}297 / keyword("self") {LiteralType::This}298 / keyword("$") {LiteralType::Dollar}299 / keyword("super") {LiteralType::Super}300 ) b:position!() {Expr::Literal(Span(s.source.clone(), codeidx(a), codeidx(b)), v)}301302 rule import_kind() -> ImportKind303 = keyword("importstr") { ImportKind::Str }304 / keyword("importbin") { ImportKind::Bin }305 / keyword("import") { ImportKind::Normal }306307 pub rule expr_basic(s: &ParserSettings) -> Expr308 = literal(s)309310 / string_expr(s) / number_expr(s)311 / array_expr(s)312 / obj_expr(s)313 / array_expr(s)314 / array_comp_expr(s)315316 / kind:spanned(<import_kind()>, s) _ path:expr(s) {Expr::Import(kind, Box::new(path))}317318 / var_expr(s)319 / local_expr(s)320 / if_then_else_expr(s)321322 / kw:spanned(<keyword("function")>, s) _ "(" _ params:params(s) _ ")" _ expr:expr(s) {Expr::Function(kw.span, params, Box::new(expr))}323 / assert:assertion(s) _ ";" _ rest:expr(s) { Expr::AssertExpr(Box::new(AssertExpr{324 assert, rest325 })) }326327 / err_kw:spanned(<keyword("error")>, s) _ expr:expr(s) { Expr::ErrorStmt(err_kw.span, Box::new(expr)) }328329 rule slice_part(s: &ParserSettings) -> Option<Spanned<Expr>>330 = _ e:(e:spanned(<expr(s)>, s) _{e})? {e}331 pub rule slice_desc(s: &ParserSettings) -> SliceDesc332 = start:slice_part(s) ":" pair:(end:slice_part(s) step:(":" e:slice_part(s){e})? {(end, step.flatten())})? {333 let (end, step) = if let Some((end, step)) = pair {334 (end, step)335 }else{336 (None, None)337 };338339 SliceDesc { start, end, step }340 }341342 rule binop(x: rule<()>) -> ()343 = quiet!{ x() } / expected!("<binary op>")344 rule unaryop(x: rule<()>) -> ()345 = quiet!{ x() } / expected!("<unary op>")346347 rule ensure_null_coaelse()348 = "" {?349 #[cfg(not(feature = "exp-null-coaelse"))] return Err("!!!experimental null coaelscing was not enabled");350 #[cfg(feature = "exp-null-coaelse")] Ok(())351 }352 use jrsonnet_ir::BinaryOpType::*;353 use jrsonnet_ir::UnaryOpType::*;354 rule expr(s: &ParserSettings) -> Expr355 = precedence! {356 a:(@) _ binop(<"||">) _ b:@ {expr_bin!(a Or b)}357 a:(@) _ binop(<"??">) _ ensure_null_coaelse() b:@ {358 #[cfg(feature = "exp-null-coaelse")] return expr_bin!(a NullCoaelse b);359 unreachable!("ensure_null_coaelse will fail if feature is not enabled")360 }361 --362 a:(@) _ binop(<"&&">) _ b:@ {expr_bin!(a And b)}363 --364 a:(@) _ binop(<"|">) _ b:@ {expr_bin!(a BitOr b)}365 --366 a:@ _ binop(<"^">) _ b:(@) {expr_bin!(a BitXor b)}367 --368 a:(@) _ binop(<"&">) _ b:@ {expr_bin!(a BitAnd b)}369 --370 a:(@) _ binop(<"==">) _ b:@ {expr_bin!(a Eq b)}371 a:(@) _ binop(<"!=">) _ b:@ {expr_bin!(a Neq b)}372 --373 a:(@) _ binop(<"<">) _ b:@ {expr_bin!(a Lt b)}374 a:(@) _ binop(<">">) _ b:@ {expr_bin!(a Gt b)}375 a:(@) _ binop(<"<=">) _ b:@ {expr_bin!(a Lte b)}376 a:(@) _ binop(<">=">) _ b:@ {expr_bin!(a Gte b)}377 a:(@) _ binop(<keyword("in")>) _ b:@ {expr_bin!(a In b)}378 --379 a:(@) _ binop(<"<<">) _ b:@ {expr_bin!(a Lhs b)}380 a:(@) _ binop(<">>">) _ b:@ {expr_bin!(a Rhs b)}381 --382 a:(@) _ binop(<"+">) _ b:@ {expr_bin!(a Add b)}383 a:(@) _ binop(<"-">) _ b:@ {expr_bin!(a Sub b)}384 --385 a:(@) _ binop(<"*">) _ b:@ {expr_bin!(a Mul b)}386 a:(@) _ binop(<"/">) _ b:@ {expr_bin!(a Div b)}387 a:(@) _ binop(<"%">) _ b:@ {expr_bin!(a Mod b)}388 --389 unaryop(<"+">) _ b:@ {expr_un!(Plus b)}390 unaryop(<"-">) _ b:@ {expr_un!(Minus b)}391 unaryop(<"!">) _ b:@ {expr_un!(Not b)}392 unaryop(<"~">) _ b:@ {expr_un!(BitNot b)}393 --394 value:(@) _ "[" _ slice:slice_desc(s) _ "]" {Expr::Slice(Box::new(Slice{value, slice}))}395 indexable:(@) _ parts:index_part(s)+ {Expr::Index{indexable: Box::new(indexable), parts}}396 a:(@) _ args:spanned(<"(" _ a:args(s) _ ")" {a}>, s) ts:(_ keyword("tailstrict"))? {Expr::Apply(Box::new(a), args, ts.is_some())}397 a:(@) _ "{" _ body:objinside(s) _ "}" {Expr::ObjExtend(Box::new(a), body)}398 --399 e:expr_basic(s) {e}400 "(" _ e:expr(s) _ ")" {e}401 }402 pub rule index_part(s: &ParserSettings) -> IndexPart403 = n:("?" _ ensure_null_coaelse())? "." _ value:id_loc(s) {IndexPart {404 span: value.span,405 value: value.value,406 #[cfg(feature = "exp-null-coaelse")]407 null_coaelse: n.is_some(),408 }}409 / n:("?" _ "." _ ensure_null_coaelse())? value:spanned(<"[" _ v:expr(s) _ "]" {v}>, s) {IndexPart {410 span: value.span,411 value: value.value,412 #[cfg(feature = "exp-null-coaelse")]413 null_coaelse: n.is_some(),414 }}415416 pub rule jsonnet(s: &ParserSettings) -> Expr = _ e:expr(s) _ {e}417 }418}419420fn codeidx(i: usize) -> u32 {421 u32::try_from(i).expect("code has 4g hard limit")422}423424pub type ParseError = peg::error::ParseError<peg::str::LineCol>;425pub fn parse(str: &str, settings: &ParserSettings) -> Result<Expr, ParseError> {426 jsonnet_parser::jsonnet(str, settings)427}428/// Used for importstr values429pub fn string_to_expr(str: IStr, settings: &ParserSettings) -> Spanned<Expr> {430 let len = str.len();431 Spanned::new(432 Expr::Str(str),433 Span(settings.source.clone(), 0, codeidx(len)),434 )435}436437#[cfg(test)]438mod tests {439 #[test]440 #[cfg(not(feature = "exp-null-coaelse"))]441 fn snapshots() {442 use std::fs;443444 use insta::{assert_snapshot, glob};445 use jrsonnet_ir::{IStr, Source};446447 use crate::{ParserSettings, parse};448449 glob!("tests/*.jsonnet", |path| {450 let input = fs::read_to_string(path).expect("read test file");451 let v = parse(452 &input,453 &ParserSettings {454 source: Source::new_virtual("<test>".into(), IStr::empty()),455 },456 )457 .unwrap();458 let v = format!("{v:#?}");459 assert_snapshot!(v);460 });461 }462}1use jrsonnet_gcmodule::Acyclic;2use jrsonnet_ir::{3 ArgsDesc, AssertExpr, AssertStmt, BinaryOp, BindSpec, CompSpec, Destruct, DestructRest, Expr,4 ExprParam, ExprParams, FieldMember, FieldName, ForSpecData, IStr, IdentityKind, IfElse,5 IfSpecData, ImportKind, IndexPart, Member, NumValue, ObjBody, ObjComp, ObjMembers, Slice,6 SliceDesc, Source, Span, Spanned, TrivialVal, Visibility, unescape,7};8use peg::parser;910pub struct ParserSettings {11 pub source: Source,12}1314macro_rules! expr_bin {15 ($a:ident $op:ident $b:ident) => {16 Expr::BinaryOp(Box::new(BinaryOp {17 lhs: $a,18 op: $op,19 rhs: $b,20 }))21 };22}23macro_rules! expr_un {24 ($op:ident $a:ident) => {25 Expr::UnaryOp($op, Box::new($a))26 };27}2829parser! {30 pub grammar jsonnet_parser() for str {31 use peg::ParseLiteral;3233 rule eof() = quiet!{![_]} / expected!("<eof>")34 rule eol() = "\n" / eof()3536 /// Standard C-like comments37 rule comment()38 = "//" (!eol()[_])* eol()39 / "/*" (!("*/")[_])* "*/"40 / "#" (!eol()[_])* eol()4142 rule single_whitespace() = quiet!{([' ' | '\r' | '\n' | '\t'] / comment())} / expected!("<whitespace>")43 rule _() = quiet!{([' ' | '\r' | '\n' | '\t']+) / comment()}* / expected!("<whitespace>")4445 /// For comma-delimited elements46 rule comma() = quiet!{_ "," _} / expected!("<comma>")47 rule alpha() -> char = c:$(['_' | 'a'..='z' | 'A'..='Z']) {c.chars().next().unwrap()}48 rule digit() -> char = d:$(['0'..='9']) {d.chars().next().unwrap()}49 rule end_of_ident() = !['0'..='9' | '_' | 'a'..='z' | 'A'..='Z']50 /// Sequence of digits51 rule uint_str() -> &'input str = a:$(digit()+ ("_" digit()+)*) { a }52 /// Number in scientific notation format53 rule number() -> f64 = quiet!{a:$(uint_str() ("." uint_str())? (['e'|'E'] (s:['+'|'-'])? uint_str())?) {? a.replace('_',"").parse().map_err(|_| "<number>") }} / expected!("<number>")5455 /// Reserved word followed by any non-alphanumberic56 rule reserved() = ("assert" / "else" / "error" / "false" / "for" / "function" / "if" / "import" / "importstr" / "importbin" / "in" / "local" / "null" / "tailstrict" / "then" / "self" / "super" / "true") end_of_ident()57 rule id() -> IStr = v:$(quiet!{ !reserved() alpha() (alpha() / digit())*} / expected!("<identifier>")) { v.into() }5859 rule keyword(id: &'static str) -> ()60 = #{|input, pos| input.parse_string_literal(pos, id)} end_of_ident()6162 pub rule param(s: &ParserSettings) -> ExprParam = destruct:destruct(s) default:(_ "=" _ default:expr(s){default})? { ExprParam { destruct, default } }63 pub rule params(s: &ParserSettings) -> ExprParams64 = params:param(s) ** comma() comma()? { ExprParams::new(params) }65 / { ExprParams::new(Vec::new()) }6667 pub rule arg(s: &ParserSettings) -> (Option<IStr>, Expr)68 = name:(quiet! { (s:id() _ "=" !['='] _ {s})? } / expected!("<argument name>")) expr:expr(s) {(name, expr)}6970 pub rule args(s: &ParserSettings) -> ArgsDesc71 = args:arg(s)**comma() comma()? {?72 let unnamed_count = args.iter().take_while(|(n, _)| n.is_none()).count();73 let mut unnamed = Vec::with_capacity(unnamed_count);74 let mut names = Vec::with_capacity(args.len() - unnamed_count);75 let mut values = Vec::with_capacity(args.len() - unnamed_count);76 let mut named_started = false;77 for (name, value) in args {78 if let Some(name) = name {79 named_started = true;80 names.push(name);81 values.push(value);82 } else {83 if named_started {84 return Err("<named argument>")85 }86 unnamed.push(value);87 }88 }89 Ok(ArgsDesc{unnamed, names, values})90 }9192 pub rule destruct_rest() -> DestructRest93 = "..." into:(_ into:id() {into})? {into.map_or_else(|| DestructRest::Drop, DestructRest::Keep)}94 pub rule destruct_array(s: &ParserSettings) -> Destruct95 = "[" _ start:destruct(s)**comma() rest:(96 comma() _ rest:destruct_rest()? end:(97 comma() end:destruct(s)**comma() (_ comma())? {end}98 / comma()? {Vec::new()}99 ) {(rest, end)}100 / comma()? {(None, Vec::new())}101 ) _ "]" {?102 #[cfg(feature = "exp-destruct")] return Ok(Destruct::Array {103 start,104 rest: rest.0,105 end: rest.1,106 });107 #[cfg(not(feature = "exp-destruct"))] Err("!!!experimental destructuring was not enabled")108 }109 pub rule destruct_object(s: &ParserSettings) -> Destruct110 = "{" _111 fields:(name:id() into:(_ ":" _ into:destruct(s) {into})? default:(_ "=" _ v:spanned(<expr(s)>, s) {v})? {(name, into, default)})**comma()112 rest:(113 comma() rest:destruct_rest()? {rest}114 / comma()? {None}115 )116 _ "}" {?117 #[cfg(feature = "exp-destruct")] return Ok(Destruct::Object {118 fields,119 rest,120 });121 #[cfg(not(feature = "exp-destruct"))] Err("!!!experimental destructuring was not enabled")122 }123 pub rule destruct(s: &ParserSettings) -> Destruct124 = v:spanned(<id()>, s) {Destruct::Full(v)}125 / "?" {?126 #[cfg(feature = "exp-destruct")] return Ok(Destruct::Skip);127 #[cfg(not(feature = "exp-destruct"))] Err("!!!experimental destructuring was not enabled")128 }129 / arr:destruct_array(s) {arr}130 / obj:destruct_object(s) {obj}131132 pub rule bind(s: &ParserSettings) -> BindSpec133 = into:destruct(s) _ "=" _ value:expr(s) {BindSpec::Field{into, value}}134 / name:spanned(<id()>, s) _ "(" _ params:params(s) _ ")" _ "=" _ value:expr(s) {BindSpec::Function{name, params, value}}135136 pub rule assertion(s: &ParserSettings) -> AssertStmt137 = keyword("assert") _ assertion:spanned(<expr(s)>, s) message:(_ ":" _ e:expr(s) {e})? { AssertStmt{assertion, message} }138139 pub rule whole_line() -> &'input str140 = str:$((!['\n'][_])* "\n") {str}141 pub rule string_block() -> String142 = "|||" chomped:"-"? (!['\n']single_whitespace())* "\n"143 empty_lines:$(['\n']*)144 prefix:[' ' | '\t']+ first_line:whole_line()145 lines:("\n" {"\n"} / [' ' | '\t']*<{prefix.len()}> s:whole_line() {s})*146 [' ' | '\t']*<, {prefix.len() - 1}> "|||"147 {148 let mut l = empty_lines.to_owned();149 l.push_str(first_line);150 l.extend(lines);151 if chomped.is_some() {152 debug_assert!(l.ends_with('\n'));153 l.truncate(l.len() - 1);154 }155 l156 }157158 rule hex_char()159 = quiet! { ['0'..='9' | 'a'..='f' | 'A'..='F'] } / expected!("<hex char>")160161 rule string_char(c: rule<()>)162 = (!['\\']!c()[_])+163 / "\\\\"164 / "\\u" hex_char() hex_char() hex_char() hex_char()165 / "\\x" hex_char() hex_char()166 / ['\\'] (quiet! { ['b' | 'f' | 'n' | 'r' | 't' | '"' | '\''] } / expected!("<escape character>"))167 pub rule string() -> String168 = ['"'] str:$(string_char(<"\"">)*) ['"'] {? unescape::unescape(str).ok_or("<escaped string>")}169 / ['\''] str:$(string_char(<"\'">)*) ['\''] {? unescape::unescape(str).ok_or("<escaped string>")}170 / quiet!{ "@'" str:$(("''" / (!['\''][_]))*) "'" {str.replace("''", "'")}171 / "@\"" str:$(("\"\"" / (!['"'][_]))*) "\"" {str.replace("\"\"", "\"")}172 / string_block() } / expected!("<string>")173174 pub rule field_name(s: &ParserSettings) -> FieldName175 = name:id() {FieldName::Fixed(name)}176 / name:string() {FieldName::Fixed(name.into())}177 / "[" _ expr:expr(s) _ "]" {FieldName::Dyn(expr)}178 pub rule visibility() -> Visibility179 = ":::" {Visibility::Unhide}180 / "::" {Visibility::Hidden}181 / ":" {Visibility::Normal}182 pub rule field(s: &ParserSettings) -> FieldMember183 = name:spanned(<field_name(s)>, s) _ plus:"+"? _ visibility:visibility() _ value:expr(s) {FieldMember{184 name,185 plus: plus.is_some(),186 params: None,187 visibility,188 value,189 }}190 / name:spanned(<field_name(s)>, s) _ "(" _ params:params(s) _ ")" _ visibility:visibility() _ value:expr(s) {FieldMember{191 name,192 plus: false,193 params: Some(params),194 visibility,195 value,196 }}197 pub rule obj_local(s: &ParserSettings) -> BindSpec198 = keyword("local") _ bind:bind(s) {bind}199 pub rule member(s: &ParserSettings) -> Member200 = bind:obj_local(s) {Member::BindStmt(bind)}201 / assertion:assertion(s) {Member::AssertStmt(assertion)}202 / field:field(s) {Member::Field(field)}203 pub rule objinside(s: &ParserSettings) -> ObjBody204 = members:(member(s) ** comma()) comma()? _ compspecs:compspecs(s)? {?205 Ok(if let Some(compspecs) = compspecs {206 let mut locals = Vec::new();207 let mut field = None;208 for member in members {209 match member {210 Member::Field(field_member) => if field.replace(field_member).is_some() {211 return Err("<object comprehension can only contain one field>")212 },213 Member::BindStmt(bind_spec) => locals.push(bind_spec),214 Member::AssertStmt(assert_stmt) => return Err("<asserts are unsupported in object comprehension>"),215 }216 }217 ObjBody::ObjComp(ObjComp {218 locals,219 field: Box::new(field.ok_or("<missing object comprehension field>")?),220 compspecs221 })222 } else {223 let mut locals = Vec::new();224 let mut asserts = Vec::new();225 let mut fields = Vec::new();226 for member in members {227 match member {228 Member::Field(field_member) => fields.push(field_member),229 Member::BindStmt(bind_spec) => locals.push(bind_spec),230 Member::AssertStmt(assert_stmt) => asserts.push(assert_stmt),231 }232 }233 ObjBody::MemberList(ObjMembers {234 locals,235 asserts,236 fields237 })238 })239 }240 pub rule ifspec(s: &ParserSettings) -> IfSpecData241 = i:spanned(<keyword("if")>, s) _ cond:expr(s) {IfSpecData { span: i.span, cond }}242 pub rule forspec(s: &ParserSettings) -> ForSpecData243 = keyword("for") _ destruct:destruct(s) _ keyword("in") _ over:expr(s) { ForSpecData { destruct, over } }244 rule ensure_object_iteration()245 = "" {?246 #[cfg(not(feature = "exp-object-iteration"))] return Err("!!!experimental object iteration was not enabled");247 #[cfg(feature = "exp-object-iteration")] Ok(())248 }249 pub rule forobjspec(s: &ParserSettings) -> CompSpec250 = ensure_object_iteration() keyword("for") _ "[" _ key:id() _ "]" _ vis:visibility() _ value:destruct(s) _ keyword("in") _ over:expr(s) {251 #[cfg(feature = "exp-object-iteration")] return CompSpec::ForObjSpec(jrsonnet_ir::ForObjSpecData { key, visibility: vis, value, over });252 #[cfg(not(feature = "exp-object-iteration"))] unreachable!("ensure_object_iteration will fail if feature is not enabled")253 }254 rule compspec(s: &ParserSettings) -> CompSpec255 = i:ifspec(s) { CompSpec::IfSpec(i) } / f:forobjspec(s) { f } / f:forspec(s) {CompSpec::ForSpec(f)}256 pub rule compspecs(s: &ParserSettings) -> Vec<CompSpec>257 = specs:compspec(s) ++ _ {?258 if matches!(specs[0], CompSpec::IfSpec(_)) {259 return Err("<first compspec should be for>")260 }261 Ok(specs)262 }263 pub rule local_expr(s: &ParserSettings) -> Expr264 = keyword("local") _ binds:bind(s) ** comma() (_ ",")? _ ";" _ expr:expr(s) { Expr::LocalExpr(binds, Box::new(expr)) }265 pub rule string_expr(s: &ParserSettings) -> Expr266 = s:string() {Expr::Trivial(TrivialVal::Str(s.into()))}267 pub rule obj_expr(s: &ParserSettings) -> Expr268 = "{" _ body:objinside(s) _ "}" {Expr::Obj(body)}269 pub rule array_expr(s: &ParserSettings) -> Expr270 = "[" _ elems:(expr(s) ** comma()) _ comma()? "]" {Expr::Arr(elems)}271 pub rule array_comp_expr(s: &ParserSettings) -> Expr272 = "[" _ expr:expr(s) _ comma()? _ specs:(r: compspecs(s) _ {r}) "]" {273 Expr::ArrComp(Box::new(expr), specs)274 }275 pub rule number_expr(s: &ParserSettings) -> Expr276 = n:number() {? NumValue::new(n).map_or_else(|| Err("!!!numbers are finite"), |n| Ok(Expr::Trivial(TrivialVal::Num(n))))}277278 rule spanned<T: Acyclic>(x: rule<T>, s: &ParserSettings) -> Spanned<T>279 = a:position!() n:x() b:position!() { Spanned::new(n, Span(s.source.clone(), codeidx(a), codeidx(b))) }280281 pub rule var_expr(s: &ParserSettings) -> Expr282 = n:spanned(<id()>, s) { Expr::Var(n) }283 pub rule id_loc(s: &ParserSettings) -> Spanned<Expr>284 = a:position!() n:id() b:position!() { Spanned::new(Expr::Trivial(TrivialVal::Str(n)), Span(s.source.clone(), codeidx(a), codeidx(b))) }285 pub rule if_then_else_expr(s: &ParserSettings) -> Expr286 = cond:ifspec(s) _ keyword("then") _ cond_then:expr(s) cond_else:(_ keyword("else") _ e:expr(s) {e})? {Expr::IfElse(Box::new(IfElse{287 cond,288 cond_then,289 cond_else,290 }))}291292 pub rule literal(s: &ParserSettings) -> Expr293 = keyword("null") { Expr::Trivial(TrivialVal::Null) }294 / keyword("true") { Expr::Trivial(TrivialVal::Bool(true)) }295 / keyword("false") { Expr::Trivial(TrivialVal::Bool(false)) }296 / a:position!() v:(297 keyword("self") {IdentityKind::This}298 / keyword("$") {IdentityKind::Dollar}299 / keyword("super") {IdentityKind::Super}300 ) b:position!() { Expr::Identity(Span(s.source.clone(), codeidx(a), codeidx(b)), v) }301302 rule import_kind() -> ImportKind303 = keyword("importstr") { ImportKind::Str }304 / keyword("importbin") { ImportKind::Bin }305 / keyword("import") { ImportKind::Normal }306307 pub rule expr_basic(s: &ParserSettings) -> Expr308 = literal(s)309310 / string_expr(s) / number_expr(s)311 / array_expr(s)312 / obj_expr(s)313 / array_expr(s)314 / array_comp_expr(s)315316 / kind:spanned(<import_kind()>, s) _ path:expr(s) {Expr::Import(kind, Box::new(path))}317318 / var_expr(s)319 / local_expr(s)320 / if_then_else_expr(s)321322 / kw:spanned(<keyword("function")>, s) _ "(" _ params:params(s) _ ")" _ expr:expr(s) {Expr::Function(kw.span, params, Box::new(expr))}323 / assert:assertion(s) _ ";" _ rest:expr(s) { Expr::AssertExpr(Box::new(AssertExpr{324 assert, rest325 })) }326327 / err_kw:spanned(<keyword("error")>, s) _ expr:expr(s) { Expr::ErrorStmt(err_kw.span, Box::new(expr)) }328329 rule slice_part(s: &ParserSettings) -> Option<Spanned<Expr>>330 = _ e:(e:spanned(<expr(s)>, s) _{e})? {e}331 pub rule slice_desc(s: &ParserSettings) -> SliceDesc332 = start:slice_part(s) ":" pair:(end:slice_part(s) step:(":" e:slice_part(s){e})? {(end, step.flatten())})? {333 let (end, step) = if let Some((end, step)) = pair {334 (end, step)335 }else{336 (None, None)337 };338339 SliceDesc { start, end, step }340 }341342 rule binop(x: rule<()>) -> ()343 = quiet!{ x() } / expected!("<binary op>")344 rule unaryop(x: rule<()>) -> ()345 = quiet!{ x() } / expected!("<unary op>")346347 rule ensure_null_coaelse()348 = "" {?349 #[cfg(not(feature = "exp-null-coaelse"))] return Err("!!!experimental null coaelscing was not enabled");350 #[cfg(feature = "exp-null-coaelse")] Ok(())351 }352 use jrsonnet_ir::BinaryOpType::*;353 use jrsonnet_ir::UnaryOpType::*;354 rule expr(s: &ParserSettings) -> Expr355 = precedence! {356 a:(@) _ binop(<"||">) _ b:@ {expr_bin!(a Or b)}357 a:(@) _ binop(<"??">) _ ensure_null_coaelse() b:@ {358 #[cfg(feature = "exp-null-coaelse")] return expr_bin!(a NullCoaelse b);359 unreachable!("ensure_null_coaelse will fail if feature is not enabled")360 }361 --362 a:(@) _ binop(<"&&">) _ b:@ {expr_bin!(a And b)}363 --364 a:(@) _ binop(<"|">) _ b:@ {expr_bin!(a BitOr b)}365 --366 a:@ _ binop(<"^">) _ b:(@) {expr_bin!(a BitXor b)}367 --368 a:(@) _ binop(<"&">) _ b:@ {expr_bin!(a BitAnd b)}369 --370 a:(@) _ binop(<"==">) _ b:@ {expr_bin!(a Eq b)}371 a:(@) _ binop(<"!=">) _ b:@ {expr_bin!(a Neq b)}372 --373 a:(@) _ binop(<"<">) _ b:@ {expr_bin!(a Lt b)}374 a:(@) _ binop(<">">) _ b:@ {expr_bin!(a Gt b)}375 a:(@) _ binop(<"<=">) _ b:@ {expr_bin!(a Lte b)}376 a:(@) _ binop(<">=">) _ b:@ {expr_bin!(a Gte b)}377 a:(@) _ binop(<keyword("in")>) _ b:@ {expr_bin!(a In b)}378 --379 a:(@) _ binop(<"<<">) _ b:@ {expr_bin!(a Lhs b)}380 a:(@) _ binop(<">>">) _ b:@ {expr_bin!(a Rhs b)}381 --382 a:(@) _ binop(<"+">) _ b:@ {expr_bin!(a Add b)}383 a:(@) _ binop(<"-">) _ b:@ {expr_bin!(a Sub b)}384 --385 a:(@) _ binop(<"*">) _ b:@ {expr_bin!(a Mul b)}386 a:(@) _ binop(<"/">) _ b:@ {expr_bin!(a Div b)}387 a:(@) _ binop(<"%">) _ b:@ {expr_bin!(a Mod b)}388 --389 unaryop(<"+">) _ b:@ {expr_un!(Plus b)}390 unaryop(<"-">) _ b:@ {expr_un!(Minus b)}391 unaryop(<"!">) _ b:@ {expr_un!(Not b)}392 unaryop(<"~">) _ b:@ {expr_un!(BitNot b)}393 --394 value:(@) _ "[" _ slice:slice_desc(s) _ "]" {Expr::Slice(Box::new(Slice{value, slice}))}395 indexable:(@) _ parts:index_part(s)+ {Expr::Index{indexable: Box::new(indexable), parts}}396 a:(@) _ args:spanned(<"(" _ a:args(s) _ ")" {a}>, s) ts:(_ keyword("tailstrict"))? {Expr::Apply(Box::new(a), args, ts.is_some())}397 a:(@) _ "{" _ body:objinside(s) _ "}" {Expr::ObjExtend(Box::new(a), body)}398 --399 e:expr_basic(s) {e}400 "(" _ e:expr(s) _ ")" {e}401 }402 pub rule index_part(s: &ParserSettings) -> IndexPart403 = n:("?" _ ensure_null_coaelse())? "." _ value:id_loc(s) {IndexPart {404 span: value.span,405 value: value.value,406 #[cfg(feature = "exp-null-coaelse")]407 null_coaelse: n.is_some(),408 }}409 / n:("?" _ "." _ ensure_null_coaelse())? value:spanned(<"[" _ v:expr(s) _ "]" {v}>, s) {IndexPart {410 span: value.span,411 value: value.value,412 #[cfg(feature = "exp-null-coaelse")]413 null_coaelse: n.is_some(),414 }}415416 pub rule jsonnet(s: &ParserSettings) -> Expr = _ e:expr(s) _ {e}417 }418}419420fn codeidx(i: usize) -> u32 {421 u32::try_from(i).expect("code has 4g hard limit")422}423424pub type ParseError = peg::error::ParseError<peg::str::LineCol>;425pub fn parse(str: &str, settings: &ParserSettings) -> Result<Expr, ParseError> {426 jsonnet_parser::jsonnet(str, settings)427}428/// Used for importstr values429pub fn string_to_expr(str: IStr, settings: &ParserSettings) -> Spanned<Expr> {430 let len = str.len();431 Spanned::new(432 Expr::Trivial(TrivialVal::Str(str)),433 Span(settings.source.clone(), 0, codeidx(len)),434 )435}436437#[cfg(test)]438mod tests {439 #[test]440 #[cfg(not(feature = "exp-null-coaelse"))]441 fn snapshots() {442 use std::fs;443444 use insta::{assert_snapshot, glob};445 use jrsonnet_ir::{IStr, Source};446447 use crate::{ParserSettings, parse};448449 glob!("tests/*.jsonnet", |path| {450 let input = fs::read_to_string(path).expect("read test file");451 let v = parse(452 &input,453 &ParserSettings {454 source: Source::new_virtual("<test>".into(), IStr::empty()),455 },456 )457 .unwrap();458 let v = format!("{v:#?}");459 assert_snapshot!(v);460 });461 }462}crates/jrsonnet-peg-parser/src/snapshots/jrsonnet_peg_parser__tests__snapshots@array_comp.jsonnet.snapdiffbeforeafterboth--- a/crates/jrsonnet-peg-parser/src/snapshots/jrsonnet_peg_parser__tests__snapshots@array_comp.jsonnet.snap
+++ b/crates/jrsonnet-peg-parser/src/snapshots/jrsonnet_peg_parser__tests__snapshots@array_comp.jsonnet.snap
@@ -1,5 +1,6 @@
---
source: crates/jrsonnet-peg-parser/src/lib.rs
+assertion_line: 459
expression: v
input_file: crates/jrsonnet-peg-parser/src/tests/array_comp.jsonnet
---
@@ -14,8 +15,10 @@
parts: [
IndexPart {
span: virtual:<test>:7-15,
- value: Str(
- "deepJoin",
+ value: Trivial(
+ Str(
+ "deepJoin",
+ ),
),
},
],
crates/jrsonnet-peg-parser/src/snapshots/jrsonnet_peg_parser__tests__snapshots@basic_math.jsonnet.snapdiffbeforeafterboth--- a/crates/jrsonnet-peg-parser/src/snapshots/jrsonnet_peg_parser__tests__snapshots@basic_math.jsonnet.snap
+++ b/crates/jrsonnet-peg-parser/src/snapshots/jrsonnet_peg_parser__tests__snapshots@basic_math.jsonnet.snap
@@ -1,5 +1,6 @@
---
source: crates/jrsonnet-peg-parser/src/lib.rs
+assertion_line: 459
expression: v
input_file: crates/jrsonnet-peg-parser/src/tests/basic_math.jsonnet
---
@@ -7,18 +8,24 @@
[
BinaryOp(
BinaryOp {
- lhs: Num(
- 2.0,
+ lhs: Trivial(
+ Num(
+ 2.0,
+ ),
),
op: Add,
rhs: BinaryOp(
BinaryOp {
- lhs: Num(
- 2.0,
+ lhs: Trivial(
+ Num(
+ 2.0,
+ ),
),
op: Mul,
- rhs: Num(
- 2.0,
+ rhs: Trivial(
+ Num(
+ 2.0,
+ ),
),
},
),
@@ -26,18 +33,24 @@
),
BinaryOp(
BinaryOp {
- lhs: Num(
- 2.0,
+ lhs: Trivial(
+ Num(
+ 2.0,
+ ),
),
op: Add,
rhs: BinaryOp(
BinaryOp {
- lhs: Num(
- 2.0,
+ lhs: Trivial(
+ Num(
+ 2.0,
+ ),
),
op: Mul,
- rhs: Num(
- 2.0,
+ rhs: Trivial(
+ Num(
+ 2.0,
+ ),
),
},
),
@@ -47,24 +60,32 @@
BinaryOp {
lhs: BinaryOp(
BinaryOp {
- lhs: Num(
- 2.0,
+ lhs: Trivial(
+ Num(
+ 2.0,
+ ),
),
op: Add,
- rhs: Num(
- 2.0,
+ rhs: Trivial(
+ Num(
+ 2.0,
+ ),
),
},
),
op: Add,
rhs: BinaryOp(
BinaryOp {
- lhs: Num(
- 2.0,
+ lhs: Trivial(
+ Num(
+ 2.0,
+ ),
),
op: Mul,
- rhs: Num(
- 2.0,
+ rhs: Trivial(
+ Num(
+ 2.0,
+ ),
),
},
),
@@ -72,24 +93,32 @@
),
BinaryOp(
BinaryOp {
- lhs: Num(
- 2.0,
+ lhs: Trivial(
+ Num(
+ 2.0,
+ ),
),
op: Add,
rhs: BinaryOp(
BinaryOp {
- lhs: Num(
- 2.0,
+ lhs: Trivial(
+ Num(
+ 2.0,
+ ),
),
op: Add,
rhs: BinaryOp(
BinaryOp {
- lhs: Num(
- 2.0,
+ lhs: Trivial(
+ Num(
+ 2.0,
+ ),
),
op: Mul,
- rhs: Num(
- 2.0,
+ rhs: Trivial(
+ Num(
+ 2.0,
+ ),
),
},
),
@@ -99,18 +128,24 @@
),
BinaryOp(
BinaryOp {
- lhs: Num(
- 2.0,
+ lhs: Trivial(
+ Num(
+ 2.0,
+ ),
),
op: Add,
rhs: BinaryOp(
BinaryOp {
- lhs: Num(
- 3.0,
+ lhs: Trivial(
+ Num(
+ 3.0,
+ ),
),
op: Mul,
- rhs: Num(
- 4.0,
+ rhs: Trivial(
+ Num(
+ 4.0,
+ ),
),
},
),
crates/jrsonnet-peg-parser/src/snapshots/jrsonnet_peg_parser__tests__snapshots@comment_eof.jsonnet.snapdiffbeforeafterboth--- a/crates/jrsonnet-peg-parser/src/snapshots/jrsonnet_peg_parser__tests__snapshots@comment_eof.jsonnet.snap
+++ b/crates/jrsonnet-peg-parser/src/snapshots/jrsonnet_peg_parser__tests__snapshots@comment_eof.jsonnet.snap
@@ -1,5 +1,6 @@
---
source: crates/jrsonnet-peg-parser/src/lib.rs
+assertion_line: 459
expression: v
input_file: crates/jrsonnet-peg-parser/src/tests/comment_eof.jsonnet
---
@@ -16,8 +17,10 @@
plus: false,
params: None,
visibility: Normal,
- value: Num(
- 1.0,
+ value: Trivial(
+ Num(
+ 1.0,
+ ),
),
},
],
crates/jrsonnet-peg-parser/src/snapshots/jrsonnet_peg_parser__tests__snapshots@default_nondefault.jsonnet.snapdiffbeforeafterboth--- a/crates/jrsonnet-peg-parser/src/snapshots/jrsonnet_peg_parser__tests__snapshots@default_nondefault.jsonnet.snap
+++ b/crates/jrsonnet-peg-parser/src/snapshots/jrsonnet_peg_parser__tests__snapshots@default_nondefault.jsonnet.snap
@@ -1,5 +1,6 @@
---
source: crates/jrsonnet-peg-parser/src/lib.rs
+assertion_line: 459
expression: v
input_file: crates/jrsonnet-peg-parser/src/tests/default_nondefault.jsonnet
---
@@ -14,8 +15,10 @@
"foo" from virtual:<test>:8-11,
),
default: Some(
- Str(
- "foo",
+ Trivial(
+ Str(
+ "foo",
+ ),
),
),
},
@@ -44,14 +47,12 @@
),
binds_len: 2,
},
- value: Literal(
- virtual:<test>:28-32,
+ value: Trivial(
Null,
),
},
],
- Literal(
- virtual:<test>:34-38,
+ Trivial(
Null,
),
)
crates/jrsonnet-peg-parser/src/snapshots/jrsonnet_peg_parser__tests__snapshots@imports.jsonnet.snapdiffbeforeafterboth--- a/crates/jrsonnet-peg-parser/src/snapshots/jrsonnet_peg_parser__tests__snapshots@imports.jsonnet.snap
+++ b/crates/jrsonnet-peg-parser/src/snapshots/jrsonnet_peg_parser__tests__snapshots@imports.jsonnet.snap
@@ -1,5 +1,6 @@
---
source: crates/jrsonnet-peg-parser/src/lib.rs
+assertion_line: 459
expression: v
input_file: crates/jrsonnet-peg-parser/src/tests/imports.jsonnet
---
@@ -7,20 +8,26 @@
[
Import(
Normal from virtual:<test>:2-8,
- Str(
- "hello",
+ Trivial(
+ Str(
+ "hello",
+ ),
),
),
Import(
Str from virtual:<test>:18-27,
- Str(
- "garnish.txt",
+ Trivial(
+ Str(
+ "garnish.txt",
+ ),
),
),
Import(
Bin from virtual:<test>:43-52,
- Str(
- "garnish.bin",
+ Trivial(
+ Str(
+ "garnish.bin",
+ ),
),
),
],
crates/jrsonnet-peg-parser/src/snapshots/jrsonnet_peg_parser__tests__snapshots@multiline.jsonnet.snapdiffbeforeafterboth--- a/crates/jrsonnet-peg-parser/src/snapshots/jrsonnet_peg_parser__tests__snapshots@multiline.jsonnet.snap
+++ b/crates/jrsonnet-peg-parser/src/snapshots/jrsonnet_peg_parser__tests__snapshots@multiline.jsonnet.snap
@@ -1,21 +1,30 @@
---
source: crates/jrsonnet-peg-parser/src/lib.rs
+assertion_line: 459
expression: v
input_file: crates/jrsonnet-peg-parser/src/tests/multiline.jsonnet
---
Arr(
[
- Str(
- "Hello world!\na\n",
+ Trivial(
+ Str(
+ "Hello world!\na\n",
+ ),
),
- Str(
- "Hello world!\na\n",
+ Trivial(
+ Str(
+ "Hello world!\na\n",
+ ),
),
- Str(
- "Hello world!\n\ta\n",
+ Trivial(
+ Str(
+ "Hello world!\n\ta\n",
+ ),
),
- Str(
- "Hello world!\n a\n",
+ Trivial(
+ Str(
+ "Hello world!\n a\n",
+ ),
),
],
)
crates/jrsonnet-peg-parser/src/snapshots/jrsonnet_peg_parser__tests__snapshots@reserved.jsonnet.snapdiffbeforeafterboth--- a/crates/jrsonnet-peg-parser/src/snapshots/jrsonnet_peg_parser__tests__snapshots@reserved.jsonnet.snap
+++ b/crates/jrsonnet-peg-parser/src/snapshots/jrsonnet_peg_parser__tests__snapshots@reserved.jsonnet.snap
@@ -1,12 +1,12 @@
---
source: crates/jrsonnet-peg-parser/src/lib.rs
+assertion_line: 459
expression: v
input_file: crates/jrsonnet-peg-parser/src/tests/reserved.jsonnet
---
Arr(
[
- Literal(
- virtual:<test>:2-6,
+ Trivial(
Null,
),
Var(
crates/jrsonnet-peg-parser/src/snapshots/jrsonnet_peg_parser__tests__snapshots@slice.jsonnet.snapdiffbeforeafterboth--- a/crates/jrsonnet-peg-parser/src/snapshots/jrsonnet_peg_parser__tests__snapshots@slice.jsonnet.snap
+++ b/crates/jrsonnet-peg-parser/src/snapshots/jrsonnet_peg_parser__tests__snapshots@slice.jsonnet.snap
@@ -1,5 +1,6 @@
---
source: crates/jrsonnet-peg-parser/src/lib.rs
+assertion_line: 459
expression: v
input_file: crates/jrsonnet-peg-parser/src/tests/slice.jsonnet
---
@@ -12,8 +13,10 @@
),
slice: SliceDesc {
start: Some(
- Num(
- 1.0,
+ Trivial(
+ Num(
+ 1.0,
+ ),
) from virtual:<test>:4-5,
),
end: None,
@@ -28,8 +31,10 @@
),
slice: SliceDesc {
start: Some(
- Num(
- 1.0,
+ Trivial(
+ Num(
+ 1.0,
+ ),
) from virtual:<test>:11-12,
),
end: None,
@@ -45,8 +50,10 @@
slice: SliceDesc {
start: None,
end: Some(
- Num(
- 1.0,
+ Trivial(
+ Num(
+ 1.0,
+ ),
) from virtual:<test>:20-21,
),
step: None,
@@ -62,8 +69,10 @@
start: None,
end: None,
step: Some(
- Num(
- 1.0,
+ Trivial(
+ Num(
+ 1.0,
+ ),
) from virtual:<test>:29-30,
),
},
@@ -83,8 +92,10 @@
"len" from virtual:<test>:38-41,
),
op: Sub,
- rhs: Num(
- 1.0,
+ rhs: Trivial(
+ Num(
+ 1.0,
+ ),
),
},
) from virtual:<test>:38-45,
crates/jrsonnet-peg-parser/src/snapshots/jrsonnet_peg_parser__tests__snapshots@string_escaping.jsonnet.snapdiffbeforeafterboth--- a/crates/jrsonnet-peg-parser/src/snapshots/jrsonnet_peg_parser__tests__snapshots@string_escaping.jsonnet.snap
+++ b/crates/jrsonnet-peg-parser/src/snapshots/jrsonnet_peg_parser__tests__snapshots@string_escaping.jsonnet.snap
@@ -1,24 +1,35 @@
---
source: crates/jrsonnet-peg-parser/src/lib.rs
+assertion_line: 459
expression: v
input_file: crates/jrsonnet-peg-parser/src/tests/string_escaping.jsonnet
---
Arr(
[
- Str(
- "Hello, \"world\"!",
+ Trivial(
+ Str(
+ "Hello, \"world\"!",
+ ),
),
- Str(
- "Hello 'world'!",
+ Trivial(
+ Str(
+ "Hello 'world'!",
+ ),
),
- Str(
- "\\\\",
+ Trivial(
+ Str(
+ "\\\\",
+ ),
),
- Str(
- "Hello\nWorld",
+ Trivial(
+ Str(
+ "Hello\nWorld",
+ ),
),
- Str(
- "Hello\\n\"World\"",
+ Trivial(
+ Str(
+ "Hello\\n\"World\"",
+ ),
),
],
)
crates/jrsonnet-peg-parser/src/snapshots/jrsonnet_peg_parser__tests__snapshots@subexp.jsonnet.snapdiffbeforeafterboth--- a/crates/jrsonnet-peg-parser/src/snapshots/jrsonnet_peg_parser__tests__snapshots@subexp.jsonnet.snap
+++ b/crates/jrsonnet-peg-parser/src/snapshots/jrsonnet_peg_parser__tests__snapshots@subexp.jsonnet.snap
@@ -1,5 +1,6 @@
---
source: crates/jrsonnet-peg-parser/src/lib.rs
+assertion_line: 459
expression: v
input_file: crates/jrsonnet-peg-parser/src/tests/subexp.jsonnet
---
@@ -22,8 +23,10 @@
into: Full(
"x" from virtual:<test>:11-12,
),
- value: Num(
- 1.0,
+ value: Trivial(
+ Num(
+ 1.0,
+ ),
),
},
],
crates/jrsonnet-peg-parser/src/snapshots/jrsonnet_peg_parser__tests__snapshots@suffix.jsonnet.snapdiffbeforeafterboth--- a/crates/jrsonnet-peg-parser/src/snapshots/jrsonnet_peg_parser__tests__snapshots@suffix.jsonnet.snap
+++ b/crates/jrsonnet-peg-parser/src/snapshots/jrsonnet_peg_parser__tests__snapshots@suffix.jsonnet.snap
@@ -1,5 +1,6 @@
---
source: crates/jrsonnet-peg-parser/src/lib.rs
+assertion_line: 459
expression: v
input_file: crates/jrsonnet-peg-parser/src/tests/suffix.jsonnet
---
@@ -12,8 +13,10 @@
parts: [
IndexPart {
span: virtual:<test>:6-10,
- value: Str(
- "test",
+ value: Trivial(
+ Str(
+ "test",
+ ),
),
},
],
@@ -24,8 +27,10 @@
),
ArgsDesc {
unnamed: [
- Num(
- 2.0,
+ Trivial(
+ Num(
+ 2.0,
+ ),
),
],
names: [],
@@ -41,16 +46,20 @@
parts: [
IndexPart {
span: virtual:<test>:24-28,
- value: Str(
- "test",
+ value: Trivial(
+ Str(
+ "test",
+ ),
),
},
],
},
ArgsDesc {
unnamed: [
- Num(
- 2.0,
+ Trivial(
+ Num(
+ 2.0,
+ ),
),
],
names: [],