From 30caeaab671f7fe7d7582ce7e645302a139c15a0 Mon Sep 17 00:00:00 2001 From: Leo Tenenbaum Date: Sun, 19 Apr 2020 01:05:46 -0400 Subject: new for loop system: cgen --- cgen.c | 94 ++++++++++++++++++++++++++++++++++------------------------------ main.c | 8 ++++++ parse.c | 25 +++++++---------- run | 18 +++++++++++++ test.toc | 8 +++++- types.c | 57 ++++++++++++++++++++++++++++++++------- 6 files changed, 140 insertions(+), 70 deletions(-) create mode 100644 run 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; -- cgit v1.2.3