Forward declared type
Some checks failed
CI / ci (MinSizeRel, ubuntu-latest) (push) Failing after 1m8s
CI / ci (Release, ubuntu-latest) (push) Failing after 1m6s
CI / ci (RelWithDebInfo, ubuntu-latest) (push) Failing after 1m8s
CI / ci (Debug, ubuntu-latest) (push) Failing after 2m29s

This commit is contained in:
David Gonzalez Martin 2025-05-23 20:02:10 -06:00
parent 5de4ba76f5
commit e95eea0504
3 changed files with 375 additions and 72 deletions

View File

@ -625,16 +625,108 @@ Value = struct
i128_offset: u64 = 64 * 2;
void_offset: u64 = i128_offset + 2;
ScopeKind = enum
{
global,
function,
local,
for_each,
macro_declaration,
macro_instantiation,
}
Scope = struct
{
parent: &Scope,
line: u32,
column: u32,
kind: ScopeKind,
}
Variable = struct
{
storage: &Value,
type: &Type,
scope: &Scope,
name: []u8,
line: u32,
column: u32,
}
Linkage = enum
{
internal,
external,
}
Global = struct
{
variable: Variable,
initial_value: &Value,
next: &Global,
linkage: Linkage,
emitted: u1,
}
Local = struct
{
variable: Variable,
initial_value: &Value,
next: &Local,
}
Argument = struct
{
variable: Variable,
index: u32,
}
MacroDeclaration = struct
{
foo: u32,
}
MacroInstantiation = struct
{
foo: u32,
}
LLVMContext = struct;
LLVMModule = struct;
LLVMBuilder = struct;
LLVMDIBuilder = struct;
LLVMValue = struct;
LLVMType = struct;
LLVMMetadata = struct;
LLVMBasicBlock = struct;
LLVMIntrinsicId = typealias u32;
Module = struct
{
arena: &Arena,
base_type_allocation: &Type,
void_value: &Value,
// Parser data
content: []u8,
offset: u64,
line_offset: u64,
line_character_offset: u64,
first_pointer_type: &Type,
first_slice_type: &Type,
first_pair_struct_type: &Type,
first_array_type: &Type,
first_type: &Type,
last_type: &Type,
va_list_type: &Type,
void_value: &Value,
first_global: &Global,
last_global: &Global,
first_macro_declaration: &MacroDeclaration,
last_macro_declaration: &MacroDeclaration,
current_function: &Global,
current_macro_declaration: &MacroDeclaration,
current_macro_instantiation: &MacroInstantiation,
}
module_integer_type = fn (module: &Module, integer: TypeInteger) &Type
@ -724,6 +816,29 @@ get_column = fn (module: &Module) u32
return #truncate(column);
}
Checkpoint = struct
{
offset: u64,
line_offset: u64,
line_character_offset: u64,
}
get_checkpoint = fn (module: &Module) Checkpoint
{
return {
.offset = module.offset,
.line_offset = module.line_offset,
.line_character_offset = module.line_character_offset,
};
}
set_checkpoint = fn (module: &Module, checkpoint: Checkpoint) void
{
module.offset = checkpoint.offset;
module.line_offset = checkpoint.line_offset;
module.line_character_offset = checkpoint.line_character_offset;
}
skip_space = fn (module: &Module) void
{
while (1)
@ -817,8 +932,231 @@ parse_identifier = fn (module: &Module) []u8
return result;
}
GlobalAttributeKeyword = enum
{
export,
extern,
}
GlobalKeyword = enum
{
bits,
enum,
fn,
macro,
struct,
typealias,
union,
}
left_bracket: u8 = '[';
right_bracket: u8 = ']';
left_parenthesis: u8 = '(';
right_parenthesis: u8 = ')';
left_brace: u8 = '{';
right_brace: u8 = '}';
parse_type = fn (module: &Module, scope: &Scope) &Type
{
>start_character = module.content[module.offset];
if (is_identifier_start(start_character))
{
#trap();
}
else if (start_character == '&')
{
#trap();
}
else if (start_character == left_bracket)
{
#trap();
}
else if (start_character == '#')
{
#trap();
}
else
{
report_error();
}
}
parse = fn (module: &Module) void
{
>scope = &module.scope;
while (1)
{
skip_space(module);
if (module.offset == module.content.length)
{
break;
}
>is_export: u1 = 0;
>is_extern: u1 = 0;
>global_line = get_line(module);
>global_column = get_line(module);
if (consume_character_if_match(module, left_bracket))
{
while (module.offset < module.content.length)
{
>global_attribute_keyword_string = parse_identifier(module);
>global_attribute_keyword_s2e = #string_to_enum(GlobalAttributeKeyword, global_attribute_keyword_string);
if (!global_attribute_keyword_s2e.is_valid)
{
report_error();
}
>global_attribute_keyword = global_attribute_keyword_s2e.enum_value;
switch (global_attribute_keyword)
{
.export =>
{
is_export = 1;
},
.extern =>
{
is_extern = 1;
},
}
if (consume_character_if_match(module, right_bracket))
{
break;
}
else
{
report_error();
}
}
skip_space(module);
}
>global_name = parse_identifier(module);
>last_global = module.first_global;
while (last_global)
{
if (string_equal(global_name, last_global.variable.name))
{
report_error();
}
if (!last_global.next)
{
break;
}
last_global = last_global.next;
}
>type_it = module.first_type;
>forward_declaration: &Type = 0;
while (type_it)
{
if (string_equal(global_name, type_it.name))
{
if (type_it.id == .forward_declaration)
{
forward_declaration = type_it;
break;
}
else
{
report_error();
}
}
if (!type_it.next)
{
break;
}
type_it = type_it.next;
}
>global_type: &Type = 0;
if (consume_character_if_match(module, ':'))
{
skip_space(module);
global_type = parse_type(module, scope);
skip_space(module);
}
expect_character(module, '=');
skip_space(module);
>is_global_keyword: u1 = 0;
if (is_identifier_start(module.content[module.offset]))
{
>checkpoint = get_checkpoint(module);
>global_keyword_string = parse_identifier(module);
skip_space(module);
>global_keyword_s2e = #string_to_enum(GlobalKeyword, global_keyword_string);
is_global_keyword = global_keyword_s2e.is_valid;
if (is_global_keyword)
{
>global_keyword = global_keyword_s2e.enum_value;
switch (global_keyword)
{
.bits =>
{
#trap();
},
.enum =>
{
#trap();
},
.fn =>
{
#trap();
},
.macro =>
{
#trap();
},
.struct =>
{
#trap();
},
.typealias =>
{
#trap();
},
.union =>
{
#trap();
},
}
}
else
{
set_checkpoint(module, checkpoint);
}
}
if (!is_global_keyword)
{
#trap();
}
}
}
emit = fn (module: &Module) void
@ -908,6 +1246,9 @@ compile = fn (arena: &Arena, options: CompileOptions) void
.offset = 0,
.line_offset = 0,
.line_character_offset = 0,
.scope = {
zero,
},
};
parse(&module);

