quakeforge/libs/video/renderer/vulkan/vkgen/vkstruct.r
Bill Currie c1b85a3db7 [vkgen] Support custom parsing in multi-type fields
This allows the likes of:

    qfv_pushconstantrangeinfo_s = {
	.name = qfv_pushconstantrangeinfo_t;
	.type = (QFDictionary);
	.dictionary = {
	    .parse = {
		type = (labeledarray, qfv_pushconstantinfo_t, name);
		size = num_pushconstants;
		values = pushconstants;
	    };
	    stageFlags = $name.auto;
	};
	stageFlags = auto;
    };

Leading to:

    pushConstants = {
	vertex   = { Model = mat4; blend = float; };
	fragment = { colors = uint; base_color = vec4; fog = vec4; };
    };

Where the label of the labeled array (which pushConstants is) is
actually an enum flag and the dictionary value is another labeled array.
2023-06-16 18:53:37 +09:00

564 lines
14 KiB
R

#include <hash.h>
#include <qfile.h>
#include <runtime.h>
#include <string.h>
#include <types.h>
#include <Array.h>
#include <PropertyList.h>
#include "vkfielddef.h"
#include "vkfieldtype.h"
#include "vkgen.h"
#include "vkstruct.h"
@implementation Struct
-(void) dealloc
{
[field_dict release];
[field_defs release];
[parse_def release];
[only release];
str_free (outname);
str_free (label_field);
[super dealloc];
}
-(string) name
{
return str_mid(type.strct.tag, 4);
}
-(void) addToQueue
{
string name = [self name];
if (!Hash_Find (processed_types, name)) {
//printf (" +%s\n", name);
Hash_Add (processed_types, (void *) name);
[queue addObject: self];
}
}
-(void) queueFieldTypes
{
qfot_struct_t *strct =&type.strct;
PLItem *field_dict = [parse getObjectForKey:[self name]];
int readonly = [field_dict string] == "readonly";
if (readonly) {
return;
}
for (int i = 0; i < strct.num_fields; i++) {
qfot_var_t *var = &strct.fields[i];
if (field_dict) {
PLItem *item = [field_dict getObjectForKey:var.name];
FieldDef *def = [FieldDef fielddef:item
struct:self
field:var.name];
if (![def searchType]) {
continue;
}
}
Type *type = [Type findType:var.type];
[type addToQueue];
}
}
-(qfot_var_t *)findField:(string) fieldName
{
for (int i = 0; i < type.strct.num_fields; i++) {
qfot_var_t *var = &type.strct.fields[i];
if (var.name == fieldName) {
return var;
}
}
return nil;
}
-(string)sTypeName
{
string s = "VK_STRUCTURE_TYPE";
string name = [self outname];
int length = strlen (name);
int start, end, c;
for (start = 2; start < length; start = end) {
for (end = start + 1; end < length; end++) {
c = str_char (name, end);
if (c >= 'A' && c <= 'Z') {
break;
}
}
s += "_" + str_mid (name, start, end);
}
str_free (name);
return str_upper (s);
}
-(void) setLabelField:(string)label_field
{
self.label_field = label_field;
}
-(void) writeForward
{
PLItem *field_dict = [parse getObjectForKey:[self name]];
int readonly = [field_dict string] == "readonly";
if (!readonly) {
fprintf (output_file, "static int %s (const plfield_t *field,"
" const plitem_t *item, void *data, plitem_t *messages,"
" void *context);\n",
[self parseFunc]);
}
}
static void
write_function_head (Struct *self)
{
fprintf (output_file, "static int %s (const plfield_t *field,"
" const plitem_t *item, void *data, plitem_t *messages,"
" void *context)\n",
[self parseFunc]);
fprintf (output_file, "{\n");
}
static void
write_function_tail (Struct *self)
{
fprintf (output_file, "}\n");
}
static void
write_parse_type (Struct *self, PLItem *item)
{
if ([item string] == "auto") {
fprintf (output_file, "\t\tif (!PL_ParseStruct (%s_fields, item, "
"data, messages, context)) {\n", [self outname]);
fprintf (output_file, "\t\t\treturn 0;\n");
fprintf (output_file, "\t\t}\n");
} else {
//FieldDef *def = [FieldDef fielddef:item struct:self field:".parse"];
[self.parse_def writeParse];
}
}
static void
write_auto_parse (Struct *self, string field, int name)
{
string item = name ? "name" : "item";
fprintf (output_file, "\t\tdo {\n");
fprintf (output_file, "\t\t\tplfield_t *f = find_field (%s_fields, %s, "
"item, messages);\n", [self outname], sprintf ("\"%s\"", field));
fprintf (output_file, "\t\t\tif (!f) {\n");
fprintf (output_file, "\t\t\t\treturn 0;\n");
fprintf (output_file, "\t\t\t}\n");
if (name) {
fprintf (output_file, "\t\t\tplitem_t *name = "
"PL_NewString (field->name);\n");
}
fprintf (output_file, "\t\t\tf->parser (f, %s, &%s, messages, context);\n",
item, sprintf ("((%s *) data)->%s", [self outname], field));
if (name) {
fprintf (output_file, "\t\t\tPL_Release (name);\n");
}
fprintf (output_file, "\t\t} while (0);\n");
}
static int
check_need_table (Struct *self, PLItem *field_dict, string type)
{
string key = nil;
switch (type) {
case "QFDictionary": key = ".dictionary"; break;
case "QFArray": key = ".array"; break;
case "QFBinary": key = ".binary"; break;
case "QFString": key = ".string"; break;
}
PLItem *type_obj = [field_dict getObjectForKey:key];
int count = [type_obj numKeys];
if (!count) {
return 0;
}
for (int i = 0; i < count; i++) {
string field = [type_obj keyAtIndex:i];
PLItem *item = [type_obj getObjectForKey:field];
string str = [item string];
if (field == ".parse") {
if (str != "auto") {
self.parse_def = [[FieldDef fielddef:item
struct:self
field:"parse"] retain];
}
return 1;
}
if (str == "$auto") {
return 1;
}
}
return 0;
}
static void
write_type (Struct *self, PLItem *field_dict, string type)
{
string key = nil;
switch (type) {
case "QFDictionary": key = ".dictionary"; break;
case "QFArray": key = ".array"; break;
case "QFBinary": key = ".binary"; break;
case "QFString": key = ".string"; break;
}
PLItem *type_obj = [field_dict getObjectForKey:key];
int count = [type_obj numKeys];
if (!count) {
//FIXME errors
return;
}
fprintf (output_file, "\tif (type == %s) {\n", type);
for (int i = 0; i < count; i++) {
string field = [type_obj keyAtIndex:i];
PLItem *item = [type_obj getObjectForKey:field];
string str = [item string];
if (field == ".parse") {
write_parse_type (self, item);
continue;
}
switch (str) {
case "$item.string":
str = "vkstrdup (context, PL_String (item))";
break;
case "$item.line":
str = "PL_Line (item)";
break;
case "$name":
str = "vkstrdup (context, field->name)";
break;
case "$index":
str = "field->offset";
break;
case "$auto":
write_auto_parse (self, field, 0);
continue;
case "$name.auto":
write_auto_parse (self, field, 1);
continue;
}
fprintf (output_file, "\t\t((%s *) data)->%s = %s;\n", [self outname],
field, str);
}
fprintf (output_file, "\t\treturn 1;\n");
fprintf (output_file, "\t}\n");
}
static void
write_parser (Struct *self, int have_sType, PLItem *only)
{
write_function_head (self);
if (have_sType) {
fprintf (output_file, "\t((%s *) data)->sType", [self outname]);
fprintf (output_file, " = %s;\n", [self sTypeName]);
}
if (self.label_field) {
fprintf (output_file, "\t((%s *) data)->%s", [self outname],
self.label_field);
fprintf (output_file, " = vkstrdup (context, field->name);\n");
}
if (only) {
fprintf (output_file, "\tplfield_t *f = &%s_fields[0];\n",
[self outname]);
fprintf (output_file,
"\tif (!PL_CheckType (PL_Type (item), f->type)) {\n"
"\t\tPL_TypeMismatch (messages, item, "
"f->name, f->type, PL_Type (item));\n"
"\t\treturn 0;\n"
"\t}\n"
"\tvoid *flddata = (byte *)data + f->offset;\n"
"\treturn f->parser (f, item, flddata, messages, "
"context);\n");
} else {
fprintf (output_file,
"\tif (PL_Type (item) == QFString\n"
"\t\t&& !(item = parse_reference (item, \"%s\", "
"messages, context))) {\n"
"\t\treturn 0;\n"
"\t}\n"
"\treturn PL_ParseStruct (%s_fields, item, data, "
"messages, context);\n",
[self outname], [self outname]);
}
write_function_tail (self);
}
static void
write_cexpr (Struct *self, Array *field_defs)
{
fprintf (output_file, "static exprsym_t %s_symbols[] = {\n",
[self outname]);
if (field_defs) {
PLItem *field_def;
qfot_var_t *field;
for (int i = [field_defs count]; i-- > 0; ) {
FieldDef *field_def = [field_defs objectAtIndex:i];
[field_def writeSymbol];
}
} else {
for (int i = 0; i < self.type.strct.num_fields; i++) {
qfot_var_t *field = &self.type.strct.fields[i];
if (field.name == "sType" || field.name == "pNext") {
continue;
}
Type *field_type = [Type findType: field.type];
fprintf (output_file,
"\t{\"%s\", &%s, (void *) field_offset (%s, %s)},\n",
field.name, [field_type cexprType], [self outname],
field.name);
}
}
fprintf (output_file, "\t{ }\n");
fprintf (output_file, "};\n");
fprintf (output_file, "static exprtab_t %s_symtab = {\n", [self outname]);
fprintf (output_file, "\t%s_symbols,\n", [self outname]);
fprintf (output_file, "};\n");
fprintf (output_file, "exprtype_t %s_type = {\n", [self outname]);
fprintf (output_file, "\t.name = \"%s\",\n", [self outname]);
fprintf (output_file, "\t.size = sizeof (%s),\n", [self outname]);
fprintf (output_file, "\t.binops = cexpr_struct_binops,\n");
fprintf (output_file, "\t.unops = 0,\n");
fprintf (output_file, "\t.data = &%s_symtab,\n", [self outname]);
fprintf (output_file, "};\n");
fprintf (output_file, "\n");
fprintf (header_file, "extern exprtype_t %s_type;\n", [self outname]);
}
static void
write_table (Struct *self, PLItem *field_dict, Array *field_defs,
PLItem *only, int need_parser)
{
qfot_type_t *type = self.type;
int have_sType = 0;
int have_pNext = 0;
int readonly = [field_dict string] == "readonly";
for (int i = 0; i < type.strct.num_fields; i++) {
qfot_var_t *field = &type.strct.fields[i];
if (field.name == "sType") {
have_sType = 1;
}
if (field.name == "pNext") {
have_pNext = 1;
self.write_symtab = 1;
}
}
for (int i = [field_defs count]; i-- > 0; ) {
FieldDef *field_def = [field_defs objectAtIndex:i];
[field_def writeParseData];
}
[self.parse_def writeParseData];
if (!readonly) {
fprintf (output_file, "static plfield_t %s_fields[] = {\n",
[self outname]);
if (!only) {
fprintf (output_file,
"\t{\"@inherit\", 0, QFString, parse_inherit, "
"&%s_fields},\n", [self outname]);
}
if (have_pNext) {
fprintf (output_file,
"\t{\"@next\", field_offset (%s, pNext), "
"QFArray, parse_next, 0},", [self outname]);
}
for (int i = [field_defs count]; i-- > 0; ) {
FieldDef *field_def = [field_defs objectAtIndex:i];
[field_def writeField];
}
fprintf (output_file, "\t{ }\n");
fprintf (output_file, "};\n");
if (need_parser) {
write_parser (self, have_sType, only);
}
if (have_pNext) {
fprintf (output_file, "static parserref_t %s_parser = ",
[self outname]);
fprintf (output_file, "{\"%s\", %s, sizeof(%s)};\n",
[self outname], [self parseFunc], [self outname]);
}
}
}
-(void) initParse:(PLItem *)parse
{
if ([parse string] == "skip") {
skip = 1;
return;
}
field_dict = [parse retain];
PLItem *new_name = [field_dict getObjectForKey:".name"];
if (new_name) {
outname = str_hold ([new_name string]);
}
field_defs = [[Array array] retain];
only = [[field_dict getObjectForKey:".only"] retain];
if (only) {
string field_name = [only string];
qfot_var_t *field = nil;
for (int i = 0; i < type.strct.num_fields; i++) {
qfot_var_t *f = &type.strct.fields[i];
if (f.name == field_name) {
field = f;
break;
}
}
Type *field_type = [Type findType: field.type];
FieldDef *field_def = [field_type fielddef:self field:field.name];
if (!field_def) {
field_def = [FieldDef fielddef:nil
struct:self
field:field.name];
}
[field_defs addObject: field_def];
} else if (field_dict) {
PLItem *field_keys = [field_dict allKeys];
for (int i = [field_keys count]; i-- > 0; ) {
string field_name = [[field_keys getObjectAtIndex:i] string];
if (str_mid(field_name, 0, 1) == ".") {
continue;
}
PLItem *field_item = [field_dict getObjectForKey:field_name];
FieldDef *field_def = [FieldDef fielddef:field_item
struct:self
field:field_name];
[field_defs addObject: field_def];
}
} else {
for (int i = 0; i < type.strct.num_fields; i++) {
qfot_var_t *field = &type.strct.fields[i];
if (field.name == "sType" || field.name == "pNext") {
continue;
}
Type *field_type = [Type findType: field.type];
FieldDef *field_def = [field_type fielddef:self field:field.name];
if (!field_def) {
field_def = [FieldDef fielddef:nil
struct:self
field:field.name];
}
[field_defs addObject: field_def];
}
}
}
-(void) writeTable
{
if (skip) {
return;
}
if ([field_dict getObjectForKey:".type"]) {
PLItem *type = [field_dict getObjectForKey:".type"];
string str = [type string];
int need_table = 0;
if (str) {
need_table |= check_need_table (self, field_dict, str);
} else {
for (int i = [type count]; i-- > 0; ) {
string str = [[type getObjectAtIndex:i] string];
need_table |= check_need_table (self, field_dict, str);
}
}
if (need_table) {
write_table (self, field_dict, field_defs, only, 0);
}
write_function_head (self);
fprintf (output_file, "\tpltype_t type = PL_Type (item);\n");
if (str) {
write_type (self, field_dict, str);
} else {
for (int i = [type count]; i-- > 0; ) {
str = [[type getObjectAtIndex:i] string];
write_type (self, field_dict, str);
}
}
fprintf (output_file,
"\tPL_TypeMismatch (messages, item, field->name, %s, type);\n",
parseItemType (type));
fprintf (output_file, "\treturn 0;\n");
write_function_tail (self);
write_cexpr (self, field_defs);
return;
}
write_table (self, field_dict, field_defs, only, 1);
write_cexpr (self, field_defs);
}
-(void) writeSymtabInit
{
PLItem *field_dict = [parse getObjectForKey:[self outname]];
if ([parse string] == "skip") {
return;
}
fprintf (output_file, "\tcexpr_init_symtab (&%s_symtab, context);\n",
[self outname]);
}
-(void) writeSymtabEntry
{
if (!write_symtab || [parse string] == "skip") {
return;
}
fprintf (output_file,
"\tHash_Add (parser_table, &%s_parser);\n",
[self outname]);
}
-(string) outname
{
if (outname) {
return outname;
}
if (alias) {
return [alias name];
}
return [self name];
}
-(string) cexprType
{
return [self outname] + "_type";
}
-(string) parseType
{
return "QFMultiType | (1 << QFString) | (1 << QFDictionary)";
}
-(string) parseFunc
{
return "parse_" + [self outname];
}
-(string) parseData
{
return "0";
}
@end