aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGinger Bill <bill@gingerbill.org>2017-01-27 17:43:42 +0000
committerGinger Bill <bill@gingerbill.org>2017-01-27 17:43:42 +0000
commit92453369c5558feaaaa116fbc54968b087e1aeab (patch)
treea00501fdc52f69c7dd7c415e103b9b13d51e6ad5 /src
parent832009f33acc573d44dd9dfb470ad8fef72216ff (diff)
Remove while loop and readd c-style for loops i.e. all loops are just `for`
Diffstat (limited to 'src')
-rw-r--r--src/check_stmt.c36
-rw-r--r--src/ir.c44
-rw-r--r--src/parser.c161
-rw-r--r--src/tokenizer.c1
4 files changed, 159 insertions, 83 deletions
diff --git a/src/check_stmt.c b/src/check_stmt.c
index fd8e22908..3a1fdf023 100644
--- a/src/check_stmt.c
+++ b/src/check_stmt.c
@@ -127,13 +127,13 @@ bool check_is_terminating(AstNode *node) {
}
case_end;
- case_ast_node(ws, WhileStmt, node);
- if (ws->cond != NULL && !check_has_break(ws->body, true)) {
- return check_is_terminating(ws->body);
+ case_ast_node(fs, ForStmt, node);
+ if (!check_has_break(fs->body, true)) {
+ return check_is_terminating(fs->body);
}
case_end;
- case_ast_node(rs, ForStmt, node);
+ case_ast_node(rs, RangeStmt, node);
if (!check_has_break(rs->body, true)) {
return check_is_terminating(rs->body);
}
@@ -566,27 +566,33 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
}
case_end;
- case_ast_node(ws, WhileStmt, node);
+ case_ast_node(fs, ForStmt, node);
u32 new_flags = mod_flags | Stmt_BreakAllowed | Stmt_ContinueAllowed;
check_open_scope(c, node);
- if (ws->init != NULL) {
- check_stmt(c, ws->init, 0);
+ if (fs->init != NULL) {
+ check_stmt(c, fs->init, 0);
}
- if (ws->cond) {
- Operand operand = {Addressing_Invalid};
- check_expr(c, &operand, ws->cond);
- if (operand.mode != Addressing_Invalid &&
- !is_type_boolean(operand.type)) {
- error_node(ws->cond, "Non-boolean condition in `while` statement");
+ if (fs->cond != NULL) {
+ Operand o = {Addressing_Invalid};
+ check_expr(c, &o, fs->cond);
+ if (o.mode != Addressing_Invalid && !is_type_boolean(o.type)) {
+ error_node(fs->cond, "Non-boolean condition in `for` statement");
+ }
+ }
+ if (fs->post != NULL) {
+ check_stmt(c, fs->post, 0);
+
+ if (fs->post->kind != AstNode_AssignStmt) {
+ error_node(fs->post, "`for` statement post statement must be an assignment");
}
}
- check_stmt(c, ws->body, new_flags);
+ check_stmt(c, fs->body, new_flags);
check_close_scope(c);
case_end;
- case_ast_node(rs, ForStmt, node);
+ case_ast_node(rs, RangeStmt, node);
u32 new_flags = mod_flags | Stmt_BreakAllowed | Stmt_ContinueAllowed;
check_open_scope(c, node);
diff --git a/src/ir.c b/src/ir.c
index 29e81c899..d2f423d4e 100644
--- a/src/ir.c
+++ b/src/ir.c
@@ -4470,44 +4470,54 @@ void ir_build_stmt_internal(irProcedure *proc, AstNode *node) {
proc->curr_block = done;
case_end;
- case_ast_node(ws, WhileStmt, node);
- ir_emit_comment(proc, str_lit("WhileStmt"));
- if (ws->init != NULL) {
- irBlock *init = ir_add_block(proc, node, "while.init");
+ case_ast_node(fs, ForStmt, node);
+ ir_emit_comment(proc, str_lit("ForStmt"));
+ if (fs->init != NULL) {
+ irBlock *init = ir_add_block(proc, node, "for.init");
ir_emit_jump(proc, init);
proc->curr_block = init;
- ir_build_stmt(proc, ws->init);
+ ir_build_stmt(proc, fs->init);
}
- irBlock *body = ir_add_block(proc, node, "while.body");
- irBlock *done = ir_add_block(proc, node, "while.done"); // NOTE(bill): Append later
-
+ irBlock *body = ir_add_block(proc, node, "for.body");
+ irBlock *done = ir_add_block(proc, node, "for.done"); // NOTE(bill): Append later
irBlock *loop = body;
-
- if (ws->cond != NULL) {
- loop = ir_add_block(proc, node, "while.loop");
+ if (fs->cond != NULL) {
+ loop = ir_add_block(proc, node, "for.loop");
+ }
+ irBlock *cont = loop;
+ if (fs->post != NULL) {
+ cont = ir_add_block(proc, node, "for.post");
}
ir_emit_jump(proc, loop);
proc->curr_block = loop;
+
if (loop != body) {
- ir_build_cond(proc, ws->cond, body, done);
+ ir_build_cond(proc, fs->cond, body, done);
proc->curr_block = body;
}
- ir_push_target_list(proc, done, loop, NULL);
+ ir_push_target_list(proc, done, cont, NULL);
ir_open_scope(proc);
- ir_build_stmt(proc, ws->body);
+ ir_build_stmt(proc, fs->body);
ir_close_scope(proc, irDeferExit_Default, NULL);
ir_pop_target_list(proc);
- ir_emit_jump(proc, loop);
+
+ ir_emit_jump(proc, cont);
+
+ if (fs->post != NULL) {
+ proc->curr_block = cont;
+ ir_build_stmt(proc, fs->post);
+ ir_emit_jump(proc, loop);
+ }
proc->curr_block = done;
case_end;
- case_ast_node(rs, ForStmt, node);
- ir_emit_comment(proc, str_lit("ForStmt"));
+ case_ast_node(rs, RangeStmt, node);
+ ir_emit_comment(proc, str_lit("RangeStmt"));
Type *val_type = NULL;
Type *idx_type = NULL;
diff --git a/src/parser.c b/src/parser.c
index b3b1822c2..0a9b39ea9 100644
--- a/src/parser.c
+++ b/src/parser.c
@@ -221,16 +221,18 @@ AST_NODE_KIND(_ComplexStmtBegin, "", i32) \
Token token; \
AstNodeArray results; \
}) \
- AST_NODE_KIND(WhileStmt, "while statement", struct { \
+ AST_NODE_KIND(ForStmt, "for statement", struct { \
Token token; \
AstNode *init; \
AstNode *cond; \
+ AstNode *post; \
AstNode *body; \
}) \
- AST_NODE_KIND(ForStmt, "range statement", struct { \
+ AST_NODE_KIND(RangeStmt, "range statement", struct { \
Token token; \
AstNode *value; \
AstNode *index; \
+ Token in_token; \
AstNode *expr; \
AstNode *body; \
}) \
@@ -501,8 +503,10 @@ Token ast_node_token(AstNode *node) {
return node->WhenStmt.token;
case AstNode_ReturnStmt:
return node->ReturnStmt.token;
- case AstNode_WhileStmt:
- return node->WhileStmt.token;
+ case AstNode_ForStmt:
+ return node->ForStmt.token;
+ case AstNode_RangeStmt:
+ return node->RangeStmt.token;
case AstNode_MatchStmt:
return node->MatchStmt.token;
case AstNode_CaseClause:
@@ -904,24 +908,28 @@ AstNode *make_return_stmt(AstFile *f, Token token, AstNodeArray results) {
return result;
}
-AstNode *make_while_stmt(AstFile *f, Token token, AstNode *init, AstNode *cond, AstNode *body) {
- AstNode *result = make_node(f, AstNode_WhileStmt);
- result->WhileStmt.token = token;
- result->WhileStmt.init = init;
- result->WhileStmt.cond = cond;
- result->WhileStmt.body = body;
- return result;
-}
-AstNode *make_for_stmt(AstFile *f, Token token, AstNode *value, AstNode *index, AstNode *expr, AstNode *body) {
+
+AstNode *make_for_stmt(AstFile *f, Token token, AstNode *init, AstNode *cond, AstNode *post, AstNode *body) {
AstNode *result = make_node(f, AstNode_ForStmt);
result->ForStmt.token = token;
- result->ForStmt.value = value;
- result->ForStmt.index = index;
- result->ForStmt.expr = expr;
+ result->ForStmt.init = init;
+ result->ForStmt.cond = cond;
+ result->ForStmt.post = post;
result->ForStmt.body = body;
return result;
}
+AstNode *make_range_stmt(AstFile *f, Token token, AstNode *value, AstNode *index, Token in_token, AstNode *expr, AstNode *body) {
+ AstNode *result = make_node(f, AstNode_RangeStmt);
+ result->RangeStmt.token = token;
+ result->RangeStmt.value = value;
+ result->RangeStmt.index = index;
+ result->RangeStmt.in_token = in_token;
+ result->RangeStmt.expr = expr;
+ result->RangeStmt.body = body;
+ return result;
+}
+
AstNode *make_match_stmt(AstFile *f, Token token, AstNode *init, AstNode *tag, AstNode *body) {
AstNode *result = make_node(f, AstNode_MatchStmt);
result->MatchStmt.token = token;
@@ -1258,7 +1266,6 @@ void fix_advance_to_next_stmt(AstFile *f) {
case Token_if:
case Token_when:
case Token_return:
- case Token_while:
case Token_range:
case Token_match:
case Token_defer:
@@ -1626,7 +1633,7 @@ void parse_proc_tags(AstFile *f, u64 *tags, AstNode **foreign_library_token, Str
AstNodeArray parse_lhs_expr_list(AstFile *f);
AstNodeArray parse_rhs_expr_list(AstFile *f);
-AstNode * parse_simple_stmt (AstFile *f);
+AstNode * parse_simple_stmt (AstFile *f, bool in_stmt_ok);
AstNode * parse_type (AstFile *f);
AstNode *convert_stmt_to_expr(AstFile *f, AstNode *statement, String kind) {
@@ -1673,7 +1680,7 @@ AstNode *parse_if_expr(AstFile *f) {
if (allow_token(f, Token_Semicolon)) {
cond = parse_expr(f, false);
} else {
- init = parse_simple_stmt(f);
+ init = parse_simple_stmt(f, false);
if (allow_token(f, Token_Semicolon)) {
cond = parse_expr(f, false);
} else {
@@ -2261,7 +2268,8 @@ AstNode *parse_value_decl(AstFile *f, AstNodeArray lhs) {
return make_value_decl(f, is_mutable, lhs, type, values);
}
-AstNode *parse_simple_stmt(AstFile *f) {
+
+AstNode *parse_simple_stmt(AstFile *f, bool in_stmt_ok) {
AstNodeArray lhs = parse_lhs_expr_list(f);
Token token = f->curr_token;
switch (token.kind) {
@@ -2293,6 +2301,28 @@ AstNode *parse_simple_stmt(AstFile *f) {
return make_assign_stmt(f, token, lhs, rhs);
} break;
+ case Token_in:
+ if (in_stmt_ok) {
+ allow_token(f, Token_in);
+ AstNode *expr = parse_expr(f, false);
+ switch (f->curr_token.kind) {
+ case Token_HalfOpenRange:
+ case Token_Ellipsis: {
+ Token op = f->curr_token;
+ next_token(f);
+ AstNode *right = parse_expr(f, false);
+ expr = make_interval_expr(f, op, expr, right);
+ } break;
+ }
+
+ AstNodeArray rhs = {0};
+ array_init_count(&rhs, heap_allocator(), 1);
+ rhs.e[0] = expr;
+
+ return make_assign_stmt(f, token, lhs, rhs);
+ }
+ break;
+
case Token_Colon:
return parse_value_decl(f, lhs);
}
@@ -2782,7 +2812,7 @@ AstNode *parse_if_stmt(AstFile *f) {
if (allow_token(f, Token_Semicolon)) {
cond = parse_expr(f, false);
} else {
- init = parse_simple_stmt(f);
+ init = parse_simple_stmt(f, false);
if (allow_token(f, Token_Semicolon)) {
cond = parse_expr(f, false);
} else {
@@ -2900,47 +2930,78 @@ AstNode *parse_give_stmt(AstFile *f) {
return make_expr_stmt(f, ge);
}
-AstNode *parse_while_stmt(AstFile *f) {
+AstNode *parse_for_stmt(AstFile *f) {
if (f->curr_proc == NULL) {
- syntax_error(f->curr_token, "You cannot use a while statement in the file scope");
+ syntax_error(f->curr_token, "You cannot use a for statement in the file scope");
return make_bad_stmt(f, f->curr_token, f->curr_token);
}
- Token token = expect_token(f, Token_while);
+ Token token = expect_token(f, Token_for);
AstNode *init = NULL;
AstNode *cond = NULL;
+ AstNode *post = NULL;
AstNode *body = NULL;
+ bool is_range = false;
- isize prev_level = f->expr_level;
- f->expr_level = -1;
-
+ if (f->curr_token.kind != Token_OpenBrace) {
+ isize prev_level = f->expr_level;
+ f->expr_level = -1;
+ if (f->curr_token.kind != Token_Semicolon) {
+ cond = parse_simple_stmt(f, true);
+ if (cond->kind == AstNode_AssignStmt &&
+ cond->AssignStmt.op.kind == Token_in) {
+ is_range = true;
+ }
+ }
- cond = parse_simple_stmt(f);
- if (is_ast_node_complex_stmt(cond)) {
- syntax_error(f->curr_token, "You are not allowed that type of statement in a while statement, it is too complex!");
- }
+ if (!is_range && f->curr_token.kind == Token_Semicolon) {
+ next_token(f);
+ init = cond;
+ cond = NULL;
+ if (f->curr_token.kind != Token_Semicolon) {
+ cond = parse_simple_stmt(f, false);
+ }
+ expect_semicolon(f, cond);
+ if (f->curr_token.kind != Token_OpenBrace) {
+ post = parse_simple_stmt(f, false);
+ }
+ }
- if (allow_token(f, Token_Semicolon)) {
- init = cond;
- cond = parse_simple_stmt(f);
+ f->expr_level = prev_level;
}
- f->expr_level = prev_level;
body = parse_block_stmt(f, false);
- cond = convert_stmt_to_expr(f, cond, str_lit("boolean expression"));
-
- return make_while_stmt(f, token, init, cond, body);
-}
-
+ if (is_range) {
+ GB_ASSERT(cond->kind == AstNode_AssignStmt);
+ Token in_token = cond->AssignStmt.op;
+ AstNode *value = NULL;
+ AstNode *index = NULL;
+ switch (cond->AssignStmt.lhs.count) {
+ case 1:
+ value = cond->AssignStmt.lhs.e[0];
+ break;
+ case 2:
+ value = cond->AssignStmt.lhs.e[0];
+ index = cond->AssignStmt.lhs.e[1];
+ break;
+ default:
+ error_node(cond, "Expected at 1 or 2 identifiers");
+ return make_bad_stmt(f, token, f->curr_token);
+ }
-AstNode *parse_for_stmt(AstFile *f) {
- if (f->curr_proc == NULL) {
- syntax_error(f->curr_token, "You cannot use a for statement in the file scope");
- return make_bad_stmt(f, f->curr_token, f->curr_token);
+ AstNode *rhs = NULL;
+ if (cond->AssignStmt.rhs.count > 0) {
+ rhs = cond->AssignStmt.rhs.e[0];
+ }
+ return make_range_stmt(f, token, value, index, in_token, rhs, body);
}
+ cond = convert_stmt_to_expr(f, cond, str_lit("boolean expression"));
+ return make_for_stmt(f, token, init, cond, post, body);
+
+#if 0
Token token = expect_token(f, Token_for);
AstNodeArray names = parse_ident_list(f);
parse_check_name_list_for_reserves(f, names);
@@ -2977,7 +3038,8 @@ AstNode *parse_for_stmt(AstFile *f) {
return make_bad_stmt(f, token, f->curr_token);
}
- return make_for_stmt(f, token, value, index, expr, body);
+ return make_range_stmt(f, token, value, index, expr, body);
+#endif
}
AstNode *parse_case_clause(AstFile *f) {
@@ -3030,7 +3092,7 @@ AstNode *parse_match_stmt(AstFile *f) {
AstNode *var = parse_identifier(f);
expect_token_after(f, Token_in, "match type name");
- tag = parse_simple_stmt(f);
+ tag = parse_simple_stmt(f, false);
f->expr_level = prev_level;
@@ -3052,13 +3114,13 @@ AstNode *parse_match_stmt(AstFile *f) {
isize prev_level = f->expr_level;
f->expr_level = -1;
if (f->curr_token.kind != Token_Semicolon) {
- tag = parse_simple_stmt(f);
+ tag = parse_simple_stmt(f, false);
}
if (allow_token(f, Token_Semicolon)) {
init = tag;
tag = NULL;
if (f->curr_token.kind != Token_OpenBrace) {
- tag = parse_simple_stmt(f);
+ tag = parse_simple_stmt(f, false);
}
}
@@ -3151,13 +3213,12 @@ AstNode *parse_stmt(AstFile *f) {
case Token_Sub:
case Token_Xor:
case Token_Not:
- s = parse_simple_stmt(f);
+ s = parse_simple_stmt(f, false);
expect_semicolon(f, s);
return s;
case Token_if: return parse_if_stmt(f);
case Token_when: return parse_when_stmt(f);
- case Token_while: return parse_while_stmt(f);
case Token_for: return parse_for_stmt(f);
case Token_match: return parse_match_stmt(f);
case Token_defer: return parse_defer_stmt(f);
diff --git a/src/tokenizer.c b/src/tokenizer.c
index c21c09942..8fa836941 100644
--- a/src/tokenizer.c
+++ b/src/tokenizer.c
@@ -92,7 +92,6 @@ TOKEN_KIND(Token__KeywordBegin, "_KeywordBegin"), \
TOKEN_KIND(Token_then, "then"), \
TOKEN_KIND(Token_if, "if"), \
TOKEN_KIND(Token_else, "else"), \
- TOKEN_KIND(Token_while, "while"), \
TOKEN_KIND(Token_for, "for"), \
TOKEN_KIND(Token_in, "in"), \
TOKEN_KIND(Token_when, "when"), \