bloat-buster/src/main.zig

190 lines
6.2 KiB
Zig

const lib = @import("lib.zig");
const configuration = @import("configuration");
const os = lib.os;
const llvm = @import("LLVM.zig");
const Arena = lib.Arena;
const compiler = @import("bootstrap.zig");
const BuildMode = compiler.BuildMode;
test {
_ = lib;
_ = llvm;
_ = compiler;
}
fn fail() noreturn {
lib.libc.exit(1);
}
const Command = enum {
@"test",
compile,
};
const Compile = struct {
relative_file_path: [:0]const u8,
build_mode: BuildMode,
has_debug_info: bool,
silent: bool,
};
fn compile_file(arena: *Arena, compile: Compile) compiler.Options {
const checkpoint = arena.position;
defer arena.restore(checkpoint);
const relative_file_path = compile.relative_file_path;
if (relative_file_path.len < 5) {
fail();
}
const extension_start = lib.string.last_character(relative_file_path, '.') orelse fail();
if (!lib.string.equal(relative_file_path[extension_start..], ".bbb")) {
fail();
}
const separator_index = lib.string.last_character(relative_file_path, '/') orelse 0;
const base_start = separator_index + @intFromBool(separator_index != 0 or relative_file_path[separator_index] == '/');
const base_name = relative_file_path[base_start..extension_start];
const is_compiler = lib.string.equal(relative_file_path, "src/compiler.bbb");
const output_path_dir = arena.join_string(&.{
base_cache_dir,
if (is_compiler) "/compiler/" else "/",
@tagName(compile.build_mode),
"_",
if (compile.has_debug_info) "di" else "nodi",
});
os.make_directory(base_cache_dir);
if (is_compiler) {
os.make_directory(base_cache_dir ++ "/compiler");
}
os.make_directory(output_path_dir);
const output_path_base = arena.join_string(&.{
output_path_dir,
"/",
base_name,
});
const output_object_path = arena.join_string(&.{ output_path_base, ".o" });
const output_executable_path = output_path_base;
const file_content = lib.file.read(arena, relative_file_path);
const file_path = os.absolute_path(arena, relative_file_path);
const c_abi_object_path = arena.duplicate_string(configuration.c_abi_object_path);
const convert_options = compiler.Options{
.executable = output_executable_path,
.objects = if (lib.string.equal(base_name, "c_abi")) &.{ output_object_path, c_abi_object_path } else &.{output_object_path},
.name = base_name,
.build_mode = compile.build_mode,
.content = file_content,
.path = file_path,
.has_debug_info = compile.has_debug_info,
.target = compiler.Target.get_native(),
.silent = compile.silent,
};
compiler.compile(arena, convert_options);
return convert_options;
}
const base_cache_dir = "bb-cache";
pub const panic = lib.panic_struct;
pub const std_options = lib.std_options;
pub const main = lib.main;
pub fn entry_point(arguments: []const [*:0]const u8, environment: [*:null]const ?[*:0]const u8) void {
lib.GlobalState.initialize();
const arena = lib.global.arena;
if (arguments.len < 2) {
lib.print_string("error: Not enough arguments\n");
fail();
}
const command = lib.string.to_enum(Command, lib.cstring.to_slice(arguments[1])) orelse fail();
switch (command) {
.compile => {
const relative_file_path = lib.cstring.to_slice(arguments[2]);
_ = compile_file(arena, .{
.relative_file_path = relative_file_path,
.build_mode = .debug_none,
.has_debug_info = true,
.silent = false,
});
},
.@"test" => {
if (arguments.len != 2) {
fail();
}
const stop_at_failure = true;
const names = &[_][]const u8{
"minimal",
// "comments",
// "constant_add",
// "constant_and",
// "constant_div",
// "constant_mul",
// "constant_rem",
// "constant_or",
// "constant_sub",
// "constant_xor",
// "constant_shift_left",
// "constant_shift_right",
// "minimal_stack",
// "minimal_stack_arithmetic",
// "pointer",
// "extend",
};
var build_modes: [@typeInfo(BuildMode).@"enum".fields.len]BuildMode = undefined;
inline for (@typeInfo(BuildMode).@"enum".fields, 0..) |field, field_index| {
const build_mode = @field(BuildMode, field.name);
build_modes[field_index] = build_mode;
}
for (names) |name| {
for (build_modes) |build_mode| {
for ([2]bool{ true, false }) |has_debug_info| {
const position = arena.position;
defer arena.restore(position);
const relative_file_path = arena.join_string(&.{ "tests/", name, ".bbb" });
const compile_result = compile_file(arena, .{
.relative_file_path = relative_file_path,
.build_mode = build_mode,
.has_debug_info = has_debug_info,
.silent = true,
});
const result = lib.os.run_child_process(arena, &.{compile_result.executable}, environment, .{
.stdout = .inherit,
.stderr = .inherit,
.null_file_descriptor = null,
});
if (!result.is_successful()) {
lib.print_string("Failed to run test ");
lib.print_string(name);
lib.print_string(" with build mode ");
lib.print_string(@tagName(build_mode));
if (stop_at_failure) {
lib.libc.exit(1);
}
}
}
}
}
},
}
}