summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--eval.c5
-rw-r--r--parse.c28
-rw-r--r--test.toc6
-rw-r--r--types.c9
4 files changed, 42 insertions, 6 deletions
diff --git a/eval.c b/eval.c
index c6a659a..9764c1f 100644
--- a/eval.c
+++ b/eval.c
@@ -136,8 +136,9 @@ static bool eval_expr(Expression *e, Value *v) {
case EXPR_FN:
v->fn = *e->fn;
return true;
- case EXPR_IF: {
- err_print(e->where, "compile time if not supported yet."); /* TODO */
+ case EXPR_IF:
+ case EXPR_WHILE: {
+ err_print(e->where, "compile time if/while not supported yet."); /* TODO */
} break;
case EXPR_CALL:
err_print(e->where, "Compile time function calling not supported yet."); /* TODO */
diff --git a/parse.c b/parse.c
index a753bda..63a8637 100644
--- a/parse.c
+++ b/parse.c
@@ -68,6 +68,7 @@ typedef enum {
EXPR_BINARY_OP,
EXPR_UNARY_OP,
EXPR_IF,
+ EXPR_WHILE,
EXPR_FN,
EXPR_CALL,
EXPR_BLOCK,
@@ -106,6 +107,11 @@ typedef struct {
Block body;
} IfExpr;
+typedef struct {
+ struct Expression *cond;
+ Block body;
+} WhileExpr;
+
#define EXPR_FLAG_FOUND_TYPE 0x01
typedef struct Expression {
@@ -130,6 +136,7 @@ typedef struct Expression {
DirectExpr direct;
Identifier ident;
IfExpr if_;
+ WhileExpr while_;
struct FnExpr *fn;
Block block;
};
@@ -799,7 +806,21 @@ static bool parse_expr(Parser *p, Expression *e, Token *end) {
return true;
}
case KW_WHILE: {
- /* TODO */
+ e->kind = EXPR_WHILE;
+ WhileExpr *w = &e->while_;
+ t->token++;
+ Token *cond_end = expr_find_end(p, EXPR_CAN_END_WITH_LBRACE, NULL);
+ if (!cond_end) return false;
+ if (!token_is_kw(cond_end, KW_LBRACE)) {
+ t->token = cond_end;
+ tokr_err(t, "Expected { to open while body.");
+ return false;
+ }
+ Expression *cond = parser_new_expr(p);
+ w->cond = cond;
+ if (!parse_expr(p, cond, cond_end))
+ return false;
+ if (!parse_block(p, &w->body)) return false;
return true;
}
default: break;
@@ -1429,6 +1450,11 @@ static void fprint_expr(FILE *out, Expression *e) {
if (e->if_.next_elif)
fprint_expr(out, e->if_.next_elif);
break;
+ case EXPR_WHILE:
+ fprintf(out, "while ");
+ fprint_expr(out, e->while_.cond);
+ fprint_block(out, &e->while_.body);
+ break;
case EXPR_CALL:
fprint_expr(out, e->call.fn);
fprint_args(out, &e->call.args);
diff --git a/test.toc b/test.toc
index 94e8ff7..846008d 100644
--- a/test.toc
+++ b/test.toc
@@ -1,10 +1,10 @@
main @= fn() {
{
- i := 0;
- asdf := if (fn(i: i64) i64 { i - 1024 })(i) {
+ i := 1;
+ asdf := while (fn(i: i64) i64 { i - 1024 })(i) {
i = i * 2;
i
- } else { 0 };
+ };
}
(fn(){})();
};
diff --git a/types.c b/types.c
index 7e9e929..021c3ee 100644
--- a/types.c
+++ b/types.c
@@ -379,6 +379,15 @@ static bool type_of_expr(Typer *tr, Expression *e) {
return false;
}
} break;
+ case EXPR_WHILE: {
+ WhileExpr *w = &e->while_;
+ if (!types_block(tr, &w->body))
+ return false;
+ if (!type_of_expr()) {
+ /* TODO: is type_of_expr really necessary? why not just never descend into fns unless it's a decl? */
+ }
+ *t = w->body.ret_expr->type;
+ } break;
case EXPR_CALL: {
CallExpr *c = &e->call;
Expression *f = c->fn;