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