diff options
Diffstat (limited to 'src/ast/base.zig')
| -rw-r--r-- | src/ast/base.zig | 208 |
1 files changed, 14 insertions, 194 deletions
diff --git a/src/ast/base.zig b/src/ast/base.zig index c283fee8c..ad0d34efd 100644 --- a/src/ast/base.zig +++ b/src/ast/base.zig @@ -43,174 +43,28 @@ pub const RefCtx = struct { } }; -/// Sets the range of bits starting at `start_bit` upto and excluding `start_bit` + `number_of_bits` -/// to be specific, if the range is N bits long, the N lower bits of `value` will be used; if any of -/// the other bits in `value` are set to 1, this function will panic. -/// -/// ```zig -/// var val: u8 = 0b10000000; -/// setBits(&val, 2, 4, 0b00001101); -/// try testing.expectEqual(@as(u8, 0b10110100), val); -/// ``` -/// -/// ## Panics -/// This method will panic if the `value` exceeds the bit range of the type of `target` -pub fn setBits( - comptime TargetType: type, - target: TargetType, - comptime start_bit: comptime_int, - comptime number_of_bits: comptime_int, - value: TargetType, -) TargetType { - const end_bit = start_bit + number_of_bits; - - comptime { - if (number_of_bits == 0) @compileError("non-zero number_of_bits must be provided"); - - if (@typeInfo(TargetType) == .Int) { - if (@typeInfo(TargetType).Int.signedness != .unsigned) { - @compileError("requires an unsigned integer, found " ++ @typeName(TargetType)); - } - if (start_bit >= @bitSizeOf(TargetType)) { - @compileError("start_bit index is out of bounds of the bit field"); - } - if (end_bit > @bitSizeOf(TargetType)) { - @compileError("start_bit + number_of_bits is out of bounds of the bit field"); - } - } else if (@typeInfo(TargetType) == .ComptimeInt) { - @compileError("comptime_int is unsupported"); - } else { - @compileError("requires an unsigned integer, found " ++ @typeName(TargetType)); - } - } - - if (comptime std.debug.runtime_safety) { - if (getBits(TargetType, value, 0, (end_bit - start_bit)) != value) @panic("value exceeds bit range"); - } - - const bitmask: TargetType = comptime blk: { - var bitmask = ~@as(TargetType, 0); - bitmask <<= (@bitSizeOf(TargetType) - end_bit); - bitmask >>= (@bitSizeOf(TargetType) - end_bit); - bitmask >>= start_bit; - bitmask <<= start_bit; - break :blk ~bitmask; - }; - - return (target & bitmask) | (value << start_bit); -} - -pub fn getBits(comptime TargetType: type, target: anytype, comptime start_bit: comptime_int, comptime number_of_bits: comptime_int) TargetType { - comptime { - if (number_of_bits == 0) @compileError("non-zero number_of_bits must be provided"); - - if (@typeInfo(TargetType) == .Int) { - if (@typeInfo(TargetType).Int.signedness != .unsigned) { - @compileError("requires an unsigned integer, found " ++ @typeName(TargetType)); - } - if (start_bit >= @bitSizeOf(TargetType)) { - @compileError("start_bit index is out of bounds of the bit field"); - } - if (start_bit + number_of_bits > @bitSizeOf(TargetType)) { - @compileError("start_bit + number_of_bits is out of bounds of the bit field"); - } - } else if (@typeInfo(TargetType) == .ComptimeInt) { - if (target < 0) { - @compileError("requires an unsigned integer, found " ++ @typeName(TargetType)); - } - } else { - @compileError("requires an unsigned integer, found " ++ @typeName(TargetType)); - } - } - - return @truncate(TargetType, target >> start_bit); -} - -pub const Ref = enum(TotalSize) { - default = std.math.maxInt(TotalSize), - _, - - pub const TotalSize = u62; - - pub fn format(ref: Ref, comptime _: []const u8, _: std.fmt.FormatOptions, writer: anytype) !void { - try std.fmt.format( - writer, - "Ref: sourceIndex = {d}, innerIndex = {d}, is_source_contents_slice = {}", - .{ - ref.sourceIndex(), - ref.innerIndex(), - ref.isSourceContentsSlice(), - }, - ); - } - +pub const Ref = packed struct { const max_ref_int = std.math.maxInt(Ref.Int); pub const BitInt = std.meta.Int(.unsigned, @bitSizeOf(Ref)); + source_index: Int = max_ref_int, + inner_index: Int = 0, + is_source_contents_slice: bool = false, + pub inline fn asBitInt(this: Ref) BitInt { return @bitCast(BitInt, this); } // 2 bits of padding for whatever is the parent pub const Int = u30; - pub const None = Ref.init(std.math.maxInt(u30), std.math.maxInt(u30), false); - pub const RuntimeRef = Ref.init(std.math.maxInt(u30), std.math.maxInt(u30) - 1, false); - - const source_index_offset = 1; - const inner_index_offset = 1 + 30; - - pub inline fn sourceIndex(this: Ref) Int { - return @truncate(Int, getBits(TotalSize, @enumToInt(this), source_index_offset, 30)); - } - - pub inline fn innerIndex(this: Ref) Int { - return @truncate(Int, getBits(TotalSize, @enumToInt(this), inner_index_offset, 30)); - } - - pub inline fn isSourceContentsSlice(this: Ref) bool { - return (getBits(TotalSize, @enumToInt(this), 0, 1) & 1) != 0; - } - - pub fn atIndex(value: anytype) Ref { - return @intToEnum(Ref, setBits(TotalSize, 0, inner_index_offset, 30, @truncate(Int, value))); - } - - pub fn init(inner_index: Int, source_index: Int, is_source_contents_slice: bool) Ref { - return @intToEnum( - Ref, - setBits( - TotalSize, - 0, - 0, - 1, - @as( - TotalSize, - @boolToInt(is_source_contents_slice), - ), - ) | setBits( - TotalSize, - 0, - source_index_offset, - 30, - source_index, - ) | setBits( - TotalSize, - 0, - inner_index_offset, - 30, - inner_index, - ), - ); - } - - const Old = struct { - inner_index: Int = 0, - source_index: Int = std.math.maxInt(Int), - is_source_contents_slice: bool = false, + pub const None = Ref{ + .inner_index = max_ref_int, + .source_index = max_ref_int, + }; + pub const RuntimeRef = Ref{ + .inner_index = max_ref_int, + .source_index = max_ref_int - 1, }; - pub fn initSourceEnd(old: Old) Ref { - return init(old.inner_index, old.source_index, old.is_source_contents_slice); - } pub fn toInt(int: anytype) Int { return @intCast(Int, int); @@ -227,7 +81,7 @@ pub const Ref = enum(TotalSize) { // but we want to ensure that the value of the unused bits in the u64 are 0 // i have not looked at the assembly to verify that the unused bits default to 0 // so we set it to u64 0 just to be sure - return @as(u64, @enumToInt(key)); + return @as(u64, 0) | @as(u64, key.asBitInt()); } pub inline fn hash64(key: Ref) u64 { @@ -246,44 +100,10 @@ pub const Ref = enum(TotalSize) { } pub fn jsonStringify(self: *const Ref, options: anytype, writer: anytype) !void { - return try std.json.stringify([2]u32{ self.sourceIndex(), self.innerIndex() }, options, writer); + return try std.json.stringify([2]u32{ self.source_index, self.inner_index }, options, writer); } }; -test "Ref" { - { - const first = .{ .inner_index = 0, .source_index = 1, .is_source_contents_slice = true }; - const ref = Ref.initSourceEnd(.{ .inner_index = 0, .source_index = 1, .is_source_contents_slice = true }); - try std.testing.expectEqual(ref.innerIndex(), first.inner_index); - try std.testing.expectEqual(ref.sourceIndex(), first.source_index); - try std.testing.expectEqual(ref.isSourceContentsSlice(), first.is_source_contents_slice); - } - - { - const first = .{ .inner_index = 100, .source_index = 0, .is_source_contents_slice = true }; - const ref = Ref.initSourceEnd(.{ .inner_index = 100, .source_index = 0, .is_source_contents_slice = true }); - try std.testing.expectEqual(ref.innerIndex(), first.inner_index); - try std.testing.expectEqual(ref.sourceIndex(), first.source_index); - try std.testing.expectEqual(ref.isSourceContentsSlice(), first.is_source_contents_slice); - } - - { - const first = .{ .inner_index = 20, .source_index = 100, .is_source_contents_slice = true }; - const ref = Ref.initSourceEnd(.{ .inner_index = 20, .source_index = 100, .is_source_contents_slice = true }); - try std.testing.expectEqual(ref.innerIndex(), first.inner_index); - try std.testing.expectEqual(ref.sourceIndex(), first.source_index); - try std.testing.expectEqual(ref.isSourceContentsSlice(), first.is_source_contents_slice); - } - - { - const first = .{ .inner_index = 30, .source_index = 100, .is_source_contents_slice = false }; - const ref = Ref.initSourceEnd(.{ .inner_index = 30, .source_index = 100, .is_source_contents_slice = false }); - try std.testing.expectEqual(ref.innerIndex(), first.inner_index); - try std.testing.expectEqual(ref.sourceIndex(), first.source_index); - try std.testing.expectEqual(ref.isSourceContentsSlice(), first.is_source_contents_slice); - } -} - // 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 |
