stage2: make same line doc comments a parse error

Allowing same line doc comments causes some ambiguity as to how
generated docs should represent the case in which both same line
and preceding line doc comments are present:

/// preceding line
const foobar = 42; /// same line

Furthermore disallowing these makes things simpler as there is now only
one way to add a doc comment to a decl or struct field.
This commit is contained in:
Isaac Freund 2021-02-19 22:54:47 +01:00
parent 6f6568b1fd
commit 95b95ea33e
No known key found for this signature in database
GPG Key ID: 86DED400DDFD7A11
3 changed files with 39 additions and 59 deletions

View File

@ -146,6 +146,7 @@ pub const Tree = struct {
.ExpectedFn => |*x| return x.render(tokens, stream),
.ExpectedReturnType => |*x| return x.render(tokens, stream),
.ExpectedAggregateKw => |*x| return x.render(tokens, stream),
.SameLineDocComment => |*x| return x.render(tokens, stream),
.UnattachedDocComment => |*x| return x.render(tokens, stream),
.ExpectedEqOrSemi => |*x| return x.render(tokens, stream),
.ExpectedSemiOrLBrace => |*x| return x.render(tokens, stream),
@ -200,6 +201,7 @@ pub const Tree = struct {
.ExpectedFn => |x| return x.token,
.ExpectedReturnType => |x| return x.token,
.ExpectedAggregateKw => |x| return x.token,
.SameLineDocComment => |x| return x.token,
.UnattachedDocComment => |x| return x.token,
.ExpectedEqOrSemi => |x| return x.token,
.ExpectedSemiOrLBrace => |x| return x.token,
@ -2250,6 +2252,7 @@ pub const Error = union(enum) {
ExpectedFn: ExpectedFn,
ExpectedReturnType: ExpectedReturnType,
ExpectedAggregateKw: ExpectedAggregateKw,
SameLineDocComment: SameLineDocComment,
UnattachedDocComment: UnattachedDocComment,
ExpectedEqOrSemi: ExpectedEqOrSemi,
ExpectedSemiOrLBrace: ExpectedSemiOrLBrace,
@ -2326,6 +2329,7 @@ pub const Error = union(enum) {
pub const ExpectedParamType = SimpleError("Expected parameter type");
pub const ExpectedPubItem = SimpleError("Expected function or variable declaration after pub");
pub const SameLineDocComment = SimpleError("Same line documentation comment");
pub const UnattachedDocComment = SimpleError("Unattached documentation comment");
pub const ExtraAlignQualifier = SimpleError("Extra align qualifier");
pub const ExtraConstQualifier = SimpleError("Extra const qualifier");

View File

@ -190,7 +190,7 @@ const Parser = struct {
var trailing_comma = false;
while (true) {
const doc_comment = p.eatDocComments();
const doc_comment = try p.eatDocComments ();
switch (p.token_tags[p.tok_i]) {
.keyword_test => {
@ -515,7 +515,6 @@ const Parser = struct {
switch (p.token_tags[p.tok_i]) {
.semicolon => {
const semicolon_token = p.nextToken();
try p.parseAppendedDocComment(semicolon_token);
return p.addNode(.{
.tag = .fn_decl,
.main_token = p.nodes.items(.main_token)[fn_proto],
@ -557,7 +556,6 @@ const Parser = struct {
const var_decl = try p.parseVarDecl();
if (var_decl != 0) {
const semicolon_token = try p.expectToken(.semicolon);
try p.parseAppendedDocComment(semicolon_token);
return var_decl;
}
if (thread_local_token != null) {
@ -585,7 +583,6 @@ const Parser = struct {
const usingnamespace_token = try p.expectToken(.keyword_usingnamespace);
const expr = try p.expectExpr();
const semicolon_token = try p.expectToken(.semicolon);
try p.parseAppendedDocComment(semicolon_token);
return p.addNode(.{
.tag = .@"usingnamespace",
.main_token = usingnamespace_token,
@ -2885,7 +2882,7 @@ const Parser = struct {
}
while (true) {
const doc_comment = p.eatDocComments();
const doc_comment = try p.eatDocComments();
const identifier = try p.expectToken(.identifier);
switch (p.token_tags[p.nextToken()]) {
.comma => {
@ -3274,7 +3271,7 @@ const Parser = struct {
/// such as in the case of anytype and `...`. Caller must look for rparen to find
/// out when there are no more param decls left.
fn expectParamDecl(p: *Parser) !Node.Index {
_ = p.eatDocComments();
_ = try p.eatDocComments();
switch (p.token_tags[p.tok_i]) {
.keyword_noalias, .keyword_comptime => p.tok_i += 1,
.ellipsis3 => {
@ -4075,8 +4072,13 @@ const Parser = struct {
}
/// Skips over doc comment tokens. Returns the first one, if any.
fn eatDocComments(p: *Parser) ?TokenIndex {
if (p.eatToken(.doc_comment)) |first_line| {
fn eatDocComments(p: *Parser) !?TokenIndex {
if (p.eatToken(.doc_comment)) |tok| {
var first_line = tok;
if (tok > 0 and tokensOnSameLine(p, tok - 1, tok)) {
try p.warn(.{ .SameLineDocComment = .{ .token = tok } });
first_line = p.eatToken(.doc_comment) orelse return null;
}
while (p.eatToken(.doc_comment)) |_| {}
return first_line;
}
@ -4087,14 +4089,6 @@ const Parser = struct {
return std.mem.indexOfScalar(u8, p.source[p.token_starts[token1]..p.token_starts[token2]], '\n') == null;
}
/// Eat a single-line doc comment on the same line as another node
fn parseAppendedDocComment(p: *Parser, after_token: TokenIndex) !void {
const comment_token = p.eatToken(.doc_comment) orelse return;
if (!p.tokensOnSameLine(after_token, comment_token)) {
p.tok_i -= 1;
}
}
fn eatToken(p: *Parser, tag: Token.Tag) ?TokenIndex {
return if (p.token_tags[p.tok_i] == tag) p.nextToken() else null;
}

View File

@ -1016,23 +1016,6 @@ test "zig fmt: linksection" {
);
}
//test "zig fmt: correctly move doc comments on struct fields" {
// try testTransform(
// \\pub const section_64 = extern struct {
// \\ sectname: [16]u8, /// name of this section
// \\ segname: [16]u8, /// segment this section goes in
// \\};
// ,
// \\pub const section_64 = extern struct {
// \\ /// name of this section
// \\ sectname: [16]u8,
// \\ /// segment this section goes in
// \\ segname: [16]u8,
// \\};
// \\
// );
//}
test "zig fmt: correctly space struct fields with doc comments" {
try testTransform(
\\pub const S = struct {
@ -1449,31 +1432,6 @@ test "zig fmt: async call in if condition" {
// \\
// );
//}
//
//test "zig fmt: same-line doc comment on variable declaration" {
// try testTransform(
// \\pub const MAP_ANONYMOUS = 0x1000; /// allocated from memory, swap space
// \\pub const MAP_FILE = 0x0000; /// map from file (default)
// \\
// \\pub const EMEDIUMTYPE = 124; /// Wrong medium type
// \\
// \\// nameserver query return codes
// \\pub const ENSROK = 0; /// DNS server returned answer with no data
// ,
// \\/// allocated from memory, swap space
// \\pub const MAP_ANONYMOUS = 0x1000;
// \\/// map from file (default)
// \\pub const MAP_FILE = 0x0000;
// \\
// \\/// Wrong medium type
// \\pub const EMEDIUMTYPE = 124;
// \\
// \\// nameserver query return codes
// \\/// DNS server returned answer with no data
// \\pub const ENSROK = 0;
// \\
// );
//}
test "zig fmt: if-else with comment before else" {
try testCanonical(
@ -3625,6 +3583,30 @@ test "zig fmt: file ends with struct field" {
// });
//}
test "zig fmt: same line doc comment returns error" {
try testError(
\\const Foo = struct{
\\ bar: u32, /// comment
\\ foo: u32, /// comment
\\ /// commment
\\};
\\
\\const a = 42; /// comment
\\
\\extern fn foo() void; /// comment
\\
\\/// comment
\\
, &[_]Error{
.SameLineDocComment,
.SameLineDocComment,
.UnattachedDocComment,
.SameLineDocComment,
.SameLineDocComment,
.UnattachedDocComment,
});
}
test "zig fmt: integer literals with underscore separators" {
try testTransform(
\\const
@ -4388,6 +4370,6 @@ fn testError(source: []const u8, expected_errors: []const Error) !void {
std.testing.expect(tree.errors.len == expected_errors.len);
for (expected_errors) |expected, i| {
std.testing.expect(expected == tree.errors[i]);
std.testing.expectEqual(expected, tree.errors[i]);
}
}