#include "spl_attr.h" static spl_attr_info_t spl_builtin_attrs[] = { {NULL, "extern", SPL_ATTR_STAGE_IR, SPL_ATTR_TARGET_DECL, SPL_ATTR_REQUIRED, 1, 1}, {NULL, "inline", SPL_ATTR_STAGE_OPT, SPL_ATTR_TARGET_DECL, SPL_ATTR_OPTIONAL, 0, 0}, {NULL, "noinline", SPL_ATTR_STAGE_OPT, SPL_ATTR_TARGET_DECL, SPL_ATTR_OPTIONAL, 0, 0}, {NULL, "align", SPL_ATTR_STAGE_LAYOUT, SPL_ATTR_TARGET_TYPE, SPL_ATTR_REQUIRED, 1, 1}, {NULL, "volatile", SPL_ATTR_STAGE_IR, SPL_ATTR_TARGET_EXPR, SPL_ATTR_REQUIRED, 0, 0}, {NULL, "atomic", SPL_ATTR_STAGE_IR, SPL_ATTR_TARGET_EXPR, SPL_ATTR_REQUIRED, 0, 1}, }; void spl_attr_init(spl_attr_t *ctx) { vec_init(ctx->table); vec_push(ctx->table, (spl_attr_node_t){0}); vec_init(ctx->registry); spl_attr_register_builtins(ctx); } void spl_attr_drop(spl_attr_t *ctx) { for (usize i = 1; i < vec_size(ctx->table); ++i) vec_free(vec_at(ctx->table, i).args); vec_free(ctx->table); vec_free(ctx->registry); } spl_attr_id_t spl_attr_alloc(spl_attr_t *ctx, spl_attr_info_t *info, spl_attr_arg_vec_t args) { spl_attr_node_t a = {0}; a.info = info; a.args = args; vec_push(ctx->table, a); return vec_size(ctx->table) - 1; } spl_attr_node_t *spl_attr_node(const spl_attr_t *ctx, spl_attr_id_t id) { if (!id || id >= vec_size(ctx->table)) return NULL; return &vec_at(ctx->table, id); } void spl_attr_registry_add(spl_attr_t *ctx, spl_attr_info_t *info) { vec_push(ctx->registry, info); } static int name_eq(const char *a, const char *b) { if (a == NULL && b == NULL) return 1; if (a == NULL || b == NULL) return 0; return strcmp(a, b) == 0; } spl_attr_info_t *spl_attr_lookup(spl_attr_t *ctx, const char *ns, const char *name) { for (usize i = 0; i < vec_size(ctx->registry); ++i) { spl_attr_info_t *info = vec_at(ctx->registry, i); if (name_eq(info->ns, ns) && strcmp(info->name, name) == 0) return info; } return NULL; } void spl_attr_register_builtins(spl_attr_t *ctx) { usize n = sizeof(spl_builtin_attrs) / sizeof(spl_builtin_attrs[0]); for (usize i = 0; i < n; ++i) spl_attr_registry_add(ctx, &spl_builtin_attrs[i]); } static const char *attr_stage_name(spl_attr_stage_t s) { switch (s) { case SPL_ATTR_STAGE_SEMA: return "SEMA"; case SPL_ATTR_STAGE_LAYOUT: return "LAYOUT"; case SPL_ATTR_STAGE_IR: return "IR"; case SPL_ATTR_STAGE_OPT: return "OPT"; case SPL_ATTR_STAGE_BACKEND: return "BACKEND"; } return "?"; } static const char *attr_target_name(spl_attr_target_t t) { switch (t) { case SPL_ATTR_TARGET_DECL: return "DECL"; case SPL_ATTR_TARGET_TYPE: return "TYPE"; case SPL_ATTR_TARGET_EXPR: return "EXPR"; case SPL_ATTR_TARGET_STMT: return "STMT"; } return "?"; } static const char *attr_demand_name(spl_attr_demand_t d) { return d == SPL_ATTR_REQUIRED ? "REQUIRED" : "OPTIONAL"; } void spl_attr_dump_id(const spl_attr_t *ctx, spl_attr_id_t id) { if (!ctx || !id) { printf("?"); return; } spl_attr_node_t *a = spl_attr_node(ctx, id); if (!a || !a->info) { printf("?"); return; } printf("%s", a->info->name); if (vec_size(a->args) > 0) { printf("("); for (usize i = 0; i < vec_size(a->args); ++i) { if (i > 0) printf(", "); spl_attr_arg_t *arg = &vec_at(a->args, i); switch (arg->kind) { case SPL_ATTR_ARG_INT: printf("%zd", arg->value.i); break; case SPL_ATTR_ARG_STR: printf("\"%s\"", arg->value.s ? arg->value.s : ""); break; case SPL_ATTR_ARG_DEF: printf("def#%zu", arg->value.d); break; case SPL_ATTR_ARG_TYPE: printf("type#%zu", arg->value.t); break; } } printf(")"); } } void spl_attr_dump(const spl_attr_t *ctx) { if (!ctx) return; printf("AttrTable:\n"); for (usize i = 1; i < vec_size(ctx->table); ++i) { spl_attr_node_t *a = &vec_at(ctx->table, i); printf(" #%zu ", i); spl_attr_dump_id(ctx, i); if (a->info) { printf(" [stage=%s target=%s demand=%s consumed=0x%x]", attr_stage_name(a->info->stage), attr_target_name(a->info->target), attr_demand_name(a->info->demand), a->consumed_mask); } printf("\n"); } }