summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLeo Tenenbaum <pommicket@gmail.com>2019-10-30 11:19:37 -0400
committerLeo Tenenbaum <pommicket@gmail.com>2019-10-30 11:19:37 -0400
commit4d39d9ac98e5a723c7e8cf96396df28602c9d11c (patch)
treed66ddd469ede000a7c82ed26dff92be0b6fd38e4
parent63236327eadba13784763ffd975870e049ac757a (diff)
fixed some problems with user-defined types
-rw-r--r--eval.c34
-rw-r--r--identifiers.c4
-rw-r--r--parse.c8
-rw-r--r--test.toc23
-rw-r--r--types.c50
5 files changed, 70 insertions, 49 deletions
diff --git a/eval.c b/eval.c
index ad38f1d..a8a3fe0 100644
--- a/eval.c
+++ b/eval.c
@@ -707,6 +707,15 @@ static bool eval_expr(Evaluator *ev, Expression *e, Value *v) {
switch (e->unary.op) {
case UNARY_ADDRESS: {
Expression *o = e->unary.of;
+ if (o->type.kind == TYPE_TYPE) {
+ if (!eval_expr(ev, e->unary.of, &of)) return false;
+ /* "address" of type (pointer to type) */
+ v->type = evalr_calloc(ev, 1, sizeof *v->type); /* TODO: this might be bad in the future; should free this at some point */
+ /* v->type->flags = 0; */
+ v->type->kind = TYPE_PTR;
+ v->type->ptr = of.type;
+ break;
+ }
switch (o->kind) {
case EXPR_IDENT: {
IdentDecl *id = ident_decl(o->ident);
@@ -888,18 +897,23 @@ static bool eval_expr(Evaluator *ev, Expression *e, Value *v) {
if (!eval_expr(ev, &d->expr, &d->val)) return false;
d->flags |= DECL_FLAG_FOUND_VAL;
}
- if (d->type.kind == TYPE_TUPLE) {
- long index = 0;
- arr_foreach(d->idents, Identifier, decl_i) {
- if (*decl_i == e->ident) {
- break;
- }
- index++;
- assert(index < (long)arr_len(d->idents)); /* identifier got its declaration set to here, but it's not here */
+
+ long index = 0;
+ arr_foreach(d->idents, Identifier, decl_i) {
+ if (*decl_i == e->ident) {
+ break;
}
- *v = d->val.tuple[index];
+ index++;
+ assert(index < (long)arr_len(d->idents)); /* identifier got its declaration set to here, but it's not here */
+ }
+ if (e->type.kind == TYPE_TYPE) {
+ /* set v to a user type, not the underlying type */
+ v->type = evalr_malloc(ev, sizeof *v->type); /* TODO: fix this (free eventually) */
+ v->type->flags = 0;
+ v->type->kind = TYPE_USER;
+ v->type->user.name = d->idents[index];
} else {
- *v = d->val;
+ *v = d->type.kind == TYPE_TUPLE ? d->val.tuple[index] : d->val;
}
} else {
char *s = ident_to_str(e->ident);
diff --git a/identifiers.c b/identifiers.c
index 3dc4099..c29f8ce 100644
--- a/identifiers.c
+++ b/identifiers.c
@@ -196,5 +196,7 @@ static Value *ident_decl_val(Identifier i) {
}
static inline Type *ident_typeval(Identifier i) {
- return ident_decl_val(i)->type;
+ Value *val = ident_decl_val(i);
+ if (!val) return NULL;
+ return val->type;
}
diff --git a/parse.c b/parse.c
index b9671ae..aa88283 100644
--- a/parse.c
+++ b/parse.c
@@ -333,6 +333,8 @@ static bool parse_type(Parser *p, Type *type, U16 flags) {
Tokenizer *t = p->tokr;
type->where = t->token->where;
type->flags = 0;
+ U16 could_be_expr = flags & PARSE_TYPE_EXPR;
+ flags &= (U16)~PARSE_TYPE_EXPR; /* don't include this most of the time in children */
switch (t->token->kind) {
case TOKEN_KW:
type->kind = TYPE_BUILTIN;
@@ -426,7 +428,7 @@ static bool parse_type(Parser *p, Type *type, U16 flags) {
t->token++; /* move past ( */
while (1) {
Type *child = parser_arr_add(p, &type->tuple);
- if (!parse_type(p, child, flags)) return false;
+ if (!parse_type(p, child, flags | could_be_expr)) return false; /* if this could be an expression, it could just be (2, 3) */
if (child->kind == TYPE_TUPLE) {
err_print(child->where, "Tuples cannot contain tuples.");
return false;
@@ -449,7 +451,7 @@ static bool parse_type(Parser *p, Type *type, U16 flags) {
type->kind = TYPE_PTR;
type->ptr = parser_malloc(p, sizeof *type->ptr);
t->token++; /* move past & */
- if (!parse_type(p, type->ptr, flags)) return false;
+ if (!parse_type(p, type->ptr, flags | could_be_expr)) return false; /* if this could be an expression, it could just be &foo (where foo is a variable) */
if (type->ptr->kind == TYPE_TUPLE) {
err_print(type->ptr->where, "You cannot have a pointer to a tuple.");
return false;
@@ -461,7 +463,7 @@ static bool parse_type(Parser *p, Type *type, U16 flags) {
}
break;
case TOKEN_IDENT:
- if (!(flags & PARSE_TYPE_EXPR)) {
+ if (!could_be_expr) {
/* user-defined type */
type->kind = TYPE_USER;
type->user.name = t->token->ident;
diff --git a/test.toc b/test.toc
index cb0e6ea..3f05dda 100644
--- a/test.toc
+++ b/test.toc
@@ -3,25 +3,12 @@ puti @= fn(x: int) {
");
};
-Foo @= [3]int;
-
-f @= fn() Foo {
- a : Foo;
- (a as [3]int)[0] = 8;
- (a as [3]int)[1] = 9;
- (a as [3]int)[2] = 10;
- a
-};
-
main @= fn() {
- foo : Foo;
- foo = f();
- puti((foo as [3]int)[0]);
- puti((foo as [3]int)[1]);
- puti((foo as [3]int)[2]);
{
- Foo, Bar @= int, float;
- // Bar @= [3]Foo;
- y: Bar = 0.342 as Bar;
+ Int @= int;
+ Ptr @= &Int;
+ asdf : Int = 1343 as Int;
+ p : Ptr = &asdf as Ptr;
+ // puti(*(p as &Int) as int);
}
};
diff --git a/types.c b/types.c
index 76f5101..5f60845 100644
--- a/types.c
+++ b/types.c
@@ -2,7 +2,7 @@ static bool types_stmt(Typer *tr, Statement *s);
static bool types_decl(Typer *tr, Declaration *d);
static bool types_expr(Typer *tr, Expression *e);
static bool types_block(Typer *tr, Block *b);
-static bool type_resolve(Typer *tr, Type *t);
+static bool type_resolve(Typer *tr, Type *t, Location where);
static inline void *typer_malloc(Typer *tr, size_t bytes) {
return allocr_malloc(&tr->allocr, bytes);
@@ -200,16 +200,18 @@ static bool expr_must_lval(Expression *e) {
return false;
}
-static bool type_of_fn(Typer *tr, FnExpr *f, Type *t) {
+static bool type_of_fn(Typer *tr, Expression *e, Type *t) {
+ assert(e->kind == EXPR_FN);
+ FnExpr *f = &e->fn;
t->kind = TYPE_FN;
t->fn.types = NULL;
Type *ret_type = typer_arr_add(tr, &t->fn.types);
- if (!type_resolve(tr, &f->ret_type))
+ if (!type_resolve(tr, &f->ret_type, e->where))
return false;
*ret_type = f->ret_type;
arr_foreach(f->params, Declaration, decl) {
if (!types_decl(tr, decl)) return false;
- if (!type_resolve(tr, &decl->type))
+ if (!type_resolve(tr, &decl->type, e->where))
return false;
for (size_t i = 0; i < arr_len(decl->idents); i++) {
Type *param_type = typer_arr_add(tr, &t->fn.types);
@@ -281,7 +283,7 @@ static bool type_of_ident(Typer *tr, Location where, Identifier i, Type *t) {
} else {
if ((d->flags & DECL_FLAG_HAS_EXPR) && (d->expr.kind == EXPR_FN)) {
/* allow using a function before declaring it */
- if (!type_of_fn(tr, &d->expr.fn, t)) return false;
+ if (!type_of_fn(tr, &d->expr, t)) return false;
return true;
} else {
if (location_after(d->where, where)) {
@@ -298,7 +300,7 @@ static bool type_of_ident(Typer *tr, Location where, Identifier i, Type *t) {
}
/* fixes the type (replaces [5+3]int with [8]int, etc.) */
-static bool type_resolve(Typer *tr, Type *t) {
+static bool type_resolve(Typer *tr, Type *t, Location where) {
Evaluator *ev = tr->evalr;
if (t->flags & TYPE_FLAG_RESOLVED) return true;
switch (t->kind) {
@@ -333,30 +335,38 @@ static bool type_resolve(Typer *tr, Type *t) {
size = val_to_u64(&val, n_expr->type.builtin);
}
t->arr.n = (UInteger)size;
- if (!type_resolve(tr, t->arr.of))
+ if (!type_resolve(tr, t->arr.of, where))
return false;
} break;
case TYPE_FN:
arr_foreach(t->fn.types, Type, child_type) {
- if (!type_resolve(tr, child_type))
+ if (!type_resolve(tr, child_type, where))
return false;
}
break;
case TYPE_TUPLE:
arr_foreach(t->tuple, Type, child_type) {
- if (!type_resolve(tr, child_type))
+ if (!type_resolve(tr, child_type, where))
return false;
}
break;
case TYPE_PTR:
- if (!type_resolve(tr, t->ptr))
+ if (!type_resolve(tr, t->ptr, where))
return false;
break;
case TYPE_SLICE:
- if (!type_resolve(tr, t->slice))
+ if (!type_resolve(tr, t->slice, where))
return false;
break;
case TYPE_USER:
+ /* just check if it's actually defined */
+ if (!ident_typeval(t->user.name)) {
+ char *s = ident_to_str(t->user.name);
+ err_print(where, "Use of undeclared type %s.", s);
+ free(s);
+ return false;
+ }
+ break;
case TYPE_UNKNOWN:
case TYPE_VOID:
case TYPE_TYPE:
@@ -484,11 +494,11 @@ static bool types_expr(Typer *tr, Expression *e) {
Type prev_ret_type = tr->ret_type;
bool prev_can_ret = tr->can_ret;
FnExpr *f = &e->fn;
- if (!type_of_fn(tr, f, t)) {
+ if (!type_of_fn(tr, e, t)) {
success = false;
goto fn_ret;
}
- bool has_named_ret_vals = e->fn.ret_decls != NULL;
+ bool has_named_ret_vals = f->ret_decls != NULL;
if (has_named_ret_vals) {
/* set return type to void to not allow return values */
tr->ret_type.kind = TYPE_VOID;
@@ -580,13 +590,14 @@ static bool types_expr(Typer *tr, Expression *e) {
CastExpr *c = &e->cast;
if (!types_expr(tr, c->expr))
return false;
- if (!type_resolve(tr, &c->type))
+ if (!type_resolve(tr, &c->type, e->where))
return false;
Status status = type_cast_status(&c->expr->type, &c->type);
if (status != STATUS_NONE) {
char *from = type_to_str(&c->expr->type);
char *to = type_to_str(&c->type);
if (status == STATUS_ERR)
+
err_print(e->where, "Cannot cast from type %s to %s.", from, to);
else
warn_print(e->where, "Casting from type %s to %s.", from, to);
@@ -598,7 +609,7 @@ static bool types_expr(Typer *tr, Expression *e) {
*t = c->type;
} break;
case EXPR_NEW:
- if (!type_resolve(tr, &e->new.type))
+ if (!type_resolve(tr, &e->new.type, e->where))
return false;
if (e->new.n) {
if (!types_expr(tr, e->new.n)) return false;
@@ -861,6 +872,11 @@ static bool types_expr(Typer *tr, Expression *e) {
*t = *of_type;
break;
case UNARY_ADDRESS:
+ if (of_type->kind == TYPE_TYPE) {
+ /* oh it's a type! */
+ t->kind = TYPE_TYPE;
+ break;
+ }
if (!expr_must_lval(of)) {
err_print(e->where, "Cannot take address of non-lvalue."); /* FEATURE: better err */
return false;
@@ -1116,7 +1132,7 @@ static bool types_decl(Typer *tr, Declaration *d) {
if (d->flags & DECL_FLAG_ANNOTATES_TYPE) {
/* type supplied */
assert(d->type.kind != TYPE_VOID); /* there's no way to annotate void */
- if (!type_resolve(tr, &d->type)) {
+ if (!type_resolve(tr, &d->type, d->where)) {
success = false;
goto ret;
}
@@ -1163,7 +1179,7 @@ static bool types_decl(Typer *tr, Declaration *d) {
success = false;
goto ret;
}
- if (!type_resolve(tr, val->type)) {
+ if (!type_resolve(tr, val->type, d->where)) {
success = false;
goto ret;
}