-
Notifications
You must be signed in to change notification settings - Fork 225
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
chore: unify of expression formatting in parentheses (#3138)
- Loading branch information
kek kek kek
authored
Oct 18, 2023
1 parent
3bb250e
commit 6beecfa
Showing
10 changed files
with
502 additions
and
67 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,177 @@ | ||
use crate::visitor::FmtVisitor; | ||
use noirc_frontend::hir::resolution::errors::Span; | ||
use noirc_frontend::lexer::Lexer; | ||
use noirc_frontend::token::Token; | ||
use noirc_frontend::Expression; | ||
|
||
pub(crate) fn recover_comment_removed(original: &str, new: String) -> String { | ||
if changed_comment_content(original, &new) { | ||
original.to_string() | ||
} else { | ||
new | ||
} | ||
} | ||
|
||
pub(crate) fn changed_comment_content(original: &str, new: &str) -> bool { | ||
comments(original).ne(comments(new)) | ||
} | ||
|
||
pub(crate) fn comments(source: &str) -> impl Iterator<Item = String> + '_ { | ||
Lexer::new(source).skip_comments(false).flatten().filter_map(|spanned| { | ||
if let Token::LineComment(content) | Token::BlockComment(content) = spanned.into_token() { | ||
Some(content) | ||
} else { | ||
None | ||
} | ||
}) | ||
} | ||
|
||
#[derive(Debug)] | ||
pub(crate) struct Expr { | ||
pub(crate) leading: String, | ||
pub(crate) expr: String, | ||
pub(crate) trailing: String, | ||
pub(crate) different_line: bool, | ||
} | ||
|
||
pub(crate) struct Exprs<'me> { | ||
pub(crate) visitor: &'me FmtVisitor<'me>, | ||
pub(crate) elements: std::iter::Peekable<std::vec::IntoIter<Expression>>, | ||
pub(crate) last_position: u32, | ||
pub(crate) end_position: u32, | ||
} | ||
|
||
impl<'me> Exprs<'me> { | ||
pub(crate) fn new( | ||
visitor: &'me FmtVisitor<'me>, | ||
span: Span, | ||
elements: Vec<Expression>, | ||
) -> Self { | ||
Self { | ||
visitor, | ||
last_position: span.start() + 1, /*(*/ | ||
end_position: span.end() - 1, /*)*/ | ||
elements: elements.into_iter().peekable(), | ||
} | ||
} | ||
} | ||
|
||
impl Iterator for Exprs<'_> { | ||
type Item = Expr; | ||
|
||
fn next(&mut self) -> Option<Self::Item> { | ||
let element = self.elements.next()?; | ||
let element_span = element.span; | ||
|
||
let start = self.last_position; | ||
let end = element_span.start(); | ||
|
||
let is_last = self.elements.peek().is_none(); | ||
let next_start = self.elements.peek().map_or(self.end_position, |expr| expr.span.start()); | ||
|
||
let (leading, newlines) = self.leading(start, end); | ||
let expr = self.visitor.format_expr(element); | ||
let trailing = self.trailing(element_span.end(), next_start, is_last); | ||
|
||
Expr { leading, expr, trailing, different_line: newlines }.into() | ||
} | ||
} | ||
|
||
impl<'me> Exprs<'me> { | ||
pub(crate) fn leading(&mut self, start: u32, end: u32) -> (String, bool) { | ||
let mut newlines = false; | ||
|
||
let leading = slice!(self.visitor, start, end); | ||
let leading_trimmed = slice!(self.visitor, start, end).trim(); | ||
|
||
let starts_with_block_comment = leading_trimmed.starts_with("/*"); | ||
let ends_with_block_comment = leading_trimmed.ends_with("*/"); | ||
let starts_with_single_line_comment = leading_trimmed.starts_with("//"); | ||
|
||
if ends_with_block_comment { | ||
let comment_end = leading_trimmed.rfind(|c| c == '/').unwrap(); | ||
|
||
if leading[comment_end..].contains('\n') { | ||
newlines = true; | ||
} | ||
} else if starts_with_single_line_comment || starts_with_block_comment { | ||
newlines = true; | ||
}; | ||
|
||
(leading_trimmed.to_string(), newlines) | ||
} | ||
|
||
pub(crate) fn trailing(&mut self, start: u32, end: u32, is_last: bool) -> String { | ||
let slice = slice!(self.visitor, start, end); | ||
let comment_end = find_comment_end(slice, is_last); | ||
let trailing = slice[..comment_end].trim_matches(',').trim(); | ||
self.last_position = start + (comment_end as u32); | ||
trailing.to_string() | ||
} | ||
} | ||
|
||
pub(crate) trait FindToken { | ||
fn find_token(&self, token: Token) -> Option<u32>; | ||
fn find_token_with(&self, f: impl Fn(&Token) -> bool) -> Option<u32>; | ||
} | ||
|
||
impl FindToken for str { | ||
fn find_token(&self, token: Token) -> Option<u32> { | ||
Lexer::new(self) | ||
.flatten() | ||
.find_map(|it| (it.token() == &token).then(|| it.to_span().start())) | ||
} | ||
|
||
fn find_token_with(&self, f: impl Fn(&Token) -> bool) -> Option<u32> { | ||
Lexer::new(self) | ||
.skip_comments(false) | ||
.flatten() | ||
.into_iter() | ||
.find_map(|spanned| f(spanned.token()).then(|| spanned.to_span().end())) | ||
} | ||
} | ||
|
||
pub(crate) fn find_comment_end(slice: &str, is_last: bool) -> usize { | ||
fn find_comment_end(slice: &str) -> usize { | ||
slice | ||
.find_token_with(|token| { | ||
matches!(token, Token::LineComment(_) | Token::BlockComment(_)) | ||
}) | ||
.map(|index| index as usize) | ||
.unwrap_or(slice.len()) | ||
} | ||
|
||
if is_last { | ||
return slice.len(); | ||
} | ||
|
||
let mut block_open_index = slice.find("/*"); | ||
if let Some(index) = block_open_index { | ||
match slice.find('/') { | ||
Some(slash) if slash < index => block_open_index = None, | ||
_ if slice[..index].ends_with('/') => block_open_index = None, | ||
_ => (), | ||
} | ||
} | ||
|
||
let newline_index = slice.find('\n'); | ||
if let Some(separator_index) = slice.find_token(Token::Comma).map(|index| index as usize) { | ||
match (block_open_index, newline_index) { | ||
(Some(block), None) if block > separator_index => separator_index + 1, | ||
(Some(block), None) => { | ||
let slice = &slice[block..]; | ||
std::cmp::max(find_comment_end(slice) + block, separator_index + 1) | ||
} | ||
(Some(block), Some(newline)) if block < newline => { | ||
let slice = &slice[block..]; | ||
std::cmp::max(find_comment_end(slice) + block, separator_index + 1) | ||
} | ||
(_, Some(newline)) if newline > separator_index => newline + 1, | ||
_ => slice.len(), | ||
} | ||
} else if let Some(newline_index) = newline_index { | ||
newline_index + 1 | ||
} else { | ||
0 | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.