126 lines
3.4 KiB
Zig
126 lines
3.4 KiB
Zig
|
const std = @import("std");
|
||
|
const builtin = @import("builtin");
|
||
|
const Scope = @import("scope.zig").Scope;
|
||
|
const Module = @import("module.zig").Module;
|
||
|
|
||
|
/// Values are ref-counted, heap-allocated, and copy-on-write
|
||
|
/// If there is only 1 ref then write need not copy
|
||
|
pub const Value = struct {
|
||
|
id: Id,
|
||
|
typeof: *Type,
|
||
|
ref_count: usize,
|
||
|
|
||
|
pub fn ref(base: *Value) void {
|
||
|
base.ref_count += 1;
|
||
|
}
|
||
|
|
||
|
pub fn deref(base: *Value, module: *Module) void {
|
||
|
base.ref_count -= 1;
|
||
|
if (base.ref_count == 0) {
|
||
|
base.typeof.base.deref(module);
|
||
|
switch (base.id) {
|
||
|
Id.Type => @fieldParentPtr(Type, "base", base).destroy(module),
|
||
|
Id.Fn => @fieldParentPtr(Fn, "base", base).destroy(module),
|
||
|
Id.Void => @fieldParentPtr(Void, "base", base).destroy(module),
|
||
|
Id.Bool => @fieldParentPtr(Bool, "base", base).destroy(module),
|
||
|
Id.NoReturn => @fieldParentPtr(NoReturn, "base", base).destroy(module),
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
pub fn dump(base: *const Value) void {
|
||
|
std.debug.warn("{}", @tagName(base.id));
|
||
|
}
|
||
|
|
||
|
pub const Id = enum {
|
||
|
Type,
|
||
|
Fn,
|
||
|
Void,
|
||
|
Bool,
|
||
|
NoReturn,
|
||
|
};
|
||
|
|
||
|
pub const Type = @import("type.zig").Type;
|
||
|
|
||
|
pub const Fn = struct {
|
||
|
base: Value,
|
||
|
|
||
|
/// parent should be the top level decls or container decls
|
||
|
fndef_scope: *Scope.FnDef,
|
||
|
|
||
|
/// parent is scope for last parameter
|
||
|
child_scope: *Scope,
|
||
|
|
||
|
/// parent is child_scope
|
||
|
block_scope: *Scope.Block,
|
||
|
|
||
|
/// Creates a Fn value with 1 ref
|
||
|
pub fn create(module: *Module, fn_type: *Type.Fn, fndef_scope: *Scope.FnDef) !*Fn {
|
||
|
const self = try module.a().create(Fn{
|
||
|
.base = Value{
|
||
|
.id = Value.Id.Fn,
|
||
|
.typeof = &fn_type.base,
|
||
|
.ref_count = 1,
|
||
|
},
|
||
|
.fndef_scope = fndef_scope,
|
||
|
.child_scope = &fndef_scope.base,
|
||
|
.block_scope = undefined,
|
||
|
});
|
||
|
fn_type.base.base.ref();
|
||
|
fndef_scope.fn_val = self;
|
||
|
fndef_scope.base.ref();
|
||
|
return self;
|
||
|
}
|
||
|
|
||
|
pub fn destroy(self: *Fn, module: *Module) void {
|
||
|
self.fndef_scope.base.deref(module);
|
||
|
module.a().destroy(self);
|
||
|
}
|
||
|
};
|
||
|
|
||
|
pub const Void = struct {
|
||
|
base: Value,
|
||
|
|
||
|
pub fn get(module: *Module) *Void {
|
||
|
module.void_value.base.ref();
|
||
|
return module.void_value;
|
||
|
}
|
||
|
|
||
|
pub fn destroy(self: *Void, module: *Module) void {
|
||
|
module.a().destroy(self);
|
||
|
}
|
||
|
};
|
||
|
|
||
|
pub const Bool = struct {
|
||
|
base: Value,
|
||
|
x: bool,
|
||
|
|
||
|
pub fn get(module: *Module, x: bool) *Bool {
|
||
|
if (x) {
|
||
|
module.true_value.base.ref();
|
||
|
return module.true_value;
|
||
|
} else {
|
||
|
module.false_value.base.ref();
|
||
|
return module.false_value;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
pub fn destroy(self: *Bool, module: *Module) void {
|
||
|
module.a().destroy(self);
|
||
|
}
|
||
|
};
|
||
|
|
||
|
pub const NoReturn = struct {
|
||
|
base: Value,
|
||
|
|
||
|
pub fn get(module: *Module) *NoReturn {
|
||
|
module.noreturn_value.base.ref();
|
||
|
return module.noreturn_value;
|
||
|
}
|
||
|
|
||
|
pub fn destroy(self: *NoReturn, module: *Module) void {
|
||
|
module.a().destroy(self);
|
||
|
}
|
||
|
};
|
||
|
};
|