diff options
| author | Kimplul <kimi.h.kuparinen@gmail.com> | 2023-03-30 21:13:47 +0300 |
|---|---|---|
| committer | Kimplul <kimi.h.kuparinen@gmail.com> | 2023-03-30 21:13:47 +0300 |
| commit | b8211cda90f8a9cb14657d3328cfa9ec78722c5c (patch) | |
| tree | 047036fd67d8b46ca2fd88b2597b03fd99fbc867 /src/scope.c | |
| parent | 78cf00cb506cb86112cb715e4d2d69ec11b20c42 (diff) | |
| download | ek-b8211cda90f8a9cb14657d3328cfa9ec78722c5c.tar.gz ek-b8211cda90f8a9cb14657d3328cfa9ec78722c5c.zip | |
change to left-to-right resolver
Diffstat (limited to 'src/scope.c')
| -rw-r--r-- | src/scope.c | 541 |
1 files changed, 411 insertions, 130 deletions
diff --git a/src/scope.c b/src/scope.c index eca425b..e9cf75c 100644 --- a/src/scope.c +++ b/src/scope.c @@ -11,6 +11,231 @@ #include <cu/scope.h> #include <cu/actualize.h> +static int generic_type(struct scope *scope, struct ast_node *type) +{ + if (!type) + return 0; + + if (type->_type.kind == AST_TYPE_STRUCT) { + /* check if the structure takes template parameters */ + struct ast_node *struc = file_scope_find_type(scope, type); + assert(struc); + assert(struc->node_type == AST_STRUCT); + return struc->_struct.generics != NULL; + } + + if (type->_type.kind == AST_TYPE_UNION) { + /* check if the structure takes template parameters */ + struct ast_node *unio = file_scope_find_type(scope, + type->_type.unio.id); + assert(unio); + assert(unio->node_type == AST_UNION); + return unio->_union.generics != NULL; + } + + if (type->_type.kind == AST_TYPE_TEMPLATE) + return type->_type.template.actual == NULL; + + return generic_type(scope, type->_type.next); +} + +static int referential_type(struct scope *scope, struct ast_node *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(scope, type->_type.next); +} + +static int primitive_type(struct scope *scope, struct ast_node *type) +{ + if (!type) + return 1; + + if (referential_type(scope, type)) + return 0; + + if (generic_type(scope, type)) + return 0; + + return 1; +} + +static struct param_node *find_primitive(struct scope *scope, struct proc_node *node, + struct ast_node *type) +{ + struct param_node *param = node->primitives; + while (param) { + if (types_match(param->type, type)) + return param; + + param = param->next; + } + + return NULL; +} + +static int match_generic(struct scope *scope, struct ast_node *a, + struct ast_node *b) +{ + return implements(0, scope, a, b); +} + +static int add_next_resolve(struct scope *scope, struct ast_node *proc, + struct proc_node *node, struct ast_node *params) +{ + assert(node); + if (params && actualize_temp_type(scope, params)) + return -1; + + /* TODO: variadics? */ + /* we've run out of params, check if this is a suitable node */ + if (!params) { + /* node is already occupied, error on ambiguous definition */ + if (node->proc) { + semantic_error(scope->fctx, proc, "ambiguous callable"); + semantic_error(scope->fctx, node->proc, "matches here"); + return -1; + } + + node->proc = proc; + return 0; + } + + assert(params->node_type == AST_VAR); + if (primitive_type(scope, params->type)) { + struct param_node *found = find_primitive(scope, node, params->type); + if (found) + return add_next_resolve(scope, proc, found->proc, + params->next); + + found = calloc(1, sizeof(struct param_node)); + found->type = params->type; + found->next = node->primitives; + node->primitives = found; + + struct proc_node *next = calloc(1, sizeof(struct proc_node)); + found->proc = next; + return add_next_resolve(scope, proc, next, params->next); + } + + if (referential_type(scope, params->type)) { + /* TODO: I don't think there's a good way to check if the + * referential types are identical, but could be worth a shot */ + if (!node->referential) { + node->referential = calloc(1, sizeof(struct param_node)); + node->referential->type = params->type; + + struct proc_node *next = calloc(1, sizeof(struct proc_node)); + node->referential->proc = next; + + return add_next_resolve(scope, proc, next, params->next); + } + + if (!types_match(node->referential->type, params->type)) { + semantic_error(scope->fctx, params->type, + "ambiguous referential"); + semantic_error(scope->fctx, node->referential->type, + "matches here"); + return -1; + } + + /* common reference */ + destroy_ast_tree(params->type); + params->_var.type = NULL; + params->type = node->referential->type; + return add_next_resolve(scope, proc, node->referential->proc, params->next); + } + + /* otherwise try to use type as fallback */ + if (!node->fallback) { + node->fallback = calloc(1, sizeof(struct param_node)); + node->fallback->type = params->type; + + struct proc_node *next = calloc(1, sizeof(struct proc_node)); + node->fallback->proc = next; + return add_next_resolve(scope, proc, next, params->next); + } + + if (!match_generic(scope, node->fallback->type, params->type)) { + semantic_error(scope->fctx, params->type, "ambiguous generic"); + semantic_info(scope->fctx, node->fallback->type, + "matches here"); + return -1; + } + + /* common reference */ + destroy_ast_tree(params->type); + params->_var.type = NULL; + params->type = node->fallback->type; + return add_next_resolve(scope, proc, node->fallback->proc, + params->next); +} + +static int add_resolve(struct scope *scope, struct proc_node *root, + struct ast_node *proc) +{ + assert(root); + + 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, root, params); +} + +static struct ast_node *proc_resolve(struct scope *scope, + struct proc_node *node, + struct ast_node *args) +{ + assert(node); + if (!args) { + if (node->proc) + return node->proc; + + return NULL; + } + + /* first check if we match a primitive type */ + struct param_node *found = find_primitive(scope, node, args->type); + if (found) + return proc_resolve(scope, found->proc, args->next); + + /* no primitives, check referentials */ + struct param_node *ref = node->referential; + if (ref) { + /* this works on the assumption that references actually are + * references to previous nodes, which we've hopefully + * initialized with real types by now. + * However, that doesn't happen, because the fallback isn't the + * one that the type is assigned to. Therefore, fuck. */ + if (types_match(args->type, ref->type)) + return proc_resolve(scope, ref->proc, args->next); + } + + /* referential didn't match, check fallback */ + struct param_node *fallback = node->fallback; + if (!fallback) + return NULL; + + if (implements(0, scope, args->type, fallback->type)) { + /* my idea is that we could lock each node individually and + * allow multithreading scopes, but I realize that recursively + * checking templates might cause a lock... */ + init_template_type(fallback->type, fallback->type, args->type); + return proc_resolve(scope, fallback->proc, 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() @@ -75,6 +300,38 @@ void destroy_actuals(struct actual *actuals) } while ((prev = cur)); } +void destroy_proc_node(struct proc_node *); + +void destroy_param_nodes(struct param_node *param) +{ + if (!param) + return; + + destroy_proc_node(param->proc); + destroy_param_nodes(param->next); + free(param); +} + +void destroy_proc_node(struct proc_node *proc) +{ + destroy_param_nodes(proc->primitives); + destroy_param_nodes(proc->referential); + destroy_param_nodes(proc->fallback); + free(proc); +} + +void destroy_callable(struct callable *callable) +{ + struct callable *prev = callable, *cur; + if (prev) + do { + cur = prev->next; + destroy_proc_node(prev->root); + destroy_ast_node(prev->id); + free(prev); + } while ((prev = cur)); +} + void destroy_scope(struct scope *scope) { if (!scope) @@ -87,12 +344,11 @@ void destroy_scope(struct scope *scope) } destroy_scratch(scope->scratch); + destroy_callable(scope->callable); destroy_visible(scope, scope->vars); destroy_visible(scope, scope->procs); - destroy_visible(scope, scope->macros); destroy_visible(scope, scope->builtins); - destroy_visible(scope, scope->overrides); destroy_visible(scope, scope->enums); destroy_visible(scope, scope->structs); @@ -149,8 +405,8 @@ static struct scratch *create_scratch(struct ast_node *scratch) } CREATE_VISIBLE(create_var, vars, AST_VAR); -CREATE_VISIBLE(create_proc, procs, AST_PROC); CREATE_VISIBLE(create_macro, macros, AST_MACRO); +CREATE_VISIBLE(create_proc, procs, AST_PROC); CREATE_VISIBLE(create_enum, enums, AST_ENUM); CREATE_VISIBLE(create_alias, aliases, AST_ALIAS); @@ -174,9 +430,8 @@ CREATE_VISIBLE(create_template, templates, AST_TEMPLATE); } REFERENCE_VISIBLE(reference_var, vars, AST_VAR); -REFERENCE_VISIBLE(reference_proc, procs, AST_PROC); REFERENCE_VISIBLE(reference_macro, macros, AST_MACRO); -REFERENCE_VISIBLE(reference_override, overrides, AST_PROC); +REFERENCE_VISIBLE(reference_proc, procs, AST_PROC); REFERENCE_VISIBLE(reference_enum, enums, AST_ENUM); REFERENCE_VISIBLE(reference_alias, aliases, AST_ALIAS); @@ -212,9 +467,8 @@ FIND_VISIBLE(scope_find_template, templates, AST_TEMPLATE, _template); /* 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_override, overrides, AST_PROC, _proc); FIND_VISIBLE(scope_find_macro, macros, AST_MACRO, _macro); +FIND_VISIBLE(scope_find_proc, procs, AST_PROC, _proc); struct ast_node *scope_find(struct scope *scope, struct ast_node *id) { @@ -453,10 +707,11 @@ static struct ast_node *match_macro(int global, struct scope *scope, return NULL; } -static struct ast_node *match_proc(int global, struct scope *scope, +static struct ast_node *match_proc(enum match_flags flags, struct scope *scope, struct ast_node *id, struct ast_node *args); -static int implements_proc(struct scope *scope, struct ast_node *arg_type, +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) { assert(proc->node_type == AST_PROC); @@ -481,7 +736,7 @@ static int implements_proc(struct scope *scope, struct ast_node *arg_type, */ /* TODO: detect loops, such as when two template return params rely on * eachother */ - if (!implements(scope, impl_ret, ret)) { + 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"); @@ -498,7 +753,8 @@ out: return impl != NULL; } -static int implements_var(struct scope *scope, struct ast_node *arg_type, +static int implements_var(enum match_flags flags, struct scope *scope, + struct ast_node *arg_type, struct ast_node *param_type, struct ast_node *var) { assert(var->node_type == AST_VAR); @@ -506,10 +762,15 @@ static int implements_var(struct scope *scope, struct ast_node *arg_type, return 0; } -static int implements_template(struct scope *scope, struct ast_node *arg_type, +static int implements_template(enum match_flags flags, struct scope *scope, + struct ast_node *arg_type, struct ast_node *param_type) { assert(param_type->_type.kind == AST_TYPE_TEMPLATE); + if (param_type->_type.template.actual) + return implements(flags, scope, arg_type, + param_type->_type.template.actual); + struct ast_node *template = param_type->_type.template.template; /* if we already know we implement this template, nothing to do */ if (find_implementation(template, arg_type)) @@ -530,7 +791,8 @@ static int implements_template(struct scope *scope, struct ast_node *arg_type, if (elem) do { if (elem->node_type == AST_VAR) { - if (implements_var(scope, arg_type, param_type, + if (implements_var(flags, scope, arg_type, + param_type, elem)) continue; @@ -544,7 +806,8 @@ static int implements_template(struct scope *scope, struct ast_node *arg_type, } else if (elem->node_type == AST_PROC) { - if (implements_proc(scope, arg_type, param_type, + if (implements_proc(flags, scope, arg_type, + param_type, elem)) continue; @@ -571,41 +834,40 @@ not_implemented: return 0; } -static int implements_alias(struct scope *scope, struct ast_node *arg_type, +static int implements_alias(enum match_flags flags, struct scope *scope, + struct ast_node *arg_type, struct ast_node *param_type) { - struct ast_node *a_act = NULL, *p_act = NULL; - if (arg_type->_type.kind == AST_TYPE_ALIAS) - a_act = arg_type->_type.alias.actual; - else - a_act = arg_type; + while (arg_type && arg_type->_type.kind == AST_TYPE_ALIAS) + arg_type = arg_type->_type.alias.actual; - if (param_type->_type.kind == AST_TYPE_ALIAS) - p_act = param_type->_type.alias.actual; - else - p_act = param_type; + while (param_type && param_type->_type.kind == AST_TYPE_ALIAS) + param_type = param_type->_type.alias.actual; - return implements(scope, a_act, p_act); + return implements(flags, scope, arg_type, param_type); } -static int implements_typeof(struct scope *scope, struct ast_node *arg_type, +static int implements_typeof(enum match_flags flags, struct scope *scope, + struct ast_node *arg_type, struct ast_node *param_type) { - struct ast_node *a_act = NULL, *p_act = NULL; - if (arg_type->_type.kind == AST_TYPE_TYPEOF) - a_act = arg_type->_type.typeo.actual; - else - a_act = arg_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; - if (param_type->_type.kind == AST_TYPE_TYPEOF) - p_act = param_type->_type.typeo.actual; - else - p_act = param_type; + return implements(flags, scope, arg_type, param_type); +} - return implements(scope, a_act, p_act); +static int implements_pointer(enum match_flags flags, struct scope *scope, + struct ast_node *arg_type, + struct ast_node *param_type) +{ + return implements(flags, scope, arg_type, param_type); } -int implements(struct scope *scope, +int implements(enum match_flags flags, struct scope *scope, struct ast_node *arg_type, struct ast_node *param_type) { /* if both types are null, they are uninitialized and we'll assume they @@ -627,18 +889,28 @@ int implements(struct scope *scope, if (param_type->_type.kind == AST_TYPE_ALIAS || arg_type->_type.kind == AST_TYPE_ALIAS) { assert(param_type->_type.next == NULL); - return implements_alias(scope, arg_type, param_type); + return implements_alias(flags, scope, arg_type, param_type); } + if (param_type->_type.kind == AST_TYPE_TYPEOF || arg_type->_type.kind == AST_TYPE_TYPEOF) { - return implements_typeof(scope, arg_type, param_type); + /* if we're comparing procedure definitions, be more lenient */ + if (!(flags & MATCH_CALL) && + param_type->_type.kind != arg_type->_type.kind) + return 0; + + return implements_typeof(flags, scope, arg_type, param_type); } /* having the arg be a template is a bit of a special case */ - if (arg_type->_type.kind == AST_TYPE_TEMPLATE) - return implements(scope, arg_type->_type.template.actual, + if (arg_type->_type.kind == AST_TYPE_TEMPLATE) { + if (arg_type->_type.template.actual == NULL) + return types_match(arg_type, param_type); + + return implements(flags, scope, arg_type->_type.template.actual, param_type); + } /* TODO: do aliases and templates have to be converted to types? Are * there any situations where a template will have to be followed by @@ -646,14 +918,20 @@ int implements(struct scope *scope, /* if the parameter type is not a template, it's an actual type and therefore the * argument type must be identical to it */ if (param_type->_type.kind == AST_TYPE_TEMPLATE) { - /* the argument type must at this point be templateable, i.e. - * 'i64 does not implement some_type, but would implement - * 'some_type - if (!is_templateable(arg_type)) - return 0; - */ + if (param_type->_type.template.actual == NULL) + return implements_template(flags, scope, arg_type, + param_type); - return implements_template(scope, arg_type, param_type); + return implements(flags, scope, arg_type, + param_type->_type.template.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)) @@ -661,7 +939,7 @@ int implements(struct scope *scope, /* if both types have next elements in them, analyze them as well */ if (arg_type->_type.next && param_type->_type.next) - return implements(scope, arg_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 */ @@ -672,7 +950,8 @@ int implements(struct scope *scope, return 0; } -static int match_args(struct scope *scope, int variadic, +/* 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) { @@ -681,9 +960,11 @@ static int match_args(struct scope *scope, int variadic, return 1; while (params && args) { - if (!implements(scope, args->type, params->type)) + if (!implements(flags, scope, args->type, params->type)) return 0; + init_template_type(params->type, params->type, args->type); + params = params->next; args = args->next; } @@ -708,44 +989,34 @@ static int match_args(struct scope *scope, int variadic, return 1; } -static struct ast_node *iter_procs(struct scope *scope, struct visible *first, - struct ast_node *id, struct ast_node *args) +static int match_params(enum match_flags flags, struct scope *scope, + int variadic, + struct ast_node *args, struct ast_node *params) { - struct visible *prev = first, *cur; - if (prev) - do { - cur = prev->next; - struct ast_node *proc = prev->node; - /* must have identical IDs */ - if (!identical_ast_nodes(0, proc->_proc.id, id)) - continue; - - const int variadic = ast_flags(proc, AST_FLAG_VARIADIC); - const struct ast_node *sign = proc->_proc.sign; - const struct ast_node *params = sign->_type.sign.params; - if (match_args(scope, variadic, args, params)) - return proc; - - } while ((prev = cur)); + 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; + } - return NULL; + int ret = match_args(flags, tmp_scope, variadic, args, params_clone); + destroy_ast_tree(params_clone); + destroy_scope(tmp_scope); + return ret; } -static struct ast_node *match_proc(int global, struct scope *scope, +static struct ast_node *match_proc(enum match_flags flags, struct scope *scope, struct ast_node *id, struct ast_node *args) { - struct ast_node *override = - iter_procs(scope, scope->overrides, id, args); - if (override) - return override; - - struct ast_node *proc = iter_procs(scope, scope->procs, id, args); - if (proc) - return proc; - - if (global && !scope_flags(scope, SCOPE_FILE)) - return match_proc(global, scope->parent, id, args); - + struct callable *cb = scope->callable; + while (cb) { + if (identical_ast_nodes(0, cb->id, id)) + return proc_resolve(scope, cb->root, args); + } return NULL; } @@ -758,7 +1029,9 @@ int scope_add_macro(struct scope *scope, struct ast_node *macro) struct ast_node *params = macro->_macro.params; int macro_exists = match_macro(0, scope, id, params) != NULL; - int proc_exists = match_proc(0, scope, id, params) != NULL; + // TODO: search for any proc with same number of parameters as macro */ + // int proc_exists = match_proc(0, scope, id, params) != NULL; + int proc_exists = 0; if (macro_exists || proc_exists) { semantic_error(scope->fctx, macro, "macro redefined"); @@ -785,11 +1058,11 @@ int scope_add_proc(struct scope *scope, struct ast_node *proc) struct ast_node *sign = proc->_proc.sign; struct ast_node *params = sign->_type.sign.params; - int macro_exists = match_macro(0, scope, id, params) != NULL; - int proc_exists = match_proc(0, scope, id, params) != NULL; + struct ast_node *macro_exists = match_macro(0, scope, id, params); - if (macro_exists || proc_exists) { + if (macro_exists) { semantic_error(scope->fctx, proc, "proc redefined"); + semantic_info(scope->fctx, macro_exists, "previously as macro"); return -1; } @@ -835,43 +1108,34 @@ int scope_add_existing_proc(struct scope *scope, struct visible *visible) struct ast_node *sign = proc->_proc.sign; struct ast_node *params = sign->_type.sign.params; - int macro_exists = match_macro(0, scope, id, params) != NULL; - int proc_exists = match_proc(0, scope, id, params) != NULL; - - if (macro_exists || proc_exists) { + struct ast_node *macro_exists = match_macro(0, scope, id, params); + if (macro_exists) { semantic_error(scope->fctx, proc, "proc redefined"); + semantic_info(scope->fctx, macro_exists, "previously as macro"); return -1; } - struct ast_node *template = NULL; - while (params) { - if ((template = extract_template(params->type))) - break; - - params = params->next; + if (!scope->callable) { + scope->callable = calloc(1, sizeof(struct callable)); + scope->callable->root = calloc(1, sizeof(struct proc_node)); + scope->callable->id = clone_ast_node(id); + return add_resolve(scope, scope->callable->root, proc); } - if (template) { - visible->next = scope->procs; - scope->procs = visible; - } - else { - /* override is maybe a bit misleading, but essentially any - * procedure with no templates */ - visible->next = scope->overrides; - scope->overrides = visible; - } - - int public = scope_flags(scope, SCOPE_PUBLIC); - if (scope_flags(scope, - SCOPE_FILE) && ast_flags(proc, AST_FLAG_PUBLIC)) { - if (template) - return reference_proc(public, scope->parent, visible); + struct callable *cb = scope->callable; + while (cb) { + if (identical_ast_nodes(0, cb->id, id)) + return add_resolve(scope, cb->root, proc); - return reference_override(public, scope->parent, visible); + cb = cb->next; } - return 0; + cb = calloc(1, sizeof(struct callable)); + cb->root = calloc(1, sizeof(struct proc_node)); + cb->id = clone_ast_node(id); + cb->next = scope->callable; + scope->callable = cb; + return add_resolve(scope, cb->root, proc); } #define FIND_FILE_VISIBLE(name, obj_type) \ @@ -904,8 +1168,8 @@ struct ast_node *file_scope_find_type(struct scope *scope, FIND_FILE_VISIBLE(file_scope_find_var, var); FIND_FILE_VISIBLE(file_scope_find_proc, proc); -FIND_FILE_VISIBLE(file_scope_find_override, override); FIND_FILE_VISIBLE(file_scope_find_macro, macro); + FIND_FILE_VISIBLE(file_scope_find_alias, alias); FIND_FILE_VISIBLE(file_scope_find_template, template); @@ -919,10 +1183,6 @@ struct ast_node *file_scope_find(struct scope *scope, struct ast_node *id) if (found) return found; - found = file_scope_find_override(scope, id); - if (found) - return found; - found = file_scope_find_proc(scope, id); if (found) return found; @@ -950,7 +1210,7 @@ struct ast_node *scope_resolve_macro(struct scope *scope, struct ast_node *call) return match_macro(0, scope, id, args); } -static int template_contains_proc(struct scope *scope, +static int template_contains_proc(enum match_flags flags, struct scope *scope, struct ast_node *template, struct ast_node *id, struct ast_node *args) { @@ -970,7 +1230,7 @@ static int template_contains_proc(struct scope *scope, 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_args(scope, variadic, args, params)) + if (match_params(flags, scope, variadic, args, params)) return 1; } while ((elem = elem->next)); @@ -998,7 +1258,8 @@ struct ast_node *scope_resolve_proc(struct scope *scope, struct ast_node *call) if (!template) goto next; - if (!template_contains_proc(scope, template, id, args)) { + if (!template_contains_proc(MATCH_CALL, scope, template, id, + args)) { char *cstr = call_str(call); char *tstr = type_str(arg); semantic_error(scope->fctx, arg, @@ -1014,7 +1275,7 @@ next: arg = arg->next; } - struct ast_node *proc = match_proc(0, scope, id, args); + struct ast_node *proc = match_proc(MATCH_CALL, scope, id, args); if (!proc) return NULL; @@ -1040,10 +1301,10 @@ struct ast_node *scope_resolve_actual(struct scope *scope, assert(!ast_flags(actual, AST_FLAG_VARIADIC)); /* could also check that arguments aren't templates */ - const struct ast_node *args = call->_call.args; - const struct ast_node *sign = actual->_proc.sign; - const struct ast_node *params = sign->_type.sign.params; - if (match_args(scope, 0, args, params)) + 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)) return actual; } while ((prev = cur)); @@ -1234,8 +1495,16 @@ int scope_add_actual(struct scope *scope, struct ast_node *node) static struct ast_node *find_actual(struct actual *actuals, struct ast_node *node) { - /* TODO */ - internal_error("finding actuals not yet implemented"); + assert(node->node_type == AST_ID); + + if (actuals) + do { + struct ast_node *actual = actuals->node; + if (identical_ast_nodes(0, actual->_proc.id, node)) + return actual; + + } while ((actuals = actuals->next)); + return NULL; } @@ -1256,3 +1525,15 @@ int scope_add_scratch(struct scope *scope, struct ast_node *scratch) scope->scratch = new; return 0; } + +struct scope *create_temp_scope(struct scope *parent) +{ + struct scope *scope = create_scope(); + if (!scope) { + internal_error("failed allocating temp scope"); + } + + scope->parent = parent; + scope->fctx = parent->fctx; + return scope; +} |
