wip
This commit is contained in:
		
							parent
							
								
									0eee2a4ff3
								
							
						
					
					
						commit
						b87029d776
					
				| @ -396,7 +396,7 @@ pub const Type = struct { | |||||||
|         }; |         }; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     fn resolve(ty: *Type, module: *Module) void { |     fn resolve_abi(ty: *Type, module: *Module) void { | ||||||
|         if (ty.llvm.abi == null) { |         if (ty.llvm.abi == null) { | ||||||
|             const abi_type = switch (ty.bb) { |             const abi_type = switch (ty.bb) { | ||||||
|                 .void, .noreturn => module.llvm.void_type, |                 .void, .noreturn => module.llvm.void_type, | ||||||
| @ -439,7 +439,11 @@ pub const Type = struct { | |||||||
|                 else => @trap(), |                 else => @trap(), | ||||||
|             }; |             }; | ||||||
|             ty.llvm.abi = abi_type; |             ty.llvm.abi = abi_type; | ||||||
|  |         } | ||||||
|  |     } | ||||||
| 
 | 
 | ||||||
|  |     fn resolve_memory(ty: *Type, module: *Module) void { | ||||||
|  |         if (ty.llvm.memory == null) { | ||||||
|             const memory_type = switch (ty.bb) { |             const memory_type = switch (ty.bb) { | ||||||
|                 .void, |                 .void, | ||||||
|                 .noreturn, |                 .noreturn, | ||||||
| @ -447,7 +451,7 @@ pub const Type = struct { | |||||||
|                 .array, |                 .array, | ||||||
|                 .structure, |                 .structure, | ||||||
|                 .@"union", |                 .@"union", | ||||||
|                 => abi_type, |                 => ty.llvm.abi.?, | ||||||
|                 .integer => module.llvm.context.get_integer_type(@intCast(ty.get_byte_size() * 8)).to_type(), |                 .integer => module.llvm.context.get_integer_type(@intCast(ty.get_byte_size() * 8)).to_type(), | ||||||
|                 .enumerator => |enumerator| enumerator.backing_type.llvm.memory.?, |                 .enumerator => |enumerator| enumerator.backing_type.llvm.memory.?, | ||||||
|                 .bits => |bits| bits.backing_type.llvm.memory.?, // TODO: see assert below |                 .bits => |bits| bits.backing_type.llvm.memory.?, // TODO: see assert below | ||||||
| @ -456,8 +460,12 @@ pub const Type = struct { | |||||||
|             }; |             }; | ||||||
|             ty.llvm.memory = memory_type; |             ty.llvm.memory = memory_type; | ||||||
|             if (ty.bb == .bits) assert(ty.llvm.memory == ty.llvm.abi); |             if (ty.bb == .bits) assert(ty.llvm.memory == ty.llvm.abi); | ||||||
|  |         } | ||||||
|  |     } | ||||||
| 
 | 
 | ||||||
|  |     fn resolve_debug(ty: *Type, module: *Module) void { | ||||||
|         if (module.has_debug_info) { |         if (module.has_debug_info) { | ||||||
|  |             if (ty.llvm.debug == null) { | ||||||
|                 const debug_type = switch (ty.bb) { |                 const debug_type = switch (ty.bb) { | ||||||
|                     .void, .noreturn => module.llvm.di_builder.create_basic_type(ty.name, 0, .void, .{ .no_return = ty.bb == .noreturn }), |                     .void, .noreturn => module.llvm.di_builder.create_basic_type(ty.name, 0, .void, .{ .no_return = ty.bb == .noreturn }), | ||||||
|                     .integer => |integer| module.llvm.di_builder.create_basic_type(ty.name, @max(lib.next_power_of_two(integer.bit_count), 8), switch (integer.bit_count) { |                     .integer => |integer| module.llvm.di_builder.create_basic_type(ty.name, @max(lib.next_power_of_two(integer.bit_count), 8), switch (integer.bit_count) { | ||||||
| @ -467,12 +475,16 @@ pub const Type = struct { | |||||||
|                             false => .unsigned, |                             false => .unsigned, | ||||||
|                         }, |                         }, | ||||||
|                     }, .{}), |                     }, .{}), | ||||||
|                     .pointer => |pointer| b: { |                     .pointer => |pointer| p: { | ||||||
|                         pointer.type.resolve(module); |                         pointer.type.resolve_debug(module); | ||||||
|                         break :b module.llvm.di_builder.create_pointer_type(pointer.type.llvm.debug.?, 64, 64, 0, ty.name).to_type(); |                         break :p if (ty.llvm.debug) |d| d else b: { | ||||||
|  |                             const pointer_type = module.llvm.di_builder.create_pointer_type(pointer.type.llvm.debug.?, 64, 64, 0, ty.name).to_type(); | ||||||
|  |                             break :b pointer_type; | ||||||
|  |                         }; | ||||||
|                     }, |                     }, | ||||||
|                     .array => |array| module.llvm.di_builder.create_array_type(array.element_count, 0, array.element_type.llvm.debug.?, &.{}).to_type(), |                     .array => |array| module.llvm.di_builder.create_array_type(array.element_count, 0, array.element_type.llvm.debug.?, &.{}).to_type(), | ||||||
|                     .enumerator => |enumerator| blk: { |                     .enumerator => |enumerator| blk: { | ||||||
|  |                         enumerator.backing_type.resolve_debug(module); | ||||||
|                         var enumerator_buffer: [64]*llvm.DI.Enumerator = undefined; |                         var enumerator_buffer: [64]*llvm.DI.Enumerator = undefined; | ||||||
|                         const enumerators = enumerator_buffer[0..enumerator.fields.len]; |                         const enumerators = enumerator_buffer[0..enumerator.fields.len]; | ||||||
|                         for (enumerators, enumerator.fields) |*enumerator_pointer, *field| { |                         for (enumerators, enumerator.fields) |*enumerator_pointer, *field| { | ||||||
| @ -483,21 +495,21 @@ pub const Type = struct { | |||||||
|                         break :blk enumeration_type.to_type(); |                         break :blk enumeration_type.to_type(); | ||||||
|                     }, |                     }, | ||||||
|                     .structure => |structure| blk: { |                     .structure => |structure| blk: { | ||||||
|                         const struct_type = module.llvm.di_builder.create_replaceable_composite_type(module.llvm.debug_tag, ty.name, module.scope.llvm.?, module.llvm.file, structure.line); |                         const fwd = module.llvm.di_builder.create_replaceable_composite_type(module.llvm.debug_tag, ty.name, module.scope.llvm.?, module.llvm.file, structure.line); | ||||||
|                         ty.llvm.debug = struct_type.to_type(); |                         ty.llvm.debug = fwd.to_type(); | ||||||
|                         module.llvm.debug_tag += 1; |                         module.llvm.debug_tag += 1; | ||||||
| 
 | 
 | ||||||
|                         var llvm_debug_member_type_buffer: [64]*llvm.DI.Type.Derived = undefined; |                         var llvm_debug_member_type_buffer: [64]*llvm.DI.Type.Derived = undefined; | ||||||
|                         const llvm_debug_member_types = llvm_debug_member_type_buffer[0..structure.fields.len]; |                         const llvm_debug_member_types = llvm_debug_member_type_buffer[0..structure.fields.len]; | ||||||
| 
 | 
 | ||||||
|                         for (structure.fields, llvm_debug_member_types) |field, *llvm_debug_member_type| { |                         for (structure.fields, llvm_debug_member_types) |field, *llvm_debug_member_type| { | ||||||
|                             field.type.resolve(module); |                             field.type.resolve_debug(module); | ||||||
|                             const member_type = module.llvm.di_builder.create_member_type(module.scope.llvm.?, field.name, module.llvm.file, field.line, field.type.get_byte_size() * 8, @intCast(field.type.get_byte_alignment() * 8), field.bit_offset, .{}, field.type.llvm.debug.?); |                             const member_type = module.llvm.di_builder.create_member_type(module.scope.llvm.?, field.name, module.llvm.file, field.line, field.type.get_byte_size() * 8, @intCast(field.type.get_byte_alignment() * 8), field.bit_offset, .{}, field.type.llvm.debug.?); | ||||||
|                             llvm_debug_member_type.* = member_type; |                             llvm_debug_member_type.* = member_type; | ||||||
|                         } |                         } | ||||||
| 
 | 
 | ||||||
|                         const debug_struct_type = module.llvm.di_builder.create_struct_type(module.scope.llvm.?, ty.name, module.llvm.file, structure.line, structure.bit_size, @intCast(structure.bit_alignment), .{}, llvm_debug_member_types); |                         const debug_struct_type = module.llvm.di_builder.create_struct_type(module.scope.llvm.?, ty.name, module.llvm.file, structure.line, structure.bit_size, @intCast(structure.bit_alignment), .{}, llvm_debug_member_types); | ||||||
|                         const forward_declared: *llvm.DI.Type.Composite = @ptrCast(ty.llvm.debug); |                         const forward_declared: *llvm.DI.Type.Composite = @ptrCast(fwd); | ||||||
|                         forward_declared.replace_all_uses_with(debug_struct_type); |                         forward_declared.replace_all_uses_with(debug_struct_type); | ||||||
|                         break :blk debug_struct_type.to_type(); |                         break :blk debug_struct_type.to_type(); | ||||||
|                     }, |                     }, | ||||||
| @ -512,6 +524,7 @@ pub const Type = struct { | |||||||
|                         break :blk struct_type.to_type(); |                         break :blk struct_type.to_type(); | ||||||
|                     }, |                     }, | ||||||
|                     .alias => |alias| blk: { |                     .alias => |alias| blk: { | ||||||
|  |                         alias.type.resolve_debug(module); | ||||||
|                         const typedef = module.llvm.di_builder.create_typedef(alias.type.llvm.debug.?, ty.name, module.llvm.file, alias.line, alias.scope.llvm.?, 0); |                         const typedef = module.llvm.di_builder.create_typedef(alias.type.llvm.debug.?, ty.name, module.llvm.file, alias.line, alias.scope.llvm.?, 0); | ||||||
|                         break :blk typedef.to_type(); |                         break :blk typedef.to_type(); | ||||||
|                     }, |                     }, | ||||||
| @ -524,7 +537,7 @@ pub const Type = struct { | |||||||
|                         const llvm_debug_member_types = llvm_debug_member_type_buffer[0..union_type.fields.len]; |                         const llvm_debug_member_types = llvm_debug_member_type_buffer[0..union_type.fields.len]; | ||||||
| 
 | 
 | ||||||
|                         for (union_type.fields, llvm_debug_member_types) |field, *llvm_debug_member_type| { |                         for (union_type.fields, llvm_debug_member_types) |field, *llvm_debug_member_type| { | ||||||
|                             field.type.resolve(module); |                             field.type.resolve_debug(module); | ||||||
|                             const member_type = module.llvm.di_builder.create_member_type(module.scope.llvm.?, field.name, module.llvm.file, field.line, field.type.get_byte_size() * 8, @intCast(field.type.get_byte_alignment() * 8), 0, .{}, field.type.llvm.debug.?); |                             const member_type = module.llvm.di_builder.create_member_type(module.scope.llvm.?, field.name, module.llvm.file, field.line, field.type.get_byte_size() * 8, @intCast(field.type.get_byte_alignment() * 8), 0, .{}, field.type.llvm.debug.?); | ||||||
|                             llvm_debug_member_type.* = member_type; |                             llvm_debug_member_type.* = member_type; | ||||||
|                         } |                         } | ||||||
| @ -536,11 +549,18 @@ pub const Type = struct { | |||||||
|                     }, |                     }, | ||||||
|                     else => @trap(), |                     else => @trap(), | ||||||
|                 }; |                 }; | ||||||
|  | 
 | ||||||
|                 ty.llvm.debug = debug_type; |                 ty.llvm.debug = debug_type; | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     fn resolve(ty: *Type, module: *Module) void { | ||||||
|  |         ty.resolve_abi(module); | ||||||
|  |         ty.resolve_memory(module); | ||||||
|  |         ty.resolve_debug(module); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     const Bits = struct { |     const Bits = struct { | ||||||
|         fields: []const Struct.Field, |         fields: []const Struct.Field, | ||||||
|         backing_type: *Type, |         backing_type: *Type, | ||||||
| @ -1271,6 +1291,26 @@ pub const Module = struct { | |||||||
|     has_debug_info: bool, |     has_debug_info: bool, | ||||||
|     silent: bool, |     silent: bool, | ||||||
| 
 | 
 | ||||||
|  |     const Checkpoint = struct { | ||||||
|  |         offset: u64, | ||||||
|  |         line_offset: u64, | ||||||
|  |         line_character_offset: u64, | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     pub fn get_checkpoint(module: *Module) Checkpoint { | ||||||
|  |         return .{ | ||||||
|  |             .offset = module.offset, | ||||||
|  |             .line_offset = module.line_offset, | ||||||
|  |             .line_character_offset = module.line_character_offset, | ||||||
|  |         }; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     pub fn set_checkpoint(module: *Module, checkpoint: Checkpoint) void { | ||||||
|  |         module.offset = checkpoint.offset; | ||||||
|  |         module.line_offset = checkpoint.line_offset; | ||||||
|  |         module.line_character_offset = checkpoint.line_character_offset; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     const LLVM = struct { |     const LLVM = struct { | ||||||
|         context: *llvm.Context, |         context: *llvm.Context, | ||||||
|         module: *llvm.Module, |         module: *llvm.Module, | ||||||
| @ -1569,7 +1609,7 @@ pub const Module = struct { | |||||||
|     pub fn get_pointer_type(module: *Module, pointer: Pointer) *Type { |     pub fn get_pointer_type(module: *Module, pointer: Pointer) *Type { | ||||||
|         const p = Type.Pointer{ |         const p = Type.Pointer{ | ||||||
|             .type = pointer.type, |             .type = pointer.type, | ||||||
|             .alignment = if (pointer.alignment) |a| a else if (pointer.type.bb != .unresolved) pointer.type.get_byte_alignment() else null, |             .alignment = if (pointer.alignment) |a| a else if (pointer.type.bb != .unresolved and pointer.type.bb != .forward_declaration) pointer.type.get_byte_alignment() else null, | ||||||
|         }; |         }; | ||||||
|         const all_types = module.types.get_slice(); |         const all_types = module.types.get_slice(); | ||||||
|         const pointer_type = for (module.pointer_types.get_slice()) |pointer_type_index| { |         const pointer_type = for (module.pointer_types.get_slice()) |pointer_type_index| { | ||||||
| @ -1646,13 +1686,13 @@ pub const Module = struct { | |||||||
|                     }, |                     }, | ||||||
|                     false => { |                     false => { | ||||||
|                         var length_inferred = false; |                         var length_inferred = false; | ||||||
|                         const offset = module.offset; |                         const checkpoint = module.get_checkpoint(); | ||||||
|                         if (module.consume_character_if_match('_')) { |                         if (module.consume_character_if_match('_')) { | ||||||
|                             module.skip_space(); |                             module.skip_space(); | ||||||
|                             if (module.consume_character_if_match(']')) { |                             if (module.consume_character_if_match(']')) { | ||||||
|                                 length_inferred = true; |                                 length_inferred = true; | ||||||
|                             } else { |                             } else { | ||||||
|                                 module.offset = offset; |                                 module.set_checkpoint(checkpoint); | ||||||
|                             } |                             } | ||||||
|                         } |                         } | ||||||
| 
 | 
 | ||||||
| @ -1853,17 +1893,46 @@ pub const Module = struct { | |||||||
|     fn skip_space(noalias module: *Module) void { |     fn skip_space(noalias module: *Module) void { | ||||||
|         while (true) { |         while (true) { | ||||||
|             const offset = module.offset; |             const offset = module.offset; | ||||||
|             while (module.offset < module.content.len and is_space(module.content[module.offset])) { | 
 | ||||||
|                 module.line_offset += @intFromBool(module.content[module.offset] == '\n'); |             while (true) { | ||||||
|                 module.line_character_offset = if (module.content[module.offset] == '\n') module.offset else module.line_character_offset; |                 if (module.offset == module.content.len) { | ||||||
|  |                     break; | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 assert(module.offset < module.content.len); | ||||||
|  | 
 | ||||||
|  |                 const ch = module.content[module.offset]; | ||||||
|  | 
 | ||||||
|  |                 const is_space_ch = is_space(ch); | ||||||
|  |                 if (!is_space_ch) { | ||||||
|  |                     break; | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 module.line_offset += @intFromBool(ch == '\n'); | ||||||
|  |                 module.line_character_offset = if (ch == '\n') module.offset else module.line_character_offset; | ||||||
|                 module.offset += 1; |                 module.offset += 1; | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             if (module.offset + 1 < module.content.len) { |             if (module.offset + 1 < module.content.len) { | ||||||
|                 const i = module.offset; |                 const i = module.offset; | ||||||
|                 const is_comment = module.content[i] == '/' and module.content[i + 1] == '/'; |                 const first_ch = module.content[i]; | ||||||
|  |                 const second_ch = module.content[i + 1]; | ||||||
|  |                 const is_comment = first_ch == '/' and second_ch == '/'; | ||||||
|  | 
 | ||||||
|                 if (is_comment) { |                 if (is_comment) { | ||||||
|                     while (module.offset < module.content.len and module.content[module.offset] != '\n') { |                     while (true) { | ||||||
|  |                         if (module.offset == module.content.len) { | ||||||
|  |                             break; | ||||||
|  |                         } | ||||||
|  | 
 | ||||||
|  |                         assert(module.offset < module.content.len); | ||||||
|  | 
 | ||||||
|  |                         const ch = module.content[module.offset]; | ||||||
|  | 
 | ||||||
|  |                         if (ch == '\n') { | ||||||
|  |                             break; | ||||||
|  |                         } | ||||||
|  | 
 | ||||||
|                         module.offset += 1; |                         module.offset += 1; | ||||||
|                     } |                     } | ||||||
| 
 | 
 | ||||||
| @ -2537,7 +2606,7 @@ pub const Module = struct { | |||||||
|         var result = value_builder.left; |         var result = value_builder.left; | ||||||
|         const precedence = value_builder.precedence; |         const precedence = value_builder.precedence; | ||||||
|         while (true) { |         while (true) { | ||||||
|             const checkpoint = module.offset; |             const checkpoint = module.get_checkpoint(); | ||||||
|             const token = module.tokenize(); |             const token = module.tokenize(); | ||||||
|             const token_rule = &rules[@intFromEnum(token)]; |             const token_rule = &rules[@intFromEnum(token)]; | ||||||
|             const token_precedence: Precedence = switch (token_rule.precedence) { |             const token_precedence: Precedence = switch (token_rule.precedence) { | ||||||
| @ -2548,7 +2617,7 @@ pub const Module = struct { | |||||||
|                 else => |p| p, |                 else => |p| p, | ||||||
|             }; |             }; | ||||||
|             if (@intFromEnum(precedence) > @intFromEnum(token_precedence)) { |             if (@intFromEnum(precedence) > @intFromEnum(token_precedence)) { | ||||||
|                 module.offset = checkpoint; |                 module.set_checkpoint(checkpoint); | ||||||
|                 break; |                 break; | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
| @ -2562,12 +2631,15 @@ pub const Module = struct { | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     fn parse_statement(module: *Module, scope: *Scope) *Statement { |     fn parse_statement(module: *Module, scope: *Scope) *Statement { | ||||||
|  |         var require_semicolon = true; | ||||||
|  | 
 | ||||||
|         const statement_line = module.get_line(); |         const statement_line = module.get_line(); | ||||||
|         const statement_column = module.get_column(); |         const statement_column = module.get_column(); | ||||||
| 
 | 
 | ||||||
|         const statement_start_character = module.content[module.offset]; |  | ||||||
|         const statement = module.statements.add(); |         const statement = module.statements.add(); | ||||||
|         var require_semicolon = true; | 
 | ||||||
|  |         const statement_start_character = module.content[module.offset]; | ||||||
|  | 
 | ||||||
|         statement.* = .{ |         statement.* = .{ | ||||||
|             .bb = switch (statement_start_character) { |             .bb = switch (statement_start_character) { | ||||||
|                 '>' => blk: { |                 '>' => blk: { | ||||||
| @ -2610,6 +2682,7 @@ pub const Module = struct { | |||||||
|                     .expression = module.parse_value(scope, .{}), |                     .expression = module.parse_value(scope, .{}), | ||||||
|                 }, |                 }, | ||||||
|                 'A'...'Z', 'a'...'z' => blk: { |                 'A'...'Z', 'a'...'z' => blk: { | ||||||
|  |                     const checkpoint = module.get_checkpoint(); | ||||||
|                     const statement_start_identifier = module.parse_identifier(); |                     const statement_start_identifier = module.parse_identifier(); | ||||||
| 
 | 
 | ||||||
|                     if (lib.string.to_enum(StatementStartKeyword, statement_start_identifier)) |statement_start_keyword| switch (statement_start_keyword) { |                     if (lib.string.to_enum(StatementStartKeyword, statement_start_identifier)) |statement_start_keyword| switch (statement_start_keyword) { | ||||||
| @ -2636,10 +2709,11 @@ pub const Module = struct { | |||||||
| 
 | 
 | ||||||
|                             var is_else = false; |                             var is_else = false; | ||||||
|                             if (is_identifier_start_ch(module.content[module.offset])) { |                             if (is_identifier_start_ch(module.content[module.offset])) { | ||||||
|  |                                 const else_checkpoint = module.get_checkpoint(); | ||||||
|                                 const identifier = module.parse_identifier(); |                                 const identifier = module.parse_identifier(); | ||||||
|                                 is_else = lib.string.equal(identifier, "else"); |                                 is_else = lib.string.equal(identifier, "else"); | ||||||
|                                 if (!is_else) { |                                 if (!is_else) { | ||||||
|                                     module.offset -= identifier.len; |                                     module.set_checkpoint(else_checkpoint); | ||||||
|                                 } else { |                                 } else { | ||||||
|                                     module.skip_space(); |                                     module.skip_space(); | ||||||
|                                 } |                                 } | ||||||
| @ -2772,10 +2846,7 @@ pub const Module = struct { | |||||||
| 
 | 
 | ||||||
|                             const token = module.tokenize(); |                             const token = module.tokenize(); | ||||||
|                             const kind: Statement.ForEach.Kind = switch (token) { |                             const kind: Statement.ForEach.Kind = switch (token) { | ||||||
|                                 .@")" => b: { |                                 .@")" => .slice, | ||||||
|                                     module.offset += 1; |  | ||||||
|                                     break :b .slice; |  | ||||||
|                                 }, |  | ||||||
|                                 .@".." => b: { |                                 .@".." => b: { | ||||||
|                                     if (left_value_count != 1) { |                                     if (left_value_count != 1) { | ||||||
|                                         module.report_error(); |                                         module.report_error(); | ||||||
| @ -2794,28 +2865,6 @@ pub const Module = struct { | |||||||
|                             }; |                             }; | ||||||
|                             statement.bb.for_each.kind = kind; |                             statement.bb.for_each.kind = kind; | ||||||
| 
 | 
 | ||||||
|                             module.skip_space(); |  | ||||||
|                             //     if (!module.consume_character_if_match(',')) { |  | ||||||
|                             //         module.expect_character(right_parenthesis); |  | ||||||
|                             //         @trap(); |  | ||||||
|                             //     } |  | ||||||
|                             // |  | ||||||
|                             // while (true) { |  | ||||||
|                             //     module.skip_space(); |  | ||||||
|                             // |  | ||||||
|                             //     right_value_buffer[right_value_count] = module.parse_value(scope, .{ |  | ||||||
|                             //         .kind = .left, |  | ||||||
|                             //     }); |  | ||||||
|                             //     right_value_count += 1; |  | ||||||
|                             // |  | ||||||
|                             //     module.skip_space(); |  | ||||||
|                             // |  | ||||||
|                             //     if (!module.consume_character_if_match(',')) { |  | ||||||
|                             //         module.expect_character(right_parenthesis); |  | ||||||
|                             //         break; |  | ||||||
|                             //     } |  | ||||||
|                             // } |  | ||||||
| 
 |  | ||||||
|                             if (kind == .slice and left_value_count != right_value_count) { |                             if (kind == .slice and left_value_count != right_value_count) { | ||||||
|                                 module.report_error(); |                                 module.report_error(); | ||||||
|                             } |                             } | ||||||
| @ -2831,6 +2880,8 @@ pub const Module = struct { | |||||||
|                             statement.bb.for_each.left_values = left_values; |                             statement.bb.for_each.left_values = left_values; | ||||||
|                             statement.bb.for_each.right_values = right_values; |                             statement.bb.for_each.right_values = right_values; | ||||||
| 
 | 
 | ||||||
|  |                             module.skip_space(); | ||||||
|  | 
 | ||||||
|                             const predicate = module.parse_statement(&statement.bb.for_each.scope); |                             const predicate = module.parse_statement(&statement.bb.for_each.scope); | ||||||
|                             statement.bb.for_each.predicate = predicate; |                             statement.bb.for_each.predicate = predicate; | ||||||
| 
 | 
 | ||||||
| @ -2862,10 +2913,11 @@ pub const Module = struct { | |||||||
|                                 const is_else = is_else_blk: { |                                 const is_else = is_else_blk: { | ||||||
|                                     var is_else = false; |                                     var is_else = false; | ||||||
|                                     if (is_identifier_start_ch(module.content[module.offset])) { |                                     if (is_identifier_start_ch(module.content[module.offset])) { | ||||||
|  |                                         const else_checkpoint = module.get_checkpoint(); | ||||||
|                                         const i = module.parse_identifier(); |                                         const i = module.parse_identifier(); | ||||||
|                                         is_else = lib.string.equal(i, "else"); |                                         is_else = lib.string.equal(i, "else"); | ||||||
|                                         if (!is_else) { |                                         if (!is_else) { | ||||||
|                                             module.offset -= i.len; |                                             module.set_checkpoint(else_checkpoint); | ||||||
|                                         } |                                         } | ||||||
|                                     } |                                     } | ||||||
| 
 | 
 | ||||||
| @ -2936,7 +2988,7 @@ pub const Module = struct { | |||||||
|                         .@"break" => break :blk .break_statement, |                         .@"break" => break :blk .break_statement, | ||||||
|                         .@"continue" => break :blk .continue_statement, |                         .@"continue" => break :blk .continue_statement, | ||||||
|                     } else { |                     } else { | ||||||
|                         module.offset -= statement_start_identifier.len; |                         module.set_checkpoint(checkpoint); | ||||||
| 
 | 
 | ||||||
|                         const left = module.parse_value(scope, .{ |                         const left = module.parse_value(scope, .{ | ||||||
|                             .kind = .left, |                             .kind = .left, | ||||||
| @ -4035,7 +4087,7 @@ pub const Module = struct { | |||||||
| 
 | 
 | ||||||
|             var global_keyword = false; |             var global_keyword = false; | ||||||
|             if (is_identifier_start_ch(module.content[module.offset])) { |             if (is_identifier_start_ch(module.content[module.offset])) { | ||||||
|                 const identifier_offset = module.offset; |                 const checkpoint = module.get_checkpoint(); | ||||||
|                 const global_string = module.parse_identifier(); |                 const global_string = module.parse_identifier(); | ||||||
|                 module.skip_space(); |                 module.skip_space(); | ||||||
| 
 | 
 | ||||||
| @ -4435,10 +4487,7 @@ pub const Module = struct { | |||||||
| 
 | 
 | ||||||
|                                 module.skip_space(); |                                 module.skip_space(); | ||||||
| 
 | 
 | ||||||
|                                 switch (module.content[module.offset]) { |                                 _ = module.consume_character_if_match(','); | ||||||
|                                     ',' => module.offset += 1, |  | ||||||
|                                     else => {}, |  | ||||||
|                                 } |  | ||||||
|                             } |                             } | ||||||
| 
 | 
 | ||||||
|                             module.skip_space(); |                             module.skip_space(); | ||||||
| @ -4688,10 +4737,7 @@ pub const Module = struct { | |||||||
| 
 | 
 | ||||||
|                                 module.skip_space(); |                                 module.skip_space(); | ||||||
| 
 | 
 | ||||||
|                                 switch (module.content[module.offset]) { |                                 _ = module.consume_character_if_match(','); | ||||||
|                                     ',' => module.offset += 1, |  | ||||||
|                                     else => {}, |  | ||||||
|                                 } |  | ||||||
|                             } |                             } | ||||||
| 
 | 
 | ||||||
|                             module.skip_space(); |                             module.skip_space(); | ||||||
| @ -4713,7 +4759,7 @@ pub const Module = struct { | |||||||
|                         }, |                         }, | ||||||
|                     } |                     } | ||||||
|                 } else { |                 } else { | ||||||
|                     module.offset = identifier_offset; |                     module.set_checkpoint(checkpoint); | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
| @ -5189,20 +5235,28 @@ pub const Module = struct { | |||||||
|                                     } |                                     } | ||||||
|                                 } else { |                                 } else { | ||||||
|                                     assert(argument_abi.abi_count == 1); |                                     assert(argument_abi.abi_count == 1); | ||||||
|  |                                     const destination_type = argument_abi.get_coerce_to_type(); | ||||||
|  | 
 | ||||||
|  |                                     const v = switch (src.bb) { | ||||||
|  |                                         .zero => destination_type.llvm.abi.?.get_zero().to_value(), | ||||||
|  |                                         else => b: { | ||||||
|                                             // TODO: handmade change |                                             // TODO: handmade change | ||||||
|                                             if (src.type.?.bb != .pointer) { |                                             if (src.type.?.bb != .pointer) { | ||||||
|                                                 assert(src.kind == .right); |                                                 assert(src.kind == .right); | ||||||
|                                                 assert(src.type.?.bb == .structure); |                                                 assert(src.type.?.bb == .structure); | ||||||
|  |                                                 const ty = src.type.?; | ||||||
|                                                 src.type = null; |                                                 src.type = null; | ||||||
|                                                 src.kind = .left; |                                                 src.kind = .left; | ||||||
|                                         module.analyze_value_type(src, .{}); |                                                 module.analyze_value_type(src, .{ .type = module.get_pointer_type(.{ .type = ty }) }); | ||||||
|                                             } |                                             } | ||||||
|                                     module.emit_value(src, .memory); | 
 | ||||||
| 
 | 
 | ||||||
|                                             assert(src.type.?.bb == .pointer); |                                             assert(src.type.?.bb == .pointer); | ||||||
|  |                                             assert(src.type.?.llvm.abi == module.llvm.pointer_type); | ||||||
|  |                                             module.emit_value(src, .memory); | ||||||
|  | 
 | ||||||
|                                             const source_type = src.type.?.bb.pointer.type; |                                             const source_type = src.type.?.bb.pointer.type; | ||||||
|                                             assert(source_type == argument_abi.semantic_type); |                                             assert(source_type == argument_abi.semantic_type); | ||||||
|                                     const destination_type = argument_abi.get_coerce_to_type(); |  | ||||||
|                                             const load = module.create_coerced_load(src.llvm.?, source_type, destination_type); |                                             const load = module.create_coerced_load(src.llvm.?, source_type, destination_type); | ||||||
| 
 | 
 | ||||||
|                                             const is_cmse_ns_call = false; |                                             const is_cmse_ns_call = false; | ||||||
| @ -5214,7 +5268,11 @@ pub const Module = struct { | |||||||
|                                                 @trap(); |                                                 @trap(); | ||||||
|                                             } |                                             } | ||||||
| 
 | 
 | ||||||
|                                     llvm_abi_argument_value_buffer[abi_argument_count] = load; |                                             break :b load; | ||||||
|  |                                         }, | ||||||
|  |                                     }; | ||||||
|  | 
 | ||||||
|  |                                     llvm_abi_argument_value_buffer[abi_argument_count] = v; | ||||||
|                                     abi_argument_count += 1; |                                     abi_argument_count += 1; | ||||||
|                                 } |                                 } | ||||||
|                             } |                             } | ||||||
| @ -5866,18 +5924,18 @@ pub const Module = struct { | |||||||
|                         } |                         } | ||||||
|                     } |                     } | ||||||
| 
 | 
 | ||||||
|                     if (lib.optimization_mode == .Debug) { |                     // if (lib.optimization_mode == .Debug) { | ||||||
|                         const verify_result = llvm_function_value.verify(); |                     //     const verify_result = llvm_function_value.verify(); | ||||||
|                         if (!verify_result.success) { |                     //     if (!verify_result.success) { | ||||||
|                             lib.print_string(module.llvm.module.to_string()); |                     //         lib.print_string(module.llvm.module.to_string()); | ||||||
|                             lib.print_string("============================\n"); |                     //         lib.print_string("============================\n"); | ||||||
|                             lib.print_string(llvm_function_value.to_string()); |                     //         lib.print_string(llvm_function_value.to_string()); | ||||||
|                             lib.print_string("============================\n"); |                     //         lib.print_string("============================\n"); | ||||||
|                             lib.print_string(verify_result.error_message orelse unreachable); |                     //         lib.print_string(verify_result.error_message orelse unreachable); | ||||||
|                             lib.print_string("\n============================\n"); |                     //         lib.print_string("\n============================\n"); | ||||||
|                             lib.os.abort(); |                     //         lib.os.abort(); | ||||||
|                         } |                     //     } | ||||||
|                     } |                     // } | ||||||
|                 }, |                 }, | ||||||
|                 .global => { |                 .global => { | ||||||
|                     module.analyze(global.variable.initial_value, .{ .type = global.variable.type }, .memory); |                     module.analyze(global.variable.initial_value, .{ .type = global.variable.type }, .memory); | ||||||
| @ -5917,6 +5975,26 @@ pub const Module = struct { | |||||||
|             } |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  |         if (false) { | ||||||
|  |             const fwd = module.llvm.di_builder.create_replaceable_composite_type(0, "S", module.scope.llvm.?, module.llvm.file, 0); | ||||||
|  |             var types: [1]*llvm.DI.Type.Derived = undefined; | ||||||
|  |             const pointer_type = module.llvm.di_builder.create_pointer_type(fwd.to_type(), 64, 64, 0, "&S"); | ||||||
|  |             types[0] = module.llvm.di_builder.create_member_type(module.scope.llvm.?, "self", module.llvm.file, 0, 64, 64, 0, .{}, pointer_type.to_type()); | ||||||
|  |             const debug_struct_type = module.llvm.di_builder.create_struct_type(module.scope.llvm.?, "S", module.llvm.file, 0, 64, 64, .{}, &types); | ||||||
|  |             fwd.replace_all_uses_with(debug_struct_type); | ||||||
|  |             const struct_type = module.llvm.context.get_struct_type(&.{module.llvm.pointer_type}); | ||||||
|  |             const llvm_function_type = llvm.Type.Function.get(struct_type.to_type(), &.{}, false); | ||||||
|  |             const llvm_function_value = module.llvm.module.create_function(.{ | ||||||
|  |                 .name = "foo", | ||||||
|  |                 .linkage = .ExternalLinkage, | ||||||
|  |                 .type = llvm_function_type, | ||||||
|  |             }); | ||||||
|  | 
 | ||||||
|  |             const subroutine_type = module.llvm.di_builder.create_subroutine_type(module.llvm.file, &.{debug_struct_type.to_type()}, .{}); | ||||||
|  |             const subprogram = module.llvm.di_builder.create_function(module.scope.llvm.?, "foo", "foo", module.llvm.file, 0, subroutine_type, false, false, 0, .{}, false); | ||||||
|  |             llvm_function_value.set_subprogram(subprogram); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|         if (module.has_debug_info) { |         if (module.has_debug_info) { | ||||||
|             module.llvm.di_builder.finalize(); |             module.llvm.di_builder.finalize(); | ||||||
|         } |         } | ||||||
| @ -8315,93 +8393,16 @@ pub const Module = struct { | |||||||
|                         }, |                         }, | ||||||
|                         .noreturn => module.report_error(), |                         .noreturn => module.report_error(), | ||||||
|                         else => { |                         else => { | ||||||
|                             const return_value = rv orelse module.report_error(); |  | ||||||
|                             module.analyze(return_value, .{ |  | ||||||
|                                 .type = return_abi.semantic_type, |  | ||||||
|                             }, .memory); |  | ||||||
| 
 |  | ||||||
|                             if (module.has_debug_info) { |                             if (module.has_debug_info) { | ||||||
|                                 module.llvm.builder.set_current_debug_location(last_statement_debug_location.*); |                                 module.llvm.builder.set_current_debug_location(last_statement_debug_location.*); | ||||||
|                             } |                             } | ||||||
| 
 | 
 | ||||||
|                             // Clang equivalent: CodeGenFunction::EmitReturnStmt |  | ||||||
|                             const return_alloca = module.current_function.?.variable.storage.?.bb.function.return_alloca orelse module.report_error(); |                             const return_alloca = module.current_function.?.variable.storage.?.bb.function.return_alloca orelse module.report_error(); | ||||||
|  |                             const return_value = rv orelse module.report_error(); | ||||||
|  |                             module.analyze_value_type(return_value, .{ .type = return_abi.semantic_type }); | ||||||
| 
 | 
 | ||||||
|                             switch (return_abi.semantic_type.get_evaluation_kind()) { |                             const pointer_type = module.get_pointer_type(.{ .type = return_abi.semantic_type }); | ||||||
|                                 .scalar => { |                             module.emit_assignment(return_alloca, pointer_type, return_value); | ||||||
|                                     switch (return_abi.flags.kind) { |  | ||||||
|                                         .indirect => { |  | ||||||
|                                             @trap(); |  | ||||||
|                                         }, |  | ||||||
|                                         else => { |  | ||||||
|                                             // assert(!return_value.?.lvalue); |  | ||||||
|                                             assert(return_value.type.?.is_abi_equal(return_abi.semantic_type, module)); |  | ||||||
|                                             _ = module.create_store(.{ |  | ||||||
|                                                 .source_value = return_value.llvm.?, |  | ||||||
|                                                 .destination_value = return_alloca, |  | ||||||
|                                                 .type = return_abi.semantic_type, |  | ||||||
|                                             }); |  | ||||||
|                                         }, |  | ||||||
|                                     } |  | ||||||
|                                 }, |  | ||||||
|                                 // TODO: handcoded code, might be wrong |  | ||||||
|                                 .aggregate => switch (return_value.kind) { |  | ||||||
|                                     .left => @trap(), |  | ||||||
|                                     .right => { |  | ||||||
|                                         assert(return_value.type.?.is_abi_equal(return_abi.semantic_type, module)); |  | ||||||
|                                         _ = module.create_store(.{ |  | ||||||
|                                             .source_value = return_value.llvm.?, |  | ||||||
|                                             .destination_value = return_alloca, |  | ||||||
|                                             .type = return_abi.semantic_type, |  | ||||||
|                                         }); |  | ||||||
|                                     }, |  | ||||||
|                                     // switch (return_value.lvalue) { |  | ||||||
|                                     //     true => { |  | ||||||
|                                     //         const abi_alignment = return_abi.semantic_type.get_byte_alignment(); |  | ||||||
|                                     //         const abi_size = return_abi.semantic_type.get_byte_size(); |  | ||||||
|                                     //         switch (return_abi.flags.kind) { |  | ||||||
|                                     //             .indirect => { |  | ||||||
|                                     //                 _ = module.llvm.builder.create_memcpy( |  | ||||||
|                                     //                     unreachable, //return_alloca, |  | ||||||
|                                     //                     abi_alignment, return_value.llvm, abi_alignment, module.integer_type(64, false).llvm.handle.to_integer().get_constant(abi_size, @intFromBool(false)).to_value()); |  | ||||||
|                                     //             }, |  | ||||||
|                                     //             else => { |  | ||||||
|                                     //                 switch (return_abi.semantic_type.get_evaluation_kind()) { |  | ||||||
|                                     //                     .aggregate => { |  | ||||||
|                                     //                         // TODO: this is 100% wrong, fix |  | ||||||
|                                     //                         assert(abi_alignment == return_abi.semantic_type.get_byte_alignment()); |  | ||||||
|                                     //                         assert(abi_size == return_abi.semantic_type.get_byte_size()); |  | ||||||
|                                     //                         _ = module.llvm.builder.create_memcpy( |  | ||||||
|                                     //                             unreachable, //return_alloca, |  | ||||||
|                                     //                             abi_alignment, return_value.llvm, abi_alignment, module.integer_type(64, false).llvm.handle.to_integer().get_constant(abi_size, @intFromBool(false)).to_value()); |  | ||||||
|                                     //                     }, |  | ||||||
|                                     //                     .scalar => { |  | ||||||
|                                     //                         const destination_type = return_abi.semantic_type; |  | ||||||
|                                     //                         const source_type = return_abi.semantic_type; |  | ||||||
|                                     //                         assert(return_value.type == source_type); |  | ||||||
|                                     //                         const ret_val = switch (return_value.type.bb) { |  | ||||||
|                                     //                             .pointer => return_value.llvm, |  | ||||||
|                                     //                             // TODO: this feels hacky |  | ||||||
|                                     //                             else => switch (return_value.lvalue) { |  | ||||||
|                                     //                                 true => module.create_load(.{ .type = return_value.type, .value = return_value.llvm }), |  | ||||||
|                                     //                                 false => return_value.llvm, |  | ||||||
|                                     //                             }, |  | ||||||
|                                     //                         }; |  | ||||||
|                                     //                         _ = module.create_store(.{ .source_value = ret_val, .source_type = source_type, |  | ||||||
|                                     //                             .destination_value = unreachable, //return_alloca, |  | ||||||
|                                     //                             .destination_type = destination_type }); |  | ||||||
|                                     //                     }, |  | ||||||
|                                     //                     .complex => @trap(), |  | ||||||
|                                     //                 } |  | ||||||
|                                     //             }, |  | ||||||
|                                     //         } |  | ||||||
|                                     //     }, |  | ||||||
|                                     //     false => { |  | ||||||
|                                     //     }, |  | ||||||
|                                     // } |  | ||||||
|                                 }, |  | ||||||
|                                 .complex => @trap(), |  | ||||||
|                             } |  | ||||||
|                         }, |                         }, | ||||||
|                     } |                     } | ||||||
| 
 | 
 | ||||||
| @ -8667,8 +8668,10 @@ pub const Module = struct { | |||||||
|                             module.llvm.builder.clear_insertion_position(); |                             module.llvm.builder.clear_insertion_position(); | ||||||
|                         } |                         } | ||||||
| 
 | 
 | ||||||
|                         if (!all_blocks_terminated) { |  | ||||||
|                         module.llvm.builder.position_at_end(exit_block); |                         module.llvm.builder.position_at_end(exit_block); | ||||||
|  |                         if (all_blocks_terminated) { | ||||||
|  |                             _ = module.llvm.builder.create_unreachable(); | ||||||
|  |                             module.llvm.builder.clear_insertion_position(); | ||||||
|                         } |                         } | ||||||
|                     }, |                     }, | ||||||
|                     else => @trap(), |                     else => @trap(), | ||||||
| @ -9366,7 +9369,6 @@ pub const Module = struct { | |||||||
|         value: *llvm.Value, |         value: *llvm.Value, | ||||||
|         type: *Type, |         type: *Type, | ||||||
|     } { |     } { | ||||||
|         _ = module; |  | ||||||
|         var source_pointer = source_value; |         var source_pointer = source_value; | ||||||
|         var source_type = source_ty; |         var source_type = source_ty; | ||||||
|         assert(source_type.bb == .structure and source_type.bb.structure.fields.len > 0); |         assert(source_type.bb == .structure and source_type.bb.structure.fields.len > 0); | ||||||
| @ -9376,7 +9378,15 @@ pub const Module = struct { | |||||||
| 
 | 
 | ||||||
|         source_pointer = switch (first_field_size < destination_size and first_field_size < source_size) { |         source_pointer = switch (first_field_size < destination_size and first_field_size < source_size) { | ||||||
|             true => source_pointer, |             true => source_pointer, | ||||||
|             false => @trap(), // TODO: make sure `source_type` is also updated here |             false => b: { | ||||||
|  |                 source_pointer = module.llvm.builder.create_struct_gep(source_type.llvm.memory.?.to_struct(), source_pointer, 0); | ||||||
|  |                 source_type = module.get_pointer_type(.{ .type = first_field_type }); | ||||||
|  |                 if (first_field_type.bb == .structure) { | ||||||
|  |                     @trap(); | ||||||
|  |                 } else { | ||||||
|  |                     break :b source_pointer; | ||||||
|  |                 } | ||||||
|  |             }, | ||||||
|         }; |         }; | ||||||
| 
 | 
 | ||||||
|         return .{ .value = source_pointer, .type = source_type }; |         return .{ .value = source_pointer, .type = source_type }; | ||||||
| @ -9497,9 +9507,10 @@ pub const Module = struct { | |||||||
|         return result; |         return result; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     pub fn coerce_int_or_pointer_to_int_or_pointer(module: *Module, source: *llvm.Value, source_ty: *Type, destination_ty: *Type) *llvm.Value { |     pub fn coerce_int_or_pointer_to_int_or_pointer(module: *Module, s: *llvm.Value, source_ty: *Type, destination_ty: *Type) *llvm.Value { | ||||||
|         const source_type = source_ty; |         const source_type = source_ty; | ||||||
|         var destination_type = destination_ty; |         var destination_type = destination_ty; | ||||||
|  |         var source = s; | ||||||
|         switch (source_type == destination_type) { |         switch (source_type == destination_type) { | ||||||
|             true => return source, |             true => return source, | ||||||
|             false => { |             false => { | ||||||
| @ -9507,7 +9518,7 @@ pub const Module = struct { | |||||||
|                     @trap(); |                     @trap(); | ||||||
|                 } else { |                 } else { | ||||||
|                     if (source_type.bb == .pointer) { |                     if (source_type.bb == .pointer) { | ||||||
|                         @trap(); |                         source = module.llvm.builder.create_ptr_to_int(source, module.integer_type(64, false).llvm.abi.?); | ||||||
|                     } |                     } | ||||||
| 
 | 
 | ||||||
|                     if (destination_type.bb == .pointer) { |                     if (destination_type.bb == .pointer) { | ||||||
|  | |||||||
							
								
								
									
										365
									
								
								src/compiler.bbb
									
									
									
									
									
								
							
							
						
						
									
										365
									
								
								src/compiler.bbb
									
									
									
									
									
								
							| @ -586,11 +586,30 @@ CompileOptions = struct | |||||||
|     silent: u1, |     silent: u1, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | ScopeKind = enum | ||||||
|  | { | ||||||
|  |     global, | ||||||
|  |     function, | ||||||
|  |     local, | ||||||
|  |     for_each, | ||||||
|  |     macro_declaration, | ||||||
|  |     macro_instantiation_function, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | Scope = struct | ||||||
|  | { | ||||||
|  |     parent: &Scope, | ||||||
|  |     line: u32, | ||||||
|  |     column: u32, | ||||||
|  |     kind: ScopeKind, | ||||||
|  | } | ||||||
|  | 
 | ||||||
| TypeId = enum | TypeId = enum | ||||||
| { | { | ||||||
|     void, |     void, | ||||||
|     noreturn, |     noreturn, | ||||||
|     integer, |     integer, | ||||||
|  |     function, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| TypeInteger = struct | TypeInteger = struct | ||||||
| @ -599,9 +618,18 @@ TypeInteger = struct | |||||||
|     signed: u1, |     signed: u1, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | TypeFunction = struct | ||||||
|  | { | ||||||
|  |     semantic_argument_type: &Type, | ||||||
|  |     semantic_argument_types: []&Type, | ||||||
|  |     calling_convention: CallingConvention, | ||||||
|  |     is_variable_arguments: u1, | ||||||
|  | } | ||||||
|  | 
 | ||||||
| TypeContent = union | TypeContent = union | ||||||
| { | { | ||||||
|     integer: TypeInteger, |     integer: TypeInteger, | ||||||
|  |     function: TypeFunction, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| Type = struct | Type = struct | ||||||
| @ -630,11 +658,36 @@ Module = struct | |||||||
|     arena: &Arena, |     arena: &Arena, | ||||||
|     base_type_allocation: &Type, |     base_type_allocation: &Type, | ||||||
|     void_value: &Value, |     void_value: &Value, | ||||||
|     // Parser data |     // Parser data start | ||||||
|     content: []u8, |     content: []u8, | ||||||
|     offset: u64, |     offset: u64, | ||||||
|     line_offset: u64, |     line_offset: u64, | ||||||
|     line_character_offset: u64, |     line_character_offset: u64, | ||||||
|  |     // Parser data end | ||||||
|  |     scope: Scope, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | ModuleCheckpoint = struct | ||||||
|  | { | ||||||
|  |     offset: u64, | ||||||
|  |     line_offset: u64, | ||||||
|  |     line_character_offset: u64, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | get_checkpoint = fn (module: &Module) ModuleCheckpoint | ||||||
|  | { | ||||||
|  |     return { | ||||||
|  |         .offset = module.offset, | ||||||
|  |         .line_offset = module.line_offset, | ||||||
|  |         .line_character_offset = module.line_character_offset, | ||||||
|  |     }; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | set_checkpoint = fn (module: &Module, checkpoint: ModuleCheckpoint) void | ||||||
|  | { | ||||||
|  |     module.offset = checkpoint.offset; | ||||||
|  |     module.line_offset = checkpoint.line_offset; | ||||||
|  |     module.line_character_offset = checkpoint.line_character_offset; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| module_integer_type = fn (module: &Module, integer: TypeInteger) &Type | module_integer_type = fn (module: &Module, integer: TypeInteger) &Type | ||||||
| @ -655,6 +708,13 @@ module_noreturn_type = fn (module: &Module) &Type | |||||||
|     return module_void_type(module) + 1; |     return module_void_type(module) + 1; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | left_bracket: u8 = '['; | ||||||
|  | right_bracket: u8 = ']'; | ||||||
|  | left_parenthesis: u8 = '('; | ||||||
|  | right_parenthesis: u8 = ')'; | ||||||
|  | left_brace: u8 = '{'; | ||||||
|  | right_brace: u8 = '}'; | ||||||
|  | 
 | ||||||
| is_space = fn (ch: u8) u1 | is_space = fn (ch: u8) u1 | ||||||
| { | { | ||||||
|     return ch == ' ' or ch == '\n' or ch == '\t' or ch == '\r'; |     return ch == ' ' or ch == '\n' or ch == '\t' or ch == '\r'; | ||||||
| @ -697,7 +757,7 @@ is_hex = fn (ch: u8) u1 | |||||||
| 
 | 
 | ||||||
| is_identifier_start = fn (ch: u8) u1 | is_identifier_start = fn (ch: u8) u1 | ||||||
| { | { | ||||||
|     return (ch >= 'a' and ch >= 'z') or (ch >= 'A' and ch <= 'Z') or ch == '_'; |     return (ch >= 'a' and ch <= 'z') or (ch >= 'A' and ch <= 'Z') or ch == '_'; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| is_identifier = fn (ch: u8) u1 | is_identifier = fn (ch: u8) u1 | ||||||
| @ -817,8 +877,309 @@ parse_identifier = fn (module: &Module) []u8 | |||||||
|     return result; |     return result; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | parse_type = fn (module: &Module) &Type | ||||||
|  | { | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | ValueBuilder = struct | ||||||
|  | { | ||||||
|  |     foo: u32, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | parse_value = fn (module: &Module, scope: &Scope, v: ValueBuilder) &Value | ||||||
|  | { | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | GlobalKeyword = enum | ||||||
|  | { | ||||||
|  |     export, | ||||||
|  |     extern, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | GlobalKind = enum | ||||||
|  | { | ||||||
|  |     bits, | ||||||
|  |     enum, | ||||||
|  |     fn, | ||||||
|  |     macro, | ||||||
|  |     struct, | ||||||
|  |     typealias, | ||||||
|  |     union, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | CallingConvention = enum | ||||||
|  | { | ||||||
|  |     c, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | FunctionKeyword = enum | ||||||
|  | { | ||||||
|  |     cc, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | InlineBehavior = enum | ||||||
|  | { | ||||||
|  |     default, | ||||||
|  |     always_inline, | ||||||
|  |     no_inline, | ||||||
|  |     inline_hint, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | FunctionAttributes = struct | ||||||
|  | { | ||||||
|  |     inline_behavior: InlineBehavior, | ||||||
|  |     naked: u1, | ||||||
|  | } | ||||||
|  | 
 | ||||||
| parse = fn (module: &Module) void | parse = fn (module: &Module) void | ||||||
| { | { | ||||||
|  |     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_column(module); | ||||||
|  | 
 | ||||||
|  |         if (consume_character_if_match(module, left_bracket)) | ||||||
|  |         { | ||||||
|  |             while (module.offset < module.content.length) | ||||||
|  |             { | ||||||
|  |                 >global_keyword_string = parse_identifier(module); | ||||||
|  |                 >global_keyword_s2e = #string_to_enum(GlobalKeyword, global_keyword_string); | ||||||
|  |                 if (!global_keyword_s2e.is_valid) | ||||||
|  |                 { | ||||||
|  |                     report_error(); | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 >global_keyword = global_keyword_s2e.enum_value; | ||||||
|  |                 switch (global_keyword) | ||||||
|  |                 { | ||||||
|  |                     .export => { is_export = 1; } | ||||||
|  |                     .extern => { is_extern = 1; } | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 if (consume_character_if_match(module, right_bracket)) | ||||||
|  |                 { | ||||||
|  |                     break; | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 report_error(); | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             skip_space(module); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         >global_name = parse_identifier(module); | ||||||
|  | 
 | ||||||
|  |         // TODO: check if the name is repeated in global namespace | ||||||
|  | 
 | ||||||
|  |         skip_space(module); | ||||||
|  | 
 | ||||||
|  |         >global_type: &Type = zero; | ||||||
|  | 
 | ||||||
|  |         if (consume_character_if_match(module, ':')) | ||||||
|  |         { | ||||||
|  |             skip_space(module); | ||||||
|  | 
 | ||||||
|  |             global_type = parse_type(module); | ||||||
|  | 
 | ||||||
|  |             skip_space(module); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         expect_character(module, '='); | ||||||
|  | 
 | ||||||
|  |         skip_space(module); | ||||||
|  | 
 | ||||||
|  |         >has_global_keyword: u1 = 0; | ||||||
|  | 
 | ||||||
|  |         if (is_identifier_start(module.content[module.offset])) | ||||||
|  |         { | ||||||
|  |             >checkpoint = get_checkpoint(module); | ||||||
|  | 
 | ||||||
|  |             >global_string = parse_identifier(module); | ||||||
|  | 
 | ||||||
|  |             skip_space(module); | ||||||
|  | 
 | ||||||
|  |             >global_kind_s2e = #string_to_enum(GlobalKind, global_string); | ||||||
|  | 
 | ||||||
|  |             if (global_kind_s2e.is_valid) | ||||||
|  |             { | ||||||
|  |                 >global_kind = global_kind_s2e.enum_value; | ||||||
|  | 
 | ||||||
|  |                 switch (global_kind) | ||||||
|  |                 { | ||||||
|  |                     .bits => { | ||||||
|  |                         #trap(); | ||||||
|  |                     }, | ||||||
|  |                     .enum => { | ||||||
|  |                         #trap(); | ||||||
|  |                     }, | ||||||
|  |                     .fn => { | ||||||
|  |                         >calling_convention: CallingConvention = .c; | ||||||
|  |                         >function_attributes: FunctionAttributes = zero; | ||||||
|  |                         >is_variable_arguments: u1 = 0; | ||||||
|  | 
 | ||||||
|  |                         if (consume_character_if_match(module, left_bracket)) | ||||||
|  |                         { | ||||||
|  |                             while (module.offset < module.content.length) | ||||||
|  |                             { | ||||||
|  |                                 >function_identifier = parse_identifier(module); | ||||||
|  | 
 | ||||||
|  |                                 >function_keyword_s2e = #string_to_enum(FunctionKeyword, function_identifier); | ||||||
|  |                                 if (function_keyword_s2e.is_valid) | ||||||
|  |                                 { | ||||||
|  |                                     >function_keyword = function_keyword_s2e.enum_value; | ||||||
|  | 
 | ||||||
|  |                                     skip_space(module); | ||||||
|  | 
 | ||||||
|  |                                     switch (function_keyword) | ||||||
|  |                                     { | ||||||
|  |                                         .cc => { | ||||||
|  |                                             expect_character(module, left_parenthesis); | ||||||
|  | 
 | ||||||
|  |                                             skip_space(module); | ||||||
|  | 
 | ||||||
|  |                                             >calling_convention_string = parse_identifier(module); | ||||||
|  | 
 | ||||||
|  |                                             >calling_convention_s2e = #string_to_enum(CallingConvention, calling_convention_string); | ||||||
|  | 
 | ||||||
|  |                                             if (calling_convention_s2e.is_valid) | ||||||
|  |                                             { | ||||||
|  |                                                 calling_convention = calling_convention_s2e.enum_value; | ||||||
|  |                                                 skip_space(module); | ||||||
|  |                                                 expect_character(module, right_parenthesis); | ||||||
|  |                                             } | ||||||
|  |                                             else | ||||||
|  |                                             { | ||||||
|  |                                                 report_error(); | ||||||
|  |                                             } | ||||||
|  |                                         }, | ||||||
|  |                                     } | ||||||
|  | 
 | ||||||
|  |                                     skip_space(module); | ||||||
|  | 
 | ||||||
|  |                                     if (consume_character_if_match(module, right_bracket)) | ||||||
|  |                                     { | ||||||
|  |                                         break; | ||||||
|  |                                     } | ||||||
|  |                                     else | ||||||
|  |                                     { | ||||||
|  |                                         report_error(); | ||||||
|  |                                     } | ||||||
|  |                                 } | ||||||
|  |                                 else | ||||||
|  |                                 { | ||||||
|  |                                     report_error(); | ||||||
|  |                                 } | ||||||
|  |                             } | ||||||
|  |                         } | ||||||
|  | 
 | ||||||
|  |                         skip_space(module); | ||||||
|  | 
 | ||||||
|  |                         expect_character(module, left_parenthesis); | ||||||
|  | 
 | ||||||
|  |                         >semantic_argument_type_buffer: [64]&Type = undefined; | ||||||
|  |                         >semantic_argument_name_buffer: [64][]u8 = undefined; | ||||||
|  |                         >semantic_argument_count: u64 = 0; | ||||||
|  | 
 | ||||||
|  |                         while (module.offset < module.content.length) | ||||||
|  |                         { | ||||||
|  |                             skip_space(module); | ||||||
|  | 
 | ||||||
|  |                             if (consume_character_if_match(module, '.')) | ||||||
|  |                             { | ||||||
|  |                                 expect_character(module, '.'); | ||||||
|  |                                 expect_character(module, '.'); | ||||||
|  |                                 skip_space(module); | ||||||
|  |                                 expect_character(module, right_parenthesis); | ||||||
|  |                                 is_variable_arguments = 1; | ||||||
|  |                                 break; | ||||||
|  |                             } | ||||||
|  | 
 | ||||||
|  |                             if (consume_character_if_match(module, right_parenthesis)) | ||||||
|  |                             { | ||||||
|  |                                 break; | ||||||
|  |                             } | ||||||
|  | 
 | ||||||
|  |                             >argument_name = parse_identifier(module); | ||||||
|  |                             semantic_argument_name_buffer[semantic_argument_count] = argument_name; | ||||||
|  | 
 | ||||||
|  |                             skip_space(module); | ||||||
|  | 
 | ||||||
|  |                             expect_character(module, ':'); | ||||||
|  | 
 | ||||||
|  |                             skip_space(module); | ||||||
|  | 
 | ||||||
|  |                             >argument_type = parse_type(module); | ||||||
|  |                             semantic_argument_type_buffer[semantic_argument_count] = argument_type; | ||||||
|  | 
 | ||||||
|  |                             skip_space(module); | ||||||
|  | 
 | ||||||
|  |                             if (consume_character_if_match(module, ',')) | ||||||
|  |                             { | ||||||
|  |                                 skip_space(module); | ||||||
|  |                             } | ||||||
|  | 
 | ||||||
|  |                             semantic_argument_count += 1; | ||||||
|  |                         } | ||||||
|  | 
 | ||||||
|  |                         skip_space(module); | ||||||
|  | 
 | ||||||
|  |                         >return_type = parse_type(module); | ||||||
|  |                         >argument_types: []&Type = zero; | ||||||
|  |                         if (semantic_argument_count != 0) | ||||||
|  |                         { | ||||||
|  |                             argument_types.pointer = arena_allocate[&Type](module.arena, semantic_argument_count); | ||||||
|  |                             argument_types.length = semantic_argument_count; | ||||||
|  |                             memcpy(#pointer_cast(argument_types.pointer), #pointer_cast(&semantic_argument_type_buffer), semantic_argument_count * #byte_size(&Type)); | ||||||
|  |                         } | ||||||
|  | 
 | ||||||
|  |                         skip_space(module); | ||||||
|  | 
 | ||||||
|  |                         >is_declaration = consume_character_if_match(module, ';'); | ||||||
|  | 
 | ||||||
|  |                         >function_type = arena_allocate[Type](module.arena, 1); | ||||||
|  |                         function_type.& = zero; | ||||||
|  | 
 | ||||||
|  |                         #trap(); | ||||||
|  |                     }, | ||||||
|  |                     .macro => { | ||||||
|  |                         #trap(); | ||||||
|  |                     }, | ||||||
|  |                     .struct => { | ||||||
|  |                         #trap(); | ||||||
|  |                     }, | ||||||
|  |                     .typealias => { | ||||||
|  |                         #trap(); | ||||||
|  |                     }, | ||||||
|  |                     .union => { | ||||||
|  |                         #trap(); | ||||||
|  |                     }, | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |             else | ||||||
|  |             { | ||||||
|  |                 set_checkpoint(module, checkpoint); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         if (!has_global_keyword) | ||||||
|  |         { | ||||||
|  |             >v = parse_value(module, &module.scope, zero); | ||||||
|  |             skip_space(module); | ||||||
|  |             expect_character(module, ';'); | ||||||
|  | 
 | ||||||
|  |             #trap(); | ||||||
|  |         } | ||||||
|  |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| emit = fn (module: &Module) void | emit = fn (module: &Module) void | ||||||
|  | |||||||
| @ -332,4 +332,5 @@ const names = &[_][]const u8{ | |||||||
|     "generic_pointer_macro", |     "generic_pointer_macro", | ||||||
|     "break_continue", |     "break_continue", | ||||||
|     "noreturn_macro", |     "noreturn_macro", | ||||||
|  |     "self_referential_struct", | ||||||
| }; | }; | ||||||
|  | |||||||
							
								
								
									
										11
									
								
								tests/self_referential_struct.bbb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								tests/self_referential_struct.bbb
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,11 @@ | |||||||
|  | S = struct | ||||||
|  | { | ||||||
|  |     self: &S, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | [export] main = fn [cc(c)] () s32 | ||||||
|  | { | ||||||
|  |     >s: S = zero; | ||||||
|  |     s.self = &s; | ||||||
|  |     return 0; | ||||||
|  | } | ||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user