| 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 | 856 | |
| 857 | 857 | .LineComment, |
| 858 | 858 | .DocComment, |
| 859 | .ContainerDocComment, | |
| 859 | 860 | .ShebangLine, |
| 860 | 861 | => { |
| 861 | 862 | try out.write("<span class=\"tok-comment\">"); |
lib/std/special/docs/index.html+1-1| ... | ... | @@ -484,7 +484,7 @@ |
| 484 | 484 | doc comments. |
| 485 | 485 | </p> |
| 486 | 486 | </div> |
| 487 | <div id="fnDocs" class="hidden"></div> | |
| 487 | <div id="tldDocs" class="hidden"></div> | |
| 488 | 488 | <div id="sectFnErrors" class="hidden"> |
| 489 | 489 | <h2>Errors</h2> |
| 490 | 490 | <div id="fnErrorsAnyError"> |
lib/std/special/docs/main.js+19-12| ... | ... | @@ -20,7 +20,7 @@ |
| 20 | 20 | var domListValues = document.getElementById("listValues"); |
| 21 | 21 | var domFnProto = document.getElementById("fnProto"); |
| 22 | 22 | var domFnProtoCode = document.getElementById("fnProtoCode"); |
| 23 | var domFnDocs = document.getElementById("fnDocs"); | |
| 23 | var domTldDocs = document.getElementById("tldDocs"); | |
| 24 | 24 | var domSectFnErrors = document.getElementById("sectFnErrors"); |
| 25 | 25 | var domListFnErrors = document.getElementById("listFnErrors"); |
| 26 | 26 | var domTableFnErrors = document.getElementById("tableFnErrors"); |
| ... | ... | @@ -34,7 +34,6 @@ |
| 34 | 34 | var domListSearchResults = document.getElementById("listSearchResults"); |
| 35 | 35 | var domSectSearchNoResults = document.getElementById("sectSearchNoResults"); |
| 36 | 36 | var domSectInfo = document.getElementById("sectInfo"); |
| 37 | var domListInfo = document.getElementById("listInfo"); | |
| 38 | 37 | var domTdTarget = document.getElementById("tdTarget"); |
| 39 | 38 | var domTdZigVer = document.getElementById("tdZigVer"); |
| 40 | 39 | var domHdrName = document.getElementById("hdrName"); |
| ... | ... | @@ -102,7 +101,7 @@ |
| 102 | 101 | function render() { |
| 103 | 102 | domStatus.classList.add("hidden"); |
| 104 | 103 | domFnProto.classList.add("hidden"); |
| 105 | domFnDocs.classList.add("hidden"); | |
| 104 | domTldDocs.classList.add("hidden"); | |
| 106 | 105 | domSectPkgs.classList.add("hidden"); |
| 107 | 106 | domSectTypes.classList.add("hidden"); |
| 108 | 107 | domSectNamespaces.classList.add("hidden"); |
| ... | ... | @@ -190,11 +189,11 @@ |
| 190 | 189 | |
| 191 | 190 | var docs = zigAnalysis.astNodes[decl.src].docs; |
| 192 | 191 | if (docs != null) { |
| 193 | domFnDocs.innerHTML = markdown(docs); | |
| 192 | domTldDocs.innerHTML = markdown(docs); | |
| 194 | 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 | 199 | function typeIsErrSet(typeIndex) { |
| ... | ... | @@ -274,8 +273,8 @@ |
| 274 | 273 | docsSource = protoSrcNode.docs; |
| 275 | 274 | } |
| 276 | 275 | if (docsSource != null) { |
| 277 | domFnDocs.innerHTML = markdown(docsSource); | |
| 278 | domFnDocs.classList.remove("hidden"); | |
| 276 | domTldDocs.innerHTML = markdown(docsSource); | |
| 277 | domTldDocs.classList.remove("hidden"); | |
| 279 | 278 | } |
| 280 | 279 | domFnProto.classList.remove("hidden"); |
| 281 | 280 | } |
| ... | ... | @@ -893,8 +892,8 @@ |
| 893 | 892 | |
| 894 | 893 | var docs = zigAnalysis.astNodes[decl.src].docs; |
| 895 | 894 | if (docs != null) { |
| 896 | domFnDocs.innerHTML = markdown(docs); | |
| 897 | domFnDocs.classList.remove("hidden"); | |
| 895 | domTldDocs.innerHTML = markdown(docs); | |
| 896 | domTldDocs.classList.remove("hidden"); | |
| 898 | 897 | } |
| 899 | 898 | |
| 900 | 899 | domFnProto.classList.remove("hidden"); |
| ... | ... | @@ -906,8 +905,8 @@ |
| 906 | 905 | |
| 907 | 906 | var docs = zigAnalysis.astNodes[decl.src].docs; |
| 908 | 907 | if (docs != null) { |
| 909 | domFnDocs.innerHTML = markdown(docs); | |
| 910 | domFnDocs.classList.remove("hidden"); | |
| 908 | domTldDocs.innerHTML = markdown(docs); | |
| 909 | domTldDocs.classList.remove("hidden"); | |
| 911 | 910 | } |
| 912 | 911 | |
| 913 | 912 | domFnProto.classList.remove("hidden"); |
| ... | ... | @@ -957,6 +956,14 @@ |
| 957 | 956 | varsList.sort(byNameProperty); |
| 958 | 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 | 967 | if (typesList.length !== 0) { |
| 961 | 968 | resizeDomList(domListTypes, typesList.length, '<li><a href="#"></a></li>'); |
| 962 | 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 | 576 | |
| 577 | 577 | pub const Root = struct { |
| 578 | 578 | base: Node, |
| 579 | doc_comments: ?*DocComment, | |
| 580 | 579 | decls: DeclList, |
| 581 | 580 | eof_token: TokenIndex, |
| 582 | 581 | |
| ... | ... | @@ -2254,7 +2253,6 @@ pub const Node = struct { |
| 2254 | 2253 | test "iterate" { |
| 2255 | 2254 | var root = Node.Root{ |
| 2256 | 2255 | .base = Node{ .id = Node.Id.Root }, |
| 2257 | .doc_comments = null, | |
| 2258 | 2256 | .decls = Node.Root.DeclList.init(std.debug.global_allocator), |
| 2259 | 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 | 58 | node.* = Node.Root{ |
| 59 | 59 | .base = Node{ .id = .Root }, |
| 60 | 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 | 61 | .eof_token = undefined, |
| 69 | 62 | }; |
| 70 | 63 | node.decls = parseContainerMembers(arena, it, tree) catch |err| { |
| ... | ... | @@ -94,6 +87,11 @@ fn parseContainerMembers(arena: *Allocator, it: *TokenIterator, tree: *Tree) !No |
| 94 | 87 | var list = Node.Root.DeclList.init(arena); |
| 95 | 88 | |
| 96 | 89 | while (true) { |
| 90 | if (try parseContainerDocComments(arena, it, tree)) |node| { | |
| 91 | try list.push(node); | |
| 92 | continue; | |
| 93 | } | |
| 94 | ||
| 97 | 95 | const doc_comments = try parseDocComment(arena, it, tree); |
| 98 | 96 | |
| 99 | 97 | if (try parseTestDecl(arena, it, tree)) |node| { |
| ... | ... | @@ -155,12 +153,35 @@ fn parseContainerMembers(arena: *Allocator, it: *TokenIterator, tree: *Tree) !No |
| 155 | 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 | 162 | break; |
| 159 | 163 | } |
| 160 | 164 | |
| 161 | 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 | 185 | /// TestDecl <- KEYWORD_test STRINGLITERAL Block |
| 165 | 186 | fn parseTestDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 166 | 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 | 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 | 2625 | const std = @import("std"); |
| 2570 | 2626 | const mem = std.mem; |
| 2571 | 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 | 299 | assert(!decl.requireSemiColon()); |
| 300 | 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 | 313 | else => unreachable, |
| 303 | 314 | } |
| 304 | 315 | } |
lib/std/zig/tokenizer.zig+13-1| ... | ... | @@ -142,6 +142,7 @@ pub const Token = struct { |
| 142 | 142 | FloatLiteral, |
| 143 | 143 | LineComment, |
| 144 | 144 | DocComment, |
| 145 | ContainerDocComment, | |
| 145 | 146 | BracketStarBracket, |
| 146 | 147 | BracketStarCBracket, |
| 147 | 148 | ShebangLine, |
| ... | ... | @@ -211,6 +212,7 @@ pub const Token = struct { |
| 211 | 212 | .FloatLiteral => "FloatLiteral", |
| 212 | 213 | .LineComment => "LineComment", |
| 213 | 214 | .DocComment => "DocComment", |
| 215 | .ContainerDocComment => "ContainerDocComment", | |
| 214 | 216 | .ShebangLine => "ShebangLine", |
| 215 | 217 | |
| 216 | 218 | .Bang => "!", |
| ... | ... | @@ -387,6 +389,7 @@ pub const Tokenizer = struct { |
| 387 | 389 | LineComment, |
| 388 | 390 | DocCommentStart, |
| 389 | 391 | DocComment, |
| 392 | ContainerDocComment, | |
| 390 | 393 | Zero, |
| 391 | 394 | IntegerLiteral, |
| 392 | 395 | IntegerLiteralWithRadix, |
| ... | ... | @@ -1076,6 +1079,10 @@ pub const Tokenizer = struct { |
| 1076 | 1079 | '/' => { |
| 1077 | 1080 | state = State.DocCommentStart; |
| 1078 | 1081 | }, |
| 1082 | '!' => { | |
| 1083 | result.id = Token.Id.ContainerDocComment; | |
| 1084 | state = State.ContainerDocComment; | |
| 1085 | }, | |
| 1079 | 1086 | '\n' => break, |
| 1080 | 1087 | else => { |
| 1081 | 1088 | state = State.LineComment; |
| ... | ... | @@ -1096,7 +1103,7 @@ pub const Tokenizer = struct { |
| 1096 | 1103 | self.checkLiteralCharacter(); |
| 1097 | 1104 | }, |
| 1098 | 1105 | }, |
| 1099 | State.LineComment, State.DocComment => switch (c) { | |
| 1106 | State.LineComment, State.DocComment, State.ContainerDocComment => switch (c) { | |
| 1100 | 1107 | '\n' => break, |
| 1101 | 1108 | else => self.checkLiteralCharacter(), |
| 1102 | 1109 | }, |
| ... | ... | @@ -1234,6 +1241,9 @@ pub const Tokenizer = struct { |
| 1234 | 1241 | State.DocComment, State.DocCommentStart => { |
| 1235 | 1242 | result.id = Token.Id.DocComment; |
| 1236 | 1243 | }, |
| 1244 | State.ContainerDocComment => { | |
| 1245 | result.id = Token.Id.ContainerDocComment; | |
| 1246 | }, | |
| 1237 | 1247 | |
| 1238 | 1248 | State.NumberDot, |
| 1239 | 1249 | State.NumberDotHex, |
| ... | ... | @@ -1601,6 +1611,8 @@ test "tokenizer - line comment and doc comment" { |
| 1601 | 1611 | testTokenize("/// a", [_]Token.Id{Token.Id.DocComment}); |
| 1602 | 1612 | testTokenize("///", [_]Token.Id{Token.Id.DocComment}); |
| 1603 | 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 | 1618 | test "tokenizer - line comment followed by identifier" { |
src-self-hosted/translate_c.zig-1| ... | ... | @@ -174,7 +174,6 @@ pub fn translate( |
| 174 | 174 | tree.root_node.* = ast.Node.Root{ |
| 175 | 175 | .base = ast.Node{ .id = ast.Node.Id.Root }, |
| 176 | 176 | .decls = ast.Node.Root.DeclList.init(arena), |
| 177 | .doc_comments = null, | |
| 178 | 177 | // initialized with the eof token at the end |
| 179 | 178 | .eof_token = undefined, |
| 180 | 179 | }; |
src/all_types.hpp+1| ... | ... | @@ -968,6 +968,7 @@ struct AstNodeContainerDecl { |
| 968 | 968 | AstNode *init_arg_expr; // enum(T), struct(endianness), or union(T), or union(enum(T)) |
| 969 | 969 | ZigList<AstNode *> fields; |
| 970 | 970 | ZigList<AstNode *> decls; |
| 971 | Buf doc_comments; | |
| 971 | 972 | |
| 972 | 973 | ContainerKind kind; |
| 973 | 974 | ContainerLayout layout; |
src/dump_analysis.cpp+1| ... | ... | @@ -1088,6 +1088,7 @@ static void anal_dump_node(AnalDumpCtx *ctx, const AstNode *node) { |
| 1088 | 1088 | break; |
| 1089 | 1089 | case NodeTypeContainerDecl: |
| 1090 | 1090 | field_nodes = &node->data.container_decl.fields; |
| 1091 | doc_comments_buf = &node->data.container_decl.doc_comments; | |
| 1091 | 1092 | break; |
| 1092 | 1093 | default: |
| 1093 | 1094 | break; |
src/parser.cpp+26-1| ... | ... | @@ -493,6 +493,9 @@ static AstNode *ast_parse_root(ParseContext *pc) { |
| 493 | 493 | node->data.container_decl.layout = ContainerLayoutAuto; |
| 494 | 494 | node->data.container_decl.kind = ContainerKindStruct; |
| 495 | 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 | 500 | return node; |
| 498 | 501 | } |
| ... | ... | @@ -514,6 +517,21 @@ static Token *ast_parse_doc_comments(ParseContext *pc, Buf *buf) { |
| 514 | 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 | 535 | // ContainerMembers |
| 518 | 536 | // <- TestDecl ContainerMembers |
| 519 | 537 | // / TopLevelComptime ContainerMembers |
| ... | ... | @@ -523,7 +541,11 @@ static Token *ast_parse_doc_comments(ParseContext *pc, Buf *buf) { |
| 523 | 541 | // / |
| 524 | 542 | static AstNodeContainerDecl ast_parse_container_members(ParseContext *pc) { |
| 525 | 543 | AstNodeContainerDecl res = {}; |
| 544 | Buf tld_doc_comment_buf = BUF_INIT; | |
| 545 | buf_resize(&tld_doc_comment_buf, 0); | |
| 526 | 546 | for (;;) { |
| 547 | ast_parse_container_doc_comments(pc, &tld_doc_comment_buf); | |
| 548 | ||
| 527 | 549 | AstNode *test_decl = ast_parse_test_decl(pc); |
| 528 | 550 | if (test_decl != nullptr) { |
| 529 | 551 | res.decls.append(test_decl); |
| ... | ... | @@ -566,7 +588,7 @@ static AstNodeContainerDecl ast_parse_container_members(ParseContext *pc) { |
| 566 | 588 | |
| 567 | 589 | break; |
| 568 | 590 | } |
| 569 | ||
| 591 | res.doc_comments = tld_doc_comment_buf; | |
| 570 | 592 | return res; |
| 571 | 593 | } |
| 572 | 594 | |
| ... | ... | @@ -2802,6 +2824,9 @@ static AstNode *ast_parse_container_decl_auto(ParseContext *pc) { |
| 2802 | 2824 | |
| 2803 | 2825 | res->data.container_decl.fields = members.fields; |
| 2804 | 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 | 2830 | return res; |
| 2806 | 2831 | } |
| 2807 | 2832 |
src/tokenizer.cpp+32| ... | ... | @@ -198,6 +198,7 @@ enum TokenizeState { |
| 198 | 198 | TokenizeStateSawSlash, |
| 199 | 199 | TokenizeStateSawSlash2, |
| 200 | 200 | TokenizeStateSawSlash3, |
| 201 | TokenizeStateSawSlashBang, | |
| 201 | 202 | TokenizeStateSawBackslash, |
| 202 | 203 | TokenizeStateSawPercent, |
| 203 | 204 | TokenizeStateSawPlus, |
| ... | ... | @@ -209,6 +210,7 @@ enum TokenizeState { |
| 209 | 210 | TokenizeStateSawBar, |
| 210 | 211 | TokenizeStateSawBarBar, |
| 211 | 212 | TokenizeStateDocComment, |
| 213 | TokenizeStateContainerDocComment, | |
| 212 | 214 | TokenizeStateLineComment, |
| 213 | 215 | TokenizeStateLineString, |
| 214 | 216 | TokenizeStateLineStringEnd, |
| ... | ... | @@ -938,6 +940,9 @@ void tokenize(Buf *buf, Tokenization *out) { |
| 938 | 940 | case '/': |
| 939 | 941 | t.state = TokenizeStateSawSlash3; |
| 940 | 942 | break; |
| 943 | case '!': | |
| 944 | t.state = TokenizeStateSawSlashBang; | |
| 945 | break; | |
| 941 | 946 | case '\n': |
| 942 | 947 | cancel_token(&t); |
| 943 | 948 | t.state = TokenizeStateStart; |
| ... | ... | @@ -965,6 +970,19 @@ void tokenize(Buf *buf, Tokenization *out) { |
| 965 | 970 | break; |
| 966 | 971 | } |
| 967 | 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 | 986 | case TokenizeStateSawBackslash: |
| 969 | 987 | switch (c) { |
| 970 | 988 | case '\\': |
| ... | ... | @@ -1055,6 +1073,17 @@ void tokenize(Buf *buf, Tokenization *out) { |
| 1055 | 1073 | break; |
| 1056 | 1074 | } |
| 1057 | 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 | 1087 | case TokenizeStateSymbolFirstC: |
| 1059 | 1088 | switch (c) { |
| 1060 | 1089 | case '"': |
| ... | ... | @@ -1545,6 +1574,7 @@ void tokenize(Buf *buf, Tokenization *out) { |
| 1545 | 1574 | case TokenizeStateSawBarBar: |
| 1546 | 1575 | case TokenizeStateLBracket: |
| 1547 | 1576 | case TokenizeStateDocComment: |
| 1577 | case TokenizeStateContainerDocComment: | |
| 1548 | 1578 | end_token(&t); |
| 1549 | 1579 | break; |
| 1550 | 1580 | case TokenizeStateSawDotDot: |
| ... | ... | @@ -1559,6 +1589,7 @@ void tokenize(Buf *buf, Tokenization *out) { |
| 1559 | 1589 | case TokenizeStateLineComment: |
| 1560 | 1590 | case TokenizeStateSawSlash2: |
| 1561 | 1591 | case TokenizeStateSawSlash3: |
| 1592 | case TokenizeStateSawSlashBang: | |
| 1562 | 1593 | break; |
| 1563 | 1594 | } |
| 1564 | 1595 | if (t.state != TokenizeStateError) { |
| ... | ... | @@ -1606,6 +1637,7 @@ const char * token_name(TokenId id) { |
| 1606 | 1637 | case TokenIdDash: return "-"; |
| 1607 | 1638 | case TokenIdDivEq: return "/="; |
| 1608 | 1639 | case TokenIdDocComment: return "DocComment"; |
| 1640 | case TokenIdContainerDocComment: return "ContainerDocComment"; | |
| 1609 | 1641 | case TokenIdDot: return "."; |
| 1610 | 1642 | case TokenIdDotStar: return ".*"; |
| 1611 | 1643 | case TokenIdEllipsis2: return ".."; |
src/tokenizer.hpp+1| ... | ... | @@ -43,6 +43,7 @@ enum TokenId { |
| 43 | 43 | TokenIdDash, |
| 44 | 44 | TokenIdDivEq, |
| 45 | 45 | TokenIdDocComment, |
| 46 | TokenIdContainerDocComment, | |
| 46 | 47 | TokenIdDot, |
| 47 | 48 | TokenIdDotStar, |
| 48 | 49 | TokenIdEllipsis2, |