Basic enumerator
All checks were successful
All checks were successful
This commit is contained in:
parent
6c8cc69b6c
commit
104d9fde5c
@ -204,12 +204,24 @@ pub const ResolvedType = struct {
|
|||||||
debug: *llvm.DI.Type,
|
debug: *llvm.DI.Type,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub const Enumerator = struct {
|
||||||
|
fields: []const Enumerator.Field,
|
||||||
|
backing_type: *Type,
|
||||||
|
line: u32,
|
||||||
|
implicit_backing_type: bool,
|
||||||
|
|
||||||
|
pub const Field = struct {
|
||||||
|
name: []const u8,
|
||||||
|
value: u64,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
pub const Type = struct {
|
pub const Type = struct {
|
||||||
bb: union(enum) {
|
bb: union(enum) {
|
||||||
void,
|
void,
|
||||||
noreturn,
|
noreturn,
|
||||||
integer: Type.Integer,
|
integer: Type.Integer,
|
||||||
enumerator,
|
enumerator: Enumerator,
|
||||||
float,
|
float,
|
||||||
bits,
|
bits,
|
||||||
pointer: Type.Pointer,
|
pointer: Type.Pointer,
|
||||||
@ -233,6 +245,7 @@ pub const Type = struct {
|
|||||||
} else {
|
} else {
|
||||||
const llvm_type = switch (ty.bb) {
|
const llvm_type = switch (ty.bb) {
|
||||||
.void, .noreturn => module.llvm.void_type,
|
.void, .noreturn => module.llvm.void_type,
|
||||||
|
.enumerator => |enumerator| enumerator.backing_type.resolve(module).handle,
|
||||||
.integer => |integer| module.llvm.context.get_integer_type(integer.bit_count).to_type(),
|
.integer => |integer| module.llvm.context.get_integer_type(integer.bit_count).to_type(),
|
||||||
// Consider function types later since we need to deal with ABI
|
// Consider function types later since we need to deal with ABI
|
||||||
.function => null,
|
.function => null,
|
||||||
@ -249,6 +262,16 @@ pub const Type = struct {
|
|||||||
true => .signed,
|
true => .signed,
|
||||||
false => .unsigned,
|
false => .unsigned,
|
||||||
}, .{}),
|
}, .{}),
|
||||||
|
.enumerator => |enumerator| blk: {
|
||||||
|
var enumerator_buffer: [64]*llvm.DI.Enumerator = undefined;
|
||||||
|
const enumerators = enumerator_buffer[0..enumerator.fields.len];
|
||||||
|
for (enumerators, enumerator.fields) |*enumerator_pointer, *field| {
|
||||||
|
enumerator_pointer.* = module.llvm.di_builder.create_enumerator(field.name, @bitCast(field.value), false);
|
||||||
|
}
|
||||||
|
const alignment = 0; // TODO
|
||||||
|
const enumeration_type = module.llvm.di_builder.create_enumeration_type(module.scope.llvm.?, ty.name, module.llvm.file, enumerator.line, enumerator.backing_type.get_bit_size(), alignment, enumerators, enumerator.backing_type.llvm.debug.?);
|
||||||
|
break :blk enumeration_type.to_type();
|
||||||
|
},
|
||||||
.function => |function| b: {
|
.function => |function| b: {
|
||||||
var debug_argument_type_buffer: [64]*llvm.DI.Type = undefined;
|
var debug_argument_type_buffer: [64]*llvm.DI.Type = undefined;
|
||||||
const semantic_debug_argument_types = debug_argument_type_buffer[0 .. function.semantic_argument_types.len + 1 + @intFromBool(function.is_var_args)];
|
const semantic_debug_argument_types = debug_argument_type_buffer[0 .. function.semantic_argument_types.len + 1 + @intFromBool(function.is_var_args)];
|
||||||
@ -390,6 +413,7 @@ pub const Type = struct {
|
|||||||
.pointer => 8,
|
.pointer => 8,
|
||||||
.function => 1,
|
.function => 1,
|
||||||
.array => |array| array.element_type.get_byte_alignment(),
|
.array => |array| array.element_type.get_byte_alignment(),
|
||||||
|
.enumerator => |enumerator| enumerator.backing_type.get_byte_alignment(),
|
||||||
else => @trap(),
|
else => @trap(),
|
||||||
};
|
};
|
||||||
return result;
|
return result;
|
||||||
@ -557,6 +581,7 @@ pub const Value = struct {
|
|||||||
infer_or_ignore,
|
infer_or_ignore,
|
||||||
array_initialization: ArrayInitialization,
|
array_initialization: ArrayInitialization,
|
||||||
array_expression: ArrayExpression,
|
array_expression: ArrayExpression,
|
||||||
|
enum_literal: []const u8,
|
||||||
},
|
},
|
||||||
type: ?*Type = null,
|
type: ?*Type = null,
|
||||||
llvm: ?*llvm.Value = null,
|
llvm: ?*llvm.Value = null,
|
||||||
@ -578,7 +603,7 @@ pub const Value = struct {
|
|||||||
cast_to,
|
cast_to,
|
||||||
extend: *Value,
|
extend: *Value,
|
||||||
integer_max: *Type,
|
integer_max: *Type,
|
||||||
int_from_enum,
|
int_from_enum: *Value,
|
||||||
int_from_pointer,
|
int_from_pointer,
|
||||||
pointer_cast: *Value,
|
pointer_cast: *Value,
|
||||||
select,
|
select,
|
||||||
@ -1480,6 +1505,12 @@ pub const Module = struct {
|
|||||||
.precedence = .none,
|
.precedence = .none,
|
||||||
};
|
};
|
||||||
count += 1;
|
count += 1;
|
||||||
|
r[@intFromEnum(Token.Id.@".")] = .{
|
||||||
|
.before = rule_before_dot,
|
||||||
|
.after = rule_after_dot,
|
||||||
|
.precedence = .postfix,
|
||||||
|
};
|
||||||
|
count += 1;
|
||||||
|
|
||||||
assert(count == r.len);
|
assert(count == r.len);
|
||||||
break :blk r;
|
break :blk r;
|
||||||
@ -1667,17 +1698,19 @@ pub const Module = struct {
|
|||||||
'.' => blk: {
|
'.' => blk: {
|
||||||
const next_ch = module.content[start_index + 1];
|
const next_ch = module.content[start_index + 1];
|
||||||
const token_id: Token.Id = switch (next_ch) {
|
const token_id: Token.Id = switch (next_ch) {
|
||||||
|
else => .@".",
|
||||||
'&' => .@".&",
|
'&' => .@".&",
|
||||||
else => @trap(),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
module.offset += switch (token_id) {
|
module.offset += switch (token_id) {
|
||||||
|
.@"." => 1,
|
||||||
.@".&" => 2,
|
.@".&" => 2,
|
||||||
else => @trap(),
|
else => @trap(),
|
||||||
};
|
};
|
||||||
const token = switch (token_id) {
|
const token = switch (token_id) {
|
||||||
else => unreachable,
|
else => unreachable,
|
||||||
inline .@".&",
|
inline .@".&",
|
||||||
|
.@".",
|
||||||
=> |tid| @unionInit(Token, @tagName(tid), {}),
|
=> |tid| @unionInit(Token, @tagName(tid), {}),
|
||||||
};
|
};
|
||||||
break :blk token;
|
break :blk token;
|
||||||
@ -2020,6 +2053,26 @@ pub const Module = struct {
|
|||||||
return block;
|
return block;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn rule_before_dot(noalias module: *Module, value_builder: Value.Builder) *Value {
|
||||||
|
_ = value_builder;
|
||||||
|
module.skip_space();
|
||||||
|
const identifier = module.parse_identifier();
|
||||||
|
|
||||||
|
const value = module.values.add();
|
||||||
|
value.* = .{
|
||||||
|
.bb = .{
|
||||||
|
.enum_literal = identifier,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn rule_after_dot(noalias module: *Module, value_builder: Value.Builder) *Value {
|
||||||
|
_ = module;
|
||||||
|
_ = value_builder;
|
||||||
|
@trap();
|
||||||
|
}
|
||||||
|
|
||||||
fn rule_before_identifier(noalias module: *Module, value_builder: Value.Builder) *Value {
|
fn rule_before_identifier(noalias module: *Module, value_builder: Value.Builder) *Value {
|
||||||
const identifier = value_builder.token.identifier;
|
const identifier = value_builder.token.identifier;
|
||||||
assert(!lib.string.equal(identifier, ""));
|
assert(!lib.string.equal(identifier, ""));
|
||||||
@ -2068,7 +2121,7 @@ pub const Module = struct {
|
|||||||
},
|
},
|
||||||
.kind = if (variable.type) |t| switch (t.bb) {
|
.kind = if (variable.type) |t| switch (t.bb) {
|
||||||
.array, .function => .left,
|
.array, .function => .left,
|
||||||
.integer, .pointer => value_builder.kind,
|
.integer, .pointer, .enumerator => value_builder.kind,
|
||||||
else => @trap(),
|
else => @trap(),
|
||||||
} else value_builder.kind,
|
} else value_builder.kind,
|
||||||
// if (variable.type != null and variable.type.?.bb == .function) .left else value_builder.kind,
|
// if (variable.type != null and variable.type.?.bb == .function) .left else value_builder.kind,
|
||||||
@ -2128,6 +2181,20 @@ pub const Module = struct {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
.int_from_enum => blk: {
|
||||||
|
module.skip_space();
|
||||||
|
module.expect_character(left_parenthesis);
|
||||||
|
module.skip_space();
|
||||||
|
const arg_value = module.parse_value(.{});
|
||||||
|
module.expect_character(right_parenthesis);
|
||||||
|
break :blk .{
|
||||||
|
.bb = .{
|
||||||
|
.intrinsic = .{
|
||||||
|
.int_from_enum = arg_value,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
},
|
||||||
.pointer_cast => blk: {
|
.pointer_cast => blk: {
|
||||||
module.skip_space();
|
module.skip_space();
|
||||||
module.expect_character(left_parenthesis);
|
module.expect_character(left_parenthesis);
|
||||||
@ -2303,9 +2370,11 @@ pub const Module = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn rule_before_parenthesis(noalias module: *Module, value_builder: Value.Builder) *Value {
|
fn rule_before_parenthesis(noalias module: *Module, value_builder: Value.Builder) *Value {
|
||||||
_ = module;
|
|
||||||
_ = value_builder;
|
_ = value_builder;
|
||||||
@trap();
|
module.skip_space();
|
||||||
|
const v = module.parse_value(.{});
|
||||||
|
module.expect_character(right_parenthesis);
|
||||||
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn rule_after_call(noalias module: *Module, value_builder: Value.Builder) *Value {
|
fn rule_after_call(noalias module: *Module, value_builder: Value.Builder) *Value {
|
||||||
@ -2589,6 +2658,86 @@ pub const Module = struct {
|
|||||||
storage.bb = .external_function;
|
storage.bb = .external_function;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
.@"enum" => {
|
||||||
|
const is_implicit_type = module.content[module.offset] == left_brace;
|
||||||
|
const maybe_backing_type: ?*Type = switch (is_implicit_type) {
|
||||||
|
true => null,
|
||||||
|
false => module.parse_type(),
|
||||||
|
};
|
||||||
|
|
||||||
|
module.skip_space();
|
||||||
|
|
||||||
|
module.expect_character(left_brace);
|
||||||
|
|
||||||
|
var highest_value: u64 = 0;
|
||||||
|
var lowest_value = ~@as(u64, 0);
|
||||||
|
|
||||||
|
var field_buffer: [64]Enumerator.Field = undefined;
|
||||||
|
var field_count: u64 = 0;
|
||||||
|
|
||||||
|
while (true) : (field_count += 1) {
|
||||||
|
module.skip_space();
|
||||||
|
|
||||||
|
if (module.consume_character_if_match(right_brace)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
const field_index = field_count;
|
||||||
|
const field_name = module.parse_identifier();
|
||||||
|
module.skip_space();
|
||||||
|
|
||||||
|
const field_value = if (module.consume_character_if_match('=')) blk: {
|
||||||
|
module.skip_space();
|
||||||
|
const field_value = module.parse_integer_value(false);
|
||||||
|
break :blk field_value;
|
||||||
|
} else {
|
||||||
|
@trap();
|
||||||
|
};
|
||||||
|
|
||||||
|
field_buffer[field_index] = .{
|
||||||
|
.name = field_name,
|
||||||
|
.value = field_value,
|
||||||
|
};
|
||||||
|
|
||||||
|
highest_value = @max(highest_value, field_value);
|
||||||
|
lowest_value = @min(lowest_value, field_value);
|
||||||
|
|
||||||
|
module.skip_space();
|
||||||
|
module.expect_character(',');
|
||||||
|
}
|
||||||
|
|
||||||
|
module.skip_space();
|
||||||
|
|
||||||
|
_ = module.consume_character_if_match(';');
|
||||||
|
|
||||||
|
const backing_type = maybe_backing_type orelse blk: {
|
||||||
|
const bits_needed = 64 - @clz(highest_value);
|
||||||
|
const int_type = module.integer_type(bits_needed, false);
|
||||||
|
break :blk int_type;
|
||||||
|
};
|
||||||
|
|
||||||
|
if (maybe_backing_type) |bt| {
|
||||||
|
const bits_needed = 64 - @clz(highest_value);
|
||||||
|
if (bits_needed > bt.get_bit_size()) {
|
||||||
|
module.report_error();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const fields = module.arena.allocate(Enumerator.Field, field_count);
|
||||||
|
@memcpy(fields, field_buffer[0..field_count]);
|
||||||
|
|
||||||
|
_ = module.types.append(.{
|
||||||
|
.bb = .{
|
||||||
|
.enumerator = .{
|
||||||
|
.backing_type = backing_type,
|
||||||
|
.fields = fields,
|
||||||
|
.implicit_backing_type = is_implicit_type,
|
||||||
|
.line = global_line,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
.name = global_name,
|
||||||
|
});
|
||||||
|
},
|
||||||
else => @trap(),
|
else => @trap(),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -2622,6 +2771,51 @@ pub const Module = struct {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn parse_integer_value(module: *Module, sign: bool) u64 {
|
||||||
|
const start = module.offset;
|
||||||
|
const integer_start_ch = module.content[start];
|
||||||
|
assert(!is_space(integer_start_ch));
|
||||||
|
assert(is_decimal_ch(integer_start_ch));
|
||||||
|
|
||||||
|
const absolute_value: u64 = switch (integer_start_ch) {
|
||||||
|
'0' => blk: {
|
||||||
|
module.offset += 1;
|
||||||
|
|
||||||
|
const next_ch = module.content[module.offset];
|
||||||
|
break :blk switch (sign) {
|
||||||
|
false => switch (next_ch) {
|
||||||
|
'x' => b: {
|
||||||
|
module.offset += 1;
|
||||||
|
break :b module.parse_hexadecimal();
|
||||||
|
},
|
||||||
|
'o' => {
|
||||||
|
// TODO: parse octal
|
||||||
|
module.report_error();
|
||||||
|
},
|
||||||
|
'b' => {
|
||||||
|
// TODO: parse binary
|
||||||
|
module.report_error();
|
||||||
|
},
|
||||||
|
'0'...'9' => {
|
||||||
|
module.report_error();
|
||||||
|
},
|
||||||
|
// Zero literal
|
||||||
|
else => 0,
|
||||||
|
},
|
||||||
|
true => switch (next_ch) {
|
||||||
|
'x', 'o', 'b', '0' => module.report_error(),
|
||||||
|
'1'...'9' => module.parse_decimal(),
|
||||||
|
else => unreachable,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
'1'...'9' => module.parse_decimal(),
|
||||||
|
else => unreachable,
|
||||||
|
};
|
||||||
|
|
||||||
|
return absolute_value;
|
||||||
|
}
|
||||||
|
|
||||||
fn initialize_llvm(module: *Module) void {
|
fn initialize_llvm(module: *Module) void {
|
||||||
llvm.default_initialize();
|
llvm.default_initialize();
|
||||||
const context = llvm.Context.create();
|
const context = llvm.Context.create();
|
||||||
@ -3328,6 +3522,14 @@ pub const Module = struct {
|
|||||||
const constant_integer = max_type.resolve(module).handle.to_integer().get_constant(max_value, @intFromBool(false));
|
const constant_integer = max_type.resolve(module).handle.to_integer().get_constant(max_value, @intFromBool(false));
|
||||||
break :blk constant_integer.to_value();
|
break :blk constant_integer.to_value();
|
||||||
},
|
},
|
||||||
|
.int_from_enum => |enum_value| blk: {
|
||||||
|
module.emit_value(function, enum_value);
|
||||||
|
break :blk enum_value.llvm.?;
|
||||||
|
},
|
||||||
|
.pointer_cast => |pointer_value| blk: {
|
||||||
|
module.emit_value(function, pointer_value);
|
||||||
|
break :blk pointer_value.llvm.?;
|
||||||
|
},
|
||||||
.truncate => |value_to_truncate| blk: {
|
.truncate => |value_to_truncate| blk: {
|
||||||
if (value_to_truncate.llvm == null) {
|
if (value_to_truncate.llvm == null) {
|
||||||
module.emit_value(function, value_to_truncate);
|
module.emit_value(function, value_to_truncate);
|
||||||
@ -3336,10 +3538,6 @@ pub const Module = struct {
|
|||||||
const truncate = module.llvm.builder.create_truncate(llvm_value, value_type.llvm.handle.?);
|
const truncate = module.llvm.builder.create_truncate(llvm_value, value_type.llvm.handle.?);
|
||||||
break :blk truncate;
|
break :blk truncate;
|
||||||
},
|
},
|
||||||
.pointer_cast => |pointer_value| blk: {
|
|
||||||
module.emit_value(function, pointer_value);
|
|
||||||
break :blk pointer_value.llvm.?;
|
|
||||||
},
|
|
||||||
else => @trap(),
|
else => @trap(),
|
||||||
},
|
},
|
||||||
.dereference => |dereferenceable_value| blk: {
|
.dereference => |dereferenceable_value| blk: {
|
||||||
@ -3784,6 +3982,15 @@ pub const Module = struct {
|
|||||||
else => @trap(),
|
else => @trap(),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
.enum_literal => |enum_literal_name| blk: {
|
||||||
|
const enum_int_value = for (value_type.bb.enumerator.fields) |*field| {
|
||||||
|
if (lib.string.equal(enum_literal_name, field.name)) {
|
||||||
|
break field.value;
|
||||||
|
}
|
||||||
|
} else module.report_error();
|
||||||
|
const llvm_value = value_type.llvm.handle.?.to_integer().get_constant(enum_int_value, @intFromBool(false));
|
||||||
|
break :blk llvm_value.to_value();
|
||||||
|
},
|
||||||
else => @trap(),
|
else => @trap(),
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -4000,6 +4207,19 @@ pub const Module = struct {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
.enum_literal => |enum_literal| {
|
||||||
|
_ = enum_literal;
|
||||||
|
if (expected_type.bb != .enumerator) {
|
||||||
|
module.report_error();
|
||||||
|
}
|
||||||
|
// const field = for (expected_type.bb.enumerator.fields) |*field| {
|
||||||
|
// if (lib.string.equal(field.name, enum_literal)) {
|
||||||
|
// break field;
|
||||||
|
// }
|
||||||
|
// } else {
|
||||||
|
// module.report_error();
|
||||||
|
// };
|
||||||
|
},
|
||||||
else => @trap(),
|
else => @trap(),
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -4048,6 +4268,15 @@ pub const Module = struct {
|
|||||||
}
|
}
|
||||||
break :blk integer_max_type;
|
break :blk integer_max_type;
|
||||||
},
|
},
|
||||||
|
.int_from_enum => |enum_value| blk: {
|
||||||
|
module.analyze_value_type(function, enum_value, .{});
|
||||||
|
if (enum_value.type.?.bb != .enumerator) {
|
||||||
|
module.report_error();
|
||||||
|
}
|
||||||
|
|
||||||
|
const enum_backing_type = enum_value.type.?.bb.enumerator.backing_type;
|
||||||
|
break :blk enum_backing_type;
|
||||||
|
},
|
||||||
else => @trap(),
|
else => @trap(),
|
||||||
},
|
},
|
||||||
.dereference => |dereferenced_value| blk: {
|
.dereference => |dereferenced_value| blk: {
|
||||||
@ -4675,6 +4904,7 @@ const Token = union(Id) {
|
|||||||
@"]",
|
@"]",
|
||||||
|
|
||||||
@",",
|
@",",
|
||||||
|
@".",
|
||||||
|
|
||||||
const Id = enum {
|
const Id = enum {
|
||||||
none,
|
none,
|
||||||
@ -4732,6 +4962,7 @@ const Token = union(Id) {
|
|||||||
@"]",
|
@"]",
|
||||||
|
|
||||||
@",",
|
@",",
|
||||||
|
@".",
|
||||||
};
|
};
|
||||||
|
|
||||||
const Integer = struct {
|
const Integer = struct {
|
||||||
|
@ -204,6 +204,8 @@ const names = &[_][]const u8{
|
|||||||
"byte_size",
|
"byte_size",
|
||||||
"basic_branch",
|
"basic_branch",
|
||||||
"basic_array",
|
"basic_array",
|
||||||
|
"basic_enum",
|
||||||
"argv",
|
"argv",
|
||||||
"assignment_operators",
|
"assignment_operators",
|
||||||
|
"basic_enum",
|
||||||
};
|
};
|
||||||
|
Loading…
x
Reference in New Issue
Block a user