diff --git a/lib/std/zig/parser_test.zig b/lib/std/zig/parser_test.zig index e4778b35e1..623682056c 100644 --- a/lib/std/zig/parser_test.zig +++ b/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( diff --git a/lib/std/zig/render.zig b/lib/std/zig/render.zig index 6fd091d32c..89a9f472ef 100644 --- a/lib/std/zig/render.zig +++ b/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. } diff --git a/src/translate_c.zig b/src/translate_c.zig index 995ff16b1c..8b7aedcee1 100644 --- a/src/translate_c.zig +++ b/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 }); diff --git a/src/translate_c/ast.zig b/src/translate_c/ast.zig index b22e61c65e..3921acd546 100644 --- a/src/translate_c/ast.zig +++ b/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; +}