Skip to content

Commit 412ef7d

Browse files
authored
Simplify command parsing (#2560)
1 parent 85d2bf8 commit 412ef7d

3 files changed

Lines changed: 119 additions & 93 deletions

File tree

generator/VkXMLParser.cpp

Lines changed: 63 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -19,18 +19,15 @@
1919
#include <vector>
2020

2121
void checkNoList( std::string const & item, int line );
22+
bool containsByNameAndExport( std::vector<Command> const & commands, std::string const & name, std::vector<std::string> const & exports );
2223
bool isLenByStructMember( std::string const & name, std::vector<Param> const & params, std::map<std::string, Struct> const & structs );
2324
std::pair<std::string, BaseType>
2425
parseBaseType( tinyxml2::XMLElement const * element, std::map<std::string, std::string> const & attributes, std::string const & api );
2526
std::pair<std::vector<std::string>, std::pair<std::string, Bitmask>> parseBitmask( tinyxml2::XMLElement const * element,
2627
std::map<std::string, std::string> const & attributes );
27-
void parseCommand( tinyxml2::XMLElement const * element,
28-
std::string const & api,
29-
std::map<std::string, Command> & commands,
30-
std::vector<std::pair<std::string, Command>> & skippedCommands );
31-
std::pair<std::map<std::string, Command>, std::vector<std::pair<std::string, Command>>> parseCommands( tinyxml2::XMLElement const * element,
32-
std::string const & api );
33-
std::pair<std::string, Constant> parseConstant( tinyxml2::XMLElement const * element );
28+
void parseCommand( tinyxml2::XMLElement const * element, std::vector<Command> & commands );
29+
std::vector<Command> parseCommands( tinyxml2::XMLElement const * element );
30+
std::pair<std::string, Constant> parseConstant( tinyxml2::XMLElement const * element );
3431
CategoryAlias parseCategoryAlias( tinyxml2::XMLElement const * element, std::map<std::string, std::string> const & attributes, std::string const & category );
3532
std::pair<std::vector<std::string>, std::pair<std::string, Define>> parseDefine( tinyxml2::XMLElement const * element,
3633
std::map<std::string, std::string> const & attributes );
@@ -68,6 +65,21 @@ void checkNoList( std::string const & item, int line )
6865
checkForError( "vk.xml", item.find( ',' ) == std::string::npos, line, "item <" + item + "> contains unexpected coma, looks like list" );
6966
}
7067

68+
bool containsByNameAndExport( std::vector<Command> const & commands, std::string const & name, std::vector<std::string> const & exports )
69+
{
70+
// check if there is a command with the specified name and at least one export in the specified exports list
71+
return std::ranges::any_of(
72+
commands,
73+
[&name, &exports]( Command const & command )
74+
{
75+
return ( command.name == name ) &&
76+
std::ranges::any_of(
77+
command.exports,
78+
[&exports]( std::string const & commandExport )
79+
{ return std::ranges::any_of( exports, [&commandExport]( std::string const & exportItem ) { return exportItem == commandExport; } ); } );
80+
} );
81+
}
82+
7183
bool isLenByStructMember( std::string const & name, std::vector<Param> const & params, std::map<std::string, Struct> const & structs )
7284
{
7385
// check if name specifies a member of a struct
@@ -167,10 +179,7 @@ std::pair<std::vector<std::string>, std::pair<std::string, Bitmask>> parseBitmas
167179
return { api, { name, { .require = require, .type = type, .xmlLine = line } } };
168180
}
169181

170-
void parseCommand( tinyxml2::XMLElement const * element,
171-
std::string const & api,
172-
std::map<std::string, Command> & commands,
173-
std::vector<std::pair<std::string, Command>> & skippedCommands )
182+
void parseCommand( tinyxml2::XMLElement const * element, std::vector<Command> & commands )
174183
{
175184
int const line = element->GetLineNum();
176185
std::map<std::string, std::string> attributes = getAttributes( element );
@@ -195,12 +204,14 @@ void parseCommand( tinyxml2::XMLElement const * element,
195204
}
196205
}
197206

