mie: add data structures for registering and applying extensible traits
This commit is contained in:
39
mie/include/mie/trait/trait-table.h
Normal file
39
mie/include/mie/trait/trait-table.h
Normal 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
|
||||
42
mie/include/mie/trait/trait.h
Normal file
42
mie/include/mie/trait/trait.h
Normal 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
183
mie/trait/trait-table.c
Normal 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;
|
||||
}
|
||||
Reference in New Issue
Block a user