diff options
Diffstat (limited to 'src/actualize.c')
| -rw-r--r-- | src/actualize.c | 1855 |
1 files changed, 844 insertions, 1011 deletions
diff --git a/src/actualize.c b/src/actualize.c index 744dc1a..6d85640 100644 --- a/src/actualize.c +++ b/src/actualize.c @@ -18,11 +18,8 @@ #define UNUSED(x) do { (void)(x); } while (0) -static int replace_type_id(struct ast_node *nodes, struct ast_node *id, - struct ast_node *replacement); - struct act_stack { - struct ast_node *node; + struct ast *node; struct act_stack *next; }; @@ -35,23 +32,36 @@ enum act_flags { struct act_state { enum act_flags flags; - struct ast_node *last_var; - struct ast_node *cur_trait; - struct ast_node *cur_proc; + struct ast *cur_proc; struct act_stack *defer_stack; struct act_stack *goto_stack; struct act_stack *label_stack; }; -static int is_lvalue(struct ast_node *n) +static int replace_type_id(struct ast *nodes, char *id, + struct type *replacement); + +static int actualize(struct act_state *state, struct scope *scope, + struct ast *node); + +static int actualize_list(struct act_state *state, struct scope *scope, + struct ast *l); + +static int actualize_type(struct act_state *state, struct scope *scope, + struct type *node); + +static int actualize_type_list(struct act_state *state, struct scope *scope, + struct type *node); + +static int is_lvalue(struct ast *n) { - if (n->node_type == AST_ARR_ACCESS) + if (n->k == AST_ARR) return 1; - if (n->node_type == AST_ID) + if (n->k == AST_ID) return 1; - if (n->node_type == AST_UNOP && AST_UNOP(n).op == AST_DEREF) + if (n->k == AST_DEREF) return 1; return 0; @@ -68,85 +78,65 @@ static enum act_flags act_flags(struct act_state *state, enum act_flags flags) return state->flags & flags; } -/* TODO: this could be improved if we get a global void thing */ -static int is_void(struct ast_node *type) +static bool is_void(struct type *t) { - assert(type->node_type == AST_TYPE); - if (AST_TYPE(type).kind != AST_TYPE_PRIMITIVE) - return 0; + /* missing return is void */ + if (!t) + return 1; - return AST_PRIMITIVE_TYPE(type).type == AST_VOID; + return t->k == TYPE_VOID; } -static struct ast_node *void_type() +static struct type *void_type() { - struct ast_node *v = gen_primitive(AST_VOID, NULL, NULL_LOC()); - ast_set_flags(v, AST_FLAG_INIT | AST_FLAG_ACTUAL); - v->type = v; - return v; + return tgen_primitive(TYPE_VOID, strdup("void"), NULL, NULL_LOC()); } -static struct ast_node *i27_type(struct scope *scope) +static struct type *i27_type(struct scope *scope) { - struct ast_node *i27 = gen_id(strdup("i27"), NULL_LOC()); - struct ast_node *def = file_scope_find_type(scope, i27); + struct ast *def = file_scope_find_type(scope, "i27"); if (!def) { error("missing definition of type 'i27'"); return NULL; } - struct ast_node *a = gen_primitive(AST_I27, def, def->loc); - ast_set_flags(a, AST_FLAG_INIT | AST_FLAG_ACTUAL); - a->type = a; - return a; + return tgen_primitive(TYPE_I27, strdup("i27"), def, def->loc); } -static struct ast_node *i9_type(struct scope *scope) +static struct type *i9_type(struct scope *scope) { - struct ast_node *i27 = gen_id(strdup("i9"), NULL_LOC()); - struct ast_node *def = file_scope_find_type(scope, i27); + struct ast *def = file_scope_find_type(scope, "i9"); if (!def) { error("missing definition of type 'i9'"); return NULL; } - struct ast_node *a = gen_primitive(AST_I9, def, def->loc); - ast_set_flags(a, AST_FLAG_INIT | AST_FLAG_ACTUAL); - a->type = a; - return a; + return tgen_primitive(TYPE_I9, strdup("i9"), def, def->loc); } -static struct ast_node *str_type(struct scope *scope) +static struct type *str_type(struct scope *scope) { - struct ast_node *str = gen_id(strdup("str"), NULL_LOC()); - struct ast_node *def = file_scope_find_type(scope, str); + struct ast *def = file_scope_find_type(scope, "str"); if (!def) { error("missing definition of type 'str'"); return NULL; } - struct ast_node *a = gen_primitive(AST_STR, def, def->loc); - ast_set_flags(a, AST_FLAG_INIT | AST_FLAG_ACTUAL); - a->type = a; - return a; + return tgen_primitive(TYPE_STR, strdup("str"), def, def->loc); } -static struct ast_node *bool_type(struct scope *scope) +static struct type *bool_type(struct scope *scope) { - struct ast_node *b = gen_id(strdup("bool"), NULL_LOC()); - struct ast_node *def = file_scope_find_type(scope, b); + struct ast *def = file_scope_find_type(scope, "bool"); if (!def) { error("missing definition of type 'bool'"); return NULL; } - struct ast_node *a = gen_primitive(AST_BOOL, def, def->loc); - ast_set_flags(a, AST_FLAG_INIT | AST_FLAG_ACTUAL); - a->type = a; - return a; + return tgen_primitive(TYPE_BOOL, strdup("bool"), def, def->loc); } -static int push_defer(struct act_state *state, struct ast_node *expr) +static int push_defer(struct act_state *state, struct ast *expr) { struct act_stack *new = calloc(1, sizeof(struct act_stack)); if (!new) { @@ -160,7 +150,7 @@ static int push_defer(struct act_state *state, struct ast_node *expr) return 0; } -static int push_label(struct act_state *state, struct ast_node *label) +static int push_label(struct act_state *state, struct ast *label) { struct act_stack *new = calloc(1, sizeof(struct act_stack)); if (!new) { @@ -174,23 +164,20 @@ static int push_label(struct act_state *state, struct ast_node *label) return 0; } -static struct ast_node *find_label(struct act_state *state, - struct ast_node *label) +static struct ast *find_label(struct act_state *state, char *label) { - assert(label->node_type == AST_LABEL); struct act_stack *prev = state->label_stack, *cur; if (prev) do { cur = prev->next; - if (same_id(AST_LABEL(prev->node).id, - AST_LABEL(label).id)) + if (same_id(label_id(prev->node), label)) return prev->node; } while ((prev = cur)); return NULL; } -static int push_goto(struct act_state *state, struct ast_node *got) +static int push_goto(struct act_state *state, struct ast *got) { struct act_stack *new = calloc(1, sizeof(struct act_stack)); if (!new) { @@ -204,17 +191,17 @@ static int push_goto(struct act_state *state, struct ast_node *got) return 0; } -static struct ast_node *clone_defers(struct act_state *state, +static struct ast *clone_defers(struct act_state *state, struct act_stack *to) { struct act_stack *from = state->defer_stack; /* maintain reverse order */ - struct ast_node *defers = NULL, *prev = NULL; + struct ast *defers = NULL, *prev = NULL; while (from != to) { - struct ast_node *defer = clone_ast_node(from->node); + struct ast *defer = clone_ast(from->node); if (prev) - prev->next = defer; + prev->n = defer; if (!defers) defers = defer; @@ -263,130 +250,78 @@ static void destroy_act_state(struct act_state *state) clear_gotos(state, NULL); } -static int actualize(struct act_state *state, struct scope *scope, - struct ast_node *node); -static int analyze(struct scope *scope, struct ast_node *tree); +static void type_mismatch(struct scope *scope, struct ast *node, struct type *a, struct type *b) +{ + char *left_type = type_str(a); + char *right_type = type_str(b); + semantic_error(scope->fctx, node, + "type mismatch: %s vs %s", + left_type, right_type); + free(left_type); + free(right_type); +} + +static int analyze(struct scope *scope, struct ast *tree); -static int eval_const_if(struct scope *scope, struct ast_node *node) +static int eval_const_if(struct scope *scope, struct ast *node) { assert(node - && node->node_type == AST_IF + && node->k == AST_IF && ast_flags(node, AST_FLAG_CONST)); - int eval = 0; - struct ast_node *cond = node->_if.cond; - struct ast_node *next = node->next; - - switch (cond->node_type) { - /* for now just check if the variable exists, might change in - * the future */ - case AST_ID: eval = file_scope_find_var(scope, cond) != NULL; - break; - default: semantic_error(scope->fctx, node, - "const if conditional at file scope unimplemented"); - return -1; - } - - if (eval) { - /* condition evaluated true, so keep the if block */ - struct ast_node *body = node->_if.body; - ast_last_node(body)->next = node->next; - - /* an if must have a body, otherwise the parser messed up */ - assert(body); - - *node = *body; - free(body); - return 0; - } - - struct ast_node *els = node->_if.els; - if (els) { - *node = *els; - ast_last_node(els)->next = next; - free(els); - return 0; - } - - if (next) { - /* copy the next node into our place */ - *node = *next; - free(next); - return 0; - } - - free(node); - return 0; + semantic_error(scope->fctx, node, + "const if unimplemented"); + return -1; } -static int analyze_visibility(struct scope *scope, struct ast_node *node) +static int analyze_visibility(struct scope *scope, struct ast *node) { if (!node) return 0; - int ret = 0; node->scope = scope; - /* TODO: add error checking */ - switch (node->node_type) { - case AST_PROC: { - ret |= scope_add_proc(scope, node); - break; - } - - case AST_VAR: { - ret |= scope_add_var(scope, node); - break; - } + switch (node->k) { + case AST_PROC_DEF: return scope_add_proc(scope, node); + case AST_MACRO_DEF: return scope_add_macro(scope, node); + case AST_VAR_DEF: return scope_add_var(scope, node); case AST_IMPORT: { - const char *file = AST_IMPORT(node).file; - ret |= process_file(&scope, + const char *file = import_file(node); + return process_file(&scope, (int)ast_flags(node, AST_FLAG_PUBLIC), file); - break; } case AST_IF: { assert(ast_flags(node, AST_FLAG_CONST)); - ret |= eval_const_if(scope, node); - if (ret) + if (eval_const_if(scope, node)) return -1; /* since a const if likely replaced the current node with * something else, we have to analyze the replacement */ - ret = analyze(scope, node); - break; + return analyze(scope, node); } - case AST_STRUCT: { + case AST_STRUCT_DEF: { /* we shouldn't get any anonymous structs at this stage */ - struct ast_node *id = AST_STRUCT(node).id; - ret |= scope_add_type(scope, id, node); - break; + char *id = struct_id(node); + return scope_add_type(scope, id, node); } - case AST_ENUM: { - struct ast_node *id = AST_ENUM(node).id; - ret |= scope_add_type(scope, id, node); - break; + case AST_ENUM_DEF: { + char *id = enum_id(node); + return scope_add_type(scope, id, node); } - case AST_ALIAS: { - struct ast_node *id = AST_ALIAS(node).id; - ret |= scope_add_type(scope, id, node); - break; + case AST_ALIAS_DEF: { + char *id = alias_id(node); + return scope_add_type(scope, id, node); } - case AST_TRAIT: { - struct ast_node *id = AST_TRAIT(node).id; - ret |= scope_add_type(scope, id, node); - break; - } - - case AST_MACRO_CONSTRUCT: { - ret |= scope_add_macro(scope, node); - break; + case AST_TRAIT_DEF: { + char *id = trait_id(node); + return scope_add_type(scope, id, node); } case AST_EMPTY: { @@ -394,145 +329,188 @@ static int analyze_visibility(struct scope *scope, struct ast_node *node) } default: - ret = -1; semantic_error(scope->fctx, node, "unknown top element"); - break; + return -1; }; - return ret; + return 0; } -static int analyze_var(struct scope *scope, struct ast_node *node) +static int analyze_var(struct scope *scope, struct ast *node) { struct act_state state = {0}; return actualize(&state, scope, node); } -static void set_type(struct ast_node *node, struct ast_node *type) +static void set_type(struct ast *node, struct type *type) +{ + node->t = clone_type_list(type); +} + +static void replace_type(struct type *t, struct type *r) { - assert(type->node_type == AST_TYPE); - node->type = clone_ast_node(type); + /* free strings before they get overwritten */ + if (t->id) + free(t->id); + + struct src_loc loc = t->loc; + struct scope *scope = t->scope; + + *t = *r; + + /* clone so we don't accidentally free same string twice later */ + if (t->id) + t->id = strdup(t->id); + + /* these things we generally don't want to replace */ + t->loc = loc; + t->scope = scope; } -static int analyze_proc(struct scope *scope, struct ast_node *node) +static void replace_ast(struct ast *n, struct ast *t) { - /* not sure if this is the best place for this */ - AST_PROC(node).id->scope = scope; + if (n->s) + free(n->s); + + struct src_loc loc = n->loc; + struct scope *scope = n->scope; + *n = *t; + + if (n->s) + n->s = strdup(n->s); + + n->loc = loc; + t->scope = scope; +} + +static int analyze_proc(struct scope *scope, struct ast *node) +{ struct scope *proc_scope = create_scope(); scope_add_scope(scope, proc_scope); node->scope = proc_scope; - struct ast_node *sign = AST_PROC(node).sign; - + struct ast *params = proc_params(node); struct act_state state = {0}; - int ret = actualize(&state, proc_scope, sign); - set_type(node, sign); - return ret; + if (actualize_list(&state, proc_scope, params)) + return -1; + + struct type *rtype = proc_rtype(node); + + if (actualize_type_list(&state, proc_scope, rtype)) + return -1; + + if (!rtype) + proc_rtype(node) = void_type(); + + struct type *callable = tgen_callable(NULL, proc_rtype(node), node->loc); + foreach_node(p, params) { + /* we must manually 'start' the chain **/ + if (!callable_ptypes(callable)) { + callable_ptypes(callable) = clone_type(p->t); + continue; + } + + type_append(callable_ptypes(callable), p->t); + } + + set_type(node, callable); + return 0; } -static struct ast_node *analyze_type_expand(struct scope *scope, - struct ast_node *n) +static struct ast *analyze_type_expand(struct scope *scope, + struct ast *n) { - assert(n->node_type == AST_TYPE_EXPAND); - struct ast_node *trait = file_scope_find_type(scope, - AST_TYPE_EXPAND(n).id); + assert(n->k == AST_TYPE_EXPAND); + struct ast *trait = file_scope_find_type(scope, type_expand_id(n)); if (!trait) { semantic_error(scope->fctx, n, "no such type"); return NULL; } - if (trait->node_type != AST_TRAIT) { + if (trait->k != AST_TRAIT_DEF) { semantic_error(scope->fctx, n, "not a trait"); return NULL; } semantic_info(scope->fctx, n, "FIXME: skipping type param check for now"); - struct ast_node *body = AST_TRAIT(trait).raw_body; - body = clone_ast_node(body); + struct ast *body = trait_raw_body(trait); + body = clone_ast(body); - struct ast_node *pa = AST_TYPE_EXPAND(n).args; - foreach_node(pt, AST_TRAIT(trait).params) { - replace_type_id(body, AST_VAR(pt).id, pa); - pa = pa->next; + struct type *pa = type_expand_args(n); + foreach_node(pt, trait_params(trait)) { + replace_type_id(body, var_id(pt), pa); + pa = pa->n; } return body; } -static int implements_trait(struct ast_node *body, struct ast_node *id) +static int implements_trait(struct ast *body, char *id) { foreach_node(n, body) { - if (n->node_type != AST_ID) + /* traits don't currently take generic parameters I guess? */ + if (n->k != AST_ID) continue; - if (same_id(n, id)) + if (same_id(id_str(n), id)) return 1; } return 0; } -static void mark_implemented(struct ast_node *n) -{ - assert(n->node_type == AST_TYPE_EXPAND); - /** @todo very hacky but good enough for now */ - struct ast_node *id = AST_TYPE_EXPAND(n).id; - n->node_type = AST_ID; - AST_ID(n).id = strdup(AST_ID(id).id); -} - -static int analyze_struct(struct scope *scope, struct ast_node *node) +static int analyze_struct(struct scope *scope, struct ast *node) { - assert(node->node_type == AST_STRUCT); - struct ast_node *generics = AST_STRUCT(node).generics; + assert(node->k == AST_STRUCT_DEF); + struct ast *params = struct_params(node); struct scope *struct_scope = create_scope(); if (!struct_scope) return -1; scope_add_scope(node->scope, struct_scope); node->scope = struct_scope; - if (generics) + if (params) ast_set_flags(node, AST_FLAG_GENERIC); - struct ast_node *type = gen_type(AST_TYPE_STRUCT, node, NULL, - node->loc); + struct type *type = tgen_type(TYPE_STRUCT, + NULL, NULL, + node, NULL, + strdup(struct_id(node)), + node->loc); - foreach_node(n, AST_STRUCT(node).body) { - if (n->node_type != AST_TYPE_EXPAND) + foreach_node(n, struct_body(node)) { + if (n->k != AST_TYPE_EXPAND) continue; - if (implements_trait(AST_STRUCT(node).body, - AST_TYPE_EXPAND(n).id)) { - n->node_type = AST_EMPTY; + if (implements_trait(struct_body(node), type_expand_id(n))) { + n->k = AST_EMPTY; continue; } - if (same_id(AST_STRUCT(node).id, AST_TYPE_EXPAND(n).id)) { + if (same_id(struct_id(node), type_expand_id(n))) { semantic_error(scope->fctx, n, "recursive trait implementations not allowed"); return -1; } - struct ast_node *body = analyze_type_expand(scope, n); + struct ast *body = analyze_type_expand(scope, n); if (!body) { - n->node_type = AST_EMPTY; + n->k = AST_EMPTY; continue; } - replace_type_id(body, AST_TYPE_EXPAND(n).id, type); - ast_block_last(body)->next = n->next; - n->next = body; - - mark_implemented(n); + replace_type_id(body, type_expand_id(n), type); + ast_block_last(body)->n = n->n; + n->n = body; } - foreach_node(n, AST_STRUCT(node).body) { - switch (n->node_type) { + foreach_node(n, struct_body(node)) { + switch (n->k) { case AST_EMPTY: continue; case AST_ID: continue; /* prototypes are checked later */ - case AST_PROC: if (!AST_PROC(n).body) continue; + case AST_PROC_DEF: if (!proc_body(n)) continue; default: } @@ -540,9 +518,9 @@ static int analyze_struct(struct scope *scope, struct ast_node *node) return -1; } - foreach_node(n, AST_STRUCT(node).body) { + foreach_node(n, struct_body(node)) { /* also checks prototypes */ - if (n->node_type != AST_PROC) + if (n->k != AST_PROC_DEF) continue; if (analyze_proc(struct_scope, n)) @@ -550,38 +528,47 @@ static int analyze_struct(struct scope *scope, struct ast_node *node) } /* check that all prototypes are implemented */ - foreach_node(n, AST_STRUCT(node).body) { - if (n->node_type != AST_PROC) + foreach_node(n, struct_body(node)) { + if (n->k != AST_PROC_DEF) continue; - if (AST_PROC(n).body) + if (proc_body(n)) continue; - struct ast_node *proc = scope_find_proc(struct_scope, - AST_PROC(n).id); + struct ast *proc = scope_find_proc(struct_scope, proc_id(n)); if (!proc) { semantic_error(scope->fctx, n, "missing implementation"); return -1; } - if (!equiv_nodes(AST_PROC(n).sign, AST_PROC(proc).sign)) { + if (!types_match(n->t, proc->t)) { semantic_error(scope->fctx, n, "mismatched signatures"); semantic_info(scope->fctx, proc, "note: here"); return -1; } } + char *id = strdup(struct_id(node)); + if (same_id(id, "i27")) + node->t = tgen_primitive(TYPE_I27, id, node, node->loc); + else if (same_id(id, "i9")) + node->t = tgen_primitive(TYPE_I9, id, node, node->loc); + else if (same_id(id, "bool")) + node->t = tgen_primitive(TYPE_BOOL, id, node, node->loc); + else + node->t = tgen_struct(id, node, node->loc); + /** @todo there is the possibility that two different traits add the * same prototype, which is reported in traits but not structs? */ return 0; } /* quite a lot of overlap with analyze_struct, kind of ugly I guess */ -static int analyze_trait(struct scope *scope, struct ast_node *node) +static int analyze_trait(struct scope *scope, struct ast *node) { - assert(node->node_type == AST_TRAIT); - struct ast_node *generics = AST_TRAIT(node).params; + assert(node->k == AST_TRAIT_DEF); + struct ast *params = trait_params(node); struct scope *trait_scope = create_scope(); if (!trait_scope) return -1; @@ -589,54 +576,55 @@ static int analyze_trait(struct scope *scope, struct ast_node *node) scope_add_scope(node->scope, trait_scope); node->scope = trait_scope; /** @todo should probably add in aliases for the traits in scope? */ - if (generics) + if (params) ast_set_flags(node, AST_FLAG_GENERIC); - struct ast_node *type = gen_type(AST_TYPE_TRAIT, node, NULL, node->loc); + struct type *type = tgen_type(TYPE_TRAIT, NULL, NULL, + node, NULL, strdup(trait_id(node)), + node->loc); + + /* copy body */ + node->a2 = clone_ast(trait_raw_body(node)); - AST_TRAIT(node).body = clone_ast_node(AST_TRAIT(node).raw_body); /* do type expansions */ - foreach_node(n, AST_TRAIT(node).body) { - if (n->node_type != AST_TYPE_EXPAND) + foreach_node(n, trait_body(node)) { + if (n->k != AST_TYPE_EXPAND) continue; /* don't re-expand already implemented traits */ - if (implements_trait(AST_TRAIT(node).body, - AST_TYPE_EXPAND(n).id)) { + if (implements_trait(trait_body(node), type_expand_id(n))) { /* not sure about this, but at least we don't have stray * type expands everywhere */ - n->node_type = AST_EMPTY; + n->k = AST_EMPTY; continue; } - if (same_id(AST_TRAIT(node).id, AST_TYPE_EXPAND(n).id)) { + if (same_id(trait_id(node), type_expand_id(n))) { semantic_error(scope->fctx, n, "recursive trait implementations not allowed"); return -1; } - struct ast_node *body = analyze_type_expand(scope, n); + struct ast *body = analyze_type_expand(scope, n); if (!body) { - n->node_type = AST_EMPTY; + n->k = AST_EMPTY; continue; } - replace_type_id(body, AST_TYPE_EXPAND(n).id, type); - ast_last_node(body)->next = n->next; - n->next = body; - - mark_implemented(n); + replace_type_id(body, type_expand_id(n), type); + ast_last(body)->n = n->n; + n->n = body; } /* add all procedure definitions to scope */ - foreach_node(n, AST_TRAIT(node).body) { + foreach_node(n, trait_body(node)) { /* kind of a hack but these shouldn't be shown to * analyze_visibility */ - switch (n->node_type) { + switch (n->k) { case AST_EMPTY: continue; case AST_ID: continue; /* prototypes are added later */ - case AST_PROC: if (!AST_PROC(n).body) continue; + case AST_PROC_DEF: if (!proc_body(n)) continue; default: } @@ -649,47 +637,49 @@ static int analyze_trait(struct scope *scope, struct ast_node *node) * would be. Add a prototypes -list to scopes? */ /* add all prototypes that don't have matching definition to scope */ - foreach_node(n, AST_TRAIT(node).body) { - if (n->node_type != AST_PROC) + foreach_node(n, trait_body(node)) { + if (n->k != AST_PROC_DEF) continue; - if (AST_PROC(n).body) + if (proc_body(n)) continue; /* prototypes are checked only if there's no implementation */ - if (scope_find_proc(trait_scope, AST_PROC(n).id)) + if (scope_find_proc(trait_scope, proc_id(n))) continue; if (analyze_visibility(trait_scope, n)) return -1; } - foreach_node(n, AST_TRAIT(node).body) { - if (n->node_type != AST_PROC) + foreach_node(n, trait_body(node)) { + if (n->k != AST_PROC_DEF) continue; if (analyze_proc(trait_scope, n)) return -1; } + node->t = tgen_trait(strdup(struct_id(node)), node, node->loc); + return 0; } -static int analyze_signs(struct scope *scope, struct ast_node *node) +static int analyze_signs(struct scope *scope, struct ast *node) { /** @todo aliases? */ - switch (node->node_type) { - case AST_VAR: return analyze_var(scope, node); break; - case AST_PROC: return analyze_proc(scope, node); break; - case AST_STRUCT: return analyze_struct(scope, node); break; - case AST_TRAIT: return analyze_trait(scope, node); break; + switch (node->k) { + case AST_VAR_DEF: return analyze_var(scope, node); break; + case AST_PROC_DEF: return analyze_proc(scope, node); break; + case AST_STRUCT_DEF: return analyze_struct(scope, node); break; + case AST_TRAIT_DEF: return analyze_trait(scope, node); break; default: } return 0; } -static int analyze(struct scope *scope, struct ast_node *tree) +static int analyze(struct scope *scope, struct ast *tree) { foreach_node(node, tree) { if (analyze_visibility(scope, node)) @@ -707,13 +697,13 @@ static int analyze(struct scope *scope, struct ast_node *tree) return -1; printf("//actualized:\n"); - dump_ast_node(0, node); + ast_dump(0, node); } return 0; } -int analyze_root(struct scope *scope, struct ast_node *tree) +int analyze_root(struct scope *scope, struct ast *tree) { if (analyze(scope, tree)) return -1; @@ -721,22 +711,13 @@ int analyze_root(struct scope *scope, struct ast_node *tree) return 0; } -static int structs_match(struct ast_node *a, struct ast_node *b) +static int structs_match(struct type *a, struct type *b) { - /** @todo: iterate over elements in structure */ - /** @todo: check tag as well? */ - return 0; + /* dunno, let's go with this for now */ + return a->d == b->d; } -static int primitives_match(struct ast_node *a, struct ast_node *b) -{ - enum ast_primitive at = AST_PRIMITIVE_TYPE(a).type; - enum ast_primitive bt = AST_PRIMITIVE_TYPE(b).type; - - return at == bt; -} - -int types_match(struct ast_node *a, struct ast_node *b) +int types_match(struct type *a, struct type *b) { if (!a && !b) return 1; @@ -744,111 +725,85 @@ int types_match(struct ast_node *a, struct ast_node *b) if (!a || !b) return 0; - assert(a->node_type == AST_TYPE); - assert(b->node_type == AST_TYPE); - /* if the type kind doesn't match, we're done. */ - if (AST_TYPE(a).kind != AST_TYPE(b).kind) + if (a->k != b->k) return 0; - if (AST_TYPE(a).kind == AST_TYPE_STRUCT) + if (a->k == TYPE_STRUCT) return structs_match(a, b); - if (AST_TYPE(a).kind == AST_TYPE_POINTER) - return types_match(AST_PTR_TYPE(a).base, - AST_PTR_TYPE(b).base); - - if (AST_TYPE(a).kind == AST_TYPE_PRIMITIVE) - return primitives_match(a, b); + if (a->k == TYPE_PTR) + return types_match(ptr_base(a), ptr_base(b)); - return 0; + return 1; } -static int _replace_id(struct ast_node *node, void *data) +static int _replace_id(struct ast *node, void *data) { if (!node) return 0; - if (node->node_type != AST_ID) - return ast_call_on(_replace_id, node, data); + if (node->k != AST_ID) + return 0; - struct ast_node **pair = data; - struct ast_node *id = pair[0]; - struct ast_node *expr = pair[1]; + struct ast **pair = data; + struct ast *id = pair[0]; + struct ast *expr = pair[1]; - if (!same_id(node, id)) - return ast_call_on(_replace_id, node, data); + /* no match, continue */ + if (!same_id(id_str(node), id_str(id))) + return 0; - struct ast_node *clone = clone_ast_node(expr); + struct ast *clone = clone_ast(expr); if (!clone) { internal_error("failed cloning replacement expr"); return -1; } - clone->next = node->next; + clone->n = node->n; clone->scope = node->scope; - *node = *clone; + replace_ast(node, clone); /* a succesful replacement needs no futher replacements, I think */ return 0; } -static int replace_id(struct ast_node *body, struct ast_node *id, - struct ast_node *expr) +static int replace_id(struct ast *body, struct ast *id, + struct ast *expr) { - struct ast_node *pair[2] = {id, expr}; - return ast_call_on(_replace_id, body, pair); + struct ast *pair[2] = {id, expr}; + return ast_visit(_replace_id, NULL, body, pair); } -static int actualize_macro_construct(struct act_state *state, - struct scope *scope, struct ast_node *n) +static int actualize_macro_def(struct act_state *state, + struct scope *scope, struct ast *n) { UNUSED(state); /* macro bodies, arguments, etc aren't expanded upon until the macro is * called, so just try to add it to the local scope */ - assert(n && n->node_type == AST_MACRO_CONSTRUCT); + assert(n && n->k == AST_MACRO_DEF); return scope_add_macro(scope, n); } -struct ast_node *extract_trait(struct ast_node *type) -{ - if (!type) - return 0; - - assert(type->node_type == AST_TYPE); - if (type->_type.kind == AST_TYPE_TRAIT) - return type; - - return extract_trait(type->_type.next); -} - -static void actualize_trait_types(struct ast_node *params, - struct ast_node *args) -{ - /** @todo replace trait types with arg types, should probably be merged - * */ - assert(!args && !params); -} - static int actualize_macro_expand(struct act_state *state, struct scope *scope, - struct ast_node *macro_expand) + struct ast *macro_expand) { - assert(macro_expand->node_type == AST_MACRO_EXPAND); - struct ast_node *id = AST_MACRO_EXPAND(macro_expand).id; - struct ast_node *macro = file_scope_find_macro(scope, id); + assert(macro_expand->k == AST_MACRO_EXPAND); + char *id = macro_expand_id(macro_expand); + struct ast *macro = file_scope_find_macro(scope, id); if (!macro) { semantic_error(scope->fctx, macro_expand, "no such macro"); return -1; } - assert(macro->node_type == AST_MACRO_CONSTRUCT); + assert(macro->k == AST_MACRO_DEF); if (ast_flags(macro, AST_FLAG_VARIADIC)) { semantic_error(scope->fctx, macro, "variadic macros not yet implemented"); return -1; } - struct ast_node *body = clone_ast_node(AST_MACRO_CONSTRUCT(macro).body); + struct ast *body = clone_ast(macro_def_body(macro)); if (!body) { internal_error("failed allocating body for macro expansion"); return -1; @@ -856,63 +811,79 @@ static int actualize_macro_expand(struct act_state *state, /** @todo update all macro IDs to the correct scope */ body->scope = macro_expand->scope; - body->next = macro_expand->next; + body->n = macro_expand->n; - struct ast_node *param = AST_MACRO_CONSTRUCT(macro).params; - struct ast_node *arg = AST_MACRO_EXPAND(macro_expand).args; + struct ast *param = macro_def_params(macro); + struct ast *arg = macro_expand_args(macro_expand); - /* TODO: actual replacements */ while (param && arg) { /* feels slightly hacky, but essentially replace each individual * component in the arg list by breaking it out of the list * temporarily. After the replacement, insert it back into the * list so the cleanup is easier. */ - struct ast_node *next_arg = arg->next; - arg->next = NULL; + struct ast *next_arg = arg->n; + arg->n = NULL; if (replace_id(body, param, arg)) { semantic_error(scope->fctx, macro_expand, "failed replacing params with args"); - arg->next = next_arg; + arg->n = next_arg; return -1; } - param = param->next; - arg = arg->next = next_arg; + param = param->n; + arg = arg->n = next_arg; } + free(macro_expand_id(macro_expand)); *macro_expand = *body; /* actualize the new content */ return actualize(state, scope, macro_expand); } static int actualize_call(struct act_state *state, - struct scope *scope, struct ast_node *call) + struct scope *scope, struct ast *call) { - assert(call && call->node_type == AST_CALL); + assert(call && call->k == AST_CALL); - /* check that arguments exist, make sure they have types etc. */ - /* TODO: procedure callbacks? */ - int ret = actualize(state, scope, AST_CALL(call).args); - if (ret) - return ret; + if (actualize_list(state, scope, call_args(call))) + return -1; - ret = actualize(state, scope, AST_CALL(call).expr); - if (ret) - return ret; + if (actualize_list(state, scope, call_expr(call))) + return -1; - semantic_info(scope->fctx, call, "FIXME: skipping type checks for now"); - struct ast_node *expr = AST_CALL(call).expr; - if (AST_TYPE(expr->type).kind != AST_TYPE_SIGN) { - char *tstr = type_str(expr->type); - semantic_info(scope->fctx, call, "not a callable type: %s", + struct ast *expr = call_expr(call); + if (expr->t->k != TYPE_CALLABLE) { + char *tstr = type_str(expr->t); + semantic_error(scope->fctx, call, "not a callable type: %s", tstr); free(tstr); return -1; } - struct ast_node *sign = expr->type; - set_type(call, AST_SIGN_TYPE(sign).ret); + struct type *callable = expr->t; + struct type *ptypes = callable_ptypes(callable); + struct ast *arg = call_args(call); + foreach_type(p, ptypes) { + if (!arg) { + semantic_error(scope->fctx, call, "too many arguments"); + return -1; + } + + if (!types_match(p, arg->t)) { + type_mismatch(scope, arg, p, arg->t); + return -1; + } + + arg = arg->n; + } + + if (arg) { + semantic_error(scope->fctx, arg, "too many arguments"); + return -1; + } + + set_type(call, callable_rtype(callable)); return 0; } @@ -923,7 +894,7 @@ static void warn_unused_labels(struct act_state *state, struct scope *scope) return; do { - struct ast_node *label = labels->node; + struct ast *label = labels->node; if (!ast_flags(label, AST_FLAG_ACTUAL)) semantic_warn(scope->fctx, label, "unused label"); @@ -939,7 +910,7 @@ static int undefined_gotos(struct act_state *state, struct scope *scope) return ret; do { - struct ast_node *got = gotos->node; + struct ast *got = gotos->node; if (!ast_flags(got, AST_FLAG_ACTUAL)) { semantic_warn(scope->fctx, got, "undefined label"); @@ -952,39 +923,35 @@ static int undefined_gotos(struct act_state *state, struct scope *scope) } static int actualize_proc(struct act_state *state, - struct scope *scope, struct ast_node *proc) + struct scope *scope, struct ast *proc) { + UNUSED(state); /* actualize_proc is called on trait procs as well, but I believe * that's fine? */ - assert(proc && proc->node_type == AST_PROC); - struct ast_node *sign = AST_PROC(proc).sign; + assert(proc && proc->k == AST_PROC_DEF); - /* signature should already be typed etc. */ struct act_state new_state = {0}; - if (actualize(&new_state, proc->scope, sign)) - return -1; - - set_type(proc, sign); + /* params should already have been actualized, should maybe check */ /* actualize body */ new_state.cur_proc = proc; - if (actualize(&new_state, proc->scope, AST_PROC(proc).body)) + if (actualize(&new_state, proc->scope, proc_body(proc))) return -1; if (!act_flags(&new_state, ACT_HAS_RETURN)) { - if (!is_void(AST_SIGN_TYPE(sign).ret)) { + if (!is_void(proc_rtype(proc))) { semantic_error(scope->fctx, proc, "no return with non-void return type"); return -1; } /* add 'implicit' return */ - struct ast_node *body = AST_PROC(proc).body; - struct ast_node *r = gen_return(NULL, NULL_LOC()); + struct ast *body = proc_body(proc); + struct ast *r = gen_return(NULL, NULL, NULL_LOC()); r->scope = body->scope; - ast_append(AST_BLOCK(body).body, r); + ast_append(block_body(body), r); } - else if (ast_block_last(AST_PROC(proc).body)->node_type != AST_RETURN) { + else if (ast_block_last(proc_body(proc))->k != AST_RETURN) { /* TODO: something more sophisticated than this */ semantic_warn(scope->fctx, proc, "unable to determine explicit return for all branches"); @@ -996,63 +963,41 @@ static int actualize_proc(struct act_state *state, return -1; /* if we're main, don't mangle the entry point */ - struct ast_node *id = AST_PROC(proc).id; - if (strcmp("main", AST_ID(id).id) == 0) - ast_set_flags(id, AST_FLAG_NOMANGLE); + char *id = proc_id(proc); + if (strcmp("main", id) == 0) + ast_set_flags(proc, AST_FLAG_NOMANGLE); /* we have successfully actualized the procedure */ return 0; } static int actualize_binop(struct act_state *state, - struct scope *scope, struct ast_node *binop) + struct scope *scope, struct ast *binop) { - assert(binop && binop->node_type == AST_BINOP); + assert(binop && is_binop(binop)); - struct ast_node *left = AST_BINOP(binop).left; - struct ast_node *right = AST_BINOP(binop).right; - - int ret = 0; - ret |= actualize(state, scope, left); - ret |= actualize(state, scope, right); - if (ret) - return ret; + struct ast *left = binop_left(binop); + struct ast *right = binop_right(binop); - if (!left->type) { - semantic_error(scope->fctx, binop, - "unable to detect lefthand type"); + if (actualize(state, scope, left)) return -1; - } - if (!right->type) { - semantic_error(scope->fctx, binop, - "unable to detect righthand type"); + if (actualize(state, scope, right)) return -1; - } - if (!types_match(left->type, right->type)) { - char *left_type = type_str(left); - char *right_type = type_str(right); - semantic_error(scope->fctx, binop, - "type mismatch (%s vs %s)", left_type, - right_type); - free(left_type); - free(right_type); + if (!types_match(left->t, right->t)) { + type_mismatch(scope, binop, left->t, right->t); return -1; } - /* TODO: also check trait types, just because two traits collapse - * to the same actual type doesn't mean that the two trait types - * should be allowed to operate on eachother */ - /* types are the same, so the type of this expression is whichever */ - set_type(binop, left->type); + set_type(binop, left->t); return 0; } static int actualize_block(struct act_state *state, - struct scope *scope, struct ast_node *node) + struct scope *scope, struct ast *node) { struct scope *block_scope = scope; if (!ast_flags(node, AST_FLAG_UNHYGIENIC)) { @@ -1066,20 +1011,21 @@ static int actualize_block(struct act_state *state, } struct act_stack *defers = state->defer_stack; - foreach_node(pt, node->_block.body) { + foreach_node(pt, block_body(node)) { if (actualize(state, block_scope, pt)) return -1; } - if (node->_block.body == NULL) { - node->type = void_type(); - node->_block.body = gen_empty(); + if (block_body(node) == NULL) { + node->t = void_type(); + /* still not a huge fan of directly mucking about with ast slots */ + block_body(node) = gen_empty(NULL_LOC()); return 0; } /* the block type is the last statement in the block's type */ - set_type(node, ast_last_node(node->_block.body)->type); - if (!node->type) { + set_type(node, ast_last(block_body(node))->t); + if (!node->t) { semantic_error(scope->fctx, node, "unable to detect block type"); return -1; @@ -1088,8 +1034,8 @@ static int actualize_block(struct act_state *state, /* TODO: currently defers are sort of duplicated after a return, unsure * if they should be handled here or somewhere else */ if (state->defer_stack) { - node->_block.defers = clone_defers(state, defers); - if (!node->_block.defers) { + block_defers(node) = clone_defers(state, defers); + if (!block_defers(node)) { internal_error("failed cloning defers"); return -1; } @@ -1101,10 +1047,10 @@ static int actualize_block(struct act_state *state, } static int actualize_id(struct act_state *state, - struct scope *scope, struct ast_node *id) + struct scope *scope, struct ast *id) { UNUSED(state); - assert(id && id->node_type == AST_ID); + assert(id && id->k == AST_ID); id->scope = scope; /** @todo vars and procs kind of override eachother, i.e. @@ -1119,16 +1065,16 @@ static int actualize_id(struct act_state *state, * Either add in some syntax to distinguish procedure calls and * pointer calls or make procs and vars share the same namespace. * */ - struct ast_node *decl = file_scope_find_var(scope, id); + struct ast *decl = file_scope_find_var(scope, id_str(id)); if (decl) { - set_type(id, decl->type); + set_type(id, decl->t); decl->uses++; return 0; } - decl = file_scope_find_proc(scope, id); + decl = file_scope_find_proc(scope, id_str(id)); if (decl) { - set_type(id, decl->type); + set_type(id, decl->t); decl->uses++; return 0; } @@ -1138,320 +1084,268 @@ static int actualize_id(struct act_state *state, } static int actualize_var(struct act_state *state, - struct scope *scope, struct ast_node *var) + struct scope *scope, struct ast *var) { - assert(var && var->node_type == AST_VAR); - struct ast_node *init = AST_VAR(var).init; - struct ast_node *type = AST_VAR(var).type; + assert(var && var->k == AST_VAR_DEF); + struct ast *init = var_init(var); + struct type *type = var_type(var); /* one of these must be defined, otherwise the parser fucked up */ assert(type || init); - if (init && actualize(state, scope, init)) + if (init && actualize_list(state, scope, init)) return -1; - if (type && actualize(state, scope, type)) + if (type && actualize_type_list(state, scope, type)) return -1; - if (init && init->node_type == AST_INIT) { - assert(!init->type); + if (init && init->k == AST_INIT) { + assert(!init->t); set_type(init, type); /* TODO: some kind of check_init() */ } if (init && type) { /* make sure the asked type and the actualized types match */ - if (!types_match(init->type, type)) { - char *init_type = type_str(init->type); - char *req_type = type_str(type); - semantic_error(scope->fctx, var, - "type mismatch (%s vs %s)", - req_type, init_type); - free(init_type); - free(req_type); + if (!types_match(init->t, type)) { + type_mismatch(scope, var, init->t, type); return -1; } } - /* this is important for lowering */ - AST_VAR(var).id->scope = scope; var->scope = scope; if (init) /* infer */ - set_type(var, init->type); + set_type(var, init->t); if (type) - /* TODO: should there be some default value? */ + /* TODO: should there be some default zero value? */ /* declare */ set_type(var, type); /* an unnamed var is a var in a signature that should not produce a * warning on not being used (if I ever get around to adding those kinds * of warnings) */ - if (AST_VAR(var).id && !ast_flags(var, AST_FLAG_MEMBER)) + if (var_id(var) && !ast_flags(var, AST_FLAG_MEMBER)) return scope_add_var(scope, var); - /* TODO: we should make sure the type is fully qualified in bodies */ return 0; } -#define ENTER_ACT() \ - enum act_flags old_flags = state->flags; \ - struct ast_node *old_trait = state->cur_trait; - -#define EXIT_ACT(r) \ - do { \ - state->cur_trait = old_trait; \ - state->flags = old_flags; \ - return r; \ - } while (0); - -static enum ast_primitive id_to_primitive(struct ast_node *id) +static int actualize_tid(struct act_state *state, struct scope *scope, struct type *t) { - const char *name = AST_ID(id).id; - if (strcmp(name, "i27") == 0) - return AST_I27; + UNUSED(state); - if (strcmp(name, "i9") == 0) - return AST_I9; + /* no id means void */ + if (!t->id) { + replace_type(t, void_type()); + return 0; + } - if (strcmp(name, "bool") == 0) - return AST_BOOL; + struct src_loc l = t->loc; - /** @todo some better error reporting should probably be used */ - internal_error( "illegal primitive: %s\n", name); - return AST_VOID; -} + struct ast *def = file_scope_find_type(scope, t->id); + if (!def) { + type_error(scope->fctx, t, "no such type"); + return -1; + } -static int struct_is_primitive(struct ast_node *s) -{ - struct ast_node *id = AST_STRUCT(s).id; - const char *name = AST_ID(id).id; - if (strcmp(name, "i27") == 0) - return 1; + assert(t->n == NULL); + assert(def->k != AST_TRAIT_DEF); - if (strcmp(name, "i9") == 0) - return 1; + if (def->k == AST_ALIAS_DEF) { + replace_type(t, clone_type_list(def->t)); + t->a = def; + return 0; + } + else if (def->k == AST_STRUCT_DEF) { + replace_type(t, clone_type_list(def->t)); + return 0; + } + else if (def->k == AST_ENUM_DEF) { + replace_type(t, clone_type_list(def->t)); + return 0; + } - if (strcmp(name, "bool") == 0) - return 1; + return -1; +} - /* special case of a special case? - if (strcmp(name, "str")) - return 1; - */ +static int actualize_ptr(struct act_state *state, struct scope *scope, struct type *t) +{ + assert(ptr_base(t)); + if (actualize_type(state, scope, ptr_base(t))) + return -1; return 0; } -static int actualize_type(struct act_state *state, - struct scope *scope, struct ast_node *type) +static int actualize_callable(struct act_state *state, struct scope *scope, struct type *t) { - /* TODO: there's gotta be a better way to handle flags. Maybe macros - * like ENTER_ACTUALIZE and EXIT_ACTUALIZE? */ - /* TODO: get rid of aliases, expand implements, fill out structures, - * etc. */ - assert(type->node_type == AST_TYPE); - ENTER_ACT(); + struct type *ptypes = callable_ptypes(t); + struct type *rtype = callable_rtype(t); - if (actualize(state, scope, AST_TYPE(type).next)) { - EXIT_ACT(-1); + foreach_type(p, ptypes){ + if (actualize_type(state, scope, p)) + return -1; } - switch (AST_TYPE(type).kind) { - case AST_TYPE_ID: { - /* type IDs can really only be aliases to something else, or if - * they're missing, void */ - if (!AST_ID_TYPE(type).id) { - /* no ID means void */ - AST_ID_TYPE(type).id = - gen_id(strdup("void"), NULL_LOC()); - } - - struct ast_node *exists = file_scope_find_type(scope, - AST_ID_TYPE( - type).id); - if (!exists) { - semantic_error(scope->fctx, type, "no such type"); - EXIT_ACT(-1); - } + if (!rtype) + callable_rtype(t) = void_type(); - if (exists->node_type == AST_TYPE) { - assert(AST_TYPE(exists).kind == AST_TYPE_PRIMITIVE); - AST_TYPE(type) = AST_TYPE(exists); - break; - } + if (actualize_type(state, scope, rtype)) + return -1; - /* - if (actualize(state, exists->scope, exists)) - EXIT_ACT(-1); - */ + return 0; +} - assert(AST_TYPE(type).next == NULL); - if (exists->node_type == AST_ALIAS) { - AST_TYPE(type).aliased = exists; - AST_TYPE(type) = AST_TYPE(exists); - } - else if (exists->node_type == AST_TRAIT) { - /* this is kind of weird, have to think about it */ - *type = *gen_type(AST_TYPE_TRAIT, exists, - NULL, exists->loc); - } - else if (exists->node_type == AST_STRUCT) { - if (struct_is_primitive(exists)) { - *type = *gen_primitive( - id_to_primitive(AST_STRUCT(exists).id), - exists, - exists->loc); - } else { - *type = *gen_type(AST_TYPE_STRUCT, exists, - NULL, exists->loc); - } - } - else if (exists->node_type == AST_ENUM) { - *type = *gen_type(AST_TYPE_ENUM, exists, - NULL, exists->loc); - } +static int actualize_i27(struct act_state *state, struct scope *scope, struct type *t) +{ + /* not much to do */ + if (t->d) + return 0; - break; + struct ast *def = file_scope_find_type(scope, "i27"); + if (!def) { + error("missing definition of type 'i27'"); + return NULL; } - case AST_TYPE_CONSTRUCT: - /** @todo fully qualified constructs should be added to the - * actual list for code generation */ - semantic_info(scope->fctx, type, - "constructs unimplemented, continuing with compilation to see what breaks"); - break; + t->d = def; + return 0; +} - case AST_TYPE_ARR: - /* TODO: expression should be expandable to integer constant */ - semantic_info(scope->fctx, type, - "arrays unimplemented, continuing with compilation to see what breaks"); - break; +static int actualize_i9(struct act_state *state, struct scope *scope, struct type *t) +{ + /* not much to do */ + if (t->d) + return 0; - case AST_TYPE_POINTER: - assert(AST_PTR_TYPE(type).base); - if (actualize(state, scope, AST_PTR_TYPE(type).base)) - EXIT_ACT(-1); - break; + struct ast *def = file_scope_find_type(scope, "i9"); + if (!def) { + error("missing definition of type 'i9'"); + return NULL; + } - case AST_TYPE_SIGN: { - struct ast_node *params = AST_SIGN_TYPE(type).params; - struct ast_node *ret = AST_SIGN_TYPE(type).ret; + t->d = def; + return 0; +} - foreach_node(p, params){ - if (actualize(state, scope, p)) - EXIT_ACT(-1); - } +static int actualize_bool(struct act_state *state, struct scope *scope, struct type *t) +{ + /* not much to do */ + if (t->d) + return 0; - if (!ret) - ret = AST_SIGN_TYPE(type).ret = void_type(); + struct ast *def = file_scope_find_type(scope, "bool"); + if (!def) { + error("missing definition of type 'bool'"); + return NULL; + } - if (actualize(state, scope, ret)) - EXIT_ACT(-1); + t->d = def; + return 0; +} - break; - } +static int actualize_type(struct act_state *state, + struct scope *scope, + struct type *t) +{ + if (!t) + return 0; - case AST_TYPE_TRAIT: { - assert(ast_flags(type, AST_FLAG_ACTUAL)); - semantic_info(scope->fctx, type, - "FIXME skipping trait type checks"); - break; - } + t->scope = scope; - case AST_TYPE_STRUCT: { - assert(ast_flags(type, AST_FLAG_ACTUAL)); - semantic_info(scope->fctx, type, - "FIXME skipping struct type checks"); - break; - } + if (actualize_type(state, scope, t->n)) + return -1; - case AST_TYPE_PRIMITIVE: { - assert(ast_flags(type, AST_FLAG_ACTUAL)); - semantic_info(scope->fctx, type, - "FIXME skipping primitive type checks"); - break; - } + switch (t->k) { + case TYPE_I27: return actualize_i27(state, scope, t); + case TYPE_I9: return actualize_i9(state, scope, t); + case TYPE_BOOL: return actualize_bool(state, scope, t); + case TYPE_ID: return actualize_tid(state, scope, t); + case TYPE_PTR: return actualize_ptr(state, scope, t); + case TYPE_CALLABLE: return actualize_callable(state, scope, t); + case TYPE_VOID: return 0; /* void is by default actualized */ default: - semantic_error(scope->fctx, type, "unimplemented type"); - EXIT_ACT(-1); + type_info(scope->fctx, t, + "unimplemented type"); + type_info(scope->fctx, t, + "continuing with compilation to see what breaks"); + return 0; } - /* generally speaking */ - EXIT_ACT(0); + return 0; } -static int actualize_empty(struct act_state *state, - struct scope *scope, struct ast_node *node) +static int actualize_type_list(struct act_state *state, + struct scope *scope, + struct type *l) { - UNUSED(state); - /* TODO: converting to void is common enough that it might be worth - * creating a function for */ - struct ast_node *void_id = gen_id(strdup("void"), NULL_LOC()); - if (!void_id) { - internal_error( - "couldn't allocate type id for empty statement\n"); - return -1; - } - - node->type = gen_type(AST_TYPE_ID, void_id, NULL, NULL_LOC()); - if (!node->type) { - internal_error("couldn't allocate type for empty statement\n"); - return -1; + foreach_type(t, l) { + if (actualize_type(state, scope, t)) + return -1; } return 0; } -static int integral_type(struct ast_node *type) +static int actualize_empty(struct act_state *state, + struct scope *scope, struct ast *node) { - assert(type->node_type == AST_TYPE); - if (AST_TYPE(type).kind != AST_TYPE_PRIMITIVE) - return 0; + UNUSED(state); + UNUSED(scope); + node->t = void_type(); + return 0; +} - /* here would be awesome with an enum of our base types */ - enum ast_primitive p = AST_PRIMITIVE_TYPE(type).type; - switch (p) { - case AST_I9: return 1; - case AST_I27: return 1; - default: return 0; +static int integral_type(struct type *type) +{ + switch (type->k) { + case TYPE_I27: + case TYPE_I9: + case TYPE_BOOL: + return true; /* maybe? */ + default: } - return 0; + return false; } -static int pointer_type(struct ast_node *type) +static int pointer_type(struct type *type) { - assert(type->node_type == AST_TYPE); - return type->_type.kind == AST_TYPE_POINTER; + return type->k == TYPE_PTR; } -static int pointer_conversion(struct ast_node *a, struct ast_node *b) +static int pointer_conversion(struct type *a, struct type *b) { - assert(a->node_type == AST_TYPE); - assert(b->node_type == AST_TYPE); if (pointer_type(a)) { - if (AST_TYPE(b).kind != AST_TYPE_PRIMITIVE) + if (!is_primitive(b)) return 0; /* for now */ - return AST_PRIMITIVE_TYPE(b).type == AST_I27; + return b->k == TYPE_I27; } return 0; } -static size_t member_count(struct ast_node *exists) +static size_t member_count(struct ast *exists) { - assert(exists->node_type == AST_STRUCT); - struct ast_node *body = exists->_struct.body; - return ast_list_len(body); + assert(exists->k == AST_STRUCT_DEF); + struct ast *body = struct_body(exists); + + size_t count = 0; + foreach_node(n, body) { + if (n->k == AST_VAR_DEF) + count++; + } + + return count; } -static struct ast_node *lookup_member_idx(struct ast_node *body, - struct ast_node *find, +static struct ast *lookup_member_idx(struct ast *body, + char *find, size_t *idx) { /* micro-optimisation, likely way premature but speeds up selection @@ -1459,27 +1353,26 @@ static struct ast_node *lookup_member_idx(struct ast_node *body, (void)(find); assert(idx); size_t i = *idx; - struct ast_node *m = body; + struct ast *m = body; while (i != 0 && m) { - m = m->next; + m = m->n; i--; } return m; } -static struct ast_node *lookup_member_name(struct ast_node *body, - struct ast_node *find, +static struct ast *lookup_member_name(struct ast *body, + char *find, size_t *idx) { - assert(find->node_type == AST_ID); size_t i = 0; - struct ast_node *m = body; + struct ast *m = body; while (m) { - assert(m->node_type == AST_VAR); - if (same_id(find, AST_VAR(m).id)) + assert(m->k == AST_VAR_DEF); + if (same_id(find, var_id(m))) break; - m = m->next; + m = m->n; i++; } @@ -1489,25 +1382,25 @@ static struct ast_node *lookup_member_name(struct ast_node *body, return m; } -static struct ast_node *lookup_struct_member(struct ast_node *struc, - struct ast_node *find, size_t *idx) +static struct ast *lookup_struct_member(struct ast *struc, + char *find, size_t *idx) { if (find) - return lookup_member_name(struc->_struct.body, find, idx); + return lookup_member_name(struct_body(struc), find, idx); - return lookup_member_idx(struc->_struct.body, find, idx); + return lookup_member_idx(struct_body(struc), find, idx); } -static struct ast_node *lookup_enum_member(struct ast_node *enu, - struct ast_node *find) +static struct ast *lookup_enum_member(struct ast *enu, + char *find) { size_t i = 0; - struct ast_node *m = enu->_enum.body; + struct ast *m = enum_body(enu); while (m) { - assert(m->node_type == AST_VAL); - if (same_id(find, AST_VAL(m).id)) + assert(m->k == AST_VAL); + if (same_id(find, val_id(m))) break; - m = m->next; + m = m->n; i++; } @@ -1515,7 +1408,7 @@ static struct ast_node *lookup_enum_member(struct ast_node *enu, } static int init_struct(struct act_state *state, struct scope *scope, - struct ast_node *exists, struct ast_node *init) + struct ast *exists, struct ast *init) { size_t i = 0; size_t mcount = member_count(exists); @@ -1527,7 +1420,7 @@ static int init_struct(struct act_state *state, struct scope *scope, return -1; } - struct ast_node *args = init->_init.body; + struct ast *args = init_body(init); while (args) { if (i >= mcount) { semantic_error(scope->fctx, args, @@ -1546,15 +1439,15 @@ static int init_struct(struct act_state *state, struct scope *scope, if ((ret = actualize(state, scope, args))) break; - struct ast_node *find = NULL; + char *find = NULL; if (ast_flags(args, AST_FLAG_MEMBER)) - find = args->_var.id; + find = var_id(args); - struct ast_node *member = + struct ast *member = lookup_struct_member(exists, find, &i); if (!member) { - char *sstr = type_str(exists->type); + char *sstr = type_str(exists->t); semantic_error(scope->fctx, args, "no such member in %s", sstr); @@ -1563,9 +1456,9 @@ static int init_struct(struct act_state *state, struct scope *scope, break; } - if (!types_match(args->type, member->type)) { - char *astr = type_str(args->type); - char *mstr = type_str(member->type); + if (!types_match(args->t, member->t)) { + char *astr = type_str(args->t); + char *mstr = type_str(member->t); semantic_error(scope->fctx, args, "%s does not match %s", astr, mstr); free(astr); @@ -1575,7 +1468,7 @@ static int init_struct(struct act_state *state, struct scope *scope, } initd[i] = 1; - args = args->next; + args = args->n; i++; } @@ -1585,108 +1478,70 @@ static int init_struct(struct act_state *state, struct scope *scope, static int actualize_struct_init_cast(struct act_state *state, struct scope *scope, - struct ast_node *init, - struct ast_node *actual) + struct ast *init, + struct type *type) { - struct ast_node *def = AST_STRUCT_TYPE(actual).def; + struct ast *def = type->d; return init_struct(state, scope, def, init); } static int actualize_init_cast(struct act_state *state, - struct scope *scope, struct ast_node *init, - struct ast_node *type) + struct scope *scope, struct ast *init, + struct type *type) { - if (AST_TYPE(type).kind == AST_TYPE_STRUCT) + if (type->k == TYPE_STRUCT) return actualize_struct_init_cast(state, scope, init, type); - semantic_error(scope->fctx, type, + type_error(scope->fctx, type, "type is not a struct"); return -1; } -static int proc_pointer(struct ast_node *type) -{ - if (type->_type.kind != AST_TYPE_POINTER) - return 0; - - struct ast_node *next = type->_type.next; - if (next->_type.kind != AST_TYPE_SIGN) - return 0; - - return 1; -} - -static int proc_choice(struct ast_node *expr, struct ast_node *type) -{ - if (expr->node_type != AST_ID) - return 0; - - if (!proc_pointer(type)) - return 0; - - return 1; -} - -/* still slightly unsure about this, but hey ho */ -static int match_proc(struct act_state *state, struct scope *scope, - struct ast_node *cast) -{ - (void)(state); - semantic_error(scope->fctx, cast, - "procedure signature casts not yet implemented"); - return -1; -} - static int actualize_cast(struct act_state *state, - struct scope *scope, struct ast_node *cast) + struct scope *scope, struct ast *cast) { - assert(cast->node_type == AST_CAST); - struct ast_node *expr = cast->_cast.expr; - struct ast_node *type = cast->_cast.type; + assert(cast->k == AST_CAST); + struct ast *expr = cast_expr(cast); + struct type *type = cast_type(cast); - if (actualize(state, scope, type)) + if (actualize_type(state, scope, type)) return -1; - if (proc_choice(expr, type)) { - set_type(cast, type); - return match_proc(state, scope, cast); - } - if (actualize(state, scope, expr)) return -1; - if (expr->node_type == AST_INIT) { + if (expr->k == AST_INIT) { set_type(cast, type); return actualize_init_cast(state, scope, expr, type); } - if (types_match(expr->type, type)) { + if (types_match(expr->t, type)) { set_type(cast, type); return 0; } - if (integral_type(expr->type) && integral_type(type)) { + if (integral_type(expr->t) && integral_type(type)) { set_type(cast, type); return 0; } - if (pointer_type(expr->type) && pointer_type(type)) { + if (pointer_type(expr->t) && pointer_type(type)) { set_type(cast, type); return 0; } - if (pointer_conversion(expr->type, type) - || pointer_conversion(type, expr->type)) { + if (pointer_conversion(expr->t, type) + || pointer_conversion(type, expr->t)) { set_type(cast, type); return 0; } /* TODO: arrays? */ - char *left_type = type_str(expr); + char *left_type = type_str(expr->t); char *right_type = type_str(type); - semantic_error(scope->fctx, cast, "illegal cast (%s vs %s)", + semantic_error(scope->fctx, cast, "illegal cast: %s vs %s", left_type, right_type); free(left_type); free(right_type); @@ -1694,17 +1549,22 @@ static int actualize_cast(struct act_state *state, } static int actualize_const(struct act_state *state, struct scope *scope, - struct ast_node *cons) + struct ast *cons) { UNUSED(state); - assert(cons->node_type == AST_CONST); - if (AST_CONST(cons).kind == AST_CONST_INTEGER) - cons->type = i27_type(scope); + if (cons->k == AST_CONST_INT) + cons->t = i27_type(scope); + + else if (cons->k == AST_CONST_CHAR) + cons->t = i9_type(scope); - else if (AST_CONST(cons).kind == AST_CONST_STRING) - cons->type = str_type(scope); + else if (cons->k == AST_CONST_BOOL) + cons->t = bool_type(scope); - if (cons->type) + else if (cons->k == AST_CONST_STR) + cons->t = str_type(scope); + + if (cons->t) return 0; semantic_error(scope->fctx, cons, "unimplemented constant"); @@ -1712,13 +1572,13 @@ static int actualize_const(struct act_state *state, struct scope *scope, } static int actualize_alias(struct act_state *state, struct scope *scope, - struct ast_node *alias) + struct ast *alias) { /* I shall have to think about things, as currently very deeply nested * aliases might be a bit cumbersome to work with. Still, this works * well enough I suppose. */ - assert(alias->node_type == AST_ALIAS); - if (actualize(state, scope, AST_ALIAS(alias).type)) { + assert(alias->k == AST_ALIAS_DEF); + if (actualize_type(state, scope, alias_type(alias))) { /* usually we don't want to output errors upon errors, but this * is likely a useful message as it might show where a loop is * occuring */ @@ -1731,9 +1591,9 @@ static int actualize_alias(struct act_state *state, struct scope *scope, } static int actualize_defer(struct act_state *state, - struct scope *scope, struct ast_node *node) + struct scope *scope, struct ast *node) { - struct ast_node *expr = node->_defer.expr; + struct ast *expr = defer_expr(node); /* TODO: should the actualization only happen when the defers are * called? */ if (actualize(state, scope, expr)) @@ -1742,61 +1602,54 @@ static int actualize_defer(struct act_state *state, if (push_defer(state, expr)) return -1; - node->type = void_type(); + node->t = void_type(); return 0; } static int actualize_return(struct act_state *state, struct scope *scope, - struct ast_node *node) + struct ast *node) { act_set_flags(state, ACT_HAS_RETURN); - struct ast_node *expr = node->_return.expr; + struct ast *expr = return_expr(node); if (expr) { if (actualize(state, scope, expr)) return -1; - set_type(node, expr->type); + set_type(node, expr->t); } else { - node->type = void_type(); + node->t = void_type(); } assert(state->cur_proc); - struct ast_node *cur_proc = state->cur_proc; - struct ast_node *sign = AST_PROC(cur_proc).sign; - struct ast_node *ret = AST_SIGN_TYPE(sign).ret; - if (!types_match(node->type, ret)) { - char *rt = type_str(ret); - char *et = type_str(node); - semantic_error(scope->fctx, node, - "return type mismatch: %s", et); - - semantic_info(scope->fctx, ret, - "vs %s", rt); - free(rt); - free(et); + struct ast *cur_proc = state->cur_proc; + struct type *rtype = proc_rtype(cur_proc); + if (!types_match(node->t, rtype)) { + /* hmm, should this be "return type mismatch? */ + type_mismatch(scope, node, rtype, node->t); return -1; } if (state->defer_stack) { - AST_RETURN(node).defers = clone_defers(state, NULL); - if (!node->_return.defers) { + return_defers(node) = clone_defers(state, NULL); + if (!return_defers(node)) { internal_error("failed cloning return defers"); return -1; } } + return 0; } /* Still slightly unsure if this works in all cases, but a good start * nonetheless. */ -static void actualize_goto_defer(struct ast_node *got, struct ast_node *label) +static void actualize_goto_defer(struct ast *got, struct ast *label) { - struct ast_node *goto_defers = AST_GOTO(got).defers; - struct ast_node *label_defers = AST_LABEL(label).defers; + struct ast *goto_defers = goto_defers(got); + struct ast *label_defers = label_defers(label); /* since we're dealing with singly linked lists, keep a reference to one * node before the current goto defer. */ - struct ast_node *prev_defer = NULL; + struct ast *prev_defer = NULL; /* this goto has a defined label */ ast_set_flags(got, AST_FLAG_ACTUAL); @@ -1808,12 +1661,12 @@ static void actualize_goto_defer(struct ast_node *got, struct ast_node *label) /* find first common defer statement */ while (goto_len > label_len) { prev_defer = goto_defers; - goto_defers = goto_defers->next; + goto_defers = goto_defers->n; goto_len--; } while (label_len > goto_len) { - label_defers = label_defers->next; + label_defers = label_defers->n; label_len--; } @@ -1823,15 +1676,15 @@ static void actualize_goto_defer(struct ast_node *got, struct ast_node *label) * unlikely that goto stuff would be a major bottleneck. */ while (!equiv_nodes(goto_defers, label_defers)) { prev_defer = goto_defers; - label_defers = label_defers->next; - goto_defers = goto_defers->next; + label_defers = label_defers->n; + goto_defers = goto_defers->n; } /* only the defers below the common defer should be executed by the goto */ if (goto_defers) { /* fuck, I actually need the one previous to this */ - assert(prev_defer->next == goto_defers); - prev_defer->next = NULL; + assert(prev_defer->n == goto_defers); + prev_defer->n = NULL; } /* nothing to do */ @@ -1839,16 +1692,16 @@ static void actualize_goto_defer(struct ast_node *got, struct ast_node *label) static int actualize_goto(struct act_state *state, struct scope *scope, - struct ast_node *node) + struct ast *node) { - assert(node->node_type == AST_GOTO); + assert(node->k == AST_GOTO); push_goto(state, node); /* clone all defers as we don't know where the label might be */ - node->_goto.defers = clone_defers(state, NULL); - node->type = void_type(); + goto_defers(node) = clone_defers(state, NULL); + node->t = void_type(); - struct ast_node *label = find_label(state, node->_goto.label); + struct ast *label = find_label(state, goto_label(node)); /* this is a jump backwards, i.e. we can already do it */ if (label) actualize_goto_defer(node, label); @@ -1858,24 +1711,24 @@ static int actualize_goto(struct act_state *state, struct scope *scope, } static void actualize_goto_defers(struct act_state *state, - struct ast_node *label) + struct ast *label) { struct act_stack *prev = state->goto_stack, *cur; if (prev) do { cur = prev->next; - struct ast_node *got = prev->node; - if (equiv_nodes(AST_GOTO(got).label, label)) + struct ast *got = prev->node; + if (same_id(goto_label(got), label_id(label))) actualize_goto_defer(got, label); } while ((prev = cur)); } static int actualize_label(struct act_state *state, struct scope *scope, - struct ast_node *node) + struct ast *node) { - assert(node->node_type == AST_LABEL); - struct ast_node *prev = find_label(state, node); + assert(node->k == AST_LABEL); + struct ast *prev = find_label(state, label_id(node)); if (prev) { semantic_error(scope->fctx, node, "label redefined"); semantic_info(scope->fctx, prev, "previous definition"); @@ -1884,60 +1737,65 @@ static int actualize_label(struct act_state *state, struct scope *scope, push_label(state, node); /* clone all defers */ - node->_label.defers = clone_defers(state, NULL); - node->type = void_type(); + label_defers(node) = clone_defers(state, NULL); + node->t = void_type(); actualize_goto_defers(state, node); return 0; } static int actualize_unop(struct act_state *state, - struct scope *scope, struct ast_node *node) + struct scope *scope, struct ast *node) { - assert(node->node_type == AST_UNOP); - struct ast_node *expr = AST_UNOP(node).expr; + assert(is_unop(node)); + struct ast *expr = unop_expr(node); if (actualize(state, scope, expr)) return -1; /* generally speaking */ - set_type(node, expr->type); + set_type(node, expr->t); - switch (node->_unop.op) { + switch (node->k) { case AST_DEREF: { - struct ast_node *type = expr->type; - if (AST_TYPE(type).kind != AST_TYPE_POINTER) { - /* TODO: or array */ + struct type *type = expr->t; + if (type->k!= TYPE_PTR) { + /** @todo or array? */ + char *tstr = type_str(type); semantic_error(scope->fctx, expr, - "trying to dereference something that's not a pointer"); + "not a pointer: %s", + tstr); + free(tstr); return -1; } - set_type(node, AST_PTR_TYPE(type).base); - assert(node->type); + set_type(node, ptr_base(type)); + assert(node->t); break; } case AST_REF: { - node->type = gen_type(AST_TYPE_POINTER, NULL, NULL, - NULL_LOC()); - set_type(node->AST_TYPE(type).next, expr->type); + /** @todo array pointer decay? */ + node->t = tgen_ptr(clone_type(expr->t), node->loc); break; } case AST_LNOT: { - if (AST_TYPE(expr->type).kind != AST_TYPE_PRIMITIVE) { + if (is_primitive(expr->t)) { + char *tstr = type_str(expr->t); semantic_error(scope->fctx, node, - "'!' only implemented for primitive types"); + "'!' only implemented for primitive types: %s", + tstr); + free(tstr); return -1; } - if (AST_PRIMITIVE_TYPE(expr->type).type == AST_VOID) { + if (expr->t->k == TYPE_VOID) { semantic_error(scope->fctx, node, "'!' not implemented for void"); return -1; } - node->type = bool_type(scope); + node->t = bool_type(scope); break; } @@ -1950,79 +1808,90 @@ static int actualize_unop(struct act_state *state, } static int actualize_as(struct act_state *state, - struct scope *scope, struct ast_node *as) + struct scope *scope, struct ast *as) { - assert(as->node_type == AST_AS); - struct ast_node *type = AST_AS(as).type; - if (actualize(state, scope, type)) + assert(as->k == AST_AS); + struct type *type = as->t; + if (actualize_type(state, scope, type)) return -1; set_type(as, type); return 0; } -static int _replace_type_id(struct ast_node *node, void *data) -{ - if (!node) - return 0; +struct replace_data { + char *id; + struct type *replacement; +}; - struct ast_node **pair = data; - struct ast_node *id = pair[0]; - struct ast_node *replacement = pair[1]; +static int _replace_type_id(struct type *type, void *data) +{ + struct replace_data *pair = data; + struct type *replacement = pair->replacement; + char *id = pair->id; - if (node->node_type != AST_TYPE) - goto next; + switch (type->k) { + case TYPE_ID: { + replace_type(type, clone_type(replacement)); + break; + } - switch (AST_TYPE(node).kind) { - case AST_TYPE_ID: *node = *clone_ast_node(replacement); break; - case AST_TYPE_TRAIT: { - struct ast_node *def = AST_TRAIT_TYPE(node).def; + case TYPE_TRAIT: { + struct ast *def = type->d; assert(def); - struct ast_node *name = AST_TRAIT(def).id; + + char *name = trait_id(def); if (same_id(id, name)) - *node = *clone_ast_node(replacement); + replace_type(type, clone_type(replacement)); break; } - case AST_TYPE_STRUCT: { - struct ast_node *def = AST_STRUCT_TYPE(node).def; + case TYPE_STRUCT: { + struct ast *def = type->d; assert(def); - struct ast_node *name = AST_STRUCT(def).id; + char *name = struct_id(def); if (same_id(id, name)) - *node = *clone_ast_node(replacement); + replace_type(type, clone_type(replacement)); break; } + default: } -next: - return ast_call_on(_replace_type_id, node, data); + return 0; } -static int replace_type_id(struct ast_node *nodes, struct ast_node *id, - struct ast_node *replacement) +static int _replace_ast_type_id(struct ast *node, void *data) { - assert(replacement->node_type == AST_TYPE); - struct ast_node *pair[2] = {id, replacement}; - return ast_call_on(_replace_type_id, nodes, pair); + if (!node) + return 0; + + return type_visit_list(_replace_type_id, NULL, node->t, data); +} + +static int replace_type_id(struct ast *nodes, char *id, + struct type *replacement) +{ + struct replace_data pair = {id, replacement}; + return ast_visit(_replace_ast_type_id, NULL, nodes, &pair); } /* lots of overlap with actualize_struct, kind of ugly... */ static int actualize_trait(struct act_state *state, struct scope *scope, - struct ast_node *node) + struct ast *node) { - assert(node->node_type == AST_TRAIT); - foreach_node(n, AST_TRAIT(node).body) { + assert(node->k == AST_TRAIT_DEF); + foreach_node(n, trait_body(node)) { /* there's really only prodcedure body actualization left I * guess, as type stuff was taken care of in the analysis phase * */ - if (n->node_type != AST_PROC) + if (n->k != AST_PROC_DEF) continue; /* don't actualize prototypes, duh */ - if (!AST_PROC(n).body) + if (!proc_body(n)) continue; if (actualize(state, node->scope, n)) @@ -2033,18 +1902,18 @@ static int actualize_trait(struct act_state *state, struct scope *scope, } static int actualize_struct(struct act_state *state, - struct scope *scope, struct ast_node *node) + struct scope *scope, struct ast *node) { - assert(node->node_type == AST_STRUCT); - foreach_node(n, AST_STRUCT(node).body) { + assert(node->k == AST_STRUCT_DEF); + foreach_node(n, struct_body(node)) { /* there's really only prodcedure body actualization left I * guess, as type stuff was taken care of in the analysis phase * */ - if (n->node_type != AST_PROC) + if (n->k != AST_PROC_DEF) continue; /* don't actualize prototypes, duh */ - if (!AST_PROC(n).body) + if (!proc_body(n)) continue; if (actualize(state, node->scope, n)) @@ -2057,23 +1926,23 @@ static int actualize_struct(struct act_state *state, /* could maybe be renamed, but essentially dot in copper works as either * -> or . in C, so allow structures or traits and single level pointers to * structures or traits. */ -static int has_members(struct ast_node *type) +static int has_members(struct type *type) { /* most likely */ - if (AST_TYPE(type).kind == AST_TYPE_STRUCT) + if (type->k == TYPE_STRUCT) return 1; - if (AST_TYPE(type).kind == AST_TYPE_TRAIT) + if (type->k == TYPE_TRAIT) return 1; - if (AST_TYPE(type).kind == AST_TYPE_CONSTRUCT) + if (type->k == TYPE_CONSTRUCT) return 1; return 0; } static int actualize_dot(struct act_state *state, - struct scope *scope, struct ast_node *node) + struct scope *scope, struct ast *node) { /* TODO: handle enums as well, idea is something like * enum whatever {A_FLAG} @@ -2083,19 +1952,18 @@ static int actualize_dot(struct act_state *state, * possibly also if the expr is of type whatever then .A_FLAG just gets * the corresponding constant? **/ - assert(node->node_type == AST_DOT); - struct ast_node *expr = AST_DOT(node).expr; + assert(node->k == AST_DOT); + struct ast *expr = dot_expr(node); if (actualize(state, scope, expr)) return -1; - struct ast_node *id = AST_DOT(node).id; - struct ast_node *type = expr->type; + char *id = dot_id(node); + struct type *type = expr->t; - struct ast_node *def = NULL; - switch (AST_TYPE(type).kind) { - case AST_TYPE_PRIMITIVE: def = AST_PRIMITIVE_TYPE(type).def; break; - case AST_TYPE_TRAIT: def = AST_TRAIT_TYPE(type).def; break; - case AST_TYPE_STRUCT: def = AST_STRUCT_TYPE(type).def; break; + struct ast *def = NULL; + switch (type->k) { + case TYPE_TRAIT: + case TYPE_STRUCT: def = type->d; break; default: { char *tstr = type_str(type); semantic_error(scope->fctx, node, @@ -2106,17 +1974,17 @@ static int actualize_dot(struct act_state *state, } } - struct ast_node *exists = scope_find_var(def->scope, id); + struct ast *exists = scope_find_var(def->scope, id); if (exists) { - assert(exists->type); - set_type(node, exists->type); + assert(exists->t); + set_type(node, exists->t); return 0; } exists = scope_find_proc(def->scope, id); if (exists) { - assert(exists->type); - set_type(node, exists->type); + assert(exists->t); + set_type(node, exists->t); return 0; } @@ -2126,42 +1994,33 @@ static int actualize_dot(struct act_state *state, } static int actualize_init(struct act_state *state, - struct scope *scope, struct ast_node *node) + struct scope *scope, struct ast *node) { - assert(node->node_type == AST_INIT); + assert(node->k == AST_INIT); /* for now just do the types, the named stuff will be checked later */ /* TODO: how to make sure all members are initialized? */ - int ret = 0; - enum act_flags old_flags = state->flags; - ret = actualize(state, scope, node->_init.body); - state->flags = old_flags; - return ret; + return actualize_list(state, scope, init_body(node)); } static int actualize_assign(struct act_state *state, struct scope *scope, - struct ast_node *node) + struct ast *node) { - assert(node->node_type == AST_ASSIGN); - struct ast_node *to = node->_assign.to; + assert(node->k == AST_ASSIGN); + struct ast *to = assign_to(node); if (actualize(state, scope, to)) return -1; - struct ast_node *from = node->_assign.from; - if (actualize(state, scope, from)) + struct ast *from = assign_from(node); + if (actualize_list(state, scope, from)) return -1; - if (from->node_type == AST_INIT) { - set_type(node, to->type); - return actualize_init_cast(state, scope, from, to->type); + if (from->k == AST_INIT) { + set_type(node, to->t); + return actualize_init_cast(state, scope, from, to->t); } - if (!types_match(to->type, from->type)) { - char *tostr = type_str(to->type); - char *fromstr = type_str(from->type); - semantic_error(scope->fctx, node, "type mismatch (%s vs %s)", - tostr, fromstr); - free(tostr); - free(fromstr); + if (!types_match(to->t, from->t)) { + type_mismatch(scope, node, to->t, from->t); return -1; } @@ -2172,84 +2031,77 @@ static int actualize_assign(struct act_state *state, struct scope *scope, return -1; } - set_type(node, to->type); + set_type(node, to->t); return 0; } static int actualize_fetch(struct act_state *state, struct scope *scope, - struct ast_node *fetch) + struct ast *fetch) { - assert(fetch->node_type == AST_FETCH); - struct ast_node *type = fetch->_fetch.type; - if (actualize(state, scope, type)) + assert(fetch->k == AST_FETCH); + struct type *type = fetch_type(fetch); + if (actualize_type(state, scope, type)) return -1; - if (type->_type.kind != AST_TYPE_ENUM) { - semantic_error(scope->fctx, type, "type is not an enum"); + if (type->k != TYPE_ENUM) { + type_error(scope->fctx, type, "type is not an enum"); return -1; } - struct ast_node *id = fetch->_fetch.id; - struct ast_node *def = - file_scope_find_type(scope, AST_ID_TYPE(type).id); + char *id = fetch_id(fetch); + struct ast *def = type->d; assert(def); - struct ast_node *member = lookup_enum_member(def, id); + struct ast *member = lookup_enum_member(def, id); if (!member) { char *estr = type_str(type); - semantic_error(scope->fctx, id, "no such member in enum %s"); + semantic_error(scope->fctx, fetch, "no such member in enum %s"); free(estr); return -1; } - set_type(fetch, def->type); + set_type(fetch, def->t); return 0; } static int actualize_enum(struct act_state *state, struct scope *scope, - struct ast_node *node) + struct ast *node) { - assert(node->node_type == AST_ENUM); - struct ast_node *type = node->_enum.type; + assert(node->k == AST_ENUM_DEF); + struct type *type = enum_type(node); struct scope *enum_scope = node->scope; /* TODO: here we could save space by choosing the smallest type that * fits */ if (!type) { type = i27_type(scope); - node->_enum.type = type; - } else if (actualize(state, enum_scope, type)) + node->t = type; + } else if (actualize_type(state, enum_scope, type)) return -1; long long counter = 0; - node->type = type; - struct ast_node *members = node->_enum.body; + node->t = type; + struct ast *members = enum_body(node); while (members) { set_type(members, type); - if (members->_val.val) { - struct ast_node *val = members->_val.val; + if (val_val(members)) { + struct ast *val = val_val(members); if (actualize(state, enum_scope, val)) return -1; - if (val->node_type != AST_CONST) { + if (val->k != AST_CONST_INT) { semantic_error(scope->fctx, members, "unable to process nonconstant expression"); return -1; } - if (val->_const.kind != AST_CONST_INTEGER) { - semantic_error(scope->fctx, members, - "not expandable to an integer constant"); - return -1; - } - - counter = val->_const.integer; + counter = int_val(val); } else { - members->_val.val = gen_int(counter, NULL_LOC()); + val_val(members) = gen_const_int(counter, NULL_LOC()); } - members = members->next; + members = members->n; counter++; } @@ -2258,21 +2110,21 @@ static int actualize_enum(struct act_state *state, struct scope *scope, } static int actualize_if(struct act_state *state, struct scope *scope, - struct ast_node *node) + struct ast *node) { - assert(node->node_type == AST_IF); - if (actualize(state, scope, AST_IF(node).cond)) + assert(node->k == AST_IF); + if (actualize(state, scope, if_cond(node))) return -1; - if (actualize(state, scope, AST_IF(node).body)) + if (actualize(state, scope, if_body(node))) return -1; - if (actualize(state, scope, AST_IF(node).els)) + if (actualize(state, scope, if_else(node))) return -1; if (ast_flags(node, AST_FLAG_DOEXPR)) { - struct ast_node *tt = ast_last_node(AST_IF(node).body)->type; - struct ast_node *ft = ast_last_node(AST_IF(node).els)->type; + struct type *tt = ast_last(if_body(node))->t; + struct type *ft = ast_last(if_else(node))->t; if (!types_match(tt, ft)) { semantic_error(scope->fctx, node, "mismatched if/else body values"); @@ -2283,143 +2135,124 @@ static int actualize_if(struct act_state *state, struct scope *scope, return 0; } - node->type = void_type(); + node->t = void_type(); return 0; } static int actualize_for(struct act_state *state, struct scope *scope, - struct ast_node *node) + struct ast *node) { - assert(node->node_type == AST_FOR); - if (actualize(state, scope, AST_FOR(node).pre)) + assert(node->k == AST_FOR); + if (actualize_list(state, scope, for_pre(node))) return -1; - if (actualize(state, scope, AST_FOR(node).post)) + if (actualize_list(state, scope, for_post(node))) return -1; - if (actualize(state, scope, AST_FOR(node).cond)) + if (actualize_list(state, scope, for_cond(node))) return -1; - if (actualize(state, scope, AST_FOR(node).body)) + if (actualize_list(state, scope, for_body(node))) return -1; - node->type = void_type(); + node->t = void_type(); + return 0; +} + +static int actualize_comparison(struct act_state *state, struct scope *scope, struct ast *node) +{ + assert(is_comparison(node)); + struct ast *left = comparison_left(node); + struct ast *right = comparison_right(node); + + if (actualize(state, scope, left)) + return -1; + + if (actualize(state, scope, right)) + return -1; + + if (!is_primitive(left->t)) { + type_error(scope->fctx, left->t, "primitive type required"); + return -1; + } + + if (!is_primitive(right->t)) { + type_error(scope->fctx, right->t, "primitive type required"); + return -1; + } + + if (!types_match(left->t, right->t)) { + type_mismatch(scope, node, left->t, right->t); + return -1; + } + + set_type(node, bool_type(scope)); return 0; } static int actualize(struct act_state *state, struct scope *scope, - struct ast_node *node) + struct ast *node) { - int ret = 0; if (!node) - return ret; + return 0; if (!node->scope) node->scope = scope; - /* this node was already actualized, presumed to be fine */ - if (ast_flags(node, AST_FLAG_ACTUAL)) { - return 0; - } - - /* actualization started */ - ast_set_flags(node, AST_FLAG_INIT); + if (is_unop(node)) + return actualize_unop(state, scope, node); - /* actualization done for this node (optimistic) */ - ast_set_flags(node, AST_FLAG_ACTUAL); + if (is_binop(node)) + return actualize_binop(state, scope, node); - switch (node->node_type) { - case AST_PROC: - ret |= actualize_proc(state, scope, node); - break; + if (is_comparison(node)) + return actualize_comparison(state, scope, node); - case AST_TRAIT: ret |= actualize_trait(state, scope, node); break; - case AST_ALIAS: ret |= actualize_alias(state, scope, node); break; - case AST_MACRO_CONSTRUCT: ret |= actualize_macro_construct(state, scope, - node); break; - case AST_MACRO_EXPAND: ret |= - actualize_macro_expand(state, scope, node); break; - case AST_CALL: ret |= actualize_call(state, scope, node); break; - case AST_BINOP: ret |= actualize_binop(state, scope, node); break; - case AST_BLOCK: ret |= actualize_block(state, scope, node); break; - case AST_ID: ret |= actualize_id(state, scope, node); break; - case AST_VAR: ret |= actualize_var(state, scope, node); break; - case AST_TYPE: ret |= actualize_type(state, scope, node); break; - case AST_EMPTY: ret |= actualize_empty(state, scope, node); break; - case AST_CAST: ret |= actualize_cast(state, scope, node); break; - case AST_CONST: ret |= actualize_const(state, scope, node); break; - case AST_DEFER: ret |= actualize_defer(state, scope, node); break; - case AST_RETURN: ret |= actualize_return(state, scope, node); break; - case AST_GOTO: ret |= actualize_goto(state, scope, node); break; - case AST_LABEL: ret |= actualize_label(state, scope, node); break; - case AST_UNOP: ret |= actualize_unop(state, scope, node); break; - case AST_AS: ret |= actualize_as(state, scope, node); break; - case AST_STRUCT: ret |= actualize_struct(state, scope, node); break; - case AST_DOT: ret |= actualize_dot(state, scope, node); break; - case AST_INIT: ret |= actualize_init(state, scope, node); break; - case AST_ASSIGN: ret |= actualize_assign(state, scope, node); break; - case AST_FETCH: ret |= actualize_fetch(state, scope, node); break; - case AST_ENUM: ret |= actualize_enum(state, scope, node); break; - case AST_IF: ret |= actualize_if(state, scope, node); break; - case AST_FOR: ret |= actualize_for(state, scope, node); break; + if (is_const(node)) + return actualize_const(state, scope, node); + switch (node->k) { + case AST_PROC_DEF: return actualize_proc(state, scope, node); + case AST_TRAIT_DEF: return actualize_trait(state, scope, node); + case AST_ALIAS_DEF: return actualize_alias(state, scope, node); + case AST_ENUM_DEF: return actualize_enum(state, scope, node); + case AST_MACRO_DEF: return actualize_macro_def(state, scope, node); + case AST_STRUCT_DEF: return actualize_struct(state, scope, node); + case AST_VAR_DEF: return actualize_var(state, scope, node); + case AST_CALL: return actualize_call(state, scope, node); + case AST_BLOCK: return actualize_block(state, scope, node); + case AST_ID: return actualize_id(state, scope, node); + case AST_EMPTY: return actualize_empty(state, scope, node); + case AST_CAST: return actualize_cast(state, scope, node); + case AST_DEFER: return actualize_defer(state, scope, node); + case AST_RETURN: return actualize_return(state, scope, node); + case AST_GOTO: return actualize_goto(state, scope, node); + case AST_LABEL: return actualize_label(state, scope, node); + case AST_AS: return actualize_as(state, scope, node); + case AST_DOT: return actualize_dot(state, scope, node); + case AST_INIT: return actualize_init(state, scope, node); + case AST_ASSIGN: return actualize_assign(state, scope, node); + case AST_FETCH: return actualize_fetch(state, scope, node); + case AST_IF: return actualize_if(state, scope, node); + case AST_FOR: return actualize_for(state, scope, node); + case AST_MACRO_EXPAND: return actualize_macro_expand(state, scope, node); default: /* more like internal_error, maybe? */ semantic_error(scope->fctx, node, "unimplemented actualization"); - break; - } - return ret; -} - -int actualize_main(struct scope *root) -{ - struct ast_node *main_id = gen_id(strdup("main"), NULL_LOC()); - - struct act_state state = {0}; - - /* skip checking signature for now */ - struct ast_node *main = file_scope_find_proc(root, main_id); - if (!main) { - /* libraries are not really compilable... */ - error("no main"); return -1; } - int ret = actualize(&state, root, main); - destroy_act_state(&state); - return ret; -} - -void replace_type(struct ast_node *type, struct ast_node *from, - struct ast_node *to) -{ - if (!type) - return; - - assert(type->node_type == AST_TYPE); - assert(from->node_type == AST_TYPE); - assert(to->node_type == AST_TYPE); - - if (types_match(type, from)) { - assert(type->_type.next == NULL); - struct ast_node *clone = clone_ast_node(to); - *type = *clone; - return; - } - replace_type(type->_type.next, from, to); + return 0; } -void replace_param_types(struct ast_node *param, struct ast_node *param_type, - struct ast_node *arg_type) +static int actualize_list(struct act_state *state, struct scope *scope, + struct ast *l) { - if (arg_type->_type.kind == AST_TYPE_TRAIT) { - replace_param_types(param, param_type, arg_type); - return; + foreach_node(n, l) { + if (actualize(state, scope, n)) + return -1; } - while (param) { - replace_type(param->type, param_type, arg_type); - param = param->next; - } + return 0; } |
