diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/bundler.zig | 5 | ||||
-rw-r--r-- | src/js_ast.zig | 605 | ||||
-rw-r--r-- | src/js_parser/js_parser.zig | 320 | ||||
-rw-r--r-- | src/js_printer.zig | 161 |
4 files changed, 877 insertions, 214 deletions
diff --git a/src/bundler.zig b/src/bundler.zig index 96ec6027c..4e68964df 100644 --- a/src/bundler.zig +++ b/src/bundler.zig @@ -244,9 +244,11 @@ pub const Bundler = struct { else => {}, } - return try bundler.print( + const output_file = try bundler.print( result, ); + js_ast.Stmt.Data.Store.reset(); + return output_file; } pub fn print( @@ -284,6 +286,7 @@ pub const Bundler = struct { js_printer.Options{ .to_module_ref = Ref.RuntimeRef }, &_linker, ); + return options.OutputFile{ .path = out_path, .contents = print_result.js, diff --git a/src/js_ast.zig b/src/js_ast.zig index 4b65d8018..425ff6a83 100644 --- a/src/js_ast.zig +++ b/src/js_ast.zig @@ -6,6 +6,7 @@ usingnamespace @import("global.zig"); usingnamespace @import("ast/base.zig"); const ImportRecord = @import("import_record.zig").ImportRecord; +const allocators = @import("allocators.zig"); // There are three types. // 1. Expr (expression) @@ -1071,6 +1072,106 @@ pub const Stmt = struct { var None = S.Empty{}; + pub inline fn getBlock(self: *const @This()) *S.Block { + return Data.Store.Block.at(self.data.s_block); + } + pub inline fn getBreak(self: *const @This()) *S.Break { + return Data.Store.Break.at(self.data.s_break); + } + pub inline fn getClass(self: *const @This()) *S.Class { + return Data.Store.Class.at(self.data.s_class); + } + pub inline fn getComment(self: *const @This()) *S.Comment { + return Data.Store.Comment.at(self.data.s_comment); + } + pub inline fn getContinue(self: *const @This()) *S.Continue { + return Data.Store.Continue.at(self.data.s_continue); + } + pub inline fn getDebugger(self: *const @This()) S.Debugger { + return S.Debugger{}; + } + pub inline fn getDirective(self: *const @This()) *S.Directive { + return Data.Store.Directive.at(self.data.s_directive); + } + pub inline fn getDoWhile(self: *const @This()) *S.DoWhile { + return Data.Store.DoWhile.at(self.data.s_do_while); + } + pub inline fn getEmpty(self: *const @This()) S.Empty { + return S.Empty{}; + } + pub inline fn getEnum(self: *const @This()) *S.Enum { + return Data.Store.Enum.at(self.data.s_enum); + } + pub inline fn getExportClause(self: *const @This()) *S.ExportClause { + return Data.Store.ExportClause.at(self.data.s_export_clause); + } + pub inline fn getExportDefault(self: *const @This()) *S.ExportDefault { + return Data.Store.ExportDefault.at(self.data.s_export_default); + } + pub inline fn getExportEquals(self: *const @This()) *S.ExportEquals { + return Data.Store.ExportEquals.at(self.data.s_export_equals); + } + pub inline fn getExportFrom(self: *const @This()) *S.ExportFrom { + return Data.Store.ExportFrom.at(self.data.s_export_from); + } + pub inline fn getExportStar(self: *const @This()) *S.ExportStar { + return Data.Store.ExportStar.at(self.data.s_export_star); + } + pub inline fn getExpr(self: *const @This()) *S.SExpr { + return Data.Store.SExpr.at(self.data.s_expr); + } + pub inline fn getForIn(self: *const @This()) *S.ForIn { + return Data.Store.ForIn.at(self.data.s_for_in); + } + pub inline fn getForOf(self: *const @This()) *S.ForOf { + return Data.Store.ForOf.at(self.data.s_for_of); + } + pub inline fn getFor(self: *const @This()) *S.For { + return Data.Store.For.at(self.data.s_for); + } + pub inline fn getFunction(self: *const @This()) *S.Function { + return Data.Store.Function.at(self.data.s_function); + } + pub inline fn getIf(self: *const @This()) *S.If { + return Data.Store.If.at(self.data.s_if); + } + pub inline fn getImport(self: *const @This()) *S.Import { + return Data.Store.Import.at(self.data.s_import); + } + pub inline fn getLabel(self: *const @This()) *S.Label { + return Data.Store.Label.at(self.data.s_label); + } + pub inline fn getLazyExport(self: *const @This()) *S.LazyExport { + return Data.Store.LazyExport.at(self.data.s_lazy_export); + } + pub inline fn getLocal(self: *const @This()) *S.Local { + return Data.Store.Local.at(self.data.s_local); + } + pub inline fn getNamespace(self: *const @This()) *S.Namespace { + return Data.Store.Namespace.at(self.data.s_namespace); + } + pub inline fn getReturn(self: *const @This()) *S.Return { + return Data.Store.Return.at(self.data.s_return); + } + pub inline fn getSwitch(self: *const @This()) *S.Switch { + return Data.Store.Switch.at(self.data.s_switch); + } + pub inline fn getThrow(self: *const @This()) *S.Throw { + return Data.Store.Throw.at(self.data.s_throw); + } + pub inline fn getTry(self: *const @This()) *S.Try { + return Data.Store.Try.at(self.data.s_try); + } + pub inline fn getTypeScript(self: *const @This()) S.TypeScript { + return S.TypeScript{}; + } + pub inline fn getWhile(self: *const @This()) *S.While { + return Data.Store.While.at(self.data.s_while); + } + pub inline fn getWith(self: *const @This()) *S.With { + return Data.Store.With.at(self.data.s_with); + } + pub fn init(origData: anytype, loc: logger.Loc) Stmt { if (@typeInfo(@TypeOf(origData)) != .Pointer and @TypeOf(origData) != S.Empty) { @compileError("Stmt.init needs a pointer."); @@ -1186,9 +1287,7 @@ pub const Stmt = struct { } } inline fn comptime_alloc(allocator: *std.mem.Allocator, comptime tag_name: string, comptime typename: type, origData: anytype, loc: logger.Loc) Stmt { - var st = allocator.create(typename) catch unreachable; - st.* = origData; - return Stmt{ .loc = loc, .data = @unionInit(Data, tag_name, st) }; + return Stmt{ .loc = loc, .data = @unionInit(Data, tag_name, Data.Store.append(typename, origData)) }; } inline fn comptime_init(comptime tag_name: string, comptime typename: type, origData: anytype, loc: logger.Loc) Stmt { @@ -1213,7 +1312,7 @@ pub const Stmt = struct { return Stmt.comptime_alloc(allocator, "s_continue", S.Continue, origData, loc); }, S.Debugger => { - return Stmt.comptime_alloc(allocator, "s_debugger", S.Debugger, origData, loc); + return Stmt{ .loc = loc, .data = .{ .s_debugger = origData } }; }, S.Directive => { return Stmt.comptime_alloc(allocator, "s_directive", S.Directive, origData, loc); @@ -1288,7 +1387,7 @@ pub const Stmt = struct { return Stmt.comptime_alloc(allocator, "s_try", S.Try, origData, loc); }, S.TypeScript => { - return Stmt.comptime_alloc(allocator, "s_type_script", S.TypeScript, origData, loc); + return Stmt{ .loc = loc, .data = Data{ .s_type_script = S.TypeScript{} } }; }, S.While => { return Stmt.comptime_alloc(allocator, "s_while", S.While, origData, loc); @@ -1340,39 +1439,469 @@ pub const Stmt = struct { }; pub const Data = union(Tag) { - s_block: *S.Block, - s_break: *S.Break, - s_class: *S.Class, - s_comment: *S.Comment, - s_continue: *S.Continue, - s_debugger: *S.Debugger, - s_directive: *S.Directive, - s_do_while: *S.DoWhile, - s_empty: S.Empty, - s_enum: *S.Enum, - s_export_clause: *S.ExportClause, - s_export_default: *S.ExportDefault, - s_export_equals: *S.ExportEquals, - s_export_from: *S.ExportFrom, - s_export_star: *S.ExportStar, - s_expr: *S.SExpr, - s_for_in: *S.ForIn, - s_for_of: *S.ForOf, - s_for: *S.For, - s_function: *S.Function, - s_if: *S.If, - s_import: *S.Import, - s_label: *S.Label, - s_lazy_export: *S.LazyExport, - s_local: *S.Local, - s_namespace: *S.Namespace, - s_return: *S.Return, - s_switch: *S.Switch, - s_throw: *S.Throw, - s_try: *S.Try, - s_type_script: *S.TypeScript, - s_while: *S.While, - s_with: *S.With, + s_block: Store.ListIndex, + s_break: Store.ListIndex, + s_class: Store.ListIndex, + s_comment: Store.ListIndex, + s_continue: Store.ListIndex, + s_debugger: S.Debugger, + s_directive: Store.ListIndex, + s_do_while: Store.ListIndex, + s_empty: S.Empty, // special case, its a zero value type + s_enum: Store.ListIndex, + s_export_clause: Store.ListIndex, + s_export_default: Store.ListIndex, + s_export_equals: Store.ListIndex, + s_export_from: Store.ListIndex, + s_export_star: Store.ListIndex, + s_expr: Store.ListIndex, + s_for_in: Store.ListIndex, + s_for_of: Store.ListIndex, + s_for: Store.ListIndex, + s_function: Store.ListIndex, + s_if: Store.ListIndex, + s_import: Store.ListIndex, + s_label: Store.ListIndex, + s_lazy_export: Store.ListIndex, + s_local: Store.ListIndex, + s_namespace: Store.ListIndex, + s_return: Store.ListIndex, + s_switch: Store.ListIndex, + s_throw: Store.ListIndex, + s_try: Store.ListIndex, + s_type_script: S.TypeScript, + s_while: Store.ListIndex, + s_with: Store.ListIndex, + + pub const Store = struct { + pub const ListIndex = packed struct { + index: u31, + is_overflowing: bool = false, + }; + + pub const Block = NewStore(S.Block); + pub const Break = NewStore(S.Break); + pub const Class = NewStore(S.Class); + pub const Comment = NewStore(S.Comment); + pub const Continue = NewStore(S.Continue); + pub const Directive = NewStore(S.Directive); + pub const DoWhile = NewStore(S.DoWhile); + pub const Enum = NewStore(S.Enum); + pub const ExportClause = NewStore(S.ExportClause); + pub const ExportDefault = NewStore(S.ExportDefault); + pub const ExportEquals = NewStore(S.ExportEquals); + pub const ExportFrom = NewStore(S.ExportFrom); + pub const ExportStar = NewStore(S.ExportStar); + pub const SExpr = NewStore(S.SExpr); + pub const ForIn = NewStore(S.ForIn); + pub const ForOf = NewStore(S.ForOf); + pub const For = NewStore(S.For); + pub const Function = NewStore(S.Function); + pub const If = NewStore(S.If); + pub const Import = NewStore(S.Import); + pub const Label = NewStore(S.Label); + pub const LazyExport = NewStore(S.LazyExport); + pub const Local = NewStore(S.Local); + pub const Namespace = NewStore(S.Namespace); + pub const Return = NewStore(S.Return); + pub const Switch = NewStore(S.Switch); + pub const Throw = NewStore(S.Throw); + pub const Try = NewStore(S.Try); + pub const TypeScript = NewStore(S.TypeScript); + pub const While = NewStore(S.While); + pub const With = NewStore(S.With); + + threadlocal var has_inited = false; + pub fn create(allocator: *std.mem.Allocator) void { + if (has_inited) { + return; + } + + has_inited = true; + _ = Block.init(allocator); + _ = Break.init(allocator); + _ = Class.init(allocator); + _ = Comment.init(allocator); + _ = Continue.init(allocator); + _ = Directive.init(allocator); + _ = DoWhile.init(allocator); + _ = Enum.init(allocator); + _ = ExportClause.init(allocator); + _ = ExportDefault.init(allocator); + _ = ExportEquals.init(allocator); + _ = ExportFrom.init(allocator); + _ = ExportStar.init(allocator); + _ = SExpr.init(allocator); + _ = ForIn.init(allocator); + _ = ForOf.init(allocator); + _ = For.init(allocator); + _ = Function.init(allocator); + _ = If.init(allocator); + _ = Import.init(allocator); + _ = Label.init(allocator); + _ = LazyExport.init(allocator); + _ = Local.init(allocator); + _ = Namespace.init(allocator); + _ = Return.init(allocator); + _ = Switch.init(allocator); + _ = Throw.init(allocator); + _ = Try.init(allocator); + _ = While.init(allocator); + _ = With.init(allocator); + } + + pub fn reset() void { + Block.reset(); + Break.reset(); + Class.reset(); + Comment.reset(); + Continue.reset(); + Directive.reset(); + DoWhile.reset(); + Enum.reset(); + ExportClause.reset(); + ExportDefault.reset(); + ExportEquals.reset(); + ExportFrom.reset(); + ExportStar.reset(); + SExpr.reset(); + ForIn.reset(); + ForOf.reset(); + For.reset(); + Function.reset(); + If.reset(); + Import.reset(); + Label.reset(); + LazyExport.reset(); + Local.reset(); + Namespace.reset(); + Return.reset(); + Switch.reset(); + Throw.reset(); + Try.reset(); + While.reset(); + With.reset(); + } + + pub fn append(comptime ValueType: type, value: anytype) ListIndex { + switch (comptime ValueType) { + S.Block => { + return Block.append(value); + }, + S.Break => { + return Break.append(value); + }, + S.Class => { + return Class.append(value); + }, + S.Comment => { + return Comment.append(value); + }, + S.Continue => { + return Continue.append(value); + }, + + S.Directive => { + return Directive.append(value); + }, + S.DoWhile => { + return DoWhile.append(value); + }, + S.Empty => { + return Empty.append(value); + }, + S.Enum => { + return Enum.append(value); + }, + S.ExportClause => { + return ExportClause.append(value); + }, + S.ExportDefault => { + return ExportDefault.append(value); + }, + S.ExportEquals => { + return ExportEquals.append(value); + }, + S.ExportFrom => { + return ExportFrom.append(value); + }, + S.ExportStar => { + return ExportStar.append(value); + }, + S.SExpr => { + return SExpr.append(value); + }, + S.ForIn => { + return ForIn.append(value); + }, + S.ForOf => { + return ForOf.append(value); + }, + S.For => { + return For.append(value); + }, + S.Function => { + return Function.append(value); + }, + S.If => { + return If.append(value); + }, + S.Import => { + return Import.append(value); + }, + S.Label => { + return Label.append(value); + }, + S.LazyExport => { + return LazyExport.append(value); + }, + S.Local => { + return Local.append(value); + }, + S.Namespace => { + return Namespace.append(value); + }, + S.Return => { + return Return.append(value); + }, + S.Switch => { + return Switch.append(value); + }, + S.Throw => { + return Throw.append(value); + }, + S.Try => { + return Try.append(value); + }, + + S.While => { + return While.append(value); + }, + S.With => { + return With.append(value); + }, + else => { + @compileError("Invalid type passed to Stmt.Data.set " ++ @typeName(ValueType)); + }, + } + } + + pub fn NewStore(comptime ValueType: type) type { + const count = 1024; + const max_index = count - 1; + const list_count = count; + return struct { + pub threadlocal var backing_buf: [count]ValueType = undefined; + pub threadlocal var backing_buf_used: u16 = 0; + const Allocator = std.mem.Allocator; + const Self = @This(); + const NotFound = allocators.NotFound; + const Unassigned = allocators.Unassigned; + + overflow_list: std.ArrayListUnmanaged(ValueType), + allocator: *Allocator, + + pub threadlocal var instance: Self = undefined; + pub threadlocal var self: *Self = undefined; + + pub fn reset() void { + backing_buf_used = 0; + self.overflow_list.shrinkRetainingCapacity(0); + } + + pub fn init(allocator: *std.mem.Allocator) *Self { + instance = Self{ + .allocator = allocator, + .overflow_list = std.ArrayListUnmanaged(ValueType){}, + }; + + self = &instance; + return self; + } + + pub fn isOverflowing() bool { + return backing_buf_used >= @as(u16, count); + } + + pub fn at(index: ListIndex) *ValueType { + std.debug.assert(index.index != NotFound.index and index.index != Unassigned.index); + + if (index.is_overflowing) { + return &self.overflow_list.items[index.index]; + } else { + return &backing_buf[index.index]; + } + } + + pub fn exists(value: ValueType) bool { + return isSliceInBuffer(value, backing_buf); + } + + pub fn append(value: ValueType) ListIndex { + var result = ListIndex{ .index = std.math.maxInt(u31), .is_overflowing = backing_buf_used > max_index }; + if (result.is_overflowing) { + result.index = @intCast(u31, self.overflow_list.items.len); + self.overflow_list.append(self.allocator, value) catch unreachable; + } else { + result.index = backing_buf_used; + backing_buf[result.index] = value; + backing_buf_used += 1; + if (backing_buf_used >= max_index) { + self.overflow_list = @TypeOf(self.overflow_list).initCapacity(self.allocator, count) catch unreachable; + } + } + + return result; + } + + pub fn update(result: *ListIndex, value: ValueType) !*ValueType { + if (result.index.index == NotFound.index or result.index.index == Unassigned.index) { + result.index.is_overflowing = backing_buf_used > max_index; + if (result.index.is_overflowing) { + result.index.index = @intCast(u31, self.overflow_list.items.len); + } else { + result.index.index = backing_buf_used; + backing_buf_used += 1; + if (backing_buf_used >= max_index) { + self.overflow_list = try @TypeOf(self.overflow_list).initCapacity(self.allocator, count); + } + } + } + + if (result.index.is_overflowing) { + if (self.overflow_list.items.len == result.index.index) { + const real_index = self.overflow_list.items.len; + try self.overflow_list.append(self.allocator, value); + } else { + self.overflow_list.items[result.index.index] = value; + } + + return &self.overflow_list.items[result.index.index]; + } else { + backing_buf[result.index.index] = value; + + return &backing_buf[result.index.index]; + } + } + }; + } + }; + + pub inline fn set(data: *Data, value: anytype) void { + const ValueType = @TypeOf(value); + if (@typeInfo(ValueType) == .Pointer) { + data.setValue(@TypeOf(value.*), value.*); + } else { + data.setValue(@TypeOf(value), value); + } + } + + pub inline fn setValue(data: *Data, comptime ValueType: type, value: ValueType) void { + switch (comptime ValueType) { + S.Block => { + data.s_block = Block.append(value); + }, + S.Break => { + data.s_break = Break.append(value); + }, + S.Class => { + data.s_class = Class.append(value); + }, + S.Comment => { + data.s_comment = Comment.append(value); + }, + S.Continue => { + data.s_continue = Continue.append(value); + }, + S.Debugger => { + data.s_debugger = Debugger.append(value); + }, + S.Directive => { + data.s_directive = Directive.append(value); + }, + S.DoWhile => { + data.s_do_while = DoWhile.append(value); + }, + S.Empty => { + data.s_empty = Empty.append(value); + }, + S.Enum => { + data.s_enum = Enum.append(value); + }, + S.ExportClause => { + data.s_export_clause = ExportClause.append(value); + }, + S.ExportDefault => { + data.s_export_default = ExportDefault.append(value); + }, + S.ExportEquals => { + data.s_export_equals = ExportEquals.append(value); + }, + S.ExportFrom => { + data.s_export_from = ExportFrom.append(value); + }, + S.ExportStar => { + data.s_export_star = ExportStar.append(value); + }, + S.SExpr => { + data.s_s_expr = SExpr.append(value); + }, + S.ForIn => { + data.s_for_in = ForIn.append(value); + }, + S.ForOf => { + data.s_for_of = ForOf.append(value); + }, + S.For => { + data.s_for = For.append(value); + }, + S.Function => { + data.s_function = Function.append(value); + }, + S.If => { + data.s_if = If.append(value); + }, + S.Import => { + data.s_import = Import.append(value); + }, + S.Label => { + data.s_label = Label.append(value); + }, + S.LazyExport => { + data.s_lazy_export = LazyExport.append(value); + }, + S.Local => { + data.s_local = Local.append(value); + }, + S.Namespace => { + data.s_namespace = Namespace.append(value); + }, + S.Return => { + data.s_return = Return.append(value); + }, + S.Switch => { + data.s_switch = Switch.append(value); + }, + S.Throw => { + data.s_throw = Throw.append(value); + }, + S.Try => { + data.s_try = Try.append(value); + }, + S.TypeScript => { + data.s_type_script = value; + }, + S.While => { + data.s_while = While.append(value); + }, + S.With => { + data.s_with = With.append(value); + }, + else => { + @compileError("Invalid type passed to Stmt.Data.set " ++ @typeName(ValueType)); + }, + } + } }; pub fn caresAboutScope(self: *Stmt) bool { diff --git a/src/js_parser/js_parser.zig b/src/js_parser/js_parser.zig index 6776dba7b..63e135295 100644 --- a/src/js_parser/js_parser.zig +++ b/src/js_parser/js_parser.zig @@ -53,7 +53,9 @@ pub const ImportScanner = struct { // zls needs the hint, it seems. const stmt: Stmt = _stmt; switch (stmt.data) { - .s_import => |st| { + .s_import => { + var st = stmt.getImport(); + var record: ImportRecord = p.import_records.items[st.import_record_index]; // The official TypeScript compiler always removes unused imported @@ -364,7 +366,9 @@ pub const ImportScanner = struct { } } }, - .s_function => |st| { + .s_function => { + var st = stmt.getFunction(); + if (st.func.flags.is_export) { if (st.func.name) |name| { try p.recordExport(name.loc, p.symbols.items[name.ref.?.inner_index].original_name, name.ref.?); @@ -373,7 +377,9 @@ pub const ImportScanner = struct { } } }, - .s_class => |st| { + .s_class => { + var st = stmt.getClass(); + if (st.is_export) { if (st.class.class_name) |name| { try p.recordExport(name.loc, p.symbols.items[name.ref.?.inner_index].original_name, name.ref.?); @@ -382,7 +388,9 @@ pub const ImportScanner = struct { } } }, - .s_local => |st| { + .s_local => { + var st = stmt.getLocal(); + if (st.is_export) { for (st.decls) |decl| { p.recordExportedBinding(decl.binding); @@ -422,15 +430,21 @@ pub const ImportScanner = struct { } } }, - .s_export_default => |st| { + .s_export_default => { + var st = stmt.getExportDefault(); + try p.recordExport(st.default_name.loc, "default", st.default_name.ref.?); }, - .s_export_clause => |st| { + .s_export_clause => { + var st = stmt.getExportClause(); + for (st.items) |item| { try p.recordExport(item.alias_loc, item.alias, item.name.ref.?); } }, - .s_export_star => |st| { + .s_export_star => { + var st = stmt.getExportStar(); + try p.import_records_for_current_part.append(st.import_record_index); if (st.alias) |alias| { @@ -449,7 +463,9 @@ pub const ImportScanner = struct { try p.export_star_import_records.append(st.import_record_index); } }, - .s_export_from => |st| { + .s_export_from => { + var st = stmt.getExportFrom(); + try p.import_records_for_current_part.append(st.import_record_index); for (st.items) |item| { @@ -606,7 +622,9 @@ pub const SideEffects = enum(u2) { return false; }, - .s_local => |local| { + .s_local => |local__| { + var local = stmt.getLocal(); + return local.kind != .k_var; // if (local.kind != .k_var) { // // Omit these statements entirely @@ -614,8 +632,8 @@ pub const SideEffects = enum(u2) { // } }, - .s_block => |block| { - for (block.stmts) |child| { + .s_block => { + for (stmt.getBlock().stmts) |child| { if (shouldKeepStmtInDeadControlFlow(child)) { return true; } @@ -624,7 +642,8 @@ pub const SideEffects = enum(u2) { return false; }, - .s_if => |_if_| { + .s_if => { + const _if_ = stmt.getIf(); if (shouldKeepStmtInDeadControlFlow(_if_.yes)) { return true; } @@ -634,15 +653,16 @@ pub const SideEffects = enum(u2) { return shouldKeepStmtInDeadControlFlow(no); }, - .s_while => |__while__| { - return shouldKeepStmtInDeadControlFlow(__while__.body); + .s_while => { + return shouldKeepStmtInDeadControlFlow(stmt.getWhile().body); }, - .s_do_while => |__while__| { - return shouldKeepStmtInDeadControlFlow(__while__.body); + .s_do_while => { + return shouldKeepStmtInDeadControlFlow(stmt.getDoWhile().body); }, - .s_for => |__for__| { + .s_for => { + const __for__ = stmt.getFor(); if (__for__.init) |init_| { if (shouldKeepStmtInDeadControlFlow(init_)) { return true; @@ -652,15 +672,20 @@ pub const SideEffects = enum(u2) { return shouldKeepStmtInDeadControlFlow(__for__.body); }, - .s_for_in => |__for__| { + .s_for_in => { + const __for__ = stmt.getForIn(); return shouldKeepStmtInDeadControlFlow(__for__.init) or shouldKeepStmtInDeadControlFlow(__for__.body); }, - .s_for_of => |__for__| { + .s_for_of => { + const __for__ = stmt.getForOf(); + return shouldKeepStmtInDeadControlFlow(__for__.init) or shouldKeepStmtInDeadControlFlow(__for__.body); }, - .s_label => |label| { + .s_label => { + const label = stmt.getLabel(); + return shouldKeepStmtInDeadControlFlow(label.stmt); }, else => { @@ -1071,8 +1096,8 @@ fn statementCaresAboutScope(stmt: Stmt) bool { => { return false; }, - .s_local => |s| { - return s.kind != .k_var; + .s_local => { + return stmt.getLocal().kind != .k_var; }, else => { return true; @@ -1525,42 +1550,6 @@ pub const Parser = struct { } } - // for (stmts) |stmt| { - // var _stmts = ([_]Stmt{stmt}); - - // switch (stmt.data) { - // // Split up top-level multi-declaration variable statements - - // .s_local => |local| { - // for (local.decls) |decl| { - // var decls = try p.allocator.alloc(Decl, 1); - // var clone = S.Local{ - // .kind = local.kind, - // .decls = decls, - // .is_export = local.is_export, - // .was_ts_import_equals = local.was_ts_import_equals, - // }; - // _stmts[0] = p.s(clone, stmt.loc); - - // try p.appendPart(&parts, &_stmts); - // } - // }, - // // Move imports (and import-like exports) to the top of the file to - // // ensure that if they are converted to a require() call, the effects - // // will take place before any other statements are evaluated. - // .s_import, .s_export_from, .s_export_star => { - // try p.appendPart(&before, &_stmts); - // }, - - // .s_export_equals => { - // try p.appendPart(&after, &_stmts); - // }, - // else => { - // try p.appendPart(&parts, &_stmts); - // }, - // } - // } - // p.popScope(); var parts_slice: []js_ast.Part = &([_]js_ast.Part{}); if (before.items.len > 0 or after.items.len > 0) { @@ -3997,7 +3986,7 @@ pub const P = struct { return stmt; } - if (stmt.data.s_function.func.name) |name| { + if (stmt.getFunction().func.name) |name| { defaultName = js_ast.LocRef{ .loc = defaultLoc, .ref = name.ref }; } else { defaultName = try p.createDefaultName(defaultLoc); @@ -4033,12 +4022,12 @@ pub const P = struct { }, .s_function => |func_container| { - if (func_container.func.name) |name| { + if (stmt.getFunction().func.name) |name| { break :default_name_getter LocRef{ .loc = defaultLoc, .ref = name.ref }; } else {} }, .s_class => |class| { - if (class.class.class_name) |name| { + if (stmt.getClass().class.class_name) |name| { break :default_name_getter LocRef{ .loc = defaultLoc, .ref = name.ref }; } else {} }, @@ -4077,12 +4066,12 @@ pub const P = struct { }, .s_function => |func_container| { - if (func_container.func.name) |_name| { + if (stmt.getFunction().func.name) |_name| { break :default_name_getter LocRef{ .loc = defaultLoc, .ref = _name.ref }; } else {} }, .s_class => |class| { - if (class.class.class_name) |_name| { + if (stmt.getClass().class.class_name) |_name| { break :default_name_getter LocRef{ .loc = defaultLoc, .ref = _name.ref }; } else {} }, @@ -4578,8 +4567,8 @@ pub const P = struct { // Only require "const" statement initializers when we know we're a normal for loop if (init_) |init_stmt| { switch (init_stmt.data) { - .s_local => |local| { - if (local.kind == .k_const) { + .s_local => { + if (init_stmt.getLocal().kind == .k_const) { try p.requireInitializers(decls); } }, @@ -5006,7 +4995,8 @@ pub const P = struct { if (opts.is_namespace_scope and opts.is_export) { var decls: []G.Decl = &([_]G.Decl{}); switch (stmt.data) { - .s_local => |local| { + .s_local => { + const local = stmt.getLocal(); var _decls = try List(G.Decl).initCapacity(p.allocator, local.decls.len); for (local.decls) |decl| { try extractDeclsForBinding(decl.binding, &_decls); @@ -5136,7 +5126,9 @@ pub const P = struct { const _stmts: []Stmt = stmts.items; for (_stmts) |stmt| { switch (stmt.data) { - .s_local => |local| { + .s_local => |local__| { + var local = stmt.getLocal(); + if (local.was_ts_import_equals and !local.is_export) { import_equal_count += 1; } @@ -5978,15 +5970,15 @@ pub const P = struct { isDirectivePrologue = false; switch (stmt.data) { .s_expr => |expr| { - switch (expr.value.data) { + switch (stmt.getExpr().value.data) { .e_string => |str| { if (!str.prefer_template) { - stmt.data = Stmt.Data{ - .s_directive = p.m(S.Directive{ - .value = str.value, - // .legacy_octal_loc = str.legacy_octal_loc, - }), - }; + // stmt.data = Stmt.Data{ + // .s_directive = p.m(S.Directive{ + // .value = str.value, + // // .legacy_octal_loc = str.legacy_octal_loc, + // }), + // }; isDirectivePrologue = true; if (strings.eqlUtf16("use strict", str.value)) { @@ -6011,7 +6003,9 @@ pub const P = struct { if (!p.options.suppress_warnings_about_weird_code) { var needsCheck = true; switch (stmt.data) { - .s_return => |ret| { + .s_return => |retu| { + const ret = stmt.getReturn(); + if (ret.value == null and !p.latest_return_had_semicolon) { returnWithoutSemicolonStart = stmt.loc.start; needsCheck = false; @@ -9169,13 +9163,19 @@ pub const P = struct { // check if the imported file is marked as "sideEffects: false" before we // can remove a SImport statement. Otherwise the import must be kept for // its side effects. - .s_import => |st| {}, - .s_class => |st| { + .s_import => { + var st = stmt.getImport(); + }, + .s_class => { + var st = stmt.getClass(); + if (!p.classCanBeRemovedIfUnused(&st.class)) { return false; } }, - .s_expr => |st| { + .s_expr => { + var st = stmt.getExpr(); + if (st.does_not_affect_tree_shaking) { // Expressions marked with this are automatically generated and have // no side effects by construction. @@ -9184,7 +9184,9 @@ pub const P = struct { return false; } }, - .s_local => |st| { + .s_local => { + var st = stmt.getLocal(); + for (st.decls) |decl| { if (!p.bindingCanBeRemovedIfUnused(decl.binding)) { return false; @@ -9201,14 +9203,16 @@ pub const P = struct { // Exports are tracked separately, so this isn't necessary .s_export_clause, .s_export_from => {}, - .s_export_default => |st| { + .s_export_default => { + var st = stmt.getExportDefault(); + switch (st.value) { .stmt => |s2| { switch (s2.data) { // These never have side effects .s_function => {}, - .s_class => |class| { - if (!p.classCanBeRemovedIfUnused(&class.class)) { + .s_class => { + if (!p.classCanBeRemovedIfUnused(&stmt.getClass().class)) { return false; } }, @@ -10393,7 +10397,8 @@ pub const P = struct { .s_comment => { continue; }, - .s_directive => |dir| { + .s_directive => { + const dir = stmt.getDirective(); if (strings.utf16EqlString(dir.value, "use strict")) { return stmt.loc; } @@ -10704,17 +10709,23 @@ pub const P = struct { // These don't contain anything to traverse .s_debugger, .s_empty, .s_comment => {}, - .s_type_script => |data| { + .s_type_script => { + var data = stmt.getTypeScript(); + // Erase TypeScript constructs from the output completely return; }, - .s_directive => |data| { + .s_directive => { + var data = stmt.getDirective(); + // if p.isStrictMode() && s.LegacyOctalLoc.Start > 0 { // p.markStrictModeFeature(legacyOctalEscape, p.source.RangeOfLegacyOctalEscape(s.LegacyOctalLoc), "") // } return; }, - .s_import => |data| { + .s_import => { + var data = stmt.getImport(); + try p.recordDeclaredSymbol(data.namespace_ref); if (data.default_name) |default_name| { @@ -10727,7 +10738,9 @@ pub const P = struct { } } }, - .s_export_clause => |data| { + .s_export_clause => { + var data = stmt.getExportClause(); + // "export {foo}" var end: usize = 0; for (data.items) |*item| { @@ -10755,7 +10768,9 @@ pub const P = struct { // jarred: does that mean we can remove them here, since we're not bundling for production? data.items = data.items[0..end]; }, - .s_export_from => |data| { + .s_export_from => { + var data = stmt.getExportFrom(); + // "export {foo} from 'path'" const name = p.loadNameFromRef(data.namespace_ref); data.namespace_ref = try p.newSymbol(.other, name); @@ -10771,7 +10786,9 @@ pub const P = struct { item.name.ref = ref; } }, - .s_export_star => |data| { + .s_export_star => { + var data = stmt.getExportStar(); + // "export {foo} from 'path'" const name = p.loadNameFromRef(data.namespace_ref); data.namespace_ref = try p.newSymbol(.other, name); @@ -10795,7 +10812,9 @@ pub const P = struct { stmts.appendAssumeCapacity(p.s(S.ExportClause{ .items = items.toOwnedSlice(), .is_single_line = true }, stmt.loc)); } }, - .s_export_default => |data| { + .s_export_default => { + var data = stmt.getExportDefault(); + if (data.default_name.ref) |ref| { try p.recordDeclaredSymbol(ref); } @@ -10828,7 +10847,8 @@ pub const P = struct { .stmt => |s2| { switch (s2.data) { - .s_function => |func| { + .s_function => { + var func = s2.getFunction(); var name: string = ""; if (func.func.name) |func_loc| { name = p.loadNameFromRef(func_loc.ref.?); @@ -10846,7 +10866,8 @@ pub const P = struct { // prevent doubling export default function name return; }, - .s_class => |class| { + .s_class => { + var class = s2.getClass(); var shadow_ref = p.visitClass(s2.loc, &class.class); stmts.appendSlice(p.lowerClass(js_ast.StmtOrExpr{ .stmt = stmt.* }, shadow_ref)) catch unreachable; return; @@ -10856,7 +10877,9 @@ pub const P = struct { }, } }, - .s_export_equals => |data| { + .s_export_equals => { + var data = stmt.getExportEquals(); + // "module.exports = value" stmts.append( Expr.assignStmt( @@ -10879,7 +10902,9 @@ pub const P = struct { ) catch unreachable; p.recordUsage(p.module_ref); }, - .s_break => |data| { + .s_break => { + var data = stmt.getBreak(); + if (data.label) |*label| { const name = p.loadNameFromRef(label.ref orelse p.panic("Expected label to have a ref", .{})); const res = p.findLabelSymbol(label.loc, name); @@ -10893,7 +10918,9 @@ pub const P = struct { p.log.addRangeError(p.source, r, "Cannot use \"break\" here") catch unreachable; } }, - .s_continue => |data| { + .s_continue => { + var data = stmt.getContinue(); + if (data.label) |*label| { const name = p.loadNameFromRef(label.ref orelse p.panic("Expected continue label to have a ref", .{})); const res = p.findLabelSymbol(label.loc, name); @@ -10907,7 +10934,9 @@ pub const P = struct { p.log.addRangeError(p.source, r, "Cannot use \"continue\" here") catch unreachable; } }, - .s_label => |data| { + .s_label => { + var data = stmt.getLabel(); + p.pushScopeForVisitPass(.label, stmt.loc) catch unreachable; const name = p.loadNameFromRef(data.name.ref orelse unreachable); const ref = p.newSymbol(.label, name) catch unreachable; @@ -10923,7 +10952,9 @@ pub const P = struct { data.stmt = p.visitSingleStmt(data.stmt, StmtsKind.none); p.popScope(); }, - .s_local => |data| { + .s_local => { + var data = stmt.getLocal(); + for (data.decls) |*d| { p.visitBinding(d.binding, null); @@ -10968,16 +10999,22 @@ pub const P = struct { // TODO: do we need to relocate vars? I don't think so. if (data.kind == .k_var) {} }, - .s_expr => |data| { + .s_expr => { + var data = stmt.getExpr(); + p.stmt_expr_value = data.value.data; data.value = p.visitExpr(data.value); // simplify unused data.value = SideEffects.simpifyUnusedExpr(p, data.value) orelse data.value.toEmpty(); }, - .s_throw => |data| { + .s_throw => { + var data = stmt.getThrow(); + data.value = p.visitExpr(data.value); }, - .s_return => |data| { + .s_return => { + var data = stmt.getReturn(); + // Forbid top-level return inside modules with ECMAScript-style exports if (p.fn_or_arrow_data_visit.is_outside_fn_or_arrow) { const where = where: { @@ -11005,7 +11042,9 @@ pub const P = struct { } } }, - .s_block => |data| { + .s_block => { + var data = stmt.getBlock(); + { p.pushScopeForVisitPass(.block, stmt.loc) catch unreachable; @@ -11031,22 +11070,30 @@ pub const P = struct { stmts.append(stmt.*) catch unreachable; return; }, - .s_with => |data| { + .s_with => { + var data = stmt.getWith(); + notimpl(); }, - .s_while => |data| { + .s_while => { + var data = stmt.getWhile(); + data.test_ = p.visitExpr(data.test_); data.body = p.visitLoopBody(data.body); // TODO: simplify boolean expression }, - .s_do_while => |data| { + .s_do_while => { + var data = stmt.getDoWhile(); + data.test_ = p.visitExpr(data.test_); data.body = p.visitLoopBody(data.body); // TODO: simplify boolean expression }, - .s_if => |data| { + .s_if => { + var data = stmt.getIf(); + data.test_ = p.visitExpr(data.test_); const effects = SideEffects.toBoolean(data.test_.data); @@ -11076,7 +11123,9 @@ pub const P = struct { } } }, - .s_for => |data| { + .s_for => { + var data = stmt.getFor(); + { p.pushScopeForVisitPass(.block, stmt.loc) catch unreachable; @@ -11100,7 +11149,9 @@ pub const P = struct { // TODO: Potentially relocate "var" declarations to the top level }, - .s_for_in => |data| { + .s_for_in => { + var data = stmt.getForIn(); + { p.pushScopeForVisitPass(.block, stmt.loc) catch unreachable; defer p.popScope(); @@ -11125,7 +11176,9 @@ pub const P = struct { // } } }, - .s_for_of => |data| { + .s_for_of => { + var data = stmt.getForOf(); + p.pushScopeForVisitPass(.block, stmt.loc) catch unreachable; defer p.popScope(); _ = p.visitForLoopInit(data.init, true); @@ -11142,7 +11195,9 @@ pub const P = struct { // p.lowerObjectRestInForLoopInit(s.Init, &s.Body) }, - .s_try => |data| { + .s_try => { + var data = stmt.getTry(); + p.pushScopeForVisitPass(.block, stmt.loc) catch unreachable; { var _stmts = List(Stmt).fromOwnedSlice(p.allocator, data.body); @@ -11176,7 +11231,9 @@ pub const P = struct { p.popScope(); } }, - .s_switch => |data| { + .s_switch => { + var data = stmt.getSwitch(); + data.test_ = p.visitExpr(data.test_); { p.pushScopeForVisitPass(.block, data.body_loc) catch unreachable; @@ -11201,7 +11258,9 @@ pub const P = struct { // TODO: duplicate case checker }, - .s_function => |data| { + .s_function => { + var data = stmt.getFunction(); + data.func = p.visitFunc(data.func, data.func.open_parens_loc); // Handle exporting this function from a namespace @@ -11232,7 +11291,9 @@ pub const P = struct { // ); return; }, - .s_class => |data| { + .s_class => { + var data = stmt.getClass(); + const shadow_ref = p.visitClass(stmt.loc, &data.class); // Remove the export flag inside a namespace @@ -11255,7 +11316,9 @@ pub const P = struct { return; }, - .s_enum => |data| { + .s_enum => { + var data = stmt.getEnum(); + p.recordDeclaredSymbol(data.name.ref.?) catch unreachable; p.pushScopeForVisitPass(.entry, stmt.loc) catch unreachable; defer p.popScope(); @@ -11372,7 +11435,9 @@ pub const P = struct { ); return; }, - .s_namespace => |data| { + .s_namespace => { + var data = stmt.getNamespace(); + p.recordDeclaredSymbol(data.name.ref.?) catch unreachable; // Scan ahead for any variables inside this namespace. This must be done @@ -11381,7 +11446,9 @@ pub const P = struct { // We need to convert the uses into property accesses on the namespace. for (data.stmts) |child_stmt| { switch (child_stmt.data) { - .s_local => |local| { + .s_local => |local__| { + var local = stmt.getLocal(); + if (local.is_export) { p.markExportedDeclsInsideNamespace(data.arg, local.decls); } @@ -11625,12 +11692,16 @@ pub const P = struct { pub fn visitForLoopInit(p: *P, stmt: Stmt, is_in_or_of: bool) Stmt { switch (stmt.data) { - .s_expr => |st| { + .s_expr => { + var st = stmt.getExpr(); + const assign_target = if (is_in_or_of) js_ast.AssignTarget.replace else js_ast.AssignTarget.none; p.stmt_expr_value = st.value.data; st.value = p.visitExprInOut(st.value, ExprIn{ .assign_target = assign_target }); }, - .s_local => |st| { + .s_local => { + var st = stmt.getLocal(); + for (st.decls) |*dec| { p.visitBinding(dec.binding, null); if (dec.value) |val| { @@ -11843,8 +11914,8 @@ pub const P = struct { pub fn visitSingleStmt(p: *P, stmt: Stmt, kind: StmtsKind) Stmt { const has_if_scope = has_if: { switch (stmt.data) { - .s_function => |func| { - break :has_if func.func.flags.has_if_scope; + .s_function => { + break :has_if stmt.getFunction().func.flags.has_if_scope; }, else => { break :has_if false; @@ -11874,7 +11945,7 @@ pub const P = struct { return Stmt{ .data = Prefill.Data.SEmpty, .loc = loc }; } - if (stmts.len == 1 and std.meta.activeTag(stmts[0].data) != .s_local or (std.meta.activeTag(stmts[0].data) == .s_local and stmts[0].data.s_local.kind == S.Local.Kind.k_var)) { + if (stmts.len == 1 and std.meta.activeTag(stmts[0].data) != .s_local or (std.meta.activeTag(stmts[0].data) == .s_local and stmts[0].getLocal().kind == S.Local.Kind.k_var)) { // "let" and "const" must be put in a block when in a single-statement context return stmts[0]; } @@ -12080,7 +12151,8 @@ pub const P = struct { // moves this statement to the end when it generates code. break :list_getter &after; }, - .s_function => |data| { + .s_function => { + var data = stmt.getFunction(); // Manually hoist block-level function declarations to preserve semantics. // This is only done for function declarations that are not generators // or async functions, since this is a backwards-compatibility hack from @@ -12422,8 +12494,8 @@ pub const P = struct { for (parts) |part| { for (part.stmts) |stmt| { switch (stmt.data) { - .s_export_clause => |clause| { - for (clause.items) |item| { + .s_export_clause => { + for (stmt.getExportClause().items) |item| { if (p.named_imports.getEntry(item.name.ref.?)) |_import| { _import.value.is_exported = true; } @@ -12531,6 +12603,8 @@ pub const P = struct { } pub fn init(allocator: *std.mem.Allocator, log: *logger.Log, source: *const logger.Source, define: *Define, lexer: js_lexer.Lexer, opts: Parser.Options) !*P { + Stmt.Data.Store.create(allocator); + var scope_order = try ScopeOrderList.initCapacity(allocator, 1); var scope = try allocator.create(Scope); scope.* = Scope{ diff --git a/src/js_printer.zig b/src/js_printer.zig index efbb7aa90..a95d3e43a 100644 --- a/src/js_printer.zig +++ b/src/js_printer.zig @@ -319,7 +319,7 @@ pub fn NewPrinter(comptime ascii_only: bool) type { switch (stmt.data) { .s_block => |block| { p.printSpace(); - p.printBlock(stmt.loc, block.stmts); + p.printBlock(stmt.loc, stmt.getBlock().stmts); p.printNewline(); }, else => { @@ -1144,8 +1144,8 @@ pub fn NewPrinter(comptime ascii_only: bool) type { var wasPrinted = false; if (e.body.stmts.len == 1 and e.prefer_expr) { switch (e.body.stmts[0].data) { - .s_return => |ret| { - if (ret.value) |val| { + .s_return => { + if (e.body.stmts[0].getReturn().value) |val| { p.arrow_expr_start = p.js.lenI(); p.printExpr(val, .comma, ExprFlag.None()); wasPrinted = true; @@ -2060,12 +2060,14 @@ pub fn NewPrinter(comptime ascii_only: bool) type { p.comptime_flush(); p.addSourceMapping(stmt.loc); - switch (stmt.data) { - .s_comment => |s| { + .s_comment => |s_list_index| { + const s = stmt.getComment(); p.printIndentedComment(s.text); }, - .s_function => |s| { + .s_function => |s_list_index| { + const s = stmt.getFunction(); + p.printIndent(); p.printSpaceBeforeIdentifier(); if (s.func.flags.is_export) { @@ -2086,7 +2088,9 @@ pub fn NewPrinter(comptime ascii_only: bool) type { p.printFunc(s.func); p.printNewline(); }, - .s_class => |s| { + .s_class => |s_list_index| { + const s = stmt.getClass(); + p.printIndent(); p.printSpaceBeforeIdentifier(); if (s.is_export) { @@ -2097,12 +2101,14 @@ pub fn NewPrinter(comptime ascii_only: bool) type { p.printClass(s.class); p.printNewline(); }, - .s_empty => |s| { + .s_empty => |s_list_index| { p.printIndent(); p.print(";"); p.printNewline(); }, - .s_export_default => |s| { + .s_export_default => |s_list_index| { + const s = stmt.getExportDefault(); + p.printIndent(); p.printSpaceBeforeIdentifier(); p.print("export default"); @@ -2119,7 +2125,8 @@ pub fn NewPrinter(comptime ascii_only: bool) type { }, .stmt => |s2| { switch (s2.data) { - .s_function => |func| { + .s_function => { + const func = s2.getFunction(); p.printSpaceBeforeIdentifier(); if (func.func.flags.is_async) { p.print("async "); @@ -2138,7 +2145,8 @@ pub fn NewPrinter(comptime ascii_only: bool) type { p.printFunc(func.func); p.printNewline(); }, - .s_class => |class| { + .s_class => { + const class = s2.getClass(); p.printSpaceBeforeIdentifier(); if (class.class.class_name) |name| { p.print("class "); @@ -2156,7 +2164,9 @@ pub fn NewPrinter(comptime ascii_only: bool) type { }, } }, - .s_export_star => |s| { + .s_export_star => |s_list_index| { + const s = stmt.getExportStar(); + p.printIndent(); p.printSpaceBeforeIdentifier(); p.print("export"); @@ -2175,7 +2185,9 @@ pub fn NewPrinter(comptime ascii_only: bool) type { p.printQuotedUTF8(p.import_records[s.import_record_index].path.text, false); p.printSemicolonAfterStatement(); }, - .s_export_clause => |s| { + .s_export_clause => |s_list_index| { + const s = stmt.getExportClause(); + p.printIndent(); p.printSpaceBeforeIdentifier(); p.print("export"); @@ -2218,7 +2230,9 @@ pub fn NewPrinter(comptime ascii_only: bool) type { p.print("}"); p.printSemicolonAfterStatement(); }, - .s_export_from => |s| { + .s_export_from => |s_list_index| { + const s = stmt.getExportFrom(); + p.printIndent(); p.printSpaceBeforeIdentifier(); p.print("export"); @@ -2266,7 +2280,9 @@ pub fn NewPrinter(comptime ascii_only: bool) type { p.printQuotedUTF8(p.import_records[s.import_record_index].path.text, false); p.printSemicolonAfterStatement(); }, - .s_local => |s| { + .s_local => |s_list_index| { + const s = stmt.getLocal(); + switch (s.kind) { .k_const => { p.printDeclStmt(s.is_export, "const", s.decls); @@ -2279,18 +2295,22 @@ pub fn NewPrinter(comptime ascii_only: bool) type { }, } }, - .s_if => |s| { + .s_if => |s_list_index| { + const s = stmt.getIf(); + p.printIndent(); p.printIf(s); }, - .s_do_while => |s| { + .s_do_while => |s_list_index| { + const s = stmt.getDoWhile(); + p.printIndent(); p.printSpaceBeforeIdentifier(); p.print("do"); switch (s.body.data) { - .s_block => |block| { + .s_block => { p.printSpace(); - p.printBlock(s.body.loc, block.stmts); + p.printBlock(s.body.loc, s.body.getBlock().stmts); p.printSpace(); }, else => { @@ -2310,7 +2330,9 @@ pub fn NewPrinter(comptime ascii_only: bool) type { p.print(")"); p.printSemicolonAfterStatement(); }, - .s_for_in => |s| { + .s_for_in => |s_list_index| { + const s = stmt.getForIn(); + p.printIndent(); p.printSpaceBeforeIdentifier(); p.print("for"); @@ -2325,7 +2347,9 @@ pub fn NewPrinter(comptime ascii_only: bool) type { p.print(")"); p.printBody(s.body); }, - .s_for_of => |s| { + .s_for_of => |s_list_index| { + const s = stmt.getForOf(); + p.printIndent(); p.printSpaceBeforeIdentifier(); p.print("for"); @@ -2344,7 +2368,9 @@ pub fn NewPrinter(comptime ascii_only: bool) type { p.print(")"); p.printBody(s.body); }, - .s_while => |s| { + .s_while => |s_list_index| { + const s = stmt.getWhile(); + p.printIndent(); p.printSpaceBeforeIdentifier(); p.print("while"); @@ -2354,7 +2380,9 @@ pub fn NewPrinter(comptime ascii_only: bool) type { p.print(")"); p.printBody(s.body); }, - .s_with => |s| { + .s_with => |s_list_index| { + const s = stmt.getWith(); + p.printIndent(); p.printSpaceBeforeIdentifier(); p.print("with"); @@ -2364,13 +2392,17 @@ pub fn NewPrinter(comptime ascii_only: bool) type { p.print(")"); p.printBody(s.body); }, - .s_label => |s| { + .s_label => |s_list_index| { + const s = stmt.getLabel(); + p.printIndent(); p.printSymbol(s.name.ref orelse Global.panic("Internal error: expected label to have a name {s}", .{s})); p.print(":"); p.printBody(s.stmt); }, - .s_try => |s| { + .s_try => |s_list_index| { + const s = stmt.getTry(); + p.printIndent(); p.printSpaceBeforeIdentifier(); p.print("try"); @@ -2399,7 +2431,9 @@ pub fn NewPrinter(comptime ascii_only: bool) type { p.printNewline(); }, - .s_for => |s| { + .s_for => |s_list_index| { + const s = stmt.getFor(); + p.printIndent(); p.printSpaceBeforeIdentifier(); p.print("for"); @@ -2426,7 +2460,9 @@ pub fn NewPrinter(comptime ascii_only: bool) type { p.print(")"); p.printBody(s.body); }, - .s_switch => |s| { + .s_switch => |s_list_index| { + const s = stmt.getSwitch(); + p.printIndent(); p.printSpaceBeforeIdentifier(); p.print("switch"); @@ -2459,7 +2495,7 @@ pub fn NewPrinter(comptime ascii_only: bool) type { switch (c.body[0].data) { .s_block => |block| { p.printSpace(); - p.printBlock(c.body[0].loc, block.stmts); + p.printBlock(c.body[0].loc, c.body[0].getBlock().stmts); p.printNewline(); continue; }, @@ -2482,7 +2518,9 @@ pub fn NewPrinter(comptime ascii_only: bool) type { p.printNewline(); p.needs_semicolon = false; }, - .s_import => |s| { + .s_import => |s_list_index| { + const s = stmt.getImport(); + var item_count: usize = 0; p.printIndent(); p.printSpaceBeforeIdentifier(); @@ -2562,18 +2600,24 @@ pub fn NewPrinter(comptime ascii_only: bool) type { p.printQuotedUTF8(p.import_records[s.import_record_index].path.text, false); p.printSemicolonAfterStatement(); }, - .s_block => |s| { + .s_block => |s_list_index| { + const s = stmt.getBlock(); + p.printIndent(); p.printBlock(stmt.loc, s.stmts); p.printNewline(); }, - .s_debugger => |s| { + .s_debugger => |s_list_index| { + const s = stmt.getDebugger(); + p.printIndent(); p.printSpaceBeforeIdentifier(); p.print("debugger"); p.printSemicolonAfterStatement(); }, - .s_directive => |s| { + .s_directive => |s_list_index| { + const s = stmt.getDirective(); + const c = p.bestQuoteCharForString(s.value, false); p.printIndent(); p.printSpaceBeforeIdentifier(); @@ -2582,7 +2626,9 @@ pub fn NewPrinter(comptime ascii_only: bool) type { p.print(c); p.printSemicolonAfterStatement(); }, - .s_break => |s| { + .s_break => |s_list_index| { + const s = stmt.getBreak(); + p.printIndent(); p.printSpaceBeforeIdentifier(); p.print("break"); @@ -2593,7 +2639,9 @@ pub fn NewPrinter(comptime ascii_only: bool) type { p.printSemicolonAfterStatement(); }, - .s_continue => |s| { + .s_continue => |s_list_index| { + const s = stmt.getContinue(); + p.printIndent(); p.printSpaceBeforeIdentifier(); p.print("continue"); @@ -2604,7 +2652,9 @@ pub fn NewPrinter(comptime ascii_only: bool) type { } p.printSemicolonAfterStatement(); }, - .s_return => |s| { + .s_return => |s_list_index| { + const s = stmt.getReturn(); + p.printIndent(); p.printSpaceBeforeIdentifier(); p.print("return"); @@ -2615,7 +2665,9 @@ pub fn NewPrinter(comptime ascii_only: bool) type { } p.printSemicolonAfterStatement(); }, - .s_throw => |s| { + .s_throw => |s_list_index| { + const s = stmt.getThrow(); + p.printIndent(); p.printSpaceBeforeIdentifier(); p.print("throw"); @@ -2623,7 +2675,9 @@ pub fn NewPrinter(comptime ascii_only: bool) type { p.printExpr(s.value, .lowest, ExprFlag.None()); p.printSemicolonAfterStatement(); }, - .s_expr => |s| { + .s_expr => |s_list_index| { + const s = stmt.getExpr(); + p.printIndent(); p.stmt_start = p.js.lenI(); p.printExpr(s.value, .lowest, ExprFlag.ExprResultIsUnused()); @@ -2637,14 +2691,18 @@ pub fn NewPrinter(comptime ascii_only: bool) type { pub fn printForLoopInit(p: *Printer, initSt: Stmt) void { switch (initSt.data) { - .s_expr => |s| { + .s_expr => |s_list_index| { + const s = initSt.getExpr(); + p.printExpr( s.value, .lowest, ExprFlag{ .forbid_in = true, .expr_result_is_unused = true }, ); }, - .s_local => |s| { + .s_local => |s_list_index| { + const s = initSt.getLocal(); + switch (s.kind) { .k_var => { p.printDecls("var", s.decls, ExprFlag{ .forbid_in = true }); @@ -2673,7 +2731,7 @@ pub fn NewPrinter(comptime ascii_only: bool) type { switch (s.yes.data) { .s_block => |block| { p.printSpace(); - p.printBlock(s.yes.loc, block.stmts); + p.printBlock(s.yes.loc, s.yes.getBlock().stmts); if (s.no != null) { p.printSpace(); @@ -2721,11 +2779,11 @@ pub fn NewPrinter(comptime ascii_only: bool) type { switch (no_block.data) { .s_block => |no| { p.printSpace(); - p.printBlock(no_block.loc, no.stmts); + p.printBlock(no_block.loc, no_block.getBlock().stmts); p.printNewline(); }, .s_if => |no| { - p.printIf(no); + p.printIf(no_block.getIf()); }, else => { p.printNewline(); @@ -2737,32 +2795,31 @@ pub fn NewPrinter(comptime ascii_only: bool) type { } } - pub fn wrapToAvoidAmbiguousElse(_s: *const Stmt.Data) bool { - var s = _s; - + pub fn wrapToAvoidAmbiguousElse(s_: *const Stmt.Data) bool { + var s = s_; while (true) { switch (s.*) { - .s_if => |*current| { - if (current.*.no) |*no| { + .s_if => |index| { + if (Stmt.Data.Store.If.at(index).no) |*no| { s = &no.data; } else { return true; } }, .s_for => |current| { - s = ¤t.body.data; + s = &Stmt.Data.Store.For.at(current).body.data; }, .s_for_in => |current| { - s = ¤t.body.data; + s = &Stmt.Data.Store.ForIn.at(current).body.data; }, .s_for_of => |current| { - s = ¤t.body.data; + s = &Stmt.Data.Store.ForOf.at(current).body.data; }, .s_while => |current| { - s = ¤t.body.data; + s = &Stmt.Data.Store.While.at(current).body.data; }, .s_with => |current| { - s = ¤t.body.data; + s = &Stmt.Data.Store.With.at(current).body.data; }, else => { return false; |