diff options
author | 2023-04-26 22:32:31 -0700 | |
---|---|---|
committer | 2023-04-26 22:32:31 -0700 | |
commit | 316a75005b393be4054a2be0acf9d14a4871ba22 (patch) | |
tree | 8b823adb3c3b81b37da841e0113860519aa20e88 | |
parent | 5b76ee769e7ba46a1cad08002f1830eed7a34067 (diff) | |
download | bun-316a75005b393be4054a2be0acf9d14a4871ba22.tar.gz bun-316a75005b393be4054a2be0acf9d14a4871ba22.tar.zst bun-316a75005b393be4054a2be0acf9d14a4871ba22.zip |
Inline spreads of array literals
-rw-r--r-- | src/js_ast.zig | 41 | ||||
-rw-r--r-- | src/js_parser.zig | 11 |
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) { |