198-
auto commandIt = commands.find( alias );
207+
auto commandIt = findByName( commands, alias );
199208
checkForError( "vk.xml", commandIt != commands.end(), line, "command <" + name + "> is aliased to unknown command <" + alias + ">" );
200209
checkForError( "vk.xml",
201-
commandIt->second.aliases.insert( { name, line } ).second,
210+
std::find_if( std::next( commandIt ), commands.end(), [&alias]( Command const & c ) { return c.name == alias; } ) == commands.end(),
202211
line,
203-
"command <" + name + "> is already listed as alias for command <" + alias + ">" );
212+
"command <" + name + "> is aliased to multiply specfied command <" + alias + ">" );
213+
checkForError(
214+
"vk.xml", commandIt->aliases.insert( { name, line } ).second, line, "command <" + name + "> is already listed as alias for command <" + alias + ">" );
204215
}
205216
else
206217
{
@@ -255,7 +266,7 @@ void parseCommand( tinyxml2::XMLElement const * element,
255266
}
256267
else if ( attribute.first == "export" )
257268
{
258-
command.export_ = tokenize( attribute.second, "," );
269+
command.exports = tokenize( attribute.second, "," );
259270
}
260271
else if ( attribute.first == "queues" )
261272
{
@@ -281,7 +292,6 @@ void parseCommand( tinyxml2::XMLElement const * element,
281292
}
282293
}
283294

284-
std::string name;
285295
for ( auto child : children )
286296
{
287297
std::string value = child->Value();
@@ -291,15 +301,29 @@ void parseCommand( tinyxml2::XMLElement const * element,
291301
}
292302
else if ( value == "param" )
293303
{
294-
Param param = parseParam( child );
295-
if ( param.api.empty() || ( std::ranges::find( param.api, api ) != param.api.end() ) )
304+
Param param = parseParam( child );
305+
auto paramIt = findByName( command.params, param.name );
306+
if ( paramIt == command.params.end() )
296307
{
297308
command.params.push_back( std::move( param ) );
298309
}
310+
else
311+
{
312+
checkForError( "vk.xml",
313+
param.api != paramIt->api,
314+
param.xmlLine,
315+
"command <" + command.name + "> has the parameter <" + param.name + "> multiply defined for the same set of apis" );
316+
std::vector<std::string> api = param.api;
317+
param.api = paramIt->api;
318+
checkForError( "vk.xml",
319+
param == *paramIt,
320+
param.xmlLine,
321+
"command <" + command.name + "> has the parameter <" + param.name + "> multiply defined with different attributes" );
322+
}
299323
}
300324
else if ( value == "proto" )
301325
{
302-
std::tie( name, command.returnType ) = parseProto( child );
326+
std::tie( command.name, command.returnType ) = parseProto( child );
303327
}
304328
}
305329

@@ -330,46 +354,38 @@ void parseCommand( tinyxml2::XMLElement const * element,
330354
checkForError( "vk.xml",
331355
( command.returnType.name == "VkResult" ) || command.errorCodes.empty(),
332356
line,
333-
"command <" + name + "> does not return a VkResult but specifies errorcodes" );
357+
"command <" + command.name + "> does not return a VkResult but specifies errorcodes" );
334358
checkForError( "vk.xml",
335359
( command.returnType.name == "VkResult" ) || command.successCodes.empty(),
336360
line,
337-
"command <" + name + "> does not return a VkResult but specifies successcodes" );
361+
"command <" + command.name + "> does not return a VkResult but specifies successcodes" );
338362
checkForError(
339363
"vk.xml",
340-
command.api.empty() || command.export_.empty() ||
341-
( ( command.export_.size() == 1 ) && std::ranges::any_of( command.api, [&command]( auto const & a ) { return a == command.export_.front(); } ) ),
364+
command.api.empty() || command.exports.empty() ||
365+
( ( command.exports.size() == 1 ) && std::ranges::any_of( command.api, [&command]( auto const & a ) { return a == command.exports.front(); } ) ),
342366
line,
343-
"command <" + name + "> has disjunct attributes <api> and <export>" );
367+
"command <" + command.name + "> has disjunct attributes <api> and <export>" );
344368

