Hi!
I’ve been playing around with Zig and it’s been a really nice experience.
Although, I’m now facing a problem that seems like a good opportunity to reach out to the community.
I’m struggling writing the deinit function for a tree-like data structure (a very simple AST to be exact).
The AST is implemented as a mutually recursive pair of data structures: a struct Node and a union Ast tagged with leaf and node (I’m open to suggestions if it is not the best/more idiomatic way of implementing an AST in Zig).
My understanding is that I have to recursively free the sub-trees before freeing a node. So far I think I’ve managed through the error messages about freeing the sub-trees (although it is not really tested yet). Somehow, I can’t figure out how to free the data stored in the current node: an operator implemented as an enum.
Here is the code I have so far:
const std = @import("std");
pub const Operator = enum { seq, par, con, dis, };
pub const Node = struct {
const Self = @This();
operator: Operator,
left: ?*const Ast,
right: ?*const Ast,
fn init(allocator: std.mem.Allocator, operator: Operator) !Self {
const node = try allocator.create(Node);
node.* = .{ .operator = operator, .left = null, .right = null };
return node.*;
}
fn deinit(self: *Self, allocator: std.mem.Allocator) void {
if (self.left) |left| {
switch (left.*) {
.leaf => |leaf| allocator.free(leaf),
.node => |node| node.deinit(allocator),
}
}
if (self.right) |right| {
switch (right.*) {
.leaf => |leaf| allocator.free(leaf),
.node => |node| node.deinit(allocator),
}
}
allocator.free(self.*.operator);
self.* = undefined;
}
};
pub const NodeTag = enum { leaf, node };
pub const Ast = union(NodeTag) {
leaf: [][]u8,
node: *Node,
};
test "Node" {
const allocator = std.testing.allocator;
var node = try Node.init(allocator, Operator.con);
defer node.deinit(allocator);
}
I end up with the following error message (line number are wrong as I’ve removed irrelevant parts):
$ zig test src/ast.zig
truncated/bin/zig/lib/std/mem/Allocator.zig:439:45: error: access of union field 'pointer' while field 'enum' is active
const Slice = @typeInfo(@TypeOf(memory)).pointer;
~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~
truncated/bin/zig/lib/std/builtin.zig:550:18: note: union declared here
pub const Type = union(enum) {
^~~~~
referenced by:
deinit: src/ast.zig:84:23
test.Node: src/ast.zig:101:22
- deinit: src/ast.zig:84:
allocator.free(self.*.operator);
I’m working with version 0.16.0-dev.2261+d6b3dd25a (0.16 from a few weeks back).