Commit f837c7c9cd

Vexu <git@vexu.eu>
2019-12-19 15:07:33
translate-c-2 compound assign
1 parent 6cd402f
Changed files (5)
lib/std/zig/ast.zig
@@ -1431,13 +1431,13 @@ pub const Node = struct {
             AssignBitShiftRight,
             AssignBitXor,
             AssignDiv,
-            AssignMinus,
-            AssignMinusWrap,
+            AssignSub,
+            AssignSubWrap,
             AssignMod,
-            AssignPlus,
-            AssignPlusWrap,
-            AssignTimes,
-            AssignTimesWarp,
+            AssignAdd,
+            AssignAddWrap,
+            AssignMult,
+            AssignMultWrap,
             BangEqual,
             BitAnd,
             BitOr,
@@ -1490,13 +1490,13 @@ pub const Node = struct {
                 Op.AssignBitShiftRight,
                 Op.AssignBitXor,
                 Op.AssignDiv,
-                Op.AssignMinus,
-                Op.AssignMinusWrap,
+                Op.AssignSub,
+                Op.AssignSubWrap,
                 Op.AssignMod,
-                Op.AssignPlus,
-                Op.AssignPlusWrap,
-                Op.AssignTimes,
-                Op.AssignTimesWarp,
+                Op.AssignAdd,
+                Op.AssignAddWrap,
+                Op.AssignMult,
+                Op.AssignMultWrap,
                 Op.BangEqual,
                 Op.BitAnd,
                 Op.BitOr,
lib/std/zig/parse.zig
@@ -1981,19 +1981,19 @@ fn parseAssignOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
 
     const token = nextToken(it);
     const op = switch (token.ptr.id) {
-        .AsteriskEqual => Op{ .AssignTimes = {} },
+        .AsteriskEqual => Op{ .AssignMult = {} },
         .SlashEqual => Op{ .AssignDiv = {} },
         .PercentEqual => Op{ .AssignMod = {} },
-        .PlusEqual => Op{ .AssignPlus = {} },
-        .MinusEqual => Op{ .AssignMinus = {} },
+        .PlusEqual => Op{ .AssignAdd = {} },
+        .MinusEqual => Op{ .AssignSub = {} },
         .AngleBracketAngleBracketLeftEqual => Op{ .AssignBitShiftLeft = {} },
         .AngleBracketAngleBracketRightEqual => Op{ .AssignBitShiftRight = {} },
         .AmpersandEqual => Op{ .AssignBitAnd = {} },
         .CaretEqual => Op{ .AssignBitXor = {} },
         .PipeEqual => Op{ .AssignBitOr = {} },
-        .AsteriskPercentEqual => Op{ .AssignTimesWarp = {} },
-        .PlusPercentEqual => Op{ .AssignPlusWrap = {} },
-        .MinusPercentEqual => Op{ .AssignMinusWrap = {} },
+        .AsteriskPercentEqual => Op{ .AssignMultWrap = {} },
+        .PlusPercentEqual => Op{ .AssignAddWrap = {} },
+        .MinusPercentEqual => Op{ .AssignSubWrap = {} },
         .Equal => Op{ .Assign = {} },
         else => {
             putBackToken(it, token.index);
src-self-hosted/clang.zig
@@ -1120,3 +1120,11 @@ pub extern fn ZigClangUnaryOperator_getOpcode(*const ZigClangUnaryOperator) ZigC
 pub extern fn ZigClangUnaryOperator_getType(*const ZigClangUnaryOperator) ZigClangQualType;
 pub extern fn ZigClangUnaryOperator_getSubExpr(*const ZigClangUnaryOperator) *const ZigClangExpr;
 pub extern fn ZigClangUnaryOperator_getBeginLoc(*const ZigClangUnaryOperator) ZigClangSourceLocation;
+
+pub extern fn ZigClangCompoundAssignOperator_getType(*const ZigClangCompoundAssignOperator) ZigClangQualType;
+pub extern fn ZigClangCompoundAssignOperator_getComputationLHSType(*const ZigClangCompoundAssignOperator) ZigClangQualType;
+pub extern fn ZigClangCompoundAssignOperator_getComputationResultType(*const ZigClangCompoundAssignOperator) ZigClangQualType;
+pub extern fn ZigClangCompoundAssignOperator_getBeginLoc(*const ZigClangCompoundAssignOperator) ZigClangSourceLocation;
+pub extern fn ZigClangCompoundAssignOperator_getOpcode(*const ZigClangCompoundAssignOperator) ZigClangBO;
+pub extern fn ZigClangCompoundAssignOperator_getLHS(*const ZigClangCompoundAssignOperator) *const ZigClangExpr;
+pub extern fn ZigClangCompoundAssignOperator_getRHS(*const ZigClangCompoundAssignOperator) *const ZigClangExpr;
src-self-hosted/translate_c.zig
@@ -898,6 +898,7 @@ fn transStmt(
         .CallExprClass => return transCallExpr(rp, scope, @ptrCast(*const ZigClangCallExpr, stmt), result_used),
         .UnaryExprOrTypeTraitExprClass => return transUnaryExprOrTypeTraitExpr(rp, scope, @ptrCast(*const ZigClangUnaryExprOrTypeTraitExpr, stmt), result_used),
         .UnaryOperatorClass => return transUnaryOperator(rp, scope, @ptrCast(*const ZigClangUnaryOperator, stmt), result_used),
+        .CompoundAssignOperatorClass => return transCompoundAssignOperator(rp, scope, @ptrCast(*const ZigClangCompoundAssignOperator, stmt), result_used),
         else => {
             return revertAndWarn(
                 rp,
@@ -2178,21 +2179,21 @@ fn transUnaryOperator(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangUnar
     const op_expr = ZigClangUnaryOperator_getSubExpr(stmt);
     switch (ZigClangUnaryOperator_getOpcode(stmt)) {
         .PostInc => if (qualTypeHaswrappingOverflow(ZigClangUnaryOperator_getType(stmt)))
-            return transCreatePostCrement(rp, scope, stmt, .AssignPlusWrap, .PlusPercentEqual, "+%=", used)
+            return transCreatePostCrement(rp, scope, stmt, .AssignAddWrap, .PlusPercentEqual, "+%=", used)
         else
-            return transCreatePostCrement(rp, scope, stmt, .AssignPlus, .PlusEqual, "+=", used),
+            return transCreatePostCrement(rp, scope, stmt, .AssignAdd, .PlusEqual, "+=", used),
         .PostDec => if (qualTypeHaswrappingOverflow(ZigClangUnaryOperator_getType(stmt)))
-            return transCreatePostCrement(rp, scope, stmt, .AssignMinusWrap, .MinusPercentEqual, "-%=", used)
+            return transCreatePostCrement(rp, scope, stmt, .AssignSubWrap, .MinusPercentEqual, "-%=", used)
         else
-            return transCreatePostCrement(rp, scope, stmt, .AssignMinus, .MinusEqual, "-=", used),
+            return transCreatePostCrement(rp, scope, stmt, .AssignSub, .MinusEqual, "-=", used),
         .PreInc => if (qualTypeHaswrappingOverflow(ZigClangUnaryOperator_getType(stmt)))
-            return transCreatePreCrement(rp, scope, stmt, .AssignPlusWrap, .PlusPercentEqual, "+%=", used)
+            return transCreatePreCrement(rp, scope, stmt, .AssignAddWrap, .PlusPercentEqual, "+%=", used)
         else
-            return transCreatePreCrement(rp, scope, stmt, .AssignPlus, .PlusEqual, "+=", used),
+            return transCreatePreCrement(rp, scope, stmt, .AssignAdd, .PlusEqual, "+=", used),
         .PreDec => if (qualTypeHaswrappingOverflow(ZigClangUnaryOperator_getType(stmt)))
-            return transCreatePreCrement(rp, scope, stmt, .AssignMinusWrap, .MinusPercentEqual, "-%=", used)
+            return transCreatePreCrement(rp, scope, stmt, .AssignSubWrap, .MinusPercentEqual, "-%=", used)
         else
-            return transCreatePreCrement(rp, scope, stmt, .AssignMinus, .MinusEqual, "-=", used),
+            return transCreatePreCrement(rp, scope, stmt, .AssignSub, .MinusEqual, "-=", used),
         .AddrOf => {
             const op_node = try transCreateNodePrefixOp(rp.c, .AddressOf, .Ampersand, "&");
             op_node.rhs = try transExpr(rp, scope, op_expr, used, .r_value);
@@ -2232,7 +2233,7 @@ fn transUnaryOperator(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangUnar
             op_node.rhs = try transBoolExpr(rp, scope, op_expr, .used, .r_value, true);
             return &op_node.base;
         },
-        else => return revertAndWarn(rp, error.UnsupportedTranslation, ZigClangUnaryOperator_getBeginLoc(stmt), "TODO handle C translation UO_Real", .{}),
+        else => return revertAndWarn(rp, error.UnsupportedTranslation, ZigClangUnaryOperator_getBeginLoc(stmt), "unsupported C translation {}", .{ZigClangUnaryOperator_getOpcode(stmt)}),
     }
 }
 
@@ -2353,13 +2354,129 @@ fn transCreatePostCrement(
     try block_scope.block_node.statements.push(assign);
 
     const break_node = try transCreateNodeBreak(rp.c, block_scope.label);
-    break_node.rhs = try transCreateNodeIdentifier(rp.c,tmp);
+    break_node.rhs = try transCreateNodeIdentifier(rp.c, tmp);
     try block_scope.block_node.statements.push(&break_node.base);
     _ = try appendToken(rp.c, .Semicolon, ";");
     block_scope.block_node.rbrace = try appendToken(rp.c, .RBrace, "}");
     return &block_scope.block_node.base;
 }
 
+fn transCompoundAssignOperator(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangCompoundAssignOperator, used: ResultUsed) TransError!*ast.Node {
+    switch (ZigClangCompoundAssignOperator_getOpcode(stmt)) {
+        .MulAssign => if (qualTypeHaswrappingOverflow(ZigClangCompoundAssignOperator_getType(stmt)))
+            return transCreateCompoundAssign(rp, scope, stmt, .AssignMultWrap, .AsteriskPercentEqual, "*%=", .MultWrap, .AsteriskPercent, "*%", used)
+        else
+            return transCreateCompoundAssign(rp, scope, stmt, .AssignMult, .AsteriskEqual, "*=", .Mult, .Asterisk, "*", used),
+        .AddAssign => if (qualTypeHaswrappingOverflow(ZigClangCompoundAssignOperator_getType(stmt)))
+            return transCreateCompoundAssign(rp, scope, stmt, .AssignAddWrap, .PlusPercentEqual, "+%=", .AddWrap, .PlusPercent, "+%", used)
+        else
+            return transCreateCompoundAssign(rp, scope, stmt, .AssignAdd, .PlusEqual, "+=", .Add, .Plus, "+", used),
+        .SubAssign => if (qualTypeHaswrappingOverflow(ZigClangCompoundAssignOperator_getType(stmt)))
+            return transCreateCompoundAssign(rp, scope, stmt, .AssignSubWrap, .MinusPercentEqual, "-%=", .SubWrap, .MinusPercent, "-%", used)
+        else
+            return transCreateCompoundAssign(rp, scope, stmt, .AssignSub, .MinusPercentEqual, "-=", .Sub, .Minus, "-", used),
+        .ShlAssign => return transCreateCompoundAssign(rp, scope, stmt, .AssignBitShiftLeft, .AngleBracketAngleBracketLeftEqual, "<<=", .BitShiftLeft, .AngleBracketAngleBracketLeft, "<<", used),
+        .ShrAssign => return transCreateCompoundAssign(rp, scope, stmt, .AssignBitShiftRight, .AngleBracketAngleBracketRightEqual, ">>=", .BitShiftRight, .AngleBracketAngleBracketRight, ">>", used),
+        .AndAssign => return transCreateCompoundAssign(rp, scope, stmt, .AssignBitAnd, .AmpersandEqual, "&=", .BitAnd, .Ampersand, "&", used),
+        .XorAssign => return transCreateCompoundAssign(rp, scope, stmt, .AssignBitXor, .CaretEqual, "^=", .BitXor, .Caret, "^", used),
+        .OrAssign => return transCreateCompoundAssign(rp, scope, stmt, .AssignBitOr, .PipeEqual, "|=", .BitOr, .Pipe, "|", used),
+        else => return revertAndWarn(
+            rp,
+            error.UnsupportedTranslation,
+            ZigClangCompoundAssignOperator_getBeginLoc(stmt),
+            "unsupported C translation {}",
+            .{ZigClangCompoundAssignOperator_getOpcode(stmt)},
+        ),
+    }
+}
+
+fn transCreateCompoundAssign(
+    rp: RestorePoint,
+    scope: *Scope,
+    stmt: *const ZigClangCompoundAssignOperator,
+    assign_op: ast.Node.InfixOp.Op,
+    assign_tok_id: std.zig.Token.Id,
+    assign_bytes: []const u8,
+    bin_op: ast.Node.InfixOp.Op,
+    bin_tok_id: std.zig.Token.Id,
+    bin_bytes: []const u8,
+    used: ResultUsed,
+) TransError!*ast.Node {
+    const is_shift = bin_op == .BitShiftLeft or bin_op == .BitShiftRight;
+    const lhs = ZigClangCompoundAssignOperator_getLHS(stmt);
+    const rhs = ZigClangCompoundAssignOperator_getRHS(stmt);
+    const loc = ZigClangCompoundAssignOperator_getBeginLoc(stmt);
+    if (used == .unused) {
+        // common case
+        // c: lhs += rhs
+        // zig: lhs += rhs
+        const lhs_node = try transExpr(rp, scope, lhs, .used, .l_value);
+        const eq_token = try appendToken(rp.c, assign_tok_id, assign_bytes);
+        var rhs_node = try transExpr(rp, scope, rhs, .used, .r_value);
+
+        if (is_shift) {
+            const as_node = try transCreateNodeBuiltinFnCall(rp.c, "@as");
+            const rhs_type = try qualTypeToLog2IntRef(rp, getExprQualType(rp.c, rhs), loc);
+            try as_node.params.push(rhs_type);
+            _ = try appendToken(rp.c, .Comma, ",");
+            try as_node.params.push(rhs_node);
+            as_node.rparen_token = try appendToken(rp.c, .RParen, ")");
+            rhs_node = &as_node.base;
+        }
+        if (scope.id != .Condition)
+            _ = try appendToken(rp.c, .Semicolon, ";");
+        return transCreateNodeInfixOp(rp, scope, lhs_node, assign_op, eq_token, rhs_node, .used, false);
+    }
+    // worst case
+    // c:   lhs += rhs
+    // zig: (blk: {
+    // zig:     const _ref = &lhs;
+    // zig:     _ref.* = _ref.* + rhs;
+    // zig:     break :blk _ref.*
+    // zig: })
+    const block_scope = try Scope.Block.init(rp.c, scope, "blk");
+    block_scope.block_node = try transCreateNodeBlock(rp.c, block_scope.label);
+    const ref = try std.fmt.allocPrint(rp.c.a(), "_ref_{}", .{rp.c.getMangle()});
+
+    const node = try transCreateNodeVarDecl(rp.c, false, true, ref);
+    node.eq_token = try appendToken(rp.c, .Equal, "=");
+    const addr_node = try transCreateNodePrefixOp(rp.c, .AddressOf, .Ampersand, "&");
+    addr_node.rhs = try transExpr(rp, scope, lhs, .used, .l_value);
+    node.init_node = &addr_node.base;
+    node.semicolon_token = try appendToken(rp.c, .Semicolon, ";");
+    try block_scope.block_node.statements.push(&node.base);
+
+    const lhs_node = try transCreateNodeIdentifier(rp.c, ref);
+    const ref_node = try transCreateNodePtrDeref(rp.c, lhs_node);
+    _ = try appendToken(rp.c, .Semicolon, ";");
+    const bin_token = try appendToken(rp.c, bin_tok_id, bin_bytes);
+    var rhs_node = try transExpr(rp, scope, rhs, .used, .r_value);
+    if (is_shift) {
+        const as_node = try transCreateNodeBuiltinFnCall(rp.c, "@as");
+        const rhs_type = try qualTypeToLog2IntRef(rp, getExprQualType(rp.c, rhs), loc);
+        try as_node.params.push(rhs_type);
+        _ = try appendToken(rp.c, .Comma, ",");
+        try as_node.params.push(rhs_node);
+        as_node.rparen_token = try appendToken(rp.c, .RParen, ")");
+        rhs_node = &as_node.base;
+    }
+    const rhs_bin = try transCreateNodeInfixOp(rp, scope, ref_node, bin_op, bin_token, rhs_node, .used, false);
+
+    _ = try appendToken(rp.c, .Semicolon, ";");
+
+    const eq_token = try appendToken(rp.c, .Equal, "=");
+    const assign = try transCreateNodeInfixOp(rp, scope, ref_node, .Assign, eq_token, rhs_bin, .used, false);
+    try block_scope.block_node.statements.push(assign);
+
+    const break_node = try transCreateNodeBreak(rp.c, block_scope.label);
+    break_node.rhs = ref_node;
+    try block_scope.block_node.statements.push(&break_node.base);
+    block_scope.block_node.rbrace = try appendToken(rp.c, .RBrace, "}");
+    // semicolon must immediately follow rbrace because it is the last token in a block
+    _ = try appendToken(rp.c, .Semicolon, ";");
+    return &block_scope.block_node.base;
+}
+
 fn transCPtrCast(
     rp: RestorePoint,
     loc: ZigClangSourceLocation,
@@ -2585,7 +2702,7 @@ fn qualTypeToLog2IntRef(rp: RestorePoint, qt: ZigClangQualType, source_loc: ZigC
     const inner_field_access = try transCreateNodeFieldAccess(rp.c, &import_fn_call.base, "math");
     const outer_field_access = try transCreateNodeFieldAccess(rp.c, inner_field_access, "Log2Int");
     const log2int_fn_call = try transCreateNodeFnCall(rp.c, outer_field_access);
-    try @ptrCast(*ast.Node.SuffixOp.Op.Call, &log2int_fn_call.op).params.push(zig_type_node);
+    try @fieldParentPtr(ast.Node.SuffixOp, "base", &log2int_fn_call.base).op.Call.params.push(zig_type_node);
     log2int_fn_call.rtoken = try appendToken(rp.c, .RParen, ")");
 
     return &log2int_fn_call.base;
@@ -3317,7 +3434,7 @@ fn transCreateNodeShiftOp(
     const lhs_expr = ZigClangBinaryOperator_getLHS(stmt);
     const rhs_expr = ZigClangBinaryOperator_getRHS(stmt);
     const rhs_location = ZigClangExpr_getBeginLoc(rhs_expr);
-    // lhs >> u5(rh)
+    // lhs >> @as(u5, rh)
 
     const lhs = try transExpr(rp, scope, lhs_expr, .used, .l_value);
     const op_token = try appendToken(rp.c, op_tok_id, bytes);
test/translate_c.zig
@@ -1830,33 +1830,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
         \\}
     });
 
-    /////////////// Cases for only stage1 which are TODO items for stage2 ////////////////
-
-    cases.add("macro defines string literal with hex",
-        \\#define FOO "aoeu\xab derp"
-        \\#define FOO2 "aoeu\x0007a derp"
-        \\#define FOO_CHAR '\xfF'
-    , &[_][]const u8{
-        \\pub const FOO = "aoeu\xab derp";
-    ,
-        \\pub const FOO2 = "aoeuz derp";
-    ,
-        \\pub const FOO_CHAR = 255;
-    });
-
-    cases.add("macro defines string literal with octal",
-        \\#define FOO "aoeu\023 derp"
-        \\#define FOO2 "aoeu\0234 derp"
-        \\#define FOO_CHAR '\077'
-    , &[_][]const u8{
-        \\pub const FOO = "aoeu\x13 derp";
-    ,
-        \\pub const FOO2 = "aoeu\x134 derp";
-    ,
-        \\pub const FOO_CHAR = 63;
-    });
-
-    cases.addC("shift right assign",
+    cases.add_2("shift right assign",
         \\int log2(unsigned a) {
         \\    int i = 0;
         \\    while (a > 0) {
@@ -1864,18 +1838,17 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
         \\    }
         \\    return i;
         \\}
-    , &[_][]const u8{
-        \\pub export fn log2(_arg_a: c_uint) c_int {
-        \\    var a = _arg_a;
+    , &[_][]const u8{// TODO function arguments should be copied
+        \\pub export fn log2(a: c_uint) c_int {
         \\    var i: c_int = 0;
-        \\    while (a > @as(c_uint, 0)) {
-        \\        a >>= @as(@import("std").math.Log2Int(c_uint), 1);
+        \\    while ((a > @as(c_uint, 0))) {
+        \\        a >>= @as(@import("std").math.Log2Int(c_int), 1);
         \\    }
         \\    return i;
         \\}
     });
 
-    cases.addC("shift right assign with a fixed size type",
+    cases.add_2("shift right assign with a fixed size type",
         \\#include <stdint.h>
         \\int log2(uint32_t a) {
         \\    int i = 0;
@@ -1885,27 +1858,16 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
         \\    return i;
         \\}
     , &[_][]const u8{
-        \\pub export fn log2(_arg_a: u32) c_int {
-        \\    var a = _arg_a;
+        \\pub export fn log2(a: u32) c_int {
         \\    var i: c_int = 0;
-        \\    while (a > @as(c_uint, 0)) {
-        \\        a >>= @as(u5, 1);
+        \\    while ((a > @as(c_uint, 0))) {
+        \\        a >>= @as(@import("std").math.Log2Int(c_int), 1);
         \\    }
         \\    return i;
         \\}
     });
 
-    cases.addC("__extension__ cast",
-        \\int foo(void) {
-        \\    return __extension__ 1;
-        \\}
-    , &[_][]const u8{
-        \\pub export fn foo() c_int {
-        \\    return 1;
-        \\}
-    });
-
-    cases.addC("compound assignment operators",
+    cases.add_2("compound assignment operators",
         \\void foo(void) {
         \\    int a = 0;
         \\    a += (a += 1);
@@ -1920,50 +1882,50 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
     , &[_][]const u8{
         \\pub export fn foo() void {
         \\    var a: c_int = 0;
-        \\    a += (x: {
-        \\        const _ref = &a;
-        \\        _ref.* = (_ref.* + 1);
-        \\        break :x _ref.*;
+        \\    a += (blk: {
+        \\        const _ref_1 = &a;
+        \\        _ref_1.* = _ref_1.* + 1;
+        \\        break :blk _ref_1.*;
         \\    });
-        \\    a -= (x: {
-        \\        const _ref = &a;
-        \\        _ref.* = (_ref.* - 1);
-        \\        break :x _ref.*;
+        \\    a -= (blk: {
+        \\        const _ref_2 = &a;
+        \\        _ref_2.* = _ref_2.* - 1;
+        \\        break :blk _ref_2.*;
         \\    });
-        \\    a *= (x: {
-        \\        const _ref = &a;
-        \\        _ref.* = (_ref.* * 1);
-        \\        break :x _ref.*;
+        \\    a *= (blk: {
+        \\        const _ref_3 = &a;
+        \\        _ref_3.* = _ref_3.* * 1;
+        \\        break :blk _ref_3.*;
         \\    });
-        \\    a &= (x: {
-        \\        const _ref = &a;
-        \\        _ref.* = (_ref.* & 1);
-        \\        break :x _ref.*;
+        \\    a &= (blk: {
+        \\        const _ref_4 = &a;
+        \\        _ref_4.* = _ref_4.* & 1;
+        \\        break :blk _ref_4.*;
         \\    });
-        \\    a |= (x: {
-        \\        const _ref = &a;
-        \\        _ref.* = (_ref.* | 1);
-        \\        break :x _ref.*;
+        \\    a |= (blk: {
+        \\        const _ref_5 = &a;
+        \\        _ref_5.* = _ref_5.* | 1;
+        \\        break :blk _ref_5.*;
         \\    });
-        \\    a ^= (x: {
-        \\        const _ref = &a;
-        \\        _ref.* = (_ref.* ^ 1);
-        \\        break :x _ref.*;
+        \\    a ^= (blk: {
+        \\        const _ref_6 = &a;
+        \\        _ref_6.* = _ref_6.* ^ 1;
+        \\        break :blk _ref_6.*;
         \\    });
-        \\    a >>= @as(@import("std").math.Log2Int(c_int), (x: {
-        \\        const _ref = &a;
-        \\        _ref.* = (_ref.* >> @as(@import("std").math.Log2Int(c_int), 1));
-        \\        break :x _ref.*;
+        \\    a >>= @as(@import("std").math.Log2Int(c_int), (blk: {
+        \\        const _ref_7 = &a;
+        \\        _ref_7.* = _ref_7.* >> @as(@import("std").math.Log2Int(c_int), 1);
+        \\        break :blk _ref_7.*;
         \\    }));
-        \\    a <<= @as(@import("std").math.Log2Int(c_int), (x: {
-        \\        const _ref = &a;
-        \\        _ref.* = (_ref.* << @as(@import("std").math.Log2Int(c_int), 1));
-        \\        break :x _ref.*;
+        \\    a <<= @as(@import("std").math.Log2Int(c_int), (blk: {
+        \\        const _ref_8 = &a;
+        \\        _ref_8.* = _ref_8.* << @as(@import("std").math.Log2Int(c_int), 1);
+        \\        break :blk _ref_8.*;
         \\    }));
         \\}
     });
 
-    cases.addC("compound assignment operators unsigned",
+    cases.add_2("compound assignment operators unsigned",
         \\void foo(void) {
         \\    unsigned a = 0;
         \\    a += (a += 1);
@@ -1978,50 +1940,50 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
     , &[_][]const u8{
         \\pub export fn foo() void {
         \\    var a: c_uint = @as(c_uint, 0);
-        \\    a +%= (x: {
-        \\        const _ref = &a;
-        \\        _ref.* = (_ref.* +% @as(c_uint, 1));
-        \\        break :x _ref.*;
+        \\    a +%= (blk: {
+        \\        const _ref_1 = &a;
+        \\        _ref_1.* = _ref_1.* +% @as(c_uint, 1);
+        \\        break :blk _ref_1.*;
         \\    });
-        \\    a -%= (x: {
-        \\        const _ref = &a;
-        \\        _ref.* = (_ref.* -% @as(c_uint, 1));
-        \\        break :x _ref.*;
+        \\    a -%= (blk: {
+        \\        const _ref_2 = &a;
+        \\        _ref_2.* = _ref_2.* -% @as(c_uint, 1);
+        \\        break :blk _ref_2.*;
         \\    });
-        \\    a *%= (x: {
-        \\        const _ref = &a;
-        \\        _ref.* = (_ref.* *% @as(c_uint, 1));
-        \\        break :x _ref.*;
+        \\    a *%= (blk: {
+        \\        const _ref_3 = &a;
+        \\        _ref_3.* = _ref_3.* *% @as(c_uint, 1);
+        \\        break :blk _ref_3.*;
         \\    });
-        \\    a &= (x: {
-        \\        const _ref = &a;
-        \\        _ref.* = (_ref.* & @as(c_uint, 1));
-        \\        break :x _ref.*;
+        \\    a &= (blk: {
+        \\        const _ref_4 = &a;
+        \\        _ref_4.* = _ref_4.* & @as(c_uint, 1);
+        \\        break :blk _ref_4.*;
         \\    });
-        \\    a |= (x: {
-        \\        const _ref = &a;
-        \\        _ref.* = (_ref.* | @as(c_uint, 1));
-        \\        break :x _ref.*;
+        \\    a |= (blk: {
+        \\        const _ref_5 = &a;
+        \\        _ref_5.* = _ref_5.* | @as(c_uint, 1);
+        \\        break :blk _ref_5.*;
         \\    });
-        \\    a ^= (x: {
-        \\        const _ref = &a;
-        \\        _ref.* = (_ref.* ^ @as(c_uint, 1));
-        \\        break :x _ref.*;
+        \\    a ^= (blk: {
+        \\        const _ref_6 = &a;
+        \\        _ref_6.* = _ref_6.* ^ @as(c_uint, 1);
+        \\        break :blk _ref_6.*;
         \\    });
-        \\    a >>= @as(@import("std").math.Log2Int(c_uint), (x: {
-        \\        const _ref = &a;
-        \\        _ref.* = (_ref.* >> @as(@import("std").math.Log2Int(c_uint), 1));
-        \\        break :x _ref.*;
+        \\    a >>= @as(@import("std").math.Log2Int(c_uint), (blk: {
+        \\        const _ref_7 = &a;
+        \\        _ref_7.* = _ref_7.* >> @as(@import("std").math.Log2Int(c_int), 1);
+        \\        break :blk _ref_7.*;
         \\    }));
-        \\    a <<= @as(@import("std").math.Log2Int(c_uint), (x: {
-        \\        const _ref = &a;
-        \\        _ref.* = (_ref.* << @as(@import("std").math.Log2Int(c_uint), 1));
-        \\        break :x _ref.*;
+        \\    a <<= @as(@import("std").math.Log2Int(c_uint), (blk: {
+        \\        const _ref_8 = &a;
+        \\        _ref_8.* = _ref_8.* << @as(@import("std").math.Log2Int(c_int), 1);
+        \\        break :blk _ref_8.*;
         \\    }));
         \\}
     });
 
-    cases.addC("post increment/decrement",
+    cases.add_2("post increment/decrement",
         \\void foo(void) {
         \\    int i = 0;
         \\    unsigned u = 0;
@@ -2042,30 +2004,66 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
         \\    i -= 1;
         \\    u +%= 1;
         \\    u -%= 1;
-        \\    i = (x: {
-        \\        const _ref = &i;
-        \\        const _tmp = _ref.*;
-        \\        _ref.* += 1;
-        \\        break :x _tmp;
-        \\    });
-        \\    i = (x: {
-        \\        const _ref = &i;
-        \\        const _tmp = _ref.*;
-        \\        _ref.* -= 1;
-        \\        break :x _tmp;
-        \\    });
-        \\    u = (x: {
-        \\        const _ref = &u;
-        \\        const _tmp = _ref.*;
-        \\        _ref.* +%= 1;
-        \\        break :x _tmp;
-        \\    });
-        \\    u = (x: {
-        \\        const _ref = &u;
-        \\        const _tmp = _ref.*;
-        \\        _ref.* -%= 1;
-        \\        break :x _tmp;
-        \\    });
+        \\    i = blk: {
+        \\        const _ref_1 = &i;
+        \\        const _tmp_2 = _ref_1.*;
+        \\        _ref_1.* += 1;
+        \\        break :blk _tmp_2;
+        \\    };
+        \\    i = blk: {
+        \\        const _ref_3 = &i;
+        \\        const _tmp_4 = _ref_3.*;
+        \\        _ref_3.* -= 1;
+        \\        break :blk _tmp_4;
+        \\    };
+        \\    u = blk: {
+        \\        const _ref_5 = &u;
+        \\        const _tmp_6 = _ref_5.*;
+        \\        _ref_5.* +%= 1;
+        \\        break :blk _tmp_6;
+        \\    };
+        \\    u = blk: {
+        \\        const _ref_7 = &u;
+        \\        const _tmp_8 = _ref_7.*;
+        \\        _ref_7.* -%= 1;
+        \\        break :blk _tmp_8;
+        \\    };
+        \\}
+    });
+
+    /////////////// Cases for only stage1 which are TODO items for stage2 ////////////////
+
+    cases.add("macro defines string literal with hex",
+        \\#define FOO "aoeu\xab derp"
+        \\#define FOO2 "aoeu\x0007a derp"
+        \\#define FOO_CHAR '\xfF'
+    , &[_][]const u8{
+        \\pub const FOO = "aoeu\xab derp";
+    ,
+        \\pub const FOO2 = "aoeuz derp";
+    ,
+        \\pub const FOO_CHAR = 255;
+    });
+
+    cases.add("macro defines string literal with octal",
+        \\#define FOO "aoeu\023 derp"
+        \\#define FOO2 "aoeu\0234 derp"
+        \\#define FOO_CHAR '\077'
+    , &[_][]const u8{
+        \\pub const FOO = "aoeu\x13 derp";
+    ,
+        \\pub const FOO2 = "aoeu\x134 derp";
+    ,
+        \\pub const FOO_CHAR = 63;
+    });
+
+    cases.addC("__extension__ cast",
+        \\int foo(void) {
+        \\    return __extension__ 1;
+        \\}
+    , &[_][]const u8{
+        \\pub export fn foo() c_int {
+        \\    return 1;
         \\}
     });
 
@@ -2789,4 +2787,207 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
         \\    });
         \\}
     });
+
+    cases.addC("shift right assign",
+        \\int log2(unsigned a) {
+        \\    int i = 0;
+        \\    while (a > 0) {
+        \\        a >>= 1;
+        \\    }
+        \\    return i;
+        \\}
+    , &[_][]const u8{
+        \\pub export fn log2(_arg_a: c_uint) c_int {
+        \\    var a = _arg_a;
+        \\    var i: c_int = 0;
+        \\    while (a > @as(c_uint, 0)) {
+        \\        a >>= @as(@import("std").math.Log2Int(c_uint), 1);
+        \\    }
+        \\    return i;
+        \\}
+    });
+
+    cases.addC("shift right assign with a fixed size type",
+        \\#include <stdint.h>
+        \\int log2(uint32_t a) {
+        \\    int i = 0;
+        \\    while (a > 0) {
+        \\        a >>= 1;
+        \\    }
+        \\    return i;
+        \\}
+    , &[_][]const u8{
+        \\pub export fn log2(_arg_a: u32) c_int {
+        \\    var a = _arg_a;
+        \\    var i: c_int = 0;
+        \\    while (a > @as(c_uint, 0)) {
+        \\        a >>= @as(u5, 1);
+        \\    }
+        \\    return i;
+        \\}
+    });
+
+    cases.addC("compound assignment operators",
+        \\void foo(void) {
+        \\    int a = 0;
+        \\    a += (a += 1);
+        \\    a -= (a -= 1);
+        \\    a *= (a *= 1);
+        \\    a &= (a &= 1);
+        \\    a |= (a |= 1);
+        \\    a ^= (a ^= 1);
+        \\    a >>= (a >>= 1);
+        \\    a <<= (a <<= 1);
+        \\}
+    , &[_][]const u8{
+        \\pub export fn foo() void {
+        \\    var a: c_int = 0;
+        \\    a += (x: {
+        \\        const _ref = &a;
+        \\        _ref.* = (_ref.* + 1);
+        \\        break :x _ref.*;
+        \\    });
+        \\    a -= (x: {
+        \\        const _ref = &a;
+        \\        _ref.* = (_ref.* - 1);
+        \\        break :x _ref.*;
+        \\    });
+        \\    a *= (x: {
+        \\        const _ref = &a;
+        \\        _ref.* = (_ref.* * 1);
+        \\        break :x _ref.*;
+        \\    });
+        \\    a &= (x: {
+        \\        const _ref = &a;
+        \\        _ref.* = (_ref.* & 1);
+        \\        break :x _ref.*;
+        \\    });
+        \\    a |= (x: {
+        \\        const _ref = &a;
+        \\        _ref.* = (_ref.* | 1);
+        \\        break :x _ref.*;
+        \\    });
+        \\    a ^= (x: {
+        \\        const _ref = &a;
+        \\        _ref.* = (_ref.* ^ 1);
+        \\        break :x _ref.*;
+        \\    });
+        \\    a >>= @as(@import("std").math.Log2Int(c_int), (x: {
+        \\        const _ref = &a;
+        \\        _ref.* = (_ref.* >> @as(@import("std").math.Log2Int(c_int), 1));
+        \\        break :x _ref.*;
+        \\    }));
+        \\    a <<= @as(@import("std").math.Log2Int(c_int), (x: {
+        \\        const _ref = &a;
+        \\        _ref.* = (_ref.* << @as(@import("std").math.Log2Int(c_int), 1));
+        \\        break :x _ref.*;
+        \\    }));
+        \\}
+    });
+
+    cases.addC("compound assignment operators unsigned",
+        \\void foo(void) {
+        \\    unsigned a = 0;
+        \\    a += (a += 1);
+        \\    a -= (a -= 1);
+        \\    a *= (a *= 1);
+        \\    a &= (a &= 1);
+        \\    a |= (a |= 1);
+        \\    a ^= (a ^= 1);
+        \\    a >>= (a >>= 1);
+        \\    a <<= (a <<= 1);
+        \\}
+    , &[_][]const u8{
+        \\pub export fn foo() void {
+        \\    var a: c_uint = @as(c_uint, 0);
+        \\    a +%= (x: {
+        \\        const _ref = &a;
+        \\        _ref.* = (_ref.* +% @as(c_uint, 1));
+        \\        break :x _ref.*;
+        \\    });
+        \\    a -%= (x: {
+        \\        const _ref = &a;
+        \\        _ref.* = (_ref.* -% @as(c_uint, 1));
+        \\        break :x _ref.*;
+        \\    });
+        \\    a *%= (x: {
+        \\        const _ref = &a;
+        \\        _ref.* = (_ref.* *% @as(c_uint, 1));
+        \\        break :x _ref.*;
+        \\    });
+        \\    a &= (x: {
+        \\        const _ref = &a;
+        \\        _ref.* = (_ref.* & @as(c_uint, 1));
+        \\        break :x _ref.*;
+        \\    });
+        \\    a |= (x: {
+        \\        const _ref = &a;
+        \\        _ref.* = (_ref.* | @as(c_uint, 1));
+        \\        break :x _ref.*;
+        \\    });
+        \\    a ^= (x: {
+        \\        const _ref = &a;
+        \\        _ref.* = (_ref.* ^ @as(c_uint, 1));
+        \\        break :x _ref.*;
+        \\    });
+        \\    a >>= @as(@import("std").math.Log2Int(c_uint), (x: {
+        \\        const _ref = &a;
+        \\        _ref.* = (_ref.* >> @as(@import("std").math.Log2Int(c_uint), 1));
+        \\        break :x _ref.*;
+        \\    }));
+        \\    a <<= @as(@import("std").math.Log2Int(c_uint), (x: {
+        \\        const _ref = &a;
+        \\        _ref.* = (_ref.* << @as(@import("std").math.Log2Int(c_uint), 1));
+        \\        break :x _ref.*;
+        \\    }));
+        \\}
+    });
+
+    cases.addC("post increment/decrement",
+        \\void foo(void) {
+        \\    int i = 0;
+        \\    unsigned u = 0;
+        \\    i++;
+        \\    i--;
+        \\    u++;
+        \\    u--;
+        \\    i = i++;
+        \\    i = i--;
+        \\    u = u++;
+        \\    u = u--;
+        \\}
+    , &[_][]const u8{
+        \\pub export fn foo() void {
+        \\    var i: c_int = 0;
+        \\    var u: c_uint = @as(c_uint, 0);
+        \\    i += 1;
+        \\    i -= 1;
+        \\    u +%= 1;
+        \\    u -%= 1;
+        \\    i = (x: {
+        \\        const _ref = &i;
+        \\        const _tmp = _ref.*;
+        \\        _ref.* += 1;
+        \\        break :x _tmp;
+        \\    });
+        \\    i = (x: {
+        \\        const _ref = &i;
+        \\        const _tmp = _ref.*;
+        \\        _ref.* -= 1;
+        \\        break :x _tmp;
+        \\    });
+        \\    u = (x: {
+        \\        const _ref = &u;
+        \\        const _tmp = _ref.*;
+        \\        _ref.* +%= 1;
+        \\        break :x _tmp;
+        \\    });
+        \\    u = (x: {
+        \\        const _ref = &u;
+        \\        const _tmp = _ref.*;
+        \\        _ref.* -%= 1;
+        \\        break :x _tmp;
+        \\    });
+        \\}
+    });
 }