aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Voss <mail@thomasvoss.com> 2024-06-18 16:02:30 +0200
committerThomas Voss <mail@thomasvoss.com> 2024-06-18 16:02:30 +0200
commit7c84f809ae7ef73d460bcd1daf3620540bf1380e (patch)
tree63462f06ef20625870dd2de540328f69b93e805c
parente8dcd5bbc2c92dd82c6f7c405ab4f95956b35dec (diff)
Some more typechecking for functions
-rw-r--r--src/analyzer.c126
-rw-r--r--src/codegen.c8
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);
}