345-
if ( command.api.empty() || ( std::ranges::find( command.api, api ) != command.api.end() ) )
346-
{
347-
checkForError( "vk.xml", commands.insert( { name, command } ).second, line, "command <" + name + "> already specified for api <" + api + ">" );
348-
}
349-
else
350-
{
351-
skippedCommands.push_back( { name, command } );
352-
}
369+
checkForError( "vk.xml", !containsByNameAndExport( commands, command.name, command.exports ), line, "command <" + command.name + "> already specified" );
370+
commands.push_back( std::move( command ) );
353371
}
354372
}
355373

356-
std::pair<std::map<std::string, Command>, std::vector<std::pair<std::string, Command>>> parseCommands( tinyxml2::XMLElement const * element,
357-
std::string const & api )
374+
std::vector<Command> parseCommands( tinyxml2::XMLElement const * element )
358375
{
359376
int const line = element->GetLineNum();
360377
checkAttributes( "vk.xml", line, getAttributes( element ), {}, { { "comment", {} } } );
361378

362379
std::vector<tinyxml2::XMLElement const *> children = getChildElements( element );
363380
checkElements( "vk.xml", line, children, { { "command", MultipleAllowed::Yes } } );
364381

365-
std::map<std::string, Command> commands;
366-
std::vector<std::pair<std::string, Command>> skippedCommands;
382+
std::vector<Command> commands;
367383
for ( auto child : children )
368384
{
369-
parseCommand( child, api, commands, skippedCommands );
385+
parseCommand( child, commands );
370386
}
371387

372-
return { commands, skippedCommands };
388+
return commands;
373389
}
374390

