diff options
author | Leo Tenenbaum <pommicket@gmail.com> | 2019-09-23 11:22:54 -0400 |
---|---|---|
committer | Leo Tenenbaum <pommicket@gmail.com> | 2019-09-23 11:22:54 -0400 |
commit | f68d40f063608c15d5cf7db2dd506f6676bbd440 (patch) | |
tree | 32924bc3b80abda66a92feb3714b74d47459ab6f | |
parent | 7910074a8cc73f6ac5b8345851ff16058e60272b (diff) |
improved if/elif/else; started while
-rw-r--r-- | parse.c | 18 | ||||
-rw-r--r-- | test.toc | 8 | ||||
-rw-r--r-- | tokenizer.c | 5 | ||||
-rw-r--r-- | types.c | 76 |
4 files changed, 54 insertions, 53 deletions
@@ -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; } @@ -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"}; @@ -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: { |