2018-07-13 03:08:40 +08:00
|
|
|
const std = @import("std");
|
2020-04-19 07:41:45 +08:00
|
|
|
const Type = @import("type.zig").Type;
|
|
|
|
const log2 = std.math.log2;
|
|
|
|
const assert = std.debug.assert;
|
2018-07-13 03:08:40 +08:00
|
|
|
|
2020-04-18 12:09:43 +08:00
|
|
|
/// This is the raw data, with no bookkeeping, no memory awareness,
|
|
|
|
/// no de-duplication, and no type system awareness.
|
|
|
|
/// It's important for this struct to be small.
|
2020-04-19 07:41:45 +08:00
|
|
|
/// This union takes advantage of the fact that the first page of memory
|
|
|
|
/// is unmapped, giving us 4096 possible enum tags that have no payload.
|
|
|
|
pub const Value = extern union {
|
|
|
|
/// If the tag value is less than Tag.no_payload_count, then no pointer
|
|
|
|
/// dereference is needed.
|
|
|
|
tag_if_small_enough: usize,
|
|
|
|
ptr_otherwise: *Payload,
|
2020-04-18 12:09:43 +08:00
|
|
|
|
|
|
|
pub const Tag = enum {
|
2020-04-19 07:41:45 +08:00
|
|
|
// The first section of this enum are tags that require no payload.
|
2020-04-18 12:09:43 +08:00
|
|
|
void_type,
|
|
|
|
noreturn_type,
|
|
|
|
bool_type,
|
|
|
|
usize_type,
|
|
|
|
void_value,
|
|
|
|
noreturn_value,
|
|
|
|
bool_true,
|
|
|
|
bool_false,
|
2020-04-19 07:41:45 +08:00
|
|
|
// Bump this when adding items above.
|
|
|
|
pub const last_no_payload_tag = Tag.bool_false;
|
|
|
|
pub const no_payload_count = @enumToInt(last_no_payload_tag) + 1;
|
|
|
|
// After this, the tag requires a payload.
|
2020-04-18 12:09:43 +08:00
|
|
|
|
2020-04-19 07:41:45 +08:00
|
|
|
ty,
|
2020-04-18 12:09:43 +08:00
|
|
|
int_u64,
|
|
|
|
int_i64,
|
|
|
|
function,
|
|
|
|
ref,
|
|
|
|
bytes,
|
2018-07-23 11:27:58 +08:00
|
|
|
};
|
|
|
|
|
2020-04-19 07:41:45 +08:00
|
|
|
pub fn initTag(comptime tag: Tag) Value {
|
|
|
|
comptime assert(@enumToInt(tag) < Tag.no_payload_count);
|
|
|
|
return .{ .tag_if_small_enough = @enumToInt(tag) };
|
|
|
|
}
|
2018-07-13 03:08:40 +08:00
|
|
|
|
2020-04-19 07:41:45 +08:00
|
|
|
pub fn initPayload(payload: *Payload) Value {
|
|
|
|
assert(@enumToInt(payload.tag) >= Tag.no_payload_count);
|
|
|
|
return .{ .ptr_otherwise = payload };
|
|
|
|
}
|
2018-07-23 11:27:58 +08:00
|
|
|
|
2020-04-19 07:41:45 +08:00
|
|
|
pub fn tag(self: Value) Tag {
|
|
|
|
if (self.tag_if_small_enough < Tag.no_payload_count) {
|
|
|
|
return @intToEnum(self.tag_if_small_enough);
|
|
|
|
} else {
|
|
|
|
return self.ptr_otherwise.tag;
|
|
|
|
}
|
|
|
|
}
|
2018-07-13 03:08:40 +08:00
|
|
|
|
2020-04-19 07:41:45 +08:00
|
|
|
/// This type is not copyable since it may contain pointers to its inner data.
|
|
|
|
pub const Payload = struct {
|
|
|
|
tag: Tag,
|
2018-07-13 03:08:40 +08:00
|
|
|
|
2020-04-19 07:41:45 +08:00
|
|
|
pub const Int_u64 = struct {
|
|
|
|
base: Payload = Payload{ .tag = .int_u64 },
|
|
|
|
int: u64,
|
|
|
|
};
|
2018-07-13 03:08:40 +08:00
|
|
|
|
2020-04-19 07:41:45 +08:00
|
|
|
pub const Int_i64 = struct {
|
|
|
|
base: Payload = Payload{ .tag = .int_i64 },
|
|
|
|
int: i64,
|
|
|
|
};
|
|
|
|
|
|
|
|
pub const Function = struct {
|
|
|
|
base: Payload = Payload{ .tag = .function },
|
|
|
|
};
|
|
|
|
|
|
|
|
pub const ArraySentinel0_u8_Type = struct {
|
|
|
|
base: Payload = Payload{ .tag = .array_sentinel_0_u8_type },
|
|
|
|
len: u64,
|
|
|
|
};
|
|
|
|
|
|
|
|
pub const SingleConstPtrType = struct {
|
|
|
|
base: Payload = Payload{ .tag = .single_const_ptr_type },
|
|
|
|
elem_type: *Type,
|
|
|
|
};
|
|
|
|
|
|
|
|
pub const Ref = struct {
|
|
|
|
base: Payload = Payload{ .tag = .ref },
|
|
|
|
pointee: *MemoryCell,
|
|
|
|
};
|
|
|
|
|
|
|
|
pub const Bytes = struct {
|
|
|
|
base: Payload = Payload{ .tag = .bytes },
|
|
|
|
data: []u8,
|
|
|
|
};
|
2018-07-14 09:56:38 +08:00
|
|
|
|
2020-04-19 07:41:45 +08:00
|
|
|
pub const Ty = struct {
|
|
|
|
base: Payload = Payload{ .tag = .fully_qualified_type },
|
|
|
|
ptr: *Type,
|
|
|
|
};
|
2020-04-18 12:09:43 +08:00
|
|
|
};
|
|
|
|
};
|
2018-07-23 11:27:58 +08:00
|
|
|
|
2020-04-19 07:41:45 +08:00
|
|
|
/// This is the heart of resource management of the Zig compiler. The Zig compiler uses
|
|
|
|
/// stop-the-world mark-and-sweep garbage collection during compilation to manage the resources
|
|
|
|
/// associated with evaluating compile-time code and semantic analysis. Each `MemoryCell` represents
|
|
|
|
/// a root.
|
2020-04-18 12:09:43 +08:00
|
|
|
pub const MemoryCell = struct {
|
|
|
|
parent: Parent,
|
2020-04-19 07:41:45 +08:00
|
|
|
contents: Value,
|
2018-07-23 11:27:58 +08:00
|
|
|
|
2020-04-18 12:09:43 +08:00
|
|
|
pub const Parent = union(enum) {
|
|
|
|
none,
|
|
|
|
struct_field: struct {
|
|
|
|
struct_base: *MemoryCell,
|
2018-07-23 11:27:58 +08:00
|
|
|
field_index: usize,
|
2020-04-18 12:09:43 +08:00
|
|
|
},
|
|
|
|
array_elem: struct {
|
|
|
|
array_base: *MemoryCell,
|
2018-07-23 11:27:58 +08:00
|
|
|
elem_index: usize,
|
2020-04-18 12:09:43 +08:00
|
|
|
},
|
|
|
|
union_field: *MemoryCell,
|
|
|
|
err_union_code: *MemoryCell,
|
|
|
|
err_union_payload: *MemoryCell,
|
|
|
|
optional_payload: *MemoryCell,
|
|
|
|
optional_flag: *MemoryCell,
|
2018-07-19 12:08:47 +08:00
|
|
|
};
|
2018-07-13 03:08:40 +08:00
|
|
|
};
|