Merge pull request #93 from birth-software/fix-macos-build

fix macos build
This commit is contained in:
David 2024-02-24 11:21:19 -06:00 committed by GitHub
commit 3a78cfe11d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 243 additions and 24 deletions

View File

@ -36,6 +36,13 @@ fn reportUnterminatedArgumentError(string: []const u8) noreturn {
std.debug.panic("Unterminated argument: {s}", .{string}); std.debug.panic("Unterminated argument: {s}", .{string});
} }
const Error = struct{
message: []const u8,
node: Node.Index,
};
pub fn createContext(allocator: Allocator) !*const Context{ pub fn createContext(allocator: Allocator) !*const Context{
const context: *Context = try allocator.create(Context); const context: *Context = try allocator.create(Context);
@ -69,25 +76,38 @@ pub fn compileBuildExecutable(context: *const Context, arguments: [][:0]u8) !voi
.link_libc = @import("builtin").os.tag == .macos, .link_libc = @import("builtin").os.tag == .macos,
.generate_debug_information = true, .generate_debug_information = true,
.name = "build", .name = "build",
.is_test = false,
}, },
}; };
try unit.compile(context); try unit.compile(context);
const argv: []const []const u8 = &.{ "nat/build", "-compiler_path", context.executable_absolute_path };
const result = try std.ChildProcess.run(.{ const result = try std.ChildProcess.run(.{
.allocator = context.allocator, .allocator = context.allocator,
.argv = &.{ "nat/build", "-compiler_path", context.executable_absolute_path }, .argv = argv,
}); });
switch (result.term) {
.Exited => |exit_code| { const success = switch (result.term) {
if (exit_code != 0) @panic("Bad exit code"); .Exited => |exit_code| exit_code == 0,
}, else => false,
.Signal => @panic("Signaled"), };
.Stopped => @panic("Stopped"), if (!success) {
.Unknown => @panic("Unknown"), std.debug.print("The following command terminated with failure ({s}): {s}\n", .{@tagName(result.term), argv});
if (result.stdout.len > 0) {
std.debug.print("STDOUT:\n{s}\n", .{result.stdout});
}
if (result.stderr.len > 0) {
std.debug.print("STDOUT:\n{s}\n", .{result.stderr});
}
std.os.abort();
} }
} }
pub fn buildExecutable(context: *const Context, arguments: [][:0]u8) !void { const ExecutableOptions = struct{
is_test: bool,
};
pub fn buildExecutable(context: *const Context, arguments: [][:0]u8, options: ExecutableOptions) !void {
var maybe_executable_path: ?[]const u8 = null; var maybe_executable_path: ?[]const u8 = null;
var maybe_main_package_path: ?[]const u8 = null; var maybe_main_package_path: ?[]const u8 = null;
var target_triplet: []const u8 = switch (@import("builtin").os.tag) { var target_triplet: []const u8 = switch (@import("builtin").os.tag) {
@ -242,6 +262,7 @@ pub fn buildExecutable(context: *const Context, arguments: [][:0]u8) !void {
}, },
.generate_debug_information = generate_debug_information, .generate_debug_information = generate_debug_information,
.name = executable_name, .name = executable_name,
.is_test = options.is_test,
}, },
}; };
@ -577,6 +598,7 @@ pub const Type = union(enum) {
}; };
pub const Instruction = union(enum) { pub const Instruction = union(enum) {
add_overflow: AddOverflow,
argument_declaration: *Debug.Declaration.Argument, argument_declaration: *Debug.Declaration.Argument,
branch: Branch, branch: Branch,
block: Debug.Block.Index, block: Debug.Block.Index,
@ -758,6 +780,12 @@ pub const Instruction = union(enum) {
source: V, source: V,
}; };
const AddOverflow = struct{
left: V,
right: V,
type: Type.Index,
};
pub const List = BlockList(@This(), enum {}); pub const List = BlockList(@This(), enum {});
pub usingnamespace @This().List.Index; pub usingnamespace @This().List.Index;
}; };
@ -1065,6 +1093,10 @@ pub const Debug = struct {
lexed, lexed,
parsed, parsed,
}; };
pub fn getPath(file: *File, allocator: Allocator) ![]const u8 {
return try std.mem.concat(allocator, u8, &.{ file.package.directory.path, "/", file.relative_path});
}
}; };
}; };
@ -1074,6 +1106,7 @@ pub const Mutability = enum(u1) {
}; };
pub const IntrinsicId = enum { pub const IntrinsicId = enum {
add_overflow,
assert, assert,
@"asm", //this is processed separately as it need special parsing @"asm", //this is processed separately as it need special parsing
cast, cast,
@ -1085,6 +1118,7 @@ pub const IntrinsicId = enum {
size, size,
sign_extend, sign_extend,
syscall, syscall,
trap,
zero_extend, zero_extend,
}; };
@ -1561,11 +1595,86 @@ pub const Builder = struct {
switch (argument_node.id) { switch (argument_node.id) {
.string_literal => { .string_literal => {
const error_message = try unit.fixupStringLiteral(context, argument_node.token); const error_message = try unit.fixupStringLiteral(context, argument_node.token);
std.debug.panic("Compile error: {s}", .{error_message}); builder.reportCompileError(unit, context, .{
.message = error_message,
.node = node_index,
});
}, },
else => |t| @panic(@tagName(t)), else => |t| @panic(@tagName(t)),
} }
}, },
.add_overflow => {
assert(argument_node_list.len == 2);
const left = try builder.resolveRuntimeValue(unit, context, type_expect, argument_node_list[0], .right);
const right_type_expect = switch (type_expect) {
.none => Type.Expect { .type = left.type },
else => type_expect,
};
const right = try builder.resolveRuntimeValue(unit, context, right_type_expect, argument_node_list[1], .right);
const add_overflow = try unit.instructions.append(context.allocator, .{
.add_overflow = .{
.left = left,
.right = right,
.type = left.type,
},
});
try builder.appendInstruction(unit, context, add_overflow);
const result_type = try unit.getOptionalType(context, left.type);
const extract_value = try unit.instructions.append(context.allocator, .{
.extract_value = .{
.expression = .{
.value = .{
.runtime = add_overflow,
},
.type = result_type,
},
.index = 1,
},
});
try builder.appendInstruction(unit, context, extract_value);
const carry = try builder.newBasicBlock(unit, context);
const normal = try builder.newBasicBlock(unit, context);
try builder.branch(unit, context, extract_value, carry, normal);
builder.current_basic_block = carry;
try builder.buildRet(unit, context, .{
.value = .{
.@"comptime" = .{
.constant_int = .{
.value = 1,
},
},
},
.type = left.type,
});
builder.current_basic_block = normal;
const result_extract_value = try unit.instructions.append(context.allocator, .{
.extract_value = .{
.expression = .{
.value = .{
.runtime = add_overflow,
},
.type = result_type,
},
.index = 0,
},
});
try builder.appendInstruction(unit, context, result_extract_value);
return V{
.value = .{
.runtime = result_extract_value,
},
.type = left.type,
};
},
else => |t| @panic(@tagName(t)), else => |t| @panic(@tagName(t)),
} }
} }
@ -3364,6 +3473,7 @@ pub const Builder = struct {
fields: u32 = 0, fields: u32 = 0,
declarations: u32 = 0, declarations: u32 = 0,
comptime_blocks: u32 = 0, comptime_blocks: u32 = 0,
test_declarations: u32 = 0,
} = .{}; } = .{};
for (container_nodes) |member_index| { for (container_nodes) |member_index| {
@ -3379,6 +3489,7 @@ pub const Builder = struct {
.declaration => result.declarations += 1, .declaration => result.declarations += 1,
.field => result.fields += 1, .field => result.fields += 1,
.comptime_block => result.comptime_blocks += 1, .comptime_block => result.comptime_blocks += 1,
.test_declaration => result.test_declarations += 1,
} }
} }
@ -3388,6 +3499,7 @@ pub const Builder = struct {
var declaration_nodes = try ArrayList(Node.Index).initCapacity(context.allocator, count.declarations); var declaration_nodes = try ArrayList(Node.Index).initCapacity(context.allocator, count.declarations);
var field_nodes = try ArrayList(Node.Index).initCapacity(context.allocator, count.fields); var field_nodes = try ArrayList(Node.Index).initCapacity(context.allocator, count.fields);
var comptime_block_nodes = try ArrayList(Node.Index).initCapacity(context.allocator, count.comptime_blocks); var comptime_block_nodes = try ArrayList(Node.Index).initCapacity(context.allocator, count.comptime_blocks);
var test_declarations = try ArrayList(Node.Index).initCapacity(context.allocator, count.test_declarations);
for (container_nodes) |member_index| { for (container_nodes) |member_index| {
const member_node = unit.getNode(member_index); const member_node = unit.getNode(member_index);
@ -3396,6 +3508,7 @@ pub const Builder = struct {
.comptime_block => &comptime_block_nodes, .comptime_block => &comptime_block_nodes,
.declaration => &declaration_nodes, .declaration => &declaration_nodes,
.field => &field_nodes, .field => &field_nodes,
.test_declaration => &test_declarations,
}; };
array_list.appendAssumeCapacity(member_index); array_list.appendAssumeCapacity(member_index);
} }
@ -3587,6 +3700,10 @@ pub const Builder = struct {
} }
} }
if (unit.descriptor.is_test and count.test_declarations > 0) {
unreachable;
}
return type_index; return type_index;
} }
@ -5109,6 +5226,11 @@ pub const Builder = struct {
break :blk v; break :blk v;
}, },
}, },
.integer => {
const v = try builder.resolveRuntimeValue(unit, context, Type.Expect.none, node.left, .left);
_ = v;
unreachable;
},
else => |t| @panic(@tagName(t)), else => |t| @panic(@tagName(t)),
}, },
.none => { .none => {
@ -7864,6 +7986,16 @@ pub const Builder = struct {
try builder.appendInstruction(unit, context, ret); try builder.appendInstruction(unit, context, ret);
unit.basic_blocks.get(builder.current_basic_block).terminated = true; unit.basic_blocks.get(builder.current_basic_block).terminated = true;
} }
fn reportCompileError(builder: *Builder, unit: *Unit, context: *const Context, err: Error) noreturn{
const err_node = unit.getNode(err.node);
const file = unit.files.get(builder.current_file);
const token_debug_info = builder.getTokenDebugInfo(unit, err_node.token);
std.debug.print("{s}:{}:{}: \x1b[31merror:\x1b[0m {s}\n", .{file.getPath(context.allocator) catch unreachable, token_debug_info.line + 1, token_debug_info.column + 1, err.message});
// std.debug.print("[COMPILATION {s}] ", .{if (compilation_success) "\x1b[32mOK\x1b[0m" else "\x1b[31mFAILED\x1b[0m"});
// file.relative_path
std.os.abort();
}
}; };
pub const Enum = struct { pub const Enum = struct {
@ -8607,7 +8739,6 @@ pub const FixedKeyword = enum {
@"var", @"var",
void, void,
noreturn, noreturn,
function,
@"while", @"while",
bool, bool,
true, true,
@ -8628,6 +8759,7 @@ pub const FixedKeyword = enum {
@"for", @"for",
undefined, undefined,
@"break", @"break",
@"test",
}; };
pub const Descriptor = struct { pub const Descriptor = struct {
@ -8636,6 +8768,7 @@ pub const Descriptor = struct {
target: std.Target, target: std.Target,
only_parse: bool, only_parse: bool,
link_libc: bool, link_libc: bool,
is_test: bool,
generate_debug_information: bool, generate_debug_information: bool,
name: []const u8, name: []const u8,
}; };
@ -8649,6 +8782,7 @@ fn getContainerMemberType(member_id: Node.Id) MemberType {
.enum_field, .enum_field,
.container_field, .container_field,
=> .field, => .field,
.test_declaration => .test_declaration,
else => |t| @panic(@tagName(t)), else => |t| @panic(@tagName(t)),
}; };
} }
@ -8657,6 +8791,7 @@ const MemberType = enum {
declaration, declaration,
field, field,
comptime_block, comptime_block,
test_declaration,
}; };
pub const Token = struct { pub const Token = struct {
@ -8737,7 +8872,6 @@ pub const Token = struct {
operator_compare_greater, operator_compare_greater,
operator_compare_greater_equal, operator_compare_greater_equal,
// Fixed keywords // Fixed keywords
fixed_keyword_function,
fixed_keyword_const, fixed_keyword_const,
fixed_keyword_var, fixed_keyword_var,
fixed_keyword_void, fixed_keyword_void,
@ -8763,7 +8897,7 @@ pub const Token = struct {
fixed_keyword_for, fixed_keyword_for,
fixed_keyword_undefined, fixed_keyword_undefined,
fixed_keyword_break, fixed_keyword_break,
unused0, fixed_keyword_test,
unused1, unused1,
unused2, unused2,
unused3, unused3,

View File

@ -2605,7 +2605,7 @@ pub fn codegen(unit: *Compilation.Unit, context: *const Compilation.Context) !vo
try assembly_statements.appendSlice(context.allocator, "\n\t"); try assembly_statements.appendSlice(context.allocator, "\n\t");
} }
try constraints.appendSlice(context.allocator, ",~{dirflag},~{fpsr},~{flags}"); // try constraints.appendSlice(context.allocator, ",~{dirflag},~{fpsr},~{flags}");
}, },
else => |t| @panic(@tagName(t)), else => |t| @panic(@tagName(t)),
} }
@ -3090,6 +3090,15 @@ pub fn codegen(unit: *Compilation.Unit, context: *const Compilation.Context) !vo
const intrinsic_call = try llvm.callIntrinsic("llvm.trap", parameter_types, parameter_values); const intrinsic_call = try llvm.callIntrinsic("llvm.trap", parameter_types, parameter_values);
try llvm.llvm_instruction_map.putNoClobber(context.allocator, instruction_index, intrinsic_call); try llvm.llvm_instruction_map.putNoClobber(context.allocator, instruction_index, intrinsic_call);
}, },
.add_overflow => |add_overflow| {
const intrinsic_type = try llvm.getType(unit, context, add_overflow.type);
const parameter_types = [_]*LLVM.Type{intrinsic_type};
const left = try llvm.emitRightValue(unit, context, add_overflow.left);
const right = try llvm.emitRightValue(unit, context, add_overflow.right);
const arguments = [_]*LLVM.Value{ left, right };
const intrinsic_call = try llvm.callIntrinsic("llvm.sadd.with.overflow", &parameter_types, &arguments);
try llvm.llvm_instruction_map.putNoClobber(context.allocator, instruction_index, intrinsic_call);
},
else => |t| @panic(@tagName(t)), else => |t| @panic(@tagName(t)),
} }
} }

