Forward declared type
This commit is contained in:
parent
5de4ba76f5
commit
e95eea0504
347
src/compiler.bbb
347
src/compiler.bbb
@ -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);
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user