Commit 62bfff5e87

Vexu <git@vexu.eu>
2019-12-18 12:30:34
translate-c-2 fix expression grouping bugs
1 parent f54e7d6
Changed files (3)
lib
std
src-self-hosted
test
lib/std/zig/render.zig
@@ -1629,7 +1629,7 @@ fn renderExpression(
         .If => {
             const if_node = @fieldParentPtr(ast.Node.If, "base", base);
 
-            const lparen = tree.prevToken(if_node.condition.firstToken());
+            const lparen = tree.nextToken(if_node.if_token);
             const rparen = tree.nextToken(if_node.condition.lastToken());
 
             try renderToken(tree, stream, if_node.if_token, indent, start_col, Space.Space); // if
src-self-hosted/translate_c.zig
@@ -954,13 +954,6 @@ fn transBinaryOperator(
     }
     const lhs_node = try transExpr(rp, scope, ZigClangBinaryOperator_getLHS(stmt), .used, .l_value);
     switch (op) {
-        .PtrMemD, .PtrMemI, .Cmp => return revertAndWarn(
-            rp,
-            error.UnsupportedTranslation,
-            ZigClangBinaryOperator_getBeginLoc(stmt),
-            "TODO: handle more C binary operators: {}",
-            .{op},
-        ),
         .Add => {
             if (cIsUnsignedInteger(qt)) {
                 op_token = try appendToken(rp.c, .PlusPercent, "+%");
@@ -1205,6 +1198,26 @@ fn transBoolExpr(
         undefined;
     var res = try transExpr(rp, scope, expr, used, lrvalue);
 
+    if (isBoolRes(res))
+        return res;
+    const ty = ZigClangQualType_getTypePtr(getExprQualTypeBeforeImplicitCast(rp.c, expr));
+    const node = try finishBoolExpr(rp, scope, ZigClangExpr_getBeginLoc(expr), ty, res, used);
+
+    if (grouped) {
+        const rparen = try appendToken(rp.c, .RParen, ")");
+        const grouped_expr = try rp.c.a().create(ast.Node.GroupedExpression);
+        grouped_expr.* = .{
+            .lparen = lparen,
+            .expr = node,
+            .rparen = rparen,
+        };
+        return maybeSuppressResult(rp, scope, used, &grouped_expr.base);
+    } else {
+        return maybeSuppressResult(rp, scope, used, node);
+    }
+}
+
+fn isBoolRes(res: *ast.Node) bool {
     switch (res.id) {
         .InfixOp => switch (@fieldParentPtr(ast.Node.InfixOp, "base", res).op) {
             .BoolOr,
@@ -1215,23 +1228,20 @@ fn transBoolExpr(
             .GreaterThan,
             .LessOrEqual,
             .GreaterOrEqual,
-            => return res,
+            => return true,
 
             else => {},
         },
-
         .PrefixOp => switch (@fieldParentPtr(ast.Node.PrefixOp, "base", res).op) {
-            .BoolNot => return res,
+            .BoolNot => return true,
 
             else => {},
         },
-
-        .BoolLiteral => return res,
-
+        .BoolLiteral => return true,
+        .GroupedExpression => return isBoolRes(@fieldParentPtr(ast.Node.GroupedExpression, "base", res).expr),
         else => {},
     }
-    const ty = ZigClangQualType_getTypePtr(getExprQualTypeBeforeImplicitCast(rp.c, expr));
-    return finishBoolExpr(rp, scope, ZigClangExpr_getBeginLoc(expr), ty, res, used, grouped);
+    return false;
 }
 
 fn finishBoolExpr(
@@ -1241,14 +1251,13 @@ fn finishBoolExpr(
     ty: *const ZigClangType,
     node: *ast.Node,
     used: ResultUsed,
-    grouped: bool,
 ) TransError!*ast.Node {
     switch (ZigClangType_getTypeClass(ty)) {
         .Builtin => {
             const builtin_ty = @ptrCast(*const ZigClangBuiltinType, ty);
 
             switch (ZigClangBuiltinType_getKind(builtin_ty)) {
-                .Bool,
+                .Bool => return node,
                 .Char_U,
                 .UChar,
                 .Char_S,
@@ -1276,12 +1285,12 @@ fn finishBoolExpr(
                 => {
                     const op_token = try appendToken(rp.c, .BangEqual, "!=");
                     const rhs_node = try transCreateNodeInt(rp.c, 0);
-                    return transCreateNodeInfixOp(rp, scope, node, .BangEqual, op_token, rhs_node, used, grouped);
+                    return transCreateNodeInfixOp(rp, scope, node, .BangEqual, op_token, rhs_node, used, false);
                 },
                 .NullPtr => {
                     const op_token = try appendToken(rp.c, .EqualEqual, "==");
                     const rhs_node = try transCreateNodeNullLiteral(rp.c);
-                    return transCreateNodeInfixOp(rp, scope, node, .EqualEqual, op_token, rhs_node, used, grouped);
+                    return transCreateNodeInfixOp(rp, scope, node, .EqualEqual, op_token, rhs_node, used, false);
                 },
                 else => {},
             }
@@ -1289,13 +1298,13 @@ fn finishBoolExpr(
         .Pointer => {
             const op_token = try appendToken(rp.c, .BangEqual, "!=");
             const rhs_node = try transCreateNodeNullLiteral(rp.c);
-            return transCreateNodeInfixOp(rp, scope, node, .BangEqual, op_token, rhs_node, used, grouped);
+            return transCreateNodeInfixOp(rp, scope, node, .BangEqual, op_token, rhs_node, used, false);
         },
         .Typedef => {
             const typedef_ty = @ptrCast(*const ZigClangTypedefType, ty);
             const typedef_decl = ZigClangTypedefType_getDecl(typedef_ty);
             const underlying_type = ZigClangTypedefNameDecl_getUnderlyingType(typedef_decl);
-            return finishBoolExpr(rp, scope, loc, ZigClangQualType_getTypePtr(underlying_type), node, used, grouped);
+            return finishBoolExpr(rp, scope, loc, ZigClangQualType_getTypePtr(underlying_type), node, used);
         },
         .Enum => {
             const enum_ty = @ptrCast(*const ZigClangEnumType, ty);
@@ -1305,12 +1314,12 @@ fn finishBoolExpr(
 
             const op_token = try appendToken(rp.c, .BangEqual, "!=");
             const rhs_node = try transCreateNodeInt(rp.c, 0);
-            return transCreateNodeInfixOp(rp, scope, &builtin_node.base, .BangEqual, op_token, rhs_node, used, grouped);
+            return transCreateNodeInfixOp(rp, scope, &builtin_node.base, .BangEqual, op_token, rhs_node, used, false);
         },
         .Elaborated => {
             const elaborated_ty = @ptrCast(*const ZigClangElaboratedType, ty);
             const named_type = ZigClangElaboratedType_getNamedType(elaborated_ty);
-            return finishBoolExpr(rp, scope, loc, ZigClangQualType_getTypePtr(named_type), node, used, grouped);
+            return finishBoolExpr(rp, scope, loc, ZigClangQualType_getTypePtr(named_type), node, used);
         },
         else => {},
     }
@@ -2009,8 +2018,8 @@ fn transFloatingLiteral(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangFl
 }
 
 fn transConditionalOperator(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangConditionalOperator, used: ResultUsed) TransError!*ast.Node {
-    const gropued = scope.id == .Condition;
-    const lparen = if (gropued) try appendToken(rp.c, .LParen, "(") else undefined;
+    const grouped = scope.id == .Condition;
+    const lparen = if (grouped) try appendToken(rp.c, .LParen, "(") else undefined;
     const if_node = try transCreateNodeIf(rp.c);
     var cond_scope = Scope{
         .parent = scope,
@@ -2029,7 +2038,7 @@ fn transConditionalOperator(rp: RestorePoint, scope: *Scope, stmt: *const ZigCla
     if_node.@"else" = try transCreateNodeElse(rp.c);
     if_node.@"else".?.body = try transExpr(rp, scope, false_expr, .used, .r_value);
 
-    if (gropued) {
+    if (grouped) {
         const rparen = try appendToken(rp.c, .RParen, ")");
         const grouped_expr = try rp.c.a().create(ast.Node.GroupedExpression);
         grouped_expr.* = .{
test/translate_c.zig
@@ -1400,17 +1400,13 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
         \\pub const Bar = enum_Bar;
     });
 
-    cases.add_2("bitwise binary operators, simpler parens", // TODO can combine with "bitwise binary operators" when parens are correctly preserved/not added in translate-c-2
+    cases.add_2("bitwise binary operators, simpler parens",
         \\int max(int a, int b) {
-        \\    int c = (a & b);
-        \\    int d = (a | b);
-        \\    return (c ^ d);
+        \\    return (a & b) ^ (a | b);
         \\}
     , &[_][]const u8{
         \\pub export fn max(a: c_int, b: c_int) c_int {
-        \\    var c: c_int = (a & b);
-        \\    var d: c_int = (a | b);
-        \\    return (c ^ d);
+        \\    return ((a & b) ^ (a | b));
         \\}
     });
 
@@ -1438,17 +1434,19 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
         \\}
     });
 
-    cases.add_2("==, !=, no if", // TODO remove this test after `if` conversion supported, and switch "==, !=" to addC_both
+    cases.add_2("==, !=",
         \\int max(int a, int b) {
-        \\    int c = (a == b);
-        \\    int d = (a != b);
-        \\    return (c != d);
+        \\    if (a == b)
+        \\        return a;
+        \\    if (a != b)
+        \\        return b;
+        \\    return a;
         \\}
     , &[_][]const u8{
         \\pub export fn max(a: c_int, b: c_int) c_int {
-        \\    var c: c_int = (a == b);
-        \\    var d: c_int = (a != b);
-        \\    return (c != d);
+        \\    if ((a == b)) return a;
+        \\    if ((a != b)) return b;
+        \\    return a;
         \\}
     });
 
@@ -1464,6 +1462,20 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
         \\}
     });
 
+    cases.add_2("typedeffed bool expression",
+        \\typedef char* yes;
+        \\void foo(void) {
+        \\    yes a;
+        \\    if (a) 2;
+        \\}
+    , &[_][]const u8{
+        \\pub const yes = [*c]u8;
+        \\pub export fn foo() void {
+        \\    var a: yes = undefined;
+        \\    if (a != null) _ = 2;
+        \\}
+    });
+
     /////////////// Cases for only stage1 which are TODO items for stage2 ////////////////
 
     cases.addAllowWarnings("simple data types",
@@ -1575,31 +1587,6 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
         \\}
     });
 
-    cases.addC("==, !=",
-        \\int max(int a, int b) {
-        \\    if (a == b)
-        \\        return a;
-        \\    if (a != b)
-        \\        return b;
-        \\    return a;
-        \\}
-    , &[_][]const u8{
-        \\pub export fn max(a: c_int, b: c_int) c_int {
-        \\    if (a == b) return a;
-        \\    if (a != b) return b;
-        \\    return a;
-        \\}
-    });
-    cases.addC("bitwise binary operators",
-        \\int max(int a, int b) {
-        \\    return (a & b) ^ (a | b);
-        \\}
-    , &[_][]const u8{
-        \\pub export fn max(a: c_int, b: c_int) c_int {
-        \\    return (a & b) ^ (a | b);
-        \\}
-    });
-
     cases.addC("logical and, logical or",
         \\int max(int a, int b) {
         \\    if (a < b || a == b)
@@ -2596,4 +2583,30 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
         \\    }
         \\}
     });
+
+    cases.addC("==, !=",
+        \\int max(int a, int b) {
+        \\    if (a == b)
+        \\        return a;
+        \\    if (a != b)
+        \\        return b;
+        \\    return a;
+        \\}
+    , &[_][]const u8{
+        \\pub export fn max(a: c_int, b: c_int) c_int {
+        \\    if (a == b) return a;
+        \\    if (a != b) return b;
+        \\    return a;
+        \\}
+    });
+
+    cases.addC("bitwise binary operators",
+        \\int max(int a, int b) {
+        \\    return (a & b) ^ (a | b);
+        \\}
+    , &[_][]const u8{
+        \\pub export fn max(a: c_int, b: c_int) c_int {
+        \\    return (a & b) ^ (a | b);
+        \\}
+    });
 }