View File

@ -184,6 +184,9 @@ pub const Node = struct {
symbol_attribute_export, symbol_attribute_export,
symbol_attributes, symbol_attributes,
metadata, metadata,
test_declaration,
all_errors,
error_union,
}; };
}; };
@ -1372,7 +1375,6 @@ const Analyzer = struct {
}); });
}, },
.operator_ampersand => try analyzer.pointerOrArrayTypeExpression(.single_pointer_type), .operator_ampersand => try analyzer.pointerOrArrayTypeExpression(.single_pointer_type),
.operator_bang => unreachable, // error
.operator_left_bracket => switch (analyzer.peekTokenAhead(1)) { .operator_left_bracket => switch (analyzer.peekTokenAhead(1)) {
.operator_ampersand => try analyzer.pointerOrArrayTypeExpression(.many_pointer_type), .operator_ampersand => try analyzer.pointerOrArrayTypeExpression(.many_pointer_type),
.operator_asterisk => @panic("Meant to use ampersand?"), .operator_asterisk => @panic("Meant to use ampersand?"),
@ -1382,6 +1384,30 @@ const Analyzer = struct {
} }
fn errorUnionExpression(analyzer: *Analyzer) !Node.Index { fn errorUnionExpression(analyzer: *Analyzer) !Node.Index {
if (analyzer.peekToken() == .operator_bang) {
const error_union_token = try analyzer.expectToken(.operator_bang);
if (analyzer.peekToken() == .operator_asterisk) {
analyzer.consumeToken();
// All errors
const all_errors_node = try analyzer.addNode(.{
.id = .all_errors,
.token = error_union_token,
.left = .null,
.right = .null,
});
const type_node = try analyzer.suffixExpression();
const error_union = try analyzer.addNode(.{
.id = .error_union,
.token = error_union_token,
.left = all_errors_node,
.right = type_node,
});
return error_union;
} else {
unreachable;
}
} else {
const suffix_expression = try analyzer.suffixExpression(); const suffix_expression = try analyzer.suffixExpression();
return switch (analyzer.peekToken()) { return switch (analyzer.peekToken()) {
@ -1389,6 +1415,7 @@ const Analyzer = struct {
else => suffix_expression, else => suffix_expression,
}; };
} }
}
fn suffixExpression(analyzer: *Analyzer) !Node.Index { fn suffixExpression(analyzer: *Analyzer) !Node.Index {
analyzer.suffix_depth += 1; analyzer.suffix_depth += 1;
@ -1666,6 +1693,7 @@ const Analyzer = struct {
} }
}, },
.fixed_keyword_const, .fixed_keyword_var => try analyzer.symbolDeclaration(), .fixed_keyword_const, .fixed_keyword_var => try analyzer.symbolDeclaration(),
.fixed_keyword_test => try analyzer.testDeclaration(),
else => |t| @panic(@tagName(t)), else => |t| @panic(@tagName(t)),
}; };
@ -1696,6 +1724,18 @@ const Analyzer = struct {
}); });
} }
fn testDeclaration(analyzer: *Analyzer) !Node.Index {
const test_token = try analyzer.expectToken(.fixed_keyword_test);
const name_node: Node.Index = if (analyzer.peekToken() == .string_literal) try analyzer.identifierNode() else .null;
const test_block = try analyzer.block();
return try analyzer.addNode(.{
.token = test_token,
.id = .test_declaration,
.left = test_block,
.right = name_node,
});
}
fn primaryTypeExpression(analyzer: *Analyzer) anyerror!Node.Index { fn primaryTypeExpression(analyzer: *Analyzer) anyerror!Node.Index {
const token_i = analyzer.token_i; const token_i = analyzer.token_i;
const token = analyzer.peekToken(); const token = analyzer.peekToken();

View File

@ -42,11 +42,18 @@ pub fn main() !void {
todo(); todo();
} else if (equal(u8, command, "exe")) { } else if (equal(u8, command, "exe")) {
const context = try Compilation.createContext(allocator); const context = try Compilation.createContext(allocator);
try Compilation.buildExecutable(context, command_arguments); try Compilation.buildExecutable(context, command_arguments, .{
.is_test = false,
});
} else if (equal(u8, command, "lib")) { } else if (equal(u8, command, "lib")) {
todo(); todo();
} else if (equal(u8, command, "obj")) { } else if (equal(u8, command, "obj")) {
todo(); todo();
} else if (equal(u8, command, "test")) {
const context = try Compilation.createContext(allocator);
try Compilation.buildExecutable(context, command_arguments, .{
.is_test = true,
});
} else { } else {
todo(); todo();
} }

View File

@ -12,10 +12,23 @@ const Cpu = enum{
const Abi = enum{ const Abi = enum{
none, none,
gnu, gnu, msvc,
msvc,
}; };
const CallingConvention = enum{ const CallingConvention = enum{
system_v, system_v,
}; };
const PanicReason = enum{
integer_overflow,
null_unwrap,
};
const panic = fn (reason: PanicReason) noreturn{
#trap();
}
const TestFunction = struct{
name: []const u8,
function: &const fn () !*void,
};

View File

@ -415,6 +415,15 @@ const waitpid = fn(pid: Process.Id, flags: u32) ?u32 {
} }
} }
}, },
.macos => {
var status: s32 = undefined;
if (macos.waitpid(pid, status.&, #cast(flags)) != -1) {
const status_u: u32 = #cast(status);
return status_u;
} else {
return null;
}
},
else => #error("OS not supported"), else => #error("OS not supported"),
} }

