Files
mie/mie/ctx.c

487 lines
13 KiB
C

#include <blue/core/bstr.h>
#include <blue/ds/hashmap.h>
#include <blue/ds/list.h>
#include <blue/ds/string.h>
#include <mie/attribute/attribute-definition.h>
#include <mie/ctx.h>
#include <mie/dialect/arith.h>
#include <mie/dialect/builtin.h>
#include <mie/dialect/dialect.h>
#include <mie/dialect/index.h>
#include <mie/interface/interface-definition.h>
#include <mie/ir/op-definition.h>
#include <mie/ir/op.h>
#include <mie/pass/pass-definition.h>
#include <mie/pass/pass.h>
#include <mie/trait/trait-definition.h>
#include <mie/trait/trait.h>
#include <mie/type/function.h>
#include <mie/type/storage.h>
#include <mie/type/type-definition.h>
#include <mie/type/type.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)
#define TRAIT_NS_ID \
MIE_ID(0xeb, 0x02, 0xcc, 0xe5, 0x32, 0x80, 0x4e, 0xc3, 0x84, 0xf3, \
0xc0, 0x07, 0x72, 0xf0, 0x4c, 0xca)
#define ATTRIBUTE_NS_ID \
MIE_ID(0xc6, 0x94, 0x38, 0x34, 0xdb, 0x08, 0x45, 0xc7, 0xb9, 0x89, \
0x69, 0x82, 0x7a, 0x9d, 0x42, 0xd8)
#define PASS_NS_ID \
MIE_ID(0x76, 0xfc, 0xdd, 0xb5, 0xc0, 0x20, 0x47, 0x13, 0x8d, 0xfa, \
0x3f, 0x28, 0x2f, 0x81, 0x6d, 0x7d)
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);
mie_id traits_ns = TRAIT_NS_ID;
mie_id_map_init(&out->ctx_traits, &traits_ns);
mie_id attributes_ns = ATTRIBUTE_NS_ID;
mie_id_map_init(&out->ctx_attributes, &attributes_ns);
mie_id pass_ns = PASS_NS_ID;
mie_id_map_init(&out->ctx_passes, &pass_ns);
return out;
}
struct mie_op *mie_ctx_create_op(
const struct mie_ctx *ctx, const char *dialect, const char *op)
{
const struct mie_op_definition *def
= mie_ctx_get_op_definition(ctx, dialect, op);
if (!def) {
return NULL;
}
struct mie_op *out = mie_op_create();
if (!out) {
return NULL;
}
out->op_flags |= MIE_OP_F_OP_RESOLVED;
out->op_info = def;
out->op_dialect = def->op_parent;
return out;
}
bool mie_ctx_resolve_op(const struct mie_ctx *ctx, struct mie_op *op)
{
if (op->op_flags & MIE_OP_F_OP_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_op_definition *op_info
= mie_dialect_get_op(dialect, op_name);
if (!op_info) {
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_OP_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);
}
const struct mie_op_definition *mie_ctx_get_op_definition(
const struct mie_ctx *ctx, const char *dialect_name, const char *op_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 op_name_rope = B_ROPE_CSTR(op_name);
mie_id_init_ns(&id, mie_id_map_get_ns(&dialect->d_ops), &op_name_rope);
target = mie_id_map_get(&dialect->d_ops, &id);
return b_unbox(struct mie_op_definition, target, op_id);
}
struct mie_type_definition *mie_ctx_get_type_definition(
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_type_definition, target, ty_id);
}
const struct mie_trait_definition *mie_ctx_get_trait_definition(
const struct mie_ctx *ctx, const char *dialect_name, const char *trait_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 trait_name_rope = B_ROPE_CSTR(trait_name);
mie_id_init_ns(&id, mie_id_map_get_ns(&dialect->d_traits), &trait_name_rope);
target = mie_id_map_get(&dialect->d_traits, &id);
return b_unbox(struct mie_trait_definition, target, tr_id);
}
const struct mie_attribute_definition *mie_ctx_get_attribute_definition(
const struct mie_ctx *ctx, const char *dialect_name,
const char *attribute_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 attribute_name_rope = B_ROPE_CSTR(attribute_name);
mie_id_init_ns(
&id, mie_id_map_get_ns(&dialect->d_attributes),
&attribute_name_rope);
target = mie_id_map_get(&dialect->d_attributes, &id);
return b_unbox(struct mie_attribute_definition, target, a_id);
}
const struct mie_interface_definition *mie_ctx_get_interface_definition(
const struct mie_ctx *ctx, const char *dialect_name,
const char *interface_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 interface_name_rope = B_ROPE_CSTR(interface_name);
mie_id_init_ns(
&id, mie_id_map_get_ns(&dialect->d_interfaces),
&interface_name_rope);
target = mie_id_map_get(&dialect->d_interfaces, &id);
return b_unbox(struct mie_interface_definition, target, if_id);
}
struct mie_type *mie_ctx_get_type(
struct mie_ctx *ctx, const char *dialect_name, const char *type_name)
{
char full_name[256];
snprintf(full_name, sizeof full_name, "%s.%s", dialect_name, type_name);
b_rope full_name_rope = B_ROPE_CSTR(full_name);
mie_id id;
mie_id_init_ns(&id, mie_id_map_get_ns(&ctx->ctx_types), &full_name_rope);
mie_id *target = mie_id_map_get(&ctx->ctx_types, &id);
struct mie_type *type = b_unbox(struct mie_type, target, ty_id);
if (type) {
return type;
}
struct mie_type_definition *type_info
= mie_ctx_get_type_definition(ctx, dialect_name, type_name);
if (!type_info /* || (type_info->ty_flags & MIE_DIALECT_TYPE_PARAMETISED) */) {
/* cannot initialise unknown or parametised types */
return NULL;
}
if (type_info->ty_data_size < sizeof(struct mie_type)) {
/* invalid type info */
return NULL;
}
type = malloc(type_info->ty_data_size);
if (!type) {
return NULL;
}
memset(type, 0x0, sizeof *type);
type->ty_def = type_info;
type->ty_name = b_bstr_fmt(NULL, "%s.%s", dialect_name, type_name);
if (type_info->ty_init) {
type_info->ty_init(type_info, type);
}
mie_id_map_put(&ctx->ctx_types, &type->ty_id, &full_name_rope);
return type;
}
const struct mie_trait *mie_ctx_get_trait(
struct mie_ctx *ctx, const char *dialect_name, const char *trait_name)
{
char full_name[256];
snprintf(full_name, sizeof full_name, "%s.%s", dialect_name, trait_name);
b_rope full_name_rope = B_ROPE_CSTR(full_name);
mie_id id;
mie_id_init_ns(&id, mie_id_map_get_ns(&ctx->ctx_traits), &full_name_rope);
mie_id *target = mie_id_map_get(&ctx->ctx_traits, &id);
struct mie_trait *trait = b_unbox(struct mie_trait, target, tr_id);
if (trait) {
return trait;
}
const struct mie_trait_definition *trait_info
= mie_ctx_get_trait_definition(ctx, dialect_name, trait_name);
if (!trait_info /* || (trait_info->ty_flags & MIE_DIALECT_TYPE_PARAMETISED) */) {
/* cannot initialise unknown or parametised traits */
return NULL;
}
if (trait_info->tr_data_size < sizeof(struct mie_trait)) {
/* invalid trait info */
return NULL;
}
trait = malloc(trait_info->tr_data_size);
if (!trait) {
return NULL;
}
memset(trait, 0x0, sizeof trait_info->tr_data_size);
trait->tr_def = trait_info;
trait->tr_name = b_bstr_fmt(NULL, "%s.%s", dialect_name, trait_name);
if (trait_info->tr_init) {
trait_info->tr_init(trait_info, trait);
}
mie_id_map_put(&ctx->ctx_traits, &trait->tr_id, &full_name_rope);
return trait;
}
struct mie_type *mie_ctx_get_storage_type(
struct mie_ctx *ctx, const struct mie_type **parts, size_t nr_parts)
{
struct mie_id_builder id_builder;
mie_id_builder_begin(&id_builder, &ctx->ctx_types.map_ns_id);
mie_storage_type_build_id(&id_builder, parts, nr_parts);
mie_id id;
mie_id_builder_end(&id_builder, &id);
mie_id *target = mie_id_map_get(&ctx->ctx_types, &id);
struct mie_type *type = b_unbox(struct mie_type, target, ty_id);
if (type) {
return type;
}
struct mie_storage_type *new_type = mie_storage_type_create();
for (size_t i = 0; i < nr_parts; i++) {
mie_storage_type_add_part(new_type, parts[i]);
}
new_type->st_base.ty_id = id;
mie_id_map_put_id(&ctx->ctx_types, &new_type->st_base.ty_id);
return (struct mie_type *)new_type;
}
struct mie_type *mie_ctx_get_function_type(
struct mie_ctx *ctx, const struct mie_type **in, size_t nr_in,
const struct mie_type **out, size_t nr_out)
{
struct mie_id_builder id_builder;
mie_id_builder_begin(&id_builder, &ctx->ctx_types.map_ns_id);
mie_function_type_build_id(&id_builder, in, nr_in, out, nr_out);
mie_id id;
mie_id_builder_end(&id_builder, &id);
mie_id *target = mie_id_map_get(&ctx->ctx_types, &id);
struct mie_type *type = b_unbox(struct mie_type, target, ty_id);
if (type) {
return type;
}
struct mie_function_type *new_type = mie_function_type_create();
for (size_t i = 0; i < nr_in; i++) {
mie_function_type_add_in_part(new_type, in[i]);
}
for (size_t i = 0; i < nr_out; i++) {
mie_function_type_add_out_part(new_type, out[i]);
}
new_type->func_base.ty_id = id;
mie_id_map_put_id(&ctx->ctx_types, &new_type->func_base.ty_id);
return (struct mie_type *)new_type;
}
enum mie_status mie_ctx_register_pass(
struct mie_ctx *ctx, struct mie_pass_definition *pass)
{
if (pass->p_data_size < sizeof(struct mie_pass)) {
return MIE_ERR_INVALID_ARGUMENT;
}
switch (pass->p_type) {
case MIE_PASS_ANALYSE:
case MIE_PASS_TRANSFORM:
break;
default:
return MIE_ERR_INVALID_ARGUMENT;
}
mie_id id;
struct mie_id_builder id_builder;
mie_id_builder_begin(&id_builder, mie_id_map_get_ns(&ctx->ctx_passes));
mie_id_builder_add_cstr(&id_builder, pass->p_name);
mie_id_builder_end(&id_builder, &id);
mie_id *target = mie_id_map_get(&ctx->ctx_passes, &id);
if (target) {
return MIE_ERR_NAME_EXISTS;
}
pass->p_id = id;
mie_id_map_put_id(&ctx->ctx_passes, &pass->p_id);
return MIE_SUCCESS;
}
enum mie_status mie_ctx_get_pass(
struct mie_ctx *ctx, const char *name,
const struct mie_attribute_map *args, struct mie_pass **out)
{
mie_id id;
struct mie_id_builder id_builder;
mie_id_builder_begin(&id_builder, mie_id_map_get_ns(&ctx->ctx_passes));
mie_id_builder_add_cstr(&id_builder, name);
mie_id_builder_end(&id_builder, &id);
mie_id *target = mie_id_map_get(&ctx->ctx_passes, &id);
if (!target) {
return MIE_ERR_NO_ENTRY;
}
struct mie_pass_definition *pass_def
= b_unbox(struct mie_pass_definition, target, p_id);
if (pass_def->p_data_size < sizeof(struct mie_pass)) {
return MIE_ERR_BAD_STATE;
}
struct mie_pass *pass = malloc(pass_def->p_data_size);
if (!pass) {
return MIE_ERR_NO_MEMORY;
}
memset(pass, 0x0, pass_def->p_data_size);
pass->p_def = pass_def;
enum mie_status status = MIE_SUCCESS;
if (pass_def->p_init) {
status = pass_def->p_init(pass, args);
}
if (status != MIE_SUCCESS) {
free(pass);
pass = NULL;
}
*out = pass;
return status;
}