aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com> 2023-04-26 22:32:31 -0700
committerGravatar Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com> 2023-04-26 22:32:31 -0700
commit316a75005b393be4054a2be0acf9d14a4871ba22 (patch)
tree8b823adb3c3b81b37da841e0113860519aa20e88
parent5b76ee769e7ba46a1cad08002f1830eed7a34067 (diff)
downloadbun-316a75005b393be4054a2be0acf9d14a4871ba22.tar.gz
bun-316a75005b393be4054a2be0acf9d14a4871ba22.tar.zst
bun-316a75005b393be4054a2be0acf9d14a4871ba22.zip
Inline spreads of array literals
-rw-r--r--src/js_ast.zig41
-rw-r--r--src/js_parser.zig11
2 files changed, 52 insertions, 0 deletions
diff --git a/src/js_ast.zig b/src/js_ast.zig
index 35fe6b6ec..3cf99211b 100644
--- a/src/js_ast.zig
+++ b/src/js_ast.zig
@@ -1354,6 +1354,47 @@ pub const E = struct {
return this.items.slice();
}
+ pub fn inlineSpreadOfArrayLiterals(
+ this: *Array,
+ allocator: std.mem.Allocator,
+ estimated_count: usize,
+ ) !ExprNodeList {
+ var out = try allocator.alloc(
+ Expr,
+ // This over-allocates a little but it's fine
+ estimated_count + @as(usize, this.items.len),
+ );
+ var remain = out;
+ for (this.items.slice()) |item| {
+ switch (item.data) {
+ .e_spread => |val| {
+ if (val.value.data == .e_array) {
+ for (val.value.data.e_array.items.slice()) |inner_item| {
+ if (inner_item.data == .e_missing) {
+ remain[0] = Expr.init(E.Undefined, .{}, inner_item.loc);
+ remain = remain[1..];
+ } else {
+ remain[0] = inner_item;
+ remain = remain[1..];
+ }
+ }
+
+ // skip empty arrays
+ // don't include the inlined spread.
+ continue;
+ }
+ // non-arrays are kept in
+ },
+ else => {},
+ }
+
+ remain[0] = item;
+ remain = remain[1..];
+ }
+
+ return ExprNodeList.init(out[0 .. out.len - remain.len]);
+ }
+
pub fn toJS(this: @This(), ctx: JSC.C.JSContextRef, exception: JSC.C.ExceptionRef) JSC.C.JSValueRef {
var stack = std.heap.stackFallback(32 * @sizeOf(ExprNodeList), JSC.getAllocator(ctx));
var allocator = stack.get();
diff --git a/src/js_parser.zig b/src/js_parser.zig
index 3a35ed679..f49247f9c 100644
--- a/src/js_parser.zig
+++ b/src/js_parser.zig
@@ -16146,11 +16146,17 @@ fn NewParser_(
p.maybeCommaSpreadError(e_.comma_after_spread);
}
var items = e_.items.slice();
+ var spread_item_count: usize = 0;
for (items) |*item| {
switch (item.data) {
.e_missing => {},
.e_spread => |spread| {
spread.value = p.visitExprInOut(spread.value, ExprIn{ .assign_target = in.assign_target });
+
+ spread_item_count += if (spread.value.data == .e_array)
+ @as(usize, spread.value.data.e_array.items.len)
+ else
+ 0;
},
.e_binary => |e2| {
if (in.assign_target != .none and e2.op == .bin_assign) {
@@ -16174,6 +16180,11 @@ fn NewParser_(
},
}
}
+
+ // "[1, ...[2, 3], 4]" => "[1, 2, 3, 4]"
+ if (p.options.features.minify_syntax and spread_item_count > 0 and in.assign_target == .none) {
+ e_.items = e_.inlineSpreadOfArrayLiterals(p.allocator, spread_item_count) catch e_.items;
+ }
},
.e_object => |e_| {
if (in.assign_target != .none) {