diff options
author | 2021-05-04 15:58:18 -0700 | |
---|---|---|
committer | 2021-05-04 15:58:18 -0700 | |
commit | a9ca6c8a07d489f0daf3cbaa7aeb62c89745da25 (patch) | |
tree | 89e6d33ba4391a58af8549b7032fd328858d7710 /src | |
parent | a4322470530f710fed320ccc740d6ef320c940c5 (diff) | |
download | bun-a9ca6c8a07d489f0daf3cbaa7aeb62c89745da25.tar.gz bun-a9ca6c8a07d489f0daf3cbaa7aeb62c89745da25.tar.zst bun-a9ca6c8a07d489f0daf3cbaa7aeb62c89745da25.zip |
the fast way
Former-commit-id: 808e5cfac3f776ae8e772f0c4f158f0078e6fbed
Diffstat (limited to 'src')
-rw-r--r-- | src/js_parser/js_parser.zig | 145 |
1 files changed, 81 insertions, 64 deletions
diff --git a/src/js_parser/js_parser.zig b/src/js_parser/js_parser.zig index 8fed3f736..1023a1065 100644 --- a/src/js_parser/js_parser.zig +++ b/src/js_parser/js_parser.zig @@ -1265,6 +1265,8 @@ 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>"); @@ -1487,6 +1489,8 @@ 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 }; @@ -1547,7 +1551,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 = undefined, + current_scope: ?*js_ast.Scope = null, scopes_for_current_part: List(*js_ast.Scope), symbols: List(js_ast.Symbol), ts_use_counts: List(u32), @@ -1556,6 +1560,7 @@ 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, @@ -1848,7 +1853,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) { @@ -1878,7 +1883,7 @@ pub const P = struct { p.checkForNonBMPCodePoint(loc, name); ref = try p.newSymbol(.unbound, name); declare_loc = loc; - try p.module_scope.members.put(name, js_ast.Scope.Member{ .ref = ref, .loc = logger.Loc.Empty }); + try p.module_scope.members.put(p.allocator, name, js_ast.Scope.Member{ .ref = ref, .loc = logger.Loc.Empty }); break; } } @@ -2141,7 +2146,7 @@ pub const P = struct { ); const namespace_ref = try p.newSymbol(.other, namespace_identifier); - try p.module_scope.generated.append(namespace_ref); + try p.module_scope.generated.append(p.allocator, namespace_ref); for (imports) |alias, i| { const ref = symbols.get(alias) orelse unreachable; @@ -2181,7 +2186,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) { @@ -2222,20 +2227,8 @@ 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 = try p.unshiftScopeOrder(); + var order = p.scopes_in_order.orderedRemove(0); // Sanity-check that the scopes generated by the first and second passes match if (!order.loc.eql(loc) or order.scope.kind != kind) { @@ -2250,17 +2243,16 @@ 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; - 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; + if (parent) |_parent| { + scope.parent = _parent; + try _parent.children.append(p.allocator, scope); + scope.strict_mode = _parent.strict_mode; } p.current_scope = scope; @@ -2277,8 +2269,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) { - if (parent.kind != js_ast.Scope.Kind.function_args) { + if (kind == js_ast.Scope.Kind.function_body and parent != null) { + if (parent.?.kind != js_ast.Scope.Kind.function_args) { p.panic("Internal error", .{}); } @@ -2288,7 +2280,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(entry.key, entry.value); + try scope.members.put(p.allocator, entry.key, entry.value); } } } @@ -2547,13 +2539,22 @@ 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; + var to_discard = p.current_scope orelse unreachable; + assert(to_discard.kind != .entry); + 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 - p.scopes_in_order.shrinkRetainingCapacity(scope_index); + // 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); + } var children = parent.children; // Remove the last child from the parent scope @@ -2562,7 +2563,9 @@ pub const P = struct { p.panic("Internal error", .{}); } - _ = children.popOrNull(); + _ = children.pop(); + to_discard.deinit(p.allocator); + p.scopes_in_order.shrinkAndFree(scope_index); } pub fn parseFn(p: *P, name: ?js_ast.LocRef, opts: FnOrArrowDataParse) G.Fn { @@ -2706,7 +2709,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; } @@ -2777,9 +2780,7 @@ pub const P = struct { const name = js_ast.LocRef{ .loc = loc, .ref = try p.newSymbol(Symbol.Kind.other, identifier) }; - var scope = p.current_scope; - - try scope.generated.append(name.ref orelse unreachable); + try p.current_scope.?.generated.append(p.allocator, name.ref orelse unreachable); return name; } @@ -3318,19 +3319,14 @@ 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.With{ .body = body, .value = test_, .body_loc = body_loc }, loc); + return p.s(S.While{ + .body = body, + .test_ = test_, + }, loc); }, .t_with => { p.lexer.next(); @@ -3338,6 +3334,16 @@ 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(); @@ -3775,8 +3781,7 @@ 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); - var scope: *Scope = p.current_scope; - try scope.generated.append(stmt.namespace_ref); + try p.current_scope.?.generated.append(p.allocator, stmt.namespace_ref); } var item_refs = std.StringHashMap(LocRef).init(p.allocator); @@ -3851,11 +3856,13 @@ 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); @@ -3893,7 +3900,6 @@ 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(); @@ -3908,6 +3914,8 @@ pub const P = struct { else => {}, } var stmt = p.parseStmt(&nestedOpts) catch unreachable; + + p.popScope(); return p.s(S.Label{ .name = _name, .stmt = stmt }, loc); } }, @@ -4041,7 +4049,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) { @@ -4241,14 +4249,16 @@ pub const P = struct { switch (p.lexer.token) { .t_identifier => { const name = p.lexer.identifier; - 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"))) { + + 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)) { // 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 = ref }, loc); + return p.b(B.Identifier{ .ref = p.storeNameInRef(name) catch unreachable }, loc); }, .t_open_bracket => { p.lexer.next(); @@ -4640,6 +4650,7 @@ 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) { @@ -4669,7 +4680,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{}) }; } @@ -4752,7 +4763,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; @@ -4784,7 +4795,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 { @@ -4802,7 +4813,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)]; @@ -4834,7 +4845,7 @@ pub const P = struct { } } - try scope.members.put(name, js_ast.Scope.Member{ .ref = ref, .loc = loc }); + try scope.members.put(p.allocator, name, js_ast.Scope.Member{ .ref = ref, .loc = loc }); return ref; } @@ -4871,7 +4882,6 @@ 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{ @@ -4898,6 +4908,7 @@ 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{ @@ -4913,7 +4924,6 @@ 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{}; @@ -4922,6 +4932,9 @@ pub const P = struct { p.allow_in = oldAllowIn; p.fn_or_arrow_data_parse = oldFnOrArrowData; + + p.popScope(); + return G.FnBody{ .loc = loc, .stmts = stmts }; } @@ -4951,7 +4964,6 @@ 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; @@ -4961,6 +4973,7 @@ 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 } }; } @@ -5027,10 +5040,12 @@ 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 { - // allocated_names is lazily allocated - if (p.allocated_names.capacity > 0) { + 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) { 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 }; @@ -5042,7 +5057,9 @@ pub const P = struct { } pub fn loadNameFromRef(p: *P, ref: js_ast.Ref) string { - if (ref.source_index == std.math.maxInt(Ref.Int)) { + 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)) { assert(ref.inner_index < p.allocated_names.items.len); return p.allocated_names.items[ref.inner_index]; } else { |