summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLeo Tenenbaum <pommicket@gmail.com>2019-09-23 11:22:54 -0400
committerLeo Tenenbaum <pommicket@gmail.com>2019-09-23 11:22:54 -0400
commitf68d40f063608c15d5cf7db2dd506f6676bbd440 (patch)
tree32924bc3b80abda66a92feb3714b74d47459ab6f
parent7910074a8cc73f6ac5b8345851ff16058e60272b (diff)
improved if/elif/else; started while
-rw-r--r--parse.c18
-rw-r--r--test.toc8
-rw-r--r--tokenizer.c5
-rw-r--r--types.c76
4 files changed, 54 insertions, 53 deletions
diff --git a/parse.c b/parse.c
index f4408eb..49b13e8 100644
--- a/parse.c
+++ b/parse.c
@@ -100,14 +100,7 @@ typedef struct {
Array args; /* of Expression */
} CallExpr;
-typedef enum {
- IFEXPR_IF,
- IFEXPR_ELIF,
- IFEXPR_ELSE
-} IfExprKind;
-
typedef struct {
- IfExprKind kind;
struct Expression *cond; /* NULL = this is an else */
struct Expression *next_elif; /* next elif/else of this statement */
Block body;
@@ -752,7 +745,6 @@ static bool parse_expr(Parser *p, Expression *e, Token *end) {
case KW_IF: {
IfExpr *i = &e->if_;
e->kind = EXPR_IF;
- i->kind = IFEXPR_IF;
t->token++;
Token *cond_end = expr_find_end(p, EXPR_CAN_END_WITH_LBRACE, NULL);
if (!cond_end) return false;
@@ -772,7 +764,7 @@ static bool parse_expr(Parser *p, Expression *e, Token *end) {
curr->next_elif = NULL;
break;
}
- if (curr->kind == IFEXPR_ELSE) {
+ if (curr->cond == NULL) {
tokr_err(t, "You can't have more elif/elses after an else.");
return false;
}
@@ -785,7 +777,6 @@ static bool parse_expr(Parser *p, Expression *e, Token *end) {
if (is_else) {
t->token++;
nexti->cond = NULL;
- nexti->kind = IFEXPR_ELSE;
if (!parse_block(p, &nexti->body)) return false;
} else {
/* elif */
@@ -801,13 +792,16 @@ static bool parse_expr(Parser *p, Expression *e, Token *end) {
if (!parse_expr(p, cond, cond_end))
return false;
nexti->cond = cond;
- nexti->kind = IFEXPR_ELIF;
if (!parse_block(p, &nexti->body)) return false;
}
curr = nexti;
}
return true;
}
+ case KW_WHILE: {
+ /* TODO */
+ return true;
+ }
default: break;
}
@@ -1020,7 +1014,7 @@ static bool parse_expr(Parser *p, Expression *e, Token *end) {
}
return true;
}
- tokr_err(t, "Not implemented yet.");
+ tokr_err(t, "Unrecognized expression.");
t->token = end + 1;
return false;
}
diff --git a/test.toc b/test.toc
index 31d337a..788cdcd 100644
--- a/test.toc
+++ b/test.toc
@@ -1,11 +1,13 @@
main @= fn() {
- x := 1;
- foo := if x {
+ //x := 1;
+ /*foo := if x {
9
} elif 7-3 {
5
} elif main {
3
- } else {7 };
+ } else {7 };*/
+
+ bar := if 1 { 9 };
};
diff --git a/tokenizer.c b/tokenizer.c
index 96f62e0..e62b4fe 100644
--- a/tokenizer.c
+++ b/tokenizer.c
@@ -37,6 +37,7 @@ typedef enum {
KW_IF,
KW_ELIF,
KW_ELSE,
+ KW_WHILE,
KW_FN,
KW_INT,
KW_I8,
@@ -55,8 +56,8 @@ typedef enum {
static const char *keywords[KW_COUNT] =
{";", "=", ":", "@", ",", "(", ")", "{", "}", "[", "]", "==", "<", "<=", "+", "-", "*",
- "&", "/", "if", "elif", "else", "fn", "int", "i8", "i16", "i32", "i64", "u8", "u16",
- "u32", "u64", "float", "f32", "f64"};
+ "&", "/", "if", "elif", "else", "while", "fn", "int", "i8", "i16", "i32", "i64", "u8",
+ "u16", "u32", "u64", "float", "f32", "f64"};
static const char *directives[DIRECT_COUNT] =
{"C"};
diff --git a/types.c b/types.c
index ad98da1..8c42d7e 100644
--- a/types.c
+++ b/types.c
@@ -333,46 +333,50 @@ static bool type_of_expr(Typer *tr, Expression *e) {
} break;
case EXPR_IF: {
IfExpr *i = &e->if_;
- if (i->cond) {
- if (!type_of_expr(tr, i->cond))
- return false;
- if (!type_can_be_truthy(&i->cond->type)) {
- char *s = type_to_str(&i->cond->type);
- err_print(i->cond->where, "Type %s cannot be the condition of an if statement.", s);
- free(s);
- return false;
- }
- }
- if (!types_block(tr, &i->body))
+ IfExpr *curr = i;
+ Type *curr_type = t;
+ bool has_else = false;
+ if (!types_block(tr, &curr->body))
return false;
- if (i->body.ret_expr)
- *t = i->body.ret_expr->type;
- else
- t->kind = TYPE_VOID;
- if (i->next_elif) {
- if (!type_of_expr(tr, i->next_elif))
- return false;
- if (!type_eq(t, &i->next_elif->type)) {
- char *this_type = type_to_str(t);
- char *that_type = type_to_str(&i->next_elif->type);
+ *t = curr->body.ret_expr->type;
+ while (1) {
+ if (curr->cond) {
+ if (!type_of_expr(tr, curr->cond))
+ return false;
+ if (!type_can_be_truthy(&curr->cond->type)) {
+ char *s = type_to_str(&curr->cond->type);
+ err_print(curr->cond->where, "Type %s cannot be the condition of an if statement.", s);
+ free(s);
+ return false;
+ }
+ } else {
+ has_else = true;
+ }
+ if (curr->next_elif) {
+ IfExpr *nexti = &curr->next_elif->if_;
+ Type *next_type = &curr->next_elif->type;
+ if (!types_block(tr, &nexti->body)) {
+ return false;
+ }
+ *next_type = nexti->body.ret_expr->type;
+ if (!type_eq(curr_type, next_type)) {
+ char *currstr = type_to_str(curr_type);
+ char *nextstr = type_to_str(next_type);
+ err_print(curr->next_elif->where, "Mismatched types in if/elif/else chain. Previous block was of type %s, but this one is of type %s.", currstr, nextstr);
+ free(currstr);
+ free(nextstr);
+ return false;
+ }
+ curr = nexti;
- err_print(e->where, "elif/else block of an if statement has a different type. Expected %s, but got %s.", that_type, this_type);
- return false;
+ } else {
+ break;
}
}
- if (i->kind == IFEXPR_IF && t->kind != TYPE_VOID) {
- /* make sure there's an else at the end of this chain */
- bool has_else = false;
- IfExpr *curr = i;
- do {
- curr = &curr->next_elif->if_;
- if (curr->kind == IFEXPR_ELSE)
- has_else = true;
- } while (curr->next_elif);
- if (!has_else) {
- err_print(e->where, "non-void if block with no else");
- return false;
- }
+
+ if (!has_else && t->kind == TYPE_VOID) {
+ err_print(e->where, "non-void if block with no else");
+ return false;
}
} break;
case EXPR_CALL: {