Skip to content

Commit

Permalink
fix(parser): change unterminated regex error to be non-recoverable (#…
Browse files Browse the repository at this point in the history
…5285)

closes #5257
  • Loading branch information
Boshen committed Aug 28, 2024
1 parent cffce11 commit e6fd52e
Show file tree
Hide file tree
Showing 6 changed files with 19 additions and 191 deletions.
6 changes: 3 additions & 3 deletions crates/oxc_parser/src/cursor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -223,10 +223,10 @@ impl<'a> ParserImpl<'a> {
}

/// Tell lexer to read a regex
pub(crate) fn read_regex(&mut self) -> (u32, RegExpFlags) {
let (token, pattern_end, flags) = self.lexer.next_regex(self.cur_kind());
pub(crate) fn read_regex(&mut self) -> Result<(u32, RegExpFlags)> {
let (token, pattern_end, flags) = self.lexer.next_regex(self.cur_kind())?;
self.token = token;
(pattern_end, flags)
Ok((pattern_end, flags))
}

/// Tell lexer to read a template substitution tail
Expand Down
15 changes: 7 additions & 8 deletions crates/oxc_parser/src/js/expression.rs
Original file line number Diff line number Diff line change
Expand Up @@ -189,10 +189,9 @@ impl<'a> ParserImpl<'a> {
}
}
Kind::LParen => self.parse_parenthesized_expression(span),
Kind::Slash | Kind::SlashEq => {
let literal = self.parse_literal_regexp();
Ok(self.ast.expression_from_reg_exp_literal(literal))
}
Kind::Slash | Kind::SlashEq => self
.parse_literal_regexp()
.map(|literal| self.ast.expression_from_reg_exp_literal(literal)),
// JSXElement, JSXFragment
Kind::LAngle if self.source_type.is_jsx() => self.parse_jsx_expression(),
_ => self.parse_identifier_expression(),
Expand Down Expand Up @@ -336,11 +335,11 @@ impl<'a> ParserImpl<'a> {
Ok(self.ast.big_int_literal(self.end_span(span), raw, base))
}

pub(crate) fn parse_literal_regexp(&mut self) -> RegExpLiteral<'a> {
pub(crate) fn parse_literal_regexp(&mut self) -> Result<RegExpLiteral<'a>> {
let span = self.start_span();

// split out pattern
let (pattern_end, flags) = self.read_regex();
let (pattern_end, flags) = self.read_regex()?;
let pattern_start = self.cur_token().start + 1; // +1 to exclude `/`
let pattern = &self.source_text[pattern_start as usize..pattern_end as usize];
self.bump_any();
Expand All @@ -350,11 +349,11 @@ impl<'a> ParserImpl<'a> {
.parse_regular_expression
.then(|| self.parse_regex_pattern(pattern_start, pattern, flags));

self.ast.reg_exp_literal(
Ok(self.ast.reg_exp_literal(
self.end_span(span),
EmptyObject,
RegExp { pattern: self.ast.atom(pattern), flags },
)
))
}

