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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (module.has_debug_info) {
|
fn resolve_debug(ty: *Type, module: *Module) void {
|
||||||
|
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,32 +5235,44 @@ pub const Module = struct {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
assert(argument_abi.abi_count == 1);
|
assert(argument_abi.abi_count == 1);
|
||||||
// TODO: handmade change
|
|
||||||
if (src.type.?.bb != .pointer) {
|
|
||||||
assert(src.kind == .right);
|
|
||||||
assert(src.type.?.bb == .structure);
|
|
||||||
src.type = null;
|
|
||||||
src.kind = .left;
|
|
||||||
module.analyze_value_type(src, .{});
|
|
||||||
}
|
|
||||||
module.emit_value(src, .memory);
|
|
||||||
|
|
||||||
assert(src.type.?.bb == .pointer);
|
|
||||||
const source_type = src.type.?.bb.pointer.type;
|
|
||||||
assert(source_type == argument_abi.semantic_type);
|
|
||||||
const destination_type = argument_abi.get_coerce_to_type();
|
const destination_type = argument_abi.get_coerce_to_type();
|
||||||
const load = module.create_coerced_load(src.llvm.?, source_type, destination_type);
|
|
||||||
|
|
||||||
const is_cmse_ns_call = false;
|
const v = switch (src.bb) {
|
||||||
if (is_cmse_ns_call) {
|
.zero => destination_type.llvm.abi.?.get_zero().to_value(),
|
||||||
@trap();
|
else => b: {
|
||||||
}
|
// TODO: handmade change
|
||||||
const maybe_undef = false;
|
if (src.type.?.bb != .pointer) {
|
||||||
if (maybe_undef) {
|
assert(src.kind == .right);
|
||||||
@trap();
|
assert(src.type.?.bb == .structure);
|
||||||
}
|
const ty = src.type.?;
|
||||||
|
src.type = null;
|
||||||
|
src.kind = .left;
|
||||||
|
module.analyze_value_type(src, .{ .type = module.get_pointer_type(.{ .type = ty }) });
|
||||||
|
}
|
||||||
|
|
||||||
llvm_abi_argument_value_buffer[abi_argument_count] = load;
|
|
||||||
|
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;
|
||||||
|
assert(source_type == argument_abi.semantic_type);
|
||||||
|
const load = module.create_coerced_load(src.llvm.?, source_type, destination_type);
|
||||||
|
|
||||||
|
const is_cmse_ns_call = false;
|
||||||
|
if (is_cmse_ns_call) {
|
||||||
|
@trap();
|
||||||
|
}
|
||||||
|
const maybe_undef = false;
|
||||||
|
if (maybe_undef) {
|
||||||
|
@trap();
|
||||||
|
}
|
||||||
|
|
||||||
|
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