diff options
Diffstat (limited to 'src/actualize.c')
| -rw-r--r-- | src/actualize.c | 186 |
1 files changed, 143 insertions, 43 deletions
diff --git a/src/actualize.c b/src/actualize.c index 8aec279..e79bfa2 100644 --- a/src/actualize.c +++ b/src/actualize.c @@ -494,6 +494,23 @@ int alias_match(struct ast_node *a, struct ast_node *b) return types_match(a_act, b_act); } +static int typeof_match(struct ast_node *a, struct ast_node *b) +{ + struct ast_node *a_act = NULL, *b_act = NULL; + if (a->_type.kind == AST_TYPE_TYPEOF) + a_act = a->_type.typeo.actual; + else + a_act = a; + + + if (b->_type.kind == AST_TYPE_TYPEOF) + b_act = b->_type.typeo.actual; + else + b_act = b; + + return types_match(a_act, b_act); +} + int types_match(struct ast_node *a, struct ast_node *b) { if (!a && !b) @@ -508,9 +525,17 @@ 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_TEMPLATE || b->_type.kind == AST_TYPE_TEMPLATE) { + /* TODO: check template type name */ if (template_match(a, b)) return 1; return 0; @@ -676,6 +701,7 @@ static int actualize_proc_call(struct act_state *state, struct ast_node *params = sign->_type.sign.params; struct ast_node *args = call->_call.args; + /* fuck, analyze_proc gobbles up the return type typeof */ actualize_template_types(params, args); if (actualize(state, tmp, sign)) @@ -773,6 +799,7 @@ static int actualize_call(struct act_state *state, assert(call && call->node_type == AST_CALL); /* check that arguments exist, make sure they have types etc. */ + /* TODO: procedure callbacks? */ int ret = actualize(state, scope, call->_call.args); if (ret) return ret; @@ -795,7 +822,7 @@ get_callable: if (callable->node_type == AST_PROC && !ast_flags(callable->_proc.sign, AST_FLAG_ACTUAL)) { /* since we're in types only mode, this should be fine */ - if (actualize(state, scope, callable)) + if (actualize(state, callable->scope, callable)) return -1; goto get_callable; @@ -866,26 +893,27 @@ static int actualize_proc(struct act_state *state, } struct ast_node *sign = actual->_proc.sign; - if (act_flags(state, ACT_ONLY_TYPES)) { - struct scope *param_scope = create_scope(); - scope_add_scope(scope, param_scope); + struct scope *param_scope = create_scope(); + scope_add_scope(scope, param_scope); - /* procedure type is the signature */ - sign->scope = param_scope; - actual->type = sign; + /* procedure type is the signature */ + sign->scope = param_scope; + actual->type = sign; - /* TODO: if we're actualizing the types here, how can we avoid - * duplicates in the scope proc list? Or can we at all? */ + /* TODO: if we're actualizing the types here, how can we avoid + * duplicates in the scope proc list? Or can we at all? */ - /* actualize types in signature */ - /* note to self: this could likely be made more explicit, but - * essentially we only want to actualize the signature when - * we're in the analysis phase. After that, the call to the proc - * will initialize the types for us, so this step would - * overwrite the type info. I think, at least. */ - return actualize(state, param_scope, sign); - } + /* actualize types in signature */ + /* note to self: this could likely be made more explicit, but + * essentially we only want to actualize the signature when + * we're in the analysis phase. After that, the call to the proc + * will initialize the types for us, so this step would + * overwrite the type info. I think, at least. */ + if (actualize(state, param_scope, sign)) + return -1; + if (act_flags(state, ACT_ONLY_TYPES)) + return 0; /* struct ast_node *params = sign->_type.sign.params; while (params) { @@ -1215,21 +1243,11 @@ static int actualize_type(struct act_state *state, if (actualize(state, scope, expr)) EXIT_ACT(-1); - /* I suspect there are more ways than this that we can fail, but - * this is a decent starting point */ - if (expr->type->_type.kind == AST_TYPE_TYPEOF) { - semantic_error(scope->fctx, type, - "couldn't actualize type expression\n"); - EXIT_ACT(-1); - } - + /* TODO: for now just trust that the expression is not looped or + * anything dumb like that, but I would feel better if I figure + * out some check */ assert(type->_type.next == NULL); - /* clone node to make sure we don't accidentally step on - * anyone's toes and double free anything */ - struct ast_node *clone = clone_ast_node(expr->type); - *type = *clone; - free(clone); - destroy_ast_node(expr); + type->_type.typeo.actual = expr->type; break; } @@ -1275,13 +1293,6 @@ static int actualize_type(struct act_state *state, } ast_set_flags(type, AST_FLAG_ACTUAL); - - if (type->_type.kind == AST_TYPE_TYPEOF) { - semantic_error(scope->fctx, type, - "couldn't convert expression to type"); - EXIT_ACT(-1); - } - /* generally speaking */ EXIT_ACT(0); } @@ -1520,34 +1531,87 @@ static int init_struct(struct act_state *state, struct scope *scope, return ret; } +static struct ast_node *actual_type(struct ast_node *type) +{ + assert(type->node_type == AST_TYPE); + if (type->_type.kind == AST_TYPE_ALIAS) + return actual_type(type->_type.alias.actual); + + if (type->_type.kind == AST_TYPE_TEMPLATE) + return actual_type(type->_type.template.actual); + + if (type->_type.kind == AST_TYPE_TYPEOF) + return actual_type(type->_type.typeo.actual); + + return type; +} + static int actualize_struct_init(struct act_state *state, struct scope *scope, struct ast_node *init, struct ast_node *struct_type) { - if (struct_type->_type.kind != AST_TYPE_STRUCT) { + struct ast_node *actual = actual_type(struct_type); + if (actual->_type.kind != AST_TYPE_STRUCT) { semantic_error(scope->fctx, struct_type, "type is not a structure"); return -1; } - struct ast_node *id = struct_type->_type.struc.id; + struct ast_node *id = actual->_type.struc.id; struct ast_node *exists = file_scope_resolve_type(scope, id); assert(exists); return init_struct(state, scope, exists, init); } +static int proc_pointer(struct ast_node *type) +{ + if (type->_type.kind != AST_TYPE_POINTER) + return 0; + + struct ast_node *next = type->_type.next; + if (next->_type.kind != AST_TYPE_SIGN) + return 0; + + return 1; +} + +static int proc_choice(struct ast_node *expr, struct ast_node *type) +{ + if (expr->node_type != AST_ID) + return 0; + + if (!proc_pointer(type)) + return 0; + + return 1; +} + +/* still slightly unsure about this, but hey ho */ +static int match_proc(struct act_state *state, struct scope *scope, + struct ast_node *cast) +{ + semantic_error(scope->fctx, cast, + "procedure signature casts not yet implemented"); + return -1; +} + static int actualize_cast(struct act_state *state, struct scope *scope, struct ast_node *cast) { assert(cast->node_type == AST_CAST); struct ast_node *expr = cast->_cast.expr; + struct ast_node *type = cast->_cast.type; - if (actualize(state, scope, expr)) + if (actualize(state, scope, type)) return -1; - struct ast_node *type = cast->_cast.type; - if (actualize(state, scope, type)) + if (proc_choice(expr, type)) { + cast->type = type; + return match_proc(state, scope, cast); + } + + if (actualize(state, scope, expr)) return -1; if (expr->node_type == AST_INIT) { @@ -2186,8 +2250,44 @@ void replace_type(struct ast_node *type, struct ast_node *from, void replace_param_types(struct ast_node *param, struct ast_node *param_type, struct ast_node *arg_type) { + if (arg_type->_type.kind == AST_TYPE_TEMPLATE) { + replace_param_types(param, param_type, arg_type); + return; + } + while (param) { replace_type(param->type, param_type, arg_type); param = param->next; } } + +void init_template_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 *template = extract_template(type); + if (template) { + /* TODO: this shares a fair bit of similarities with + * actualize_template_types, could probably create a common + * backend? */ + while (type != template) { + type = param_type->_type.next; + type = arg_type->_type.next; + assert(param_type); + assert(arg_type); + } + + template->_type.template.actual = arg_type; + } +} + +void init_template_types(struct ast_node *params, struct ast_node *param_type, + struct ast_node *arg_type) +{ + while (params) { + init_template_type(params->type, param_type, arg_type); + params = params->next; + } +} |
