From 5266bec9263db75e223f35efa8f77f7815f2d57e Mon Sep 17 00:00:00 2001 From: David Gonzalez Martin Date: Tue, 17 Jun 2025 05:44:10 -0600 Subject: [PATCH] Pass 'basic_macro' --- src/compiler.bbb | 427 +++++++++++++++++++++++++++++++++++++++++++++-- src/compiler.hpp | 1 - 2 files changed, 416 insertions(+), 12 deletions(-) diff --git a/src/compiler.bbb b/src/compiler.bbb index ee6352f..38ecdc8 100644 --- a/src/compiler.bbb +++ b/src/compiler.bbb @@ -1045,6 +1045,8 @@ Value = struct; Local = struct; Block = struct; Module = struct; +MacroDeclaration = struct; +MacroInstantiation = struct; ScopeKind = enum { @@ -1779,7 +1781,7 @@ ValueId = enum variable, local, unary_type, - macro_reference, + macro, call, array_initialization, array_expression, @@ -1797,6 +1799,7 @@ ValueId = enum undefined, select, string_to_enum, + macro_instantiation, } ValueConstantInteger = struct @@ -2023,6 +2026,41 @@ ValueStringToEnum = struct string: &Value, } +ConstantArgumentId = enum +{ + value, + type, +} + +ConstantArgumentContent = union +{ + value: &Value, + type: &Type, +} + +ConstantArgument = struct +{ + name: []u8, + content: ConstantArgumentContent, + id: ConstantArgumentId, +} + +MacroInstantiation = struct +{ + declaration: &MacroDeclaration, + instantiation_function: &Global, + declaration_arguments: []Argument, + instantiation_arguments: []&Value, + constant_arguments: []ConstantArgument, + return_type: &Type, + block: &Block, + scope: Scope, + line: u32, + column: u32, + return_alloca: &LLVMValue, + return_block: &LLVMBasicBlock, +} + ValueContent = union { constant_integer: ValueConstantInteger, @@ -2042,6 +2080,8 @@ ValueContent = union aggregate_initialization: ValueAggregateInitialization, select: ValueSelect, string_to_enum: ValueStringToEnum, + macro: &MacroDeclaration, + macro_instantiation: MacroInstantiation, } ValueKind = enum @@ -2126,12 +2166,18 @@ void_offset: u64 = i128_offset + 2; MacroDeclaration = struct { - foo: u32, + arguments: []Argument, + constant_arguments: []ConstantArgument, + return_type: &Type, + block: &Block, + name: []u8, + scope: Scope, + next: &MacroDeclaration, } -MacroInstantiation = struct +macro_declaration_is_generic = fn (declaration: &MacroDeclaration) u1 { - foo: u32, + return declaration.constant_arguments.length != 0; } [extern] LLVMInitializeX86TargetInfo = fn [cc(c)] () void; @@ -2464,6 +2510,7 @@ LLVMICmpPredicate = enum u32 [extern] LLVMSetSubprogram = fn [cc(c)] (function: &LLVMValue, subprogram: &LLVMMetadata) void; [extern] LLVMGetSubprogram = fn [cc(c)] (function: &LLVMValue) &LLVMMetadata; +[extern] llvm_subprogram_replace_type = fn [cc(c)] (subprogram: &LLVMMetadata, subroutine_type: &LLVMMetadata) void; [extern] LLVMLookupIntrinsicID = fn [cc(c)] (name_pointer: &u8, name_length: u64) LLVMIntrinsicId; [extern] LLVMGetIntrinsicDeclaration = fn [cc(c)] (module: &LLVMModule, intrinsic_id: LLVMIntrinsicId, argument_type_pointer: &&LLVMType, argument_type_count: u64) &LLVMValue; @@ -4905,6 +4952,12 @@ tokenize = fn (module: &Module) Token parse_precedence = fn (module: &Module, scope: &Scope, builder: ValueBuilder) &Value; +scope_to_macro_declaration = fn (scope: &Scope) &MacroDeclaration +{ + assert(scope.kind == .macro_declaration); + return #field_parent_pointer(scope, "scope"); +} + reference_identifier = fn (module: &Module, current_scope: &Scope, identifier: []u8, kind: ValueKind) &Value { assert(!string_equal(identifier, "")); @@ -4936,9 +4989,22 @@ reference_identifier = fn (module: &Module, current_scope: &Scope, identifier: [ >macro_declaration = module.first_macro_declaration; - while (macro_declaration != zero) + while (macro_declaration) { - #trap(); + if (string_equal(identifier, macro_declaration.name)) + { + >result = new_value(module); + result.& = { + .content = { + .macro = macro_declaration, + }, + .id = .macro, + zero, + }; + return result; + } + + macro_declaration = macro_declaration.next; } }, .function => @@ -4995,7 +5061,25 @@ reference_identifier = fn (module: &Module, current_scope: &Scope, identifier: [ }, .macro_declaration => { - #trap(); + assert(scope.parent != zero); + >macro_declaration = scope_to_macro_declaration(scope); + + for (&constant_argument: macro_declaration.constant_arguments) + { + if (string_equal(identifier, constant_argument.name)) + { + #trap(); + } + } + + for (&argument: macro_declaration.arguments) + { + if (string_equal(identifier, argument.variable.name)) + { + variable = &argument.variable; + break; + } + } }, .macro_instantiation => { @@ -5761,9 +5845,44 @@ parse_right = fn (module: &Module, scope: &Scope, builder: ValueBuilder) &Value switch (left.id) { - .macro_reference => + .macro => { - #trap(); + >declaration = left.content.macro; + + if (macro_declaration_is_generic(declaration)) + { + report_error(); + } + + >instantiation_line = get_line(module); + >instantiation_column = get_column(module); + + >arguments = parse_call_arguments(module, scope); + + result.& = { + .content = { + .macro_instantiation = { + .declaration = declaration, + .instantiation_function = module.current_function, + .declaration_arguments = zero, + .instantiation_arguments = arguments, + .constant_arguments = zero, + .return_type = declaration.return_type, + .scope = { + .parent = scope, + .line = declaration.scope.line, + .column = declaration.scope.column, + .kind = .macro_instantiation, + zero, + }, + .line = instantiation_line, + .column = instantiation_column, + zero, + }, + }, + .id = .macro_instantiation, + zero, + }; }, else => { @@ -5789,7 +5908,7 @@ parse_right = fn (module: &Module, scope: &Scope, builder: ValueBuilder) &Value result = new_value(module); - if (left.id == .macro_reference) + if (left.id == .macro) { #trap(); } @@ -7016,7 +7135,118 @@ parse = fn (module: &Module) void }, .macro => { - #trap(); + >constant_argument_buffer: [64]ConstantArgument = undefined; + >constant_argument_count: u64 = 0; + + >is_generic = consume_character_if_match(module, left_bracket); + >macro_declaration = arena_allocate[MacroDeclaration](module.arena, 1); + macro_declaration.& = { + .name = global_name, + .scope = { + .parent = scope, + .line = global_line, + .column = global_column, + .kind = .macro_declaration, + zero, + }, + zero, + }; + + if (is_generic) + { + // END OF SCOPE + if (constant_argument_count == 0) + { + report_error(); + } + #trap(); + } + else + { + assert(constant_argument_count == 0); + } + + expect_character(module, left_parenthesis); + + macro_declaration.constant_arguments = arena_allocate_slice[ConstantArgument](module.arena, constant_argument_count); + memcpy(#pointer_cast(macro_declaration.constant_arguments.pointer), #pointer_cast(&constant_argument_buffer), constant_argument_count * #byte_size(ConstantArgument)); + + if (module.first_macro_declaration) + { + assert(module.first_macro_declaration != zero); + module.last_macro_declaration.next = macro_declaration; + } + else + { + assert(!module.first_macro_declaration); + module.first_macro_declaration = macro_declaration; + } + + module.last_macro_declaration = macro_declaration; + module.current_macro_declaration = macro_declaration; + + >scope = ¯o_declaration.scope; + + >argument_buffer: [64]Argument = undefined; + >argument_count: u64 = 0; + + while (1) + { + skip_space(module); + + if (consume_character_if_match(module, right_parenthesis)) + { + break; + } + + >argument_index = argument_count; + + >argument_line = get_line(module); + >argument_column = get_column(module); + + >argument_name = arena_duplicate_string(module.arena, parse_identifier(module)); + + skip_space(module); + expect_character(module, ':'); + skip_space(module); + + >argument_type = parse_type(module, scope); + + >argument = &argument_buffer[argument_index]; + argument.& = { + .variable = { + .type = argument_type, + .scope = scope, + .name = argument_name, + .line = argument_line, + .column = argument_column, + zero, + }, + .index = #truncate(argument_index + 1), + }; + + argument_count += 1; + + skip_space(module); + consume_character_if_match(module, ','); + } + + skip_space(module); + + >return_type = parse_type(module, scope); + macro_declaration.return_type = return_type; + + >arguments = arena_allocate_slice[Argument](module.arena, argument_count); + memcpy(#pointer_cast(arguments.pointer), #pointer_cast(&argument_buffer), argument_count * #byte_size(Argument)); + macro_declaration.arguments = arguments; + + skip_space(module); + + >block = parse_block(module, scope); + macro_declaration.block = block; + + // END OF SCOPE + module.current_macro_declaration = zero; }, .opaque => { @@ -9084,6 +9314,41 @@ get_enum_name_array_global = fn (module: &Module, enum_type: &Type) &Global return enum_type.content.enum.name_array; } +resolve_type = fn (module: &Module, type: &Type) &Type +{ + >result: &Type = zero; + + switch (type.id) + { + .unresolved => + { + #trap(); + }, + .integer => + { + result = type; + }, + else => + { + #trap(); + }, + } + + assert(result != zero); + return result; +} + +BlockCopy = struct +{ + source: &Block, + destination: &Block, +} + +copy_block = fn (module: &Module, parent_scope: &Scope, copy: BlockCopy) void +{ + #trap(); +} + analyze_type = fn (module: &Module, value: &Value, expected_type: &Type, analysis: TypeAnalysis) void { assert(!value.type); @@ -10647,6 +10912,145 @@ analyze_type = fn (module: &Module, value: &Value, expected_type: &Type, analysi value_type = expected_type; }, + .macro_instantiation => + { + if (module.current_macro_declaration) + { + report_error(); + } + + >current_function = module.current_function; + if (!current_function) + { + report_error(); + } + + module.current_function = zero; + + >current_macro_instantiation = module.current_macro_instantiation; + assert(!current_macro_instantiation); // TODO + >macro_instantiation = &value.content.macro_instantiation; + module.current_macro_instantiation = macro_instantiation; + + >declaration = macro_instantiation.declaration; + >declaration_arguments = declaration.arguments; + >instantiation_declaration_arguments = arena_allocate_slice[Argument](module.arena, declaration_arguments.length); + macro_instantiation.declaration_arguments = instantiation_declaration_arguments; + + >subprogram: &LLVMMetadata = zero; + if (module.has_debug_info) + { + >subroutine_type: &LLVMMetadata = zero; + >is_local_to_unit: u1 = 1; + >is_definition: u1 = 1; + >flags: LLVMDIFlags = zero; + >is_optimized = build_mode_is_optimized(module.build_mode); + subprogram = LLVMDIBuilderCreateFunction(module.llvm.di_builder, module.scope.llvm, declaration.name.pointer, declaration.name.length, declaration.name.pointer, declaration.name.length, module.llvm.file, macro_instantiation.scope.line, subroutine_type, #extend(is_local_to_unit), #extend(is_definition), macro_instantiation.scope.line, flags, #extend(is_optimized)); + } + + macro_instantiation.scope.llvm = subprogram; + + // First copy + for (i: 0..declaration_arguments.length) + { + >instantiation_declaration_argument = &instantiation_declaration_arguments[i]; + >declaration_argument = &declaration_arguments[i]; + instantiation_declaration_argument.& = { + .variable = { + .type = declaration_argument.variable.type, + .scope = ¯o_instantiation.scope, + .name = declaration_argument.variable.name, + .line = declaration_argument.variable.line, + .column = declaration_argument.variable.column, + zero, + }, + .index = declaration_argument.index, + }; + } + + >declaration_constant_arguments = declaration.constant_arguments; + >instantiation_constant_arguments = macro_instantiation.constant_arguments; + + for (i: 0..declaration_constant_arguments.length) + { + >declaration_constant_argument = &declaration_constant_arguments[i]; + >instantiation_constant_argument = &instantiation_constant_arguments[i]; + + assert(declaration_constant_argument.id == instantiation_constant_argument.id); + + instantiation_constant_argument.name = declaration_constant_argument.name; + + switch (declaration_constant_argument.id) + { + .value => + { + #trap(); + }, + .type => + { + #trap(); + }, + } + } + + value_type = resolve_type(module, declaration.return_type); + assert(value_type.id != .unresolved); + macro_instantiation.return_type = value_type; + + for (&argument: macro_instantiation.declaration_arguments) + { + argument.variable.type = resolve_type(module, argument.variable.type); + } + + >instantiation_arguments = macro_instantiation.instantiation_arguments; + if (instantiation_arguments.length != instantiation_declaration_arguments.length) + { + report_error(); + } + + if (module.has_debug_info) + { + for (i: 0..instantiation_arguments.length) + { + >instantiation_argument = instantiation_arguments[i]; + >declaration_argument = &instantiation_declaration_arguments[i]; + + >argument_type = declaration_argument.variable.type; + assert(argument_type != zero); + analyze_type(module, instantiation_argument, argument_type, { .must_be_constant = analysis.must_be_constant, zero }); + } + + >type_buffer: [64]&LLVMMetadata = undefined; + >type_count = instantiation_arguments.length + 1; + + resolve_type_in_place_debug(module, value_type); + type_buffer[0] = value_type.llvm.debug; + + for (i: 0..instantiation_declaration_arguments.length) + { + >declaration_argument = &instantiation_declaration_arguments[i]; + >type = declaration_argument.variable.type; + resolve_type_in_place_debug(module, type); + type_buffer[i + 1] = type.llvm.debug; + } + + LLVMSetCurrentDebugLocation2(module.llvm.builder, zero); + >flags: LLVMDIFlags = zero; + >subroutine_type = LLVMDIBuilderCreateSubroutineType(module.llvm.di_builder, module.llvm.file, &type_buffer[0], #truncate(type_count), flags); + assert(macro_instantiation.scope.llvm != zero); + llvm_subprogram_replace_type(subprogram, subroutine_type); + } + + assert(!macro_instantiation.block); + macro_instantiation.block = arena_allocate[Block](module.arena, 1); + + copy_block(module, ¯o_instantiation.scope, { + .source = declaration.block, + .destination = macro_instantiation.block, + }); + + #trap(); + }, else => { #trap(); @@ -16223,6 +16627,7 @@ names: [_][]u8 = "pointer_struct_initialization", "slice_array_literal", "slice_only_start", + "basic_macro", ]; [export] main = fn [cc(c)] (argument_count: u32, argv: &&u8, envp: &&u8) s32 diff --git a/src/compiler.hpp b/src/compiler.hpp index 1f7cb18..24d4233 100644 --- a/src/compiler.hpp +++ b/src/compiler.hpp @@ -1029,7 +1029,6 @@ struct MacroDeclaration { Slice arguments; Slice constant_arguments; - TypeList types; Type* return_type; Block* block; String name;