feature. See also
. The project being documented here (as the example) is the Zig library itself.
Scope.Root
pub const Root = struct
File
Code
pub const Root = struct {
base: Scope,
translator: *Translator,
sym_table: SymbolTable,
blank_macros: std.array_hash_map.String(void),
nodes: std.ArrayList(ast.Node),
container_member_fns_map: ContainerMemberFnsHashMap,
pub fn init(t: *Translator) Root {
return .{
.base = .{
.id = .root,
.parent = null,
},
.translator = t,
.sym_table = .empty,
.blank_macros = .empty,
.nodes = .empty,
.container_member_fns_map = .empty,
};
}
pub fn deinit(root: *Root) void {
root.sym_table.deinit(root.translator.gpa);
root.blank_macros.deinit(root.translator.gpa);
root.nodes.deinit(root.translator.gpa);
for (root.container_member_fns_map.values()) |*members| {
members.member_fns.deinit(root.translator.gpa);
}
root.container_member_fns_map.deinit(root.translator.gpa);
}
pub fn containsNow(root: *Root, name: []const u8) bool {
return root.sym_table.contains(name);
}
pub fn contains(root: *Root, name: []const u8) bool {
return root.containsNow(name) or root.translator.global_names.contains(name) or root.translator.weak_global_names.contains(name);
}
pub fn addMemberFunction(root: *Root, func_ty: aro.Type.Func, func: *ast.Payload.Func) !void {
std.debug.assert(func.data.name != null);
if (func_ty.params.len == 0) return;
const param1_base = func_ty.params[0].qt.base(root.translator.comp);
const container_qt = if (param1_base.type == .pointer)
param1_base.type.pointer.child.base(root.translator.comp).qt
else
param1_base.qt;
if (root.container_member_fns_map.getPtr(container_qt)) |members| {
try members.member_fns.append(root.translator.gpa, func);
}
}
pub fn processContainerMemberFns(root: *Root) !void {
const gpa = root.translator.gpa;
const arena = root.translator.arena;
var member_names: std.array_hash_map.String(void) = .empty;
defer member_names.deinit(gpa);
for (root.container_member_fns_map.keys(), root.container_member_fns_map.values()) |container_qt, members| {
const container_name = root.translator.unnamed_typedefs.get(container_qt) orelse
container_qt.getRecord(root.translator.comp).?.name.lookup(root.translator.comp);
std.debug.assert(container_name.len > 0);
member_names.clearRetainingCapacity();
const decls_ptr = switch (members.container_decl_ptr.tag()) {
.@"struct", .@"union" => blk_record: {
const payload: *ast.Payload.Container = @alignCast(@fieldParentPtr("base", members.container_decl_ptr.ptr_otherwise));
for (payload.data.fields) |field| {
try member_names.put(gpa, field.name, {});
}
break :blk_record &payload.data.decls;
},
.opaque_literal => blk_opaque: {
const container_decl = try ast.Node.Tag.@"opaque".create(arena, .{
.layout = .none,
.fields = &.{},
.decls = &.{},
});
members.container_decl_ptr.* = container_decl;
break :blk_opaque &container_decl.castTag(.@"opaque").?.data.decls;
},
else => continue,
};
const old_decls = decls_ptr.*;
const new_decls = try arena.alloc(ast.Node, old_decls.len + members.member_fns.items.len * 2);
@memcpy(new_decls[0..old_decls.len], old_decls);
// so don't add arena.free(old_variables).
const func_ref_vars = new_decls[old_decls.len..];
var count: u32 = 0;
for (members.member_fns.items) |func| {
const func_name = func.data.name.?;
const member_name_slot = try member_names.getOrPutValue(gpa, func_name, {});
if (member_name_slot.found_existing) continue;
func_ref_vars[count] = try ast.Node.Tag.pub_var_simple.create(arena, .{
.name = func_name,
.init = try ast.Node.Tag.root_ref.create(arena, func_name),
});
count += 1;
}
for (members.member_fns.items) |func| {
const func_name = func.data.name.?;
const func_name_alias = blk: {
// 1. typedef struct { ... } foo; -> foo_get_bar() extracts "get_bar"
// 2. typedef struct _foo foo; -> foo_get_bar() extracts "get_bar"
const container_name_trimmed = std.mem.trimStart(u8, container_name, "_");
const suffix = std.mem.cutPrefix(u8, func_name, container_name_trimmed);
if (suffix) |alias| if (alias.len > 0 and alias[0] == '_') {
const alias_trimmed = std.mem.trimStart(u8, alias, "_");
if (alias_trimmed.len > 0) break :blk alias_trimmed;
};
const func_name_trimmed = std.mem.trimEnd(u8, func_name, "_");
const last_idx = std.mem.findLast(u8, func_name_trimmed, "_") orelse continue;
break :blk func_name[last_idx + 1 ..];
};
if (root.contains(func_name_alias)) continue;
const member_name_slot = try member_names.getOrPutValue(gpa, func_name_alias, {});
if (member_name_slot.found_existing) continue;
func_ref_vars[count] = try ast.Node.Tag.pub_var_simple.create(arena, .{
.name = func_name_alias,
.init = try ast.Node.Tag.root_ref.create(arena, func_name),
});
count += 1;
}
decls_ptr.* = new_decls[0 .. old_decls.len + count];
}
}
}