aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Jarred Sumner <jarred@jarredsumner.com> 2021-05-27 21:35:28 -0700
committerGravatar Jarred Sumner <jarred@jarredsumner.com> 2021-05-27 21:35:28 -0700
commitcbf0b77e52d77ae8a0fe00606e7be2d2af39b83c (patch)
tree405873010d4a64741ecb2891045c7b261e923ca3
parentb6e7f01e6ae61bd47b23b918d86d511c390e3510 (diff)
downloadbun-cbf0b77e52d77ae8a0fe00606e7be2d2af39b83c.tar.gz
bun-cbf0b77e52d77ae8a0fe00606e7be2d2af39b83c.tar.zst
bun-cbf0b77e52d77ae8a0fe00606e7be2d2af39b83c.zip
lists
-rw-r--r--src/bundler.zig4
-rw-r--r--src/cli.zig3
-rw-r--r--src/defines.zig335
-rw-r--r--src/js_ast.zig1177
-rw-r--r--src/js_parser/js_parser.zig504
-rw-r--r--src/js_printer.zig176
-rw-r--r--src/resolver/package_json.zig21
-rw-r--r--src/resolver/tsconfig_json.zig43
8 files changed, 1571 insertions, 692 deletions
diff --git a/src/bundler.zig b/src/bundler.zig
index 4e68964df..dcb5a25c5 100644
--- a/src/bundler.zig
+++ b/src/bundler.zig
@@ -247,7 +247,10 @@ pub const Bundler = struct {
const output_file = try bundler.print(
result,
);
+
js_ast.Stmt.Data.Store.reset();
+ js_ast.Expr.Data.Store.reset();
+
return output_file;
}
@@ -286,6 +289,7 @@ pub const Bundler = struct {
js_printer.Options{ .to_module_ref = Ref.RuntimeRef },
&_linker,
);
+ // allocator.free(result.source.contents);
return options.OutputFile{
.path = out_path,
diff --git a/src/cli.zig b/src/cli.zig
index dbacee76f..93d473e85 100644
--- a/src/cli.zig
+++ b/src/cli.zig
@@ -387,6 +387,9 @@ pub const Cli = struct {
}
}
+ Output.println("Expr count: {d}", .{js_ast.Expr.icount});
+ Output.println("Stmt count: {d}", .{js_ast.Stmt.icount});
+
if (!did_write) {
for (result.output_files) |file, i| {
try writer.writeAll(file.contents);
diff --git a/src/defines.zig b/src/defines.zig
index 214094847..c16bf9edb 100644
--- a/src/defines.zig
+++ b/src/defines.zig
@@ -63,63 +63,63 @@ pub const DefineData = struct {
var user_defines = UserDefines.init(allocator);
try user_defines.ensureCapacity(defines.count());
- var iter = defines.iterator();
- while (iter.next()) |entry| {
- var splitter = std.mem.split(entry.key, ".");
- while (splitter.next()) |part| {
- if (!js_lexer.isIdentifier(part)) {
- if (strings.eql(part, entry.key)) {
- try log.addErrorFmt(null, logger.Loc{}, allocator, "The define key \"{s}\" must be a valid identifier", .{entry.key});
- } else {
- try log.addErrorFmt(null, logger.Loc{}, allocator, "The define key \"{s}\" contains invalid identifier \"{s}\"", .{ part, entry.key });
- }
- break;
- }
- }
-
- if (js_lexer.isIdentifier(entry.value) and !js_lexer.Keywords.has(entry.value)) {
- var ident: *js_ast.E.Identifier = try allocator.create(js_ast.E.Identifier);
- ident.ref = Ref.None;
- ident.can_be_removed_if_unused = true;
- user_defines.putAssumeCapacity(
- entry.key,
- DefineData{
- .value = js_ast.Expr.Data{ .e_identifier = ident },
- .original_name = entry.value,
- .can_be_removed_if_unused = true,
- },
- );
- // user_defines.putAssumeCapacity(
- // entry.key,
- // DefineData{ .value = js_ast.Expr.Data{.e_identifier = } },
- // );
- continue;
- }
- var _log = log;
- var source = logger.Source{
- .contents = entry.value,
- .path = defines_path,
- .identifier_name = "defines",
- .key_path = fs.Path.initWithNamespace("defines", "internal"),
- };
- var expr = try json_parser.ParseJSON(&source, _log, allocator);
- var data: js_ast.Expr.Data = undefined;
- switch (expr.data) {
- .e_missing => {
- continue;
- },
- .e_null, .e_boolean, .e_string, .e_number, .e_object, .e_array => {
- data = expr.data;
- },
- else => {
- continue;
- },
- }
-
- user_defines.putAssumeCapacity(entry.key, DefineData{
- .value = data,
- });
- }
+ // var iter = defines.iterator();
+ // while (iter.next()) |entry| {
+ // var splitter = std.mem.split(entry.key, ".");
+ // while (splitter.next()) |part| {
+ // if (!js_lexer.isIdentifier(part)) {
+ // if (strings.eql(part, entry.key)) {
+ // try log.addErrorFmt(null, logger.Loc{}, allocator, "The define key \"{s}\" must be a valid identifier", .{entry.key});
+ // } else {
+ // try log.addErrorFmt(null, logger.Loc{}, allocator, "The define key \"{s}\" contains invalid identifier \"{s}\"", .{ part, entry.key });
+ // }
+ // break;
+ // }
+ // }
+
+ // if (js_lexer.isIdentifier(entry.value) and !js_lexer.Keywords.has(entry.value)) {
+ // var ident: *js_ast.E.Identifier = try allocator.create(js_ast.E.Identifier);
+ // ident.ref = Ref.None;
+ // ident.can_be_removed_if_unused = true;
+ // user_defines.putAssumeCapacity(
+ // entry.key,
+ // DefineData{
+ // .value = js_ast.Expr.Data{ .e_identifier = ident },
+ // .original_name = entry.value,
+ // .can_be_removed_if_unused = true,
+ // },
+ // );
+ // // user_defines.putAssumeCapacity(
+ // // entry.key,
+ // // DefineData{ .value = js_ast.Expr.Data{.e_identifier = } },
+ // // );
+ // continue;
+ // }
+ // var _log = log;
+ // var source = logger.Source{
+ // .contents = entry.value,
+ // .path = defines_path,
+ // .identifier_name = "defines",
+ // .key_path = fs.Path.initWithNamespace("defines", "internal"),
+ // };
+ // var expr = try json_parser.ParseJSON(&source, _log, allocator);
+ // var data: js_ast.Expr.Data = undefined;
+ // switch (expr.data) {
+ // .e_missing => {
+ // continue;
+ // },
+ // .e_null, .e_boolean, .e_string, .e_number, .e_object, .e_array => {
+ // data = expr.data;
+ // },
+ // else => {
+ // continue;
+ // },
+ // }
+
+ // user_defines.putAssumeCapacity(entry.key, DefineData{
+ // .value = data,
+ // });
+ // }
return user_defines;
}
@@ -157,117 +157,118 @@ pub const Define = struct {
define.allocator = allocator;
define.identifiers = std.StringHashMap(IdentifierDefine).init(allocator);
define.dots = std.StringHashMap([]DotDefine).init(allocator);
- try define.identifiers.ensureCapacity(641);
- try define.dots.ensureCapacity(64);
-
- var undefined_val = try allocator.create(js_ast.E.Undefined);
- var val = js_ast.Expr.Data{ .e_undefined = undefined_val };
- var ident_define = IdentifierDefine{
- .value = val,
- };
- var value_define = DefineData{ .value = val, .valueless = true };
- // Step 1. Load the globals into the hash tables
- for (GlobalDefinesKey) |global| {
- if (global.len == 1) {
-
- // TODO: when https://github.com/ziglang/zig/pull/8596 is merged, switch to putAssumeCapacityNoClobber
- define.identifiers.putAssumeCapacity(global[0], value_define);
- } else {
- const key = global[global.len - 1];
- // TODO: move this to comptime
- // TODO: when https://github.com/ziglang/zig/pull/8596 is merged, switch to putAssumeCapacityNoClobber
- if (define.dots.getEntry(key)) |entry| {
- var list = try std.ArrayList(DotDefine).initCapacity(allocator, entry.value.len + 1);
- list.appendSliceAssumeCapacity(entry.value);
- list.appendAssumeCapacity(DotDefine{
- .parts = global[0..global.len],
- .data = value_define,
- });
-
- define.dots.putAssumeCapacity(key, list.toOwnedSlice());
- } else {
- var list = try std.ArrayList(DotDefine).initCapacity(allocator, 1);
- list.appendAssumeCapacity(DotDefine{
- .parts = global[0..global.len],
- .data = value_define,
- });
-
- define.dots.putAssumeCapacity(key, list.toOwnedSlice());
- }
- }
- }
-
- var nan_val = try allocator.create(js_ast.E.Number);
- nan_val.value = std.math.nan_f64;
-
- var inf_val = try allocator.create(js_ast.E.Number);
- inf_val.value = std.math.inf_f64;
-
- // Step 2. Swap in certain literal values because those can be constant folded
- define.identifiers.putAssumeCapacity("undefined", value_define);
- define.identifiers.putAssumeCapacity("NaN", DefineData{
- .value = js_ast.Expr.Data{ .e_number = nan_val },
- });
- define.identifiers.putAssumeCapacity("Infinity", DefineData{
- .value = js_ast.Expr.Data{ .e_number = inf_val },
- });
-
- // Step 3. Load user data into hash tables
- // At this stage, user data has already been validated.
- if (_user_defines) |user_defines| {
- var iter = user_defines.iterator();
- while (iter.next()) |user_define| {
- // If it has a dot, then it's a DotDefine.
- // e.g. process.env.NODE_ENV
- if (strings.lastIndexOfChar(user_define.key, '.')) |last_dot| {
- const tail = user_define.key[last_dot + 1 .. user_define.key.len];
- const remainder = user_define.key[0..last_dot];
- const count = std.mem.count(u8, remainder, ".") + 1;
- var parts = try allocator.alloc(string, count + 1);
- var splitter = std.mem.split(remainder, ".");
- var i: usize = 0;
- while (splitter.next()) |split| : (i += 1) {
- parts[i] = split;
- }
- parts[i] = tail;
- var didFind = false;
- var initial_values: []DotDefine = &([_]DotDefine{});
-
- // "NODE_ENV"
- if (define.dots.getEntry(tail)) |entry| {
- for (entry.value) |*part| {
- // ["process", "env"] === ["process", "env"] (if that actually worked)
- if (arePartsEqual(part.parts, parts)) {
- part.data = part.data.merge(user_define.value);
- didFind = true;
- break;
- }
- }
-
- initial_values = entry.value;
- }
-
- if (!didFind) {
- var list = try std.ArrayList(DotDefine).initCapacity(allocator, initial_values.len + 1);
- if (initial_values.len > 0) {
- list.appendSliceAssumeCapacity(initial_values);
- }
-
- list.appendAssumeCapacity(DotDefine{
- .data = user_define.value,
- // TODO: do we need to allocate this?
- .parts = parts,
- });
- try define.dots.put(tail, list.toOwnedSlice());
- }
- } else {
- // e.g. IS_BROWSER
- try define.identifiers.put(user_define.key, user_define.value);
- }
- }
- }
-
return define;
+ // try define.identifiers.ensureCapacity(641);
+ // try define.dots.ensureCapacity(64);
+
+ // var undefined_val = try allocator.create(js_ast.E.Undefined);
+ // var val = js_ast.Expr.Data{ .e_undefined = undefined_val };
+ // var ident_define = IdentifierDefine{
+ // .value = val,
+ // };
+ // var value_define = DefineData{ .value = val, .valueless = true };
+ // // Step 1. Load the globals into the hash tables
+ // for (GlobalDefinesKey) |global| {
+ // if (global.len == 1) {
+
+ // // TODO: when https://github.com/ziglang/zig/pull/8596 is merged, switch to putAssumeCapacityNoClobber
+ // define.identifiers.putAssumeCapacity(global[0], value_define);
+ // } else {
+ // const key = global[global.len - 1];
+ // // TODO: move this to comptime
+ // // TODO: when https://github.com/ziglang/zig/pull/8596 is merged, switch to putAssumeCapacityNoClobber
+ // if (define.dots.getEntry(key)) |entry| {
+ // var list = try std.ArrayList(DotDefine).initCapacity(allocator, entry.value.len + 1);
+ // list.appendSliceAssumeCapacity(entry.value);
+ // list.appendAssumeCapacity(DotDefine{
+ // .parts = global[0..global.len],
+ // .data = value_define,
+ // });
+
+ // define.dots.putAssumeCapacity(key, list.toOwnedSlice());
+ // } else {
+ // var list = try std.ArrayList(DotDefine).initCapacity(allocator, 1);
+ // list.appendAssumeCapacity(DotDefine{
+ // .parts = global[0..global.len],
+ // .data = value_define,
+ // });
+
+ // define.dots.putAssumeCapacity(key, list.toOwnedSlice());
+ // }
+ // }
+ // }
+
+ // var nan_val = try allocator.create(js_ast.E.Number);
+ // nan_val.value = std.math.nan_f64;
+
+ // var inf_val = try allocator.create(js_ast.E.Number);
+ // inf_val.value = std.math.inf_f64;
+
+ // // Step 2. Swap in certain literal values because those can be constant folded
+ // define.identifiers.putAssumeCapacity("undefined", value_define);
+ // define.identifiers.putAssumeCapacity("NaN", DefineData{
+ // .value = js_ast.Expr.Data{ .e_number = nan_val },
+ // });
+ // define.identifiers.putAssumeCapacity("Infinity", DefineData{
+ // .value = js_ast.Expr.Data{ .e_number = inf_val },
+ // });
+
+ // // Step 3. Load user data into hash tables
+ // // At this stage, user data has already been validated.
+ // if (_user_defines) |user_defines| {
+ // var iter = user_defines.iterator();
+ // while (iter.next()) |user_define| {
+ // // If it has a dot, then it's a DotDefine.
+ // // e.g. process.env.NODE_ENV
+ // if (strings.lastIndexOfChar(user_define.key, '.')) |last_dot| {
+ // const tail = user_define.key[last_dot + 1 .. user_define.key.len];
+ // const remainder = user_define.key[0..last_dot];
+ // const count = std.mem.count(u8, remainder, ".") + 1;
+ // var parts = try allocator.alloc(string, count + 1);
+ // var splitter = std.mem.split(remainder, ".");
+ // var i: usize = 0;
+ // while (splitter.next()) |split| : (i += 1) {
+ // parts[i] = split;
+ // }
+ // parts[i] = tail;
+ // var didFind = false;
+ // var initial_values: []DotDefine = &([_]DotDefine{});
+
+ // // "NODE_ENV"
+ // if (define.dots.getEntry(tail)) |entry| {
+ // for (entry.value) |*part| {
+ // // ["process", "env"] === ["process", "env"] (if that actually worked)
+ // if (arePartsEqual(part.parts, parts)) {
+ // part.data = part.data.merge(user_define.value);
+ // didFind = true;
+ // break;
+ // }
+ // }
+
+ // initial_values = entry.value;
+ // }
+
+ // if (!didFind) {
+ // var list = try std.ArrayList(DotDefine).initCapacity(allocator, initial_values.len + 1);
+ // if (initial_values.len > 0) {
+ // list.appendSliceAssumeCapacity(initial_values);
+ // }
+
+ // list.appendAssumeCapacity(DotDefine{
+ // .data = user_define.value,
+ // // TODO: do we need to allocate this?
+ // .parts = parts,
+ // });
+ // try define.dots.put(tail, list.toOwnedSlice());
+ // }
+ // } else {
+ // // e.g. IS_BROWSER
+ // try define.identifiers.put(user_define.key, user_define.value);
+ // }
+ // }
+ // }
+
+ // return define;
}
};
diff --git a/src/js_ast.zig b/src/js_ast.zig
index 425ff6a83..08439a6cb 100644
--- a/src/js_ast.zig
+++ b/src/js_ast.zig
@@ -8,6 +8,15 @@ usingnamespace @import("ast/base.zig");
const ImportRecord = @import("import_record.zig").ImportRecord;
const allocators = @import("allocators.zig");
+pub const ListIndex = packed struct {
+ index: u31,
+ is_overflowing: bool = false,
+
+ pub fn eql(a: ListIndex, b: ListIndex) bool {
+ return @bitCast(u32, a) == @bitCast(u32, b);
+ }
+};
+
// There are three types.
// 1. Expr (expression)
// 2. Stmt (statement)
@@ -1171,8 +1180,9 @@ pub const Stmt = struct {
pub inline fn getWith(self: *const @This()) *S.With {
return Data.Store.With.at(self.data.s_with);
}
-
+ pub var icount: usize = 0;
pub fn init(origData: anytype, loc: logger.Loc) Stmt {
+ icount += 1;
if (@typeInfo(@TypeOf(origData)) != .Pointer and @TypeOf(origData) != S.Empty) {
@compileError("Stmt.init needs a pointer.");
}
@@ -1295,6 +1305,7 @@ pub const Stmt = struct {
}
pub fn alloc(allocator: *std.mem.Allocator, origData: anytype, loc: logger.Loc) Stmt {
+ icount += 1;
switch (@TypeOf(origData)) {
S.Block => {
return Stmt.comptime_alloc(allocator, "s_block", S.Block, origData, loc);
@@ -1439,46 +1450,41 @@ pub const Stmt = struct {
};
pub const Data = union(Tag) {
- s_block: Store.ListIndex,
- s_break: Store.ListIndex,
- s_class: Store.ListIndex,
- s_comment: Store.ListIndex,
- s_continue: Store.ListIndex,
+ s_block: ListIndex,
+ s_break: ListIndex,
+ s_class: ListIndex,
+ s_comment: ListIndex,
+ s_continue: ListIndex,
s_debugger: S.Debugger,
- s_directive: Store.ListIndex,
- s_do_while: Store.ListIndex,
+ s_directive: ListIndex,
+ s_do_while: ListIndex,
s_empty: S.Empty, // special case, its a zero value type
- s_enum: Store.ListIndex,
- s_export_clause: Store.ListIndex,
- s_export_default: Store.ListIndex,
- s_export_equals: Store.ListIndex,
- s_export_from: Store.ListIndex,
- s_export_star: Store.ListIndex,
- s_expr: Store.ListIndex,
- s_for_in: Store.ListIndex,
- s_for_of: Store.ListIndex,
- s_for: Store.ListIndex,
- s_function: Store.ListIndex,
- s_if: Store.ListIndex,
- s_import: Store.ListIndex,
- s_label: Store.ListIndex,
- s_lazy_export: Store.ListIndex,
- s_local: Store.ListIndex,
- s_namespace: Store.ListIndex,
- s_return: Store.ListIndex,
- s_switch: Store.ListIndex,
- s_throw: Store.ListIndex,
- s_try: Store.ListIndex,
+ s_enum: ListIndex,
+ s_export_clause: ListIndex,
+ s_export_default: ListIndex,
+ s_export_equals: ListIndex,
+ s_export_from: ListIndex,
+ s_export_star: ListIndex,
+ s_expr: ListIndex,
+ s_for_in: ListIndex,
+ s_for_of: ListIndex,
+ s_for: ListIndex,
+ s_function: ListIndex,
+ s_if: ListIndex,
+ s_import: ListIndex,
+ s_label: ListIndex,
+ s_lazy_export: ListIndex,
+ s_local: ListIndex,
+ s_namespace: ListIndex,
+ s_return: ListIndex,
+ s_switch: ListIndex,
+ s_throw: ListIndex,
+ s_try: ListIndex,
s_type_script: S.TypeScript,
- s_while: Store.ListIndex,
- s_with: Store.ListIndex,
+ s_while: ListIndex,
+ s_with: ListIndex,
pub const Store = struct {
- pub const ListIndex = packed struct {
- index: u31,
- is_overflowing: bool = false,
- };
-
pub const Block = NewStore(S.Block);
pub const Break = NewStore(S.Break);
pub const Class = NewStore(S.Class);
@@ -1687,7 +1693,7 @@ pub const Stmt = struct {
}
pub fn NewStore(comptime ValueType: type) type {
- const count = 1024;
+ const count = 8096;
const max_index = count - 1;
const list_count = count;
return struct {
@@ -1931,15 +1937,122 @@ pub const Expr = struct {
}
pub const Query = struct { expr: Expr, loc: logger.Loc };
- pub fn getProperty(expr: *const Expr, name: string) ?Query {
+ pub fn getArray(exp: *const Expr) *E.Array {
+ return Data.Store.Array.at(exp.data.e_array);
+ }
+ pub fn getUnary(exp: *const Expr) *E.Unary {
+ return Data.Store.Unary.at(exp.data.e_unary);
+ }
+ pub fn getBinary(exp: *const Expr) *E.Binary {
+ return Data.Store.Binary.at(exp.data.e_binary);
+ }
+ pub fn getThis(exp: *const Expr) *E.This {
+ return E.This{};
+ }
+ pub fn getClass(exp: *const Expr) *E.Class {
+ return Data.Store.Class.at(exp.data.e_class);
+ }
+ pub fn getBoolean(exp: *const Expr) *E.Boolean {
+ return Data.Store.Boolean.at(exp.data.e_boolean);
+ }
+ pub fn getSuper(exp: *const Expr) *E.Super {
+ return Data.Store.Super.at(exp.data.e_super);
+ }
+ pub fn getNull(exp: *const Expr) *E.Null {
+ return Data.Store.Null.at(exp.data.e_null);
+ }
+ pub fn getUndefined(exp: *const Expr) *E.Undefined {
+ return Data.Store.Undefined.at(exp.data.e_undefined);
+ }
+ pub fn getNew(exp: *const Expr) *E.New {
+ return Data.Store.New.at(exp.data.e_new);
+ }
+ pub fn getNewTarget(exp: *const Expr) *E.NewTarget {
+ return &E.NewTarget{};
+ }
+ pub fn getFunction(exp: *const Expr) *E.Function {
+ return Data.Store.Function.at(exp.data.e_function);
+ }
+
+ pub fn getCall(exp: *const Expr) *E.Call {
+ return Data.Store.Call.at(exp.data.e_call);
+ }
+ pub fn getDot(exp: *const Expr) *E.Dot {
+ return Data.Store.Dot.at(exp.data.e_dot);
+ }
+ pub fn getIndex(exp: *const Expr) *E.Index {
+ return Data.Store.Index.at(exp.data.e_index);
+ }
+ pub fn getArrow(exp: *const Expr) *E.Arrow {
+ return Data.Store.Arrow.at(exp.data.e_arrow);
+ }
+ pub fn getIdentifier(exp: *const Expr) *E.Identifier {
+ return Data.Store.Identifier.at(exp.data.e_identifier);
+ }
+ pub fn getImportIdentifier(exp: *const Expr) *E.ImportIdentifier {
+ return Data.Store.ImportIdentifier.at(exp.data.e_import_identifier);
+ }
+ pub fn getPrivateIdentifier(exp: *const Expr) *E.PrivateIdentifier {
+ return Data.Store.PrivateIdentifier.at(exp.data.e_private_identifier);
+ }
+ pub fn getJsxElement(exp: *const Expr) *E.JSXElement {
+ return Data.Store.JSXElement.at(exp.data.e_jsx_element);
+ }
+ pub fn getMissing(exp: *const Expr) *E.Missing {
+ return Data.Store.Missing.at(exp.data.e_missing);
+ }
+ pub fn getNumber(exp: *const Expr) *E.Number {
+ return Data.Store.Number.at(exp.data.e_number);
+ }
+ pub fn getBigInt(exp: *const Expr) *E.BigInt {
+ return Data.Store.BigInt.at(exp.data.e_big_int);
+ }
+ pub fn getObject(exp: *const Expr) *E.Object {
+ return Data.Store.Object.at(exp.data.e_object);
+ }
+ pub fn getSpread(exp: *const Expr) *E.Spread {
+ return Data.Store.Spread.at(exp.data.e_spread);
+ }
+ pub fn getString(exp: *const Expr) *E.String {
+ return Data.Store.String.at(exp.data.e_string);
+ }
+ pub fn getTemplatePart(exp: *const Expr) *E.TemplatePart {
+ return Data.Store.TemplatePart.at(exp.data.e_template_part);
+ }
+ pub fn getTemplate(exp: *const Expr) *E.Template {
+ return Data.Store.Template.at(exp.data.e_template);
+ }
+ pub fn getRegExp(exp: *const Expr) *E.RegExp {
+ return Data.Store.RegExp.at(exp.data.e_reg_exp);
+ }
+ pub fn getAwait(exp: *const Expr) *E.Await {
+ return Data.Store.Await.at(exp.data.e_await);
+ }
+ pub fn getYield(exp: *const Expr) *E.Yield {
+ return Data.Store.Yield.at(exp.data.e_yield);
+ }
+ pub fn getIf(exp: *const Expr) *E.If {
+ return Data.Store.If.at(exp.data.e_if);
+ }
+ pub fn getRequire(exp: *const Expr) *E.Require {
+ return Data.Store.Require.at(exp.data.e_require);
+ }
+ pub fn getRequireOrRequireResolve(exp: *const Expr) *E.RequireOrRequireResolve {
+ return Data.Store.RequireOrRequireResolve.at(exp.data.e_require_or_require_resolve);
+ }
+ pub fn getImport(exp: *const Expr) *E.Import {
+ return Data.Store.Import.at(exp.data.e_import);
+ }
+
+ pub fn asProperty(expr: *const Expr, name: string) ?Query {
if (std.meta.activeTag(expr.data) != .e_object) return null;
- const obj: *const E.Object = expr.data.e_object;
+ const obj = expr.getObject();
for (obj.properties) |prop| {
const value = prop.value orelse continue;
const key = prop.key orelse continue;
if (std.meta.activeTag(key.data) != .e_string) continue;
- const key_str: *const E.String = key.data.e_string;
+ const key_str: *const E.String = key.getString();
if (key_str.eql(string, name)) {
return Query{ .expr = value, .loc = key.loc };
}
@@ -1948,20 +2061,20 @@ pub const Expr = struct {
return null;
}
- pub fn getString(expr: *const Expr, allocator: *std.mem.Allocator) ?string {
+ pub fn asString(expr: *const Expr, allocator: *std.mem.Allocator) ?string {
if (std.meta.activeTag(expr.data) != .e_string) return null;
- const key_str: *const E.String = expr.data.e_string;
+ const key_str: *const E.String = expr.getString();
return if (key_str.isUTF8()) key_str.utf8 else key_str.string(allocator) catch null;
}
- pub fn getBool(
+ pub fn asBool(
expr: *const Expr,
) ?bool {
if (std.meta.activeTag(expr.data) != .e_boolean) return null;
- const obj = expr.data.e_boolean;
+ const obj = expr.getBoolean();
return obj.value;
}
@@ -2021,7 +2134,7 @@ pub const Expr = struct {
return null;
}
- return [2]f64{ left.e_number.value, right.e_number.value };
+ return [2]f64{ Expr.Data.Store.Number.at(left.e_number).value, Expr.Data.Store.Number.at(right.e_number).value };
}
pub fn isAnonymousNamed(e: *Expr) bool {
@@ -2041,411 +2154,584 @@ pub const Expr = struct {
}
}
+ pub var icount: usize = 0;
pub fn init(exp: anytype, loc: logger.Loc) Expr {
- switch (@TypeOf(exp)) {
- *E.Array => {
+ icount += 1;
+ const st = exp.*;
+ switch (@TypeOf(st)) {
+ E.Array => {
return Expr{
.loc = loc,
- .data = Data{ .e_array = exp },
+ .data = Data{
+ .e_array = Data.Store.Array.append(st),
+ },
};
},
- *E.Unary => {
+ E.Class => {
return Expr{
.loc = loc,
- .data = Data{ .e_unary = exp },
+ .data = Data{
+ .e_class = Data.Store.Class.append(st),
+ },
};
},
- *E.Binary => {
+ E.Unary => {
return Expr{
.loc = loc,
- .data = Data{ .e_binary = exp },
+ .data = Data{
+ .e_unary = Data.Store.Unary.append(st),
+ },
};
},
- *E.This => {
+ E.Binary => {
return Expr{
.loc = loc,
- .data = Data{ .e_this = exp },
+ .data = Data{
+ .e_binary = Data.Store.Binary.append(st),
+ },
};
},
- *E.Boolean => {
+ E.This => {
return Expr{
.loc = loc,
- .data = Data{ .e_boolean = exp },
+ .data = Data{
+ .e_this = st,
+ },
};
},
- *E.Super => {
+ E.Boolean => {
return Expr{
.loc = loc,
- .data = Data{ .e_super = exp },
+ .data = Data{
+ .e_boolean = Data.Store.Boolean.append(st),
+ },
};
},
- *E.Null => {
+ E.Super => {
return Expr{
.loc = loc,
- .data = Data{ .e_null = exp },
+ .data = Data{
+ .e_super = st,
+ },
};
},
- *E.Undefined => {
+ E.Null => {
return Expr{
.loc = loc,
- .data = Data{ .e_undefined = exp },
+ .data = Data{
+ .e_null = st,
+ },
};
},
- *E.New => {
+ E.Undefined => {
return Expr{
.loc = loc,
- .data = Data{ .e_new = exp },
+ .data = Data{
+ .e_undefined = st,
+ },
};
},
- *E.NewTarget => {
+ E.New => {
return Expr{
.loc = loc,
- .data = Data{ .e_new_target = exp },
+ .data = Data{
+ .e_new = Data.Store.New.append(st),
+ },
};
},
- *E.Function => {
+ E.NewTarget => {
return Expr{
.loc = loc,
- .data = Data{ .e_function = exp },
+ .data = Data{
+ .e_new_target = st,
+ },
};
},
- *E.ImportMeta => {
+ E.Function => {
return Expr{
.loc = loc,
- .data = Data{ .e_import_meta = exp },
+ .data = Data{
+ .e_function = Data.Store.Function.append(st),
+ },
};
},
- *E.Call => {
+ E.ImportMeta => {
return Expr{
.loc = loc,
- .data = Data{ .e_call = exp },
+ .data = Data{
+ .e_import_meta = Data.Store.ImportMeta.append(st),
+ },
};
},
- *E.Dot => {
+ E.Call => {
return Expr{
.loc = loc,
- .data = Data{ .e_dot = exp },
+ .data = Data{
+ .e_call = Data.Store.Call.append(st),
+ },
};
},
- *E.Index => {
+ E.Dot => {
return Expr{
.loc = loc,
- .data = Data{ .e_index = exp },
+ .data = Data{
+ .e_dot = Data.Store.Dot.append(st),
+ },
};
},
- *E.Arrow => {
+ E.Index => {
return Expr{
.loc = loc,
- .data = Data{ .e_arrow = exp },
+ .data = Data{
+ .e_index = Data.Store.Index.append(st),
+ },
};
},
- *E.Identifier => {
+ E.Arrow => {
return Expr{
.loc = loc,
- .data = Data{ .e_identifier = exp },
+ .data = Data{
+ .e_arrow = Data.Store.Arrow.append(st),
+ },
};
},
- *E.ImportIdentifier => {
+ E.Identifier => {
return Expr{
.loc = loc,
- .data = Data{ .e_import_identifier = exp },
+ .data = Data{
+ .e_identifier = Data.Store.Identifier.append(st),
+ },
};
},
- *E.PrivateIdentifier => {
+ E.ImportIdentifier => {
return Expr{
.loc = loc,
- .data = Data{ .e_private_identifier = exp },
+ .data = Data{
+ .e_import_identifier = Data.Store.ImportIdentifier.append(st),
+ },
};
},
- *E.JSXElement => {
+ E.PrivateIdentifier => {
return Expr{
.loc = loc,
- .data = Data{ .e_jsx_element = exp },
+ .data = Data{
+ .e_private_identifier = Data.Store.PrivateIdentifier.append(st),
+ },
};
},
- *E.Missing => {
+ E.JSXElement => {
return Expr{
.loc = loc,
- .data = Data{ .e_missing = exp },
+ .data = Data{
+ .e_jsx_element = Data.Store.JSXElement.append(st),
+ },
};
},
- *E.Number => {
- return Expr{
- .loc = loc,
- .data = Data{ .e_number = exp },
- };
+ E.Missing => {
+ return Expr{ .loc = loc, .data = Data{ .e_missing = E.Missing{} } };
},
- *E.BigInt => {
+ E.Number => {
return Expr{
.loc = loc,
- .data = Data{ .e_big_int = exp },
+ .data = Data{
+ .e_number = Data.Store.Number.append(st),
+ },
};
},
- *E.Object => {
+ E.BigInt => {
return Expr{
.loc = loc,
- .data = Data{ .e_object = exp },
+ .data = Data{
+ .e_big_int = Data.Store.BigInt.append(st),
+ },
};
},
- *E.Spread => {
+ E.Object => {
return Expr{
.loc = loc,
- .data = Data{ .e_spread = exp },
+ .data = Data{
+ .e_object = Data.Store.Object.append(st),
+ },
};
},
- *E.String => {
+ E.Spread => {
return Expr{
.loc = loc,
- .data = Data{ .e_string = exp },
+ .data = Data{
+ .e_spread = Data.Store.Spread.append(st),
+ },
};
},
- *E.TemplatePart => {
+ E.String => {
return Expr{
.loc = loc,
- .data = Data{ .e_template_part = exp },
+ .data = Data{
+ .e_string = Data.Store.String.append(st),
+ },
};
},
- *E.Class => {
+ E.TemplatePart => {
return Expr{
.loc = loc,
- .data = Data{ .e_class = exp },
+ .data = Data{
+ .e_template_part = Data.Store.TemplatePart.append(st),
+ },
};
},
- *E.Template => {
+ E.Template => {
return Expr{
.loc = loc,
- .data = Data{ .e_template = exp },
+ .data = Data{
+ .e_template = Data.Store.Template.append(st),
+ },
};
},
- *E.RegExp => {
+ E.RegExp => {
return Expr{
.loc = loc,
- .data = Data{ .e_reg_exp = exp },
+ .data = Data{
+ .e_reg_exp = Data.Store.RegExp.append(st),
+ },
};
},
- *E.Await => {
+ E.Await => {
return Expr{
.loc = loc,
- .data = Data{ .e_await = exp },
+ .data = Data{
+ .e_await = Data.Store.Await.append(st),
+ },
};
},
- *E.Yield => {
+ E.Yield => {
return Expr{
.loc = loc,
- .data = Data{ .e_yield = exp },
+ .data = Data{
+ .e_yield = Data.Store.Yield.append(st),
+ },
};
},
- *E.If => {
+ E.If => {
return Expr{
.loc = loc,
- .data = Data{ .e_if = exp },
+ .data = Data{
+ .e_if = Data.Store.If.append(st),
+ },
};
},
-
- *E.Import => {
+ E.RequireOrRequireResolve => {
return Expr{
.loc = loc,
- .data = Data{ .e_import = exp },
+ .data = Data{
+ .e_require_or_require_resolve = Data.Store.RequireOrRequireResolve.append(st),
+ },
};
},
- *E.Require => {
+ E.Import => {
return Expr{
.loc = loc,
- .data = Data{ .e_require = exp },
+ .data = Data{
+ .e_import = Data.Store.Import.append(st),
+ },
};
},
- *E.RequireOrRequireResolve => {
+ E.Require => {
return Expr{
.loc = loc,
- .data = Data{ .e_require_or_require_resolve = exp },
+ .data = Data{
+ .e_require = Data.Store.Require.append(st),
+ },
};
},
else => {
- @compileError("Expr.init needs a pointer to E.*");
+ @compileError("Invalid type passed to Expr.init");
},
}
}
pub fn alloc(allocator: *std.mem.Allocator, st: anytype, loc: logger.Loc) Expr {
+ icount += 1;
switch (@TypeOf(st)) {
E.Array => {
- var dat = allocator.create(E.Array) catch unreachable;
- dat.* = st;
- return Expr{ .loc = loc, .data = Data{ .e_array = dat } };
+ return Expr{
+ .loc = loc,
+ .data = Data{
+ .e_array = Data.Store.Array.append(st),
+ },
+ };
},
E.Class => {
- var dat = allocator.create(E.Class) catch unreachable;
- dat.* = st;
- return Expr{ .loc = loc, .data = Data{ .e_class = dat } };
+ return Expr{
+ .loc = loc,
+ .data = Data{
+ .e_class = Data.Store.Class.append(st),
+ },
+ };
},
E.Unary => {
- var dat = allocator.create(E.Unary) catch unreachable;
- dat.* = st;
- return Expr{ .loc = loc, .data = Data{ .e_unary = dat } };
+ return Expr{
+ .loc = loc,
+ .data = Data{
+ .e_unary = Data.Store.Unary.append(st),
+ },
+ };
},
E.Binary => {
- var dat = allocator.create(E.Binary) catch unreachable;
- dat.* = st;
- return Expr{ .loc = loc, .data = Data{ .e_binary = dat } };
+ return Expr{
+ .loc = loc,
+ .data = Data{
+ .e_binary = Data.Store.Binary.append(st),
+ },
+ };
},
E.This => {
- var dat = allocator.create(E.This) catch unreachable;
- dat.* = st;
- return Expr{ .loc = loc, .data = Data{ .e_this = dat } };
+ return Expr{
+ .loc = loc,
+ .data = Data{
+ .e_this = st,
+ },
+ };
},
E.Boolean => {
- var dat = allocator.create(E.Boolean) catch unreachable;
- dat.* = st;
- return Expr{ .loc = loc, .data = Data{ .e_boolean = dat } };
+ return Expr{
+ .loc = loc,
+ .data = Data{
+ .e_boolean = Data.Store.Boolean.append(st),
+ },
+ };
},
E.Super => {
- var dat = allocator.create(E.Super) catch unreachable;
- dat.* = st;
- return Expr{ .loc = loc, .data = Data{ .e_super = dat } };
+ return Expr{
+ .loc = loc,
+ .data = Data{
+ .e_super = st,
+ },
+ };
},
E.Null => {
- var dat = allocator.create(E.Null) catch unreachable;
- dat.* = st;
- return Expr{ .loc = loc, .data = Data{ .e_null = dat } };
+ return Expr{
+ .loc = loc,
+ .data = Data{
+ .e_null = st,
+ },
+ };
},
E.Undefined => {
- var dat = allocator.create(E.Undefined) catch unreachable;
- dat.* = st;
- return Expr{ .loc = loc, .data = Data{ .e_undefined = dat } };
+ return Expr{
+ .loc = loc,
+ .data = Data{
+ .e_undefined = st,
+ },
+ };
},
E.New => {
- var dat = allocator.create(E.New) catch unreachable;
- dat.* = st;
- return Expr{ .loc = loc, .data = Data{ .e_new = dat } };
+ return Expr{
+ .loc = loc,
+ .data = Data{
+ .e_new = Data.Store.New.append(st),
+ },
+ };
},
E.NewTarget => {
- var dat = allocator.create(E.NewTarget) catch unreachable;
- dat.* = st;
- return Expr{ .loc = loc, .data = Data{ .e_new_target = dat } };
+ return Expr{
+ .loc = loc,
+ .data = Data{ .e_new_target = st },
+ };
},
E.Function => {
- var dat = allocator.create(E.Function) catch unreachable;
- dat.* = st;
- return Expr{ .loc = loc, .data = Data{ .e_function = dat } };
+ return Expr{
+ .loc = loc,
+ .data = Data{
+ .e_function = Data.Store.Function.append(st),
+ },
+ };
},
E.ImportMeta => {
- var dat = allocator.create(E.ImportMeta) catch unreachable;
- dat.* = st;
- return Expr{ .loc = loc, .data = Data{ .e_import_meta = dat } };
+ return Expr{
+ .loc = loc,
+ .data = Data{
+ .e_import_meta = st,
+ },
+ };
},
E.Call => {
- var dat = allocator.create(E.Call) catch unreachable;
- dat.* = st;
- return Expr{ .loc = loc, .data = Data{ .e_call = dat } };
+ return Expr{
+ .loc = loc,
+ .data = Data{
+ .e_call = Data.Store.Call.append(st),
+ },
+ };
},
E.Dot => {
- var dat = allocator.create(E.Dot) catch unreachable;
- dat.* = st;
- return Expr{ .loc = loc, .data = Data{ .e_dot = dat } };
+ return Expr{
+ .loc = loc,
+ .data = Data{
+ .e_dot = Data.Store.Dot.append(st),
+ },
+ };
},
E.Index => {
- var dat = allocator.create(E.Index) catch unreachable;
- dat.* = st;
- return Expr{ .loc = loc, .data = Data{ .e_index = dat } };
+ return Expr{
+ .loc = loc,
+ .data = Data{
+ .e_index = Data.Store.Index.append(st),
+ },
+ };
},
E.Arrow => {
- var dat = allocator.create(E.Arrow) catch unreachable;
- dat.* = st;
- return Expr{ .loc = loc, .data = Data{ .e_arrow = dat } };
+ return Expr{
+ .loc = loc,
+ .data = Data{
+ .e_arrow = Data.Store.Arrow.append(st),
+ },
+ };
},
E.Identifier => {
- var dat = allocator.create(E.Identifier) catch unreachable;
- dat.* = st;
- return Expr{ .loc = loc, .data = Data{ .e_identifier = dat } };
+ return Expr{
+ .loc = loc,
+ .data = Data{
+ .e_identifier = Data.Store.Identifier.append(st),
+ },
+ };
},
E.ImportIdentifier => {
- var dat = allocator.create(E.ImportIdentifier) catch unreachable;
- dat.* = st;
- return Expr{ .loc = loc, .data = Data{ .e_import_identifier = dat } };
+ return Expr{
+ .loc = loc,
+ .data = Data{
+ .e_import_identifier = Data.Store.ImportIdentifier.append(st),
+ },
+ };
},
E.PrivateIdentifier => {
- var dat = allocator.create(E.PrivateIdentifier) catch unreachable;
- dat.* = st;
- return Expr{ .loc = loc, .data = Data{ .e_private_identifier = dat } };
+ return Expr{
+ .loc = loc,
+ .data = Data{
+ .e_private_identifier = Data.Store.PrivateIdentifier.append(st),
+ },
+ };
},
E.JSXElement => {
- var dat = allocator.create(E.JSXElement) catch unreachable;
- dat.* = st;
- return Expr{ .loc = loc, .data = Data{ .e_jsx_element = dat } };
+ return Expr{
+ .loc = loc,
+ .data = Data{
+ .e_jsx_element = Data.Store.JSXElement.append(st),
+ },
+ };
},
E.Missing => {
return Expr{ .loc = loc, .data = Data{ .e_missing = E.Missing{} } };
},
E.Number => {
- var dat = allocator.create(E.Number) catch unreachable;
- dat.* = st;
- return Expr{ .loc = loc, .data = Data{ .e_number = dat } };
+ return Expr{
+ .loc = loc,
+ .data = Data{
+ .e_number = Data.Store.Number.append(st),
+ },
+ };
},
E.BigInt => {
- var dat = allocator.create(E.BigInt) catch unreachable;
- dat.* = st;
- return Expr{ .loc = loc, .data = Data{ .e_big_int = dat } };
+ return Expr{
+ .loc = loc,
+ .data = Data{
+ .e_big_int = Data.Store.BigInt.append(st),
+ },
+ };
},
E.Object => {
- var dat = allocator.create(E.Object) catch unreachable;
- dat.* = st;
- return Expr{ .loc = loc, .data = Data{ .e_object = dat } };
+ return Expr{
+ .loc = loc,
+ .data = Data{
+ .e_object = Data.Store.Object.append(st),
+ },
+ };
},
E.Spread => {
- var dat = allocator.create(E.Spread) catch unreachable;
- dat.* = st;
- return Expr{ .loc = loc, .data = Data{ .e_spread = dat } };
+ return Expr{
+ .loc = loc,
+ .data = Data{
+ .e_spread = Data.Store.Spread.append(st),
+ },
+ };
},
E.String => {
- var dat = allocator.create(E.String) catch unreachable;
- dat.* = st;
- return Expr{ .loc = loc, .data = Data{ .e_string = dat } };
+ return Expr{
+ .loc = loc,
+ .data = Data{
+ .e_string = Data.Store.String.append(st),
+ },
+ };
},
E.TemplatePart => {
- var dat = allocator.create(E.TemplatePart) catch unreachable;
- dat.* = st;
- return Expr{ .loc = loc, .data = Data{ .e_template_part = dat } };
+ return Expr{
+ .loc = loc,
+ .data = Data{
+ .e_template_part = Data.Store.TemplatePart.append(st),
+ },
+ };
},
E.Template => {
- var dat = allocator.create(E.Template) catch unreachable;
- dat.* = st;
- return Expr{ .loc = loc, .data = Data{ .e_template = dat } };
+ return Expr{
+ .loc = loc,
+ .data = Data{
+ .e_template = Data.Store.Template.append(st),
+ },
+ };
},
E.RegExp => {
- var dat = allocator.create(E.RegExp) catch unreachable;
- dat.* = st;
- return Expr{ .loc = loc, .data = Data{ .e_reg_exp = dat } };
+ return Expr{
+ .loc = loc,
+ .data = Data{
+ .e_reg_exp = Data.Store.RegExp.append(st),
+ },
+ };
},
E.Await => {
- var dat = allocator.create(E.Await) catch unreachable;
- dat.* = st;
- return Expr{ .loc = loc, .data = Data{ .e_await = dat } };
+ return Expr{
+ .loc = loc,
+ .data = Data{
+ .e_await = Data.Store.Await.append(st),
+ },
+ };
},
E.Yield => {
- var dat = allocator.create(E.Yield) catch unreachable;
- dat.* = st;
- return Expr{ .loc = loc, .data = Data{ .e_yield = dat } };
+ return Expr{
+ .loc = loc,
+ .data = Data{
+ .e_yield = Data.Store.Yield.append(st),
+ },
+ };
},
E.If => {
- var dat = allocator.create(E.If) catch unreachable;
- dat.* = st;
- return Expr{ .loc = loc, .data = Data{ .e_if = dat } };
+ return Expr{
+ .loc = loc,
+ .data = Data{
+ .e_if = Data.Store.If.append(st),
+ },
+ };
},
E.RequireOrRequireResolve => {
- var dat = allocator.create(E.RequireOrRequireResolve) catch unreachable;
- dat.* = st;
- return Expr{ .loc = loc, .data = Data{ .e_require_or_require_resolve = dat } };
+ return Expr{
+ .loc = loc,
+ .data = Data{
+ .e_require_or_require_resolve = Data.Store.RequireOrRequireResolve.append(st),
+ },
+ };
},
E.Import => {
- var dat = allocator.create(E.Import) catch unreachable;
- dat.* = st;
- return Expr{ .loc = loc, .data = Data{ .e_import = dat } };
+ return Expr{
+ .loc = loc,
+ .data = Data{
+ .e_import = Data.Store.Import.append(st),
+ },
+ };
},
E.Require => {
- var dat = allocator.create(E.Require) catch unreachable;
- dat.* = st;
- return Expr{ .loc = loc, .data = Data{ .e_require = dat } };
+ return Expr{
+ .loc = loc,
+ .data = Data{
+ .e_require = Data.Store.Require.append(st),
+ },
+ };
},
else => {
@@ -2850,13 +3136,16 @@ pub const Expr = struct {
return true;
},
- .e_if => |ex| {
+ .e_if => {
+ const ex = a.getIf();
return isBoolean(ex.yes) and isBoolean(ex.no);
},
- .e_unary => |ex| {
+ .e_unary => {
+ const ex = a.getUnary();
return ex.op == .un_not or ex.op == .un_delete;
},
- .e_binary => |ex| {
+ .e_binary => {
+ const ex = a.getBinary();
switch (ex.op) {
.bin_strict_eq, .bin_strict_ne, .bin_loose_eq, .bin_loose_ne, .bin_lt, .bin_gt, .bin_le, .bin_ge, .bin_instanceof, .bin_in => {
return true;
@@ -2905,13 +3194,16 @@ pub const Expr = struct {
.e_null, .e_undefined => {
return expr.at(E.Boolean{ .value = true }, allocator);
},
- .e_boolean => |b| {
+ .e_boolean => {
+ const b = expr.getBoolean();
return expr.at(E.Boolean{ .value = b.value }, allocator);
},
- .e_number => |n| {
+ .e_number => {
+ const n = expr.getNumber();
return expr.at(E.Boolean{ .value = (n.value == 0 or std.math.isNan(n.value)) }, allocator);
},
- .e_big_int => |b| {
+ .e_big_int => {
+ const b = expr.getBigInt();
return expr.at(E.Boolean{ .value = strings.eql(b.value, "0") }, allocator);
},
.e_function,
@@ -2921,12 +3213,14 @@ pub const Expr = struct {
return expr.at(E.Boolean{ .value = false }, allocator);
},
// "!!!a" => "!a"
- .e_unary => |un| {
+ .e_unary => {
+ const un = expr.getUnary();
if (un.op == Op.Code.un_not and isBoolean(un.value)) {
return un.value;
}
},
- .e_binary => |ex| {
+ .e_binary => {
+ const ex = expr.getBinary();
// TODO: evaluate whether or not it is safe to do this mutation since it's modifying in-place.
// Make sure that these transformations are all safe for special values.
// For example, "!(a < b)" is not the same as "a >= b" if a and/or b are
@@ -2974,50 +3268,385 @@ pub const Expr = struct {
pub fn isOptionalChain(self: *const @This()) bool {
return switch (self.data) {
- .e_dot => |dot| dot.optional_chain != null,
- .e_index => |dot| dot.optional_chain != null,
- .e_call => |dot| dot.optional_chain != null,
+ .e_dot => self.getDot().optional_chain != null,
+ .e_index => self.getIndex().optional_chain != null,
+ .e_call => self.getCall().optional_chain != null,
else => false,
};
}
pub const Data = union(Tag) {
- e_array: *E.Array,
- e_unary: *E.Unary,
- e_binary: *E.Binary,
- e_this: *E.This,
- e_class: *E.Class,
- e_boolean: *E.Boolean,
- e_super: *E.Super,
- e_null: *E.Null,
- e_undefined: *E.Undefined,
- e_new: *E.New,
- e_new_target: *E.NewTarget,
- e_function: *E.Function,
- e_import_meta: *E.ImportMeta,
- e_call: *E.Call,
- e_dot: *E.Dot,
- e_index: *E.Index,
- e_arrow: *E.Arrow,
- e_identifier: *E.Identifier,
- e_import_identifier: *E.ImportIdentifier,
- e_private_identifier: *E.PrivateIdentifier,
- e_jsx_element: *E.JSXElement,
+ e_array: ListIndex,
+ e_unary: ListIndex,
+ e_binary: ListIndex,
+
+ e_class: ListIndex,
+ e_boolean: ListIndex,
+
e_missing: E.Missing,
- e_number: *E.Number,
- e_big_int: *E.BigInt,
- e_object: *E.Object,
- e_spread: *E.Spread,
- e_string: *E.String,
- e_template_part: *E.TemplatePart,
- e_template: *E.Template,
- e_reg_exp: *E.RegExp,
- e_await: *E.Await,
- e_yield: *E.Yield,
- e_if: *E.If,
- e_require: *E.Require,
- e_require_or_require_resolve: *E.RequireOrRequireResolve,
- e_import: *E.Import,
+ e_this: E.This,
+ e_super: E.Super,
+ e_null: E.Null,
+ e_undefined: E.Undefined,
+ e_new_target: E.NewTarget,
+
+ e_new: ListIndex,
+
+ e_function: ListIndex,
+ e_import_meta: E.ImportMeta,
+ e_call: ListIndex,
+ e_dot: ListIndex,
+ e_index: ListIndex,
+ e_arrow: ListIndex,
+ e_identifier: ListIndex,
+ e_import_identifier: ListIndex,
+ e_private_identifier: ListIndex,
+ e_jsx_element: ListIndex,
+
+ e_number: ListIndex,
+ e_big_int: ListIndex,
+ e_object: ListIndex,
+ e_spread: ListIndex,
+ e_string: ListIndex,
+ e_template_part: ListIndex,
+ e_template: ListIndex,
+ e_reg_exp: ListIndex,
+ e_await: ListIndex,
+ e_yield: ListIndex,
+ e_if: ListIndex,
+ e_require: ListIndex,
+ e_require_or_require_resolve: ListIndex,
+ e_import: ListIndex,
+
+ pub const Store = struct {
+ pub const Array = NewStore(E.Array);
+ pub const Unary = NewStore(E.Unary);
+ pub const Binary = NewStore(E.Binary);
+ pub const This = NewStore(E.This);
+ pub const Class = NewStore(E.Class);
+ pub const Boolean = NewStore(E.Boolean);
+ pub const Super = NewStore(E.Super);
+ pub const Null = NewStore(E.Null);
+ pub const Undefined = NewStore(E.Undefined);
+ pub const New = NewStore(E.New);
+ pub const Function = NewStore(E.Function);
+ pub const ImportMeta = NewStore(E.ImportMeta);
+ pub const Call = NewStore(E.Call);
+ pub const Dot = NewStore(E.Dot);
+ pub const Index = NewStore(E.Index);
+ pub const Arrow = NewStore(E.Arrow);
+ pub const Identifier = NewStore(E.Identifier);
+ pub const ImportIdentifier = NewStore(E.ImportIdentifier);
+ pub const PrivateIdentifier = NewStore(E.PrivateIdentifier);
+ pub const JSXElement = NewStore(E.JSXElement);
+ pub const Missing = NewStore(E.Missing);
+ pub const Number = NewStore(E.Number);
+ pub const BigInt = NewStore(E.BigInt);
+ pub const Object = NewStore(E.Object);
+ pub const Spread = NewStore(E.Spread);
+ pub const String = NewStore(E.String);
+ pub const TemplatePart = NewStore(E.TemplatePart);
+ pub const Template = NewStore(E.Template);
+ pub const RegExp = NewStore(E.RegExp);
+ pub const Await = NewStore(E.Await);
+ pub const Yield = NewStore(E.Yield);
+ pub const If = NewStore(E.If);
+ pub const Require = NewStore(E.Require);
+ pub const RequireOrRequireResolve = NewStore(E.RequireOrRequireResolve);
+ pub const Import = NewStore(E.Import);
+
+ threadlocal var has_inited = false;
+ pub fn create(allocator: *std.mem.Allocator) void {
+ if (has_inited) {
+ return;
+ }
+
+ has_inited = true;
+ _ = Array.init(allocator);
+ _ = Unary.init(allocator);
+ _ = Binary.init(allocator);
+ _ = This.init(allocator);
+ _ = Class.init(allocator);
+ _ = Boolean.init(allocator);
+ _ = New.init(allocator);
+ _ = Function.init(allocator);
+ _ = ImportMeta.init(allocator);
+ _ = Call.init(allocator);
+ _ = Dot.init(allocator);
+ _ = Index.init(allocator);
+ _ = Arrow.init(allocator);
+ _ = Identifier.init(allocator);
+ _ = ImportIdentifier.init(allocator);
+ _ = PrivateIdentifier.init(allocator);
+ _ = JSXElement.init(allocator);
+ _ = Missing.init(allocator);
+ _ = Number.init(allocator);
+ _ = BigInt.init(allocator);
+ _ = Object.init(allocator);
+ _ = Spread.init(allocator);
+ _ = String.init(allocator);
+ _ = TemplatePart.init(allocator);
+ _ = Template.init(allocator);
+ _ = RegExp.init(allocator);
+ _ = Await.init(allocator);
+ _ = Yield.init(allocator);
+ _ = If.init(allocator);
+ _ = Require.init(allocator);
+ _ = RequireOrRequireResolve.init(allocator);
+ _ = Import.init(allocator);
+ }
+
+ pub fn reset() void {
+ Array.reset();
+ Unary.reset();
+ Binary.reset();
+ This.reset();
+ Class.reset();
+ Boolean.reset();
+ New.reset();
+ Function.reset();
+ ImportMeta.reset();
+ Call.reset();
+ Dot.reset();
+ Index.reset();
+ Arrow.reset();
+ Identifier.reset();
+ ImportIdentifier.reset();
+ PrivateIdentifier.reset();
+ JSXElement.reset();
+ Missing.reset();
+ Number.reset();
+ BigInt.reset();
+ Object.reset();
+ Spread.reset();
+ String.reset();
+ TemplatePart.reset();
+ Template.reset();
+ RegExp.reset();
+ Await.reset();
+ Yield.reset();
+ If.reset();
+ Require.reset();
+ RequireOrRequireResolve.reset();
+ Import.reset();
+ }
+
+ pub fn append(comptime ValueType: type, value: anytype) ListIndex {
+ switch (comptime ValueType) {
+ E.Array => {
+ return Array.append(value);
+ },
+ E.Unary => {
+ return Unary.append(value);
+ },
+ E.Binary => {
+ return Binary.append(value);
+ },
+ E.This => {
+ return This.append(value);
+ },
+ E.Class => {
+ return Class.append(value);
+ },
+ E.Boolean => {
+ return Boolean.append(value);
+ },
+ E.Super => {
+ return Super.append(value);
+ },
+ E.Null => {
+ return Null.append(value);
+ },
+ E.Undefined => {
+ return Undefined.append(value);
+ },
+ E.New => {
+ return New.append(value);
+ },
+ E.NewTarget => {
+ return @compileError("NewTarget bad");
+ },
+ E.Function => {
+ return Function.append(value);
+ },
+ E.ImportMeta => {
+ return ImportMeta.append(value);
+ },
+ E.Call => {
+ return Call.append(value);
+ },
+ E.Dot => {
+ return Dot.append(value);
+ },
+ E.Index => {
+ return Index.append(value);
+ },
+ E.Arrow => {
+ return Arrow.append(value);
+ },
+ E.Identifier => {
+ return Identifier.append(value);
+ },
+ E.ImportIdentifier => {
+ return ImportIdentifier.append(value);
+ },
+ E.PrivateIdentifier => {
+ return PrivateIdentifier.append(value);
+ },
+ E.JSXElement => {
+ return JSXElement.append(value);
+ },
+ E.Missing => {
+ return Missing.append(value);
+ },
+ E.Number => {
+ return Number.append(value);
+ },
+ E.BigInt => {
+ return BigInt.append(value);
+ },
+ E.Object => {
+ return Object.append(value);
+ },
+ E.Spread => {
+ return Spread.append(value);
+ },
+ E.String => {
+ return String.append(value);
+ },
+ E.TemplatePart => {
+ return TemplatePart.append(value);
+ },
+ E.Template => {
+ return Template.append(value);
+ },
+ E.RegExp => {
+ return RegExp.append(value);
+ },
+ E.Await => {
+ return Await.append(value);
+ },
+ E.Yield => {
+ return Yield.append(value);
+ },
+ E.If => {
+ return If.append(value);
+ },
+ E.Require => {
+ return Require.append(value);
+ },
+ E.RequireOrRequireResolve => {
+ return RequireOrRequireResolve.append(value);
+ },
+ E.Import => {
+ return Import.append(value);
+ },
+ else => {
+ @compileError("Invalid type passed to Stmt.Data.set " ++ @typeName(ValueType));
+ },
+ }
+ }
+
+ pub fn NewStore(comptime ValueType: type) type {
+ const count = 8096;
+ const max_index = count - 1;
+ const list_count = count;
+ return struct {
+ pub threadlocal var backing_buf: [count]ValueType = undefined;
+ pub threadlocal var backing_buf_used: u16 = 0;
+ const Allocator = std.mem.Allocator;
+ const Self = @This();
+ const NotFound = allocators.NotFound;
+ const Unassigned = allocators.Unassigned;
+
+ overflow_list: std.ArrayListUnmanaged(ValueType),
+ allocator: *Allocator,
+
+ pub threadlocal var instance: Self = undefined;
+ pub threadlocal var self: *Self = undefined;
+
+ pub fn reset() void {
+ backing_buf_used = 0;
+ self.overflow_list.shrinkRetainingCapacity(0);
+ }
+
+ pub fn init(allocator: *std.mem.Allocator) *Self {
+ instance = Self{
+ .allocator = allocator,
+ .overflow_list = std.ArrayListUnmanaged(ValueType){},
+ };
+
+ self = &instance;
+ return self;
+ }
+
+ pub fn isOverflowing() bool {
+ return backing_buf_used >= @as(u16, count);
+ }
+
+ pub fn at(index: ListIndex) *ValueType {
+ std.debug.assert(index.index != NotFound.index and index.index != Unassigned.index);
+
+ if (index.is_overflowing) {
+ return &self.overflow_list.items[index.index];
+ } else {
+ return &backing_buf[index.index];
+ }
+ }
+
+ pub fn exists(value: ValueType) bool {
+ return isSliceInBuffer(value, backing_buf);
+ }
+
+ pub fn append(value: ValueType) ListIndex {
+ var result = ListIndex{ .index = std.math.maxInt(u31), .is_overflowing = backing_buf_used > max_index };
+ if (result.is_overflowing) {
+ result.index = @intCast(u31, self.overflow_list.items.len);
+ self.overflow_list.append(self.allocator, value) catch unreachable;
+ } else {
+ result.index = backing_buf_used;
+ backing_buf[result.index] = value;
+ backing_buf_used += 1;
+ if (backing_buf_used >= max_index) {
+ self.overflow_list = @TypeOf(self.overflow_list).initCapacity(self.allocator, count) catch unreachable;
+ }
+ }
+
+ return result;
+ }
+
+ pub fn update(result: *ListIndex, value: ValueType) !*ValueType {
+ if (result.index.index == NotFound.index or result.index.index == Unassigned.index) {
+ result.index.is_overflowing = backing_buf_used > max_index;
+ if (result.index.is_overflowing) {
+ result.index.index = @intCast(u31, self.overflow_list.items.len);
+ } else {
+ result.index.index = backing_buf_used;
+ backing_buf_used += 1;
+ if (backing_buf_used >= max_index) {
+ self.overflow_list = try @TypeOf(self.overflow_list).initCapacity(self.allocator, count);
+ }
+ }
+ }
+
+ if (result.index.is_overflowing) {
+ if (self.overflow_list.items.len == result.index.index) {
+ const real_index = self.overflow_list.items.len;
+ try self.overflow_list.append(self.allocator, value);
+ } else {
+ self.overflow_list.items[result.index.index] = value;
+ }
+
+ return &self.overflow_list.items[result.index.index];
+ } else {
+ backing_buf[result.index.index] = value;
+
+ return &backing_buf[result.index.index];
+ }
+ }
+ };
+ }
+ };
pub fn isBooleanValue(self: *Expr) bool {
// TODO:
diff --git a/src/js_parser/js_parser.zig b/src/js_parser/js_parser.zig
index 63e135295..be5cc6a36 100644
--- a/src/js_parser/js_parser.zig
+++ b/src/js_parser/js_parser.zig
@@ -18,7 +18,9 @@ pub fn ExpressionTransposer(comptime ctx: type, visitor: fn (ptr: *ctx, arg: Exp
pub fn maybeTransposeIf(self: *@This(), arg: Expr, state: anytype) Expr {
switch (arg.data) {
- .e_if => |ex| {
+ .e_if => {
+ const ex = arg.getIf();
+
ex.yes = self.maybeTransposeIf(ex.yes, state);
ex.no = self.maybeTransposeIf(ex.no, state);
return arg;
@@ -407,7 +409,7 @@ pub const ImportScanner = struct {
if (decl.value) |val| {
while (true) {
if (@as(Expr.Tag, val.data) == .e_dot) {
- value = val.data.e_dot.target;
+ value = val.getDot().target;
} else {
break;
}
@@ -419,7 +421,7 @@ pub const ImportScanner = struct {
if (@as(Expr.Tag, val.data) == .e_identifier) {
// Is this import statement unused?
if (@as(Binding.Tag, decl.binding.data) == .b_identifier and p.symbols.items[decl.binding.data.b_identifier.ref.inner_index].use_count_estimate == 0) {
- p.ignoreUsage(val.data.e_identifier.ref);
+ p.ignoreUsage(val.getIdentifier().ref);
scanner.removed_import_equals = true;
continue;
@@ -507,16 +509,20 @@ pub const SideEffects = enum(u2) {
pub fn toNumber(data: Expr.Data) ?f64 {
switch (data) {
- .e_null => |e| {
+ .e_null => {
return 0;
},
- .e_undefined => |e| {
+ .e_undefined => {
return std.math.nan_f64;
},
- .e_boolean => |e| {
+ .e_boolean => {
+ const e = Expr.Data.Store.Boolean.at(data.e_boolean);
+
return if (e.value) 1.0 else 0.0;
},
- .e_number => |e| {
+ .e_number => {
+ const e = Expr.Data.Store.Number.at(data.e_number);
+
return e.value;
},
else => {},
@@ -542,12 +548,14 @@ pub const SideEffects = enum(u2) {
return null;
},
- .e_dot => |dot| {
- if (dot.can_be_removed_if_unused) {
+ .e_dot => {
+ if (expr.getDot().can_be_removed_if_unused) {
return null;
}
},
- .e_identifier => |ident| {
+ .e_identifier => {
+ const ident = expr.getIdentifier();
+
if (ident.must_keep_due_to_with_stmt) {
return expr;
}
@@ -556,7 +564,8 @@ pub const SideEffects = enum(u2) {
return null;
}
},
- .e_if => |__if__| {
+ .e_if => {
+ const __if__ = expr.getIf();
__if__.yes = simpifyUnusedExpr(p, __if__.yes) orelse __if__.yes.toEmpty();
__if__.no = simpifyUnusedExpr(p, __if__.no) orelse __if__.no.toEmpty();
@@ -566,7 +575,9 @@ pub const SideEffects = enum(u2) {
}
},
- .e_call => |call| {
+ .e_call => {
+ const call = expr.getCall();
+
// A call that has been marked "__PURE__" can be removed if all arguments
// can be removed. The annotation causes us to ignore the target.
if (call.can_be_unwrapped_if_unused) {
@@ -574,7 +585,8 @@ pub const SideEffects = enum(u2) {
}
},
- .e_binary => |bin| {
+ .e_binary => {
+ const bin = expr.getBinary();
switch (bin.op) {
// We can simplify "==" and "!=" even though they can call "toString" and/or
// "valueOf" if we can statically determine that the types of both sides are
@@ -589,7 +601,8 @@ pub const SideEffects = enum(u2) {
}
},
- .e_new => |call| {
+ .e_new => {
+ const call = expr.getNew();
// A constructor call that has been marked "__PURE__" can be removed if all arguments
// can be removed. The annotation causes us to ignore the target.
if (call.can_be_unwrapped_if_unused) {
@@ -702,30 +715,41 @@ pub const SideEffects = enum(u2) {
pub fn eql(left: Expr.Data, right: Expr.Data, p: *P) Equality {
var equality = Equality{};
switch (left) {
- .e_null => |l| {
+ .e_null => {
equality.equal = @as(Expr.Tag, right) == Expr.Tag.e_null;
equality.ok = equality.equal;
},
- .e_undefined => |l| {
+ .e_undefined => {
equality.ok = @as(Expr.Tag, right) == Expr.Tag.e_undefined;
equality.equal = equality.ok;
},
- .e_boolean => |l| {
+ .e_boolean => {
+ const l = Expr.Data.Store.Boolean.at(left.e_boolean);
+ const r = Expr.Data.Store.Boolean.at(right.e_boolean);
+
equality.ok = @as(Expr.Tag, right) == Expr.Tag.e_boolean;
- equality.equal = equality.ok and l.value == right.e_boolean.value;
+ equality.equal = equality.ok and l.value == r.value;
},
- .e_number => |l| {
+ .e_number => {
+ const l = Expr.Data.Store.Number.at(left.e_number);
+ const r = Expr.Data.Store.Number.at(right.e_number);
+
equality.ok = @as(Expr.Tag, right) == Expr.Tag.e_number;
- equality.equal = equality.ok and l.value == right.e_number.value;
+ equality.equal = equality.ok and l.value == r.value;
},
- .e_big_int => |l| {
+ .e_big_int => {
+ const l = Expr.Data.Store.BigInt.at(left.e_big_int);
+ const r = Expr.Data.Store.BigInt.at(right.e_big_int);
+
equality.ok = @as(Expr.Tag, right) == Expr.Tag.e_big_int;
- equality.equal = equality.ok and strings.eql(l.value, right.e_big_int.value);
+ equality.equal = equality.ok and strings.eql(l.value, r.value);
},
- .e_string => |l| {
+ .e_string => {
+ const l = Expr.Data.Store.String.at(left.e_string);
+ const r = Expr.Data.Store.String.at(right.e_string);
+
equality.ok = @as(Expr.Tag, right) == Expr.Tag.e_string;
if (equality.ok) {
- const r = right.e_string;
equality.equal = r.eql(E.String, l);
}
},
@@ -743,7 +767,8 @@ pub const SideEffects = enum(u2) {
.e_null, .e_undefined, .e_boolean, .e_number, .e_big_int, .e_string => {
return true;
},
- .e_unary => |e| {
+ .e_unary => {
+ const e = Expr.Data.Store.Unary.at(data.e_unary);
switch (e.op) {
// number or bigint
.un_pos,
@@ -766,7 +791,8 @@ pub const SideEffects = enum(u2) {
else => {},
}
},
- .e_binary => |e| {
+ .e_binary => {
+ const e = Expr.Data.Store.Binary.at(data.e_binary);
switch (e.op) {
// boolean
.bin_lt,
@@ -819,7 +845,8 @@ pub const SideEffects = enum(u2) {
else => {},
}
},
- .e_if => |e| {
+ .e_if => {
+ const e = Expr.Data.Store.If.at(data.e_if);
return isPrimitiveWithSideEffects(e.yes.data) and isPrimitiveWithSideEffects(e.no.data);
},
else => {},
@@ -875,7 +902,8 @@ pub const SideEffects = enum(u2) {
return Result{ .value = true, .side_effects = .could_have_side_effects, .ok = true };
},
- .e_unary => |e| {
+ .e_unary => {
+ const e = Expr.Data.Store.Unary.at(exp.e_unary);
switch (e.op) {
// Always number or bigint
.un_pos, .un_neg, .un_cpl, .un_pre_dec, .un_pre_inc, .un_post_dec, .un_post_inc => {
@@ -894,7 +922,8 @@ pub const SideEffects = enum(u2) {
}
},
- .e_binary => |e| {
+ .e_binary => {
+ const e = Expr.Data.Store.Binary.at(exp.e_binary);
switch (e.op) {
// always string or number or bigint
.bin_add,
@@ -957,16 +986,20 @@ pub const SideEffects = enum(u2) {
.e_null, .e_undefined => {
return Result{ .ok = true, .value = false, .side_effects = .no_side_effects };
},
- .e_boolean => |e| {
+ .e_boolean => {
+ const e = Expr.Data.Store.Boolean.at(exp.e_boolean);
return Result{ .ok = true, .value = e.value, .side_effects = .no_side_effects };
},
- .e_number => |e| {
+ .e_number => {
+ const e = Expr.Data.Store.Number.at(exp.e_number);
return Result{ .ok = true, .value = e.value != 0.0 and !std.math.isNan(e.value), .side_effects = .no_side_effects };
},
- .e_big_int => |e| {
+ .e_big_int => {
+ const e = Expr.Data.Store.BigInt.at(exp.e_big_int);
return Result{ .ok = true, .value = !strings.eqlComptime(e.value, "0"), .side_effects = .no_side_effects };
},
- .e_string => |e| {
+ .e_string => {
+ const e = Expr.Data.Store.String.at(exp.e_string);
return Result{ .ok = true, .value = std.math.max(e.value.len, e.utf8.len) > 0, .side_effects = .no_side_effects };
},
.e_function, .e_arrow, .e_reg_exp => {
@@ -975,7 +1008,8 @@ pub const SideEffects = enum(u2) {
.e_object, .e_array, .e_class => {
return Result{ .ok = true, .value = true, .side_effects = .could_have_side_effects };
},
- .e_unary => |e_| {
+ .e_unary => {
+ const e_ = Expr.Data.Store.Unary.at(exp.e_unary);
switch (e_.op) {
.un_void => {
return Result{ .ok = true, .value = false, .side_effects = .could_have_side_effects };
@@ -995,7 +1029,8 @@ pub const SideEffects = enum(u2) {
else => {},
}
},
- .e_binary => |e_| {
+ .e_binary => {
+ const e_ = Expr.Data.Store.Binary.at(exp.e_binary);
switch (e_.op) {
.bin_logical_or => {
// "anything || truthy" is truthy
@@ -1683,7 +1718,7 @@ pub const Prefill = struct {
pub var Filename = Expr.Data{ .e_string = &Prefill.String.Filename };
pub var LineNumber = Expr.Data{ .e_string = &Prefill.String.LineNumber };
pub var ColumnNumber = Expr.Data{ .e_string = &Prefill.String.ColumnNumber };
- pub var This = Expr.Data{ .e_this = &Prefill.Value.EThis };
+ pub var This = Expr.Data{ .e_this = E.This{} };
};
pub const Runtime = struct {
pub var JSXFilename = "__jsxFilename";
@@ -1696,12 +1731,12 @@ pub const Prefill = struct {
};
};
-var keyExprData = Expr.Data{ .e_string = &Prefill.String.Key };
-var jsxChildrenKeyData = Expr.Data{ .e_string = &Prefill.String.Children };
+// var keyExprData = Expr.Data{ .e_string = Prefill.String.Key };
+// var jsxChildrenKeyData = Expr.Data{ .e_string = Prefill.String.Children };
var nullExprValueData = E.Null{};
var falseExprValueData = E.Boolean{ .value = false };
-var nullValueExpr = Expr.Data{ .e_null = &nullExprValueData };
-var falseValueExpr = Expr.Data{ .e_boolean = &falseExprValueData };
+var nullValueExpr = Expr.Data{ .e_null = nullExprValueData };
+var falseValueExpr = Expr.Data{ .e_boolean = falseExprValueData };
// P is for Parser!
// public only because of Binding.ToExpr
@@ -1947,13 +1982,13 @@ pub const P = struct {
}
const str = arg.data.e_string;
- const import_record_index = p.addImportRecord(.dynamic, arg.loc, str.string(p.allocator) catch unreachable);
+ const import_record_index = p.addImportRecord(.dynamic, arg.loc, arg.getString().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;
return p.e(E.Import{
.expr = arg,
.import_record_index = Ref.toInt(import_record_index),
- // .leading_interior_comments = arg.data.e_string.
+ // .leading_interior_comments = arg.getString().
}, state.loc);
}
@@ -1973,7 +2008,9 @@ pub const P = struct {
pub fn transposeRequire(p: *P, arg: Expr, transpose_state: anytype) Expr {
switch (arg.data) {
- .e_string => |str| {
+ .e_string => {
+ const str = arg.getString();
+
// Ignore calls to require() if the control flow is provably dead here.
// We don't want to spend time scanning the required files if they will
// never be used.
@@ -2592,10 +2629,14 @@ pub const P = struct {
.e_missing => {
return null;
},
- .e_identifier => |ex| {
+ .e_identifier => {
+ const ex = expr.getIdentifier();
+
return p.b(B.Identifier{ .ref = ex.ref }, expr.loc);
},
- .e_array => |ex| {
+ .e_array => {
+ const ex = expr.getArray();
+
if (ex.comma_after_spread) |spread| {
invalid_loc.append(spread) catch unreachable;
}
@@ -2612,7 +2653,7 @@ pub const P = struct {
var _expr = item;
if (@as(Expr.Tag, item.data) == .e_spread) {
is_spread = true;
- item = item.data.e_spread.value;
+ item = item.getSpread().value;
}
const res = p.convertExprToBindingAndInitializer(&item, invalid_loc, is_spread);
items.append(js_ast.ArrayBinding{ .binding = res.binding orelse unreachable, .default_value = res.override_expr }) catch unreachable;
@@ -2624,7 +2665,9 @@ pub const P = struct {
.is_single_line = ex.is_single_line,
}, expr.loc);
},
- .e_object => |ex| {
+ .e_object => {
+ const ex = expr.getObject();
+
if (ex.comma_after_spread) |sp| {
invalid_loc.append(sp) catch unreachable;
}
@@ -2676,7 +2719,9 @@ pub const P = struct {
var override: ?ExprNodeIndex = null;
// zig syntax is sometimes painful
switch (expr.*.data) {
- .e_binary => |bin| {
+ .e_binary => {
+ const bin = expr.getBinary();
+
if (bin.op == .bin_assign) {
initializer = bin.right;
expr = &bin.left;
@@ -4050,7 +4095,9 @@ pub const P = struct {
// Handle the default export of an abstract class in TypeScript
if (p.options.ts 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 ident = expr.getIdentifier();
+
var stmtOpts = ParseStatementOptions{
.ts_decorators = opts.ts_decorators,
.is_name_optional = true,
@@ -4880,7 +4927,9 @@ pub const P = struct {
}
if (is_identifier) {
switch (expr.data) {
- .e_identifier => |ident| {
+ .e_identifier => {
+ var ident = expr.getIdentifier();
+
if (p.lexer.token == .t_colon and !opts.hasDecorators()) {
_ = try p.pushScopeForParsePass(.label, loc);
defer p.popScope();
@@ -5244,22 +5293,20 @@ pub const P = struct {
if (strings.eqlComptime(name, "require") and p.lexer.token == .t_open_paren) {
// "import ns = require('x')"
try p.lexer.next();
- const path = p.e(p.lexer.toEString(), p.lexer.loc());
+ var path = p.e(p.lexer.toEString(), p.lexer.loc());
try p.lexer.expect(.t_string_literal);
try p.lexer.expect(.t_close_paren);
const args = p.allocator.alloc(ExprNodeIndex, 1) catch unreachable;
args[0] = path;
- var call_ptr = p.allocator.create(E.Call) catch unreachable;
- call_ptr.* = E.Call{ .target = value, .args = args };
- value.data = .{ .e_call = call_ptr };
+ value.data = .{ .e_call = Expr.Data.Store.Call.append(E.Call{ .target = value, .args = args }) };
} else {
// "import Foo = Bar"
// "import Foo = Bar.Baz"
while (p.lexer.token == .t_dot) {
try p.lexer.next();
- var dot = p.allocator.create(E.Dot) catch unreachable;
- dot.* = E.Dot{ .target = value, .name = p.lexer.identifier, .name_loc = p.lexer.loc() };
- value.data = .{ .e_dot = dot };
+ value.data = .{ .e_dot = Expr.Data.Store.Dot.append(
+ E.Dot{ .target = value, .name = p.lexer.identifier, .name_loc = p.lexer.loc() },
+ ) };
try p.lexer.expect(.t_identifier);
}
}
@@ -5969,9 +6016,11 @@ pub const P = struct {
if (isDirectivePrologue) {
isDirectivePrologue = false;
switch (stmt.data) {
- .s_expr => |expr| {
- switch (stmt.getExpr().value.data) {
- .e_string => |str| {
+ .s_expr => {
+ const expr = stmt.getExpr();
+ switch (expr.value.data) {
+ .e_string => {
+ const str = expr.value.getString();
if (!str.prefer_template) {
// stmt.data = Stmt.Data{
// .s_directive = p.m(S.Directive{
@@ -6584,10 +6633,14 @@ pub const P = struct {
if (had_pure_comment_before and level.lt(.call)) {
expr = try p.parseSuffix(expr, @intToEnum(Level, @enumToInt(Level.call) - 1), errors, flags);
switch (expr.data) {
- .e_call => |ex| {
+ .e_call => {
+ const ex = expr.getCall();
+
ex.can_be_unwrapped_if_unused = true;
},
- .e_new => |ex| {
+ .e_new => {
+ const ex = expr.getNew();
+
ex.can_be_unwrapped_if_unused = true;
},
else => {},
@@ -6673,10 +6726,14 @@ pub const P = struct {
pub fn markExprAsParenthesized(p: *P, expr: *Expr) void {
switch (expr.data) {
- .e_array => |ex| {
+ .e_array => {
+ const ex = expr.getArray();
+
ex.is_parenthesized = true;
},
- .e_object => |ex| {
+ .e_object => {
+ const ex = expr.getObject();
+
ex.is_parenthesized = true;
},
else => {
@@ -6752,7 +6809,9 @@ pub const P = struct {
// Handle index signatures
if (p.options.ts and p.lexer.token == .t_colon and wasIdentifier and opts.is_class) {
switch (expr.data) {
- .e_identifier => |ident| {
+ .e_identifier => {
+ var ident = expr.getIdentifier();
+
try p.lexer.next();
try p.skipTypeScriptType(.lowest);
try p.lexer.expect(.t_close_bracket);
@@ -6901,7 +6960,9 @@ pub const P = struct {
// Forbid the names "constructor" and "prototype" in some cases
if (!is_computed) {
switch (key.data) {
- .e_string => |str| {
+ .e_string => {
+ const str = key.getString();
+
if (str.eql(string, "constructor") or (opts.is_static and str.eql(string, "prototype"))) {
// TODO: fmt error message to include string value.
p.log.addRangeError(p.source, key_range, "Invalid field name") catch unreachable;
@@ -6924,7 +6985,9 @@ pub const P = struct {
// Special-case private identifiers
switch (key.data) {
- .e_private_identifier => |private| {
+ .e_private_identifier => {
+ const private = key.getPrivateIdentifier();
+
const name = p.loadNameFromRef(private.ref);
if (strings.eqlComptime(name, "#constructor")) {
p.log.addRangeError(p.source, key_range, "Invalid field name \"#constructor\"") catch unreachable;
@@ -6968,7 +7031,9 @@ pub const P = struct {
// Forbid the names "constructor" and "prototype" in some cases
if (opts.is_class and !is_computed) {
switch (key.data) {
- .e_string => |str| {
+ .e_string => {
+ const str = key.getString();
+
if (!opts.is_static and str.eql(string, "constructor")) {
if (kind == .get) {
p.log.addRangeError(p.source, key_range, "Class constructor cannot be a getter") catch unreachable;
@@ -7035,7 +7100,9 @@ pub const P = struct {
// Special-case private identifiers
switch (key.data) {
- .e_private_identifier => |private| {
+ .e_private_identifier => {
+ const private = key.getPrivateIdentifier();
+
var declare: Symbol.Kind = undefined;
var suffix: string = "";
switch (kind) {
@@ -7172,7 +7239,9 @@ pub const P = struct {
// Forbid decorators on class constructors
if (opts.ts_decorators.len > 0) {
switch ((property.key orelse p.panic("Internal error: Expected property {s} to have a key.", .{property})).data) {
- .e_string => |str| {
+ .e_string => {
+ const str = property.key.?.getString();
+
if (str.eql(string, "constructor")) {
p.log.addError(p.source, first_decorator_loc, "TypeScript does not allow decorators on class constructors") catch unreachable;
}
@@ -7996,7 +8065,9 @@ pub const P = struct {
// Warn about "!a in b" instead of "!(a in b)"
switch (left.data) {
- .e_unary => |unary| {
+ .e_unary => {
+ const unary = expr.getUnary();
+
if (unary.op == .un_not) {
// TODO:
// p.log.addRangeWarning(source: ?Source, r: Range, text: string)
@@ -8017,7 +8088,9 @@ pub const P = struct {
// example of code with this problem: https://github.com/mrdoob/three.js/pull/11182.
if (!p.options.suppress_warnings_about_weird_code) {
switch (left.data) {
- .e_unary => |unary| {
+ .e_unary => {
+ const unary = expr.getUnary();
+
if (unary.op == .un_not) {
// TODO:
// p.log.addRangeWarning(source: ?Source, r: Range, text: string)
@@ -9212,7 +9285,7 @@ pub const P = struct {
// These never have side effects
.s_function => {},
.s_class => {
- if (!p.classCanBeRemovedIfUnused(&stmt.getClass().class)) {
+ if (!p.classCanBeRemovedIfUnused(&s2.getClass().class)) {
return false;
}
},
@@ -9346,14 +9419,18 @@ pub const P = struct {
// 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 => {
+ const e_ = expr.getString();
+
// 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 => {
+ const e_ = expr.getNumber();
+
// idc about legacy octal loc
},
- .e_this => |e_| {
+ .e_this => {
if (p.valueForThis(expr.loc)) |exp| {
return exp;
}
@@ -9365,8 +9442,8 @@ pub const P = struct {
// }
},
- .e_import_meta => |exp| {
- const is_delete_target = std.meta.activeTag(p.delete_target) == .e_import_meta and exp == p.delete_target.e_import_meta;
+ .e_import_meta => {
+ const is_delete_target = std.meta.activeTag(p.delete_target) == .e_import_meta and &expr.data.e_import_meta == &p.delete_target.e_import_meta;
if (p.define.dots.get("meta")) |meta| {
for (meta) |define| {
@@ -9382,11 +9459,15 @@ pub const P = struct {
return p.e(E.Identifier{ .ref = p.import_meta_ref }, expr.loc);
}
},
- .e_spread => |exp| {
+ .e_spread => {
+ const exp = expr.getSpread();
+
exp.value = p.visitExpr(exp.value);
},
- .e_identifier => |e_| {
- const is_delete_target = @as(Expr.Tag, p.delete_target) == .e_identifier and e_ == p.delete_target.e_identifier;
+ .e_identifier => {
+ const e_ = expr.getIdentifier();
+
+ const is_delete_target = @as(Expr.Tag, p.delete_target) == .e_identifier and expr.data.e_identifier.index == p.delete_target.e_identifier.index;
const name = p.loadNameFromRef(e_.ref);
if (p.isStrictMode() and js_lexer.StrictModeReservedWords.has(name)) {
@@ -9437,10 +9518,14 @@ pub const P = struct {
.was_originally_identifier = true,
});
},
- .e_private_identifier => |e_| {
+ .e_private_identifier => {
+ const e_ = expr.getPrivateIdentifier();
+
p.panic("Unexpected private identifier. This is an internal error - not your fault.", .{});
},
- .e_jsx_element => |e_| {
+ .e_jsx_element => {
+ const e_ = expr.getJsxElement();
+
const tag = tagger: {
if (e_.tag) |_tag| {
break :tagger p.visitExpr(_tag);
@@ -9475,7 +9560,7 @@ pub const P = struct {
if (e_.properties.len > 0) {
if (e_.key) |key| {
var props = List(G.Property).fromOwnedSlice(p.allocator, e_.properties);
- props.append(G.Property{ .key = Expr{ .loc = key.loc, .data = keyExprData }, .value = key }) catch unreachable;
+ // props.append(G.Property{ .key = Expr{ .loc = key.loc, .data = keyExprData }, .value = key }) catch unreachable;
args[0] = p.e(E.Object{ .properties = props.toOwnedSlice() }, expr.loc);
} else {
args[0] = p.e(E.Object{ .properties = e_.properties }, expr.loc);
@@ -9513,7 +9598,7 @@ pub const P = struct {
for (e_.children) |child, i| {
e_.children[i] = p.visitExpr(child);
}
- const children_key = Expr{ .data = jsxChildrenKeyData, .loc = expr.loc };
+ const children_key = p.e(E.String{ .utf8 = "key" }, expr.loc);
if (e_.children.len == 1) {
props.append(G.Property{
@@ -9540,29 +9625,29 @@ pub const P = struct {
}
if (p.options.jsx.development) {
- args[3] = Expr{ .loc = expr.loc, .data = falseValueExpr };
+ // args[3] = Expr{ .loc = expr.loc, .data = falseValueExpr };
// placeholder src prop for now
- var source = p.allocator.alloc(G.Property, 3) catch unreachable;
- p.recordUsage(p.jsx_filename_ref);
- source[0] = G.Property{
- .key = Expr{ .loc = expr.loc, .data = Prefill.Data.Filename },
- .value = p.e(E.Identifier{ .ref = p.jsx_filename_ref }, expr.loc),
- };
+ // var source = p.allocator.alloc(G.Property, 3) catch unreachable;
+ // p.recordUsage(p.jsx_filename_ref);
+ // source[0] = G.Property{
+ // .key = Expr{ .loc = expr.loc, .data = Prefill.Data.Filename },
+ // .value = p.e(E.Identifier{ .ref = p.jsx_filename_ref }, expr.loc),
+ // };
- source[1] = G.Property{
- .key = Expr{ .loc = expr.loc, .data = Prefill.Data.LineNumber },
- .value = p.e(E.Number{ .value = @intToFloat(f64, expr.loc.start) }, expr.loc),
- };
+ // source[1] = G.Property{
+ // .key = Expr{ .loc = expr.loc, .data = Prefill.Data.LineNumber },
+ // .value = p.e(E.Number{ .value = @intToFloat(f64, expr.loc.start) }, expr.loc),
+ // };
- source[2] = G.Property{
- .key = Expr{ .loc = expr.loc, .data = Prefill.Data.ColumnNumber },
- .value = p.e(E.Number{ .value = @intToFloat(f64, expr.loc.start) }, expr.loc),
- };
+ // source[2] = G.Property{
+ // .key = Expr{ .loc = expr.loc, .data = Prefill.Data.ColumnNumber },
+ // .value = p.e(E.Number{ .value = @intToFloat(f64, expr.loc.start) }, expr.loc),
+ // };
- args[4] = p.e(E.Object{
- .properties = source,
- }, expr.loc);
- args[5] = Expr{ .data = Prefill.Data.This, .loc = expr.loc };
+ // args[4] = p.e(E.Object{
+ // .properties = source,
+ // }, expr.loc);
+ // args[5] = Expr{ .data = Prefill.Data.This, .loc = expr.loc };
}
return p.e(E.Call{
@@ -9577,7 +9662,9 @@ pub const P = struct {
}
},
- .e_template => |e_| {
+ .e_template => {
+ const e_ = expr.getTemplate();
+
if (e_.tag) |tag| {
e_.tag = p.visitExpr(tag);
}
@@ -9588,10 +9675,14 @@ pub const P = struct {
}
},
- .e_binary => |e_| {
+ .e_binary => {
+ const e_ = expr.getBinary();
+
switch (e_.left.data) {
// Special-case private identifiers
- .e_private_identifier => |private| {
+ .e_private_identifier => {
+ const private = expr.getPrivateIdentifier();
+
if (e_.op == .bin_in) {
const name = p.loadNameFromRef(private.ref);
const result = p.findSymbol(e_.left.loc, name) catch unreachable;
@@ -9612,8 +9703,8 @@ pub const P = struct {
else => {},
}
- const is_call_target = @as(Expr.Tag, p.call_target) == .e_binary and e_ == p.call_target.e_binary;
- const is_stmt_expr = @as(Expr.Tag, p.stmt_expr_value) == .e_binary and e_ == p.stmt_expr_value.e_binary;
+ const is_call_target = @as(Expr.Tag, p.call_target) == .e_binary and expr.data.e_binary.index == p.call_target.e_binary.index;
+ const is_stmt_expr = @as(Expr.Tag, p.stmt_expr_value) == .e_binary and expr.data.e_binary.index == p.stmt_expr_value.e_binary.index;
const was_anonymous_named_expr = p.isAnonymousNamedExpr(e_.right);
e_.left = p.visitExprInOut(e_.left, ExprIn{
@@ -9861,7 +9952,7 @@ pub const P = struct {
// Optionally preserve the name
if (@as(Expr.Tag, e_.left.data) == .e_identifier) {
- e_.right = p.maybeKeepExprSymbolName(e_.right, p.symbols.items[e_.left.data.e_identifier.ref.inner_index].original_name, was_anonymous_named_expr);
+ e_.right = p.maybeKeepExprSymbolName(e_.right, p.symbols.items[e_.left.getIdentifier().ref.inner_index].original_name, was_anonymous_named_expr);
}
},
.bin_add_assign => {
@@ -9912,9 +10003,11 @@ pub const P = struct {
else => {},
}
},
- .e_index => |e_| {
- const is_call_target = std.meta.activeTag(p.call_target) == .e_index and e_ == p.call_target.e_index;
- const is_delete_target = std.meta.activeTag(p.delete_target) == .e_index and e_ == p.delete_target.e_index;
+ .e_index => {
+ const e_ = expr.getIndex();
+
+ const is_call_target = std.meta.activeTag(p.call_target) == .e_index and expr.data.e_index.index == p.call_target.e_index.index;
+ const is_delete_target = std.meta.activeTag(p.delete_target) == .e_index and expr.data.e_index.index == p.delete_target.e_index.index;
const target = p.visitExprInOut(e_.target, ExprIn{
// this is awkward due to a zig compiler bug
@@ -9928,7 +10021,7 @@ pub const P = struct {
in.assign_target,
is_delete_target,
e_.target,
- e_.index.data.e_string.string(p.allocator) catch unreachable,
+ e_.index.getString().string(p.allocator) catch unreachable,
e_.index.loc,
is_call_target,
)) |val| {
@@ -9940,20 +10033,22 @@ pub const P = struct {
// though this is a run-time error, we make it a compile-time error when
// bundling because scope hoisting means these will no longer be run-time
// errors.
- if ((in.assign_target != .none or is_delete_target) and @as(Expr.Tag, e_.target.data) == .e_identifier and p.symbols.items[e_.target.data.e_identifier.ref.inner_index].kind == .import) {
+ if ((in.assign_target != .none or is_delete_target) and @as(Expr.Tag, e_.target.data) == .e_identifier and p.symbols.items[e_.target.getIdentifier().ref.inner_index].kind == .import) {
const r = js_lexer.rangeOfIdentifier(p.source, e_.target.loc);
p.log.addRangeErrorFmt(
p.source,
r,
p.allocator,
"Cannot assign to property on import \"{s}\"",
- .{p.symbols.items[e_.target.data.e_identifier.ref.inner_index].original_name},
+ .{p.symbols.items[e_.target.getIdentifier().ref.inner_index].original_name},
) catch unreachable;
}
return p.e(e_, expr.loc);
},
- .e_unary => |e_| {
+ .e_unary => {
+ const e_ = expr.getUnary();
+
switch (e_.op) {
.un_typeof => {
e_.value = p.visitExprInOut(e_.value, ExprIn{ .assign_target = e_.op.unaryAssignTarget() });
@@ -10017,9 +10112,11 @@ pub const P = struct {
},
}
},
- .e_dot => |e_| {
- const is_delete_target = @as(Expr.Tag, p.delete_target) == .e_dot and e_ == p.delete_target.e_dot;
- const is_call_target = @as(Expr.Tag, p.call_target) == .e_dot and e_ == p.call_target.e_dot;
+ .e_dot => {
+ const e_ = expr.getDot();
+
+ const is_delete_target = @as(Expr.Tag, p.delete_target) == .e_dot and expr.data.e_dot.index == p.delete_target.e_dot.index;
+ const is_call_target = @as(Expr.Tag, p.call_target) == .e_dot and expr.data.e_dot.index == p.call_target.e_dot.index;
if (p.define.dots.get(e_.name)) |parts| {
for (parts) |define| {
@@ -10045,7 +10142,7 @@ pub const P = struct {
}
// Track ".then().catch()" chains
- if (is_call_target and @as(Expr.Tag, p.then_catch_chain.next_target) == .e_dot and p.then_catch_chain.next_target.e_dot == e_) {
+ if (is_call_target and @as(Expr.Tag, p.then_catch_chain.next_target) == .e_dot and p.then_catch_chain.next_target.e_dot.index == expr.data.e_dot.index) {
if (strings.eqlComptime(e_.name, "catch")) {
p.then_catch_chain = ThenCatchChain{
.next_target = e_.target.data,
@@ -10074,8 +10171,10 @@ pub const P = struct {
}
}
},
- .e_if => |e_| {
- const is_call_target = @as(Expr.Data, p.call_target) == .e_if and e_ == p.call_target.e_if;
+ .e_if => {
+ const e_ = expr.getIf();
+
+ const is_call_target = @as(Expr.Data, p.call_target) == .e_if and expr.data.e_if.index == p.call_target.e_if.index;
e_.test_ = p.visitExpr(e_.test_);
@@ -10103,16 +10202,22 @@ pub const P = struct {
}
}
},
- .e_await => |e_| {
+ .e_await => {
+ const e_ = expr.getAwait();
+
p.await_target = e_.value.data;
e_.value = p.visitExpr(e_.value);
},
- .e_yield => |e_| {
+ .e_yield => {
+ const e_ = expr.getYield();
+
if (e_.value) |val| {
e_.value = p.visitExpr(val);
}
},
- .e_array => |e_| {
+ .e_array => {
+ const e_ = expr.getArray();
+
if (in.assign_target != .none) {
if (e_.comma_after_spread) |spread| {
p.log.addRangeError(p.source, logger.Range{ .loc = spread, .len = 1 }, "Unexpected \",\" after rest pattern") catch unreachable;
@@ -10126,10 +10231,14 @@ pub const P = struct {
const data = item.data;
switch (data) {
.e_missing => {},
- .e_spread => |spread| {
+ .e_spread => {
+ const spread = item.getSpread();
+
spread.value = p.visitExprInOut(spread.value, ExprIn{ .assign_target = in.assign_target });
},
- .e_binary => |e2| {
+ .e_binary => {
+ const e2 = item.getBinary();
+
if (in.assign_target != .none and e2.op == .bin_assign) {
const was_anonymous_named_expr = p.isAnonymousNamedExpr(e2.right);
e2.left = p.visitExprInOut(e2.left, ExprIn{ .assign_target = .replace });
@@ -10138,7 +10247,7 @@ pub const P = struct {
if (@as(Expr.Tag, e2.left.data) == .e_identifier) {
e2.right = p.maybeKeepExprSymbolName(
e2.right,
- p.symbols.items[e2.left.data.e_identifier.ref.inner_index].original_name,
+ p.symbols.items[e2.left.getIdentifier().ref.inner_index].original_name,
was_anonymous_named_expr,
);
}
@@ -10153,7 +10262,9 @@ pub const P = struct {
e_.items[i] = item;
}
},
- .e_object => |e_| {
+ .e_object => {
+ const e_ = expr.getObject();
+
if (in.assign_target != .none) {
p.maybeCommaSpreadError(e_.comma_after_spread);
}
@@ -10167,7 +10278,7 @@ pub const P = struct {
// Forbid duplicate "__proto__" properties according to the specification
if (!property.flags.is_computed and !property.flags.was_shorthand and !property.flags.is_method and in.assign_target == .none and key.data.isStringValue() and strings.eqlComptime(
// __proto__ is utf8, assume it lives in refs
- key.data.e_string.utf8,
+ key.getString().utf8,
"__proto__",
)) {
if (has_proto) {
@@ -10183,7 +10294,9 @@ pub const P = struct {
// Extract the initializer for expressions like "({ a: b = c } = d)"
if (in.assign_target != .none and property.initializer != null and property.value != null) {
switch (property.value.?.data) {
- .e_binary => |bin| {
+ .e_binary => {
+ const bin = property.value.?.getBinary();
+
if (bin.op == .bin_assign) {
property.initializer = bin.right;
property.value = bin.left;
@@ -10205,7 +10318,7 @@ pub const P = struct {
if (@as(Expr.Tag, val.data) == .e_identifier) {
property.initializer = p.maybeKeepExprSymbolName(
property.initializer orelse unreachable,
- p.symbols.items[val.data.e_identifier.ref.inner_index].original_name,
+ p.symbols.items[val.getIdentifier().ref.inner_index].original_name,
was_anonymous_named_expr,
);
}
@@ -10213,30 +10326,34 @@ pub const P = struct {
}
}
},
- .e_import => |e_| {
+ .e_import => {
+ const e_ = expr.getImport();
+
const state = TransposeState{
- .is_await_target = if (p.await_target != null) p.await_target.?.e_import == e_ else false,
- .is_then_catch_target = e_ == p.then_catch_chain.next_target.e_import and p.then_catch_chain.has_catch,
+ .is_await_target = if (p.await_target != null) p.await_target.?.e_import.eql(expr.data.e_index) else false,
+ .is_then_catch_target = expr.data.e_import.eql(p.then_catch_chain.next_target.e_import) and p.then_catch_chain.has_catch,
.loc = e_.expr.loc,
};
e_.expr = p.visitExpr(e_.expr);
return p.import_transposer.maybeTransposeIf(e_.expr, state);
},
- .e_call => |e_| {
+ .e_call => {
+ const e_ = expr.getCall();
+
p.call_target = e_.target.data;
p.then_catch_chain = ThenCatchChain{
.next_target = e_.target.data,
.has_multiple_args = e_.args.len >= 2,
- .has_catch = @as(Expr.Tag, p.then_catch_chain.next_target) == .e_call and p.then_catch_chain.next_target.e_call == e_ and p.then_catch_chain.has_catch,
+ .has_catch = @as(Expr.Tag, p.then_catch_chain.next_target) == .e_call and p.then_catch_chain.next_target.e_call.eql(expr.data.e_call) and p.then_catch_chain.has_catch,
};
// Prepare to recognize "require.resolve()" calls
// const could_be_require_resolve = (e_.args.len == 1 and @as(
// Expr.Tag,
// e_.target.data,
- // ) == .e_dot and e_.target.data.e_dot.optional_chain == null and strings.eql(
+ // ) == .e_dot and e_.target.getDot().optional_chain == null and strings.eql(
// e_.target.dat.e_dot.name,
// "resolve",
// ));
@@ -10252,7 +10369,7 @@ pub const P = struct {
has_spread = has_spread or @as(Expr.Tag, e_.args[i].data) == .e_spread;
}
- if (e_.optional_chain == null and @as(Expr.Tag, e_.target.data) == .e_identifier and e_.target.data.e_identifier.ref.eql(p.require_ref)) {
+ if (e_.optional_chain == null and @as(Expr.Tag, e_.target.data) == .e_identifier and e_.target.getIdentifier().ref.eql(p.require_ref)) {
// Heuristic: omit warnings inside try/catch blocks because presumably
// the try/catch statement is there to handle the potential run-time
// error from the unbundled require() call failing.
@@ -10266,7 +10383,9 @@ pub const P = struct {
return expr;
},
- .e_new => |e_| {
+ .e_new => {
+ const e_ = expr.getNew();
+
e_.target = p.visitExpr(e_.target);
// p.warnA
@@ -10275,7 +10394,9 @@ pub const P = struct {
e_.args[i] = p.visitExpr(e_.args[i]);
}
},
- .e_arrow => |e_| {
+ .e_arrow => {
+ const e_ = expr.getArrow();
+
const old_fn_or_arrow_data = std.mem.toBytes(p.fn_or_arrow_data_visit);
p.fn_or_arrow_data_visit = FnOrArrowDataVisit{
.is_arrow = true,
@@ -10310,13 +10431,17 @@ pub const P = struct {
p.fn_only_data_visit.is_inside_async_arrow_fn = old_inside_async_arrow_fn;
p.fn_or_arrow_data_visit = std.mem.bytesToValue(@TypeOf(p.fn_or_arrow_data_visit), &old_fn_or_arrow_data);
},
- .e_function => |e_| {
+ .e_function => {
+ const e_ = expr.getFunction();
+
e_.func = p.visitFunc(e_.func, expr.loc);
if (e_.func.name) |name| {
return p.keepExprSymbolName(expr, p.symbols.items[name.ref.?.inner_index].original_name);
}
},
- .e_class => |e_| {
+ .e_class => {
+ const e_ = expr.getClass();
+
// This might be wrong.
_ = p.visitClass(expr.loc, e_);
},
@@ -10387,7 +10512,7 @@ pub const P = struct {
// var value = p.callRuntime(_value.loc, "ℹ", p.expr_list.items[start..p.expr_list.items.len]);
// // Make sure tree shaking removes this if the function is never used
- // value.data.e_call.can_be_unwrapped_if_unused = true;
+ // value.getCall().can_be_unwrapped_if_unused = true;
// return value;
}
@@ -10473,13 +10598,19 @@ pub const P = struct {
return true;
},
- .e_dot => |ex| {
+ .e_dot => {
+ const ex = expr.getDot();
+
return ex.can_be_removed_if_unused;
},
- .e_class => |ex| {
+ .e_class => {
+ const ex = expr.getClass();
+
return p.classCanBeRemovedIfUnused(ex);
},
- .e_identifier => |ex| {
+ .e_identifier => {
+ const ex = expr.getIdentifier();
+
if (ex.must_keep_due_to_with_stmt) {
return false;
}
@@ -10507,7 +10638,9 @@ pub const P = struct {
return true;
}
},
- .e_import_identifier => |ex| {
+ .e_import_identifier => {
+ const ex = expr.getImportIdentifier();
+
// References to an ES6 import item are always side-effect free in an
// ECMAScript environment.
//
@@ -10526,10 +10659,14 @@ pub const P = struct {
// references as being side-effect free.
return true;
},
- .e_if => |ex| {
+ .e_if => {
+ const ex = expr.getIf();
+
return p.exprCanBeRemovedIfUnused(ex.test_) and p.exprCanBeRemovedIfUnused(ex.yes) and p.exprCanBeRemovedIfUnused(ex.no);
},
- .e_array => |ex| {
+ .e_array => {
+ const ex = expr.getArray();
+
for (ex.items) |item| {
if (!p.exprCanBeRemovedIfUnused(item)) {
return false;
@@ -10538,7 +10675,9 @@ pub const P = struct {
return true;
},
- .e_object => |ex| {
+ .e_object => {
+ const ex = expr.getObject();
+
for (ex.properties) |property| {
// The key must still be evaluated if it's computed or a spread
@@ -10554,7 +10693,9 @@ pub const P = struct {
}
return true;
},
- .e_call => |ex| {
+ .e_call => {
+ const ex = expr.getCall();
+
// A call that has been marked "__PURE__" can be removed if all arguments
// can be removed. The annotation causes us to ignore the target.
if (ex.can_be_unwrapped_if_unused) {
@@ -10567,7 +10708,9 @@ pub const P = struct {
return true;
},
- .e_new => |ex| {
+ .e_new => {
+ const ex = expr.getNew();
+
// A call that has been marked "__PURE__" can be removed if all arguments
// can be removed. The annotation causes us to ignore the target.
if (ex.can_be_unwrapped_if_unused) {
@@ -10580,7 +10723,9 @@ pub const P = struct {
return true;
},
- .e_unary => |ex| {
+ .e_unary => {
+ const ex = expr.getUnary();
+
switch (ex.op) {
.un_typeof, .un_void, .un_not => {
return p.exprCanBeRemovedIfUnused(ex.value);
@@ -10588,7 +10733,9 @@ pub const P = struct {
else => {},
}
},
- .e_binary => |ex| {
+ .e_binary => {
+ const ex = expr.getBinary();
+
switch (ex.op) {
.bin_strict_eq, .bin_strict_ne, .bin_comma, .bin_logical_or, .bin_logical_and, .bin_nullish_coalescing => {
return p.exprCanBeRemovedIfUnused(ex.left) and p.exprCanBeRemovedIfUnused(ex.right);
@@ -10620,7 +10767,7 @@ pub const P = struct {
is_call_target: bool,
) ?Expr {
if (@as(Expr.Tag, target.data) == .e_identifier) {
- const id = target.data.e_identifier;
+ const id = target.getIdentifier();
// Rewrite property accesses on explicit namespace imports as an identifier.
// This lets us replace them easily in the printer to rebind them to
@@ -10830,7 +10977,9 @@ pub const P = struct {
// Discard type-only export default statements
if (p.options.ts) {
switch (expr.data) {
- .e_identifier => |ident| {
+ .e_identifier => {
+ var ident = expr.getIdentifier();
+
const symbol = p.symbols.items[ident.ref.inner_index];
if (symbol.kind == .unbound) {
if (p.local_type_names.get(symbol.original_name)) |local_type| {
@@ -11362,13 +11511,17 @@ pub const P = struct {
if (enum_value.value != null) {
enum_value.value = p.visitExpr(enum_value.value.?);
switch (enum_value.value.?.data) {
- .e_number => |num| {
+ .e_number => {
+ const num = assign_target.getNumber();
+
// prob never allocates in practice
values_so_far.put(name.string(p.allocator) catch unreachable, num.value) catch unreachable;
has_numeric_value = true;
next_numeric_value = num.value + 1.0;
},
- .e_string => |str| {
+ .e_string => {
+ const str = assign_target.getString();
+
has_string_value = true;
},
else => {},
@@ -11751,10 +11904,14 @@ pub const P = struct {
.e_arrow => {
return true;
},
- .e_function => |func| {
+ .e_function => {
+ const func = expr.getFunction();
+
return func.func.name == null;
},
- .e_class => |class| {
+ .e_class => {
+ const class = expr.getClass();
+
return class.class_name == null;
},
else => {
@@ -11765,7 +11922,9 @@ pub const P = struct {
pub fn valueForDefine(p: *P, loc: logger.Loc, assign_target: js_ast.AssignTarget, is_delete_target: bool, define_data: *const DefineData) Expr {
switch (define_data.value) {
- .e_identifier => |ident| {
+ .e_identifier => {
+ var ident = Expr.Data.Store.Identifier.at(define_data.value.e_identifier);
+
return p.handleIdentifier(
loc,
ident,
@@ -11788,7 +11947,9 @@ pub const P = struct {
pub fn isDotDefineMatch(p: *P, expr: Expr, parts: []const string) bool {
switch (expr.data) {
- .e_dot => |ex| {
+ .e_dot => {
+ const ex = expr.getDot();
+
if (parts.len > 1) {
if (ex.optional_chain != null) {
return false;
@@ -11800,10 +11961,12 @@ pub const P = struct {
return is_tail_match and p.isDotDefineMatch(ex.target, parts[0..last]);
}
},
- .e_import_meta => |ex| {
+ .e_import_meta => {
return parts.len == 2 and strings.eqlComptime(parts[0], "import") and strings.eqlComptime(parts[1], "meta");
},
- .e_identifier => |ex| {
+ .e_identifier => {
+ const ex = expr.getIdentifier();
+
// The last expression must be an identifier
if (parts.len == 1) {
const name = p.loadNameFromRef(ex.ref);
@@ -12027,7 +12190,7 @@ pub const P = struct {
// Special-case EPrivateIdentifier to allow it here
if (is_private) {
- p.recordDeclaredSymbol(property.key.?.data.e_private_identifier.ref) catch unreachable;
+ p.recordDeclaredSymbol(property.key.?.getPrivateIdentifier().ref) catch unreachable;
} else if (property.key) |key| {
class.properties[i].key = p.visitExpr(key);
}
@@ -12050,7 +12213,7 @@ pub const P = struct {
if (is_private) {} else if (!property.flags.is_method and !property.flags.is_computed) {
if (property.key) |key| {
if (@as(Expr.Tag, key.data) == .e_string) {
- name_to_keep = key.data.e_string.string(p.allocator) catch unreachable;
+ name_to_keep = key.getString().string(p.allocator) catch unreachable;
}
}
}
@@ -12327,7 +12490,9 @@ pub const P = struct {
while (i < items.len) : (i += 1) {
var is_spread = false;
switch (items[i].data) {
- .e_spread => |v| {
+ .e_spread => {
+ const v = items[i].getSpread();
+
is_spread = true;
items[i] = v.value;
},
@@ -12604,6 +12769,7 @@ pub const P = struct {
pub fn init(allocator: *std.mem.Allocator, log: *logger.Log, source: *const logger.Source, define: *Define, lexer: js_lexer.Lexer, opts: Parser.Options) !*P {
Stmt.Data.Store.create(allocator);
+ Expr.Data.Store.create(allocator);
var scope_order = try ScopeOrderList.initCapacity(allocator, 1);
var scope = try allocator.create(Scope);
diff --git a/src/js_printer.zig b/src/js_printer.zig
index a95d3e43a..de467a105 100644
--- a/src/js_printer.zig
+++ b/src/js_printer.zig
@@ -682,7 +682,8 @@ pub fn NewPrinter(comptime ascii_only: bool) type {
pub fn isUnboundEvalIdentifier(p: *Printer, value: Expr) bool {
switch (value.data) {
- .e_identifier => |ident| {
+ .e_identifier => {
+ const ident = value.getIdentifier();
if (ident.ref.is_source_contents_slice) return false;
const symbol = p.symbols.get(p.symbols.follow(ident.ref)) orelse return false;
@@ -838,37 +839,41 @@ pub fn NewPrinter(comptime ascii_only: bool) type {
defer debugl("</printExpr>");
switch (expr.data) {
- .e_missing => |e| {},
- .e_undefined => |e| {
+ .e_missing => {},
+ .e_undefined => {
p.printSpaceBeforeIdentifier();
p.printUndefined(level);
},
- .e_super => |e| {
+ .e_super => {
p.printSpaceBeforeIdentifier();
p.print("super");
},
- .e_null => |e| {
+ .e_null => {
p.printSpaceBeforeIdentifier();
p.print("null");
},
- .e_this => |e| {
+ .e_this => {
p.printSpaceBeforeIdentifier();
p.print("this");
},
- .e_spread => |e| {
+ .e_spread => {
+ const e = expr.getSpread();
+
p.print("...");
p.printExpr(e.value, .comma, ExprFlag.None());
},
- .e_new_target => |e| {
+ .e_new_target => {
p.printSpaceBeforeIdentifier();
p.print("new.target");
},
- .e_import_meta => |e| {
+ .e_import_meta => {
p.printSpaceBeforeIdentifier();
p.print("import.meta");
},
- .e_new => |e| {
+ .e_new => {
+ const e = expr.getNew();
+
const has_pure_comment = e.can_be_unwrapped_if_unused;
const wrap = level.gte(.call) or (has_pure_comment and level.gte(.postfix));
@@ -908,7 +913,9 @@ pub fn NewPrinter(comptime ascii_only: bool) type {
p.print(")");
}
},
- .e_call => |e| {
+ .e_call => {
+ const e = expr.getCall();
+
var wrap = level.gte(.new) or flags.forbid_call;
var target_flags = ExprFlag.None();
if (e.optional_chain == null) {
@@ -964,10 +971,14 @@ pub fn NewPrinter(comptime ascii_only: bool) type {
p.print(")");
}
},
- .e_require => |e| {
+ .e_require => {
+ const e = expr.getRequire();
+
p.printRequireOrImportExpr(e.import_record_index, &([_]G.Comment{}), level, flags);
},
- .e_require_or_require_resolve => |e| {
+ .e_require_or_require_resolve => {
+ const e = expr.getRequireOrRequireResolve();
+
const wrap = level.gte(.new) or flags.forbid_call;
if (wrap) {
p.print("(");
@@ -992,7 +1003,9 @@ pub fn NewPrinter(comptime ascii_only: bool) type {
p.print(")");
}
},
- .e_import => |e| {
+ .e_import => {
+ const e = expr.getImport();
+
// Handle non-string expressions
if (Ref.isSourceIndexNull(e.import_record_index)) {
const wrap = level.gte(.new) or flags.forbid_call;
@@ -1024,7 +1037,9 @@ pub fn NewPrinter(comptime ascii_only: bool) type {
p.printRequireOrImportExpr(e.import_record_index, e.leading_interior_comments, level, flags);
}
},
- .e_dot => |e| {
+ .e_dot => {
+ const e = expr.getDot();
+
var wrap = false;
if (e.optional_chain == null) {
flags.has_non_optional_chain_parent = false;
@@ -1063,7 +1078,9 @@ pub fn NewPrinter(comptime ascii_only: bool) type {
p.print(")");
}
},
- .e_index => |e| {
+ .e_index => {
+ const e = expr.getIndex();
+
var wrap = false;
if (e.optional_chain == null) {
flags.has_non_optional_chain_parent = false;
@@ -1086,7 +1103,8 @@ pub fn NewPrinter(comptime ascii_only: bool) type {
}
switch (e.index.data) {
- .e_private_identifier => |priv| {
+ .e_private_identifier => {
+ const priv = e.index.getPrivateIdentifier();
if (is_optional_chain_start) {
p.print(".");
}
@@ -1104,7 +1122,9 @@ pub fn NewPrinter(comptime ascii_only: bool) type {
p.print(")");
}
},
- .e_if => |e| {
+ .e_if => {
+ const e = expr.getIf();
+
const wrap = level.gte(.conditional);
if (wrap) {
p.print("(");
@@ -1123,7 +1143,9 @@ pub fn NewPrinter(comptime ascii_only: bool) type {
p.print(")");
}
},
- .e_arrow => |e| {
+ .e_arrow => {
+ const e = expr.getArrow();
+
const wrap = level.gte(.assign);
if (wrap) {
@@ -1163,7 +1185,9 @@ pub fn NewPrinter(comptime ascii_only: bool) type {
p.print(")");
}
},
- .e_function => |e| {
+ .e_function => {
+ const e = expr.getFunction();
+
const n = p.js.lenI();
var wrap = p.stmt_start == n or p.export_default_start == n;
@@ -1190,7 +1214,9 @@ pub fn NewPrinter(comptime ascii_only: bool) type {
p.print(")");
}
},
- .e_class => |e| {
+ .e_class => {
+ const e = expr.getClass();
+
const n = p.js.lenI();
var wrap = p.stmt_start == n or p.export_default_start == n;
if (wrap) {
@@ -1208,7 +1234,9 @@ pub fn NewPrinter(comptime ascii_only: bool) type {
p.print(")");
}
},
- .e_array => |e| {
+ .e_array => {
+ const e = expr.getArray();
+
p.print("[");
if (e.items.len > 0) {
if (!e.is_single_line) {
@@ -1249,7 +1277,9 @@ pub fn NewPrinter(comptime ascii_only: bool) type {
p.print("]");
},
- .e_object => |e| {
+ .e_object => {
+ const e = expr.getObject();
+
const n = p.js.lenI();
const wrap = p.stmt_start == n or p.arrow_expr_start == n;
@@ -1288,11 +1318,15 @@ pub fn NewPrinter(comptime ascii_only: bool) type {
p.print(")");
}
},
- .e_boolean => |e| {
+ .e_boolean => {
+ const e = expr.getBoolean();
+
p.printSpaceBeforeIdentifier();
p.print(if (e.value) "true" else "false");
},
- .e_string => |e| {
+ .e_string => {
+ const e = expr.getString();
+
// If this was originally a template literal, print it as one as long as we're not minifying
if (e.prefer_template) {
p.print("`");
@@ -1306,7 +1340,9 @@ pub fn NewPrinter(comptime ascii_only: bool) type {
p.printString(e.*, c);
p.print(c);
},
- .e_template => |e| {
+ .e_template => {
+ const e = expr.getTemplate();
+
if (e.tag) |tag| {
// Optional chains are forbidden in template tags
if (expr.isOptionalChain()) {
@@ -1341,7 +1377,9 @@ pub fn NewPrinter(comptime ascii_only: bool) type {
}
p.print("`");
},
- .e_reg_exp => |e| {
+ .e_reg_exp => {
+ const e = expr.getRegExp();
+
const n = p.js.len();
// Avoid forming a single-line comment
@@ -1354,12 +1392,16 @@ pub fn NewPrinter(comptime ascii_only: bool) type {
// Need a space before the next identifier to avoid it turning into flags
p.prev_reg_exp_end = p.js.lenI();
},
- .e_big_int => |e| {
+ .e_big_int => {
+ const e = expr.getBigInt();
+
p.printSpaceBeforeIdentifier();
p.print(e.value);
p.print('n');
},
- .e_number => |e| {
+ .e_number => {
+ const e = expr.getNumber();
+
const value = e.value;
const absValue = std.math.fabs(value);
@@ -1399,7 +1441,9 @@ pub fn NewPrinter(comptime ascii_only: bool) type {
p.prev_num_end = p.js.lenI();
}
},
- .e_identifier => |e| {
+ .e_identifier => {
+ const e = expr.getIdentifier();
+
const name = p.renamer.nameForSymbol(e.ref);
const wrap = p.js.lenI() == p.for_of_init_start and strings.eqlComptime(name, "let");
@@ -1414,7 +1458,9 @@ pub fn NewPrinter(comptime ascii_only: bool) type {
p.print(")");
}
},
- .e_import_identifier => |e| {
+ .e_import_identifier => {
+ const e = expr.getImportIdentifier();
+
// Potentially use a property access instead of an identifier
const ref = p.symbols.follow(e.ref);
var didPrint = false;
@@ -1427,7 +1473,7 @@ pub fn NewPrinter(comptime ascii_only: bool) type {
var wrap = false;
if (p.call_target) |target| {
- wrap = e.was_originally_identifier and target.e_import_identifier == e;
+ wrap = e.was_originally_identifier and target.e_import_identifier.index == expr.data.e_import_identifier.index;
}
if (wrap) {
@@ -1456,7 +1502,9 @@ pub fn NewPrinter(comptime ascii_only: bool) type {
p.printSymbol(e.ref);
}
},
- .e_await => |e| {
+ .e_await => {
+ const e = expr.getAwait();
+
const wrap = level.gte(.prefix);
if (wrap) {
@@ -1472,7 +1520,9 @@ pub fn NewPrinter(comptime ascii_only: bool) type {
p.print(")");
}
},
- .e_yield => |e| {
+ .e_yield => {
+ const e = expr.getYield();
+
const wrap = level.gte(.assign);
if (wrap) {
p.print("(");
@@ -1493,7 +1543,9 @@ pub fn NewPrinter(comptime ascii_only: bool) type {
p.print(")");
}
},
- .e_unary => |e| {
+ .e_unary => {
+ const e = expr.getUnary();
+
const entry: Op = Op.Table.get(e.op);
const wrap = level.gte(entry.level);
@@ -1524,7 +1576,9 @@ pub fn NewPrinter(comptime ascii_only: bool) type {
p.print(")");
}
},
- .e_binary => |e| {
+ .e_binary => {
+ const e = expr.getBinary();
+
const entry: Op = Op.Table.get(e.op);
var wrap = level.gte(entry.level) or (e.op == Op.Code.bin_in and flags.forbid_in);
@@ -1559,7 +1613,8 @@ pub fn NewPrinter(comptime ascii_only: bool) type {
// "??" can't directly contain "||" or "&&" without being wrapped in parentheses
.bin_nullish_coalescing => {
switch (e.left.data) {
- .e_binary => |left| {
+ .e_binary => {
+ const left = e.left.getBinary();
switch (left.op) {
.bin_logical_and, .bin_logical_or => {
left_level = .prefix;
@@ -1571,7 +1626,8 @@ pub fn NewPrinter(comptime ascii_only: bool) type {
}
switch (e.right.data) {
- .e_binary => |right| {
+ .e_binary => {
+ const right = e.right.getBinary();
switch (right.op) {
.bin_logical_and, .bin_logical_or => {
right_level = .prefix;
@@ -1585,7 +1641,8 @@ pub fn NewPrinter(comptime ascii_only: bool) type {
// "**" can't contain certain unary expressions
.bin_pow => {
switch (e.left.data) {
- .e_unary => |left| {
+ .e_unary => {
+ const left = e.left.getUnary();
if (left.op.unaryAssignTarget() == .none) {
left_level = .call;
}
@@ -1601,7 +1658,7 @@ pub fn NewPrinter(comptime ascii_only: bool) type {
// Special-case "#foo in bar"
if (e.op == .bin_in and @as(Expr.Tag, e.left.data) == .e_private_identifier) {
- p.printSymbol(e.left.data.e_private_identifier.ref);
+ p.printSymbol(e.left.getPrivateIdentifier().ref);
} else {
flags.forbid_in = true;
p.printExpr(e.left, left_level, flags);
@@ -1701,7 +1758,8 @@ pub fn NewPrinter(comptime ascii_only: bool) type {
if (item.value) |val| {
switch (val.data) {
- .e_function => |func| {
+ .e_function => {
+ const func = val.getFunction();
if (item.flags.is_method) {
if (func.func.flags.is_async) {
p.printSpaceBeforeIdentifier();
@@ -1728,7 +1786,8 @@ pub fn NewPrinter(comptime ascii_only: bool) type {
if (item.value) |val| {
switch (val.data) {
- .e_function => |func| {
+ .e_function => {
+ const func = val.getFunction();
if (item.flags.is_method) {
p.printFunc(func.func);
return;
@@ -1749,10 +1808,11 @@ pub fn NewPrinter(comptime ascii_only: bool) type {
}
switch (_key.data) {
- .e_private_identifier => |key| {
- p.printSymbol(key.ref);
+ .e_private_identifier => {
+ p.printSymbol(_key.getPrivateIdentifier().ref);
},
- .e_string => |key| {
+ .e_string => {
+ const key = _key.getString();
p.addSourceMapping(_key.loc);
if (key.isUTF8()) {
p.printSpaceBeforeIdentifier();
@@ -1761,7 +1821,9 @@ pub fn NewPrinter(comptime ascii_only: bool) type {
// Use a shorthand property if the names are the same
if (item.value) |val| {
switch (val.data) {
- .e_identifier => |e| {
+ .e_identifier => {
+ const e = val.getIdentifier();
+
// TODO: is needing to check item.flags.was_shorthand a bug?
// esbuild doesn't have to do that...
// maybe it's a symptom of some other underlying issue
@@ -1774,7 +1836,9 @@ pub fn NewPrinter(comptime ascii_only: bool) type {
}
// if (strings) {}
},
- .e_import_identifier => |e| {
+ .e_import_identifier => {
+ const e = val.getImportIdentifier();
+
const ref = p.symbols.follow(e.ref);
if (p.symbols.get(ref)) |symbol| {
if (symbol.namespace_alias == null and strings.eql(key.utf8, p.renamer.nameForSymbol(e.ref))) {
@@ -1795,7 +1859,9 @@ pub fn NewPrinter(comptime ascii_only: bool) type {
// Use a shorthand property if the names are the same
if (item.value) |val| {
switch (val.data) {
- .e_identifier => |e| {
+ .e_identifier => {
+ const e = val.getIdentifier();
+
// TODO: is needing to check item.flags.was_shorthand a bug?
// esbuild doesn't have to do that...
// maybe it's a symptom of some other underlying issue
@@ -1808,7 +1874,9 @@ pub fn NewPrinter(comptime ascii_only: bool) type {
}
// if (strings) {}
},
- .e_import_identifier => |e| {
+ .e_import_identifier => {
+ const e = val.getImportIdentifier();
+
const ref = p.symbols.follow(e.ref);
if (p.symbols.get(ref)) |symbol| {
if (symbol.namespace_alias == null and strings.utf16EqlString(key.value, p.renamer.nameForSymbol(e.ref))) {
@@ -1843,8 +1911,8 @@ pub fn NewPrinter(comptime ascii_only: bool) type {
if (item.kind != .normal) {
switch (item.value.?.data) {
- .e_function => |func| {
- p.printFunc(func.func);
+ .e_function => {
+ p.printFunc(item.value.?.getFunction().func);
return;
},
else => {},
@@ -1853,7 +1921,8 @@ pub fn NewPrinter(comptime ascii_only: bool) type {
if (item.value) |val| {
switch (val.data) {
- .e_function => |f| {
+ .e_function => {
+ const f = val.getFunction();
if (item.flags.is_method) {
p.printFunc(f.func);
@@ -1979,7 +2048,8 @@ pub fn NewPrinter(comptime ascii_only: bool) type {
}
switch (property.key.data) {
- .e_string => |str| {
+ .e_string => {
+ const str = property.key.getString();
if (str.isUTF8()) {
p.addSourceMapping(property.key.loc);
p.printSpaceBeforeIdentifier();
diff --git a/src/resolver/package_json.zig b/src/resolver/package_json.zig
index 1594de702..a9952c8b1 100644
--- a/src/resolver/package_json.zig
+++ b/src/resolver/package_json.zig
@@ -79,8 +79,8 @@ pub const PackageJSON = struct {
.main_fields = MainFieldMap.init(r.allocator),
};
- if (json.getProperty("type")) |type_json| {
- if (type_json.expr.getString(r.allocator)) |type_str| {
+ if (json.asProperty("type")) |type_json| {
+ if (type_json.expr.asString(r.allocator)) |type_str| {
switch (options.ModuleType.List.get(type_str) orelse options.ModuleType.unknown) {
.cjs => {
package_json.module_type = .cjs;
@@ -105,10 +105,10 @@ pub const PackageJSON = struct {
// Read the "main" fields
for (r.opts.main_fields) |main| {
- if (json.getProperty(main)) |main_json| {
+ if (json.asProperty(main)) |main_json| {
const expr: js_ast.Expr = main_json.expr;
- if ((expr.getString(r.allocator))) |str| {
+ if ((expr.asString(r.allocator))) |str| {
if (str.len > 0) {
package_json.main_fields.put(main, str) catch unreachable;
}
@@ -129,14 +129,15 @@ pub const PackageJSON = struct {
// "./dist/index.node.esm.js": "./dist/index.browser.esm.js"
// },
//
- if (json.getProperty("browser")) |browser_prop| {
+ if (json.asProperty("browser")) |browser_prop| {
switch (browser_prop.expr.data) {
- .e_object => |obj| {
+ .e_object => {
+ const obj = browser_prop.expr.getObject();
// The value is an object
// Remap all files in the browser field
for (obj.properties) |prop| {
- var _key_str = (prop.key orelse continue).getString(r.allocator) orelse continue;
+ var _key_str = (prop.key orelse continue).asString(r.allocator) orelse continue;
const value: js_ast.Expr = prop.value orelse continue;
// Normalize the path so we can compare against it without getting
@@ -151,11 +152,13 @@ pub const PackageJSON = struct {
const key = r.allocator.dupe(u8, r.fs.normalize(_key_str)) catch unreachable;
switch (value.data) {
- .e_string => |str| {
+ .e_string => {
+ const str = value.getString();
// If this is a string, it's a replacement package
package_json.browser_map.put(key, str.string(r.allocator) catch unreachable) catch unreachable;
},
- .e_boolean => |boolean| {
+ .e_boolean => {
+ const boolean = value.getBoolean();
if (!boolean.value) {
package_json.browser_map.put(key, "") catch unreachable;
}
diff --git a/src/resolver/tsconfig_json.zig b/src/resolver/tsconfig_json.zig
index 79fb6e677..7b6977bba 100644
--- a/src/resolver/tsconfig_json.zig
+++ b/src/resolver/tsconfig_json.zig
@@ -74,9 +74,9 @@ pub const TSConfigJSON = struct {
var result: TSConfigJSON = TSConfigJSON{ .abs_path = source.key_path.text, .paths = PathsMap.init(allocator) };
errdefer allocator.free(result.paths);
- if (json.getProperty("extends")) |extends_value| {
+ if (json.asProperty("extends")) |extends_value| {
log.addWarning(&source, extends_value.loc, "\"extends\" is not implemented yet") catch unreachable;
- // if ((extends_value.expr.getString(allocator) catch null)) |str| {
+ // if ((extends_value.expr.asString(allocator) catch null)) |str| {
// if (extends(str, source.rangeOfString(extends_value.loc))) |base| {
// result.jsx = base.jsx;
// result.base_url_for_paths = base.base_url_for_paths;
@@ -90,48 +90,48 @@ pub const TSConfigJSON = struct {
var has_base_url = false;
// Parse "compilerOptions"
- if (json.getProperty("compilerOptions")) |compiler_opts| {
+ if (json.asProperty("compilerOptions")) |compiler_opts| {
// Parse "baseUrl"
- if (compiler_opts.expr.getProperty("baseUrl")) |base_url_prop| {
- if ((base_url_prop.expr.getString(allocator))) |base_url| {
+ if (compiler_opts.expr.asProperty("baseUrl")) |base_url_prop| {
+ if ((base_url_prop.expr.asString(allocator))) |base_url| {
result.base_url = base_url;
has_base_url = true;
}
}
// Parse "jsxFactory"
- if (compiler_opts.expr.getProperty("jsxFactory")) |jsx_prop| {
- if (jsx_prop.expr.getString(allocator)) |str| {
+ if (compiler_opts.expr.asProperty("jsxFactory")) |jsx_prop| {
+ if (jsx_prop.expr.asString(allocator)) |str| {
result.jsx.factory = try parseMemberExpressionForJSX(log, &source, jsx_prop.loc, str, allocator);
}
}
// Parse "jsxFragmentFactory"
- if (compiler_opts.expr.getProperty("jsxFactory")) |jsx_prop| {
- if (jsx_prop.expr.getString(allocator)) |str| {
+ if (compiler_opts.expr.asProperty("jsxFactory")) |jsx_prop| {
+ if (jsx_prop.expr.asString(allocator)) |str| {
result.jsx.fragment = try parseMemberExpressionForJSX(log, &source, jsx_prop.loc, str, allocator);
}
}
// Parse "jsxImportSource"
- if (compiler_opts.expr.getProperty("jsxImportSource")) |jsx_prop| {
- if (jsx_prop.expr.getString(allocator)) |str| {
+ if (compiler_opts.expr.asProperty("jsxImportSource")) |jsx_prop| {
+ if (jsx_prop.expr.asString(allocator)) |str| {
result.jsx.import_source = str;
}
}
// Parse "useDefineForClassFields"
- if (compiler_opts.expr.getProperty("useDefineForClassFields")) |use_define_value_prop| {
- if (use_define_value_prop.expr.getBool()) |val| {
+ if (compiler_opts.expr.asProperty("useDefineForClassFields")) |use_define_value_prop| {
+ if (use_define_value_prop.expr.asBool()) |val| {
result.use_define_for_class_fields = val;
}
}
// Parse "importsNotUsedAsValues"
- if (compiler_opts.expr.getProperty("importsNotUsedAsValues")) |jsx_prop| {
+ if (compiler_opts.expr.asProperty("importsNotUsedAsValues")) |jsx_prop| {
// This should never allocate since it will be utf8
- if ((jsx_prop.expr.getString(allocator))) |str| {
+ if ((jsx_prop.expr.asString(allocator))) |str| {
switch (ImportsNotUsedAsValue.List.get(str) orelse ImportsNotUsedAsValue.invalid) {
.preserve, .err => {
result.preserve_imports_not_used_as_values = true;
@@ -145,14 +145,15 @@ pub const TSConfigJSON = struct {
}
// Parse "paths"
- if (compiler_opts.expr.getProperty("paths")) |paths_prop| {
+ if (compiler_opts.expr.asProperty("paths")) |paths_prop| {
switch (paths_prop.expr.data) {
- .e_object => |paths| {
+ .e_object => {
+ var paths = paths_prop.expr.getObject();
result.base_url_for_paths = result.base_url;
result.paths = PathsMap.init(allocator);
for (paths.properties) |property| {
const key_prop = property.key orelse continue;
- const key = (key_prop.getString(allocator)) orelse continue;
+ const key = (key_prop.asString(allocator)) orelse continue;
if (!TSConfigJSON.isValidTSConfigPathNoBaseURLPattern(key, log, &source, allocator, key_prop.loc)) {
continue;
@@ -182,13 +183,15 @@ pub const TSConfigJSON = struct {
// Matching "folder1/file2" should first check "projectRoot/folder1/file2"
// and then, if that didn't work, also check "projectRoot/generated/folder1/file2".
switch (value_prop.data) {
- .e_array => |array| {
+ .e_array => {
+ const array = value_prop.getArray();
+
if (array.items.len > 0) {
var values = allocator.alloc(string, array.items.len) catch unreachable;
errdefer allocator.free(values);
var count: usize = 0;
for (array.items) |expr| {
- if ((expr.getString(allocator))) |str| {
+ if ((expr.asString(allocator))) |str| {
if (TSConfigJSON.isValidTSConfigPathPattern(
str,
log,