authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-11-17 22:31:12+00:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2019-11-17 22:31:12+00:00
log57b8614a5a287d0a312b1cade463ec5485f0518f
treefda14f96b79a6878208ab483027f9fad97cf2460
parent4e28d7a5f7d6346acc42a7524dd77fa5f9322029
parent314cb707fce553e51d2ffd5c1ea506fbd1acdf76
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #3697 from Vexu/container-docs

Implement container level doc comments

14 files changed, 190 insertions(+), 25 deletions(-)

doc/docgen.zig+1
...@@ -856,6 +856,7 @@ fn tokenizeAndPrintRaw(docgen_tokenizer: *Tokenizer, out: var, source_token: Tok...@@ -856,6 +856,7 @@ fn tokenizeAndPrintRaw(docgen_tokenizer: *Tokenizer, out: var, source_token: Tok
856856
857 .LineComment,857 .LineComment,
858 .DocComment,858 .DocComment,
859 .ContainerDocComment,
859 .ShebangLine,860 .ShebangLine,
860 => {861 => {
861 try out.write("<span class=\"tok-comment\">");862 try out.write("<span class=\"tok-comment\">");
lib/std/special/docs/index.html+1-1
...@@ -484,7 +484,7 @@...@@ -484,7 +484,7 @@
484 doc comments.484 doc comments.
485 </p>485 </p>
486 </div>486 </div>
487 <div id="fnDocs" class="hidden"></div>487 <div id="tldDocs" class="hidden"></div>
488 <div id="sectFnErrors" class="hidden">488 <div id="sectFnErrors" class="hidden">
489 <h2>Errors</h2>489 <h2>Errors</h2>
490 <div id="fnErrorsAnyError">490 <div id="fnErrorsAnyError">
lib/std/special/docs/main.js+19-12
...@@ -20,7 +20,7 @@...@@ -20,7 +20,7 @@
20 var domListValues = document.getElementById("listValues");20 var domListValues = document.getElementById("listValues");
21 var domFnProto = document.getElementById("fnProto");21 var domFnProto = document.getElementById("fnProto");
22 var domFnProtoCode = document.getElementById("fnProtoCode");22 var domFnProtoCode = document.getElementById("fnProtoCode");
23 var domFnDocs = document.getElementById("fnDocs");23 var domTldDocs = document.getElementById("tldDocs");
24 var domSectFnErrors = document.getElementById("sectFnErrors");24 var domSectFnErrors = document.getElementById("sectFnErrors");
25 var domListFnErrors = document.getElementById("listFnErrors");25 var domListFnErrors = document.getElementById("listFnErrors");
26 var domTableFnErrors = document.getElementById("tableFnErrors");26 var domTableFnErrors = document.getElementById("tableFnErrors");
...@@ -34,7 +34,6 @@...@@ -34,7 +34,6 @@
34 var domListSearchResults = document.getElementById("listSearchResults");34 var domListSearchResults = document.getElementById("listSearchResults");
35 var domSectSearchNoResults = document.getElementById("sectSearchNoResults");35 var domSectSearchNoResults = document.getElementById("sectSearchNoResults");
36 var domSectInfo = document.getElementById("sectInfo");36 var domSectInfo = document.getElementById("sectInfo");
37 var domListInfo = document.getElementById("listInfo");
38 var domTdTarget = document.getElementById("tdTarget");37 var domTdTarget = document.getElementById("tdTarget");
39 var domTdZigVer = document.getElementById("tdZigVer");38 var domTdZigVer = document.getElementById("tdZigVer");
40 var domHdrName = document.getElementById("hdrName");39 var domHdrName = document.getElementById("hdrName");
...@@ -102,7 +101,7 @@...@@ -102,7 +101,7 @@
102 function render() {101 function render() {
103 domStatus.classList.add("hidden");102 domStatus.classList.add("hidden");
104 domFnProto.classList.add("hidden");103 domFnProto.classList.add("hidden");
105 domFnDocs.classList.add("hidden");104 domTldDocs.classList.add("hidden");
106 domSectPkgs.classList.add("hidden");105 domSectPkgs.classList.add("hidden");
107 domSectTypes.classList.add("hidden");106 domSectTypes.classList.add("hidden");
108 domSectNamespaces.classList.add("hidden");107 domSectNamespaces.classList.add("hidden");
...@@ -190,11 +189,11 @@...@@ -190,11 +189,11 @@
190189
191 var docs = zigAnalysis.astNodes[decl.src].docs;190 var docs = zigAnalysis.astNodes[decl.src].docs;
192 if (docs != null) {191 if (docs != null) {
193 domFnDocs.innerHTML = markdown(docs);192 domTldDocs.innerHTML = markdown(docs);
194 } else {193 } else {
195 domFnDocs.innerHTML = '<p>There are no doc comments for this declaration.</p>';194 domTldDocs.innerHTML = '<p>There are no doc comments for this declaration.</p>';
196 }195 }
197 domFnDocs.classList.remove("hidden");196 domTldDocs.classList.remove("hidden");
198 }197 }
199198
200 function typeIsErrSet(typeIndex) {199 function typeIsErrSet(typeIndex) {
...@@ -274,8 +273,8 @@...@@ -274,8 +273,8 @@
274 docsSource = protoSrcNode.docs;273 docsSource = protoSrcNode.docs;
275 }274 }
276 if (docsSource != null) {275 if (docsSource != null) {
277 domFnDocs.innerHTML = markdown(docsSource);276 domTldDocs.innerHTML = markdown(docsSource);
278 domFnDocs.classList.remove("hidden");277 domTldDocs.classList.remove("hidden");
279 }278 }
280 domFnProto.classList.remove("hidden");279 domFnProto.classList.remove("hidden");
281 }280 }
...@@ -893,8 +892,8 @@...@@ -893,8 +892,8 @@
893892
894 var docs = zigAnalysis.astNodes[decl.src].docs;893 var docs = zigAnalysis.astNodes[decl.src].docs;
895 if (docs != null) {894 if (docs != null) {
896 domFnDocs.innerHTML = markdown(docs);895 domTldDocs.innerHTML = markdown(docs);
897 domFnDocs.classList.remove("hidden");896 domTldDocs.classList.remove("hidden");
898 }897 }
899898
900 domFnProto.classList.remove("hidden");899 domFnProto.classList.remove("hidden");
...@@ -906,8 +905,8 @@...@@ -906,8 +905,8 @@
906905
907 var docs = zigAnalysis.astNodes[decl.src].docs;906 var docs = zigAnalysis.astNodes[decl.src].docs;
908 if (docs != null) {907 if (docs != null) {
909 domFnDocs.innerHTML = markdown(docs);908 domTldDocs.innerHTML = markdown(docs);
910 domFnDocs.classList.remove("hidden");909 domTldDocs.classList.remove("hidden");
911 }910 }
912911
913 domFnProto.classList.remove("hidden");912 domFnProto.classList.remove("hidden");
...@@ -957,6 +956,14 @@...@@ -957,6 +956,14 @@
957 varsList.sort(byNameProperty);956 varsList.sort(byNameProperty);
958 valsList.sort(byNameProperty);957 valsList.sort(byNameProperty);
959958
959 if (container.src != null) {
960 var docs = zigAnalysis.astNodes[container.src].docs;
961 if (docs != null) {
962 domTldDocs.innerHTML = markdown(docs);
963 domTldDocs.classList.remove("hidden");
964 }
965 }
966
960 if (typesList.length !== 0) {967 if (typesList.length !== 0) {
961 resizeDomList(domListTypes, typesList.length, '<li><a href="#"></a></li>');968 resizeDomList(domListTypes, typesList.length, '<li><a href="#"></a></li>');
962 for (var i = 0; i < typesList.length; i += 1) {969 for (var i = 0; i < typesList.length; i += 1) {
lib/std/zig/ast.zig-2
...@@ -576,7 +576,6 @@ pub const Node = struct {...@@ -576,7 +576,6 @@ pub const Node = struct {
576576
577 pub const Root = struct {577 pub const Root = struct {
578 base: Node,578 base: Node,
579 doc_comments: ?*DocComment,
580 decls: DeclList,579 decls: DeclList,
581 eof_token: TokenIndex,580 eof_token: TokenIndex,
582581
...@@ -2254,7 +2253,6 @@ pub const Node = struct {...@@ -2254,7 +2253,6 @@ pub const Node = struct {
2254test "iterate" {2253test "iterate" {
2255 var root = Node.Root{2254 var root = Node.Root{
2256 .base = Node{ .id = Node.Id.Root },2255 .base = Node{ .id = Node.Id.Root },
2257 .doc_comments = null,
2258 .decls = Node.Root.DeclList.init(std.debug.global_allocator),2256 .decls = Node.Root.DeclList.init(std.debug.global_allocator),
2259 .eof_token = 0,2257 .eof_token = 0,
2260 };2258 };
lib/std/zig/parse.zig+28-7
...@@ -58,13 +58,6 @@ fn parseRoot(arena: *Allocator, it: *TokenIterator, tree: *Tree) Allocator.Error...@@ -58,13 +58,6 @@ fn parseRoot(arena: *Allocator, it: *TokenIterator, tree: *Tree) Allocator.Error
58 node.* = Node.Root{58 node.* = Node.Root{
59 .base = Node{ .id = .Root },59 .base = Node{ .id = .Root },
60 .decls = undefined,60 .decls = undefined,
61 // TODO: Because zig fmt collapses consecutive comments separated by blank lines into
62 // a single multi-line comment, it is currently impossible to have a container-level
63 // doc comment and NO doc comment on the first decl. For now, simply
64 // ignore the problem and assume that there will be no container-level
65 // doc comments.
66 // See: https://github.com/ziglang/zig/issues/2288
67 .doc_comments = null,
68 .eof_token = undefined,61 .eof_token = undefined,
69 };62 };
70 node.decls = parseContainerMembers(arena, it, tree) catch |err| {63 node.decls = parseContainerMembers(arena, it, tree) catch |err| {
...@@ -94,6 +87,11 @@ fn parseContainerMembers(arena: *Allocator, it: *TokenIterator, tree: *Tree) !No...@@ -94,6 +87,11 @@ fn parseContainerMembers(arena: *Allocator, it: *TokenIterator, tree: *Tree) !No
94 var list = Node.Root.DeclList.init(arena);87 var list = Node.Root.DeclList.init(arena);
9588
96 while (true) {89 while (true) {
90 if (try parseContainerDocComments(arena, it, tree)) |node| {
91 try list.push(node);
92 continue;
93 }
94
97 const doc_comments = try parseDocComment(arena, it, tree);95 const doc_comments = try parseDocComment(arena, it, tree);
9896
99 if (try parseTestDecl(arena, it, tree)) |node| {97 if (try parseTestDecl(arena, it, tree)) |node| {
...@@ -155,12 +153,35 @@ fn parseContainerMembers(arena: *Allocator, it: *TokenIterator, tree: *Tree) !No...@@ -155,12 +153,35 @@ fn parseContainerMembers(arena: *Allocator, it: *TokenIterator, tree: *Tree) !No
155 continue;153 continue;
156 }154 }
157155
156 // Dangling doc comment
157 if (doc_comments != null) {
158 try tree.errors.push(AstError{
159 .UnattachedDocComment = AstError.UnattachedDocComment{ .token = doc_comments.?.firstToken() },
160 });
161 }
158 break;162 break;
159 }163 }
160164
161 return list;165 return list;
162}166}
163167
168/// Eat a multiline container doc comment
169fn parseContainerDocComments(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
170 var lines = Node.DocComment.LineList.init(arena);
171 while (eatToken(it, .ContainerDocComment)) |line| {
172 try lines.push(line);
173 }
174
175 if (lines.len == 0) return null;
176
177 const node = try arena.create(Node.DocComment);
178 node.* = Node.DocComment{
179 .base = Node{ .id = .DocComment },
180 .lines = lines,
181 };
182 return &node.base;
183}
184
164/// TestDecl <- KEYWORD_test STRINGLITERAL Block185/// TestDecl <- KEYWORD_test STRINGLITERAL Block
165fn parseTestDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {186fn parseTestDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
166 const test_token = eatToken(it, .Keyword_test) orelse return null;187 const test_token = eatToken(it, .Keyword_test) orelse return null;
lib/std/zig/parser_test.zig+56
...@@ -2566,6 +2566,62 @@ test "zig fmt: comments at several places in struct init" {...@@ -2566,6 +2566,62 @@ test "zig fmt: comments at several places in struct init" {
2566 );2566 );
2567}2567}
25682568
2569test "zig fmt: top level doc comments" {
2570 try testCanonical(
2571 \\//! tld 1
2572 \\//! tld 2
2573 \\//! tld 3
2574 \\
2575 \\// comment
2576 \\
2577 \\/// A doc
2578 \\const A = struct {
2579 \\ //! A tld 1
2580 \\ //! A tld 2
2581 \\ //! A tld 3
2582 \\};
2583 \\
2584 \\/// B doc
2585 \\const B = struct {
2586 \\ //! B tld 1
2587 \\ //! B tld 2
2588 \\ //! B tld 3
2589 \\
2590 \\ /// b doc
2591 \\ b: u32,
2592 \\};
2593 \\
2594 \\/// C doc
2595 \\const C = struct {
2596 \\ //! C tld 1
2597 \\ //! C tld 2
2598 \\ //! C tld 3
2599 \\
2600 \\ /// c1 doc
2601 \\ c1: u32,
2602 \\
2603 \\ //! C tld 4
2604 \\ //! C tld 5
2605 \\ //! C tld 6
2606 \\
2607 \\ /// c2 doc
2608 \\ c2: u32,
2609 \\};
2610 \\
2611 );
2612 try testCanonical(
2613 \\//! Top-level documentation.
2614 \\
2615 \\/// This is A
2616 \\pub const A = usize;
2617 \\
2618 );
2619 try testCanonical(
2620 \\//! Nothing here
2621 \\
2622 );
2623}
2624
2569const std = @import("std");2625const std = @import("std");
2570const mem = std.mem;2626const mem = std.mem;
2571const warn = std.debug.warn;2627const warn = std.debug.warn;
lib/std/zig/render.zig+11
...@@ -299,6 +299,17 @@ fn renderTopLevelDecl(allocator: *mem.Allocator, stream: var, tree: *ast.Tree, i...@@ -299,6 +299,17 @@ fn renderTopLevelDecl(allocator: *mem.Allocator, stream: var, tree: *ast.Tree, i
299 assert(!decl.requireSemiColon());299 assert(!decl.requireSemiColon());
300 try renderExpression(allocator, stream, tree, indent, start_col, decl, Space.Newline);300 try renderExpression(allocator, stream, tree, indent, start_col, decl, Space.Newline);
301 },301 },
302
303 ast.Node.Id.DocComment => {
304 const comment = @fieldParentPtr(ast.Node.DocComment, "base", decl);
305 var it = comment.lines.iterator(0);
306 while (it.next()) |line_token_index| {
307 try renderToken(tree, stream, line_token_index.*, indent, start_col, Space.Newline);
308 if (it.peek()) |_| {
309 try stream.writeByteNTimes(' ', indent);
310 }
311 }
312 },
302 else => unreachable,313 else => unreachable,
303 }314 }
304}315}
lib/std/zig/tokenizer.zig+13-1
...@@ -142,6 +142,7 @@ pub const Token = struct {...@@ -142,6 +142,7 @@ pub const Token = struct {
142 FloatLiteral,142 FloatLiteral,
143 LineComment,143 LineComment,
144 DocComment,144 DocComment,
145 ContainerDocComment,
145 BracketStarBracket,146 BracketStarBracket,
146 BracketStarCBracket,147 BracketStarCBracket,
147 ShebangLine,148 ShebangLine,
...@@ -211,6 +212,7 @@ pub const Token = struct {...@@ -211,6 +212,7 @@ pub const Token = struct {
211 .FloatLiteral => "FloatLiteral",212 .FloatLiteral => "FloatLiteral",
212 .LineComment => "LineComment",213 .LineComment => "LineComment",
213 .DocComment => "DocComment",214 .DocComment => "DocComment",
215 .ContainerDocComment => "ContainerDocComment",
214 .ShebangLine => "ShebangLine",216 .ShebangLine => "ShebangLine",
215217
216 .Bang => "!",218 .Bang => "!",
...@@ -387,6 +389,7 @@ pub const Tokenizer = struct {...@@ -387,6 +389,7 @@ pub const Tokenizer = struct {
387 LineComment,389 LineComment,
388 DocCommentStart,390 DocCommentStart,
389 DocComment,391 DocComment,
392 ContainerDocComment,
390 Zero,393 Zero,
391 IntegerLiteral,394 IntegerLiteral,
392 IntegerLiteralWithRadix,395 IntegerLiteralWithRadix,
...@@ -1076,6 +1079,10 @@ pub const Tokenizer = struct {...@@ -1076,6 +1079,10 @@ pub const Tokenizer = struct {
1076 '/' => {1079 '/' => {
1077 state = State.DocCommentStart;1080 state = State.DocCommentStart;
1078 },1081 },
1082 '!' => {
1083 result.id = Token.Id.ContainerDocComment;
1084 state = State.ContainerDocComment;
1085 },
1079 '\n' => break,1086 '\n' => break,
1080 else => {1087 else => {
1081 state = State.LineComment;1088 state = State.LineComment;
...@@ -1096,7 +1103,7 @@ pub const Tokenizer = struct {...@@ -1096,7 +1103,7 @@ pub const Tokenizer = struct {
1096 self.checkLiteralCharacter();1103 self.checkLiteralCharacter();
1097 },1104 },
1098 },1105 },
1099 State.LineComment, State.DocComment => switch (c) {1106 State.LineComment, State.DocComment, State.ContainerDocComment => switch (c) {
1100 '\n' => break,1107 '\n' => break,
1101 else => self.checkLiteralCharacter(),1108 else => self.checkLiteralCharacter(),
1102 },1109 },
...@@ -1234,6 +1241,9 @@ pub const Tokenizer = struct {...@@ -1234,6 +1241,9 @@ pub const Tokenizer = struct {
1234 State.DocComment, State.DocCommentStart => {1241 State.DocComment, State.DocCommentStart => {
1235 result.id = Token.Id.DocComment;1242 result.id = Token.Id.DocComment;
1236 },1243 },
1244 State.ContainerDocComment => {
1245 result.id = Token.Id.ContainerDocComment;
1246 },
12371247
1238 State.NumberDot,1248 State.NumberDot,
1239 State.NumberDotHex,1249 State.NumberDotHex,
...@@ -1601,6 +1611,8 @@ test "tokenizer - line comment and doc comment" {...@@ -1601,6 +1611,8 @@ test "tokenizer - line comment and doc comment" {
1601 testTokenize("/// a", [_]Token.Id{Token.Id.DocComment});1611 testTokenize("/// a", [_]Token.Id{Token.Id.DocComment});
1602 testTokenize("///", [_]Token.Id{Token.Id.DocComment});1612 testTokenize("///", [_]Token.Id{Token.Id.DocComment});
1603 testTokenize("////", [_]Token.Id{Token.Id.LineComment});1613 testTokenize("////", [_]Token.Id{Token.Id.LineComment});
1614 testTokenize("//!", [_]Token.Id{Token.Id.ContainerDocComment});
1615 testTokenize("//!!", [_]Token.Id{Token.Id.ContainerDocComment});
1604}1616}
16051617
1606test "tokenizer - line comment followed by identifier" {1618test "tokenizer - line comment followed by identifier" {
src-self-hosted/translate_c.zig-1
...@@ -174,7 +174,6 @@ pub fn translate(...@@ -174,7 +174,6 @@ pub fn translate(
174 tree.root_node.* = ast.Node.Root{174 tree.root_node.* = ast.Node.Root{
175 .base = ast.Node{ .id = ast.Node.Id.Root },175 .base = ast.Node{ .id = ast.Node.Id.Root },
176 .decls = ast.Node.Root.DeclList.init(arena),176 .decls = ast.Node.Root.DeclList.init(arena),
177 .doc_comments = null,
178 // initialized with the eof token at the end177 // initialized with the eof token at the end
179 .eof_token = undefined,178 .eof_token = undefined,
180 };179 };
src/all_types.hpp+1
...@@ -968,6 +968,7 @@ struct AstNodeContainerDecl {...@@ -968,6 +968,7 @@ struct AstNodeContainerDecl {
968 AstNode *init_arg_expr; // enum(T), struct(endianness), or union(T), or union(enum(T))968 AstNode *init_arg_expr; // enum(T), struct(endianness), or union(T), or union(enum(T))
969 ZigList<AstNode *> fields;969 ZigList<AstNode *> fields;
970 ZigList<AstNode *> decls;970 ZigList<AstNode *> decls;
971 Buf doc_comments;
971972
972 ContainerKind kind;973 ContainerKind kind;
973 ContainerLayout layout;974 ContainerLayout layout;
src/dump_analysis.cpp+1
...@@ -1088,6 +1088,7 @@ static void anal_dump_node(AnalDumpCtx *ctx, const AstNode *node) {...@@ -1088,6 +1088,7 @@ static void anal_dump_node(AnalDumpCtx *ctx, const AstNode *node) {
1088 break;1088 break;
1089 case NodeTypeContainerDecl:1089 case NodeTypeContainerDecl:
1090 field_nodes = &node->data.container_decl.fields;1090 field_nodes = &node->data.container_decl.fields;
1091 doc_comments_buf = &node->data.container_decl.doc_comments;
1091 break;1092 break;
1092 default:1093 default:
1093 break;1094 break;
src/parser.cpp+26-1
...@@ -493,6 +493,9 @@ static AstNode *ast_parse_root(ParseContext *pc) {...@@ -493,6 +493,9 @@ static AstNode *ast_parse_root(ParseContext *pc) {
493 node->data.container_decl.layout = ContainerLayoutAuto;493 node->data.container_decl.layout = ContainerLayoutAuto;
494 node->data.container_decl.kind = ContainerKindStruct;494 node->data.container_decl.kind = ContainerKindStruct;
495 node->data.container_decl.is_root = true;495 node->data.container_decl.is_root = true;
496 if (buf_len(&members.doc_comments) != 0) {
497 node->data.container_decl.doc_comments = members.doc_comments;
498 }
496499
497 return node;500 return node;
498}501}
...@@ -514,6 +517,21 @@ static Token *ast_parse_doc_comments(ParseContext *pc, Buf *buf) {...@@ -514,6 +517,21 @@ static Token *ast_parse_doc_comments(ParseContext *pc, Buf *buf) {
514 return first_doc_token;517 return first_doc_token;
515}518}
516519
520static void ast_parse_container_doc_comments(ParseContext *pc, Buf *buf) {
521 if (buf_len(buf) != 0 && peek_token(pc)->id == TokenIdContainerDocComment) {
522 buf_append_char(buf, '\n');
523 }
524 Token *doc_token = nullptr;
525 while ((doc_token = eat_token_if(pc, TokenIdContainerDocComment))) {
526 if (buf->list.length == 0) {
527 buf_resize(buf, 0);
528 }
529 // chops off '//!' but leaves '\n'
530 buf_append_mem(buf, buf_ptr(pc->buf) + doc_token->start_pos + 3,
531 doc_token->end_pos - doc_token->start_pos - 3);
532 }
533}
534
517// ContainerMembers535// ContainerMembers
518// <- TestDecl ContainerMembers536// <- TestDecl ContainerMembers
519// / TopLevelComptime ContainerMembers537// / TopLevelComptime ContainerMembers
...@@ -523,7 +541,11 @@ static Token *ast_parse_doc_comments(ParseContext *pc, Buf *buf) {...@@ -523,7 +541,11 @@ static Token *ast_parse_doc_comments(ParseContext *pc, Buf *buf) {
523// /541// /
524static AstNodeContainerDecl ast_parse_container_members(ParseContext *pc) {542static AstNodeContainerDecl ast_parse_container_members(ParseContext *pc) {
525 AstNodeContainerDecl res = {};543 AstNodeContainerDecl res = {};
544 Buf tld_doc_comment_buf = BUF_INIT;
545 buf_resize(&tld_doc_comment_buf, 0);
526 for (;;) {546 for (;;) {
547 ast_parse_container_doc_comments(pc, &tld_doc_comment_buf);
548
527 AstNode *test_decl = ast_parse_test_decl(pc);549 AstNode *test_decl = ast_parse_test_decl(pc);
528 if (test_decl != nullptr) {550 if (test_decl != nullptr) {
529 res.decls.append(test_decl);551 res.decls.append(test_decl);
...@@ -566,7 +588,7 @@ static AstNodeContainerDecl ast_parse_container_members(ParseContext *pc) {...@@ -566,7 +588,7 @@ static AstNodeContainerDecl ast_parse_container_members(ParseContext *pc) {
566588
567 break;589 break;
568 }590 }
569591 res.doc_comments = tld_doc_comment_buf;
570 return res;592 return res;
571}593}
572594
...@@ -2802,6 +2824,9 @@ static AstNode *ast_parse_container_decl_auto(ParseContext *pc) {...@@ -2802,6 +2824,9 @@ static AstNode *ast_parse_container_decl_auto(ParseContext *pc) {
28022824
2803 res->data.container_decl.fields = members.fields;2825 res->data.container_decl.fields = members.fields;
2804 res->data.container_decl.decls = members.decls;2826 res->data.container_decl.decls = members.decls;
2827 if (buf_len(&members.doc_comments) != 0) {
2828 res->data.container_decl.doc_comments = members.doc_comments;
2829 }
2805 return res;2830 return res;
2806}2831}
28072832
src/tokenizer.cpp+32
...@@ -198,6 +198,7 @@ enum TokenizeState {...@@ -198,6 +198,7 @@ enum TokenizeState {
198 TokenizeStateSawSlash,198 TokenizeStateSawSlash,
199 TokenizeStateSawSlash2,199 TokenizeStateSawSlash2,
200 TokenizeStateSawSlash3,200 TokenizeStateSawSlash3,
201 TokenizeStateSawSlashBang,
201 TokenizeStateSawBackslash,202 TokenizeStateSawBackslash,
202 TokenizeStateSawPercent,203 TokenizeStateSawPercent,
203 TokenizeStateSawPlus,204 TokenizeStateSawPlus,
...@@ -209,6 +210,7 @@ enum TokenizeState {...@@ -209,6 +210,7 @@ enum TokenizeState {
209 TokenizeStateSawBar,210 TokenizeStateSawBar,
210 TokenizeStateSawBarBar,211 TokenizeStateSawBarBar,
211 TokenizeStateDocComment,212 TokenizeStateDocComment,
213 TokenizeStateContainerDocComment,
212 TokenizeStateLineComment,214 TokenizeStateLineComment,
213 TokenizeStateLineString,215 TokenizeStateLineString,
214 TokenizeStateLineStringEnd,216 TokenizeStateLineStringEnd,
...@@ -938,6 +940,9 @@ void tokenize(Buf *buf, Tokenization *out) {...@@ -938,6 +940,9 @@ void tokenize(Buf *buf, Tokenization *out) {
938 case '/':940 case '/':
939 t.state = TokenizeStateSawSlash3;941 t.state = TokenizeStateSawSlash3;
940 break;942 break;
943 case '!':
944 t.state = TokenizeStateSawSlashBang;
945 break;
941 case '\n':946 case '\n':
942 cancel_token(&t);947 cancel_token(&t);
943 t.state = TokenizeStateStart;948 t.state = TokenizeStateStart;
...@@ -965,6 +970,19 @@ void tokenize(Buf *buf, Tokenization *out) {...@@ -965,6 +970,19 @@ void tokenize(Buf *buf, Tokenization *out) {
965 break;970 break;
966 }971 }
967 break;972 break;
973 case TokenizeStateSawSlashBang:
974 switch (c) {
975 case '\n':
976 set_token_id(&t, t.cur_tok, TokenIdContainerDocComment);
977 end_token(&t);
978 t.state = TokenizeStateStart;
979 break;
980 default:
981 set_token_id(&t, t.cur_tok, TokenIdContainerDocComment);
982 t.state = TokenizeStateContainerDocComment;
983 break;
984 }
985 break;
968 case TokenizeStateSawBackslash:986 case TokenizeStateSawBackslash:
969 switch (c) {987 switch (c) {
970 case '\\':988 case '\\':
...@@ -1055,6 +1073,17 @@ void tokenize(Buf *buf, Tokenization *out) {...@@ -1055,6 +1073,17 @@ void tokenize(Buf *buf, Tokenization *out) {
1055 break;1073 break;
1056 }1074 }
1057 break;1075 break;
1076 case TokenizeStateContainerDocComment:
1077 switch (c) {
1078 case '\n':
1079 end_token(&t);
1080 t.state = TokenizeStateStart;
1081 break;
1082 default:
1083 // do nothing
1084 break;
1085 }
1086 break;
1058 case TokenizeStateSymbolFirstC:1087 case TokenizeStateSymbolFirstC:
1059 switch (c) {1088 switch (c) {
1060 case '"':1089 case '"':
...@@ -1545,6 +1574,7 @@ void tokenize(Buf *buf, Tokenization *out) {...@@ -1545,6 +1574,7 @@ void tokenize(Buf *buf, Tokenization *out) {
1545 case TokenizeStateSawBarBar:1574 case TokenizeStateSawBarBar:
1546 case TokenizeStateLBracket:1575 case TokenizeStateLBracket:
1547 case TokenizeStateDocComment:1576 case TokenizeStateDocComment:
1577 case TokenizeStateContainerDocComment:
1548 end_token(&t);1578 end_token(&t);
1549 break;1579 break;
1550 case TokenizeStateSawDotDot:1580 case TokenizeStateSawDotDot:
...@@ -1559,6 +1589,7 @@ void tokenize(Buf *buf, Tokenization *out) {...@@ -1559,6 +1589,7 @@ void tokenize(Buf *buf, Tokenization *out) {
1559 case TokenizeStateLineComment:1589 case TokenizeStateLineComment:
1560 case TokenizeStateSawSlash2:1590 case TokenizeStateSawSlash2:
1561 case TokenizeStateSawSlash3:1591 case TokenizeStateSawSlash3:
1592 case TokenizeStateSawSlashBang:
1562 break;1593 break;
1563 }1594 }
1564 if (t.state != TokenizeStateError) {1595 if (t.state != TokenizeStateError) {
...@@ -1606,6 +1637,7 @@ const char * token_name(TokenId id) {...@@ -1606,6 +1637,7 @@ const char * token_name(TokenId id) {
1606 case TokenIdDash: return "-";1637 case TokenIdDash: return "-";
1607 case TokenIdDivEq: return "/=";1638 case TokenIdDivEq: return "/=";
1608 case TokenIdDocComment: return "DocComment";1639 case TokenIdDocComment: return "DocComment";
1640 case TokenIdContainerDocComment: return "ContainerDocComment";
1609 case TokenIdDot: return ".";1641 case TokenIdDot: return ".";
1610 case TokenIdDotStar: return ".*";1642 case TokenIdDotStar: return ".*";
1611 case TokenIdEllipsis2: return "..";1643 case TokenIdEllipsis2: return "..";
src/tokenizer.hpp+1
...@@ -43,6 +43,7 @@ enum TokenId {...@@ -43,6 +43,7 @@ enum TokenId {
43 TokenIdDash,43 TokenIdDash,
44 TokenIdDivEq,44 TokenIdDivEq,
45 TokenIdDocComment,45 TokenIdDocComment,
46 TokenIdContainerDocComment,
46 TokenIdDot,47 TokenIdDot,
47 TokenIdDotStar,48 TokenIdDotStar,
48 TokenIdEllipsis2,49 TokenIdEllipsis2,