From 7352f2c357619e23ed348bdadd48f38f9acd4d86 Mon Sep 17 00:00:00 2001
From: Leo Tenenbaum <pommicket@gmail.com>
Date: Fri, 25 Oct 2019 09:57:28 -0400
Subject: compile time arrays and slices!

---
 cgen.c   | 29 +++++++++++++++++------------
 eval.c   | 59 +++++++++++++++++++++++++++++++++++++++++++++--------------
 main.c   |  1 +
 scope.c  |  2 ++
 test.toc | 45 ++++++++++++++++++++++-----------------------
 5 files changed, 87 insertions(+), 49 deletions(-)

diff --git a/cgen.c b/cgen.c
index f8e35ff..ab2f370 100644
--- a/cgen.c
+++ b/cgen.c
@@ -1043,7 +1043,7 @@ static bool cgen_val_ptr_pre(CGenerator *g, void *v, Type *t, Location where) {
 				return false;
 		}
 		if (!cgen_type_pre(g, t->slice, where)) return false;
-		cgen_write(g, "(d%p_[])", where.code); /* TODO: improve this somehow? */
+		cgen_write(g, "(d%p_[])", v); /* TODO: improve this somehow? */
 		if (!cgen_type_post(g, t->slice, where)) return false;
 		cgen_write(g, " = {");
 		for (U64 i = 0; i < s->n; i++) {
@@ -1051,11 +1051,12 @@ static bool cgen_val_ptr_pre(CGenerator *g, void *v, Type *t, Location where) {
 			if (!cgen_val_ptr(g, (char *)s->data + i * compiler_sizeof(t->slice), t->slice, where))
 				return false;
 		}
-		cgen_write(g, "}");
+		cgen_write(g, "};");
+		cgen_nl(g);
 	} break;
 	case TYPE_ARR:
 		for (size_t i = 0; i < t->arr.n; i++) {
-			if (!cgen_val_ptr_pre(g, (char *)v + i * compiler_sizeof(t->arr.of), t->arr.of, where))
+			if (!cgen_val_ptr_pre(g, (char *)*(void **)v + i * compiler_sizeof(t->arr.of), t->arr.of, where))
 				return false;
 		}
 		break;
