diff options
Diffstat (limited to 'src/js_ast.zig')
-rw-r--r-- | src/js_ast.zig | 605 |
1 files changed, 567 insertions, 38 deletions
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 { |