diff --git a/build.zig b/build.zig index f084a63..19581bf 100644 --- a/build.zig +++ b/build.zig @@ -510,6 +510,7 @@ pub fn build(b: *std.Build) !void { const test_command = b.addRunArtifact(test_runner); test_command.step.dependOn(&compiler.step); + b.installArtifact(test_runner); test_command.step.dependOn(b.getInstallStep()); if (b.args) |args| { diff --git a/build/test_runner.zig b/build/test_runner.zig index d676eff..f753297 100644 --- a/build/test_runner.zig +++ b/build/test_runner.zig @@ -29,9 +29,12 @@ fn collectDirectoryDirEntries(allocator: Allocator, path: []const u8) ![]const [ return dir_entries.items; } +const bootstrap_relative_path = "zig-out/bin/nat"; + fn runStandalone(allocator: Allocator, args: struct { directory_path: []const u8, group_name: []const u8, + self_hosted: bool, is_test: bool, }) !void { const test_names = try collectDirectoryDirEntries(allocator, args.directory_path); @@ -52,7 +55,7 @@ fn runStandalone(allocator: Allocator, args: struct { const compile_run = try std.ChildProcess.run(.{ .allocator = allocator, // TODO: delete -main_source_file? - .argv = &.{ "zig-out/bin/nat", if (args.is_test) "test" else "exe", "-main_source_file", source_file_path }, + .argv = &.{ if (args.self_hosted) self_hosted_relative_path else bootstrap_relative_path, if (args.is_test) "test" else "exe", "-main_source_file", source_file_path }, .max_output_bytes = std.math.maxInt(u64), }); ran_compilation_count += 1; @@ -77,7 +80,7 @@ fn runStandalone(allocator: Allocator, args: struct { std.debug.print("STDERR:\n\n{s}\n\n", .{compile_run.stderr}); } - if (compilation_success) { + if (compilation_success and !args.self_hosted) { const test_path = try std.mem.concat(allocator, u8, &.{ "nat/", test_name }); const test_run = try std.ChildProcess.run(.{ .allocator = allocator, @@ -117,7 +120,9 @@ fn runStandalone(allocator: Allocator, args: struct { } } -fn runStandaloneTests(allocator: Allocator) !void { +fn runStandaloneTests(allocator: Allocator, args: struct { + self_hosted: bool, +}) !void { const standalone_test_dir_path = "test/standalone"; const standalone_test_names = try collectDirectoryDirEntries(allocator, standalone_test_dir_path); @@ -135,7 +140,7 @@ fn runStandaloneTests(allocator: Allocator) !void { const compile_run = try std.ChildProcess.run(.{ .allocator = allocator, // TODO: delete -main_source_file? - .argv = &.{ "zig-out/bin/nat", "exe", "-main_source_file", source_file_path }, + .argv = &.{ if (args.self_hosted) self_hosted_relative_path else bootstrap_relative_path, "exe", "-main_source_file", source_file_path }, .max_output_bytes = std.math.maxInt(u64), }); ran_compilation_count += 1; @@ -160,7 +165,7 @@ fn runStandaloneTests(allocator: Allocator) !void { std.debug.print("STDERR:\n\n{s}\n\n", .{compile_run.stderr}); } - if (compilation_success) { + if (compilation_success and !args.self_hosted) { const test_path = try std.mem.concat(allocator, u8, &.{ "nat/", standalone_test_name }); const test_run = try std.ChildProcess.run(.{ .allocator = allocator, @@ -200,13 +205,15 @@ fn runStandaloneTests(allocator: Allocator) !void { } } -fn runBuildTests(allocator: Allocator) !void { +fn runBuildTests(allocator: Allocator, args: struct { + self_hosted: bool, +}) !void { std.debug.print("\n[BUILD TESTS]\n\n", .{}); const previous_cwd = try std.fs.cwd().realpathAlloc(allocator, "."); const test_dir_path = "test/build"; const test_names = try collectDirectoryDirEntries(allocator, test_dir_path); const test_dir_realpath = try std.fs.cwd().realpathAlloc(allocator, test_dir_path); - const compiler_realpath = try std.fs.cwd().realpathAlloc(allocator, "zig-out/bin/nat"); + const compiler_realpath = try std.fs.cwd().realpathAlloc(allocator, if (args.self_hosted) self_hosted_relative_path else bootstrap_relative_path); try std.posix.chdir(test_dir_realpath); const total_compilation_count = test_names.len; @@ -250,7 +257,7 @@ fn runBuildTests(allocator: Allocator) !void { std.debug.print("STDERR:\n\n{s}\n\n", .{compile_run.stderr}); } - if (compilation_success) { + if (compilation_success and !args.self_hosted) { const test_path = try std.mem.concat(allocator, u8, &.{ "nat/", test_name }); const test_run = try std.ChildProcess.run(.{ .allocator = allocator, @@ -294,13 +301,15 @@ fn runBuildTests(allocator: Allocator) !void { } } -fn runStdTests(allocator: Allocator) !void { +fn runStdTests(allocator: Allocator, args: struct { + self_hosted: bool, +}) !void { var errors = false; std.debug.print("std... ", .{}); const result = try std.ChildProcess.run(.{ .allocator = allocator, - .argv = &.{ "zig-out/bin/nat", "test", "-main_source_file", "lib/std/std.nat", "-name", "std" }, + .argv = &.{ if (args.self_hosted) self_hosted_relative_path else bootstrap_relative_path, "test", "-main_source_file", "lib/std/std.nat", "-name", "std" }, .max_output_bytes = std.math.maxInt(u64), }); const compilation_result: TestError!bool = switch (result.term) { @@ -323,7 +332,7 @@ fn runStdTests(allocator: Allocator) !void { std.debug.print("STDERR:\n\n{s}\n\n", .{result.stderr}); } - if (compilation_success) { + if (compilation_success and !args.self_hosted) { const test_run = try std.ChildProcess.run(.{ .allocator = allocator, // TODO: delete -main_source_file? @@ -486,50 +495,107 @@ fn runCmakeTests(allocator: Allocator, dir_path: []const u8) !void { } } -pub fn main() !void { +const self_hosted_exe_name = "compiler"; +const self_hosted_relative_path = "nat/" ++ self_hosted_exe_name; + +fn compile_self_hosted(allocator: Allocator, args: struct { + is_test: bool, +}) !void { + const compile_run = try std.ChildProcess.run(.{ + .allocator = allocator, + // TODO: delete -main_source_file? + .argv = &.{ bootstrap_relative_path, if (args.is_test) "test" else "exe", "-main_source_file", "src/main.nat", "-name", self_hosted_exe_name }, + .max_output_bytes = std.math.maxInt(u64), + }); + + const compilation_result: TestError!bool = switch (compile_run.term) { + .Exited => |exit_code| if (exit_code == 0) true else error.abnormal_exit_code, + .Signal => error.signaled, + .Stopped => error.stopped, + .Unknown => error.unknown, + }; + + _ = try compilation_result; +} + +fn run_test_suite(allocator: Allocator, args: struct { + self_hosted: bool, +}) bool { + const self_hosted = args.self_hosted; + std.debug.print("TESTING {s} COMPILER...\n=================\n", .{if (self_hosted) "SELF-HOSTED" else "BOOTSTRAP"}); var errors = false; - var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator); - const allocator = arena.allocator(); runStandalone(allocator, .{ .directory_path = "test/standalone", .group_name = "STANDALONE", .is_test = false, + .self_hosted = self_hosted, }) catch { errors = true; }; - runBuildTests(allocator) catch { + runBuildTests(allocator, .{ + .self_hosted = self_hosted, + }) catch { errors = true; }; runStandalone(allocator, .{ .directory_path = "test/tests", .group_name = "TEST EXECUTABLE", .is_test = true, + .self_hosted = self_hosted, }) catch { errors = true; }; // - runStdTests(allocator) catch { + runStdTests(allocator, .{ + .self_hosted = self_hosted, + }) catch { errors = true; }; - runCmakeTests(allocator, "test/cc") catch { - errors = true; - }; - runCmakeTests(allocator, "test/c++") catch { - errors = true; - }; + if (!self_hosted) { + runCmakeTests(allocator, "test/cc") catch { + errors = true; + }; + runCmakeTests(allocator, "test/c++") catch { + errors = true; + }; - switch (@import("builtin").os.tag) { - .macos => {}, - .windows => {}, - .linux => switch (@import("builtin").abi) { - .gnu => runCmakeTests(allocator, "test/cc_linux") catch { - errors = true; + switch (@import("builtin").os.tag) { + .macos => {}, + .windows => {}, + .linux => switch (@import("builtin").abi) { + .gnu => runCmakeTests(allocator, "test/cc_linux") catch { + errors = true; + }, + .musl => {}, + else => @compileError("ABI not supported"), }, - .musl => {}, - else => @compileError("ABI not supported"), - }, - else => @compileError("OS not supported"), + else => @compileError("OS not supported"), + } + } + + return errors; +} + +pub fn main() !void { + var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator); + const allocator = arena.allocator(); + + var errors = run_test_suite(allocator, .{ + .self_hosted = false, + }); + + if (!errors) { + if (compile_self_hosted(allocator, .{ + .is_test = false, + })) |_| { + errors = errors or run_test_suite(allocator, .{ + .self_hosted = true, + }); + } else |err| { + err catch {}; + errors = true; + } } if (errors) { diff --git a/src/main.nat b/src/main.nat index 6fcbf13..f4515eb 100644 --- a/src/main.nat +++ b/src/main.nat @@ -1,20 +1,4 @@ const std = #import("std"); -const main = fn() s32 { - const size = 0x1000; - - if (std.page_allocator.allocate(size, alignment = 12)) |result| { - result[0] = 0; - std.print(bytes = "Allocation succeeded. Freeing...\n"); - if (std.page_allocator.free(bytes_ptr = result.ptr, bytes_len = result.len)) { - std.print(bytes = "Memory freed successfully\n"); - return 0; - } else { - std.print(bytes = "Memory freed with errors\n"); - return 1; - } - } else { - std.print(bytes = "Allocation failed!\n"); - return 1; - } +const main = fn() *!void { }