Fix newline parsing behaviour in markup

This commit is contained in:
Laurenz 2023-09-12 11:45:24 +02:00
parent 14d28dbf4e
commit e39be71a54
3 changed files with 59 additions and 22 deletions

View File

@ -571,13 +571,13 @@ fn code(p: &mut Parser, stop: impl FnMut(&Parser) -> bool) {
fn code_exprs(p: &mut Parser, mut stop: impl FnMut(&Parser) -> bool) { fn code_exprs(p: &mut Parser, mut stop: impl FnMut(&Parser) -> bool) {
while !p.eof() && !stop(p) { while !p.eof() && !stop(p) {
p.stop_at_newline(true); p.enter_newline_mode(NewlineMode::Contextual);
let prev = p.prev_end(); let prev = p.prev_end();
code_expr(p); code_expr(p);
if p.progress(prev) && !p.eof() && !stop(p) && !p.eat_if(SyntaxKind::Semicolon) { if p.progress(prev) && !p.eof() && !stop(p) && !p.eat_if(SyntaxKind::Semicolon) {
p.expected("semicolon or line break"); p.expected("semicolon or line break");
} }
p.unstop(); p.exit_newline_mode();
if !p.progress(prev) && !p.eof() { if !p.progress(prev) && !p.eof() {
p.unexpected(); p.unexpected();
} }
@ -593,7 +593,7 @@ fn code_expr_or_pattern(p: &mut Parser) {
} }
fn embedded_code_expr(p: &mut Parser) { fn embedded_code_expr(p: &mut Parser) {
p.stop_at_newline(true); p.enter_newline_mode(NewlineMode::Stop);
p.enter(LexMode::Code); p.enter(LexMode::Code);
p.assert(SyntaxKind::Hashtag); p.assert(SyntaxKind::Hashtag);
p.unskip(); p.unskip();
@ -611,12 +611,8 @@ fn embedded_code_expr(p: &mut Parser) {
code_expr_prec(p, true, 0, false); code_expr_prec(p, true, 0, false);
// Consume error for things like `#12p` or `#"abc\"`.# // Consume error for things like `#12p` or `#"abc\"`.#
if !p.progress(prev) { if !p.progress(prev) && !p.current().is_trivia() && !p.eof() {
if p.current().is_trivia() { p.unexpected();
// p.unskip();
} else if !p.eof() {
p.unexpected();
}
} }
let semi = let semi =
@ -627,7 +623,7 @@ fn embedded_code_expr(p: &mut Parser) {
} }
p.exit(); p.exit();
p.unstop(); p.exit_newline_mode();
} }
fn code_expr_prec( fn code_expr_prec(
@ -772,7 +768,7 @@ pub(super) fn reparse_block(text: &str, range: Range<usize>) -> Option<SyntaxNod
fn code_block(p: &mut Parser) { fn code_block(p: &mut Parser) {
let m = p.marker(); let m = p.marker();
p.enter(LexMode::Code); p.enter(LexMode::Code);
p.stop_at_newline(false); p.enter_newline_mode(NewlineMode::Continue);
p.assert(SyntaxKind::LeftBrace); p.assert(SyntaxKind::LeftBrace);
code(p, |p| { code(p, |p| {
p.at(SyntaxKind::RightBrace) p.at(SyntaxKind::RightBrace)
@ -781,7 +777,7 @@ fn code_block(p: &mut Parser) {
}); });
p.expect_closing_delimiter(m, SyntaxKind::RightBrace); p.expect_closing_delimiter(m, SyntaxKind::RightBrace);
p.exit(); p.exit();
p.unstop(); p.exit_newline_mode();
p.wrap(m, SyntaxKind::CodeBlock); p.wrap(m, SyntaxKind::CodeBlock);
} }
@ -852,7 +848,7 @@ fn invalidate_destructuring(p: &mut Parser, m: Marker) {
} }
fn collection(p: &mut Parser, keyed: bool) -> SyntaxKind { fn collection(p: &mut Parser, keyed: bool) -> SyntaxKind {
p.stop_at_newline(false); p.enter_newline_mode(NewlineMode::Continue);
let m = p.marker(); let m = p.marker();
p.assert(SyntaxKind::LeftParen); p.assert(SyntaxKind::LeftParen);
@ -901,7 +897,7 @@ fn collection(p: &mut Parser, keyed: bool) -> SyntaxKind {
} }
p.expect_closing_delimiter(m, SyntaxKind::RightParen); p.expect_closing_delimiter(m, SyntaxKind::RightParen);
p.unstop(); p.exit_newline_mode();
if parenthesized && count == 1 { if parenthesized && count == 1 {
SyntaxKind::Parenthesized SyntaxKind::Parenthesized
@ -1442,10 +1438,20 @@ struct Parser<'s> {
current: SyntaxKind, current: SyntaxKind,
modes: Vec<LexMode>, modes: Vec<LexMode>,
nodes: Vec<SyntaxNode>, nodes: Vec<SyntaxNode>,
stop_at_newline: Vec<bool>, newline_modes: Vec<NewlineMode>,
balanced: bool, balanced: bool,
} }
/// How to proceed with parsing when seeing a newline.
enum NewlineMode {
/// Stop always.
Stop,
/// Proceed if there is no continuation with `else` or `.`
Contextual,
/// Just proceed like with normal whitespace.
Continue,
}
#[derive(Debug, Copy, Clone, Eq, PartialEq)] #[derive(Debug, Copy, Clone, Eq, PartialEq)]
struct Marker(usize); struct Marker(usize);
@ -1462,7 +1468,7 @@ impl<'s> Parser<'s> {
current, current,
modes: vec![], modes: vec![],
nodes: vec![], nodes: vec![],
stop_at_newline: vec![], newline_modes: vec![],
balanced: true, balanced: true,
} }
} }
@ -1597,13 +1603,13 @@ impl<'s> Parser<'s> {
} }
} }
fn stop_at_newline(&mut self, stop: bool) { fn enter_newline_mode(&mut self, stop: NewlineMode) {
self.stop_at_newline.push(stop); self.newline_modes.push(stop);
} }
fn unstop(&mut self) { fn exit_newline_mode(&mut self) {
self.unskip(); self.unskip();
self.stop_at_newline.pop(); self.newline_modes.pop();
self.lexer.jump(self.prev_end); self.lexer.jump(self.prev_end);
self.lex(); self.lex();
self.skip(); self.skip();
@ -1654,8 +1660,15 @@ impl<'s> Parser<'s> {
self.current = self.lexer.next(); self.current = self.lexer.next();
if self.lexer.mode() == LexMode::Code if self.lexer.mode() == LexMode::Code
&& self.lexer.newline() && self.lexer.newline()
&& self.stop_at_newline.last().copied().unwrap_or(false) && match self.newline_modes.last() {
&& !matches!(self.lexer.clone().next(), SyntaxKind::Else | SyntaxKind::Dot) Some(NewlineMode::Continue) => false,
Some(NewlineMode::Contextual) => !matches!(
self.lexer.clone().next(),
SyntaxKind::Else | SyntaxKind::Dot
),
Some(NewlineMode::Stop) => true,
None => false,
}
{ {
self.current = SyntaxKind::Eof; self.current = SyntaxKind::Eof;
} }

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.6 KiB

View File

@ -0,0 +1,24 @@
// Test newline continuations.
---
#{
"hello"
.clusters()
if false {
}
else {
("1", "2")
}
}
---
#"hello"
.codepoints()
#if false {
}
else {
("1", "2")
}