diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/syntax/lexer.rs | 39 | ||||
| -rw-r--r-- | src/syntax/parser.rs | 46 | ||||
| -rw-r--r-- | src/syntax/reparser.rs | 8 |
3 files changed, 47 insertions, 46 deletions
diff --git a/src/syntax/lexer.rs b/src/syntax/lexer.rs index ee73a595..d0e5c9bd 100644 --- a/src/syntax/lexer.rs +++ b/src/syntax/lexer.rs @@ -80,12 +80,6 @@ impl Lexer<'_> { self.error = Some((message.into(), ErrorPos::Full)); SyntaxKind::Error } - - /// Construct a positioned syntax error. - fn error_at_end(&mut self, message: impl Into<EcoString>) -> SyntaxKind { - self.error = Some((message.into(), ErrorPos::End)); - SyntaxKind::Error - } } /// Shared. @@ -209,7 +203,7 @@ impl Lexer<'_> { if self.s.eat_if("u{") { let hex = self.s.eat_while(char::is_ascii_alphanumeric); if !self.s.eat_if('}') { - return self.error_at_end("expected closing brace"); + return self.error("unclosed unicode escape sequence"); } if u32::from_str_radix(hex, 16) @@ -251,20 +245,15 @@ impl Lexer<'_> { } if found != backticks { - let remaining = backticks - found; - let noun = if remaining == 1 { "backtick" } else { "backticks" }; - return self.error_at_end(if found == 0 { - eco_format!("expected {} {}", remaining, noun) - } else { - eco_format!("expected {} more {}", remaining, noun) - }); + return self.error("unclosed raw text"); } SyntaxKind::Raw } fn link(&mut self) -> SyntaxKind { - let mut bracket_stack = Vec::new(); + let mut brackets = Vec::new(); + #[rustfmt::skip] self.s.eat_while(|c: char| { match c { @@ -275,20 +264,24 @@ impl Lexer<'_> { | ',' | '-' | '.' | '/' | ':' | ';' | '=' | '?' | '@' | '_' | '~' | '\'' => true, '[' => { - bracket_stack.push(SyntaxKind::LeftBracket); + brackets.push(SyntaxKind::LeftBracket); true } '(' => { - bracket_stack.push(SyntaxKind::LeftParen); + brackets.push(SyntaxKind::LeftParen); true } - ']' => bracket_stack.pop() == Some(SyntaxKind::LeftBracket), - ')' => bracket_stack.pop() == Some(SyntaxKind::LeftParen), + ']' => brackets.pop() == Some(SyntaxKind::LeftBracket), + ')' => brackets.pop() == Some(SyntaxKind::LeftParen), _ => false, } }); - if !bracket_stack.is_empty() { - return self.error_at_end("expected closing bracket in link"); + + if !brackets.is_empty() { + return self.error( + "automatic links cannot contain unbalanced brackets, \ + use the `link` function instead", + ); } // Don't include the trailing characters likely to be part of text. @@ -328,7 +321,7 @@ impl Lexer<'_> { } if !self.s.eat_if('>') { - return self.error_at_end("expected closing angle bracket"); + return self.error("unclosed label"); } SyntaxKind::Label @@ -620,7 +613,7 @@ impl Lexer<'_> { }); if !self.s.eat_if('"') { - return self.error_at_end("expected quote"); + return self.error("unclosed string"); } SyntaxKind::Str diff --git a/src/syntax/parser.rs b/src/syntax/parser.rs index c7dbc936..3b82ce16 100644 --- a/src/syntax/parser.rs +++ b/src/syntax/parser.rs @@ -71,7 +71,7 @@ pub(super) fn reparse_markup( match p.current() { SyntaxKind::LeftBracket => *nesting += 1, SyntaxKind::RightBracket if *nesting > 0 => *nesting -= 1, - _ if stop(p.current) => break, + _ if stop(p.current()) => break, _ => {} } @@ -141,7 +141,7 @@ fn strong(p: &mut Parser) { || p.at(SyntaxKind::Parbreak) || p.at(SyntaxKind::RightBracket) }); - p.expect(SyntaxKind::Star); + p.expect_closing_delimiter(m, SyntaxKind::Star); p.wrap(m, SyntaxKind::Strong); } @@ -153,7 +153,7 @@ fn emph(p: &mut Parser) { || p.at(SyntaxKind::Parbreak) || p.at(SyntaxKind::RightBracket) }); - p.expect(SyntaxKind::Underscore); + p.expect_closing_delimiter(m, SyntaxKind::Underscore); p.wrap(m, SyntaxKind::Emph); } @@ -220,15 +220,15 @@ fn equation(p: &mut Parser) { let m = p.marker(); p.enter(LexMode::Math); p.assert(SyntaxKind::Dollar); - math(p, |kind| kind == SyntaxKind::Dollar); - p.expect(SyntaxKind::Dollar); + math(p, |p| p.at(SyntaxKind::Dollar)); + p.expect_closing_delimiter(m, SyntaxKind::Dollar); p.exit(); p.wrap(m, SyntaxKind::Equation); } -fn math(p: &mut Parser, mut stop: impl FnMut(SyntaxKind) -> bool) { +fn math(p: &mut Parser, mut stop: impl FnMut(&Parser) -> bool) { let m = p.marker(); - while !p.eof() && !stop(p.current()) { + while !p.eof() && !stop(p) { let prev = p.prev_end(); math_expr(p); if !p.progress(prev) { @@ -514,22 +514,18 @@ fn maybe_wrap_in_math(p: &mut Parser, arg: Marker, named: Option<Marker>) { } } -fn code(p: &mut Parser, stop: impl FnMut(SyntaxKind) -> bool) { +fn code(p: &mut Parser, stop: impl FnMut(&Parser) -> bool) { let m = p.marker(); code_exprs(p, stop); p.wrap(m, SyntaxKind::Code); } -fn code_exprs(p: &mut Parser, mut stop: impl FnMut(SyntaxKind) -> bool) { - while !p.eof() && !stop(p.current()) { +fn code_exprs(p: &mut Parser, mut stop: impl FnMut(&Parser) -> bool) { + while !p.eof() && !stop(p) { p.stop_at_newline(true); let prev = p.prev_end(); code_expr(p); - if p.progress(prev) - && !p.eof() - && !stop(p.current()) - && !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.unstop(); @@ -725,8 +721,12 @@ fn code_block(p: &mut Parser) { p.enter(LexMode::Code); p.stop_at_newline(false); p.assert(SyntaxKind::LeftBrace); - code(p, |kind| kind == SyntaxKind::RightBrace); - p.expect(SyntaxKind::RightBrace); + code(p, |p| { + p.at(SyntaxKind::RightBrace) + || p.at(SyntaxKind::RightBracket) + || p.at(SyntaxKind::RightParen) + }); + p.expect_closing_delimiter(m, SyntaxKind::RightBrace); p.exit(); p.unstop(); p.wrap(m, SyntaxKind::CodeBlock); @@ -737,7 +737,7 @@ fn content_block(p: &mut Parser) { p.enter(LexMode::Markup); p.assert(SyntaxKind::LeftBracket); markup(p, true, 0, |p| p.at(SyntaxKind::RightBracket)); - p.expect(SyntaxKind::RightBracket); + p.expect_closing_delimiter(m, SyntaxKind::RightBracket); p.exit(); p.wrap(m, SyntaxKind::ContentBlock); } @@ -800,6 +800,8 @@ fn invalidate_destructuring(p: &mut Parser, m: Marker) { fn collection(p: &mut Parser, keyed: bool) -> SyntaxKind { p.stop_at_newline(false); + + let m = p.marker(); p.assert(SyntaxKind::LeftParen); let mut count = 0; @@ -845,7 +847,7 @@ fn collection(p: &mut Parser, keyed: bool) -> SyntaxKind { } } - p.expect(SyntaxKind::RightParen); + p.expect_closing_delimiter(m, SyntaxKind::RightParen); p.unstop(); if parenthesized && count == 1 { @@ -1586,6 +1588,12 @@ impl<'s> Parser<'s> { at } + fn expect_closing_delimiter(&mut self, open: Marker, kind: SyntaxKind) { + if !self.eat_if(kind) { + self.nodes[open.0].convert_to_error("unclosed delimiter"); + } + } + fn expected(&mut self, thing: &str) { self.unskip(); if self diff --git a/src/syntax/reparser.rs b/src/syntax/reparser.rs index c744eeb2..9e2b0a1b 100644 --- a/src/syntax/reparser.rs +++ b/src/syntax/reparser.rs @@ -306,15 +306,15 @@ mod tests { test("Hello #{ x + 1 }!", 9..10, "abc", true); test("A#{}!", 3..3, "\"", false); test("#{ [= x] }!", 5..5, "=", true); - test("#[[]]", 3..3, "\\", false); - test("#[[ab]]", 4..5, "\\", false); + test("#[[]]", 3..3, "\\", true); + test("#[[ab]]", 4..5, "\\", true); test("#{}}", 2..2, "{", false); test("A: #[BC]", 6..6, "{", true); - test("A: #[BC]", 6..6, "#{", false); + test("A: #[BC]", 6..6, "#{", true); test("A: #[BC]", 6..6, "#{}", true); test("#{\"ab\"}A", 5..5, "c", true); test("#{\"ab\"}A", 5..6, "c", false); - test("a#[]b", 3..3, "#{", false); + test("a#[]b", 3..3, "#{", true); test("a#{call(); abc}b", 8..8, "[]", true); test("a #while x {\n g(x) \n} b", 12..12, "//", true); test("a#[]b", 3..3, "[hey]", true); |
