summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--err.c2
-rw-r--r--eval.c16
-rw-r--r--main.c5
-rw-r--r--parse.c2
-rw-r--r--test.toc12
-rw-r--r--types.c128
-rw-r--r--types.h3
7 files changed, 119 insertions, 49 deletions
diff --git a/err.c b/err.c
index 3c2d5d5..0d8c09c 100644
--- a/err.c
+++ b/err.c
@@ -118,7 +118,7 @@ static void err_print_footer_(Location where, bool show_ctx_stack) {
print_location_highlight(err_ctx_file(ctx), where);
if (ctx && show_ctx_stack) {
arr_foreach(ctx->instance_stack, Location, inst) {
- err_fprint(ctx, "While generating the instance of a function\n\t");
+ err_fprint(ctx, "While generating this instance of a function or struct:\n\t");
print_location_highlight(err_ctx_file(ctx), *inst);
}
}
diff --git a/eval.c b/eval.c
index 3d72f7b..46d737d 100644
--- a/eval.c
+++ b/eval.c
@@ -741,7 +741,21 @@ static Value *ident_val(Identifier i) {
case IDECL_DECL: {
Declaration *decl = i->decl;
int idx = decl_ident_index(decl, i);
- if (decl->flags & DECL_IS_CONST)
+ if (decl->flags & DECL_IS_PARAM) {
+ if (decl->val_stack) {
+ Value *valp = *(Value **)arr_last(decl->val_stack);
+ if (arr_len(decl->idents) > 1)
+ return &valp->tuple[idx];
+ else
+ return valp;
+ } else {
+ /* struct parameter */
+ if (arr_len(decl->idents) > 1)
+ return &decl->val.tuple[idx];
+ else
+ return &decl->val;
+ }
+ } else if (decl->flags & DECL_IS_CONST)
return decl_val_at_index(decl, idx);
else if (decl->val_stack) {
Value *valp = *(Value **)arr_last(decl->val_stack);
diff --git a/main.c b/main.c
index 1c6d7d8..5addc27 100644
--- a/main.c
+++ b/main.c
@@ -18,11 +18,14 @@
/*
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 .
- make call_arg_param_order work more like parameterized_struct_arg_order
+
+- inferred struct params?
+does this work: fn (a::=3, b::=2)
+ - should either work or give an error: fn()
---
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/parse.c b/parse.c
index 17c9819..206e59a 100644
--- a/parse.c
+++ b/parse.c
@@ -621,6 +621,7 @@ static bool parse_type(Parser *p, Type *type) {
err_print(param->where, "Struct parameters must be constant.");
goto struct_fail;
}
+ param->flags |= DECL_IS_PARAM;
}
}
if (!token_is_kw(t->token, KW_LBRACE)) {
@@ -934,6 +935,7 @@ static bool parse_fn_expr(Parser *p, FnExpr *f) {
success = false;
goto ret;
}
+ param->flags |= DECL_IS_PARAM;
}
}
diff --git a/test.toc b/test.toc
index e115d6b..fcd6119 100644
--- a/test.toc
+++ b/test.toc
@@ -2,10 +2,18 @@
// #include "std/io.toc";
// };
-Thing ::= struct(t::Type=int) {
+
+
+Thing ::= struct(t::=int, u::t=3) {
it : t;
+ that : [u]t;
};
main ::= fn() {
- a: Thing();
+ a: Thing(u = 172, t = u8);
+ b: Thing();
+ c : Thing(i16);
+ d: Thing(u8, 428);
+ e: Thing(t = int, u = 3);
+ f: Thing(i16, 3);
}; \ No newline at end of file
diff --git a/types.c b/types.c
index 28a59c2..1435390 100644
--- a/types.c
+++ b/types.c
@@ -956,8 +956,12 @@ 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) {
+/*
+ *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, Location where) {
+ size_t nargs = arr_len(args);
+
/*
it would be nice if this code and the code for arguments to normal functions
weren't split into two separate functions.
@@ -967,11 +971,16 @@ static bool parameterized_struct_arg_order(StructDef *struc, Argument *args, I16
nparams += arr_len(param->idents);
*order = err_malloc(nparams * sizeof **order);
+
+ if (nargs > nparams) {
+ err_print(args[nparams].where, "Expected at most %lu argument%s to parameterized type, but got %lu.", nparams, plural_suffix(nparams), nargs);
+ return false;
+ }
for (size_t i = 0; i < nparams; ++i)
(*order)[i] = -1;
int p = 0; /* sequential parameter */
+ I16 argno = 0;
-
arr_foreach(args, Argument, arg) {
int param_idx;
if (arg->name) {
@@ -1006,8 +1015,23 @@ static bool parameterized_struct_arg_order(StructDef *struc, Argument *args, I16
free(s);
return false;
}
- (*order)[arg - args] = (I16)param_idx;
+ (*order)[param_idx] = argno;
+ ++argno;
+ }
+
+ p = 0;
+ arr_foreach(struc->params, Declaration, param) {
+ arr_foreach(param->idents, Identifier, ident) {
+ if ((*order)[p] == -1 && !(param->flags & DECL_HAS_EXPR)) {
+ char *s = ident_to_str(*ident);
+ err_print(where, "Parameter #%d (%s) not set in parameterized struct instantiation.", p+1, s);
+ free(s);
+ return false;
+ }
+ ++p;
+ }
}
+
return true;
}
@@ -1468,6 +1492,8 @@ static bool types_expr(Typer *tr, Expression *e) {
if (expr_is_definitely_const(f) || type_is_builtin(&f->type, BUILTIN_TYPE)) {
Value val;
+
+
if (!eval_expr(tr->evalr, f, &val))
return false;
if (type_is_builtin(&f->type, BUILTIN_TYPE)) {
@@ -1481,65 +1507,76 @@ static bool types_expr(Typer *tr, Expression *e) {
info_print(base->struc->where, "struct was declared here.");
return false;
}
+ Copier cop = copier_create(tr->allocr, tr->block);
+ HashTable *table = &base->struc->instances;
+ StructDef struc;
+ copy_struct(&cop, &struc, base->struc);
size_t nparams = 0;
- arr_foreach(base->struc->params, Declaration, param)
+ arr_foreach(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;
- }
- 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)) {
+ if (!parameterized_struct_arg_order(&struc, c->args, &order, e->where)) {
free(order);
return false;
}
Type *arg_types = NULL;
arr_set_len(&arg_types, nparams);
Value *arg_vals = typer_malloc(tr, nparams * sizeof *arg_vals);
-
- 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 (i_copy == 0) {
- /* here we are */
- ith_parameter = param;
- index_in_decl = (int)(ident - param->idents);
- break;
- }
- --i_copy;
+ ErrCtx *err_ctx = tr->err_ctx;
+ size_t p = 0;
+ arr_foreach(struc.params, Declaration, param) {
+ Value param_val = {0};
+ bool is_tuple = arr_len(param->idents) > 1;
+ int ident_idx = 0;
+ /* temporarily add this instance to the stack, while we type the decl, in case you, e.g., pass t = float to struct(t::Type, u::t = "hello") */
+ *(Location *)arr_add(&err_ctx->instance_stack) = e->where;
+ if (!types_decl(tr, param)) {
+ arr_remove_last(&err_ctx->instance_stack);
+ return false;
+ }
+ arr_remove_last(&err_ctx->instance_stack);
+
+ arr_foreach(param->idents, Identifier, ident) {
+ Type *type = decl_type_at_index(param, ident_idx);
+ arg_types[p] = *type;
+ Value ident_val;
+ if (order[p] == -1) {
+ ident_val = *decl_val_at_index(param, ident_idx);
+ } else {
+ Argument *arg = &c->args[order[p]];
+ assert(arg->val.type.flags & TYPE_IS_RESOLVED);
+ assert(type->flags & TYPE_IS_RESOLVED);
+ if (!type_eq(&arg->val.type, type)) {
+ char *expected = type_to_str(type),
+ *got = type_to_str(&arg->val.type);
+ err_print(arg->where, "Wrong struct parameter type. Expected %s, but got %s.", expected, got);
+ return false;
}
+ if (!eval_expr(tr->evalr, &arg->val, &ident_val))
+ 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;
+ if (is_tuple)
+ *(Value *)arr_adda(&param_val.tuple, tr->allocr) = ident_val;
+ else
+ param_val = ident_val;
+ arg_vals[p] = ident_val;
+ ++p;
+ ++ident_idx;
}
- assert(arg_types[i].flags & TYPE_IS_RESOLVED);
+ param->val = param_val;
+ param->flags |= DECL_FOUND_VAL;
}
-
args_val.tuple = arg_vals;
args_type.tuple = arg_types;
args_type.kind = TYPE_TUPLE;
args_type.flags = TYPE_IS_RESOLVED;
Instance *inst = instance_table_adda(tr->allocr, table, args_val, &args_type, &already_exists);
if (!already_exists) {
- Copier cop = copier_create(tr->allocr, tr->block);
- copy_struct(&cop, &inst->struc, base->struc);
+ inst->struc = struc;
size_t i = 0;
arr_foreach(inst->struc.params, Declaration, param) {
param->flags |= DECL_FOUND_VAL;
@@ -1547,8 +1584,8 @@ static bool types_expr(Typer *tr, Expression *e) {
param->val = arg_vals[i];
++i;
} else {
- assert(param->type.kind == TYPE_TUPLE);
- size_t nmembers = arr_len(param->type.tuple);
+
+ size_t nmembers = arr_len(param->idents);
param->val.tuple = typer_malloc(tr, nmembers * sizeof *param->val.tuple);
for (size_t idx = 0; idx < nmembers; ++idx) {
param->val.tuple[idx] = arg_vals[i];
@@ -1560,8 +1597,13 @@ static bool types_expr(Typer *tr, Expression *e) {
Type struct_t = {0};
struct_t.kind = TYPE_STRUCT;
struct_t.struc = &inst->struc;
- if (!type_resolve(tr, &struct_t, e->where)) /* resolve the struct */
+ *(Location *)arr_add(&err_ctx->instance_stack) = e->where;
+ if (!type_resolve(tr, &struct_t, e->where)) /* resolve the struct */ {
+ arr_remove_last(&err_ctx->instance_stack);
return false;
+ }
+ arr_remove_last(&err_ctx->instance_stack);
+
inst->struc.instance_id = table->n;
}
/* expression is actually a type */
diff --git a/types.h b/types.h
index e20f03a..18836bf 100644
--- a/types.h
+++ b/types.h
@@ -782,7 +782,8 @@ enum {
DECL_FOUND_VAL = 0x0040,
DECL_INFER = 0x0080, /* infer the value (e.g. fn(t::Type=, x:t)) */
DECL_EXPORT = 0x0100,
- DECL_FOREIGN = 0x0200
+ DECL_FOREIGN = 0x0200,
+ DECL_IS_PARAM = 0x0400
};
typedef U16 DeclFlags;