aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar Jarred Sumner <jarred@jarredsumner.com> 2021-05-04 15:58:18 -0700
committerGravatar Jarred Sumner <jarred@jarredsumner.com> 2021-05-04 15:58:18 -0700
commita9ca6c8a07d489f0daf3cbaa7aeb62c89745da25 (patch)
tree89e6d33ba4391a58af8549b7032fd328858d7710 /src
parenta4322470530f710fed320ccc740d6ef320c940c5 (diff)
downloadbun-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.zig145
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 {