zig fmt: builtin calls and array access

This commit is contained in:
Andrew Kelley 2021-02-03 22:12:11 -07:00
parent f5279cbada
commit 725adf8332
4 changed files with 308 additions and 196 deletions

View File

@ -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
};
}

View File

@ -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,

View File

@ -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 =

View File

@ -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], &params, space);
} else if (datas[node].rhs == 0) {
const params = [_]ast.Node.Index{datas[node].lhs};
return renderBuiltinCall(ais, tree, main_tokens[node], &params, space);
} else {
const params = [_]ast.Node.Index{ datas[node].lhs, datas[node].rhs };
return renderBuiltinCall(ais, tree, main_tokens[node], &params, 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);