190 lines
6.2 KiB
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);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
}
|
|
}
|