@@ -1354,6 +1354,12 @@ pub const AliasList = std.ArrayList(struct {
1354
1354
name : []const u8 ,
1355
1355
});
1356
1356
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
+
1357
1363
pub const ResultUsed = enum {
1358
1364
used ,
1359
1365
unused ,
@@ -1558,6 +1564,7 @@ pub fn ScopeExtra(comptime ScopeExtraContext: type, comptime ScopeExtraType: typ
1558
1564
blank_macros : std .StringArrayHashMap (void ),
1559
1565
context : * ScopeExtraContext ,
1560
1566
nodes : std .ArrayList (ast .Node ),
1567
+ container_member_fns_list : std .ArrayList (ContainerMemberFns ),
1561
1568
1562
1569
pub fn init (c : * ScopeExtraContext ) Root {
1563
1570
return .{
@@ -1569,13 +1576,18 @@ pub fn ScopeExtra(comptime ScopeExtraContext: type, comptime ScopeExtraType: typ
1569
1576
.blank_macros = std .StringArrayHashMap (void ).init (c .gpa ),
1570
1577
.context = c ,
1571
1578
.nodes = std .ArrayList (ast .Node ).init (c .gpa ),
1579
+ .container_member_fns_list = std .ArrayList (ContainerMemberFns ).init (c .gpa ),
1572
1580
};
1573
1581
}
1574
1582
1575
1583
pub fn deinit (scope : * Root ) void {
1576
1584
scope .sym_table .deinit ();
1577
1585
scope .blank_macros .deinit ();
1578
1586
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 ();
1579
1591
}
1580
1592
1581
1593
/// 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
1588
1600
pub fn contains (scope : * Root , name : []const u8 ) bool {
1589
1601
return scope .containsNow (name ) or scope .context .global_names .contains (name ) or scope .context .weak_global_names .contains (name );
1590
1602
}
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
+ }
1591
1653
};
1592
1654
1593
1655
pub fn findBlockScope (inner : * ScopeExtraScope , c : * ScopeExtraContext ) ! * Block {
@@ -1702,6 +1764,66 @@ pub fn ScopeExtra(comptime ScopeExtraContext: type, comptime ScopeExtraType: typ
1702
1764
scope = scope .parent .? ;
1703
1765
}
1704
1766
}
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
+ }
1705
1827
};
1706
1828
}
1707
1829
0 commit comments