diff options
author | Thomas Voss <mail@thomasvoss.com> | 2024-06-18 16:02:30 +0200 |
---|---|---|
committer | Thomas Voss <mail@thomasvoss.com> | 2024-06-18 16:02:30 +0200 |
commit | 7c84f809ae7ef73d460bcd1daf3620540bf1380e (patch) | |
tree | 63462f06ef20625870dd2de540328f69b93e805c | |
parent | e8dcd5bbc2c92dd82c6f7c405ab4f95956b35dec (diff) |
Some more typechecking for functions
-rw-r--r-- | src/analyzer.c | 126 | ||||
-rw-r--r-- | src/codegen.c | 8 |
2 files changed, 77 insertions, 57 deletions
diff --git a/src/analyzer.c b/src/analyzer.c index 43b1f61..3bce1af 100644 --- a/src/analyzer.c +++ b/src/analyzer.c @@ -25,28 +25,34 @@ struct environs { size_t len, cap; }; +struct typechkctx { + struct type fnret; +}; + static struct environ *create_environments(struct ast, struct lexemes, struct environs *, idx_t_, idx_t_, arena *) __attribute__((returns_nonnull, nonnull)); -static void typecheckast(struct environs, struct type *, struct ast, - struct lexemes) + +static void typechkast(struct environs, struct type *, struct ast, + struct lexemes) __attribute__((nonnull)); -static idx_t_ typecheckdecl(struct environs, struct type *, struct ast, - struct lexemes, idx_t_, idx_t_) +static idx_t_ typechkdecl(struct typechkctx, struct environs, struct type *, + struct ast, struct lexemes, idx_t_, idx_t_) __attribute__((nonnull)); -static idx_t_ typecheckstmt(struct environs, struct type *, struct ast, - struct lexemes, idx_t_, idx_t_) +static idx_t_ typechkstmt(struct typechkctx, struct environs, struct type *, + struct ast, struct lexemes, idx_t_, idx_t_) __attribute__((nonnull)); -static idx_t_ typecheckexpr(struct environs, struct type *, struct ast, - struct lexemes, idx_t_, idx_t_) +static idx_t_ typechkexpr(struct typechkctx, struct environs, struct type *, + struct ast, struct lexemes, idx_t_, idx_t_) __attribute__((nonnull)); -static idx_t_ typecheckfn(struct environs, struct type *, struct ast, - struct lexemes, idx_t_, idx_t_) +static idx_t_ typechkfn(struct typechkctx, struct environs, struct type *, + struct ast, struct lexemes, idx_t_, idx_t_) __attribute__((nonnull)); -static idx_t_ typecheckblk(struct environs, struct type *, struct ast, - struct lexemes, idx_t_, idx_t_) +static idx_t_ typechkblk(struct typechkctx, struct environs, struct type *, + struct ast, struct lexemes, idx_t_, idx_t_) __attribute__((nonnull)); + static const struct type *typegrab(struct ast, struct lexemes, idx_t_) __attribute__((returns_nonnull)); static bool typecompat(struct type, struct type); @@ -64,7 +70,7 @@ analyzeast(struct ast ast, struct lexemes toks) memset(types, 0, ast.len * sizeof(*types)); create_environments(ast, toks, &evs, 0, ast.len - 1, &a); - typecheckast(evs, types, ast, toks); + typechkast(evs, types, ast, toks); arena_free(&a); free(evs.buf); @@ -130,17 +136,14 @@ create_environments(struct ast ast, struct lexemes toks, struct environs *evs, } void -typecheckast(struct environs evs, struct type *types, struct ast ast, - struct lexemes toks) +typechkast(struct environs evs, struct type *types, struct ast ast, + struct lexemes toks) { - for (idx_t_ i = 0; likely(i < ast.len);) { + struct typechkctx ctx = {0}; + for (idx_t_ i = 0; likely(i < ast.len); + i = typechkdecl(ctx, evs, types, ast, toks, 0, i)) + { assert(ast.kinds[i] == ASTDECL || ast.kinds[i] == ASTCDECL); - if (types[i].kind == TYPE_UNSET) - i = typecheckdecl(evs, types, ast, toks, 0, i); - else { - while (++i < ast.len && ast.kinds[i] != ASTDECL && ast.kinds[i] != ASTCDECL) - ; - } } } @@ -155,8 +158,8 @@ typegrab(struct ast ast, struct lexemes toks, idx_t_ i) } idx_t_ -typecheckdecl(struct environs evs, struct type *types, struct ast ast, - struct lexemes toks, idx_t_ evi, idx_t_ i) +typechkdecl(struct typechkctx ctx, struct environs evs, struct type *types, + struct ast ast, struct lexemes toks, idx_t_ evi, idx_t_ i) { types[i].kind = TYPE_CHECKING; @@ -168,7 +171,7 @@ typecheckdecl(struct environs evs, struct type *types, struct ast ast, if (p.lhs != AST_EMPTY) ltype = *typegrab(ast, toks, p.lhs); - idx_t_ ni = typecheckexpr(evs, types, ast, toks, evi, p.rhs); + idx_t_ ni = typechkexpr(ctx, evs, types, ast, toks, evi, p.rhs); rtype = types[p.rhs]; if (ltype.kind == TYPE_UNSET) @@ -181,16 +184,25 @@ typecheckdecl(struct environs evs, struct type *types, struct ast ast, } idx_t_ -typecheckstmt(struct environs evs, struct type *types, struct ast ast, - struct lexemes toks, idx_t_ evi, idx_t_ i) +typechkstmt(struct typechkctx ctx, struct environs evs, struct type *types, + struct ast ast, struct lexemes toks, idx_t_ evi, idx_t_ i) { switch (ast.kinds[i]) { case ASTDECL: case ASTCDECL: - return typecheckdecl(evs, types, ast, toks, evi, i); + return typechkdecl(ctx, evs, types, ast, toks, evi, i); case ASTRET: { - idx_t_ ni = typecheckexpr(evs, types, ast, toks, evi, ast.kids[i].rhs); + idx_t_ expr = ast.kids[i].rhs; + if (expr == AST_EMPTY) { + if (ctx.fnret.kind != TYPE_UNSET) + err("analyzer: %s: Type mismatch", __func__); + return i + 1; + } + + idx_t_ ni = typechkexpr(ctx, evs, types, ast, toks, evi, ast.kids[i].rhs); types[i] = types[ast.kids[i].rhs]; + if (!typecompat(ctx.fnret, types[i])) + err("analyzer: %s: Type mismatch", __func__); return ni; } } @@ -200,8 +212,8 @@ typecheckstmt(struct environs evs, struct type *types, struct ast ast, } idx_t_ -typecheckexpr(struct environs evs, struct type *types, struct ast ast, - struct lexemes toks, idx_t_ evi, idx_t_ i) +typechkexpr(struct typechkctx ctx, struct environs evs, struct type *types, + struct ast ast, struct lexemes toks, idx_t_ evi, idx_t_ i) { switch (ast.kinds[i]) { case ASTNUMLIT: @@ -220,11 +232,11 @@ typecheckexpr(struct environs evs, struct type *types, struct ast ast, continue; switch (types[j].kind) { case TYPE_UNSET: - typecheckdecl(evs, types, ast, toks, evi, j); + typechkdecl(ctx, evs, types, ast, toks, evi, j); break; case TYPE_CHECKING: - err("analyzer: Circular definition of ā%.*sā", (int)sv2.len, - sv2.p); + err("analyzer: Circular definition of ā%.*sā", (int)sv.len, + sv.p); } types[i] = types[j]; return i + 1; @@ -235,7 +247,7 @@ typecheckexpr(struct environs evs, struct type *types, struct ast ast, } } case ASTFN: - return typecheckfn(evs, types, ast, toks, evi, i); + return typechkfn(ctx, evs, types, ast, toks, evi, i); default: err("analyzer: Unexpected AST kind %u", ast.kinds[i]); __builtin_unreachable(); @@ -243,47 +255,49 @@ typecheckexpr(struct environs evs, struct type *types, struct ast ast, } idx_t_ -typecheckfn(struct environs evs, struct type *types, struct ast ast, - struct lexemes toks, idx_t_ evi, idx_t_ i) +typechkfn(struct typechkctx ctx, struct environs evs, struct type *types, + struct ast ast, struct lexemes toks, idx_t_ evi, idx_t_ i) { struct type t = {.kind = TYPE_FN}; struct pair p = ast.kids[i]; idx_t_ proto = p.lhs; - if (ast.kids[proto].rhs != AST_EMPTY) + if (ast.kids[proto].rhs != AST_EMPTY) { t.ret = typegrab(ast, toks, ast.kids[proto].rhs); + ctx.fnret = *t.ret; + } types[i] = t; - idx_t_ ni = typecheckblk(evs, types, ast, toks, evi, p.rhs); - // if (!typecompat(types[i], types[p.rhs])) - // err("analyzer: Type mismatch"); + idx_t_ ni = typechkblk(ctx, evs, types, ast, toks, evi, p.rhs); return ni; } idx_t_ -typecheckblk(struct environs evs, struct type *types, struct ast ast, - struct lexemes toks, idx_t_ evi, idx_t_ i) +typechkblk(struct typechkctx ctx, struct environs evs, struct type *types, + struct ast ast, struct lexemes toks, idx_t_ evi, idx_t_ i) { struct pair p = ast.kids[i]; for (i = p.lhs; i <= p.rhs;) - i = typecheckstmt(evs, types, ast, toks, evi, i); + i = typechkstmt(ctx, evs, types, ast, toks, evi, i); return i; } bool typecompat(struct type lhs, struct type rhs) { - if (rhs.kind == TYPE_FN) + switch (lhs.kind) { + case TYPE_FN: return lhs.ret == rhs.ret; + case TYPE_NUM: + if (rhs.size == 0) + return true; + return lhs.issigned == rhs.issigned && lhs.size >= rhs.size; + case TYPE_F16: + case TYPE_F32: + case TYPE_F64: + return lhs.size >= rhs.size; + case TYPE_RUNE: + return lhs.kind == rhs.kind; + } - if (lhs.kind == rhs.kind) - return true; - - /* TODO: Need to actually parse it! 256 should not coerce to i8. */ - if (rhs.kind == TYPE_NUM) - return true; - - if (lhs.issigned != rhs.issigned) - return false; - - return lhs.size >= rhs.size; + __builtin_unreachable(); } diff --git a/src/codegen.c b/src/codegen.c index f8a3f32..1a0bb53 100644 --- a/src/codegen.c +++ b/src/codegen.c @@ -66,9 +66,15 @@ codegen(const char *file, struct type *types, struct ast ast, size_t type = ast.kids[proto].rhs; struct strview sv = toks.strs[ast.lexemes[type]]; - /* TODO: Make int 32bit on 32bit platforms */ + /* Very very temporary! */ if (strncmp("int", sv.p, sv.len) == 0) ret = LLVMInt64Type(); + else if (strncmp("i32", sv.p, sv.len) == 0) + ret = LLVMInt32Type(); + else if (strncmp("u32", sv.p, sv.len) == 0) + ret = LLVMInt32Type(); + else if (strncmp("i128", sv.p, sv.len) == 0) + ret = LLVMInt128Type(); else err("codegen: Unknown type: %.*s", (int)sv.len, sv.p); } |