no tests for this yet. I think the quickest path to testing will be creating the .o files and linking with libc, executing, and then comparing output.
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);
|
|
}
|
|
};
|
|
};
|