Skip to content

Commit

Permalink
fix(es/codegen): Handle minify number (#9541)
Browse files Browse the repository at this point in the history
**Related issue:**

- Closes #9540
  • Loading branch information
magic-akari authored Sep 11, 2024
1 parent 3fc47fc commit 8b1e442
Show file tree
Hide file tree
Showing 15 changed files with 107 additions and 70 deletions.
6 changes: 6 additions & 0 deletions .changeset/popular-crabs-hang.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
swc_core: patch
swc_ecma_codegen: patch
---

fix(es/codegen): Handle minify number
19 changes: 19 additions & 0 deletions crates/swc/tests/fixture/issues-9xxx/9540/input/.swcrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"jsc": {
"parser": {
"syntax": "typescript",
"tsx": false
},
"target": "es2022",
"loose": false,
"minify": {
"compress": false,
"mangle": false
}
},
"module": {
"type": "es6"
},
"minify": true,
"isModule": true
}
4 changes: 4 additions & 0 deletions crates/swc/tests/fixture/issues-9xxx/9540/input/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
219994525426954..toString();
219994525420000..toString();
12300000..toString(1);
12300001..toString(1);
1 change: 1 addition & 0 deletions crates/swc/tests/fixture/issues-9xxx/9540/output/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
0xc815778a650a.toString();21999452542e4.toString();123e5.toString(1);0xbbaee1.toString(1);
103 changes: 55 additions & 48 deletions crates/swc_ecma_codegen/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -697,7 +697,7 @@ where
fn emit_num_lit_internal(
&mut self,
num: &Number,
detect_dot: bool,
mut detect_dot: bool,
) -> std::result::Result<bool, io::Error> {
self.wr.commit_pending_semi()?;

Expand All @@ -722,7 +722,7 @@ where
if num.value.is_infinite() && num.raw.is_some() {
self.wr.write_str_lit(DUMMY_SP, num.raw.as_ref().unwrap())?;
} else {
value = minify_number(num.value);
value = minify_number(num.value, &mut detect_dot);
self.wr.write_str_lit(DUMMY_SP, &value)?;
}
} else {
Expand Down Expand Up @@ -4327,69 +4327,76 @@ fn is_empty_comments(span: &Span, comments: &Option<&dyn Comments>) -> bool {
span.is_dummy() || comments.map_or(true, |c| !c.has_leading(span.span_hi() - BytePos(1)))
}

fn minify_number(num: f64) -> String {
let mut printed = num.to_string();
fn minify_number(num: f64, detect_dot: &mut bool) -> String {
// ddddd -> 0xhhhh
// len(0xhhhh) == len(ddddd)
// 10000000 <= num <= 0xffffff
'hex: {
if num.fract() == 0.0 && num.abs() <= u64::MAX as f64 {
let int = num.abs() as u64;

let mut original = printed.clone();
if int < 10000000 {
break 'hex;
}

if num.fract() == 0.0 && (i64::MIN as f64) <= num && num <= (i64::MAX as f64) {
let hex = format!(
"{}{:#x}",
if num.is_sign_negative() { "-" } else { "" },
num as i64
);
// use scientific notation
if int % 1000 == 0 {
break 'hex;
}

if hex.len() < printed.len() {
printed = hex;
*detect_dot = false;
return format!(
"{}{:#x}",
if num.is_sign_negative() { "-" } else { "" },
int
);
}
}

if original.starts_with("0.") {
original.replace_range(0..1, "");
}
let mut num = num.to_string();

if original.starts_with("-0.") {
original.replace_range(1..2, "");
if num.contains(".") {
*detect_dot = false;
}

if original.starts_with(".000") {
let mut cnt = 3;

for &v in original.as_bytes().iter().skip(4) {
if v == b'0' {
cnt += 1;
} else {
break;
}
if let Some(num) = num.strip_prefix("0.") {
let cnt = clz(num);
if cnt > 2 {
return format!("{}e-{}", &num[cnt..], num.len());
}
return format!(".{}", num);
}

original.replace_range(0..cnt + 1, "");

let remain_len = original.len();
if let Some(num) = num.strip_prefix("-0.") {
let cnt = clz(num);
if cnt > 2 {
return format!("-{}e-{}", &num[cnt..], num.len());
}
return format!("-.{}", num);
}

original.push_str("e-");
original.push_str(&(remain_len + cnt).to_string());
} else if original.ends_with("000") {
let mut cnt = 3;
if num.ends_with("000") {
*detect_dot = false;

for &v in original.as_bytes().iter().rev().skip(3) {
if v == b'0' {
cnt += 1;
} else {
break;
}
}
let cnt = num
.as_bytes()
.iter()
.rev()
.skip(3)
.take_while(|&&c| c == b'0')
.count()
+ 3;

original.truncate(original.len() - cnt);
original.push('e');
original.push_str(&cnt.to_string());
num.truncate(num.len() - cnt);
num.push('e');
num.push_str(&cnt.to_string());
}

if original.len() < printed.len() {
printed = original;
}
num
}

printed
fn clz(s: &str) -> usize {
s.as_bytes().iter().take_while(|&&c| c == b'0').count()
}

fn span_has_leading_comment(cmt: &dyn Comments, span: Span) -> bool {
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion crates/swc_ecma_codegen/tests/fixture/number/output.min.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ export default function(r, t, e) {
var d = c[_ - 15], v = (d << 25 | d >>> 7) ^ (d << 14 | d >>> 18) ^ d >>> 3, H = c[_ - 2], p = (H << 15 | H >>> 17) ^ (H << 13 | H >>> 19) ^ H >>> 10;
c[_] = v + c[_ - 7] + p + c[_ - 16];
}
var w = h & u ^ ~h & f, A = n & o ^ n & s ^ o & s, g = (n << 30 | n >>> 2) ^ (n << 19 | n >>> 13) ^ (n << 10 | n >>> 22), y = l + ((h << 26 | h >>> 6) ^ (h << 21 | h >>> 11) ^ (h << 7 | h >>> 25)) + w + i[_] + c[_], B = g + A;
l = f, f = u, u = h, h = a + y | 0, a = s, s = o, o = n, n = y + B | 0;
var w = h & u ^ ~h & f, x = n & o ^ n & s ^ o & s, A = (n << 30 | n >>> 2) ^ (n << 19 | n >>> 13) ^ (n << 10 | n >>> 22), g = l + ((h << 26 | h >>> 6) ^ (h << 21 | h >>> 11) ^ (h << 7 | h >>> 25)) + w + i[_] + c[_], y = A + x;
l = f, f = u, u = h, h = a + g | 0, a = s, s = o, o = n, n = g + y | 0;
}
// Intermediate hash value
e[0] = e[0] + n | 0, e[1] = e[1] + o | 0, e[2] = e[2] + s | 0, e[3] = e[3] + a | 0, e[4] = e[4] + h | 0, e[5] = e[5] + u | 0, e[6] = e[6] + f | 0, e[7] = e[7] + l | 0;
Expand Down

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
!(function(o) {
!(function(c) {
try {
throw 0;
} catch (c) {
o = 123456789 / 0;
} catch (o) {
c = 123456789 / 0;
}
console.log(o);
console.log(c);
})();
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ var v = 42 ** -0;
var i = NaN ** 1;
var n = 2 ** Infinity;
var N = 2 ** -Infinity;
var f = (-7) ** 0.5;
var t = 2324334 ** 34343443;
var y = (-2324334) ** 34343443;
var I = 2 ** -3;
var b = 2 ** -3;
var c = 2 ** (5 - 7);
var d = 3 ** -10;
var c = (-7) ** 0.5;
var f = 2324334 ** 34343443;
var t = (-2324334) ** 34343443;
var x = 2 ** -3;
var y = 2 ** -3;
var I = 2 ** (5 - 7);
var b = 3 ** -10;
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
var a = (-7) ** 0.5;
var r = 2324334 ** 34343443;
var v = (-2324334) ** 34343443;
var b = 2 ** -3;
var c = 2 ** -3;
var d = 2 ** (5 - 7);
var x = 2 ** -3;
var b = 2 ** (5 - 7);
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@ const o = 85;
const s = 342391;
const t = 3735928559;
const e = 1000.0001;
const _ = _1000;
const a = -_1000;
const d = _1000;
const _ = -_1000;
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@
<div>test</div>
<script>var test2="😋",test3="😋"</script>
<div>number</div>
<script>var test4=123456789</script>
<script>var test4=0x75bcd15</script>
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@
<div>test</div>
<script>var test2="\uD83D\uDE0B",test3="\uD83D\uDE0B"</script>
<div>number</div>
<script>var test4=123456789</script>
<script>var test4=0x75bcd15</script>

0 comments on commit 8b1e442

Please sign in to comment.