diff options
author | Leo Tenenbaum <pommicket@gmail.com> | 2020-02-20 14:39:44 -0500 |
---|---|---|
committer | Leo Tenenbaum <pommicket@gmail.com> | 2020-02-20 14:39:44 -0500 |
commit | 9055d35ad80f804e4bfb5ef9968b25dad92f3764 (patch) | |
tree | dc74c6b237203a038bcfa338580dcd6c7d4a7e98 | |
parent | cfc2e1f3841785ee7466240913f6b13797fb4760 (diff) |
fixing default arguments for parameterized structs
-rw-r--r-- | infer.c | 50 | ||||
-rw-r--r-- | main.c | 3 | ||||
-rw-r--r-- | test.toc | 42 | ||||
-rw-r--r-- | types.c | 131 |
4 files changed, 127 insertions, 99 deletions
@@ -25,27 +25,43 @@ static bool infer_from_expr(Typer *tr, Expression *match, Expression *to, Expres break; case EXPR_CALL: { #if 0 - /* TODO: infer from parameterized structs */ - size_t nargs = arr_len(match->struc.args); - Declaration *param = to->struc->params; - int ident_idx = 0; - for (i = 0; i < nargs; ++i) { - Expression *arg = &match->struc.args[i]; - Value val = *decl_val_at_index(param, ident_idx); - Expression val_expr = {0}; - val_expr.kind = EXPR_VAL; - val_expr.val = val; - val_expr.type = *decl_type_at_index(param, ident_idx); - val_expr.flags = EXPR_FOUND_TYPE; - if (!infer_from_expr(tr, arg, &val_expr, &val_expr, idents, vals, types)) { + if (to->kind == EXPR_TYPE) { + /* maybe it's a parameterized struct? */ + /* it might not be possible that it's not, but might as well keep that possibility around. */ + Value fn_val = {0}; + if (!types_expr(tr, match->call.fn)) { return false; } - ++ident_idx; - if (ident_idx >= (int)arr_len(param->idents)) { - ++param; - ident_idx = 0; + if (type_is_builtin(&match->call.fn->type, BUILTIN_TYPE)) { + /* it's a parameterized struct */ + if (!eval_expr(tr->evalr, match->call.fn, &fn_val)) { + return false; + } + assert(fn_val.type->kind == TYPE_STRUCT); + + size_t nargs = arr_len(match->call.args); + Declaration *param = fn_val.type->struc->params; + int ident_idx = 0; + for (size_t i = 0; i < nargs; ++i) { + Expression *arg = &match->call.args[i]; + Value val = *decl_val_at_index(param, ident_idx); + Expression val_expr = {0}; + val_expr.kind = EXPR_VAL; + val_expr.val = val; + val_expr.type = *decl_type_at_index(param, ident_idx); + val_expr.flags = EXPR_FOUND_TYPE; + if (!infer_from_expr(tr, arg, &val_expr, &val_expr, idents, vals, types)) { + return false; + } + ++ident_idx; + if (ident_idx >= (int)arr_len(param->idents)) { + ++param; + ident_idx = 0; + } + } } } + #endif while (to->kind == EXPR_IDENT) { @@ -20,8 +20,9 @@ TODO: struct parameters - make sure inference works with struct params +- split up a,b::int for parameterized structs (?also maybe normal parameters?) - allow accessing parameters with . -- should argument set twice error be in call_arg_param_order? +- make call_arg_param_order work more like parameterized_struct_arg_order --- see infer.c "is resolved_to necessary" (now that ident system has changed) replace is_reference in type_resolve_ with system for checking if type is @@ -1,41 +1,11 @@ -io ::= nms { -#include "std/io.toc"; -}; - -LinkedList ::= struct(t::Type) { - head : t; - tail : &LinkedList(t); -}; - -arr_to_ll ::= fn(t::Type, data: []t) l : LinkedList(t) { - if data.len == 1 { - l.head = data[0]; - l.tail = 0 as &LinkedList(t); - } else { - l.head = data[0]; - l.tail = new(LinkedList(t)); - *l.tail = arr_to_ll(t, data[1:]); - } -}; - -do_thing ::= fn() int { +// io ::= nms { +// #include "std/io.toc"; +// }; - a := new(int, 3); - a[0] = 10; - a[1] = 20; - a[2] = 30; - x := arr_to_ll(int, a); - p := &x; - i := 0; - while p { - io.puti(p.head); - p = p.tail; - i += 1; - } - i +Thing ::= struct(t::Type=int) { + it : t; }; main ::= fn() { - x ::= do_thing(); - do_thing(); + a: Thing(); };
\ No newline at end of file @@ -956,6 +956,61 @@ static bool call_arg_param_order(Allocator *allocr, FnExpr *fn, Type *fn_type, A return true; } +/* *order must be freed, regardless of return value. if (*order)[i] == -1, that parameter was not set. */ +static bool parameterized_struct_arg_order(StructDef *struc, Argument *args, I16 **order) { + /* + it would be nice if this code and the code for arguments to normal functions + weren't split into two separate functions. + */ + size_t nparams = 0; + arr_foreach(struc->params, Declaration, param) + nparams += arr_len(param->idents); + + *order = err_malloc(nparams * sizeof **order); + for (size_t i = 0; i < nparams; ++i) + (*order)[i] = -1; + int p = 0; /* sequential parameter */ + + + arr_foreach(args, Argument, arg) { + int param_idx; + if (arg->name) { + param_idx = 0; + arr_foreach(struc->params, Declaration, param) { + arr_foreach(param->idents, Identifier, ident) { + if (ident_eq_str(*ident, arg->name)) + goto struct_params_done; + ++param_idx; + } + } + struct_params_done:; + } else { + param_idx = p; + ++p; + } + if ((*order)[param_idx] != -1) { + Identifier param_name = NULL; + int counter = param_idx; + arr_foreach(struc->params, Declaration, param) { + arr_foreach(param->idents, Identifier, ident) { + if (--counter < 0) { + param_name = *ident; + break; + } + } + if (param_name) break; + } + + char *s = ident_to_str(param_name); + err_print(arg->where, "Parameter #%d (%s) set twice in parameterized type instantiation.", param_idx+1, s); + free(s); + return false; + } + (*order)[arg - args] = (I16)param_idx; + } + return true; +} + static Value get_builtin_val(BuiltinVal val) { Value v; switch (val) { @@ -1435,61 +1490,48 @@ static bool types_expr(Typer *tr, Expression *e) { err_print(e->where, "Expected at most %lu argument%s to parameterized type, but got %lu.", nparams, plural_suffix(nparams), nargs); return false; } - - /* - it would be nice if this code and the code for arguments to normal functions - used the same stuff for named arguments, etc. - */ - Value *arg_vals = typer_malloc(tr, nparams * sizeof *arg_vals); + HashTable *table = &base->struc->instances; + bool already_exists; + Value args_val = {0}; + Type args_type = {0}; + I16 *order; + if (!parameterized_struct_arg_order(base->struc, c->args, &order)) { + free(order); + return false; + } Type *arg_types = NULL; arr_set_len(&arg_types, nparams); - U8 *params_set = err_calloc(1, nparams); - int p = 0; /* sequential parameter */ + Value *arg_vals = typer_malloc(tr, nparams * sizeof *arg_vals); - arr_foreach(c->args, Argument, arg) { - int param_idx; - if (arg->name) { - param_idx = 0; - arr_foreach(base->struc->params, Declaration, param) { - arr_foreach(param->idents, Identifier, ident) { - if (ident_eq_str(*ident, arg->name)) - goto struct_params_done; - ++param_idx; - } - } - struct_params_done:; - } else { - param_idx = p; - ++p; - } - if (params_set[param_idx]) { - Identifier param_name = NULL; - int counter = param_idx; + for (size_t i = 0; i < nparams; ++i) { + if (order[i] == -1) { + Declaration *ith_parameter = NULL; + int index_in_decl = -1; + size_t i_copy = i; + /* fetch ith parameter */ arr_foreach(base->struc->params, Declaration, param) { arr_foreach(param->idents, Identifier, ident) { - if (--counter < 0) { - param_name = *ident; + if (i_copy == 0) { + /* here we are */ + ith_parameter = param; + index_in_decl = (int)(ident - param->idents); break; } + --i_copy; } - if (param_name) break; } - - char *s = ident_to_str(param_name); - err_print(arg->where, "Parameter #%d (%s) set twice in parameterized type instantiation.", param_idx+1, s); - free(s); - return false; + assert(ith_parameter); + arg_types[i] = *decl_type_at_index(ith_parameter, index_in_decl); + arg_vals[i] = *decl_val_at_index(ith_parameter, index_in_decl); + } else { + Argument *arg = &c->args[order[i]]; + arg_types[i] = arg->val.type; + if (!eval_expr(tr->evalr, &arg->val, &arg_vals[i])) + return false; } - params_set[param_idx] = true; - arg_types[param_idx] = arg->val.type; - if (!eval_expr(tr->evalr, &arg->val, &arg_vals[param_idx])) - return false; + assert(arg_types[i].flags & TYPE_IS_RESOLVED); } - - HashTable *table = &base->struc->instances; - bool already_exists; - Value args_val = {0}; - Type args_type = {0}; + args_val.tuple = arg_vals; args_type.tuple = arg_types; args_type.kind = TYPE_TUPLE; @@ -1531,7 +1573,6 @@ static bool types_expr(Typer *tr, Expression *e) { t->kind = TYPE_BUILTIN; t->builtin = BUILTIN_TYPE; arr_clear(&arg_types); - free(params_set); goto ret; } fn_decl = val.fn; |