mirror of
https://github.com/swc-project/swc.git
synced 2024-12-29 16:42:28 +03:00
fix(es/lexer): Don't report lexer errors while backtracking (#3051)
swc_ecma_parser: - Share backtracking state with the lexer. - Don't report lexing errors while backtracking (Closes #2896)
This commit is contained in:
parent
c658af4365
commit
61e9b5f841
@ -0,0 +1,19 @@
|
|||||||
|
/*#__PURE__*/ React.createElement("div", null, "Dot goes here: \xb7 ¬AnEntity; ");
|
||||||
|
/*#__PURE__*/ React.createElement("div", null, "Be careful of \"-ed strings!");
|
||||||
|
/*#__PURE__*/ React.createElement("div", null, "{{braces}}");
|
||||||
|
// Escapes do nothing
|
||||||
|
/*#__PURE__*/ React.createElement("div", null, "\\n");
|
||||||
|
// Also works in string literal attributes
|
||||||
|
/*#__PURE__*/ React.createElement("div", {
|
||||||
|
attr: "{…}\\"
|
||||||
|
});
|
||||||
|
// Does not happen for a string literal that happens to be inside an attribute (and escapes then work)
|
||||||
|
/*#__PURE__*/ React.createElement("div", {
|
||||||
|
attr: "{…}\""
|
||||||
|
});
|
||||||
|
// Preserves single quotes
|
||||||
|
/*#__PURE__*/ React.createElement("div", {
|
||||||
|
attr: "\""
|
||||||
|
});
|
||||||
|
// https://github.com/microsoft/TypeScript/issues/35732
|
||||||
|
/*#__PURE__*/ React.createElement("div", null, "🐈🐕🐇🐑");
|
@ -0,0 +1,7 @@
|
|||||||
|
React.createElement("div", null, "Dot goes here: \xb7 ¬AnEntity; "), React.createElement("div", null, "Be careful of \"-ed strings!"), React.createElement("div", null, "{{braces}}"), React.createElement("div", null, "\\n"), React.createElement("div", {
|
||||||
|
attr: "{…}\\"
|
||||||
|
}), React.createElement("div", {
|
||||||
|
attr: "{…}\""
|
||||||
|
}), React.createElement("div", {
|
||||||
|
attr: "\""
|
||||||
|
}), React.createElement("div", null, "🐈🐕🐇🐑");
|
@ -0,0 +1,19 @@
|
|||||||
|
/*#__PURE__*/ React.createElement("div", null, "Dot goes here: \xb7 ¬AnEntity; ");
|
||||||
|
/*#__PURE__*/ React.createElement("div", null, "Be careful of \"-ed strings!");
|
||||||
|
/*#__PURE__*/ React.createElement("div", null, "{{braces}}");
|
||||||
|
// Escapes do nothing
|
||||||
|
/*#__PURE__*/ React.createElement("div", null, "\\n");
|
||||||
|
// Also works in string literal attributes
|
||||||
|
/*#__PURE__*/ React.createElement("div", {
|
||||||
|
attr: "{…}\\"
|
||||||
|
});
|
||||||
|
// Does not happen for a string literal that happens to be inside an attribute (and escapes then work)
|
||||||
|
/*#__PURE__*/ React.createElement("div", {
|
||||||
|
attr: "{…}\""
|
||||||
|
});
|
||||||
|
// Preserves single quotes
|
||||||
|
/*#__PURE__*/ React.createElement("div", {
|
||||||
|
attr: "\""
|
||||||
|
});
|
||||||
|
// https://github.com/microsoft/TypeScript/issues/35732
|
||||||
|
/*#__PURE__*/ React.createElement("div", null, "🐈🐕🐇🐑");
|
@ -0,0 +1,7 @@
|
|||||||
|
React.createElement("div", null, "Dot goes here: \xb7 ¬AnEntity; "), React.createElement("div", null, "Be careful of \"-ed strings!"), React.createElement("div", null, "{{braces}}"), React.createElement("div", null, "\\n"), React.createElement("div", {
|
||||||
|
attr: "{…}\\"
|
||||||
|
}), React.createElement("div", {
|
||||||
|
attr: "{…}\""
|
||||||
|
}), React.createElement("div", {
|
||||||
|
attr: "\""
|
||||||
|
}), React.createElement("div", null, "🐈🐕🐇🐑");
|
@ -16,6 +16,7 @@ use swc_common::{
|
|||||||
comments::{Comment, CommentKind},
|
comments::{Comment, CommentKind},
|
||||||
BytePos, Span, SyntaxContext,
|
BytePos, Span, SyntaxContext,
|
||||||
};
|
};
|
||||||
|
use tracing::warn;
|
||||||
use unicode_xid::UnicodeXID;
|
use unicode_xid::UnicodeXID;
|
||||||
|
|
||||||
/// Collector for raw string.
|
/// Collector for raw string.
|
||||||
@ -117,6 +118,11 @@ impl<'a, I: Input> Lexer<'a, I> {
|
|||||||
#[cold]
|
#[cold]
|
||||||
#[inline(never)]
|
#[inline(never)]
|
||||||
pub(super) fn emit_error_span(&mut self, span: Span, kind: SyntaxError) {
|
pub(super) fn emit_error_span(&mut self, span: Span, kind: SyntaxError) {
|
||||||
|
if self.ctx.ignore_error {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
warn!("Lexer error at {:?}", span);
|
||||||
let err = Error {
|
let err = Error {
|
||||||
error: Box::new((span, kind)),
|
error: Box::new((span, kind)),
|
||||||
};
|
};
|
||||||
|
@ -326,6 +326,9 @@ pub struct EsConfig {
|
|||||||
/// Syntactic context.
|
/// Syntactic context.
|
||||||
#[derive(Debug, Clone, Copy, Default)]
|
#[derive(Debug, Clone, Copy, Default)]
|
||||||
pub struct Context {
|
pub struct Context {
|
||||||
|
/// `true` while backtracking
|
||||||
|
ignore_error: bool,
|
||||||
|
|
||||||
/// Is in module code?
|
/// Is in module code?
|
||||||
module: bool,
|
module: bool,
|
||||||
can_be_module: bool,
|
can_be_module: bool,
|
||||||
|
@ -39,8 +39,6 @@ pub type PResult<T> = Result<T, Error>;
|
|||||||
/// EcmaScript parser.
|
/// EcmaScript parser.
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Parser<I: Tokens> {
|
pub struct Parser<I: Tokens> {
|
||||||
/// [false] while backtracking
|
|
||||||
emit_err: bool,
|
|
||||||
state: State,
|
state: State,
|
||||||
input: Buffer<I>,
|
input: Buffer<I>,
|
||||||
}
|
}
|
||||||
@ -63,7 +61,6 @@ impl<'a, I: Input> Parser<Lexer<'a, I>> {
|
|||||||
impl<I: Tokens> Parser<I> {
|
impl<I: Tokens> Parser<I> {
|
||||||
pub fn new_from(input: I) -> Self {
|
pub fn new_from(input: I) -> Self {
|
||||||
Parser {
|
Parser {
|
||||||
emit_err: true,
|
|
||||||
state: Default::default(),
|
state: Default::default(),
|
||||||
input: Buffer::new(input),
|
input: Buffer::new(input),
|
||||||
}
|
}
|
||||||
@ -209,7 +206,7 @@ impl<I: Tokens> Parser<I> {
|
|||||||
|
|
||||||
#[cold]
|
#[cold]
|
||||||
fn emit_err(&self, span: Span, error: SyntaxError) {
|
fn emit_err(&self, span: Span, error: SyntaxError) {
|
||||||
if !self.emit_err || !self.syntax().early_errors() {
|
if self.ctx().ignore_error || !self.syntax().early_errors() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -220,7 +217,7 @@ impl<I: Tokens> Parser<I> {
|
|||||||
|
|
||||||
#[cold]
|
#[cold]
|
||||||
fn emit_error(&self, error: Error) {
|
fn emit_error(&self, error: Error) {
|
||||||
if !self.emit_err || !self.syntax().early_errors() {
|
if self.ctx().ignore_error || !self.syntax().early_errors() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -229,7 +226,7 @@ impl<I: Tokens> Parser<I> {
|
|||||||
|
|
||||||
#[cold]
|
#[cold]
|
||||||
fn emit_strict_mode_err(&self, span: Span, error: SyntaxError) {
|
fn emit_strict_mode_err(&self, span: Span, error: SyntaxError) {
|
||||||
if !self.emit_err {
|
if self.ctx().ignore_error {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let error = Error {
|
let error = Error {
|
||||||
|
@ -490,14 +490,22 @@ impl<I: Tokens> Parser<I> {
|
|||||||
if !self.input.syntax().typescript() {
|
if !self.input.syntax().typescript() {
|
||||||
return Ok(false);
|
return Ok(false);
|
||||||
}
|
}
|
||||||
let prev_emit_err = self.emit_err;
|
let prev_ignore_error = self.input.get_ctx().ignore_error;
|
||||||
let mut cloned = self.clone();
|
let mut cloned = self.clone();
|
||||||
cloned.emit_err = false;
|
let ctx = Context {
|
||||||
|
ignore_error: true,
|
||||||
|
..self.input.get_ctx()
|
||||||
|
};
|
||||||
|
cloned.set_ctx(ctx);
|
||||||
let res = op(&mut cloned);
|
let res = op(&mut cloned);
|
||||||
match res {
|
match res {
|
||||||
Ok(Some(res)) if res => {
|
Ok(Some(res)) if res => {
|
||||||
*self = cloned;
|
*self = cloned;
|
||||||
self.emit_err = prev_emit_err;
|
let ctx = Context {
|
||||||
|
ignore_error: prev_ignore_error,
|
||||||
|
..self.input.get_ctx()
|
||||||
|
};
|
||||||
|
self.input.set_ctx(ctx);
|
||||||
Ok(res)
|
Ok(res)
|
||||||
}
|
}
|
||||||
Err(err) => Ok(false),
|
Err(err) => Ok(false),
|
||||||
@ -513,18 +521,32 @@ impl<I: Tokens> Parser<I> {
|
|||||||
if !self.input.syntax().typescript() {
|
if !self.input.syntax().typescript() {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
trace_cur!(self, try_parse_ts);
|
#[cfg(feature = "debug")]
|
||||||
let prev_emit_err = self.emit_err;
|
let _tracing = {
|
||||||
|
let cur = format!("{:?}", self.input.cur());
|
||||||
|
tracing::span!(tracing::Level::ERROR, "try_parse_ts", cur = &*cur).entered()
|
||||||
|
};
|
||||||
|
|
||||||
|
trace_cur!(self, try_parse_ts);
|
||||||
|
|
||||||
|
let prev_ignore_error = self.input.get_ctx().ignore_error;
|
||||||
let mut cloned = self.clone();
|
let mut cloned = self.clone();
|
||||||
cloned.emit_err = false;
|
let ctx = Context {
|
||||||
|
ignore_error: true,
|
||||||
|
..self.input.get_ctx()
|
||||||
|
};
|
||||||
|
cloned.set_ctx(ctx);
|
||||||
let res = op(&mut cloned);
|
let res = op(&mut cloned);
|
||||||
match res {
|
match res {
|
||||||
Ok(Some(res)) => {
|
Ok(Some(res)) => {
|
||||||
*self = cloned;
|
*self = cloned;
|
||||||
trace_cur!(self, try_parse_ts__success_value);
|
trace_cur!(self, try_parse_ts__success_value);
|
||||||
|
let ctx = Context {
|
||||||
|
ignore_error: prev_ignore_error,
|
||||||
|
..self.input.get_ctx()
|
||||||
|
};
|
||||||
|
self.input.set_ctx(ctx);
|
||||||
|
|
||||||
self.emit_err = prev_emit_err;
|
|
||||||
Some(res)
|
Some(res)
|
||||||
}
|
}
|
||||||
Ok(None) => {
|
Ok(None) => {
|
||||||
@ -1069,7 +1091,11 @@ impl<I: Tokens> Parser<I> {
|
|||||||
debug_assert!(self.input.syntax().typescript());
|
debug_assert!(self.input.syntax().typescript());
|
||||||
|
|
||||||
let mut cloned = self.clone();
|
let mut cloned = self.clone();
|
||||||
cloned.emit_err = false;
|
let ctx = Context {
|
||||||
|
ignore_error: true,
|
||||||
|
..cloned.ctx()
|
||||||
|
};
|
||||||
|
cloned.set_ctx(ctx);
|
||||||
let res = op(&mut cloned);
|
let res = op(&mut cloned);
|
||||||
res
|
res
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1 @@
|
|||||||
|
<div>children</div>; '<>hello</>';
|
@ -0,0 +1,100 @@
|
|||||||
|
{
|
||||||
|
"type": "Script",
|
||||||
|
"span": {
|
||||||
|
"start": 0,
|
||||||
|
"end": 34,
|
||||||
|
"ctxt": 0
|
||||||
|
},
|
||||||
|
"body": [
|
||||||
|
{
|
||||||
|
"type": "ExpressionStatement",
|
||||||
|
"span": {
|
||||||
|
"start": 0,
|
||||||
|
"end": 20,
|
||||||
|
"ctxt": 0
|
||||||
|
},
|
||||||
|
"expression": {
|
||||||
|
"type": "JSXElement",
|
||||||
|
"span": {
|
||||||
|
"start": 0,
|
||||||
|
"end": 19,
|
||||||
|
"ctxt": 0
|
||||||
|
},
|
||||||
|
"opening": {
|
||||||
|
"type": "JSXOpeningElement",
|
||||||
|
"name": {
|
||||||
|
"type": "Identifier",
|
||||||
|
"span": {
|
||||||
|
"start": 1,
|
||||||
|
"end": 4,
|
||||||
|
"ctxt": 0
|
||||||
|
},
|
||||||
|
"value": "div",
|
||||||
|
"optional": false
|
||||||
|
},
|
||||||
|
"span": {
|
||||||
|
"start": 0,
|
||||||
|
"end": 5,
|
||||||
|
"ctxt": 0
|
||||||
|
},
|
||||||
|
"attributes": [],
|
||||||
|
"selfClosing": false,
|
||||||
|
"typeArguments": null
|
||||||
|
},
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"type": "JSXText",
|
||||||
|
"span": {
|
||||||
|
"start": 5,
|
||||||
|
"end": 13,
|
||||||
|
"ctxt": 0
|
||||||
|
},
|
||||||
|
"value": "children",
|
||||||
|
"raw": "children"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"closing": {
|
||||||
|
"type": "JSXClosingElement",
|
||||||
|
"span": {
|
||||||
|
"start": 13,
|
||||||
|
"end": 19,
|
||||||
|
"ctxt": 0
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"type": "Identifier",
|
||||||
|
"span": {
|
||||||
|
"start": 15,
|
||||||
|
"end": 18,
|
||||||
|
"ctxt": 0
|
||||||
|
},
|
||||||
|
"value": "div",
|
||||||
|
"optional": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "ExpressionStatement",
|
||||||
|
"span": {
|
||||||
|
"start": 21,
|
||||||
|
"end": 34,
|
||||||
|
"ctxt": 0
|
||||||
|
},
|
||||||
|
"expression": {
|
||||||
|
"type": "StringLiteral",
|
||||||
|
"span": {
|
||||||
|
"start": 21,
|
||||||
|
"end": 33,
|
||||||
|
"ctxt": 0
|
||||||
|
},
|
||||||
|
"value": "<>hello</>",
|
||||||
|
"hasEscape": false,
|
||||||
|
"kind": {
|
||||||
|
"type": "normal",
|
||||||
|
"containsQuote": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"interpreter": null
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user