From 46b5ce1b8f52329a18095da9ca4a5ee58345ff92 Mon Sep 17 00:00:00 2001 From: Leo Tenenbaum Date: Thu, 19 Sep 2019 13:26:01 -0400 Subject: added arg type checking --- parse.c | 12 +++++++----- test.toc | 3 ++- types.c | 41 ++++++++++++++++++++++++++++++----------- util/err.c | 9 +++++++++ 4 files changed, 48 insertions(+), 17 deletions(-) diff --git a/parse.c b/parse.c index effe5f7..ad4372c 100644 --- a/parse.c +++ b/parse.c @@ -79,6 +79,12 @@ typedef struct { Array args; /* of Expression */ } DirectExpr; +typedef struct { + struct Expression *fn; + Array args; /* of Expression */ + unsigned long out_var; /* which out variable is used for this call (used by cgen) */ +} CallExpr; + typedef struct Expression { Location where; ExprKind kind; @@ -96,11 +102,7 @@ typedef struct Expression { struct Expression *lhs; struct Expression *rhs; } binary; - struct { - struct Expression *fn; - Array args; /* of Expression */ - unsigned long out_var; /* which out variable is used for this call (used by cgen) */ - } call; + CallExpr call; DirectExpr direct; Identifier ident; struct FnExpr *fn; diff --git a/test.toc b/test.toc index 5c5af41..71b5fce 100644 --- a/test.toc +++ b/test.toc @@ -8,5 +8,6 @@ times2 @= fn(x: int) int { x + x }; main @= fn() { print_int(times2(5)); - foo := fn (x, y, z : float, A:double) {}; + foo := fn (x, y, z,w : float, A:double) {}; + foo(foo,4,5,3,5); }; diff --git a/types.c b/types.c index 9c43c13..f5ca20a 100644 --- a/types.c +++ b/types.c @@ -223,8 +223,9 @@ static bool type_resolve(Type *t) { return true; } -/* NOTE: this does descend into un/binary ops, etc. but NOT into functions */ +/* NOTE: this does descend into un/binary ops, calls, etc. but NOT into any blocks */ static bool type_of_expr(Expression *e, Type *t) { + /* TODO: only get the type of an expr once (flag) */ t->flags = 0; t->kind = TYPE_UNKNOWN; /* default to unknown type (in the case of an error) */ switch (e->kind) { @@ -261,20 +262,44 @@ static bool type_of_expr(Expression *e, Type *t) { if (!type_of_ident(e->where, e->ident, t, false)) return false; } break; case EXPR_CALL: { - Expression *f = e->call.fn; + CallExpr *c = &e->call; + Expression *f = c->fn; if (f->kind == EXPR_IDENT) { /* allow calling a function before declaring it */ if (!type_of_ident(f->where, f->ident, &f->type, true)) return false; } else { if (!type_of_expr(f, &f->type)) return false; } + arr_foreach(&c->args, Expression, arg) { + if (!type_of_expr(arg, &arg->type)) + return false; + } if (f->type.kind != TYPE_FN) { char *type = type_to_str(&f->type); err_print(e->where, "Calling non-function (type %s).", type); return false; } - /* TODO: Make sure args match fn type */ - *t = *(Type*)f->type.fn.types.data; + Type *ret_type = (Type *)f->type.fn.types.data; + Type *param_types = ret_type + 1; + Expression *args = c->args.data; + size_t nparams = f->type.fn.types.len - 1; + if (nparams != c->args.len) { + err_print(e->where, "Expected %lu arguments to function, but got %lu.", (unsigned long)nparams, (unsigned long)c->args.len); + return false; + } + bool ret = true; + for (size_t p = 0; p < nparams; p++) { + Type *expected = ¶m_types[p]; + Type *got = &args[p].type; + if (!type_eq(expected, got)) { + ret = false; + char *estr = type_to_str(expected); + char *gstr = type_to_str(got); + err_print(args[p].where, "Expected type %s as %lu%s argument to function, but got %s.", estr, 1+(unsigned long)p, ordinals(1+p), gstr); + } + } + if (!ret) return false; + *t = *ret_type; break; } case EXPR_DIRECT: @@ -405,6 +430,7 @@ static bool types_block(Block *b) { return ret; } +/* does descend into blocks, unlike type_of_expr. */ static bool types_expr(Expression *e) { Type *t = &e->type; if (!type_of_expr(e, t)) return false; @@ -436,13 +462,6 @@ static bool types_expr(Expression *e) { return false; } } break; - case EXPR_CALL: { - bool ret = true; - arr_foreach(&e->call.args, Expression, arg) { - if (!types_expr(arg)) ret = false; - } - return ret; - } break; default: break; } return true; diff --git a/util/err.c b/util/err.c index 3fe3b53..c5d32b2 100644 --- a/util/err.c +++ b/util/err.c @@ -12,6 +12,15 @@ #define TEXT_IMPORTANT(x) x #endif +static inline const char *ordinals(size_t x) { + switch (x % 10) { + case 1: return "st"; + case 2: return "nd"; + case 3: return "rd"; + default: return "th"; + } +} + typedef uint32_t LineNo; typedef struct { -- cgit v1.2.3