First comptime for implementation

This commit is contained in:
David Gonzalez Martin 2024-04-19 08:39:01 -06:00
parent 57a7a07b52
commit 28776701fc
8 changed files with 592 additions and 402 deletions

View File

@ -4125,6 +4125,7 @@ pub const V = struct {
constant_int: ConstantInt,
function_declaration: Type.Index,
enum_value: Enum.Field.Index,
enum_fields: []const Enum.Field.Index,
error_value: Type.Error.Field.Index,
function_definition: Function.Definition.Index,
global: *Debug.Declaration.Global,
@ -4181,7 +4182,7 @@ pub const V = struct {
.comptime_int => .comptime_int,
.constant_struct => |constant_struct| unit.constant_structs.get(constant_struct).type,
.function_declaration => |function_type| function_type,
.polymorphic_function=> .polymorphic_function,
.polymorphic_function => .polymorphic_function,
else => |t| @panic(@tagName(t)),
};
}
@ -4202,6 +4203,7 @@ pub const Debug = struct {
global,
local,
argument,
@"comptime",
};
pub const Global = struct {
@ -4906,6 +4908,41 @@ pub const Builder = struct {
},
else => |t| @panic(@tagName(t)),
},
.@"comptime" => |ct| switch (ct) {
.enum_value => |enum_field_index| {
const enum_field = unit.enum_fields.get(enum_field_index);
const enum_name = unit.getIdentifier(enum_field.name);
const enum_name_z = try context.allocator.dupeZ(u8, enum_name);
const string_literal = try builder.processStringLiteralFromStringAndDebugInfo(unit, context, enum_name_z, .{
.line = 0,
.column = 0,
});
switch (type_expect) {
.type => |type_index| switch (unit.types.get(type_index).*) {
.slice => |slice| {
assert(slice.child_type == .u8);
const constant_slice = try unit.constant_slices.append(context.my_allocator, .{
.array = string_literal,
.start = 0,
.end = enum_name.len,
.type = type_index,
});
return V{
.type = type_index,
.value = .{
.@"comptime" = .{
.constant_slice = constant_slice,
},
},
};
},
else => |t| @panic(@tagName(t)),
},
else => |t| @panic(@tagName(t)),
}
},
else => |t| @panic(@tagName(t)),
},
else => |t| @panic(@tagName(t)),
}
},
@ -5033,7 +5070,7 @@ pub const Builder = struct {
.line = 0,
.column = 0,
});
const slice = try unit.constant_slices.append(context.my_allocator,.{
const slice = try unit.constant_slices.append(context.my_allocator, .{
.array = string_literal,
.start = 0,
.end = identifier_z.len,
@ -5108,7 +5145,7 @@ pub const Builder = struct {
}
}
fn get_fields_array(builder: *Builder, unit: *Unit, context: *const Context, container_type_index: Type.Index, token: Token.Index) !*Debug.Declaration.Global{
fn get_fields_array(builder: *Builder, unit: *Unit, context: *const Context, container_type_index: Type.Index, token: Token.Index) !*Debug.Declaration.Global {
if (unit.fields_array.get(container_type_index)) |result| return result else {
const container_type = unit.types.get(container_type_index);
@ -5612,7 +5649,7 @@ pub const Builder = struct {
return instantiation_global;
},
else => {}
else => {},
}
inline for (@typeInfo(Debug.Declaration.Global.Attribute).Enum.fields) |attribute_enum_field| {
@ -5924,6 +5961,9 @@ pub const Builder = struct {
unreachable;
},
.pointer => |source_pointer| if (source_pointer.type == destination_slice.child_type) {
unreachable;
} else unreachable,
else => |t| @panic(@tagName(t)),
}
},
@ -8608,11 +8648,11 @@ pub const Builder = struct {
const field_node = unit.getNode(field_node_index);
const identifier = switch (unit.getTokenId(field_node.token)) {
.identifier => unit.getExpectedTokenBytes(field_node.token, .identifier),
.discard => try std.mem.concat(context.allocator, u8, &.{"_", &.{'0' + b: {
.discard => try std.mem.concat(context.allocator, u8, &.{ "_", &.{'0' + b: {
const ch = '0' + ignore_field_count;
ignore_field_count += 1;
break :b ch;
}}}),
}} }),
else => unreachable,
};
const hash = try unit.processIdentifier(context, identifier);
@ -9453,6 +9493,22 @@ pub const Builder = struct {
else => |t| @panic(@tagName(t)),
}
},
.fields => {
assert(argument_node_list.len == 1);
const container_type_index = try builder.resolveType(unit, context, argument_node_list[0], &.{});
const container_type = unit.types.get(container_type_index);
switch (container_type.*) {
.integer => |*integer| switch (integer.kind) {
.@"enum" => |*enum_type| {
return V.Comptime{
.enum_fields = enum_type.fields.slice(),
};
},
else => |t| @panic(@tagName(t)),
},
else => |t| @panic(@tagName(t)),
}
},
else => |t| @panic(@tagName(t)),
}
},
@ -9719,7 +9775,6 @@ pub const Builder = struct {
}
}
fn resolveRuntimeValue(builder: *Builder, unit: *Unit, context: *const Context, type_expect: Type.Expect, node_index: Node.Index, side: Side) anyerror!V {
const node = unit.getNode(node_index);
@ -13220,7 +13275,6 @@ pub const Builder = struct {
};
const argument_value = try builder.resolveRuntimeValue(unit, context, arg_type_expect, argument_node_index, .right);
switch (argument_abi.kind) {
.direct => {
assert(argument_value.type == argument_type_index);
@ -13562,7 +13616,6 @@ pub const Builder = struct {
},
else => |t| @panic(@tagName(t)),
}
},
}
}
@ -13849,10 +13902,46 @@ pub const Builder = struct {
assert(slices_and_range_node.len > 0);
assert(payloads.len > 0);
const for_expressions = unit.getNode(statement_node.right);
assert(for_expressions.id == .for_expressions);
const body_node_index = for_expressions.left;
if (slices_and_range_node.len != payloads.len) {
@panic("Slice/range count does not match payload count");
}
if (slices_and_range_node.len == 1 and unit.getNode(slices_and_range_node[0]).id == .comptime_expression) {
const node = unit.getNode(slices_and_range_node[0]);
assert(slices_and_range_node.len == 1);
const comptime_value = try builder.resolveComptimeValue(unit, context, Type.Expect.none, .{}, node.left, null, .right, &.{}, null, &.{});
switch (comptime_value) {
.enum_fields => |enum_fields| {
const first_enum_field = unit.enum_fields.get(enum_fields[0]);
const payload_node = unit.getNode(payloads[0]);
const emit = false;
const comptime_payload = try builder.emitLocalVariableDeclaration(unit, context, payload_node.token, .@"const", first_enum_field.parent, V{
.type = first_enum_field.parent,
.value = .{
.@"comptime" = .{
.enum_value = enum_fields[0],
},
},
}, emit, null);
_ = comptime_payload; // autofix
const identifier = unit.getExpectedTokenBytes(payload_node.token, .identifier);
const hash = try unit.processIdentifier(context, identifier);
const symbol_lookup = builder.current_scope.lookupDeclaration(hash, false) orelse unreachable;
const local_symbol: *Debug.Declaration.Local = @fieldParentPtr("declaration", symbol_lookup.declaration);
for (enum_fields) |enum_field_index| {
local_symbol.init_value.value.@"comptime".enum_value = enum_field_index; // autofix
_ = try builder.resolveRuntimeValue(unit, context, Type.Expect{ .type = .void }, body_node_index, .right);
// const enum_field = unit.enum_fields.get(enum_field_index);
}
},
else => |t| @panic(@tagName(t)),
}
} else {
const count = slices_and_range_node.len;
var slices = UnpinnedArray(V){};
@ -13945,7 +14034,7 @@ pub const Builder = struct {
},
};
},
.pointer => |pointer| switch (unit.types.get(pointer.type).*){
.pointer => |pointer| switch (unit.types.get(pointer.type).*) {
.array => |array| {
const slice_type = try unit.getSliceType(context, .{
.child_pointer_type = try unit.getPointerType(context, .{
@ -14136,9 +14225,6 @@ pub const Builder = struct {
}
}
const for_expressions = unit.getNode(statement_node.right);
assert(for_expressions.id == .for_expressions);
const body_node_index = for_expressions.left;
_ = try builder.resolveRuntimeValue(unit, context, Type.Expect{ .type = .void }, body_node_index, .right);
const else_node_index = for_expressions.right;
@ -14207,6 +14293,7 @@ pub const Builder = struct {
try builder.jump(unit, context, builder.loop_header_block);
builder.current_basic_block = exit_block;
}
},
.break_expression => {
try builder.jump(unit, context, builder.loop_exit_block);
@ -14727,7 +14814,7 @@ pub const Builder = struct {
else => {},
}
const PhiInfo = struct{
const PhiInfo = struct {
block: BasicBlock.Index,
instruction: Instruction.Index,
};
@ -14908,7 +14995,6 @@ pub const Builder = struct {
} else {
unreachable;
}
},
else => |t| @panic(@tagName(t)),
}
@ -16030,14 +16116,14 @@ pub const Builder = struct {
const line = token_debug_info.line + 1;
const column = token_debug_info.column + 1;
const file_path = file.getPath(context.allocator) catch unreachable;
write(.panic, file_path) catch {};
write(.panic, ":") catch {};
Unit.dumpInt(line, 10, false) catch {};
write(.panic, ":") catch {};
Unit.dumpInt(column, 10, false) catch {};
write(.panic, ":\x1b[0m ") catch {};
write(.panic, err.message) catch {};
write(.panic, "\n") catch {};
write(.panic, file_path) catch unreachable;
write(.panic, ":") catch unreachable;
Unit.dumpInt(line, 10, false) catch unreachable;
write(.panic, ":") catch unreachable;
Unit.dumpInt(column, 10, false) catch unreachable;
write(.panic, ":\x1b[0m ") catch unreachable;
write(.panic, err.message) catch unreachable;
write(.panic, "\n") catch unreachable;
std.posix.abort();
}
@ -17101,44 +17187,7 @@ pub const Unit = struct {
}
};
pub const FixedKeyword = enum {
@"comptime",
@"const",
@"var",
void,
noreturn,
@"while",
bool,
true,
false,
@"fn",
@"unreachable",
@"return",
ssize,
usize,
@"switch",
@"if",
@"else",
@"struct",
@"enum",
null,
@"align",
@"for",
undefined,
@"break",
@"test",
@"catch",
@"try",
@"orelse",
@"error",
@"and",
@"or",
bitfield,
Self,
any,
type,
@"continue"
};
pub const FixedKeyword = enum { @"comptime", @"const", @"var", void, noreturn, @"while", bool, true, false, @"fn", @"unreachable", @"return", ssize, usize, @"switch", @"if", @"else", @"struct", @"enum", null, @"align", @"for", undefined, @"break", @"test", @"catch", @"try", @"orelse", @"error", @"and", @"or", bitfield, Self, any, type, @"continue" };
pub const Descriptor = struct {
main_package_path: []const u8,

View File

@ -625,7 +625,6 @@ const Analyzer = struct {
.operator_switch_case => break,
else => {},
}
}
break :blk switch (array_list.length) {
@ -1830,7 +1829,10 @@ const Analyzer = struct {
},
else => |t| @panic(@tagName(t)),
},
.identifier, .discard, => b: {
.identifier,
.discard,
.string_literal,
=> b: {
analyzer.consumeToken();
switch (container_type) {

View File

@ -23,7 +23,7 @@ pub fn build(b: *std.Build) !void {
const self_hosted_ci = b.option(bool, "self_hosted_ci", "This option enables the self-hosted CI behavior") orelse false;
const third_party_ci = b.option(bool, "third_party_ci", "This option enables the third-party CI behavior") orelse false;
const is_ci = self_hosted_ci or third_party_ci;
const print_stack_trace = b.option(bool, "print_stack_trace", "This option enables printing stack traces inside the compiler") orelse is_ci or os == .macos;
const print_stack_trace = b.option(bool, "print_stack_trace", "This option enables printing stack traces inside the compiler") orelse is_ci;
const native_target = b.resolveTargetQuery(.{});
const optimization = b.standardOptimizeOption(.{});
const use_debug = b.option(bool, "use_debug", "This option enables the LLVM debug build in the development PC") orelse false;

View File

@ -41,6 +41,77 @@ const MapFlags = switch (os) {
else => #error("OS not supported"),
};
const AccessMode = enum(u2) {
read_only = 0,
write_only = 1,
read_write = 2,
};
const OpenFlags = switch (os) {
.macos => bitfield(u32) {
access_mode: AccessMode,
non_block: bool = false,
append: bool = false,
shared_lock: bool = false,
exclusive_lock: bool = false,
async: bool = false,
sync: bool = false,
no_follow: bool = false,
creat: bool = false,
truncate: bool = false,
exclusive: bool = false,
_: u3 = 0,
evt_only: bool = false,
_: u1 = 0,
no_ctty: bool = false,
_: u2 = 0,
directory: bool = false,
symlink: bool = false,
dsync: bool = false,
_: u1 = 0,
cloexec: bool = false,
_: u4 = 0,
alert: bool = false,
_: u1 = 0,
popup: bool = false,
},
.linux => linux.OpenFlags,
else => #error("OS not supported"),
};
const TimeSpec = struct{
seconds: s64,
nanoseconds: s64,
};
const Stat = switch (os) {
.macos => struct{
dev: s32,
mode: u16,
nlink: u16,
inode: u64,
uid: u32,
gid: u32,
rdev: s32,
a_timespec: TimeSpec,
m_timespec: TimeSpec,
c_timespec: TimeSpec,
birth_timespec: TimeSpec,
size: s64,
blocks: s64,
block_size: s32,
flags: u32,
gen: u32,
lspare: s32,
qspare: [2]s64,
},
.linux => linux.Stat,
else => #error("OS not supported"),
};
const FileDescriptor = s32;
const ProcessId = s32;
const MAP_FAILED = 0xffffffffffffffff;
@ -71,7 +142,9 @@ const get_map_flags = fn(flags: std.os.MapFlags) MapFlags{
};
}
const write :: extern = fn cc(.c) (file_descriptor: FileDescriptor, bytes_ptr: [&]const u8, bytes_len: usize) ssize;
const open :: extern = fn cc(.c) (path: [&:0]const u8, flags: OpenFlags) s32;
const read :: extern = fn cc(.c) (file_descriptor: FileDescriptor, bytes_ptr: [&]const u8, byte_count: usize) ssize;
const write :: extern = fn cc(.c) (file_descriptor: FileDescriptor, bytes_ptr: [&]const u8, byte_count: usize) ssize;
const exit :: extern = fn cc(.c) (exit_code: s32) noreturn;
const fork :: extern = fn cc(.c) () ProcessId;
const mmap :: extern = fn cc(.c) (address: ?[&]const u8, length: usize, protection_flags: ProtectionFlags, map_flags: MapFlags, file_descriptor: FileDescriptor, offset: u64) usize;
@ -80,5 +153,6 @@ const execve :: extern = fn cc(.c) (path: [&:0]const u8, argv: [&:null]const ?[&
const realpath :: extern = fn cc(.c) (path: [&:0]const u8, resolved_path: [&:0]u8) ?[&:0]u8;
const waitpid :: extern = fn cc(.c) (pid: ProcessId, status: &s32, flags: s32) s32;
const mprotect :: extern = fn cc(.c) (address: &any, size: usize, flags: ProtectionFlags) s32;
const fstat :: extern = fn cc(.c) (file_descriptor: FileDescriptor, stat: &Stat) s32;
const _NSGetExecutablePath :: extern = fn cc(.c) (buffer: [&:0]u8, buffer_size: &u32) s32;

View File

@ -46,17 +46,9 @@ const FileDescriptor = struct{
const read = fn(file_descriptor: FileDescriptor, bytes: []u8) ReadError!usize {
if (bytes.length > 0) {
switch (current) {
.linux => {
.linux, .macos => {
const len: usize = #min(max_file_operation_byte_count, bytes.length);
const syscall_result = system.read(file_descriptor.handle, bytes);
const byte_count = unwrap_syscall(syscall_result) catch |err| switch (err) {
else => return ReadError.failed,
};
return byte_count;
},
.macos => {
const len: usize = #min(max_file_operation_byte_count, bytes.length);
const syscall_result = system.read(file_descriptor.handle, bytes);
const syscall_result = system.read(file_descriptor.handle, bytes.pointer, bytes.length);
const byte_count = unwrap_syscall(syscall_result) catch |err| switch (err) {
else => return ReadError.failed,
};
@ -119,13 +111,8 @@ const FileDescriptor = struct{
}
const get_size = fn (file_descriptor: FileDescriptor) GetAttributesError!u64 {
switch (current) {
.linux => {
const file_attributes = try file_descriptor.get_attributes();
return file_attributes.size;
},
else => #error("OS not supported"),
}
}
const GetAttributesError = error{
@ -134,9 +121,9 @@ const FileDescriptor = struct{
const get_attributes = fn (file_descriptor: FileDescriptor) GetAttributesError!FileAttributes {
switch (current) {
.linux => {
var stat_buffer: linux.Stat = undefined;
const raw_result = linux.fstat(file_descriptor.handle, stat_buffer.&);
.linux, .macos => {
var stat_buffer: system.Stat = undefined;
const raw_result = system.fstat(file_descriptor.handle, stat_buffer.&);
const result = unwrap_syscall(raw_result) catch |err| switch (err) {
else => return GetAttributesError.failed,
};
@ -396,14 +383,34 @@ const AccessMode = enum(u2) {
const open = fn(path: [&:0]const u8, open_flags: OpenFlags) OpenError!FileDescriptor{
switch (current) {
.linux => {
const flags = linux.OpenFlags{
const flags = system.OpenFlags{
.access_mode = switch (open_flags.access_mode) {
.read_only => .read_only,
.write_only => .write_only,
.read_write => .read_write,
},
};
const syscall_result = linux.open(path, flags, 0);
const syscall_result = system.open(path, flags, 0);
const result = unwrap_syscall(syscall_result) catch |err| switch (err) {
else => unreachable,
};
const r: u32 = #cast(result);
const file_descriptor = FileDescriptor{
.handle = #cast(r),
};
return file_descriptor;
},
.macos => {
const flags = system.OpenFlags{
.access_mode = switch (open_flags.access_mode) {
.read_only => .read_only,
.write_only => .write_only,
.read_write => .read_write,
},
};
const syscall_result = system.open(path, flags);
const result = unwrap_syscall(syscall_result) catch |err| switch (err) {
else => unreachable,
};

View File

@ -919,8 +919,8 @@ const openat = fn(directory_file_descriptor: FileDescriptor, path: [&:0]const u8
return result;
}
const read = fn(file_descriptor: FileDescriptor, bytes: []u8) usize {
const result = #syscall(#cast(Syscall.read), #cast(file_descriptor), #cast(bytes.pointer), bytes.length);
const read = fn(file_descriptor: FileDescriptor, byte_pointer: [&]u8, byte_count: usize) usize {
const result = #syscall(#cast(Syscall.read), #cast(file_descriptor), #cast(byte_pointer), byte_count);
return result;
}

View File

@ -19,6 +19,45 @@ const Token = struct {
};
};
const FixedKeyword = enum{
"comptime",
"const",
"var",
"void",
"noreturn",
"while",
"bool",
"true",
"false",
"fn",
"unreachable",
"return",
"ssize",
"usize",
""switch",
"if",
"else",
"struct",
"enum",
"null",
"align",
"for",
"undefined",
"break",
"test",
"catch",
"try",
"orelse",
"error",
"and",
"or",
"bitfield",
"Self",
"any",
"type",
"continue",
};
const lex = fn (arena: &Arena, bytes: []const u8) *!void {
if (bytes.length >= 0xffffffff) {
unreachable;
@ -72,10 +111,11 @@ const lex = fn (arena: &Arena, bytes: []const u8) *!void {
's' => .keyword_signed_integer,
else => unreachable,
};
} else {
//unreachable;
}
}
const string_length = index - start_index;
const string = bytes[start_index..][0..string_length];
},
else => index += 1,
}

View File

@ -0,0 +1,18 @@
const std = #import("std");
const print = std.print;
const Enum = enum{
first_name,
second_name,
third_name,
};
const main = fn () *!void {
print("Enum values:\n");
for ($#fields(Enum)) |e| {
const name: []const u8 = #name(e);
print(name);
print("\n");
}
}