@@ -1839,6 +1839,143 @@ pub fn create_struct(db: *Database, opts: CreateStructOptions) !StructID {
18391839 return struct_id ;
18401840}
18411841
1842+ /// Returns the last part of the reference, and the beginning part of the
1843+ /// reference
1844+ fn get_ref_last_component (ref : []const u8 ) ! struct { []const u8 , ? []const u8 } {
1845+ var it = std .mem .splitScalar (u8 , ref , '.' );
1846+ var last : ? []const u8 = null ;
1847+ while (it .next ()) | comp | {
1848+ last = comp ;
1849+ }
1850+
1851+ log .debug (" last={?s}" , .{last });
1852+
1853+ return if (last ) | l |
1854+ if (l .len == ref .len )
1855+ .{ l , null }
1856+ else
1857+ .{ l , ref [0 .. ref .len - l .len - 1 ] }
1858+ else
1859+ error .EmptyRef ;
1860+ }
1861+
1862+ fn strip_ref_prefix (expected_prefix : []const u8 , ref : []const u8 ) ! []const u8 {
1863+ var prefix_it = std .mem .splitScalar (u8 , expected_prefix , '.' );
1864+ var ref_it = std .mem .splitScalar (u8 , ref , '.' );
1865+
1866+ while (prefix_it .next ()) | prefix_comp | {
1867+ const ref_comp = ref_it .next () orelse return error .RefTooShort ;
1868+
1869+ if (! std .mem .eql (u8 , prefix_comp , ref_comp ))
1870+ return error .RefPrefixNotExpected ;
1871+ }
1872+
1873+ const index = ref_it .index orelse return error .RefTooShort ;
1874+ return ref [index .. ];
1875+ }
1876+
1877+ pub fn get_struct_ref (db : * Database , ref : []const u8 ) ! StructID {
1878+ log .debug ("get_struct_ref: ref={s}" , .{ref });
1879+ var arena = std .heap .ArenaAllocator .init (db .gpa );
1880+ defer arena .deinit ();
1881+
1882+ const base_ref = try strip_ref_prefix ("types.peripherals" , ref );
1883+ log .debug (" base_ref={s}" , .{base_ref });
1884+ const struct_name , const rest_ref = try get_ref_last_component (base_ref );
1885+ log .debug (" rest_ref={?s} struct_name={s}" , .{ rest_ref , struct_name });
1886+
1887+ return if (rest_ref ) | rest | blk : {
1888+ var it = std .mem .splitScalar (u8 , rest , '.' );
1889+ const peripheral_name = it .next () orelse return error .NoPeripheral ;
1890+ log .debug (" peripheral_name={s}" , .{peripheral_name });
1891+ const peripheral_id = try db .get_peripheral_by_name (peripheral_name ) orelse return error .NoPeripheral ;
1892+ var struct_id = try db .get_peripheral_struct (peripheral_id );
1893+ if (it .index == null ) {
1894+ log .debug ("struct_name={s}" , .{struct_name });
1895+ return if (std .mem .eql (u8 , struct_name , peripheral_name ))
1896+ struct_id
1897+ else
1898+ error .NoPeripheral ;
1899+ }
1900+
1901+ break :blk while (it .next ()) | name | {
1902+ const struct_decl = try db .get_struct_decl_by_name (arena .allocator (), struct_id , name );
1903+ log .debug (" struct_decl.name={s}" , .{struct_decl .name });
1904+ if (it .index == null and std .mem .eql (u8 , struct_name , struct_decl .name ))
1905+ break struct_decl .struct_id ;
1906+
1907+ struct_id = struct_decl .struct_id ;
1908+ } else error .RefNotFound ;
1909+ } else blk : {
1910+ log .debug (" just getting peripheral struct: peripheral_name={s}" , .{struct_name });
1911+ // just getting a peripheral
1912+ const peripheral_id = try db .get_peripheral_by_name (struct_name ) orelse return error .NoPeripheral ;
1913+ break :blk try db .get_peripheral_struct (peripheral_id );
1914+ };
1915+ }
1916+
1917+ pub fn get_enum_ref (db : * Database , ref : []const u8 ) ! EnumID {
1918+ var arena = std .heap .ArenaAllocator .init (db .gpa );
1919+ defer arena .deinit ();
1920+
1921+ log .debug ("get_enum_ref: ref={s}" , .{ref });
1922+
1923+ const enum_name , const struct_ref = try get_ref_last_component (ref );
1924+
1925+ // An enum that can be referenced has a struct as a parent
1926+ const struct_id = try db .get_struct_ref (struct_ref orelse return error .InvalidRef );
1927+
1928+ // TODO: create a `get_enum_id_by_name()` function
1929+ const e = try db .get_enum_by_name (arena .allocator (), struct_id , enum_name );
1930+ return e .id ;
1931+ }
1932+
1933+ pub fn get_register_ref (db : * Database , ref : []const u8 ) ! RegisterID {
1934+ var arena = std .heap .ArenaAllocator .init (db .gpa );
1935+ defer arena .deinit ();
1936+
1937+ log .debug ("get_register_ref: ref={s}" , .{ref });
1938+
1939+ const register_name , const struct_ref = try get_ref_last_component (ref );
1940+ const struct_id = try db .get_struct_ref (struct_ref orelse return error .InvalidRef );
1941+ const register = try db .get_register_by_name (arena .allocator (), struct_id , register_name );
1942+ return register .id ;
1943+ }
1944+
1945+ pub fn set_register_field_enum_id (db : * Database , register_id : RegisterID , field_name : []const u8 , enum_id : EnumID ) ! void {
1946+ try db .exec (
1947+ \\UPDATE struct_fields
1948+ \\SET enum_id = ?
1949+ \\WHERE struct_id = (
1950+ \\ SELECT struct_id
1951+ \\ FROM registers
1952+ \\ WHERE id = ?
1953+ \\)
1954+ \\AND name = ?;
1955+ , .{
1956+ .enum_id = enum_id ,
1957+ .register_id = register_id ,
1958+ .name = field_name ,
1959+ });
1960+
1961+ log .debug ("set_register_field_enum_id: register_id={} field_name={s} enum_id={}" , .{
1962+ register_id ,
1963+ field_name ,
1964+ enum_id ,
1965+ });
1966+ }
1967+
1968+ pub fn cleanup_unused_enums (db : * Database ) ! void {
1969+ try db .exec (
1970+ \\DELETE FROM enums
1971+ \\WHERE id NOT IN (
1972+ \\ SELECT DISTINCT enum_id
1973+ \\ FROM struct_fields
1974+ \\ WHERE enum_id IS NOT NULL
1975+ \\)
1976+ , .{});
1977+ }
1978+
18421979pub fn apply_patch (db : * Database , ndjson : []const u8 ) ! void {
18431980 var list = std .ArrayList (std .json .Parsed (Patch )).init (db .gpa );
18441981 defer {
@@ -1852,6 +1989,35 @@ pub fn apply_patch(db: *Database, ndjson: []const u8) !void {
18521989 errdefer p .deinit ();
18531990 try list .append (p );
18541991 }
1992+
1993+ for (list .items ) | patch | {
1994+ switch (patch .value ) {
1995+ .add_enum = > | add_enum | {
1996+ const struct_id = try db .get_struct_ref (add_enum .parent );
1997+
1998+ const enum_id = try db .create_enum (struct_id , .{
1999+ .name = add_enum .@"enum" .name ,
2000+ .description = add_enum .@"enum" .description ,
2001+ .size_bits = add_enum .@"enum" .bitsize ,
2002+ });
2003+
2004+ for (add_enum .@"enum" .fields ) | enum_field | {
2005+ try db .add_enum_field (enum_id , .{
2006+ .name = enum_field .name ,
2007+ .description = enum_field .description ,
2008+ .value = enum_field .value ,
2009+ });
2010+ }
2011+ },
2012+ .set_enum_type = > | set_enum_type | {
2013+ const enum_id = try db .get_enum_ref (set_enum_type .to );
2014+ const field_name , const register_ref = try get_ref_last_component (set_enum_type .of );
2015+ const register_id = try db .get_register_ref (register_ref orelse return error .InvalidRef );
2016+ try db .set_register_field_enum_id (register_id , field_name , enum_id );
2017+ try db .cleanup_unused_enums ();
2018+ },
2019+ }
2020+ }
18552021}
18562022
18572023pub fn to_zig (db : * Database , out_writer : anytype ) ! void {
0 commit comments