From 1f4198b9327eef2909a416ee585accdb96ade398 Mon Sep 17 00:00:00 2001 From: Kevin Amado Date: Tue, 22 Feb 2022 21:17:50 -0500 Subject: [PATCH] feat: pattern lambdas done right --- src/alejandra_engine/src/rules/pattern.rs | 495 +++++++++++++------ src/alejandra_engine/tests/cases/comment/out | 6 +- src/alejandra_engine/tests/cases/pattern/out | 210 +++----- 3 files changed, 403 insertions(+), 308 deletions(-) diff --git a/src/alejandra_engine/src/rules/pattern.rs b/src/alejandra_engine/src/rules/pattern.rs index 2aee8fb..634d841 100644 --- a/src/alejandra_engine/src/rules/pattern.rs +++ b/src/alejandra_engine/src/rules/pattern.rs @@ -1,195 +1,175 @@ -pub fn rule( +use std::collections::LinkedList; + +#[derive(Debug)] +struct Argument { + comments_before: LinkedList, + item: Option, + comment_after: Option, +} + +impl Default for Argument { + fn default() -> Argument { + Argument { + comments_before: LinkedList::new(), + item: None, + comment_after: None, + } + } +} + +#[derive(Debug)] +struct Pattern { + initial_at: Option, + comments_after_initial_at: LinkedList, + arguments: LinkedList, + comments_before_curly_b_close: LinkedList, + comments_before_end_at: LinkedList, + end_at: Option, +} + +impl Default for Pattern { + fn default() -> Pattern { + Pattern { + initial_at: None, + comments_after_initial_at: LinkedList::new(), + arguments: LinkedList::new(), + comments_before_curly_b_close: LinkedList::new(), + comments_before_end_at: LinkedList::new(), + end_at: None, + } + } +} + +fn parse( build_ctx: &crate::builder::BuildCtx, node: &rnix::SyntaxNode, -) -> std::collections::LinkedList { - let mut steps = std::collections::LinkedList::new(); +) -> Pattern { + let mut pattern = Pattern::default(); let mut children = crate::children::Children::new_with_configuration( build_ctx, node, true, ); - let has_comments = children.has_comments(); - let has_comments_between_curly_b = node - .children_with_tokens() - .skip_while(|element| { - element.kind() != rnix::SyntaxKind::TOKEN_CURLY_B_OPEN - }) - .take_while(|element| { - element.kind() != rnix::SyntaxKind::TOKEN_CURLY_B_CLOSE - }) - .any(|element| element.kind() == rnix::SyntaxKind::TOKEN_COMMENT); - - let items_count = node - .children_with_tokens() - .filter(|element| { - matches!( - element.kind(), - rnix::SyntaxKind::TOKEN_ELLIPSIS - | rnix::SyntaxKind::NODE_PAT_ENTRY - ) - }) - .count(); - - let max_items = if node - .children_with_tokens() - .any(|element| element.kind() == rnix::SyntaxKind::TOKEN_ELLIPSIS) - { - 2 - } else { - 1 - }; - - let layout = if has_comments || children.has_newlines() { - &crate::config::Layout::Tall - } else { - build_ctx.config.layout() - }; - // x @ - let mut at = false; let child = children.peek_next().unwrap(); if let rnix::SyntaxKind::NODE_PAT_BIND = child.element.kind() { - at = true; - match layout { - crate::config::Layout::Tall => { - steps.push_back(crate::builder::Step::FormatWider( - child.element, - )); - } - crate::config::Layout::Wide => { - steps.push_back(crate::builder::Step::Format(child.element)); - } - } + pattern.initial_at = Some(child.element); children.move_next(); } // /**/ - let mut comment = false; children.drain_comments_and_newlines(|element| match element { crate::children::DrainCommentOrNewline::Comment(text) => { - steps.push_back(crate::builder::Step::NewLine); - steps.push_back(crate::builder::Step::Pad); - steps.push_back(crate::builder::Step::Comment(text)); - comment = true; + pattern.comments_after_initial_at.push_back(text); } crate::children::DrainCommentOrNewline::Newline(_) => {} }); - if comment { - steps.push_back(crate::builder::Step::NewLine); - steps.push_back(crate::builder::Step::Pad); - } else if at { - steps.push_back(crate::builder::Step::Whitespace); - } - // { - let child = children.get_next().unwrap(); - steps.push_back(crate::builder::Step::Format(child.element)); - steps.push_back(crate::builder::Step::Indent); + children.move_next(); - let mut last_kind = rnix::SyntaxKind::TOKEN_CURLY_B_OPEN; + // arguments + loop { + let mut argument = Argument::default(); - while let Some(child) = children.peek_next() { - let kind = child.element.kind(); - match kind { - // /**/ - rnix::SyntaxKind::TOKEN_COMMENT => { - if let rnix::SyntaxKind::TOKEN_COMMA - | rnix::SyntaxKind::TOKEN_COMMENT - | rnix::SyntaxKind::TOKEN_CURLY_B_OPEN - | rnix::SyntaxKind::TOKEN_ELLIPSIS - | rnix::SyntaxKind::NODE_PAT_ENTRY = last_kind - { - steps.push_back(crate::builder::Step::NewLine); - steps.push_back(crate::builder::Step::Pad); + // Before an item we can have: comma, comments, whitespace + loop { + let child = children.peek_next().unwrap(); + // eprintln!("before item {:?}", child.element.kind()); + + match child.element.kind() { + rnix::SyntaxKind::NODE_PAT_ENTRY + | rnix::SyntaxKind::TOKEN_CURLY_B_CLOSE + | rnix::SyntaxKind::TOKEN_ELLIPSIS => { + break; } - - children.drain_comment(|text| { - steps.push_back(crate::builder::Step::Comment(text)); - }); - - last_kind = kind; - } - // item - rnix::SyntaxKind::TOKEN_ELLIPSIS - | rnix::SyntaxKind::NODE_PAT_ENTRY => { - if let rnix::SyntaxKind::TOKEN_CURLY_B_OPEN = last_kind { - if has_comments_between_curly_b || items_count > max_items { - steps.push_back(crate::builder::Step::NewLine); - steps.push_back(crate::builder::Step::Pad); - } + rnix::SyntaxKind::TOKEN_COMMA => { + children.move_next(); } + rnix::SyntaxKind::TOKEN_COMMENT => { + let content = + child.element.into_token().unwrap().to_string(); - if let rnix::SyntaxKind::TOKEN_COMMA - | rnix::SyntaxKind::TOKEN_COMMENT = last_kind - { - if !has_comments_between_curly_b && items_count <= max_items - { - steps.push_back(crate::builder::Step::Whitespace); - } else { - steps.push_back(crate::builder::Step::NewLine); - steps.push_back(crate::builder::Step::Pad); - } + argument.comments_before.push_back(content); + children.move_next(); } + rnix::SyntaxKind::TOKEN_WHITESPACE => { + children.move_next(); + } + _ => {} + } + } - match layout { - crate::config::Layout::Tall => { - steps.push_back(crate::builder::Step::FormatWider( - child.element, - )); - } - crate::config::Layout::Wide => { - steps.push_back(crate::builder::Step::Format( - child.element, - )); - } - }; - children.move_next(); - last_kind = kind; - } - // , - rnix::SyntaxKind::TOKEN_COMMA => { - if let rnix::SyntaxKind::TOKEN_COMMENT = last_kind { - steps.push_back(crate::builder::Step::NewLine); - steps.push_back(crate::builder::Step::Pad); - } - steps.push_back(crate::builder::Step::Format(child.element)); - children.move_next(); - last_kind = kind; - } - // \n - rnix::SyntaxKind::TOKEN_WHITESPACE => { - children.move_next(); - } - _ => { + // item + let child = children.peek_next().unwrap(); + // eprintln!("item {:?}", child.element.kind()); + match child.element.kind() { + rnix::SyntaxKind::TOKEN_CURLY_B_CLOSE => { + pattern.comments_before_curly_b_close = + argument.comments_before; break; } + rnix::SyntaxKind::TOKEN_ELLIPSIS + | rnix::SyntaxKind::NODE_PAT_ENTRY => { + argument.item = Some(child.element); + children.move_next(); + } + _ => {} } - } - // } - let child = children.get_next().unwrap(); - steps.push_back(crate::builder::Step::Dedent); - if has_comments_between_curly_b || items_count > max_items { - if let rnix::SyntaxKind::NODE_PAT_ENTRY = last_kind { - steps.push_back(crate::builder::Step::Token( - rnix::SyntaxKind::TOKEN_COMMA, - ",".to_string(), - )) + // After an item we can have: comma, comments, whitespace + loop { + let child = children.peek_next().unwrap(); + // eprintln!("after item {:?}", child.element.kind()); + + match child.element.kind() { + rnix::SyntaxKind::NODE_PAT_ENTRY + | rnix::SyntaxKind::TOKEN_ELLIPSIS + | rnix::SyntaxKind::TOKEN_CURLY_B_CLOSE => { + break; + } + rnix::SyntaxKind::TOKEN_COMMA => { + children.move_next(); + } + rnix::SyntaxKind::TOKEN_COMMENT => { + let content = + child.element.into_token().unwrap().to_string(); + + children.move_next(); + argument.comment_after = Some(content); + break; + } + rnix::SyntaxKind::TOKEN_WHITESPACE => { + let content = + child.element.into_token().unwrap().to_string(); + + children.move_next(); + if crate::utils::count_newlines(&content) > 0 { + break; + } + } + _ => {} + } } - steps.push_back(crate::builder::Step::NewLine); - steps.push_back(crate::builder::Step::Pad); + + pattern.arguments.push_back(argument); } - steps.push_back(crate::builder::Step::Format(child.element)); // /**/ - let mut comment = false; children.drain_comments_and_newlines(|element| match element { crate::children::DrainCommentOrNewline::Comment(text) => { - steps.push_back(crate::builder::Step::NewLine); - steps.push_back(crate::builder::Step::Pad); - steps.push_back(crate::builder::Step::Comment(text)); - comment = true; + pattern.comments_before_curly_b_close.push_back(text); + } + crate::children::DrainCommentOrNewline::Newline(_) => {} + }); + + // } + children.move_next(); + + // /**/ + children.drain_comments_and_newlines(|element| match element { + crate::children::DrainCommentOrNewline::Comment(text) => { + pattern.comments_before_end_at.push_back(text); } crate::children::DrainCommentOrNewline::Newline(_) => {} }); @@ -197,23 +177,210 @@ pub fn rule( // @ x if let Some(child) = children.peek_next() { if let rnix::SyntaxKind::NODE_PAT_BIND = child.element.kind() { - if comment { + pattern.end_at = Some(child.element); + } + } + + pattern +} + +pub fn rule( + build_ctx: &crate::builder::BuildCtx, + node: &rnix::SyntaxNode, +) -> std::collections::LinkedList { + let mut steps = std::collections::LinkedList::new(); + + let pattern = parse(build_ctx, node); + + let has_comments_between_curly_b = + pattern.arguments.iter().any(|argument| { + argument.comment_after.is_some() + || !argument.comments_before.is_empty() + }); + + let has_comments = has_comments_between_curly_b + || !pattern.comments_after_initial_at.is_empty() + || !pattern.comments_before_end_at.is_empty(); + + let has_ellipsis = pattern.arguments.iter().any(|argument| { + if argument.item.is_some() { + argument.item.as_ref().unwrap().kind() + == rnix::SyntaxKind::TOKEN_ELLIPSIS + } else { + false + } + }); + + let arguments_count = pattern.arguments.len(); + + let arguments_count_for_tall = if has_ellipsis { 2 } else { 1 }; + + let layout = if has_comments + || arguments_count > arguments_count_for_tall + || (arguments_count > 0 && has_comments_between_curly_b) + { + &crate::config::Layout::Tall + } else { + build_ctx.config.layout() + }; + + // x @ + if let Some(element) = &pattern.initial_at { + let element = element.clone(); + match layout { + crate::config::Layout::Tall => { + steps.push_back(crate::builder::Step::FormatWider(element)); + } + crate::config::Layout::Wide => { + steps.push_back(crate::builder::Step::Format(element)); + } + } + } + + // /**/ + if !pattern.comments_after_initial_at.is_empty() { + steps.push_back(crate::builder::Step::NewLine); + steps.push_back(crate::builder::Step::Pad); + for text in pattern.comments_after_initial_at { + steps.push_back(crate::builder::Step::Comment(text)); + steps.push_back(crate::builder::Step::NewLine); + steps.push_back(crate::builder::Step::Pad); + } + } else if pattern.initial_at.is_some() { + steps.push_back(crate::builder::Step::Whitespace); + } + + // { + steps.push_back(crate::builder::Step::Token( + rnix::SyntaxKind::TOKEN_CURLY_B_OPEN, + "{".to_string(), + )); + match layout { + crate::config::Layout::Tall => { + steps.push_back(crate::builder::Step::Indent); + } + crate::config::Layout::Wide => {} + }; + + // arguments + let mut index = 0; + for argument in pattern.arguments { + match layout { + crate::config::Layout::Tall => { steps.push_back(crate::builder::Step::NewLine); steps.push_back(crate::builder::Step::Pad); - } else { - steps.push_back(crate::builder::Step::Whitespace); } - match layout { - crate::config::Layout::Tall => { - steps.push_back(crate::builder::Step::FormatWider( - child.element, + crate::config::Layout::Wide => { + if index > 0 { + steps.push_back(crate::builder::Step::Whitespace); + } + } + } + + // /**/ + if !argument.comments_before.is_empty() { + for text in argument.comments_before { + steps.push_back(crate::builder::Step::Comment(text)); + steps.push_back(crate::builder::Step::NewLine); + steps.push_back(crate::builder::Step::Pad); + } + } + + // argument + let element = argument.item.unwrap(); + let element_kind = element.kind(); + match layout { + crate::config::Layout::Tall => { + steps.push_back(crate::builder::Step::FormatWider(element)); + } + crate::config::Layout::Wide => { + steps.push_back(crate::builder::Step::Format(element)); + } + }; + + // , + match layout { + crate::config::Layout::Tall => { + if !matches!(element_kind, rnix::SyntaxKind::TOKEN_ELLIPSIS) { + steps.push_back(crate::builder::Step::Token( + rnix::SyntaxKind::TOKEN_COMMA, + ",".to_string(), )); } - crate::config::Layout::Wide => { - steps - .push_back(crate::builder::Step::Format(child.element)); + } + crate::config::Layout::Wide => { + if index + 1 < arguments_count { + steps.push_back(crate::builder::Step::Token( + rnix::SyntaxKind::TOKEN_COMMA, + ",".to_string(), + )); } } + }; + + // possible inline comment + if let Some(text) = argument.comment_after { + if text.starts_with('#') { + steps.push_back(crate::builder::Step::Whitespace); + } else { + steps.push_back(crate::builder::Step::NewLine); + steps.push_back(crate::builder::Step::Pad); + } + steps.push_back(crate::builder::Step::Comment(text)); + } + + index += 1; + } + + // /**/ + let has_comments_before_curly_b_close = + !pattern.comments_before_curly_b_close.is_empty(); + for text in pattern.comments_before_curly_b_close { + steps.push_back(crate::builder::Step::NewLine); + steps.push_back(crate::builder::Step::Pad); + steps.push_back(crate::builder::Step::Comment(text)); + } + + // } + match layout { + crate::config::Layout::Tall => { + steps.push_back(crate::builder::Step::Dedent); + if arguments_count > 0 || has_comments_before_curly_b_close { + steps.push_back(crate::builder::Step::NewLine); + steps.push_back(crate::builder::Step::Pad); + } + } + crate::config::Layout::Wide => {} + }; + steps.push_back(crate::builder::Step::Token( + rnix::SyntaxKind::TOKEN_CURLY_B_OPEN, + "}".to_string(), + )); + + // /**/ + if pattern.comments_before_end_at.is_empty() { + if pattern.end_at.is_some() { + steps.push_back(crate::builder::Step::Whitespace); + } + } else { + steps.push_back(crate::builder::Step::NewLine); + steps.push_back(crate::builder::Step::Pad); + for text in pattern.comments_before_end_at { + steps.push_back(crate::builder::Step::Comment(text)); + steps.push_back(crate::builder::Step::NewLine); + steps.push_back(crate::builder::Step::Pad); + } + } + + // @ x + if let Some(element) = pattern.end_at { + match layout { + crate::config::Layout::Tall => { + steps.push_back(crate::builder::Step::FormatWider(element)); + } + crate::config::Layout::Wide => { + steps.push_back(crate::builder::Step::Format(element)); + } } } diff --git a/src/alejandra_engine/tests/cases/comment/out b/src/alejandra_engine/tests/cases/comment/out index b33ef4a..ff9dd0e 100644 --- a/src/alejandra_engine/tests/cases/comment/out +++ b/src/alejandra_engine/tests/cases/comment/out @@ -97,10 +97,8 @@ d) ({ - a, - # comment - b ? 2, - # comment + a, # comment + b ? 2, # comment }: _) ] diff --git a/src/alejandra_engine/tests/cases/pattern/out b/src/alejandra_engine/tests/cases/pattern/out index 262775f..f83c3a5 100644 --- a/src/alejandra_engine/tests/cases/pattern/out +++ b/src/alejandra_engine/tests/cases/pattern/out @@ -1,15 +1,13 @@ [ ({ foo, - bar + bar, # Some comment - , baz, }: {}) ({ foo, - bar - # Some comment + bar, # Some comment }: {}) (a @ { self, @@ -96,21 +94,19 @@ _) ({ b, - e + e, /* f */ - , ... }: _) ({ b, - e + e, /* f */ - , ... /* h @@ -119,11 +115,10 @@ _) ({ b, - e + e, /* f */ - , /* g */ @@ -132,11 +127,10 @@ _) ({ b, - e + e, /* f */ - , /* g */ @@ -199,11 +193,10 @@ /* d */ - e + e, /* f */ - , ... }: _) @@ -212,11 +205,10 @@ /* d */ - e + e, /* f */ - , ... /* h @@ -228,11 +220,10 @@ /* d */ - e + e, /* f */ - , /* g */ @@ -244,11 +235,10 @@ /* d */ - e + e, /* f */ - , /* g */ @@ -259,21 +249,19 @@ }: _) ({ - b + b, /* c */ - , e, ... }: _) ({ - b + b, /* c */ - , e, ... /* @@ -282,11 +270,10 @@ }: _) ({ - b + b, /* c */ - , e, /* g @@ -295,11 +282,10 @@ }: _) ({ - b + b, /* c */ - , e, /* g @@ -311,30 +297,26 @@ }: _) ({ - b + b, /* c */ - , - e + e, /* f */ - , ... }: _) ({ - b + b, /* c */ - , - e + e, /* f */ - , ... /* h @@ -342,16 +324,14 @@ }: _) ({ - b + b, /* c */ - , - e + e, /* f */ - , /* g */ @@ -359,16 +339,14 @@ }: _) ({ - b + b, /* c */ - , - e + e, /* f */ - , /* g */ @@ -379,11 +357,10 @@ }: _) ({ - b + b, /* c */ - , /* d */ @@ -392,11 +369,10 @@ }: _) ({ - b + b, /* c */ - , /* d */ @@ -408,11 +384,10 @@ }: _) ({ - b + b, /* c */ - , /* d */ @@ -424,11 +399,10 @@ }: _) ({ - b + b, /* c */ - , /* d */ @@ -443,36 +417,32 @@ }: _) ({ - b + b, /* c */ - , /* d */ - e + e, /* f */ - , ... }: _) ({ - b + b, /* c */ - , /* d */ - e + e, /* f */ - , ... /* h @@ -480,19 +450,17 @@ }: _) ({ - b + b, /* c */ - , /* d */ - e + e, /* f */ - , /* g */ @@ -500,19 +468,17 @@ }: _) ({ - b + b, /* c */ - , /* d */ - e + e, /* f */ - , /* g */ @@ -575,11 +541,10 @@ a */ b, - e + e, /* f */ - , ... }: _) @@ -588,11 +553,10 @@ a */ b, - e + e, /* f */ - , ... /* h @@ -604,11 +568,10 @@ a */ b, - e + e, /* f */ - , /* g */ @@ -620,11 +583,10 @@ a */ b, - e + e, /* f */ - , /* g */ @@ -702,11 +664,10 @@ /* d */ - e + e, /* f */ - , ... }: _) @@ -718,11 +679,10 @@ /* d */ - e + e, /* f */ - , ... /* h @@ -737,11 +697,10 @@ /* d */ - e + e, /* f */ - , /* g */ @@ -756,11 +715,10 @@ /* d */ - e + e, /* f */ - , /* g */ @@ -774,11 +732,10 @@ /* a */ - b + b, /* c */ - , e, ... }: @@ -787,11 +744,10 @@ /* a */ - b + b, /* c */ - , e, ... /* @@ -803,11 +759,10 @@ /* a */ - b + b, /* c */ - , e, /* g @@ -819,11 +774,10 @@ /* a */ - b + b, /* c */ - , e, /* g @@ -838,16 +792,14 @@ /* a */ - b + b, /* c */ - , - e + e, /* f */ - , ... }: _) @@ -855,16 +807,14 @@ /* a */ - b + b, /* c */ - , - e + e, /* f */ - , ... /* h @@ -875,16 +825,14 @@ /* a */ - b + b, /* c */ - , - e + e, /* f */ - , /* g */ @@ -895,16 +843,14 @@ /* a */ - b + b, /* c */ - , - e + e, /* f */ - , /* g */ @@ -918,11 +864,10 @@ /* a */ - b + b, /* c */ - , /* d */ @@ -934,11 +879,10 @@ /* a */ - b + b, /* c */ - , /* d */ @@ -953,11 +897,10 @@ /* a */ - b + b, /* c */ - , /* d */ @@ -972,11 +915,10 @@ /* a */ - b + b, /* c */ - , /* d */ @@ -994,19 +936,17 @@ /* a */ - b + b, /* c */ - , /* d */ - e + e, /* f */ - , ... }: _) @@ -1014,19 +954,17 @@ /* a */ - b + b, /* c */ - , /* d */ - e + e, /* f */ - , ... /* h @@ -1037,19 +975,17 @@ /* a */ - b + b, /* c */ - , /* d */ - e + e, /* f */ - , /* g */ @@ -1060,19 +996,17 @@ /* a */ - b + b, /* c */ - , /* d */ - e + e, /* f */ - , /* g */ @@ -1096,11 +1030,10 @@ /* a */ - null + null, /* c */ - , /* d */ @@ -1112,11 +1045,10 @@ /* a */ - null + null, /* f */ - , /* g */ @@ -1143,12 +1075,11 @@ a */ # - null + null, /* c */ # - , /* d */ @@ -1163,12 +1094,11 @@ a */ # - null + null, /* f */ # - , /* g */