summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLeo Tenenbaum <pommicket@gmail.com>2020-04-19 17:13:26 -0400
committerLeo Tenenbaum <pommicket@gmail.com>2020-04-19 17:13:26 -0400
commitb79c4e942dba34ee1b2e5ce907629c7f77f88f07 (patch)
treeb89f880afde67f1dd6256a1df4bd772f67c1513a
parent30caeaab671f7fe7d7582ce7e645302a139c15a0 (diff)
annotating index type for loops
-rw-r--r--allocator.c2
-rw-r--r--cgen.c46
-rw-r--r--main.c2
-rw-r--r--parse.c6
-rwxr-xr-x[-rw-r--r--]run5
-rwxr-xr-xrung2
-rw-r--r--test.toc14
-rw-r--r--types.c197
-rw-r--r--types.h1
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))
diff --git a/cgen.c b/cgen.c
index fbf4881..6511ce9 100644
--- a/cgen.c
+++ b/cgen.c
@@ -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: {
diff --git a/main.c b/main.c
index 83be85f..d37938b 100644
--- a/main.c
+++ b/main.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
diff --git a/parse.c b/parse.c
index 8901cb5..2befa8b 100644
--- a/parse.c
+++ b/parse.c
@@ -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) {
diff --git a/run b/run
index 2237ab5..8957de6 100644..100755
--- a/run
+++ b/run
@@ -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
diff --git a/rung b/rung
index 1ed2a55..1454e1f 100755
--- a/rung
+++ b/rung
@@ -1,2 +1,2 @@
#!/bin/bash
-gdb toc \ No newline at end of file
+gdb -tui toc
diff --git a/test.toc b/test.toc
index c6627a2..cb0b448 100644
--- a/test.toc
+++ b/test.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);
}
}
diff --git a/types.c b/types.c
index ba52b75..9c83a87 100644
--- a/types.c
+++ b/types.c
@@ -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;
diff --git a/types.h b/types.h
index b61f190..38262e6 100644
--- a/types.h
+++ b/types.h
@@ -880,7 +880,6 @@ typedef Declaration *DeclarationPtr;
typedef struct ForExpr {
U8 flags;
- Type *type; /* NULL before typing */
Declaration header;
Block body;
union {