summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLeo Tenenbaum <pommicket@gmail.com>2019-10-21 11:09:07 -0400
committerLeo Tenenbaum <pommicket@gmail.com>2019-10-21 11:09:07 -0400
commit9d1960f4cd0e1a78abfecce4d5bfa4d850955852 (patch)
tree89622e6011aee006e017537d2251be21f8d71f37
parent965d5dee1fe6cd28ad92d7f5007c90b6d7d2ff58 (diff)
compile time recursion
-rw-r--r--arr.c6
-rw-r--r--cgen.c7
-rw-r--r--decls_cgen.c2
-rw-r--r--eval.c21
-rw-r--r--main.c6
-rw-r--r--out.c30
-rw-r--r--scope.c16
-rw-r--r--test.toc36
-rw-r--r--types.c6
9 files changed, 50 insertions, 80 deletions
diff --git a/arr.c b/arr.c
index f21790b..c87cf6f 100644
--- a/arr.c
+++ b/arr.c
@@ -62,7 +62,7 @@ static void *arr_add_(void **arr, size_t item_sz) {
} else {
hdr = arr_hdr(*arr);
if (hdr->len >= hdr->cap) {
- arr_resv_(arr, hdr->len * 2, item_sz);
+ arr_resv_(arr, hdr->len * 2 + 1, item_sz);
hdr = arr_hdr(*arr);
}
}
@@ -76,7 +76,7 @@ static void *arr_adda_(void **arr, size_t item_sz, Allocator *a) {
} else {
hdr = arr_hdr(*arr);
if (hdr->len >= hdr->cap) {
- arr_resva_(arr, hdr->len * 2, item_sz, a);
+ arr_resva_(arr, hdr->len * 2 + 1, item_sz, a);
hdr = arr_hdr(*arr);
}
}
@@ -101,6 +101,8 @@ static void *arr_last_(void *arr, size_t item_sz) {
/* OPTIM: shrink array */
static void arr_remove_last_(void **arr, size_t item_sz) {
+
+ assert(arr_hdr(*arr)->len);
arr_hdr(*arr)->len--; (void)item_sz;
}
diff --git a/cgen.c b/cgen.c
index 1266f20..3c9600a 100644
--- a/cgen.c
+++ b/cgen.c
@@ -29,7 +29,7 @@ static bool cgen_block_enter(CGenerator *g, Block *b) {
stmts = b->stmts;
}
if (b) g->indent_lvl++;
- return block_enter(b, stmts);
+ return block_enter(b, stmts, 0);
}
static void cgen_block_exit(CGenerator *g, Block *into) {
@@ -896,7 +896,6 @@ static bool cgen_block(CGenerator *g, Block *b, const char *ret_name, uint16_t f
arr_foreach(b->stmts, Statement, s)
if (!cgen_stmt(g, s))
return false;
-
if (b->ret_expr && ret_name) {
if (b->ret_expr->type.kind == TYPE_TUPLE) {
if (!cgen_set_tuple(g, NULL, NULL, ret_name, b->ret_expr))
@@ -942,7 +941,7 @@ static void cgen_zero_value(CGenerator *g, Type *t) {
static bool cgen_fn(CGenerator *g, FnExpr *f, Location where) {
FnExpr *prev_fn = g->fn;
Block *prev_block = g->block;
- fn_enter(f);
+ fn_enter(f, 0);
if (!cgen_fn_header(g, f, where))
return false;
cgen_write(g, " ");
@@ -956,7 +955,6 @@ static bool cgen_fn(CGenerator *g, FnExpr *f, Location where) {
if (!cgen_block_enter(g, &f->body)) return false;
if (!cgen_block(g, &f->body, NULL, CGEN_BLOCK_FLAG_NOENTER | CGEN_BLOCK_FLAG_NOBRACES))
return false;
-
if (f->ret_decls) {
if (cgen_uses_ptr(&f->ret_type)) {
} else {
@@ -1048,6 +1046,7 @@ static bool cgen_ret(CGenerator *g, Expression *ret) {
}
cgen_write(g, "return");
} else {
+ if (!cgen_expr_pre(g, ret)) return false;
cgen_write(g, "return ");
if (!cgen_expr(g, ret)) return false;
diff --git a/decls_cgen.c b/decls_cgen.c
index ca29bfc..189b032 100644
--- a/decls_cgen.c
+++ b/decls_cgen.c
@@ -85,7 +85,7 @@ static bool cgen_decls_block(CGenerator *g, Block *b) {
static bool cgen_decls_decl(CGenerator *g, Declaration *d) {
if (cgen_fn_is_direct(g, d)) {
d->expr.fn.c.name = d->idents[0];
- fn_enter(&d->expr.fn);
+ fn_enter(&d->expr.fn, 0);
if (!cgen_fn_header(g, &d->expr.fn, d->where))
return false;
cgen_write(g, ";");
diff --git a/eval.c b/eval.c
index 60bb15f..38bfb7e 100644
--- a/eval.c
+++ b/eval.c
@@ -1,6 +1,6 @@
static bool eval_block(Evaluator *ev, Block *b, Value *v);
static bool eval_expr(Evaluator *ev, Expression *e, Value *v);
-static bool block_enter(Block *b, Statement *stmts);
+static bool block_enter(Block *b, Statement *stmts, U32 flags);
static void block_exit(Block *b, Statement *stmts);
static void evalr_create(Evaluator *ev) {
@@ -764,6 +764,7 @@ static bool eval_expr(Evaluator *ev, Expression *e, Value *v) {
}
} else {
char *s = ident_to_str(e->ident);
+
err_print(e->where, "Cannot evaluate non-constant '%s' at compile time.", s);
free(s);
return false;
@@ -805,19 +806,25 @@ static bool eval_expr(Evaluator *ev, Expression *e, Value *v) {
return false;
FnExpr *fn = fnv.fn;
/* set parameter declaration values */
- long arg = 0;
Declaration *params = fn->params;
- fn_enter(fn);
+ /* OPTIM (NOTE: currently needed for recursion) */
+ Value *args = NULL;
+ arr_resv(&args, arr_len(e->call.arg_exprs));
+ for (size_t i = 0; i < arr_len(e->call.arg_exprs); i++) {
+ if (!eval_expr(ev, &e->call.arg_exprs[i], &args[i]))
+ return false;
+ }
+ fn_enter(fn, 0);
+ long arg = 0;
arr_foreach(params, Declaration, p) {
arr_foreach(p->idents, Identifier, i) {
IdentDecl *id = ident_decl(*i);
- Value *paramval = &id->val;
- if (!eval_expr(ev, &e->call.arg_exprs[arg], paramval))
- return false;
+ id->val = args[arg];
id->flags |= IDECL_FLAG_HAS_VAL;
arg++;
}
}
+ arr_clear(&args);
if (!eval_block(ev, &fn->body, v)) {
fn_exit(fn);
return false;
@@ -877,7 +884,7 @@ static bool eval_stmt(Evaluator *ev, Statement *stmt) {
}
static bool eval_block(Evaluator *ev, Block *b, Value *v) {
- block_enter(b, b->stmts);
+ block_enter(b, b->stmts, 0);
arr_foreach(b->stmts, Statement, stmt) {
if (!eval_stmt(ev, stmt))
return false;
diff --git a/main.c b/main.c
index 5e8a306..8113d10 100644
--- a/main.c
+++ b/main.c
@@ -1,9 +1,7 @@
/*
TODO:
-fix recursion with block_enter/exit
-arr => slice casting
del slices
-run time return statements
+slice notation (x[a:b])
bf interpreter
error on failed calloc in output
unicode variable names
@@ -81,7 +79,7 @@ int main(int argc, char **argv) {
evalr_create(&ev);
typer_create(&tr, &ev);
- if (!block_enter(NULL, f.stmts)) /* enter global scope */
+ if (!block_enter(NULL, f.stmts, SCOPE_FLAG_CHECK_REDECL)) /* enter global scope */
return false;
if (!types_file(&tr, &f)) {
diff --git a/out.c b/out.c
index 249b3e0..ba1a23a 100644
--- a/out.c
+++ b/out.c
@@ -18,7 +18,7 @@ typedef struct { void *data; u64 n; } slice_;
/* declarations */
void puti(i64 x);
-i64 foo(i64 x);
+i64 factorial(i64 x);
void main__(void);
/* code */
int main() {
@@ -34,31 +34,21 @@ void puti(i64 x) {
}
-i64 foo(i64 x) {
+i64 factorial(i64 x) {
- slice_ C; {
- slice_ expr__; slice_ a0_; a0_.data = calloc(x, sizeof(i64)); a0_.n = x;expr__ = a0_;C = expr__;}
- i64 i; {
- i64 expr__; expr__ = 0;i = expr__;}
- while ((i<x)) {
- (((i64(*))(C.data))[i]) = i;;
- i = (i+1);;
- };
- i64 total; {
- i64 expr__; expr__ = 0;total = expr__;}
- i = 0;;
- while ((i<x)) {
- total = (total+(((i64(*))(C.data))[i]));;
- i = (i+1);;
- };
- return total;
+ i64 a0_;
+ if ((x==0)) {
+ a0_ = 1;
+ } else {
+ a0_ = (x*(factorial((x-1))));
+ }return a0_;
}
void main__(void) {
- i64( A[45]) = {0};
- i64( B[4950]) = {0};
+ i64( a342[120]) = {0};
+ (puti((factorial(20))));
}
diff --git a/scope.c b/scope.c
index 8ecda21..5afee76 100644
--- a/scope.c
+++ b/scope.c
@@ -1,8 +1,10 @@
-static bool add_ident_decls(Block *b, Declaration *d) {
+#define SCOPE_FLAG_CHECK_REDECL 0x0001
+
+static bool add_ident_decls(Block *b, Declaration *d, U32 flags) {
bool ret = true;
arr_foreach(d->idents, Identifier, ident) {
IdentDecl **decls = &(*ident)->decls;
- if (arr_len(*decls)) {
+ if ((flags & SCOPE_FLAG_CHECK_REDECL) && arr_len(*decls)) {
/* check that it hasn't been declared in this block */
IdentDecl *prev = arr_last(*decls);
if (prev->scope == b) {
@@ -34,12 +36,12 @@ static void remove_ident_decls(Block *b, Declaration *d) {
}
/* pass NULL for block for global scope */
-static bool block_enter(Block *b, Statement *stmts) {
+static bool block_enter(Block *b, Statement *stmts, uint32_t flags) {
bool ret = true;
arr_foreach(stmts, Statement, stmt) {
if (stmt->kind == STMT_DECL) {
Declaration *decl = &stmt->decl;
- if (!add_ident_decls(b, decl))
+ if (!add_ident_decls(b, decl, flags))
ret = false;
}
}
@@ -56,11 +58,11 @@ static void block_exit(Block *b, Statement *stmts) {
}
/* does NOT enter function's block body */
-static void fn_enter(FnExpr *f) {
+static void fn_enter(FnExpr *f, U32 flags) {
arr_foreach(f->params, Declaration, decl)
- add_ident_decls(&f->body, decl);
+ add_ident_decls(&f->body, decl, flags);
arr_foreach(f->ret_decls, Declaration, decl)
- add_ident_decls(&f->body, decl);
+ add_ident_decls(&f->body, decl, flags);
}
static void fn_exit(FnExpr *f) {
diff --git a/test.toc b/test.toc
index 42c8a36..7ccd36c 100644
--- a/test.toc
+++ b/test.toc
@@ -5,40 +5,12 @@ puti @= fn(x: int) {
#C("printf(\"%ld\\n\", (long)x)");
};
-// foo @= fn(x:int) int {
-// if x < 4 {
-// return 7;
-// } else {
-// return 5;
-// }
-// 4
-// };
-foo @= fn(x: int) int {
- C := new(int, x);
- i := 0;
- while i < x {
- C[i] = i;
- i = i + 1;
- }
- total := 0;
- i = 0;
- while i < x {
- total = total + C[i];
- i = i + 1;
- }
- total
-
+factorial @= fn(x: int) int {
+ if x == 0 { 1 } else { x * factorial(x-1) }
};
main @= fn() {
- A : [foo(10)]int;
- B : [foo(100)]int;
- // C := new(int, 10);
- // i := 0;
- // while i < 10 {
- // C[i] = 7;
- // i = i + 1;
- // }
- // puti(C[9]);
+ a342 : [factorial(5)]int;
+ puti(factorial(20));
};
diff --git a/types.c b/types.c
index 5612eb3..5213e9b 100644
--- a/types.c
+++ b/types.c
@@ -483,7 +483,7 @@ static bool types_expr(Typer *tr, Expression *e) {
tr->ret_type = t->fn.types[0];
}
tr->can_ret = true;
- fn_enter(f);
+ fn_enter(f, SCOPE_FLAG_CHECK_REDECL);
bool block_success = true;
block_success = types_block(tr, &e->fn.body);
fn_exit(f);
@@ -1014,7 +1014,7 @@ static bool types_block(Typer *tr, Block *b) {
bool success = true;
Block *prev_block = tr->block;
tr->block = b;
- if (!block_enter(b, b->stmts)) return false;
+ if (!block_enter(b, b->stmts, SCOPE_FLAG_CHECK_REDECL)) return false;
arr_foreach(b->stmts, Statement, s) {
if (!types_stmt(tr, s))
success = false;
@@ -1034,7 +1034,7 @@ static bool types_block(Typer *tr, Block *b) {
static bool types_decl(Typer *tr, Declaration *d) {
bool success = true;
- if (d->flags & DECL_FLAG_FOUND_TYPE) goto ret;
+ if (d->flags & DECL_FLAG_FOUND_TYPE) return true;
Declaration **dptr = typer_arr_add(tr, &tr->in_decls);
*dptr = d;
if (d->flags & DECL_FLAG_ANNOTATES_TYPE) {