diff options
| author | Martin Haug <mhaug@live.de> | 2021-11-10 20:41:10 +0100 |
|---|---|---|
| committer | Martin Haug <mhaug@live.de> | 2021-11-10 20:41:10 +0100 |
| commit | 3162c6a83a910f34d6ed7e966c11b7e7b5bd4088 (patch) | |
| tree | ce14dfbc48186a010183c637614a6f2d54f12264 /src/parse | |
| parent | 91f2f97572c64d7eb25c88ad0ebb18192cf8eddf (diff) | |
Comments and neighbors
Diffstat (limited to 'src/parse')
| -rw-r--r-- | src/parse/mod.rs | 15 | ||||
| -rw-r--r-- | src/parse/parser.rs | 9 | ||||
| -rw-r--r-- | src/parse/tokens.rs | 26 |
3 files changed, 39 insertions, 11 deletions
diff --git a/src/parse/mod.rs b/src/parse/mod.rs index 1f1ac266..f2fae5f2 100644 --- a/src/parse/mod.rs +++ b/src/parse/mod.rs @@ -26,14 +26,14 @@ pub fn parse(src: &str) -> Rc<GreenNode> { } /// Parse an atomic primary. Returns `Some` if all of the input was consumed. -pub fn parse_atomic(src: &str, _: bool) -> Option<Vec<Green>> { +pub fn parse_atomic(src: &str, _: bool) -> Option<(Vec<Green>, bool)> { let mut p = Parser::new(src, TokenMode::Code); primary(&mut p, true).ok()?; p.eject_partial() } /// Parse some markup. Returns `Some` if all of the input was consumed. -pub fn parse_markup(src: &str, _: bool) -> Option<Vec<Green>> { +pub fn parse_markup(src: &str, _: bool) -> Option<(Vec<Green>, bool)> { let mut p = Parser::new(src, TokenMode::Markup); markup(&mut p); p.eject() @@ -41,7 +41,10 @@ pub fn parse_markup(src: &str, _: bool) -> Option<Vec<Green>> { /// Parse some markup without the topmost node. Returns `Some` if all of the /// input was consumed. -pub fn parse_markup_elements(src: &str, mut at_start: bool) -> Option<Vec<Green>> { +pub fn parse_markup_elements( + src: &str, + mut at_start: bool, +) -> Option<(Vec<Green>, bool)> { let mut p = Parser::new(src, TokenMode::Markup); while !p.eof() { markup_node(&mut p, &mut at_start); @@ -50,7 +53,7 @@ pub fn parse_markup_elements(src: &str, mut at_start: bool) -> Option<Vec<Green> } /// Parse a template literal. Returns `Some` if all of the input was consumed. -pub fn parse_template(source: &str, _: bool) -> Option<Vec<Green>> { +pub fn parse_template(source: &str, _: bool) -> Option<(Vec<Green>, bool)> { let mut p = Parser::new(source, TokenMode::Code); if !matches!(p.peek(), Some(NodeKind::LeftBracket)) { return None; @@ -61,7 +64,7 @@ pub fn parse_template(source: &str, _: bool) -> Option<Vec<Green>> { } /// Parse a code block. Returns `Some` if all of the input was consumed. -pub fn parse_block(source: &str, _: bool) -> Option<Vec<Green>> { +pub fn parse_block(source: &str, _: bool) -> Option<(Vec<Green>, bool)> { let mut p = Parser::new(source, TokenMode::Code); if !matches!(p.peek(), Some(NodeKind::LeftBrace)) { return None; @@ -72,7 +75,7 @@ pub fn parse_block(source: &str, _: bool) -> Option<Vec<Green>> { } /// Parse a comment. Returns `Some` if all of the input was consumed. -pub fn parse_comment(source: &str, _: bool) -> Option<Vec<Green>> { +pub fn parse_comment(source: &str, _: bool) -> Option<(Vec<Green>, bool)> { let mut p = Parser::new(source, TokenMode::Code); comment(&mut p).ok()?; p.eject() diff --git a/src/parse/parser.rs b/src/parse/parser.rs index 31c918a8..a37cb9c6 100644 --- a/src/parse/parser.rs +++ b/src/parse/parser.rs @@ -48,9 +48,9 @@ impl<'s> Parser<'s> { } /// End the parsing process and return multiple children. - pub fn eject(self) -> Option<Vec<Green>> { + pub fn eject(self) -> Option<(Vec<Green>, bool)>{ if self.eof() && self.group_success() { - Some(self.children) + Some((self.children, self.tokens.was_unterminated())) } else { None } @@ -97,8 +97,9 @@ impl<'s> Parser<'s> { /// End the parsing process and return multiple children, even if there /// remains stuff in the string. - pub fn eject_partial(self) -> Option<Vec<Green>> { - self.group_success().then(|| self.children) + pub fn eject_partial(self) -> Option<(Vec<Green>, bool)> { + self.group_success() + .then(|| (self.children, self.tokens.was_unterminated())) } /// Whether the end of the source string or group is reached. diff --git a/src/parse/tokens.rs b/src/parse/tokens.rs index 27ec046d..7be31fe1 100644 --- a/src/parse/tokens.rs +++ b/src/parse/tokens.rs @@ -13,6 +13,7 @@ use crate::util::EcoString; pub struct Tokens<'s> { s: Scanner<'s>, mode: TokenMode, + has_unterminated: bool, } /// What kind of tokens to emit. @@ -28,7 +29,11 @@ impl<'s> Tokens<'s> { /// Create a new token iterator with the given mode. #[inline] pub fn new(src: &'s str, mode: TokenMode) -> Self { - Self { s: Scanner::new(src), mode } + Self { + s: Scanner::new(src), + mode, + has_unterminated: false, + } } /// Get the current token mode. @@ -63,6 +68,12 @@ impl<'s> Tokens<'s> { pub fn scanner(&self) -> Scanner<'s> { self.s } + + /// Whether the last token was unterminated. + #[inline] + pub fn was_unterminated(&self) -> bool { + self.has_unterminated + } } impl<'s> Iterator for Tokens<'s> { @@ -248,6 +259,7 @@ impl<'s> Tokens<'s> { ) } } else { + self.has_unterminated = true; NodeKind::Error( ErrorPos::End, "expected closing brace".into(), @@ -346,6 +358,7 @@ impl<'s> Tokens<'s> { let remaining = backticks - found; let noun = if remaining == 1 { "backtick" } else { "backticks" }; + self.has_unterminated = true; NodeKind::Error( ErrorPos::End, if found == 0 { @@ -393,6 +406,7 @@ impl<'s> Tokens<'s> { display, })) } else { + self.has_unterminated = true; NodeKind::Error( ErrorPos::End, if !display || (!escaped && dollar) { @@ -481,18 +495,23 @@ impl<'s> Tokens<'s> { if self.s.eat_if('"') { NodeKind::Str(string) } else { + self.has_unterminated = true; NodeKind::Error(ErrorPos::End, "expected quote".into()) } } fn line_comment(&mut self) -> NodeKind { self.s.eat_until(is_newline); + if self.s.peek().is_none() { + self.has_unterminated = true; + } NodeKind::LineComment } fn block_comment(&mut self) -> NodeKind { let mut state = '_'; let mut depth = 1; + let mut terminated = false; // Find the first `*/` that does not correspond to a nested `/*`. while let Some(c) = self.s.eat() { @@ -500,6 +519,7 @@ impl<'s> Tokens<'s> { ('*', '/') => { depth -= 1; if depth == 0 { + terminated = true; break; } '_' @@ -512,6 +532,10 @@ impl<'s> Tokens<'s> { } } + if !terminated { + self.has_unterminated = true; + } + NodeKind::BlockComment } |
