Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion crates/oxc_parser/src/cursor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ impl<'a> ParserImpl<'a> {

/// Get current template string
pub(crate) fn cur_template_string(&self) -> Option<&'a str> {
self.lexer.get_template_string(self.token)
self.lexer.get_template_string(self.token.start)
}

/// Peek next token, returns EOF for final peek
Expand Down
30 changes: 19 additions & 11 deletions crates/oxc_parser/src/js/expression.rs
Original file line number Diff line number Diff line change
Expand Up @@ -546,18 +546,26 @@ impl<'a> ParserImpl<'a> {
_ => unreachable!(),
};

// `cooked = None` when template literal has invalid escape sequence
// This is matched by `is_valid_escape_sequence` in `Lexer::read_template_literal`
let cooked = self.cur_template_string();
let lone_surrogates = self.cur_token().lone_surrogates;
// Get `raw`
let raw_span = self.cur_token().span();
let mut raw = Atom::from(
&self.source_text[raw_span.start as usize + 1..(raw_span.end - end_offset) as usize],
);

let cur_src = self.cur_src();
let raw = &cur_src[1..cur_src.len() - end_offset as usize];
let raw = Atom::from(if cooked.is_some() && raw.contains('\r') {
self.ast.str(&raw.cow_replace("\r\n", "\n").cow_replace('\r', "\n"))
// Get `cooked`.
// Also replace `\r` with `\n` in `raw`.
// If contains `\r`, then `escaped` must be `true` (because `\r` needs unescaping),
// so we can skip searching for `\r` in common case where contains no escapes.
let (cooked, lone_surrogates) = if self.cur_token().escaped {
// `cooked = None` when template literal has invalid escape sequence
let cooked = self.cur_template_string().map(Atom::from);
if cooked.is_some() && raw.contains('\r') {
raw = self.ast.atom(&raw.cow_replace("\r\n", "\n").cow_replace('\r', "\n"));
}
(cooked, self.cur_token().lone_surrogates)
} else {
raw
});
(Some(raw), false)
};

self.bump_any();

Expand All @@ -572,7 +580,7 @@ impl<'a> ParserImpl<'a> {
let tail = matches!(cur_kind, Kind::TemplateTail | Kind::NoSubstitutionTemplate);
self.ast.template_element_with_lone_surrogates(
span,
TemplateElementValue { raw, cooked: cooked.map(Atom::from) },
TemplateElementValue { raw, cooked },
tail,
lone_surrogates,
)
Expand Down
16 changes: 2 additions & 14 deletions crates/oxc_parser/src/lexer/template.rs
Original file line number Diff line number Diff line change
Expand Up @@ -399,20 +399,8 @@ impl<'a> Lexer<'a> {
self.token.escaped = true;
}

pub(crate) fn get_template_string(&self, token: Token) -> Option<&'a str> {
if token.escaped {
return self.escaped_templates[&token.start];
}
let raw = &self.source.whole()[token.start as usize..token.end as usize];
Some(match token.kind {
Kind::NoSubstitutionTemplate | Kind::TemplateTail => {
&raw[1..raw.len() - 1] // omit surrounding quotes or leading "}" and trailing "`"
}
Kind::TemplateHead | Kind::TemplateMiddle => {
&raw[1..raw.len() - 2] // omit leading "`" or "}" and trailing "${"
}
_ => raw,
})
pub(crate) fn get_template_string(&self, span_start: u32) -> Option<&'a str> {
self.escaped_templates[&span_start]
}
}

Expand Down
Loading