Skip to content

Commit cc4a74c

Browse files
committed
translate-c: add detect possible member functions
If the function where the first argument is a container or a pointer to a container, then add a const variable that store the function, and the variable name is the function name without the prefix.
1 parent f01833e commit cc4a74c

File tree

3 files changed

+168
-0
lines changed

3 files changed

+168
-0
lines changed

lib/compiler/aro_translate_c.zig

+122
Original file line numberDiff line numberDiff line change
@@ -1354,6 +1354,12 @@ pub const AliasList = std.ArrayList(struct {
13541354
name: []const u8,
13551355
});
13561356

1357+
// Associates a container (structure or union) with its relevant member functions.
1358+
pub const ContainerMemberFns = struct {
1359+
container_decl: ast.Node,
1360+
member_fns: std.ArrayList(*ast.Payload.Func),
1361+
};
1362+
13571363
pub const ResultUsed = enum {
13581364
used,
13591365
unused,
@@ -1558,6 +1564,7 @@ pub fn ScopeExtra(comptime ScopeExtraContext: type, comptime ScopeExtraType: typ
15581564
blank_macros: std.StringArrayHashMap(void),
15591565
context: *ScopeExtraContext,
15601566
nodes: std.ArrayList(ast.Node),
1567+
container_member_fns_list: std.ArrayList(ContainerMemberFns),
15611568

15621569
pub fn init(c: *ScopeExtraContext) Root {
15631570
return .{
@@ -1569,13 +1576,18 @@ pub fn ScopeExtra(comptime ScopeExtraContext: type, comptime ScopeExtraType: typ
15691576
.blank_macros = std.StringArrayHashMap(void).init(c.gpa),
15701577
.context = c,
15711578
.nodes = std.ArrayList(ast.Node).init(c.gpa),
1579+
.container_member_fns_list = std.ArrayList(ContainerMemberFns).init(c.gpa),
15721580
};
15731581
}
15741582

15751583
pub fn deinit(scope: *Root) void {
15761584
scope.sym_table.deinit();
15771585
scope.blank_macros.deinit();
15781586
scope.nodes.deinit();
1587+
for (scope.container_member_fns_list.items) |item| {
1588+
item.member_fns.deinit();
1589+
}
1590+
scope.container_member_fns_list.deinit();
15791591
}
15801592

15811593
/// Check if the global scope contains this name, without looking into the "future", e.g.
@@ -1588,6 +1600,56 @@ pub fn ScopeExtra(comptime ScopeExtraContext: type, comptime ScopeExtraType: typ
15881600
pub fn contains(scope: *Root, name: []const u8) bool {
15891601
return scope.containsNow(name) or scope.context.global_names.contains(name) or scope.context.weak_global_names.contains(name);
15901602
}
1603+
1604+
pub fn addContainerDecl(scope: *Root, decl_node: ast.Node) !void {
1605+
const tag = decl_node.tag();
1606+
std.debug.assert(tag == .var_simple or tag == .pub_var_simple);
1607+
const container = switch (tag) {
1608+
inline .var_simple, .pub_var_simple => |t| decl_node.castTag(t).?.data.init,
1609+
else => unreachable,
1610+
};
1611+
const c_tag = container.tag();
1612+
if (!(c_tag == .@"struct" or c_tag == .@"union")) return;
1613+
1614+
const gpa = scope.context.gpa;
1615+
const item: ContainerMemberFns = .{
1616+
.container_decl = decl_node,
1617+
.member_fns = std.ArrayList(*ast.Payload.Func).init(gpa),
1618+
};
1619+
try scope.container_member_fns_list.append(item);
1620+
}
1621+
1622+
pub fn addMemberFunction(scope: *Root, func: *ast.Payload.Func) !void {
1623+
if (func.data.params.len == 0) return;
1624+
const param1_node = func.data.params[0].type;
1625+
const param1_type_name = if (param1_node.tag() == .c_pointer) blk_type: {
1626+
const actual_param_node = param1_node.castTag(.c_pointer).?.data.elem_type;
1627+
if (actual_param_node.tag() == .identifier)
1628+
break :blk_type actual_param_node.castTag(.identifier).?.data
1629+
else
1630+
break :blk_type null;
1631+
} else if (param1_node.tag() == .identifier)
1632+
param1_node.castTag(.identifier).?.data
1633+
else
1634+
null;
1635+
1636+
const fn_name = func.data.name orelse return;
1637+
_ = fn_name;
1638+
const type_name = param1_type_name orelse return;
1639+
1640+
for (scope.container_member_fns_list.items) |*item| {
1641+
const decl_node = item.container_decl;
1642+
switch (decl_node.tag()) {
1643+
inline .var_simple, .pub_var_simple => |tag| {
1644+
const data = decl_node.castTag(tag).?.data;
1645+
if (std.mem.eql(u8, type_name, data.name)) {
1646+
try item.member_fns.append(func);
1647+
} else continue;
1648+
},
1649+
else => unreachable,
1650+
}
1651+
}
1652+
}
15911653
};
15921654

15931655
pub fn findBlockScope(inner: *ScopeExtraScope, c: *ScopeExtraContext) !*Block {
@@ -1702,6 +1764,66 @@ pub fn ScopeExtra(comptime ScopeExtraContext: type, comptime ScopeExtraType: typ
17021764
scope = scope.parent.?;
17031765
}
17041766
}
1767+
pub fn processContainerMemberFnsList(c: *ScopeExtraContext, list: std.ArrayList(ContainerMemberFns)) !void {
1768+
for (list.items) |item| {
1769+
const decl_tag = item.container_decl.tag();
1770+
const decl_data = switch (decl_tag) {
1771+
inline .var_simple, .pub_var_simple => |t| item.container_decl.castTag(t).?.data,
1772+
else => unreachable,
1773+
};
1774+
1775+
var container_data = switch (decl_data.init.tag()) {
1776+
inline .@"struct", .@"union" => |t| &decl_data.init.castTag(t).?.data,
1777+
else => unreachable,
1778+
};
1779+
1780+
const arena = c.arena;
1781+
const old_variables = container_data.variables;
1782+
var new_variables = try arena.alloc(ast.Node, old_variables.len + item.member_fns.items.len);
1783+
@memcpy(new_variables[0..old_variables.len], old_variables);
1784+
// Assume the allocator of container_data.variables is arena,
1785+
// so don't add arena.free(old_variables).
1786+
var func_ref_vars = new_variables[old_variables.len..];
1787+
var last_name_array = try c.gpa.alloc([]const u8, item.member_fns.items.len);
1788+
defer c.gpa.free(last_name_array);
1789+
var count: u32 = 0;
1790+
for (item.member_fns.items, 0..) |func, i| {
1791+
const func_name = func.data.name orelse continue;
1792+
const ident_payload = try c.arena.create(ast.Payload.Value);
1793+
ident_payload.* = .{
1794+
.base = .{ .tag = .identifier },
1795+
.data = func_name,
1796+
};
1797+
1798+
const last_index = std.mem.lastIndexOf(u8, func_name, "_");
1799+
const last_name = if (last_index) |index| func_name[index + 1 ..] else continue;
1800+
last_name_array[i] = last_name;
1801+
var same_count: u32 = 0;
1802+
for (last_name_array[0..i]) |name| {
1803+
if (std.mem.eql(u8, name, last_name)) {
1804+
same_count += 1;
1805+
}
1806+
}
1807+
const var_name = if (same_count == 0)
1808+
last_name
1809+
else
1810+
try std.fmt.allocPrint(c.arena, "{s}{d}", .{ last_name, same_count });
1811+
1812+
// compare all before last_name
1813+
const payload = try c.arena.create(ast.Payload.SimpleVarDecl);
1814+
payload.* = .{
1815+
.base = .{ .tag = decl_tag },
1816+
.data = .{
1817+
.name = @as([]const u8, @ptrCast(var_name)),
1818+
.init = ast.Node.initPayload(&ident_payload.base),
1819+
},
1820+
};
1821+
func_ref_vars[count] = ast.Node.initPayload(&payload.base);
1822+
count += 1;
1823+
}
1824+
container_data.variables = new_variables[0 .. old_variables.len + count];
1825+
}
1826+
}
17051827
};
17061828
}
17071829

src/translate_c.zig

+3
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,7 @@ pub fn translate(
182182
try addTopLevelDecl(&context, alias.alias, node);
183183
}
184184

185+
try Scope.processContainerMemberFnsList(&context, context.global_scope.container_member_fns_list);
185186
return ast.render(gpa, context.global_scope.nodes.items);
186187
}
187188

