This commit is contained in:
David Gonzalez Martin 2025-06-05 19:57:05 -06:00
parent 4bb8f8f973
commit 07a4f6d9d1
5 changed files with 199 additions and 147 deletions

View File

@ -5516,17 +5516,22 @@ compile_file = fn (arena: &Arena, compile_options: CompileFile) void
compile(arena, options); compile(arena, options);
} }
names: [_][]u8 = [
"minimal",
];
[export] main = fn [cc(c)] (argument_count: u32, argv: &&u8) s32 [export] main = fn [cc(c)] (argument_count: u32, argv: &&u8) s32
{ {
global_state_initialize(); global_state_initialize();
>arena = global_state.arena; >arena = global_state.arena;
if (argument_count < 2) >arguments = argv[..#extend(argument_count)];
if (arguments.length < 2)
{ {
return 1; return 1;
} }
>command_string = c_string_to_slice(argv[1]); >command_string = c_string_to_slice(arguments[1]);
>command_string_to_enum = #string_to_enum(CompilerCommand, command_string); >command_string_to_enum = #string_to_enum(CompilerCommand, command_string);
if (!command_string_to_enum.is_valid) if (!command_string_to_enum.is_valid)
@ -5539,7 +5544,7 @@ compile_file = fn (arena: &Arena, compile_options: CompileFile) void
{ {
.compile => .compile =>
{ {
if (argument_count < 3) if (arguments.length < 3)
{ {
return 1; return 1;
} }
@ -5549,7 +5554,7 @@ compile_file = fn (arena: &Arena, compile_options: CompileFile) void
if (argument_count >= 4) if (argument_count >= 4)
{ {
>build_mode_string_to_enum = #string_to_enum(BuildMode, c_string_to_slice(argv[3])); >build_mode_string_to_enum = #string_to_enum(BuildMode, c_string_to_slice(arguments[3]));
if (!build_mode_string_to_enum.is_valid) if (!build_mode_string_to_enum.is_valid)
{ {
return 1; return 1;
@ -5559,7 +5564,7 @@ compile_file = fn (arena: &Arena, compile_options: CompileFile) void
if (argument_count >= 5) if (argument_count >= 5)
{ {
>has_debug_info_string = c_string_to_slice(argv[4]); >has_debug_info_string = c_string_to_slice(arguments[4]);
if (string_equal(has_debug_info_string, "true")) if (string_equal(has_debug_info_string, "true"))
{ {
has_debug_info = 1; has_debug_info = 1;
@ -5574,7 +5579,7 @@ compile_file = fn (arena: &Arena, compile_options: CompileFile) void
} }
} }
>relative_file_path_pointer = argv[2]; >relative_file_path_pointer = arguments[2];
if (!relative_file_path_pointer) if (!relative_file_path_pointer)
{ {
return 1; return 1;
@ -5591,7 +5596,22 @@ compile_file = fn (arena: &Arena, compile_options: CompileFile) void
}, },
.test => .test =>
{ {
// TODO if (arguments.length != 2)
{
report_error();
}
>debug_info_array: [_]u1 = [1, 0];
for (name: names)
{
for (build_mode: #enum_values(BuildMode))
{
for (has_debug_info: debug_info_array)
{
}
}
}
#trap(); #trap();
}, },
} }

View File

@ -548,45 +548,45 @@ void entry_point(Slice<char* const> arguments, Slice<char* const> envp)
bool has_debug_info_array[] = {true, false}; bool has_debug_info_array[] = {true, false};
for (auto name: names) // for (auto name: names)
{ // {
for (BuildMode build_mode = BuildMode::debug_none; build_mode < BuildMode::count; build_mode = (BuildMode)((backing_type(BuildMode))build_mode + 1)) // for (BuildMode build_mode = BuildMode::debug_none; build_mode < BuildMode::count; build_mode = (BuildMode)((backing_type(BuildMode))build_mode + 1))
{ // {
for (bool has_debug_info : has_debug_info_array) // for (bool has_debug_info : has_debug_info_array)
{ // {
auto position = arena->position; // auto position = arena->position;
//
String relative_file_path_parts[] = { string_literal("tests/"), name, string_literal(".bbb") }; // String relative_file_path_parts[] = { string_literal("tests/"), name, string_literal(".bbb") };
auto relative_file_path = arena_join_string(arena, array_to_slice(relative_file_path_parts)); // auto relative_file_path = arena_join_string(arena, array_to_slice(relative_file_path_parts));
//
auto executable_path = compile_file(arena, { // auto executable_path = compile_file(arena, {
.relative_file_path = relative_file_path, // .relative_file_path = relative_file_path,
.build_mode = build_mode, // .build_mode = build_mode,
.has_debug_info = has_debug_info, // .has_debug_info = has_debug_info,
.silent = true, // .silent = true,
}); // });
//
char* const arguments[] = // char* const arguments[] =
{ // {
(char*)executable_path.pointer, // (char*)executable_path.pointer,
0, // 0,
}; // };
Slice<char* const> arg_slice = array_to_slice(arguments); // Slice<char* const> arg_slice = array_to_slice(arguments);
arg_slice.length -= 1; // arg_slice.length -= 1;
auto execution = os_execute(arena, arg_slice, environment, {}); // auto execution = os_execute(arena, arg_slice, environment, {});
auto success = execution.termination_kind == TerminationKind::exit && execution.termination_code == 0; // auto success = execution.termination_kind == TerminationKind::exit && execution.termination_code == 0;
if (!success) // if (!success)
{ // {
print(string_literal("Test failed: ")); // print(string_literal("Test failed: "));
print(executable_path); // print(executable_path);
print(string_literal("\n")); // print(string_literal("\n"));
bb_fail(); // bb_fail();
} // }
//
arena_restore(arena, position); // arena_restore(arena, position);
} // }
} // }
} // }
for (BuildMode compiler_build_mode = BuildMode::debug_none; compiler_build_mode < BuildMode::count; compiler_build_mode = (BuildMode)((backing_type(BuildMode))compiler_build_mode + 1)) for (BuildMode compiler_build_mode = BuildMode::debug_none; compiler_build_mode < BuildMode::count; compiler_build_mode = (BuildMode)((backing_type(BuildMode))compiler_build_mode + 1))
{ {
@ -599,24 +599,10 @@ void entry_point(Slice<char* const> arguments, Slice<char* const> envp)
.silent = true, .silent = true,
}); });
Slice<String> name_slice = array_to_slice(names);
for (auto name: name_slice(0, 1))
{
for (BuildMode build_mode = BuildMode::debug_none; build_mode < BuildMode::count; build_mode = (BuildMode)((backing_type(BuildMode))build_mode + 1))
{
for (bool has_debug_info : has_debug_info_array)
{
// COMPILATION START
String relative_file_path_parts[] = { string_literal("tests/"), name, string_literal(".bbb") };
auto relative_file_path = arena_join_string(arena, array_to_slice(relative_file_path_parts));
char* const compiler_arguments[] = char* const compiler_arguments[] =
{ {
(char*)compiler.pointer, (char*)compiler.pointer,
(char*)"compile", (char*)"test",
(char*)relative_file_path.pointer,
(char*)build_mode_to_string(build_mode).pointer,
(char*)(has_debug_info ? "true" : "false"),
0, 0,
}; };
Slice<char* const> arg_slice = array_to_slice(compiler_arguments); Slice<char* const> arg_slice = array_to_slice(compiler_arguments);
@ -625,50 +611,11 @@ void entry_point(Slice<char* const> arguments, Slice<char* const> envp)
auto success = execution.termination_kind == TerminationKind::exit && execution.termination_code == 0; auto success = execution.termination_kind == TerminationKind::exit && execution.termination_code == 0;
if (!success) if (!success)
{ {
print(string_literal("Self-hosted test failed to compile: ")); print(string_literal("Self-hosted tests failed to compile: "));
print(name); print(build_mode_to_string(compiler_build_mode));
print(string_literal("\n")); print(compiler_has_debug_info ? string_literal(" with debug info\n") : string_literal(" with no debug info\n"));
bb_fail(); bb_fail();
} }
// COMPILATION END
// RUN START
String exe_parts[] = {
string_literal("self-hosted-bb-cache/"),
build_mode_to_string(compiler_build_mode),
string_literal("_"),
compiler_has_debug_info ? string_literal("di") : string_literal("nodi"),
string_literal("/"),
build_mode_to_string(build_mode),
string_literal("_"),
has_debug_info ? string_literal("di") : string_literal("nodi"),
string_literal("/"),
name,
};
String exe_path = arena_join_string(arena, array_to_slice(exe_parts));
char* const run_arguments[] =
{
(char*)exe_path.pointer,
0,
};
arg_slice = array_to_slice(run_arguments);
arg_slice.length -= 1;
execution = os_execute(arena, arg_slice, environment, {});
success = execution.termination_kind == TerminationKind::exit && execution.termination_code == 0;
if (!success)
{
print(string_literal("Self-hosted test failed to run: "));
print(name);
print(string_literal("\n"));
bb_fail();
}
// RUN END
}
}
}
} }
} }
} break; } break;

View File

@ -895,6 +895,7 @@ enum class UnaryTypeId
{ {
align_of, align_of,
byte_size, byte_size,
enum_values,
integer_max, integer_max,
}; };

View File

@ -1215,6 +1215,7 @@ fn Type* resolve_type(Module* module, Type* type)
} break; } break;
case TypeId::void_type: case TypeId::void_type:
case TypeId::integer: case TypeId::integer:
case TypeId::enumerator:
{ {
result = type; result = type;
} break; } break;
@ -3054,6 +3055,37 @@ fn void analyze_type(Module* module, Value* value, Type* expected_type, TypeAnal
value->unary_type.type = unary_type; value->unary_type.type = unary_type;
auto unary_type_id = value->unary_type.id; auto unary_type_id = value->unary_type.id;
if (unary_type_id == UnaryTypeId::enum_values)
{
auto element_type = unary_type;
if (element_type->id != TypeId::enumerator)
{
report_error();
}
auto fields = unary_type->enumerator.fields;
auto element_count = fields.length;
if (element_count == 0)
{
report_error();
}
auto array_type = get_array_type(module, element_type, element_count);
switch (value->kind)
{
case ValueKind::right:
{
value_type = array_type;
} break;
case ValueKind::left:
{
value_type = get_pointer_type(module, array_type);
} break;
}
}
else
{
if (expected_type) if (expected_type)
{ {
value_type = expected_type; value_type = expected_type;
@ -3086,12 +3118,17 @@ fn void analyze_type(Module* module, Value* value, Type* expected_type, TypeAnal
{ {
value = integer_max_value(unary_type->integer.bit_count, unary_type->integer.is_signed); value = integer_max_value(unary_type->integer.bit_count, unary_type->integer.is_signed);
} break; } break;
case UnaryTypeId::enum_values:
{
unreachable();
} break;
} }
if (value > max_value) if (value > max_value)
{ {
report_error(); report_error();
} }
}
typecheck(module, expected_type, value_type); typecheck(module, expected_type, value_type);
} break; } break;
@ -4827,6 +4864,7 @@ fn void invalidate_analysis(Module* module, Value* value)
{ {
case ValueId::variable_reference: case ValueId::variable_reference:
case ValueId::constant_integer: case ValueId::constant_integer:
case ValueId::unary_type:
break; break;
case ValueId::aggregate_initialization: case ValueId::aggregate_initialization:
{ {
@ -6953,6 +6991,43 @@ fn void emit_value(Module* module, Value* value, TypeKind type_kind, bool expect
auto constant_integer = LLVMConstInt(resolved_value_type->llvm.abi, max_value, is_signed); auto constant_integer = LLVMConstInt(resolved_value_type->llvm.abi, max_value, is_signed);
llvm_value = constant_integer; llvm_value = constant_integer;
} break; } break;
case UnaryTypeId::enum_values:
{
LLVMValueRef buffer[64];
assert(type_kind == TypeKind::memory);
assert(unary_type->id == TypeId::enumerator);
auto fields = unary_type->enumerator.fields;
auto llvm_enum_type = unary_type->llvm.memory;
u64 i = 0;
for (auto& field : fields)
{
auto v = field.value;
buffer[i] = LLVMConstInt(llvm_enum_type, v, false);
i += 1;
}
auto array_value = LLVMConstArray2(llvm_enum_type, buffer, i);
switch (value->kind)
{
case ValueKind::right:
{
llvm_value = array_value;
} break;
case ValueKind::left:
{
auto is_constant = true;
assert(resolved_value_type->id == TypeId::pointer);
auto array_type = resolved_value_type->pointer.element_type;
assert(array_type->id == TypeId::array);
resolve_type_in_place(module, array_type);
auto value_array_variable = llvm_module_create_global_variable(module->llvm.module, array_type->llvm.memory, is_constant, LLVMInternalLinkage, array_value, string_literal("enum.values"), 0, LLVMNotThreadLocal, 0, 0);
auto alignment = get_byte_alignment(resolved_value_type);
LLVMSetAlignment(value_array_variable, alignment);
LLVMSetUnnamedAddress(value_array_variable, LLVMGlobalUnnamedAddr);
llvm_value = value_array_variable;
} break;
}
} break;
} }
} break; } break;
case ValueId::binary: case ValueId::binary:
@ -8228,6 +8303,14 @@ fn void analyze_statement(Module* module, Scope* scope, Statement* statement, u3
analyze_type(module, right, 0, {}); analyze_type(module, right, 0, {});
if (right->kind == ValueKind::right)
{
if (!is_slice(right->type))
{
reanalyze_type_as_left_value(module, right);
}
}
Type* aggregate_type = 0; Type* aggregate_type = 0;
switch (right->kind) switch (right->kind)
@ -8235,10 +8318,7 @@ fn void analyze_statement(Module* module, Scope* scope, Statement* statement, u3
case ValueKind::right: case ValueKind::right:
{ {
aggregate_type = right->type; aggregate_type = right->type;
if (!is_slice(aggregate_type)) assert(is_slice(aggregate_type));
{
report_error();
}
} break; } break;
case ValueKind::left: case ValueKind::left:
{ {

View File

@ -7,6 +7,7 @@ enum class ValueIntrinsic
byte_size, byte_size,
enum_from_int, enum_from_int,
enum_name, enum_name,
enum_values,
extend, extend,
has_debug_info, has_debug_info,
integer_max, integer_max,
@ -1159,6 +1160,7 @@ fn Token tokenize(Module* module)
string_literal("byte_size"), string_literal("byte_size"),
string_literal("enum_from_int"), string_literal("enum_from_int"),
string_literal("enum_name"), string_literal("enum_name"),
string_literal("enum_values"),
string_literal("extend"), string_literal("extend"),
string_literal("has_debug_info"), string_literal("has_debug_info"),
string_literal("integer_max"), string_literal("integer_max"),
@ -1711,6 +1713,7 @@ fn Value* parse_left(Module* module, Scope* scope, ValueBuilder builder)
} break; } break;
case ValueIntrinsic::align_of: case ValueIntrinsic::align_of:
case ValueIntrinsic::byte_size: case ValueIntrinsic::byte_size:
case ValueIntrinsic::enum_values:
case ValueIntrinsic::integer_max: case ValueIntrinsic::integer_max:
{ {
skip_space(module); skip_space(module);
@ -1726,6 +1729,7 @@ fn Value* parse_left(Module* module, Scope* scope, ValueBuilder builder)
{ {
case ValueIntrinsic::align_of: id = UnaryTypeId::align_of; break; case ValueIntrinsic::align_of: id = UnaryTypeId::align_of; break;
case ValueIntrinsic::byte_size: id = UnaryTypeId::byte_size; break; case ValueIntrinsic::byte_size: id = UnaryTypeId::byte_size; break;
case ValueIntrinsic::enum_values: id = UnaryTypeId::enum_values; break;
case ValueIntrinsic::integer_max: id = UnaryTypeId::integer_max; break; case ValueIntrinsic::integer_max: id = UnaryTypeId::integer_max; break;
default: unreachable(); default: unreachable();
} }