[qfcc] Add a handle type for engine resources

I never liked the various hacks I had come up with for representing
resource handles in Ruamoko. Structs with an int were awkward to test,
pointers and ints could be modified, etc etc. The new @handle keyword (@
used to keep handle free for use) works just like struct, union and
enum in syntax, but creates an opaque type suitable for a 32-bit handle.
The backing type is a function so v6 progs can use it without (all the
necessary opcodes exist) and no modifications were needed for
type-checking in binary expressions, but only assignment and comparisons
are supported, and (of course) nil. Tested using cbuf_t and QFile: seems
to work as desired.

I had considered 64-bit handles, but really, if more than 4G resource
objects are needed, I'm not sure QF can handle the game. However, that
limit is per resource manager, not total.
This commit is contained in:
Bill Currie 2023-05-25 10:41:28 +09:00
parent d07bd20552
commit 6d5e8922a5
17 changed files with 105 additions and 11 deletions

View file

@ -48,6 +48,7 @@ typedef enum {
ty_array,
ty_class,
ty_alias,
ty_handle,
} ty_meta_e;
typedef struct qfot_alias_s {
@ -57,6 +58,11 @@ typedef struct qfot_alias_s {
pr_string_t name; ///< alias name, may be null
} qfot_alias_t;
typedef struct qfot_handle_s {
etype_t type;
pr_string_t tag;
} qfot_handle_t;
typedef struct qfot_fldptr_s {
etype_t type; ///< ev_field or ev_ptr
pr_ptr_t aux_type; ///< referenced type
@ -119,6 +125,7 @@ typedef struct qfot_type_s {
qfot_array_t array; ///< ty_array
pr_string_t class; ///< ty_class
qfot_alias_t alias; ///< ty_alias
qfot_handle_t handle; ///< ty_handle
};
} qfot_type_t;

View file

@ -237,6 +237,7 @@ pr_debug_type_size (const progs_t *pr, const qfot_type_t *type)
qfot_type_t *aux_type;
switch (type->meta) {
case ty_basic:
case ty_handle:
return pr_type_size[type->type];
case ty_struct:
case ty_union:
@ -1052,6 +1053,7 @@ static void
value_string (pr_debug_data_t *data, qfot_type_t *type, pr_type_t *value)
{
switch (type->meta) {
case ty_handle:
case ty_basic:
switch (type->type) {
#define EV_TYPE(t) \

View file

@ -95,6 +95,9 @@ void print_type (qfot_type_t *type)
//printf (" %d %s ", type.alias.type, type.alias.name);
print_type (type.alias.aux_type);
break;
case ty_handle:
//printf (" %s\n", type.handle.tag);
break;
}
}

View file

@ -60,6 +60,8 @@ static string get_type_key (void *type, void *unused)
return [[String alloc] initWithType: type];
}
}
// fallthrough
case ty_handle:
case ty_class:
return [[Type alloc] initWithType: type];
case ty_array:

View file

@ -1,11 +1,11 @@
#ifndef __ruamoko_cbuf_h
#define __ruamoko_cbuf_h
typedef struct { int x; } cbuf_t;
typedef @handle cbuf_h cbuf_t;
@extern void Cbuf_AddText (cbuf_t *cbuf, string text);
@extern void Cbuf_InsertText (cbuf_t *cbuf, string text);
@extern void Cbuf_Execute (cbuf_t *cbuf);
@extern void Cbuf_Execute_Sets (cbuf_t *cbuf);
@extern void Cbuf_AddText (cbuf_t cbuf, string text);
@extern void Cbuf_InsertText (cbuf_t cbuf, string text);
@extern void Cbuf_Execute (cbuf_t cbuf);
@extern void Cbuf_Execute_Sets (cbuf_t cbuf);
#endif//__ruamoko_cbuf_h

View file

@ -1,7 +1,7 @@
#ifndef __ruamoko_qfile_h
#define __ruamoko_qfile_h
typedef struct _qfile_t *QFile;
typedef @handle _qfile_t QFile;
@extern int Qrename (string old, string new);
@extern int Qremove (string path);

View file

@ -16,6 +16,7 @@ typedef enum {
ty_array,
ty_class,
ty_alias,
ty_handle,
} ty_meta_e;
typedef struct qfot_alias_s {
@ -25,6 +26,11 @@ typedef struct qfot_alias_s {
string name;
} qfot_alias_t;
typedef struct qfot_handle_s {
etype_t type;
string tag;
} qfot_handle_t;
typedef struct qfot_fldptr_s {
etype_t type;
struct qfot_type_s *aux_type;
@ -73,6 +79,7 @@ typedef struct qfot_type_s {
qfot_array_t array;
string class;
qfot_alias_t alias;
qfot_handle_t handle;
};
} qfot_type_t;

View file

@ -1,6 +1,6 @@
#include <cbuf.h>
void Cbuf_AddText (cbuf_t *cbuf, string text) = #0;
void Cbuf_InsertText (cbuf_t *cbuf, string text) = #0;
void Cbuf_Execute (cbuf_t *cbuf) = #0;
void Cbuf_Execute_Sets (cbuf_t *cbuf) = #0;
void Cbuf_AddText (cbuf_t cbuf, string text) = #0;
void Cbuf_InsertText (cbuf_t cbuf, string text) = #0;
void Cbuf_Execute (cbuf_t cbuf) = #0;
void Cbuf_Execute_Sets (cbuf_t cbuf) = #0;

View file

@ -53,6 +53,9 @@ static void type_free (void *t, void *unused)
case ty_alias:
str_free (type.alias.name);
break;
case ty_handle:
str_free (type.handle.tag);
break;
}
obj_free (t);
}
@ -179,6 +182,11 @@ static void type_free (void *t, void *unused)
}
type.alias.full_type = t;
goto hash_type;
case ty_handle:
if (!(type.handle.tag = qdb_get_string (target, type.handle.tag))) {
goto error;
}
goto hash_type;
}
goto error;
hash_type:
@ -197,6 +205,7 @@ error:
int size = 0;
switch (type.meta) {
case ty_handle:
case ty_basic:
size = pr_type_size[type.type];
break;

View file

@ -43,6 +43,8 @@ typedef struct {
void (*emit) (struct def_s *def, void *data, int index);
} struct_def_t;
struct symbol_s *find_handle (struct symbol_s *tag, struct type_s *type);
struct symtab_s *start_struct (int *su, struct symbol_s *tag,
struct symtab_s *parent);
struct symbol_s *find_struct (int su, struct symbol_s *tag,

View file

@ -444,6 +444,7 @@ static const char *ty_meta_names[] = {
"ty_array",
"ty_class",
"ty_alias",
"ty_handle",
};
#define NUM_META ((int)(sizeof (ty_meta_names) / sizeof (ty_meta_names[0])))
const int vector_types = (1 << ev_float)
@ -531,6 +532,9 @@ dump_qfo_types (qfo_t *qfo, int base_address)
type->alias.type, type->alias.aux_type,
type->alias.full_type);
break;
case ty_handle:
printf (" %-5x\n", type->handle.tag);
break;
}
}
}

