summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--main.c4
-rw-r--r--misc.c3
-rw-r--r--test.toc4
-rw-r--r--types.c75
4 files changed, 80 insertions, 6 deletions
diff --git a/main.c b/main.c
index 7ab8c62..f8d4b69 100644
--- a/main.c
+++ b/main.c
@@ -19,8 +19,10 @@
/*
TODO:
struct parameters
-- check for empty parameter lists
+- error on empty parameter list
+- error on non-const param decls
- make sure inference works
+- should argument set twice error be in call_arg_param_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
diff --git a/misc.c b/misc.c
index 497a94f..f11c755 100644
--- a/misc.c
+++ b/misc.c
@@ -57,3 +57,6 @@ static inline U32 rand_u32(U32 seed) {
static inline bool strs_equal(const char *a, const char *b) {
return strcmp(a, b) == 0;
}
+
+#define plural_suffix(x) ((x) == 1 ? "" : "s")
+
diff --git a/test.toc b/test.toc
index 2ded528..4133e4a 100644
--- a/test.toc
+++ b/test.toc
@@ -2,10 +2,10 @@
// #include "std/io.toc";
// };
-foo ::= struct(t::Type) {
+foo ::= struct(t::Type,u::Type) {
x: t;
};
main ::= fn() {
- a:foo(int);
+ foo(u = int, u = float);
}; \ No newline at end of file
diff --git a/types.c b/types.c
index 5b37c1e..a800865 100644
--- a/types.c
+++ b/types.c
@@ -862,8 +862,8 @@ static bool call_arg_param_order(Allocator *allocr, FnExpr *fn, Type *fn_type, A
size_t nparams = arr_len(fn_type->fn.types)-1;
size_t nargs = arr_len(args);
if (nargs > nparams) {
- err_print(where, "Expected at most %lu arguments to function, but got %lu.",
- nparams, nargs);
+ err_print(where, "Expected at most %lu argument%s to function, but got %lu.",
+ nparams, plural_suffix(nparams), nargs);
return false;
}
@@ -1418,8 +1418,77 @@ static bool types_expr(Typer *tr, Expression *e) {
return false;
}
if (!base->struc->params) {
- int x;
+ err_print(e->where, "Passing arguments to struct, but it doesn't take any.");
+ info_print(base->struc->where, "struct was declared here.");
+ return false;
+ }
+
+ size_t nparams = 0;
+ arr_foreach(base->struc->params, Declaration, param)
+ nparams += arr_len(param->idents);
+ size_t nargs = arr_len(c->args);
+ if (nargs > nparams) {
+ 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 = err_malloc(nparams * sizeof *arg_vals);
+ Type *arg_types = err_malloc(nparams * sizeof *arg_types);
+ U8 *params_set = err_calloc(1, nparams);
+ int p = 0; /* sequential parameter */
+
+ 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;
+ arr_foreach(base->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;
+ }
+ 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;
+ }
+
+ for (size_t i = 0; i < nparams; ++i)
+ print_val(arg_vals[i], arg_types + i);
+
+ /* TODO: look up args in instance table, etc. */
+
+ free(arg_vals);
+ free(arg_types);
+ free(params_set);
return true;
}
fn_decl = val.fn;