Commit 78fba4e021

Veikka Tuominen <git@vexu.eu>
2021-02-15 15:07:21
translate-c: get all run-translated-c tests passing
1 parent 77a11e6
Changed files (4)
lib/std/zig/parser_test.zig
@@ -3669,12 +3669,12 @@ test "zig fmt: hexadeciaml float literals with underscore separators" {
     );
 }
 
-//test "zig fmt: C var args" {
-//    try testCanonical(
-//        \\pub extern "c" fn printf(format: [*:0]const u8, ...) c_int;
-//        \\
-//    );
-//}
+test "zig fmt: C var args" {
+   try testCanonical(
+       \\pub extern "c" fn printf(format: [*:0]const u8, ...) c_int;
+       \\
+   );
+}
 
 //test "zig fmt: Only indent multiline string literals in function calls" {
 //    try testCanonical(
lib/std/zig/render.zig
@@ -1308,7 +1308,7 @@ fn renderFnProto(ais: *Ais, tree: ast.Tree, fn_proto: ast.full.FnProto, space: S
                 .r_paren => break,
                 .comma => {
                     try renderToken(ais, tree, last_param_token, .space); // ,
-                    last_param_token += 1;
+                    continue;
                 },
                 else => {}, // Parameter type without a name.
             }
src/translate_c/ast.zig
@@ -491,7 +491,10 @@ pub const Payload = struct {
 
     pub const Enum = struct {
         base: Payload,
-        data: []Field,
+        data: struct {
+            int_type: Node,
+            fields: []Field,
+        },
 
         pub const Field = struct {
             name: []const u8,
@@ -825,11 +828,6 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex {
             .main_token = try c.addToken(.identifier, "void"),
             .data = undefined,
         }),
-        .@"anytype" => return c.addNode(.{
-            .tag = .@"anytype",
-            .main_token = try c.addToken(.keyword_anytype, "anytype"),
-            .data = undefined,
-        }),
         .noreturn_type => return c.addNode(.{
             .tag = .identifier,
             .main_token = try c.addToken(.identifier, "noreturn"),
@@ -946,7 +944,7 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex {
             const payload = node.castTag(.char_literal).?.data;
             return c.addNode(.{
                 .tag = .identifier,
-                .main_token = try c.addToken(.string_literal, payload),
+                .main_token = try c.addToken(.char_literal, payload),
                 .data = undefined,
             });
         },
@@ -1268,7 +1266,7 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex {
             const lhs = try c.addNode(.{
                 .tag = .identifier,
                 .main_token = try c.addToken(.identifier, "_"),
-                .data = .{ .lhs = undefined, .rhs = undefined },
+                .data = undefined,
             });
             return c.addNode(.{
                 .tag = .assign,
@@ -1510,7 +1508,7 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex {
                     .rhs = try c.addNode(.{
                         .tag = .integer_literal,
                         .main_token = try c.addTokenFmt(.integer_literal, "{d}", .{payload.count}),
-                        .data = .{ .lhs = undefined, .rhs = undefined },
+                        .data = undefined,
                     }),
                 },
             });
@@ -1519,7 +1517,7 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex {
             const payload = node.castTag(.empty_array).?.data;
 
             const type_expr = try renderArrayType(c, 0, payload);
-            return renderArrayInit(c, 0, &.{});
+            return renderArrayInit(c, type_expr, &.{});
         },
         .array_init => {
             const payload = node.castTag(.array_init).?.data;
@@ -1534,15 +1532,17 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex {
         .@"struct", .@"union" => return renderRecord(c, node),
         .@"enum" => {
             const payload = node.castTag(.@"enum").?.data;
+            _ = try c.addToken(.keyword_extern, "extern");
             const enum_tok = try c.addToken(.keyword_enum, "enum");
-
+            _ = try c.addToken(.l_paren, "(");
+            const arg_expr = try renderNode(c, payload.int_type);
+            _ = try c.addToken(.r_paren, ")");
             _ = try c.addToken(.l_brace, "{");
-            const members = try c.gpa.alloc(NodeIndex, std.math.max(payload.len + 1, 1));
+            const members = try c.gpa.alloc(NodeIndex, std.math.max(payload.fields.len + 1, 1));
             defer c.gpa.free(members);
             members[0] = 0;
-            members[1] = 0;
 
-            for (payload) |field, i| {
+            for (payload.fields) |field, i| {
                 const name_tok = try c.addIdentifier(field.name);
                 const value_expr = if (field.value) |some| blk: {
                     _ = try c.addToken(.equal, "=");
@@ -1560,7 +1560,7 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex {
                 _ = try c.addToken(.comma, ",");
             }
             // make non-exhaustive
-            members[payload.len] = try c.addNode(.{
+            members[payload.fields.len] = try c.addNode(.{
                 .tag = .container_field_init,
                 .main_token = try c.addIdentifier("_"),
                 .data = .{
@@ -1571,26 +1571,18 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex {
             _ = try c.addToken(.comma, ",");
             _ = try c.addToken(.r_brace, "}");
 
-            if (members.len <= 2) {
-                return c.addNode(.{
-                    .tag = .container_decl_two_comma,
-                    .main_token = enum_tok,
-                    .data = .{
-                        .lhs = members[0],
-                        .rhs = members[1],
-                    },
-                });
-            } else {
-                const span = try c.listToSpan(members);
-                return c.addNode(.{
-                    .tag = .container_decl_comma,
-                    .main_token = enum_tok,
-                    .data = .{
-                        .lhs = span.start,
-                        .rhs = span.end,
-                    },
-                });
-            }
+            const span = try c.listToSpan(members);
+            return c.addNode(.{
+                .tag = .container_decl_arg_comma,
+                .main_token = enum_tok,
+                .data = .{
+                    .lhs = arg_expr,
+                    .rhs = try c.addExtra(NodeSubRange{
+                        .start = span.start,
+                        .end = span.end,
+                    }),
+                },
+            });
         },
         .enum_redecl => {
             const payload = node.castTag(.enum_redecl).?.data;
@@ -1701,12 +1693,16 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex {
                 });
             }
         },
+        .@"anytype" => unreachable, // Handled in renderParams
     }
 }
 
 fn renderRecord(c: *Context, node: Node) !NodeIndex {
     const payload = @fieldParentPtr(Payload.Record, "base", node.ptr_otherwise).data;
-    if (payload.is_packed) _ = try c.addToken(.keyword_packed, "packed");
+    if (payload.is_packed)
+        _ = try c.addToken(.keyword_packed, "packed")
+    else
+        _ = try c.addToken(.keyword_extern, "extern");
     const kind_tok = if (node.tag() == .@"struct")
         try c.addToken(.keyword_struct, "struct")
     else
@@ -1829,7 +1825,7 @@ fn renderArrayType(c: *Context, len: usize, elem_type: Node) !NodeIndex {
     const len_expr = try c.addNode(.{
         .tag = .integer_literal,
         .main_token = try c.addTokenFmt(.integer_literal, "{d}", .{len}),
-        .data = .{ .lhs = undefined, .rhs = undefined },
+        .data = undefined,
     });
     _ = try c.addToken(.r_bracket, "]");
     const elem_type_expr = try renderNode(c, elem_type);
@@ -1920,6 +1916,8 @@ fn renderNodeGrouped(c: *Context, node: Node) !NodeIndex {
         .negate_wrap,
         .bit_not,
         .func,
+        .call,
+        .array_type,
         => {
             // no grouping needed
             return renderNode(c, node);
@@ -1954,7 +1952,6 @@ fn renderNodeGrouped(c: *Context, node: Node) !NodeIndex {
         .array_cat,
         .array_filler,
         .@"if",
-        .call,
         .@"enum",
         .@"struct",
         .@"union",
@@ -1962,7 +1959,6 @@ fn renderNodeGrouped(c: *Context, node: Node) !NodeIndex {
         .tuple,
         .container_init,
         .block,
-        .array_type,
         => return c.addNode(.{
             .tag = .grouped_expression,
             .main_token = try c.addToken(.l_paren, "("),
@@ -2161,7 +2157,7 @@ fn renderVar(c: *Context, node: Node) !NodeIndex {
         const res = try c.addNode(.{
             .tag = .integer_literal,
             .main_token = try c.addTokenFmt(.integer_literal, "{d}", .{some}),
-            .data = .{ .lhs = undefined, .rhs = undefined },
+            .data = undefined,
         });
         _ = try c.addToken(.r_paren, ")");
         break :blk res;
@@ -2173,7 +2169,7 @@ fn renderVar(c: *Context, node: Node) !NodeIndex {
         const res = try c.addNode(.{
             .tag = .string_literal,
             .main_token = try c.addTokenFmt(.string_literal, "\"{s}\"", .{std.zig.fmtEscapes(some)}),
-            .data = .{ .lhs = undefined, .rhs = undefined },
+            .data = undefined,
         });
         _ = try c.addToken(.r_paren, ")");
         break :blk res;
@@ -2232,39 +2228,10 @@ fn renderFunc(c: *Context, node: Node) !NodeIndex {
     const fn_token = try c.addToken(.keyword_fn, "fn");
     if (payload.name) |some| _ = try c.addIdentifier(some);
 
-    _ = try c.addToken(.l_paren, "(");
-    const first = if (payload.params.len != 0) blk: {
-        const param = payload.params[0];
-        if (param.is_noalias) _ = try c.addToken(.keyword_noalias, "noalias");
-        if (param.name) |some| {
-            _ = try c.addIdentifier(some);
-            _ = try c.addToken(.colon, ":");
-        }
-        break :blk try renderNode(c, param.type);
-    } else 0;
-
+    const params = try renderParams(c, payload.params, payload.is_var_args);
+    defer params.deinit();
     var span: NodeSubRange = undefined;
-    if (payload.params.len > 1) {
-        var params = try c.gpa.alloc(NodeIndex, payload.params.len);
-        defer c.gpa.free(params);
-
-        params[0] = first;
-        for (payload.params[1..]) |param, i| {
-            _ = try c.addToken(.comma, ",");
-            if (param.is_noalias) _ = try c.addToken(.keyword_noalias, "noalias");
-            if (param.name) |some| {
-                _ = try c.addIdentifier(some);
-                _ = try c.addToken(.colon, ":");
-            }
-            params[i + 1] = try renderNode(c, param.type);
-        }
-        span = try c.listToSpan(params);
-    }
-    if (payload.is_var_args) {
-        if (payload.params.len != 0) _ = try c.addToken(.comma, ",");
-        _ = try c.addToken(.ellipsis3, "...");
-    }
-    _ = try c.addToken(.r_paren, ")");
+    if (params.items.len > 1) span = try c.listToSpan(params.items);
 
     const align_expr = if (payload.alignment) |some| blk: {
         _ = try c.addToken(.keyword_align, "align");
@@ -2272,7 +2239,7 @@ fn renderFunc(c: *Context, node: Node) !NodeIndex {
         const res = try c.addNode(.{
             .tag = .integer_literal,
             .main_token = try c.addTokenFmt(.integer_literal, "{d}", .{some}),
-            .data = .{ .lhs = undefined, .rhs = undefined },
+            .data = undefined,
         });
         _ = try c.addToken(.r_paren, ")");
         break :blk res;
@@ -2284,7 +2251,7 @@ fn renderFunc(c: *Context, node: Node) !NodeIndex {
         const res = try c.addNode(.{
             .tag = .string_literal,
             .main_token = try c.addTokenFmt(.string_literal, "\"{s}\"", .{std.zig.fmtEscapes(some)}),
-            .data = .{ .lhs = undefined, .rhs = undefined },
+            .data = undefined,
         });
         _ = try c.addToken(.r_paren, ")");
         break :blk res;
@@ -2296,8 +2263,8 @@ fn renderFunc(c: *Context, node: Node) !NodeIndex {
         _ = try c.addToken(.period, ".");
         const res = try c.addNode(.{
             .tag = .enum_literal,
-            .main_token = try c.addTokenFmt(.identifier, "{}", .{some}),
-            .data = .{ .lhs = undefined, .rhs = undefined },
+            .main_token = try c.addTokenFmt(.identifier, "{s}", .{@tagName(some)}),
+            .data = undefined,
         });
         _ = try c.addToken(.r_paren, ")");
         break :blk res;
@@ -2307,12 +2274,12 @@ fn renderFunc(c: *Context, node: Node) !NodeIndex {
 
     const fn_proto = try blk: {
         if (align_expr == 0 and section_expr == 0 and callconv_expr == 0) {
-            if (payload.params.len < 2)
+            if (params.items.len < 2)
                 break :blk c.addNode(.{
                     .tag = .fn_proto_simple,
                     .main_token = fn_token,
                     .data = .{
-                        .lhs = first,
+                        .lhs = params.items[0],
                         .rhs = return_type_expr,
                     },
                 })
@@ -2329,13 +2296,13 @@ fn renderFunc(c: *Context, node: Node) !NodeIndex {
                     },
                 });
         }
-        if (payload.params.len < 2)
+        if (params.items.len < 2)
             break :blk c.addNode(.{
                 .tag = .fn_proto_one,
                 .main_token = fn_token,
                 .data = .{
                     .lhs = try c.addExtra(std.zig.ast.Node.FnProtoOne{
-                        .param = first,
+                        .param = params.items[0],
                         .align_expr = align_expr,
                         .section_expr = section_expr,
                         .callconv_expr = callconv_expr,
@@ -2383,35 +2350,10 @@ fn renderMacroFunc(c: *Context, node: Node) !NodeIndex {
     const fn_token = try c.addToken(.keyword_fn, "fn");
     _ = try c.addIdentifier(payload.name);
 
-    _ = try c.addToken(.l_paren, "(");
-    const first = if (payload.params.len != 0) blk: {
-        const param = payload.params[0];
-        if (param.is_noalias) _ = try c.addToken(.keyword_noalias, "noalias");
-        if (param.name) |some| {
-            _ = try c.addIdentifier(some);
-            _ = try c.addToken(.colon, ":");
-        }
-        break :blk try renderNode(c, param.type);
-    } else 0;
-
+    const params = try renderParams(c, payload.params, false);
+    defer params.deinit();
     var span: NodeSubRange = undefined;
-    if (payload.params.len > 1) {
-        var params = try c.gpa.alloc(NodeIndex, payload.params.len);
-        defer c.gpa.free(params);
-
-        params[0] = first;
-        for (payload.params[1..]) |param, i| {
-            _ = try c.addToken(.comma, ",");
-            if (param.is_noalias) _ = try c.addToken(.keyword_noalias, "noalias");
-            if (param.name) |some| {
-                _ = try c.addIdentifier(some);
-                _ = try c.addToken(.colon, ":");
-            }
-            params[i + 1] = try renderNode(c, param.type);
-        }
-        span = try c.listToSpan(params);
-    }
-    _ = try c.addToken(.r_paren, ")");
+    if (params.items.len > 1) span = try c.listToSpan(params.items);
 
     const callconv_expr = blk: {
         _ = try c.addToken(.keyword_callconv, "callconv");
@@ -2420,7 +2362,7 @@ fn renderMacroFunc(c: *Context, node: Node) !NodeIndex {
         const res = try c.addNode(.{
             .tag = .enum_literal,
             .main_token = try c.addToken(.identifier, "Inline"),
-            .data = .{ .lhs = undefined, .rhs = undefined },
+            .data = undefined,
         });
         _ = try c.addToken(.r_paren, ")");
         break :blk res;
@@ -2428,13 +2370,13 @@ fn renderMacroFunc(c: *Context, node: Node) !NodeIndex {
     const return_type_expr = try renderNode(c, payload.return_type);
 
     const fn_proto = try blk: {
-        if (payload.params.len < 2)
+        if (params.items.len < 2)
             break :blk c.addNode(.{
                 .tag = .fn_proto_one,
                 .main_token = fn_token,
                 .data = .{
                     .lhs = try c.addExtra(std.zig.ast.Node.FnProtoOne{
-                        .param = first,
+                        .param = params.items[0],
                         .align_expr = 0,
                         .section_expr = 0,
                         .callconv_expr = callconv_expr,
@@ -2467,3 +2409,32 @@ fn renderMacroFunc(c: *Context, node: Node) !NodeIndex {
         },
     });
 }
+
+fn renderParams(c: *Context, params: []Payload.Param, is_var_args: bool) !std.ArrayList(NodeIndex) {
+    _ = try c.addToken(.l_paren, "(");
+    var rendered = std.ArrayList(NodeIndex).init(c.gpa);
+    errdefer rendered.deinit();
+    try rendered.ensureCapacity(std.math.max(params.len, 1));
+
+    for (params) |param, i| {
+        if (i != 0) _ = try c.addToken(.comma, ",");
+        if (param.is_noalias) _ = try c.addToken(.keyword_noalias, "noalias");
+        if (param.name) |some| {
+            _ = try c.addIdentifier(some);
+            _ = try c.addToken(.colon, ":");
+        }
+        if (param.type.tag() == .@"anytype") {
+            _ = try c.addToken(.keyword_anytype, "anytype");
+            continue;
+        }
+        rendered.appendAssumeCapacity(try renderNode(c, param.type));
+    }
+    if (is_var_args) {
+        if (params.len != 0) _ = try c.addToken(.comma, ",");
+        _ = try c.addToken(.ellipsis3, "...");
+    }
+    _ = try c.addToken(.r_paren, ")");
+
+    if (rendered.items.len == 0) rendered.appendAssumeCapacity(0);
+    return rendered;
+}
src/translate_c.zig
@@ -990,7 +990,10 @@ fn transEnumDecl(c: *Context, enum_decl: *const clang.EnumDecl) Error!?Node {
             }));
         }
 
-        break :blk try Tag.@"enum".create(c.arena, try c.arena.dupe(ast.Payload.Enum.Field, fields.items));
+        break :blk try Tag.@"enum".create(c.arena, .{
+            .int_type = init_arg_expr,
+            .fields = try c.arena.dupe(ast.Payload.Enum.Field, fields.items),
+        });
     } else blk: {
         _ = try c.opaque_demotes.put(c.gpa, @ptrToInt(enum_decl.getCanonicalDecl()), {});
         break :blk Tag.opaque_literal.init();
@@ -1540,8 +1543,8 @@ fn finishBoolExpr(
             }
         },
         .Pointer => {
-            // node == null
-            return Tag.equal.create(c.arena, .{ .lhs = node, .rhs = Tag.null_literal.init() });
+            // node != null
+            return Tag.not_equal.create(c.arena, .{ .lhs = node, .rhs = Tag.null_literal.init() });
         },
         .Typedef => {
             const typedef_ty = @ptrCast(*const clang.TypedefType, ty);
@@ -1675,7 +1678,8 @@ fn transStringLiteralAsArray(
     const ty = expr_base.getType().getTypePtr();
     const const_arr_ty = @ptrCast(*const clang.ConstantArrayType, ty);
 
-    const arr_type = try transQualType(c, const_arr_ty.getElementType(), expr_base.getBeginLoc());
+    const elem_type = try transQualType(c, const_arr_ty.getElementType(), expr_base.getBeginLoc());
+    const arr_type = try Tag.array_type.create(c.arena, .{ .len = array_size, .elem_type = elem_type });
     const init_list = try c.arena.alloc(Node, array_size);
 
     var i: c_uint = 0;
@@ -2668,7 +2672,7 @@ fn transUnaryOperator(c: *Context, scope: *Scope, stmt: *const clang.UnaryOperat
             return Tag.bit_not.create(c.arena, try transExpr(c, scope, op_expr, .used));
         },
         .LNot => {
-            return Tag.not.create(c.arena, try transExpr(c, scope, op_expr, .used));
+            return Tag.not.create(c.arena, try transBoolExpr(c, scope, op_expr, .used));
         },
         .Extension => {
             return transExpr(c, scope, stmt.getSubExpr(), used);
@@ -2969,8 +2973,15 @@ fn transBreak(c: *Context, scope: *Scope) TransError!Node {
 
 fn transFloatingLiteral(c: *Context, scope: *Scope, stmt: *const clang.FloatingLiteral, used: ResultUsed) TransError!Node {
     // TODO use something more accurate
-    const dbl = stmt.getValueAsApproximateDouble();
-    const node = try transCreateNodeNumber(c, dbl, .float);
+    var dbl = stmt.getValueAsApproximateDouble();
+    const is_negative = dbl < 0;
+    if (is_negative) dbl = -dbl;
+    const str = try std.fmt.allocPrint(c.arena, "{d}", .{dbl});
+    var node = if (dbl == std.math.floor(dbl))
+        try Tag.integer_literal.create(c.arena, str)
+    else
+        try Tag.float_literal.create(c.arena, str);
+    if (is_negative) node = try Tag.negate.create(c.arena, node);
     return maybeSuppressResult(c, scope, used, node);
 }
 
@@ -3004,8 +3015,11 @@ fn transBinaryConditionalOperator(c: *Context, scope: *Scope, stmt: *const clang
         },
     };
     defer cond_scope.deinit();
-    const cond_node = try transBoolExpr(c, &cond_scope.base, cond_expr, .used);
-    var then_body = try Tag.identifier.create(c.arena, mangled_name);
+
+    const cond_ident = try Tag.identifier.create(c.arena, mangled_name);
+    const ty = getExprQualType(c, cond_expr).getTypePtr();
+    const cond_node = try finishBoolExpr(c, &cond_scope.base, cond_expr.getBeginLoc(), ty, cond_ident, .used);
+    var then_body = cond_ident;
     if (!res_is_bool and isBoolRes(init_node)) {
         then_body = try Tag.bool_to_int.create(c.arena, then_body);
     }
@@ -3489,11 +3503,13 @@ fn transCreateNodeAPInt(c: *Context, int: *const clang.APSInt) !Node {
         else => @compileError("unimplemented"),
     }
 
-    const big: math.big.int.Const = .{ .limbs = limbs, .positive = !is_negative };
+    const big: math.big.int.Const = .{ .limbs = limbs, .positive = true };
     const str = big.toStringAlloc(c.arena, 10, false) catch |err| switch (err) {
         error.OutOfMemory => return error.OutOfMemory,
     };
-    return Tag.integer_literal.create(c.arena, str);
+    const res = try Tag.integer_literal.create(c.arena, str);
+    if (is_negative) return Tag.negate.create(c.arena, res);
+    return res;
 }
 
 fn transCreateNodeNumber(c: *Context, num: anytype, num_kind: enum { int, float }) !Node {
@@ -3567,7 +3583,7 @@ fn transCreateNodeShiftOp(
 
     const rhs_type = try qualTypeToLog2IntRef(c, stmt.getType(), rhs_location);
     const rhs = try transExprCoercing(c, scope, rhs_expr, .used);
-    const rhs_casted = try Tag.int_cast.create(c.arena, .{ .lhs = rhs_type, .rhs = rhs_type });
+    const rhs_casted = try Tag.int_cast.create(c.arena, .{ .lhs = rhs_type, .rhs = rhs });
 
     return transCreateNodeInfixOp(c, scope, op, lhs, rhs_casted, used);
 }
@@ -3622,7 +3638,8 @@ fn transType(c: *Context, ty: *const clang.Type, source_loc: clang.SourceLocatio
             const is_volatile = child_qt.isVolatileQualified();
             const elem_type = try transQualType(c, child_qt, source_loc);
             if (typeIsOpaque(c, child_qt.getTypePtr(), source_loc) or qualTypeWasDemotedToOpaque(c, child_qt)) {
-                return Tag.single_pointer.create(c.arena, .{ .is_const = is_const, .is_volatile = is_volatile, .elem_type = elem_type });
+                const ptr = try Tag.single_pointer.create(c.arena, .{ .is_const = is_const, .is_volatile = is_volatile, .elem_type = elem_type });
+                return Tag.optional_type.create(c.arena, ptr);
             }
 
             return Tag.c_pointer.create(c.arena, .{ .is_const = is_const, .is_volatile = is_volatile, .elem_type = elem_type });