AstGen: implement error set decls

This commit is contained in:
Andrew Kelley
2021-04-19 16:03:46 -07:00
parent 2083208f19
commit 7f931a7522
4 changed files with 88 additions and 73 deletions

View File

@@ -604,73 +604,6 @@ fn astgenAndSemaVarDecl(
}
fn errorSetDecl(
gz: *GenZir,
scope: *Scope,
rl: ResultLoc,
node: ast.Node.Index,
) InnerError!Zir.Inst.Ref {
const astgen = gz.astgen;
const tree = &astgen.file.tree;
const main_tokens = tree.nodes.items(.main_token);
const token_tags = tree.tokens.items(.tag);
// Count how many fields there are.
const error_token = main_tokens[node];
const count: usize = count: {
var tok_i = error_token + 2;
var count: usize = 0;
while (true) : (tok_i += 1) {
switch (token_tags[tok_i]) {
.doc_comment, .comma => {},
.identifier => count += 1,
.r_brace => break :count count,
else => unreachable,
}
} else unreachable; // TODO should not need else unreachable here
};
const gpa = astgen.gpa;
var new_decl_arena = std.heap.ArenaAllocator.init(gpa);
errdefer new_decl_arena.deinit();
const arena = &new_decl_arena.allocator;
const fields = try arena.alloc([]const u8, count);
{
var tok_i = error_token + 2;
var field_i: usize = 0;
while (true) : (tok_i += 1) {
switch (token_tags[tok_i]) {
.doc_comment, .comma => {},
.identifier => {
fields[field_i] = try astgen.identifierTokenStringTreeArena(tok_i, tree, arena);
field_i += 1;
},
.r_brace => break,
else => unreachable,
}
}
}
const error_set = try arena.create(Module.ErrorSet);
error_set.* = .{
.owner_decl = astgen.decl,
.node_offset = astgen.decl.nodeIndexToRelative(node),
.names_ptr = fields.ptr,
.names_len = @intCast(u32, fields.len),
};
const error_set_ty = try Type.Tag.error_set.create(arena, error_set);
const error_set_val = try Value.Tag.ty.create(arena, error_set_ty);
const new_decl = try mod.createAnonymousDecl(scope, &new_decl_arena, .{
.ty = Type.initTag(.type),
.val = error_set_val,
});
const decl_index = try mod.declareDeclDependency(astgen.decl, new_decl);
const result = try gz.addDecl(.decl_val, decl_index, node);
return rvalue(gz, scope, rl, result, node);
}
if (mod.lookupIdentifier(scope, ident_name)) |decl| {
const msg = msg: {
const msg = try mod.errMsg(
@@ -761,3 +694,20 @@ fn errorSetDecl(
);
}
const error_set = try arena.create(Module.ErrorSet);
error_set.* = .{
.owner_decl = astgen.decl,
.node_offset = astgen.decl.nodeIndexToRelative(node),
.names_ptr = fields.ptr,
.names_len = @intCast(u32, fields.len),
};
const error_set_ty = try Type.Tag.error_set.create(arena, error_set);
const error_set_val = try Value.Tag.ty.create(arena, error_set_ty);
const new_decl = try mod.createAnonymousDecl(scope, &new_decl_arena, .{
.ty = Type.initTag(.type),
.val = error_set_val,
});
const decl_index = try mod.declareDeclDependency(astgen.decl, new_decl);
const result = try gz.addDecl(.decl_val, decl_index, node);
return rvalue(gz, scope, rl, result, node);

View File

@@ -1463,6 +1463,7 @@ fn blockExprStmts(
.enum_decl,
.enum_decl_nonexhaustive,
.opaque_decl,
.error_set_decl,
.int_to_enum,
.enum_to_int,
.type_info,
@@ -2930,11 +2931,37 @@ fn errorSetDecl(
node: ast.Node.Index,
) InnerError!Zir.Inst.Ref {
const astgen = gz.astgen;
const gpa = astgen.gpa;
const tree = &astgen.file.tree;
const main_tokens = tree.nodes.items(.main_token);
const token_tags = tree.tokens.items(.tag);
return astgen.failNode(node, "TODO AstGen errorSetDecl", .{});
var field_names: std.ArrayListUnmanaged(u32) = .{};
defer field_names.deinit(gpa);
{
const error_token = main_tokens[node];
var tok_i = error_token + 2;
var field_i: usize = 0;
while (true) : (tok_i += 1) {
switch (token_tags[tok_i]) {
.doc_comment, .comma => {},
.identifier => {
const str_index = try gz.identAsString(tok_i);
try field_names.append(gpa, str_index);
field_i += 1;
},
.r_brace => break,
else => unreachable,
}
}
}
const result = try gz.addPlNode(.error_set_decl, node, Zir.Inst.ErrorSetDecl{
.fields_len = @intCast(u32, field_names.items.len),
});
try astgen.extra.appendSlice(gpa, field_names.items);
return rvalue(gz, scope, rl, result, node);
}
fn orelseCatchExpr(

View File

@@ -343,6 +343,7 @@ pub fn analyzeBody(
.enum_decl_nonexhaustive => try sema.zirEnumDecl(block, inst, true),
.union_decl => try sema.zirUnionDecl(block, inst),
.opaque_decl => try sema.zirOpaqueDecl(block, inst),
.error_set_decl => try sema.zirErrorSetDecl(block, inst),
.add => try sema.zirArithmetic(block, inst),
.addwrap => try sema.zirArithmetic(block, inst),
@@ -978,6 +979,17 @@ fn zirOpaqueDecl(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerEr
return sema.mod.fail(&block.base, sema.src, "TODO implement zirOpaqueDecl", .{});
}
fn zirErrorSetDecl(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {
const tracy = trace(@src());
defer tracy.end();
const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
const src = inst_data.src();
const extra = sema.code.extraData(Zir.Inst.ErrorSetDecl, inst_data.payload_index);
return sema.mod.fail(&block.base, sema.src, "TODO implement zirErrorSetDecl", .{});
}
fn zirRetPtr(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {
const tracy = trace(@src());
defer tracy.end();

View File

@@ -307,6 +307,9 @@ pub const Inst = struct {
/// An opaque type definition. Provides an AST node only.
/// Uses the `node` union field.
opaque_decl,
/// An error set type definition. Contains a list of field names.
/// Uses the `pl_node` union field. Payload is `ErrorSetDecl`.
error_set_decl,
/// Declares the beginning of a statement. Used for debug info.
/// Uses the `node` union field.
dbg_stmt_node,
@@ -986,6 +989,7 @@ pub const Inst = struct {
.enum_decl,
.enum_decl_nonexhaustive,
.opaque_decl,
.error_set_decl,
.dbg_stmt_node,
.decl_ref,
.decl_val,
@@ -2011,6 +2015,11 @@ pub const Inst = struct {
fields_len: u32,
};
/// Trailing: field_name: u32 // for every field: null terminated string index
pub const ErrorSetDecl = struct {
fields_len: u32,
};
/// A f128 value, broken up into 4 u32 parts.
pub const Float128 = struct {
piece0: u32,
@@ -2328,6 +2337,8 @@ const Writer = struct {
.builtin_async_call,
=> try self.writePlNode(stream, inst),
.error_set_decl => try self.writePlNodeErrorSetDecl(stream, inst),
.add_with_overflow,
.sub_with_overflow,
.mul_with_overflow,
@@ -2596,11 +2607,7 @@ const Writer = struct {
try stream.print("\"{}\")", .{std.zig.fmtEscapes(str)});
}
fn writePlNode(
self: *Writer,
stream: anytype,
inst: Inst.Index,
) (@TypeOf(stream).Error || error{OutOfMemory})!void {
fn writePlNode(self: *Writer, stream: anytype, inst: Inst.Index) !void {
const inst_data = self.code.instructions.items(.data)[inst].pl_node;
try stream.writeAll("TODO) ");
try self.writeSrc(stream, inst_data.src());
@@ -2616,6 +2623,25 @@ const Writer = struct {
try self.writeSrc(stream, inst_data.src());
}
fn writePlNodeErrorSetDecl(self: *Writer, stream: anytype, inst: Inst.Index) !void {
const inst_data = self.code.instructions.items(.data)[inst].pl_node;
const extra = self.code.extraData(Inst.ErrorSetDecl, inst_data.payload_index);
const fields = self.code.extra[extra.end..][0..extra.data.fields_len];
try stream.writeAll("{\n");
self.indent += 2;
for (fields) |str_index| {
const name = self.code.nullTerminatedString(str_index);
try stream.writeByteNTimes(' ', self.indent);
try stream.print("{},\n", .{std.zig.fmtId(name)});
}
self.indent -= 2;
try stream.writeByteNTimes(' ', self.indent);
try stream.writeAll("}) ");
try self.writeSrc(stream, inst_data.src());
}
fn writePlNodeOverflowArithmetic(self: *Writer, stream: anytype, inst: Inst.Index) !void {
const inst_data = self.code.instructions.items(.data)[inst].pl_node;
const extra = self.code.extraData(Inst.OverflowArithmetic, inst_data.payload_index).data;