diff options
author | Leo Tenenbaum <pommicket@gmail.com> | 2020-04-19 17:13:26 -0400 |
---|---|---|
committer | Leo Tenenbaum <pommicket@gmail.com> | 2020-04-19 17:13:26 -0400 |
commit | b79c4e942dba34ee1b2e5ce907629c7f77f88f07 (patch) | |
tree | b89f880afde67f1dd6256a1df4bd772f67c1513a | |
parent | 30caeaab671f7fe7d7582ce7e645302a139c15a0 (diff) |
annotating index type for loops
-rw-r--r-- | allocator.c | 2 | ||||
-rw-r--r-- | cgen.c | 46 | ||||
-rw-r--r-- | main.c | 2 | ||||
-rw-r--r-- | parse.c | 6 | ||||
-rwxr-xr-x[-rw-r--r--] | run | 5 | ||||
-rwxr-xr-x | rung | 2 | ||||
-rw-r--r-- | test.toc | 14 | ||||
-rw-r--r-- | types.c | 197 | ||||
-rw-r--r-- | types.h | 1 |
9 files changed, 171 insertions, 104 deletions
diff --git a/allocator.c b/allocator.c index 75bdac6..8baedb5 100644 --- a/allocator.c +++ b/allocator.c @@ -25,7 +25,7 @@ static void *err_malloc(size_t bytes); static void *err_calloc(size_t n, size_t sz); static void *err_realloc(void *prev, size_t new_size); #ifdef TOC_DEBUG -//#define NO_ALLOCATOR 1 /* useful for debugging; valgrind checks writing past the end of a malloc, but that won't work with an allocator */ +#define NO_ALLOCATOR 1 /* useful for debugging; valgrind checks writing past the end of a malloc, but that won't work with an allocator */ #endif /* number of bytes a page hold, not including the header */ #define PAGE_BYTES (16384 - sizeof(Page)) @@ -1440,6 +1440,10 @@ static void cgen_expr(CGenerator *g, Expression *e) { Declaration *header_decl = &fo->header; Identifier val_ident = header_decl->idents[0]; Identifier index_ident = header_decl->idents[1]; + Type *fo_type = &header_decl->type; + assert(fo_type->kind == TYPE_TUPLE && arr_len(fo_type->tuple) == 2); + Type *val_type = &fo_type->tuple[0]; + Type *index_type = &fo_type->tuple[1]; bool has_val = !ident_eq_str(val_ident, "_"); bool has_index = !ident_eq_str(index_ident, "_"); @@ -1454,9 +1458,9 @@ static void cgen_expr(CGenerator *g, Expression *e) { if (is_range) { if (fo->range.to) { /* pre generate to */ - cgen_type_pre(g, fo->type); + cgen_type_pre(g, val_type); cgen_write(g, " to_"); - cgen_type_post(g, fo->type); + cgen_type_post(g, val_type); cgen_write(g, " = "); cgen_expr(g, fo->range.to); cgen_write(g, "; "); @@ -1464,21 +1468,21 @@ static void cgen_expr(CGenerator *g, Expression *e) { /* set value to from */ if (has_val) { - cgen_type_pre(g, fo->type); + cgen_type_pre(g, val_type); cgen_write(g, " "); cgen_ident(g, val_ident); - cgen_type_post(g, fo->type); + cgen_type_post(g, val_type); cgen_write(g, "; "); Expression val_expr = {0}; val_expr.flags = EXPR_FOUND_TYPE; val_expr.kind = EXPR_IDENT; val_expr.ident = val_ident; - val_expr.type = *fo->type; + val_expr.type = *val_type; cgen_set(g, &val_expr, NULL, fo->range.from, NULL); } else { - cgen_type_pre(g, fo->type); + cgen_type_pre(g, val_type); cgen_write(g, " val_"); - cgen_type_post(g, fo->type); + cgen_type_post(g, val_type); cgen_write(g, "; "); cgen_set(g, NULL, "val_", fo->range.from, NULL); } @@ -1496,11 +1500,13 @@ static void cgen_expr(CGenerator *g, Expression *e) { bool generate_index = has_index || !is_range; if (generate_index) { - cgen_write(g, "i64 "); + cgen_type_pre(g, index_type); + cgen_write(g, " "); if (has_index) cgen_ident(g, index_ident); else cgen_write(g, "i_"); + cgen_type_post(g, index_type); /* not needed yet, but keeping it here to prevent potential future problems */ cgen_write(g, " = 0"); } cgen_write(g, "; "); @@ -1513,7 +1519,7 @@ static void cgen_expr(CGenerator *g, Expression *e) { 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, val_type); cgen_write(g, " %c= to_", positive_step ? '<' : '>'); } else { if (has_index) @@ -1540,7 +1546,7 @@ 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, val_type); } if (has_val) cgen_ident(g, val_ident); @@ -1548,7 +1554,7 @@ static void cgen_expr(CGenerator *g, Expression *e) { 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, val_type); } else { cgen_write(g, "1"); } @@ -1566,18 +1572,18 @@ static void cgen_expr(CGenerator *g, Expression *e) { 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, val_type); if (uses_ptr) cgen_write(g, " p_"); else cgen_write(g, "(*p_)"); - cgen_type_post(g, fo->type); + cgen_type_post(g, val_type); cgen_write(g, " = "); if (of_type->kind == TYPE_SLICE) { cgen_write(g, "(("); - cgen_type_pre(g, fo->type); + cgen_type_pre(g, val_type); if (!uses_ptr) cgen_write(g, "(*)"); - cgen_type_post(g, fo->type); + cgen_type_post(g, val_type); cgen_write(g, ")of_%sdata) + ", uses_ptr ? "->" : "."); if (has_index) cgen_ident(g, index_ident); @@ -1592,10 +1598,10 @@ static void cgen_expr(CGenerator *g, Expression *e) { cgen_write(g, "]"); } cgen_write(g, "; "); - cgen_type_pre(g, fo->type); + cgen_type_pre(g, val_type); cgen_write(g, " "); cgen_ident(g, val_ident); - cgen_type_post(g, fo->type); + cgen_type_post(g, val_type); cgen_write(g, "; "); if (uses_ptr) { cgen_ident(g, val_ident); @@ -1605,10 +1611,11 @@ static void cgen_expr(CGenerator *g, Expression *e) { Expression set_expr = {0}; set_expr.kind = EXPR_IDENT; set_expr.ident = val_ident; - set_expr.type = *fo->type; + set_expr.type = *val_type; set_expr.flags = EXPR_FOUND_TYPE; cgen_set(g, &set_expr, NULL, NULL, "(*p_)"); + cgen_nl(g); } } } @@ -1632,7 +1639,6 @@ static void cgen_expr(CGenerator *g, Expression *e) { cgen_ident_id(g, e->cgen.id); } else { FnType *fn_type = &e->call.fn->type.fn; - cgen_write(g, "("); cgen_expr(g, e->call.fn); if (e->call.instance) { cgen_fn_instance_number(g, e->call.instance->fn->instance_id); @@ -1651,7 +1657,7 @@ static void cgen_expr(CGenerator *g, Expression *e) { if (i < nparams-1) ++i; } - cgen_write(g, "))"); + cgen_write(g, ")"); } break; case EXPR_C: { @@ -18,6 +18,7 @@ replace weird EXPR_FOR system with just a declaration- would make "for use p := - cgen.c - eval.c - copy.c +consider: don't do inference for function calls; get rid of was_expr -- now that we have struct params EXPR_IDENT should be a string before typing, also struct member accesses do we need the possibility that IdentSlot.decl is NULL? use @@ -30,7 +31,6 @@ 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 @@ -146,6 +146,9 @@ static bool type_builtin_is_numerical(BuiltinType b) { return type_builtin_is_int(b) || type_builtin_is_float(b); } +static bool type_is_int(Type *t) { + return t->kind == TYPE_BUILTIN && type_builtin_is_int(t->builtin); +} /* returns -1 on failure */ static int kw_to_builtin_type(Keyword kw) { @@ -1384,7 +1387,6 @@ static Status parse_expr(Parser *p, Expression *e, Token *end) { e->kind = EXPR_FOR; ForExpr *fo = e->for_ = parser_malloc(p, sizeof *fo); fo->flags = 0; - fo->type = NULL; Block *prev_block = p->block; fo->body.parent = p->block; p->block = &fo->body; @@ -2707,7 +2709,7 @@ static void fprint_expr(FILE *out, Expression *e) { if (found_type) { if (fo->range.stepval) { fprintf(out, ","); - fprint_val(out, *fo->range.stepval, fo->type); + fprint_val(out, *fo->range.stepval, &fo->header.type.tuple[0]); } } else { if (fo->range.step) { @@ -1,4 +1,7 @@ #!/bin/sh +if [ "$CC" = "" ]; then + CC=tcc +fi if [ "$2" = "" ]; then tocf=test.toc else @@ -12,7 +15,7 @@ fi ./toc $tocf || exit 1 if [ "$1" = "c" ]; then - gcc out.c -g -Wno-builtin-declaration-mismatch && ./a.out + $CC out.c -g -Wno-builtin-declaration-mismatch && ./a.out elif [ "$1" = "pc" ]; then cat out.c fi @@ -1,2 +1,2 @@ #!/bin/bash -gdb toc
\ No newline at end of file +gdb -tui toc @@ -1,11 +1,15 @@ #include "std/io.toc"; main ::= fn() { - a : [5]int; - for x, i := &a { - *x = i; + a : [5][]char; + for x, i : (&[]char, u8) = &a { + *x = "foo"; } - for y := a { - puti(y); + for y : []char = a { + puts(y); + } + for x, i := a { + puti(i); + puts(x); } } @@ -33,6 +33,12 @@ static inline void typer_block_exit(Typer *tr) { tr->block = *(Block **)arr_last(tr->blocks); } +static inline void construct_resolved_builtin_type(Type *t, BuiltinType builtin) { + t->kind = TYPE_BUILTIN; + t->builtin = builtin; + t->was_expr = NULL; + t->flags = TYPE_IS_RESOLVED; +} static size_t compiler_sizeof_builtin(BuiltinType b) { switch (b) { @@ -820,16 +826,41 @@ static Status type_resolve(Typer *tr, Type *t, Location where) { } break; case TYPE_EXPR: { Value typeval; - if (!types_expr(tr, t->expr)) + Expression *expr = t->expr; + if (!types_expr(tr, expr)) return false; - if (t->expr->type.kind == TYPE_UNKNOWN && tr->err_ctx->have_errored) + if (expr->type.kind == TYPE_UNKNOWN && tr->err_ctx->have_errored) return false; /* silently fail (e.g. if a function couldn't be typed) */ - if (!type_is_builtin(&t->expr->type, BUILTIN_TYPE)) { - err_print(t->expr->where, "This expression is not a type, but it's being used as one."); - return false; + if (!type_is_builtin(&expr->type, BUILTIN_TYPE)) { + /* ok maybe it's a tuple of types, which we'll convert to a TYPE_TUPLE */ + bool is_tuple_of_types = false; + if (expr->kind == EXPR_TUPLE) { + Type *tuple = NULL; + is_tuple_of_types = true; + arr_foreach(expr->tuple, Expression, sub) { + if (!type_is_builtin(&sub->type, BUILTIN_TYPE)) { + is_tuple_of_types = false; + break; + } + if (!eval_expr(tr->evalr, sub, &typeval)) + return false; + Type *subtype = typer_arr_add(tr, &tuple); + *subtype = *typeval.type; + } + if (is_tuple_of_types) { + t->kind = TYPE_TUPLE; + t->was_expr = expr; + t->flags = TYPE_IS_RESOLVED; + t->tuple = tuple; + break; + } + } + if (!is_tuple_of_types) { + err_print(expr->where, "This expression is not a type, but it's being used as one."); + return false; + } } - Expression *expr = t->expr; - if (!eval_expr(tr->evalr, t->expr, &typeval)) + if (!eval_expr(tr->evalr, expr, &typeval)) return false; *t = *typeval.type; if (t->kind == TYPE_STRUCT) { @@ -1521,7 +1552,10 @@ static Status types_expr(Typer *tr, Expression *e) { case EXPR_FOR: { ForExpr *fo = e->for_; Declaration *header = &fo->header; + *(Declaration **)typer_arr_add(tr, &tr->in_decls) = header; + fo->body.uses = NULL; + typer_block_enter(tr, &fo->body); bool in_header = true; bool annotated_index = true; { @@ -1538,16 +1572,50 @@ static Status types_expr(Typer *tr, Expression *e) { *(Identifier *)arr_add(&header->idents) = ident_insert_with_len(typer_get_idents(tr), "_", 1); } } + + Type *fo_type_tuple = NULL; + /* fo_type is (val_type, index_type) */ + arr_set_lena(&fo_type_tuple, 2, tr->allocr); + memset(fo_type_tuple, 0, 2*sizeof *fo_type_tuple); + Type *val_type = &fo_type_tuple[0]; + Type *index_type = &fo_type_tuple[1]; + if (header->flags & DECL_ANNOTATES_TYPE) { - fo->type = &header->type; - if (!type_resolve(tr, fo->type, header->where)) - goto for_fail; - } else { - fo->type = NULL; + Type *header_type = &header->type; + if (!type_resolve(tr, header_type, header->where)) + return false; + if (annotated_index) { + if (header_type->kind != TYPE_TUPLE || arr_len(header_type->tuple) != 2) { + char *s = type_to_str(header_type); + err_print(header->where, "Expected annotated for loop type to be (val_type, index_type), but got %s instead.", s); + free(s); + goto for_fail; + } + fo_type_tuple = header_type->tuple; + val_type = &fo_type_tuple[0]; + index_type = &fo_type_tuple[1]; + if (!type_is_int(index_type)) { + char *s = type_to_str(index_type); + err_print(header->where, "Expected index type of for loop to be a builtin integer type, but it's %s.", s); + free(s); + goto for_fail; + } + } else { + *val_type = header->type; + } + } + Type *fo_type = &header->type; + fo_type->flags = TYPE_IS_RESOLVED; + fo_type->was_expr = NULL; + fo_type->kind = TYPE_TUPLE; + fo_type->tuple = fo_type_tuple; + + assert(fo_type->flags & TYPE_IS_RESOLVED); + + if (!index_type->flags) { + construct_resolved_builtin_type(index_type, BUILTIN_I64); } - fo->body.uses = NULL; - typer_block_enter(tr, &fo->body); if (fo->flags & FOR_IS_RANGE) { if (!types_expr(tr, fo->range.from)) goto for_fail; { @@ -1581,46 +1649,54 @@ static Status types_expr(Typer *tr, Expression *e) { } } - if (fo->type) { - if (!type_eq(fo->type, &fo->range.from->type)) { - char *exp = type_to_str(fo->type); + if (val_type->flags) { + if (!type_eq(val_type, &fo->range.from->type)) { + char *exp = type_to_str(val_type); char *got = type_to_str(&fo->range.from->type); err_print(e->where, "Type of for loop does not match the type of the from expression. Expected %s, but got %s.", exp, got); free(exp); free(got); goto for_fail; } - if ((fo->type->flags & TYPE_IS_FLEXIBLE)) - fo->type = &fo->range.from->type; } else { - fo->type = &fo->range.from->type; + *val_type = fo->range.from->type; } - if (fo->range.step && !type_eq(fo->type, &fo->range.step->type)) { - char *exp = type_to_str(fo->type); - char *got = type_to_str(&fo->range.step->type); - err_print(e->where, "Type of for loop does not match the type of the step expression. Expected %s, but got %s.", exp, got); - free(exp); free(got); - goto for_fail; - } - - if ((fo->type->flags & TYPE_IS_FLEXIBLE) && fo->range.step) - fo->type = &fo->range.step->type; + if (fo->range.step) { + if (!type_eq(val_type, &fo->range.step->type)) { + char *exp = type_to_str(val_type); + char *got = type_to_str(&fo->range.step->type); + err_print(e->where, "Type of for loop does not match the type of the step expression. Expected %s, but got %s.", exp, got); + free(exp); free(got); + goto for_fail; + } + if (val_type->flags & TYPE_IS_FLEXIBLE) + *val_type = fo->range.step->type; - if (fo->range.to && !type_eq(fo->type, &fo->range.to->type)) { - char *exp = type_to_str(fo->type); - char *got = type_to_str(&fo->range.to->type); - err_print(e->where, "Type of for loop does not match the type of the to expression. Expected %s, but got %s.", exp, got); - free(exp); free(got); - goto for_fail; + Value *stepval = typer_malloc(tr, sizeof *fo->range.stepval); + if (!eval_expr(tr->evalr, fo->range.step, stepval)) { + info_print(fo->range.step->where, "Note that the step of a for loop must be a compile-time constant."); + goto for_fail; + } + val_cast(stepval, &fo->range.step->type, stepval, val_type); + fo->range.stepval = stepval; } - if (fo->type->flags & TYPE_IS_FLEXIBLE) { - if (fo->range.to) - fo->type = &fo->range.to->type; - fo->type->flags &= (TypeFlags)~(TypeFlags)TYPE_IS_FLEXIBLE; + + if (fo->range.to) { + if (!type_eq(val_type, &fo->range.to->type)) { + char *exp = type_to_str(val_type); + char *got = type_to_str(&fo->range.to->type); + err_print(e->where, "Type of for loop does not match the type of the to expression. Expected %s, but got %s.", exp, got); + free(exp); free(got); + goto for_fail; + } + if (val_type->flags & TYPE_IS_FLEXIBLE) + *val_type = fo->range.to->type; } + val_type->flags &= (TypeFlags)~(TypeFlags)TYPE_IS_FLEXIBLE; } else { if (!types_expr(tr, fo->of)) goto for_fail; + Type *iter_type = &fo->of->type; bool uses_ptr = false; @@ -1757,46 +1833,23 @@ static Status types_expr(Typer *tr, Expression *e) { iter_type = ptr_type; } if (header->flags & DECL_ANNOTATES_TYPE) { - if (!type_eq(iter_type, fo->type)) { + if (!type_eq(iter_type, val_type)) { char *exp = type_to_str(iter_type); - char *got = type_to_str(fo->type); - err_print(e->where, "Expected to iterate over type %s, but it was annotated as iterating over type %s."); + char *got = type_to_str(val_type); + err_print(e->where, "Expected to iterate over type %s, but it was annotated as iterating over type %s.", exp, got); free(exp); free(got); goto for_fail; } - } else fo->type = iter_type; - } - if ((fo->flags & FOR_IS_RANGE) && fo->range.step) { - Value *stepval = typer_malloc(tr, sizeof *fo->range.stepval); - if (!eval_expr(tr->evalr, fo->range.step, stepval)) { - info_print(fo->range.step->where, "Note that the step of a for loop must be a compile-time constant."); - goto for_fail; - } - val_cast(stepval, &fo->range.step->type, stepval, fo->type); - fo->range.stepval = stepval; + } else *val_type = *iter_type; } + 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; - } + assert(header->type.flags & TYPE_IS_RESOLVED); + assert(index_type->flags & TYPE_IS_RESOLVED); + assert(val_type->flags & TYPE_IS_RESOLVED); + header->flags |= DECL_FOUND_TYPE; if (!types_block(tr, &fo->body)) goto for_fail; @@ -880,7 +880,6 @@ typedef Declaration *DeclarationPtr; typedef struct ForExpr { U8 flags; - Type *type; /* NULL before typing */ Declaration header; Block body; union { |