@@ -1083,13 +1084,13 @@ static bool cgen_val_ptr(CGenerator *g, void *v, Type *t, Location where) {
 		cgen_write(g, "{");
 		for (size_t i = 0; i < t->arr.n; i++) {
 			if (i) cgen_write(g, ", ");
-			if (!cgen_val_ptr(g, (char *)v + i * compiler_sizeof(t->arr.of), t->arr.of, where))
+			if (!cgen_val_ptr(g, *(char **)v + i * compiler_sizeof(t->arr.of), t->arr.of, where))
 				return false;
 		}
 		cgen_write(g, "}");
 		break;
 	case TYPE_SLICE:
-		cgen_write(g, "{d%p_, %lu}", where.code, ((Slice *)v)->n);
+		cgen_write(g, "{d%p_, %lu}", v, ((Slice *)v)->n);
 		break;
 	case TYPE_FN:
 		cgen_fn_name(g, *(FnExpr **)v);
@@ -1117,6 +1118,10 @@ static bool cgen_val_ptr(CGenerator *g, void *v, Type *t, Location where) {
 	return true;
 }
 
+static bool cgen_val_pre(CGenerator *g, Value *v, Type *t, Location where) {
+	return cgen_val_ptr_pre(g, v, t, where);
+}
+
 /* generates a value fit for use as an initializer */
 static bool cgen_val(CGenerator *g, Value *v, Type *t, Location where) {
 	/* 
@@ -1126,6 +1131,7 @@ static bool cgen_val(CGenerator *g, Value *v, Type *t, Location where) {
 	return cgen_val_ptr(g, v, t, where);
 }
 
+
 static bool cgen_decl(CGenerator *g, Declaration *d) {
 	if (cgen_fn_is_direct(g, d)) {
 		if (!cgen_fn(g, &d->expr.fn, d->where))
@@ -1134,6 +1140,8 @@ static bool cgen_decl(CGenerator *g, Declaration *d) {
 		if (d->type.kind == TYPE_TUPLE) {
 			long idx = 0;
 			arr_foreach(d->idents, Identifier, i) {
+				if (!cgen_val_pre(g, &d->val.tuple[idx], &d->type.tuple[idx], d->where))
+					return false;
 				if (!cgen_type_pre(g, &d->type.tuple[idx], d->where)) return false;
 				cgen_write(g, " ");
 				cgen_ident(g, *i);
@@ -1142,20 +1150,17 @@ static bool cgen_decl(CGenerator *g, Declaration *d) {
 				if (!cgen_val(g, &d->val.tuple[idx], &d->type.tuple[idx], d->where))
 					return false;
 				idx++;
+				cgen_write(g, ";");
+				cgen_nl(g);
 			}
-			cgen_write(g, ";");
-			cgen_nl(g);
 		} else {
+			if (!cgen_val_pre(g, &d->val, &d->type, d->where))
+				return false;
 			if (!cgen_type_pre(g, &d->type, d->where)) return false;
 			cgen_write(g, " ");
 			cgen_ident(g, d->idents[0]);
 			if (!cgen_type_post(g, &d->type, d->where)) return false;
 			cgen_write(g, " = ");
-			if (d->type.kind == TYPE_ARR) {
-				I64 *nums = d->val.arr;
-				printf("%ld\n",nums[0]);
-			}
-			return true;
 			if (!cgen_val(g, &d->val, &d->type, d->where))
 				return false;
 			cgen_write(g, ";");
diff --git a/eval.c b/eval.c
index 4c0402b..564d409 100644
--- a/eval.c
+++ b/eval.c
@@ -1,4 +1,4 @@
-static bool eval_block(Evaluator *ev, Block *b, Value *v);
+static bool eval_block(Evaluator *ev, Block *b, Type *t, Value *v);
 static bool eval_expr(Evaluator *ev, Expression *e, Value *v);
 static bool block_enter(Block *b, Statement *stmts, U32 flags);
 static void block_exit(Block *b, Statement *stmts);
@@ -41,15 +41,15 @@ static size_t compiler_sizeof(Type *t) {
 	case TYPE_BUILTIN:
 		return compiler_sizeof_builtin(t->builtin);
 	case TYPE_FN:
-		return sizeof t->fn;
+		return sizeof(FnExpr *);
 	case TYPE_PTR:
-		return sizeof t->ptr;
+		return sizeof(void *);
 	case TYPE_ARR:
 		return t->arr.n * compiler_sizeof(t->arr.of);
 	case TYPE_TUPLE:
-		return sizeof t->tuple;
+		return sizeof(Value *);
 	case TYPE_SLICE:
-		return sizeof t->slice;
+		return sizeof(Slice);
 	case TYPE_VOID:
 	case TYPE_UNKNOWN:
 		return 0;
@@ -141,6 +141,29 @@ static void u64_to_val(Value *v, BuiltinType v_type, U64 x) {
 		i64_to_val(v, v_type, (I64)x);
 }
 
+static void val_copy(Value *dest, Value *src, Type *t) {
+	switch (t->kind) {
+	case TYPE_BUILTIN:
+	case TYPE_FN:
+	case TYPE_PTR:
+	case TYPE_SLICE:
+	case TYPE_VOID:
+	case TYPE_UNKNOWN:
+		*dest = *src;
+		break;
+	case TYPE_ARR: {
+		size_t bytes = t->arr.n * compiler_sizeof(t->arr.of);
+		dest->arr = err_malloc(bytes);
+		memcpy(dest->arr, src->arr, bytes);
+	} break;
+	case TYPE_TUPLE: {
+		size_t bytes = arr_len(t->tuple) * sizeof(*dest->tuple);
+		dest->tuple = malloc(bytes);
+		memcpy(dest->tuple, src->tuple, bytes);
+	} break;
+	}
+}
+
 #define builtin_casts_to_int(x)					\
 	case BUILTIN_I8:							\
 	vout->i8 = (I8)vin->x; break;				\
@@ -477,8 +500,10 @@ static bool eval_set(Evaluator *ev, Expression *set, Value *to) {
 		case BINARY_AT_INDEX: {
 			void *ptr;
 			Type *type;
+			/* get pointer to x[i] */
 			if (!eval_expr_ptr_at_index(ev, set, &ptr, &type))
 				return false;
+			/* set it to to */
 			eval_deref_set(ptr, to, type);
 		} break;
 		default: break;
@@ -723,12 +748,12 @@ static bool eval_expr(Evaluator *ev, Expression *e, Value *v) {
 			Value cond;
 			if (!eval_expr(ev, i->cond, &cond)) return false;
 			if (val_truthiness(&cond, &i->cond->type)) {
-				if (!eval_block(ev, &i->body, v)) return false;
+				if (!eval_block(ev, &i->body, &e->type, v)) return false;
 			} else if (i->next_elif) {
 				if (!eval_expr(ev, i->next_elif, v)) return false;
 			}
 		} else {
-			if (!eval_block(ev, &i->body, v)) return false;
+			if (!eval_block(ev, &i->body, &e->type, v)) return false;
 		}
 	} break;
 	case EXPR_WHILE: {
@@ -740,11 +765,11 @@ static bool eval_expr(Evaluator *ev, Expression *e, Value *v) {
 				if (!val_truthiness(&cond, &w->cond->type))
 					break;
 			}
-			if (!eval_block(ev, &w->body, v)) return false;
+			if (!eval_block(ev, &w->body, &e->type, v)) return false;
 		}
 	} break;
 	case EXPR_BLOCK:
-		if (!eval_block(ev, &e->block, v)) return false;
+		if (!eval_block(ev, &e->block, &e->type, v)) return false;
 		break;
 	case EXPR_LITERAL_BOOL:
 		v->boolv = e->booll;
