diff options
Diffstat (limited to 'src/js_parser/js_parser.zig')
-rw-r--r-- | src/js_parser/js_parser.zig | 1265 |
1 files changed, 531 insertions, 734 deletions
diff --git a/src/js_parser/js_parser.zig b/src/js_parser/js_parser.zig index 18b3396d7..55b3f9449 100644 --- a/src/js_parser/js_parser.zig +++ b/src/js_parser/js_parser.zig @@ -1,4 +1,65 @@ -usingnamespace @import("imports.zig"); +pub const std = @import("std"); +pub const logger = @import("../logger.zig"); +pub const js_lexer = @import("../js_lexer.zig"); +pub const importRecord = @import("../import_record.zig"); +pub const js_ast = @import("../js_ast.zig"); +pub const options = @import("../options.zig"); +pub const js_printer = @import("../js_printer.zig"); +pub const renamer = @import("../renamer.zig"); +const _runtime = @import("../runtime.zig"); +pub const RuntimeImports = _runtime.Runtime.Imports; +pub const RuntimeFeatures = _runtime.Runtime.Features; +pub const RuntimeNames = _runtime.Runtime.Names; +pub const fs = @import("../fs.zig"); +const _hash_map = @import("../hash_map.zig"); +const _global = @import("../global.zig"); +const string = _global.string; +const Output = _global.Output; +const Global = _global.Global; +const Environment = _global.Environment; +const strings = _global.strings; +const MutableString = _global.MutableString; +const stringZ = _global.stringZ; +const default_allocator = _global.default_allocator; +const C = _global.C; +const G = js_ast.G; +const Define = @import("../defines.zig").Define; +const DefineData = @import("../defines.zig").DefineData; +const FeatureFlags = @import("../feature_flags.zig"); +pub const isPackagePath = @import("../resolver/resolver.zig").isPackagePath; +pub const ImportKind = importRecord.ImportKind; +pub const BindingNodeIndex = js_ast.BindingNodeIndex; +const Decl = G.Decl; +const Property = G.Property; +const Arg = G.Arg; + +pub const StmtNodeIndex = js_ast.StmtNodeIndex; +pub const ExprNodeIndex = js_ast.ExprNodeIndex; +pub const ExprNodeList = js_ast.ExprNodeList; +pub const StmtNodeList = js_ast.StmtNodeList; +pub const BindingNodeList = js_ast.BindingNodeList; + +pub const assert = std.debug.assert; + +pub const LocRef = js_ast.LocRef; +pub const S = js_ast.S; +pub const B = js_ast.B; +pub const T = js_lexer.T; +pub const E = js_ast.E; +pub const Stmt = js_ast.Stmt; +pub const Expr = js_ast.Expr; +pub const Binding = js_ast.Binding; +pub const Symbol = js_ast.Symbol; +pub const Level = js_ast.Op.Level; +pub const Op = js_ast.Op; +pub const Scope = js_ast.Scope; +pub const locModuleScope = logger.Loc{ .start = -100 }; +const Ref = @import("../ast/base.zig").Ref; + +pub const StringHashMap = _hash_map.StringHashMap; +pub const AutoHashMap = _hash_map.AutoHashMap; +const StringHashMapUnamanged = _hash_map.StringHashMapUnamanged; +const ObjectPool = @import("../pool.zig").ObjectPool; const NodeFallbackModules = @import("../node_fallbacks.zig"); // Dear reader, @@ -15,7 +76,6 @@ const NodeFallbackModules = @import("../node_fallbacks.zig"); // While the names for Expr, Binding, and Stmt are directly copied from esbuild, those were likely inspired by Go's parser. // which is another example of a very fast parser. -const TemplatePartTuple = std.meta.Tuple(&[_]type{ []E.TemplatePart, logger.Loc }); const ScopeOrderList = std.ArrayListUnmanaged(?ScopeOrder); const JSXFactoryName = "JSX"; @@ -253,11 +313,12 @@ pub const ImportScanner = struct { kept_import_equals: bool = false, removed_import_equals: bool = false, - pub fn scan(comptime P: type, p: P, stmts: []Stmt, comptime convert_exports: bool) !ImportScanner { + pub fn scan(comptime P: type, p: P, stmts: []Stmt) !ImportScanner { var scanner = ImportScanner{}; var stmts_end: usize = 0; + const allocator = p.allocator; - for (stmts) |_stmt, _stmt_i| { + for (stmts) |_stmt| { // zls needs the hint, it seems. var stmt: Stmt = _stmt; switch (stmt.data) { @@ -353,7 +414,7 @@ pub const ImportScanner = struct { } // Remove the star import if it's unused - if (st.star_name_loc) |star_name| { + if (st.star_name_loc) |_| { found_imports = true; const symbol = p.symbols.items[st.namespace_ref.inner_index]; @@ -449,7 +510,7 @@ pub const ImportScanner = struct { record.contains_default_alias = record.contains_default_alias or st.default_name != null; const existing_items: ImportItemForNamespaceMap = p.import_items_for_namespace.get(namespace_ref) orelse - ImportItemForNamespaceMap.init(p.allocator); + ImportItemForNamespaceMap.init(allocator); // ESM requires live bindings // CommonJS does not require live bindings @@ -482,7 +543,7 @@ pub const ImportScanner = struct { }; } - try p.import_records_for_current_part.append(st.import_record_index); + try p.import_records_for_current_part.append(allocator, st.import_record_index); if (st.star_name_loc != null) { record.contains_import_star = true; @@ -543,7 +604,7 @@ pub const ImportScanner = struct { if (decl.value) |val| { while (true) { if (@as(Expr.Tag, val.data) == .e_dot) { - value = val.getDot().target; + value = val.data.e_dot.target; } else { break; } @@ -619,7 +680,7 @@ pub const ImportScanner = struct { }, else => {}, } - var decls = try p.allocator.alloc(G.Decl, 1); + var decls = try allocator.alloc(G.Decl, 1); decls[0] = G.Decl{ .binding = p.b(B.Identifier{ .ref = st.default_name.ref.? }, stmt.loc), .value = ex }; stmt = p.s(S.Local{ @@ -639,7 +700,7 @@ pub const ImportScanner = struct { } } - var decls = try p.allocator.alloc(G.Decl, 1); + var decls = try allocator.alloc(G.Decl, 1); decls[0] = G.Decl{ .binding = p.b(B.Identifier{ .ref = st.default_name.ref.? }, stmt.loc), .value = p.e(E.Function{ .func = func.func }, stmt.loc) }; stmt = p.s(S.Local{ @@ -657,7 +718,7 @@ pub const ImportScanner = struct { } } - var decls = try p.allocator.alloc(G.Decl, 1); + var decls = try allocator.alloc(G.Decl, 1); decls[0] = G.Decl{ .binding = p.b(B.Identifier{ .ref = st.default_name.ref.? }, stmt.loc), .value = p.e(E.Class{ @@ -694,7 +755,7 @@ pub const ImportScanner = struct { } }, .s_export_star => |st| { - try p.import_records_for_current_part.append(st.import_record_index); + try p.import_records_for_current_part.append(allocator, st.import_record_index); if (st.alias) |alias| { // "export * as ns from 'path'" @@ -709,11 +770,11 @@ pub const ImportScanner = struct { try p.recordExport(alias.loc, alias.original_name, st.namespace_ref); } else { // "export * from 'path'" - try p.export_star_import_records.append(st.import_record_index); + try p.export_star_import_records.append(allocator, st.import_record_index); } }, .s_export_from => |st| { - try p.import_records_for_current_part.append(st.import_record_index); + try p.import_records_for_current_part.append(allocator, st.import_record_index); for (st.items) |item| { const ref = item.name.ref orelse p.panic("Expected export from item to have a name {s}", .{st}); @@ -1063,11 +1124,11 @@ pub const SideEffects = enum(u2) { }, .s_while => { - return shouldKeepStmtInDeadControlFlow(stmt.getWhile().body); + return shouldKeepStmtInDeadControlFlow(stmt.data.s_while.body); }, .s_do_while => { - return shouldKeepStmtInDeadControlFlow(stmt.getDoWhile().body); + return shouldKeepStmtInDeadControlFlow(stmt.data.s_do_while.body); }, .s_for => |__for__| { @@ -1102,7 +1163,7 @@ pub const SideEffects = enum(u2) { // Returns "equal, ok". If "ok" is false, then nothing is known about the two // values. If "ok" is true, the equality or inequality of the two values is // stored in "equal". - pub fn eql(left: Expr.Data, right: Expr.Data, p: anytype) Equality { + pub fn eql(left: Expr.Data, right: Expr.Data, _: anytype) Equality { var equality = Equality{}; switch (left) { .e_null => { @@ -1629,7 +1690,7 @@ const TempRef = struct { }; const ImportNamespaceCallOrConstruct = struct { - ref: js_ast.Ref, + ref: Ref, is_construct: bool = false, }; @@ -1652,26 +1713,55 @@ const StrictModeFeature = enum { if_else_function_stmt, }; -const SymbolMergeResult = enum { - forbidden, - replace_with_new, - overwrite_with_new, - keep_existing, - become_private_get_set_pair, - become_private_static_get_set_pair, -}; +const Map = _hash_map.AutoHashMapUnmanaged; + +const List = std.ArrayListUnmanaged; +const ListManaged = std.ArrayList; +const LocList = ListManaged(logger.Loc); +const StmtList = ListManaged(Stmt); -const Map = AutoHashMap; +// This hash table is used every time we parse function args +// Rather than allocating a new hash table each time, we can just reuse the previous allocation + +const StringVoidMap = struct { + allocator: std.mem.Allocator, + map: std.StringHashMapUnmanaged(void) = std.StringHashMapUnmanaged(void){}, + + /// Returns true if the map already contained the given key. + pub fn getOrPutContains(this: *StringVoidMap, key: string) bool { + const entry = this.map.getOrPut(this.allocator, key) catch unreachable; + return entry.found_existing; + } -const List = std.ArrayList; -const LocList = List(logger.Loc); -const StmtList = List(Stmt); + pub fn contains(this: *StringVoidMap, key: string) bool { + return this.map.contains(key); + } + + fn init(allocator: std.mem.Allocator) anyerror!StringVoidMap { + return StringVoidMap{ .allocator = allocator }; + } + + pub fn reset(this: *StringVoidMap) void { + // We must reset or the hash table will contain invalid pointers + this.map.clearRetainingCapacity(); + } -const SymbolUseMap = Map(js_ast.Ref, js_ast.Symbol.Use); -const StringRefMap = StringHashMap(js_ast.Ref); -const StringBoolMap = StringHashMap(bool); -const RefBoolMap = Map(js_ast.Ref, bool); -const RefRefMap = Map(js_ast.Ref, js_ast.Ref); + pub inline fn get(allocator: std.mem.Allocator) *Node { + return Pool.get(allocator); + } + + pub inline fn release(node: *Node) void { + Pool.release(node); + } + + pub const Pool = ObjectPool(StringVoidMap, init, true); + pub const Node = Pool.Node; +}; + +const SymbolUseMap = Map(Ref, js_ast.Symbol.Use); +const StringBoolMap = _hash_map.StringHashMapUnmanaged(bool); +const RefMap = Map(Ref, void); +const RefRefMap = Map(Ref, Ref); const ImportRecord = importRecord.ImportRecord; const Flags = js_ast.Flags; const ScopeOrder = struct { @@ -1722,7 +1812,7 @@ const FnOrArrowDataParse = struct { // restored on the call stack around code that parses nested functions and // arrow expressions. const FnOrArrowDataVisit = struct { - // super_index_ref: ?*js_ast.Ref = null, + // super_index_ref: ?*Ref = null, is_arrow: bool = false, is_async: bool = false, @@ -1743,18 +1833,18 @@ const FnOnlyDataVisit = struct { // This is a reference to the magic "arguments" variable that exists inside // functions in JavaScript. It will be non-nil inside functions and nil // otherwise. - arguments_ref: ?js_ast.Ref = null, + arguments_ref: ?Ref = null, // Arrow functions don't capture the value of "this" and "arguments". Instead, // the values are inherited from the surrounding context. If arrow functions // are turned into regular functions due to lowering, we will need to generate // local variables to capture these values so they are preserved correctly. - this_capture_ref: ?js_ast.Ref = null, - arguments_capture_ref: ?js_ast.Ref = null, + this_capture_ref: ?Ref = null, + arguments_capture_ref: ?Ref = null, // Inside a static class property initializer, "this" expressions should be // replaced with the class name. - this_class_static_ref: ?js_ast.Ref = null, + this_class_static_ref: ?Ref = null, // If we're inside an async arrow function and async functions are not // supported, then we will have to convert that arrow function to a generator @@ -1837,18 +1927,18 @@ pub const ScanPassResult = struct { pub const ParsePassSymbolUse = struct { ref: Ref, used: bool = false, import_record_index: u32 }; pub const NamespaceCounter = struct { count: u16, import_record_index: u32 }; pub const ParsePassSymbolUsageMap = std.StringArrayHashMap(ParsePassSymbolUse); - import_records: List(ImportRecord), + import_records: ListManaged(ImportRecord), named_imports: js_ast.Ast.NamedImports, used_symbols: ParsePassSymbolUsageMap, - import_records_to_keep: List(u32), + import_records_to_keep: ListManaged(u32), approximate_newline_count: usize = 0, - pub fn init(allocator: *std.mem.Allocator) ScanPassResult { + pub fn init(allocator: std.mem.Allocator) ScanPassResult { return .{ - .import_records = List(ImportRecord).init(allocator), + .import_records = ListManaged(ImportRecord).init(allocator), .named_imports = js_ast.Ast.NamedImports.init(allocator), .used_symbols = ParsePassSymbolUsageMap.init(allocator), - .import_records_to_keep = List(u32).init(allocator), + .import_records_to_keep = ListManaged(u32).init(allocator), .approximate_newline_count = 0, }; } @@ -1867,7 +1957,7 @@ pub const Parser = struct { log: *logger.Log, source: *const logger.Source, define: *Define, - allocator: *std.mem.Allocator, + allocator: std.mem.Allocator, pub const Options = struct { jsx: options.JSX.Pragma, @@ -1932,7 +2022,6 @@ pub const Parser = struct { // Parse the file in the first pass, but do not bind symbols var opts = ParseStatementOptions{ .is_module_scope = true }; - debugl("<p.parseStmtsUpTo>"); // Parsing seems to take around 2x as much time as visiting. // Which makes sense. @@ -2031,14 +2120,13 @@ pub const Parser = struct { // Parse the file in the first pass, but do not bind symbols var opts = ParseStatementOptions{ .is_module_scope = true }; - debugl("<p.parseStmtsUpTo>"); // Parsing seems to take around 2x as much time as visiting. // Which makes sense. // June 4: "Parsing took: 18028000" // June 4: "Rest of this took: 8003000" const stmts = try p.parseStmtsUpTo(js_lexer.T.t_end_of_file, &opts); - debugl("</p.parseStmtsUpTo>"); + try p.prepareForVisitPass(); // ESM is always strict mode. I don't think we need this. @@ -2061,10 +2149,9 @@ pub const Parser = struct { // }, logger.Loc.Empty); // } - debugl("<p.appendPart>"); - var before = List(js_ast.Part).init(p.allocator); - var after = List(js_ast.Part).init(p.allocator); - var parts = List(js_ast.Part).init(p.allocator); + var before = ListManaged(js_ast.Part).init(p.allocator); + var after = ListManaged(js_ast.Part).init(p.allocator); + var parts = ListManaged(js_ast.Part).init(p.allocator); try p.appendPart(&parts, stmts); var did_import_fast_refresh = false; @@ -2286,7 +2373,7 @@ pub const Parser = struct { .import_record_index = import_record_id, }, ) catch unreachable; - p.is_import_item.put(automatic_namespace_ref, true) catch unreachable; + p.is_import_item.put(p.allocator, automatic_namespace_ref, .{}) catch unreachable; import_records[import_record_i] = import_record_id; import_record_i += 1; } @@ -2370,7 +2457,7 @@ pub const Parser = struct { .import_record_index = import_record_id, }, ) catch unreachable; - p.is_import_item.put(classic_namespace_ref, true) catch unreachable; + p.is_import_item.put(p.allocator, classic_namespace_ref, .{}) catch unreachable; import_records[import_record_i] = import_record_id; declared_symbols[declared_symbols_i] = .{ .ref = classic_namespace_ref, .is_top_level = true }; declared_symbols_i += 1; @@ -2403,7 +2490,7 @@ pub const Parser = struct { .import_record_index = import_record_id, }, ) catch unreachable; - p.is_import_item.put(p.jsx_refresh_runtime.ref, true) catch unreachable; + p.is_import_item.put(p.allocator, p.jsx_refresh_runtime.ref, .{}) catch unreachable; import_records[import_record_i] = import_record_id; p.recordUsage(p.jsx_refresh_runtime.ref); } @@ -2415,7 +2502,7 @@ pub const Parser = struct { .stmts = jsx_part_stmts[0..stmt_i], .declared_symbols = declared_symbols, .import_record_indices = import_records, - .symbol_uses = SymbolUseMap.init(p.allocator), + .symbol_uses = SymbolUseMap{}, .tag = .jsx_import, }) catch unreachable; } @@ -2448,7 +2535,7 @@ pub const Parser = struct { .import_record_index = import_record_id, }, ) catch unreachable; - p.is_import_item.put(p.jsx_refresh_runtime.ref, true) catch unreachable; + p.is_import_item.put(p.allocator, p.jsx_refresh_runtime.ref, .{}) catch unreachable; var import_records = try p.allocator.alloc(@TypeOf(import_record_id), 1); import_records[0] = import_record_id; declared_symbols[0] = .{ .ref = p.jsx_refresh_runtime.ref, .is_top_level = true }; @@ -2459,7 +2546,7 @@ pub const Parser = struct { .stmts = part_stmts, .declared_symbols = declared_symbols, .import_record_indices = import_records, - .symbol_uses = SymbolUseMap.init(p.allocator), + .symbol_uses = SymbolUseMap{}, }) catch unreachable; } @@ -2470,24 +2557,24 @@ pub const Parser = struct { if (FeatureFlags.auto_import_buffer) { // If they use Buffer...just automatically import it. // ✨ magic ✨ (i don't like this) - if (p.symbols.items[p.buffer_ref.inner_index].use_count_estimate > 0) { - var named_import = p.named_imports.getOrPut(p.buffer_ref); - - // if Buffer is actually an import, let them use that one instead. - if (!named_import.found_existing) { - const import_record_id = p.addImportRecord( - .require, - logger.Loc.empty, - NodeFallbacks.buffer_fallback_import_name, - ); - var import_stmt = p.s(S.Import{ - .namespace_ref = p.buffer_ref, - .star_name_loc = loc, - .is_single_line = true, - .import_record_index = import_record_id, - }, loc); - } - } + // if (p.symbols.items[p.buffer_ref.inner_index].use_count_estimate > 0) { + // var named_import = p.named_imports.getOrPut(p.buffer_ref); + + // // if Buffer is actually an import, let them use that one instead. + // if (!named_import.found_existing) { + // const import_record_id = p.addImportRecord( + // .require, + // logger.Loc.empty, + // NodeFallbackModules.buffer_fallback_import_name, + // ); + // var import_stmt = p.s(S.Import{ + // .namespace_ref = p.buffer_ref, + // .star_name_loc = loc, + // .is_single_line = true, + // .import_record_index = import_record_id, + // }, loc); + // } + // } } const has_cjs_imports = p.cjs_import_stmts.items.len > 0 and p.options.transform_require_to_import; @@ -2542,7 +2629,7 @@ pub const Parser = struct { .stmts = p.cjs_import_stmts.items, .declared_symbols = declared_symbols, .import_record_indices = import_records, - .symbol_uses = SymbolUseMap.init(p.allocator), + .symbol_uses = SymbolUseMap{}, }) catch unreachable; } @@ -2582,20 +2669,18 @@ pub const Parser = struct { before.deinit(); parts_slice = parts.items; } - debugl("</p.appendPart>"); // Pop the module scope to apply the "ContainsDirectEval" rules // p.popScope(); - debugl("<result.Ast>"); + result.ast = try p.toAST(parts_slice, exports_kind, wrapper_expr); result.ok = true; - debugl("</result.Ast>"); return result; } - pub fn init(_options: Options, log: *logger.Log, source: *const logger.Source, define: *Define, allocator: *std.mem.Allocator) !Parser { - const lexer = try js_lexer.Lexer.init(log, source, allocator); + pub fn init(_options: Options, log: *logger.Log, source: *const logger.Source, define: *Define, allocator: std.mem.Allocator) !Parser { + const lexer = try js_lexer.Lexer.init(log, source.*, allocator); return Parser{ .options = _options, .allocator = allocator, @@ -2795,10 +2880,10 @@ const ImportItemForNamespaceMap = std.StringArrayHashMap(LocRef); pub const MacroState = struct { refs: MacroRefs, - prepend_stmts: *List(Stmt) = undefined, + prepend_stmts: *ListManaged(Stmt) = undefined, imports: std.AutoArrayHashMap(i32, Ref), - pub fn init(allocator: *std.mem.Allocator) MacroState { + pub fn init(allocator: std.mem.Allocator) MacroState { return MacroState{ .refs = MacroRefs.init(allocator), .prepend_stmts = undefined, @@ -2827,7 +2912,7 @@ pub fn NewParser( const P = @This(); pub const jsx_transform_type: JSXTransformType = js_parser_jsx; macro: MacroState = undefined, - allocator: *std.mem.Allocator, + allocator: std.mem.Allocator, options: Parser.Options, log: *logger.Log, define: *Define, @@ -2843,19 +2928,19 @@ pub fn NewParser( fn_or_arrow_data_parse: FnOrArrowDataParse = FnOrArrowDataParse{}, fn_or_arrow_data_visit: FnOrArrowDataVisit = FnOrArrowDataVisit{}, fn_only_data_visit: FnOnlyDataVisit = FnOnlyDataVisit{}, - allocated_names: List(string), + allocated_names: List(string) = .{}, latest_arrow_arg_loc: logger.Loc = logger.Loc.Empty, forbid_suffix_after_as_loc: logger.Loc = logger.Loc.Empty, current_scope: *js_ast.Scope = undefined, - scopes_for_current_part: List(*js_ast.Scope), - symbols: List(js_ast.Symbol), - ts_use_counts: List(u32), - exports_ref: js_ast.Ref = js_ast.Ref.None, - require_ref: js_ast.Ref = js_ast.Ref.None, - module_ref: js_ast.Ref = js_ast.Ref.None, - buffer_ref: js_ast.Ref = js_ast.Ref.None, - import_meta_ref: js_ast.Ref = js_ast.Ref.None, - promise_ref: ?js_ast.Ref = null, + scopes_for_current_part: List(*js_ast.Scope) = .{}, + symbols: List(js_ast.Symbol) = .{}, + ts_use_counts: List(u32) = .{}, + exports_ref: Ref = Ref.None, + require_ref: Ref = Ref.None, + module_ref: Ref = Ref.None, + buffer_ref: Ref = Ref.None, + import_meta_ref: Ref = Ref.None, + promise_ref: ?Ref = null, scopes_in_order_visitor_index: usize = 0, has_classic_runtime_warned: bool = false, @@ -2865,9 +2950,9 @@ pub fn NewParser( cjs_import_stmts: std.ArrayList(Stmt), - injected_define_symbols: List(Ref), - symbol_uses: SymbolUseMap, - declared_symbols: List(js_ast.DeclaredSymbol), + injected_define_symbols: List(Ref) = .{}, + symbol_uses: SymbolUseMap = .{}, + declared_symbols: List(js_ast.DeclaredSymbol) = .{}, runtime_imports: RuntimeImports = RuntimeImports{}, parse_pass_symbol_uses: ParsePassSymbolUsageType = undefined, @@ -2877,17 +2962,17 @@ pub fn NewParser( // legacy_octal_literals: map[js_ast.E]logger.Range, // For lowering private methods - // weak_map_ref: ?js_ast.Ref, - // weak_set_ref: ?js_ast.Ref, + // weak_map_ref: ?Ref, + // weak_set_ref: ?Ref, // private_getters: RefRefMap, // private_setters: RefRefMap, // These are for TypeScript should_fold_numeric_constants: bool = false, - emitted_namespace_vars: RefBoolMap, - is_exported_inside_namespace: RefRefMap, - known_enum_values: Map(js_ast.Ref, StringHashMap(f64)), - local_type_names: StringBoolMap, + emitted_namespace_vars: RefMap = RefMap{}, + is_exported_inside_namespace: RefRefMap = .{}, + known_enum_values: Map(Ref, _hash_map.StringHashMapUnmanaged(f64)) = .{}, + local_type_names: StringBoolMap = StringBoolMap{}, // This is the reference to the generated function argument for the namespace, // which is different than the reference to the namespace itself: @@ -2903,7 +2988,7 @@ pub fn NewParser( // // This variable is "ns2" not "ns1". It is only used during the second // "visit" pass. - enclosing_namespace_arg_ref: ?js_ast.Ref = null, + enclosing_namespace_arg_ref: ?Ref = null, jsx_filename: GeneratedSymbol = GeneratedSymbol{ .ref = Ref.None, .primary = Ref.None, .backup = Ref.None }, jsx_runtime: GeneratedSymbol = GeneratedSymbol{ .ref = Ref.None, .primary = Ref.None, .backup = Ref.None }, @@ -2919,19 +3004,18 @@ pub fn NewParser( // Imports (both ES6 and CommonJS) are tracked at the top level import_records: ImportRecordList, - import_records_for_current_part: List(u32), - export_star_import_records: List(u32), + import_records_for_current_part: List(u32) = .{}, + export_star_import_records: List(u32) = .{}, // These are for handling ES6 imports and exports es6_import_keyword: logger.Range = logger.Range.None, es6_export_keyword: logger.Range = logger.Range.None, enclosing_class_keyword: logger.Range = logger.Range.None, - import_items_for_namespace: std.AutoHashMap(js_ast.Ref, ImportItemForNamespaceMap), - is_import_item: RefBoolMap, + import_items_for_namespace: std.AutoHashMapUnmanaged(Ref, ImportItemForNamespaceMap) = .{}, + is_import_item: RefMap = .{}, named_imports: NamedImportsType, named_exports: js_ast.Ast.NamedExports, - top_level_symbol_to_parts: Map(js_ast.Ref, List(u32)), - import_namespace_cc_map: Map(ImportNamespaceCallOrConstruct, bool), + import_namespace_cc_map: Map(ImportNamespaceCallOrConstruct, bool) = .{}, // When we're only scanning the imports // If they're using the automatic JSX runtime @@ -2955,7 +3039,7 @@ pub fn NewParser( // symbols must be separate from the pass that binds identifiers to declared // symbols to handle declaring a hoisted "var" symbol in a nested scope and // binding a name to it in a parent or sibling scope. - scopes_in_order: ScopeOrderList, + scopes_in_order: ScopeOrderList = .{}, // These properties are for the visit pass, which runs after the parse pass. // The visit pass binds identifiers to declared symbols, does constant @@ -3036,7 +3120,7 @@ pub fn NewParser( then_catch_chain: ThenCatchChain, // Temporary variables used for lowering - temp_refs_to_declare: List(TempRef), + temp_refs_to_declare: List(TempRef) = .{}, temp_ref_count: i32 = 0, // When bundling, hoisted top-level local variables declared with "var" in @@ -3044,7 +3128,7 @@ pub fn NewParser( // The old "var" statements are turned into regular assignments instead. This // makes it easier to quickly scan the top-level statements for "var" locals // with the guarantee that all will be found. - relocated_top_level_vars: List(js_ast.LocRef), + relocated_top_level_vars: List(js_ast.LocRef) = .{}, // ArrowFunction is a special case in the grammar. Although it appears to be // a PrimaryExpression, it's actually an AssignmentExpression. This means if @@ -3068,7 +3152,7 @@ pub fn NewParser( require_resolve_transposer: RequireResolveTransposer, // This is a general place to put lots of Expr objects - expr_list: List(Expr), + expr_list: List(Expr) = .{}, scope_order_to_visit: []ScopeOrder = &([_]ScopeOrder{}), @@ -3081,11 +3165,10 @@ pub fn NewParser( if (p.is_control_flow_dead) { return p.e(E.Null{}, arg.loc); } - const str = arg.data.e_string; const import_record_index = p.addImportRecord(.dynamic, arg.loc, arg.data.e_string.string(p.allocator) catch unreachable); p.import_records.items[import_record_index].handles_import_errors = (state.is_await_target and p.fn_or_arrow_data_visit.try_body_count != 0) or state.is_then_catch_target; - p.import_records_for_current_part.append(import_record_index) catch unreachable; + p.import_records_for_current_part.append(p.allocator, import_record_index) catch unreachable; return p.e(E.Import{ .expr = arg, .import_record_index = Ref.toInt(import_record_index), @@ -3105,11 +3188,11 @@ pub fn NewParser( }, state.loc); } - pub fn transposeRequireResolve(p: *P, arg: Expr, transpose_state: anytype) Expr { + pub fn transposeRequireResolve(_: *P, arg: Expr, _: anytype) Expr { return arg; } - pub fn transposeRequire(p: *P, arg: Expr, transpose_state: anytype) Expr { + pub fn transposeRequire(p: *P, arg: Expr, _: anytype) Expr { switch (arg.data) { .e_string => |str| { @@ -3124,7 +3207,7 @@ pub fn NewParser( const import_record_index = p.addImportRecord(.require, arg.loc, pathname); p.import_records.items[import_record_index].handles_import_errors = p.fn_or_arrow_data_visit.try_body_count != 0; - p.import_records_for_current_part.append(import_record_index) catch unreachable; + p.import_records_for_current_part.append(p.allocator, import_record_index) catch unreachable; if (!p.options.transform_require_to_import) { return p.e(E.Require{ .import_record_index = import_record_index }, arg.loc); @@ -3192,7 +3275,7 @@ pub fn NewParser( pub const Hoisted = Binding.ToExpr(P, P.wrapIdentifierHoisting); }; - pub fn s(p: *P, t: anytype, loc: logger.Loc) Stmt { + pub fn s(_: *P, t: anytype, loc: logger.Loc) Stmt { const Type = @TypeOf(t); // Output.print("\nStmt: {s} - {d}\n", .{ @typeName(@TypeOf(t)), loc.start }); if (@typeInfo(Type) == .Pointer) { @@ -3215,7 +3298,7 @@ pub fn NewParser( return Stmt.init(std.meta.Child(Type), t, loc); } else { - return Stmt.alloc(p.allocator, Type, t, loc); + return Stmt.alloc(Type, t, loc); } } @@ -3278,7 +3361,6 @@ pub fn NewParser( parser.export_star_import_records.deinit(); parser.import_items_for_namespace.deinit(); parser.named_imports.deinit(); - parser.top_level_symbol_to_parts.deinit(); parser.import_namespace_cc_map.deinit(); parser.scopes_in_order.deinit(); parser.temp_refs_to_declare.deinit(); @@ -3292,6 +3374,7 @@ pub fn NewParser( // That's part of why we do this. // Instead of rehashing `name` for every scope, we do it just once. const hash = @TypeOf(p.module_scope.members).getHash(name); + const allocator = p.allocator; const ref: Ref = brk: { var _scope: ?*Scope = p.current_scope; @@ -3308,7 +3391,7 @@ pub fn NewParser( // Forbid referencing "arguments" inside class bodies if (scope.forbid_arguments and !did_forbid_argumen and strings.eqlComptime(name, "arguments")) { const r = js_lexer.rangeOfIdentifier(p.source, loc); - p.log.addRangeErrorFmt(p.source, r, p.allocator, "Cannot access \"{s}\" here", .{name}) catch unreachable; + p.log.addRangeErrorFmt(p.source, r, allocator, "Cannot access \"{s}\" here", .{name}) catch unreachable; did_forbid_argumen = true; } @@ -3323,7 +3406,7 @@ pub fn NewParser( p.checkForNonBMPCodePoint(loc, name); const _ref = p.newSymbol(.unbound, name) catch unreachable; declare_loc = loc; - p.module_scope.members.putWithHash(name, hash, js_ast.Scope.Member{ .ref = _ref, .loc = logger.Loc.Empty }) catch unreachable; + p.module_scope.members.putWithHash(allocator, name, hash, js_ast.Scope.Member{ .ref = _ref, .loc = logger.Loc.Empty }) catch unreachable; break :brk _ref; }; @@ -3396,14 +3479,14 @@ pub fn NewParser( } } - pub fn recordUsage(p: *P, ref: js_ast.Ref) void { + pub fn recordUsage(p: *P, ref: Ref) void { // The use count stored in the symbol is used for generating symbol names // during minification. These counts shouldn't include references inside dead // code regions since those will be culled. if (!p.is_control_flow_dead) { std.debug.assert(p.symbols.items.len > ref.inner_index); p.symbols.items[ref.inner_index].use_count_estimate += 1; - var result = p.symbol_uses.getOrPut(ref) catch unreachable; + var result = p.symbol_uses.getOrPut(p.allocator, ref) catch unreachable; if (!result.found_existing) { result.entry.value = Symbol.Use{ .count_estimate = 1 }; } else { @@ -3446,80 +3529,6 @@ pub fn NewParser( } } - fn canMergeSymbols(p: *P, scope: *js_ast.Scope, existing: Symbol.Kind, new: Symbol.Kind) SymbolMergeResult { - if (existing == .unbound) { - return .replace_with_new; - } - - // In TypeScript, imports are allowed to silently collide with symbols within - // the module. Presumably this is because the imports may be type-only: - // - // import {Foo} from 'bar' - // class Foo {} - // - if (is_typescript_enabled and existing == .import) { - return .replace_with_new; - } - - // "enum Foo {} enum Foo {}" - // "namespace Foo { ... } enum Foo {}" - if (new == .ts_enum and (existing == .ts_enum or existing == .ts_namespace)) { - return .replace_with_new; - } - - // "namespace Foo { ... } namespace Foo { ... }" - // "function Foo() {} namespace Foo { ... }" - // "enum Foo {} namespace Foo { ... }" - if (new == .ts_namespace) { - switch (existing) { - .ts_namespace, .hoisted_function, .generator_or_async_function, .ts_enum, .class => { - return .keep_existing; - }, - else => {}, - } - } - - // "var foo; var foo;" - // "var foo; function foo() {}" - // "function foo() {} var foo;" - // "function *foo() {} function *foo() {}" but not "{ function *foo() {} function *foo() {} }" - if (Symbol.isKindHoistedOrFunction(new) and Symbol.isKindHoistedOrFunction(existing) and (scope.kind == .entry or scope.kind == .function_body or - (Symbol.isKindHoisted(new) and Symbol.isKindHoisted(existing)))) - { - return .keep_existing; - } - - // "get #foo() {} set #foo() {}" - // "set #foo() {} get #foo() {}" - if ((existing == .private_get and new == .private_set) or - (existing == .private_set and new == .private_get)) - { - return .become_private_get_set_pair; - } - if ((existing == .private_static_get and new == .private_static_set) or - (existing == .private_static_set and new == .private_static_get)) - { - return .become_private_static_get_set_pair; - } - - // "try {} catch (e) { var e }" - if (existing == .catch_identifier and new == .hoisted) { - return .replace_with_new; - } - - // "function() { var arguments }" - if (existing == .arguments and new == .hoisted) { - return .keep_existing; - } - - // "function() { let arguments }" - if (existing == .arguments and new != .hoisted) { - return .overwrite_with_new; - } - - return .forbidden; - } - pub fn handleIdentifier(p: *P, loc: logger.Loc, ident: E.Identifier, _original_name: ?string, opts: IdentifierOpts) Expr { const ref = ident.ref; @@ -3572,20 +3581,21 @@ pub fn NewParser( p: *P, import_path: string, imports: anytype, - parts: *List(js_ast.Part), + parts: *ListManaged(js_ast.Part), symbols: anytype, additional_stmt: ?Stmt, comptime suffix: string, comptime is_internal: bool, ) !void { + const allocator = p.allocator; const import_record_i = p.addImportRecordByRange(.stmt, logger.Range.None, import_path); var import_record: *ImportRecord = &p.import_records.items[import_record_i]; import_record.is_internal = is_internal; - var import_path_identifier = try import_record.path.name.nonUniqueNameString(p.allocator); - var namespace_identifier = try p.allocator.alloc(u8, import_path_identifier.len + suffix.len); - var clause_items = try p.allocator.alloc(js_ast.ClauseItem, imports.len); - var stmts = try p.allocator.alloc(Stmt, 1 + if (additional_stmt != null) @as(usize, 1) else @as(usize, 0)); - var declared_symbols = try p.allocator.alloc(js_ast.DeclaredSymbol, imports.len); + var import_path_identifier = try import_record.path.name.nonUniqueNameString(allocator); + var namespace_identifier = try allocator.alloc(u8, import_path_identifier.len + suffix.len); + var clause_items = try allocator.alloc(js_ast.ClauseItem, imports.len); + var stmts = try allocator.alloc(Stmt, 1 + if (additional_stmt != null) @as(usize, 1) else @as(usize, 0)); + var declared_symbols = try allocator.alloc(js_ast.DeclaredSymbol, imports.len); std.mem.copy(u8, namespace_identifier[0..suffix.len], suffix); std.mem.copy( u8, @@ -3594,7 +3604,7 @@ pub fn NewParser( ); const namespace_ref = try p.newSymbol(.other, namespace_identifier); - try p.module_scope.generated.append(namespace_ref); + try p.module_scope.generated.append(allocator, namespace_ref); for (imports) |alias, i| { const ref = symbols.get(alias) orelse unreachable; const alias_name = if (@TypeOf(symbols) == RuntimeImports) RuntimeImports.all[alias] else alias; @@ -3605,7 +3615,7 @@ pub fn NewParser( .name = LocRef{ .ref = ref, .loc = logger.Loc{} }, }; declared_symbols[i] = js_ast.DeclaredSymbol{ .ref = ref, .is_top_level = true }; - try p.is_import_item.put(ref, true); + try p.is_import_item.put(allocator, ref, .{}); try p.named_imports.put(ref, js_ast.NamedImport{ .alias = alias_name, .alias_loc = logger.Loc{}, @@ -3623,7 +3633,7 @@ pub fn NewParser( stmts[1] = add; } - var import_records = try p.allocator.alloc(@TypeOf(import_record_i), 1); + var import_records = try allocator.alloc(@TypeOf(import_record_i), 1); import_records[0] = import_record_i; // Append a single import to the end of the file (ES6 imports are hoisted @@ -3632,7 +3642,7 @@ pub fn NewParser( .stmts = stmts, .declared_symbols = declared_symbols, .import_record_indices = import_records, - .symbol_uses = SymbolUseMap.init(p.allocator), + .symbol_uses = SymbolUseMap{}, }) catch unreachable; } @@ -3691,8 +3701,8 @@ pub fn NewParser( if (p.options.jsx.development) generated_symbols_count += 1; } - try p.module_scope.generated.ensureUnusedCapacity(generated_symbols_count * 3); - try p.module_scope.members.ensureCapacity(generated_symbols_count * 3 + p.module_scope.members.count()); + try p.module_scope.generated.ensureUnusedCapacity(p.allocator, generated_symbols_count * 3); + try p.module_scope.members.ensureCapacity(p.allocator, generated_symbols_count * 3 + p.module_scope.members.count()); p.exports_ref = try p.declareCommonJSSymbol(.hoisted, "exports"); p.module_ref = try p.declareCommonJSSymbol(.hoisted, "module"); @@ -3817,6 +3827,7 @@ pub fn NewParser( fn hoistSymbols(p: *P, scope: *js_ast.Scope) void { if (!scope.kindStopsHoisting()) { var iter = scope.members.iterator(); + const allocator = p.allocator; nextMember: while (iter.next()) |res| { var symbol = &p.symbols.items[res.value.ref.inner_index]; if (!symbol.isHoisted()) { @@ -3873,18 +3884,18 @@ pub fn NewParser( // declaration can both silently shadow another hoisted symbol if (symbol.kind != .catch_identifier and symbol.kind != .hoisted_function) { const r = js_lexer.rangeOfIdentifier(p.source, res.value.loc); - var notes = p.allocator.alloc(logger.Data, 1) catch unreachable; + var notes = allocator.alloc(logger.Data, 1) catch unreachable; notes[0] = logger.rangeData( p.source, r, - std.fmt.allocPrint(p.allocator, "{s} has already been declared", .{symbol.original_name}) catch unreachable, + std.fmt.allocPrint(allocator, "{s} has already been declared", .{symbol.original_name}) catch unreachable, ); p.log.addRangeErrorFmtWithNotes( p.source, js_lexer.rangeOfIdentifier(p.source, existing_member_entry.value.loc), - p.allocator, + allocator, notes, "{s} was originally declared here", .{existing_symbol.original_name}, @@ -3896,7 +3907,7 @@ pub fn NewParser( } if (_scope.kindStopsHoisting()) { - _scope.members.putWithHash(symbol.original_name, hash, res.value) catch unreachable; + _scope.members.putWithHash(allocator, symbol.original_name, hash, res.value) catch unreachable; break; } __scope = _scope.parent; @@ -3904,7 +3915,7 @@ pub fn NewParser( } } - for (scope.children.items) |_item, i| { + for (scope.children.items) |_, i| { p.hoistSymbols(scope.children.items[i]); } } @@ -3931,32 +3942,26 @@ pub fn NewParser( p.current_scope = order.scope; - try p.scopes_for_current_part.append(order.scope); + try p.scopes_for_current_part.append(p.allocator, order.scope); } fn pushScopeForParsePass(p: *P, comptime kind: js_ast.Scope.Kind, loc: logger.Loc) !usize { - debugl("<pushScopeForParsePass>"); - defer debugl("</pushScopeForParsePass>"); var parent: *Scope = p.current_scope; + const allocator = p.allocator; + var scope = try allocator.create(Scope); - var scope = try p.allocator.create(Scope); scope.* = Scope{ - .members = @TypeOf(scope.members).init(p.allocator), - .children = @TypeOf(scope.children).init( - p.allocator, - ), - .generated = @TypeOf(scope.generated).init(p.allocator), .kind = kind, .label_ref = null, .parent = parent, }; - try parent.children.append(scope); + try parent.children.append(allocator, scope); scope.strict_mode = parent.strict_mode; p.current_scope = scope; - if (comptime !isRelease) { + if (comptime !Environment.isRelease) { // Enforce that scope locations are strictly increasing to help catch bugs // where the pushed scopes are mistmatched between the first and second passes if (p.scopes_in_order.items.len > 0) { @@ -3985,14 +3990,14 @@ pub fn NewParser( // // the name of a function expression is allowed. const adjacent_symbols = p.symbols.items[entry.value.ref.inner_index]; if (adjacent_symbols.kind != .hoisted_function) { - try scope.members.put(entry.key, entry.value); + try scope.members.put(allocator, entry.key, entry.value); } } } // Remember the length in case we call popAndDiscardScope() later const scope_index = p.scopes_in_order.items.len; - try p.scopes_in_order.append(p.allocator, ScopeOrder{ .loc = loc, .scope = scope }); + try p.scopes_in_order.append(allocator, ScopeOrder{ .loc = loc, .scope = scope }); // Output.print("\nLoc: {d}\n", .{loc.start}); return scope_index; } @@ -4023,7 +4028,6 @@ pub fn NewParser( var is_spread = false; for (ex.items) |_, i| { var item = ex.items[i]; - var _expr = item; if (item.data == .e_spread) { is_spread = true; item = item.data.e_spread.value; @@ -4118,7 +4122,7 @@ pub fn NewParser( } fn forbidLexicalDecl(p: *P, loc: logger.Loc) !void { - try p.log.addRangeError(p.source, p.lexer.range(), "Cannot use a declaration in a single-statement context"); + try p.log.addError(p.source, loc, "Cannot use a declaration in a single-statement context"); } fn logExprErrors(p: *P, errors: *DeferredErrors) void { @@ -4295,7 +4299,7 @@ pub fn NewParser( p.fn_or_arrow_data_parse.allow_yield = if (opts.allow_yield == .allow_expr) AwaitOrYield.forbid_all else AwaitOrYield.allow_ident; // If "super()" is allowed in the body, it's allowed in the arguments p.fn_or_arrow_data_parse.allow_super_call = opts.allow_super_call; - var args = List(G.Arg).init(p.allocator); + var args = List(G.Arg){}; while (p.lexer.token != T.t_close_paren) { // Skip over "this" type annotations if (is_typescript_enabled and p.lexer.token == T.t_this) { @@ -4328,7 +4332,7 @@ pub fn NewParser( var text = p.lexer.identifier; var arg = try p.parseBinding(); - if (is_typescript_enabled) { + if (comptime is_typescript_enabled) { if (is_identifier and opts.is_constructor) { // Skip over TypeScript accessibility modifiers, which turn this argument // into a class field when used inside a class constructor. This is known @@ -4380,7 +4384,7 @@ pub fn NewParser( default_value = try p.parseExpr(.comma); } - args.append(G.Arg{ + args.append(p.allocator, G.Arg{ .ts_decorators = ts_decorators, .binding = arg, .default = default_value, @@ -4452,7 +4456,7 @@ pub fn NewParser( return &([_]ExprNodeIndex{}); } - var decorators = List(ExprNodeIndex).init(p.allocator); + var decorators = ListManaged(ExprNodeIndex).init(p.allocator); while (p.lexer.token == T.t_at) { try p.lexer.next(); @@ -5024,24 +5028,24 @@ pub fn NewParser( var scope = p.current_scope; - try scope.generated.append(name.ref orelse unreachable); + try scope.generated.append(p.allocator, name.ref orelse unreachable); return name; } - pub fn newSymbol(p: *P, kind: Symbol.Kind, identifier: string) !js_ast.Ref { + pub fn newSymbol(p: *P, kind: Symbol.Kind, identifier: string) !Ref { const inner_index = Ref.toInt(p.symbols.items.len); - try p.symbols.append(Symbol{ + try p.symbols.append(p.allocator, Symbol{ .kind = kind, .original_name = identifier, .link = null, }); if (is_typescript_enabled) { - try p.ts_use_counts.append(0); + try p.ts_use_counts.append(p.allocator, 0); } - return js_ast.Ref{ + return Ref{ .source_index = Ref.toInt(p.source.index), .inner_index = inner_index, }; @@ -5313,7 +5317,7 @@ pub fn NewParser( return stmt; } - if (stmt.getFunction().func.name) |name| { + if (stmt.data.s_function.func.name) |name| { defaultName = js_ast.LocRef{ .loc = defaultLoc, .ref = name.ref }; } else { defaultName = try p.createDefaultName(defaultLoc); @@ -5377,7 +5381,7 @@ pub fn NewParser( // Handle the default export of an abstract class in TypeScript if (is_typescript_enabled and is_identifier and (p.lexer.token == .t_class or opts.ts_decorators != null) and strings.eqlComptime(name, "abstract")) { switch (expr.data) { - .e_identifier => |ident| { + .e_identifier => { var stmtOpts = ParseStatementOptions{ .ts_decorators = opts.ts_decorators, .is_name_optional = true, @@ -5461,7 +5465,7 @@ pub fn NewParser( } try p.lexer.next(); - var namespace_ref: js_ast.Ref = js_ast.Ref.None; + var namespace_ref: Ref = Ref.None; var alias: ?js_ast.G.ExportStarAlias = null; var path: ParsedPath = undefined; @@ -5694,8 +5698,16 @@ pub fn NewParser( try p.lexer.next(); try p.lexer.expect(.t_open_paren); const test_ = try p.parseExpr(.lowest); - const body_loc = p.lexer.loc(); try p.lexer.expect(.t_close_paren); + + const body_loc = p.lexer.loc(); + _ = try p.pushScopeForParsePass(.block, body_loc); + defer p.popScope(); + + var stmtOpts = ParseStatementOptions{}; + const body = try p.parseStmt(&stmtOpts); + + return p.s(S.With{ .body = body, .body_loc = body_loc, .value = test_ }, loc); }, .t_switch => { try p.lexer.next(); @@ -5709,12 +5721,12 @@ pub fn NewParser( defer p.popScope(); try p.lexer.expect(.t_open_brace); - var cases = List(js_ast.Case).init(p.allocator); + var cases = ListManaged(js_ast.Case).init(p.allocator); var foundDefault = false; var stmtOpts = ParseStatementOptions{ .lexical_decl = .allow_all }; var value: ?js_ast.Expr = null; while (p.lexer.token != .t_close_brace) { - var body = List(js_ast.Stmt).init(p.allocator); + var body = StmtList.init(p.allocator); value = null; if (p.lexer.token == .t_default) { if (foundDefault) { @@ -5910,7 +5922,7 @@ pub fn NewParser( } if (isForAwait and !p.lexer.isContextualKeyword("of")) { - if (init_) |init_stmt| { + if (init_ != null) { try p.lexer.expectedString("\"of\""); } else { try p.lexer.unexpected(); @@ -5942,7 +5954,7 @@ pub fn NewParser( if (init_) |init_stmt| { switch (init_stmt.data) { .s_local => { - if (init_stmt.getLocal().kind == .k_const) { + if (init_stmt.data.s_local.kind == .k_const) { try p.requireInitializers(decls); } }, @@ -6176,7 +6188,7 @@ pub fn NewParser( const name = try path_name.nonUniqueNameString(p.allocator); stmt.namespace_ref = try p.newSymbol(.other, name); var scope: *Scope = p.current_scope; - try scope.generated.append(stmt.namespace_ref); + try scope.generated.append(p.allocator, stmt.namespace_ref); } var item_refs = ImportItemForNamespaceMap.init(p.allocator); @@ -6191,7 +6203,7 @@ pub fn NewParser( if (stmt.default_name) |*name_loc| { const name = p.loadNameFromRef(name_loc.ref orelse unreachable); const ref = try p.declareSymbol(.import, name_loc.loc, name); - try p.is_import_item.put(ref, true); + try p.is_import_item.put(p.allocator, ref, .{}); name_loc.ref = ref; if (comptime ParsePassSymbolUsageType != void) { if (!is_macro) { @@ -6229,7 +6241,7 @@ pub fn NewParser( const ref = try p.declareSymbol(.import, item.name.loc, name); p.checkForNonBMPCodePoint(item.alias_loc, item.alias); - try p.is_import_item.put(ref, true); + try p.is_import_item.put(p.allocator, ref, .{}); item.name.ref = ref; item_refs.putAssumeCapacity(item.alias, LocRef{ .loc = item.name.loc, .ref = ref }); @@ -6277,7 +6289,7 @@ pub fn NewParser( } // Track the items for this namespace - try p.import_items_for_namespace.put(stmt.namespace_ref, item_refs); + try p.import_items_for_namespace.put(p.allocator, stmt.namespace_ref, item_refs); return p.s(stmt, loc); }, @@ -6483,7 +6495,7 @@ pub fn NewParser( var decls: []G.Decl = &([_]G.Decl{}); switch (stmt.data) { .s_local => |local| { - var _decls = try List(G.Decl).initCapacity(p.allocator, local.decls.len); + var _decls = try ListManaged(G.Decl).initCapacity(p.allocator, local.decls.len); for (local.decls) |decl| { try extractDeclsForBinding(decl.binding, &_decls); } @@ -6557,7 +6569,7 @@ pub fn NewParser( try p.lexer.expect(.t_identifier); if (opts.is_module_scope) { - p.local_type_names.put(name, true) catch unreachable; + p.local_type_names.put(p.allocator, name, true) catch unreachable; } try p.skipTypeScriptTypeParameters(); @@ -6578,7 +6590,7 @@ pub fn NewParser( const old_has_non_local_export_declare_inside_namespace = p.has_non_local_export_declare_inside_namespace; p.has_non_local_export_declare_inside_namespace = false; - var stmts: List(Stmt) = List(Stmt).init(p.allocator); + var stmts: ListManaged(Stmt) = ListManaged(Stmt).init(p.allocator); if (p.lexer.token == .t_dot) { const dot_loc = p.lexer.loc(); @@ -6598,7 +6610,7 @@ pub fn NewParser( .is_namespace_scope = true, .is_typescript_declare = opts.is_typescript_declare, }; - stmts = List(Stmt).fromOwnedSlice(p.allocator, try p.parseStmtsUpTo(.t_close_brace, &_opts)); + stmts = ListManaged(Stmt).fromOwnedSlice(p.allocator, try p.parseStmtsUpTo(.t_close_brace, &_opts)); try p.lexer.next(); } const has_non_local_export_declare_inside_namespace = p.has_non_local_export_declare_inside_namespace; @@ -6634,7 +6646,7 @@ pub fn NewParser( if ((stmts.items.len == import_equal_count and !has_non_local_export_declare_inside_namespace) or opts.is_typescript_declare) { p.popAndDiscardScope(scope_index); if (opts.is_module_scope) { - p.local_type_names.put(name_text, true) catch unreachable; + p.local_type_names.put(p.allocator, name_text, true) catch unreachable; } return p.s(S.TypeScript{}, loc); } @@ -6662,7 +6674,7 @@ pub fn NewParser( // run the renamer. For external-facing things the renamer will avoid // collisions automatically so this isn't important for correctness. arg_ref = p.newSymbol(.hoisted, strings.cat(p.allocator, "_", name_text) catch unreachable) catch unreachable; - p.current_scope.generated.append(arg_ref.?) catch unreachable; + p.current_scope.generated.append(p.allocator, arg_ref.?) catch unreachable; } else { arg_ref = p.newSymbol(.hoisted, name_text) catch unreachable; } @@ -6684,7 +6696,7 @@ pub fn NewParser( try p.lexer.expect(.t_identifier); if (opts.is_module_scope) { - p.local_type_names.put(name, true) catch unreachable; + p.local_type_names.put(p.allocator, name, true) catch unreachable; } try p.skipTypeScriptTypeParameters(); @@ -6773,7 +6785,7 @@ pub fn NewParser( return p.lexer.string_literal_slice; } else if (p.lexer.utf16ToStringWithValidation(p.lexer.string_literal)) |alias| { return alias; - } else |err| { + } else |_| { const r = p.source.rangeOfString(loc); // TODO: improve error message try p.log.addRangeErrorFmt(p.source, r, p.allocator, "Invalid {s} alias because it contains an unpaired Unicode surrogate (like emoji)", .{kind}); @@ -6794,7 +6806,7 @@ pub fn NewParser( fn parseImportClause( p: *P, ) !ImportClause { - var items = List(js_ast.ClauseItem).init(p.allocator); + var items = ListManaged(js_ast.ClauseItem).init(p.allocator); try p.lexer.expect(.t_open_brace); var is_single_line = !p.lexer.has_newline_before; @@ -6948,7 +6960,7 @@ pub fn NewParser( .t_open_bracket => { try p.lexer.next(); var is_single_line = !p.lexer.has_newline_before; - var items = List(js_ast.ArrayBinding).init(p.allocator); + var items = ListManaged(js_ast.ArrayBinding).init(p.allocator); var has_spread = false; // "in" expressions are allowed @@ -7019,7 +7031,7 @@ pub fn NewParser( // p.markSyntaxFeature(compat.Destructuring, p.lexer.Range()) try p.lexer.next(); var is_single_line = false; - var properties = List(js_ast.B.Property).init(p.allocator); + var properties = ListManaged(js_ast.B.Property).init(p.allocator); // "in" expressions are allowed var old_allow_in = p.allow_in; @@ -7162,7 +7174,7 @@ pub fn NewParser( } fn parseAndDeclareDecls(p: *P, kind: Symbol.Kind, opts: *ParseStatementOptions) anyerror![]G.Decl { - var decls = List(G.Decl).init(p.allocator); + var decls = ListManaged(G.Decl).init(p.allocator); while (true) { // Forbid "let let" and "const let" but not "var let" @@ -7189,7 +7201,7 @@ pub fn NewParser( } // If we end with a .t_close_paren, that's a bug. It means we aren't following the last parenthese - if (isDebug) { + if (Environment.isDebug) { std.debug.assert(p.lexer.token != .t_close_paren); } } @@ -7299,7 +7311,7 @@ pub fn NewParser( // run the renamer. For external-facing things the renamer will avoid // collisions automatically so this isn't important for correctness. arg_ref = p.newSymbol(.hoisted, strings.cat(p.allocator, "_", name_text) catch unreachable) catch unreachable; - p.current_scope.generated.append(arg_ref) catch unreachable; + p.current_scope.generated.append(p.allocator, arg_ref) catch unreachable; } else { arg_ref = p.declareSymbol(.hoisted, name_loc, name_text) catch unreachable; } @@ -7326,7 +7338,7 @@ pub fn NewParser( } fn parseExportClause(p: *P) !ExportClauseResult { - var items = List(js_ast.ClauseItem).initCapacity(p.allocator, 1) catch unreachable; + var items = ListManaged(js_ast.ClauseItem).initCapacity(p.allocator, 1) catch unreachable; try p.lexer.expect(.t_open_brace); var is_single_line = !p.lexer.has_newline_before; var first_non_identifier_loc = logger.Loc{ .start = 0 }; @@ -7419,7 +7431,7 @@ pub fn NewParser( } // TODO: - pub fn checkForNonBMPCodePoint(p: *P, loc: logger.Loc, name: string) void {} + pub fn checkForNonBMPCodePoint(_: *P, _: logger.Loc, _: string) void {} fn parseStmtsUpTo(p: *P, eend: js_lexer.T, _opts: *ParseStatementOptions) ![]Stmt { var opts = _opts.*; @@ -7497,7 +7509,7 @@ pub fn NewParser( if (needsCheck and returnWithoutSemicolonStart != -1) { switch (stmt.data) { - .s_expr => |exp| { + .s_expr => { try p.log.addWarning( p.source, logger.Loc{ .start = returnWithoutSemicolonStart + 6 }, @@ -7516,43 +7528,24 @@ pub fn NewParser( } fn markStrictModeFeature(p: *P, feature: StrictModeFeature, r: logger.Range, detail: string) !void { - var text: string = undefined; - var can_be_transformed = false; - switch (feature) { - .with_statement => { - text = "With statements"; - }, - .delete_bare_name => { - text = "\"delete\" of a bare identifier"; - }, - .for_in_var_init => { - text = "Variable initializers within for-in loops"; - can_be_transformed = true; - }, - .eval_or_arguments => { - text = try std.fmt.allocPrint(p.allocator, "Declarations with the name {s}", .{detail}); - }, - .reserved_word => { - text = try std.fmt.allocPrint(p.allocator, "{s} is a reserved word and", .{detail}); - }, - .legacy_octal_literal => { - text = "Legacy octal literals"; - }, - .legacy_octal_escape => { - text = "Legacy octal escape sequences"; - }, - .if_else_function_stmt => { - text = "Function declarations inside if statements"; - }, + const can_be_transformed = feature == StrictModeFeature.for_in_var_init; + const text = switch (feature) { + .with_statement => "With statements", + .delete_bare_name => "\"delete\" of a bare identifier", + .for_in_var_init => "Variable initializers within for-in loops", + .eval_or_arguments => try std.fmt.allocPrint(p.allocator, "Declarations with the name {s}", .{detail}), + .reserved_word => try std.fmt.allocPrint(p.allocator, "{s} is a reserved word and", .{detail}), + .legacy_octal_literal => "Legacy octal literals", + .legacy_octal_escape => "Legacy octal escape sequences", + .if_else_function_stmt => "Function declarations inside if statements", // else => { // text = "This feature"; // }, - } + }; var scope = p.current_scope; if (p.isStrictMode()) { var why: string = ""; - var notes: []logger.Data = &[_]logger.Data{}; var where: logger.Range = logger.Range.None; switch (scope.strict_mode) { .implicit_strict_mode_import => { @@ -7576,15 +7569,15 @@ pub fn NewParser( try p.log.addRangeErrorWithNotes(p.source, r, try std.fmt.allocPrint(p.allocator, "{s} cannot be used in strict mode", .{text}), &([_]logger.Data{logger.rangeData(p.source, where, why)})); } else if (!can_be_transformed and p.isStrictModeOutputFormat()) { - try p.log.addRangeError(p.source, r, try std.fmt.allocPrint(p.allocator, "{s} cannot be used with \"esm\" due to strict mode", .{text})); + try p.log.addRangeError(p.source, r, try std.fmt.allocPrint(p.allocator, "{s} cannot be used with esm due to strict mode", .{text})); } } - pub fn isStrictMode(p: *P) bool { + pub inline fn isStrictMode(p: *P) bool { return p.current_scope.strict_mode != .sloppy_mode; } - pub inline fn isStrictModeOutputFormat(p: *P) bool { + pub inline fn isStrictModeOutputFormat(_: *P) bool { return true; } @@ -7620,7 +7613,7 @@ pub fn NewParser( const ref = try p.newSymbol(kind, name); if (member == null) { - try p.module_scope.members.putWithHash(name, name_hash, Scope.Member{ .ref = ref, .loc = logger.Loc.Empty }); + try p.module_scope.members.putWithHash(p.allocator, name, name_hash, Scope.Member{ .ref = ref, .loc = logger.Loc.Empty }); return ref; } @@ -7628,7 +7621,7 @@ pub fn NewParser( // this module will be unable to reference this symbol. However, we must // still add the symbol to the scope so it gets minified (automatically- // generated code may still reference the symbol). - try p.module_scope.generated.append(ref); + try p.module_scope.generated.append(p.allocator, ref); return ref; } @@ -7660,13 +7653,13 @@ pub fn NewParser( var ref = try p.newSymbol(kind, name); const scope = p.current_scope; - var entry = try scope.members.getOrPut(name); + var entry = try scope.members.getOrPut(p.allocator, name); if (entry.found_existing) { const existing = entry.entry.value; var symbol: *Symbol = &p.symbols.items[@intCast(usize, existing.ref.inner_index)]; if (comptime !is_generated) { - switch (p.canMergeSymbols(scope, symbol.kind, kind)) { + switch (scope.canMergeSymbols(symbol.kind, kind, is_typescript_enabled)) { .forbidden => { const r = js_lexer.rangeOfIdentifier(p.source, loc); var notes = try p.allocator.alloc(logger.Data, 1); @@ -7695,7 +7688,7 @@ pub fn NewParser( } else { // Ensure that EImportIdentifier is created for the symbol in handleIdentifier if (symbol.kind == .import and kind != .import) { - try p.is_import_item.put(ref, true); + try p.is_import_item.put(p.allocator, ref, .{}); } p.symbols.items[ref.inner_index].link = existing.ref; @@ -7704,7 +7697,7 @@ pub fn NewParser( entry.entry.value = js_ast.Scope.Member{ .ref = ref, .loc = loc }; if (comptime is_generated) { - try p.module_scope.generated.append(ref); + try p.module_scope.generated.append(p.allocator, ref); } return ref; } @@ -7745,29 +7738,26 @@ pub fn NewParser( // The name is optional if (p.lexer.token == .t_identifier) { + const text = p.lexer.identifier; + // Don't declare the name "arguments" since it's shadowed and inaccessible - var _name = js_ast.LocRef{ + name = js_ast.LocRef{ .loc = p.lexer.loc(), - .ref = null, + .ref = if (text.len > 0 and !strings.eqlComptime(text, "arguments")) + try p.declareSymbol(.hoisted_function, p.lexer.loc(), text) + else + try p.newSymbol(.hoisted_function, text), }; - const text = p.lexer.identifier; - if (text.len > 0 and !strings.eqlComptime(text, "arguments")) { - _name.ref = try p.declareSymbol(.hoisted_function, _name.loc, text); - } else { - _name.ref = try p.newSymbol(.hoisted_function, text); - } - - name = _name; try p.lexer.next(); } // Even anonymous functions can have TypeScript type parameters - if (is_typescript_enabled) { + if (comptime is_typescript_enabled) { try p.skipTypeScriptTypeParameters(); } - var func = try p.parseFn(name, FnOrArrowDataParse{ + const func = try p.parseFn(name, FnOrArrowDataParse{ .async_range = async_range, .allow_await = if (is_async) .allow_expr else .allow_ident, .allow_yield = if (is_generator) .allow_expr else .allow_ident, @@ -7850,7 +7840,7 @@ pub fn NewParser( }, .b_array => |bind| { - for (bind.items) |item, i| { + for (bind.items) |_, i| { p.declareBinding(kind, &bind.items[i].binding, opts) catch unreachable; } }, @@ -7883,7 +7873,7 @@ pub fn NewParser( return self.mm(@TypeOf(kind), kind); } - pub fn storeNameInRef(p: *P, name: string) !js_ast.Ref { + pub fn storeNameInRef(p: *P, name: string) !Ref { if (comptime ParsePassSymbolUsageType != void) { if (p.parse_pass_symbol_uses.getPtr(name)) |res| { res.used = true; @@ -7893,19 +7883,19 @@ pub fn NewParser( if (@ptrToInt(p.source.contents.ptr) <= @ptrToInt(name.ptr) and (@ptrToInt(name.ptr) + name.len) <= (@ptrToInt(p.source.contents.ptr) + p.source.contents.len)) { const start = Ref.toInt(@ptrToInt(name.ptr) - @ptrToInt(p.source.contents.ptr)); const end = Ref.toInt(name.len); - return js_ast.Ref{ .source_index = start, .inner_index = end, .is_source_contents_slice = true }; + return Ref{ .source_index = start, .inner_index = end, .is_source_contents_slice = true }; } else if (p.allocated_names.capacity > 0) { const inner_index = Ref.toInt(p.allocated_names.items.len); - try p.allocated_names.append(name); - return js_ast.Ref{ .source_index = std.math.maxInt(Ref.Int), .inner_index = inner_index }; + try p.allocated_names.append(p.allocator, name); + return Ref{ .source_index = std.math.maxInt(Ref.Int), .inner_index = inner_index }; } else { p.allocated_names = try @TypeOf(p.allocated_names).initCapacity(p.allocator, 1); p.allocated_names.appendAssumeCapacity(name); - return js_ast.Ref{ .source_index = std.math.maxInt(Ref.Int), .inner_index = 0 }; + return Ref{ .source_index = std.math.maxInt(Ref.Int), .inner_index = 0 }; } } - pub fn loadNameFromRef(p: *P, ref: js_ast.Ref) string { + pub fn loadNameFromRef(p: *P, ref: Ref) string { if (ref.is_source_contents_slice) { return p.source.contents[ref.source_index .. ref.source_index + ref.inner_index]; } else if (ref.source_index == std.math.maxInt(Ref.Int)) { @@ -8034,9 +8024,8 @@ pub fn NewParser( pub fn skipTypeScriptArrowArgsWithBacktracking(p: *P) anyerror!void { try p.skipTypescriptFnArgs(); - p.lexer.expect(.t_equals_greater_than) catch |err| { + p.lexer.expect(.t_equals_greater_than) catch return error.Backtrack; - }; } pub fn skipTypeScriptTypeArgumentsWithBacktracking(p: *P) anyerror!void { @@ -8050,9 +8039,9 @@ pub fn NewParser( } pub fn skipTypeScriptArrowReturnTypeWithBacktracking(p: *P) anyerror!void { - p.lexer.expect(.t_colon) catch |err| { + p.lexer.expect(.t_colon) catch return error.Backtrack; - }; + try p.skipTypescriptReturnType(); // Check the token after this and backtrack if it's the wrong one if (p.lexer.token != .t_equals_greater_than) { @@ -8189,7 +8178,7 @@ pub fn NewParser( p.current_scope = current_scope.parent orelse p.panic("Internal error: attempted to call popScope() on the topmost scope", .{}); } - pub fn markExprAsParenthesized(p: *P, expr: *Expr) void { + pub fn markExprAsParenthesized(_: *P, expr: *Expr) void { switch (expr.data) { .e_array => |ex| { ex.is_parenthesized = true; @@ -8270,7 +8259,7 @@ pub fn NewParser( // Handle index signatures if (is_typescript_enabled and p.lexer.token == .t_colon and wasIdentifier and opts.is_class) { switch (expr.data) { - .e_identifier => |ident| { + .e_identifier => { try p.lexer.next(); try p.skipTypeScriptType(.lowest); try p.lexer.expect(.t_close_bracket); @@ -8313,15 +8302,10 @@ pub fn NewParser( // Support contextual keywords if (kind == .normal and !opts.is_generator) { // Does the following token look like a key? - var couldBeModifierKeyword = p.lexer.isIdentifierOrKeyword(); - if (!couldBeModifierKeyword) { - switch (p.lexer.token) { - .t_open_bracket, .t_numeric_literal, .t_string_literal, .t_asterisk, .t_private_identifier => { - couldBeModifierKeyword = true; - }, - else => {}, - } - } + const couldBeModifierKeyword = p.lexer.isIdentifierOrKeyword() or switch (p.lexer.token) { + .t_open_bracket, .t_numeric_literal, .t_string_literal, .t_asterisk, .t_private_identifier => true, + else => false, + }; // If so, check for a modifier keyword if (couldBeModifierKeyword) { @@ -8370,9 +8354,21 @@ pub fn NewParser( key = p.e(E.String{ .utf8 = name }, name_range.loc); // Parse a shorthand property - const isShorthandProperty = (!opts.is_class and kind == .normal and p.lexer.token != .t_colon and p.lexer.token != .t_open_paren and p.lexer.token != .t_less_than and !opts.is_generator and !opts.is_async and !js_lexer.Keywords.has(name)); + const isShorthandProperty = (!opts.is_class and + kind == .normal and + p.lexer.token != .t_colon and + p.lexer.token != .t_open_paren and + p.lexer.token != .t_less_than and + !opts.is_generator and + !opts.is_async and + !js_lexer.Keywords.has(name)); + if (isShorthandProperty) { - if ((p.fn_or_arrow_data_parse.allow_await != .allow_ident and strings.eqlComptime(name, "await")) or (p.fn_or_arrow_data_parse.allow_yield != .allow_ident and strings.eqlComptime(name, "yield"))) { + if ((p.fn_or_arrow_data_parse.allow_await != .allow_ident and + strings.eqlComptime(name, "await")) or + (p.fn_or_arrow_data_parse.allow_yield != .allow_ident and + strings.eqlComptime(name, "yield"))) + { // TODO: add fmt to addRangeError p.log.addRangeError(p.source, name_range, "Cannot use \"yield\" or \"await\" here.") catch unreachable; } @@ -8660,7 +8656,7 @@ pub fn NewParser( var body_loc = p.lexer.loc(); try p.lexer.expect(T.t_open_brace); - var properties = List(G.Property).init(p.allocator); + var properties = ListManaged(G.Property).init(p.allocator); // Allow "in" and private fields inside class bodies const old_allow_in = p.allow_in; @@ -8750,8 +8746,8 @@ pub fn NewParser( return true; } - pub fn parseTemplateParts(p: *P, include_raw: bool) ![]E.TemplatePart { - var parts = List(E.TemplatePart).initCapacity(p.allocator, 1) catch unreachable; + pub fn parseTemplateParts(p: *P, _: bool) ![]E.TemplatePart { + var parts = ListManaged(E.TemplatePart).initCapacity(p.allocator, 1) catch unreachable; // Allow "in" inside template literals var oldAllowIn = p.allow_in; p.allow_in = true; @@ -8774,7 +8770,7 @@ pub fn NewParser( try p.lexer.next(); break :parseTemplatePart; } - std.debug.assert(p.lexer.token != .t_end_of_file); + if (comptime Environment.allow_assert) std.debug.assert(p.lexer.token != .t_end_of_file); } p.allow_in = oldAllowIn; @@ -8799,7 +8795,7 @@ pub fn NewParser( p.allow_in = true; defer p.allow_in = old_allow_in; - var args = List(Expr).init(p.allocator); + var args = ListManaged(Expr).init(p.allocator); try p.lexer.expect(.t_open_paren); while (p.lexer.token != .t_close_paren) { @@ -8828,9 +8824,7 @@ pub fn NewParser( return _parseSuffix(p, left, level, errors orelse &DeferredErrors.None, flags); } pub fn _parseSuffix(p: *P, _left: Expr, level: Level, errors: *DeferredErrors, flags: Expr.EFlags) anyerror!Expr { - var expr: Expr = Expr{ .loc = logger.Loc.Empty, .data = Prefill.Data.EMissing }; var left = _left; - var loc = p.lexer.loc(); var optional_chain: ?js_ast.OptionalChain = null; while (true) { if (p.lexer.loc().start == p.after_arrow_body_loc.start) { @@ -9604,6 +9598,7 @@ pub fn NewParser( import.import_record_index = record_id; p.is_import_item.ensureCapacity( + p.allocator, @intCast(u32, p.is_import_item.count() + import.items.len), ) catch unreachable; @@ -9618,7 +9613,7 @@ pub fn NewParser( const name_ref = p.declareSymbol(.import, this.loc, clause.original_name) catch unreachable; clause.name = LocRef{ .loc = this.loc, .ref = name_ref }; - p.is_import_item.put(name_ref, true) catch unreachable; + p.is_import_item.putAssumeCapacity(name_ref, .{}); p.macro.imports.putAssumeCapacity(js_ast.Macro.JSNode.SymbolMap.generateImportHash(import_hash_name, import_data.path), name_ref); @@ -9825,7 +9820,7 @@ pub fn NewParser( return try p.parseStringLiteral(); }, .t_template_head => { - var head = p.lexer.toEString(); + const head = p.lexer.toEString(); const parts = try p.parseTemplateParts(false); @@ -9978,12 +9973,12 @@ pub fn NewParser( // Special-case the weird "new.target" expression here if (p.lexer.token == .t_dot) { try p.lexer.next(); + if (p.lexer.token != .t_identifier or !strings.eqlComptime(p.lexer.raw(), "target")) { try p.lexer.unexpected(); return error.SyntaxError; } - const r = logger.Range{ .loc = loc, .len = p.lexer.range().end().start - loc.start }; try p.lexer.next(); return p.e(E.NewTarget{}, loc); } @@ -10015,7 +10010,7 @@ pub fn NewParser( .t_open_bracket => { try p.lexer.next(); var is_single_line = !p.lexer.has_newline_before; - var items = List(Expr).init(p.allocator); + var items = ListManaged(Expr).init(p.allocator); var self_errors = DeferredErrors{}; var comma_after_spread = logger.Loc{}; @@ -10086,7 +10081,7 @@ pub fn NewParser( .t_open_brace => { try p.lexer.next(); var is_single_line = !p.lexer.has_newline_before; - var properties = List(G.Property).init(p.allocator); + var properties = ListManaged(G.Property).init(p.allocator); var self_errors = DeferredErrors{}; var comma_after_spread = logger.Loc{}; @@ -10270,7 +10265,6 @@ pub fn NewParser( p.es6_import_keyword = js_lexer.rangeOfIdentifier(p.source, loc); try p.lexer.next(); if (p.lexer.isContextualKeyword("meta")) { - const r = p.lexer.range(); try p.lexer.next(); p.has_import_meta = true; return p.e(E.ImportMeta{}, loc); @@ -10435,7 +10429,7 @@ pub fn NewParser( if (@as(JSXTag.TagType, tag.data) == .tag) { start_tag = tag.data.tag; var spread_loc: logger.Loc = logger.Loc.Empty; - var props = List(G.Property).init(p.allocator); + var props = ListManaged(G.Property).init(p.allocator); var key_prop_i: i32 = -1; var spread_prop_i: i32 = -1; var i: i32 = 0; @@ -10463,7 +10457,7 @@ pub fn NewParser( continue; } - var prop_name = p.e(E.String{ .utf8 = prop_name_literal }, key_range.loc); + const prop_name = p.e(E.String{ .utf8 = prop_name_literal }, key_range.loc); // Parse the value var value: Expr = undefined; @@ -10540,7 +10534,7 @@ pub fn NewParser( // Use ExpectJSXElementChild() so we parse child strings try p.lexer.expectJSXElementChild(.t_greater_than); - var children = List(Expr).init(p.allocator); + var children = ListManaged(Expr).init(p.allocator); while (true) { switch (p.lexer.token) { @@ -10636,21 +10630,24 @@ pub fn NewParser( return try p._parsePrefix(level, errors orelse &DeferredErrors.None, flags); } - fn appendPart(p: *P, parts: *List(js_ast.Part), stmts: []Stmt) !void { - p.symbol_uses = SymbolUseMap.init(p.allocator); - p.declared_symbols.deinit(); - p.declared_symbols = @TypeOf(p.declared_symbols).init(p.allocator); - p.import_records_for_current_part.deinit(); - p.import_records_for_current_part = @TypeOf(p.import_records_for_current_part).init(p.allocator); - p.scopes_for_current_part.deinit(); - p.scopes_for_current_part = @TypeOf(p.scopes_for_current_part).init(p.allocator); + fn appendPart(p: *P, parts: *ListManaged(js_ast.Part), stmts: []Stmt) !void { + p.symbol_uses = SymbolUseMap{}; + const allocator = p.allocator; + p.declared_symbols.deinit( + allocator, + ); + p.declared_symbols = @TypeOf(p.declared_symbols){}; + p.import_records_for_current_part.deinit(allocator); + p.import_records_for_current_part = @TypeOf(p.import_records_for_current_part){}; + p.scopes_for_current_part.deinit(allocator); + p.scopes_for_current_part = @TypeOf(p.scopes_for_current_part){}; var opts = PrependTempRefsOpts{}; - var partStmts = List(Stmt).fromOwnedSlice(p.allocator, stmts); + var partStmts = ListManaged(Stmt).fromOwnedSlice(allocator, stmts); try p.visitStmtsAndPrependTempRefs(&partStmts, &opts); // Insert any relocated variable statements now if (p.relocated_top_level_vars.items.len > 0) { - var already_declared = RefBoolMap.init(p.allocator); + var already_declared = RefMap{}; for (p.relocated_top_level_vars.items) |*local| { // Follow links because "var" declarations may be merged due to hoisting while (local.ref != null) { @@ -10662,17 +10659,17 @@ pub fn NewParser( } const ref = local.ref orelse continue; if (!already_declared.contains(ref)) { - try already_declared.put(ref, true); + try already_declared.put(allocator, ref, .{}); - const decls = try p.allocator.alloc(G.Decl, 1); + const decls = try allocator.alloc(G.Decl, 1); decls[0] = Decl{ .binding = p.b(B.Identifier{ .ref = ref }, local.loc), }; try partStmts.append(p.s(S.Local{ .decls = decls }, local.loc)); } } - p.relocated_top_level_vars.deinit(); - p.relocated_top_level_vars = @TypeOf(p.relocated_top_level_vars).init(p.allocator); + p.relocated_top_level_vars.deinit(allocator); + p.relocated_top_level_vars = @TypeOf(p.relocated_top_level_vars){}; // Follow links because "var" declarations may be merged due to hoisting @@ -10683,16 +10680,19 @@ pub fn NewParser( if (partStmts.items.len > 0) { const _stmts = partStmts.toOwnedSlice(); - var part = js_ast.Part{ + + try parts.append(js_ast.Part{ .stmts = _stmts, .symbol_uses = p.symbol_uses, - .declared_symbols = p.declared_symbols.toOwnedSlice(), - .import_record_indices = p.import_records_for_current_part.toOwnedSlice(), - .scopes = p.scopes_for_current_part.toOwnedSlice(), + .declared_symbols = p.declared_symbols.toOwnedSlice( + p.allocator, + ), + .import_record_indices = p.import_records_for_current_part.toOwnedSlice( + p.allocator, + ), + .scopes = p.scopes_for_current_part.toOwnedSlice(p.allocator), .can_be_removed_if_unused = p.stmtsCanBeRemovedIfUnused(_stmts), - }; - - try parts.append(part); + }); } } @@ -10744,7 +10744,7 @@ pub fn NewParser( // 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_import => {}, .s_class => |st| { if (!p.classCanBeRemovedIfUnused(&st.class)) { return false; @@ -10808,15 +10808,13 @@ pub fn NewParser( return true; } - fn visitStmtsAndPrependTempRefs(p: *P, stmts: *List(Stmt), opts: *PrependTempRefsOpts) !void { + fn visitStmtsAndPrependTempRefs(p: *P, stmts: *ListManaged(Stmt), opts: *PrependTempRefsOpts) !void { if (only_scan_imports_and_do_not_visit) { @compileError("only_scan_imports_and_do_not_visit must not run this."); } - var old_temp_refs = p.temp_refs_to_declare; - var old_temp_ref_count = p.temp_ref_count; - p.temp_refs_to_declare.deinit(); - p.temp_refs_to_declare = @TypeOf(p.temp_refs_to_declare).init(p.allocator); + p.temp_refs_to_declare.deinit(p.allocator); + p.temp_refs_to_declare = @TypeOf(p.temp_refs_to_declare){}; p.temp_ref_count = 0; try p.visitStmts(stmts, opts.kind); @@ -10825,7 +10823,7 @@ pub fn NewParser( if (opts.fn_body_loc != null) { // Capture "this" if (p.fn_only_data_visit.this_capture_ref) |ref| { - try p.temp_refs_to_declare.append(TempRef{ + try p.temp_refs_to_declare.append(p.allocator, TempRef{ .ref = ref, .value = p.e(E.This{}, opts.fn_body_loc orelse p.panic("Internal error: Expected opts.fn_body_loc to exist", .{})), }); @@ -10834,7 +10832,7 @@ pub fn NewParser( } fn recordDeclaredSymbol(p: *P, ref: Ref) !void { - try p.declared_symbols.append(js_ast.DeclaredSymbol{ + try p.declared_symbols.append(p.allocator, js_ast.DeclaredSymbol{ .ref = ref, .is_top_level = p.current_scope == p.module_scope, }); @@ -10883,7 +10881,7 @@ pub fn NewParser( ); p.pushScopeForVisitPass(.function_body, body.loc) catch unreachable; - var stmts = List(Stmt).fromOwnedSlice(p.allocator, body.stmts); + var stmts = ListManaged(Stmt).fromOwnedSlice(p.allocator, body.stmts); var temp_opts = PrependTempRefsOpts{ .kind = StmtsKind.fn_body, .fn_body_loc = body.loc }; p.visitStmtsAndPrependTempRefs(&stmts, &temp_opts) catch unreachable; func.body = G.FnBody{ .stmts = stmts.toOwnedSlice(), .loc = body.loc }; @@ -10930,12 +10928,12 @@ pub fn NewParser( // Output.print("\nVisit: {s} - {d}\n", .{ @tagName(expr.data), expr.loc.start }); switch (expr.data) { .e_null, .e_super, .e_boolean, .e_big_int, .e_reg_exp, .e_new_target, .e_undefined => {}, - .e_string => |e_| { + .e_string => { // If you're using this, you're probably not using 0-prefixed legacy octal notation // if e.LegacyOctalLoc.Start > 0 { }, - .e_number => |e_| { + .e_number => { // idc about legacy octal loc }, @@ -11125,7 +11123,7 @@ pub fn NewParser( const include_filename = FeatureFlags.include_filename_in_jsx and p.options.jsx.development; const args = p.allocator.alloc(Expr, if (p.options.jsx.development) @as(usize, 6) else @as(usize, 4)) catch unreachable; args[0] = tag; - var props = List(G.Property).fromOwnedSlice(p.allocator, e_.properties); + var props = ListManaged(G.Property).fromOwnedSlice(p.allocator, e_.properties); // arguments needs to be like // { // ...props, @@ -11261,7 +11259,6 @@ pub fn NewParser( if (p.macro.refs.get(ref)) |import_record_id| { const name = p.symbols.items[ref.inner_index].original_name; const record = &p.import_records.items[import_record_id]; - const prepend_offset = p.macro.prepend_stmts.items.len; // We must visit it to convert inline_identifiers and record usage const macro_result = (p.options.macro_context.call( record.path.text, @@ -11332,7 +11329,7 @@ pub fn NewParser( } const is_call_target = @as(Expr.Tag, p.call_target) == .e_binary and expr.data.e_binary == p.call_target.e_binary; - const is_stmt_expr = @as(Expr.Tag, p.stmt_expr_value) == .e_binary and expr.data.e_binary == p.stmt_expr_value.e_binary; + // const is_stmt_expr = @as(Expr.Tag, p.stmt_expr_value) == .e_binary and expr.data.e_binary == p.stmt_expr_value.e_binary; const was_anonymous_named_expr = p.isAnonymousNamedExpr(e_.right); if (comptime jsx_transform_type == .macro) { @@ -12007,7 +12004,6 @@ pub fn NewParser( } } - var has_spread = false; for (e_.items) |*item| { switch (item.data) { .e_missing => {}, @@ -12130,7 +12126,7 @@ pub fn NewParser( // const could_be_require_resolve = (e_.args.len == 1 and @as( // Expr.Tag, // e_.target.data, - // ) == .e_dot and e_.target.getDot().optional_chain == null and strings.eql( + // ) == .e_dot and e_.target.data.e_dot.optional_chain == null and strings.eql( // e_.target.dat.e_dot.name, // "resolve", // )); @@ -12241,7 +12237,7 @@ pub fn NewParser( }); p.pushScopeForVisitPass(.function_body, e_.body.loc) catch unreachable; - var stmts_list = List(Stmt).fromOwnedSlice(p.allocator, dupe); + var stmts_list = ListManaged(Stmt).fromOwnedSlice(p.allocator, dupe); var temp_opts = PrependTempRefsOpts{ .kind = StmtsKind.fn_body }; p.visitStmtsAndPrependTempRefs(&stmts_list, &temp_opts) catch unreachable; p.allocator.free(e_.body.stmts); @@ -12271,7 +12267,13 @@ pub fn NewParser( fn visitArgs(p: *P, args: []G.Arg, opts: VisitArgsOpts) void { const strict_loc = fnBodyContainsUseStrict(opts.body); const has_simple_args = isSimpleParameterList(args, opts.has_rest_arg); - var duplicate_args_check: ?StringBoolMap = null; + var duplicate_args_check: ?*StringVoidMap.Node = null; + defer { + if (duplicate_args_check) |checker| { + StringVoidMap.release(checker); + } + } + // Section 15.2.1 Static Semantics: Early Errors: "It is a Syntax Error if // FunctionBodyContainsUseStrict of FunctionBody is true and // IsSimpleParameterList of FormalParameters is false." @@ -12284,11 +12286,14 @@ pub fn NewParser( // functions which have simple parameter lists and which are not defined in // strict mode code." if (opts.is_unique_formal_parameters or strict_loc != null or !has_simple_args or p.isStrictMode()) { - duplicate_args_check = StringBoolMap.init(p.allocator); + duplicate_args_check = StringVoidMap.get(_global.default_allocator); } var i: usize = 0; - var duplicate_args_check_ptr: ?*StringBoolMap = if (duplicate_args_check != null) &duplicate_args_check.? else null; + var duplicate_args_check_ptr: ?*StringVoidMap = if (duplicate_args_check != null) + &duplicate_args_check.?.data + else + null; while (i < args.len) : (i += 1) { if (args[i].ts_decorators.len > 0) { @@ -12311,7 +12316,7 @@ pub fn NewParser( return decs; } - pub fn keepExprSymbolName(p: *P, _value: Expr, name: string) Expr { + pub fn keepExprSymbolName(_: *P, _value: Expr, _: string) Expr { return _value; // var start = p.expr_list.items.len; // p.expr_list.ensureUnusedCapacity(2) catch unreachable; @@ -12441,7 +12446,7 @@ pub fn NewParser( return true; } }, - .e_import_identifier => |ex| { + .e_import_identifier => { // References to an ES6 import item are always side-effect free in an // ECMAScript environment. @@ -12596,8 +12601,8 @@ pub fn NewParser( fn maybeRewritePropertyAccess( p: *P, loc: logger.Loc, - assign_target: js_ast.AssignTarget, - is_delete_target: bool, + _: js_ast.AssignTarget, + _: bool, target: js_ast.Expr, name: string, name_loc: logger.Loc, @@ -12645,17 +12650,17 @@ pub fn NewParser( // the value is ignored because that's what the TypeScript compiler does. } - fn visitAndAppendStmt(p: *P, stmts: *List(Stmt), stmt: *Stmt) !void { + fn visitAndAppendStmt(p: *P, stmts: *ListManaged(Stmt), stmt: *Stmt) !void { switch (stmt.data) { // These don't contain anything to traverse .s_debugger, .s_empty, .s_comment => {}, - .s_type_script => |data| { + .s_type_script => { // Erase TypeScript constructs from the output completely return; }, - .s_directive => |data| { + .s_directive => { // if p.isStrictMode() && s.LegacyOctalLoc.Start > 0 { // p.markStrictModeFeature(legacyOctalEscape, p.source.RangeOfLegacyOctalEscape(s.LegacyOctalLoc), "") @@ -12719,14 +12724,14 @@ pub fn NewParser( const name = p.loadNameFromRef(data.namespace_ref); data.namespace_ref = try p.newSymbol(.other, name); - try p.current_scope.generated.append(data.namespace_ref); + try p.current_scope.generated.append(p.allocator, data.namespace_ref); try p.recordDeclaredSymbol(data.namespace_ref); // This is a re-export and the symbols created here are used to reference for (data.items) |*item| { const _name = p.loadNameFromRef(item.name.ref orelse unreachable); const ref = try p.newSymbol(.other, _name); - try p.current_scope.generated.append(data.namespace_ref); + try p.current_scope.generated.append(p.allocator, data.namespace_ref); try p.recordDeclaredSymbol(data.namespace_ref); item.name.ref = ref; } @@ -12736,7 +12741,7 @@ pub fn NewParser( // "export * from 'path'" const name = p.loadNameFromRef(data.namespace_ref); data.namespace_ref = try p.newSymbol(.other, name); - try p.current_scope.generated.append(data.namespace_ref); + try p.current_scope.generated.append(p.allocator, data.namespace_ref); try p.recordDeclaredSymbol(data.namespace_ref); // "export * as ns from 'path'" @@ -12748,12 +12753,12 @@ pub fn NewParser( // because Safari doesn't support it and I've seen cases where this breaks p.recordUsage(data.namespace_ref); - try stmts.ensureCapacity(stmts.items.len + 2); + try stmts.ensureTotalCapacity(stmts.items.len + 2); stmts.appendAssumeCapacity(p.s(S.Import{ .namespace_ref = data.namespace_ref, .star_name_loc = alias.loc, .import_record_index = data.import_record_index }, stmt.loc)); var items = try List(js_ast.ClauseItem).initCapacity(p.allocator, 1); items.appendAssumeCapacity(js_ast.ClauseItem{ .alias = alias.original_name, .original_name = alias.original_name, .alias_loc = alias.loc, .name = LocRef{ .loc = alias.loc, .ref = data.namespace_ref } }); - stmts.appendAssumeCapacity(p.s(S.ExportClause{ .items = items.toOwnedSlice(), .is_single_line = true }, stmt.loc)); + stmts.appendAssumeCapacity(p.s(S.ExportClause{ .items = items.toOwnedSlice(p.allocator), .is_single_line = true }, stmt.loc)); return; } }, @@ -12839,7 +12844,8 @@ pub fn NewParser( return; }, .s_class => |class| { - var shadow_ref = p.visitClass(s2.loc, &class.class); + // TODO: https://github.com/Jarred-Sumner/bun/issues/51 + _ = p.visitClass(s2.loc, &class.class); if (p.options.enable_bundling) { var export_default_args = p.allocator.alloc(Expr, 2) catch unreachable; @@ -13039,7 +13045,7 @@ pub fn NewParser( // as a loop body. This is used to enable optimizations specific to the // topmost scope in a loop body block. const kind = if (std.meta.eql(p.loop_body, stmt.data)) StmtsKind.loop_body else StmtsKind.none; - var _stmts = List(Stmt).fromOwnedSlice(p.allocator, data.stmts); + var _stmts = ListManaged(Stmt).fromOwnedSlice(p.allocator, data.stmts); p.visitStmts(&_stmts, kind) catch unreachable; data.stmts = _stmts.toOwnedSlice(); p.popScope(); @@ -13058,7 +13064,14 @@ pub fn NewParser( return; }, .s_with => |data| { - notimpl(); + // using with is forbidden in strict mode + // we largely only deal with strict mode + // however, old code should still technically transpile + // we do not attempt to preserve all the semantics of with + data.value = p.visitExpr(data.value); + // This stmt should be a block + if (comptime Environment.allow_assert) std.debug.assert(data.body.data == .s_block); + data.body = p.visitSingleStmt(data.body, StmtsKind.none); }, .s_while => |data| { data.test_ = p.visitExpr(data.test_); @@ -13206,7 +13219,7 @@ pub fn NewParser( .s_try => |data| { p.pushScopeForVisitPass(.block, stmt.loc) catch unreachable; { - var _stmts = List(Stmt).fromOwnedSlice(p.allocator, data.body); + var _stmts = ListManaged(Stmt).fromOwnedSlice(p.allocator, data.body); p.fn_or_arrow_data_visit.try_body_count += 1; p.visitStmts(&_stmts, StmtsKind.none) catch unreachable; p.fn_or_arrow_data_visit.try_body_count -= 1; @@ -13220,7 +13233,7 @@ pub fn NewParser( if (catch_.binding != null) { p.visitBinding(catch_.binding.?, null); } - var _stmts = List(Stmt).fromOwnedSlice(p.allocator, catch_.body); + var _stmts = ListManaged(Stmt).fromOwnedSlice(p.allocator, catch_.body); p.visitStmts(&_stmts, StmtsKind.none) catch unreachable; catch_.body = _stmts.toOwnedSlice(); } @@ -13230,7 +13243,7 @@ pub fn NewParser( if (data.finally) |*finally| { p.pushScopeForVisitPass(.block, finally.loc) catch unreachable; { - var _stmts = List(Stmt).fromOwnedSlice(p.allocator, finally.stmts); + var _stmts = ListManaged(Stmt).fromOwnedSlice(p.allocator, finally.stmts); p.visitStmts(&_stmts, StmtsKind.none) catch unreachable; finally.stmts = _stmts.toOwnedSlice(); } @@ -13254,7 +13267,7 @@ pub fn NewParser( // Check("case", *c.Value, c.Value.Loc) // p.warnAboutTypeofAndString(s.Test, *c.Value) } - var _stmts = List(Stmt).fromOwnedSlice(p.allocator, case.body); + var _stmts = ListManaged(Stmt).fromOwnedSlice(p.allocator, case.body); p.visitStmts(&_stmts, StmtsKind.none) catch unreachable; data.cases[i].body = _stmts.toOwnedSlice(); } @@ -13322,13 +13335,14 @@ pub fn NewParser( defer p.popScope(); p.recordDeclaredSymbol(data.arg) catch unreachable; + const allocator = p.allocator; // Scan ahead for any variables inside this namespace. This must be done // ahead of time before visiting any statements inside the namespace // because we may end up visiting the uses before the declarations. // We need to convert the uses into property accesses on the namespace. for (data.values) |value| { if (!value.ref.isNull()) { - p.is_exported_inside_namespace.put(value.ref, data.arg) catch unreachable; + p.is_exported_inside_namespace.put(allocator, value.ref, data.arg) catch unreachable; } } @@ -13338,13 +13352,14 @@ pub fn NewParser( var next_numeric_value: f64 = 0.0; var has_numeric_value = true; - var value_exprs = List(Expr).initCapacity(p.allocator, data.values.len) catch unreachable; + var value_exprs = ListManaged(Expr).initCapacity(allocator, data.values.len) catch unreachable; // Track values so they can be used by constant folding. We need to follow // links here in case the enum was merged with a preceding namespace - var values_so_far = StringHashMap(f64).init(p.allocator); - p.known_enum_values.put(data.name.ref orelse p.panic("Expected data.name.ref", .{}), values_so_far) catch unreachable; - p.known_enum_values.put(data.arg, values_so_far) catch unreachable; + var values_so_far = _hash_map.StringHashMapUnmanaged(f64){}; + + p.known_enum_values.put(allocator, data.name.ref orelse p.panic("Expected data.name.ref", .{}), values_so_far) catch unreachable; + p.known_enum_values.put(allocator, data.arg, values_so_far) catch unreachable; // We normally don't fold numeric constants because they might increase code // size, but it's important to fold numeric constants inside enums since @@ -13363,18 +13378,18 @@ pub fn NewParser( .e_number => |num| { // prob never allocates in practice - values_so_far.put(name.string(p.allocator) catch unreachable, num.value) catch unreachable; + values_so_far.put(allocator, name.string(allocator) catch unreachable, num.value) catch unreachable; has_numeric_value = true; next_numeric_value = num.value + 1.0; }, - .e_string => |str| { + .e_string => { has_string_value = true; }, else => {}, } } else if (has_numeric_value) { enum_value.value = p.e(E.Number{ .value = next_numeric_value }, enum_value.loc); - values_so_far.put(name.string(p.allocator) catch unreachable, next_numeric_value) catch unreachable; + values_so_far.put(allocator, name.string(allocator) catch unreachable, next_numeric_value) catch unreachable; next_numeric_value += 1; } else { enum_value.value = p.e(E.Undefined{}, enum_value.loc); @@ -13389,7 +13404,7 @@ pub fn NewParser( enum_value.name, enum_value.loc, ), - }, enum_value.loc), enum_value.value orelse unreachable, p.allocator); + }, enum_value.loc), enum_value.value orelse unreachable, allocator); p.recordUsage(data.arg); @@ -13408,7 +13423,7 @@ pub fn NewParser( .index = assign_target, }, enum_value.loc), p.e(enum_value.name, enum_value.loc), - p.allocator, + allocator, ), ) catch unreachable; } @@ -13417,7 +13432,7 @@ pub fn NewParser( p.should_fold_numeric_constants = old_should_fold_numeric_constants; - var value_stmts = List(Stmt).initCapacity(p.allocator, value_exprs.items.len) catch unreachable; + var value_stmts = ListManaged(Stmt).initCapacity(allocator, value_exprs.items.len) catch unreachable; // Generate statements from expressions for (value_exprs.items) |expr| { value_stmts.appendAssumeCapacity(p.s(S.SExpr{ .value = expr }, expr.loc)); @@ -13453,7 +13468,7 @@ pub fn NewParser( } var prepend_temp_refs = PrependTempRefsOpts{ .kind = StmtsKind.fn_body }; - var prepend_list = List(Stmt).fromOwnedSlice(p.allocator, data.stmts); + var prepend_list = ListManaged(Stmt).fromOwnedSlice(p.allocator, data.stmts); const old_enclosing_namespace_arg_ref = p.enclosing_namespace_arg_ref; p.enclosing_namespace_arg_ref = data.arg; @@ -13489,7 +13504,7 @@ pub fn NewParser( } } - pub fn appendIfBodyPreservingScope(p: *P, stmts: *List(Stmt), body: Stmt) !void { + pub fn appendIfBodyPreservingScope(p: *P, stmts: *ListManaged(Stmt), body: Stmt) !void { switch (body.data) { .s_block => |block| { var keep_block = false; @@ -13523,7 +13538,7 @@ pub fn NewParser( switch (binding.data) { .b_missing => {}, .b_identifier => |ident| { - p.is_exported_inside_namespace.put(ident.ref, ref) catch unreachable; + p.is_exported_inside_namespace.put(p.allocator, ident.ref, ref) catch unreachable; }, .b_array => |array| { for (array.items) |item| { @@ -13543,7 +13558,7 @@ pub fn NewParser( fn generateClosureForTypeScriptNamespaceOrEnum( p: *P, - stmts: *List(Stmt), + stmts: *ListManaged(Stmt), stmt_loc: logger.Loc, is_export: bool, name_loc: logger.Loc, @@ -13559,14 +13574,15 @@ pub fn NewParser( name_ref = link; symbol = p.symbols.items[name_ref.inner_index]; } + const allocator = p.allocator; // Make sure to only emit a variable once for a given namespace, since there // can be multiple namespace blocks for the same namespace if (symbol.kind == .ts_namespace or symbol.kind == .ts_enum and !p.emitted_namespace_vars.contains(name_ref)) { - p.emitted_namespace_vars.put(name_ref, true) catch unreachable; + p.emitted_namespace_vars.put(allocator, name_ref, .{}) catch unreachable; - var decls = p.allocator.alloc(G.Decl, 1) catch unreachable; + var decls = allocator.alloc(G.Decl, 1) catch unreachable; decls[0] = G.Decl{ .binding = p.b(B.Identifier{ .ref = name_ref }, name_loc) }; if (p.enclosing_namespace_arg_ref == null) { @@ -13625,12 +13641,12 @@ pub fn NewParser( name_loc, ), p.e(E.Object{ .properties = &[_]G.Property{} }, name_loc), - p.allocator, + allocator, ), }, name_loc, ), - p.allocator, + allocator, ); p.recordUsage(namespace); p.recordUsage(namespace); @@ -13646,16 +13662,16 @@ pub fn NewParser( E.Object{ .properties = &[_]G.Property{} }, name_loc, ), - p.allocator, + allocator, ), }, name_loc); p.recordUsage(name_ref); p.recordUsage(name_ref); } - var func_args = p.allocator.alloc(G.Arg, 1) catch unreachable; + var func_args = allocator.alloc(G.Arg, 1) catch unreachable; func_args[0] = .{ .binding = p.b(B.Identifier{ .ref = arg_ref }, name_loc) }; - var args_list = p.allocator.alloc(ExprNodeIndex, 1) catch unreachable; + var args_list = allocator.alloc(ExprNodeIndex, 1) catch unreachable; args_list[0] = arg_expr; const func = G.Fn{ .args = func_args, @@ -13663,7 +13679,7 @@ pub fn NewParser( .open_parens_loc = stmt_loc, .body = G.FnBody{ .loc = stmt_loc, - .stmts = try p.allocator.dupe(StmtNodeIndex, stmts_inside_closure), + .stmts = try allocator.dupe(StmtNodeIndex, stmts_inside_closure), }, }; const target = p.e( @@ -13691,7 +13707,13 @@ pub fn NewParser( stmts.append(closure) catch unreachable; } - fn lowerClass(p: *P, stmtorexpr: js_ast.StmtOrExpr, ref: Ref) []Stmt { + // TODO: https://github.com/Jarred-Sumner/bun/issues/51 + fn lowerClass( + p: *P, + stmtorexpr: js_ast.StmtOrExpr, + // ref + _: Ref, + ) []Stmt { switch (stmtorexpr) { .stmt => |stmt| { var stmts = p.allocator.alloc(Stmt, 1) catch unreachable; @@ -13752,13 +13774,13 @@ pub fn NewParser( loc: logger.Loc, ref: Ref, ) Expr { - p.relocated_top_level_vars.append(LocRef{ .loc = loc, .ref = ref }) catch unreachable; + p.relocated_top_level_vars.append(p.allocator, LocRef{ .loc = loc, .ref = ref }) catch unreachable; var _ref = ref; p.recordUsage(_ref); return Expr.initIdentifier(_ref, loc); } - fn isAnonymousNamedExpr(p: *P, expr: ExprNodeIndex) bool { + fn isAnonymousNamedExpr(_: *P, expr: ExprNodeIndex) bool { switch (expr.data) { .e_arrow => { return true; @@ -13861,7 +13883,7 @@ pub fn NewParser( return false; } - fn visitBinding(p: *P, binding: BindingNodeIndex, duplicate_arg_check: ?*StringBoolMap) void { + fn visitBinding(p: *P, binding: BindingNodeIndex, duplicate_arg_check: ?*StringVoidMap) void { switch (binding.data) { .b_missing => {}, .b_identifier => |bind| { @@ -13870,10 +13892,8 @@ pub fn NewParser( if (isEvalOrArguments(name)) { p.markStrictModeFeature(.eval_or_arguments, js_lexer.rangeOfIdentifier(p.source, binding.loc), name) catch unreachable; } - if (duplicate_arg_check) |dup| { - const res = dup.getOrPut(name) catch unreachable; - if (res.found_existing) { + if (dup.getOrPutContains(name)) { p.log.addRangeErrorFmt( p.source, js_lexer.rangeOfIdentifier(p.source, binding.loc), @@ -13882,7 +13902,6 @@ pub fn NewParser( .{name}, ) catch unreachable; } - res.entry.value = true; } }, .b_array => |bind| { @@ -13945,15 +13964,9 @@ pub fn NewParser( } fn visitSingleStmt(p: *P, stmt: Stmt, kind: StmtsKind) Stmt { - const has_if_scope = has_if: { - switch (stmt.data) { - .s_function => { - break :has_if stmt.getFunction().func.flags.has_if_scope; - }, - else => { - break :has_if false; - }, - } + const has_if_scope = switch (stmt.data) { + .s_function => stmt.data.s_function.func.flags.has_if_scope, + else => false, }; // Introduce a fake block scope for function declarations inside if statements @@ -13961,7 +13974,7 @@ pub fn NewParser( p.pushScopeForVisitPass(.block, stmt.loc) catch unreachable; } - var stmts = List(Stmt).initCapacity(p.allocator, 1) catch unreachable; + var stmts = ListManaged(Stmt).initCapacity(p.allocator, 1) catch unreachable; stmts.append(stmt) catch unreachable; p.visitStmts(&stmts, kind) catch unreachable; @@ -13978,7 +13991,7 @@ pub fn NewParser( 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].getLocal().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].data.s_local.kind == S.Local.Kind.k_var)) { // "let" and "const" must be put in a block when in a single-statement context return stmts[0]; } @@ -14031,7 +14044,10 @@ pub fn NewParser( const old_enclosing_class_keyword = p.enclosing_class_keyword; p.enclosing_class_keyword = class.class_keyword; p.current_scope.recursiveSetStrictMode(.implicit_strict_mode_class); - var class_name_ref: Ref = if (class.class_name != null) class.class_name.?.ref.? else p.newSymbol(.other, "this") catch unreachable; + var class_name_ref: Ref = if (class.class_name != null) + class.class_name.?.ref.? + else + p.newSymbol(.other, "this") catch unreachable; var shadow_ref = Ref.None; @@ -14044,7 +14060,7 @@ pub fn NewParser( shadow_ref = p.newSymbol(Symbol.Kind.cconst, identifier) catch unreachable; p.recordDeclaredSymbol(shadow_ref) catch unreachable; if (class.class_name) |class_name| { - p.current_scope.members.put(identifier, Scope.Member{ .loc = class_name.loc, .ref = shadow_ref }) catch unreachable; + p.current_scope.members.put(p.allocator, identifier, Scope.Member{ .loc = class_name.loc, .ref = shadow_ref }) catch unreachable; } } @@ -14053,7 +14069,10 @@ pub fn NewParser( } p.pushScopeForVisitPass(.class_body, class.body_loc) catch unreachable; - defer p.popScope(); + defer { + p.popScope(); + p.enclosing_class_keyword = old_enclosing_class_keyword; + } var i: usize = 0; while (i < class.properties.len) : (i += 1) { @@ -14064,7 +14083,7 @@ pub fn NewParser( // Special-case EPrivateIdentifier to allow it here if (is_private) { - p.recordDeclaredSymbol(property.key.?.getPrivateIdentifier().ref) catch unreachable; + p.recordDeclaredSymbol(property.key.?.data.e_private_identifier.ref) catch unreachable; } else if (property.key) |key| { class.properties[i].key = p.visitExpr(key); } @@ -14116,12 +14135,12 @@ pub fn NewParser( if (p.symbols.items[shadow_ref.inner_index].use_count_estimate == 0) { // Don't generate a shadowing name if one isn't needed shadow_ref = Ref.None; - } else if (class.class_name) |class_name| { + } else if (class.class_name) |_| { // If there was originally no class name but something inside needed one // (e.g. there was a static property initializer that referenced "this"), // store our generated name so the class expression ends up with a name. class.class_name = LocRef{ .loc = name_scope_loc, .ref = class_name_ref }; - p.current_scope.generated.append(class_name_ref) catch unreachable; + p.current_scope.generated.append(p.allocator, class_name_ref) catch unreachable; p.recordDeclaredSymbol(class_name_ref) catch unreachable; } } @@ -14164,7 +14183,7 @@ pub fn NewParser( break :brk generated_symbol.ref; }; - p.module_scope.generated.append(ref) catch unreachable; + p.module_scope.generated.append(p.allocator, ref) catch unreachable; } else { ref = p.runtime_imports.at(name).?; } @@ -14179,7 +14198,7 @@ pub fn NewParser( } // Try separating the list for appending, so that it's not a pointer. - fn visitStmts(p: *P, stmts: *List(Stmt), kind: StmtsKind) !void { + fn visitStmts(p: *P, stmts: *ListManaged(Stmt), _: StmtsKind) !void { if (only_scan_imports_and_do_not_visit) { @compileError("only_scan_imports_and_do_not_visit must not run this."); } @@ -14190,9 +14209,9 @@ pub fn NewParser( defer p.is_control_flow_dead = old_is_control_flow_dead; // visit all statements first - var visited = try List(Stmt).initCapacity(p.allocator, stmts.items.len); - var before = List(Stmt).init(p.allocator); - var after = List(Stmt).init(p.allocator); + var visited = try ListManaged(Stmt).initCapacity(p.allocator, stmts.items.len); + var before = ListManaged(Stmt).init(p.allocator); + var after = ListManaged(Stmt).init(p.allocator); if (p.current_scope == p.module_scope) { p.macro.prepend_stmts = &before; @@ -14202,7 +14221,7 @@ pub fn NewParser( defer visited.deinit(); defer after.deinit(); - for (stmts.items) |*stmt, i| { + for (stmts.items) |*stmt| { const list = list_getter: { switch (stmt.data) { .s_export_equals => { @@ -14231,7 +14250,7 @@ pub fn NewParser( var visited_count = visited.items.len; if (p.is_control_flow_dead) { var end: usize = 0; - for (visited.items) |item, i| { + for (visited.items) |item| { if (!SideEffects.shouldKeepStmtInDeadControlFlow(item)) { continue; } @@ -14267,7 +14286,7 @@ pub fn NewParser( } } - fn extractDeclsForBinding(binding: Binding, decls: *List(G.Decl)) !void { + fn extractDeclsForBinding(binding: Binding, decls: *ListManaged(G.Decl)) !void { switch (binding.data) { .b_property, .b_missing => {}, .b_identifier => { @@ -14292,7 +14311,7 @@ pub fn NewParser( // This assumes that the open parenthesis has already been parsed by the caller pub fn parseParenExpr(p: *P, loc: logger.Loc, level: Level, opts: ParenExprOpts) anyerror!Expr { - var items_list = List(Expr).init(p.allocator); + var items_list = ListManaged(Expr).init(p.allocator); var errors = DeferredErrors{}; var arrowArgErrors = DeferredArrowArgErrors{}; var spread_range = logger.Range{}; @@ -14319,7 +14338,6 @@ pub fn NewParser( // Scan over the comma-separated arguments or expressions while (p.lexer.token != .t_close_paren) { - const item_loc = p.lexer.loc(); const is_spread = p.lexer.token == .t_dot_dot_dot; if (is_spread) { @@ -14383,8 +14401,8 @@ pub fn NewParser( return error.SyntaxError; } - var invalidLog = List(logger.Loc).init(p.allocator); - var args = List(G.Arg).init(p.allocator); + var invalidLog = LocList.init(p.allocator); + var args = ListManaged(G.Arg).init(p.allocator); if (opts.is_async) { // markl,oweredsyntaxpoksdpokasd @@ -14500,7 +14518,7 @@ pub fn NewParser( for (to_flatten.children.items) |item| { item.parent = parent; - parent.children.append(item) catch unreachable; + parent.children.append(p.allocator, item) catch unreachable; } } @@ -14512,6 +14530,7 @@ pub fn NewParser( } pub fn toAST(p: *P, _parts: []js_ast.Part, exports_kind: js_ast.ExportsKind, commonjs_wrapper_expr: ?Expr) !js_ast.Ast { + const allocator = p.allocator; var parts = _parts; // Insert an import statement for any runtime imports we generated @@ -14531,21 +14550,11 @@ pub fn NewParser( p.import_records_for_current_part.shrinkRetainingCapacity(0); p.declared_symbols.shrinkRetainingCapacity(0); - var result = if (p.options.features.hot_module_reloading) try ImportScanner.scan( - *P, - p, - part.stmts, - true, - ) else try ImportScanner.scan( - *P, - p, - part.stmts, - false, - ); + var result = try ImportScanner.scan(*P, p, part.stmts); kept_import_equals = kept_import_equals or result.kept_import_equals; removed_import_equals = removed_import_equals or result.removed_import_equals; part.import_record_indices = part.import_record_indices; - part.declared_symbols = p.declared_symbols.toOwnedSlice(); + part.declared_symbols = p.declared_symbols.toOwnedSlice(allocator); part.stmts = result.stmts; if (part.stmts.len > 0) { if (p.module_scope.contains_direct_eval and part.declared_symbols.len > 0) { @@ -14586,16 +14595,14 @@ pub fn NewParser( if (commonjs_wrapper_expr) |commonjs_wrapper| { var part = &parts[parts.len - 1]; - var require_function_args = p.allocator.alloc(Arg, 2) catch unreachable; + var require_function_args = allocator.alloc(Arg, 2) catch unreachable; var imports_count: u32 = 0; // We have to also move export from, since we will preserve those var exports_from_count: u32 = 0; - var additional_stmts_because_of_exports: u32 = 0; - // Two passes. First pass just counts. - for (parts[parts.len - 1].stmts) |stmt, i| { + for (parts[parts.len - 1].stmts) |stmt| { imports_count += switch (stmt.data) { .s_import => @as(u32, 1), else => @as(u32, 0), @@ -14607,17 +14614,13 @@ pub fn NewParser( }; } - var new_stmts_list = p.allocator.alloc(Stmt, exports_from_count + imports_count + 1) catch unreachable; + var new_stmts_list = allocator.alloc(Stmt, exports_from_count + imports_count + 1) catch unreachable; var imports_list = new_stmts_list[0..imports_count]; var exports_list = if (exports_from_count > 0) new_stmts_list[imports_list.len + 1 ..] else &[_]Stmt{}; - const name_ref = null; require_function_args[0] = G.Arg{ .binding = p.b(B.Identifier{ .ref = p.module_ref }, logger.Loc.Empty) }; require_function_args[1] = G.Arg{ .binding = p.b(B.Identifier{ .ref = p.exports_ref }, logger.Loc.Empty) }; - var exports_identifier: ExprNodeIndex = undefined; - var exports_identifier_set = false; - const default_name_loc_ref = LocRef{ .ref = name_ref, .loc = logger.Loc.Empty }; var imports_list_i: u32 = 0; var exports_list_i: u32 = 0; @@ -14631,166 +14634,6 @@ pub fn NewParser( imports_list_i += 1; }, - // .s_export_default => |s_export| { - // if (!exports_identifier_set) { - // exports_identifier = p.e(E.Identifier{ .ref = p.exports_ref }, logger.Loc.Empty); - // exports_identifier_set = true; - // } - - // switch (s_export.value) { - // .expr => |default_expr| { - // part.stmts[i] = Expr.assignStmt(p.e( - // E.Dot{ .name = "default", .name_loc = part.stmts[i].loc, .target = exports_identifier }, - // part.stmts[i].loc, - // ), default_expr, p.allocator); - // }, - // .stmt => |default_stmt| { - // switch (default_stmt.data) { - // .s_function => |func| { - // part.stmts[i] = Expr.assignStmt(p.e( - // E.Dot{ .name = "default", .name_loc = part.stmts[i].loc, .target = exports_identifier }, - // part.stmts[i].loc, - // ), p.e( - // E.Function{ .func = func.func }, - // default_stmt.loc, - // ), p.allocator); - // }, - // .s_class => |class| { - // part.stmts[i] = Expr.assignStmt( - // p.e( - // E.Dot{ .name = "default", .name_loc = part.stmts[i].loc, .target = exports_identifier }, - // part.stmts[i].loc, - // ), - // p.e( - // default_stmt.data.s_class.class, - // default_stmt.loc, - // ), - // p.allocator, - // ); - // }, - // else => unreachable, - // } - // }, - // } - // }, - - // .s_function => |func| { - // if (!exports_identifier_set) { - // exports_identifier = p.e(E.Identifier{ .ref = p.exports_ref }, logger.Loc.Empty); - // exports_identifier_set = true; - // } - - // part.stmts[i] = Expr.assignStmt(p.e( - // E.Dot{ .name = "default", .name_loc = part.stmts[i].loc, .target = exports_identifier }, - // part.stmts[i].loc, - // ), default_expr, p.allocator); - // }, - // .s_local => |local| { - // if (!exports_identifier_set) { - // exports_identifier = p.e(E.Identifier{ .ref = p.exports_ref }, logger.Loc.Empty); - // exports_identifier_set = true; - // } - - // const items = local.decls; - - // for (items[1..]) |item| { - // assignment = Expr.joinWithComma(assignment, Expr.assign( - // p.e(E.Dot{ - // .name = item.alias, - // .target = exports_identifier, - // .name_loc = item.alias_loc, - // }, item.alias_loc), - // p.e( - // E.Identifier{ - // .ref = item.name.ref.?, - // }, - // item.name.loc, - // ), - // p.allocator, - // ), p.allocator); - // } - - // const original_loc = part.stmts[i].loc; - // part.stmts[i] = p.s(S.SExpr{ - // .value = assignment, - // }, original_loc); - - // }, - // .s_class => |class| { - // if (!exports_identifier_set) { - // exports_identifier = p.e(E.Identifier{ .ref = p.exports_ref }, logger.Loc.Empty); - // exports_identifier_set = true; - // } - - // part.stmts[i] = Expr.assignStmt( - // }, - - // .s_export_clause => |s_export| { - // const items = s_export.items; - // switch (items.len) { - // 0 => { - // part.stmts[i] = Stmt.empty(); - // }, - // 1 => { - // if (!exports_identifier_set) { - // exports_identifier = p.e(E.Identifier{ .ref = p.exports_ref }, logger.Loc.Empty); - // exports_identifier_set = true; - // } - - // part.stmts[i] = Expr.assignStmt(p.e( - // E.Dot{ - // .name = items[0].alias, - // .target = exports_identifier, - // .name_loc = items[0].alias_loc, - // }, - // items[0].alias_loc, - // ), p.e( - // E.Identifier{ - // .ref = items[0].name.ref.?, - // }, - // items[0].name.loc, - // ), p.allocator); - // }, - // else => { - // if (!exports_identifier_set) { - // exports_identifier = p.e(E.Identifier{ .ref = p.exports_ref }, logger.Loc.Empty); - // exports_identifier_set = true; - // } - // var assignment = Expr.assign(p.e( - // E.Dot{ - // .name = items[0].alias, - // .target = exports_identifier, - // .name_loc = items[0].alias_loc, - // }, - // items[0].alias_loc, - // ), p.e(E.Identifier{ - // .ref = items[0].name.ref.?, - // }, items[0].name.loc), p.allocator); - - // for (items[1..]) |item| { - // assignment = Expr.joinWithComma(assignment, Expr.assign( - // p.e(E.Dot{ - // .name = item.alias, - // .target = exports_identifier, - // .name_loc = item.alias_loc, - // }, item.alias_loc), - // p.e( - // E.Identifier{ - // .ref = item.name.ref.?, - // }, - // item.name.loc, - // ), - // p.allocator, - // ), p.allocator); - // } - - // const original_loc = part.stmts[i].loc; - // part.stmts[i] = p.s(S.SExpr{ - // .value = assignment, - // }, original_loc); - // }, - // } - // }, .s_export_star, .s_export_from => { exports_list[exports_list_i] = part.stmts[i]; part.stmts[i] = Stmt.empty(); @@ -14853,7 +14696,7 @@ pub fn NewParser( // We have to also move export from, since we will preserve those var exports_from_count: usize = 0; // Two passes. First pass just counts. - for (parts[parts.len - 1].stmts) |stmt, i| { + for (parts[parts.len - 1].stmts) |stmt| { imports_count += switch (stmt.data) { .s_import => @as(usize, 1), else => @as(usize, 0), @@ -14887,7 +14730,7 @@ pub fn NewParser( const has_any_exports = named_exports_count > 0; const toplevel_stmts_count = 4 + (@intCast(usize, @boolToInt(has_any_exports)) * 2); - var _stmts = p.allocator.alloc( + var _stmts = allocator.alloc( Stmt, end_iife_stmts_count + toplevel_stmts_count + (named_exports_count * 2) + imports_count + exports_from_count, ) catch unreachable; @@ -14898,7 +14741,7 @@ pub fn NewParser( // in debug: crash in the printer due to undefined memory // in release: print ";" instead. // this should never happen regardless, but i'm just being cautious here. - if (comptime !isDebug) { + if (comptime !Environment.isDebug) { std.mem.set(Stmt, _stmts, Stmt.empty()); } @@ -14923,7 +14766,7 @@ pub fn NewParser( var export_list_i: usize = 0; // We must always copy it into the new stmts array - for (part.stmts) |stmt, i| { + for (part.stmts) |stmt| { switch (stmt.data) { .s_import => { imports_list[import_list_i] = stmt; @@ -14940,10 +14783,10 @@ pub fn NewParser( } } - var args_list: []Expr = if (isDebug) &Prefill.HotModuleReloading.DebugEnabledArgs else &Prefill.HotModuleReloading.DebugDisabled; + var args_list: []Expr = if (Environment.isDebug) &Prefill.HotModuleReloading.DebugEnabledArgs else &Prefill.HotModuleReloading.DebugDisabled; const new_call_args_count: usize = comptime if (is_react_fast_refresh_enabled) 3 else 2; - var call_args = try p.allocator.alloc(Expr, new_call_args_count + 1); + var call_args = try allocator.alloc(Expr, new_call_args_count + 1); var new_call_args = call_args[0..new_call_args_count]; var hmr_module_ident = p.e(E.Identifier{ .ref = p.hmr_module.ref }, logger.Loc.Empty); @@ -14953,11 +14796,7 @@ pub fn NewParser( if (is_react_fast_refresh_enabled) { new_call_args[2] = p.e(E.Identifier{ .ref = p.jsx_refresh_runtime.ref }, logger.Loc.Empty); } - var exports_dot = p.e(E.Dot{ - .target = hmr_module_ident, - .name = ExportsStringName, - .name_loc = logger.Loc.Empty, - }, logger.Loc.Empty); + var hmr_module_class_ident = p.e(E.Identifier{ .ref = p.runtime_imports.__HMRClient.?.ref }, logger.Loc.Empty); var toplevel_stmts_i: u8 = 0; // HMRClient.activate(true) @@ -14976,7 +14815,7 @@ pub fn NewParser( logger.Loc.Empty, ); toplevel_stmts_i += 1; - var decls = try p.allocator.alloc(G.Decl, 2 + named_exports_count); + var decls = try allocator.alloc(G.Decl, 2 + named_exports_count); var first_decl = decls[0..2]; // We cannot rely on import.meta.url because if we import it within a blob: url, it will be nonsensical // var __hmrModule = new HMRModule(123123124, "/index.js"), __exports = __hmrModule.exports; @@ -15006,18 +14845,17 @@ pub fn NewParser( }, logger.Loc.Empty), }; - var export_clauses = try p.allocator.alloc(js_ast.ClauseItem, named_exports_count); + var export_clauses = try allocator.alloc(js_ast.ClauseItem, named_exports_count); var named_export_i: usize = 0; - var decl_i: usize = 1; var named_exports_iter = p.named_exports.iterator(); - var export_properties = try p.allocator.alloc(G.Property, named_exports_count); + var export_properties = try allocator.alloc(G.Property, named_exports_count); var export_name_string_length: usize = 0; while (named_exports_iter.next()) |named_export| { export_name_string_length += named_export.key_ptr.len + "$$hmr_".len; } - var export_name_string_all = try p.allocator.alloc(u8, export_name_string_length); + var export_name_string_all = try allocator.alloc(u8, export_name_string_length); var export_name_string_remainder = export_name_string_all; var hmr_module_exports_dot = p.e( E.Dot{ @@ -15029,7 +14867,7 @@ pub fn NewParser( ); var exports_decls = decls[first_decl.len..]; named_exports_iter = p.named_exports.iterator(); - var update_function_args = try p.allocator.alloc(G.Arg, 1); + var update_function_args = try allocator.alloc(G.Arg, 1); var exports_ident = p.e(E.Identifier{ .ref = p.exports_ref }, logger.Loc.Empty); update_function_args[0] = G.Arg{ .binding = p.b(B.Identifier{ .ref = p.exports_ref }, logger.Loc.Empty) }; @@ -15091,7 +14929,7 @@ pub fn NewParser( .name = named_export.key_ptr.*, .name_loc = logger.Loc.Empty, }, logger.Loc.Empty), - p.allocator, + allocator, ); export_properties[named_export_i] = G.Property{ @@ -15174,7 +15012,7 @@ pub fn NewParser( logger.Loc.Empty, ), func, - p.allocator, + allocator, ), }, logger.Loc.Empty, @@ -15232,7 +15070,7 @@ pub fn NewParser( }, logger.Loc.Empty, ), - p.allocator, + allocator, ), }, logger.Loc.Empty, @@ -15258,28 +15096,10 @@ pub fn NewParser( } { - // Map locals to parts - p.top_level_symbol_to_parts = @TypeOf(p.top_level_symbol_to_parts).init(p.allocator); - var i: usize = 0; - while (i < parts.len) : (i += 1) { - const part = parts[i]; - for (part.declared_symbols) |declared| { - if (declared.is_top_level) { - if (p.top_level_symbol_to_parts.contains(declared.ref)) { - try p.top_level_symbol_to_parts.get(declared.ref).?.append(@intCast(u32, i)); - } else { - var list = try List(u32).initCapacity(p.allocator, 1); - list.appendAssumeCapacity(@intCast(u32, i)); - try p.top_level_symbol_to_parts.put(declared.ref, list); - } - } - } - } // Each part tracks the other parts it depends on within this file // var local_dependencies = AutoHashMap(u32, u32).init(p.allocator); - i = 0; // while (i < parts.len) : (i += 1) { // const part = parts[i]; // if (part.symbol_uses.count() > 0) { @@ -15326,7 +15146,6 @@ pub fn NewParser( .module_ref = p.module_ref, .import_records = p.import_records.items, .export_star_import_records = p.export_star_import_records.items, - .top_level_symbol_to_parts = p.top_level_symbol_to_parts, .approximate_newline_count = p.lexer.approximate_newline_count, .exports_kind = exports_kind, .named_imports = p.named_imports, @@ -15349,7 +15168,7 @@ pub fn NewParser( } pub fn init( - allocator: *std.mem.Allocator, + allocator: std.mem.Allocator, log: *logger.Log, source: *const logger.Source, define: *Define, @@ -15360,11 +15179,9 @@ pub fn NewParser( var scope_order = try ScopeOrderList.initCapacity(allocator, 1); var scope = try allocator.create(Scope); scope.* = Scope{ - .members = @TypeOf(scope.members).init(allocator), - .children = @TypeOf(scope.children).init( - allocator, - ), - .generated = @TypeOf(scope.generated).init(allocator), + .members = @TypeOf(scope.members){}, + .children = @TypeOf(scope.children){}, + .generated = @TypeOf(scope.generated){}, .kind = .entry, .label_ref = null, .parent = null, @@ -15377,37 +15194,16 @@ pub fn NewParser( // It will fail for the case in the "in-keyword.js" file .allow_in = true, - .symbol_uses = SymbolUseMap.init(allocator), .call_target = nullExprData, .delete_target = nullExprData, .stmt_expr_value = nullExprData, - .expr_list = List(Expr).init(allocator), + .expr_list = .{}, .loop_body = nullStmtData, - .injected_define_symbols = @TypeOf(this.injected_define_symbols).init(allocator), - .emitted_namespace_vars = @TypeOf(this.emitted_namespace_vars).init(allocator), - .is_exported_inside_namespace = @TypeOf(this.is_exported_inside_namespace).init(allocator), - .known_enum_values = @TypeOf(this.known_enum_values).init(allocator), - .local_type_names = @TypeOf(this.local_type_names).init(allocator), - .allocated_names = @TypeOf(this.allocated_names).init(allocator), .define = define, - .scopes_for_current_part = @TypeOf(this.scopes_for_current_part).init(allocator), - .symbols = @TypeOf(this.symbols).init(allocator), - .ts_use_counts = @TypeOf(this.ts_use_counts).init(allocator), - .declared_symbols = @TypeOf(this.declared_symbols).init(allocator), .import_records = undefined, - .import_records_for_current_part = @TypeOf(this.import_records_for_current_part).init(allocator), - .export_star_import_records = @TypeOf(this.export_star_import_records).init(allocator), - .import_items_for_namespace = @TypeOf(this.import_items_for_namespace).init(allocator), .named_imports = undefined, - .named_exports = @TypeOf(this.named_exports).init(allocator), - .top_level_symbol_to_parts = @TypeOf(this.top_level_symbol_to_parts).init(allocator), - .import_namespace_cc_map = @TypeOf(this.import_namespace_cc_map).init(allocator), - .scopes_in_order = scope_order, - .current_scope = scope, - .temp_refs_to_declare = @TypeOf(this.temp_refs_to_declare).init(allocator), - .relocated_top_level_vars = @TypeOf(this.relocated_top_level_vars).init(allocator), + .named_exports = js_ast.Ast.NamedExports.init(allocator), .log = log, - .is_import_item = @TypeOf(this.is_import_item).init(allocator), .allocator = allocator, .options = opts, .then_catch_chain = ThenCatchChain{ .next_target = nullExprData }, @@ -15418,7 +15214,8 @@ pub fn NewParser( .require_resolve_transposer = undefined, .source = source, .macro = MacroState.init(allocator), - + .current_scope = scope, + .scopes_in_order = scope_order, .needs_jsx_import = if (comptime only_scan_imports_and_do_not_visit) false else NeedsJSXType{}, .lexer = lexer, }; |