mie: add data structures for registering and applying extensible traits

This commit is contained in:
2026-01-08 19:21:17 +00:00
parent 8ad3f36288
commit c686c31ca0
3 changed files with 264 additions and 0 deletions

View File

@@ -0,0 +1,39 @@
#ifndef MIE_TRAIT_TRAIT_TABLE_H_
#define MIE_TRAIT_TRAIT_TABLE_H_
#include <blue/core/btree.h>
#include <mie/id.h>
#include <mie/misc.h>
#include <mie/status.h>
/* for IR objects that support traits (ops, types, etc), this struct can be used
* to store and retrieve references to the traits that apply */
struct mie_trait_table {
struct mie_id_map tr_unique;
struct mie_id_map tr_generic;
};
struct mie_trait_table_iterator {
const struct mie_trait *it_trait;
b_queue_entry *_e;
};
MIE_API void mie_trait_table_init(struct mie_trait_table *out);
MIE_API void mie_trait_table_cleanup(struct mie_trait_table *table);
/* retrieve a trait based on its name. this function can only be used to
* retrieve non-parametised traits. to retrieve parametised traits, use
* mie_trait_table_get_generic. */
MIE_API const struct mie_trait *mie_trait_table_get_unique(
const struct mie_trait_table *table, const char *dialect_name,
const char *trait_name);
MIE_API enum mie_status mie_trait_table_get_generic(
const struct mie_trait_table *table, const char *dialect_name,
const char *trait_name, struct mie_trait_table_iterator *it);
MIE_API enum mie_status mie_trait_table_put(
struct mie_trait_table *table, const struct mie_trait *trait);
MIE_API enum mie_status mie_trait_table_iterator_move_next(
struct mie_trait_table_iterator *it);
#endif

View File

@@ -0,0 +1,42 @@
#ifndef MIE_TRAIT_TRAIT_H_
#define MIE_TRAIT_TRAIT_H_
#include <mie/id.h>
struct mie_trait;
enum mie_trait_flags {
/* a trait user can only apply the trait once. this is assumed to be the
* case unless a trait is parametised, in which case this flag can be
* used to prevent more than one specialisation from being used. */
MIE_TRAIT_F_UNIQUE = 0x01u,
MIE_TRAIT_F_PARAMETISED = 0x02u,
};
/* used to define a trait */
struct mie_trait_definition {
/* ID for the generic trait */
mie_id tr_id;
char *tr_name;
enum mie_trait_flags tr_flags;
/* the size of any corresponding struct mie_trait instances */
size_t tr_data_size;
enum mie_status (*tr_build_id)(
const struct mie_trait_definition *, const struct mie_trait *,
struct mie_id_builder *);
enum mie_status (*tr_print)(
const struct mie_trait_definition *, const struct mie_trait *,
b_stream *);
};
/* used to link an op/type/etc to a trait. if the trait is parametised, this
* struct includes any parameter values. */
struct mie_trait {
/* this is NOT the same as tr_def->tr_id */
mie_id tr_id;
const struct mie_trait_definition *tr_def;
};
#endif

183
mie/trait/trait-table.c Normal file
View File

