AstGen: implement simple enums and decls for enums
This commit is contained in:
125
src/AstGen.zig
125
src/AstGen.zig
@@ -2438,12 +2438,11 @@ fn structDeclInner(
|
||||
|
||||
const decl_inst = try gz.addBlock(tag, node);
|
||||
try gz.instructions.append(gpa, decl_inst);
|
||||
if (field_index != 0) {
|
||||
if (block_scope.instructions.items.len != 0) {
|
||||
_ = try block_scope.addBreak(.break_inline, decl_inst, .void_value);
|
||||
}
|
||||
|
||||
try astgen.extra.ensureCapacity(gpa, astgen.extra.items.len +
|
||||
@typeInfo(Zir.Inst.StructDecl).Struct.fields.len +
|
||||
try astgen.extra.ensureUnusedCapacity(gpa, @typeInfo(Zir.Inst.StructDecl).Struct.fields.len +
|
||||
bit_bag.items.len + @boolToInt(field_index != 0) + fields_data.items.len +
|
||||
block_scope.instructions.items.len +
|
||||
wip_decls.bit_bag.items.len + @boolToInt(wip_decls.decl_index != 0) +
|
||||
@@ -2483,6 +2482,7 @@ fn containerDecl(
|
||||
const tree = &astgen.file.tree;
|
||||
const token_tags = tree.tokens.items(.tag);
|
||||
const node_tags = tree.nodes.items(.tag);
|
||||
const node_datas = tree.nodes.items(.data);
|
||||
|
||||
// We must not create any types until Sema. Here the goal is only to generate
|
||||
// ZIR for all the field types, alignments, and default value expressions.
|
||||
@@ -2594,22 +2594,12 @@ fn containerDecl(
|
||||
},
|
||||
);
|
||||
}
|
||||
if (counts.values == 0 and counts.decls == 0 and arg_inst == .none) {
|
||||
return astgen.failNode(node, "TODO AstGen simple enums", .{});
|
||||
}
|
||||
// In this case we must generate ZIR code for the tag values, similar to
|
||||
// how structs are handled above.
|
||||
const tag: Zir.Inst.Tag = if (counts.nonexhaustive_node == 0)
|
||||
.enum_decl
|
||||
else
|
||||
.enum_decl_nonexhaustive;
|
||||
if (counts.total_fields == 0) {
|
||||
return gz.addPlNode(tag, node, Zir.Inst.EnumDecl{
|
||||
.tag_type = arg_inst,
|
||||
.fields_len = 0,
|
||||
.body_len = 0,
|
||||
});
|
||||
}
|
||||
|
||||
// The enum_decl instruction introduces a scope in which the decls of the enum
|
||||
// are in scope, so that tag values can refer to decls within the enum itself.
|
||||
@@ -2621,6 +2611,9 @@ fn containerDecl(
|
||||
};
|
||||
defer block_scope.instructions.deinit(gpa);
|
||||
|
||||
var wip_decls: WipDecls = .{};
|
||||
defer wip_decls.deinit(gpa);
|
||||
|
||||
var fields_data = ArrayListUnmanaged(u32){};
|
||||
defer fields_data.deinit(gpa);
|
||||
|
||||
@@ -2639,7 +2632,81 @@ fn containerDecl(
|
||||
.container_field_init => tree.containerFieldInit(member_node),
|
||||
.container_field_align => tree.containerFieldAlign(member_node),
|
||||
.container_field => tree.containerField(member_node),
|
||||
else => continue,
|
||||
|
||||
.fn_decl => {
|
||||
const fn_proto = node_datas[member_node].lhs;
|
||||
const body = node_datas[member_node].rhs;
|
||||
switch (node_tags[fn_proto]) {
|
||||
.fn_proto_simple => {
|
||||
var params: [1]ast.Node.Index = undefined;
|
||||
try astgen.fnDecl(gz, &wip_decls, body, tree.fnProtoSimple(¶ms, fn_proto));
|
||||
continue;
|
||||
},
|
||||
.fn_proto_multi => {
|
||||
try astgen.fnDecl(gz, &wip_decls, body, tree.fnProtoMulti(fn_proto));
|
||||
continue;
|
||||
},
|
||||
.fn_proto_one => {
|
||||
var params: [1]ast.Node.Index = undefined;
|
||||
try astgen.fnDecl(gz, &wip_decls, body, tree.fnProtoOne(¶ms, fn_proto));
|
||||
continue;
|
||||
},
|
||||
.fn_proto => {
|
||||
try astgen.fnDecl(gz, &wip_decls, body, tree.fnProto(fn_proto));
|
||||
continue;
|
||||
},
|
||||
else => unreachable,
|
||||
}
|
||||
},
|
||||
.fn_proto_simple => {
|
||||
var params: [1]ast.Node.Index = undefined;
|
||||
try astgen.fnDecl(gz, &wip_decls, 0, tree.fnProtoSimple(¶ms, member_node));
|
||||
continue;
|
||||
},
|
||||
.fn_proto_multi => {
|
||||
try astgen.fnDecl(gz, &wip_decls, 0, tree.fnProtoMulti(member_node));
|
||||
continue;
|
||||
},
|
||||
.fn_proto_one => {
|
||||
var params: [1]ast.Node.Index = undefined;
|
||||
try astgen.fnDecl(gz, &wip_decls, 0, tree.fnProtoOne(¶ms, member_node));
|
||||
continue;
|
||||
},
|
||||
.fn_proto => {
|
||||
try astgen.fnDecl(gz, &wip_decls, 0, tree.fnProto(member_node));
|
||||
continue;
|
||||
},
|
||||
|
||||
.global_var_decl => {
|
||||
try astgen.globalVarDecl(gz, scope, &wip_decls, member_node, tree.globalVarDecl(member_node));
|
||||
continue;
|
||||
},
|
||||
.local_var_decl => {
|
||||
try astgen.globalVarDecl(gz, scope, &wip_decls, member_node, tree.localVarDecl(member_node));
|
||||
continue;
|
||||
},
|
||||
.simple_var_decl => {
|
||||
try astgen.globalVarDecl(gz, scope, &wip_decls, member_node, tree.simpleVarDecl(member_node));
|
||||
continue;
|
||||
},
|
||||
.aligned_var_decl => {
|
||||
try astgen.globalVarDecl(gz, scope, &wip_decls, member_node, tree.alignedVarDecl(member_node));
|
||||
continue;
|
||||
},
|
||||
|
||||
.@"comptime" => {
|
||||
try astgen.comptimeDecl(gz, scope, member_node);
|
||||
continue;
|
||||
},
|
||||
.@"usingnamespace" => {
|
||||
try astgen.usingnamespaceDecl(gz, scope, member_node);
|
||||
continue;
|
||||
},
|
||||
.test_decl => {
|
||||
try astgen.testDecl(gz, scope, member_node);
|
||||
continue;
|
||||
},
|
||||
else => unreachable,
|
||||
};
|
||||
if (field_index % 32 == 0 and field_index != 0) {
|
||||
try bit_bag.append(gpa, cur_bit_bag);
|
||||
@@ -2663,27 +2730,45 @@ fn containerDecl(
|
||||
|
||||
field_index += 1;
|
||||
}
|
||||
const empty_slot_count = 32 - (field_index % 32);
|
||||
cur_bit_bag >>= @intCast(u5, empty_slot_count);
|
||||
{
|
||||
const empty_slot_count = 32 - (field_index % 32);
|
||||
cur_bit_bag >>= @intCast(u5, empty_slot_count);
|
||||
}
|
||||
|
||||
if (wip_decls.decl_index != 0) {
|
||||
const empty_slot_count = 16 - (wip_decls.decl_index % 16);
|
||||
wip_decls.cur_bit_bag >>= @intCast(u5, empty_slot_count * 2);
|
||||
}
|
||||
|
||||
const decl_inst = try gz.addBlock(tag, node);
|
||||
try gz.instructions.append(gpa, decl_inst);
|
||||
_ = try block_scope.addBreak(.break_inline, decl_inst, .void_value);
|
||||
if (block_scope.instructions.items.len != 0) {
|
||||
_ = try block_scope.addBreak(.break_inline, decl_inst, .void_value);
|
||||
}
|
||||
|
||||
try astgen.extra.ensureCapacity(gpa, astgen.extra.items.len +
|
||||
@typeInfo(Zir.Inst.EnumDecl).Struct.fields.len +
|
||||
try astgen.extra.ensureUnusedCapacity(gpa, @typeInfo(Zir.Inst.EnumDecl).Struct.fields.len +
|
||||
bit_bag.items.len + 1 + fields_data.items.len +
|
||||
block_scope.instructions.items.len);
|
||||
block_scope.instructions.items.len +
|
||||
wip_decls.bit_bag.items.len + @boolToInt(wip_decls.decl_index != 0) +
|
||||
wip_decls.name_and_value.items.len);
|
||||
const zir_datas = astgen.instructions.items(.data);
|
||||
zir_datas[decl_inst].pl_node.payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.EnumDecl{
|
||||
.tag_type = arg_inst,
|
||||
.body_len = @intCast(u32, block_scope.instructions.items.len),
|
||||
.fields_len = @intCast(u32, field_index),
|
||||
.decls_len = @intCast(u32, wip_decls.decl_index),
|
||||
});
|
||||
astgen.extra.appendSliceAssumeCapacity(block_scope.instructions.items);
|
||||
astgen.extra.appendSliceAssumeCapacity(bit_bag.items); // Likely empty.
|
||||
astgen.extra.appendAssumeCapacity(cur_bit_bag);
|
||||
astgen.extra.appendSliceAssumeCapacity(fields_data.items);
|
||||
|
||||
astgen.extra.appendSliceAssumeCapacity(wip_decls.bit_bag.items); // Likely empty.
|
||||
if (wip_decls.decl_index != 0) {
|
||||
astgen.extra.appendAssumeCapacity(wip_decls.cur_bit_bag);
|
||||
}
|
||||
astgen.extra.appendSliceAssumeCapacity(wip_decls.name_and_value.items);
|
||||
|
||||
return rvalue(gz, scope, rl, gz.indexToRef(decl_inst), node);
|
||||
},
|
||||
.keyword_opaque => {
|
||||
|
||||
98
src/Zir.zig
98
src/Zir.zig
@@ -1591,11 +1591,20 @@ pub const Inst = struct {
|
||||
/// field_name: u32,
|
||||
/// value: Ref, // if corresponding bit is set
|
||||
/// }
|
||||
/// 3. decl_bits: u32 // for every 16 decls
|
||||
/// - sets of 2 bits:
|
||||
/// 0b0X: whether corresponding decl is pub
|
||||
/// 0bX0: whether corresponding decl is exported
|
||||
/// 4. decl: { // for every decls_len
|
||||
/// name: u32, // null terminated string index
|
||||
/// value: Index,
|
||||
/// }
|
||||
pub const EnumDecl = struct {
|
||||
/// Can be `Ref.none`.
|
||||
tag_type: Ref,
|
||||
body_len: u32,
|
||||
fields_len: u32,
|
||||
decls_len: u32,
|
||||
};
|
||||
|
||||
/// Trailing:
|
||||
@@ -2231,6 +2240,7 @@ const Writer = struct {
|
||||
const extra = self.code.extraData(Inst.EnumDecl, inst_data.payload_index);
|
||||
const body = self.code.extra[extra.end..][0..extra.data.body_len];
|
||||
const fields_len = extra.data.fields_len;
|
||||
const decls_len = extra.data.decls_len;
|
||||
const tag_ty_ref = extra.data.tag_type;
|
||||
|
||||
if (tag_ty_ref != .none) {
|
||||
@@ -2238,53 +2248,63 @@ const Writer = struct {
|
||||
try stream.writeAll(", ");
|
||||
}
|
||||
|
||||
var extra_index: usize = undefined;
|
||||
|
||||
if (fields_len == 0) {
|
||||
assert(body.len == 0);
|
||||
try stream.writeAll("{}, {}) ");
|
||||
try self.writeSrc(stream, inst_data.src());
|
||||
return;
|
||||
}
|
||||
try stream.writeAll("{}, {}, {");
|
||||
extra_index = extra.end;
|
||||
} else {
|
||||
try stream.writeAll("{\n");
|
||||
self.indent += 2;
|
||||
try self.writeBody(stream, body);
|
||||
|
||||
try stream.writeAll("{\n");
|
||||
self.indent += 2;
|
||||
try self.writeBody(stream, body);
|
||||
try stream.writeByteNTimes(' ', self.indent - 2);
|
||||
try stream.writeAll("}, {\n");
|
||||
|
||||
try stream.writeByteNTimes(' ', self.indent - 2);
|
||||
try stream.writeAll("}, {\n");
|
||||
const bit_bags_count = std.math.divCeil(usize, fields_len, 32) catch unreachable;
|
||||
const body_end = extra.end + body.len;
|
||||
extra_index = body_end + bit_bags_count;
|
||||
var bit_bag_index: usize = body_end;
|
||||
var cur_bit_bag: u32 = undefined;
|
||||
var field_i: u32 = 0;
|
||||
while (field_i < fields_len) : (field_i += 1) {
|
||||
if (field_i % 32 == 0) {
|
||||
cur_bit_bag = self.code.extra[bit_bag_index];
|
||||
bit_bag_index += 1;
|
||||
}
|
||||
const has_tag_value = @truncate(u1, cur_bit_bag) != 0;
|
||||
cur_bit_bag >>= 1;
|
||||
|
||||
const bit_bags_count = std.math.divCeil(usize, fields_len, 32) catch unreachable;
|
||||
const body_end = extra.end + body.len;
|
||||
var extra_index: usize = body_end + bit_bags_count;
|
||||
var bit_bag_index: usize = body_end;
|
||||
var cur_bit_bag: u32 = undefined;
|
||||
var field_i: u32 = 0;
|
||||
while (field_i < fields_len) : (field_i += 1) {
|
||||
if (field_i % 32 == 0) {
|
||||
cur_bit_bag = self.code.extra[bit_bag_index];
|
||||
bit_bag_index += 1;
|
||||
}
|
||||
const has_tag_value = @truncate(u1, cur_bit_bag) != 0;
|
||||
cur_bit_bag >>= 1;
|
||||
|
||||
const field_name = self.code.nullTerminatedString(self.code.extra[extra_index]);
|
||||
extra_index += 1;
|
||||
|
||||
try stream.writeByteNTimes(' ', self.indent);
|
||||
try stream.print("{}", .{std.zig.fmtId(field_name)});
|
||||
|
||||
if (has_tag_value) {
|
||||
const tag_value_ref = @intToEnum(Inst.Ref, self.code.extra[extra_index]);
|
||||
const field_name = self.code.nullTerminatedString(self.code.extra[extra_index]);
|
||||
extra_index += 1;
|
||||
|
||||
try stream.writeAll(" = ");
|
||||
try self.writeInstRef(stream, tag_value_ref);
|
||||
}
|
||||
try stream.writeAll(",\n");
|
||||
}
|
||||
try stream.writeByteNTimes(' ', self.indent);
|
||||
try stream.print("{}", .{std.zig.fmtId(field_name)});
|
||||
|
||||
self.indent -= 2;
|
||||
try stream.writeByteNTimes(' ', self.indent);
|
||||
try stream.writeAll("}) ");
|
||||
if (has_tag_value) {
|
||||
const tag_value_ref = @intToEnum(Inst.Ref, self.code.extra[extra_index]);
|
||||
extra_index += 1;
|
||||
|
||||
try stream.writeAll(" = ");
|
||||
try self.writeInstRef(stream, tag_value_ref);
|
||||
}
|
||||
try stream.writeAll(",\n");
|
||||
}
|
||||
self.indent -= 2;
|
||||
try stream.writeByteNTimes(' ', self.indent);
|
||||
try stream.writeAll("}, {");
|
||||
}
|
||||
if (decls_len == 0) {
|
||||
try stream.writeAll("}) ");
|
||||
} else {
|
||||
try stream.writeAll("\n");
|
||||
self.indent += 2;
|
||||
try self.writeDecls(stream, decls_len, extra_index);
|
||||
self.indent -= 2;
|
||||
try stream.writeByteNTimes(' ', self.indent);
|
||||
try stream.writeAll("}) ");
|
||||
}
|
||||
try self.writeSrc(stream, inst_data.src());
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user