summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--copy.c7
-rw-r--r--eval.c15
-rw-r--r--identifiers.c3
-rw-r--r--main.c7
-rw-r--r--parse.c1
-rwxr-xr-xrunv2
-rw-r--r--test.toc86
-rw-r--r--types.c111
-rw-r--r--types.h7
9 files changed, 133 insertions, 106 deletions
diff --git a/copy.c b/copy.c
index 2ec6949..1fd6219 100644
--- a/copy.c
+++ b/copy.c
@@ -182,7 +182,8 @@ static void copy_expr(Copier *c, Expression *out, Expression *in) {
case EXPR_EACH: {
EachExpr *ein = &in->each;
EachExpr *eout = &out->each;
- copy_type(c, &eout->type, &ein->type);
+ if (ein->flags & EACH_ANNOTATED_TYPE)
+ copy_type(c, &eout->type, &ein->type);
if (ein->flags & EACH_IS_RANGE) {
copy_expr(c, eout->range.from = allocr_malloc(a, sizeof *eout->range.from), ein->range.from);
if (ein->range.to)
@@ -294,7 +295,7 @@ static void copy_block(Copier *c, Block *out, Block *in) {
*out = *in;
size_t nstmts = arr_len(in->stmts);
out->stmts = NULL;
- out->parent = c->block;
+ Block *prev = c->block;
c->block = out;
if (in->ret_expr)
copy_expr(c, out->ret_expr = allocr_malloc(c->allocr, sizeof *out->ret_expr), in->ret_expr);
@@ -303,5 +304,5 @@ static void copy_block(Copier *c, Block *out, Block *in) {
for (size_t i = 0; i < nstmts; i++) {
copy_stmt(c, &out->stmts[i], &in->stmts[i]);
}
- c->block = out->parent;
+ c->block = prev;
}
diff --git a/eval.c b/eval.c
index 609e6ef..9e3db26 100644
--- a/eval.c
+++ b/eval.c
@@ -1,5 +1,5 @@
static bool types_block(Typer *tr, Block *b);
-static bool types_decl(Typer *tr, Declaration *d);
+static bool types_decl(Typer *tr, Declaration *d, TypesDeclFlags flags);
static bool type_resolve(Typer *tr, Type *t, Location where);
static size_t compiler_sizeof(Type *t);
static bool eval_block(Evaluator *ev, Block *b, Type *t, Value *v);
@@ -332,9 +332,10 @@ static void fprint_val_ptr(FILE *f, void *p, Type *t) {
}
fprintf(f, "]");
break;
- case TYPE_EXPR: break;
+ case TYPE_EXPR:
+ assert(0);
+ break;
}
- assert(0);
}
static void fprint_val(FILE *f, Value v, Type *t) {
@@ -1317,18 +1318,14 @@ static bool eval_expr(Evaluator *ev, Expression *e, Value *v) {
Declaration *d = NULL;
if (is_decl) {
d = idecl->decl;
- if (!types_decl(ev->typer, d)) return false;
+ if (!types_decl(ev->typer, d, 0)) return false;
assert(d->type.flags & TYPE_IS_RESOLVED);
}
if (idecl->flags & IDECL_HAS_VAL) {
*v = idecl->val;
} else if (is_decl && (d->flags & DECL_IS_CONST)) {
if (!(d->flags & DECL_FOUND_VAL)) {
- if (!(d->flags & DECL_HAS_EXPR)){
- print_location(d->where);
- abort();
- assert(d->flags & DECL_HAS_EXPR); /* KEEP */
- }
+ assert(d->flags & DECL_HAS_EXPR); /* KEEP */
if (!eval_expr(ev, &d->expr, &d->val)) return false;
d->flags |= DECL_FOUND_VAL;
}
diff --git a/identifiers.c b/identifiers.c
index b7f5e06..7aa6ee8 100644
--- a/identifiers.c
+++ b/identifiers.c
@@ -144,12 +144,13 @@ static char *ident_to_str(Identifier i) {
return str;
}
-static void ident_add_decl(Identifier i, struct Declaration *d, struct Block *b) {
+static IdentDecl *ident_add_decl(Identifier i, struct Declaration *d, struct Block *b) {
IdentDecl *id_decl = arr_add(&i->decls);
id_decl->decl = d;
id_decl->scope = b;
id_decl->flags = 0;
id_decl->kind = IDECL_DECL;
+ return id_decl;
}
static IdentDecl *ident_decl(Identifier i) {
diff --git a/main.c b/main.c
index e98c1be..bfb3b50 100644
--- a/main.c
+++ b/main.c
@@ -1,9 +1,13 @@
/*
TODO:
test ArrInt @= Arr(int);
-new version of copy_val for copying types
+make sure fn(t @ Type, x : t) t works
+check fn(x @ int, y := x)
+new version of copy_val for copying types??
there are probably places where we enter a function and never exit (in typing?) if there's an error
+switch struct."field" to struct["field"]
+
packages
X @= newtype(int); or something
don't allow while {3; 5} (once break is added)
@@ -19,6 +23,7 @@ allow omission of trailing ; in foo @= fn() {}?
#include "toc.c"
+
int main(int argc, char **argv) {
#ifdef TOC_DEBUG
test_all();
diff --git a/parse.c b/parse.c
index 299e54d..0a1b5a9 100644
--- a/parse.c
+++ b/parse.c
@@ -770,7 +770,6 @@ static bool parse_block(Parser *p, Block *b) {
b->flags = 0;
Tokenizer *t = p->tokr;
Block *prev_block = p->block;
- b->parent = prev_block;
p->block = b;
if (!token_is_kw(t->token, KW_LBRACE)) {
tokr_err(t, "Expected '{' to open block.");
diff --git a/runv b/runv
index 08a52f8..53a72c3 100755
--- a/runv
+++ b/runv
@@ -12,7 +12,7 @@ fi
valgrind $FLAGS --track-origins=yes --error-exitcode=1 --malloc-fill=0xcd --free-fill=0xef --num-callers=100 ./toc $tocf || exit 1
if [ "$1" = "c" ]; then
- gcc out.c && ./a.out
+ gcc out.c -g && ./a.out
elif [ "$1" = "pc" ]; then
cat out.c
fi
diff --git a/test.toc b/test.toc
index e8f19ce..43db0c9 100644
--- a/test.toc
+++ b/test.toc
@@ -1,51 +1,53 @@
-// // puti @= fn(x: int) {
-// // #C("printf(\"%ld\\n\", (long)x);
-// // ");
-// // };
-// // putf @= fn(x: float) {
-// // #C("printf(\"%f\\n\", (double)x);
-// // ");
-// // };
-
-// Arr @= fn (t @ Type) Type {
-// struct {
-// data : t;
-// // len, cap : u64;
-// }
+puti @= fn(x: int) {
+ #C("printf(\"%ld\\n\", (long)x);
+");
+};
+// putf @= fn(x: float) {
+// #C("printf(\"%f\\n\", (double)x);
+// ");
// };
-// // todo: test that t @ type doesn't cause problems
-// arr_add @= fn(t @ Type, a : &Arr(t)) {
-// // if a.len >= a.cap {
-// // a.cap = a.cap * 2 + 2;
-// // new_data := new(t, a.cap);
-// // each i := 0..a.len {
-// // new_data[i] = a.data[i];
-// // }
-// // a.data = new_data;
-// // }
-// // a.data[a.len] = x;
-// // a.len += 1;
-// };
+Arr @= fn (t @ Type) Type {
+ struct {
+ data : []t;
+ len, cap : int;
+ }
+};
+// todo: test that t @ type doesn't cause problems
+arr_add @= fn(t @ Type, a : &Arr(t), x : t) {
+ if a.len >= a.cap {
+ a.cap = a.cap * 2 + 2;
+ new_data := new(t, a.cap);
+ each i := 0..a.len-1 {
+ new_data[i] = a.data[i];
+ }
+ a.data = new_data;
+ }
+ a.data[a.len] = x;
+ a.len += 1;
+};
-// main @= fn() {
-// // arr : Arr(int);
-// // // arr_add(int, &arr, 5);
-// // // arr_add(int, &arr, 10);
-// // // arr_add(int, &arr, 20);
-// // // each i := 0..arr.len - 1 {
-// // // puti(arr.data[i]);
-// // // }
-// };
-// // t @= fn(x @ Type) Type { struct { t: x; } };
-// // // pass the wrong thing to t, and the error is in the wrong place
+main @= fn() {
+ arr : Arr(int);
+ arr_add(int, &arr, 5);
+ arr_add(int, &arr, 10);
+ arr_add(int, &arr, 20);
+ each i := 0..arr.len - 1 {
+ puti(arr.data[i]);
+ }
+};
-// // f @= fn(x: t(int)) {};
+// t @= fn(x @ Type) Type { struct { t: x; } };
+// // pass the wrong thing to t, and the error is in the wrong place
-f @= fn(t @ Type, x : t) {
-};
+// f @= fn(x: t(int)) {};
-main @= fn() { f(int, 3); }; \ No newline at end of file
+// f @= fn(t @ Type, x : t) {
+// };
+
+// main @= fn() {
+// f(int,3);
+// }; \ No newline at end of file
diff --git a/types.c b/types.c
index 835570a..253e0a4 100644
--- a/types.c
+++ b/types.c
@@ -1,5 +1,4 @@
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, Location where);
@@ -184,7 +183,8 @@ static bool expr_must_lval(Expression *e) {
}
enum {
- TYPE_OF_FN_NO_COPY_EVEN_IF_CONST = 0x01,
+ /* is f an instance? (changes behaviour a bit) */
+ TYPE_OF_FN_IS_INSTANCE = 0x01
};
static bool type_of_fn(Typer *tr, FnExpr *f, Location where, Type *t, U16 flags) {
@@ -198,7 +198,7 @@ static bool type_of_fn(Typer *tr, FnExpr *f, Location where, Type *t, U16 flags)
FnExpr fn_copy;
- if (!(flags & TYPE_OF_FN_NO_COPY_EVEN_IF_CONST) && fn_has_any_const_params(f)) {
+ if (!(flags & TYPE_OF_FN_IS_INSTANCE) && fn_has_any_const_params(f)) {
Copier cop = copier_create(tr->allocr, tr->block);
copy_fn_expr(&cop, &fn_copy, f, false);
f = &fn_copy;
@@ -214,8 +214,11 @@ static bool type_of_fn(Typer *tr, FnExpr *f, Location where, Type *t, U16 flags)
entered_fn = true;
for (param_idx = 0; param_idx < nparams; param_idx++) {
Declaration *param = &f->params[param_idx];
- print_location(param->where);
- if (!types_decl(tr, param)) {
+ U16 types_decl_flags = 0;
+ if (!(flags & TYPE_OF_FN_IS_INSTANCE) && fn_has_any_const_params(f)) {
+ types_decl_flags |= TYPES_DECL_DONT_RESOLVE;
+ }
+ if (!types_decl(tr, param, types_decl_flags)) {
success = false;
goto ret;
}
@@ -225,10 +228,6 @@ static bool type_of_fn(Typer *tr, FnExpr *f, Location where, Type *t, U16 flags)
goto ret;
}
- if (!type_resolve(tr, &param->type, where)) {
- success = false;
- goto ret;
- }
U32 is_at_all_const = param->flags & (DECL_IS_CONST | DECL_SEMI_CONST);
if (is_at_all_const) {
if (!t->fn.constness) {
@@ -278,7 +277,7 @@ static bool type_of_fn(Typer *tr, FnExpr *f, Location where, Type *t, U16 flags)
if (f->ret_decls && f->ret_type.kind == TYPE_VOID /* haven't found return type yet */) {
/* find return type */
arr_foreach(f->ret_decls, Declaration, d) {
- if (!types_decl(tr, d)) {
+ if (!types_decl(tr, d, 0)) {
success = false;
goto ret;
}
@@ -305,7 +304,7 @@ static bool type_of_fn(Typer *tr, FnExpr *f, Location where, Type *t, U16 flags)
arr_foreach(f->ret_decls, Declaration, decl) {
- if (!types_decl(tr, decl)) {
+ if (!types_decl(tr, decl, 0)) {
success = false;
goto ret;
}
@@ -341,13 +340,15 @@ static bool type_of_ident(Typer *tr, Location where, Identifier i, Type *t) {
case IDECL_DECL: {
Declaration *d = decl->decl;
bool captured = false;
- if (decl->scope != NULL)
- for (Block *block = tr->block; block && block != decl->scope; block = block->parent) {
- if (block->flags & BLOCK_IS_FN) {
+ if (decl->scope != NULL) {
+ /* go back through scopes */
+ for (Block **block = arr_last(tr->blocks); *block && *block != decl->scope; block--) {
+ if ((*block)->flags & BLOCK_IS_FN) {
captured = true;
break;
}
}
+ }
if (captured && !(d->flags & DECL_IS_CONST)) {
err_print(where, "Variables cannot be captured into inner functions (but constants can).");
return false;
@@ -387,7 +388,7 @@ static bool type_of_ident(Typer *tr, Location where, Identifier i, Type *t) {
free(s);
} else {
/* let's type the declaration, and redo this (for evaling future functions) */
- if (!types_decl(tr, d)) return false;
+ if (!types_decl(tr, d, 0)) return false;
return type_of_ident(tr, where, i, t);
}
return false;
@@ -511,6 +512,8 @@ static bool type_resolve(Typer *tr, Type *t, Location where) {
return true;
}
+
+
static bool type_can_be_truthy(Type *t) {
assert(t->flags & TYPE_IS_RESOLVED);
switch (t->kind) {
@@ -1171,34 +1174,22 @@ static bool types_expr(Typer *tr, Expression *e) {
U64 *which_are_const = &which_are_const_val->u64;
*which_are_const = 0;
int semi_const_index = 0;
- /* keep track of the declaration so we can add values */
+ /* keep track of the declaration */
Declaration *param_decl = fn->params;
size_t ident_idx = 0;
for (size_t i = 0; i < arr_len(fn_type->types)-1; i++) {
bool should_be_evald = arg_is_const(&new_args[i], fn_type->constness[i]);
if (should_be_evald) {
Value *arg_val = typer_arr_add(tr, &table_index.tuple);
- printf("Evaluating expression: ");
- print_location(new_args[i].where);
-
- if (!eval_expr(tr->evalr, &new_args[i], arg_val)) {
+ if (!eval_expr(tr->evalr, &new_args[i], arg_val)) {
if (tr->evalr->enabled) {
info_print(new_args[i].where, "(error occured while trying to evaluate compile-time argument, argument #%lu)", 1+(unsigned long)i);
}
return false;
}
-
- Type *type = arr_add(&table_index_type.tuple);
- *type = fn_type->types[i+1];
- /* we need to check the type here so copy_val doesn't mess up */
- Type *expected = type;
- Type *got = &new_args[i].type;
- if (!type_eq(type, &new_args[i].type)) {
- char *estr = type_to_str(expected);
- char *gstr = type_to_str(got);
- err_print(new_args[i].where, "Expected type %s as %lu%s argument to function, but got %s.", estr, 1+(unsigned long)i, ordinals(1+i), gstr);
- return false;
- }
+
+ Type *type = &new_args[i].type;
+ *(Type *)arr_add(&table_index_type.tuple) = *type;
new_args[i].kind = EXPR_VAL;
new_args[i].flags = EXPR_FOUND_TYPE;
@@ -1231,17 +1222,21 @@ static bool types_expr(Typer *tr, Expression *e) {
if (!instance_already_exists) {
c->instance->fn = fn_copy;
/* type param declarations, etc */
- if (!type_of_fn(tr, &c->instance->fn, e->where, &f->type, TYPE_OF_FN_NO_COPY_EVEN_IF_CONST))
+ if (!type_of_fn(tr, &c->instance->fn, e->where, &f->type, TYPE_OF_FN_IS_INSTANCE))
return false;
/* fix parameter and return types (they were kind of problematic before, because we didn't know about the instance) */
- ret_type = f->type.fn.types;
- param_types = ret_type + 1;
c->instance->c.id = original_fn->instances.n; /* let's help cgen out and assign an ID to this */
/* type this instance */
- if (!types_fn(tr, fn, &f->type, e->where, c->instance))
+ if (!types_fn(tr, fn = &c->instance->fn, &f->type, e->where, c->instance))
return false;
+ c->instance->fn_type = &f->type;
arr_clear(&table_index_type.tuple);
+ } else {
+ fn = &c->instance->fn;
+ f->type = *c->instance->fn_type;
}
+ ret_type = f->type.fn.types;
+ param_types = ret_type + 1;
}
/* check types of arguments */
@@ -1668,18 +1663,31 @@ static bool types_expr(Typer *tr, Expression *e) {
return true;
}
+static bool typer_block_enter(Typer *tr, Block *b) {
+ tr->block = b;
+ *(Block **)arr_adda(&tr->blocks, tr->allocr) = b;
+ if (!block_enter(b, b->stmts, SCOPE_CHECK_REDECL)) return false;
+ return true;
+}
+
+static void typer_block_exit(Typer *tr) {
+ Block *b = tr->block;
+ block_exit(b, b->stmts);
+ arr_remove_last(&tr->blocks);
+ tr->block = *(Block **)arr_last(tr->blocks);
+}
+
static bool types_block(Typer *tr, Block *b) {
if (b->flags & BLOCK_FOUND_TYPES)
return true;
bool success = true;
- Block *prev_block = tr->block;
- tr->block = b;
- if (!block_enter(b, b->stmts, SCOPE_CHECK_REDECL)) return false;
+ if (!typer_block_enter(tr, b))
+ return false;
b->ret_expr = NULL;
arr_foreach(b->stmts, Statement, s) {
if (!types_stmt(tr, s))
success = false;
- if (s->kind == STMT_EXPR && (s->flags & STMT_EXPR_NO_SEMICOLON)) {
+ else if (s->kind == STMT_EXPR && (s->flags & STMT_EXPR_NO_SEMICOLON)) {
/* not voided */
Expression *e = &s->expr;
if (e->type.kind == TYPE_VOID) {
@@ -1688,24 +1696,27 @@ static bool types_block(Typer *tr, Block *b) {
|| e->kind == EXPR_WHILE
|| e->kind == EXPR_EACH)) {
err_print(e->where, "void expression must be followed by ;");
+ success = false;
+ goto ret;
}
} else {
if (s != (Statement *)arr_last(b->stmts)) {
err_print(e->where, "Return value must be the last statement in a block.");
- return false;
+ success = false;
+ goto ret;
}
b->ret_expr = e;
arr_remove_last(&b->stmts);
}
}
}
- block_exit(b, b->stmts);
- tr->block = prev_block;
+ ret:
+ typer_block_exit(tr);
b->flags |= BLOCK_FOUND_TYPES;
return success;
}
-static bool types_decl(Typer *tr, Declaration *d) {
+static bool types_decl(Typer *tr, Declaration *d, TypesDeclFlags flags) {
bool success = true;
if (d->flags & DECL_FOUND_TYPE) return true;
Declaration **dptr = typer_arr_add(tr, &tr->in_decls);
@@ -1713,7 +1724,12 @@ static bool types_decl(Typer *tr, Declaration *d) {
if (d->flags & DECL_ANNOTATES_TYPE) {
/* type supplied */
assert(d->type.kind != TYPE_VOID); /* there's no way to annotate void */
- if (!type_resolve(tr, &d->type, d->where)) {
+ /*
+ if it's a parameter, only partially resolve the type, so that,
+ for example, fn (x @ Type, y : x) works
+ */
+ if (!(flags & TYPES_DECL_DONT_RESOLVE)
+ && !type_resolve(tr, &d->type, d->where)) {
success = false;
goto ret;
}
@@ -1816,7 +1832,7 @@ static bool types_stmt(Typer *tr, Statement *s) {
}
break;
case STMT_DECL:
- if (!types_decl(tr, &s->decl))
+ if (!types_decl(tr, &s->decl, 0))
return false;
break;
case STMT_RET:
@@ -1855,12 +1871,13 @@ static bool types_stmt(Typer *tr, Statement *s) {
static void typer_create(Typer *tr, Evaluator *ev, Allocator *allocr) {
tr->block = NULL;
+ tr->blocks = NULL;
tr->fn = NULL;
tr->evalr = ev;
tr->in_decls = NULL;
tr->in_expr_decls = NULL;
tr->allocr = allocr;
-
+ *(Block **)arr_adda(&tr->blocks, allocr) = NULL;
}
static bool types_file(Typer *tr, ParsedFile *f) {
diff --git a/types.h b/types.h
index 01b2fa0..b4dba53 100644
--- a/types.h
+++ b/types.h
@@ -388,7 +388,6 @@ typedef struct Block {
Location start;
Location end;
struct Statement *stmts;
- struct Block *parent;
struct Expression *ret_expr; /* the return expression of this block, e.g. {foo(); 3} => 3 NULL for no expression. */
} Block;
@@ -529,6 +528,7 @@ typedef struct FnExpr {
typedef struct Instance {
Value val; /* key into hash table */
FnExpr fn; /* the typed function */
+ Type *fn_type; /* type of fn */
struct {
U64 id;
} c;
@@ -701,6 +701,7 @@ typedef struct Typer {
Expression **in_expr_decls; /* an array of expressions whose declarations (e.g. each **x := foo**) we are currently inside */
Declaration **in_decls; /* array of declarations we are currently inside */
Block *block;
+ Block **blocks; /* dyn array of all the block's we're in ([0] = NULL for global scope) */
FnExpr *fn; /* the function we're currently parsing. */
} Typer;
@@ -717,3 +718,7 @@ typedef struct CGenerator {
Identifier main_ident;
Identifiers *idents;
} CGenerator;
+
+typedef enum {
+ TYPES_DECL_DONT_RESOLVE = 0x01 /* don't resolve the annotated type (used for parameters). */
+} TypesDeclFlags;