difftreelog
fix various parsing fixes
in: master
4 files changed
cmds/jrsonnet-fmt/src/main.rsdiffbeforeafterboth--- a/cmds/jrsonnet-fmt/src/main.rs
+++ b/cmds/jrsonnet-fmt/src/main.rs
@@ -4,14 +4,18 @@
io::{self, Write},
path::PathBuf,
process,
+ rc::Rc,
};
use children::{children_between, trivia_before};
use clap::Parser;
-use dprint_core::formatting::{PrintItems, PrintOptions};
+use dprint_core::formatting::{
+ condition_helpers::is_multiple_lines, condition_resolvers::true_resolver,
+ ConditionResolverContext, LineNumber, PrintItems, PrintOptions,
+};
use jrsonnet_rowan_parser::{
nodes::{
- ArgsDesc, Assertion, BinaryOperator, Bind, CompSpec, Destruct, DestructArrayPart,
+ Arg, ArgsDesc, Assertion, BinaryOperator, Bind, CompSpec, Destruct, DestructArrayPart,
DestructRest, Expr, ExprBase, FieldName, ForSpec, IfSpec, ImportKind, Literal, Member,
Name, Number, ObjBody, ObjLocal, ParamsDesc, SliceDesc, SourceFile, Stmt, Suffix, Text,
UnaryOperator, Visibility,
@@ -64,6 +68,55 @@
$o.push_signal(dprint_core::formatting::Signal::FinishIndent);
pi!(@s; $o: $($t)*);
}};
+ (@s; $o:ident: info($v:expr) $($t:tt)*) => {{
+ $o.push_info($v);
+ pi!(@s; $o: $($t)*);
+ }};
+ (@s; $o:ident: if($s:literal, $cond:expr, $($i:tt)*) $($t:tt)*) => {{
+ $o.push_condition(dprint_core::formatting::conditions::if_true(
+ $s,
+ $cond.clone(),
+ {
+ let mut o = PrintItems::new();
+ p!(o, $($i)*);
+ o
+ },
+ ));
+ pi!(@s; $o: $($t)*);
+ }};
+ (@s; $o:ident: if_else($s:literal, $cond:expr, $($i:tt)*)($($e:tt)+) $($t:tt)*) => {{
+ $o.push_condition(dprint_core::formatting::conditions::if_true_or(
+ $s,
+ $cond.clone(),
+ {
+ let mut o = PrintItems::new();
+ p!(o, $($i)*);
+ o
+ },
+ {
+ let mut o = PrintItems::new();
+ p!(o, $($e)*);
+ o
+ },
+ ));
+ pi!(@s; $o: $($t)*);
+ }};
+ (@s; $o:ident: if_not($s:literal, $cond:expr, $($e:tt)*) $($t:tt)*) => {{
+ $o.push_condition(dprint_core::formatting::conditions::if_true_or(
+ $s,
+ $cond.clone(),
+ {
+ let o = PrintItems::new();
+ o
+ },
+ {
+ let mut o = PrintItems::new();
+ p!(o, $($e)*);
+ o
+ },
+ ));
+ pi!(@s; $o: $($t)*);
+ }};
(@s; $o:ident: {$expr:expr} $($t:tt)*) => {{
$expr.print($o);
pi!(@s; $o: $($t)*);
@@ -244,14 +297,38 @@
}
impl Printable for ArgsDesc {
fn print(&self, out: &mut PrintItems) {
- p!(out, str("(") >i nl);
- for arg in self.args() {
+ let start = LineNumber::new("start");
+ let end = LineNumber::new("end");
+ let multi_line = Rc::new(move |condition_context: &mut ConditionResolverContext| {
+ is_multiple_lines(condition_context, start, end).map(|v| !v)
+ });
+ p!(out, str("(") info(start) if("start args", multi_line, >i nl));
+ let (children, end_comments) = children_between::<Arg>(
+ self.syntax().clone(),
+ self.l_paren_token().map(Into::into).as_ref(),
+ self.r_paren_token().map(Into::into).as_ref(),
+ None,
+ );
+ let mut args = children.into_iter().peekable();
+ while let Some(ele) = args.next() {
+ if ele.should_start_with_newline {
+ p!(out, nl);
+ }
+ format_comments(&ele.before_trivia, CommentLocation::AboveItem, out);
+ let arg = ele.value;
if arg.name().is_some() || arg.assign_token().is_some() {
p!(out, {arg.name()} str(" = "));
}
- p!(out, {arg.expr()} str(",") nl)
+ let comma_between = if args.peek().is_some() {
+ true_resolver()
+ } else {
+ multi_line.clone()
+ };
+ p!(out, {arg.expr()} if("arg comma", comma_between, str(",") if_not("between args", multi_line, str(" "))));
+ format_comments(&ele.inline_trivia, CommentLocation::ItemInline, out);
+ p!(out, if("between args", multi_line, nl));
}
- p!(out, <i str(")"));
+ p!(out, if("end args", multi_line, <i info(end)) str(")"));
}
}
impl Printable for SliceDesc {
@@ -513,6 +590,7 @@
format_comments(&bind.before_trivia, CommentLocation::AboveItem, out);
p!(out, {bind.value} str(","));
format_comments(&bind.inline_trivia, CommentLocation::ItemInline, out);
+ p!(out, nl)
}
if end_comments.should_start_with_newline {
p!(out, nl)
cmds/jrsonnet-fmt/src/tests.rsdiffbeforeafterboth--- a/cmds/jrsonnet-fmt/src/tests.rs
+++ b/cmds/jrsonnet-fmt/src/tests.rs
@@ -21,55 +21,6 @@
)
}
-macro_rules! assert_formatted {
- ($input:literal, $output:literal) => {
- let formatted = reformat(indoc!($input));
- let mut expected = indoc!($output).to_owned();
- expected.push('\n');
- if formatted != expected {
- panic!(
- "bad formatting, expected\n```\n{formatted}\n```\nto be equal to\n```\n{expected}\n```",
- )
- }
- };
-}
-
-#[test]
-fn padding_stripped_for_multiline_comment() {
- assert_formatted!(
- "{
- /*
- Hello
- World
- */
- _: null,
- }",
- "{
- /*
- Hello
- World
- */
- _: null,
- }"
- );
-}
-
-#[test]
-fn last_comment_respects_spacing_with_inline_comment_above() {
- assert_formatted!(
- "{
- a: '', // Inline
-
- // Comment
- }",
- "{
- a: '', // Inline
-
- // Comment
- }"
- );
-}
-
#[test]
fn complex_comments_snapshot() {
insta::assert_display_snapshot!(reformat(indoc!(
crates/jrsonnet-rowan-parser/src/parser.rsdiffbeforeafterboth--- a/crates/jrsonnet-rowan-parser/src/parser.rs
+++ b/crates/jrsonnet-rowan-parser/src/parser.rs
@@ -450,7 +450,7 @@
p.bump();
break;
}
- if p.at_ts(COMPSPEC) {
+ if p.at_ts(TS![for]) {
if elems == 0 {
let m = p.start();
m.complete_missing(p, ExpectedSyntax::Named("field definition"));
@@ -612,7 +612,7 @@
p.bump();
break;
}
- if elems != 0 && p.at_ts(COMPSPEC) {
+ if elems != 0 && p.at_ts(TS![for]) {
while p.at_ts(COMPSPEC) {
compspecs.push(compspec(p));
}
crates/jrsonnet-rowan-parser/src/tests.rsdiffbeforeafterboth1#![cfg(test)]23use miette::{4 Diagnostic, GraphicalReportHandler, GraphicalTheme, LabeledSpan, ThemeCharacters, ThemeStyles,5};6use thiserror::Error;78use crate::{parse, AstNode};910#[derive(Debug, Error)]11#[error("syntax error")]12struct MyDiagnostic {13 code: String,14 spans: Vec<LabeledSpan>,15}16impl Diagnostic for MyDiagnostic {17 fn code<'a>(&'a self) -> Option<Box<dyn std::fmt::Display + 'a>> {18 None19 }2021 fn severity(&self) -> Option<miette::Severity> {22 None23 }2425 fn help<'a>(&'a self) -> Option<Box<dyn std::fmt::Display + 'a>> {26 None27 }2829 fn url<'a>(&'a self) -> Option<Box<dyn std::fmt::Display + 'a>> {30 None31 }3233 fn source_code(&self) -> Option<&dyn miette::SourceCode> {34 Some(&self.code)35 }3637 fn labels(&self) -> Option<Box<dyn Iterator<Item = miette::LabeledSpan> + '_>> {38 Some(Box::new(self.spans.clone().into_iter()))39 }4041 fn related<'a>(&'a self) -> Option<Box<dyn Iterator<Item = &'a dyn Diagnostic> + 'a>> {42 None43 }44}4546fn process(text: &str) -> String {47 use std::fmt::Write;48 let mut out = String::new();49 let (node, errors) = parse(text);50 write!(out, "{:#?}", node.syntax()).unwrap();51 if !errors.is_empty() && !text.is_empty() {52 writeln!(out, "===").unwrap();53 for err in &errors {54 writeln!(out, "{:?}", err).unwrap();55 }56 let mut code = text.to_string();5758 // Prettier errors at EOF position59 if code.ends_with('\n') {60 code.truncate(code.len() - 1);61 code += " ";62 }63 code += " ";6465 let diag = MyDiagnostic {66 code,67 spans: errors.into_iter().map(|e| e.into()).collect(),68 };6970 let handler = GraphicalReportHandler::new_themed(GraphicalTheme {71 characters: ThemeCharacters::ascii(),72 styles: ThemeStyles::none(),73 });7475 writeln!(out, "===").unwrap();76 handler77 .render_report(&mut out, &diag)78 .expect("fmt error?..");79 }80 out.split('\n')81 .map(|s| s.trim_end().to_string())82 .collect::<Vec<String>>()83 .join("\n")84 .trim_end()85 .to_string()86}87macro_rules! mk_test {88 ($($name:ident => $test:expr)+) => {$(89 #[test]90 fn $name() {91 let src = indoc::indoc!($test);92 let result = process(&src);93 insta::assert_snapshot!(stringify!($name), result, src);9495 }96 )+};97 }98mk_test!(99 empty => r#" "#100 function => r#"101 function(a, b = 1) a + b102 "#103 function_error_no_value => r#"104 function(a, b = ) a + b105 "#106 function_error_rparen => r#"107 function(a, b108 "#109 function_error_body => r#"110 function(a, b)111 "#112 local_novalue => r#"113 local a =114 "#115 local_no_value_recovery => r#"116 local a =117 local b = 3;118 1119 "#120121122 no_rhs => r#"123 a +124 "#125 no_lhs => r#"126 + 2127 "#128 no_operator => "129 2 2130 "131132 named_before_positional => "133 a(1, 2, b=4, 3, 5, k = 12, 6)134 "135136 wrong_field_end => "137 {138 a: 1;139 b: 2;140 }141 "142143144 plain_call => "145 std.substr(a, 0, std.length(b)) == b146 "147148 destruct => "149 local [a, b, c] = arr;150 local [a, ...] = arr_rest;151 local [..., a] = rest_arr;152 local [...] = rest_in_arr;153 local [a, ...n] = arr_rest_n;154 local [...n, a] = rest_arr_n;155 local [...n] = rest_in_arr_n;156157 local {a, b, c} = obj;158 local {a, b, c, ...} = obj_rest;159 local {a, b, c, ...n} = obj_rest_n;160161 null162 "163164 str_block_missing_indent => "165 |||166 "167 str_block_missing_termination => "168 |||169 hello170 "171 str_block_missing_newline => "172 |||hello173 "174 str_block_missing_indent_text => "175 |||176 hello177 "178179 unexpected_destruct => "180 local * = 1;181 a182 "183 arr_compspec => r#"184 [a for a in [1, 2, 3]]185 "#186 arr_compspec_comma => "187 [a, for a in [1, 2, 3]]188 "189 arr_compspec_no_elems => "190 [for a in [1, 2, 3]]191 "192 arr_compspec_incompatible_with_multiple_elems => r#"193 [a for a in [1, 2, 3], b]194 "#195 arr_compspec_incompatible_with_multiple_elems_w => r#"196 [a, b, for a in [1, 2, 3], c]197 "#198199 obj_compspec => r#"200 {a:1 for a in [1, 2, 3]}201 "#202 obj_compspec_comma => "203 {a:1, for a in [1, 2, 3]}204 "205 obj_compspec_no_elems => "206 {for a in [1, 2, 3]}207 "208 obj_compspec_incompatible_with_multiple_elems => r#"209 {a:1 for a in [1, 2, 3], b:1}210 "#211 obj_compspec_incompatible_with_multiple_elems_w => r#"212 {a:1, b:1, for a in [1, 2, 3], c:1}213 "#214215 obj_compspec_incompatible_with_asserts => r#"216 {assert 1, a: 1 for a in [1,2,3]}217 "#218219 local_method => r#"220 local221 a(x) = x,222 a = function(x) x,223 ; c224 "#225 obj_method => r#"226 {227 a(x): x,228 a: function(x) x,229 }230 "#231232 continue_after_total_failure => r#"233 local intr = $intrinsic(test);234235 local a = 1, b = 2, c = a + b;236237 [c]238 "#239);240241#[test]242fn stdlib() {243 let src = include_str!("../../jrsonnet-stdlib/src/std.jsonnet");244 let result = process(src);245 insta::assert_snapshot!("stdlib", result, src);246}247#[test]248fn eval_simple() {249 let src = "local a = 1, b = 2; a + local c = 1; c";250 let (node, errors) = parse(src);251 assert!(errors.is_empty());252253 dbg!(node);254}1#![cfg(test)]23use miette::{4 Diagnostic, GraphicalReportHandler, GraphicalTheme, LabeledSpan, ThemeCharacters, ThemeStyles,5};6use thiserror::Error;78use crate::{parse, AstNode};910#[derive(Debug, Error)]11#[error("syntax error")]12struct MyDiagnostic {13 code: String,14 spans: Vec<LabeledSpan>,15}16impl Diagnostic for MyDiagnostic {17 fn code<'a>(&'a self) -> Option<Box<dyn std::fmt::Display + 'a>> {18 None19 }2021 fn severity(&self) -> Option<miette::Severity> {22 None23 }2425 fn help<'a>(&'a self) -> Option<Box<dyn std::fmt::Display + 'a>> {26 None27 }2829 fn url<'a>(&'a self) -> Option<Box<dyn std::fmt::Display + 'a>> {30 None31 }3233 fn source_code(&self) -> Option<&dyn miette::SourceCode> {34 Some(&self.code)35 }3637 fn labels(&self) -> Option<Box<dyn Iterator<Item = miette::LabeledSpan> + '_>> {38 Some(Box::new(self.spans.clone().into_iter()))39 }4041 fn related<'a>(&'a self) -> Option<Box<dyn Iterator<Item = &'a dyn Diagnostic> + 'a>> {42 None43 }44}4546fn process(text: &str) -> String {47 use std::fmt::Write;48 let mut out = String::new();49 let (node, errors) = parse(text);50 write!(out, "{:#?}", node.syntax()).unwrap();51 if !errors.is_empty() && !text.is_empty() {52 writeln!(out, "===").unwrap();53 for err in &errors {54 writeln!(out, "{:?}", err).unwrap();55 }56 let mut code = text.to_string();5758 // Prettier errors at EOF position59 if code.ends_with('\n') {60 code.truncate(code.len() - 1);61 code += " ";62 }63 code += " ";6465 let diag = MyDiagnostic {66 code,67 spans: errors.into_iter().map(|e| e.into()).collect(),68 };6970 let handler = GraphicalReportHandler::new_themed(GraphicalTheme {71 characters: ThemeCharacters::ascii(),72 styles: ThemeStyles::none(),73 });7475 writeln!(out, "===").unwrap();76 handler77 .render_report(&mut out, &diag)78 .expect("fmt error?..");79 }80 out.split('\n')81 .map(|s| s.trim_end().to_string())82 .collect::<Vec<String>>()83 .join("\n")84 .trim_end()85 .to_string()86}87macro_rules! mk_test {88 ($($name:ident => $test:expr)+) => {$(89 #[test]90 fn $name() {91 let src = indoc::indoc!($test);92 let result = process(&src);93 insta::assert_snapshot!(stringify!($name), result, src);9495 }96 )+};97 }98mk_test!(99 empty => r#" "#100 function => r#"101 function(a, b = 1) a + b102 "#103 function_error_no_value => r#"104 function(a, b = ) a + b105 "#106 function_error_rparen => r#"107 function(a, b108 "#109 function_error_body => r#"110 function(a, b)111 "#112 local_novalue => r#"113 local a =114 "#115 local_no_value_recovery => r#"116 local a =117 local b = 3;118 1119 "#120121122 no_rhs => r#"123 a +124 "#125 no_lhs => r#"126 + 2127 "#128 no_operator => "129 2 2130 "131132 named_before_positional => "133 a(1, 2, b=4, 3, 5, k = 12, 6)134 "135136 wrong_field_end => "137 {138 a: 1;139 b: 2;140 }141 "142143144 plain_call => "145 std.substr(a, 0, std.length(b)) == b146 "147148 destruct => "149 local [a, b, c] = arr;150 local [a, ...] = arr_rest;151 local [..., a] = rest_arr;152 local [...] = rest_in_arr;153 local [a, ...n] = arr_rest_n;154 local [...n, a] = rest_arr_n;155 local [...n] = rest_in_arr_n;156157 local {a, b, c} = obj;158 local {a, b, c, ...} = obj_rest;159 local {a, b, c, ...n} = obj_rest_n;160161 null162 "163164 str_block_missing_indent => "165 |||166 "167 str_block_missing_termination => "168 |||169 hello170 "171 str_block_missing_newline => "172 |||hello173 "174 str_block_missing_indent_text => "175 |||176 hello177 "178179 unexpected_destruct => "180 local * = 1;181 a182 "183 arr_compspec => r#"184 [a for a in [1, 2, 3]]185 "#186 arr_compspec_comma => "187 [a, for a in [1, 2, 3]]188 "189 arr_compspec_no_elems => "190 [for a in [1, 2, 3]]191 "192 arr_compspec_incompatible_with_multiple_elems => r#"193 [a for a in [1, 2, 3], b]194 "#195 arr_compspec_incompatible_with_multiple_elems_w => r#"196 [a, b, for a in [1, 2, 3], c]197 "#198199 obj_compspec => r#"200 {a:1 for a in [1, 2, 3]}201 "#202 obj_compspec_comma => "203 {a:1, for a in [1, 2, 3]}204 "205 obj_compspec_no_elems => "206 {for a in [1, 2, 3]}207 "208 obj_compspec_incompatible_with_multiple_elems => r#"209 {a:1 for a in [1, 2, 3], b:1}210 "#211 obj_compspec_incompatible_with_multiple_elems_w => r#"212 {a:1, b:1, for a in [1, 2, 3], c:1}213 "#214215 obj_compspec_incompatible_with_asserts => r#"216 {assert 1, a: 1 for a in [1,2,3]}217 "#218219 local_method => r#"220 local221 a(x) = x,222 a = function(x) x,223 ; c224 "#225 obj_method => r#"226 {227 a(x): x,228 a: function(x) x,229 }230 "#231232 continue_after_total_failure => r#"233 local intr = $intrinsic(test);234235 local a = 1, b = 2, c = a + b;236237 [c]238 "#239);240241#[test]242fn stdlib() {243 let src = include_str!("../../jrsonnet-stdlib/src/std.jsonnet");244 let result = process(src);245 insta::assert_snapshot!("stdlib", result, src);246}247#[test]248fn eval_simple() {249 let src = "local a = 1, b = 2; a + local c = 1; c";250 let (node, _errors) = parse(src);251252 dbg!(node);253}