summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLeo Tenenbaum <pommicket@gmail.com>2019-11-05 14:21:41 -0500
committerLeo Tenenbaum <pommicket@gmail.com>2019-11-05 14:21:41 -0500
commit08a0853923ae5b536b9b853a35ce704ab98c6618 (patch)
tree2cde50b96edc1df03fc48f27571211fe2bce12d5
parent16db3a715f4af41c9c66952d459ffed723e186fc (diff)
fixed problems with each loops
-rw-r--r--cgen.c192
-rw-r--r--eval.c7
-rw-r--r--main.c1
-rw-r--r--parse.c1
-rw-r--r--test.toc33
-rw-r--r--types.c3
-rw-r--r--types.h1
7 files changed, 159 insertions, 79 deletions
diff --git a/cgen.c b/cgen.c
index d8afe05..bed64b9 100644
--- a/cgen.c
+++ b/cgen.c
@@ -674,120 +674,162 @@ static bool cgen_expr_pre(CGenerator *g, Expression *e) {
case EXPR_EACH: {
EachExpr *ea = &e->each;
int is_range = ea->flags & EACH_IS_RANGE;
- IdentID slice_id;
- IdentID from_id;
- if (!is_range && ea->of->type.kind == TYPE_SLICE) {
- /* pre-generate the slice */
- slice_id = g->ident_counter++;
- cgen_write(g, "slice_ ");
- cgen_ident_id(g, slice_id);
- cgen_write(g, " = ");
- if (!cgen_expr(g, ea->of)) return false;
- cgen_write(g, "; ");
- } else if (is_range) {
- /* pre-generate from */
- from_id = g->ident_counter++;
- if (!cgen_type_pre(g, &ea->type, e->where)) return false;
- cgen_write(g, " ");
- cgen_ident_id(g, from_id);
- if (!cgen_type_post(g, &ea->type, e->where)) return false;
- cgen_write(g, " = ");
- if (!cgen_expr(g, ea->range.from))
- return false;
- cgen_write(g, "; ");
+ if (is_range) {
+ if (!cgen_expr_pre(g, ea->range.from)) return false;
+ if (ea->range.to && !cgen_expr_pre(g, ea->range.to)) return false;
+ } else {
+ if (!cgen_expr_pre(g, ea->of)) return false;
}
+
ea->c.id = id;
- if (ea->index == NULL)
- ea->c.index_id = g->ident_counter++;
if (!each_enter(e, 0)) return false;
+ cgen_write(g, "{");
+ if (is_range) {
+ /* set value to from */
+ if (ea->value) {
+ if (!cgen_type_pre(g, &ea->type, e->where)) return false;
+ cgen_write(g, " ");
+ cgen_ident(g, ea->value);
+ if (!cgen_type_post(g, &ea->type, e->where)) return false;
+ cgen_write(g, "; ");
+ Expression val_expr;
+ val_expr.flags = EXPR_FLAG_FOUND_TYPE;
+ val_expr.kind = EXPR_IDENT;
+ val_expr.ident = ea->value;
+ val_expr.type = ea->type;
+ if (!cgen_set(g, &val_expr, NULL, ea->range.from, NULL))
+ return false;
+ } else {
+ if (!cgen_type_pre(g, &ea->type, e->where)) return false;
+ cgen_write(g, " val_");
+ if (!cgen_type_post(g, &ea->type, e->where)) return false;
+ cgen_write(g, "; ");
+ if (!cgen_set(g, NULL, "val_", ea->range.from, NULL))
+ return false;
+ }
+ if (ea->range.to) {
+ /* pre generate to */
+ if (!cgen_type_pre(g, &ea->type, e->where)) return false;
+ cgen_write(g, " to_");
+ if (!cgen_type_post(g, &ea->type, e->where)) return false;
+ cgen_write(g, " = ");
+ if (!cgen_expr(g, ea->range.to))
+ return false;
+ cgen_write(g, "; ");
+ }
+ } else {
+ /* pre-generate of */
+ if (!cgen_type_pre(g, &ea->of->type, e->where))
+ return false;
+ cgen_write(g, " of_");
+ if (!cgen_type_post(g, &ea->of->type, e->where))
+ return false;
+
+ cgen_write(g, "; ");
+
+ if (!cgen_set(g, NULL, "of_", ea->of, NULL))
+ return false;
+ }
cgen_write(g, "for (i64 ");
if (ea->index)
cgen_ident(g, ea->index);
else
- cgen_ident_id(g, ea->c.index_id);
+ cgen_write(g, "i_");
cgen_write(g, " = 0; ");
- if (!(is_range && !ea->range.to)) {
- if (ea->index)
- cgen_ident(g, ea->index);
- else
- cgen_ident_id(g, ea->c.index_id);
+ if (!(is_range && !ea->range.to)) { /* if it's finite */
if (is_range) {
+ if (ea->value)
+ cgen_ident(g, ea->value);
+ else
+ cgen_write(g, "val_");
bool positive_step
= ea->range.stepval == NULL || val_is_nonnegative(ea->range.stepval, &ea->type);
- cgen_write(g, " %c= ", positive_step ? '<' : '>');
- if (!cgen_expr(g, ea->range.to))
- return false;
- cgen_write(g, "-");
- cgen_ident_id(g, from_id);
+ cgen_write(g, " %c= to_", positive_step ? '<' : '>');
} else {
+ if (ea->index)
+ cgen_ident(g, ea->index);
+ else
+ cgen_write(g, "i_");
cgen_write(g, " < ");
switch (ea->of->type.kind) {
case TYPE_ARR:
cgen_write(g, "%lu", (unsigned long)ea->of->type.arr.n);
break;
case TYPE_SLICE:
- cgen_ident_id(g, slice_id);
- cgen_write(g, ".len");
+ cgen_write(g, "of_.n");
break;
default: assert(0); break;
}
}
}
cgen_write(g, "; ");
+ if (is_range) {
+ if (ea->value)
+ cgen_ident(g, ea->value);
+ else
+ cgen_write(g, "val_");
+ cgen_write(g, " += ");
+ if (ea->range.stepval) {
+ if (!cgen_val(g, ea->range.stepval, &ea->type, e->where))
+ return false;
+ } else {
+ cgen_write(g, "1");
+ }
+ cgen_write(g, ", ");
+ }
+
if (ea->index)
cgen_ident(g, ea->index);
else
- cgen_ident_id(g, ea->c.index_id);
- cgen_write(g, " += ");
- if (is_range && ea->range.stepval) {
- if (!cgen_val(g, ea->range.stepval, &ea->type, e->where))
- return false;
- } else {
- cgen_write(g, "1");
- }
+ cgen_write(g, "i_");
+ cgen_write(g, "++");
cgen_write(g, ") {");
cgen_nl(g);
if (ea->value) {
- if (is_range) {
+ if (!is_range) {
+ /* necessary for iterating over, e.g., an array of arrays */
+ if (!cgen_type_pre(g, &ea->type, e->where))
+ return false;
+ cgen_write(g, "(*p_)");
+ if (!cgen_type_post(g, &ea->type, e->where))
+ return false;
+ cgen_write(g, " = ");
+ if (ea->of->type.kind == TYPE_SLICE) {
+ cgen_write(g, "((");
+ if (!cgen_type_pre(g, &ea->type, e->where)) return false;
+ cgen_write(g, "(*)");
+ if (!cgen_type_post(g, &ea->type, e->where)) return false;
+ cgen_write(g, ")of_.data) + ");
+ if (ea->index)
+ cgen_ident(g, ea->index);
+ else
+ cgen_write(g, "i_");
+ } else {
+ cgen_write(g, "&of_[");
+ if (ea->index)
+ cgen_ident(g, ea->index);
+ else
+ cgen_write(g, "i_");
+ cgen_write(g, "]");
+ }
+ cgen_write(g, "; ");
if (!cgen_type_pre(g, &ea->type, e->where)) return false;
cgen_write(g, " ");
cgen_ident(g, ea->value);
if (!cgen_type_post(g, &ea->type, e->where)) return false;
- cgen_write(g, " = ");
- cgen_ident_id(g, from_id);
- cgen_write(g, " + ");
- if (ea->index)
- cgen_ident(g, ea->index);
- else
- cgen_ident_id(g, ea->c.index_id);
- cgen_write(g, ";");
- cgen_nl(g);
- } else {
- /* necessary for iterating over, e.g., an array of arrays */
- Expression set;
- set.flags = 0;
- set.kind = EXPR_IDENT;
- set.ident = ea->value;
-
- Expression to;
- to.flags = 0;
- to.kind = EXPR_BINARY_OP;
- to.binary.op = BINARY_AT_INDEX;
- to.binary.lhs = ea->of;
- to.binary.rhs = err_malloc(sizeof(Expression));
- to.binary.rhs->flags = 0;
- to.binary.rhs->kind = EXPR_IDENT;
- if (ea->index)
- to.binary.rhs->ident = ea->index;
- else
- to.binary.rhs->ident = cgen_ident_id_to_ident(g, ea->c.id);
- if (!cgen_set(g, &set, NULL, &to, NULL))
+ cgen_write(g, "; ");
+ Expression set_expr;
+ set_expr.kind = EXPR_IDENT;
+ set_expr.ident = ea->value;
+ set_expr.type = ea->type;
+ set_expr.flags = EXPR_FLAG_FOUND_TYPE;
+ if (!cgen_set(g, &set_expr, NULL, NULL, "(*p_)"))
return false;
}
}
if (!cgen_block(g, &ea->body, ret_name, CGEN_BLOCK_NOBRACES))
return false;
- cgen_write(g, "}");
+ cgen_write(g, "}}");
each_exit(e);
} break;
case EXPR_BLOCK:
diff --git a/eval.c b/eval.c
index 0430cbd..cf74f39 100644
--- a/eval.c
+++ b/eval.c
@@ -236,6 +236,13 @@ static void u64_to_val(Value *v, BuiltinType v_type, U64 x) {
static bool val_is_nonnegative(Value *v, Type *t) {
assert(t->kind == TYPE_BUILTIN);
+ switch (t->builtin) {
+ case BUILTIN_BOOL: assert(0); return false;
+ case BUILTIN_CHAR: return v->charv >= 0;
+ case BUILTIN_F32: return v->f32 >= 0;
+ case BUILTIN_F64: return v->f64 >= 0;
+ default: break;
+ }
if (!type_builtin_is_signed(t->builtin))
return true;
return val_to_i64(v, t->builtin) >= 0;
diff --git a/main.c b/main.c
index deb038e..9c61e10 100644
--- a/main.c
+++ b/main.c
@@ -2,6 +2,7 @@
TODO:
each
compile-time each
+allow just each arr { ... }
each pointer
compile-time each pointer
prevent each x := x
diff --git a/parse.c b/parse.c
index 9a05082..414fe09 100644
--- a/parse.c
+++ b/parse.c
@@ -1076,6 +1076,7 @@ static bool parse_expr(Parser *p, Expression *e, Token *end) {
ea->index = t->token->ident;
if (ident_eq_str(ea->index, "_")) /* ignore index */
ea->index = NULL;
+ t->token++;
} else {
tokr_err(t, "Expected identifier after , in each statement.");
return false;
diff --git a/test.toc b/test.toc
index cce5421..b68da85 100644
--- a/test.toc
+++ b/test.toc
@@ -4,13 +4,42 @@ puti @= fn(x: int) {
");
};
+putf @= fn(x: float) {
+ #C("printf(\"%f\\n\", (double)x);
+");
+};
main @= fn() {
- each i := 1..10 {
+ each i := 1..4 {
puti(i);
}
- each i := 10,-1..1 {
+ each i := 4,-1..1 {
puti(i);
}
+ each i := 1.0..4.0 {
+ putf(i);
+ }
+ each i := 7.0,-1..4.0 {
+ putf(i);
+ }
+ // each i := 0.0,-3.0.. { putf(i); }
+ foo := new(int, 10);
+ each _, i := foo {
+ foo[i] = i;
+ };
+ each x := foo {
+ puti(x);
+ }
+ each _ := foo {
+ #C("puts(\"Hello!\")");
+ }
+ bar : [10]int;
+ each _, i := foo {
+ bar[i] = i*i*i;
+ };
+ each x := bar {
+ puti(x);
+ }
+
};
diff --git a/types.c b/types.c
index 7b8e9fb..02c32bc 100644
--- a/types.c
+++ b/types.c
@@ -766,7 +766,8 @@ static bool types_expr(Typer *tr, Expression *e) {
info_print(ea->range.step->where, "Note that the step of an each loop must be a compile-time constant.");
return false;
}
- ea->range.stepval = stepval;
+ val_cast(stepval, &ea->range.step->type, stepval, &ea->type);
+ ea->range.stepval = stepval;
}
if (!each_enter(e, SCOPE_FLAG_CHECK_REDECL)) return false;
if (!types_block(tr, &ea->body)) return false;
diff --git a/types.h b/types.h
index d81ea05..cc79b87 100644
--- a/types.h
+++ b/types.h
@@ -427,7 +427,6 @@ typedef struct EachExpr {
U16 flags;
struct {
IdentID id;
- IdentID index_id; /* only set if index is NULL */
} c;
Type type;
Identifier index; /* NULL = no index */