aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/js_parser/js_parser.zig145
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 {