Registry: Commands

This commit is contained in:
Robin Voetter
2020-01-23 01:33:53 +01:00
parent 394f2d97ab
commit 1c603c6e39

View File

@@ -5,6 +5,17 @@ const Allocator = mem.Allocator;
const SegmentedList = std.SegmentedList; const SegmentedList = std.SegmentedList;
const StringHashMap = std.StringHashMap; const StringHashMap = std.StringHashMap;
fn count(haystack: []const u8, needle: u8) usize {
var total: usize = 0;
for (haystack) |elem| {
if (elem == needle) {
total += 1;
}
}
return total;
}
pub const Registry = struct { pub const Registry = struct {
arena: std.heap.ArenaAllocator, arena: std.heap.ArenaAllocator,
@@ -12,6 +23,7 @@ pub const Registry = struct {
bitmasks: StringHashMap(BitmaskInfo), bitmasks: StringHashMap(BitmaskInfo),
handles: StringHashMap(HandleInfo), handles: StringHashMap(HandleInfo),
structs: StringHashMap(StructInfo), structs: StringHashMap(StructInfo),
commands: StringHashMap(CommandInfo),
extensions: SegmentedList(ExtensionInfo, 0), extensions: SegmentedList(ExtensionInfo, 0),
@@ -28,6 +40,7 @@ pub const Registry = struct {
.bitmasks = StringHashMap(BitmaskInfo).init(allocator), .bitmasks = StringHashMap(BitmaskInfo).init(allocator),
.handles = StringHashMap(HandleInfo).init(allocator), .handles = StringHashMap(HandleInfo).init(allocator),
.structs = StringHashMap(StructInfo).init(allocator), .structs = StringHashMap(StructInfo).init(allocator),
.commands = StringHashMap(CommandInfo).init(allocator),
.extensions = undefined .extensions = undefined
}; };
@@ -44,6 +57,7 @@ pub const Registry = struct {
self.bitmasks.deinit(); self.bitmasks.deinit();
self.handles.deinit(); self.handles.deinit();
self.structs.deinit(); self.structs.deinit();
self.commands.deinit();
// Copy to stack so that the arena doesn't destroy itself // Copy to stack so that the arena doesn't destroy itself
var arena = self.arena; var arena = self.arena;
@@ -106,6 +120,35 @@ pub const Registry = struct {
} }
} }
{
std.debug.warn("Commands:\n", .{});
var it = self.commands.iterator();
while (it.next()) |kv| {
std.debug.warn(" fn {}(\n", .{kv.key});
var param_it = kv.value.parameters.iterator(0);
while (param_it.next()) |param| {
std.debug.warn(" {}: {},\n", .{param.name, param.type_info});
}
std.debug.warn(" ) {}\n", .{kv.value.return_type});
if (kv.value.success_codes.len > 0) {
std.debug.warn(" Success codes:\n", .{});
for (kv.value.success_codes) |code| {
std.debug.warn(" {}\n", .{code});
}
}
if (kv.value.error_codes.len > 0) {
std.debug.warn(" Error codes:\n", .{});
for (kv.value.error_codes) |code| {
std.debug.warn(" {}\n", .{code});
}
}
}
}
{ {
std.debug.warn("Extensions:\n", .{}); std.debug.warn("Extensions:\n", .{});
var it = self.extensions.iterator(0); var it = self.extensions.iterator(0);
@@ -151,10 +194,7 @@ const TypeInfo = struct {
} }
if (stars) |ptr_text| { if (stars) |ptr_text| {
var npointers: usize = 0; const npointers = count(ptr_text, '*');
for (ptr_text) |c| {
if (c == '*') npointers += 1;
}
type_info.pointers = allocator.alloc(TypeInfo.Pointer, npointers) catch unreachable; type_info.pointers = allocator.alloc(TypeInfo.Pointer, npointers) catch unreachable;
@@ -236,19 +276,33 @@ const TypeInfo = struct {
const StructInfo = struct { const StructInfo = struct {
const Member = struct { const Member = struct {
name: []const u8, name: []const u8,
type_info: TypeInfo, type_info: TypeInfo
}; };
members: std.SegmentedList(Member, 0), members: SegmentedList(Member, 0),
aliases: std.SegmentedList([]const u8, 0), aliases: SegmentedList([]const u8, 0),
fn init(allocator: *Allocator) StructInfo { fn init(allocator: *Allocator) StructInfo {
return .{ return .{
.members = std.SegmentedList(Member, 0).init(allocator), .members = SegmentedList(Member, 0).init(allocator),
.aliases = std.SegmentedList([]const u8, 0).init(allocator) .aliases = SegmentedList([]const u8, 0).init(allocator)
}; };
} }
fn fromXml(allocator: *Allocator, elem: *xml.Element) StructInfo {
var s = StructInfo.init(allocator);
var members = elem.findChildrenByTag("member");
while (members.next()) |member| {
const member_name = member.getCharData("name").?;
const type_info = TypeInfo.fromXml(allocator, member);
s.addMember(member_name, type_info);
}
return s;
}
fn addMember(self: *StructInfo, name: []const u8, type_info: TypeInfo) void { fn addMember(self: *StructInfo, name: []const u8, type_info: TypeInfo) void {
self.members.push(.{.name = name, .type_info = type_info}) catch unreachable; self.members.push(.{.name = name, .type_info = type_info}) catch unreachable;
} }
@@ -258,6 +312,73 @@ const StructInfo = struct {
} }
}; };
const CommandInfo = struct {
const Parameter = struct {
name: []const u8,
type_info: TypeInfo
};
parameters: SegmentedList(Parameter, 0),
return_type: []const u8, // Return type is always plain
success_codes: []const []const u8,
error_codes: []const []const u8,
aliases: SegmentedList([]const u8, 0),
fn init(allocator: *Allocator, return_type: []const u8) CommandInfo {
return .{
.parameters = SegmentedList(Parameter, 0).init(allocator),
.return_type = return_type,
.success_codes = &[_][]u8{},
.error_codes = &[_][]u8{},
.aliases = SegmentedList([]const u8, 0).init(allocator)
};
}
fn fromXml(allocator: *Allocator, elem: *xml.Element) CommandInfo {
const return_type = elem.findChildByTag("proto").?.getCharData("type").?;
var cmd = CommandInfo.init(allocator, return_type);
if (elem.getAttribute("successcodes")) |codes| {
cmd.success_codes = CommandInfo.splitResultCodes(allocator, codes);
}
if (elem.getAttribute("errorcodes")) |codes| {
cmd.error_codes = CommandInfo.splitResultCodes(allocator, codes);
}
var parameters = elem.findChildrenByTag("param");
while (parameters.next()) |param| {
const param_name = param.getCharData("name").?;
const type_info = TypeInfo.fromXml(allocator, param);
cmd.addParameter(param_name, type_info);
}
return cmd;
}
fn splitResultCodes(allocator: *Allocator, text: []const u8) []const []const u8 {
const ncodes = 1 + count(text, ',');
const codes = allocator.alloc([]const u8, ncodes) catch unreachable;
var it = mem.separate(text, ",");
for (codes) |*code, i| {
code.* = it.next().?;
}
return codes;
}
fn addParameter(self: *CommandInfo, name: []const u8, type_info: TypeInfo) void {
self.parameters.push(.{.name = name, .type_info = type_info}) catch unreachable;
}
fn addAlias(self: *CommandInfo, alias: []const u8) void {
self.aliases.push(alias) catch unreachable;
}
};
const HandleInfo = union(enum) { const HandleInfo = union(enum) {
Dispatchable, Dispatchable,
NonDispatchable, NonDispatchable,
@@ -304,12 +425,12 @@ const EnumInfo = struct {
}; };
kind: Kind, kind: Kind,
variants: std.SegmentedList(Variant, 0), variants: SegmentedList(Variant, 0),
fn init(allocator: *Allocator, kind: Kind) EnumInfo { fn init(allocator: *Allocator, kind: Kind) EnumInfo {
return .{ return .{
.kind = kind, .kind = kind,
.variants = std.SegmentedList(Variant, 0).init(allocator) .variants = SegmentedList(Variant, 0).init(allocator)
}; };
} }
@@ -385,7 +506,8 @@ pub fn generate(backing_allocator: *Allocator, root: *xml.Element) *Registry {
var registry = Registry.init(backing_allocator) catch unreachable; var registry = Registry.init(backing_allocator) catch unreachable;
processTypes(registry, root); processTypes(registry, root);
processEnumInfos(registry, root); processEnums(registry, root);
processCommands(registry, root);
processFeatures(registry, root); processFeatures(registry, root);
processExtensions(registry, root); processExtensions(registry, root);
@@ -440,20 +562,11 @@ fn processStructType(registry: *Registry, ty: *xml.Element) void {
return; return;
} }
var s = StructInfo.init(&registry.arena.allocator); const s = StructInfo.fromXml(&registry.arena.allocator, ty);
var members = ty.findChildrenByTag("member");
while (members.next()) |member| {
const member_name = member.getCharData("name").?;
const type_info = TypeInfo.fromXml(&registry.arena.allocator, member);
s.addMember(member_name, type_info);
}
if (registry.structs.put(name, s) catch unreachable) |_| unreachable; if (registry.structs.put(name, s) catch unreachable) |_| unreachable;
} }
fn processEnumInfos(registry: *Registry, root: *xml.Element) void { fn processEnums(registry: *Registry, root: *xml.Element) void {
var it = root.findChildrenByTag("enums"); var it = root.findChildrenByTag("enums");
while (it.next()) |enums| { while (it.next()) |enums| {
const name = enums.getAttribute("name").?; const name = enums.getAttribute("name").?;
@@ -464,6 +577,22 @@ fn processEnumInfos(registry: *Registry, root: *xml.Element) void {
} }
} }
fn processCommands(registry: *Registry, root: *xml.Element) void {
var commands = root.findChildByTag("commands").?;
var command_it = commands.findChildrenByTag("command");
while (command_it.next()) |elem| {
if (elem.getAttribute("alias")) |alias| {
const name = elem.getAttribute("name").?;
var cmd = &registry.commands.get(alias).?.value;
cmd.addAlias(name);
} else {
const name = elem.findChildByTag("proto").?.getCharData("name").?;
const command = CommandInfo.fromXml(&registry.arena.allocator, elem);
if (registry.commands.put(name, command) catch unreachable) |_| unreachable;
}
}
}
fn processExtensions(registry: *Registry, root: *xml.Element) void { fn processExtensions(registry: *Registry, root: *xml.Element) void {
var extensions = root.findChildByTag("extensions").?; var extensions = root.findChildByTag("extensions").?;
var ext_it = extensions.findChildrenByTag("extension"); var ext_it = extensions.findChildrenByTag("extension");