Skip to content

Commit

Permalink
Unescape template literals before emitting. (swc-project#652)
Browse files Browse the repository at this point in the history
  • Loading branch information
kdy1 authored Feb 11, 2020
1 parent 1bf81c6 commit 64f6e51
Show file tree
Hide file tree
Showing 7 changed files with 140 additions and 27 deletions.
137 changes: 115 additions & 22 deletions ecmascript/codegen/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use self::{
text_writer::WriteJs,
util::{SourceMapperExt, SpanExt, StartsWithAlphaNum},
};
use std::{io, sync::Arc};
use std::{fmt::Write, io, sync::Arc};
use swc_atoms::JsWord;
use swc_common::{comments::Comments, BytePos, SourceMap, Span, Spanned, SyntaxContext, DUMMY_SP};
use swc_ecma_ast::*;
Expand Down Expand Up @@ -347,26 +347,7 @@ impl<'a> Emitter<'a> {
// self.wr.write_str_lit(node.span, &s)?;
// return Ok(());
// }
let value = node
.value
.replace("\\", "\\\\")
.replace('\u{0008}', "\\b")
.replace('\u{000C}', "\\f")
.replace("\n", "\\n")
.replace("\r", "\\r")
.replace("\t", "\\t")
.replace('\u{000B}', "\\v")
.replace("\00", "\\x000")
.replace("\01", "\\x001")
.replace("\02", "\\x002")
.replace("\03", "\\x003")
.replace("\04", "\\x004")
.replace("\05", "\\x005")
.replace("\06", "\\x006")
.replace("\07", "\\x007")
.replace("\08", "\\x008")
.replace("\09", "\\x009")
.replace("\0", "\\0");
let value = escape(&node.value);
// let value = node.value.replace("\n", "\\n");

if !node.value.contains('\'') {
Expand Down Expand Up @@ -986,7 +967,8 @@ impl<'a> Emitter<'a> {

#[emitter]
pub fn emit_quasi(&mut self, node: &TplElement) -> Result {
self.wr.write_str_lit(node.span, &node.raw.value)?;
self.wr
.write_str_lit(node.span, &unescape(&node.raw.value))?;
return Ok(());
}

Expand Down Expand Up @@ -2062,3 +2044,114 @@ where
}
}
}

fn unescape(s: &str) -> String {
fn read_escaped(
radix: u32,
len: Option<usize>,
buf: &mut String,
chars: impl Iterator<Item = char>,
) {
let mut v = 0;
let mut pending = None;

for (i, c) in chars.enumerate() {
if let Some(len) = len {
if i == len {
pending = Some(c);
break;
}
}

match c.to_digit(radix) {
None => {
pending = Some(c);
break;
}
Some(d) => {
v = v * radix + d;
}
}
}

match radix {
2 => write!(buf, "\\b{:b}", v).unwrap(),

8 => write!(buf, "\\o{:o}", v).unwrap(),

16 => write!(buf, "\\x{:x}", v).unwrap(),

_ => unreachable!(),
}

if let Some(pending) = pending {
buf.push(pending);
}
}

let s = s.replace("\\\\", "\\");

let mut result = String::with_capacity(s.len() * 6 / 5);
let mut chars = s.chars();

while let Some(c) = chars.next() {
if c != '\\' {
result.push(c);
continue;
}

match chars.next() {
None => {
// This is wrong, but it seems like a mistake made by user.
result.push('\\');
}
Some(c) => match c {
'\\' => result.push('\\'),
'n' => result.push_str("\\\n"),
'r' => result.push_str("\\\r"),
't' => result.push_str("\\\t"),
'b' => result.push_str("\\\u{0008}"),
'f' => result.push_str("\\\u{000C}"),
'v' => result.push_str("\\\u{000B}"),
'0' => match chars.next() {
Some('b') => read_escaped(2, None, &mut result, &mut chars),
Some('o') => read_escaped(8, None, &mut result, &mut chars),
Some('x') => read_escaped(16, Some(2), &mut result, &mut chars),
nc => {
// This is wrong, but it seems like a mistake made by user.
result.push('0');
result.extend(nc);
}
},

_ => {
result.push('\\');
result.push(c);
}
},
}
}

result
}

fn escape(s: &str) -> String {
s.replace("\\", "\\\\")
.replace('\u{0008}', "\\b")
.replace('\u{000C}', "\\f")
.replace("\n", "\\n")
.replace("\r", "\\r")
.replace("\t", "\\t")
.replace('\u{000B}', "\\v")
.replace("\00", "\\x000")
.replace("\01", "\\x001")
.replace("\02", "\\x002")
.replace("\03", "\\x003")
.replace("\04", "\\x004")
.replace("\05", "\\x005")
.replace("\06", "\\x006")
.replace("\07", "\\x007")
.replace("\08", "\\x008")
.replace("\09", "\\x009")
.replace("\0", "\\0")
}
14 changes: 14 additions & 0 deletions ecmascript/codegen/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,20 @@ fn issue_546() {
);
}

#[test]
fn issue_637() {
test_from_to(
r"`\
`;", r"`\
`;",
);
}

#[test]
fn issue_639() {
test_from_to(r"`\x1b[33m Yellow \x1b[0m`;", r"`\x1b[33m Yellow \x1b[0m`;");
}

#[derive(Debug, Clone)]
struct Buf(Arc<RwLock<Vec<u8>>>);
impl Write for Buf {
Expand Down
2 changes: 1 addition & 1 deletion ecmascript/codegen/tests/references/123f89c06747ced2.js
Original file line number Diff line number Diff line change
@@ -1 +1 @@
`\u{000042}\u0042\0x42u0\A`;
`\u{000042}\u0042\x42u0\A`;
5 changes: 4 additions & 1 deletion ecmascript/codegen/tests/references/12752899d5c5eb00.js
Original file line number Diff line number Diff line change
@@ -1 +1,4 @@
`\n\r\b\v\t\f\\n\\r\n`;
`\
\\\ \ \ \
\\
`;
Expand Down
3 changes: 2 additions & 1 deletion ecmascript/codegen/tests/references/6d8c97119162ad95.js
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
`\r\n
`\\
`;
Expand Down
3 changes: 2 additions & 1 deletion ecmascript/codegen/tests/references/94be09b126b946b8.js
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
`
\r\n`;
\\
`;
Expand Down
3 changes: 2 additions & 1 deletion ecmascript/codegen/tests/references/efb88a0b6e2e170e.js
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
`
\r\n`;
\\
`;
Expand Down

0 comments on commit 64f6e51

Please sign in to comment.