| 139 | } |
| 140 | |
| 141 | fn finish(self, syntax: Mod) -> Parsed<Mod> { |
| 142 | assert_eq!( |
| 143 | self.current_token_kind(), |
| 144 | TokenKind::EndOfFile, |
| 145 | "Parser should be at the end of the file." |
| 146 | ); |
| 147 | |
| 148 | // TODO consider re-integrating lexical error handling into the parser? |
| 149 | let parse_errors = self.errors; |
| 150 | let (tokens, lex_errors) = self.tokens.finish(); |
| 151 | |
| 152 | // Fast path for when there are no lex errors. |
| 153 | // There's no fast path for when there are no parse errors because a lex error |
| 154 | // always results in a parse error. |
| 155 | if lex_errors.is_empty() { |
| 156 | return Parsed { |
| 157 | syntax, |
| 158 | tokens: Tokens::new(tokens), |
| 159 | errors: parse_errors, |
| 160 | }; |
| 161 | } |
| 162 | |
| 163 | let mut merged = Vec::with_capacity(parse_errors.len().saturating_add(lex_errors.len())); |
| 164 | |
| 165 | let mut parse_errors = parse_errors.into_iter().peekable(); |
| 166 | let mut lex_errors = lex_errors.into_iter().peekable(); |
| 167 | |
| 168 | while let (Some(parse_error), Some(lex_error)) = (parse_errors.peek(), lex_errors.peek()) { |
| 169 | match parse_error |
| 170 | .location |
| 171 | .start() |
| 172 | .cmp(&lex_error.location().start()) |
| 173 | { |
| 174 | Ordering::Less => merged.push(parse_errors.next().unwrap()), |
| 175 | Ordering::Equal => { |
| 176 | // Skip the parse error if we already have a lex error at the same location.. |
| 177 | parse_errors.next().unwrap(); |
| 178 | merged.push(lex_errors.next().unwrap().into()); |
| 179 | } |
| 180 | Ordering::Greater => merged.push(lex_errors.next().unwrap().into()), |
| 181 | } |
| 182 | } |
| 183 | |
| 184 | merged.extend(parse_errors); |
| 185 | merged.extend(lex_errors.map(ParseError::from)); |
| 186 | |
| 187 | Parsed { |
| 188 | syntax, |
| 189 | tokens: Tokens::new(tokens), |
| 190 | errors: merged, |
| 191 | } |
| 192 | } |
| 193 | |
| 194 | /// Returns the start position for a node that starts at the current token. |
| 195 | fn node_start(&self) -> TextSize { |