@@ -449,6 +450,7 @@ fn transFnDecl(c: *Context, scope: *Scope, fn_decl: *const clang.FunctionDecl) E
449450
if (scope.id != .root) {
450451
return addLocalExternFnDecl(c, scope, fn_name, Node.initPayload(&proto_node.base));
451452
}
453+
try c.global_scope.addMemberFunction(proto_node);
452454
return addTopLevelDecl(c, fn_name, Node.initPayload(&proto_node.base));
453455
}
454456

@@ -1027,6 +1029,7 @@ fn transRecordDecl(c: *Context, scope: *Scope, record_decl: *const clang.RecordD
10271029
// mangled name is of no real use here.
10281030
if (!is_unnamed and !c.global_names.contains(bare_name) and c.weak_global_names.contains(bare_name))
10291031
try c.alias_list.append(.{ .alias = bare_name, .name = name });
1032+
try c.global_scope.addContainerDecl(node);
10301033
} else {
10311034
try scope.appendNode(node);
10321035
if (node.tag() != .pub_var_simple) {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
typedef struct {
2+
int foo;
3+
} Foo;
4+
5+
int Foo_bar(Foo foo);
6+
int baz(Foo *foo);
7+
int libsomething_quux(Foo *foo);
8+
int foo1_bar(Foo *foo);
9+
int foo2_bar(Foo *foo);
10+
11+
typedef union {
12+
int foo;
13+
float numb;
14+
} UFoo;
15+
16+
int UFoo_bar(UFoo ufoo);
17+
int ubaz(UFoo *ufoo);
18+
int libsomething_union_quux(UFoo *ufoo);
19+
20+
// translate-c
21+
// c_frontend=clang
22+
//
23+
// pub const Foo = extern struct {
24+
// foo: c_int = @import("std").mem.zeroes(c_int),
25+
// pub const bar = Foo_bar;
26+
// pub const quux = libsomething_quux;
27+
// pub const bar1 = foo1_bar;
28+
// pub const bar2 = foo2_bar;
29+
// };
30+
// pub extern fn Foo_bar(foo: Foo) c_int;
31+
// pub extern fn baz(foo: [*c]Foo) c_int;
32+
// pub extern fn libsomething_quux(foo: [*c]Foo) c_int;
33+
// pub extern fn foo1_bar(foo: [*c]Foo) c_int;
34+
// pub extern fn foo2_bar(foo: [*c]Foo) c_int;
35+
// pub const UFoo = extern union {
36+
// foo: c_int,
37+
// numb: f32,
38+
// pub const bar = UFoo_bar;
39+
// pub const quux = libsomething_union_quux;
40+
// };
41+
// pub extern fn UFoo_bar(ufoo: UFoo) c_int;
42+
// pub extern fn ubaz(ufoo: [*c]UFoo) c_int;
43+
// pub extern fn libsomething_union_quux(ufoo: [*c]UFoo) c_int;

0 commit comments

Comments
 (0)