View File

@ -307,7 +307,7 @@ global_variable String names[] =
string_literal("generic_pointer_array"),
string_literal("self_referential_struct"), // TODO
// string_literal("forward_declared_type"),
string_literal("forward_declared_type"),
};
void entry_point(Slice<const char*> arguments, Slice<char* const> environment)

View File

@ -17,6 +17,8 @@ fn void analyze_block(Module* module, Block* block);
fn void emit_local_storage(Module* module, Variable* variable);
fn void emit_assignment(Module* module, LLVMValueRef left_llvm, Type* left_type, Value* right);
fn void emit_macro_instantiation(Module* module, Value* value);
fn void emit_value(Module* module, Value* value, TypeKind type_kind);
fn void analyze_value(Module* module, Value* value, Type* expected_type, TypeKind type_kind);
fn void emit_block(Module* module, LLVMBasicBlockRef basic_block)
{
@ -42,6 +44,24 @@ fn void emit_block(Module* module, LLVMBasicBlockRef basic_block)
LLVMPositionBuilderAtEnd(module->llvm.builder, basic_block);
}
fn LLVMValueRef emit_condition(Module* module, Value* condition_value)
{
auto condition_llvm_value = condition_value->llvm;
auto condition_type = condition_value->type;
assert(condition_type);
assert(condition_llvm_value);
assert(condition_type->id == TypeId::integer || condition_type->id == TypeId::pointer);
if (!(condition_type->id == TypeId::integer && condition_type->integer.bit_count == 1))
{
condition_llvm_value = LLVMBuildICmp(module->llvm.builder, LLVMIntNE, condition_llvm_value, LLVMConstNull(condition_type->llvm.abi), "");
}
assert(condition_llvm_value);
return condition_llvm_value;
}
fn LLVMValueRef emit_intrinsic_call(Module* module, IntrinsicIndex index, Slice<LLVMTypeRef> argument_types, Slice<LLVMValueRef> argument_values)
{
auto intrinsic_id = module->llvm.intrinsic_table[(backing_type(IntrinsicIndex))index];
@ -216,8 +236,6 @@ fn void dump_module(Module* module)
print(llvm_module_to_string(module->llvm.module));
}
fn void emit_value(Module* module, Value* value, TypeKind type_kind);
fn LLVMCallConv llvm_calling_convention(CallingConvention calling_convention)
{
LLVMCallConv cc;
@ -918,11 +936,8 @@ fn void resolve_type_in_place_debug(Module* module, Type* type)
case TypeId::pointer:
{
resolve_type_in_place_debug(module, type->pointer.element_type);
if (type->llvm.debug)
{
trap();
}
else
result = type->llvm.debug;
if (!result)
{
result = LLVMDIBuilderCreatePointerType(module->llvm.di_builder, type->pointer.element_type->llvm.debug, 64, 64, 0, (char*)type->name.pointer, type->name.length);
}
@ -3118,6 +3133,7 @@ fn void analyze_type(Module* module, Value* value, Type* expected_type)
if (!result_field)
{
// Field not found
report_error();
}
@ -6286,41 +6302,10 @@ fn void emit_value(Module* module, Value* value, TypeKind type_kind)
}
auto* left = value->binary.left;
if (left->llvm)
{
assert(false); // TODO: check if this if is really necessary
}
else
{
emit_value(module, left, TypeKind::abi);
}
auto left_llvm = left->llvm;
LLVMValueRef left_condition = 0;
switch (left->type->id)
{
case TypeId::integer:
{
switch (left->type->integer.bit_count)
{
case 1:
left_condition = left_llvm;
break;
default: trap();
}
} break;
default: trap();
}
assert(left_condition);
auto llvm_function = module->current_function->variable.storage->llvm;
assert(llvm_function);
auto current_basic_block = LLVMGetInsertBlock(module->llvm.builder);
auto* right_block = llvm_context_create_basic_block(module->llvm.context, string_literal("shortcircuit.right"), llvm_function);
auto* end_block = llvm_context_create_basic_block(module->llvm.context, string_literal("shortcircuit.end"), llvm_function);
@ -6339,7 +6324,11 @@ fn void emit_value(Module* module, Value* value, TypeKind type_kind)
break;
}
LLVMBuildCondBr(module->llvm.builder, left_condition, true_block, false_block);
emit_value(module, left, TypeKind::abi);
auto llvm_condition = emit_condition(module, left);
auto current_basic_block = LLVMGetInsertBlock(module->llvm.builder);
LLVMBuildCondBr(module->llvm.builder, llvm_condition, true_block, false_block);
LLVMPositionBuilderAtEnd(module->llvm.builder, right_block);
@ -7104,19 +7093,7 @@ fn void analyze_statement(Module* module, Scope* scope, Statement* statement, u3
auto condition = statement->if_st.condition;
analyze_value(module, condition, 0, TypeKind::abi);
auto condition_type = condition->type;
LLVMValueRef llvm_condition = 0;
assert(condition_type->id == TypeId::integer || condition_type->id == TypeId::pointer);
llvm_condition = condition->llvm;
if (!(condition_type->id == TypeId::integer && condition_type->integer.bit_count == 1))
{
llvm_condition = LLVMBuildICmp(module->llvm.builder, LLVMIntNE, llvm_condition, LLVMConstNull(condition_type->llvm.abi), "");
}
assert(llvm_condition);
auto llvm_condition = emit_condition(module, statement->if_st.condition);
LLVMBuildCondBr(module->llvm.builder, llvm_condition, taken_block, not_taken_block);
LLVMPositionBuilderAtEnd(module->llvm.builder, taken_block);
@ -7187,22 +7164,7 @@ fn void analyze_statement(Module* module, Scope* scope, Statement* statement, u3
else
{
analyze_value(module, condition, 0, TypeKind::abi);
auto boolean = uint1(module);
LLVMValueRef llvm_condition = condition->llvm;
auto condition_type = condition->type;
if (condition_type != boolean)
{
switch (condition_type->id)
{
case TypeId::integer:
{
llvm_condition = LLVMBuildICmp(module->llvm.builder, LLVMIntNE, llvm_condition, LLVMConstNull(condition_type->llvm.abi), "");
} break;
default: unreachable();
}
}
auto llvm_condition = emit_condition(module, condition);
LLVMBuildCondBr(module->llvm.builder, llvm_condition, body_block, exit_block);
}