View File

@ -52,5 +52,6 @@ const mmap :: extern = fn (address: ?[&]const u8, length: usize, protection_flag
const munmap :: extern = fn (address: [&]const u8, length: usize) s32; const munmap :: extern = fn (address: [&]const u8, length: usize) s32;
const execve :: extern = fn(path: [&:0]const u8, argv: [&:null]const ?[&:0]const u8, env: [&:null]const ?[&:null]const u8) s32; const execve :: extern = fn(path: [&:0]const u8, argv: [&:null]const ?[&:0]const u8, env: [&:null]const ?[&:null]const u8) s32;
const realpath :: extern = fn(path: [&:0]const u8, resolved_path: [&:0]u8) [&:0]u8; const realpath :: extern = fn(path: [&:0]const u8, resolved_path: [&:0]u8) [&:0]u8;
const waitpid :: extern = fn(pid: ProcessId, status: &s32, flags: s32) s32;
const _NSGetExecutablePath :: extern = fn (buffer: [&:0]u8, buffer_size: &u32) s32; const _NSGetExecutablePath :: extern = fn (buffer: [&:0]u8, buffer_size: &u32) s32;

View File

@ -35,6 +35,10 @@ const start :: export = fn (argc_argv_address: usize) noreturn {
std.os.exit(exit_code = result); std.os.exit(exit_code = result);
} }
const main :: export = fn (argc: s32, argv: [&:null]?[&:null]u8, env: [&:null]?[&:null]u8) s32 { const main :: export = fn (argc: s32, argv: [&]const [&:0]const u8, env: [&:null]const ?[&:null]const u8) s32 {
const argc_u: u32 = #cast(argc);
argument_count = argc_u;
argument_values = argv;
environment_values = env;
return #import("main").main(); return #import("main").main();
} }

2
test/tests/main.nat Normal file
View File

@ -0,0 +1,2 @@
test {
}