View file

@ -698,6 +698,7 @@ get_def_type (qfo_t *qfo, pr_ptr_t type)
switch ((ty_meta_e)type_def->meta) {
case ty_alias: //XXX
case ty_basic:
case ty_handle: //XXX
// field, pointer and function types store their basic type in
// the same location.
return type_def->type;
@ -726,6 +727,7 @@ get_type_size (qfo_t *qfo, pr_ptr_t type)
switch ((ty_meta_e)type_def->meta) {
case ty_alias:
return get_type_size (qfo, type_def->alias.aux_type);
case ty_handle: //XXX
case ty_basic:
// field, pointer and function types store their basic type in
// the same location.
@ -776,6 +778,7 @@ get_type_alignment_log (qfo_t *qfo, pr_ptr_t type)
switch ((ty_meta_e)type_def->meta) {
case ty_alias:
return get_type_alignment_log (qfo, type_def->alias.aux_type);
case ty_handle: //XXX
case ty_basic:
// field, pointer and function types store their basic type in
// the same location.

View file

@ -277,6 +277,19 @@ qfo_encode_alias (type_t *type, defspace_t *space)
return def;
}
static def_t *
qfo_encode_handle (type_t *type, defspace_t *space)
{
qfot_type_t *enc;
def_t *def;
def = qfo_new_encoding (type, sizeof (enc->handle), space);
enc = D_POINTER (qfot_type_t, def);
enc->handle.type = type->type;
ENC_STR (enc->handle.tag, type->name);
return def;
}
def_t *
qfo_encode_type (type_t *type, defspace_t *space)
{
@ -290,6 +303,7 @@ qfo_encode_type (type_t *type, defspace_t *space)
qfo_encode_array, // ty_array
qfo_encode_class, // ty_class
qfo_encode_alias, // ty_alias
qfo_encode_handle, // ty_handle
};
if (type->type_def && type->type_def->external) {

View file

@ -449,6 +449,7 @@ static keyword_t keywords[] = {
{"@system", SYSTEM, },
{"@overload", OVERLOAD, },
{"@attribute", ATTRIBUTE, },
{"@handle", HANDLE, },
};
static const char *

View file

@ -153,7 +153,7 @@ int yylex (void);
%token RETURN AT_RETURN ELLIPSIS
%token NIL GOTO SWITCH CASE DEFAULT ENUM
%token ARGS TYPEDEF EXTERN STATIC SYSTEM OVERLOAD NOT ATTRIBUTE
%token <op> STRUCT
%token <op> STRUCT HANDLE
%token <spec> TYPE_SPEC TYPE_NAME TYPE_QUAL
%token <spec> OBJECT_NAME
%token CLASS DEFS ENCODE END IMPLEMENTATION INTERFACE PRIVATE
@ -1085,6 +1085,19 @@ struct_specifier
symtab_addsymbol (tab, sym);
}
}
| HANDLE tag
{
symbol_t *sym = find_handle ($2, 0);
sym->type = find_type (sym->type);
$$ = make_spec (sym->type, 0, 0, 0);
if (!sym->table) {
symtab_t *tab = current_symtab;
while (tab->parent && tab->type == stab_struct) {
tab = tab->parent;
}
symtab_addsymbol (tab, sym);
}
}
;
struct_list

View file

@ -125,6 +125,18 @@ start_struct (int *su, symbol_t *tag, symtab_t *parent)
return new_symtab (parent, stab_struct);
}
symbol_t *
find_handle (symbol_t *tag, type_t *type)
{
symbol_t *sym = find_tag (ty_handle, tag, type);
if (sym->type->type == ev_invalid) {
sym->type->type = ev_func;
sym->type->width = 1;
sym->type->alignment = 1;
}
return sym;
}
symbol_t *
find_struct (int su, symbol_t *tag, type_t *type)
{

View file

@ -308,6 +308,7 @@ copy_chain (type_t *type, type_t *append)
case ty_enum:
case ty_class:
case ty_alias: //XXX is this correct?
case ty_handle:
internal_error (0, "copy object type %d", type->meta);
}
}
@ -365,6 +366,7 @@ append_type (type_t *type, type_t *new)
case ty_enum:
case ty_class:
case ty_alias: //XXX is this correct?
case ty_handle:
internal_error (0, "append to object type");
}
}
@ -432,6 +434,9 @@ types_same (type_t *a, type_t *b)
return (a->name == b->name
&& a->t.alias.aux_type == b->t.alias.aux_type
&& a->t.alias.full_type == b->t.alias.full_type);
case ty_handle:
// names have gone through save_string
return a->name == b->name;
}
internal_error (0, "we be broke");
}
@ -560,6 +565,8 @@ find_type (type_t *type)
case ty_alias:
type->t.alias.aux_type = find_type (type->t.alias.aux_type);
break;
case ty_handle:
break;
}
}
@ -807,6 +814,9 @@ print_type_str (dstring_t *str, const type_t *type)
return;
}
switch (type->meta) {
case ty_handle:
dasprintf (str, " handle %s", type->name);
return;
case ty_alias:
dasprintf (str, "({%s=", type->name);
print_type_str (str, type->t.alias.aux_type);
@ -996,6 +1006,9 @@ encode_type (dstring_t *encoding, const type_t *type)
if (!type)
return;
switch (type->meta) {
case ty_handle:
dasprintf (encoding, "{%s$}", type->name);
return;
case ty_alias:
dasprintf (encoding, "{%s>", type->name ? type->name : "");
encode_type (encoding, type->t.alias.aux_type);
@ -1331,6 +1344,7 @@ int
type_size (const type_t *type)
{
switch (type->meta) {
case ty_handle:
case ty_basic:
return pr_type_size[type->type] * type->width;
case ty_struct:
@ -1373,6 +1387,7 @@ type_width (const type_t *type)
return 4;
}
return type->width;
case ty_handle:
case ty_struct:
case ty_union:
return 1;