fn parse_regex_pattern(
Expand Down
20 changes: 9 additions & 11 deletions crates/oxc_parser/src/lexer/regex.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use oxc_syntax::identifier::is_line_terminator;

use super::{Kind, Lexer, RegExpFlags, Token};
use crate::diagnostics;
use oxc_diagnostics::Result;

impl<'a> Lexer<'a> {
/// Re-tokenize the current `/` or `/=` and return `RegExp`
Expand All @@ -10,34 +11,31 @@ impl<'a> Lexer<'a> {
/// where a `RegularExpressionLiteral` is permitted
/// Which means the parser needs to re-tokenize on `PrimaryExpression`,
/// `RegularExpressionLiteral` only appear on the right hand side of `PrimaryExpression`
pub(crate) fn next_regex(&mut self, kind: Kind) -> (Token, u32, RegExpFlags) {
pub(crate) fn next_regex(&mut self, kind: Kind) -> Result<(Token, u32, RegExpFlags)> {
self.token.start = self.offset()
- match kind {
Kind::Slash => 1,
Kind::SlashEq => 2,
_ => unreachable!(),
};
let (pattern_end, flags) = self.read_regex();
let (pattern_end, flags) = self.read_regex()?;
self.lookahead.clear();
let token = self.finish_next(Kind::RegExp);
(token, pattern_end, flags)
Ok((token, pattern_end, flags))
}

/// 12.9.5 Regular Expression Literals
fn read_regex(&mut self) -> (u32, RegExpFlags) {
fn read_regex(&mut self) -> Result<(u32, RegExpFlags)> {
let mut in_escape = false;
let mut in_character_class = false;
loop {
match self.next_char() {
None => {
self.error(diagnostics::unterminated_reg_exp(self.unterminated_range()));
return (self.offset(), RegExpFlags::empty());
return Err(diagnostics::unterminated_reg_exp(self.unterminated_range()));
// return (self.offset(), RegExpFlags::empty());
}
Some(c) if is_line_terminator(c) => {
self.error(diagnostics::unterminated_reg_exp(self.unterminated_range()));
#[allow(clippy::cast_possible_truncation)]
let pattern_end = self.offset() - c.len_utf8() as u32;
return (pattern_end, RegExpFlags::empty());
return Err(diagnostics::unterminated_reg_exp(self.unterminated_range()));
}
Some(c) => {
if in_escape {
Expand Down Expand Up @@ -79,6 +77,6 @@ impl<'a> Lexer<'a> {
flags |= flag;
}

(pattern_end, flags)
Ok((pattern_end, flags))
}
}
41 changes: 0 additions & 41 deletions tasks/coverage/parser_babel.snap
Original file line number Diff line number Diff line change
Expand Up @@ -1308,12 +1308,6 @@ Expect to Parse: tasks/coverage/babel/packages/babel-parser/test/fixtures/typesc
╭─[babel/packages/babel-parser/test/fixtures/core/uncategorised/380/input.js:1:9]
1 │ var x = /
· ──
2 │ /
╰────

× Unexpected token
╭─[babel/packages/babel-parser/test/fixtures/core/uncategorised/380/input.js:2:2]
1 │ var x = /
2 │ /
╰────

Expand Down Expand Up @@ -1696,19 +1690,6 @@ Expect to Parse: tasks/coverage/babel/packages/babel-parser/test/fixtures/typesc
╭─[babel/packages/babel-parser/test/fixtures/core/uncategorised/441/input.js:1:1]
1 │ /a\
· ────
2 │ /
╰────

× Invalid regular expression: Invalid escape
╭─[babel/packages/babel-parser/test/fixtures/core/uncategorised/441/input.js:1:3]
1 │ /a\
· ─
2 │ /
╰────

× Unexpected token
╭─[babel/packages/babel-parser/test/fixtures/core/uncategorised/441/input.js:2:2]
1 │ /a\
2 │ /
╰────

Expand Down Expand Up @@ -8218,11 +8199,6 @@ Expect to Parse: tasks/coverage/babel/packages/babel-parser/test/fixtures/typesc
2 │ /
╰────

× Unexpected token
╭─[babel/packages/babel-parser/test/fixtures/esprima/invalid-syntax/migrated_0040/input.js:3:1]
2 │ /
╰────

× Invalid Unicode escape sequence
╭─[babel/packages/babel-parser/test/fixtures/esprima/invalid-syntax/migrated_0041/input.js:1:17]
1 │ var x = /[a-z]/\ux
Expand Down Expand Up @@ -8397,11 +8373,6 @@ Expect to Parse: tasks/coverage/babel/packages/babel-parser/test/fixtures/typesc
2 │ /
╰────

× Unexpected token
╭─[babel/packages/babel-parser/test/fixtures/esprima/invalid-syntax/migrated_0062/input.js:3:1]
2 │ /
╰────

× Unterminated string
╭─[babel/packages/babel-parser/test/fixtures/esprima/invalid-syntax/migrated_0063/input.js:1:9]
1 │ var x = "
Expand Down Expand Up @@ -8942,18 +8913,6 @@ Expect to Parse: tasks/coverage/babel/packages/babel-parser/test/fixtures/typesc
2 │ /
╰────

× Invalid regular expression: Invalid escape
╭─[babel/packages/babel-parser/test/fixtures/esprima/invalid-syntax/migrated_0157/input.js:1:3]
1 │ /a\
· ─
2 │ /
╰────

× Unexpected token
╭─[babel/packages/babel-parser/test/fixtures/esprima/invalid-syntax/migrated_0157/input.js:3:1]
2 │ /
╰────

× Unexpected token
╭─[babel/packages/babel-parser/test/fixtures/esprima/invalid-syntax/migrated_0158/input.js:3:1]
2 │
Expand Down
Loading

0 comments on commit e6fd52e

Please sign in to comment.