| author | |
| committer | |
| log | 57b8614a5a287d0a312b1cade463ec5485f0518f |
| tree | fda14f96b79a6878208ab483027f9fad97cf2460 |
| parent | 4e28d7a5f7d6346acc42a7524dd77fa5f9322029 |
| parent | 314cb707fce553e51d2ffd5c1ea506fbd1acdf76 |
| signature |
Implement container level doc comments14 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 |
| 856 | 856 | ||
| 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 @@ |
| 190 | 189 | ||
| 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 | } |
| 199 | 198 | ||
| 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 @@ |
| 893 | 892 | ||
| 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 | } |
| 899 | 898 | ||
| 900 | domFnProto.classList.remove("hidden"); | 899 | domFnProto.classList.remove("hidden"); |
| ... | @@ -906,8 +905,8 @@ | ... | @@ -906,8 +905,8 @@ |
| 906 | 905 | ||
| 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 | } |
| 912 | 911 | ||
| 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); |
| 959 | 958 | ||
| 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 { |
| 576 | 576 | ||
| 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, |
| 582 | 581 | ||
| ... | @@ -2254,7 +2253,6 @@ pub const Node = struct { | ... | @@ -2254,7 +2253,6 @@ pub const Node = struct { |
| 2254 | test "iterate" { | 2253 | test "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); |
| 95 | 88 | ||
| 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); |
| 98 | 96 | ||
| 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 | } |
| 157 | 155 | ||
| 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 | } |
| 160 | 164 | ||
| 161 | return list; | 165 | return list; |
| 162 | } | 166 | } |
| 163 | 167 | ||
| 168 | /// Eat a multiline container doc comment | ||
| 169 | fn 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 Block | 185 | /// TestDecl <- KEYWORD_test STRINGLITERAL Block |
| 165 | fn parseTestDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | 186 | fn 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 | } |
| 2568 | 2568 | ||
| 2569 | test "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 | |||
| 2569 | const std = @import("std"); | 2625 | const std = @import("std"); |
| 2570 | const mem = std.mem; | 2626 | const mem = std.mem; |
| 2571 | const warn = std.debug.warn; | 2627 | const 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", |
| 215 | 217 | ||
| 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 | }, | ||
| 1237 | 1247 | ||
| 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 | } |
| 1605 | 1617 | ||
| 1606 | test "tokenizer - line comment followed by identifier" { | 1618 | test "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 end | 177 | // 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; | ||
| 971 | 972 | ||
| 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 | } | ||
| 496 | 499 | ||
| 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 | } |
| 516 | 519 | ||
| 520 | static 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 | // ContainerMembers | 535 | // ContainerMembers |
| 518 | // <- TestDecl ContainerMembers | 536 | // <- TestDecl ContainerMembers |
| 519 | // / TopLevelComptime ContainerMembers | 537 | // / 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 | // / |
| 524 | static AstNodeContainerDecl ast_parse_container_members(ParseContext *pc) { | 542 | static 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) { |
| 566 | 588 | ||
| 567 | break; | 589 | break; |
| 568 | } | 590 | } |
| 569 | 591 | res.doc_comments = tld_doc_comment_buf; | |
| 570 | return res; | 592 | return res; |
| 571 | } | 593 | } |
| 572 | 594 | ||
| ... | @@ -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) { |
| 2802 | 2824 | ||
| 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 | } |
| 2807 | 2832 |
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, |