summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWormHeamer2025-08-10 02:46:50 -0400
committerWormHeamer2025-08-10 02:46:50 -0400
commitd4c768a481b923d407201c25d3d750040b6ccd44 (patch)
tree16dd697288846b8effd1f18a3e23187654710e02
parent1c4efc8009292b6f8d6079f87645e8eb65e85f3e (diff)
add type-specifiers to let, N_UNINIT for uninitialized values
-rw-r--r--ir.c20
-rw-r--r--ir.h4
-rw-r--r--main.c73
-rw-r--r--peephole.c5
-rw-r--r--test.lang3
5 files changed, 68 insertions, 37 deletions
diff --git a/ir.c b/ir.c
index 6e91faa..125e882 100644
--- a/ir.c
+++ b/ir.c
@@ -122,7 +122,6 @@ Node *node_new_empty(Proc *p, NodeType t) {
return n;
}
-int type_check(Node *);
Node *node_newv(Proc *p, NodeType t, Node *ctrl, ...) {
Node *node = node_new_empty(p, t);
va_list ap;
@@ -317,7 +316,13 @@ void type_err(Node *n, Lexer *l) {
lex_error_at(l, n->src_pos, LE_ERROR, str_fmt(&l->arena, "type error %s (%S)", node_type_name(n->op), s));
}
-int type_check(Node *n) {
+void type_expected(Type *want, Node *n, Lexer *l) {
+ if (type_base_eql(want, &n->type)) return;
+ lex_error_at(l, n->src_pos, LE_ERROR, str_fmt(&l->arena, "type error: expected %S, but got %S",
+ type_desc(want, &l->arena), type_desc(&n->type, &l->arena)));
+}
+
+static int type_ok(Node *n) {
switch (n->op) {
case N_PHI:
n->type = (Type) { .lvl = T_TOP, .t = IN(n, 1)->type.t };
@@ -355,3 +360,14 @@ int type_check(Node *n) {
return 1;
}
}
+
+void type_check(Node *n, Lexer *l) {
+ for (int i = 0; i < n->in.len; i++) {
+ if (IN(n,i) && IN(n,i)->op == N_UNINIT) {
+ lex_error_at(l, n->src_pos, LE_ERROR,
+ str_fmt(&l->arena, "attempt to use uninitialized %S value",
+ type_desc(&IN(n,i)->type, &l->arena)));
+ }
+ }
+ if (!type_ok(n)) type_err(n, l);
+}
diff --git a/ir.h b/ir.h
index ca3e8b4..0ae71c8 100644
--- a/ir.h
+++ b/ir.h
@@ -43,9 +43,10 @@ struct Node;
int type_eql(Type *a, Type *b);
int type_base_eql(Type *a, Type *b);
int value_eql(Value *a, Value *b);
-int type_check(struct Node *n);
+void type_check(struct Node *n, Lexer *l);
Str type_desc(Type *t, Arena *arena);
void type_err(struct Node *n, Lexer *l);
+void type_expected(Type *want, struct Node *n, Lexer *l);
/* nodes */
@@ -61,6 +62,7 @@ void type_err(struct Node *n, Lexer *l);
X(RETURN, "return")\
X(KEEPALIVE, "keepalive")\
X(LIT, "literal")\
+ X(UNINIT, "uninitialized value")\
X(OP_ADD, "add")\
X(OP_SUB, "sub")\
X(OP_MUL, "mul")\
diff --git a/main.c b/main.c
index 9fba001..ae19e7a 100644
--- a/main.c
+++ b/main.c
@@ -75,14 +75,50 @@ void parse_return(Lexer *l, Proc *p) {
ctrl(p, NULL);
}
+Type parse_type(Lexer *l, Proc *proc) {
+ (void)proc;
+ Type t = { .lvl = T_BOT };
+ if (l->tok == TOK_DEREF) {
+ lex_next(l);
+ t.t = T_PTR;
+ t.next = new(&proc->arena, Type);
+ *t.next = parse_type(l, proc);
+ return t;
+ }
+ lex_expected(l, TM_IDENT);
+ if (l->tok == TOK_IDENT) {
+ if (str_eql(l->ident, S("i64"))) {
+ t.t = T_INT;
+ } else if (str_eql(l->ident, S("bool"))) {
+ t.t = T_BOOL;
+ } else {
+ lex_error(l, LE_ERROR, S("unknown type"));
+ }
+ }
+ lex_next(l);
+ return t;
+}
+
void parse_let(Lexer *l, Proc *p) {
recurse:
lex_expect(l, TM_IDENT);
Str name = l->ident;
LexSpan pos = l->pos;
- lex_expect(l, TM_EQL);
lex_next(l);
- Node *rhs = parse_expr(l, p);
+ Node *rhs = NULL;
+ Type t = { .t = T_NONE };
+ if (l->tok != TOK_EQL) {
+ t = parse_type(l, p);
+ if (l->tok != TOK_EQL) {
+ rhs = node_new(p, N_UNINIT, p->start);
+ rhs->type = t;
+ }
+ }
+ if (l->tok == TOK_EQL) {
+ lex_next(l);
+ rhs = parse_expr(l, p);
+ if (t.t != T_NONE) type_expected(&t, rhs, l);
+ }
NameBinding *b = scope_bind(&p->scope, name, rhs, pos, p);
if (b) {
lex_error_at(l, pos, LE_WARN, S("shadowing previous declaration"));
@@ -125,6 +161,11 @@ void parse_assign(Lexer *l, Proc *p) {
type_desc(&e->type, &p->arena),
type_desc(&b->node->type, &p->arena)));
}
+ if (e->op == N_UNINIT) {
+ lex_error_at(l, e->src_pos, LE_ERROR,
+ str_fmt(&p->arena, "assigning from uninitialized %S value",
+ type_desc(&e->type, &p->arena)));
+ }
scope_update(b, e, p);
}
@@ -317,29 +358,6 @@ void parse_stmt(Lexer *l, Proc *p) {
}
}
-Type parse_type(Lexer *l, Proc *proc) {
- (void)proc;
- Type t = { .lvl = T_BOT };
- if (l->tok == TOK_DEREF) {
- lex_next(l);
- t.t = T_PTR;
- t.next = new(&proc->arena, Type);
- *t.next = parse_type(l, proc);
- return t;
- }
- if (l->tok == TOK_IDENT) {
- if (str_eql(l->ident, S("i64"))) {
- t.t = T_INT;
- } else if (str_eql(l->ident, S("bool"))) {
- t.t = T_BOOL;
- }
- } else {
- lex_error(l, LE_ERROR, S("unknown type"));
- }
- lex_next(l);
- return t;
-}
-
void parse_args_list(Lexer *l, Proc *proc) {
Node *start = proc->start;
int i = 0;
@@ -390,10 +408,7 @@ void proc_opt_fwd(Proc *p, Lexer *l, Node *n) {
switch (n->op) {
case N_START:
for (int i = 0; i < n->out.len; i++) {
- if (!(NMASK(n->out.data[i]->op) & (NM_LIT | NM_PROJ))) {
- proc_opt_fwd(p, l, n->out.data[i]);
- break;
- }
+ proc_opt_fwd(p, l, n->out.data[i]);
}
break;
case N_IF_ELSE:
diff --git a/peephole.c b/peephole.c
index 58a7612..b8118db 100644
--- a/peephole.c
+++ b/peephole.c
@@ -250,10 +250,7 @@ static inline int is_zero(Node *n) {
/* needs lexer for error reporting */
Node *node_idealize(Node *n, Proc *p, Lexer *l) {
- if (!type_check(n)) {
- type_err(n, l);
- }
-
+ type_check(n, l);
if (no_opt) return NULL;
/* try to compute a literal value */
diff --git a/test.lang b/test.lang
index 24a931d..2de85c1 100644
--- a/test.lang
+++ b/test.lang
@@ -1,8 +1,9 @@
func main(a, b i64) i64 {
+ let x i64, y bool
if a = b {
let t = a
a := b
b := t
}
- return a + b
+ return a
}