375391
std::pair<std::string, Constant> parseConstant( tinyxml2::XMLElement const * element )
@@ -1020,12 +1036,11 @@ Vkxml parseRegistry( tinyxml2::XMLElement const * element, std::string const & a
10201036
std::string const value = child->Value();
10211037
if ( value == "commands" )
10221038
{
1023-
std::vector<std::pair<std::string, Command>> skippedCommands;
1024-
std::tie( vkxml.commands, skippedCommands ) = parseCommands( child, api );
1039+
vkxml.commands = parseCommands( child );
10251040

10261041
for ( auto const & command : vkxml.commands )
10271042
{
1028-
for ( auto const & param : command.second.params )
1043+
for ( auto const & param : command.params )
10291044
{
10301045
if ( param.externSync.starts_with( "maybe:" ) )
10311046
{
@@ -1034,36 +1049,36 @@ Vkxml parseRegistry( tinyxml2::XMLElement const * element, std::string const & a
10341049
pos != std::string::npos,
10351050
param.xmlLine,
10361051
"unexpected value <" + param.externSync + "> for attribute externsync of parameter <" + param.name + "> of command <" +
1037-
command.first + ">, expected format is \"maybe:<paramname>[].<membername>\"" );
1052+
command.name + ">, expected format is \"maybe:<paramname>[].<membername>\"" );
10381053
std::string memberName = param.externSync.substr( pos + 1 );
10391054
auto structIt = vkxml.structs.find( param.type.name );
10401055
checkForError( "vk.xml",
10411056
structIt != vkxml.structs.end(),
10421057
param.xmlLine,
1043-
"type <" + param.type.name + "> of parameter <" + param.name + "> of command <" + command.first +
1058+
"type <" + param.type.name + "> of parameter <" + param.name + "> of command <" + command.name +
10441059
"> with externsync attribute is not a struct" );
10451060
checkForError( "vk.xml",
10461061
containsByName( structIt->second.members, memberName ),
10471062
param.xmlLine,
1048-
"struct <" + param.type.name + "> used in externsync attribute of parameter <" + param.name + "> of command <" + command.first +
1063+
"struct <" + param.type.name + "> used in externsync attribute of parameter <" + param.name + "> of command <" + command.name +
10491064
"> does not have member <" + memberName + ">" );
10501065
}
10511066
checkForError( "vk.xml",
10521067
param.len.empty() || ( param.len == "null-terminated" ) || ( param.len == "1" ) || param.len.starts_with( "latexmath:" ) ||
1053-
containsByName( command.second.params, param.len ) || isLenByStructMember( param.len, command.second.params, vkxml.structs ),
1068+
containsByName( command.params, param.len ) || isLenByStructMember( param.len, command.params, vkxml.structs ),
10541069
param.xmlLine,
1055-
"unknown len <" + param.len + "> specified for parameter <" + param.name + "> of command <" + command.first + ">" );
1070+
"unknown len <" + param.len + "> specified for parameter <" + param.name + "> of command <" + command.name + ">" );
10561071
checkForError( "vk.xml",
10571072
vkxml.baseTypes.contains( param.type.name ) || vkxml.bitmasks.contains( param.type.name ) ||
10581073
containsByNameOrAlias( vkxml.enums, param.type.name ) || vkxml.externalTypes.contains( param.type.name ) ||
10591074
vkxml.handles.contains( param.type.name ) || containsByNameOrAlias( vkxml.structs, param.type.name ) ||
10601075
vkxml.unions.contains( param.type.name ),
10611076
param.xmlLine,
1062-
"unknown type <" + param.type.name + "> of parameter <" + param.name + "> of command <" + command.first + ">" );
1077+
"unknown type <" + param.type.name + "> of parameter <" + param.name + "> of command <" + command.name + ">" );
10631078
checkForError( "vk.xml",
10641079
param.validStructs.empty() || vkxml.structs.contains( param.validStructs ),
10651080
param.xmlLine,
1066-
"unknown validstructs <" + param.validStructs + "> specified for parameter <" + param.name + "> of command <" + command.first + ">" );
1081+
"unknown validstructs <" + param.validStructs + "> specified for parameter <" + param.name + "> of command <" + command.name + ">" );
10671082
}
10681083
}
10691084
}

generator/VkXMLParser.hpp

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,17 +58,25 @@ struct Param
5858
Type type = {};
5959
std::string validStructs = {};
6060
int xmlLine = {};
61+
62+
bool operator==( Param const & rhs ) const noexcept
63+
{
64+
return ( altLen == rhs.altLen ) && ( api == rhs.api ) && ( arraySizes == rhs.arraySizes ) && ( externSync == rhs.externSync ) &&
65+
( len == rhs.len ) && ( name == rhs.name ) && ( noAutoValidity == rhs.noAutoValidity ) && ( objectType == rhs.objectType ) &&
66+
( optional == rhs.optional ) && ( stride == rhs.stride ) && ( type == rhs.type ) && ( validStructs == rhs.validStructs );
67+
}
6168
};
6269

6370
struct Command
6471
{
72+
std::string name = {};
6573
std::string allowNoQueues = {};
6674
std::map<std::string, int> aliases = {};
6775
std::vector<std::string> api = {};
6876
std::vector<std::string> cmdBufferLevel = {};
6977
std::string conditionalRendering = {};
7078
std::vector<std::string> errorCodes = {};
71-
std::vector<std::string> export_ = {};
79+
std::vector<std::string> exports = {};
7280
std::vector<Param> params = {};
7381
std::vector<std::string> queues = {};
7482
std::string renderPass = {};
@@ -269,7 +277,7 @@ struct Vkxml
269277
{
270278
std::map<std::string, BaseType> baseTypes = {};
271279
std::map<std::string, Bitmask> bitmasks = {};
272-
std::map<std::string, Command> commands = {}; // lists only commands of the requested export
280+
std::vector<Command> commands = {};
273281
std::map<std::string, Constant> constants = {};
274282
Comment copyright = {};
275283
std::map<std::string, Define> defines = {};

0 commit comments

Comments
 (0)