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,
|
||||
};
|
||||
|
||||
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 {
|
||||
bb: union(enum) {
|
||||
void,
|
||||
noreturn,
|
||||
integer: Type.Integer,
|
||||
enumerator,
|
||||
enumerator: Enumerator,
|
||||
float,
|
||||
bits,
|
||||
pointer: Type.Pointer,
|
||||
@ -233,6 +245,7 @@ pub const Type = struct {
|
||||
} else {
|
||||
const llvm_type = switch (ty.bb) {
|
||||
.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(),
|
||||
// Consider function types later since we need to deal with ABI
|
||||
.function => null,
|
||||
@ -249,6 +262,16 @@ pub const Type = struct {
|
||||
true => .signed,
|
||||
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: {
|
||||
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)];
|
||||
@ -390,6 +413,7 @@ pub const Type = struct {
|
||||
.pointer => 8,
|
||||
.function => 1,
|
||||
.array => |array| array.element_type.get_byte_alignment(),
|
||||
.enumerator => |enumerator| enumerator.backing_type.get_byte_alignment(),
|
||||
else => @trap(),
|
||||
};
|
||||
return result;
|
||||
@ -557,6 +581,7 @@ pub const Value = struct {
|
||||
infer_or_ignore,
|
||||
array_initialization: ArrayInitialization,
|
||||
array_expression: ArrayExpression,
|
||||
enum_literal: []const u8,
|
||||
},
|
||||
type: ?*Type = null,
|
||||
llvm: ?*llvm.Value = null,
|
||||
@ -578,7 +603,7 @@ pub const Value = struct {
|
||||
cast_to,
|
||||
extend: *Value,
|
||||
integer_max: *Type,
|
||||
int_from_enum,
|
||||
int_from_enum: *Value,
|
||||
int_from_pointer,
|
||||
pointer_cast: *Value,
|
||||
select,
|
||||
@ -1480,6 +1505,12 @@ pub const Module = struct {
|
||||
.precedence = .none,
|
||||
};
|
||||
count += 1;
|
||||
r[@intFromEnum(Token.Id.@".")] = .{
|
||||
.before = rule_before_dot,
|
||||
.after = rule_after_dot,
|
||||
.precedence = .postfix,
|
||||
};
|
||||
count += 1;
|
||||
|
||||
assert(count == r.len);
|
||||
break :blk r;
|
||||
@ -1667,17 +1698,19 @@ pub const Module = struct {
|
||||
'.' => blk: {
|
||||
const next_ch = module.content[start_index + 1];
|
||||
const token_id: Token.Id = switch (next_ch) {
|
||||
else => .@".",
|
||||
'&' => .@".&",
|
||||
else => @trap(),
|
||||
};
|
||||
|
||||
module.offset += switch (token_id) {
|
||||
.@"." => 1,
|
||||
.@".&" => 2,
|
||||
else => @trap(),
|
||||
};
|
||||
const token = switch (token_id) {
|
||||
else => unreachable,
|
||||
inline .@".&",
|
||||
.@".",
|
||||
=> |tid| @unionInit(Token, @tagName(tid), {}),
|
||||
};
|
||||
break :blk token;
|
||||
@ -2020,6 +2053,26 @@ pub const Module = struct {
|
||||
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 {
|
||||
const identifier = value_builder.token.identifier;
|
||||
assert(!lib.string.equal(identifier, ""));
|
||||
@ -2068,7 +2121,7 @@ pub const Module = struct {
|
||||
},
|
||||
.kind = if (variable.type) |t| switch (t.bb) {
|
||||
.array, .function => .left,
|
||||
.integer, .pointer => value_builder.kind,
|
||||
.integer, .pointer, .enumerator => value_builder.kind,
|
||||
else => @trap(),
|
||||
} 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: {
|
||||
module.skip_space();
|
||||
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 {
|
||||
_ = module;
|
||||
_ = 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 {
|
||||
@ -2589,6 +2658,86 @@ pub const Module = struct {
|
||||
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 {
|
||||
@ -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 {
|
||||
llvm.default_initialize();
|
||||
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));
|
||||
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: {
|
||||
if (value_to_truncate.llvm == null) {
|
||||
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.?);
|
||||
break :blk truncate;
|
||||
},
|
||||
.pointer_cast => |pointer_value| blk: {
|
||||
module.emit_value(function, pointer_value);
|
||||
break :blk pointer_value.llvm.?;
|
||||
},
|
||||
else => @trap(),
|
||||
},
|
||||
.dereference => |dereferenceable_value| blk: {
|
||||
@ -3772,7 +3970,7 @@ pub const Module = struct {
|
||||
const gep = module.llvm.builder.create_gep(.{
|
||||
.type = pointer.type.llvm.handle.?,
|
||||
.aggregate = array_expression.array_like.llvm.?,
|
||||
.indices = &.{ array_expression.index.llvm.? },
|
||||
.indices = &.{array_expression.index.llvm.?},
|
||||
});
|
||||
const v = switch (value.kind) {
|
||||
.left => gep,
|
||||
@ -3784,6 +3982,15 @@ pub const Module = struct {
|
||||
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(),
|
||||
};
|
||||
|
||||
@ -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(),
|
||||
};
|
||||
|
||||
@ -4048,6 +4268,15 @@ pub const Module = struct {
|
||||
}
|
||||
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(),
|
||||
},
|
||||
.dereference => |dereferenced_value| blk: {
|
||||
@ -4675,6 +4904,7 @@ const Token = union(Id) {
|
||||
@"]",
|
||||
|
||||
@",",
|
||||
@".",
|
||||
|
||||
const Id = enum {
|
||||
none,
|
||||
@ -4732,6 +4962,7 @@ const Token = union(Id) {
|
||||
@"]",
|
||||
|
||||
@",",
|
||||
@".",
|
||||
};
|
||||
|
||||
const Integer = struct {
|
||||
|
@ -204,6 +204,8 @@ const names = &[_][]const u8{
|
||||
"byte_size",
|
||||
"basic_branch",
|
||||
"basic_array",
|
||||
"basic_enum",
|
||||
"argv",
|
||||
"assignment_operators",
|
||||
"basic_enum",
|
||||
};
|
||||
|
Loading…
x
Reference in New Issue
Block a user