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