@@ -850,7 +875,7 @@ static bool eval_expr(Evaluator *ev, Expression *e, Value *v) {
 			}
 		}
 		arr_clear(&args);
-		if (!eval_block(ev, &fn->body, v)) {
+		if (!eval_block(ev, &fn->body, &e->type, v)) {
 			fn_exit(fn);
 			return false;
 		}
@@ -921,12 +946,13 @@ static bool eval_decl(Evaluator *ev, Declaration *d) {
 	arr_foreach(d->idents, Identifier, i) {
 		IdentDecl *id = ident_decl(*i);
 		if (has_expr && d->expr.kind == EXPR_TUPLE) {
-			id->val = val.tuple[index++];
+			val_copy(&id->val, &val.tuple[index], &d->type.tuple[index]);
+			index++;
 		} else if (!has_expr && d->type.kind == TYPE_ARR) {
 			/* "stack" array */
 			id->val.arr = err_calloc(d->type.arr.n, compiler_sizeof(d->type.arr.of));
 		} else {
-			id->val = val;
+			val_copy(&id->val, &val, &d->type);
 		}
 		id->flags |= IDECL_FLAG_HAS_VAL;
 	}
@@ -952,17 +978,22 @@ static bool eval_stmt(Evaluator *ev, Statement *stmt) {
 	return true;
 }
 
-static bool eval_block(Evaluator *ev, Block *b, Value *v) {
+/* t is the type of the block. */
+static bool eval_block(Evaluator *ev, Block *b, Type *t, Value *v) {
 	block_enter(b, b->stmts, 0);
 	arr_foreach(b->stmts, Statement, stmt) {
 		if (!eval_stmt(ev, stmt))
 			return false;
 		if (ev->returning) break;
 	}
+	Value *returning = ev->returning;
+	Value r;
 	if (!ev->returning && b->ret_expr) {
-		if (!eval_expr(ev, b->ret_expr, v))
+	    returning = &r;
+		if (!eval_expr(ev, b->ret_expr, returning))
 			return false;
 	}
+	if (returning) val_copy(v, returning, t);
 	block_exit(b, b->stmts);
 	
 	return true;
diff --git a/main.c b/main.c
index a3321a9..1153983 100644
--- a/main.c
+++ b/main.c
@@ -1,6 +1,7 @@
 /* 
 TODO:
 array/slice values
+fix leaking of constant stack arrays
 make sure initializers for global variables are compile-time constants
 structs
 length of slice/arr with .len
diff --git a/scope.c b/scope.c
index 5afee76..e715cc3 100644
--- a/scope.c
+++ b/scope.c
@@ -26,6 +26,8 @@ static void remove_ident_decls(Block *b, Declaration *d) {
 		IdentDecl *last_decl = arr_last(*decls);
 		if (last_decl && last_decl->scope == b) {
 			if ((last_decl->flags & IDECL_FLAG_HAS_VAL)
+				/* don't free const arrays (there's only one per decl) */
+				&& !(last_decl->decl->flags & DECL_FLAG_CONST)  
 				&& last_decl->decl->type.kind == TYPE_ARR) {
 				/* free array on stack */
 				free(last_decl->val.arr);
diff --git a/test.toc b/test.toc
index a1b29af..15d782a 100644
--- a/test.toc
+++ b/test.toc
@@ -13,32 +13,31 @@ putf @= fn(x: float) {
 ");
 };
 
-ptriple @= fn(m: int, n: int) (int, int, int) {
-		m*m-n*n, 2*m*n, m*m+n*n
-};
-
-f @= fn() int {
-  a, b, c : int;
-  a, b, c = ptriple(3, 2);
-  a + b + c
-};
 
-aSDF @= fn() [3]int {
-	 x: [3]int;
-	 x[0] = 1;
-	 x[1] = 2;
-	 x[2] = 3;
+N @= 50;
+pascal @= fn() [N][]int {
+	 x: [N][]int;
+	 i := 0;
+	 while i < N {
+	 	   x[i] = new(int, i+1);
+		   i = i + 1;
+	 }
+	 i = 0;
+	 while i < N {
+	 	   x[i][0] = 1;
+		   x[i][i] = 1;
+		   j := 1;
+		   while j < i {
+		   		 x[i][j] = x[i-1][j-1] + x[i-1][j];
+				 j = j + 1;
+		   }
+		   i = i + 1;
+	 }
 	 x
 };
 
 main @= fn() {
-	 puti(f());
-	 A : [f()]int;
-	 x @= f();
-	 dsafsad @= ptriple;
-	 foo @= aSDF();
-	 puti(foo[0]);
-	 puti(foo[1]);
-	 puti(foo[2]);
-	 // B : [aSDF()[0]]int;
+	 ptriangle @= pascal();
+	 puti(ptriangle[49][25]);
+	 
 };	
-- 
cgit v1.2.3