summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLeo Tenenbaum <pommicket@gmail.com>2020-04-19 01:05:46 -0400
committerLeo Tenenbaum <pommicket@gmail.com>2020-04-19 01:05:46 -0400
commit30caeaab671f7fe7d7582ce7e645302a139c15a0 (patch)
treec0895a996b2ce52656b02d55fa4faeab779fc71d
parent89ae387576966f9faa89efa6f859dc8b25e3ba76 (diff)
new for loop system: cgen
-rw-r--r--cgen.c94
-rw-r--r--main.c8
-rw-r--r--parse.c25
-rw-r--r--run18
-rw-r--r--test.toc8
-rw-r--r--types.c57
6 files changed, 140 insertions, 70 deletions
diff --git a/cgen.c b/cgen.c
index 8551841..fbf4881 100644
--- a/cgen.c
+++ b/cgen.c
@@ -1435,10 +1435,14 @@ static void cgen_expr(CGenerator *g, Expression *e) {
cgen_block(g, &w->body, NULL, 0);
} break;
case EXPR_FOR: {
- /* TODO */
-#if 0
ForExpr *fo = e->for_;
int is_range = fo->flags & FOR_IS_RANGE;
+ Declaration *header_decl = &fo->header;
+ Identifier val_ident = header_decl->idents[0];
+ Identifier index_ident = header_decl->idents[1];
+ bool has_val = !ident_eq_str(val_ident, "_");
+ bool has_index = !ident_eq_str(index_ident, "_");
+
if (is_range) {
cgen_expr_pre(g, fo->range.from);
if (fo->range.to)
@@ -1459,22 +1463,22 @@ static void cgen_expr(CGenerator *g, Expression *e) {
}
/* set value to from */
- if (fo->value) {
- cgen_type_pre(g, &fo->type);
+ if (has_val) {
+ cgen_type_pre(g, fo->type);
cgen_write(g, " ");
- cgen_ident(g, fo->value);
- cgen_type_post(g, &fo->type);
+ cgen_ident(g, val_ident);
+ cgen_type_post(g, fo->type);
cgen_write(g, "; ");
- Expression val_expr;
+ Expression val_expr = {0};
val_expr.flags = EXPR_FOUND_TYPE;
val_expr.kind = EXPR_IDENT;
- val_expr.ident = fo->value;
- val_expr.type = fo->type;
+ val_expr.ident = val_ident;
+ val_expr.type = *fo->type;
cgen_set(g, &val_expr, NULL, fo->range.from, NULL);
} else {
- cgen_type_pre(g, &fo->type);
+ cgen_type_pre(g, fo->type);
cgen_write(g, " val_");
- cgen_type_post(g, &fo->type);
+ cgen_type_post(g, fo->type);
cgen_write(g, "; ");
cgen_set(g, NULL, "val_", fo->range.from, NULL);
}
@@ -1488,10 +1492,13 @@ static void cgen_expr(CGenerator *g, Expression *e) {
cgen_set(g, NULL, "of_", fo->of, NULL);
}
cgen_write(g, "for (");
- if (fo->index || !is_range) {
+
+ bool generate_index = has_index || !is_range;
+
+ if (generate_index) {
cgen_write(g, "i64 ");
- if (fo->index)
- cgen_ident(g, fo->index);
+ if (has_index)
+ cgen_ident(g, index_ident);
else
cgen_write(g, "i_");
cgen_write(g, " = 0");
@@ -1501,16 +1508,16 @@ static void cgen_expr(CGenerator *g, Expression *e) {
Type *of_type = NULL;
if (!(is_range && !fo->range.to)) { /* if it's finite */
if (is_range) {
- if (fo->value)
- cgen_ident(g, fo->value);
+ if (has_val)
+ cgen_ident(g, val_ident);
else
cgen_write(g, "val_");
bool positive_step
- = fo->range.stepval == NULL || val_is_nonnegative(*fo->range.stepval, &fo->type);
+ = fo->range.stepval == NULL || val_is_nonnegative(*fo->range.stepval, fo->type);
cgen_write(g, " %c= to_", positive_step ? '<' : '>');
} else {
- if (fo->index)
- cgen_ident(g, fo->index);
+ if (has_index)
+ cgen_ident(g, index_ident);
else
cgen_write(g, "i_");
cgen_write(g, " < ");
@@ -1533,72 +1540,72 @@ static void cgen_expr(CGenerator *g, Expression *e) {
cgen_write(g, "; ");
if (is_range) {
if (fo->range.stepval) {
- cgen_val_pre(g, fo->range.stepval, &fo->type);
+ cgen_val_pre(g, fo->range.stepval, fo->type);
}
- if (fo->value)
- cgen_ident(g, fo->value);
+ if (has_val)
+ cgen_ident(g, val_ident);
else
cgen_write(g, "val_");
cgen_write(g, " += ");
if (fo->range.stepval) {
- cgen_val(g, fo->range.stepval, &fo->type);
+ cgen_val(g, fo->range.stepval, fo->type);
} else {
cgen_write(g, "1");
}
- if (fo->index) cgen_write(g, ", ");
+ if (has_index) cgen_write(g, ", ");
}
- if (fo->index || !is_range) {
- if (fo->index)
- cgen_ident(g, fo->index);
+ if (generate_index) {
+ if (has_index)
+ cgen_ident(g, index_ident);
else
cgen_write(g, "i_");
cgen_write(g, "++");
}
cgen_write(g, ") {");
cgen_nl(g);
- if (fo->value) {
+ if (has_val) {
if (!is_range) {
/* necessary for iterating over, e.g., an array of arrays */
- cgen_type_pre(g, &fo->type);
+ cgen_type_pre(g, fo->type);
if (uses_ptr)
cgen_write(g, " p_");
else
cgen_write(g, "(*p_)");
- cgen_type_post(g, &fo->type);
+ cgen_type_post(g, fo->type);
cgen_write(g, " = ");
if (of_type->kind == TYPE_SLICE) {
cgen_write(g, "((");
- cgen_type_pre(g, &fo->type);
+ cgen_type_pre(g, fo->type);
if (!uses_ptr) cgen_write(g, "(*)");
- cgen_type_post(g, &fo->type);
+ cgen_type_post(g, fo->type);
cgen_write(g, ")of_%sdata) + ", uses_ptr ? "->" : ".");
- if (fo->index)
- cgen_ident(g, fo->index);
+ if (has_index)
+ cgen_ident(g, index_ident);
else
cgen_write(g, "i_");
} else {
cgen_write(g, "&%sof_%s[", uses_ptr ? "(*" : "", uses_ptr ? ")" : "");
- if (fo->index)
- cgen_ident(g, fo->index);
+ if (has_index)
+ cgen_ident(g, index_ident);
else
cgen_write(g, "i_");
cgen_write(g, "]");
}
cgen_write(g, "; ");
- cgen_type_pre(g, &fo->type);
+ cgen_type_pre(g, fo->type);
cgen_write(g, " ");
- cgen_ident(g, fo->value);
- cgen_type_post(g, &fo->type);
+ cgen_ident(g, val_ident);
+ cgen_type_post(g, fo->type);
cgen_write(g, "; ");
if (uses_ptr) {
- cgen_ident(g, fo->value);
+ cgen_ident(g, val_ident);
cgen_write(g, " = p_;");
cgen_nl(g);
} else {
- Expression set_expr;
+ Expression set_expr = {0};
set_expr.kind = EXPR_IDENT;
- set_expr.ident = fo->value;
- set_expr.type = fo->type;
+ set_expr.ident = val_ident;
+ set_expr.type = *fo->type;
set_expr.flags = EXPR_FOUND_TYPE;
cgen_set(g, &set_expr, NULL, NULL, "(*p_)");
@@ -1612,7 +1619,6 @@ static void cgen_expr(CGenerator *g, Expression *e) {
cgen_lbl(g, fo->body.c.break_lbl);
cgen_writeln(g, ":;");
}
-#endif
} break;
case EXPR_BLOCK:
case EXPR_IF:
diff --git a/main.c b/main.c
index 401c115..83be85f 100644
--- a/main.c
+++ b/main.c
@@ -8,6 +8,11 @@
/*
TODO:
+allow annotating index type
+things to check:
+ for x := x {}
+ for x: x = "hey" {}
+ for x:3+"foo" { a := x; }
replace weird EXPR_FOR system with just a declaration- would make "for use p := points" easier.
need to fix:
- cgen.c
@@ -22,7 +27,10 @@ is there a problem where we can get TYPE_UNKNOWN in cgen, triggering an assert(0
-simple example, but maybe try other stuff: x := #C("5");
-also make sure you can't do x:#C("5");
local structs should not be named in C
+do we consistently handle x := &some_array_or_slice; x.len
+arr_add_val => doesn't return a pointer; takes a value!
simplify eval macros with val_to_u/i64
+consider: don't do inference for function calls; get rid of was_expr -- now that we have struct params
&&, ||
start making a standard library... (printf; stringbuilder would be nice to have)
switch
diff --git a/parse.c b/parse.c
index 6445fc2..8901cb5 100644
--- a/parse.c
+++ b/parse.c
@@ -1394,20 +1394,6 @@ static Status parse_expr(Parser *p, Expression *e, Token *end) {
if (!parse_decl(p, header_decl, PARSE_DECL_IGNORE_EXPR | DECL_CAN_END_WITH_LBRACE))
goto for_fail;
- {
- size_t nidents = arr_len(header_decl->idents);
- if (nidents > 2) {
- parser_put_end(p, &header_decl->where);
- err_print(header_decl->where, "Expected at most 2 identifiers in for declaration (index and value) but got %lu.",
- (unsigned long)nidents);
- goto for_fail;
- }
- if (nidents < 2) {
- assert(nidents == 1);
- /* turn value := arr to value, _ := arr to simplify things */
- *(Identifier *)arr_add(&header_decl->idents) = parser_ident_insert(p, "_");
- }
- }
if (!token_is_kw(t->token, KW_EQ)) {
tokr_err(t, "Expected = to follow for declaration.");
goto for_fail;
@@ -2916,12 +2902,19 @@ static int decl_ident_index(Declaration *d, Identifier i) {
}
static inline Value *decl_val_at_index(Declaration *d, int i) {
+ assert(i >= 0);
return d->type.kind == TYPE_TUPLE ? &d->val.tuple[i] : &d->val;
}
static inline Type *decl_type_at_index(Declaration *d, int i) {
- if (d->type.kind == TYPE_TUPLE)
- assert(i < (int)arr_len(d->type.tuple));
+ assert(i >= 0);
+ if (d->type.kind == TYPE_TUPLE) {
+ int tuple_len = (int)arr_len(d->type.tuple);
+#if 0
+ printf("decl_type_at_index: tuple_len:%d i:%d\n", tuple_len, i);
+#endif
+ assert(i < tuple_len);
+ }
Type *ret = d->type.kind == TYPE_TUPLE ? &d->type.tuple[i] : &d->type;
assert(ret->kind != TYPE_TUPLE);
return ret;
diff --git a/run b/run
new file mode 100644
index 0000000..2237ab5
--- /dev/null
+++ b/run
@@ -0,0 +1,18 @@
+#!/bin/sh
+if [ "$2" = "" ]; then
+ tocf=test.toc
+else
+ tocf="$2"
+fi
+if [ "$1" = "noq" ]; then
+ FLAGS=
+else
+ FLAGS="-q"
+fi
+
+./toc $tocf || exit 1
+if [ "$1" = "c" ]; then
+ gcc out.c -g -Wno-builtin-declaration-mismatch && ./a.out
+elif [ "$1" = "pc" ]; then
+ cat out.c
+fi
diff --git a/test.toc b/test.toc
index f9e5a50..c6627a2 100644
--- a/test.toc
+++ b/test.toc
@@ -1,5 +1,11 @@
+#include "std/io.toc";
+
main ::= fn() {
a : [5]int;
- for x := a {
+ for x, i := &a {
+ *x = i;
+ }
+ for y := a {
+ puti(y);
}
}
diff --git a/types.c b/types.c
index ffdd5d0..ba52b75 100644
--- a/types.c
+++ b/types.c
@@ -1522,7 +1522,22 @@ static Status types_expr(Typer *tr, Expression *e) {
ForExpr *fo = e->for_;
Declaration *header = &fo->header;
*(Declaration **)typer_arr_add(tr, &tr->in_decls) = header;
-
+ bool in_header = true;
+ bool annotated_index = true;
+ {
+ size_t nidents = arr_len(header->idents);
+ if (nidents > 2) {
+ err_print(header->where, "Expected at most 2 identifiers in for declaration (index and value) but got %lu.",
+ (unsigned long)nidents);
+ goto for_fail;
+ }
+ if (nidents < 2) {
+ annotated_index = false;
+ assert(nidents == 1);
+ /* turn value := arr to value, _ := arr to simplify things */
+ *(Identifier *)arr_add(&header->idents) = ident_insert_with_len(typer_get_idents(tr), "_", 1);
+ }
+ }
if (header->flags & DECL_ANNOTATES_TYPE) {
fo->type = &header->type;
if (!type_resolve(tr, fo->type, header->where))
@@ -1709,7 +1724,6 @@ static Status types_expr(Typer *tr, Expression *e) {
decl->expr.where = fo->of->where;
}
-
size_t start = total_nstmts - nstmts;
for (size_t s = start; s < total_nstmts; ++s) {
copy_stmt(&copier, &sub->stmts[s], &fo->body.stmts[s-start]);
@@ -1735,12 +1749,12 @@ static Status types_expr(Typer *tr, Expression *e) {
goto for_fail;
}
}
- Type ptr_type = {0};
+ Type *ptr_type = typer_calloc(tr, 1, sizeof *ptr_type);
if (uses_ptr) {
- ptr_type.flags = TYPE_IS_RESOLVED;
- ptr_type.kind = TYPE_PTR;
- ptr_type.ptr = iter_type;
- iter_type = &ptr_type;
+ ptr_type->flags = TYPE_IS_RESOLVED;
+ ptr_type->kind = TYPE_PTR;
+ ptr_type->ptr = iter_type;
+ iter_type = ptr_type;
}
if (header->flags & DECL_ANNOTATES_TYPE) {
if (!type_eq(iter_type, fo->type)) {
@@ -1761,10 +1775,33 @@ static Status types_expr(Typer *tr, Expression *e) {
val_cast(stepval, &fo->range.step->type, stepval, fo->type);
fo->range.stepval = stepval;
}
+ arr_remove_lasta(&tr->in_decls, tr->allocr);
+ in_header = false;
+ /* now we need to fix the type of the declaration to (fo->type, i64) */
+ if ((header->flags & DECL_ANNOTATES_TYPE) && annotated_index) {
+ /* we're good; they fully annotated this */
+ } else {
+ Type *type = &header->type;
+ if (fo->type == type) fo->type = &fo->of->type; /* make sure we don't point to something that's about to be overriden */
+ type->kind = TYPE_TUPLE;
+ type->flags = TYPE_IS_RESOLVED;
+ type->was_expr = NULL;
+ type->tuple = NULL;
+ arr_set_lena(&type->tuple, 2, tr->allocr);
+ assert(fo->type->flags & TYPE_IS_RESOLVED);
+ type->tuple[0] = *fo->type;
+ Type *index_type = &type->tuple[1];
+ index_type->flags = TYPE_IS_RESOLVED;
+ index_type->was_expr = NULL;
+ index_type->kind = TYPE_BUILTIN;
+ index_type->builtin = BUILTIN_I64;
+ }
+ header->flags |= DECL_FOUND_TYPE;
+
if (!types_block(tr, &fo->body)) goto for_fail;
if (fo->body.ret_expr) {
- err_print(fo->body.ret_expr->where, "for loops can't return values -- you're missing a semicolon (;)");
+ err_print(fo->body.ret_expr->where, "for loops can't return values -- you're missing a semicolon (;).");
goto for_fail;
}
@@ -1773,9 +1810,11 @@ static Status types_expr(Typer *tr, Expression *e) {
typer_block_exit(tr);
break;
for_fail:
+ if (in_header)
+ arr_remove_lasta(&tr->in_decls, tr->allocr);
typer_block_exit(tr);
return false;
- };
+ }
case EXPR_IDENT: {
Block *b = tr->block;
Identifier i = e->ident;