git.delta.rocks / jrsonnet / refs/commits / d5d04bbaa62b

difftreelog

fix incorrect expression suffix handling in rowan parser

ytytztwvYaroslav Bolyukin2026-02-10parent: #bfc3583.patch.diff
in: master

31 files changed

modifiedCargo.lockdiffbeforeafterboth
704dependencies = [704dependencies = [
705 "anyhow",705 "anyhow",
706 "drop_bomb",706 "drop_bomb",
707 "hi-doc",
707 "indoc",708 "indoc",
708 "insta",709 "insta",
709 "logos",710 "logos",
710 "rowan",711 "rowan",
712 "strip-ansi-escapes",
711 "thiserror",713 "thiserror",
712]714]
713715
1317source = "registry+https://github.com/rust-lang/crates.io-index"1319source = "registry+https://github.com/rust-lang/crates.io-index"
1318checksum = "2b2231b7c3057d5e4ad0156fb3dc807d900806020c5ffa3ee6ff2c8c76fb8520"1320checksum = "2b2231b7c3057d5e4ad0156fb3dc807d900806020c5ffa3ee6ff2c8c76fb8520"
1321
1322[[package]]
1323name = "strip-ansi-escapes"
1324version = "0.2.1"
1325source = "registry+https://github.com/rust-lang/crates.io-index"
1326checksum = "2a8f8038e7e7969abb3f1b7c2a811225e9296da208539e0f79c5251d6cac0025"
1327dependencies = [
1328 "vte",
1329]
13191330
1320[[package]]1331[[package]]
1321name = "strsim"1332name = "strsim"
1470source = "registry+https://github.com/rust-lang/crates.io-index"1481source = "registry+https://github.com/rust-lang/crates.io-index"
1471checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"1482checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
1483
1484[[package]]
1485name = "vte"
1486version = "0.14.1"
1487source = "registry+https://github.com/rust-lang/crates.io-index"
1488checksum = "231fdcd7ef3037e8330d8e17e61011a2c244126acc0a982f4040ac3f9f0bc077"
1489dependencies = [
1490 "memchr",
1491]
14721492
1473[[package]]1493[[package]]
1474name = "wasip2"1494name = "wasip2"
modifiedcrates/jrsonnet-formatter/src/lib.rsdiffbeforeafterboth
685 fn print(&self, out: &mut PrintItems) {685 fn print(&self, out: &mut PrintItems) {
686 match self {686 match self {
687 Self::ExprBinary(b) => {687 Self::ExprBinary(b) => {
688 p!(out, {b.lhs_work()} str(" ") {b.binary_operator()} str(" ") {b.rhs_work()});688 p!(out, {b.lhs()} str(" ") {b.binary_operator()} str(" ") {b.rhs()});
689 }689 }
690 Self::ExprUnary(u) => p!(out, {u.unary_operator()} {u.rhs()}),690 Self::ExprUnary(u) => p!(out, {u.unary_operator()} {u.rhs()}),
691 // Self::ExprSlice(s) => {691 // Self::ExprSlice(s) => {
addedcrates/jrsonnet-formatter/src/snapshots/jrsonnet_formatter__tests__self_super.snapdiffbeforeafterboth

no changes

modifiedcrates/jrsonnet-formatter/src/tests.rsdiffbeforeafterboth
149 )));149 )));
150}150}
151
152#[test]
153fn self_super() {
154 insta::assert_snapshot!(reformat(indoc!(
155 "
156 local base = {
157 foo: 'bar',
158 method():: self.foo,
159 };
160
161 base {
162 foo: super.foo + '-extended',
163 result: self.method(),
164 }
165 "
166 )));
167}
151168
modifiedcrates/jrsonnet-rowan-parser/Cargo.tomldiffbeforeafterboth
12[dependencies]12[dependencies]
13anyhow.workspace = true13anyhow.workspace = true
14drop_bomb.workspace = true14drop_bomb.workspace = true
15hi-doc.workspace = true
15indoc.workspace = true16indoc.workspace = true
16logos.workspace = true17logos.workspace = true
17rowan.workspace = true18rowan.workspace = true
21indoc.workspace = true22indoc.workspace = true
22insta.workspace = true23insta.workspace = true
23anyhow.workspace = true24anyhow.workspace = true
25strip-ansi-escapes = "0.2.1"
2426
modifiedcrates/jrsonnet-rowan-parser/src/lib.rsdiffbeforeafterboth
47 parse.errors,47 parse.errors,
48 )48 )
49}49}
50impl ExprBinary {
51 pub fn lhs_work(&self) -> Option<Expr> {
52 support::child(self.syntax())
53 }
54 pub fn rhs_work(&self) -> Option<Expr> {
55 let mut children = support::children(self.syntax());
56 // skip lhs
57 children.next()?;
58 children.next()
59 }
60}
61impl ExprObjExtend {50impl ExprObjExtend {
62 pub fn lhs_work(&self) -> Option<Expr> {51 pub fn lhs_work(&self) -> Option<Expr> {
63 support::child(self.syntax())52 support::child(self.syntax())
modifiedcrates/jrsonnet-rowan-parser/src/marker.rsdiffbeforeafterboth
140140
141 new_m141 new_m
142 }142 }
143 /// Create new node around existing marker, not counting anything that comes after it143 /// Create new node around existing marker
144 /// If previous_pos is set - the wrapping node would not include everything that happened between wrapped node end and the current position of the parser
144 fn wrap_raw(self, p: &mut Parser, kind: SyntaxKind, error: Option<SyntaxError>) -> Self {145 fn wrap_raw(
146 self,
147 p: &mut Parser,
148 kind: SyntaxKind,
149 error: Option<SyntaxError>,
150 previous_pos: bool,
151 ) -> Self {
145 let new_m = p.start();152 let new_m = p.start();
146 match &mut p.events[self.start_event_idx] {153 match &mut p.events[self.start_event_idx] {
154161
155 let completed = new_m.complete_raw(p, kind, error);162 let completed = new_m.complete_raw(p, kind, error);
156163
164 if previous_pos {
157 match &mut p.events[self.finish_event_idx] {165 match &mut p.events[self.finish_event_idx] {
158 Event::Finish {166 Event::Finish {
159 wrapper,167 wrapper,
166 }174 }
167 _ => unreachable!(),175 _ => unreachable!(),
168 }176 }
177 }
169 completed178 completed
170 }179 }
171 pub fn wrap(self, p: &mut Parser, kind: SyntaxKind) -> Self {180 pub fn wrap(self, p: &mut Parser, kind: SyntaxKind, previous_pos: bool) -> Self {
172 self.wrap_raw(p, kind, None)181 self.wrap_raw(p, kind, None, previous_pos)
173 }182 }
174 pub fn wrap_error(self, p: &mut Parser, msg: impl AsRef<str>) -> Self {183 pub fn wrap_error(self, p: &mut Parser, msg: impl AsRef<str>, previous_pos: bool) -> Self {
175 self.wrap_raw(184 self.wrap_raw(
176 p,185 p,
177 SyntaxKind::ERROR_CUSTOM,186 SyntaxKind::ERROR_CUSTOM,
178 Some(SyntaxError::Custom {187 Some(SyntaxError::Custom {
179 error: msg.as_ref().to_owned(),188 error: msg.as_ref().to_owned(),
180 }),189 }),
190 previous_pos,
181 )191 )
182 }192 }
183}193}
modifiedcrates/jrsonnet-rowan-parser/src/parser.rsdiffbeforeafterboth
45 error: String,45 error: String,
46 },46 },
47}47}
48impl fmt::Display for SyntaxError {
49 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
50 match self {
51 SyntaxError::Unexpected { expected, found } => {
52 write!(f, "unexpected {found:?}, expecting {expected}")
53 }
54 SyntaxError::Missing { expected } => write!(f, "missing {expected}"),
55 SyntaxError::Custom { error } => write!(f, "{error}"),
56 SyntaxError::Hint { error } => write!(f, "{error}"),
57 }
58 }
59}
4860
49#[derive(Debug)]61#[derive(Debug)]
50pub struct LocatedSyntaxError {62pub struct LocatedSyntaxError {
316 break;328 break;
317 }329 }
330
331 let m = lhs.wrap(p, EXPR, false);
318332
319 // Object apply is not a real operator, we dont have something to bump333 // Object apply is not a real operator, we dont have something to bump
320 if op != BinaryOperatorKind::MetaObjectApply {334 if op != BinaryOperatorKind::MetaObjectApply {
321 p.bump();335 p.bump();
322 }336 }
323337
324 let m = lhs.wrap(p, EXPR).precede(p);338 let m = m.precede(p);
325 let parsed_rhs = expr_binding_power(p, right_binding_power)339 let parsed_rhs = expr_binding_power(p, right_binding_power)
326 .map(|v| v.precede(p).complete(p, EXPR))340 .map(|v| v.precede(p).complete(p, EXPR))
327 .is_ok();341 .is_ok();
491 errored.wrap_error(505 errored.wrap_error(
492 p,506 p,
493 "compspec may only be used if there is only one object element",507 "compspec may only be used if there is only one object element",
508 true,
494 );509 );
495 }510 }
496 m.complete(p, OBJ_BODY_MEMBER_LIST);511 m.complete(p, OBJ_BODY_MEMBER_LIST);
497 } else if !compspecs.is_empty() {512 } else if !compspecs.is_empty() {
498 for errored in asserts {513 for errored in asserts {
499 errored.wrap_error(p, "asserts can't be used in object comprehensions");514 errored.wrap_error(p, "asserts can't be used in object comprehensions", true);
500 }515 }
501 m.complete(p, OBJ_BODY_COMP);516 m.complete(p, OBJ_BODY_COMP);
502 } else {517 } else {
569 }584 }
570585
571 for errored in unnamed_after_named {586 for errored in unnamed_after_named {
572 errored.wrap_error(p, "can't use positional arguments after named");587 errored.wrap_error(p, "can't use positional arguments after named", true);
573 }588 }
574589
575 m.complete(p, ARGS_DESC);590 m.complete(p, ARGS_DESC);
615 spec.wrap_error(630 spec.wrap_error(
616 p,631 p,
617 "compspec may only be used if there is only one array element",632 "compspec may only be used if there is only one array element",
633 true,
618 );634 );
619 }635 }
620636
639 p.bump();655 p.bump();
640 // End656 // End
641 if !p.at(T![']']) {657 if !p.at(T![']']) {
642 expr(p).wrap(p, SLICE_DESC_END);658 expr(p).wrap(p, SLICE_DESC_END, true);
643 }659 }
644 if p.at(T![:]) {660 if p.at(T![:]) {
645 p.bump();661 p.bump();
646 // Step662 // Step
647 if !p.at(T![']']) {663 if !p.at(T![']']) {
648 expr(p).wrap(p, SLICE_DESC_STEP);664 expr(p).wrap(p, SLICE_DESC_STEP, true);
649 }665 }
650 }666 }
651 } else if p.at(T![::]) {667 } else if p.at(T![::]) {
652 p.bump();668 p.bump();
653 // End669 // End
654 if !p.at(T![']']) {670 if !p.at(T![']']) {
655 expr(p).wrap(p, SLICE_DESC_END);671 expr(p).wrap(p, SLICE_DESC_END, true);
656 }672 }
657 } else {673 } else {
658 // It was not a slice674 // It was not a slice
865 p.bump();881 p.bump();
866 expr(p);882 expr(p);
867 p.expect(T![then]);883 p.expect(T![then]);
868 expr(p).wrap(p, TRUE_EXPR);884 expr(p).wrap(p, TRUE_EXPR, true);
869 if p.at(T![else]) {885 if p.at(T![else]) {
870 p.bump();886 p.bump();
871 expr(p).wrap(p, FALSE_EXPR);887 expr(p).wrap(p, FALSE_EXPR, true);
872 }888 }
873 m.complete(p, EXPR_IF_THEN_ELSE)889 m.complete(p, EXPR_IF_THEN_ELSE)
874 } else if p.at(T!['[']) {890 } else if p.at(T!['[']) {
modifiedcrates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__arr_compspec_incompatible_with_multiple_elems.snapdiffbeforeafterboth
49===49===
50LocatedSyntaxError { error: Custom { error: "compspec may only be used if there is only one array element" }, range: 3..21 }50LocatedSyntaxError { error: Custom { error: "compspec may only be used if there is only one array element" }, range: 3..21 }
51===51===
52 x syntax error52 · ╭──────────────────── compspec may only be used if there is only one array element
53 ,----
54 1 | [a for a in [1, 2, 3], b]
55 : ^^^^^^^^^|^^^^^^^^
56 : `-- compspec may only be used if there is only one array element
57 `----531 │ [a for a in [1, 2, 3], b]
5854
modifiedcrates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__arr_compspec_incompatible_with_multiple_elems_w.snapdiffbeforeafterboth
56===56===
57LocatedSyntaxError { error: Custom { error: "compspec may only be used if there is only one array element" }, range: 7..25 }57LocatedSyntaxError { error: Custom { error: "compspec may only be used if there is only one array element" }, range: 7..25 }
58===58===
59 x syntax error59 · ╭──────────────────── compspec may only be used if there is only one array element
60 ,----
61 1 | [a, b, for a in [1, 2, 3], c]
62 : ^^^^^^^^^|^^^^^^^^
63 : `-- compspec may only be used if there is only one array element
64 `----601 │ [a, b, for a in [1, 2, 3], c]
6561
modifiedcrates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__arr_compspec_no_elems.snapdiffbeforeafterboth
39===39===
40LocatedSyntaxError { error: Missing { expected: Named("expression") }, range: 1..1 }40LocatedSyntaxError { error: Missing { expected: Named("expression") }, range: 1..1 }
41===41===
42 x syntax error42 · ╭── missing expression
43 ,----
44 1 | [for a in [1, 2, 3]]431 │ [for a in [1, 2, 3]]
45 : ^
46 : `-- missing expression
47 `----
4844
modifiedcrates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__continue_after_total_failure.snapdiffbeforeafterboth
64LocatedSyntaxError { error: Unexpected { expected: Unnamed(SyntaxKindSet([L_BRACK, L_PAREN, L_BRACE, SEMI, DOT, COMMA, QUESTION_MARK])), found: IDENT }, range: 14..23 }64LocatedSyntaxError { error: Unexpected { expected: Unnamed(SyntaxKindSet([L_BRACK, L_PAREN, L_BRACE, SEMI, DOT, COMMA, QUESTION_MARK])), found: IDENT }, range: 14..23 }
65LocatedSyntaxError { error: Custom { error: "unexpected tokens after end" }, range: 29..67 }65LocatedSyntaxError { error: Custom { error: "unexpected tokens after end" }, range: 29..67 }
66===66===
67 x syntax error67 · ╭─────────── unexpected IDENT, expecting L_BRACK, L_PAREN, L_BRACE, SEMI, DOT, COMMA or QUESTION_MARK
68 ,-[1:15]
69 1 | ,-> local intr = $intrinsic(test);
70 : | ^^^^|^^^^
71 : | `-- expected L_BRACK, L_PAREN, L_BRACE, SEMI, DOT, COMMA or QUESTION_MARK, found IDENT681 │ ╭─local intr = $intrinsic(test);
72 2 | |
73 3 | | local a = 1, b = 2, c = a + b;692 │ │
703 │ │ local a = 1, b = 2, c = a + b;
74 4 | |714 │ │
75 5 | |-> [c]725 │ ╰─[c] 🢒 unexpected tokens after end
76 : `---- unexpected tokens after end
77 `----
7873
modifiedcrates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__empty.snapdiffbeforeafterboth
9===9===
10LocatedSyntaxError { error: Missing { expected: Named("expression") }, range: 1..1 }10LocatedSyntaxError { error: Missing { expected: Named("expression") }, range: 1..1 }
11===11===
12 x syntax error12 · ╭── missing expression
13 ,----
14 1 |
15 : ^
16 : `-- missing expression
17 `----131 │
1814
modifiedcrates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__function_error_body.snapdiffbeforeafterboth
25===25===
26LocatedSyntaxError { error: Missing { expected: Named("expression") }, range: 15..15 }26LocatedSyntaxError { error: Missing { expected: Named("expression") }, range: 15..15 }
27===27===
28 x syntax error28 · ╭── missing expression
29 ,----
30 1 | function(a, b)
31 : ^
32 : `-- missing expression
33 `----291 │ function(a, b)
3430
modifiedcrates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__function_error_no_value.snapdiffbeforeafterboth
42===42===
43LocatedSyntaxError { error: Missing { expected: Named("expression") }, range: 16..16 }43LocatedSyntaxError { error: Missing { expected: Named("expression") }, range: 16..16 }
44===44===
45 x syntax error45 · ╭── missing expression
46 ,----
47 1 | function(a, b = ) a + b
48 : ^
49 : `-- missing expression461 │ function(a, b = ) a + b
50 `----
5147
modifiedcrates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__function_error_rparen.snapdiffbeforeafterboth
26LocatedSyntaxError { error: Missing { expected: Unnamed(SyntaxKindSet([R_PAREN, COMMA, ASSIGN])) }, range: 14..14 }26LocatedSyntaxError { error: Missing { expected: Unnamed(SyntaxKindSet([R_PAREN, COMMA, ASSIGN])) }, range: 14..14 }
27LocatedSyntaxError { error: Missing { expected: Named("expression") }, range: 14..14 }27LocatedSyntaxError { error: Missing { expected: Named("expression") }, range: 14..14 }
28===28===
29 x syntax error29 · ╭── missing R_PAREN, COMMA or ASSIGN
30 ,----
31 1 | function(a, b
32 : ^^
33 : |`-- missing expression301 │ function(a, b
34 : `-- missing R_PAREN, COMMA or ASSIGN31 · ╰── missing expression
35 `----
3632
modifiedcrates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__local_no_value_recovery.snapdiffbeforeafterboth
39LocatedSyntaxError { error: Missing { expected: Unnamed(SyntaxKindSet([L_BRACK, L_PAREN, L_BRACE, SEMI, DOT, COMMA, QUESTION_MARK])) }, range: 25..25 }39LocatedSyntaxError { error: Missing { expected: Unnamed(SyntaxKindSet([L_BRACK, L_PAREN, L_BRACE, SEMI, DOT, COMMA, QUESTION_MARK])) }, range: 25..25 }
40LocatedSyntaxError { error: Missing { expected: Named("expression") }, range: 25..25 }40LocatedSyntaxError { error: Missing { expected: Named("expression") }, range: 25..25 }
41===41===
42 x syntax error421 │ local a =
43 ,-[3:3]
44 2 | local b = 3;432 │ local b = 3;
45 3 | 144 · ╭── missing L_BRACK, L_PAREN, L_BRACE, SEMI, DOT, COMMA or QUESTION_MARK
46 : ^^
47 : |`-- missing expression
48 : `-- missing L_BRACK, L_PAREN, L_BRACE, SEMI, DOT, COMMA or QUESTION_MARK
49 `----453 │ 1
46 · ╰── missing expression
5047
modifiedcrates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__local_novalue.snapdiffbeforeafterboth
23LocatedSyntaxError { error: Missing { expected: Unnamed(SyntaxKindSet([SEMI, COMMA])) }, range: 10..10 }23LocatedSyntaxError { error: Missing { expected: Unnamed(SyntaxKindSet([SEMI, COMMA])) }, range: 10..10 }
24LocatedSyntaxError { error: Missing { expected: Named("expression") }, range: 10..10 }24LocatedSyntaxError { error: Missing { expected: Named("expression") }, range: 10..10 }
25===25===
26 x syntax error26 · ╭── missing SEMI or COMMA
27 ,----
28 1 | local a =
29 : ^^^
30 : `-- missing expression27 · ┟── missing expression
31 : |`-- missing SEMI or COMMA281 │ local a =
32 : `-- missing expression29 · ╰── missing expression
33 `----
3430
modifiedcrates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__named_before_positional.snapdiffbeforeafterboth
68LocatedSyntaxError { error: Custom { error: "can't use positional arguments after named" }, range: 16..17 }68LocatedSyntaxError { error: Custom { error: "can't use positional arguments after named" }, range: 16..17 }
69LocatedSyntaxError { error: Custom { error: "can't use positional arguments after named" }, range: 27..28 }69LocatedSyntaxError { error: Custom { error: "can't use positional arguments after named" }, range: 27..28 }
70===70===
71 x syntax error71 · ╭────── can't use positional arguments after named
72 ,----
73 1 | a(1, 2, b=4, 3, 5, k = 12, 6)
74 : | | |
75 : | | `-- can't use positional arguments after named72 · │ ╭─── can't use positional arguments after named
76 : | `-- can't use positional arguments after named731 │ a(1, 2, b=4, 3, 5, k = 12, 6)
77 : `-- can't use positional arguments after named74 · ╰─── can't use positional arguments after named
78 `----
7975
modifiedcrates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__no_lhs.snapdiffbeforeafterboth
14LocatedSyntaxError { error: Missing { expected: Named("expression") }, range: 0..0 }14LocatedSyntaxError { error: Missing { expected: Named("expression") }, range: 0..0 }
15LocatedSyntaxError { error: Custom { error: "unexpected tokens after end" }, range: 0..3 }15LocatedSyntaxError { error: Custom { error: "unexpected tokens after end" }, range: 0..3 }
16===16===
17 x syntax error17 · ╭── missing expression
18 ,----
19 1 | + 2181 │ + 2
20 : ^^|19 · ╰───── unexpected tokens after end
21 : | `-- unexpected tokens after end
22 : `-- missing expression
23 `----
2420
modifiedcrates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__no_operator.snapdiffbeforeafterboth
13===13===
14LocatedSyntaxError { error: Custom { error: "unexpected tokens after end" }, range: 2..3 }14LocatedSyntaxError { error: Custom { error: "unexpected tokens after end" }, range: 2..3 }
15===15===
16 x syntax error16 · ╭─── unexpected tokens after end
17 ,----
18 1 | 2 2
19 : |
20 : `-- unexpected tokens after end
21 `----171 │ 2 2
2218
modifiedcrates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__no_rhs.snapdiffbeforeafterboth
16===16===
17LocatedSyntaxError { error: Missing { expected: Named("expression") }, range: 4..4 }17LocatedSyntaxError { error: Missing { expected: Named("expression") }, range: 4..4 }
18===18===
19 x syntax error19 · ╭── missing expression
20 ,----
21 1 | a +
22 : ^
23 : `-- missing expression
24 `----201 │ a +
2521
modifiedcrates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__obj_compspec_incompatible_with_asserts.snapdiffbeforeafterboth
56===56===
57LocatedSyntaxError { error: Custom { error: "asserts can't be used in object comprehensions" }, range: 1..9 }57LocatedSyntaxError { error: Custom { error: "asserts can't be used in object comprehensions" }, range: 1..9 }
58===58===
59 x syntax error59 · ╭────────── asserts can't be used in object comprehensions
60 ,----
61 1 | {assert 1, a: 1 for a in [1,2,3]}601 │ {assert 1, a: 1 for a in [1,2,3]}
62 : ^^^^|^^^
63 : `-- asserts can't be used in object comprehensions
64 `----
6561
modifiedcrates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__obj_compspec_incompatible_with_multiple_elems.snapdiffbeforeafterboth
58===58===
59LocatedSyntaxError { error: Custom { error: "compspec may only be used if there is only one object element" }, range: 5..23 }59LocatedSyntaxError { error: Custom { error: "compspec may only be used if there is only one object element" }, range: 5..23 }
60===60===
61 x syntax error61 · ╭──────────────────── compspec may only be used if there is only one object element
62 ,----
63 1 | {a:1 for a in [1, 2, 3], b:1}
64 : ^^^^^^^^^|^^^^^^^^
65 : `-- compspec may only be used if there is only one object element
66 `----621 │ {a:1 for a in [1, 2, 3], b:1}
6763
modifiedcrates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__obj_compspec_incompatible_with_multiple_elems_w.snapdiffbeforeafterboth
69===69===
70LocatedSyntaxError { error: Custom { error: "compspec may only be used if there is only one object element" }, range: 11..29 }70LocatedSyntaxError { error: Custom { error: "compspec may only be used if there is only one object element" }, range: 11..29 }
71===71===
72 x syntax error72 · ╭──────────────────── compspec may only be used if there is only one object element
73 ,----
74 1 | {a:1, b:1, for a in [1, 2, 3], c:1}
75 : ^^^^^^^^^|^^^^^^^^
76 : `-- compspec may only be used if there is only one object element
77 `----731 │ {a:1, b:1, for a in [1, 2, 3], c:1}
7874
modifiedcrates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__obj_compspec_no_elems.snapdiffbeforeafterboth
39===39===
40LocatedSyntaxError { error: Missing { expected: Named("field definition") }, range: 1..1 }40LocatedSyntaxError { error: Missing { expected: Named("field definition") }, range: 1..1 }
41===41===
42 x syntax error42 · ╭── missing field definition
43 ,----
44 1 | {for a in [1, 2, 3]}431 │ {for a in [1, 2, 3]}
45 : ^
46 : `-- missing field definition
47 `----
4844
deletedcrates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__stdlib.snapdiffbeforeafterboth

no changes

addedcrates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__super_nesting.snapdiffbeforeafterboth

no changes

modifiedcrates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__unexpected_destruct.snapdiffbeforeafterboth
25===25===
26LocatedSyntaxError { error: Unexpected { expected: Named("destruction specifier"), found: MUL }, range: 6..7 }26LocatedSyntaxError { error: Unexpected { expected: Named("destruction specifier"), found: MUL }, range: 6..7 }
27===27===
28 x syntax error28 · ╭─── unexpected MUL, expecting destruction specifier
29 ,-[1:7]
30 1 | local * = 1;
31 : |
32 : `-- expected destruction specifier, found MUL291 │ local * = 1;
33 2 | a302 │ a
34 `----
3531
modifiedcrates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__wrong_field_end.snapdiffbeforeafterboth
38LocatedSyntaxError { error: Unexpected { expected: Named("comma"), found: SEMI }, range: 7..8 }38LocatedSyntaxError { error: Unexpected { expected: Named("comma"), found: SEMI }, range: 7..8 }
39LocatedSyntaxError { error: Unexpected { expected: Named("comma"), found: SEMI }, range: 14..15 }39LocatedSyntaxError { error: Unexpected { expected: Named("comma"), found: SEMI }, range: 14..15 }
40===40===
41 x syntax error411 │ {
42 ,-[2:6]42 · ╭─── unexpected SEMI, expecting comma
43 1 | {
44 2 | a: 1;
45 : |432 │ a: 1;
46 : `-- expected comma, found SEMI44 · ╭─── unexpected SEMI, expecting comma
47 3 | b: 2;453 │ b: 2;
48 : |
49 : `-- expected comma, found SEMI
50 4 | }464 │ }
51 `----
5247
modifiedcrates/jrsonnet-rowan-parser/src/tests.rsdiffbeforeafterboth
1// `never`1// `never`
2#![cfg(any())]2#![cfg(test)]
33
4use miette::{4use hi_doc::{Formatting, SnippetBuilder, Text};
5 Diagnostic, GraphicalReportHandler, GraphicalTheme, LabeledSpan, ThemeCharacters, ThemeStyles,
6};
7use thiserror::Error;5use thiserror::Error;
86
9use crate::{parse, AstNode};7use crate::{parse, AstNode};
10
11#[derive(Debug, Error)]
12#[error("syntax error")]
13struct MyDiagnostic {
14 code: String,
15 spans: Vec<LabeledSpan>,
16}
17impl Diagnostic for MyDiagnostic {
18 fn code<'a>(&'a self) -> Option<Box<dyn std::fmt::Display + 'a>> {
19 None
20 }
21
22 fn severity(&self) -> Option<miette::Severity> {
23 None
24 }
25
26 fn help<'a>(&'a self) -> Option<Box<dyn std::fmt::Display + 'a>> {
27 None
28 }
29
30 fn url<'a>(&'a self) -> Option<Box<dyn std::fmt::Display + 'a>> {
31 None
32 }
33
34 fn source_code(&self) -> Option<&dyn miette::SourceCode> {
35 Some(&self.code)
36 }
37
38 fn labels(&self) -> Option<Box<dyn Iterator<Item = miette::LabeledSpan> + '_>> {
39 Some(Box::new(self.spans.clone().into_iter()))
40 }
41
42 fn related<'a>(&'a self) -> Option<Box<dyn Iterator<Item = &'a dyn Diagnostic> + 'a>> {
43 None
44 }
45}
468
47fn process(text: &str) -> String {9fn process(text: &str) -> String {
48 use std::fmt::Write;10 use std::fmt::Write;
63 }25 }
64 code += " ";26 code += " ";
6527
66 let diag = MyDiagnostic {28 let mut s = SnippetBuilder::new(code);
67 code,29
30 for error in errors {
68 spans: errors.into_iter().map(|e| e.into()).collect(),31 s.error(Text::fragment(
32 format!("{}", error.error),
33 Formatting::default(),
34 ))
35 .range(error.range.start().into()..=error.range.end().into())
36 .build();
69 };37 }
7038
39 writeln!(out, "===").unwrap();
71 let handler = GraphicalReportHandler::new_themed(GraphicalTheme {40 let ansi = hi_doc::source_to_ansi(&s.build());
72 characters: ThemeCharacters::ascii(),
73 styles: ThemeStyles::none(),
74 });
75
76 writeln!(out, "===").unwrap();41 let text = strip_ansi_escapes::strip_str(&ansi);
77 handler
78 .render_report(&mut out, &diag)42 out.push_str(&text);
79 .expect("fmt error?..");
80 }43 }
81 out.split('\n')44 out.split('\n')
82 .map(|s| s.trim_end().to_string())45 .map(|s| s.trim_end().to_string())
238 [c]201 [c]
239 "#202 "#
203
204 super_nesting => r#"
205 super.a + super.b
206 "#
240);207);
241208
242#[test]
243fn stdlib() {
244 let src = include_str!("../../jrsonnet-stdlib/src/std.jsonnet");
245 let result = process(src);
246 insta::assert_snapshot!("stdlib", result, src);
247}
248#[test]209#[test]
249fn eval_simple() {210fn eval_simple() {
250 let src = "local a = 1, b = 2; a + local c = 1; c";211 let src = "local a = 1, b = 2; a + local c = 1; c";