(&mut self)
| 256 | } |
| 257 | |
| 258 | pub(super) fn advance(&mut self) -> Token { |
| 259 | let tok = self.tokens.next().unwrap_or(Token { |
| 260 | kind: TokenType::Endmarker, |
| 261 | line: 0, start: 0, end: 0, |
| 262 | }); |
| 263 | self.last_line = tok.line; |
| 264 | if tok.end > 0 { self.last_end = tok.end; } |
| 265 | match tok.kind { |
| 266 | TokenType::Lpar | TokenType::Lsqb | TokenType::Lbrace => { |
| 267 | self.bracket_stack.push((tok.kind, tok.start, tok.end, self.errors.len())); |
| 268 | } |
| 269 | TokenType::Rpar | TokenType::Rsqb | TokenType::Rbrace => { |
| 270 | let want_open = match tok.kind { |
| 271 | TokenType::Rpar => TokenType::Lpar, |
| 272 | TokenType::Rsqb => TokenType::Lsqb, |
| 273 | _ => TokenType::Lbrace, |
| 274 | }; |
| 275 | /* Find matching opener; report unclosed brackets above it; handle orphan closers. */ |
| 276 | if let Some(idx) = self.bracket_stack.iter().rposition(|&(k, _, _, _)| k == want_open) { |
| 277 | while self.bracket_stack.len() > idx + 1 { |
| 278 | let (k, st, en, ov) = self.bracket_stack.pop().unwrap(); |
| 279 | self.errors.truncate(ov); |
| 280 | self.errors.push(Diagnostic { |
| 281 | start: st, end: en, |
| 282 | msg: s!(str open_str(k), " was never closed"), |
| 283 | }); |
| 284 | } |
| 285 | self.bracket_stack.pop(); |
| 286 | } else if let Some(&(top_k, _, _, _)) = self.bracket_stack.last() { |
| 287 | self.errors.push(Diagnostic { |
| 288 | start: tok.start, end: tok.end, |
| 289 | msg: s!(str close_str(tok.kind), " does not match ", str open_str(top_k), ", expected ", str match_close_str(top_k)), |
| 290 | }); |
| 291 | self.bracket_stack.pop(); |
| 292 | } else { |
| 293 | self.errors.push(Diagnostic { |
| 294 | start: tok.start, end: tok.end, |
| 295 | msg: s!("unexpected ", str close_str(tok.kind), ", no matching opener"), |
| 296 | }); |
| 297 | } |
| 298 | } |
| 299 | _ => {} |
| 300 | } |
| 301 | tok |
| 302 | } |
| 303 | |
| 304 | /* Non-syncing diagnostic at peek; used when flow must continue (e.g. missing class name). */ |
| 305 | pub(super) fn diag_at_peek(&mut self, msg: &str) { |
no test coverage detected