feat(codegen): move string test to codegen (#2150)

This commit is contained in:
Wenzhe Wang 2024-01-23 23:49:36 +08:00 committed by GitHub
parent 2406e94c0d
commit 1ee6d8cea9
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 174 additions and 91 deletions

View file

@ -1075,10 +1075,79 @@ impl<const MINIFY: bool> Gen<MINIFY> for RegExpLiteral {
}
}
fn print_str<const MINIFY: bool>(s: &str, p: &mut Codegen<{ MINIFY }>) {
p.print(b'\'');
fn choose_quote(s: &str) -> char {
let mut single_cost = 0;
let mut double_cost = 0;
for c in s.chars() {
match c {
'\'' => single_cost += 1,
'"' => double_cost += 1,
_ => {}
}
}
if single_cost > double_cost {
'"'
} else {
'\''
}
}
fn print_str<const MINIFY: bool>(s: &str, p: &mut Codegen<{ MINIFY }>) {
let quote = choose_quote(s);
p.print(quote as u8);
let mut chars = s.chars();
while let Some(c) = chars.next() {
match c {
'\x00' => {
if chars.clone().next().is_some_and(|next| next.is_ascii_digit()) {
p.print_str(b"\\x00");
} else {
p.print_str(b"\\0");
}
}
'\x07' => {
p.print_str(b"\\x07");
}
// \b
'\u{8}' => {
p.print_str(b"\\b");
}
// \v
'\u{b}' => {
p.print_str(b"\\v");
}
// \f
'\u{c}' => {
p.print_str(b"\\f");
}
'\n' => {
p.print_str(b"\\n");
}
'\r' => {
p.print_str(b"\\r");
}
'\x1B' => {
p.print_str(b"\\x1B");
}
'\\' => {
p.print_str(b"\\\\");
}
'\'' => {
if quote == '\'' {
p.print_str(b"\\'");
} else {
p.print_str(b"'");
}
}
'\"' => {
if quote == '"' {
p.print_str(b"\\\"");
} else {
p.print_str(b"\"");
}
}
// Allow `U+2028` and `U+2029` in string literals
// <https://tc39.es/proposal-json-superset>
// <https://github.com/tc39/proposal-json-superset>
@ -1090,7 +1159,7 @@ fn print_str<const MINIFY: bool>(s: &str, p: &mut Codegen<{ MINIFY }>) {
_ => p.print_str(c.escape_default().to_string().as_bytes()),
}
}
p.print(b'\'');
p.print(quote as u8);
}
impl<const MINIFY: bool> Gen<MINIFY> for StringLiteral {

View file

@ -0,0 +1,102 @@
use oxc_allocator::Allocator;
use oxc_codegen::{Codegen, CodegenOptions};
use oxc_parser::Parser;
use oxc_span::SourceType;
fn test(source_text: &str, expected: &str) {
let allocator = Allocator::default();
let program = Parser::new(&allocator, source_text, SourceType::default()).parse().program;
let program = allocator.alloc(program);
let result = Codegen::<false>::new(source_text.len(), CodegenOptions).build(program);
assert_eq!(expected, result, "for source {source_text}");
}
#[test]
fn string() {
test("let x = ''", "let x = '';\n");
test(r"let x = '\b'", "let x = '\\b';\n");
test(r"let x = '\f'", "let x = '\\f';\n");
test("let x = '\t'", "let x = '\\t';\n");
test(r"let x = '\v'", "let x = '\\v';\n");
test("let x = '\\n'", "let x = '\\n';\n");
test("let x = '\\''", "let x = \"'\";\n");
test("let x = '\\\"'", "let x = '\"';\n");
// test( "let x = '\\'''", "let x = `''`;\n");
test("let x = '\\\\'", "let x = '\\\\';\n");
test("let x = '\x00'", "let x = '\\0';\n");
test("let x = '\x00!'", "let x = '\\0!';\n");
test("let x = '\x001'", "let x = '\\x001';\n");
test("let x = '\\0'", "let x = '\\0';\n");
test("let x = '\\0!'", "let x = '\\0!';\n");
test("let x = '\x07'", "let x = '\\x07';\n");
test("let x = '\x07!'", "let x = '\\x07!';\n");
test("let x = '\x071'", "let x = '\\x071';\n");
test("let x = '\\7'", "let x = '\\x07';\n");
test("let x = '\\7!'", "let x = '\\x07!';\n");
// test( "let x = '\\01'", "let x = '\x01';\n");
// test( "let x = '\x10'", "let x = '\x10';\n");
// test( "let x = '\\x10'", "let x = '\x10';\n");
test("let x = '\x1B'", "let x = '\\x1B';\n");
test("let x = '\\x1B'", "let x = '\\x1B';\n");
// test( r#"let x = '\uABCD'"#, r#"let x = "\uABCD";"#);
// test( "let x = '\\uABCD'", r#"let x = '\uABCD';\n"#);
// test( r#"let x = '\U000123AB'"#, r#"let x = '\U000123AB';\n"#);
// test( "let x = '\\u{123AB}'", r#"let x = '\U000123AB';\n"#);
// test( "let x = '\\uD808\\uDFAB'", r#"let x = '\U000123AB';\n"#);
test("let x = '\\uD808'", "let x = '\\\\ud808';\n");
test("let x = '\\uD808X'", "let x = '\\\\ud808X';\n");
test("let x = '\\uDFAB'", "let x = '\\\\udfab';\n");
test("let x = '\\uDFABX'", "let x = '\\\\udfabX';\n");
// test( "let x = '\\x80'", r#"let x = '\U00000080';\n"#);
// test( "let x = '\\xFF'", r#"let x = '\U000000FF';\n"#);
// test( "let x = '\\xF0\\x9F\\x8D\\x95'", r#"let x = '\U000000F0\U0000009F\U0000008D\U00000095';\n"#);
// test("let x = '\\uD801\\uDC02\\uDC03\\uD804'", r#"let x = '\U00010402\\uDC03\\uD804';\n"#)
}
#[test]
#[ignore]
fn template() {
test("let x = `\\0`", "let x = `\\0`;\n");
test("let x = `\\x01`", "let x = `\x01`;\n");
test("let x = `\\0${0}`", "let x = `\\0${0}`;\n");
test("let x = `\\x01${0}`", "let x = `\x01${0}`;\n");
test("let x = `${0}\\0`", "let x = `${0}\\0`;\n");
test("let x = `${0}\\x01`", "let x = `${0}\x01`;\n");
test("let x = `${0}\\0${1}`", "let x = `${0}\\0${1}`;\n");
test("let x = `${0}\\x01${1}`", "let x = `${0}\x01${1}`;\n");
test("let x = String.raw`\\1`", "let x = String.raw`\\1`;\n");
test("let x = String.raw`\\x01`", "let x = String.raw`\\x01`;\n");
test("let x = String.raw`\\1${0}`", "let x = String.raw`\\1${0}`;\n");
test("let x = String.raw`\\x01${0}`", "let x = String.raw`\\x01${0}`;\n");
test("let x = String.raw`${0}\\1`", "let x = String.raw`${0}\\1`;\n");
test("let x = String.raw`${0}\\x01`", "let x = String.raw`${0}\\x01`;\n");
test("let x = String.raw`${0}\\1${1}`", "let x = String.raw`${0}\\1${1}`;\n");
test("let x = String.raw`${0}\\x01${1}`", "let x = String.raw`${0}\\x01${1}`;\n");
test("let x = `${y}`", "let x = `${y}`;\n");
test("let x = `$(y)`", "let x = `$(y)`;\n");
test("let x = `{y}$`", "let x = `{y}$`;\n");
test("let x = `$}y{`", "let x = `$}y{`;\n");
test("let x = `\\${y}`", "let x = `\\${y}`;\n");
test("let x = `$\\{y}`", "let x = `\\${y}`;\n");
test("await tag`x`", "await tag`x`;\n");
test("await (tag`x`)", "await tag`x`;\n");
test("(await tag)`x`", "(await tag)`x`;\n");
test("await tag`${x}`", "await tag`${x}`;\n");
test("await (tag`${x}`)", "await tag`${x}`;\n");
test("(await tag)`${x}`", "(await tag)`${x}`;\n");
test("new tag`x`", "new tag`x`();\n");
test("new (tag`x`)", "new tag`x`();\n");
test("new tag()`x`", "new tag()`x`;\n");
test("(new tag)`x`", "new tag()`x`;\n");
test("new tag`${x}`", "new tag`${x}`();\n");
test("new (tag`${x}`)", "new tag`${x}`();\n");
test("new tag()`${x}`", "new tag()`${x}`;\n");
test("(new tag)`${x}`", "new tag()`${x}`;\n");
}

View file

@ -171,102 +171,14 @@ fn nullish() {
test("(a ?? b) || c", "(a??b)||c;");
}
#[test]
#[ignore]
fn string() {
test("let x = ''", "let x = \"\";");
test("let x = '\\b'", "let x = \"\\b\";");
test("let x = '\\f'", "let x = \"\\f\";");
test("let x = '\t'", "let x = \"\t\";");
test("let x = '\\v'", "let x = \"\\v\";");
test("let x = '\\n'", "let x = \"\\n\";");
test("let x = '\\''", "let x = \"'\";");
test("let x = '\\\"'", "let x = '\"';");
test("let x = '\\'\"'", "let x = `'\"`;");
test("let x = '\\\\'", "let x = \"\\\\\";");
test("let x = '\x00'", "let x = \"\\0\";");
test("let x = '\x00!'", "let x = \"\\0!\";");
test("let x = '\x001'", "let x = \"\\x001\";");
test("let x = '\\0'", "let x = \"\\0\";");
test("let x = '\\0!'", "let x = \"\\0!\";");
test("let x = '\x07'", "let x = \"\\x07\";");
test("let x = '\x07!'", "let x = \"\\x07!\";");
test("let x = '\x071'", "let x = \"\\x071\";");
test("let x = '\\7'", "let x = \"\\x07\";");
test("let x = '\\7!'", "let x = \"\\x07!\";");
test("let x = '\\01'", "let x = \"\x01\";");
test("let x = '\x10'", "let x = \"\x10\";");
test("let x = '\\x10'", "let x = \"\x10\";");
test("let x = '\x1B'", "let x = \"\\x1B\";");
test("let x = '\\x1B'", "let x = \"\\x1B\";");
test("let x = '\\uABCD'", "let x = \"\\uABCD\";");
test("let x = '\\uABCD'", "let x = \"\\uABCD\";");
test("let x = '\\U000123AB'", "let x = \"\\U000123AB\";");
test("let x = '\\u{123AB}'", "let x = \"\\U000123AB\";");
test("let x = '\\uD808\\uDFAB'", "let x = \"\\U000123AB\";");
test("let x = '\\uD808'", "let x = \"\\uD808\";");
test("let x = '\\uD808X'", "let x = \"\\uD808X\";");
test("let x = '\\uDFAB'", "let x = \"\\uDFAB\";");
test("let x = '\\uDFABX'", "let x = \"\\uDFABX\";");
test("let x = '\\x80'", "let x = \"\\U00000080\";");
test("let x = '\\xFF'", "let x = \"\\U000000FF\";");
test(
"let x = '\\xF0\\x9F\\x8D\\x95'",
"let x = \"\\U000000F0\\U0000009F\\U0000008D\\U00000095\"",
);
test("let x = '\\uD801\\uDC02\\uDC03\\uD804'", "let x = \"\\U00010402\\uDC03\\uD804\";");
}
#[test]
#[ignore]
fn template() {
test("let x = `\\0`", "let x = `\\0`;");
test("let x = `\\x01`", "let x = `\x01`;");
test("let x = `\\0${0}`", "let x = `\\0${0}`;");
test("let x = `\\x01${0}`", "let x = `\x01${0}`;");
test("let x = `${0}\\0`", "let x = `${0}\\0`;");
test("let x = `${0}\\x01`", "let x = `${0}\x01`;");
test("let x = `${0}\\0${1}`", "let x = `${0}\\0${1}`;");
test("let x = `${0}\\x01${1}`", "let x = `${0}\x01${1}`;");
test("let x = String.raw`\\1`", "let x = String.raw`\\1`;");
test("let x = String.raw`\\x01`", "let x = String.raw`\\x01`;");
test("let x = String.raw`\\1${0}`", "let x = String.raw`\\1${0}`;");
test("let x = String.raw`\\x01${0}`", "let x = String.raw`\\x01${0}`;");
test("let x = String.raw`${0}\\1`", "let x = String.raw`${0}\\1`;");
test("let x = String.raw`${0}\\x01`", "let x = String.raw`${0}\\x01`;");
test("let x = String.raw`${0}\\1${1}`", "let x = String.raw`${0}\\1${1}`;");
test("let x = String.raw`${0}\\x01${1}`", "let x = String.raw`${0}\\x01${1}`;");
test("let x = `${y}`", "let x = `${y}`;");
test("let x = `$(y)`", "let x = `$(y)`;");
test("let x = `{y}$`", "let x = `{y}$`;");
test("let x = `$}y{`", "let x = `$}y{`;");
test("let x = `\\${y}`", "let x = `\\${y}`;");
test("let x = `$\\{y}`", "let x = `\\${y}`;");
test("await tag`x`", "await tag`x`;");
test("await (tag`x`)", "await tag`x`;");
test("(await tag)`x`", "(await tag)`x`;");
test("await tag`${x}`", "await tag`${x}`;");
test("await (tag`${x}`)", "await tag`${x}`;");
test("(await tag)`${x}`", "(await tag)`${x}`;");
test("new tag`x`", "new tag`x`();");
test("new (tag`x`)", "new tag`x`();");
test("new tag()`x`", "new tag()`x`;");
test("(new tag)`x`", "new tag()`x`;");
test("new tag`x`", "new tag`x`;;");
test("new (tag`x`)", "new tag`x`;;");
test("new tag()`x`", "new tag()`x`;;");
test("(new tag)`x`", "new tag()`x`;;");
test("new tag`${x}`", "new tag`${x}`();");
test("new (tag`${x}`)", "new tag`${x}`();");
test("new tag()`${x}`", "new tag()`${x}`;");
test("(new tag)`${x}`", "new tag()`${x}`;");
test("new tag`${x}`", "new tag`${x}`;;");
test("new (tag`${x}`)", "new tag`${x}`;;");
test("new tag()`${x}`", "new tag()`${x}`;;");