From e95eea05048a45eec10c6ff21c304fae143e0629 Mon Sep 17 00:00:00 2001 From: David Gonzalez Martin Date: Fri, 23 May 2025 20:02:10 -0600 Subject: [PATCH] Forward declared type --- src/compiler.bbb | 347 ++++++++++++++++++++++++++++++++++++++++++++++- src/compiler.cpp | 2 +- src/emitter.cpp | 98 ++++--------- 3 files changed, 375 insertions(+), 72 deletions(-) diff --git a/src/compiler.bbb b/src/compiler.bbb index 6a69b54..6c5dbdf 100644 --- a/src/compiler.bbb +++ b/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); diff --git a/src/compiler.cpp b/src/compiler.cpp index f85712e..4fdfa22 100644 --- a/src/compiler.cpp +++ b/src/compiler.cpp @@ -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 arguments, Slice environment) diff --git a/src/emitter.cpp b/src/emitter.cpp index 6ffb0ee..0387ddc 100644 --- a/src/emitter.cpp +++ b/src/emitter.cpp @@ -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 argument_types, Slice 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); }