diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/actualize.c | 520 | ||||
| -rw-r--r-- | src/ast.c | 541 | ||||
| -rw-r--r-- | src/debug.c | 81 | ||||
| -rw-r--r-- | src/parser.y | 12 | ||||
| -rw-r--r-- | src/scope.c | 995 |
5 files changed, 534 insertions, 1615 deletions
diff --git a/src/actualize.c b/src/actualize.c index 7a9e13d..932fc7a 100644 --- a/src/actualize.c +++ b/src/actualize.c @@ -56,10 +56,10 @@ static enum act_flags act_flags(struct act_state *state, enum act_flags flags) static int is_void(struct ast_node *type) { assert(type->node_type == AST_TYPE); - if (type->_type.kind != AST_TYPE_ID) + if (AST_TYPE(type).kind != AST_TYPE_PRIMITIVE) return 0; - struct ast_node *id = type->_type.id; + struct ast_node *id = AST_PRIMITIVE_TYPE(type).id; if (strcmp(id->_id.id, "void") != 0) return 0; @@ -81,41 +81,45 @@ static struct ast_node *void_type() return NULL; } - struct ast_node *void_type = gen_type(AST_TYPE_ID, void_id, NULL, NULL); + struct ast_node *void_type = gen_type(AST_TYPE_PRIMITIVE, void_id, NULL, NULL); if (!void_type) { internal_error("couldn't allocate void type"); destroy_ast_node(void_id); return NULL; } + ast_set_flags(void_type, AST_FLAG_ACTUAL); + void_type->type = void_type; return void_type; } -static struct ast_node *i64_type() +static struct ast_node *i27_type() { - char *i64_str = strdup("i64"); - if (!i64_str) { - internal_error("couldn't allocate i64 string"); + char *i27_str = strdup("i27"); + if (!i27_str) { + internal_error("couldn't allocate i27 string"); return NULL; } - struct ast_node *i64_id = gen_id(i64_str, NULL_LOC()); - if (!i64_id) { - internal_error("couldn't allocate i64 id"); - free(i64_str); + struct ast_node *i27_id = gen_id(i27_str, NULL_LOC()); + if (!i27_id) { + internal_error("couldn't allocate i27 id"); + free(i27_str); return NULL; } - struct ast_node *i64_type = gen_type(AST_TYPE_ID, i64_id, NULL, NULL); - if (!i64_type) { - internal_error("couldn't allocate i64 type"); - destroy_ast_node(i64_id); + struct ast_node *i27_type = gen_type(AST_TYPE_PRIMITIVE, i27_id, NULL, NULL); + if (!i27_type) { + internal_error("couldn't allocate i27 type"); + destroy_ast_node(i27_id); return NULL; } - i64_type->type = i64_type; - return i64_type; + ast_set_flags(i27_type, AST_FLAG_ACTUAL); + + i27_type->type = i27_type; + return i27_type; } static int push_defer(struct act_state *state, struct ast_node *expr) @@ -320,9 +324,9 @@ static int analyze_file_visibility(struct scope *scope, struct ast_node *node) } case AST_IMPORT: { - const char *file = node->_import.file; - ret |= process_file(&scope, ast_flags(node, - AST_FLAG_PUBLIC), file); + const char *file = AST_IMPORT(node).file; + ret |= process_file(&scope, + ast_flags(node, AST_FLAG_PUBLIC), file); destroy_ast_tree(node); break; } @@ -340,22 +344,27 @@ static int analyze_file_visibility(struct scope *scope, struct ast_node *node) } case AST_STRUCT: { - ret |= scope_add_type(scope, node); + /* 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; } case AST_ENUM: { - ret |= scope_add_type(scope, node); + struct ast_node *id = AST_ENUM(node).id; + ret |= scope_add_type(scope, id, node); break; } case AST_ALIAS: { - ret |= scope_add_alias(scope, node); + struct ast_node *id = AST_ALIAS(node).id; + ret |= scope_add_type(scope, id, node); break; } case AST_TRAIT: { - ret |= scope_add_trait(scope, node); + struct ast_node *id = AST_TRAIT(node).id; + ret |= scope_add_type(scope, id, node); break; } @@ -378,7 +387,7 @@ static int analyze_file_visibility(struct scope *scope, struct ast_node *node) /* a block might be inserted by something, in which case jump * down into it */ assert(ast_flags(node, AST_FLAG_UNHYGIENIC)); - ret = analyze(scope, node->_block.body); + ret = analyze(scope, AST_BLOCK(node).body); break; } @@ -415,104 +424,19 @@ int analyze_root(struct scope *scope, struct ast_node *tree) return 0; } -int trait_match(struct ast_node *a, struct ast_node *b) -{ - while (a && a->_type.kind == AST_TYPE_TRAIT) - a = a->_type.trait.actual; - - while (b && b->_type.kind == AST_TYPE_TRAIT) - b = b->_type.trait.actual; - - return types_match(a, b); -} - -static int alias_match(struct ast_node *a, struct ast_node *b) -{ - while (a && a->_type.kind == AST_TYPE_ALIAS) - a = a->_type.alias.actual; - - while (b && b->_type.kind == AST_TYPE_ALIAS) - b = b->_type.alias.actual; - - return types_match(a, b); -} - -static int pointer_match(struct ast_node *a, struct ast_node *b) +static int structs_match(struct ast_node *a, struct ast_node *b) { - if (a->_type.kind != AST_TYPE_POINTER) - return 0; - - if (b->_type.kind != AST_TYPE_POINTER) - return 0; - - return types_match(a->_type.next, b->_type.next); -} - -static int typeof_match(struct ast_node *a, struct ast_node *b) -{ - while (a && a->_type.kind == AST_TYPE_TYPEOF) - a = a->_type.typeo.actual; - - while (b && b->_type.kind == AST_TYPE_TYPEOF) - b = b->_type.typeo.actual; - - return types_match(a, b); -} - -static int struct_match(struct ast_node *a, struct ast_node *b) -{ - if (!identical_ast_nodes(0, a->_type.struc.id, b->_type.struc.id)) - return 0; - - /* note a slight asymmetry, in that types on the right will match if - * they don't have impls, but structs on the left will not. */ - if (!b->_type.struc.impls) - return 1; - - if (!a->_type.struc.impls) - return 0; - - struct ast_node *a_impls = a->_type.struc.impls; - struct ast_node *b_impls = b->_type.struc.impls; - while (a_impls && b_impls) { - if (!types_match(a_impls, b_impls)) - return 0; - - b_impls = b_impls->next; - a_impls = a_impls->next; - } - - if (a_impls || b_impls) - return 0; - - return 1; + /** @todo: iterate over elements in structure */ + /** @todo: check tag as well? */ + return 0; } -static int union_match(struct ast_node *a, struct ast_node *b) +static int primitives_match(struct ast_node *a, struct ast_node *b) { - assert(a->_type.kind == AST_TYPE_UNION); - assert(b->_type.kind == AST_TYPE_UNION); - - if (!identical_ast_nodes(0, a->_type.unio.id, b->_type.unio.id)) - return 0; - - if (!a->_type.unio.impls || !b->_type.unio.impls) - return 1; - - struct ast_node *a_impls = a->_type.unio.impls; - struct ast_node *b_impls = b->_type.unio.impls; - while (a_impls && b_impls) { - a_impls = a_impls->next; - if (!types_match(a_impls, b_impls)) - return 0; + struct ast_node *a_id = AST_PRIMITIVE_TYPE(a).id; + struct ast_node *b_id = AST_PRIMITIVE_TYPE(b).id; - b_impls = b_impls->next; - } - - if (a_impls || b_impls) - return 0; - - return 1; + return strcmp(AST_ID(a_id).id, AST_ID(b_id).id) == 0; } int types_match(struct ast_node *a, struct ast_node *b) @@ -526,64 +450,25 @@ int types_match(struct ast_node *a, struct ast_node *b) assert(a->node_type == AST_TYPE); assert(b->node_type == AST_TYPE); - if (a->_type.kind == AST_TYPE_TYPEOF || - b->_type.kind == AST_TYPE_TYPEOF) { - if (typeof_match(a, b)) - return 1; - return 0; - } - - /* handle special cases that should match even with different type kinds */ - if (a->_type.kind == AST_TYPE_TRAIT || - b->_type.kind == AST_TYPE_TRAIT) { - /* TODO: check trait type name */ - if (trait_match(a, b)) - return 1; - return 0; - } - - if (a->_type.kind == AST_TYPE_ALIAS || - b->_type.kind == AST_TYPE_ALIAS) { - if (alias_match(a, b)) - return 1; - return 0; - } - - /* aliases etc. resolved, not if the kinds are different we must not - * match */ - if (a->_type.kind != b->_type.kind) - return 0; - - if (a->_type.kind == AST_TYPE_POINTER || - b->_type.kind == AST_TYPE_POINTER) { - if (pointer_match(a, b)) - return 1; + /* typeofs match 'everything' */ + if (AST_TYPE(a).kind == AST_TYPE_TYPEOF || AST_TYPE(b).kind == AST_TYPE_TYPEOF) + return 1; + /* if the type kind doesn't match, we're done. */ + if (AST_TYPE(a).kind != AST_TYPE(b).kind) return 0; - } - if (a->_type.kind == AST_TYPE_STRUCT || - b->_type.kind == AST_TYPE_STRUCT) { - if (struct_match(a, b)) - return 1; + if (AST_TYPE(a).kind == AST_TYPE_STRUCT) + return structs_match(a, b); - return 0; - } + if (AST_TYPE(a).kind == AST_TYPE_POINTER) + return types_match(AST_PTR_TYPE(a).base, + AST_PTR_TYPE(b).base); - if (a->_type.kind == AST_TYPE_UNION || - b->_type.kind == AST_TYPE_UNION) { - if (union_match(a, b)) - return 1; + if (AST_TYPE(a).kind == AST_TYPE_PRIMITIVE) + return primitives_match(a, b); - return 0; - } - - /* from here on, we know that both types are identical */ - if (!identical_ast_nodes(0, a, b)) - return 0; - - /* TODO: maybe implement some kind of recursion flag? */ - return 1; // types_match(a->_type.next, b->_type.next); + return 0; } static int _replace_id(struct ast_node *node, void *data) @@ -662,31 +547,8 @@ struct ast_node *extract_trait(struct ast_node *type) static void actualize_trait_types(struct ast_node *params, struct ast_node *args) { - /* replace parameter types with argument types */ - if (args) - do { - assert(params->type); - struct ast_node *trait = extract_trait( - params->type); - if (trait) { - /* at this point we know that the types will - * match, otherwise match_proc and friends - * fucked up */ - struct ast_node *type = params->type; - struct ast_node *base = args->type; - while (type != trait) { - type = type->_type.next; - base = base->_type.next; - assert(type); - assert(base); - } - - trait->_type.trait.actual = base; - } - params = params->next; - args = args->next; - } while (args && params); - + /** @todo replace trait types with arg types, should probably be merged + * */ /* TODO: this might not hold in variadic functions... */ assert(!args && !params); } @@ -701,16 +563,10 @@ static int actualize_proc_call(struct act_state *state, struct ast_node *sign = proc->type; assert(sign->node_type == AST_TYPE); - call->type = sign->_type.sign.ret; + call->type = AST_SIGN_TYPE(sign).ret; return 0; } - if (ast_flags(proc, AST_FLAG_VARIADIC)) { - semantic_error(scope->fctx, proc, - "variadic procs not yet implemented"); - return -1; - } - if (act_flags(state, ACT_ONLY_TYPES)) { /* TODO: better cleanup */ /* at this point we're really only interested in the return @@ -722,11 +578,6 @@ static int actualize_proc_call(struct act_state *state, return -1; } - if (scope_add_scratch(scope, sign)) { - internal_error("failed adding signature to scratch"); - return -1; - } - struct scope *tmp = create_scope(); if (!tmp) { internal_error( @@ -738,7 +589,7 @@ static int actualize_proc_call(struct act_state *state, * example, we want to use that file's scope */ scope_add_scope(proc->scope, tmp); - struct ast_node *params = sign->_type.sign.params; + struct ast_node *params = AST_SIGN_TYPE(sign).params; struct ast_node *args = call->_call.args; /* fuck, analyze_proc gobbles up the return type typeof */ actualize_trait_types(params, args); @@ -746,7 +597,7 @@ static int actualize_proc_call(struct act_state *state, if (actualize(state, tmp, sign)) return -1; - call->type = sign->_type.sign.ret; + call->type = AST_SIGN_TYPE(sign).ret; return 0; } @@ -760,14 +611,14 @@ static int actualize_proc_call(struct act_state *state, } struct ast_node *sign = def->_proc.sign; - struct ast_node *params = sign->_type.sign.params; + struct ast_node *params = AST_SIGN_TYPE(sign).params; struct ast_node *args = call->_call.args; actualize_trait_types(params, args); if (actualize(state, def->scope, def)) return -1; - call->type = sign->_type.sign.ret; + call->type = AST_SIGN_TYPE(sign).ret; return 0; } @@ -775,24 +626,24 @@ static int actualize_macro_call(struct act_state *state, struct scope *scope, struct ast_node *call, struct ast_node *macro) { - assert(call->node_type == AST_CALL && macro->node_type == AST_MACRO_EXPAND); + assert(call->node_type == AST_CALL && macro->node_type == AST_MACRO_CONSTRUCT); 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(macro->_macro.body); + struct ast_node *body = clone_ast_node(AST_MACRO_CONSTRUCT(macro).body); if (!body) { - internal_error("failed allocating body for macro call"); + internal_error("failed allocating body for macro expansion"); return -1; } body->scope = call->scope; body->next = call->next; - struct ast_node *param = macro->_macro.params; - struct ast_node *arg = call->_call.args; + struct ast_node *param = AST_MACRO_CONSTRUCT(macro).params; + struct ast_node *arg = AST_CALL(call).args; /* TODO: actual replacements */ while (param && arg) { @@ -957,7 +808,7 @@ static int actualize_proc(struct act_state *state, /* actualize body */ ret |= actualize(&new_state, sign->scope, actual->_proc.body); if (!act_flags(&new_state, ACT_HAS_RETURN)) { - if (!is_void(sign->_type.sign.ret)) { + if (!is_void(AST_SIGN_TYPE(sign).ret)) { semantic_error(scope->fctx, actual, "no return with non-void return type"); ret = -1; @@ -1013,8 +864,6 @@ static int actualize_binop(struct act_state *state, return -1; } - /* TODO: slightly unsure how I'll handle aliases, maybe the types should - * be actualized to the aliased values as well? */ if (!types_match(left->type, right->type)) { char *left_type = type_str(left); char *right_type = type_str(right); @@ -1083,7 +932,9 @@ static int actualize_id(struct act_state *state, { UNUSED(state); assert(id && id->node_type == AST_ID); - struct ast_node *decl = file_scope_find(scope, id); + /** @todo at the moment we always assume an ID is a variable, but stuff + * like function callbacks should be added in the future */ + struct ast_node *decl = file_scope_find_var(scope, id); if (!decl) { semantic_error(scope->fctx, id, "no such object"); return -1; @@ -1188,69 +1039,50 @@ static int actualize_type(struct act_state *state, EXIT_ACT(-1); } - switch (type->_type.kind) { + 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 */ - struct ast_node *id = type->_type.id; - if (!id) + if (!AST_ID_TYPE(type).id) { /* no ID means void */ - type->_type.id = gen_id(strdup("void"), NULL_LOC()); - - type->loc = id->loc; + AST_ID_TYPE(type).id = gen_id(strdup("void"), NULL_LOC()); + } - struct ast_node *exists = file_scope_resolve_type(scope, type); + 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); } - /* nothing to do, except maybe check that types are actually - * identical? */ - if (exists->node_type == AST_TYPE) + if (exists->node_type == AST_TYPE) { + assert(AST_TYPE(exists).kind == AST_TYPE_PRIMITIVE); + AST_TYPE(type) = AST_TYPE(exists); break; + } - assert(exists->node_type == AST_ALIAS - || exists->node_type == AST_TRAIT - || exists->node_type == AST_STRUCT - || exists->node_type == AST_ENUM); /* actualize whatever type we have on demand, either alias or * trait */ if (!ast_flags(exists, AST_FLAG_ACTUAL)) if (actualize(state, exists->scope, exists)) EXIT_ACT(-1); - assert(type->_type.next == NULL); - destroy_ast_node(type->_type.id); + assert(AST_TYPE(type).next == NULL); + destroy_ast_node(AST_ID_TYPE(type).id); if (exists->node_type == AST_ALIAS) { - /* TODO: check if this is good enough */ - type->_type.kind = AST_TYPE_ALIAS; - type->_type.alias.alias = exists; - type->_type.alias.actual = exists->_alias.type; + AST_TYPE(type).aliased = exists; + AST_TYPE(type) = AST_TYPE(exists); } else if (exists->node_type == AST_TRAIT) { - type->_type.kind = AST_TYPE_TRAIT; - type->_type.trait.trait = exists; - /* this should be populated later */ - type->_type.trait.actual = NULL; + /* this is kind of weird, have to think about it */ + AST_TYPE(type) = AST_TYPE(exists); } else if (exists->node_type == AST_STRUCT) { - /* I think, will still have to TODO: check */ - type->_type.kind = AST_TYPE_STRUCT; - type->_type.struc.id = - clone_ast_node(exists->_struct.id); - /* should be populated later */ - type->_type.struc.impls = NULL; + AST_TYPE(type) = AST_TYPE(exists); } else if (exists->node_type == AST_ENUM) { - type->_type.kind = AST_TYPE_ENUM; - type->_type.enu.id = clone_ast_node(exists->_enum.id); - type->_type.enu.type = exists->_enum.type; + AST_TYPE(type) = AST_TYPE(exists); } - if (ast_flags(exists, AST_FLAG_GENERIC)) - ast_set_flags(type, AST_FLAG_GENERIC); - break; } @@ -1259,7 +1091,7 @@ static int actualize_type(struct act_state *state, break; case AST_TYPE_TYPEOF: { - struct ast_node *expr = type->_type.typeo.expr; + struct ast_node *expr = AST_TYPEOF_TYPE(type).expr; /* TODO: expressions in top-level type declarations should * probably be checked for, as we might not want to accidentally * actualize procedure calls? */ @@ -1270,7 +1102,8 @@ static int actualize_type(struct act_state *state, * anything dumb like that, but I would feel better if I figure * out some check */ assert(type->_type.next == NULL); - type->_type.typeo.actual = expr->type; + /** @todo add in some 'from' field for this situation? */ + type->type = expr->type; break; } @@ -1280,14 +1113,14 @@ static int actualize_type(struct act_state *state, break; case AST_TYPE_SIGN: { - struct ast_node *params = type->_type.sign.params; - struct ast_node *ret = type->_type.sign.ret; + struct ast_node *params = AST_SIGN_TYPE(type).params; + struct ast_node *ret = AST_SIGN_TYPE(type).ret; if (actualize(state, scope, params)) EXIT_ACT(-1); if (!ret) - ret = type->_type.sign.ret = void_type(); + ret = AST_SIGN_TYPE(type).ret = void_type(); if (actualize(state, scope, ret)) EXIT_ACT(-1); @@ -1300,6 +1133,11 @@ static int actualize_type(struct act_state *state, break; } + case AST_TYPE_PRIMITIVE: { + assert(ast_flags(type, AST_FLAG_ACTUAL)); + break; + } + default: semantic_error(scope->fctx, type, "unimplemented type"); EXIT_ACT(-1); @@ -1324,26 +1162,22 @@ static int actualize_empty(struct act_state *state, node->type = gen_type(AST_TYPE_ID, void_id, NULL, NULL); if (!node->type) { - scope_add_scratch(scope, void_id); internal_error("couldn't allocate type for empty statement\n"); return -1; } - scope_add_scratch(scope, node->type); return 0; } static int integral_type(struct ast_node *type) { assert(type->node_type == AST_TYPE); - if (type->_type.kind == AST_TYPE_ALIAS) - return integral_type(type->_type.alias.actual); - - if (type->_type.kind != AST_TYPE_ID) + if (AST_TYPE(type).kind != AST_TYPE_PRIMITIVE) return 0; /* here would be awesome with an enum of our base types */ - const char *type_str = type->_type.id->_id.id; + struct ast_node *primitive = AST_PRIMITIVE_TYPE(type).id; + const char *type_str = AST_ID(primitive).id; if (strcmp(type_str, "u8")) return 1; @@ -1397,7 +1231,8 @@ static int pointer_conversion(struct ast_node *a, struct ast_node *b) if (b->_type.kind != AST_TYPE_ID) return 0; - struct ast_node *id = b->_type.id; + struct ast_node *id = AST_ID_TYPE(b).id; + /* there's gotta be a better way */ if (strcmp(id->_id.id, "usize") == 0) return 1; } @@ -1545,53 +1380,21 @@ static int init_struct(struct act_state *state, struct scope *scope, return ret; } -struct ast_node *actual_type(struct ast_node *type) -{ - assert(type->node_type == AST_TYPE); - if (type->_type.kind == AST_TYPE_ALIAS) { - if (type->_type.alias.actual) - return actual_type(type->_type.alias.actual); - - return type; - } - - if (type->_type.kind == AST_TYPE_TRAIT) { - if (type->_type.trait.actual) - return actual_type(type->_type.trait.actual); - - return type; - } - - if (type->_type.kind == AST_TYPE_TYPEOF) { - if (type->_type.typeo.actual) - return actual_type(type->_type.typeo.actual); - - return type; - } - - return type; -} - static int actualize_struct_init_cast(struct act_state *state, struct scope *scope, struct ast_node *init, struct ast_node *actual) { - struct ast_node *id = actual->_type.struc.id; - struct ast_node *exists = file_scope_resolve_type(scope, id); - assert(exists); - assert(ast_flags(exists, AST_FLAG_ACTUAL)); - - return init_struct(state, scope, exists, init); + struct ast_node *def = AST_STRUCT_TYPE(actual).def; + 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 ast_node *actual = actual_type(type); - if (actual->_type.kind == AST_TYPE_STRUCT) - return actualize_struct_init_cast(state, scope, init, actual); + if (AST_TYPE(type).kind == AST_TYPE_STRUCT) + return actualize_struct_init_cast(state, scope, init, type); semantic_error(scope->fctx, type, "type is not a struct"); @@ -1694,9 +1497,7 @@ static int actualize_const(struct act_state *state, struct scope *scope, assert(cons->node_type == AST_CONST); if (cons->_const.kind == AST_CONST_INTEGER) { /* error checking would be doog */ - cons->type = gen_type(AST_TYPE_ID, gen_id(strdup("i64"), NULL_LOC()), - NULL, NULL); - scope_add_scratch(scope, cons->type); + cons->type = i27_type(); return 0; } @@ -1711,9 +1512,13 @@ static int actualize_alias(struct act_state *state, struct scope *scope, * aliases might be a bit cumbersome to work with. Still, this works * well enough I suppose. */ assert(alias->node_type == AST_ALIAS); + if (ast_flags(alias, AST_FLAG_INIT)) { + semantic_error(scope->fctx, alias, "alias loop"); + return -1; + } + ast_set_flags(alias, AST_FLAG_INIT); - /* TODO: alias loops? */ - if (actualize(state, scope, alias->_alias.type)) { + if (actualize(state, scope, AST_ALIAS(alias).type)) { /* 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 */ @@ -1721,16 +1526,7 @@ static int actualize_alias(struct act_state *state, struct scope *scope, return -1; } - /* TODO: is this hacky? */ - if (!scope_flags(scope, SCOPE_FILE)) { - if (scope_add_alias(scope, alias)) - return -1; - } - ast_set_flags(alias, AST_FLAG_ACTUAL); - alias->type = gen_type(AST_TYPE_ALIAS, NULL, - alias->_alias.id, alias->_alias.type); - scope_add_scratch(scope, alias->type); return 0; } @@ -1777,7 +1573,6 @@ static int actualize_defer(struct act_state *state, return -1; node->type = void_type(); - scope_add_scratch(scope, node->type); return 0; } @@ -1794,13 +1589,12 @@ static int actualize_return(struct act_state *state, struct scope *scope, } else { node->type = void_type(); - if (scope_add_scratch(scope, node->type)) - return -1; } assert(state->cur_proc); struct ast_node *cur_proc = state->cur_proc; - struct ast_node *ret = cur_proc->_proc.sign->_type.sign.ret; + 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); @@ -1882,7 +1676,6 @@ static int actualize_goto(struct act_state *state, struct scope *scope, /* clone all defers as we don't know where the label might be */ node->_goto.defers = clone_defers(state, NULL); node->type = void_type(); - scope_add_scratch(scope, node->type); struct ast_node *label = find_label(state, node->_goto.label); /* this is a jump backwards, i.e. we can already do it */ @@ -1922,7 +1715,6 @@ static int actualize_label(struct act_state *state, struct scope *scope, /* clone all defers */ node->_label.defers = clone_defers(state, NULL); node->type = void_type(); - scope_add_scratch(scope, node->type); actualize_goto_defers(state, node); return 0; @@ -2011,7 +1803,6 @@ static int actualize_struct(struct act_state *state, /* cloning slightly odd, but I guess it's fine? */ struct ast_node *clone_id = clone_ast_node(node->_struct.id); node->type = gen_type(AST_TYPE_STRUCT, clone_id, NULL, NULL); - scope_add_scratch(scope, node->type); ast_set_flags(node, AST_FLAG_ACTUAL); return 0; @@ -2022,17 +1813,14 @@ static int actualize_struct(struct act_state *state, * structures or traits. */ static int has_members(struct ast_node *type) { - if (type->_type.kind == AST_TYPE_ALIAS) - return has_members(type->_type.alias.actual); - - if (type->_type.kind == AST_TYPE_POINTER) - type = type->_type.next; + if (AST_TYPE(type).kind == AST_TYPE_POINTER) + type = AST_TYPE(type).next; /* most likely */ - if (type->_type.kind == AST_TYPE_STRUCT) + if (AST_TYPE(type).kind == AST_TYPE_STRUCT) return 1; - if (type->_type.kind == AST_TYPE_TRAIT) + if (AST_TYPE(type).kind == AST_TYPE_TRAIT) return 1; return 0; @@ -2127,10 +1915,10 @@ static int actualize_fetch(struct act_state *state, struct scope *scope, } struct ast_node *id = fetch->_fetch.id; - struct ast_node *enu = file_scope_resolve_type(scope, type->_type.id); - assert(enu); + struct ast_node *def = file_scope_find_type(scope, AST_ID_TYPE(type).id); + assert(def); - struct ast_node *member = lookup_enum_member(enu, id); + struct ast_node *member = lookup_enum_member(def, id); if (!member) { char *estr = type_str(type); semantic_error(scope->fctx, id, "no such member in enum %s"); @@ -2138,7 +1926,7 @@ static int actualize_fetch(struct act_state *state, struct scope *scope, return -1; } - fetch->type = enu->type; + fetch->type = def->type; return 0; } @@ -2152,7 +1940,7 @@ static int actualize_enum(struct act_state *state, struct scope *scope, /* TODO: here we could save space by choosing the smallest type that * fits */ if (!type) { - type = i64_type(); + type = i27_type(); node->_enum.type = type; } else if (actualize(state, enum_scope, type)) return -1; @@ -2250,16 +2038,13 @@ static int actualize(struct act_state *state, struct scope *scope, int actualize_main(struct scope *root) { - /* should maybe try and figure out a shorthand for this */ - /* especially if I try to find procs by signature as well */ - struct ast_node main_id = {0}; - main_id.node_type = AST_ID; - main_id._id.id = "main"; + struct ast_node *main_id = gen_id(strdup("main"), NULL_LOC()); + struct ast_node *main_call = gen_call(main_id, NULL); struct act_state state = {0}; /* skip checking signature for now */ - struct ast_node *main = file_scope_find_proc(root, &main_id); + struct ast_node *main = file_scope_resolve_call(root, main_call); if (!main) { /* libraries are not really compilable... */ error("no main"); @@ -2287,27 +2072,19 @@ void replace_type(struct ast_node *type, struct ast_node *from, /* TODO: unsure if this is everything */ switch (type->_type.kind) { case AST_TYPE_ID: - destroy_ast_node(type->_type.id); + destroy_ast_node(AST_ID_TYPE(type).id); break; case AST_TYPE_STRUCT: - destroy_ast_node(type->_type.struc.id); + destroy_ast_node(AST_STRUCT_TYPE(type).def); break; case AST_TYPE_ENUM: - destroy_ast_node(type->_type.enu.id); - break; - - case AST_TYPE_UNION: - destroy_ast_node(type->_type.unio.id); - break; - - case AST_TYPE_PROC: - destroy_ast_node(type->_type.proc.id); + destroy_ast_node(AST_ENUM_TYPE(type).def); break; case AST_TYPE_TYPEOF: - destroy_ast_node(type->_type.typeo.expr); + destroy_ast_node(AST_TYPEOF_TYPE(type).expr); break; default: @@ -2334,37 +2111,6 @@ void replace_param_types(struct ast_node *param, struct ast_node *param_type, } } -void init_trait_type(struct ast_node *type, struct ast_node *param_type, - struct ast_node *arg_type) -{ - if (!types_match(type, param_type)) - return; - - struct ast_node *trait = extract_trait(type); - if (trait) { - /* TODO: this shares a fair bit of similarities with - * actualize_trait_types, could probably create a common - * backend? */ - while (type != trait) { - type = param_type->_type.next; - arg_type = arg_type->_type.next; - assert(type); - assert(arg_type); - } - - trait->_type.trait.actual = arg_type; - } -} - -void init_trait_types(struct ast_node *params, struct ast_node *param_type, - struct ast_node *arg_type) -{ - while (params) { - init_trait_type(params->type, param_type, arg_type); - params = params->next; - } -} - int actualize_temp_type(struct scope *scope, struct ast_node *type) { struct act_state state; @@ -17,6 +17,8 @@ #include <ek/ast.h> #include <ek/scope.h> +/** @todo alloc should maybe also keep track of all nodes in a vector or + * something and mass free all AST at a time to keep my sanity */ #define ALLOC_NODE(n, type) \ struct ast_node *n = calloc(1, sizeof(struct ast_node)); \ if (!n) { \ @@ -38,8 +40,8 @@ struct ast_node *gen_arr_access(struct ast_node *base, struct ast_node *idx, str { ALLOC_NODE(n, "arr_access"); n->node_type = AST_ARR_ACCESS; - n->arr_access.base = base; - n->arr_access.idx = idx; + AST_ARR_ACCESS(n).base = base; + AST_ARR_ACCESS(n).idx = idx; n->loc = loc; return n; } @@ -47,8 +49,8 @@ struct ast_node *gen_arr_access(struct ast_node *base, struct ast_node *idx, str void destroy_arr_access(struct ast_node *arr_access) { assert(arr_access->node_type == AST_ARR_ACCESS); - destroy_ast_node(AST_GET(arr_access, base)); - destroy_ast_node(AST_GET(arr_access, idx)); + destroy_ast_node(AST_ARR_ACCESS(arr_access).base); + destroy_ast_node(AST_ARR_ACCESS(arr_access).idx); free(arr_access); } @@ -77,18 +79,18 @@ struct ast_node *gen_type_construct(struct ast_node *id, { ALLOC_NODE(n, "type_construct"); n->node_type = AST_TYPE_CONSTRUCT; - n->type_construct.id = id; - n->type_construct.params = params; - n->type_construct.body = body; + AST_TYPE_CONSTRUCT(n).id = id; + AST_TYPE_CONSTRUCT(n).params = params; + AST_TYPE_CONSTRUCT(n).body = body; n->loc = loc; return n; } void destroy_type_construct(struct ast_node *type_construct) { - destroy_ast_node(AST_GET(type_construct, id)); - destroy_ast_node(AST_GET(type_construct, params)); - destroy_ast_node(AST_GET(type_construct, body)); + destroy_ast_node(AST_TYPE_CONSTRUCT(type_construct).id); + destroy_ast_node(AST_TYPE_CONSTRUCT(type_construct).params); + destroy_ast_node(AST_TYPE_CONSTRUCT(type_construct).body); free(type_construct); } @@ -98,8 +100,8 @@ struct ast_node *gen_type_expand(struct ast_node *id, { ALLOC_NODE(n, "type_expand"); n->node_type = AST_TYPE_EXPAND; - n->type_expand.id = id; - n->type_expand.args = args; + AST_TYPE_EXPAND(n).id = id; + AST_TYPE_EXPAND(n).args = args; n->loc = loc; return n; } @@ -107,8 +109,8 @@ struct ast_node *gen_type_expand(struct ast_node *id, void destroy_type_expand(struct ast_node *n) { assert(n->node_type == AST_TYPE_EXPAND); - destroy_ast_node(n->type_expand.args); - free((void *)n->type_expand.id); + destroy_ast_node(AST_TYPE_EXPAND(n).id); + destroy_ast_node(AST_TYPE_EXPAND(n).args); free(n); } @@ -399,9 +401,9 @@ struct ast_node *gen_macro_construct(struct ast_node *id, { ALLOC_NODE(n, "macro_construct"); n->node_type = AST_MACRO_CONSTRUCT; - n->_macro.id = id; - n->_macro.params = params; - n->_macro.body = body; + AST_MACRO_CONSTRUCT(n).id = id; + AST_MACRO_CONSTRUCT(n).params = params; + AST_MACRO_CONSTRUCT(n).body = body; n->loc = id->loc; return n; } @@ -409,9 +411,9 @@ struct ast_node *gen_macro_construct(struct ast_node *id, void destroy_macro_construct(struct ast_node *macro) { assert(macro->node_type == AST_MACRO_CONSTRUCT); - destroy_ast_node(macro->_macro.id); - DESTROY_LIST(macro->_macro.params); - DESTROY_LIST(macro->_macro.body); + destroy_ast_node(AST_MACRO_CONSTRUCT(macro).id); + DESTROY_LIST(AST_MACRO_CONSTRUCT(macro).params); + DESTROY_LIST(AST_MACRO_CONSTRUCT(macro).body); free(macro); } @@ -475,77 +477,51 @@ void destroy_case(struct ast_node *cas) free(cas); } -struct ast_node *gen_type(enum ast_type_kind kind, struct ast_node *id, - struct ast_node *expr, struct ast_node *ret) +struct ast_node *gen_type(enum ast_type_kind kind, + struct ast_node *t0, + struct ast_node *t1, + struct ast_node *t2) { ALLOC_NODE(n, "type"); n->node_type = AST_TYPE; - n->_type.kind = kind; + AST_TYPE(n).kind = kind; switch (kind) { - case AST_TYPE_GENERIC: - n->_type.generic.id = id; - n->_type.generic.args = expr; - n->loc = id->loc; - break; - - case AST_TYPE_MEMBER: - n->_type.member.id = id; - n->_type.member.expr = expr; - n->loc = id->loc; - break; - - case AST_TYPE_ALIAS: - n->_type.alias.alias = expr; - n->_type.alias.actual = ret; - n->loc = expr->loc; - break; + case AST_TYPE_PRIMITIVE: + AST_PRIMITIVE_TYPE(n).id = t0; + break; case AST_TYPE_TRAIT: - n->_type.trait.trait = expr; - n->_type.trait.actual = ret; - n->loc = expr->loc; + AST_TRAIT_TYPE(n).def = t0; break; case AST_TYPE_ID: - n->_type.id = id; - n->loc = id->loc; + AST_ID_TYPE(n).id = t0; break; case AST_TYPE_ARR: - n->_type.arr.size = expr; - if (expr) - n->loc = expr->loc; + AST_ARR_TYPE(n).size = t0; + AST_ARR_TYPE(n).base = t1; break; case AST_TYPE_TYPEOF: - n->_type.typeo.expr = expr; - n->loc = expr->loc; + AST_TYPEOF_TYPE(n).expr = t0; break; case AST_TYPE_POINTER: + AST_PTR_TYPE(n).base = t0; break; - case AST_TYPE_PROC: - n->_type.proc.params = expr; - n->_type.proc.ret = ret; - break; - - case AST_TYPE_UNION: case AST_TYPE_STRUCT: - n->_type.struc.id = id; - n->_type.struc.impls = expr; - n->loc = id->loc; + AST_STRUCT_TYPE(n).def = t0; break; case AST_TYPE_ENUM: - n->_type.enu.id = id; - n->_type.struc.impls = expr; - n->loc = id->loc; + AST_ENUM_TYPE(n).def = t0; break; case AST_TYPE_SIGN: - n->_type.sign.params = expr; - n->_type.sign.ret = ret; + AST_SIGN_TYPE(n).params = t0; + AST_SIGN_TYPE(n).ret = t1; break; } @@ -556,60 +532,45 @@ void destroy_type(struct ast_node *type) { assert(type->node_type == AST_TYPE); switch (type->_type.kind) { - case AST_TYPE_GENERIC: - destroy_ast_node(type->_type.generic.id); - DESTROY_LIST(type->_type.generic.args); - break; - - case AST_TYPE_MEMBER: - destroy_ast_node(type->_type.member.id); - destroy_ast_node(type->_type.member.expr); - break; - - case AST_TYPE_ALIAS: + case AST_TYPE_PRIMITIVE: + destroy_ast_node(AST_PRIMITIVE_TYPE(type).id); break; case AST_TYPE_TRAIT: break; case AST_TYPE_ID: - destroy_ast_node(type->_type.id); + destroy_ast_node(AST_ID_TYPE(type).id); break; case AST_TYPE_ARR: - destroy_ast_node(type->_type.arr.size); + destroy_ast_node(AST_ARR_TYPE(type).size); + destroy_ast_node(AST_ARR_TYPE(type).base); break; case AST_TYPE_TYPEOF: - destroy_ast_node(type->_type.typeo.expr); + destroy_ast_node(AST_TYPEOF_TYPE(type).expr); break; case AST_TYPE_POINTER: + destroy_ast_node(AST_PTR_TYPE(type).base); break; - case AST_TYPE_PROC: - DESTROY_LIST(type->_type.proc.params); - destroy_ast_node(type->_type.proc.ret); - break; - - case AST_TYPE_UNION: case AST_TYPE_STRUCT: - destroy_ast_node(type->_type.struc.id); - DESTROY_LIST(type->_type.struc.impls); + destroy_ast_node(AST_STRUCT_TYPE(type).def); break; case AST_TYPE_ENUM: - destroy_ast_node(type->_type.enu.id); - destroy_ast_node(type->_type.enu.type); + destroy_ast_node(AST_ENUM_TYPE(type).def); break; case AST_TYPE_SIGN: - DESTROY_LIST(type->_type.sign.params); - destroy_ast_node(type->_type.sign.ret); + DESTROY_LIST(AST_SIGN_TYPE(type).params); + destroy_ast_node(AST_SIGN_TYPE(type).ret); break; } - destroy_ast_node(type->_type.next); + destroy_ast_node(AST_TYPE(type).next); free(type); } @@ -1186,9 +1147,9 @@ static void __dump_ast(int depth, struct ast_node *node) dump_flags(node); putchar('\n'); - dump_ast(depth + 1, node->_macro.id); - dump_ast(depth + 1, node->_macro.params); - dump_ast(depth + 1, node->_macro.body); + dump_ast(depth + 1, AST_MACRO_CONSTRUCT(node).id); + dump_ast(depth + 1, AST_MACRO_CONSTRUCT(node).params); + dump_ast(depth + 1, AST_MACRO_CONSTRUCT(node).body); dump(depth, "}\n"); break; @@ -1270,80 +1231,58 @@ static void __dump_ast(int depth, struct ast_node *node) dump_flags(node); switch (node->_type.kind) { - case AST_TYPE_GENERIC: - printf(" GENERIC\n"); - dump_ast(depth + 1, node->_type.generic.id); - dump_ast(depth + 1, node->_type.generic.args); - break; - - case AST_TYPE_MEMBER: - printf(" MEMBER\n"); - dump_ast(depth + 1, node->_type.member.id); - dump_ast(depth + 1, node->_type.member.expr); - break; - - case AST_TYPE_ALIAS: - printf(" ALIAS\n"); - dump_ast(depth + 1, node->_type.alias.alias->_alias.id); - dump_ast(depth + 1, node->_type.alias.actual); + case AST_TYPE_PRIMITIVE: + printf(" PRIMITIVE\n"); + dump_ast(depth + 1, AST_PRIMITIVE_TYPE(node).id); break; case AST_TYPE_TRAIT: printf(" TRAIT\n"); - dump_ast(depth + 1, - node->_type.trait.trait->_trait.id); - dump_ast(depth + 1, node->_type.trait.actual); + /* might be a bit overkill? */ + dump_ast(depth + 1, AST_TRAIT_TYPE(node).def); break; case AST_TYPE_ID: printf(" ID\n"); - dump_ast(depth + 1, node->_type.id); + dump_ast(depth + 1, AST_ID_TYPE(node).id); break; case AST_TYPE_ARR: printf(" ARR\n"); - dump_ast(depth + 1, node->_type.arr.size); + dump_ast(depth + 1, AST_ARR_TYPE(node).size); + dump_ast(depth + 1, AST_ARR_TYPE(node).base); break; case AST_TYPE_POINTER: printf(" PTR\n"); + dump_ast(depth + 1, AST_PTR_TYPE(node).base); break; case AST_TYPE_TYPEOF: printf(" TYPEOF\n"); - dump_ast(depth + 1, node->_type.typeo.expr); - dump_ast(depth + 1, node->_type.typeo.actual); - break; - - case AST_TYPE_PROC: - printf(" PROC\n"); - dump_ast(depth + 1, node->_type.proc.params); - dump_ast(depth + 1, node->_type.proc.ret); + dump_ast(depth + 1, AST_TYPEOF_TYPE(node).expr); break; - /* not really but y'know */ - case AST_TYPE_UNION: case AST_TYPE_STRUCT: printf(" STRUCT\n"); /* oh yeah, struc is at least right now just an ID that * we can use to fetch the actual struct with. */ - dump_ast(depth + 1, node->_type.struc.id); - dump_ast(depth + 1, node->_type.struc.impls); + dump_ast(depth + 1, AST_STRUCT_TYPE(node).def); break; case AST_TYPE_ENUM: printf(" ENUM\n"); - dump_ast(depth + 1, node->_type.enu.id); - dump_ast(depth + 1, node->_type.enu.type); + dump_ast(depth + 1, AST_ENUM_TYPE(node).def); break; - case AST_TYPE_SIGN: printf(" SIGN\n"); - dump_ast(depth + 1, node->_type.sign.params); - dump_ast(depth + 1, node->_type.sign.ret); + case AST_TYPE_SIGN: + printf(" SIGN\n"); + dump_ast(depth + 1, AST_SIGN_TYPE(node).params); + dump_ast(depth + 1, AST_SIGN_TYPE(node).ret); break; } - dump_ast(depth + 1, node->_type.next); + dump_ast(depth + 1, AST_TYPE(node).next); dump(depth, "}\n"); break; @@ -1473,11 +1412,10 @@ static void __dump_ast(int depth, struct ast_node *node) dump(depth, "{CONST:"); dump_flags(node); switch (node->_const.kind) { - case AST_CONST_INTEGER: printf("%lli", node->_const.integer); + case AST_CONST_INTEGER: printf(" %lli", AST_CONST(node).integer); break; - case AST_CONST_STRING: printf("\"%s\"", node->_const.str); + case AST_CONST_STRING: printf(" \"%s\"", AST_CONST(node).str); break; - case AST_CONST_FLOAT: printf("%lf", node->_const.dbl); break; } printf("}\n"); break; @@ -1531,21 +1469,24 @@ struct ast_node *clone_ast_node(struct ast_node *node) struct ast_node *new = NULL; switch (node->node_type) { case AST_ARR_ACCESS: - new = gen_arr_access(clone_ast_node(node->arr_access.base), - clone_ast_node(node->arr_access.idx), + new = gen_arr_access( + clone_ast_node(AST_ARR_ACCESS(node).base), + clone_ast_node(AST_ARR_ACCESS(node).idx), node->loc); break; case AST_TYPE_CONSTRUCT: - new = gen_type_construct(clone_ast_node(node->type_construct.id), - clone_ast_node(node->type_construct.params), - clone_ast_node(node->type_construct.body), + new = gen_type_construct( + clone_ast_node(AST_TYPE_CONSTRUCT(node).id), + clone_ast_node(AST_TYPE_CONSTRUCT(node).params), + clone_ast_node(AST_TYPE_CONSTRUCT(node).body), node->loc); break; case AST_TYPE_EXPAND: - new = gen_type_expand(clone_ast_node(node->type_expand.id), - clone_ast_node(node->type_expand.args), + new = gen_type_expand( + clone_ast_node(AST_TYPE_EXPAND(node).id), + clone_ast_node(AST_TYPE_EXPAND(node).args), node->loc); break; @@ -1596,13 +1537,14 @@ struct ast_node *clone_ast_node(struct ast_node *node) break; case AST_MACRO_CONSTRUCT: new = gen_macro_construct( - clone_ast_node(node->_macro.id), - clone_ast_node(node->_macro.params), - clone_ast_node(node->_macro.body)); - break; + clone_ast_node(AST_MACRO_CONSTRUCT(node).id), + clone_ast_node(AST_MACRO_CONSTRUCT(node).params), + clone_ast_node(AST_MACRO_CONSTRUCT(node).body)); + break; - case AST_MACRO_EXPAND: new = gen_macro_expand(clone_ast_node(node->_macro_expand.id), - clone_ast_node(node->_macro_expand.args)); + case AST_MACRO_EXPAND: new = gen_macro_expand( + clone_ast_node(AST_MACRO_EXPAND(node).id), + clone_ast_node(AST_MACRO_EXPAND(node).args)); break; case AST_CAST: new = gen_cast(clone_ast_node(node->_cast.expr), @@ -1652,82 +1594,63 @@ struct ast_node *clone_ast_node(struct ast_node *node) /* oh, if a node has a ->type it probably isn't cloned * correctly... */ switch (node->_type.kind) { - case AST_TYPE_GENERIC: - new = gen_type(AST_TYPE_GENERIC, - clone_ast_node(node->_type.generic.id), - clone_ast_node(node->_type.generic.args), - NULL); - break; - - case AST_TYPE_MEMBER: - new = gen_type(AST_TYPE_MEMBER, - clone_ast_node(node->_type.member.id), - clone_ast_node(node->_type.member.expr), - NULL); - break; - - case AST_TYPE_ALIAS: - new = gen_type(AST_TYPE_ALIAS, NULL, - /* should make it more obvious what is a - * reference and what isn't */ - node->_type.alias.alias, - node->_type.alias.actual); + case AST_TYPE_PRIMITIVE: + new = gen_type(AST_TYPE_PRIMITIVE, + clone_ast_node(AST_PRIMITIVE_TYPE(node).id), + NULL, + NULL); break; case AST_TYPE_TRAIT: - new = gen_type(AST_TYPE_TRAIT, NULL, - node->_type.trait.trait, - /* ditto, should actual be cloned? */ - node->_type.trait.actual); + new = gen_type(AST_TYPE_TRAIT, + AST_TRAIT_TYPE(node).def, + NULL, + NULL); break; case AST_TYPE_ID: new = gen_type(AST_TYPE_ID, - clone_ast_node(node->_type.id), - NULL, NULL); + clone_ast_node(AST_ID_TYPE(node).id), + NULL, + NULL); break; case AST_TYPE_ARR: - new = gen_type(AST_TYPE_ARR, NULL, - clone_ast_node(node->_type.arr.size), - NULL); + new = gen_type(AST_TYPE_ARR, + clone_ast_node(AST_ARR_TYPE(node).size), + clone_ast_node(AST_ARR_TYPE(node).base), + NULL); break; case AST_TYPE_TYPEOF: - new = gen_type(AST_TYPE_TYPEOF, NULL, - clone_ast_node(node->_type.typeo.expr), + new = gen_type(AST_TYPE_TYPEOF, + clone_ast_node(AST_TYPEOF_TYPE(node).expr), + NULL, NULL); break; case AST_TYPE_POINTER: - new = gen_type(AST_TYPE_POINTER, NULL, NULL, NULL); + new = gen_type(AST_TYPE_POINTER, AST_PTR_TYPE(node).base, NULL, NULL); break; - case AST_TYPE_UNION: case AST_TYPE_STRUCT: new = gen_type(AST_TYPE_STRUCT, - clone_ast_node(node->_type.struc.id), - clone_ast_node(node->_type.struc.impls), + clone_ast_node(AST_STRUCT_TYPE(node).def), + NULL, NULL); break; case AST_TYPE_ENUM: new = gen_type(AST_TYPE_ENUM, - clone_ast_node(node->_type.enu.id), - clone_ast_node(node->_type.enu.type), + clone_ast_node(AST_ENUM_TYPE(node).def), + NULL, NULL); break; - case AST_TYPE_PROC: - new = gen_type(AST_TYPE_PROC, NULL, - clone_ast_node(node->_type.proc.params), - clone_ast_node(node->_type.proc.ret)); - break; - case AST_TYPE_SIGN: new = gen_type(AST_TYPE_SIGN, NULL, - clone_ast_node(node->_type.sign.params), - clone_ast_node(node->_type.sign.ret)); + clone_ast_node(AST_SIGN_TYPE(node).params), + clone_ast_node(AST_SIGN_TYPE(node).ret)); break; } @@ -1953,16 +1876,13 @@ static int identical_defer(int exact, struct ast_node *a, struct ast_node *b) static int identical_macro_construct(int exact, struct ast_node *a, struct ast_node *b) { - if (!identical_ast_nodes(exact, a->_macro.id, b->_macro.id)) - return 0; - - if (!identical_ast_nodes(exact, a->_macro.params, b->_macro.params)) + if (!identical_ast_nodes(exact, AST_MACRO_CONSTRUCT(a).id, AST_MACRO_CONSTRUCT(b).id)) return 0; - if (!identical_ast_nodes(exact, a->_macro.body, b->_macro.body)) + if (!identical_ast_nodes(exact, AST_MACRO_CONSTRUCT(a).params, AST_MACRO_CONSTRUCT(b).params)) return 0; - return 1; + return identical_ast_nodes(exact, AST_MACRO_CONSTRUCT(a).body, AST_MACRO_CONSTRUCT(b).body); } static int identical_macro_expand(int exact, struct ast_node *a, struct ast_node *b) @@ -2043,127 +1963,56 @@ static int identical_return(int exact, struct ast_node *a, struct ast_node *b) return identical_ast_nodes(exact, a->_return.expr, b->_return.expr); } -static int identical_type_alias(int exact, struct ast_node *a, - struct ast_node *b) +static int identical_type_id(int exact, struct ast_node *a, struct ast_node *b) { - if (!identical_ast_nodes(exact, a->_type.alias.alias, - b->_type.alias.alias)) - return 0; - - if (!identical_ast_nodes(exact, a->_type.alias.actual, - b->_type.alias.actual)) - return 0; - return 1; + return identical_ast_nodes(exact, AST_ID_TYPE(a).id, AST_ID_TYPE(b).id); } -static int identical_type_trait(int exact, struct ast_node *a, - struct ast_node *b) +static int identical_type_arr(int exact, struct ast_node *a, struct ast_node *b) { - if (!identical_ast_nodes(exact, a->_type.trait.trait, - b->_type.trait.trait)) - return 0; - - if (!identical_ast_nodes(exact, a->_type.trait.actual, - b->_type.trait.actual)) + if (!identical_ast_nodes(exact, AST_ARR_TYPE(a).size, AST_ARR_TYPE(b).size)) return 0; - return 1; + return identical_ast_nodes(exact, AST_ARR_TYPE(a).base, AST_ARR_TYPE(b).base); } -static int identical_type_id(int exact, struct ast_node *a, struct ast_node *b) +static int identical_type_trait(int exact, struct ast_node *a, struct ast_node *b) { - return identical_ast_nodes(exact, a->_type.id, b->_type.id); + return identical_ast_nodes(exact, AST_TRAIT_TYPE(a).def, AST_TRAIT_TYPE(b).def); } -static int identical_type_arr(int exact, struct ast_node *a, struct ast_node *b) +static int identical_type_primitive(int exact, struct ast_node *a, struct ast_node *b) { - return identical_ast_nodes(exact, a->_type.arr.size, b->_type.arr.size); + return identical_ast_nodes(exact, AST_PRIMITIVE_TYPE(a).id, AST_PRIMITIVE_TYPE(b).id); } static int identical_type_typeof(int exact, struct ast_node *a, struct ast_node *b) { - return identical_ast_nodes(exact, a->_type.typeo.expr, - b->_type.typeo.expr); -} - -static int identical_type_proc(int exact, struct ast_node *a, - struct ast_node *b) -{ - if (!identical_ast_nodes(exact, a->_type.proc.params, - b->_type.proc.params)) - return 0; - - if (!identical_ast_nodes(exact, a->_type.proc.ret, b->_type.proc.ret)) - return 0; - - return 1; + return identical_ast_nodes(exact, AST_TYPEOF_TYPE(a).expr, + AST_TYPEOF_TYPE(b).expr); } static int identical_type_sign(int exact, struct ast_node *a, struct ast_node *b) { - if (!identical_ast_nodes(exact, a->_type.sign.params, - b->_type.sign.params)) - return 0; - - if (!identical_ast_nodes(exact, a->_type.sign.ret, b->_type.sign.ret)) + if (!identical_ast_nodes(exact, AST_SIGN_TYPE(a).params, + AST_SIGN_TYPE(b).params)) return 0; - return 1; + return identical_ast_nodes(exact, AST_SIGN_TYPE(a).ret, AST_SIGN_TYPE(b).ret); } static int identical_type_struct(int exact, struct ast_node *a, struct ast_node *b) { - if (!identical_ast_nodes(exact, a->_type.struc.id, b->_type.struc.id)) - return 0; - - if (!identical_ast_nodes(1, a->_type.struc.impls, - b->_type.struc.impls)) - return 0; - - return 1; + return identical_ast_nodes(exact, AST_STRUCT_TYPE(a).def, AST_STRUCT_TYPE(b).def); } static int identical_type_enum(int exact, struct ast_node *a, struct ast_node *b) { - if (!identical_ast_nodes(exact, a->_type.enu.id, b->_type.enu.id)) - return 0; - - if (!identical_ast_nodes(exact, a->_type.enu.type, b->_type.enu.type)) - return 0; - - return 1; -} - -static int identical_type_member(int exact, struct ast_node *a, - struct ast_node *b) -{ - if (!identical_ast_nodes(exact, a->_type.member.id, b->_type.member.id)) - return 0; - - if (!identical_ast_nodes(exact, a->_type.member.expr, - b->_type.member.expr)) - return 0; - - return 1; -} - -static int identical_type_generic(int exact, struct ast_node *a, - struct ast_node *b) -{ - if (!identical_ast_nodes(exact, a->_type.generic.id, - b->_type.generic.id)) - return 0; - - /* array should always be checked, so do an exact match */ - if (!identical_ast_nodes(1, a->_type.generic.args, - b->_type.generic.args)) - return 0; - - return 1; + return identical_ast_nodes(exact, AST_ENUM_TYPE(a).def, AST_ENUM_TYPE(b).def); } static int identical_type(int exact, struct ast_node *a, struct ast_node *b) @@ -2173,18 +2022,13 @@ static int identical_type(int exact, struct ast_node *a, struct ast_node *b) int ret = 0; switch (a->_type.kind) { - case AST_TYPE_GENERIC: ret = identical_type_generic(exact, a, b); break; - case AST_TYPE_MEMBER: ret = identical_type_member(exact, a, b); break; + case AST_TYPE_PRIMITIVE: ret = identical_type_primitive(exact, a, b); break; case AST_TYPE_ENUM: ret = identical_type_enum(exact, a, b); break; - case AST_TYPE_ALIAS: ret = identical_type_alias(exact, a, b); break; - case AST_TYPE_TRAIT: ret = identical_type_trait(exact, a, b); - break; + case AST_TYPE_TRAIT: ret = identical_type_trait(exact, a, b); break; case AST_TYPE_ID: ret = identical_type_id(exact, a, b); break; case AST_TYPE_ARR: ret = identical_type_arr(exact, a, b); break; case AST_TYPE_TYPEOF: ret = identical_type_typeof(exact, a, b); break; - case AST_TYPE_PROC: ret = identical_type_proc(exact, a, b); break; case AST_TYPE_SIGN: ret = identical_type_sign(exact, a, b); break; - case AST_TYPE_UNION: case AST_TYPE_STRUCT: ret = identical_type_struct(exact, a, b); break; case AST_TYPE_POINTER: break; } @@ -2361,35 +2205,29 @@ static int identical_fetch(int exact, struct ast_node *a, struct ast_node *b) static int identical_type_expand(int exact, struct ast_node *a, struct ast_node *b) { - if (!identical_ast_nodes(exact, a->type_expand.id, b->type_expand.id)) - return 0; - - if (!identical_ast_nodes(exact, a->type_expand.args, b->type_expand.args)) + if (!identical_ast_nodes(exact, AST_TYPE_EXPAND(a).id, AST_TYPE_EXPAND(b).id)) return 0; - return 1; + return identical_ast_nodes(exact, AST_TYPE_EXPAND(a).args, AST_TYPE_EXPAND(b).args); } static int identical_type_construct(int exact, struct ast_node *a, struct ast_node *b) { - if (!identical_ast_nodes(exact, a->type_construct.id, b->type_construct.id)) + if (!identical_ast_nodes(exact, AST_TYPE_CONSTRUCT(a).id, AST_TYPE_CONSTRUCT(b).id)) return 0; - if (!identical_ast_nodes(exact, a->type_construct.params, b->type_construct.params)) + if (!identical_ast_nodes(exact, AST_TYPE_CONSTRUCT(a).params, AST_TYPE_CONSTRUCT(b).params)) return 0; - if (!identical_ast_nodes(exact, a->type_construct.body, b->type_construct.body)) - return 0; - - return 1; + return identical_ast_nodes(exact, AST_TYPE_CONSTRUCT(a).body, AST_TYPE_CONSTRUCT(b).body); } static int identical_arr_access(int exact, struct ast_node *a, struct ast_node *b) { - if (!identical_ast_nodes(exact, a->arr_access.base, b->arr_access.base)) + if (!identical_ast_nodes(exact, AST_ARR_ACCESS(a).base, AST_ARR_ACCESS(b).base)) return 0; - if (!identical_ast_nodes(exact, a->arr_access.idx, b->arr_access.idx)) + if (!identical_ast_nodes(exact, AST_ARR_ACCESS(a).idx, AST_ARR_ACCESS(b).idx)) return 0; return 1; @@ -2648,58 +2486,37 @@ static int call_on_case(int (*call)(struct ast_node *, return ret; } -static int call_on_type_alias(int (*call)(struct ast_node *, - void *), struct ast_node *node, void *data) -{ - int ret = 0; - ret |= call(node->_type.alias.alias, data); - ret |= call(node->_type.alias.actual, data); - return ret; -} - static int call_on_type_trait(int (*call)(struct ast_node *, void *), struct ast_node *node, void *data) { int ret = 0; - ret |= call(node->_type.trait.trait, data); - ret |= call(node->_type.trait.actual, data); + ret |= call(AST_TRAIT_TYPE(node).def, data); return ret; } static int call_on_type_id(int (*call)(struct ast_node *, void *), struct ast_node *node, void *data) { - return call(node->_type.id, data); + return call(AST_ID_TYPE(node).id, data); } static int call_on_type_arr(int (*call)(struct ast_node *, void *), struct ast_node *node, void *data) { - return call(node->_type.arr.size, data); + return call(AST_ARR_TYPE(node).size, data); } static int call_on_type_typeof(int (*call)(struct ast_node *, void *), struct ast_node *node, void *data) { - return call(node->_type.typeo.expr, data); + return call(AST_TYPEOF_TYPE(node).expr, data); } static int call_on_type_struct(int (*call)(struct ast_node *, void *), struct ast_node *node, void *data) { int ret = 0; - ret |= call(node->_type.struc.id, data); - ret |= call(node->_type.struc.impls, data); - return ret; -} - -static int call_on_type_proc(int (*call)(struct ast_node *, - void *), struct ast_node *node, void *data) -{ - int ret = 0; - ret |= call(node->_type.proc.id, data); - ret |= call(node->_type.proc.params, data); - ret |= call(node->_type.proc.ret, data); + ret |= call(AST_STRUCT_TYPE(node).def, data); return ret; } @@ -2707,8 +2524,8 @@ static int call_on_type_sign(int (*call)(struct ast_node *, void *), struct ast_node *node, void *data) { int ret = 0; - ret |= call(node->_type.sign.params, data); - ret |= call(node->_type.sign.ret, data); + ret |= call(AST_SIGN_TYPE(node).params, data); + ret |= call(AST_SIGN_TYPE(node).ret, data); return ret; } @@ -2716,26 +2533,15 @@ static int call_on_type_enum(int (*call)(struct ast_node *, void *), struct ast_node *node, void *data) { int ret = 0; - ret |= call(node->_type.enu.id, data); - ret |= call(node->_type.enu.type, data); + ret |= call(AST_ENUM_TYPE(node).def, data); return ret; } -static int call_on_type_member(int (*call)(struct ast_node *, - void *), struct ast_node *node, void *data) +static int call_on_type_primitive(int (*call)(struct ast_node *, void *), + struct ast_node *node, void *data) { int ret = 0; - ret |= call(node->_type.member.id, data); - ret |= call(node->_type.member.expr, data); - return ret; -} - -static int call_on_type_generic(int (*call)(struct ast_node *, - void *), struct ast_node *node, void *data) -{ - int ret = 0; - ret |= call(node->_type.generic.id, data); - ret |= call(node->_type.generic.args, data); + ret |= call(AST_PRIMITIVE_TYPE(node).id, data); return ret; } @@ -2744,23 +2550,13 @@ static int call_on_type(int (*call)(struct ast_node *, { int ret = 0; switch (node->_type.kind) { - case AST_TYPE_GENERIC: ret = call_on_type_generic(call, node, data); - break; - case AST_TYPE_MEMBER: ret = call_on_type_member(call, node, data); - break; + case AST_TYPE_PRIMITIVE: ret = call_on_type_primitive(call, node, data); break; case AST_TYPE_ENUM: ret = call_on_type_enum(call, node, data); break; - case AST_TYPE_ALIAS: ret = call_on_type_alias(call, node, data); break; - case AST_TYPE_TRAIT: ret = call_on_type_trait(call, node, data); - break; + case AST_TYPE_TRAIT: ret = call_on_type_trait(call, node, data); break; case AST_TYPE_ID: ret = call_on_type_id(call, node, data); break; case AST_TYPE_ARR: ret = call_on_type_arr(call, node, data); break; - case AST_TYPE_TYPEOF: ret = call_on_type_typeof(call, node, data); - break; - case AST_TYPE_UNION: - case AST_TYPE_STRUCT: ret = call_on_type_struct(call, node, data); - break; - case AST_TYPE_PROC: ret = call_on_type_proc(call, node, data); break; - break; + case AST_TYPE_TYPEOF: ret = call_on_type_typeof(call, node, data); break; + case AST_TYPE_STRUCT: ret = call_on_type_struct(call, node, data); break; case AST_TYPE_SIGN: ret = call_on_type_sign(call, node, data); break; case AST_TYPE_POINTER: break; } @@ -2808,9 +2604,9 @@ static int call_on_macro_construct(int (*call)(struct ast_node *, void *), struct ast_node *node, void *data) { int ret = 0; - ret |= call(node->_macro.id, data); - ret |= call(node->_macro.params, data); - ret |= call(node->_macro.body, data); + ret |= call(AST_MACRO_CONSTRUCT(node).id, data); + ret |= call(AST_MACRO_CONSTRUCT(node).params, data); + ret |= call(AST_MACRO_CONSTRUCT(node).body, data); return ret; } @@ -2850,17 +2646,18 @@ static int call_on_macro_expand(int (*call)(struct ast_node *, void *), struct a static int call_on_type_construct(int (*call)(struct ast_node *, void *), struct ast_node *type_construct, void *data) { int ret = 0; - ret |= call(AST_GET(type_construct, id), data); - ret |= call(AST_GET(type_construct, params), data); - ret |= call(AST_GET(type_construct, body), data); + /* pretty verbose, hmm */ + ret |= call(AST_TYPE_CONSTRUCT(type_construct).id, data); + ret |= call(AST_TYPE_CONSTRUCT(type_construct).params, data); + ret |= call(AST_TYPE_CONSTRUCT(type_construct).body, data); return ret; } static int call_on_type_expand(int (*call)(struct ast_node *, void *), struct ast_node *type_expand, void *data) { int ret = 0; - ret |= call(AST_GET(type_expand, id), data); - ret |= call(AST_GET(type_expand, args), data); + ret |= call(AST_TYPE_EXPAND(type_expand).id, data); + ret |= call(AST_TYPE_EXPAND(type_expand).args, data); return ret; } diff --git a/src/debug.c b/src/debug.c index 2b993bf..f145234 100644 --- a/src/debug.c +++ b/src/debug.c @@ -198,84 +198,41 @@ static void _type_str(FILE *fp, struct ast_node *type) break; case AST_TYPE_ID: { - struct ast_node *id = type->_type.id; - fprintf(fp, "%s", id->_id.id); + struct ast_node *id = AST_ID_TYPE(type).id; + fprintf(fp, "%s", AST_ID(id).id); break; } case AST_TYPE_TRAIT: { - struct ast_node *trait = type->_type.trait.trait; - assert(trait); - - struct ast_node *trait_id = trait->_trait.id; - struct ast_node *trait_act = type->_type.trait.actual; - if (trait_act) { - fprintf(fp, "%s as ", trait_id->_id.id); - _type_str(fp, trait_act); - } - else { - fprintf(fp, "%s", trait_id->_id.id); - } - break; - } - - case AST_TYPE_ALIAS: { - struct ast_node *alias = type->_type.alias.alias; - assert(alias); - - struct ast_node *alias_id = alias->_alias.id; - struct ast_node *alias_act = type->_type.alias.actual; - if (alias_act) { - /* deeply nested aliases look pretty funny here */ - fprintf(fp, "%s aka ", alias_id->_id.id); - _type_str(fp, alias_act); - } - else { - fprintf(fp, "%s", alias_id->_id.id); + struct ast_node *def = AST_TRAIT_TYPE(type).def; + if (AST_TRAIT(def).id) { + struct ast_node *name = AST_TRAIT(def).id; + fprintf(fp, "%s ", AST_ID(name).id); } + fprintf(fp, "(trait)"); break; } case AST_TYPE_STRUCT: { - struct ast_node *struc_id = type->_type.struc.id; - fprintf(fp, "%s", struc_id->_id.id); - - struct ast_node *impls = type->_type.struc.impls; - if (impls) { - fprintf(fp, "("); - while (impls) { - _type_str(fp, impls); - impls = impls->next; - if (impls) - fprintf(fp, ", "); - } - fprintf(fp, ")"); + struct ast_node *def = AST_STRUCT_TYPE(type).def; + if (AST_STRUCT(def).id) { + struct ast_node *name = AST_STRUCT(def).id; + fprintf(fp, "%s ", AST_ID(name).id); } + fprintf(fp, "(struct)"); + /** @todo print out anonymous structs with members? */ break; } - case AST_TYPE_UNION: { - struct ast_node *unio_id = type->_type.unio.id; - fprintf(fp, "%s", unio_id->_id.id); - - struct ast_node *impls = type->_type.unio.impls; - if (impls) { - fprintf(fp, "("); - while (impls) { - _type_str(fp, impls); - impls = impls->next; - if (impls) - fprintf(fp, ", "); - } - fprintf(fp, ")"); - } + case AST_TYPE_TYPEOF: { + fprintf(fp, "(typeof)"); break; } - case AST_TYPE_TYPEOF: { - _type_str(fp, type->_type.typeo.actual); - fprintf(fp, " (typeof)"); - break; + case AST_TYPE_PRIMITIVE: { + struct ast_node *id = AST_PRIMITIVE_TYPE(type).id; + fprintf(fp, "%s", AST_ID(id).id); + break; } default: diff --git a/src/parser.y b/src/parser.y index 236a106..6975041 100644 --- a/src/parser.y +++ b/src/parser.y @@ -570,23 +570,17 @@ type | "^" func_sign { /* still not entirely sold on this signature, but it's not terrible I * guess */ - $$ = gen_type(AST_TYPE_POINTER, NULL, NULL, NULL); - $$->_type.next = $2; + $$ = gen_type(AST_TYPE_POINTER, $2, NULL, NULL); } | "*" type { - $$ = gen_type(AST_TYPE_POINTER, NULL, NULL, NULL); - $$->_type.next = $2; + $$ = gen_type(AST_TYPE_POINTER, $2, NULL, NULL); } | "[" const_expr "]" type { - $$ = gen_type(AST_TYPE_ARR, NULL, $2, NULL); - $$->_type.next = $4; + $$ = gen_type(AST_TYPE_ARR, $2, $4, NULL); } | "typeof" expr { $$ = gen_type(AST_TYPE_TYPEOF, NULL, $2, NULL); } - | id "::" type { - $$ = gen_type(AST_TYPE_MEMBER, $1, $3, NULL); - } | "const" type { $$ = $2; } diff --git a/src/scope.c b/src/scope.c index d6481c3..2b8ef12 100644 --- a/src/scope.c +++ b/src/scope.c @@ -24,88 +24,53 @@ static struct ast_node *match_proc(struct scope *scope, static struct ast_node *match_macro(struct scope *scope, struct ast_node *id, struct ast_node *args); -static int generics_trait_type(struct ast_node *generics) +static struct param_node *find_matching_param(struct resolve_node *node, + struct ast_node *type) { - if (!generics) - return 0; + struct param_node *param = node->params; + while (param) { + if (types_match(type, param->type)) + return param; - if (actual_type(generics)->_type.kind == AST_TYPE_TRAIT) - return 1; + param = param->next; + } - return generics_trait_type(generics->_type.next); + return NULL; } -static int generic_type(struct ast_node *type) +static int traits_resolve(struct ast_node *arg_type, struct ast_node *param_type) { - if (!type) - return 0; - - if (type->_type.kind == AST_TYPE_STRUCT) - return generics_trait_type(type->_type.struc.impls); - - if (type->_type.kind == AST_TYPE_TRAIT) - return type->_type.trait.actual == NULL; - - return generic_type(type->_type.next); + /** @todo are more checks required? */ + return AST_TYPE(arg_type).as == AST_TRAIT_TYPE(param_type).def; } -static int referential_type(struct ast_node *type) +static int typeofs_resolve(struct ast_node *arg_type, struct ast_node *param_type) { - if (!type) - return 0; - - if (type->_type.kind == AST_TYPE_TYPEOF) - return 1; - - if (type->_type.kind == AST_TYPE_MEMBER) - return 1; - - return referential_type(type->_type.next); -} - -int primitive_type(struct ast_node *type) -{ - if (!type) - return 1; - - if (referential_type(type)) - return 0; - - if (generic_type(type)) - return 0; - - return 1; + internal_error("typeof resolve unimplemented"); + return 0; } -int fully_qualified(struct ast_node *type) +static int types_resolve(struct ast_node *arg_type, struct ast_node *param_type) { - if (!type) + /* untyped resolves all */ + if (!param_type) return 1; - assert(type->_type.kind != AST_TYPE_TRAIT); - if (type->_type.kind == AST_TYPE_STRUCT) { - if (!ast_flags(type, AST_FLAG_GENERIC)) - return 1; - - if (type->_type.struc.impls) - return fully_qualified(type->_type.struc.impls); + if (AST_TYPE(param_type).kind == AST_TYPE_TRAIT) + return traits_resolve(arg_type, param_type); - return 0; - } + if (AST_TYPE(param_type).kind == AST_TYPE_TYPEOF) + return typeofs_resolve(arg_type, param_type); - return fully_qualified(type->_type.next); + return types_match(arg_type, param_type); } -static struct param_node *find_matching_param(struct resolve_node *node, - struct ast_node *type) +static struct param_node *find_resolving_param(struct resolve_node *node, + struct ast_node *type) { struct param_node *param = node->params; while (param) { - /* untyped matches everything, yay */ - if (!param->type) - return param; - - if (types_match(type, param->type)) + if (types_resolve(type, param->type)) return param; param = param->next; @@ -181,12 +146,9 @@ static int add_next_resolve(struct scope *scope, struct ast_node *resolve, static int add_resolve(struct scope *scope, struct resolve *resolve, struct ast_node *proc) { - struct ast_node *sign = proc->_proc.sign; - struct ast_node *params = sign->_type.sign.params; - - struct scope *resolv_scope = create_scope(); - scope_add_scope(scope, resolv_scope); - return add_next_resolve(resolv_scope, proc, resolve->root, params); + struct ast_node *sign = AST_PROC(proc).sign; + struct ast_node *params = AST_SIGN_TYPE(sign).params; + return add_next_resolve(scope, proc, resolve->root, params); } static struct ast_node *resolve(struct scope *scope, @@ -194,6 +156,7 @@ static struct ast_node *resolve(struct scope *scope, struct ast_node *args) { assert(node); + /* check for no parameters case */ if (!args) { if (node->resolved) return node->resolved; @@ -201,20 +164,18 @@ static struct ast_node *resolve(struct scope *scope, return NULL; } - /* first check if we match a primitive type */ - struct param_node *found = find_matching_param(node, args->type); + struct param_node *found = find_resolving_param(node, args->type); if (found) return resolve(scope, found->resolved, args->next); return NULL; } -/* if I ever try making the parser multithreaded, this should be atomic. */ -static size_t counter = 0; struct scope *create_scope() { - /* TODO: add in a scope counter, might make things easier to see in the - * AST dump */ + /* if I ever try making the parser multithreaded, this should be atomic. */ + static size_t counter = 0; + struct scope *scope = calloc(1, sizeof(struct scope)); if (!scope) { internal_error("ran out of memory allocating scope"); @@ -242,22 +203,7 @@ void destroy_visible(struct scope *scope, struct visible *visible) if (prev) do { cur = prev->next; - /* file scope actually owns all the AST nodes, so don't - * try to destroy them in lower level scopes */ - if (scope_flags(scope, SCOPE_FILE)) - if (prev->owner == scope) - destroy_ast_node(prev->node); - free(prev); - } while ((prev = cur)); -} - -static void destroy_scratch(struct scratch *scratch) -{ - struct scratch *prev = scratch, *cur; - if (prev) - do { - cur = prev->next; - destroy_ast_node(prev->node); + /* destroy AST nodes globally somewhere? */ free(prev); } while ((prev = cur)); } @@ -268,7 +214,6 @@ void destroy_actuals(struct actual *actuals) if (prev) do { cur = prev->next; - destroy_ast_node(prev->node); free(prev); } while ((prev = cur)); } @@ -301,7 +246,6 @@ void destroy_resolve(struct resolve *resolve) do { cur = prev->next; destroy_resolve_node(prev->root); - destroy_ast_node(prev->id); free(prev); } while ((prev = cur)); } @@ -317,19 +261,12 @@ void destroy_scope(struct scope *scope) free((void *)scope->fctx.fname); } - destroy_scratch(scope->scratch); destroy_resolve(scope->proc_resolve); destroy_resolve(scope->macro_resolve); destroy_resolve(scope->type_construct_resolve); destroy_visible(scope, scope->vars); - destroy_visible(scope, scope->procs); - destroy_visible(scope, scope->builtins); - - destroy_visible(scope, scope->enums); - destroy_visible(scope, scope->structs); - destroy_visible(scope, scope->aliases); - destroy_visible(scope, scope->traits); + destroy_visible(scope, scope->types); struct scope *prev = scope->children, *cur; if (prev) @@ -353,247 +290,71 @@ int scope_flags(struct scope *scope, enum scope_flags flags) return scope->flags & flags; } -static struct visible *create_visible(struct scope *owner, +static struct visible *create_visible(struct ast_node *id, struct ast_node *node) { struct visible *visible = calloc(1, sizeof(struct visible)); + visible->id = id; visible->node = node; - visible->owner = owner; return visible; } -static struct scratch *create_scratch(struct ast_node *scratch) +struct visible *create_type(struct scope *scope, struct ast_node *id, struct ast_node *type) { - struct scratch *new = calloc(1, sizeof(struct scratch)); - new->node = scratch; - return new; -} - -/* set newest member as head of linked list */ -#define CREATE_VISIBLE(name, type, ast_type) \ - static struct visible *name(struct scope *owner, struct ast_node *node) \ - { \ - assert(node->node_type == ast_type); \ - struct visible *visible = create_visible(owner, node); \ - visible->next = owner->type; \ - owner->type = visible; \ - return visible; \ - } - -CREATE_VISIBLE(create_var, vars, AST_VAR); -CREATE_VISIBLE(create_proc, procs, AST_PROC); -CREATE_VISIBLE(create_macro, macros, AST_MACRO_CONSTRUCT); -CREATE_VISIBLE(create_type_construct, type_constructs, AST_TYPE_CONSTRUCT); - -CREATE_VISIBLE(create_enum, enums, AST_ENUM); -CREATE_VISIBLE(create_alias, aliases, AST_ALIAS); -CREATE_VISIBLE(create_struct, structs, AST_STRUCT); -CREATE_VISIBLE(create_builtin, builtins, AST_TYPE); -CREATE_VISIBLE(create_trait, traits, AST_TRAIT); - -/* TODO: check for identical names in the scope? */ -#define REFERENCE_VISIBLE(name, list, ast_type) \ - static int name(int public, struct scope *scope, struct visible *obj) \ - { \ - if (!scope) \ - return 0; \ - assert(obj->node->node_type == ast_type); \ - struct visible *ref = create_visible(obj->owner, obj->node); \ - ref->next = scope->list; \ - scope->list = ref; \ - if (scope_flags(scope, SCOPE_FILE) && public) \ - name(scope_flags(scope, SCOPE_PUBLIC), scope->parent, obj); \ - return 0; \ - } - -REFERENCE_VISIBLE(reference_var, vars, AST_VAR); -REFERENCE_VISIBLE(reference_proc, procs, AST_PROC); -REFERENCE_VISIBLE(reference_macro, macros, AST_MACRO_CONSTRUCT); - -REFERENCE_VISIBLE(reference_enum, enums, AST_ENUM); -REFERENCE_VISIBLE(reference_trait, traits, AST_TRAIT); -REFERENCE_VISIBLE(reference_alias, aliases, AST_ALIAS); -REFERENCE_VISIBLE(reference_struct, structs, AST_STRUCT); -REFERENCE_VISIBLE(reference_builtin, builtins, AST_TYPE); -REFERENCE_VISIBLE(reference_type_construct, type_constructs, AST_TYPE_CONSTRUCT); - -/* does NOT walk the scope tree upward if it doesn't find the var in the scope - * */ -#define FIND_VISIBLE(name, list, ast_type, ast_name) \ - struct ast_node *name(struct scope *scope, struct ast_node *id) \ - { \ - assert(id->node_type == AST_ID); \ - struct visible *prev = scope->list, *cur; \ - if (prev) { \ - do { \ - cur = prev->next; \ - if (identical_ast_nodes(0, \ - prev->node->ast_name.id, \ - id)) { \ - return prev->node; \ - } \ - } while ((prev = cur)); \ - } \ - return NULL; \ - } - -FIND_VISIBLE(scope_find_enum, enums, AST_ENUM, _enum); -FIND_VISIBLE(scope_find_alias, aliases, AST_ALIAS, _alias); -FIND_VISIBLE(scope_find_builtin, builtins, AST_TYPE, _type); -FIND_VISIBLE(scope_find_struct, structs, AST_STRUCT, _struct); -FIND_VISIBLE(scope_find_trait, traits, AST_TRAIT, _trait); -/* note that these return the first match for the ID, and as such might not be - * what should be called. */ -FIND_VISIBLE(scope_find_var, vars, AST_VAR, _var); -FIND_VISIBLE(scope_find_proc, procs, AST_PROC, _proc); -FIND_VISIBLE(scope_find_macro, macros, AST_MACRO_CONSTRUCT, _macro); -FIND_VISIBLE(scope_find_type_construct, type_constructs, AST_TYPE_CONSTRUCT, type_construct); - -struct ast_node *scope_find(struct scope *scope, struct ast_node *id) -{ - assert(id->node_type == AST_ID); - - struct ast_node *found = scope_find_var(scope, id); - if (found) - return found; - - found = scope_find_proc(scope, id); - if (found) - return found; - - found = scope_find_macro(scope, id); - if (found) - return found; - - found = scope_find_alias(scope, id); - if (found) - return found; - - found = scope_find_trait(scope, id); - if (found) - return found; + struct visible *n = create_visible(id, type); + if (!n) + return NULL; - return NULL; + n->next = scope->types; + scope->types = n; + return n; } -/* procedure adding requires a bit of tweaking, as a different number of - * arguments effectively means different functions, not just the name */ -#define ADD_VISIBLE(name, obj_type, ast_type, ast_name) \ - int name(struct scope *scope, struct ast_node *node) \ - { \ - assert(node->node_type == ast_type); \ - struct ast_node *shadow = file_scope_find_##obj_type(scope, \ - node->ast_name.id); \ - if (shadow) { \ - semantic_error(scope->fctx, node, \ - "shadowing is not allowed"); \ - semantic_info(scope->fctx, shadow, \ - "previous declaration was here"); \ - return -1; \ - } \ - int public = scope_flags(scope, SCOPE_PUBLIC); \ - struct visible *visible = create_##obj_type(scope, node); \ - if (scope_flags(scope, \ - SCOPE_FILE) && ast_flags(node, AST_FLAG_PUBLIC)) \ - return reference_##obj_type(public, scope->parent, visible); \ - return 0; \ - } - -struct visible *create_type(struct scope *scope, struct ast_node *type) +struct visible *create_var(struct scope *scope, struct ast_node *id, struct ast_node *var) { - switch (type->node_type) { - case AST_TYPE: return create_builtin(scope, type); - case AST_ALIAS: return create_alias(scope, type); - case AST_TRAIT: return create_trait(scope, type); - case AST_ENUM: return create_enum(scope, type); - case AST_STRUCT: return create_struct(scope, type); - default: - semantic_error(scope->fctx, type, "unknown type"); + struct visible *n = create_visible(id, var); + if (!n) return NULL; - } + + n->next = scope->vars; + scope->vars = n; + return n; } -int reference_type(int public, struct scope *scope, struct visible *visible) +int scope_add_var(struct scope *scope, struct ast_node *var) { - switch (visible->node->node_type) { - case AST_TYPE: return reference_builtin(public, scope, visible); - case AST_ALIAS: return reference_alias(public, scope, visible); - case AST_TRAIT: return reference_trait(public, scope, visible); - case AST_ENUM: return reference_enum(public, scope, visible); - case AST_STRUCT: return reference_struct(public, scope, visible); - default: - semantic_error(scope->fctx, visible->node, "unknown type"); - return 1; + struct ast_node *exists = file_scope_find_var(scope, AST_VAR(var).id); + if (exists) { + semantic_error(scope->fctx, var, "var redefined"); + semantic_info(scope->fctx, exists, "previously here"); + return -1; } + + struct visible *visible = create_var(scope, AST_VAR(var).id, var); + if (scope_flags(scope, SCOPE_FILE) && ast_flags(var, AST_FLAG_PUBLIC)) + return scope_add_var(scope->parent, var); + + return 0; } -int scope_add_type(struct scope *scope, struct ast_node *type) +int scope_add_type(struct scope *scope, struct ast_node *id, struct ast_node *type) { - struct ast_node *exists = file_scope_resolve_type(scope, type); - + struct ast_node *exists = file_scope_find_type(scope, id); /* redefining a type to itself is allowed, and might be necessary for * some generics operations. I'll have to double check this later, * though */ - /* e.g. struct (vec{t}) or something, all instances of this 'type' - * detected anywhere should be allowed to be 'added' */ - if (exists) - return 0; + if (exists) { + semantic_error(scope->fctx, type, "type redefined"); + semantic_info(scope->fctx, exists, "previously here"); + return -1; + } - int public = scope_flags(scope, SCOPE_PUBLIC); /* during a redefine, if it's redefined to public should it be * propagated upward? Probably not, but dunno for sure yet */ - struct visible *visible = create_type(scope, type); + struct visible *visible = create_type(scope, id, type); if (scope_flags(scope, SCOPE_FILE) && ast_flags(type, AST_FLAG_PUBLIC)) - return reference_type(public, scope->parent, visible); - - return 0; -} - -struct ast_node *scope_find_type(struct scope *scope, struct ast_node *id) -{ - assert(id->node_type == AST_ID); - - struct ast_node *found = scope_find_builtin(scope, id); - if (found) - return found; - - found = scope_find_enum(scope, id); - if (found) - return found; - - found = scope_find_struct(scope, id); - if (found) - return found; - - found = scope_find_alias(scope, id); - if (found) - return found; - - found = scope_find_trait(scope, id); - if (found) - return found; - - return NULL; -} - -ADD_VISIBLE(scope_add_var, var, AST_VAR, _var); -ADD_VISIBLE(scope_add_alias, alias, AST_ALIAS, _alias); -ADD_VISIBLE(scope_add_trait, trait, AST_TRAIT, _trait); - -static int add_implementation(struct ast_node *trait, struct ast_node *type) -{ - assert( - trait->node_type == AST_TRAIT && - type->node_type == AST_TYPE); - struct trait_implemented *by = calloc(1, sizeof(*type)); - if (!by) { - internal_error("failed allocating memory for implementation"); - return 1; - } + return scope_add_type(scope->parent, id, type); - by->type = type; - by->next = trait->_trait.impl_by; - trait->_trait.impl_by = by; return 0; } @@ -617,81 +378,17 @@ static void remove_implementation(struct ast_node *trait, } while ((prev = cur)); } -static int find_implementation(struct ast_node *trait, struct ast_node *type) -{ - if (!type) - return 0; - - assert(trait->node_type == AST_TRAIT); - if (type->_type.kind == AST_TYPE_TRAIT) - return find_implementation(trait, - type->_type.trait.actual); - - if (type->_type.kind == AST_TYPE_ALIAS) - return find_implementation(trait, type->_type.alias.actual); - - /* I'm not 100% sold on having to handle these special cases multiple - * times in different places, but I'm not sure what alternatives I have. - * For debugging purposes, maintaining as much info about the original - * code is useful, but I wonder if I can somehow maybe clone this stuff - * and keep a reference to the original or something without too much - * work? TODO */ - if (type->_type.kind == AST_TYPE_TYPEOF) - return find_implementation(trait, type->_type.typeo.actual); - - struct trait_implemented *prev = trait->_trait.impl_by, *cur; - if (prev) - do { - cur = prev->next; - if (identical_ast_nodes(0, prev->type, type)) { - return 1; - } - } while ((prev = cur)); - - return 0; -} - static int implements_proc(enum match_flags flags, struct scope *scope, struct ast_node *arg_type, struct ast_node *param_type, struct ast_node *proc) { + (void)(flags); + (void)(scope); + (void)(arg_type); + (void)(param_type); assert(proc->node_type == AST_PROC); - /* temp */ - struct ast_node *id = proc->_proc.id; - /* this removes type info, bit of an issue */ - struct ast_node *sign = clone_ast_node(proc->_proc.sign); - struct ast_node *params = sign->_type.sign.params; - struct ast_node *ret = sign->_type.sign.ret; - - init_trait_types(params, param_type, arg_type); - init_trait_type(ret, param_type, arg_type); - - struct ast_node *impl = match_proc(scope, id, params); - if (!impl) - goto out; - - struct ast_node *impl_ret = impl->_proc.sign->_type.sign.ret; - /* note important distinction between when to use ->type and when to not - * in short: ->type can be a trait or alias, not using it is the type - * before being resolved. - */ - /* TODO: detect loops, such as when two trait return params rely on - * eachother */ - if (!implements(flags, scope, impl_ret, ret)) { - char *irt = type_str(impl_ret); - char *prt = type_str(ret); - semantic_error(scope->fctx, proc, "return type mismatch"); - semantic_info(scope->fctx, impl, - "found return type %s, expected %s", - irt, prt); - free(irt); - free(prt); - impl = NULL; - } - -out: - destroy_ast_node(sign); - return impl != NULL; + /** @todo implement */ + return 0; } static int implements_var(enum match_flags flags, struct scope *scope, @@ -703,7 +400,7 @@ static int implements_var(enum match_flags flags, struct scope *scope, (void)(arg_type); (void)(param_type); assert(var->node_type == AST_VAR); - /* temp */ + /** @todo implement */ return 0; } @@ -711,66 +408,53 @@ static int implements_trait(enum match_flags flags, struct scope *scope, struct ast_node *arg_type, struct ast_node *param_type) { - assert(param_type->_type.kind == AST_TYPE_TRAIT); - if (param_type->_type.trait.actual) - return implements(flags, scope, arg_type, - param_type->_type.trait.actual); - - struct ast_node *trait = param_type->_type.trait.trait; - /* if we already know we implement this trait, nothing to do */ - if (find_implementation(trait, arg_type)) - return 1; - - /* optimistically assume we implement type trait */ - /* TODO: this optimism might be questionable, as some trait might rely - * on another trait being implemented by the same type. - * The other type will return an error message, and the compilation will - * fail, but the error messages generated might be misleading. Look into - * it at some point. */ - add_implementation(trait, arg_type); - - struct ast_node *body = trait->_trait.body; + assert(AST_TYPE(param_type).kind == AST_TYPE_TRAIT); + struct ast_node *trait = AST_TRAIT_TYPE(param_type).def; + struct ast_node *body = AST_TRAIT(trait).body; /* if the body is empty, match */ struct ast_node *elem = body; - if (elem) - do { - if (elem->node_type == AST_VAR) { - if (implements_var(flags, scope, arg_type, - param_type, - elem)) - continue; + if (!elem) + return 1; - char *type = type_str(arg_type); - struct ast_node *id = elem->_proc.id; - semantic_error(scope->fctx, elem, - "%s does not have member %s", - type, id->_id.id); - free(type); - goto not_implemented; - } + /* this is somewhat ugly, hmmm */ + do { + if (elem->node_type == AST_VAR) { + if (implements_var(flags, scope, arg_type, + param_type, + elem)) + continue; - else if (elem->node_type == AST_PROC) { - if (implements_proc(flags, scope, arg_type, - param_type, - elem)) - continue; + char *type = type_str(arg_type); + struct ast_node *id = elem->_proc.id; + semantic_error(scope->fctx, elem, + "%s does not have member %s", + type, id->_id.id); + free(type); + goto not_implemented; + } - char *type = type_str(arg_type); - struct ast_node *id = elem->_proc.id; - semantic_error(scope->fctx, elem, - "%s does not implement %s", - type, id->_id.id); - free(type); - goto not_implemented; - } + else if (elem->node_type == AST_PROC) { + if (implements_proc(flags, scope, arg_type, + param_type, + elem)) + continue; - else { - semantic_error(scope->fctx, elem, - "illegal trait element"); - goto not_implemented; - } - } while ((elem = elem->next)); + char *type = type_str(arg_type); + struct ast_node *id = elem->_proc.id; + semantic_error(scope->fctx, elem, + "%s does not implement %s", + type, id->_id.id); + free(type); + goto not_implemented; + } + + else { + semantic_error(scope->fctx, elem, + "illegal trait element"); + goto not_implemented; + } + } while ((elem = elem->next)); return 1; @@ -779,29 +463,11 @@ not_implemented: return 0; } -static int implements_alias(enum match_flags flags, struct scope *scope, - struct ast_node *arg_type, - struct ast_node *param_type) -{ - while (arg_type && arg_type->_type.kind == AST_TYPE_ALIAS) - arg_type = arg_type->_type.alias.actual; - - while (param_type && param_type->_type.kind == AST_TYPE_ALIAS) - param_type = param_type->_type.alias.actual; - - return implements(flags, scope, arg_type, param_type); -} - static int implements_typeof(enum match_flags flags, struct scope *scope, struct ast_node *arg_type, struct ast_node *param_type) { - while (arg_type && arg_type->_type.kind == AST_TYPE_TYPEOF) - arg_type = arg_type->_type.typeo.actual; - - while (param_type && param_type->_type.kind == AST_TYPE_TYPEOF) - param_type = param_type->_type.typeo.actual; - + internal_error("typeof implementation unimplemented"); return implements(flags, scope, arg_type, param_type); } @@ -814,8 +480,6 @@ int implements(enum match_flags flags, struct scope *scope, if (!arg_type && !param_type) return 0; - /* only the variadic argument in parameters has no type, so any actual - * type implements it */ /* slight hack: macro arguments also don't have a type, so they will * also 'implement' type */ if (!param_type) @@ -824,127 +488,20 @@ int implements(enum match_flags flags, struct scope *scope, /* at this point, we should always have some type for the argument */ assert(arg_type); - if (param_type->_type.kind == AST_TYPE_ALIAS || - arg_type->_type.kind == AST_TYPE_ALIAS) { - assert(param_type->_type.next == NULL); - return implements_alias(flags, scope, arg_type, param_type); - } - - - if (param_type->_type.kind == AST_TYPE_TYPEOF || - arg_type->_type.kind == AST_TYPE_TYPEOF) { - /* if we're comparing procedure definitions, be more lenient */ - if (!(flags & MATCH_CALL) && - param_type->_type.kind != arg_type->_type.kind) - return 0; - + if (AST_TYPE(param_type).kind == AST_TYPE_TYPEOF) return implements_typeof(flags, scope, arg_type, param_type); - } - - /* having the arg be a trait is a bit of a special case */ - if (arg_type->_type.kind == AST_TYPE_TRAIT) { - if (arg_type->_type.trait.actual == NULL) - return types_match(arg_type, param_type); - - return implements(flags, scope, arg_type->_type.trait.actual, - param_type); - } - - /* TODO: do aliases and traits have to be converted to types? Are - * there any situations where a trait will have to be followed by - * some other type? */ - /* if the parameter type is not a trait, it's an actual type and therefore the - * argument type must be identical to it */ - if (param_type->_type.kind == AST_TYPE_TRAIT) { - if (param_type->_type.trait.actual == NULL) - return implements_trait(flags, scope, arg_type, - param_type); - - return implements(flags, scope, arg_type, - param_type->_type.trait.actual); - } - - if (param_type->_type.kind == AST_TYPE_POINTER) { - if (arg_type->_type.kind != AST_TYPE_POINTER) - return 0; - - return implements(flags, scope, arg_type->_type.next, - param_type->_type.next); - } - - if (!types_match(arg_type, param_type)) - return 0; - - /* if both types have next elements in them, analyze them as well */ - if (arg_type->_type.next && param_type->_type.next) - return implements(flags, scope, arg_type->_type.next, - param_type->_type.next); - - /* if this is the last type element in both types, they match */ - if (!arg_type->_type.next && !param_type->_type.next) - return 1; - - /* otherwise, no match */ - return 0; -} - -/* has to be executed in a temporary scope */ -static int match_args(enum match_flags flags, struct scope *scope, int variadic, - const struct ast_node *args, - const struct ast_node *params) -{ - /* no arguments matches to no parameters */ - if (!params && !args) - return 1; - - while (params && args) { - if (!implements(flags, scope, args->type, params->type)) - return 0; - - init_trait_type(params->type, params->type, args->type); - - params = params->next; - args = args->next; - } - - if (args) { - /* if we have arguments left over and the proc is variadic, we - * match. The last argument is replaced with the trailing list - * of arguments beyond the parameter list. */ - if (variadic) - return 1; - - return 0; - } - /* we have more parameters compared to arguments, so there's no way we - * match */ - if (params) - return 0; + if (AST_TYPE(param_type).kind == AST_TYPE_TRAIT) + return implements_trait(flags, scope, arg_type, param_type); - /* we have the same number of arguments and they all implement the - * parameters, so we match */ - return 1; + return types_match(arg_type, param_type); } -static int match_params(enum match_flags flags, struct scope *scope, - int variadic, +static int match_actual_params(enum match_flags flags, struct scope *scope, struct ast_node *args, struct ast_node *params) { - struct scope *tmp_scope = create_temp_scope(scope); - /* if the args aren't actualized, we're in the analysis phase? */ - /* TODO: this isn't necessary for actualized procedures */ - struct ast_node *params_clone = clone_ast_node(params); - if (args->type && actualize_temp_type(tmp_scope, params_clone)) { - destroy_ast_tree(params_clone); - destroy_scope(tmp_scope); - return 0; - } - - int ret = match_args(flags, tmp_scope, variadic, args, params_clone); - destroy_ast_tree(params_clone); - destroy_scope(tmp_scope); - return ret; + /** @todo essentially just iterate over the parameters, right? */ + return 0; } static struct ast_node *match_resolve(struct scope *scope, @@ -984,32 +541,8 @@ static struct ast_node *match_type_construct(struct scope *scope, return match_resolve(scope, scope->type_construct_resolve, id, args); } -int scope_add_macro(struct scope *scope, struct ast_node *macro) -{ - assert(macro->node_type == AST_MACRO_CONSTRUCT); - /* TODO: separate between arrays and macros? */ - struct ast_node *id = macro->_macro.id; - struct ast_node *params = macro->_macro.params; - - int macro_exists = (match_macro(scope, id, params) != NULL); - if (macro_exists) { - semantic_error(scope->fctx, macro, "macro redefined"); - return -1; - } - - struct visible *new = create_macro(scope, macro); - if (!new) - return -1; - - int public = scope_flags(scope, SCOPE_PUBLIC); - if (scope_flags(scope, SCOPE_FILE) && ast_flags(macro, AST_FLAG_PUBLIC)) - return reference_macro(public, scope->parent, new); - - return 0; -} - -int add_proc_resolve(struct scope *scope, struct ast_node *proc) +static int add_proc_resolve(struct scope *scope, struct ast_node *proc) { if (!scope->proc_resolve) { scope->proc_resolve = calloc(1, sizeof(struct resolve)); @@ -1032,7 +565,7 @@ int add_proc_resolve(struct scope *scope, struct ast_node *proc) return add_resolve(scope, resolve, proc); } -int add_macro_resolve(struct scope *scope, struct ast_node *macro) +static int add_macro_resolve(struct scope *scope, struct ast_node *macro) { if (!scope->macro_resolve) { scope->macro_resolve = calloc(1, sizeof(struct resolve)); @@ -1040,7 +573,7 @@ int add_macro_resolve(struct scope *scope, struct ast_node *macro) struct resolve *resolve = scope->macro_resolve; while (resolve) { - if (identical_ast_nodes(0, resolve->id, macro->_macro.id)) + if (identical_ast_nodes(0, resolve->id, AST_MACRO_CONSTRUCT(macro).id)) return add_resolve(scope, resolve, macro); resolve = resolve->next; @@ -1048,13 +581,34 @@ int add_macro_resolve(struct scope *scope, struct ast_node *macro) resolve = calloc(1, sizeof(struct resolve)); resolve->root = calloc(1, sizeof(struct resolve_node)); - resolve->id = clone_ast_node(macro->_macro.id); + resolve->id = clone_ast_node(AST_MACRO_CONSTRUCT(macro).id); resolve->next = scope->macro_resolve; scope->macro_resolve = resolve; return add_resolve(scope, resolve, macro); } +int scope_add_macro(struct scope *scope, struct ast_node *macro) +{ + assert(macro->node_type == AST_MACRO_CONSTRUCT); + struct ast_node *id = AST_MACRO_CONSTRUCT(macro).id; + struct ast_node *params = AST_MACRO_CONSTRUCT(macro).params; + + struct ast_node *exists = match_macro(scope, id, params);; + if (exists) { + semantic_error(scope->fctx, macro, "macro redefined"); + semantic_info(scope->fctx, exists, "previously here"); + return -1; + } + + add_macro_resolve(scope, macro); + + if (scope_flags(scope, SCOPE_FILE) && ast_flags(macro, AST_FLAG_PUBLIC)) + return scope_add_macro(scope->parent, macro); + + return 0; +} + int add_type_construct_resolve(struct scope *scope, struct ast_node *type_construct) { if (!scope->type_construct_resolve) { @@ -1063,7 +617,7 @@ int add_type_construct_resolve(struct scope *scope, struct ast_node *type_constr struct resolve *resolve = scope->type_construct_resolve; while (resolve) { - if (identical_ast_nodes(0, resolve->id, AST_GET(type_construct, id))) + if (identical_ast_nodes(0, resolve->id, AST_TYPE_CONSTRUCT(type_construct).id)) return add_resolve(scope, resolve, type_construct); resolve = resolve->next; @@ -1071,39 +625,33 @@ int add_type_construct_resolve(struct scope *scope, struct ast_node *type_constr resolve = calloc(1, sizeof(struct resolve)); resolve->root = calloc(1, sizeof(struct resolve_node)); - resolve->id = clone_ast_node(AST_GET(type_construct, id)); + resolve->id = clone_ast_node(AST_TYPE_CONSTRUCT(type_construct).id); resolve->next = scope->type_construct_resolve; scope->type_construct_resolve = resolve; return add_resolve(scope, resolve, type_construct); } -/* would be useful with scope_remove_proc which also removed all references? */ int scope_add_proc(struct scope *scope, struct ast_node *proc) { assert(proc->node_type == AST_PROC); - struct ast_node *id = proc->_proc.id; - struct ast_node *sign = proc->_proc.sign; - struct ast_node *params = sign->_type.sign.params; + struct ast_node *id = AST_PROC(proc).id; + struct ast_node *sign = AST_PROC(proc).sign; + struct ast_node *params = AST_SIGN_TYPE(sign).params; - struct ast_node *macro_exists = match_proc(scope, id, params); + struct ast_node *exists = match_proc(scope, id, params); - if (macro_exists) { + if (exists) { semantic_error(scope->fctx, proc, "proc redefined"); - semantic_info(scope->fctx, macro_exists, "previously as macro"); + semantic_info(scope->fctx, exists, "previously here"); return -1; } - struct visible *new = create_proc(scope, proc); - if (!new) - return -1; - add_proc_resolve(scope, proc); - int public = scope_flags(scope, SCOPE_PUBLIC); if (scope_flags(scope, SCOPE_FILE) && ast_flags(proc, AST_FLAG_PUBLIC)) - return reference_proc(public, scope->parent, new); + return scope_add_proc(scope->parent, proc); return 0; } @@ -1112,86 +660,78 @@ int scope_add_type_construct(struct scope *scope, struct ast_node *type_construc { assert(type_construct->node_type == AST_TYPE_CONSTRUCT); - struct ast_node *id = AST_GET(type_construct, id); - struct ast_node *params = AST_GET(type_construct, params); + struct ast_node *id = AST_TYPE_CONSTRUCT(type_construct).id; + struct ast_node *params = AST_TYPE_CONSTRUCT(type_construct).params; - int type_construct_exists = (match_type_construct(scope, id, params) != NULL); - if (type_construct_exists) { + struct ast_node *exists = match_type_construct(scope, id, params); + if (exists) { semantic_error(scope->fctx, type_construct, "type construct redefined"); + semantic_info(scope->fctx, exists, "previously here"); return -1; } - struct visible *new = create_type_construct(scope, type_construct); - if (!new) - return -1; + add_type_construct_resolve(scope, type_construct); - int public = scope_flags(scope, SCOPE_PUBLIC); if (scope_flags(scope, SCOPE_FILE) && ast_flags(type_construct, AST_FLAG_PUBLIC)) - return reference_type_construct(public, scope->parent, new); + return scope_add_type_construct(scope->parent, type_construct); return 0; } -#define FIND_FILE_VISIBLE(name, obj_type) \ - struct ast_node *name(struct scope *scope, struct ast_node *id) \ - { \ - assert(id->node_type == AST_ID); \ - struct ast_node *found = scope_find_##obj_type(scope, id); \ - if (found) { \ - return found; \ - } \ - if (!scope_flags(scope, SCOPE_FILE)) { \ - return file_scope_find_##obj_type(scope->parent, id); \ - } \ - return NULL; \ +static struct ast_node *scope_find_visible(struct visible *v, struct ast_node *id) +{ + if (!v) + return NULL; + + while (v) { + if (identical_ast_nodes(0, v->id, id)) + return v->node; + + v = v->next; } + return NULL; +} + +struct ast_node *scope_find_type(struct scope *scope, struct ast_node *type) +{ + return scope_find_visible(scope->types, type); +} + struct ast_node *file_scope_find_type(struct scope *scope, struct ast_node *type) { assert(type->node_type == AST_ID); + if (!scope) + return NULL; + struct ast_node *found = scope_find_type(scope, type); if (found) return found; - if (!found && !scope_flags(scope, SCOPE_FILE)) + if (!scope_flags(scope, SCOPE_FILE)) return file_scope_find_type(scope->parent, type); return NULL; } -FIND_FILE_VISIBLE(file_scope_find_var, var); -FIND_FILE_VISIBLE(file_scope_find_proc, proc); -FIND_FILE_VISIBLE(file_scope_find_macro, macro); - -FIND_FILE_VISIBLE(file_scope_find_alias, alias); -FIND_FILE_VISIBLE(file_scope_find_trait, trait); - -struct ast_node *file_scope_find(struct scope *scope, struct ast_node *id) +struct ast_node *scope_find_var(struct scope *scope, struct ast_node *var) { - /* TODO: should probably check for incoming search and filter out params - * etc */ - assert(id->node_type == AST_ID); - - struct ast_node *found = file_scope_find_var(scope, id); - if (found) - return found; - - found = file_scope_find_proc(scope, id); - if (found) - return found; + return scope_find_visible(scope->vars, var); +} - found = file_scope_find_macro(scope, id); - if (found) - return found; +struct ast_node *file_scope_find_var(struct scope *scope, struct ast_node *var) +{ + assert(var->node_type == AST_ID); + if (!scope) + return NULL; - found = file_scope_find_alias(scope, id); + struct ast_node *found = scope_find_var(scope, var); if (found) return found; - found = file_scope_find_trait(scope, id); - if (found) - return found; + if (!scope_flags(scope, SCOPE_FILE)) + return file_scope_find_var(scope->parent, var); return NULL; } @@ -1204,43 +744,11 @@ struct ast_node *scope_resolve_macro(struct scope *scope, struct ast_node *macro return match_macro(scope, id, args); } -static int trait_contains_proc(enum match_flags flags, struct scope *scope, - struct ast_node *trait, - struct ast_node *id, struct ast_node *args) -{ - assert(trait->_type.kind == AST_TYPE_TRAIT); - trait = trait->_type.trait.trait; - - struct ast_node *elem = trait->_trait.body; - if (elem) - do { - if (elem->node_type != AST_PROC) - continue; - - if (!identical_ast_nodes(0, elem->_proc.id, id)) - continue; - - /* TODO: should I check for return type here as well? */ - int variadic = ast_flags(elem, AST_FLAG_VARIADIC); - struct ast_node *sign = elem->_proc.sign; - struct ast_node *params = sign->_type.sign.params; - if (match_params(flags, scope, variadic, args, params)) - return 1; - - } while ((elem = elem->next)); - - return 0; -} - struct ast_node *scope_resolve_proc(struct scope *scope, struct ast_node *call) { - /* TODO: we should prefer specialized procs over generic ones. - * i.e. do_stuff(a u32){} should be preferred over do_stuff(a some_type){}, - * when u32 implements some_type. */ assert(call->node_type == AST_CALL); struct ast_node *id = call->_call.id; struct ast_node *args = call->_call.args; - return match_proc(scope, id, args); } @@ -1263,10 +771,10 @@ struct ast_node *scope_resolve_actual(struct scope *scope, assert(!ast_flags(actual, AST_FLAG_VARIADIC)); /* could also check that arguments aren't traits */ - struct ast_node *args = call->_call.args; - struct ast_node *sign = actual->_proc.sign; - struct ast_node *params = sign->_type.sign.params; - if (match_params(0, scope, 0, args, params)) + struct ast_node *args = AST_CALL(call).args; + struct ast_node *sign = AST_PROC(actual).sign; + struct ast_node *params = AST_SIGN_TYPE(sign).params; + if (match_actual_params(0, scope, args, params)) return actual; } while ((prev = cur)); @@ -1302,53 +810,6 @@ struct ast_node *file_scope_resolve_call(struct scope *scope, return NULL; } -struct ast_node *scope_resolve_type(struct scope *scope, struct ast_node *type) -{ - struct ast_node *id = NULL; - switch (type->node_type) { - case AST_ID: id = type; break; - case AST_TYPE: - assert(type->_type.kind == AST_TYPE_ID); - id = type->_type.id; - break; - - case AST_ALIAS: - id = type->_alias.id; - break; - - case AST_TRAIT: - id = type->_trait.id; - break; - - case AST_STRUCT: - id = type->_struct.id; - break; - - case AST_ENUM: - id = type->_enum.id; - break; - - default: - semantic_error(scope->fctx, type, "unknown type"); - return NULL; - } - - return scope_find_type(scope, id); -} - -struct ast_node *file_scope_resolve_type(struct scope *scope, - struct ast_node *type) -{ - struct ast_node *found = scope_resolve_type(scope, type); - if (found) - return found; - - if (!scope_flags(scope, SCOPE_FILE)) - return file_scope_resolve_type(scope->parent, type); - - return NULL; -} - struct ast_node *file_scope_resolve_macro(struct scope *scope, struct ast_node *macro) { struct ast_node *found = scope_resolve_macro(scope, macro); @@ -1356,17 +817,13 @@ struct ast_node *file_scope_resolve_macro(struct scope *scope, struct ast_node * return found; if (!scope_flags(scope, SCOPE_FILE)) - return file_scope_resolve_type(scope->parent, macro); + return file_scope_resolve_macro(scope->parent, macro); return NULL; } /* this might be useful somewhere else as well */ -static const char *default_types[] = {"u8", "u16", "u32", "u64", - "i8" "i16", "i32", "i64", - "usize", "isize", - "f32", "f64", - "bool", "void"}; +static const char *default_types[] = {"void", "i9", "i27"}; /* TODO: add error checking */ int scope_add_defaults(struct scope *root) @@ -1379,35 +836,16 @@ int scope_add_defaults(struct scope *root) if (!n) return -1; - struct ast_node *a = gen_type(AST_TYPE_ID, n, NULL, NULL); + struct ast_node *a = gen_type(AST_TYPE_PRIMITIVE, n, NULL, NULL); if (!a) return -1; - scope_add_type(root, a); + scope_add_type(root, n, a); } return 0; } -void scope_destroy_defaults(struct scope *scope) -{ - /* just enough data to get through to the actual default aliases */ - struct ast_node type = {0}; - type.node_type = AST_ID; - - for (size_t i = 0; - i < sizeof(default_types) / sizeof(default_types[0]); - ++i) { - type._id.id = default_types[i]; - struct ast_node *n = scope_find_alias(scope, &type); - /* something is afoot, but at least try to free the rest */ - if (!n) - continue; - - destroy_ast_node(n); - } -} - void scope_add_scope(struct scope *parent, struct scope *child) { assert(parent); @@ -1462,19 +900,6 @@ struct ast_node *scope_find_actual(struct scope *scope, struct ast_node *node) return find_actual(scope->actuals, node); } -int scope_add_scratch(struct scope *scope, struct ast_node *scratch) -{ - struct scratch *new = create_scratch(scratch); - if (!new) { - internal_error("failed allocating scratch node"); - return -1; - } - - new->next = scope->scratch; - scope->scratch = new; - return 0; -} - struct scope *create_temp_scope(struct scope *parent) { struct scope *scope = create_scope(); |
