diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/js_parser/js_parser.zig | 145 |
1 files changed, 64 insertions, 81 deletions
diff --git a/src/js_parser/js_parser.zig b/src/js_parser/js_parser.zig index 95c4a5d8f..838bef258 100644 --- a/src/js_parser/js_parser.zig +++ b/src/js_parser/js_parser.zig @@ -1265,8 +1265,6 @@ pub const Parser = struct { var result: js_ast.Result = undefined; if (self.p) |p| { - p.fn_or_arrow_data_parse.allow_await = .allow_expr; - p.fn_or_arrow_data_parse.is_top_level = true; // Parse the file in the first pass, but do not bind symbols var opts = ParseStatementOptions{ .is_module_scope = true }; debugl("<p.parseStmtsUpTo>"); @@ -1489,8 +1487,6 @@ const ParseStatementOptions = struct { } }; -const StringPoolMap = std.StringHashMap(*E.String); - var e_missing_data = E.Missing{}; var s_missing = S.Empty{}; var nullExprData = Expr.Data{ .e_missing = &e_missing_data }; @@ -1551,7 +1547,7 @@ pub const P = struct { 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 = null, + current_scope: *js_ast.Scope = undefined, scopes_for_current_part: List(*js_ast.Scope), symbols: List(js_ast.Symbol), ts_use_counts: List(u32), @@ -1560,7 +1556,6 @@ pub const P = struct { module_ref: js_ast.Ref = js_ast.Ref.None, import_meta_ref: js_ast.Ref = js_ast.Ref.None, promise_ref: ?js_ast.Ref = null, - string_pool: StringPoolMap, has_classic_runtime_warned: bool = false, data: js_ast.AstData, @@ -1853,7 +1848,7 @@ pub const P = struct { var declare_loc: logger.Loc = undefined; var is_inside_with_scope = false; var did_forbid_argumen = false; - var scope = p.current_scope.?; + var scope = p.current_scope; while (true) { @@ -1883,7 +1878,7 @@ pub const P = struct { p.checkForNonBMPCodePoint(loc, name); ref = try p.newSymbol(.unbound, name); declare_loc = loc; - try p.module_scope.members.put(p.allocator, name, js_ast.Scope.Member{ .ref = ref, .loc = logger.Loc.Empty }); + try p.module_scope.members.put(name, js_ast.Scope.Member{ .ref = ref, .loc = logger.Loc.Empty }); break; } } @@ -2146,7 +2141,7 @@ pub const P = struct { ); const namespace_ref = try p.newSymbol(.other, namespace_identifier); - try p.module_scope.generated.append(p.allocator, namespace_ref); + try p.module_scope.generated.append(namespace_ref); for (imports) |alias, i| { const ref = symbols.get(alias) orelse unreachable; @@ -2186,7 +2181,7 @@ pub const P = struct { pub fn prepareForVisitPass(p: *P) !void { try p.pushScopeForVisitPass(js_ast.Scope.Kind.entry, locModuleScope); p.fn_or_arrow_data_visit.is_outside_fn_or_arrow = true; - p.module_scope = p.current_scope.?; + p.module_scope = p.current_scope; p.has_es_module_syntax = p.es6_import_keyword.len > 0 or p.es6_export_keyword.len > 0 or p.top_level_await_keyword.len > 0; if (p.options.jsx.parse) { if (p.options.jsx.development) { @@ -2227,8 +2222,20 @@ pub const P = struct { } } + pub fn unshiftScopeOrder(self: *P) !ScopeOrder { + if (self.scopes_in_order.items.len == 0) { + var scope = try js_ast.Scope.initPtr(self.allocator); + return ScopeOrder{ + .scope = scope, + .loc = logger.Loc.Empty, + }; + } else { + return self.scopes_in_order.orderedRemove(0); + } + } + pub fn pushScopeForVisitPass(p: *P, kind: js_ast.Scope.Kind, loc: logger.Loc) !void { - var order = p.scopes_in_order.orderedRemove(0); + var order = try p.unshiftScopeOrder(); // Sanity-check that the scopes generated by the first and second passes match if (!order.loc.eql(loc) or order.scope.kind != kind) { @@ -2243,16 +2250,17 @@ pub const P = struct { pub fn pushScopeForParsePass(p: *P, kind: js_ast.Scope.Kind, loc: logger.Loc) !usize { debugl("<pushScopeForParsePass>"); defer debugl("</pushScopeForParsePass>"); - var parent = p.current_scope; - var scope = try Scope.initPtr(p.allocator); scope.kind = kind; scope.label_ref = null; - if (parent) |_parent| { - scope.parent = _parent; - try _parent.children.append(p.allocator, scope); - scope.strict_mode = _parent.strict_mode; + var parent: *Scope = undefined; + + if (kind != .entry) { + parent = p.current_scope; + scope.parent = parent; + try parent.children.append(scope); + scope.strict_mode = parent.strict_mode; } p.current_scope = scope; @@ -2269,8 +2277,8 @@ pub const P = struct { // Copy down function arguments into the function body scope. That way we get // errors if a statement in the function body tries to re-declare any of the // arguments. - if (kind == js_ast.Scope.Kind.function_body and parent != null) { - if (parent.?.kind != js_ast.Scope.Kind.function_args) { + if (kind == js_ast.Scope.Kind.function_body) { + if (parent.kind != js_ast.Scope.Kind.function_args) { p.panic("Internal error", .{}); } @@ -2280,7 +2288,7 @@ pub const P = struct { // // 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(p.allocator, entry.key, entry.value); + try scope.members.put(entry.key, entry.value); } } } @@ -2539,22 +2547,13 @@ pub const P = struct { pub fn popAndDiscardScope(p: *P, scope_index: usize) void { // Move up to the parent scope - var to_discard = p.current_scope orelse unreachable; - assert(to_discard.kind != .entry); - + var to_discard = p.current_scope; var parent = to_discard.parent orelse unreachable; p.current_scope = parent; // Truncate the scope order where we started to pretend we never saw this scope - // var i = scope_index + 1; - // while (i < p.scopes_in_order.items.len) : (i += 1) { - // p.scopes_in_order.items[i].scope.deinit(p.allocator); - // } - var to_trim = p.scopes_in_order.items[scope_index..p.scopes_in_order.items.len]; - for (to_trim) |order| { - order.scope.deinit(p.allocator); - } + p.scopes_in_order.shrinkRetainingCapacity(scope_index); var children = parent.children; // Remove the last child from the parent scope @@ -2563,9 +2562,7 @@ pub const P = struct { p.panic("Internal error", .{}); } - _ = children.pop(); - to_discard.deinit(p.allocator); - p.scopes_in_order.shrinkAndFree(scope_index); + _ = children.popOrNull(); } pub fn parseFn(p: *P, name: ?js_ast.LocRef, opts: FnOrArrowDataParse) G.Fn { @@ -2709,7 +2706,7 @@ pub const P = struct { // shadows any variable called "arguments" in any parent scopes. But only do // this if it wasn't already declared above because arguments are allowed to // be called "arguments", in which case the real "arguments" is inaccessible. - if (!p.current_scope.?.members.contains("arguments")) { + if (!p.current_scope.members.contains("arguments")) { func.arguments_ref = p.declareSymbol(.arguments, func.open_parens_loc, "arguments") catch unreachable; p.symbols.items[func.arguments_ref.?.inner_index].must_not_be_renamed = true; } @@ -2780,7 +2777,9 @@ pub const P = struct { const name = js_ast.LocRef{ .loc = loc, .ref = try p.newSymbol(Symbol.Kind.other, identifier) }; - try p.current_scope.?.generated.append(p.allocator, name.ref orelse unreachable); + var scope = p.current_scope; + + try scope.generated.append(name.ref orelse unreachable); return name; } @@ -3319,14 +3318,19 @@ pub const P = struct { p.lexer.expect(.t_open_paren); const test_ = p.parseExpr(.lowest); + const body_loc = p.lexer.loc(); p.lexer.expect(.t_close_paren); + var stmtOpts = ParseStatementOptions{}; + + // Push a scope so we make sure to prevent any bare identifiers referenced + // within the body from being renamed. Renaming them might change the + // semantics of the code. + _ = try p.pushScopeForParsePass(.with, body_loc); const body = p.parseStmt(&stmtOpts) catch unreachable; + p.popScope(); - return p.s(S.While{ - .body = body, - .test_ = test_, - }, loc); + return p.s(S.With{ .body = body, .value = test_, .body_loc = body_loc }, loc); }, .t_with => { p.lexer.next(); @@ -3334,16 +3338,6 @@ pub const P = struct { const test_ = p.parseExpr(.lowest); const body_loc = p.lexer.loc(); p.lexer.expect(.t_close_paren); - - var stmtOpts = ParseStatementOptions{}; - - // Push a scope so we make sure to prevent any bare identifiers referenced - // within the body from being renamed. Renaming them might change the - // semantics of the code. - _ = p.pushScopeForParsePass(.with, body_loc) catch unreachable; - const body = p.parseStmt(&stmtOpts) catch unreachable; - p.popScope(); - return p.s(S.With{ .value = test_, .body_loc = body_loc, .body = body }, loc); }, .t_switch => { p.lexer.next(); @@ -3781,7 +3775,8 @@ pub const P = struct { var path_name = fs.PathName.init(strings.append(p.allocator, "import_", path.text) catch unreachable); const name = try path_name.nonUniqueNameString(p.allocator); stmt.namespace_ref = try p.newSymbol(.other, name); - try p.current_scope.?.generated.append(p.allocator, stmt.namespace_ref); + var scope: *Scope = p.current_scope; + try scope.generated.append(stmt.namespace_ref); } var item_refs = std.StringHashMap(LocRef).init(p.allocator); @@ -3856,13 +3851,11 @@ pub const P = struct { }, .t_open_brace => { _ = try p.pushScopeForParsePass(.block, loc); - + defer p.popScope(); p.lexer.next(); var stmtOpts = ParseStatementOptions{}; const stmts = p.parseStmtsUpTo(.t_close_brace, &stmtOpts) catch unreachable; - p.popScope(); p.lexer.next(); - return p.s(S.Block{ .stmts = stmts, }, loc); @@ -3900,6 +3893,7 @@ pub const P = struct { .e_identifier => |ident| { if (p.lexer.token == .t_colon and opts.hasNoDecorators()) { _ = try p.pushScopeForParsePass(.label, loc); + defer p.popScope(); // Parse a labeled statement p.lexer.next(); @@ -3914,8 +3908,6 @@ pub const P = struct { else => {}, } var stmt = p.parseStmt(&nestedOpts) catch unreachable; - - p.popScope(); return p.s(S.Label{ .name = _name, .stmt = stmt }, loc); } }, @@ -4049,7 +4041,7 @@ pub const P = struct { pub fn discardScopesUpTo(p: *P, scope_index: usize) void { // Remove any direct children from their parent - var scope = p.current_scope.?; + var scope = p.current_scope; var children = scope.children; for (p.scopes_in_order.items[scope_index..]) |child| { if (child.scope.parent == p.current_scope) { @@ -4249,16 +4241,14 @@ pub const P = struct { switch (p.lexer.token) { .t_identifier => { const name = p.lexer.identifier; - - const async_prefix = AsyncPrefixExpression.find(name); - - if ((p.fn_or_arrow_data_parse.allow_await != .allow_ident and async_prefix == .is_await) or (p.fn_or_arrow_data_parse.allow_yield != .allow_ident and async_prefix == .is_yield)) { + if ((p.fn_or_arrow_data_parse.allow_await != .allow_ident and strings.eql(name, "await")) or (p.fn_or_arrow_data_parse.allow_yield != .allow_ident and strings.eql(name, "yield"))) { // TODO: add fmt to addRangeError p.log.addRangeError(p.source, p.lexer.range(), "Cannot use \"yield\" or \"await\" here.") catch unreachable; } + const ref = p.storeNameInRef(name) catch unreachable; p.lexer.next(); - return p.b(B.Identifier{ .ref = p.storeNameInRef(name) catch unreachable }, loc); + return p.b(B.Identifier{ .ref = ref }, loc); }, .t_open_bracket => { p.lexer.next(); @@ -4650,7 +4640,6 @@ pub const P = struct { } var stmt = p.parseStmt(opts) catch break :run; - // std.debug.print("\n--Parsed-:\n\n{s}\n", .{stmt}); // Skip TypeScript types entirely if (p.options.ts) { @@ -4680,7 +4669,7 @@ pub const P = struct { if (strings.eqlUtf16("use strict", str.value)) { // Track "use strict" directives - p.current_scope.?.strict_mode = .explicit_strict_mode; + p.current_scope.strict_mode = .explicit_strict_mode; } else if (strings.eqlUtf16("use asm", str.value)) { stmt.data = Stmt.Data{ .s_empty = p.m(S.Empty{}) }; } @@ -4763,7 +4752,7 @@ pub const P = struct { // }, } - var scope = p.current_scope.?; + var scope = p.current_scope; if (p.isStrictMode()) { var why: string = ""; var notes: []logger.Data = undefined; @@ -4795,7 +4784,7 @@ pub const P = struct { } pub fn isStrictMode(p: *P) bool { - return p.current_scope.?.strict_mode != .sloppy_mode; + return p.current_scope.strict_mode != .sloppy_mode; } pub fn isStrictModeOutputFormat(p: *P) bool { @@ -4813,7 +4802,7 @@ pub const P = struct { // Allocate a new symbol var ref = try p.newSymbol(kind, name); - const scope = p.current_scope.?; + const scope = p.current_scope; if (scope.members.get(name)) |existing| { var symbol: Symbol = p.symbols.items[@intCast(usize, existing.ref.inner_index)]; @@ -4845,7 +4834,7 @@ pub const P = struct { } } - try scope.members.put(p.allocator, name, js_ast.Scope.Member{ .ref = ref, .loc = loc }); + try scope.members.put(name, js_ast.Scope.Member{ .ref = ref, .loc = loc }); return ref; } @@ -4882,6 +4871,7 @@ pub const P = struct { var name: ?js_ast.LocRef = null; _ = p.pushScopeForParsePass(.function_args, loc) catch unreachable; + defer p.popScope(); if (p.lexer.token == .t_identifier) { name = js_ast.LocRef{ @@ -4908,7 +4898,6 @@ pub const P = struct { .allow_yield = if (is_generator) .allow_expr else .allow_ident, }); - p.popScope(); p.validateFunctionName(func, .expr); return p.e(js_ast.E.Function{ @@ -4924,6 +4913,7 @@ pub const P = struct { const loc = p.lexer.loc(); _ = try p.pushScopeForParsePass(Scope.Kind.function_body, p.lexer.loc()); + defer p.popScope(); p.lexer.expect(.t_open_brace); var opts = ParseStatementOptions{}; @@ -4932,9 +4922,6 @@ pub const P = struct { p.allow_in = oldAllowIn; p.fn_or_arrow_data_parse = oldFnOrArrowData; - - p.popScope(); - return G.FnBody{ .loc = loc, .stmts = stmts }; } @@ -4964,6 +4951,7 @@ pub const P = struct { } _ = try p.pushScopeForParsePass(Scope.Kind.function_body, arrow_loc); + defer p.popScope(); var old_fn_or_arrow_data = p.fn_or_arrow_data_parse; @@ -4973,7 +4961,6 @@ pub const P = struct { var stmts = try p.allocator.alloc(Stmt, 1); stmts[0] = p.s(S.Return{ .value = expr }, arrow_loc); - p.popScope(); return E.Arrow{ .args = args, .prefer_expr = true, .body = G.FnBody{ .loc = arrow_loc, .stmts = stmts } }; } @@ -5040,12 +5027,10 @@ pub const P = struct { return self.mm(@TypeOf(kind), kind); } + // Doing this the fast way is too complicated for now. pub fn storeNameInRef(p: *P, name: string) !js_ast.Ref { - 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 = @intCast(Ref.Int, @ptrToInt(name.ptr) - @ptrToInt(p.source.contents.ptr)); - const end = @intCast(Ref.Int, name.len); - return js_ast.Ref{ .source_index = start, .inner_index = end, .is_source_contents_slice = true }; - } else if (p.allocated_names.capacity > 0) { + // allocated_names is lazily allocated + if (p.allocated_names.capacity > 0) { const inner_index = @intCast(Ref.Int, 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 }; @@ -5057,9 +5042,7 @@ pub const P = struct { } pub fn loadNameFromRef(p: *P, ref: js_ast.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)) { + if (ref.source_index == std.math.maxInt(Ref.Int)) { assert(ref.inner_index < p.allocated_names.items.len); return p.allocated_names.items[ref.inner_index]; } else { |