const std = @import("std"); const unicode = std.unicode; pub const JavascriptString = []u16; pub fn newJavascriptString(comptime text: []const u8) JavascriptString { return unicode.utf8ToUtf16LeStringLiteral(text); } pub const NodeIndex = u32; pub const NodeIndexNone = 4294967293; // TODO: figure out if we actually need this // -- original comment -- // Files are parsed in parallel for speed. We want to allow each parser to // generate symbol IDs that won't conflict with each other. We also want to be // able to quickly merge symbol tables from all files into one giant symbol // table. // // We can accomplish both goals by giving each symbol ID two parts: a source // index that is unique to the parser goroutine, and an inner index that // increments as the parser generates new symbol IDs. Then a symbol map can // be an array of arrays indexed first by source index, then by inner index. // The maps can be merged quickly by creating a single outer array containing // all inner arrays from all parsed files. pub const RefHashCtx = struct { pub fn hash(ctx: @This(), key: Ref) u32 { return @truncate(u32, std.hash.Wyhash.hash(0, std.mem.asBytes(&key))); } pub fn eql(ctx: @This(), ref: Ref, b: Ref) bool { return std.mem.readIntNative(u64, std.mem.asBytes(&ref)) == std.mem.readIntNative(u64, std.mem.asBytes(&b)); } }; pub const Ref = packed struct { source_index: Int = std.math.maxInt(Ref.Int), inner_index: Int = 0, is_source_contents_slice: bool = false, // 2 bits of padding for whatever is the parent pub const Int = u30; pub const None = Ref{ .inner_index = std.math.maxInt(Ref.Int), .source_index = std.math.maxInt(Ref.Int), }; pub const RuntimeRef = Ref{ .inner_index = std.math.maxInt(Ref.Int), .source_index = std.math.maxInt(Ref.Int) - 1, }; pub fn toInt(int: anytype) Int { return @intCast(Int, int); } pub fn hash(key: Ref) u32 { return @truncate(u32, std.hash.Wyhash.hash(0, std.mem.asBytes(&key))); } pub fn eql(ref: Ref, b: Ref) bool { return std.mem.readIntNative(u64, std.mem.asBytes(&ref)) == std.mem.readIntNative(u64, std.mem.asBytes(&b)); } pub fn isNull(self: *const Ref) bool { return self.source_index == std.math.maxInt(Ref.Int) and self.inner_index == std.math.maxInt(Ref.Int); } pub fn isSourceNull(self: *const Ref) bool { return self.source_index == std.math.maxInt(Ref.Int); } pub fn isSourceIndexNull(int: anytype) bool { return int == std.math.maxInt(Ref.Int); } pub fn jsonStringify(self: *const Ref, options: anytype, writer: anytype) !void { return try std.json.stringify([2]u32{ self.source_index, self.inner_index }, options, writer); } }; // This is kind of the wrong place, but it's shared between files pub const RequireOrImportMeta = struct { // CommonJS files will return the "require_*" wrapper function and an invalid // exports object reference. Lazily-initialized ESM files will return the // "init_*" wrapper function and the exports object for that file. wrapper_ref: Ref = Ref.None, exports_ref: Ref = Ref.None, is_wrapper_async: bool = false, }; pub inline fn debug(comptime fmt: []const u8, args: anytype) void { // Output.print(fmt, args); } pub inline fn debugl( comptime fmt: []const u8, ) void { // Output.print("{s}\n", .{fmt}); }