#define _GNU_SOURCE /* asprintf */ #include #include #include #include #include "arch.h" #include "func.h" #include "node.h" #include "ply.h" #include "sym.h" #include "type.h" static struct type *global_map_ktype(struct node *n) { struct node *map, *key; struct type *ktype; struct tfield *kfields, *f; int i, nargs = node_nargs(n); char *kname; map = n->expr.args; if (node_nargs(n) == 2) return map->next->sym->type; ktype = calloc(1, sizeof(*ktype)); assert(ktype); kfields = calloc(nargs, sizeof(*kfields)); assert(kfields); for (key = map->next, f = kfields, i = 0; key; key = key->next, f++, i++) { asprintf(&f->name, "k%d", i); f->type = key->sym->type; } f->type = &t_void; asprintf(&ktype->sou.name, ":%s_key", map->ident.name); ktype->ttype = T_STRUCT; ktype->sou.fields = kfields; type_add(ktype); return ktype; } static int global_assign_type_infer_map(struct node *n) { struct node *map, *key; struct type *ktype; map = n->expr.args; for (key = map->next; key; key = key->next) { if (type_sizeof(key->sym->type) < 0) return 0; } map->sym->type = type_map_of(global_map_ktype(n), n->sym->type); return 0; } static int global_assign_type_infer(struct prog *prog, struct node *n) { struct node *lval, *rval; lval = n->expr.args; rval = lval->next; if (!rval->sym->type) return 0; if (!lval->sym->type) { lval->sym->type = rval->sym->type; if (node_is_map(lval)) return global_assign_type_infer_map(lval); return 0; } if (type_compatible(lval->sym->type, rval->sym->type)) return 0; if (lval->ntype == N_IDENT) { node_error(n, stderr, "conflicting types for '%s'", lval->ident.name); } else { node_error(n, stderr, "conflicting types for '%s'", lval->expr.args->ident.name); } return -EINVAL; } static int global_assign_static_verify(struct node *n) { struct node *lval; int nargs = node_nargs(n); if (nargs != 2) { node_error(n, stderr, "assignment operator expects 2 arguments," " %d given", nargs); return -EINVAL; } lval = n->expr.args; if (node_is_map(lval) || (lval->ntype == N_IDENT)) return 0; node_error(n, stderr, "assignment destination must be a variable or map"); return -EINVAL; } struct type t_pid = { .ttype = T_TYPEDEF, .tdef = { .name = ":pid", .type = &t_u32 }, }; struct type t_time = { .ttype = T_TYPEDEF, .tdef = { .name = ":time", .type = &t_s64 }, }; static const struct func global_funcs[] = { { .name = ":block", .type = &t_void, }, { .name = "+", }, { .name = "-", }, { .name = ":assign", .static_verify = global_assign_static_verify, .type_infer = global_assign_type_infer, }, { .name = ":map", /* .static_verify = global_map_static_verify, */ /* .type_infer = global_map_type_infer, */ }, { .name = "pid", .type = &t_pid, }, { .name = "time", .type = &t_time, }, { .name = "quantize", }, { .name = NULL } }; static const struct func global_num_func = { .name = ":num", .type = &t_int, }; struct type t_string_array = { .ttype = T_ARRAY, .array = { .type = &t_char, .len = 64 }, /* TODO: tunable */ }; struct type t_string = { .ttype = T_TYPEDEF, .tdef = { .name = ":string", .type = &t_string_array }, }; static const struct func global_string_func = { .name = ":string", .type = &t_string, }; static const struct func global_ident_func = { .name = ":ident", }; static const struct func *global_sym_alloc_expr(struct node *n) { const struct func *func; int err; for (func = global_funcs; func->name; func++) { if (strcmp(func->name, n->expr.func)) continue; return func; } return NULL; } int global_sym_alloc(struct prog *prog, struct node *n) { const struct func *func; struct symtab *st = prog->locals; int err; switch (n->ntype) { case N_EXPR: func = global_sym_alloc_expr(n); break; case N_IDENT: st = prog->globals; func = &global_ident_func; break; case N_NUM: func = &global_num_func; break; case N_STRING: func = &global_string_func; break; } if (!func) return -ENOENT; if (func->static_verify) { err = func->static_verify(n); if (err) return err; } n->sym = sym_alloc(st, n, func); if (func->type) /* return type is static, fill it now */ n->sym->type = func->type; return 0; } int global_probe(struct prog *prog) { return 0; } struct provider global = { .name = ":", .sym_alloc = global_sym_alloc, .probe = global_probe, }; __attribute__((constructor)) static void global_init(void) { provider_register(&global); }