From 725adf833289e0a1b0826c6a774cea5283cec744 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Wed, 3 Feb 2021 22:12:11 -0700 Subject: [PATCH] zig fmt: builtin calls and array access --- lib/std/zig/ast.zig | 199 +++++++++++++++++++++--------------- lib/std/zig/parse.zig | 105 ++++++++++++++++++- lib/std/zig/parser_test.zig | 30 +++--- lib/std/zig/render.zig | 170 ++++++++++++++---------------- 4 files changed, 308 insertions(+), 196 deletions(-) diff --git a/lib/std/zig/ast.zig b/lib/std/zig/ast.zig index 64b3fa7887..3e3416e9b5 100644 --- a/lib/std/zig/ast.zig +++ b/lib/std/zig/ast.zig @@ -319,35 +319,54 @@ pub const Tree = struct { } }, - .GlobalVarDecl => unreachable, - .LocalVarDecl => unreachable, - .SimpleVarDecl => unreachable, - .AlignedVarDecl => unreachable, - .ArrayType => unreachable, - .ArrayTypeSentinel => unreachable, - .PtrTypeAligned => unreachable, - .PtrTypeSentinel => unreachable, - .PtrType => unreachable, - .SliceType => unreachable, - .StructInit => unreachable, - .SwitchCaseMulti => unreachable, - .WhileSimple => unreachable, - .WhileCont => unreachable, - .While => unreachable, - .ForSimple => unreachable, - .For => unreachable, - .FnProtoSimple => unreachable, - .FnProtoSimpleMulti => unreachable, - .FnProtoOne => unreachable, - .FnProto => unreachable, - .ContainerDecl => unreachable, - .ContainerDeclArg => unreachable, - .TaggedUnion => unreachable, - .TaggedUnionEnumTag => unreachable, - .AsmOutput => unreachable, - .AsmInput => unreachable, - .ErrorValue => unreachable, - .ErrorUnion => unreachable, + .GlobalVarDecl, + .LocalVarDecl, + .SimpleVarDecl, + .AlignedVarDecl, + => { + var i = main_tokens[n]; // mut token + while (i > 0) { + i -= 1; + switch (token_tags[i]) { + .Keyword_extern, + .Keyword_export, + .Keyword_comptime, + .Keyword_pub, + .Keyword_threadlocal, + .StringLiteral, + => continue, + + else => return i + 1, + } + } + return i; + }, + + .ArrayType => unreachable, // TODO + .ArrayTypeSentinel => unreachable, // TODO + .PtrTypeAligned => unreachable, // TODO + .PtrTypeSentinel => unreachable, // TODO + .PtrType => unreachable, // TODO + .SliceType => unreachable, // TODO + .StructInit => unreachable, // TODO + .SwitchCaseMulti => unreachable, // TODO + .WhileSimple => unreachable, // TODO + .WhileCont => unreachable, // TODO + .While => unreachable, // TODO + .ForSimple => unreachable, // TODO + .For => unreachable, // TODO + .FnProtoSimple => unreachable, // TODO + .FnProtoSimpleMulti => unreachable, // TODO + .FnProtoOne => unreachable, // TODO + .FnProto => unreachable, // TODO + .ContainerDecl => unreachable, // TODO + .ContainerDeclArg => unreachable, // TODO + .TaggedUnion => unreachable, // TODO + .TaggedUnionEnumTag => unreachable, // TODO + .AsmOutput => unreachable, // TODO + .AsmInput => unreachable, // TODO + .ErrorValue => unreachable, // TODO + .ErrorUnion => unreachable, // TODO }; } @@ -445,7 +464,9 @@ pub const Tree = struct { .Identifier, => return main_tokens[n] + end_offset, - .Call => { + .Call, + .BuiltinCall, + => { end_offset += 1; // for the `)` const params = tree.extraData(datas[n].rhs, Node.SubRange); if (params.end - params.start == 0) { @@ -453,69 +474,81 @@ pub const Tree = struct { } n = tree.extra_data[params.end - 1]; // last parameter }, - .CallOne => { - end_offset += 1; // for the `)` + .CallOne, + .ArrayAccess, + => { + end_offset += 1; // for the rparen/rbracket if (datas[n].rhs == 0) { return main_tokens[n] + end_offset; } n = datas[n].rhs; }, + .BuiltinCallTwo => { + end_offset += 1; // for the rparen + if (datas[n].rhs == 0) { + if (datas[n].lhs == 0) { + return main_tokens[n] + end_offset; + } else { + n = datas[n].lhs; + } + } else { + n = datas[n].rhs; + } + }, + .ContainerFieldInit => unreachable, .ContainerFieldAlign => unreachable, .ContainerField => unreachable, - .ArrayInitDotTwo => unreachable, - .ArrayInitDot => unreachable, - .StructInitDotTwo => unreachable, - .StructInitDot => unreachable, - .Switch => unreachable, - .If => unreachable, - .Continue => unreachable, - .EnumLiteral => unreachable, - .BuiltinCallTwo => unreachable, - .BuiltinCall => unreachable, - .ErrorSetDecl => unreachable, - .Block => unreachable, - .AsmSimple => unreachable, - .Asm => unreachable, - .SliceOpen => unreachable, - .Slice => unreachable, - .Deref => unreachable, - .ArrayAccess => unreachable, - .ArrayInitOne => unreachable, - .ArrayInit => unreachable, - .StructInitOne => unreachable, - .SwitchCaseOne => unreachable, - .SwitchRange => unreachable, - .FnDecl => unreachable, - .GlobalVarDecl => unreachable, - .LocalVarDecl => unreachable, - .SimpleVarDecl => unreachable, - .AlignedVarDecl => unreachable, - .ArrayType => unreachable, - .ArrayTypeSentinel => unreachable, - .PtrTypeAligned => unreachable, - .PtrTypeSentinel => unreachable, - .PtrType => unreachable, - .SliceType => unreachable, - .StructInit => unreachable, - .SwitchCaseMulti => unreachable, - .WhileCont => unreachable, - .While => unreachable, - .ForSimple => unreachable, - .For => unreachable, - .FnProtoSimple => unreachable, - .FnProtoSimpleMulti => unreachable, - .FnProtoOne => unreachable, - .FnProto => unreachable, - .ContainerDecl => unreachable, - .ContainerDeclArg => unreachable, - .TaggedUnion => unreachable, - .TaggedUnionEnumTag => unreachable, - .AsmOutput => unreachable, - .AsmInput => unreachable, - .ErrorValue => unreachable, + .ArrayInitDotTwo => unreachable, // TODO + .ArrayInitDot => unreachable, // TODO + .StructInitDotTwo => unreachable, // TODO + .StructInitDot => unreachable, // TODO + .Switch => unreachable, // TODO + .If => unreachable, // TODO + .Continue => unreachable, // TODO + .EnumLiteral => unreachable, // TODO + .ErrorSetDecl => unreachable, // TODO + .Block => unreachable, // TODO + .AsmSimple => unreachable, // TODO + .Asm => unreachable, // TODO + .SliceOpen => unreachable, // TODO + .Slice => unreachable, // TODO + .Deref => unreachable, // TODO + .ArrayInitOne => unreachable, // TODO + .ArrayInit => unreachable, // TODO + .StructInitOne => unreachable, // TODO + .SwitchCaseOne => unreachable, // TODO + .SwitchRange => unreachable, // TODO + .FnDecl => unreachable, // TODO + .GlobalVarDecl => unreachable, // TODO + .LocalVarDecl => unreachable, // TODO + .SimpleVarDecl => unreachable, // TODO + .AlignedVarDecl => unreachable, // TODO + .ArrayType => unreachable, // TODO + .ArrayTypeSentinel => unreachable, // TODO + .PtrTypeAligned => unreachable, // TODO + .PtrTypeSentinel => unreachable, // TODO + .PtrType => unreachable, // TODO + .SliceType => unreachable, // TODO + .StructInit => unreachable, // TODO + .SwitchCaseMulti => unreachable, // TODO + .WhileCont => unreachable, // TODO + .While => unreachable, // TODO + .ForSimple => unreachable, // TODO + .For => unreachable, // TODO + .FnProtoSimple => unreachable, // TODO + .FnProtoSimpleMulti => unreachable, // TODO + .FnProtoOne => unreachable, // TODO + .FnProto => unreachable, // TODO + .ContainerDecl => unreachable, // TODO + .ContainerDeclArg => unreachable, // TODO + .TaggedUnion => unreachable, // TODO + .TaggedUnionEnumTag => unreachable, // TODO + .AsmOutput => unreachable, // TODO + .AsmInput => unreachable, // TODO + .ErrorValue => unreachable, // TODO }; } diff --git a/lib/std/zig/parse.zig b/lib/std/zig/parse.zig index e5cac445c1..02f4dc49a3 100644 --- a/lib/std/zig/parse.zig +++ b/lib/std/zig/parse.zig @@ -3483,9 +3483,8 @@ const Parser = struct { /// ExprList <- (Expr COMMA)* Expr? /// TODO detect when we can emit BuiltinCallTwo instead of BuiltinCall. fn parseBuiltinCall(p: *Parser) !Node.Index { - const builtin_token = p.eatToken(.Builtin) orelse return null_node; - - const lparen = (try p.expectTokenRecoverable(.LParen)) orelse { + const builtin_token = p.assertToken(.Builtin); + _ = (try p.expectTokenRecoverable(.LParen)) orelse { try p.warn(.{ .ExpectedParamList = .{ .token = p.tok_i }, }); @@ -3499,8 +3498,104 @@ const Parser = struct { }, }); }; - const params = try ListParseFn(parseExpr)(p); - _ = try p.expectToken(.RParen); + if (p.eatToken(.RParen)) |_| { + return p.addNode(.{ + .tag = .BuiltinCallTwo, + .main_token = builtin_token, + .data = .{ + .lhs = 0, + .rhs = 0, + }, + }); + } + const param_one = try p.expectExpr(); + switch (p.token_tags[p.nextToken()]) { + .Comma => { + if (p.eatToken(.RParen)) |_| { + return p.addNode(.{ + .tag = .BuiltinCallTwo, + .main_token = builtin_token, + .data = .{ + .lhs = param_one, + .rhs = 0, + }, + }); + } + }, + .RParen => return p.addNode(.{ + .tag = .BuiltinCallTwo, + .main_token = builtin_token, + .data = .{ + .lhs = param_one, + .rhs = 0, + }, + }), + else => { + // This is likely just a missing comma; + // give an error but continue parsing this list. + p.tok_i -= 1; + try p.warn(.{ + .ExpectedToken = .{ .token = p.tok_i, .expected_id = .Comma }, + }); + }, + } + const param_two = try p.expectExpr(); + switch (p.token_tags[p.nextToken()]) { + .Comma => { + if (p.eatToken(.RParen)) |_| { + return p.addNode(.{ + .tag = .BuiltinCallTwo, + .main_token = builtin_token, + .data = .{ + .lhs = param_one, + .rhs = param_two, + }, + }); + } + }, + .RParen => return p.addNode(.{ + .tag = .BuiltinCallTwo, + .main_token = builtin_token, + .data = .{ + .lhs = param_one, + .rhs = param_two, + }, + }), + else => { + // This is likely just a missing comma; + // give an error but continue parsing this list. + p.tok_i -= 1; + try p.warn(.{ + .ExpectedToken = .{ .token = p.tok_i, .expected_id = .Comma }, + }); + }, + } + + var list = std.ArrayList(Node.Index).init(p.gpa); + defer list.deinit(); + + try list.appendSlice(&[_]Node.Index{ param_one, param_two }); + + while (true) { + const param = try p.expectExpr(); + try list.append(param); + switch (p.token_tags[p.nextToken()]) { + .Comma => { + if (p.eatToken(.RParen)) |_| break; + continue; + }, + .RParen => break, + else => { + // This is likely just a missing comma; + // give an error but continue parsing this list. + p.tok_i -= 1; + try p.warn(.{ + .ExpectedToken = .{ .token = p.tok_i, .expected_id = .Comma }, + }); + }, + } + } + const params = try p.listToSpan(list.items); return p.addNode(.{ .tag = .BuiltinCall, .main_token = builtin_token, diff --git a/lib/std/zig/parser_test.zig b/lib/std/zig/parser_test.zig index 988eb9c233..877e1f42a5 100644 --- a/lib/std/zig/parser_test.zig +++ b/lib/std/zig/parser_test.zig @@ -21,21 +21,21 @@ test "zig fmt: two spaced line comments before decl" { ); } -//test "zig fmt: respect line breaks after var declarations" { -// try testCanonical( -// \\const crc = -// \\ lookup_tables[0][p[7]] ^ -// \\ lookup_tables[1][p[6]] ^ -// \\ lookup_tables[2][p[5]] ^ -// \\ lookup_tables[3][p[4]] ^ -// \\ lookup_tables[4][@truncate(u8, self.crc >> 24)] ^ -// \\ lookup_tables[5][@truncate(u8, self.crc >> 16)] ^ -// \\ lookup_tables[6][@truncate(u8, self.crc >> 8)] ^ -// \\ lookup_tables[7][@truncate(u8, self.crc >> 0)]; -// \\ -// ); -//} -// +test "zig fmt: respect line breaks after var declarations" { + try testCanonical( + \\const crc = + \\ lookup_tables[0][p[7]] ^ + \\ lookup_tables[1][p[6]] ^ + \\ lookup_tables[2][p[5]] ^ + \\ lookup_tables[3][p[4]] ^ + \\ lookup_tables[4][@truncate(u8, self.crc >> 24)] ^ + \\ lookup_tables[5][@truncate(u8, self.crc >> 16)] ^ + \\ lookup_tables[6][@truncate(u8, self.crc >> 8)] ^ + \\ lookup_tables[7][@truncate(u8, self.crc >> 0)]; + \\ + ); +} + //test "zig fmt: multiline string mixed with comments" { // try testCanonical( // \\const s1 = diff --git a/lib/std/zig/render.zig b/lib/std/zig/render.zig index 7c901da458..f55b31a53a 100644 --- a/lib/std/zig/render.zig +++ b/lib/std/zig/render.zig @@ -308,7 +308,7 @@ fn renderExpression(ais: *Ais, tree: ast.Tree, node: ast.Node.Index, space: Spac const field_access = datas[node]; try renderExpression(ais, tree, field_access.lhs, .None); try renderToken(ais, tree, main_tokens[node], .None); - return renderToken(ais, tree, field_access.rhs, .None); + return renderToken(ais, tree, field_access.rhs, space); }, .ErrorUnion, @@ -362,18 +362,15 @@ fn renderExpression(ais: *Ais, tree: ast.Tree, node: ast.Node.Index, space: Spac => { const infix = datas[node]; try renderExpression(ais, tree, infix.lhs, .Space); - const op_token = main_tokens[node]; - const after_op_space: Space = if (tree.tokensOnSameLine(op_token, op_token + 1)) - .Space - else - .Newline; - { + if (tree.tokensOnSameLine(op_token, op_token + 1)) { + try renderToken(ais, tree, op_token, .Space); + } else { ais.pushIndent(); - try renderToken(ais, tree, op_token, after_op_space); + try renderToken(ais, tree, op_token, .Newline); ais.popIndent(); + ais.pushIndentOneShot(); } - ais.pushIndentOneShot(); return renderExpression(ais, tree, infix.rhs, space); }, @@ -955,28 +952,15 @@ fn renderExpression(ais: *Ais, tree: ast.Tree, node: ast.Node.Index, space: Spac return renderToken(ais, tree, after_last_param_tok, space); // ) }, - .ArrayAccess => unreachable, // TODO - //.ArrayAccess => { - // const suffix_op = base.castTag(.ArrayAccess).?; - - // const lbracket = tree.nextToken(suffix_op.lhs.lastToken()); - // const rbracket = tree.nextToken(suffix_op.index_expr.lastToken()); - - // try renderExpression(ais, tree, suffix_op.lhs, Space.None); - // try renderToken(ais, tree, lbracket, Space.None); // [ - - // const starts_with_comment = tree.token_tags[lbracket + 1] == .LineComment; - // const ends_with_comment = tree.token_tags[rbracket - 1] == .LineComment; - // { - // const new_space = if (ends_with_comment) Space.Newline else Space.None; - - // ais.pushIndent(); - // defer ais.popIndent(); - // try renderExpression(ais, tree, suffix_op.index_expr, new_space); - // } - // if (starts_with_comment) try ais.maybeInsertNewline(); - // return renderToken(ais, tree, rbracket, space); // ] - //}, + .ArrayAccess => { + const suffix = datas[node]; + const lbracket = tree.firstToken(suffix.rhs) - 1; + const rbracket = tree.lastToken(suffix.rhs) + 1; + try renderExpression(ais, tree, suffix.lhs, .None); + try renderToken(ais, tree, lbracket, .None); // [ + try renderExpression(ais, tree, suffix.rhs, .None); + return renderToken(ais, tree, rbracket, space); // ] + }, .Slice => unreachable, // TODO .SliceOpen => unreachable, // TODO @@ -1278,68 +1262,22 @@ fn renderExpression(ais: *Ais, tree: ast.Tree, node: ast.Node.Index, space: Spac // } //}, - .BuiltinCall => unreachable, // TODO - .BuiltinCallTwo => unreachable, // TODO - //.BuiltinCall => { - // const builtin_call = @fieldParentPtr(ast.Node.BuiltinCall, "base", base); - - // // TODO remove after 0.7.0 release - // if (mem.eql(u8, tree.tokenSlice(builtin_call.builtin_token), "@OpaqueType")) - // return ais.writer().writeAll("opaque {}"); - - // // TODO remove after 0.7.0 release - // { - // const params = builtin_call.paramsConst(); - // if (mem.eql(u8, tree.tokenSlice(builtin_call.builtin_token), "@Type") and - // params.len == 1) - // { - // if (params[0].castTag(.EnumLiteral)) |enum_literal| - // if (mem.eql(u8, tree.tokenSlice(enum_literal.name), "Opaque")) - // return ais.writer().writeAll("opaque {}"); - // } - // } - - // try renderToken(ais, tree, builtin_call.builtin_token, Space.None); // @name - - // const src_params_trailing_comma = blk: { - // if (builtin_call.params_len == 0) break :blk false; - // const last_node = builtin_call.params()[builtin_call.params_len - 1]; - // const maybe_comma = tree.nextToken(last_node.lastToken()); - // break :blk tree.token_tags[maybe_comma] == .Comma; - // }; - - // const lparen = tree.nextToken(builtin_call.builtin_token); - - // if (!src_params_trailing_comma) { - // try renderToken(ais, tree, lparen, Space.None); // ( - - // // render all on one line, no trailing comma - // const params = builtin_call.params(); - // for (params) |param_node, i| { - // const maybe_comment = param_node.firstToken() - 1; - // if (param_node.*.tag == .MultilineStringLiteral or tree.token_tags[maybe_comment] == .LineComment) { - // ais.pushIndentOneShot(); - // } - // try renderExpression(ais, tree, param_node, Space.None); - - // if (i + 1 < params.len) { - // const comma_token = tree.nextToken(param_node.lastToken()); - // try renderToken(ais, tree, comma_token, Space.Space); // , - // } - // } - // } else { - // // one param per line - // ais.pushIndent(); - // defer ais.popIndent(); - // try renderToken(ais, tree, lparen, Space.Newline); // ( - - // for (builtin_call.params()) |param_node| { - // try renderExpression(ais, tree, param_node, Space.Comma); - // } - // } - - // return renderToken(ais, tree, builtin_call.rparen_token, space); // ) - //}, + .BuiltinCallTwo => { + if (datas[node].lhs == 0) { + const params = [_]ast.Node.Index{}; + return renderBuiltinCall(ais, tree, main_tokens[node], ¶ms, space); + } else if (datas[node].rhs == 0) { + const params = [_]ast.Node.Index{datas[node].lhs}; + return renderBuiltinCall(ais, tree, main_tokens[node], ¶ms, space); + } else { + const params = [_]ast.Node.Index{ datas[node].lhs, datas[node].rhs }; + return renderBuiltinCall(ais, tree, main_tokens[node], ¶ms, space); + } + }, + .BuiltinCall => { + const params = tree.extra_data[datas[node].lhs..datas[node].rhs]; + return renderBuiltinCall(ais, tree, main_tokens[node], params, space); + }, .FnProtoSimple => unreachable, // TODO .FnProtoSimpleMulti => unreachable, // TODO @@ -2221,6 +2159,52 @@ fn renderParamDecl( } } +fn renderBuiltinCall( + ais: *Ais, + tree: ast.Tree, + builtin_token: ast.TokenIndex, + params: []const ast.Node.Index, + space: Space, +) Error!void { + const token_tags = tree.tokens.items(.tag); + + try renderToken(ais, tree, builtin_token, .None); // @name + + if (params.len == 0) { + try renderToken(ais, tree, builtin_token + 1, .None); // ( + return renderToken(ais, tree, builtin_token + 2, space); // ) + } + + const last_param = params[params.len - 1]; + const after_last_param_token = tree.lastToken(last_param) + 1; + + if (token_tags[after_last_param_token] != .Comma) { + // Render all on one line, no trailing comma. + try renderToken(ais, tree, builtin_token + 1, .None); // ( + + for (params) |param_node, i| { + try renderExpression(ais, tree, param_node, .None); + + if (i + 1 < params.len) { + const comma_token = tree.lastToken(param_node) + 1; + try renderToken(ais, tree, comma_token, .Space); // , + } + } + return renderToken(ais, tree, after_last_param_token, space); // ) + } else { + // Render one param per line. + ais.pushIndent(); + try renderToken(ais, tree, builtin_token + 1, Space.Newline); // ( + + for (params) |param_node| { + try renderExpression(ais, tree, param_node, .Comma); + } + ais.popIndent(); + + return renderToken(ais, tree, after_last_param_token + 1, space); // ) + } +} + /// Render an expression, and the comma that follows it, if it is present in the source. fn renderExpressionComma(ais: *Ais, tree: ast.Tree, node: ast.Node.Index, space: Space) Error!void { const token_tags = tree.tokens.items(.tag);