#include fn void compile(Arena& arena, Options options) { auto base_allocation_type_count = i128_offset + // 64 * 2 for basic integer types 2 + // u128, s128 2; // void, noreturn auto base_type_allocation = arena_allocate(arena, base_allocation_type_count); auto* type_it = base_type_allocation.pointer; bool signs[] = {false, true}; Type* previous = 0; for (bool sign: signs) { for (u32 bit_index = 0; bit_index < 64; bit_index += 1) { auto bit_count = bit_index + 1; auto first_digit = (u8)(bit_count < 10 ? bit_count % 10 + '0' : bit_count / 10 + '0'); auto second_digit = (u8)(bit_count > 9 ? bit_count % 10 + '0' : 0); u8 name_buffer[] = { u8(sign ? 's' : 'u'), first_digit, second_digit }; u64 name_length = 2 + (bit_count > 9); auto name_stack = String{name_buffer, name_length}; auto name = arena_duplicate_string(arena, name_stack); *type_it = { .integer = { .bit_count = bit_count, .is_signed = sign, }, .id = TypeId::integer, .name = name, }; if (previous) previous->next = type_it; previous = type_it; type_it += 1; } } for (bool sign: signs) { auto name = sign ? str("s128") : str("u128"); *type_it = { .integer = { .bit_count = 128, .is_signed = sign, }, .id = TypeId::integer, .name = name, .next = previous, }; if (previous) previous->next = type_it; previous = type_it; type_it += 1; } auto void_type = type_it; type_it += 1; auto noreturn_type = type_it; type_it += 1; assert(type_it - base_type_allocation.pointer == base_allocation_type_count); previous->next = void_type; *void_type = { .id = TypeId::void_type, .name = str("void"), .next = noreturn_type, }; *noreturn_type = { .id = TypeId::noreturn, .name = str("noreturn"), }; auto module = Module{ .arena = arena, .content = options.content, .first_type = base_type_allocation.pointer, .last_type = noreturn_type, .scope = { .kind = ScopeKind::global, }, .name = options.name, .path = options.path, .executable = options.executable, .objects = options.objects, .target = options.target, .build_mode = options.build_mode, .has_debug_info = options.has_debug_info, .silent = options.silent, }; module.void_value = new_value(module); *module.void_value = { .type = void_type, .id = ValueId::infer_or_ignore, }; parse(module); emit(module); } fn void compile_file(Arena& arena, Compile options) { auto relative_file_path = options.relative_file_path; if (relative_file_path.length < 5) { fail(); } auto extension_start = string_last_character(relative_file_path, '.'); if (extension_start == string_no_match) { fail(); } if (!relative_file_path(extension_start).equal(str(".bbb"))) { fail(); } auto separator_index = string_last_character(relative_file_path, '/'); separator_index = separator_index == string_no_match ? 0 : separator_index; auto base_start = separator_index + (separator_index != 0 || relative_file_path[separator_index] == '/'); auto base_name = relative_file_path(base_start, extension_start); auto is_compiler = relative_file_path.equal(str("src/compiler.bbb")); String output_path_dir_parts[] = { str(base_cache_dir), is_compiler ? str("/compiler") : str("/"), build_mode_to_string(options.build_mode), str("_"), options.has_debug_info ? str("di") : str("nodi"), }; auto output_path_dir = arena_join_string(arena, array_to_slice(output_path_dir_parts)); make_directory(base_cache_dir); if (is_compiler) { make_directory(base_cache_dir "/compiler"); } make_directory(cstr(output_path_dir)); String output_path_base_parts[] = { output_path_dir, str("/"), base_name, }; auto output_path_base = arena_join_string(arena, array_to_slice(output_path_base_parts)); String output_object_path_parts[] = { output_path_base, str(".o"), }; auto output_object_path = arena_join_string(arena, array_to_slice(output_object_path_parts)); auto output_executable_path = output_path_base; auto file_content = file_read(arena, relative_file_path); auto file_path = path_absolute(arena, relative_file_path); auto c_abi_object_path = str("build/c_abi.o"); String objects[] = { c_abi_object_path, output_object_path, }; Slice object_slice = array_to_slice(objects); object_slice = object_slice(!base_name.equal(str("c_abi"))); compile(arena, { .content = file_content, .path = file_path, .executable = output_executable_path, .name = base_name, .objects = object_slice, .target = { .cpu = CPUArchitecture::x86_64, .os = OperatingSystem::linux_, }, .build_mode = options.build_mode, .has_debug_info = options.has_debug_info, .silent = options.silent, }); } void entry_point(Slice arguments, Slice environment) { Arena& arena = arena_initialize_default(8 * mb); if (arguments.length < 2) { fail_with_message(str("error: Not enough arguments\n")); } String command_string = c_string_to_slice(arguments[1]); auto command = string_to_enum(Command, command_string); if (!is_enum_valid(command)) { fail_with_message(str("Invalid command!\n")); } switch (command) { case Command::compile: { if (arguments.length < 3) { fail_with_message(str("Not enough arguments for command 'compile'\n")); } auto build_mode = BuildMode::debug_none; auto has_debug_info = true; if (arguments.length >= 4) { auto build_mode_string = c_string_to_slice(arguments[3]); auto new_build_mode = string_to_enum(BuildMode, build_mode_string); if (!is_enum_valid(new_build_mode)) { fail_with_message(str("error: Wrong build mode\n")); } build_mode = new_build_mode; } if (arguments.length >= 5) { auto has_debug_info_string = c_string_to_slice(arguments[3]); if (has_debug_info_string.equal(str("true"))) { has_debug_info = true; } else if (has_debug_info_string.equal(str("false"))) { has_debug_info = false; } else { fail_with_message(str("Wrong value for has_debug_info\n")); } } auto relative_file_path = c_string_to_slice(arguments[2]); compile_file(arena, { .relative_file_path = relative_file_path, .build_mode = build_mode, .has_debug_info = has_debug_info, .silent = false, }); } break; case Command::test: { trap_raw(); } break; } }