487 lines
13 KiB
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;
|
|
}
|