394 lines
8.7 KiB
C
394 lines
8.7 KiB
C
#include <blue/ds/hashmap.h>
|
|
#include <blue/ds/list.h>
|
|
#include <blue/ds/string.h>
|
|
#include <mie/ctx.h>
|
|
#include <mie/dialect/dialect.h>
|
|
#include <mie/dialect/type.h>
|
|
#include <mie/ir/op.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#define DIALECT_NS_ID \
|
|
MIE_ID(0xa1, 0x35, 0x01, 0x1b, 0xe4, 0x71, 0x46, 0x08, 0x92, 0xd4, \
|
|
0xe6, 0x5a, 0x40, 0xba, 0x7f, 0xee)
|
|
|
|
#define TYPE_NS_ID \
|
|
MIE_ID(0xf5, 0x4e, 0xc5, 0x8c, 0xc0, 0x1e, 0x48, 0x47, 0xb5, 0xf4, \
|
|
0x7b, 0xb9, 0x6b, 0x47, 0xca, 0x48)
|
|
|
|
struct ctx_int_cache_entry {
|
|
b_btree_node i_node;
|
|
// struct mie_type i_type;
|
|
b_btree i_values;
|
|
};
|
|
|
|
struct ctx_int_value_cache_entry {
|
|
b_btree_node i_node;
|
|
// struct mie_int i_value;
|
|
};
|
|
|
|
#if 0
|
|
|
|
B_BTREE_DEFINE_SIMPLE_INSERT(
|
|
struct ctx_int_cache_entry, i_node, i_type.t_width, put_cached_int_type)
|
|
B_BTREE_DEFINE_SIMPLE_GET(
|
|
struct ctx_int_cache_entry, unsigned int, i_node, i_type.t_width,
|
|
get_cached_int_type)
|
|
|
|
B_BTREE_DEFINE_SIMPLE_INSERT(
|
|
struct ctx_int_value_cache_entry, i_node, i_value.i_value,
|
|
put_cached_int_value)
|
|
B_BTREE_DEFINE_SIMPLE_GET(
|
|
struct ctx_int_value_cache_entry, int64_t, i_node, i_value.i_value,
|
|
get_cached_int_value)
|
|
|
|
struct mie_ctx *mie_ctx_create(void)
|
|
{
|
|
struct mie_ctx *out = malloc(sizeof *out);
|
|
|
|
if (!out) {
|
|
return NULL;
|
|
}
|
|
|
|
memset(out, 0x0, sizeof *out);
|
|
|
|
out->ctx_true = MIE_CONST(mie_ctx_get_int(out, 1, 1));
|
|
out->ctx_false = MIE_CONST(mie_ctx_get_int(out, 0, 1));
|
|
|
|
out->ctx_null = malloc(sizeof *out->ctx_null);
|
|
if (!out->ctx_null) {
|
|
mie_ctx_destroy(out);
|
|
return NULL;
|
|
}
|
|
|
|
mie_value_init(out->ctx_null, MIE_VALUE_NONE);
|
|
|
|
out->ctx_sel_cache = b_hashmap_create(free, free);
|
|
out->ctx_string_cache = b_hashmap_create(free, free);
|
|
|
|
return out;
|
|
}
|
|
|
|
void mie_ctx_destroy(struct mie_ctx *ctx)
|
|
{
|
|
ctx->ctx_true = NULL;
|
|
ctx->ctx_false = NULL;
|
|
|
|
b_btree_node *node = b_btree_first(&ctx->ctx_int_cache);
|
|
while (node) {
|
|
struct ctx_int_cache_entry *entry
|
|
= b_unbox(struct ctx_int_cache_entry, node, i_node);
|
|
b_btree_node *next = b_btree_next(node);
|
|
b_btree_delete(&ctx->ctx_int_cache, node);
|
|
|
|
b_btree_node *node2 = b_btree_first(&entry->i_values);
|
|
while (node2) {
|
|
struct ctx_int_value_cache_entry *value = b_unbox(
|
|
struct ctx_int_value_cache_entry, node2, i_node);
|
|
b_btree_node *next2 = b_btree_next(node2);
|
|
b_btree_delete(&entry->i_values, node2);
|
|
free(value);
|
|
node2 = next2;
|
|
}
|
|
|
|
free(entry);
|
|
node = next;
|
|
}
|
|
|
|
const size_t nr_types = sizeof ctx->ctx_types / sizeof ctx->ctx_types[0];
|
|
for (size_t i = 0; i < nr_types; i++) {
|
|
if (ctx->ctx_types[i]) {
|
|
mie_value_destroy(MIE_VALUE(ctx->ctx_types[i]));
|
|
ctx->ctx_types[i] = NULL;
|
|
}
|
|
}
|
|
|
|
if (ctx->ctx_null) {
|
|
mie_value_destroy(ctx->ctx_null);
|
|
}
|
|
|
|
b_hashmap_unref(ctx->ctx_sel_cache);
|
|
|
|
free(ctx);
|
|
}
|
|
|
|
struct mie_type *mie_ctx_get_type(struct mie_ctx *ctx, enum mie_type_id type_id)
|
|
{
|
|
if (type_id == MIE_TYPE_INT) {
|
|
return NULL;
|
|
}
|
|
|
|
if (ctx->ctx_types[type_id]) {
|
|
return ctx->ctx_types[type_id];
|
|
}
|
|
|
|
struct mie_type *type = mie_type_create();
|
|
if (!type) {
|
|
return NULL;
|
|
}
|
|
|
|
type->t_id = type_id;
|
|
|
|
ctx->ctx_types[type_id] = type;
|
|
return type;
|
|
}
|
|
|
|
struct mie_value *mie_ctx_get_null(struct mie_ctx *ctx)
|
|
{
|
|
return ctx->ctx_null;
|
|
}
|
|
|
|
struct mie_type *mie_ctx_get_int_type(struct mie_ctx *ctx, unsigned int nr_bits)
|
|
{
|
|
struct ctx_int_cache_entry *entry
|
|
= get_cached_int_type(&ctx->ctx_int_cache, nr_bits);
|
|
|
|
if (entry) {
|
|
return &entry->i_type;
|
|
}
|
|
|
|
entry = malloc(sizeof *entry);
|
|
if (!entry) {
|
|
return NULL;
|
|
}
|
|
|
|
memset(entry, 0x0, sizeof *entry);
|
|
|
|
entry->i_type.t_id = MIE_TYPE_INT;
|
|
entry->i_type.t_width = nr_bits;
|
|
|
|
put_cached_int_type(&ctx->ctx_int_cache, entry);
|
|
return &entry->i_type;
|
|
}
|
|
|
|
struct mie_value *mie_ctx_get_bool(struct mie_ctx *ctx, bool val)
|
|
{
|
|
return MIE_VALUE(val ? ctx->ctx_true : ctx->ctx_false);
|
|
}
|
|
|
|
struct mie_value *mie_ctx_get_int(
|
|
struct mie_ctx *ctx, long long val, unsigned int nr_bits)
|
|
{
|
|
struct ctx_int_cache_entry *entry
|
|
= get_cached_int_type(&ctx->ctx_int_cache, nr_bits);
|
|
|
|
if (!entry) {
|
|
entry = malloc(sizeof *entry);
|
|
if (!entry) {
|
|
return NULL;
|
|
}
|
|
|
|
memset(entry, 0x0, sizeof *entry);
|
|
|
|
entry->i_type.t_id = MIE_TYPE_INT;
|
|
entry->i_type.t_width = nr_bits;
|
|
|
|
put_cached_int_type(&ctx->ctx_int_cache, entry);
|
|
}
|
|
|
|
struct ctx_int_value_cache_entry *value
|
|
= get_cached_int_value(&entry->i_values, val);
|
|
if (value) {
|
|
return MIE_VALUE(&value->i_value);
|
|
}
|
|
|
|
value = malloc(sizeof *value);
|
|
if (!value) {
|
|
return NULL;
|
|
}
|
|
|
|
memset(value, 0x0, sizeof *value);
|
|
|
|
mie_const_init(&value->i_value.i_base, &entry->i_type);
|
|
value->i_value.i_value = val;
|
|
|
|
put_cached_int_value(&entry->i_values, value);
|
|
|
|
return MIE_VALUE(&value->i_value);
|
|
}
|
|
|
|
struct mie_value *mie_ctx_get_selector(struct mie_ctx *ctx, const char *sel)
|
|
{
|
|
b_hashmap_key key = {
|
|
.key_data = sel,
|
|
.key_size = strlen(sel),
|
|
};
|
|
|
|
const b_hashmap_value *cache_entry
|
|
= b_hashmap_get(ctx->ctx_sel_cache, &key);
|
|
|
|
if (cache_entry) {
|
|
return cache_entry->value_data;
|
|
}
|
|
|
|
struct mie_selector *sel_value = malloc(sizeof *sel_value);
|
|
if (!sel_value) {
|
|
return NULL;
|
|
}
|
|
|
|
struct mie_type *sel_type = mie_ctx_get_type(ctx, MIE_TYPE_SELECTOR);
|
|
mie_const_init(&sel_value->sel_base, sel_type);
|
|
sel_value->sel_value = b_strdup(sel);
|
|
|
|
key.key_data = sel_value->sel_value;
|
|
|
|
b_hashmap_value hashmap_value = {
|
|
.value_data = sel_value,
|
|
.value_size = sizeof *sel_value,
|
|
};
|
|
|
|
b_hashmap_put(ctx->ctx_sel_cache, &key, &hashmap_value);
|
|
|
|
return MIE_VALUE(sel_value);
|
|
}
|
|
|
|
struct mie_value *mie_ctx_get_string(struct mie_ctx *ctx, const char *s)
|
|
{
|
|
b_hashmap_key key = {
|
|
.key_data = s,
|
|
.key_size = strlen(s),
|
|
};
|
|
|
|
const b_hashmap_value *cache_entry
|
|
= b_hashmap_get(ctx->ctx_string_cache, &key);
|
|
|
|
if (cache_entry) {
|
|
return cache_entry->value_data;
|
|
}
|
|
|
|
struct mie_string *string_value = malloc(sizeof *string_value);
|
|
if (!string_value) {
|
|
return NULL;
|
|
}
|
|
|
|
struct mie_type *string_type = mie_ctx_get_type(ctx, MIE_TYPE_STR);
|
|
mie_const_init(&string_value->s_base, string_type);
|
|
string_value->s_value = b_strdup(s);
|
|
|
|
key.key_data = string_value->s_value;
|
|
|
|
b_hashmap_value hashmap_value = {
|
|
.value_data = string_value,
|
|
.value_size = sizeof *string_value,
|
|
};
|
|
|
|
b_hashmap_put(ctx->ctx_string_cache, &key, &hashmap_value);
|
|
|
|
return MIE_VALUE(string_value);
|
|
}
|
|
|
|
struct mie_value *mie_ctx_create_array(struct mie_ctx *ctx)
|
|
{
|
|
struct mie_type *array_type = mie_ctx_get_type(ctx, MIE_TYPE_ARRAY);
|
|
struct mie_array *array = malloc(sizeof *array);
|
|
|
|
if (!array) {
|
|
return NULL;
|
|
}
|
|
|
|
memset(array, 0x0, sizeof *array);
|
|
mie_const_init(&array->a_base, array_type);
|
|
|
|
array->a_values = b_list_create();
|
|
|
|
return MIE_VALUE(array);
|
|
}
|
|
#endif
|
|
|
|
struct mie_ctx *mie_ctx_create(void)
|
|
{
|
|
struct mie_ctx *out = malloc(sizeof *out);
|
|
|
|
if (!out) {
|
|
return NULL;
|
|
}
|
|
|
|
memset(out, 0x0, sizeof *out);
|
|
|
|
mie_id dialects_ns = DIALECT_NS_ID;
|
|
mie_id_map_init(&out->ctx_dialects, &dialects_ns);
|
|
|
|
mie_id types_ns = TYPE_NS_ID;
|
|
mie_id_map_init(&out->ctx_types, &types_ns);
|
|
|
|
return out;
|
|
}
|
|
|
|
bool mie_ctx_resolve_op(const struct mie_ctx *ctx, struct mie_op *op)
|
|
{
|
|
if (op->op_flags & MIE_OP_F_RESOLVED) {
|
|
return true;
|
|
}
|
|
|
|
const char *dialect_name = NULL, *op_name = NULL;
|
|
|
|
char *dot = strchr(op->op_name, '.');
|
|
if (dot) {
|
|
*dot = 0;
|
|
dialect_name = op->op_name;
|
|
op_name = dot + 1;
|
|
} else {
|
|
dialect_name = NULL;
|
|
op_name = op->op_name;
|
|
}
|
|
|
|
const struct mie_dialect *dialect = mie_ctx_get_dialect(ctx, dialect_name);
|
|
if (dot) {
|
|
*dot = '.';
|
|
}
|
|
|
|
/* dialect_name is no longer valid after this point */
|
|
dialect_name = NULL;
|
|
|
|
if (!dialect) {
|
|
return false;
|
|
}
|
|
|
|
const struct mie_dialect_op *op_info
|
|
= mie_dialect_get_op(dialect, op_name);
|
|
if (!op) {
|
|
return false;
|
|
}
|
|
|
|
op->op_dialect = dialect;
|
|
op->op_info = op_info;
|
|
|
|
free(op->op_name);
|
|
op->op_name = NULL;
|
|
|
|
op->op_flags |= MIE_OP_F_RESOLVED;
|
|
|
|
return true;
|
|
}
|
|
|
|
struct mie_dialect *mie_ctx_get_dialect(const struct mie_ctx *ctx, const char *name)
|
|
{
|
|
b_rope name_rope = B_ROPE_CSTR(name);
|
|
mie_id id;
|
|
mie_id_init_ns(&id, mie_id_map_get_ns(&ctx->ctx_dialects), &name_rope);
|
|
|
|
mie_id *target = mie_id_map_get(&ctx->ctx_dialects, &id);
|
|
return b_unbox(struct mie_dialect, target, d_id);
|
|
}
|
|
|
|
struct mie_dialect_type *mie_ctx_get_dialect_type(
|
|
const struct mie_ctx *ctx, const char *dialect_name, const char *type_name)
|
|
{
|
|
b_rope dialect_name_rope = B_ROPE_CSTR(dialect_name);
|
|
mie_id id;
|
|
mie_id_init_ns(
|
|
&id, mie_id_map_get_ns(&ctx->ctx_dialects), &dialect_name_rope);
|
|
|
|
mie_id *target = mie_id_map_get(&ctx->ctx_dialects, &id);
|
|
struct mie_dialect *dialect = b_unbox(struct mie_dialect, target, d_id);
|
|
if (!dialect) {
|
|
return NULL;
|
|
}
|
|
|
|
b_rope type_name_rope = B_ROPE_CSTR(type_name);
|
|
mie_id_init_ns(&id, mie_id_map_get_ns(&dialect->d_types), &type_name_rope);
|
|
target = mie_id_map_get(&dialect->d_types, &id);
|
|
|
|
return b_unbox(struct mie_dialect_type, target, ty_id);
|
|
}
|