From 6ffaf4c2e26e90f7e75d2dd5461addcdb8741c85 Mon Sep 17 00:00:00 2001 From: Josh Wolfe Date: Mon, 13 Nov 2017 22:56:20 -0700 Subject: [PATCH] parsec supports do loop --- src/parsec.cpp | 58 ++++++++++++++++++++++++++++++++++++++++++++++--- test/parsec.zig | 27 +++++++++++++++++++++++ 2 files changed, 82 insertions(+), 3 deletions(-) diff --git a/src/parsec.cpp b/src/parsec.cpp index 1cc4a8c184..273222b2d0 100644 --- a/src/parsec.cpp +++ b/src/parsec.cpp @@ -1987,6 +1987,59 @@ static AstNode *trans_unary_expr_or_type_trait_expr(Context *c, AstNode *block, return node; } +static AstNode *trans_do_loop(Context *c, AstNode *block, DoStmt *stmt) { + stmt->getBody(); + stmt->getCond(); + + AstNode *while_node = trans_create_node(c, NodeTypeWhileExpr); + + AstNode *true_node = trans_create_node(c, NodeTypeBoolLiteral); + true_node->data.bool_literal.value = true; + while_node->data.while_expr.condition = true_node; + + AstNode *body_node; + if (stmt->getBody()->getStmtClass() == Stmt::CompoundStmtClass) { + // there's already a block in C, so we'll append our condition to it. + // c: do { + // c: a; + // c: b; + // c: } while(c); + // zig: while (true) { + // zig: a; + // zig: b; + // zig: if (!cond) break; + // zig: } + body_node = trans_stmt(c, false, block, stmt->getBody(), TransRValue); + if (body_node == nullptr) return nullptr; + assert(body_node->type == NodeTypeBlock); + } else { + // the C statement is without a block, so we need to create a block to contain it. + // c: do + // c: a; + // c: while(c); + // zig: while (true) { + // zig: a; + // zig: if (!cond) break; + // zig: } + body_node = trans_create_node(c, NodeTypeBlock); + AstNode *child_statement = trans_stmt(c, false, body_node, stmt->getBody(), TransRValue); + if (child_statement == nullptr) return nullptr; + body_node->data.block.statements.append(child_statement); + } + + // if (!cond) break; + AstNode *condition_node = trans_expr(c, true, body_node, stmt->getCond(), TransRValue); + if (condition_node == nullptr) return nullptr; + AstNode *terminator_node = trans_create_node(c, NodeTypeIfBoolExpr); + terminator_node->data.if_bool_expr.condition = trans_create_node_prefix_op(c, PrefixOpBoolNot, condition_node); + terminator_node->data.if_bool_expr.then_block = trans_create_node(c, NodeTypeBreak); + body_node->data.block.statements.append(terminator_node); + + while_node->data.while_expr.body = body_node; + + return while_node; +} + static AstNode *trans_stmt(Context *c, bool result_used, AstNode *block, Stmt *stmt, TransLRValue lrvalue) { Stmt::StmtClass sc = stmt->getStmtClass(); switch (sc) { @@ -2026,6 +2079,8 @@ static AstNode *trans_stmt(Context *c, bool result_used, AstNode *block, Stmt *s return trans_c_style_cast_expr(c, result_used, block, (CStyleCastExpr *)stmt, lrvalue); case Stmt::UnaryExprOrTypeTraitExprClass: return trans_unary_expr_or_type_trait_expr(c, block, (UnaryExprOrTypeTraitExpr *)stmt); + case Stmt::DoStmtClass: + return trans_do_loop(c, block, (DoStmt *)stmt); case Stmt::CaseStmtClass: emit_warning(c, stmt->getLocStart(), "TODO handle C CaseStmtClass"); return nullptr; @@ -2071,9 +2126,6 @@ static AstNode *trans_stmt(Context *c, bool result_used, AstNode *block, Stmt *s case Stmt::CoroutineBodyStmtClass: emit_warning(c, stmt->getLocStart(), "TODO handle C CoroutineBodyStmtClass"); return nullptr; - case Stmt::DoStmtClass: - emit_warning(c, stmt->getLocStart(), "TODO handle C DoStmtClass"); - return nullptr; case Stmt::BinaryConditionalOperatorClass: emit_warning(c, stmt->getLocStart(), "TODO handle C BinaryConditionalOperatorClass"); return nullptr; diff --git a/test/parsec.zig b/test/parsec.zig index a6f23bd2a9..077dcf832c 100644 --- a/test/parsec.zig +++ b/test/parsec.zig @@ -804,6 +804,33 @@ pub fn addCases(cases: &tests.ParseCContext) { \\ }; \\} ); + + cases.addC("do loop", + \\void foo(void) { + \\ int a = 2; + \\ do { + \\ a--; + \\ } while (a != 0); + \\ + \\ int b = 2; + \\ do + \\ b--; + \\ while (b != 0); + \\} + , + \\export fn foo() { + \\ var a: c_int = 2; + \\ while (true) { + \\ a -= 1; + \\ if (!(a != 0)) break; + \\ }; + \\ var b: c_int = 2; + \\ while (true) { + \\ b -= 1; + \\ if (!(b != 0)) break; + \\ }; + \\} + ); }