@@ -0,0 +1,183 @@
#include <mie/trait/trait-table.h>
#include <mie/trait/trait.h>
#define UNIQUE_TRAIT_NS_ID \
MIE_ID(0xd6, 0xb6, 0x72, 0xae, 0xef, 0x65, 0x40, 0x24, 0xaa, 0x6d, \
0xef, 0xfc, 0x37, 0xda, 0x5c, 0x88)
#define GENERIC_TRAIT_NS_ID \
MIE_ID(0x1a, 0x60, 0xbe, 0x20, 0xa6, 0xa0, 0x43, 0x3a, 0xb1, 0x2c, \
0x33, 0x9a, 0xac, 0x52, 0xa0, 0xca)
struct unique_trait {
mie_id u_id;
const struct mie_trait *u_trait;
};
struct generic_trait {
/* generic trait ID. */
mie_id g_id;
/* list of struct unique_trait */
b_queue g_traits;
};
static struct unique_trait *unique_trait_create(const struct mie_trait *trait)
{
struct unique_trait *out = malloc(sizeof *out);
if (!out) {
return NULL;
}
memset(out, 0x0, sizeof *out);
out->u_id = trait->tr_id;
out->u_trait = trait;
return out;
}
static void unique_trait_destroy(struct unique_trait *trait)
{
free(trait);
}
static struct generic_trait *generic_trait_create(const struct mie_trait *trait)
{
struct generic_trait *out = malloc(sizeof *out);
if (!out) {
return NULL;
}
memset(out, 0x0, sizeof *out);
out->g_id = trait->tr_def->tr_id;
struct unique_trait *entry = unique_trait_create(trait);
if (!entry) {
free(out);
return NULL;
}
b_queue_push_back(&out->g_traits, &entry->u_id.e_entry);
return out;
}
static void generic_trait_destroy(struct generic_trait *trait)
{
b_queue_entry *cur = b_queue_first(&trait->g_traits);
while (cur) {
b_queue_entry *next = b_queue_next(cur);
b_queue_delete(&trait->g_traits, cur);
struct unique_trait *u
= b_unbox(struct unique_trait, cur, u_id.e_entry);
unique_trait_destroy(u);
cur = next;
}
free(trait);
}
void mie_trait_table_init(struct mie_trait_table *out)
{
memset(out, 0x0, sizeof *out);
mie_id unique_ns = UNIQUE_TRAIT_NS_ID;
mie_id_map_init(&out->tr_unique, &unique_ns);
mie_id generic_ns = GENERIC_TRAIT_NS_ID;
mie_id_map_init(&out->tr_generic, &generic_ns);
}
void mie_trait_table_cleanup(struct mie_trait_table *table)
{
/* TODO */
}
const struct mie_trait *mie_trait_table_get_unique(
const struct mie_trait_table *table, const char *dialect_name,
const char *trait_name)
{
mie_id id;
struct mie_id_builder id_ctx;
mie_id_builder_begin(&id_ctx, mie_id_map_get_ns(&table->tr_unique));
mie_id_builder_add_cstr(&id_ctx, dialect_name);
mie_id_builder_add_char(&id_ctx, '.');
mie_id_builder_add_cstr(&id_ctx, trait_name);
mie_id_builder_end(&id_ctx, &id);
const mie_id *result = mie_id_map_get(&table->tr_unique, &id);
const struct unique_trait *entry
= b_unbox(struct unique_trait, entry, u_id);
return entry ? entry->u_trait : NULL;
}
static enum mie_status put_unique_trait(
struct mie_trait_table *table, const struct mie_trait *trait)
{
return MIE_SUCCESS;
}
static enum mie_status put_generic_trait(
struct mie_trait_table *table, const struct mie_trait *trait)
{
return MIE_SUCCESS;
}
enum mie_status mie_trait_table_put(
struct mie_trait_table *table, const struct mie_trait *trait)
{
if (trait->tr_def->tr_flags & MIE_TRAIT_F_PARAMETISED) {
return put_generic_trait(table, trait);
}
return put_unique_trait(table, trait);
}
enum mie_status mie_trait_table_get_generic(
const struct mie_trait_table *table, const char *dialect_name,
const char *trait_name, struct mie_trait_table_iterator *it)
{
mie_id id;
struct mie_id_builder id_ctx;
mie_id_builder_begin(&id_ctx, mie_id_map_get_ns(&table->tr_unique));
mie_id_builder_add_cstr(&id_ctx, dialect_name);
mie_id_builder_add_char(&id_ctx, '.');
mie_id_builder_add_cstr(&id_ctx, trait_name);
mie_id_builder_end(&id_ctx, &id);
const mie_id *result = mie_id_map_get(&table->tr_unique, &id);
const struct generic_trait *entry
= b_unbox(struct generic_trait, entry, g_id);
if (!entry || b_queue_empty(&entry->g_traits)) {
return MIE_ERR_NO_ENTRY;
}
memset(it, 0x0, sizeof *it);
it->_e = b_queue_first(&entry->g_traits);
struct unique_trait *trait
= b_unbox(struct unique_trait, it->_e, u_id.e_entry);
it->it_trait = trait->u_trait;
return MIE_SUCCESS;
}
enum mie_status mie_trait_table_iterator_move_next(
struct mie_trait_table_iterator *it)
{
if (!it->_e) {
return MIE_ERR_NO_ENTRY;
}
it->_e = b_queue_next(it->_e);
if (!it->_e) {
return MIE_ERR_NO_ENTRY;
}
struct unique_trait *trait
= b_unbox(struct unique_trait, it->_e, u_id.e_entry);
it->it_trait = trait->u_trait;
return MIE_SUCCESS;
}