diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ca94ebe..9dd5445 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -2,9 +2,6 @@ name: CI on: pull_request: - push: - branches: - - main schedule: - cron: "0 0 * * *" concurrency: @@ -13,15 +10,15 @@ concurrency: cancel-in-progress: true jobs: - build_and_test: + self_hosted_linux: runs-on: [ self-hosted, Linux, x64 ] timeout-minutes: 15 steps: - name: Checkout uses: actions/checkout@v3 - name: Set up Zig - uses: goto-bus-stop/setup-zig@v2 + uses: davidgm94/setup-zig@foo with: version: master - name: Test - run: ./ci.sh ../todo_foo_debug_path ../../../../../dev/llvm-static-release-zen4-17.0.6/out/x86_64-linux-musl-native + run: zig build test -Dllvm_path=../../../../../dev/llvm/llvm-static-release-zen4-17.0.6/out/x86_64-linux-musl-native -Dself_hosted_ci=true diff --git a/.github/workflows/ci_main.yml b/.github/workflows/ci_main.yml new file mode 100644 index 0000000..59141b9 --- /dev/null +++ b/.github/workflows/ci_main.yml @@ -0,0 +1,63 @@ +name: CI_Github_FlyCI + +on: + # pull_request: + push: + branches: + - main +concurrency: + # Cancels pending runs when a PR gets updated. + group: ${{ github.head_ref || github.run_id }}-${{ github.actor }} + cancel-in-progress: true + +jobs: + self_hosted_linux: + runs-on: [ self-hosted, Linux, x64 ] + timeout-minutes: 15 + steps: + - name: Checkout + uses: actions/checkout@v3 + - name: Set up Zig + uses: davidgm94/setup-zig@foo + with: + version: master + - name: Test + run: zig build test -Dllvm_path=../../../../../dev/llvm/llvm-static-release-zen4-17.0.6/out/x86_64-linux-musl-native -Dself_hosted_ci=true + # linux_x86_64: + # runs-on: ubuntu-latest + # timeout-minutes: 15 + # steps: + # - name: Checkout + # uses: actions/checkout@v3 + # - name: Set up Zig + # uses: davidgm94/setup-zig@foo + # with: + # version: master + # - name: Test + # run: ./ci.sh -Dthird_party_ci=true -Dtarget=x86_64-linux-musl -Dcpu=x86_64_v3 + # windows_x86_64: + # runs-on: windows-latest + # timeout-minutes: 15 + # steps: + # - name: Checkout + # uses: actions/checkout@v3 + # - name: Set up Zig + # uses: davidgm94/setup-zig@foo + # with: + # version: master + # - name: Test + # run: zig version + # macos_m1: + # runs-on: flyci-macos-large-latest-m1 + # timeout-minutes: 15 + # steps: + # - name: Checkout + # uses: actions/checkout@v3 + # - name: Set up Zig + # uses: davidgm94/setup-zig@foo + # with: + # version: master + # - name: Test zig + # run: zig version + # - name: Test macos + # run: ./ci.sh -Dthird_party_ci=true -Dtarget=aarch64-macos-none -Dcpu=apple_m1 diff --git a/.gitignore b/.gitignore index 212371e..c7e49e6 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ -zig-cache -zig-out -nat +zig-cache/ +zig-out/ +nat/ +llvm*/ diff --git a/bootstrap/Compilation.zig b/bootstrap/Compilation.zig index 643871b..da57cf0 100644 --- a/bootstrap/Compilation.zig +++ b/bootstrap/Compilation.zig @@ -38,8 +38,11 @@ fn parseArguments(context: *const Context) !Descriptor { var maybe_executable_path: ?[]const u8 = null; var maybe_main_package_path: ?[]const u8 = null; - var target_triplet: []const u8 = "x86_64-linux-gnu"; - var should_transpile_to_c: ?bool = null; + var target_triplet: []const u8 = switch (@import("builtin").os.tag) { + .linux => "x86_64-linux-gnu", + .macos => "aarch64-macos-none", + else => unreachable, + }; var maybe_only_parse: ?bool = null; var link_libc = false; var maybe_executable_name: ?[]const u8 = null; @@ -113,21 +116,6 @@ fn parseArguments(context: *const Context) !Descriptor { } else { reportUnterminatedArgumentError(current_argument); } - } else if (equal(u8, current_argument, "-transpile_to_c")) { - if (i + 1 != arguments.len) { - i += 1; - - const arg = arguments[i]; - if (std.mem.eql(u8, arg, "true")) { - should_transpile_to_c = true; - } else if (std.mem.eql(u8, arg, "false")) { - should_transpile_to_c = false; - } else { - unreachable; - } - } else { - reportUnterminatedArgumentError(current_argument); - } } else if (equal(u8, current_argument, "-parse")) { if (i + 1 != arguments.len) { i += 1; @@ -179,7 +167,6 @@ fn parseArguments(context: *const Context) !Descriptor { const cross_target = try std.zig.CrossTarget.parse(.{ .arch_os_abi = target_triplet }); const target = try std.zig.system.resolveTargetQuery(cross_target); - const transpile_to_c = should_transpile_to_c orelse false; const only_parse = maybe_only_parse orelse false; const main_package_path = if (maybe_main_package_path) |path| blk: { @@ -213,10 +200,14 @@ fn parseArguments(context: *const Context) !Descriptor { .main_package_path = main_package_path, .executable_path = executable_path, .target = target, - .transpile_to_c = transpile_to_c, .is_build = is_build, .only_parse = only_parse, - .link_libc = link_libc, + .link_libc = switch (target.os.tag) { + .linux => link_libc, + .macos => true, + .windows => link_libc, + else => unreachable, + }, .generate_debug_information = generate_debug_information, .name = executable_name, }; @@ -431,7 +422,10 @@ fn getLoggerScopeType(comptime logger_scope: LoggerScope) type { var logger_bitset = std.EnumSet(LoggerScope).initEmpty(); -var writer = std.io.getStdOut().writer(); +fn getWriter() !std.fs.File.Writer{ + const stdout = std.io.getStdOut(); + return stdout.writer(); +} fn shouldLog(comptime logger_scope: LoggerScope, logger: getLoggerScopeType(logger_scope).Logger) bool { return logger_bitset.contains(logger_scope) and getLoggerScopeType(logger_scope).Logger.bitset.contains(logger); @@ -440,21 +434,23 @@ fn shouldLog(comptime logger_scope: LoggerScope, logger: getLoggerScopeType(logg pub fn logln(comptime logger_scope: LoggerScope, logger: getLoggerScopeType(logger_scope).Logger, comptime format: []const u8, arguments: anytype) void { if (shouldLog(logger_scope, logger)) { log(logger_scope, logger, format, arguments); + const writer = try getWriter(); writer.writeByte('\n') catch unreachable; } } pub fn log(comptime logger_scope: LoggerScope, logger: getLoggerScopeType(logger_scope).Logger, comptime format: []const u8, arguments: anytype) void { if (shouldLog(logger_scope, logger)) { - std.fmt.format(writer, format, arguments) catch unreachable; + std.fmt.format(try getWriter(), format, arguments) catch unreachable; } } pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, return_address: ?usize) noreturn { - const print_stack_trace = false; + const print_stack_trace = true; switch (print_stack_trace) { true => @call(.always_inline, std.builtin.default_panic, .{ message, stack_trace, return_address }), false => { + const writer = try getWriter(); writer.writeAll("\nPANIC: ") catch {}; writer.writeAll(message) catch {}; writer.writeByte('\n') catch {}; @@ -1290,7 +1286,10 @@ pub const Builder = struct { if (unit.evaluateBooleanAtComptime(condition)) |comptime_condition| { if (comptime_condition == true) { - unreachable; + @panic("TODO: if comptime true"); + // return If{ + // .condition = .true, + // }; } else { return If{ .condition = .false, @@ -3633,7 +3632,6 @@ pub const Descriptor = struct { main_package_path: []const u8, executable_path: []const u8, target: std.Target, - transpile_to_c: bool, is_build: bool, only_parse: bool, link_libc: bool, diff --git a/bootstrap/backend/llvm.cpp b/bootstrap/backend/llvm.cpp index b8a4b82..2855228 100644 --- a/bootstrap/backend/llvm.cpp +++ b/bootstrap/backend/llvm.cpp @@ -16,6 +16,7 @@ #include "lld/Common/CommonLinkerContext.h" + using namespace llvm; extern "C" LLVMContext* NativityLLVMCreateContext() @@ -589,16 +590,26 @@ extern "C" Constant* NativityLLVMContextCreateGlobalStringPointer(IRBuilder<>& b return constant; } +void stream_to_string(raw_string_ostream& stream, const char** message_ptr, size_t* message_len) +{ + stream.flush(); + + auto string = stream.str(); + char* result = new char[string.length()]; + memcpy(result, string.c_str(), string.length()); + + *message_ptr = result; + *message_len = string.length(); +} + extern "C" bool NativityLLVMVerifyFunction(Function& function, const char** message_ptr, size_t* message_len) { std::string message_buffer; raw_string_ostream message_stream(message_buffer); bool result = verifyFunction(function, &message_stream); - message_stream.flush(); auto size = message_stream.str().size(); - *message_ptr = strndup(message_stream.str().c_str(), size); - *message_len = size; + stream_to_string(message_stream, message_ptr, message_len); // We invert the condition because LLVM conventions are just stupid return !result; @@ -610,10 +621,7 @@ extern "C" bool NativityLLVMVerifyModule(const Module& module, const char** mess raw_string_ostream message_stream(message_buffer); bool result = verifyModule(module, &message_stream); - message_stream.flush(); - auto size = message_stream.str().size(); - *message_ptr = strndup(message_stream.str().c_str(), size); - *message_len = size; + stream_to_string(message_stream, message_ptr, message_len); // We invert the condition because LLVM conventions are just stupid return !result; diff --git a/build.zig b/build.zig index 62ca281..271dd5f 100644 --- a/build.zig +++ b/build.zig @@ -1,36 +1,104 @@ const std = @import("std"); -var all: bool = false; +const assert = std.debug.assert; pub fn build(b: *std.Build) !void { - all = b.option(bool, "all", "All") orelse false; + 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; + _ = is_ci; // autofix + const native_target = b.resolveTargetQuery(.{}); const optimization = b.standardOptimizeOption(.{}); - const llvm_debug = b.option(bool, "llvm_debug", "Use LLVM in the debug version") orelse false; - const llvm_debug_path = b.option([]const u8, "llvm_debug_path", "LLVM debug path") orelse "../llvm-17-static-debug"; - const llvm_release_path = b.option([]const u8, "llvm_release_path", "LLVM release path") orelse "../llvm-17-static-release"; - const target_query = try std.zig.CrossTarget.parse(.{ - .arch_os_abi = "native-linux-musl", - }); + var target_query = b.standardTargetOptionsQueryOnly(.{}); + const os = target_query.os_tag orelse @import("builtin").os.tag; + if (os == .linux) { + target_query.abi = .musl; + } const target = b.resolveTargetQuery(target_query); - const exe = b.addExecutable(.{ + const llvm_version = "17.0.6"; + var fetcher_run: ?*std.Build.Step.Run = null; + const llvm_path = b.option([]const u8, "llvm_path", "LLVM prefix path") orelse blk: { + assert(!self_hosted_ci); + if (third_party_ci or (!target.query.isNativeOs() or !target.query.isNativeCpu())) { + const prefix = "nat/cache"; + var llvm_directory = try std.ArrayListUnmanaged(u8).initCapacity(b.allocator, 128); + llvm_directory.appendSliceAssumeCapacity(prefix ++ "/"); + llvm_directory.appendSliceAssumeCapacity("llvm-"); + llvm_directory.appendSliceAssumeCapacity(llvm_version); + llvm_directory.appendSliceAssumeCapacity("-"); + llvm_directory.appendSliceAssumeCapacity(@tagName(target.result.cpu.arch)); + llvm_directory.appendSliceAssumeCapacity("-"); + llvm_directory.appendSliceAssumeCapacity(@tagName(target.result.os.tag)); + llvm_directory.appendSliceAssumeCapacity("-"); + llvm_directory.appendSliceAssumeCapacity(@tagName(target.result.abi)); + llvm_directory.appendSliceAssumeCapacity("-"); + llvm_directory.appendSliceAssumeCapacity(if (std.mem.eql(u8, target.result.cpu.model.name, @tagName(target.result.cpu.arch))) "baseline" else target.result.cpu.model.name); + + var dir = std.fs.cwd().openDir(llvm_directory.items, .{}) catch { + const llvm_fetcher = b.addExecutable(.{ + .name = "llvm_fetcher", + .root_source_file = .{ .path = "build/llvm_fetcher.zig" }, + .target = native_target, + .optimize = .ReleaseFast, + .single_threaded = true, + }); + const run = b.addRunArtifact(llvm_fetcher); + fetcher_run = run; + run.addArg("-prefix"); + run.addArg(prefix); + run.addArg("-version"); + run.addArg(llvm_version); + run.addArg("-arch"); + run.addArg(@tagName(target.result.cpu.arch)); + run.addArg("-os"); + run.addArg(@tagName(target.result.os.tag)); + run.addArg("-abi"); + run.addArg(@tagName(target.result.abi)); + run.addArg("-cpu"); + run.addArg(target.result.cpu.model.name); + break :blk llvm_directory.items; + }; + + dir.close(); + + break :blk llvm_directory.items; + } else { + const use_debug = b.option(bool, "use_debug", "This option enables the LLVM debug build in the development PC") orelse false; + break :blk switch (use_debug) { + true => "../llvm-17-static-debug", + false => "../llvm-17-static-release", + }; + } + }; + + const compiler = b.addExecutable(.{ .name = "nat", .root_source_file = .{ .path = "bootstrap/main.zig" }, .target = target, .optimize = optimization, - .use_llvm = true, - .use_lld = true, }); - exe.formatted_panics = false; - exe.root_module.unwind_tables = false; - exe.root_module.omit_frame_pointer = false; + // compiler.formatted_panics = false; + // compiler.root_module.unwind_tables = false; + // compiler.root_module.omit_frame_pointer = false; + compiler.want_lto = false; - const llvm_dir = if (llvm_debug) llvm_debug_path else llvm_release_path; - const llvm_include_dir = try std.mem.concat(b.allocator, u8, &.{ llvm_dir, "/include" }); - const llvm_lib_dir = try std.mem.concat(b.allocator, u8, &.{ llvm_dir, "/lib" }); + compiler.linkLibC(); + compiler.linkSystemLibrary("c++"); - exe.linkLibCpp(); + if (target.result.os.tag == .windows) { + compiler.linkSystemLibrary("ole32"); + compiler.linkSystemLibrary("version"); + compiler.linkSystemLibrary("uuid"); + compiler.linkSystemLibrary("msvcrt-os"); + } - exe.addIncludePath(std.Build.LazyPath.relative(llvm_include_dir)); - exe.addCSourceFile(.{ + if (fetcher_run) |fr| { + compiler.step.dependOn(&fr.step); + } + + const llvm_include_dir = try std.mem.concat(b.allocator, u8, &.{ llvm_path, "/include" }); + const llvm_lib_dir = try std.mem.concat(b.allocator, u8, &.{ llvm_path, "/lib" }); + compiler.addIncludePath(std.Build.LazyPath.relative(llvm_include_dir)); + compiler.addCSourceFile(.{ .file = std.Build.LazyPath.relative("bootstrap/backend/llvm.cpp"), .flags = &.{"-g"}, }); @@ -218,9 +286,6 @@ pub fn build(b: *std.Build) !void { "libLLVMXCoreDisassembler.a", "libLLVMXCoreInfo.a", "libLLVMXRay.a", - // Zlib - "libz.a", - "libzstd.a", //LLD "liblldCOFF.a", "liblldCommon.a", @@ -228,14 +293,16 @@ pub fn build(b: *std.Build) !void { "liblldMachO.a", "liblldMinGW.a", "liblldWasm.a", + // Zlib + "libz.a", + if (target.result.os.tag == .windows) "zstd.lib" else "libzstd.a", }; - inline for (llvm_libraries) |llvm_library| { - exe.addObjectFile(std.Build.LazyPath.relative(try std.mem.concat(b.allocator, u8, &.{ llvm_lib_dir, "/", llvm_library }))); + for (llvm_libraries) |llvm_library| { + compiler.addObjectFile(std.Build.LazyPath.relative(try std.mem.concat(b.allocator, u8, &.{ llvm_lib_dir, "/", llvm_library }))); } - - const install_exe = b.addInstallArtifact(exe, .{}); + const install_exe = b.addInstallArtifact(compiler, .{}); b.getInstallStep().dependOn(&install_exe.step); b.installDirectory(.{ .source_dir = std.Build.LazyPath.relative("lib"), @@ -275,13 +342,28 @@ pub fn build(b: *std.Build) !void { debug_command.step.dependOn(b.getInstallStep()); debug_command.addArg(compiler_exe_path); + const test_runner = b.addExecutable(.{ + .name = "test_runner", + .root_source_file = .{ .path = "build/test_runner.zig" }, + .target = native_target, + .optimize = optimization, + .single_threaded = true, + }); + + const test_command = b.addRunArtifact(test_runner); + test_command.step.dependOn(&compiler.step); + test_command.step.dependOn(b.getInstallStep()); + if (b.args) |args| { run_command.addArgs(args); debug_command.addArgs(args); + test_command.addArgs(args); } const run_step = b.step("run", "Test the Nativity compiler"); run_step.dependOn(&run_command.step); const debug_step = b.step("debug", "Debug the Nativity compiler"); debug_step.dependOn(&debug_command.step); + const test_step = b.step("test", "Test the Nativity compiler"); + test_step.dependOn(&test_command.step); } diff --git a/build/llvm_fetcher.zig b/build/llvm_fetcher.zig new file mode 100644 index 0000000..da125d9 --- /dev/null +++ b/build/llvm_fetcher.zig @@ -0,0 +1,112 @@ +const std = @import("std"); +const equal = std.mem.eql; + +pub fn main() !void { + var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator); + const allocator = arena.allocator(); + const arguments = try std.process.argsAlloc(allocator); + var arch_arg: ?std.Target.Cpu.Arch = null; + var os_arg: ?std.Target.Os.Tag = null; + var abi_arg: ?std.Target.Abi = null; + var cpu_arg: [:0]const u8 = "baseline"; + var version_arg: ?[]const u8 = null; + var prefix_arg: [:0]const u8 = "nat"; + + const State = enum{ + none, + prefix, + version, + arch, + os, + abi, + cpu, + }; + + var state = State.none; + + for (arguments[1..]) |argument| { + switch (state) { + .none => { + if (equal(u8, argument, "-prefix")) { + state = .prefix; + } else if (equal(u8, argument, "-version")) { + state = .version; + } else if (equal(u8, argument, "-arch")) { + state = .arch; + } else if (equal(u8, argument, "-os")) { + state = .os; + } else if (equal(u8, argument, "-abi")) { + state = .abi; + } else if (equal(u8, argument, "-cpu")) { + state = .cpu; + } else return error.InvalidInput; + }, + .prefix => { + prefix_arg = argument; + state = .none; + }, + .version => { + version_arg = argument; + state = .none; + }, + .arch => { + arch_arg = std.meta.stringToEnum(std.Target.Cpu.Arch, argument) orelse return error.InvalidInput; + state = .none; + }, + .os => { + os_arg = std.meta.stringToEnum(std.Target.Os.Tag, argument) orelse return error.InvalidInput; + state = .none; + }, + .abi => { + abi_arg = std.meta.stringToEnum(std.Target.Abi, argument) orelse return error.InvalidInput; + state = .none; + }, + .cpu => { + cpu_arg = argument; + state = .none; + }, + } + } + + const version = version_arg orelse return error.InvalidInput; + const arch = arch_arg orelse return error.InvalidInput; + const os = os_arg orelse return error.InvalidInput; + const abi = abi_arg orelse return error.InvalidInput; + const cpu = cpu_arg; + const prefix = prefix_arg; + + if (state != .none) return error.InvalidInput; + + const url = try std.mem.concat(allocator, u8, &.{"https://github.com/birth-software/fetch-llvm/releases/download/v", version, "/llvm-", version, "-", @tagName(arch), "-", @tagName(os), "-", @tagName(abi), "-", cpu, ".tar.xz"}); + const uri = try std.Uri.parse(url); + var http_client = std.http.Client{ + .allocator = allocator, + }; + defer http_client.deinit(); + + var headers = std.http.Headers{ + .allocator = allocator, + }; + defer headers.deinit(); + + var request = try http_client.open(.GET, uri, headers, .{}); + defer request.deinit(); + try request.send(.{}); + try request.wait(); + + if (request.response.status != .ok) { + std.debug.panic("Status: {s} when fetching TAR {s}", .{@tagName(request.response.status), url}); + } + + var decompression = try std.compress.xz.decompress(allocator, request.reader()); + defer decompression.deinit(); + + var decompressed_buffer = std.ArrayList(u8).init(allocator); + try decompression.reader().readAllArrayList(&decompressed_buffer, std.math.maxInt(u32)); + + var memory_stream = std.io.fixedBufferStream(decompressed_buffer.items); + const directory = try std.fs.cwd().makeOpenPath(prefix, .{}); + try std.tar.pipeToFileSystem(directory, memory_stream.reader(), .{ + .mode_mode = .ignore, + }); +} diff --git a/build/test_runner.zig b/build/test_runner.zig new file mode 100644 index 0000000..bddfe0b --- /dev/null +++ b/build/test_runner.zig @@ -0,0 +1,60 @@ +const std = @import("std"); + +const TestError = error{ + junk_in_test_directory, + abnormal_exit_code, + signaled, + stopped, + unknown, + fail, +}; + +pub fn main() !void { + var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator); + const allocator = arena.allocator(); + const standalone_test_dir_path = "test/standalone"; + var standalone_test_dir = try std.fs.cwd().openDir(standalone_test_dir_path, .{ + .iterate = true, + }); + var standalone_iterator = standalone_test_dir.iterate(); + var standalone_test_names = std.ArrayListUnmanaged([]const u8){}; + + while (try standalone_iterator.next()) |entry| { + switch (entry.kind) { + .directory => try standalone_test_names.append(allocator, entry.name), + else => return error.junk_in_test_directory, + } + } + + standalone_test_dir.close(); + + var ran_test_count: usize = 0; + var failed_test_count: usize = 0; + + for (standalone_test_names.items) |standalone_test_name| { + defer ran_test_count += 1; + std.debug.print("{s}... ", .{standalone_test_name}); + const source_file_path = try std.mem.concat(allocator, u8, &.{standalone_test_dir_path, "/", standalone_test_name, "/main.nat"}); + const process_run = try std.ChildProcess.run(.{ + .allocator = allocator, + .argv = &.{"zig-out/bin/nat", "-main_source_file", source_file_path}, + }); + const result: TestError!bool = switch (process_run.term) { + .Exited => |exit_code| if (exit_code == 0) true else error.abnormal_exit_code, + .Signal => error.signaled, + .Stopped => error.stopped, + .Unknown => error.unknown, + }; + + const success = result catch b: { + failed_test_count += 1; + break :b false; + }; + std.debug.print("[{s}]\n", .{if (success) "OK" else "FAIL"}); + } + + std.debug.print("\nTest count: {}. Failed test count: {}\n", .{ran_test_count, failed_test_count}); + if (failed_test_count > 0) { + return error.fail; + } +} diff --git a/ci.sh b/ci.sh deleted file mode 100755 index 9bede8b..0000000 --- a/ci.sh +++ /dev/null @@ -1,139 +0,0 @@ -#!/usr/bin/env bash -argument_count=$#; -extra_args="" -use_debug="true" -if [ $argument_count -ne 0 ]; then - llvm_debug_path=$1 - llvm_release_path=$2 - use_debug="false" - extra_args="-Dllvm_debug_path=$llvm_debug_path -Dllvm_release_path=$llvm_release_path" -fi - -echo -e "\e[90mCompiling Nativity with Zig...\e[0m" -zig build -Dllvm_debug=$use_debug $extra_args -if [[ "$?" != 0 ]]; then - exit 1 -fi -failed_test_count=0 -passed_test_count=0 -test_directory_name=test -standalone_test_directory=$test_directory_name/standalone -standalone_test_directory_files=$standalone_test_directory/* -integral_test_directory=$test_directory_name/integral -integral_test_directory_files=$integral_test_directory/* -standalone_test_count=$(ls 2>/dev/null -Ubad1 -- $standalone_test_directory/* | wc -l) -integral_test_count=$(ls 2>/dev/null -Ubad1 -- $integral_test_directory/* | wc -l) -total_test_count=$(($standalone_test_count + $integral_test_count)) - -ran_test_count=0 -test_i=1 -passed_compilation_count=0 -failed_compilation_count=0 -failed_compilations=() -failed_tests=() -my_current_directory=$(pwd) -nat_compiler=$my_current_directory/zig-out/bin/nat - -for standalone_test_case in $standalone_test_directory_files -do - STANDALONE_TEST_NAME=${standalone_test_case##*/} - $nat_compiler -main_source_file $standalone_test_case/main.nat - - if [[ "$?" == "0" ]]; then - passed_compilation_count=$(($passed_compilation_count + 1)) - if [[ "$OSTYPE" == "linux-gnu"* ]]; then - nat/$STANDALONE_TEST_NAME - - if [[ "$?" == "0" ]]; then - passed_test_count=$(($passed_test_count + 1)) - result="\e[32mPASSED\e[0m" - else - failed_test_count=$(($failed_test_count + 1)) - result="\e[31mFAILED\e[0m" - failed_tests+=("$test_i. $STANDALONE_TEST_NAME") - fi - - ran_test_count=$(($ran_test_count + 1)) - else - result="\e[31mOS NOT SUPPORTED\e[0m" - fi - else - failed_compilation_count=$(($failed_compilation_count + 1)) - result="\e[31mCOMPILATION FAILURE\e[0m" - failed_compilations+=("$test_i. $STANDALONE_TEST_NAME") - fi - - echo -e "[$test_i/$total_test_count] [$result] [STANDALONE] $STANDALONE_TEST_NAME" - - test_i=$(($test_i + 1)) -done - -# for integral_test_case in $integral_test_directory_files -# do -# MY_TESTNAME=${integral_test_case##*/} -# cd test/integral/$MY_TESTNAME -# $nat_compiler -# -# if [[ "$?" == "0" ]]; then -# passed_compilation_count=$(($passed_compilation_count + 1)) -# if [[ "$OSTYPE" == "linux-gnu"* ]]; then -# nat/$MY_TESTNAME -# -# if [[ "$?" == "0" ]]; then -# passed_test_count=$(($passed_test_count + 1)) -# result="\e[32mPASSED\e[0m" -# else -# failed_test_count=$(($failed_test_count + 1)) -# result="\e[31mFAILED\e[0m" -# failed_tests+=("$test_i. $MY_TESTNAME") -# fi -# -# ran_test_count=$(($ran_test_count + 1)) -# else -# result="\e[31mOS NOT SUPPORTED\e[0m" -# fi -# else -# failed_compilation_count=$(($failed_compilation_count + 1)) -# result="\e[31mCOMPILATION FAILURE\e[0m" -# failed_compilations+=("$test_i. $MY_TESTNAME") -# fi -# -# echo -e "[$test_i/$total_test_count] [$result] [INTEGRAL] $MY_TESTNAME" -# -# test_i=$(($test_i + 1)) -# cd $my_current_directory -# done - -printf "\n" -echo -e "\e[35m[SUMMARY]\e[0m" -echo -e "\e[35m=========\e[0m" -echo -e "Ran $total_test_count compilations (\e[32m$passed_compilation_count\e[0m succeeded, \e[31m$failed_compilation_count\e[0m failed)." -echo -e "Ran $ran_test_count tests (\e[32m $passed_test_count\e[0m passed, \e[31m$failed_test_count\e[0m failed)." - -if [[ "$failed_compilation_count" != "0" ]]; then - printf $"\nFailed compilations:\n" - for failed_compilation in "${failed_compilations[@]}" - do - echo -e "\e[31m$failed_compilation\e[0m" - done -fi - - -if [[ "$failed_test_count" != "0" ]]; then - echo $'\n' - echo "Failed tests:" - for failed_test in "${failed_tests[@]}" - do - echo -e "\e[31m$failed_test\e[0m" - done -fi - -echo -e "\e[35m=========\e[0m" - -if [[ "$failed_test_count" == "0" && "$failed_compilation_count" == "0" ]]; then - echo -e "\e[32mSUCCESS!\e[0m" - true -else - echo -e "\e[31mFAILURE!\e[0m" - false -fi