Skip to content

Commit a066b76

Browse files
authored
fix(es/parser): Improve error message for template literals (#10690)
1 parent 03d520b commit a066b76

File tree

4 files changed

+50
-62
lines changed

4 files changed

+50
-62
lines changed

crates/swc_ecma_lexer/src/common/parser/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -513,6 +513,8 @@ pub fn parse_shebang<'a>(p: &mut impl Parser<'a>) -> PResult<Option<Atom>> {
513513
})
514514
}
515515

516+
#[cold]
517+
#[inline(never)]
516518
pub fn eof_error<'a, P: Parser<'a>>(p: &mut P) -> crate::error::Error {
517519
debug_assert!(
518520
p.input_mut().cur().is_none(),

crates/swc_ecma_parser/src/parser/macros.rs

Lines changed: 0 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,3 @@
1-
macro_rules! cur {
2-
($p:expr, true) => {{
3-
match $p.input_mut().cur() {
4-
Some(c) => {
5-
if *c == Token::Error {
6-
let c = $p.input_mut().bump();
7-
let err = c.take_error($p.input_mut());
8-
return Err(err);
9-
} else {
10-
c
11-
}
12-
}
13-
None => {
14-
let pos = $p.input().end_pos();
15-
let span = Span::new(pos, pos);
16-
let err = crate::error::Error::new(span, crate::error::SyntaxError::Eof);
17-
return Err(err);
18-
}
19-
}
20-
}};
21-
}
22-
231
macro_rules! trace_cur {
242
($p:expr, $name:ident) => {{
253
if cfg!(feature = "debug") {

crates/swc_ecma_parser/src/parser/tpl.rs

Lines changed: 47 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@ use swc_ecma_ast::*;
33
use swc_ecma_lexer::{
44
common::{
55
lexer::token::TokenFactory,
6-
parser::{buffer::Buffer, typescript::parse_ts_type, PResult, Parser as ParserTrait},
6+
parser::{
7+
buffer::Buffer, eof_error, typescript::parse_ts_type, PResult, Parser as ParserTrait,
8+
},
79
},
810
error::SyntaxError,
911
};
@@ -132,50 +134,56 @@ impl<I: Tokens> Parser<I> {
132134
self.input_mut().rescan_template_token(false);
133135
}
134136
let start = self.cur_pos();
135-
let (raw, cooked, tail, span) = match *cur!(self, true) {
136-
Token::TemplateMiddle => match self.bump() {
137-
t @ Token::TemplateMiddle => {
138-
let (cooked, raw) = t.take_template(self.input_mut());
139-
let pos = self.input.prev_span().hi;
140-
debug_assert!(start.0 <= pos.0 - 2);
141-
// case: ___${
142-
// `pos.0 - 2` means skip '${'
143-
let span = Span::new(start, BytePos::from_u32(pos.0 - 2));
144-
match cooked {
145-
Ok(cooked) => (raw, Some(cooked), false, span),
146-
Err(err) => {
147-
if is_tagged_tpl {
148-
(raw, None, false, span)
149-
} else {
150-
return Err(err);
151-
}
137+
let Some(cur) = self.input_mut().cur() else {
138+
return Err(eof_error(self));
139+
};
140+
let (raw, cooked, tail, span) = match *cur {
141+
Token::TemplateMiddle => {
142+
let t = self.bump();
143+
let (cooked, raw) = t.take_template(self.input_mut());
144+
let pos = self.input.prev_span().hi;
145+
debug_assert!(start.0 <= pos.0 - 2);
146+
// case: ___${
147+
// `pos.0 - 2` means skip '${'
148+
let span = Span::new(start, BytePos::from_u32(pos.0 - 2));
149+
match cooked {
150+
Ok(cooked) => (raw, Some(cooked), false, span),
151+
Err(err) => {
152+
if is_tagged_tpl {
153+
(raw, None, false, span)
154+
} else {
155+
return Err(err);
152156
}
153157
}
154158
}
155-
_ => unreachable!(),
156-
},
157-
Token::TemplateTail => match self.bump() {
158-
t @ Token::TemplateTail => {
159-
let (cooked, raw) = t.take_template(self.input_mut());
160-
let pos = self.input.prev_span().hi;
161-
debug_assert!(start.0 < pos.0);
162-
// case: ____`
163-
// `pos.0 - 1` means skip '`'
164-
let span = Span::new(start, BytePos::from_u32(pos.0 - 1));
165-
match cooked {
166-
Ok(cooked) => (raw, Some(cooked), true, span),
167-
Err(err) => {
168-
if is_tagged_tpl {
169-
(raw, None, true, span)
170-
} else {
171-
return Err(err);
172-
}
159+
}
160+
Token::TemplateTail => {
161+
let t = self.bump();
162+
let (cooked, raw) = t.take_template(self.input_mut());
163+
let pos = self.input.prev_span().hi;
164+
debug_assert!(start.0 < pos.0);
165+
// case: ____`
166+
// `pos.0 - 1` means skip '`'
167+
let span = Span::new(start, BytePos::from_u32(pos.0 - 1));
168+
match cooked {
169+
Ok(cooked) => (raw, Some(cooked), true, span),
170+
Err(err) => {
171+
if is_tagged_tpl {
172+
(raw, None, true, span)
173+
} else {
174+
return Err(err);
173175
}
174176
}
175177
}
176-
_ => unreachable!(),
177-
},
178-
_ => unexpected!(self, "TemplateMiddle or TemplateTail"),
178+
}
179+
Token::Error => {
180+
let t = self.input_mut().bump();
181+
let err = t.take_error(self.input_mut());
182+
return Err(err);
183+
}
184+
_ => {
185+
unexpected!(self, "`}`")
186+
}
179187
};
180188

181189
Ok(TplElement {

crates/swc_ecma_parser/tests/test262-error-references/fail/1acada3c651821cf.js.swc-stderr

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
x Unexpected token `;`. Expected TemplateMiddle or TemplateTail
1+
x Unexpected token `;`. Expected `}`
22
,-[$DIR/tests/test262-parser/fail/1acada3c651821cf.js:1:1]
33
1 | `hello ${10;test`
44
: ^

0 commit comments

Comments
 (0)