Commit 21bc3353b8

Vexu <git@vexu.eu>
2019-12-18 00:04:01
translate-c-2 character literals and more test fixes
1 parent 6d7025d
Changed files (4)
lib/std/fmt.zig
@@ -582,7 +582,9 @@ pub fn formatAsciiChar(
     comptime Errors: type,
     output: fn (@TypeOf(context), []const u8) Errors!void,
 ) Errors!void {
-    return output(context, @as(*const [1]u8, &c)[0..]);
+    if (std.ascii.isPrint(c))
+        return output(context, @as(*const [1]u8, &c)[0..]);
+    return format(context, Errors, output, "\\x{x:0<2}", .{c});
 }
 
 pub fn formatBuf(
src-self-hosted/clang.zig
@@ -78,6 +78,7 @@ pub const struct_ZigClangInitListExpr = @OpaqueType();
 pub const ZigClangPreprocessingRecord = @OpaqueType();
 pub const ZigClangFloatingLiteral = @OpaqueType();
 pub const ZigClangConstantExpr = @OpaqueType();
+pub const ZigClangCharacterLiteral = @OpaqueType();
 
 pub const ZigClangBO = extern enum {
     PtrMemD,
@@ -712,6 +713,14 @@ pub const ZigClangStringLiteral_StringKind = extern enum {
     UTF32,
 };
 
+pub const ZigClangCharacterLiteral_CharacterKind = extern enum {
+    Ascii,
+    Wide,
+    UTF8,
+    UTF16,
+    UTF32,
+};
+
 pub const ZigClangRecordDecl_field_iterator = extern struct {
     opaque: *c_void,
 };
@@ -1077,3 +1086,7 @@ pub extern fn ZigClangExpr_EvaluateAsConstantExpr(*const ZigClangExpr, *ZigClang
 
 pub extern fn ZigClangPredefinedExpr_getFunctionName(*const ZigClangPredefinedExpr) *const ZigClangStringLiteral;
 
+pub extern fn ZigClangCharacterLiteral_getBeginLoc(*const ZigClangCharacterLiteral) ZigClangSourceLocation;
+pub extern fn ZigClangCharacterLiteral_getKind(*const ZigClangCharacterLiteral) ZigClangCharacterLiteral_CharacterKind;
+pub extern fn ZigClangCharacterLiteral_getValue(*const ZigClangCharacterLiteral) c_uint;
+
src-self-hosted/translate_c.zig
@@ -49,7 +49,10 @@ const Scope = struct {
         Root,
         Condition,
         FnDef,
+
+        /// used when getting a member `a.b`
         Ref,
+        Loop,
     };
 
     const Switch = struct {
@@ -59,11 +62,6 @@ const Scope = struct {
         has_default: bool = false,
     };
 
-    /// used when getting a member `a.b`
-    const Ref = struct {
-        base: Scope,
-    };
-
     const Block = struct {
         base: Scope,
         block_node: *ast.Node.Block,
@@ -125,10 +123,6 @@ const Scope = struct {
         }
     };
 
-    const Condition = struct {
-        base: Scope,
-    };
-
     const FnDef = struct {
         base: Scope,
         params: AliasList,
@@ -169,7 +163,6 @@ const Scope = struct {
                 .Root => unreachable,
                 .Block => return @fieldParentPtr(Block, "base", scope),
                 .Condition => {
-                    const cond = @fieldParentPtr(Condition, "base", scope);
                     // comma operator used
                     return try Block.init(c, scope, "blk");
                 },
@@ -192,6 +185,7 @@ const Scope = struct {
             .FnDef => @fieldParentPtr(FnDef, "base", scope).getAlias(name),
             .Block => @fieldParentPtr(Block, "base", scope).getAlias(name),
             .Switch,
+            .Loop,
             .Condition => scope.parent.?.getAlias(name),
         };
     }
@@ -203,6 +197,7 @@ const Scope = struct {
             .FnDef => @fieldParentPtr(FnDef, "base", scope).contains(name),
             .Block => @fieldParentPtr(Block, "base", scope).contains(name),
             .Switch,
+            .Loop,
             .Condition => scope.parent.?.contains(name),
         };
     }
@@ -213,6 +208,7 @@ const Scope = struct {
             switch (scope.id) {
                 .FnDef => unreachable,
                 .Switch => return scope,
+                .Loop => return scope,
                 else => scope = scope.parent.?,
             }
         }
@@ -434,7 +430,7 @@ fn visitFnDecl(c: *Context, fn_decl: *const ZigClangFunctionDecl) Error!void {
                 error.OutOfMemory => |e| return e,
             };
         },
-        else => unreachable,
+        else => return failDecl(c, fn_decl_loc, fn_name, "unable to resolve function type {}", .{ZigClangType_getTypeClass(fn_type)}),
     };
 
     if (!decl_ctx.has_body) {
@@ -862,6 +858,7 @@ fn transStmt(
         .DefaultStmtClass => return transDefault(rp, scope, @ptrCast(*const ZigClangDefaultStmt, stmt)),
         .ConstantExprClass => return transConstantExpr(rp, scope, @ptrCast(*const ZigClangExpr, stmt), result_used),
         .PredefinedExprClass => return transPredefinedExpr(rp, scope, @ptrCast(*const ZigClangPredefinedExpr, stmt), result_used),
+        .CharacterLiteralClass => return transCharLiteral(rp, scope, @ptrCast(*const ZigClangCharacterLiteral, stmt), result_used),
         else => {
             return revertAndWarn(
                 rp,
@@ -1202,7 +1199,7 @@ fn transStringLiteral(
 
             const token = try appendToken(rp.c, .StringLiteral, buf);
             const node = try rp.c.a().create(ast.Node.StringLiteral);
-            node.* = ast.Node.StringLiteral{
+            node.* = .{
                 .token = token,
             };
             return maybeSuppressResult(rp, scope, result_used, &node.base);
@@ -1237,18 +1234,15 @@ fn writeEscapedString(buf: []u8, s: []const u8) void {
 
 // Returns either a string literal or a slice of `buf`.
 fn escapeChar(c: u8, char_buf: *[4]u8) []const u8 {
-    // TODO: https://github.com/ziglang/zig/issues/2749
-    const escaped = switch (c) {
-        // Printable ASCII except for ' " \
-        ' ', '!', '#'...'&', '('...'[', ']'...'~' => ([_]u8{c})[0..],
-        '\'', '\"', '\\' => ([_]u8{ '\\', c })[0..],
-        '\n' => return "\\n"[0..],
-        '\r' => return "\\r"[0..],
-        '\t' => return "\\t"[0..],
-        else => return std.fmt.bufPrint(char_buf[0..], "\\x{x:2}", .{c}) catch unreachable,
+    return switch (c) {
+        '\"' => "\\\""[0..],
+        '\'' => "\\'"[0..],
+        '\\' => "\\\\"[0..],
+        '\n' => "\\n"[0..],
+        '\r' => "\\r"[0..],
+        '\t' => "\\t"[0..],
+        else => std.fmt.bufPrint(char_buf[0..], "{c}", .{c}) catch unreachable,
     };
-    std.mem.copy(u8, char_buf, escaped);
-    return char_buf[0..escaped.len];
 }
 
 fn transCCast(
@@ -1459,13 +1453,11 @@ fn transIfStmt(
     // if (c) t else e
     const if_node = try transCreateNodeIf(rp.c);
 
-    var cond_scope = Scope.Condition{
-        .base = .{
-            .parent = scope,
-            .id = .Condition,
-        },
+    var cond_scope = Scope{
+        .parent = scope,
+        .id = .Condition,
     };
-    if_node.condition = try transBoolExpr(rp, &cond_scope.base, @ptrCast(*const ZigClangExpr, ZigClangIfStmt_getCond(stmt)), .used, .r_value, false);
+    if_node.condition = try transBoolExpr(rp, &cond_scope, @ptrCast(*const ZigClangExpr, ZigClangIfStmt_getCond(stmt)), .used, .r_value, false);
     _ = try appendToken(rp.c, .RParen, ")");
 
     if_node.body = try transStmt(rp, scope, ZigClangIfStmt_getThen(stmt), .unused, .r_value);
@@ -1485,16 +1477,18 @@ fn transWhileLoop(
 ) TransError!*ast.Node {
     const while_node = try transCreateNodeWhile(rp.c);
 
-    var cond_scope = Scope.Condition{
-        .base = .{
-            .parent = scope,
-            .id = .Condition,
-        },
+    var cond_scope = Scope{
+        .parent = scope,
+        .id = .Condition,
     };
-    while_node.condition = try transBoolExpr(rp, &cond_scope.base, @ptrCast(*const ZigClangExpr, ZigClangWhileStmt_getCond(stmt)), .used, .r_value, false);
+    while_node.condition = try transBoolExpr(rp, &cond_scope, @ptrCast(*const ZigClangExpr, ZigClangWhileStmt_getCond(stmt)), .used, .r_value, false);
     _ = try appendToken(rp.c, .RParen, ")");
 
-    while_node.body = try transStmt(rp, scope, ZigClangWhileStmt_getBody(stmt), .unused, .r_value);
+    var loop_scope = Scope{
+        .parent = scope,
+        .id = .Loop,
+    };
+    while_node.body = try transStmt(rp, &loop_scope, ZigClangWhileStmt_getBody(stmt), .unused, .r_value);
     return &while_node.base;
 }
 
@@ -1508,6 +1502,10 @@ fn transDoWhileLoop(
     while_node.condition = try transCreateNodeBoolLiteral(rp.c, true);
     _ = try appendToken(rp.c, .RParen, ")");
     var new = false;
+    var loop_scope = Scope{
+        .parent = scope,
+        .id = .Loop,
+    };
 
     const body_node = if (ZigClangStmt_getStmtClass(ZigClangDoStmt_getBody(stmt)) == .CompoundStmtClass) blk: {
         // there's already a block in C, so we'll append our condition to it.
@@ -1520,7 +1518,7 @@ fn transDoWhileLoop(
         // zig:   b;
         // zig:   if (!cond) break;
         // zig: }
-        break :blk (try transStmt(rp, scope, ZigClangDoStmt_getBody(stmt), .unused, .r_value)).cast(ast.Node.Block).?;
+        break :blk (try transStmt(rp, &loop_scope, ZigClangDoStmt_getBody(stmt), .unused, .r_value)).cast(ast.Node.Block).?;
     } else blk: {
         // the C statement is without a block, so we need to create a block to contain it.
         // c: do
@@ -1532,20 +1530,18 @@ fn transDoWhileLoop(
         // zig: }
         new = true;
         const block = try transCreateNodeBlock(rp.c, null);
-        try block.statements.push(try transStmt(rp, scope, ZigClangDoStmt_getBody(stmt), .unused, .r_value));
+        try block.statements.push(try transStmt(rp, &loop_scope, ZigClangDoStmt_getBody(stmt), .unused, .r_value));
         break :blk block;
     };
 
     // if (!cond) break;
     const if_node = try transCreateNodeIf(rp.c);
-    var cond_scope = Scope.Condition{
-        .base = .{
-            .parent = scope,
-            .id = .Condition,
-        },
+    var cond_scope = Scope{
+        .parent = scope,
+        .id = .Condition,
     };
     const prefix_op = try transCreateNodePrefixOp(rp.c, .BoolNot, .Bang, "!");
-    prefix_op.rhs = try transBoolExpr(rp, &cond_scope.base, @ptrCast(*const ZigClangExpr, ZigClangDoStmt_getCond(stmt)), .used, .r_value, false);
+    prefix_op.rhs = try transBoolExpr(rp, &cond_scope, @ptrCast(*const ZigClangExpr, ZigClangDoStmt_getCond(stmt)), .used, .r_value, true);
     _ = try appendToken(rp.c, .RParen, ")");
     if_node.condition = &prefix_op.base;
     if_node.body = &(try transCreateNodeBreak(rp.c, null)).base;
@@ -1563,25 +1559,26 @@ fn transForLoop(
     scope: *Scope,
     stmt: *const ZigClangForStmt,
 ) TransError!*ast.Node {
-    var inner = scope;
+    var loop_scope = Scope{
+        .parent = scope,
+        .id = .Loop,
+    };
     var block = false;
     var block_scope: ?*Scope.Block = null;
     if (ZigClangForStmt_getInit(stmt)) |init| {
         block_scope = try Scope.Block.init(rp.c, scope, null);
         block_scope.?.block_node = try transCreateNodeBlock(rp.c, null);
-        inner = &block_scope.?.base;
-        _ = try transStmt(rp, inner, init, .unused, .r_value);
+        loop_scope.parent = &block_scope.?.base;
+        _ = try transStmt(rp, &loop_scope, init, .unused, .r_value);
     }
-    var cond_scope = Scope.Condition{
-        .base = .{
-            .parent = inner,
-            .id = .Condition,
-        },
+    var cond_scope = Scope{
+        .parent = scope,
+        .id = .Condition,
     };
 
     const while_node = try transCreateNodeWhile(rp.c);
     while_node.condition = if (ZigClangForStmt_getCond(stmt)) |cond|
-        try transBoolExpr(rp, &cond_scope.base, cond, .used, .r_value, false)
+        try transBoolExpr(rp, &cond_scope, cond, .used, .r_value, false)
     else
         try transCreateNodeBoolLiteral(rp.c, true);
     _ = try appendToken(rp.c, .RParen, ")");
@@ -1589,11 +1586,11 @@ fn transForLoop(
     if (ZigClangForStmt_getInc(stmt)) |incr| {
         _ = try appendToken(rp.c, .Colon, ":");
         _ = try appendToken(rp.c, .LParen, "(");
-        while_node.continue_expr = try transExpr(rp, &cond_scope.base, incr, .unused, .r_value);
+        while_node.continue_expr = try transExpr(rp, &cond_scope, incr, .unused, .r_value);
         _ = try appendToken(rp.c, .RParen, ")");
     }
 
-    while_node.body = try transStmt(rp, inner, ZigClangForStmt_getBody(stmt), .unused, .r_value);
+    while_node.body = try transStmt(rp, &loop_scope, ZigClangForStmt_getBody(stmt), .unused, .r_value);
     if (block_scope != null) {
         try block_scope.?.block_node.statements.push(&while_node.base);
         block_scope.?.block_node.rbrace = try appendToken(rp.c, .RBrace, "}");
@@ -1617,13 +1614,11 @@ fn transSwitch(
         .pending_block = undefined,
     };
 
-    var cond_scope = Scope.Condition{
-        .base = .{
-            .parent = scope,
-            .id = .Condition,
-        },
+    var cond_scope = Scope{
+        .parent = scope,
+        .id = .Condition,
     };
-    switch_node.expr = try transExpr(rp, &cond_scope.base, ZigClangSwitchStmt_getCond(stmt), .used, .r_value);
+    switch_node.expr = try transExpr(rp, &cond_scope, ZigClangSwitchStmt_getCond(stmt), .used, .r_value);
     _ = try appendToken(rp.c, .RParen, ")");
     _ = try appendToken(rp.c, .LBrace, "{");
     switch_node.rbrace = try appendToken(rp.c, .RBrace, "}");
@@ -1753,6 +1748,41 @@ fn transPredefinedExpr(rp: RestorePoint, scope: *Scope, expr: *const ZigClangPre
     return transStringLiteral(rp, scope, ZigClangPredefinedExpr_getFunctionName(expr), used);
 }
 
+fn transCharLiteral(
+    rp: RestorePoint,
+    scope: *Scope,
+    stmt: *const ZigClangCharacterLiteral,
+    result_used: ResultUsed,
+) TransError!*ast.Node {
+    const kind = ZigClangCharacterLiteral_getKind(stmt);
+    switch (kind) {
+        .Ascii, .UTF8 => {
+            const val = ZigClangCharacterLiteral_getValue(stmt);
+            if (kind == .Ascii) {
+                // C has a somewhat obscure feature called multi-character character
+                // constant
+                if (val > 255)
+                    return transCreateNodeInt(rp.c, val);
+            }
+            var char_buf: [4]u8 = undefined;
+            const token = try appendTokenFmt(rp.c, .CharLiteral, "'{}'", .{escapeChar(@intCast(u8, val), &char_buf)});
+            const node = try rp.c.a().create(ast.Node.CharLiteral);
+            node.* = .{
+                .token = token,
+            };
+            return maybeSuppressResult(rp, scope, result_used, &node.base);
+        },
+        .UTF16, .UTF32, .Wide => return revertAndWarn(
+            rp,
+            error.UnsupportedTranslation,
+            ZigClangStmt_getBeginLoc(@ptrCast(*const ZigClangStmt, stmt)),
+            "TODO: support character literal kind {}",
+            .{kind},
+        ),
+        else => unreachable,
+    }
+}
+
 fn transCPtrCast(
     rp: RestorePoint,
     loc: ZigClangSourceLocation,
@@ -1796,6 +1826,7 @@ fn transBreak(rp: RestorePoint, scope: *Scope) TransError!*ast.Node {
         "__switch"
     else
         null);
+    _ = try appendToken(rp.c, .Semicolon, ";");
     return &br.base;
 }
 
@@ -1813,18 +1844,16 @@ fn transConditionalOperator(rp: RestorePoint, scope: *Scope, stmt: *const ZigCla
     const gropued = scope.id == .Condition;
     const lparen = if (gropued) try appendToken(rp.c, .LParen, "(") else undefined;
     const if_node = try transCreateNodeIf(rp.c);
-    var cond_scope = Scope.Condition{
-        .base = .{
-            .parent = scope,
-            .id = .Condition,
-        },
+    var cond_scope = Scope{
+        .parent = scope,
+        .id = .Condition,
     };
 
     const cond_expr = ZigClangConditionalOperator_getCond(stmt);
     const true_expr = ZigClangConditionalOperator_getTrueExpr(stmt);
     const false_expr = ZigClangConditionalOperator_getFalseExpr(stmt);
 
-    if_node.condition = try transBoolExpr(rp, &cond_scope.base, cond_expr, .used, .r_value, false);
+    if_node.condition = try transBoolExpr(rp, &cond_scope, cond_expr, .used, .r_value, false);
     _ = try appendToken(rp.c, .RParen, ")");
 
     if_node.body = try transExpr(rp, scope, true_expr, .used, .r_value);
@@ -3104,7 +3133,7 @@ fn transPreprocessorEntities(c: *Context, unit: *ZigClangASTUnit) Error!void {
 
                 var tok_it = tok_list.iterator(0);
                 const first_tok = tok_it.next().?;
-                assert(first_tok.id == .Identifier and std.mem.eql(u8, first_tok.bytes, checked_name));
+                assert(first_tok.id == .Identifier and std.mem.eql(u8, first_tok.bytes, name));
                 const next = tok_it.peek().?;
                 switch (next.id) {
                     .Identifier => {
test/translate_c.zig
@@ -600,6 +600,135 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
         \\}
     });
 
+    cases.add_both("simple union",
+        \\union Foo {
+        \\    int x;
+        \\    double y;
+        \\};
+    , &[_][]const u8{
+        \\pub const union_Foo = extern union {
+        \\    x: c_int,
+        \\    y: f64,
+        \\};
+    ,
+        \\pub const Foo = union_Foo;
+    });
+
+    cases.addC_both("string literal",
+        \\const char *foo(void) {
+        \\    return "bar";
+        \\}
+    , &[_][]const u8{
+        \\pub export fn foo() [*c]const u8 {
+        \\    return "bar";
+        \\}
+    });
+
+    cases.addC_both("return void",
+        \\void foo(void) {
+        \\    return;
+        \\}
+    , &[_][]const u8{
+        \\pub export fn foo() void {
+        \\    return;
+        \\}
+    });
+
+    cases.addC_both("for loop",
+        \\void foo(void) {
+        \\    for (int i = 0; i; i = i + 1) { }
+        \\}
+    , &[_][]const u8{
+        \\pub export fn foo() void {
+        \\    {
+        \\        var i: c_int = 0;
+        \\        while (i != 0) : (i = (i + 1)) {}
+        \\    }
+        \\}
+    });
+
+    cases.addC_both("empty for loop",
+        \\void foo(void) {
+        \\    for (;;) { }
+        \\}
+    , &[_][]const u8{
+        \\pub export fn foo() void {
+        \\    while (true) {}
+        \\}
+    });
+
+    cases.addC_both("break statement",
+        \\void foo(void) {
+        \\    for (;;) {
+        \\        break;
+        \\    }
+        \\}
+    , &[_][]const u8{
+        \\pub export fn foo() void {
+        \\    while (true) {
+        \\        break;
+        \\    }
+        \\}
+    });
+
+    cases.addC_both("continue statement",
+        \\void foo(void) {
+        \\    for (;;) {
+        \\        continue;
+        \\    }
+        \\}
+    , &[_][]const u8{
+        \\pub export fn foo() void {
+        \\    while (true) {
+        \\        continue;
+        \\    }
+        \\}
+    });
+
+    cases.addC_both("pointer casting",
+        \\float *ptrcast(int *a) {
+        \\    return (float *)a;
+        \\}
+    , &[_][]const u8{
+        \\pub export fn ptrcast(a: [*c]c_int) [*c]f32 {
+        \\    return @ptrCast([*c]f32, @alignCast(@alignOf(f32), a));
+        \\}
+    });
+
+    cases.addC_both("pointer conversion with different alignment",
+        \\void test_ptr_cast() {
+        \\    void *p;
+        \\    {
+        \\        char *to_char = (char *)p;
+        \\        short *to_short = (short *)p;
+        \\        int *to_int = (int *)p;
+        \\        long long *to_longlong = (long long *)p;
+        \\    }
+        \\    {
+        \\        char *to_char = p;
+        \\        short *to_short = p;
+        \\        int *to_int = p;
+        \\        long long *to_longlong = p;
+        \\    }
+        \\}
+    , &[_][]const u8{
+        \\pub export fn test_ptr_cast() void {
+        \\    var p: ?*c_void = undefined;
+        \\    {
+        \\        var to_char: [*c]u8 = @ptrCast([*c]u8, @alignCast(@alignOf(u8), p));
+        \\        var to_short: [*c]c_short = @ptrCast([*c]c_short, @alignCast(@alignOf(c_short), p));
+        \\        var to_int: [*c]c_int = @ptrCast([*c]c_int, @alignCast(@alignOf(c_int), p));
+        \\        var to_longlong: [*c]c_longlong = @ptrCast([*c]c_longlong, @alignCast(@alignOf(c_longlong), p));
+        \\    }
+        \\    {
+        \\        var to_char: [*c]u8 = @ptrCast([*c]u8, @alignCast(@alignOf(u8), p));
+        \\        var to_short: [*c]c_short = @ptrCast([*c]c_short, @alignCast(@alignOf(c_short), p));
+        \\        var to_int: [*c]c_int = @ptrCast([*c]c_int, @alignCast(@alignOf(c_int), p));
+        \\        var to_longlong: [*c]c_longlong = @ptrCast([*c]c_longlong, @alignCast(@alignOf(c_longlong), p));
+        \\    }
+        \\}
+    });
+
     /////////////// Cases that pass for only stage2 ////////////////
 
     cases.add_2("Parameterless function prototypes",
@@ -957,11 +1086,11 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
         \\    while (true) {
         \\        var a: c_int = 2;
         \\        a = 12;
-        \\        if (!4 != 0) break;
+        \\        if (!(4 != 0)) break;
         \\    }
         \\    while (true) {
         \\        a = 7;
-        \\        if (!4 != 0) break;
+        \\        if (!(4 != 0)) break;
         \\    }
         \\}
     });
@@ -1145,6 +1274,66 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
         \\}
     });
 
+    cases.add_2("escape sequences",
+        \\const char *escapes() {
+        \\char a = '\'',
+        \\    b = '\\',
+        \\    c = '\a',
+        \\    d = '\b',
+        \\    e = '\f',
+        \\    f = '\n',
+        \\    g = '\r',
+        \\    h = '\t',
+        \\    i = '\v',
+        \\    j = '\0',
+        \\    k = '\"';
+        \\    return "\'\\\a\b\f\n\r\t\v\0\"";
+        \\}
+        \\
+    , &[_][]const u8{
+        \\pub export fn escapes() [*c]const u8 {
+        \\    var a: u8 = @as(u8, '\'');
+        \\    var b: u8 = @as(u8, '\\');
+        \\    var c: u8 = @as(u8, '\x07');
+        \\    var d: u8 = @as(u8, '\x08');
+        \\    var e: u8 = @as(u8, '\x0c');
+        \\    var f: u8 = @as(u8, '\n');
+        \\    var g: u8 = @as(u8, '\r');
+        \\    var h: u8 = @as(u8, '\t');
+        \\    var i: u8 = @as(u8, '\x0b');
+        \\    var j: u8 = @as(u8, '\x00');
+        \\    var k: u8 = @as(u8, '\"');
+        \\    return "\'\\\x07\x08\x0c\n\r\t\x0b\x00\"";
+        \\}
+    });
+
+    cases.add_2("do loop",
+        \\void foo(void) {
+        \\    int a = 2;
+        \\    do {
+        \\        a = a - 1;
+        \\    } while (a);
+        \\
+        \\    int b = 2;
+        \\    do
+        \\        b = b -1;
+        \\    while (b);
+        \\}
+    , &[_][]const u8{
+        \\pub export fn foo() void {
+        \\    var a: c_int = 2;
+        \\    while (true) {
+        \\        a = (a - 1);
+        \\        if (!(a != 0)) break;
+        \\    }
+        \\    var b: c_int = 2;
+        \\    while (true) {
+        \\        b = (b - 1);
+        \\        if (!(b != 0)) break;
+        \\    }
+        \\}
+    });
+
     /////////////// Cases for only stage1 which are TODO items for stage2 ////////////////
 
     cases.addAllowWarnings("simple data types",
@@ -1641,33 +1830,6 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
         \\}
     });
 
-    cases.addC("do loop",
-        \\void foo(void) {
-        \\    int a = 2;
-        \\    do {
-        \\        a--;
-        \\    } while (a != 0);
-        \\
-        \\    int b = 2;
-        \\    do
-        \\        b--;
-        \\    while (b != 0);
-        \\}
-    , &[_][]const u8{
-        \\pub export fn foo() void {
-        \\    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;
-        \\    }
-        \\}
-    });
-
     cases.addC("deref function pointer",
         \\void foo(void) {}
         \\int baz(void) { return 0; }
@@ -1708,20 +1870,6 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
         \\}
     });
 
-    cases.add("simple union",
-        \\union Foo {
-        \\    int x;
-        \\    double y;
-        \\};
-    , &[_][]const u8{
-        \\pub const union_Foo = extern union {
-        \\    x: c_int,
-        \\    y: f64,
-        \\};
-    ,
-        \\pub const Foo = union_Foo;
-    });
-
     cases.add("address of operator",
         \\int foo(void) {
         \\    int x = 1234;
@@ -1736,77 +1884,6 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
         \\}
     });
 
-    cases.add("string literal",
-        \\const char *foo(void) {
-        \\    return "bar";
-        \\}
-    , &[_][]const u8{
-        \\pub fn foo() [*c]const u8 {
-        \\    return "bar";
-        \\}
-    });
-
-    cases.add("return void",
-        \\void foo(void) {
-        \\    return;
-        \\}
-    , &[_][]const u8{
-        \\pub fn foo() void {
-        \\    return;
-        \\}
-    });
-
-    cases.add("for loop",
-        \\void foo(void) {
-        \\    for (int i = 0; i < 10; i += 1) { }
-        \\}
-    , &[_][]const u8{
-        \\pub fn foo() void {
-        \\    {
-        \\        var i: c_int = 0;
-        \\        while (i < 10) : (i += 1) {}
-        \\    }
-        \\}
-    });
-
-    cases.add("empty for loop",
-        \\void foo(void) {
-        \\    for (;;) { }
-        \\}
-    , &[_][]const u8{
-        \\pub fn foo() void {
-        \\    while (true) {}
-        \\}
-    });
-
-    cases.add("break statement",
-        \\void foo(void) {
-        \\    for (;;) {
-        \\        break;
-        \\    }
-        \\}
-    , &[_][]const u8{
-        \\pub fn foo() void {
-        \\    while (true) {
-        \\        break;
-        \\    }
-        \\}
-    });
-
-    cases.add("continue statement",
-        \\void foo(void) {
-        \\    for (;;) {
-        \\        continue;
-        \\    }
-        \\}
-    , &[_][]const u8{
-        \\pub fn foo() void {
-        \\    while (true) {
-        \\        continue;
-        \\    }
-        \\}
-    });
-
     cases.add("variable name shadowing",
         \\int foo(void) {
         \\    int x = 1;
@@ -1827,16 +1904,6 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
         \\}
     });
 
-    cases.add("pointer casting",
-        \\float *ptrcast(int *a) {
-        \\    return (float *)a;
-        \\}
-    , &[_][]const u8{
-        \\fn ptrcast(a: [*c]c_int) [*c]f32 {
-        \\    return @ptrCast([*c]f32, @alignCast(@alignOf(f32), a));
-        \\}
-    });
-
     cases.add("bin not",
         \\int foo(int x) {
         \\    return ~x;
@@ -1987,74 +2054,6 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
         \\}
     });
 
-    cases.addC("pointer conversion with different alignment",
-        \\void test_ptr_cast() {
-        \\    void *p;
-        \\    {
-        \\        char *to_char = (char *)p;
-        \\        short *to_short = (short *)p;
-        \\        int *to_int = (int *)p;
-        \\        long long *to_longlong = (long long *)p;
-        \\    }
-        \\    {
-        \\        char *to_char = p;
-        \\        short *to_short = p;
-        \\        int *to_int = p;
-        \\        long long *to_longlong = p;
-        \\    }
-        \\}
-    , &[_][]const u8{
-        \\pub export fn test_ptr_cast() void {
-        \\    var p: ?*c_void = undefined;
-        \\    {
-        \\        var to_char: [*c]u8 = @ptrCast([*c]u8, @alignCast(@alignOf(u8), p));
-        \\        var to_short: [*c]c_short = @ptrCast([*c]c_short, @alignCast(@alignOf(c_short), p));
-        \\        var to_int: [*c]c_int = @ptrCast([*c]c_int, @alignCast(@alignOf(c_int), p));
-        \\        var to_longlong: [*c]c_longlong = @ptrCast([*c]c_longlong, @alignCast(@alignOf(c_longlong), p));
-        \\    }
-        \\    {
-        \\        var to_char: [*c]u8 = @ptrCast([*c]u8, @alignCast(@alignOf(u8), p));
-        \\        var to_short: [*c]c_short = @ptrCast([*c]c_short, @alignCast(@alignOf(c_short), p));
-        \\        var to_int: [*c]c_int = @ptrCast([*c]c_int, @alignCast(@alignOf(c_int), p));
-        \\        var to_longlong: [*c]c_longlong = @ptrCast([*c]c_longlong, @alignCast(@alignOf(c_longlong), p));
-        \\    }
-        \\}
-    });
-
-    cases.addC("escape sequences",
-        \\const char *escapes() {
-        \\char a = '\'',
-        \\    b = '\\',
-        \\    c = '\a',
-        \\    d = '\b',
-        \\    e = '\f',
-        \\    f = '\n',
-        \\    g = '\r',
-        \\    h = '\t',
-        \\    i = '\v',
-        \\    j = '\0',
-        \\    k = '\"';
-        \\    return "\'\\\a\b\f\n\r\t\v\0\"";
-        \\}
-        \\
-    , &[_][]const u8{
-        \\pub export fn escapes() [*c]const u8 {
-        \\    var a: u8 = @as(u8, '\'');
-        \\    var b: u8 = @as(u8, '\\');
-        \\    var c: u8 = @as(u8, '\x07');
-        \\    var d: u8 = @as(u8, '\x08');
-        \\    var e: u8 = @as(u8, '\x0c');
-        \\    var f: u8 = @as(u8, '\n');
-        \\    var g: u8 = @as(u8, '\r');
-        \\    var h: u8 = @as(u8, '\t');
-        \\    var i: u8 = @as(u8, '\x0b');
-        \\    var j: u8 = @as(u8, '\x00');
-        \\    var k: u8 = @as(u8, '\"');
-        \\    return "\'\\\x07\x08\x0c\n\r\t\x0b\x00\"";
-        \\}
-        \\
-    });
-
     if (builtin.os != builtin.Os.windows) {
         // sysv_abi not currently supported on windows
         cases.add("Macro qualified functions",
@@ -2386,4 +2385,65 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
         \\    };
         \\}
     });
+
+    cases.addC("escape sequences",
+        \\const char *escapes() {
+        \\char a = '\'',
+        \\    b = '\\',
+        \\    c = '\a',
+        \\    d = '\b',
+        \\    e = '\f',
+        \\    f = '\n',
+        \\    g = '\r',
+        \\    h = '\t',
+        \\    i = '\v',
+        \\    j = '\0',
+        \\    k = '\"';
+        \\    return "\'\\\a\b\f\n\r\t\v\0\"";
+        \\}
+        \\
+    , &[_][]const u8{
+        \\pub export fn escapes() [*c]const u8 {
+        \\    var a: u8 = @as(u8, '\'');
+        \\    var b: u8 = @as(u8, '\\');
+        \\    var c: u8 = @as(u8, '\x07');
+        \\    var d: u8 = @as(u8, '\x08');
+        \\    var e: u8 = @as(u8, '\x0c');
+        \\    var f: u8 = @as(u8, '\n');
+        \\    var g: u8 = @as(u8, '\r');
+        \\    var h: u8 = @as(u8, '\t');
+        \\    var i: u8 = @as(u8, '\x0b');
+        \\    var j: u8 = @as(u8, '\x00');
+        \\    var k: u8 = @as(u8, '\"');
+        \\    return "\'\\\x07\x08\x0c\n\r\t\x0b\x00\"";
+        \\}
+        \\
+    });
+
+    cases.addC("do loop",
+        \\void foo(void) {
+        \\    int a = 2;
+        \\    do {
+        \\        a--;
+        \\    } while (a != 0);
+        \\
+        \\    int b = 2;
+        \\    do
+        \\        b--;
+        \\    while (b != 0);
+        \\}
+    , &[_][]const u8{
+        \\pub export fn foo() void {
+        \\    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;
+        \\    }
+        \\}
+    });
 }