Merge branch 'parser-newline-comment-fix'

This commit is contained in:
KtorZ 2023-02-17 14:08:20 +01:00
commit 92021e00b4
No known key found for this signature in database
GPG Key ID: 33173CB6F77F4277
2 changed files with 119 additions and 21 deletions

View File

@ -55,8 +55,6 @@ pub fn lexer() -> impl Parser<char, Vec<(Token, Span)>, Error = ParseError> {
just('|').to(Token::Vbar), just('|').to(Token::Vbar),
just("&&").to(Token::AmperAmper), just("&&").to(Token::AmperAmper),
just('#').to(Token::Hash), just('#').to(Token::Hash),
choice((just("\n\n"), just("\r\n\r\n"))).to(Token::EmptyLine),
choice((just("\n"), just("\r\n"))).to(Token::NewLine),
)); ));
let grouping = choice(( let grouping = choice((
@ -126,29 +124,41 @@ pub fn lexer() -> impl Parser<char, Vec<(Token, Span)>, Error = ParseError> {
} }
}); });
let module_comments = just("////").ignore_then( fn comment_parser(token: Token) -> impl Parser<char, (Token, Span), Error = ParseError> {
take_until(text::newline().rewind()) let n = match token {
.to(Token::ModuleComment) Token::ModuleComment => 4,
.map_with_span(|token, span| (token, span)), Token::DocComment => 3,
); Token::Comment => 2,
_ => unreachable!(),
let doc_comments = just("///").ignore_then( };
take_until(text::newline().rewind())
.to(Token::DocComment)
.map_with_span(|token, span| (token, span)),
);
let comments = just("//").ignore_then(
take_until(text::newline().rewind())
.to(Token::Comment)
.map_with_span(|token, span| (token, span)),
);
choice(( choice((
module_comments, // NOTE: The first case here work around a bug introduced with chumsky=0.9.0 which
doc_comments, // miscalculate the offset for empty comments.
comments, just("/".repeat(n))
choice((ordinal, keyword, int, op, grouping, string)) .ignore_then(text::newline().rewind())
.to(token.clone())
.map_with_span(move |token, span: Span| {
(token, Span::new((), span.start + n..span.end))
}),
just("/".repeat(n)).ignore_then(
take_until(text::newline().rewind())
.to(token)
.map_with_span(|token, span| (token, span)),
),
))
}
let newlines = choice((
choice((just("\n\n"), just("\r\n\r\n"))).to(Token::EmptyLine),
choice((just("\n"), just("\r\n"))).to(Token::NewLine),
));
choice((
comment_parser(Token::ModuleComment),
comment_parser(Token::DocComment),
comment_parser(Token::Comment),
choice((ordinal, keyword, int, op, newlines, grouping, string))
.or(any().map(Token::Error).validate(|t, span, emit| { .or(any().map(Token::Error).validate(|t, span, emit| {
emit(ParseError::expected_input_found( emit(ParseError::expected_input_found(
span, span,

View File

@ -415,3 +415,91 @@ fn test_trace_if_false() {
assert_fmt(src, src); assert_fmt(src, src);
} }
#[test]
fn test_newline_comments() {
let src = indoc! {r#"
// My comment
//
// has a newline.
fn foo() {
True
}
// My comments
// can live apart
fn bar() {
True
}
"#};
assert_fmt(src, src);
}
#[test]
fn test_newline_doc_comments() {
let src = indoc! {r#"
/// My doc comment
///
/// has a newline.
fn foo() {
True
}
/// My doc comments
/// cannot be separated
fn bar() {
True
}
"#};
let out = indoc! {r#"
/// My doc comment
///
/// has a newline.
fn foo() {
True
}
/// My doc comments
/// cannot be separated
fn bar() {
True
}
"#};
assert_fmt(src, out);
}
#[test]
fn test_newline_module_comments() {
let src = indoc! {r#"
//// My module comment
////
//// has a newline.
fn foo() {
True
}
//// My module comments
//// cannot be separated
"#};
let out = indoc! {r#"
//// My module comment
////
//// has a newline.
//// My module comments
//// cannot be separated
fn foo() {
True
}
"#};
assert_fmt(src, out);
}