authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-07-22 20:56:59-07:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2022-07-22 20:56:59-07:00
log7502e490cb83a91133aa696e4ec0936022bee0c6
treee87e4bcdc01f312a0dcf401c959fd52830d0c56a
parentf591936480730a279d55a051f92806e19834faf7
parent92966088c2679ef670dc9776408deee98d16486f
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #12173 from ziglang/autodocs-rebased

New Autodocs!

15 files changed, 6295 insertions(+), 3113 deletions(-)

CMakeLists.txt-1
......@@ -340,7 +340,6 @@ set(STAGE1_SOURCES
340340 "${CMAKE_SOURCE_DIR}/src/stage1/bigint.cpp"
341341 "${CMAKE_SOURCE_DIR}/src/stage1/buffer.cpp"
342342 "${CMAKE_SOURCE_DIR}/src/stage1/codegen.cpp"
343 "${CMAKE_SOURCE_DIR}/src/stage1/dump_analysis.cpp"
344343 "${CMAKE_SOURCE_DIR}/src/stage1/errmsg.cpp"
345344 "${CMAKE_SOURCE_DIR}/src/stage1/error.cpp"
346345 "${CMAKE_SOURCE_DIR}/src/stage1/heap.cpp"
build.zig-1
......@@ -936,7 +936,6 @@ const stage1_sources = [_][]const u8{
936936 "src/stage1/bigint.cpp",
937937 "src/stage1/buffer.cpp",
938938 "src/stage1/codegen.cpp",
939 "src/stage1/dump_analysis.cpp",
940939 "src/stage1/errmsg.cpp",
941940 "src/stage1/error.cpp",
942941 "src/stage1/heap.cpp",
ci/azure/build.zig-1
......@@ -745,7 +745,6 @@ const stage1_sources = [_][]const u8{
745745 "src/stage1/bigint.cpp",
746746 "src/stage1/buffer.cpp",
747747 "src/stage1/codegen.cpp",
748 "src/stage1/dump_analysis.cpp",
749748 "src/stage1/errmsg.cpp",
750749 "src/stage1/error.cpp",
751750 "src/stage1/heap.cpp",
lib/docs/index.html+121-67
......@@ -26,25 +26,23 @@
2626 --search-sh-color: rgba(0, 0, 0, 0.18);
2727 --help-sh-color: rgba(0, 0, 0, 0.75);
2828 }
29
29
3030 html, body { margin: 0; padding:0; height: 100%; }
3131
3232 a {
3333 text-decoration: none;
3434 }
35
35
3636 a:hover {
3737 text-decoration: underline;
3838 }
39
39
4040 .hidden {
4141 display: none;
4242 }
4343
4444 /* layout */
4545 .canvas {
46 display: flex;
47 flex-direction: column;
4846 width: 100vw;
4947 height: 100vh;
5048 overflow: hidden;
......@@ -55,21 +53,12 @@
5553 background-color: var(--bg-color);
5654 }
5755
58 .banner {
59 background-color: darkred;
60 text-align: center;
61 color: white;
62 padding: 15px 5px;
63 }
64
65 .banner a {
66 color: bisque;
67 text-decoration: underline;
68 }
69
7056 .flex-main {
7157 display: flex;
72 overflow-y: hidden;
58 width: 100%;
59 height: 100%;
60 justify-content: center;
61
7362 z-index: 100;
7463 }
7564
......@@ -87,7 +76,7 @@
8776 overflow-wrap: break-word;
8877 flex-shrink: 0;
8978 flex-grow: 0;
90
79
9180 z-index: 300;
9281 }
9382
......@@ -97,7 +86,7 @@
9786 -webkit-overflow-scrolling: touch;
9887 flex-grow: 1;
9988 flex-shrink: 1;
100
89
10190 z-index: 200;
10291 }
10392
......@@ -106,44 +95,44 @@
10695 max-width: 85vw;
10796 flex-shrink: 1;
10897 }
109
98
11099 .help-modal {
111100 z-index: 400;
112101 }
113
102
114103 /* sidebar */
115104 .sidebar {
116105 font-size: 1rem;
117106 background-color: var(--bg-color);
118107 box-shadow: 0 0 1rem var(--sidebar-sh-color);
119108 }
120
109
121110 .sidebar .logo {
122111 padding: 1rem 0.35rem 0.35rem 0.35rem;
123112 }
124
113
125114 .sidebar .logo > svg {
126115 display: block;
127116 overflow: visible;
128117 }
129
118
130119 .sidebar h2 {
131120 margin: 0.5rem;
132121 padding: 0;
133122 font-size: 1.2rem;
134123 }
135
124
136125 .sidebar h2 > span {
137126 border-bottom: 0.125rem dotted var(--tx-color);
138127 }
139
128
140129 .sidebar .packages {
141130 list-style-type: none;
142131 margin: 0;
143132 padding: 0;
144133 background-color: var(--sidebar-pkg-bg-color);
145134 }
146
135
147136 .sidebar .packages > li > a {
148137 display: block;
149138 padding: 0.5rem 1rem;
......@@ -151,17 +140,17 @@
151140 background-color: var(--sidebar-pkglnk-bg-color);
152141 text-decoration: none;
153142 }
154
143
155144 .sidebar .packages > li > a:hover {
156145 color: var(--sidebar-pkglnk-tx-color-hover);
157146 background-color: var(--sidebar-pkglnk-bg-color-hover);
158147 }
159
148
160149 .sidebar .packages > li > a.active {
161150 color: var(--sidebar-pkglnk-tx-color-active);
162151 background-color: var(--sidebar-pkglnk-bg-color-active);
163152 }
164
153
165154 .sidebar p.str {
166155 margin: 0.5rem;
167156 font-family: var(--mono);
......@@ -194,28 +183,28 @@
194183 border-radius: 0;
195184 -webkit-appearance: none;
196185 }
197
186
198187 .docs .search:focus {
199188 background-color: var(--search-bg-color-focus);
200189 border-bottom-color: #ffbb4d;
201190 box-shadow: 0 0.3em 1em 0.125em var(--search-sh-color);
202191 }
203
192
204193 .docs .search::placeholder {
205194 font-size: 1rem;
206195 font-family: var(--ui);
207196 color: var(--tx-color);
208197 opacity: 0.5;
209198 }
210
199
211200 .docs a {
212201 color: var(--link-color);
213202 }
214
203
215204 .docs p {
216205 margin: 0.8rem 0;
217206 }
218
207
219208 .docs pre {
220209 font-family: var(--mono);
221210 font-size:1em;
......@@ -223,19 +212,19 @@
223212 padding:1em;
224213 overflow-x: auto;
225214 }
226
215
227216 .docs code {
228217 font-family: var(--mono);
229218 font-size: 1em;
230219 }
231
220
232221 .docs h1 {
233222 font-size: 1.4em;
234223 margin: 0.8em 0;
235224 padding: 0;
236225 border-bottom: 0.0625rem dashed;
237226 }
238
227
239228 .docs h2 {
240229 font-size: 1.3em;
241230 margin: 0.5em 0;
......@@ -275,7 +264,7 @@
275264 #tableFnErrors dt {
276265 font-weight: bold;
277266 }
278
267
279268 .examples {
280269 list-style-type: none;
281270 margin: 0;
......@@ -286,7 +275,7 @@
286275 white-space: nowrap;
287276 overflow-x: auto;
288277 }
289
278
290279 .docs td {
291280 margin: 0;
292281 padding: 0.5em;
......@@ -294,7 +283,7 @@
294283 text-overflow: ellipsis;
295284 overflow-x: hidden;
296285 }
297
286
298287 /* help dialog */
299288 .help-modal {
300289 display: flex;
......@@ -319,23 +308,23 @@
319308 border: 0.125rem solid #000;
320309 box-shadow: 0 0.5rem 2.5rem 0.3rem var(--help-sh-color);
321310 }
322
311
323312 .help-modal h1 {
324313 margin: 0.75em 2.5em 1em 2.5em;
325314 font-size: 1.5em;
326315 text-align: center;
327316 }
328
317
329318 .help-modal dt, .help-modal dd {
330319 display: inline;
331320 margin: 0 0.2em;
332321 }
333
322
334323 .help-modal dl {
335324 margin-left: 0.5em;
336325 margin-right: 0.5em;
337326 }
338
327
339328 .help-modal kbd {
340329 display: inline-block;
341330 padding: 0.3em 0.2em;
......@@ -352,7 +341,14 @@
352341 box-shadow: inset 0 -0.0625em 0 #c6cbd1;
353342 cursor: default;
354343 }
355
344
345 #listFns dt {
346 font-family: var(--mono);
347 }
348 .argBreaker {
349 display: none;
350 }
351
356352 /* tokens */
357353 .tok-kw {
358354 color: #333;
......@@ -382,10 +378,10 @@
382378 color: #458;
383379 font-weight: bold;
384380 }
385
381
386382 /* dark mode */
387383 @media (prefers-color-scheme: dark) {
388
384
389385 :root {
390386 --tx-color: #bbb;
391387 --bg-color: #111;
......@@ -403,7 +399,7 @@
403399 --search-sh-color: rgba(255, 255, 255, 0.28);
404400 --help-sh-color: rgba(142, 142, 142, 0.5);
405401 }
406
402
407403 .docs pre {
408404 background-color:#2A2A2A;
409405 }
......@@ -451,7 +447,7 @@
451447 .tok-type {
452448 color: #68f;
453449 }
454
450
455451 }
456452
457453 @media only screen and (max-width: 750px) {
......@@ -523,34 +519,87 @@
523519 min-width: calc(100% - 2.8rem);
524520 }
525521 }
522 .banner {
523 background-color: orange;
524 text-align: center;
525 color: black;
526 padding: 5px 5px;
527 }
528 .banner a {
529 color: black;
530 text-decoration: underline;
531 }
526532 </style>
527533 </head>
528534 <body class="canvas">
529 <div class="banner">These docs are experimental. <a href="https://kristoff.it/blog/zig-new-relationship-llvm/">Progress depends on the self-hosted compiler</a>, <a href="https://github.com/ziglang/zig/wiki/How-to-read-the-standard-library-source-code">consider reading the stdlib source in the meantime</a>.</div>
535 <div class="banner">
536 This is a beta autodoc build; expect bugs and missing information.
537 <a href="https://github.com/ziglang/zig/wiki/How-to-contribute-to-Autodoc">Report an Issue</a>,
538 <a href="https://github.com/ziglang/zig/wiki/How-to-contribute-to-Autodoc">Contribute</a>,
539 <a href="https://github.com/ziglang/zig/wiki/How-to-read-the-standard-library-source-code">Learn more about stdlib source code</a>.
540 </div>
530541 <div class="flex-main">
531542 <div class="flex-filler"></div>
532543 <div class="flex-left sidebar">
533544 <nav>
534545 <div class="logo">
535 <svg version="1.1" viewBox="0 0 150 80" xmlns="http://www.w3.org/2000/svg">
536 <g fill="#f7a41d">
537 <path d="m0,-0.08899l0,80l19,0l6,-10l12,-10l-17,0l0,-40l15,0l0,-20l-35,0zm40,0l0,20l62,0l0,-20l-62,0zm91,0l-6,10l-12,10l17,0l0,40l-15,0l0,20l35,0l0,-80l-19,0zm-83,60l0,20l62,0l0,-20l-62,0z" shape-rendering="crispEdges"></path>
538 <path d="m37,59.91101l-18,20l0,-15l18,-5z"></path>
539 <path d="m113,19.91101l18,-20l0,15l-18,5z"></path>
540 <path d="m96.98,0.54101l36.28,-10.4l-80.29,89.17l-36.28,10.4l80.29,-89.17z"></path>
541 </g>
546 <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 400 140">
547 <g fill="#F7A41D">
548 <g>
549 <polygon points="46,22 28,44 19,30"/>
550 <polygon points="46,22 33,33 28,44 22,44 22,95 31,95 20,100 12,117 0,117 0,22" shape-rendering="crispEdges"/>
551 <polygon points="31,95 12,117 4,106"/>
552 </g>
553 <g>
554 <polygon points="56,22 62,36 37,44"/>
555 <polygon points="56,22 111,22 111,44 37,44 56,32" shape-rendering="crispEdges"/>
556 <polygon points="116,95 97,117 90,104"/>
557 <polygon points="116,95 100,104 97,117 42,117 42,95" shape-rendering="crispEdges"/>
558 <polygon points="150,0 52,117 3,140 101,22"/>
559 </g>
560 <g>
561 <polygon points="141,22 140,40 122,45"/>
562 <polygon points="153,22 153,117 106,117 120,105 125,95 131,95 131,45 122,45 132,36 141,22" shape-rendering="crispEdges"/>
563 <polygon points="125,95 130,110 106,117"/>
564 </g>
565 </g>
566 <style>
567 #text { fill: #121212 }
568 @media (prefers-color-scheme: dark) { #text { fill: #f2f2f2 } }
569 </style>
570 <g id="text">
571 <g>
572 <polygon points="260,22 260,37 229,40 177,40 177,22" shape-rendering="crispEdges"/>
573 <polygon points="260,37 207,99 207,103 176,103 229,40 229,37"/>
574 <polygon points="261,99 261,117 176,117 176,103 206,99" shape-rendering="crispEdges"/>
575 </g>
576 <rect x="272" y="22" shape-rendering="crispEdges" width="22" height="95"/>
577 <g>
578 <polygon points="394,67 394,106 376,106 376,81 360,70 346,67" shape-rendering="crispEdges"/>
579 <polygon points="360,68 376,81 346,67"/>
580 <path d="M394,106c-10.2,7.3-24,12-37.7,12c-29,0-51.1-20.8-51.1-48.3c0-27.3,22.5-48.1,52-48.1 c14.3,0,29.2,5.5,38.9,14l-13,15c-7.1-6.3-16.8-10-25.9-10c-17,0-30.2,12.9-30.2,29.5c0,16.8,13.3,29.6,30.3,29.6 c5.7,0,12.8-2.3,19-5.5L394,106z"/>
581 </g>
582 </g>
542583 </svg>
584 </div>
585 <div id="sectMainPkg" class="hidden">
586 <h2><span>Main Package</span></h2>
587 <ul class="packages">
588 <li><a id="mainPkg" class="" href=""></a></li>
589 </ul>
543590 </div>
544591 <div id="sectPkgs" class="hidden">
545 <h2><span>Packages</span></h2>
592 <h2><span>Dependencies</span></h2>
546593 <ul id="listPkgs" class="packages"></ul>
547594 </div>
548595 <div id="sectInfo" class="hidden">
549596 <h2><span>Zig Version</span></h2>
550597 <p class="str" id="tdZigVer"></p>
551 <h2><span>Target</span></h2>
552 <p class="str" id="tdTarget"></p>
553598 </div>
599 <div>
600 <input id="privDeclsBox" type="checkbox"/>
601 <label for="privDeclsBox">Internal Doc Mode</label>
602 </div>
554603 </nav>
555604 </div>
556605 <div class="flex-right">
......@@ -588,7 +637,6 @@
588637 <div id="sectSearchResults" class="hidden">
589638 <h2>Search Results</h2>
590639 <ul id="listSearchResults"></ul>
591 <p id="sectSearchAllResultsLink" class="hidden"><a href="">show all results</a></p>
592640 </div>
593641 <div id="sectSearchNoResults" class="hidden">
594642 <h2>No Results Found</h2>
......@@ -617,9 +665,7 @@
617665 <div id="sectFns" class="hidden">
618666 <h2>Functions</h2>
619667 <div class="table-container">
620 <table>
621 <tbody id="listFns"></tbody>
622 </table>
668 <dl id="listFns"></dl>
623669 </div>
624670 </div>
625671 <div id="sectValues" class="hidden">
......@@ -638,7 +684,15 @@
638684 <h2>Examples</h2>
639685 <ul id="listFnExamples" class="examples"></ul>
640686 </div>
641 </section>
687 <div id="sectTests" class="hidden">
688 <h2>Tests</h2>
689 <div class="table-container">
690 <table>
691 <tbody id="listTests"></tbody>
692 </table>
693 </div>
694 </div>
695 </section>
642696 </div>
643697 <div class="flex-filler"></div>
644698 </div>
lib/docs/main.js+2275-1069
......@@ -1,73 +1,83 @@
1'use strict';
2
3var zigAnalysis;
4
15(function() {
2 var domStatus = document.getElementById("status");
3 var domSectNav = document.getElementById("sectNav");
4 var domListNav = document.getElementById("listNav");
5 var domSectPkgs = document.getElementById("sectPkgs");
6 var domListPkgs = document.getElementById("listPkgs");
7 var domSectTypes = document.getElementById("sectTypes");
8 var domListTypes = document.getElementById("listTypes");
9 var domSectNamespaces = document.getElementById("sectNamespaces");
10 var domListNamespaces = document.getElementById("listNamespaces");
11 var domSectErrSets = document.getElementById("sectErrSets");
12 var domListErrSets = document.getElementById("listErrSets");
13 var domSectFns = document.getElementById("sectFns");
14 var domListFns = document.getElementById("listFns");
15 var domSectFields = document.getElementById("sectFields");
16 var domListFields = document.getElementById("listFields");
17 var domSectGlobalVars = document.getElementById("sectGlobalVars");
18 var domListGlobalVars = document.getElementById("listGlobalVars");
19 var domSectValues = document.getElementById("sectValues");
20 var domListValues = document.getElementById("listValues");
21 var domFnProto = document.getElementById("fnProto");
22 var domFnProtoCode = document.getElementById("fnProtoCode");
23 var domSectParams = document.getElementById("sectParams");
24 var domListParams = document.getElementById("listParams");
25 var domTldDocs = document.getElementById("tldDocs");
26 var domSectFnErrors = document.getElementById("sectFnErrors");
27 var domListFnErrors = document.getElementById("listFnErrors");
28 var domTableFnErrors = document.getElementById("tableFnErrors");
29 var domFnErrorsAnyError = document.getElementById("fnErrorsAnyError");
30 var domFnExamples = document.getElementById("fnExamples");
31 var domListFnExamples = document.getElementById("listFnExamples");
32 var domFnNoExamples = document.getElementById("fnNoExamples");
33 var domDeclNoRef = document.getElementById("declNoRef");
34 var domSearch = document.getElementById("search");
35 var domSectSearchResults = document.getElementById("sectSearchResults");
36 var domListSearchResults = document.getElementById("listSearchResults");
37 var domSectSearchNoResults = document.getElementById("sectSearchNoResults");
38 var domSectSearchAllResultsLink = document.getElementById("sectSearchAllResultsLink");
39 var domSectInfo = document.getElementById("sectInfo");
40 var domTdTarget = document.getElementById("tdTarget");
41 var domTdZigVer = document.getElementById("tdZigVer");
42 var domHdrName = document.getElementById("hdrName");
43 var domHelpModal = document.getElementById("helpDialog");
44
45 var searchTimer = null;
46 var searchTrimResults = true;
47 var escapeHtmlReplacements = { "&": "&amp;", '"': "&quot;", "<": "&lt;", ">": "&gt;" };
48
49 var typeKinds = indexTypeKinds();
50 var typeTypeId = findTypeTypeId();
51 var pointerSizeEnum = { One: 0, Many: 1, Slice: 2, C: 3 };
52 var tokenKinds = {
53 Keyword: 'tok-kw',
54 String: 'tok-str',
55 Builtin: 'tok-builtin',
56 Comment: 'tok-comment',
57 Function: 'tok-fn',
58 Null: 'tok-null',
59 Number: 'tok-number',
60 Type: 'tok-type',
61 };
6 let domStatus = (document.getElementById("status"));
7 let domSectNav = (document.getElementById("sectNav"));
8 let domListNav = (document.getElementById("listNav"));
9 let domSectMainPkg = (document.getElementById("sectMainPkg"));
10 let domSectPkgs = (document.getElementById("sectPkgs"));
11 let domListPkgs = (document.getElementById("listPkgs"));
12 let domSectTypes = (document.getElementById("sectTypes"));
13 let domListTypes = (document.getElementById("listTypes"));
14 let domSectTests = (document.getElementById("sectTests"));
15 let domListTests = (document.getElementById("listTests"));
16 let domSectNamespaces = (document.getElementById("sectNamespaces"));
17 let domListNamespaces = (document.getElementById("listNamespaces"));
18 let domSectErrSets = (document.getElementById("sectErrSets"));
19 let domListErrSets = (document.getElementById("listErrSets"));
20 let domSectFns = (document.getElementById("sectFns"));
21 let domListFns = (document.getElementById("listFns"));
22 let domSectFields = (document.getElementById("sectFields"));
23 let domListFields = (document.getElementById("listFields"));
24 let domSectGlobalVars = (document.getElementById("sectGlobalVars"));
25 let domListGlobalVars = (document.getElementById("listGlobalVars"));
26 let domSectValues = (document.getElementById("sectValues"));
27 let domListValues = (document.getElementById("listValues"));
28 let domFnProto = (document.getElementById("fnProto"));
29 let domFnProtoCode = (document.getElementById("fnProtoCode"));
30 let domSectParams = (document.getElementById("sectParams"));
31 let domListParams = (document.getElementById("listParams"));
32 let domTldDocs = (document.getElementById("tldDocs"));
33 let domSectFnErrors = (document.getElementById("sectFnErrors"));
34 let domListFnErrors = (document.getElementById("listFnErrors"));
35 let domTableFnErrors =(document.getElementById("tableFnErrors"));
36 let domFnErrorsAnyError = (document.getElementById("fnErrorsAnyError"));
37 let domFnExamples = (document.getElementById("fnExamples"));
38 // let domListFnExamples = (document.getElementById("listFnExamples"));
39 let domFnNoExamples = (document.getElementById("fnNoExamples"));
40 let domDeclNoRef = (document.getElementById("declNoRef"));
41 let domSearch = (document.getElementById("search"));
42 let domSectSearchResults = (document.getElementById("sectSearchResults"));
43
44 let domListSearchResults = (document.getElementById("listSearchResults"));
45 let domSectSearchNoResults = (document.getElementById("sectSearchNoResults"));
46 let domSectInfo = (document.getElementById("sectInfo"));
47 // let domTdTarget = (document.getElementById("tdTarget"));
48 let domPrivDeclsBox = (document.getElementById("privDeclsBox"));
49 let domTdZigVer = (document.getElementById("tdZigVer"));
50 let domHdrName = (document.getElementById("hdrName"));
51 let domHelpModal = (document.getElementById("helpDialog"));
52
53
54 let searchTimer = null;
55
56
57 let escapeHtmlReplacements = { "&": "&amp;", '"': "&quot;", "<": "&lt;", ">": "&gt;" };
58
59 let typeKinds = (indexTypeKinds());
60 let typeTypeId = (findTypeTypeId());
61 let pointerSizeEnum = { One: 0, Many: 1, Slice: 2, C: 3 };
6262
6363 // for each package, is an array with packages to get to this one
64 var canonPkgPaths = computeCanonicalPackagePaths();
64 let canonPkgPaths = computeCanonicalPackagePaths();
65
66
67
6568 // for each decl, is an array with {declNames, pkgNames} to get to this one
66 var canonDeclPaths = null; // lazy; use getCanonDeclPath
69
70 let canonDeclPaths = null; // lazy; use getCanonDeclPath
71
6772 // for each type, is an array with {declNames, pkgNames} to get to this one
68 var canonTypeDecls = null; // lazy; use getCanonTypeDecl
73
74 let canonTypeDecls = null; // lazy; use getCanonTypeDecl
6975
70 var curNav = {
76
77
78
79 let curNav = {
80 showPrivDecls: false,
7181 // each element is a package name, e.g. @import("a") then within there @import("b")
7282 // starting implicitly from root package
7383 pkgNames: [],
......@@ -82,27 +92,43 @@
8292 // (a, b, c, d) comptime call; result is the value the docs refer to
8393 callName: null,
8494 };
85 var curNavSearch = "";
86 var curSearchIndex = -1;
87 var imFeelingLucky = false;
8895
89 var rootIsStd = detectRootIsStd();
96 let curNavSearch = "";
97 let curSearchIndex = -1;
98 let imFeelingLucky = false;
99
100 let rootIsStd = detectRootIsStd();
90101
91102 // map of decl index to list of non-generic fn indexes
92 var nodesToFnsMap = indexNodesToFns();
103 // let nodesToFnsMap = indexNodesToFns();
93104 // map of decl index to list of comptime fn calls
94 var nodesToCallsMap = indexNodesToCalls();
105 // let nodesToCallsMap = indexNodesToCalls();
95106
96107 domSearch.addEventListener('keydown', onSearchKeyDown, false);
97 domSectSearchAllResultsLink.addEventListener('click', onClickSearchShowAllResults, false);
98
108 domPrivDeclsBox.addEventListener('change', function() {
109 if (this.checked != curNav.showPrivDecls) {
110 if (this.checked && location.hash.length > 1 && location.hash[1] != '*'){
111 location.hash = "#*" + location.hash.substring(1);
112 return;
113 }
114 if (!this.checked && location.hash.length > 1 && location.hash[1] == '*') {
115 location.hash = "#" + location.hash.substring(2);
116 return;
117 }
118 }
119 }, false);
120
121 if (location.hash == "") {
122 location.hash = "#root";
123 }
124
99125 window.addEventListener('hashchange', onHashChange, false);
100126 window.addEventListener('keydown', onWindowKeyDown, false);
101127 onHashChange();
102128
103129 function renderTitle() {
104 var list = curNav.pkgNames.concat(curNav.declNames);
105 var suffix = " - Zig";
130 let list = curNav.pkgNames.concat(curNav.declNames);
131 let suffix = " - Zig";
106132 if (list.length === 0) {
107133 if (rootIsStd) {
108134 document.title = "std" + suffix;
......@@ -114,20 +140,221 @@
114140 }
115141 }
116142
143
144 function isDecl(x) {
145 return "value" in x;
146 }
147
148
149 function isType(x) {
150 return "kind" in x && !("value" in x);
151 }
152
153
154 function isContainerType(x) {
155 return isType(x) && typeKindIsContainer((x).kind) ;
156 }
157
158
159 function typeShorthandName(expr) {
160 let resolvedExpr = resolveValue({expr: expr});
161 if (!("type" in resolvedExpr)) {
162 return null;
163 }
164 let type = (zigAnalysis.types[resolvedExpr.type]);
165
166 outer: for (let i = 0; i < 10000; i += 1) {
167 switch (type.kind) {
168 case typeKinds.Optional:
169 case typeKinds.Pointer:
170 let child = (type).child;
171 let resolvedChild = resolveValue(child);
172 if ("type" in resolvedChild) {
173 type = zigAnalysis.types[resolvedChild.type];
174 continue;
175 } else {
176 return null;
177 }
178 default:
179 break outer;
180 }
181
182 if (i == 9999) throw "Exhausted typeShorthandName quota";
183 }
184
185
186
187 let name = undefined;
188 if (type.kind === typeKinds.Struct) {
189 name = "struct";
190 } else if (type.kind === typeKinds.Enum) {
191 name = "enum";
192 } else if (type.kind === typeKinds.Union) {
193 name = "union";
194 } else {
195 console.log("TODO: unhalndled case in typeShortName");
196 return null;
197 }
198
199 return escapeHtml(name);
200 }
201
202
203 function typeKindIsContainer(typeKind) {
204 return typeKind === typeKinds.Struct ||
205 typeKind === typeKinds.Union ||
206 typeKind === typeKinds.Enum;
207 }
208
209
210 function declCanRepresentTypeKind(typeKind) {
211 return typeKind === typeKinds.ErrorSet || typeKindIsContainer(typeKind);
212 }
213
214 //
215 // function findCteInRefPath(path) {
216 // for (let i = path.length - 1; i >= 0; i -= 1) {
217 // const ref = path[i];
218 // if ("string" in ref) continue;
219 // if ("comptimeExpr" in ref) return ref;
220 // if ("refPath" in ref) return findCteInRefPath(ref.refPath);
221 // return null;
222 // }
223
224 // return null;
225 // }
226
227
228 function resolveValue(value) {
229 let i = 0;
230 while(i < 1000) {
231 i += 1;
232
233 if ("refPath" in value.expr) {
234 value = {expr: value.expr.refPath[value.expr.refPath.length -1]};
235 continue;
236 }
237
238 if ("declRef" in value.expr) {
239 value = zigAnalysis.decls[value.expr.declRef].value;
240 continue;
241 }
242
243 if ("as" in value.expr) {
244 value = {
245 typeRef: zigAnalysis.exprs[value.expr.as.typeRefArg],
246 expr: zigAnalysis.exprs[value.expr.as.exprArg],
247 };
248 continue;
249 }
250
251 return value;
252
253 }
254 console.assert(false);
255 return ({});
256 }
257
258
259// function typeOfDecl(decl){
260// return decl.value.typeRef;
261//
262// let i = 0;
263// while(i < 1000) {
264// i += 1;
265// console.assert(isDecl(decl));
266// if ("type" in decl.value) {
267// return ({ type: typeTypeId });
268// }
269//
270//// if ("string" in decl.value) {
271//// return ({ type: {
272//// kind: typeKinds.Pointer,
273//// size: pointerSizeEnum.One,
274//// child: });
275//// }
276//
277// if ("refPath" in decl.value) {
278// decl = ({
279// value: decl.value.refPath[decl.value.refPath.length -1]
280// });
281// continue;
282// }
283//
284// if ("declRef" in decl.value) {
285// decl = zigAnalysis.decls[decl.value.declRef];
286// continue;
287// }
288//
289// if ("int" in decl.value) {
290// return decl.value.int.typeRef;
291// }
292//
293// if ("float" in decl.value) {
294// return decl.value.float.typeRef;
295// }
296//
297// if ("array" in decl.value) {
298// return decl.value.array.typeRef;
299// }
300//
301// if ("struct" in decl.value) {
302// return decl.value.struct.typeRef;
303// }
304//
305// if ("comptimeExpr" in decl.value) {
306// const cte = zigAnalysis.comptimeExprs[decl.value.comptimeExpr];
307// return cte.typeRef;
308// }
309//
310// if ("call" in decl.value) {
311// const fn_call = zigAnalysis.calls[decl.value.call];
312// let fn_decl = undefined;
313// if ("declRef" in fn_call.func) {
314// fn_decl = zigAnalysis.decls[fn_call.func.declRef];
315// } else if ("refPath" in fn_call.func) {
316// console.assert("declRef" in fn_call.func.refPath[fn_call.func.refPath.length -1]);
317// fn_decl = zigAnalysis.decls[fn_call.func.refPath[fn_call.func.refPath.length -1].declRef];
318// } else throw {};
319//
320// const fn_decl_value = resolveValue(fn_decl.value);
321// console.assert("type" in fn_decl_value); //TODO handle comptimeExpr
322// const fn_type = (zigAnalysis.types[fn_decl_value.type]);
323// console.assert(fn_type.kind === typeKinds.Fn);
324// return fn_type.ret;
325// }
326//
327// if ("void" in decl.value) {
328// return ({ type: typeTypeId });
329// }
330//
331// if ("bool" in decl.value) {
332// return ({ type: typeKinds.Bool });
333// }
334//
335// console.log("TODO: handle in `typeOfDecl` more cases: ", decl);
336// console.assert(false);
337// throw {};
338// }
339// console.assert(false);
340// return ({});
341// }
342
117343 function render() {
118344 domStatus.classList.add("hidden");
119345 domFnProto.classList.add("hidden");
120346 domSectParams.classList.add("hidden");
121347 domTldDocs.classList.add("hidden");
348 domSectMainPkg.classList.add("hidden");
122349 domSectPkgs.classList.add("hidden");
123350 domSectTypes.classList.add("hidden");
351 domSectTests.classList.add("hidden");
124352 domSectNamespaces.classList.add("hidden");
125353 domSectErrSets.classList.add("hidden");
126354 domSectFns.classList.add("hidden");
127355 domSectFields.classList.add("hidden");
128356 domSectSearchResults.classList.add("hidden");
129357 domSectSearchNoResults.classList.add("hidden");
130 domSectSearchAllResultsLink.classList.add("hidden");
131358 domSectInfo.classList.add("hidden");
132359 domHdrName.classList.add("hidden");
133360 domSectNav.classList.add("hidden");
......@@ -144,15 +371,17 @@
144371 renderInfo();
145372 renderPkgList();
146373
374 domPrivDeclsBox.checked = curNav.showPrivDecls;
375
147376 if (curNavSearch !== "") {
148377 return renderSearch();
149378 }
150379
151 var rootPkg = zigAnalysis.packages[zigAnalysis.rootPkg];
152 var pkg = rootPkg;
380 let rootPkg = zigAnalysis.packages[zigAnalysis.rootPkg];
381 let pkg = rootPkg;
153382 curNav.pkgObjs = [pkg];
154 for (var i = 0; i < curNav.pkgNames.length; i += 1) {
155 var childPkg = zigAnalysis.packages[pkg.table[curNav.pkgNames[i]]];
383 for (let i = 0; i < curNav.pkgNames.length; i += 1) {
384 let childPkg = zigAnalysis.packages[pkg.table[curNav.pkgNames[i]]];
156385 if (childPkg == null) {
157386 return render404();
158387 }
......@@ -160,52 +389,68 @@
160389 curNav.pkgObjs.push(pkg);
161390 }
162391
163 var decl = zigAnalysis.types[pkg.main];
164 curNav.declObjs = [decl];
165 for (var i = 0; i < curNav.declNames.length; i += 1) {
166 var childDecl = findSubDecl(decl, curNav.declNames[i]);
392
393 let currentType = zigAnalysis.types[pkg.main];
394 curNav.declObjs = [currentType];
395 for (let i = 0; i < curNav.declNames.length; i += 1) {
396
397
398 let childDecl = findSubDecl((currentType), curNav.declNames[i]);
167399 if (childDecl == null) {
168400 return render404();
169401 }
170 var container = getDeclContainerType(childDecl);
171 if (container == null) {
172 if (i + 1 === curNav.declNames.length) {
173 curNav.declObjs.push(childDecl);
174 break;
175 } else {
176 return render404();
402
403 let childDeclValue = resolveValue((childDecl).value).expr;
404 if ("type" in childDeclValue) {
405
406 const t = zigAnalysis.types[childDeclValue.type];
407 if (t.kind != typeKinds.Fn) {
408 childDecl = t;
177409 }
178410 }
179 decl = container;
180 curNav.declObjs.push(decl);
411
412 currentType = (childDecl);
413 curNav.declObjs.push(currentType);
181414 }
182415
183416 renderNav();
184417
185 var lastDecl = curNav.declObjs[curNav.declObjs.length - 1];
186 if (lastDecl.pubDecls != null) {
187 renderContainer(lastDecl);
188 }
189 if (lastDecl.kind == null) {
190 return renderUnknownDecl(lastDecl);
191 } else if (lastDecl.kind === 'var') {
192 return renderVar(lastDecl);
193 } else if (lastDecl.kind === 'const' && lastDecl.type != null) {
194 var typeObj = zigAnalysis.types[lastDecl.type];
195 if (typeObj.kind === typeKinds.Fn) {
196 return renderFn(lastDecl);
197 } else {
198 return renderValue(lastDecl);
418 let last = curNav.declObjs[curNav.declObjs.length - 1];
419 let lastIsDecl = isDecl(last);
420 let lastIsType = isType(last);
421 let lastIsContainerType = isContainerType(last);
422
423 if (lastIsContainerType) {
424 return renderContainer((last));
425 }
426
427 if (!lastIsDecl && !lastIsType) {
428 return renderUnknownDecl((last));
429 }
430
431 if (lastIsType) {
432 return renderType((last));
433 }
434
435 if (lastIsDecl && last.kind === 'var') {
436 return renderVar((last));
437 }
438
439 if (lastIsDecl && last.kind === 'const') {
440 let typeObj = zigAnalysis.types[resolveValue((last).value).expr.type];
441 if (typeObj && typeObj.kind === typeKinds.Fn) {
442 return renderFn((last));
199443 }
200 } else {
201 renderType(lastDecl);
444
445 return renderValue((last));
202446 }
203447 }
204448
449
205450 function renderUnknownDecl(decl) {
206451 domDeclNoRef.classList.remove("hidden");
207452
208 var docs = zigAnalysis.astNodes[decl.src].docs;
453 let docs = zigAnalysis.astNodes[decl.src].docs;
209454 if (docs != null) {
210455 domTldDocs.innerHTML = markdown(docs);
211456 } else {
......@@ -214,85 +459,130 @@
214459 domTldDocs.classList.remove("hidden");
215460 }
216461
462
217463 function typeIsErrSet(typeIndex) {
218 var typeObj = zigAnalysis.types[typeIndex];
464 let typeObj = zigAnalysis.types[typeIndex];
219465 return typeObj.kind === typeKinds.ErrorSet;
220466 }
221467
468
222469 function typeIsStructWithNoFields(typeIndex) {
223 var typeObj = zigAnalysis.types[typeIndex];
470 let typeObj = zigAnalysis.types[typeIndex];
224471 if (typeObj.kind !== typeKinds.Struct)
225472 return false;
226 return typeObj.fields == null || typeObj.fields.length === 0;
473 return (typeObj).fields.length == 0;
227474 }
228475
476
229477 function typeIsGenericFn(typeIndex) {
230 var typeObj = zigAnalysis.types[typeIndex];
478 let typeObj = zigAnalysis.types[typeIndex];
231479 if (typeObj.kind !== typeKinds.Fn) {
232480 return false;
233481 }
234 return typeObj.generic;
482 return (typeObj).generic_ret != null;
235483 }
236484
485
237486 function renderFn(fnDecl) {
238 domFnProtoCode.innerHTML = typeIndexName(fnDecl.type, true, true, fnDecl);
487 if ("refPath" in fnDecl.value.expr) {
488 let last = fnDecl.value.expr.refPath.length - 1;
489 let lastExpr = fnDecl.value.expr.refPath[last];
490 console.assert("declRef" in lastExpr);
491 fnDecl = zigAnalysis.decls[lastExpr.declRef];
492 }
239493
240 var docsSource = null;
241 var srcNode = zigAnalysis.astNodes[fnDecl.src];
494 let value = resolveValue(fnDecl.value);
495 console.assert("type" in value.expr);
496 let typeObj = (zigAnalysis.types[value.expr.type]);
497
498 domFnProtoCode.innerHTML = exprName(value.expr, {
499 wantHtml: true,
500 wantLink: true,
501 fnDecl,
502 });
503
504 let docsSource = null;
505 let srcNode = zigAnalysis.astNodes[fnDecl.src];
242506 if (srcNode.docs != null) {
243507 docsSource = srcNode.docs;
244508 }
245509
246 var typeObj = zigAnalysis.types[fnDecl.type];
247510 renderFnParamDocs(fnDecl, typeObj);
248511
249 var errSetTypeIndex = null;
250 if (typeObj.ret != null) {
251 var retType = zigAnalysis.types[typeObj.ret];
512 let retExpr = resolveValue({expr:typeObj.ret}).expr;
513 if ("type" in retExpr) {
514 let retIndex = retExpr.type;
515 let errSetTypeIndex = (null);
516 let retType = zigAnalysis.types[retIndex];
252517 if (retType.kind === typeKinds.ErrorSet) {
253 errSetTypeIndex = typeObj.ret;
518 errSetTypeIndex = retIndex;
254519 } else if (retType.kind === typeKinds.ErrorUnion) {
255 errSetTypeIndex = retType.err;
520 errSetTypeIndex = (retType).err.type;
521 }
522 if (errSetTypeIndex != null) {
523 let errSetType = (zigAnalysis.types[errSetTypeIndex]);
524 renderErrorSet(errSetType);
256525 }
257526 }
258 if (errSetTypeIndex != null) {
259 var errSetType = zigAnalysis.types[errSetTypeIndex];
260 renderErrorSet(errSetType);
261 }
262
263 var fnObj = zigAnalysis.fns[fnDecl.value];
264 var protoSrcIndex = fnObj.src;
265 if (typeIsGenericFn(fnDecl.type)) {
266 var instantiations = nodesToFnsMap[protoSrcIndex];
267 var calls = nodesToCallsMap[protoSrcIndex];
268 if (instantiations == null && calls == null) {
269 domFnNoExamples.classList.remove("hidden");
270 } else if (calls != null) {
271 if (fnObj.combined === undefined) fnObj.combined = allCompTimeFnCallsResult(calls);
272 if (fnObj.combined != null) {
273 renderContainer(fnObj.combined, calls.map(function (call) { return zigAnalysis.calls[call].result.value }));
274 }
275527
276 var domListFnExamplesFragment = createDomListFragment(calls.length, '<li></li>');
528 let protoSrcIndex = fnDecl.src;
529 if (typeIsGenericFn(value.expr.type)) {
530 // does the generic_ret contain a container?
531 var resolvedGenericRet = resolveValue({expr: typeObj.generic_ret});
532
533 if ("call" in resolvedGenericRet.expr){
534 let call = zigAnalysis.calls[resolvedGenericRet.expr.call];
535 let resolvedFunc = resolveValue({expr: call.func});
536 if (!("type" in resolvedFunc.expr)) return;
537 let callee = zigAnalysis.types[resolvedFunc.expr.type];
538 if (!callee.generic_ret) return;
539 resolvedGenericRet = resolveValue({expr: callee.generic_ret});
540 }
277541
278 for (var callI = 0; callI < calls.length; callI += 1) {
279 var liDom = domListFnExamplesFragment.children[callI];
280 liDom.innerHTML = getCallHtml(fnDecl, calls[callI]);
281 }
542 // TODO: see if unwrapping the `as` here is a good idea or not.
543 if ("as" in resolvedGenericRet.expr) {
544 resolvedGenericRet = {
545 expr: zigAnalysis.exprs[resolvedGenericRet.expr.as.exprArg]
546 };
547 }
282548
283 domListFnExamples.innerHTML = "";
284 domListFnExamples.appendChild(domListFnExamplesFragment);
285 domFnExamples.classList.remove("hidden");
286 } else if (instantiations != null) {
287 // TODO
549 if (!("type" in resolvedGenericRet.expr)) return;
550 const genericType = zigAnalysis.types[resolvedGenericRet.expr.type];
551 if (isContainerType(genericType)) {
552 renderContainer(genericType)
288553 }
554
555
556
557
558
559 // old code
560 // let instantiations = nodesToFnsMap[protoSrcIndex];
561 // let calls = nodesToCallsMap[protoSrcIndex];
562 // if (instantiations == null && calls == null) {
563 // domFnNoExamples.classList.remove("hidden");
564 // } else if (calls != null) {
565 // // if (fnObj.combined === undefined) fnObj.combined = allCompTimeFnCallsResult(calls);
566 // if (fnObj.combined != null) renderContainer(fnObj.combined);
567
568 // resizeDomList(domListFnExamples, calls.length, '<li></li>');
569
570 // for (let callI = 0; callI < calls.length; callI += 1) {
571 // let liDom = domListFnExamples.children[callI];
572 // liDom.innerHTML = getCallHtml(fnDecl, calls[callI]);
573 // }
574
575 // domFnExamples.classList.remove("hidden");
576 // } else if (instantiations != null) {
577 // // TODO
578 // }
289579 } else {
290580
291581 domFnExamples.classList.add("hidden");
292582 domFnNoExamples.classList.add("hidden");
293583 }
294584
295 var protoSrcNode = zigAnalysis.astNodes[protoSrcIndex];
585 let protoSrcNode = zigAnalysis.astNodes[protoSrcIndex];
296586 if (docsSource == null && protoSrcNode != null && protoSrcNode.docs != null) {
297587 docsSource = protoSrcNode.docs;
298588 }
......@@ -303,17 +593,17 @@
303593 domFnProto.classList.remove("hidden");
304594 }
305595
596
306597 function renderFnParamDocs(fnDecl, typeObj) {
307 var docCount = 0;
598 let docCount = 0;
308599
309 var fnObj = zigAnalysis.fns[fnDecl.value];
310 var fnNode = zigAnalysis.astNodes[fnObj.src];
311 var fields = fnNode.fields;
312 var isVarArgs = fnNode.varArgs;
600 let fnNode = zigAnalysis.astNodes[fnDecl.src];
601 let fields = (fnNode.fields);
602 let isVarArgs = fnNode.varArgs;
313603
314 for (var i = 0; i < fields.length; i += 1) {
315 var field = fields[i];
316 var fieldNode = zigAnalysis.astNodes[field];
604 for (let i = 0; i < fields.length; i += 1) {
605 let field = fields[i];
606 let fieldNode = zigAnalysis.astNodes[field];
317607 if (fieldNode.docs != null) {
318608 docCount += 1;
319609 }
......@@ -322,56 +612,55 @@
322612 return;
323613 }
324614
325 var domListParamsFragment = createDomListFragment(docCount, '<div></div>');
326 var domIndex = 0;
615 resizeDomList(domListParams, docCount, '<div></div>');
616 let domIndex = 0;
327617
328 for (var i = 0; i < fields.length; i += 1) {
329 var field = fields[i];
330 var fieldNode = zigAnalysis.astNodes[field];
618 for (let i = 0; i < fields.length; i += 1) {
619 let field = fields[i];
620 let fieldNode = zigAnalysis.astNodes[field];
331621 if (fieldNode.docs == null) {
332622 continue;
333623 }
334 var divDom = domListParamsFragment.children[domIndex];
624 let divDom = domListParams.children[domIndex];
335625 domIndex += 1;
336 var argTypeIndex = typeObj.args[i];
337626
338 var html = '<pre>' + escapeHtml(fieldNode.name) + ": ";
339 if (isVarArgs && i === typeObj.args.length - 1) {
627
628 let value = typeObj.params[i];
629 let html = '<pre>' + escapeHtml((fieldNode.name)) + ": ";
630 if (isVarArgs && i === typeObj.params.length - 1) {
340631 html += '...';
341 } else if (argTypeIndex != null) {
342 html += typeIndexName(argTypeIndex, true, true);
343632 } else {
344 html += '<span class="tok-kw">var</span>';
633 let name = exprName(value, {wantHtml: false, wantLink: false});
634 html += '<span class="tok-kw">' + name + '</span>';
345635 }
346636
347637 html += ',</pre>';
348638
349 var docs = fieldNode.docs;
639 let docs = fieldNode.docs;
350640 if (docs != null) {
351641 html += markdown(docs);
352642 }
353643 divDom.innerHTML = html;
354644 }
355
356 domListParams.innerHTML = "";
357 domListParams.appendChild(domListParamsFragment);
358645 domSectParams.classList.remove("hidden");
359646 }
360647
361648 function renderNav() {
362 var len = curNav.pkgNames.length + curNav.declNames.length;
363 var domListNavFragment = createDomListFragment(len, '<li><a href="#"></a></li>');
364 var list = [];
365 var hrefPkgNames = [];
366 var hrefDeclNames = [];
367 for (var i = 0; i < curNav.pkgNames.length; i += 1) {
649 let len = curNav.pkgNames.length + curNav.declNames.length;
650 resizeDomList(domListNav, len, '<li><a href="#"></a></li>');
651 let list = [];
652 let hrefPkgNames = [];
653 let hrefDeclNames = ([]);
654 for (let i = 0; i < curNav.pkgNames.length; i += 1) {
368655 hrefPkgNames.push(curNav.pkgNames[i]);
656 let name = curNav.pkgNames[i];
657 if (name == "root") name = zigAnalysis.rootPkgName;
369658 list.push({
370 name: curNav.pkgNames[i],
659 name: name,
371660 link: navLink(hrefPkgNames, hrefDeclNames),
372661 });
373662 }
374 for (var i = 0; i < curNav.declNames.length; i += 1) {
663 for (let i = 0; i < curNav.declNames.length; i += 1) {
375664 hrefDeclNames.push(curNav.declNames[i]);
376665 list.push({
377666 name: curNav.declNames[i],
......@@ -379,9 +668,9 @@
379668 });
380669 }
381670
382 for (var i = 0; i < list.length; i += 1) {
383 var liDom = domListNavFragment.children[i];
384 var aDom = liDom.children[0];
671 for (let i = 0; i < list.length; i += 1) {
672 let liDom = domListNav.children[i];
673 let aDom = liDom.children[0];
385674 aDom.textContent = list[i].name;
386675 aDom.setAttribute('href', list[i].link);
387676 if (i + 1 == list.length) {
......@@ -391,14 +680,12 @@
391680 }
392681 }
393682
394 domListNav.innerHTML = "";
395 domListNav.appendChild(domListNavFragment);
396683 domSectNav.classList.remove("hidden");
397684 }
398685
399686 function renderInfo() {
400687 domTdZigVer.textContent = zigAnalysis.params.zigVersion;
401 domTdTarget.textContent = zigAnalysis.params.builds[0].target;
688 //domTdTarget.textContent = zigAnalysis.params.builds[0].target;
402689
403690 domSectInfo.classList.remove("hidden");
404691 }
......@@ -409,26 +696,39 @@
409696 }
410697
411698 function renderPkgList() {
412 var rootPkg = zigAnalysis.packages[zigAnalysis.rootPkg];
413 var list = [];
414 for (var key in rootPkg.table) {
415 if (key === "root" && rootIsStd) continue;
416 var pkgIndex = rootPkg.table[key];
699 let rootPkg = zigAnalysis.packages[zigAnalysis.rootPkg];
700 let list = [];
701 for (let key in rootPkg.table) {
702 let pkgIndex = rootPkg.table[key];
417703 if (zigAnalysis.packages[pkgIndex] == null) continue;
704 if (key == zigAnalysis.params.rootName) continue;
418705 list.push({
419706 name: key,
420707 pkg: pkgIndex,
421708 });
422709 }
710
711 {
712 let aDom = domSectMainPkg.children[1].children[0].children[0];
713 aDom.textContent = zigAnalysis.rootPkgName;
714 aDom.setAttribute('href', navLinkPkg(zigAnalysis.rootPkg));
715 if (zigAnalysis.params.rootName === curNav.pkgNames[0]) {
716 aDom.classList.add("active");
717 } else {
718 aDom.classList.remove("active");
719 }
720 domSectMainPkg.classList.remove("hidden");
721 }
722
423723 list.sort(function(a, b) {
424724 return operatorCompare(a.name.toLowerCase(), b.name.toLowerCase());
425725 });
426726
427727 if (list.length !== 0) {
428 var domListPkgsFragment = createDomListFragment(list.length, '<li><a href="#"></a></li>');
429 for (var i = 0; i < list.length; i += 1) {
430 var liDom = domListPkgsFragment.children[i];
431 var aDom = liDom.children[0];
728 resizeDomList(domListPkgs, list.length, '<li><a href="#"></a></li>');
729 for (let i = 0; i < list.length; i += 1) {
730 let liDom = domListPkgs.children[i];
731 let aDom = liDom.children[0];
432732 aDom.textContent = list[i].name;
433733 aDom.setAttribute('href', navLinkPkg(list[i].pkg));
434734 if (list[i].name === curNav.pkgNames[0]) {
......@@ -438,488 +738,1338 @@
438738 }
439739 }
440740
441 domListPkgs.innerHTML = "";
442 domListPkgs.appendChild(domListPkgsFragment);
443741 domSectPkgs.classList.remove("hidden");
444742 }
445743 }
446744
745
746
447747 function navLink(pkgNames, declNames, callName) {
748 let base = '#';
749 if (curNav.showPrivDecls) {
750 base += "*";
751 }
752
448753 if (pkgNames.length === 0 && declNames.length === 0) {
449 return '#';
754 return base;
450755 } else if (declNames.length === 0 && callName == null) {
451 return '#' + pkgNames.join('.');
756 return base + pkgNames.join('.');
452757 } else if (callName == null) {
453 return '#' + pkgNames.join('.') + ';' + declNames.join('.');
758 return base + pkgNames.join('.') + ';' + declNames.join('.');
454759 } else {
455 return '#' + pkgNames.join('.') + ';' + declNames.join('.') + ';' + callName;
760 return base + pkgNames.join('.') + ';' + declNames.join('.') + ';' + callName;
456761 }
457762 }
458763
764
459765 function navLinkPkg(pkgIndex) {
460766 return navLink(canonPkgPaths[pkgIndex], []);
461767 }
462768
769
463770 function navLinkDecl(childName) {
464771 return navLink(curNav.pkgNames, curNav.declNames.concat([childName]));
465772 }
466773
467 function navLinkCall(callObj) {
468 var declNamesCopy = curNav.declNames.concat([]);
469 var callName = declNamesCopy.pop();
470
471 callName += '(';
472 for (var arg_i = 0; arg_i < callObj.args.length; arg_i += 1) {
473 if (arg_i !== 0) callName += ',';
474 var argObj = callObj.args[arg_i];
475 callName += getValueText(argObj.type, argObj.value, false, false);
476 }
477 callName += ')';
478
479 declNamesCopy.push(callName);
480 return navLink(curNav.pkgNames, declNamesCopy);
481 }
482
483 function createDomListFragment(desiredLen, templateHtml) {
484 var domTemplate = document.createElement("template");
485 domTemplate.innerHTML = templateHtml.repeat(desiredLen);
486 return domTemplate.content;
487 }
488
489 function typeIndexName(typeIndex, wantHtml, wantLink, fnDecl, linkFnNameDecl, thisTypes) {
490 if(thisTypes && thisTypes.includes(typeIndex)){
491 return token('@This', tokenKinds.Builtin, wantHtml) + '()';
492 }
493 var typeObj = zigAnalysis.types[typeIndex];
494 var declNameOk = declCanRepresentTypeKind(typeObj.kind);
495 if (wantLink) {
496 var declIndex = getCanonTypeDecl(typeIndex);
497 var declPath = getCanonDeclPath(declIndex);
498 if (declPath == null) {
499 return typeName(typeObj, wantHtml, wantLink, fnDecl, linkFnNameDecl, thisTypes);
500 }
501 var name = (wantLink && declCanRepresentTypeKind(typeObj.kind)) ?
502 declPath.declNames[declPath.declNames.length - 1] :
503 typeName(typeObj, wantHtml, false, fnDecl, linkFnNameDecl, thisTypes);
504 if (wantLink && wantHtml) {
505 return '<a href="' + navLink(declPath.pkgNames, declPath.declNames) + '">' + name + '</a>';
774 //
775 // function navLinkCall(callObj) {
776 // let declNamesCopy = curNav.declNames.concat([]);
777 // let callName = (declNamesCopy.pop());
778
779 // callName += '(';
780 // for (let arg_i = 0; arg_i < callObj.args.length; arg_i += 1) {
781 // if (arg_i !== 0) callName += ',';
782 // let argObj = callObj.args[arg_i];
783 // callName += getValueText(argObj, argObj, false, false);
784 // }
785 // callName += ')';
786
787 // declNamesCopy.push(callName);
788 // return navLink(curNav.pkgNames, declNamesCopy);
789 // }
790
791
792 function resizeDomListDl(dlDom, desiredLen) {
793 // add the missing dom entries
794 for (let i = dlDom.childElementCount / 2; i < desiredLen; i += 1) {
795 dlDom.insertAdjacentHTML('beforeend', '<dt></dt><dd></dd>');
796 }
797 // remove extra dom entries
798 while (desiredLen < dlDom.childElementCount / 2) {
799 dlDom.removeChild(dlDom.lastChild);
800 dlDom.removeChild(dlDom.lastChild);
801 }
802 }
803
804
805 function resizeDomList(listDom, desiredLen, templateHtml) {
806 // add the missing dom entries
807 for (let i = listDom.childElementCount; i < desiredLen; i += 1) {
808 listDom.insertAdjacentHTML('beforeend', templateHtml);
809 }
810 // remove extra dom entries
811 while (desiredLen < listDom.childElementCount) {
812 listDom.removeChild(listDom.lastChild);
813 }
814 }
815
816 function walkResultTypeRef(wr) {
817 if (wr.typeRef) return wr.typeRef;
818 let resolved = resolveValue(wr);
819 if (wr === resolved) {
820 return {type: 0};
821 }
822 return walkResultTypeRef(resolved);
823 }
824
825 function exprName(expr, opts) {
826 switch (Object.keys(expr)[0]) {
827 default: throw "oh no";
828 case "&": {
829 return "&" + exprName(zigAnalysis.exprs[expr["&"]]);
830 }
831 case "compileError": {
832 let compileError = expr.compileError;
833 return compileError;
834 }
835 case "enumLiteral": {
836 let literal = expr.enumLiteral;
837 return "." + literal;
838 }
839 case "void": {
840 return "void";
841 }
842 case "slice":{
843 let payloadHtml = "";
844 const lhsExpr = zigAnalysis.exprs[expr.slice.lhs];
845 const startExpr = zigAnalysis.exprs[expr.slice.start];
846 let decl = exprName(lhsExpr);
847 let start = exprName(startExpr);
848 let end = "";
849 let sentinel = "";
850 if (expr.slice['end']) {
851 const endExpr = zigAnalysis.exprs[expr.slice.end];
852 let end_ = exprName(endExpr);
853 end += end_;
854 }
855 if (expr.slice['sentinel']) {
856 const sentinelExpr = zigAnalysis.exprs[expr.slice.sentinel];
857 let sentinel_ = exprName(sentinelExpr);
858 sentinel += " :" + sentinel_;
859 }
860 payloadHtml += decl + "["+ start + ".." + end + sentinel + "]";
861 return payloadHtml;
862 }
863 case "sliceIndex": {
864 const sliceIndex = zigAnalysis.exprs[expr.sliceIndex];
865 return exprName(sliceIndex, opts);
866 }
867 case "cmpxchg":{
868 const typeIndex = zigAnalysis.exprs[expr.cmpxchg.type];
869 const ptrIndex = zigAnalysis.exprs[expr.cmpxchg.ptr];
870 const expectedValueIndex = zigAnalysis.exprs[expr.cmpxchg.expected_value];
871 const newValueIndex = zigAnalysis.exprs[expr.cmpxchg.new_value];
872 const successOrderIndex = zigAnalysis.exprs[expr.cmpxchg.success_order];
873 const failureOrderIndex = zigAnalysis.exprs[expr.cmpxchg.failure_order];
874
875 const type = exprName(typeIndex, opts);
876 const ptr = exprName(ptrIndex, opts);
877 const expectedValue = exprName(expectedValueIndex, opts);
878 const newValue = exprName(newValueIndex, opts);
879 const successOrder = exprName(successOrderIndex, opts);
880 const failureOrder = exprName(failureOrderIndex, opts);
881
882 let fnName = "@";
883
884 switch (expr.cmpxchg.name) {
885 case "cmpxchg_strong": {
886 fnName += "cmpxchgStrong"
887 break;
888 }
889 case "cmpxchg_weak": {
890 fnName += "cmpxchgWeak"
891 break;
892 }
893 default: {
894 console.log("There's only cmpxchg_strong and cmpxchg_weak");
895 }
896 }
897
898 return fnName + "(" + type + ", " + ptr + ", " + expectedValue + ", "+ newValue + ", "+"." +successOrder + ", "+ "." +failureOrder + ")";
899 }
900 case "cmpxchgIndex": {
901 const cmpxchgIndex = zigAnalysis.exprs[expr.cmpxchgIndex];
902 return exprName(cmpxchgIndex, opts);
903 }
904 case "switchOp":{
905 let condExpr = zigAnalysis.exprs[expr.switchOp.cond_index];
906 let ast = zigAnalysis.astNodes[expr.switchOp.ast];
907 let file_name = expr.switchOp.file_name;
908 let outer_decl_index = expr.switchOp.outer_decl;
909 let outer_decl = zigAnalysis.types[outer_decl_index];
910 let line = 0;
911 // console.log(expr.switchOp)
912 // console.log(outer_decl)
913 while (outer_decl_index !== 0 && outer_decl.line_number > 0) {
914 line += outer_decl.line_number;
915 outer_decl_index = outer_decl.outer_decl;
916 outer_decl = zigAnalysis.types[outer_decl_index];
917 // console.log(outer_decl)
918 }
919 line += ast.line + 1;
920 let payloadHtml = "";
921 let cond = exprName(condExpr, opts);
922
923 payloadHtml += "</br>" + "node_name: " + ast.name + "</br>" + "file: " + file_name + "</br>" + "line: " + line + "</br>";
924 payloadHtml += "switch(" + cond + ") {" + "<a href=\"https://github.com/ziglang/zig/tree/master/lib/std/" + file_name + "#L" + line + "\">" +"..." + "</a>}";
925 return payloadHtml;
926 }
927 case "switchIndex": {
928 const switchIndex = zigAnalysis.exprs[expr.switchIndex];
929 return exprName(switchIndex, opts);
930 }
931 case "refPath" : {
932 const declRef = expr.refPath[0].declRef;
933 let name = zigAnalysis.decls[declRef].name;
934 for (let i = 1; i < expr.refPath.length; i++) {
935 let component = undefined;
936 if ("string" in expr.refPath[i]) {
937 component = expr.refPath[i].string;
938 } else {
939 component = exprName(expr.refPath[i]);
940 }
941 name += "." + component;
942 }
943 return name;
944 }
945 case "fieldRef" : {
946 const enumObj = exprName({"type":expr.fieldRef.type} ,opts);
947 const field = zigAnalysis.astNodes[enumObj.ast].fields[expr.fieldRef.index];
948 const name = zigAnalysis.astNodes[field].name;
949 return name
950 }
951 case "enumToInt" : {
952 const enumToInt = zigAnalysis.exprs[expr.enumToInt];
953 return "@enumToInt(" + exprName(enumToInt, opts) + ")";
954 }
955 case "bitSizeOf" : {
956 const bitSizeOf = zigAnalysis.exprs[expr.bitSizeOf];
957 return "@bitSizeOf(" + exprName(bitSizeOf, opts) + ")";
958 }
959 case "sizeOf" : {
960 const sizeOf = zigAnalysis.exprs[expr.sizeOf];
961 return "@sizeOf(" + exprName(sizeOf, opts) + ")";
962 }
963 case "builtinIndex" : {
964 const builtinIndex = zigAnalysis.exprs[expr.builtinIndex];
965 return exprName(builtinIndex, opts);
966 }
967 case "builtin": {
968 const param_expr = zigAnalysis.exprs[expr.builtin.param];
969 let param = exprName(param_expr, opts);
970
971
972 let payloadHtml = "@";
973 switch (expr.builtin.name) {
974 case "align_of": {
975 payloadHtml += "alignOf";
976 break;
977 }
978 case "bool_to_int": {
979 payloadHtml += "boolToInt";
980 break;
981 }
982 case "embed_file": {
983 payloadHtml += "embedFile";
984 break;
985 }
986 case "error_name": {
987 payloadHtml += "errorName";
988 break;
989 }
990 case "panic": {
991 payloadHtml += "panic";
992 break;
993 }
994 case "set_cold": {
995 payloadHtml += "setCold";
996 break;
997 }
998 case "set_runtime_safety": {
999 payloadHtml += "setRuntimeSafety";
1000 break;
1001 }
1002 case "sqrt": {
1003 payloadHtml += "sqrt";
1004 break;
1005 }
1006 case "sin": {
1007 payloadHtml += "sin";
1008 break;
1009 }
1010 case "cos": {
1011 payloadHtml += "cos";
1012 break;
1013 }
1014 case "tan": {
1015 payloadHtml += "tan";
1016 break;
1017 }
1018 case "exp": {
1019 payloadHtml += "exp";
1020 break;
1021 }
1022 case "exp2": {
1023 payloadHtml += "exp2";
1024 break;
1025 }
1026 case "log": {
1027 payloadHtml += "log";
1028 break;
1029 }
1030 case "log2": {
1031 payloadHtml += "log2";
1032 break;
1033 }
1034 case "log10": {
1035 payloadHtml += "log10";
1036 break;
1037 }
1038 case "fabs": {
1039 payloadHtml += "fabs";
1040 break;
1041 }
1042 case "floor": {
1043 payloadHtml += "floor";
1044 break;
1045 }
1046 case "ceil": {
1047 payloadHtml += "ceil";
1048 break;
1049 }
1050 case "trunc": {
1051 payloadHtml += "trunc";
1052 break;
1053 }
1054 case "round": {
1055 payloadHtml += "round";
1056 break;
1057 }
1058 case "tag_name": {
1059 payloadHtml += "tagName";
1060 break;
1061 }
1062 case "reify": {
1063 payloadHtml += "Type";
1064 break;
1065 }
1066 case "type_name": {
1067 payloadHtml += "typeName";
1068 break;
1069 }
1070 case "frame_type": {
1071 payloadHtml += "Frame";
1072 break;
1073 }
1074 case "frame_size": {
1075 payloadHtml += "frameSize";
1076 break;
1077 }
1078 case "ptr_to_int": {
1079 payloadHtml += "ptrToInt";
1080 break;
1081 }
1082 case "error_to_int": {
1083 payloadHtml += "errorToInt";
1084 break;
1085 }
1086 case "int_to_error": {
1087 payloadHtml += "intToError";
1088 break;
1089 }
1090 case "maximum": {
1091 payloadHtml += "maximum";
1092 break;
1093 }
1094 case "minimum": {
1095 payloadHtml += "minimum";
1096 break;
1097 }
1098 case "bit_not": {
1099 return "~" + param;
1100 }
1101 case "clz": {
1102 return "@clz(T" + ", " + param + ")";
1103 }
1104 case "ctz": {
1105 return "@ctz(T" + ", " + param + ")";
1106 }
1107 case "pop_count": {
1108 return "@popCount(T" + ", " + param + ")";
1109 }
1110 case "byte_swap": {
1111 return "@byteSwap(T" + ", " + param + ")";
1112 }
1113 case "bit_reverse": {
1114 return "@bitReverse(T" + ", " + param + ")";
1115 }
1116 default: console.log("builtin function not handled yet or doesn't exist!");
1117 };
1118 return payloadHtml + "(" + param + ")";
1119
1120 }
1121 case "builtinBinIndex" : {
1122 const builtinBinIndex = zigAnalysis.exprs[expr.builtinBinIndex];
1123 return exprName(builtinBinIndex, opts);
1124 }
1125 case "builtinBin": {
1126 const lhsOp = zigAnalysis.exprs[expr.builtinBin.lhs];
1127 const rhsOp = zigAnalysis.exprs[expr.builtinBin.rhs];
1128 let lhs = exprName(lhsOp, opts);
1129 let rhs = exprName(rhsOp, opts);
1130
1131 let payloadHtml = "@";
1132 switch (expr.builtinBin.name) {
1133 case "float_to_int": {
1134 payloadHtml += "floatToInt";
1135 break;
1136 }
1137 case "int_to_float": {
1138 payloadHtml += "intToFloat";
1139 break;
1140 }
1141 case "int_to_ptr": {
1142 payloadHtml += "intToPtr";
1143 break;
1144 }
1145 case "int_to_enum": {
1146 payloadHtml += "intToEnum";
1147 break;
1148 }
1149 case "float_cast": {
1150 payloadHtml += "floatCast";
1151 break;
1152 }
1153 case "int_cast": {
1154 payloadHtml += "intCast";
1155 break;
1156 }
1157 case "ptr_cast": {
1158 payloadHtml += "ptrCast";
1159 break;
1160 }
1161 case "truncate": {
1162 payloadHtml += "truncate";
1163 break;
1164 }
1165 case "align_cast": {
1166 payloadHtml += "alignCast";
1167 break;
1168 }
1169 case "has_decl": {
1170 payloadHtml += "hasDecl";
1171 break;
1172 }
1173 case "has_field": {
1174 payloadHtml += "hasField";
1175 break;
1176 }
1177 case "bit_reverse": {
1178 payloadHtml += "bitReverse";
1179 break;
1180 }
1181 case "div_exact": {
1182 payloadHtml += "divExact";
1183 break;
1184 }
1185 case "div_floor": {
1186 payloadHtml += "divFloor";
1187 break;
1188 }
1189 case "div_trunc": {
1190 payloadHtml += "divTrunc";
1191 break;
1192 }
1193 case "mod": {
1194 payloadHtml += "mod";
1195 break;
1196 }
1197 case "rem": {
1198 payloadHtml += "rem";
1199 break;
1200 }
1201 case "mod_rem": {
1202 payloadHtml += "rem";
1203 break;
1204 }
1205 case "shl_exact": {
1206 payloadHtml += "shlExact";
1207 break;
1208 }
1209 case "shr_exact": {
1210 payloadHtml += "shrExact";
1211 break;
1212 }
1213 case "bitcast" : {
1214 payloadHtml += "bitCast";
1215 break;
1216 }
1217 case "align_cast" : {
1218 payloadHtml += "alignCast";
1219 break;
1220 }
1221 case "vector_type" : {
1222 payloadHtml += "Vector";
1223 break;
1224 }
1225 case "reduce": {
1226 payloadHtml += "reduce";
1227 break;
1228 }
1229 case "splat": {
1230 payloadHtml += "splat";
1231 break;
1232 }
1233 case "offset_of": {
1234 payloadHtml += "offsetOf";
1235 break;
1236 }
1237 case "bit_offset_of": {
1238 payloadHtml += "bitOffsetOf";
1239 break;
1240 }
1241 default: console.log("builtin function not handled yet or doesn't exist!");
1242 };
1243 return payloadHtml + "(" + lhs + ", " + rhs + ")";
1244
1245 }
1246 case "binOpIndex" : {
1247 const binOpIndex = zigAnalysis.exprs[expr.binOpIndex];
1248 return exprName(binOpIndex, opts);
1249 }
1250 case "binOp": {
1251 const lhsOp = zigAnalysis.exprs[expr.binOp.lhs];
1252 const rhsOp = zigAnalysis.exprs[expr.binOp.rhs];
1253 let lhs = exprName(lhsOp, opts);
1254 let rhs = exprName(rhsOp, opts);
1255
1256 let print_lhs = "";
1257 let print_rhs = "";
1258
1259 if (lhsOp['binOpIndex']) {
1260 print_lhs = "(" + lhs + ")";
5061261 } else {
507 return name;
1262 print_lhs = lhs;
1263 }
1264 if (rhsOp['binOpIndex']) {
1265 print_rhs = "(" + rhs + ")";
1266 } else {
1267 print_rhs = rhs;
5081268 }
509 } else {
510 return typeName(typeObj, wantHtml, false, fnDecl, linkFnNameDecl, thisTypes);
511 }
512 }
513
514 function shouldSkipParamName(typeIndex, paramName) {
515 var typeObj = zigAnalysis.types[typeIndex];
516 if (typeObj.kind === typeKinds.Pointer && getPtrSize(typeObj) === pointerSizeEnum.One) {
517 typeIndex = typeObj.elem;
518 }
519 return typeIndexName(typeIndex, false, true).toLowerCase() === paramName;
520 }
521
522 function getPtrSize(typeObj) {
523 return (typeObj.len == null) ? pointerSizeEnum.One : typeObj.len;
524 }
525
526 function getCallHtml(fnDecl, callIndex) {
527 var callObj = zigAnalysis.calls[callIndex];
528
529 // TODO make these links work
530 //var html = '<a href="' + navLinkCall(callObj) + '">' + escapeHtml(fnDecl.name) + '</a>(';
531 var html = escapeHtml(fnDecl.name) + '(';
532 for (var arg_i = 0; arg_i < callObj.args.length; arg_i += 1) {
533 if (arg_i !== 0) html += ', ';
534 var argObj = callObj.args[arg_i];
535 html += getValueText(argObj.type, argObj.value, true, true);
536 }
537 html += ')';
538 return html;
539 }
5401269
541 function getValueText(typeIndex, value, wantHtml, wantLink) {
542 var typeObj = zigAnalysis.types[typeIndex];
543 switch (typeObj.kind) {
544 case typeKinds.Type:
545 return typeIndexName(value, wantHtml, wantLink);
546 case typeKinds.Fn:
547 var fnObj = zigAnalysis.fns[value];
548 var declPath = fnObj.decl && getCanonDeclPath(fnObj.decl);
549 var fnName = declPath ? declPath.declNames.join('.') : '(unknown)';
550
551 if (!wantHtml) {
552 return fnName;
553 }
1270 let operator = "";
5541271
555 var str = '<span class="tok-fn">';
556 if (wantLink && declPath != null) {
557 str += '<a href="' + navLink(declPath.pkgNames, declPath.declNames) + '">';
558 str += escapeHtml(fnName);
559 str += '</a>';
560 } else {
561 str += escapeHtml(fnName);
562 }
563 str += '</span>';
564 return str;
565 case typeKinds.Int:
566 return token(value, tokenKinds.Number, wantHtml);
567 case typeKinds.Optional:
568 if(value === 'null'){
569 return token(value, tokenKinds.Null, wantHtml);
570 } else {
571 console.trace("TODO non-null optional value printing");
572 return "TODO";
573 }
574 case typeKinds.Bool:
575 return token(value, tokenKinds.Null, wantHtml);
576 default:
577 console.trace("TODO implement getValueText for this type:", zigAnalysis.typeKinds[typeObj.kind]);
578 return "TODO";
579 }
580 }
1272 switch (expr.binOp.name) {
1273 case "add": {
1274 operator += "+";
1275 break;
1276 }
1277 case "addwrap": {
1278 operator += "+%";
1279 break;
1280 }
1281 case "add_sat": {
1282 operator += "+|";
1283 break;
1284 }
1285 case "sub": {
1286 operator += "-";
1287 break;
1288 }
1289 case "subwrap": {
1290 operator += "-%";
1291 break;
1292 }
1293 case "sub_sat": {
1294 operator += "-|";
1295 break;
1296 }
1297 case "mul": {
1298 operator += "*";
1299 break;
1300 }
1301 case "mulwrap": {
1302 operator += "*%";
1303 break;
1304 }
1305 case "mul_sat": {
1306 operator += "*|";
1307 break;
1308 }
1309 case "div": {
1310 operator += "/";
1311 break;
1312 }
1313 case "shl": {
1314 operator += "<<";
1315 break;
1316 }
1317 case "shl_sat": {
1318 operator += "<<|";
1319 break;
1320 }
1321 case "shr": {
1322 operator += ">>";
1323 break;
1324 }
1325 case "bit_or" : {
1326 operator += "|";
1327 break;
1328 }
1329 case "bit_and" : {
1330 operator += "&";
1331 break;
1332 }
1333 case "array_cat" : {
1334 operator += "++";
1335 break;
1336 }
1337 case "array_mul" : {
1338 operator += "**";
1339 break;
1340 }
1341 default: console.log("operator not handled yet or doesn't exist!");
1342 };
5811343
582 function typeName(typeObj, wantHtml, wantSubLink, fnDecl, linkFnNameDecl, thisTypes) {
583 switch (typeObj.kind) {
584 case typeKinds.Array:
585 var name = "[";
586 name += token(typeObj.len, tokenKinds.Number, wantHtml);
587 name += "]";
588 name += typeIndexName(typeObj.elem, wantHtml, wantSubLink, null, null, thisTypes);
589 return name;
590 case typeKinds.Vector:
591 var name = "Vector(";
592 name += token(typeObj.len, tokenKinds.Number, wantHtml);
593 name += ", ";
594 name += typeIndexName(typeObj.elem, wantHtml, wantSubLink, null, null, thisTypes);
595 name += ")";
596 return name;
597 case typeKinds.Optional:
598 return "?" + typeIndexName(typeObj.child, wantHtml, wantSubLink, fnDecl, linkFnNameDecl, thisTypes);
599 case typeKinds.Pointer:
600 var name = "";
601 switch (typeObj.len) {
602 case pointerSizeEnum.One:
603 default:
604 name += "*";
605 break;
606 case pointerSizeEnum.Many:
607 name += "[*]";
608 break;
609 case pointerSizeEnum.Slice:
610 name += "[]";
611 break;
612 case pointerSizeEnum.C:
613 name += "[*c]";
614 break;
615 }
616 if (typeObj['const']) {
617 name += token('const', tokenKinds.Keyword, wantHtml) + ' ';
618 }
619 if (typeObj['volatile']) {
620 name += token('volatile', tokenKinds.Keyword, wantHtml) + ' ';
621 }
622 if (typeObj.align != null) {
623 name += token('align', tokenKinds.Keyword, wantHtml) + '(';
624 name += token(typeObj.align, tokenKinds.Number, wantHtml);
625
626 if (typeObj.hostIntBytes != null) {
627 name += ":";
628 name += token(typeObj.bitOffsetInHost, tokenKinds.Number, wantHtml);
629 name += ":";
630 name += token(typeObj.hostIntBytes, tokenKinds.Number, wantHtml);
631 }
632 name += ") ";
1344 return print_lhs + " " + operator + " " + print_rhs;
1345
1346 }
1347 case "errorSets": {
1348 const errUnionObj = zigAnalysis.types[expr.errorSets];
1349 let lhs = exprName(errUnionObj.lhs, opts);
1350 let rhs = exprName(errUnionObj.rhs, opts);
1351 return lhs + " || " + rhs;
1352
1353 }
1354 case "errorUnion": {
1355 const errUnionObj = zigAnalysis.types[expr.errorUnion];
1356 let lhs = exprName(errUnionObj.lhs, opts);
1357 let rhs = exprName(errUnionObj.rhs, opts);
1358 return lhs + "!" + rhs;
1359
1360 }
1361 case "struct": {
1362 const struct_name = zigAnalysis.decls[expr.struct[0].val.typeRef.refPath[0].declRef].name;
1363 let struct_body = "";
1364 struct_body += struct_name + "{ ";
1365 for (let i = 0; i < expr.struct.length; i++) {
1366 const val = expr.struct[i].name
1367 const exprArg = zigAnalysis.exprs[expr.struct[i].val.expr.as.exprArg];
1368 let value_field = exprArg[Object.keys(exprArg)[0]];
1369 if (value_field instanceof Object) {
1370 value_field = zigAnalysis.decls[value_field[0].val.typeRef.refPath[0].declRef].name;
1371 };
1372 struct_body += "." + val + " = " + value_field;
1373 if (i !== expr.struct.length - 1) {
1374 struct_body += ", ";
1375 } else {
1376 struct_body += " ";
1377 }
1378 }
1379 struct_body += "}";
1380 return struct_body;
1381 }
1382 case "typeOf_peer": {
1383 let payloadHtml = "@TypeOf("
1384 for (let i = 0; i < expr.typeOf_peer.length; i++) {
1385 let elem = zigAnalysis.exprs[expr.typeOf_peer[i]];
1386 payloadHtml += exprName(elem, {wantHtml: true, wantLink:true});
1387 if (i !== expr.typeOf_peer.length - 1) {
1388 payloadHtml += ", ";
1389 }
1390 }
1391 payloadHtml += ")";
1392 return payloadHtml;
1393
1394 }
1395 case "alignOf": {
1396 const alignRefArg = zigAnalysis.exprs[expr.alignOf];
1397 let payloadHtml = "@alignOf(" + exprName(alignRefArg, {wantHtml: true, wantLink:true}) + ")";
1398 return payloadHtml;
1399 }
1400 case "typeOf": {
1401 const typeRefArg = zigAnalysis.exprs[expr.typeOf];
1402 let payloadHtml = "@TypeOf(" + exprName(typeRefArg, {wantHtml: true, wantLink:true}) + ")";
1403 return payloadHtml;
1404 }
1405 case "null": {
1406 return "null";
1407 }
1408 case "array": {
1409 let payloadHtml = ".{";
1410 for (let i = 0; i < expr.array.length; i++) {
1411 if (i != 0) payloadHtml += ", ";
1412 let elem = zigAnalysis.exprs[expr.array[i]];
1413 payloadHtml += exprName(elem, opts);
1414 }
1415 return payloadHtml + "}";
1416 }
1417 case "comptimeExpr": {
1418 return zigAnalysis.comptimeExprs[expr.comptimeExpr].code;
1419 }
1420 case "call": {
1421 let call = zigAnalysis.calls[expr.call];
1422 let payloadHtml = "";
1423
1424
1425 switch(Object.keys(call.func)[0]){
1426 default: throw "TODO";
1427 case "declRef":
1428 case "refPath": {
1429 payloadHtml += exprName(call.func, opts);
1430 break;
6331431 }
634 name += typeIndexName(typeObj.elem, wantHtml, wantSubLink, null, null, thisTypes);
635 return name;
636 case typeKinds.Float:
637 return token('f' + typeObj.bits, tokenKinds.Type, wantHtml);
638 case typeKinds.Int:
639 var signed = (typeObj.i != null) ? 'i' : 'u';
640 var bits = typeObj[signed];
641 return token(signed + bits, tokenKinds.Type, wantHtml);
642 case typeKinds.ComptimeInt:
643 return token('comptime_int', tokenKinds.Type, wantHtml);
644 case typeKinds.ComptimeFloat:
645 return token('comptime_float', tokenKinds.Type, wantHtml);
646 case typeKinds.Type:
647 return token('type', tokenKinds.Type, wantHtml);
648 case typeKinds.Bool:
649 return token('bool', tokenKinds.Type, wantHtml);
650 case typeKinds.Void:
651 return token('void', tokenKinds.Type, wantHtml);
652 case typeKinds.EnumLiteral:
653 return token('(enum literal)', tokenKinds.Type, wantHtml);
654 case typeKinds.NoReturn:
655 return token('noreturn', tokenKinds.Type, wantHtml);
656 case typeKinds.ErrorSet:
657 if (typeObj.errors == null) {
658 return token('anyerror', tokenKinds.Type, wantHtml);
659 } else {
660 if (wantHtml) {
661 return escapeHtml(typeObj.name);
1432 }
1433 payloadHtml += "(";
1434
1435 for (let i = 0; i < call.args.length; i++) {
1436 if (i != 0) payloadHtml += ", ";
1437 payloadHtml += exprName(call.args[i], opts);
1438 }
1439
1440 payloadHtml += ")";
1441 return payloadHtml;
1442 }
1443 case "as": {
1444 // @Check : this should be done in backend because there are legit @as() calls
1445 // const typeRefArg = zigAnalysis.exprs[expr.as.typeRefArg];
1446 const exprArg = zigAnalysis.exprs[expr.as.exprArg];
1447 // return "@as(" + exprName(typeRefArg, opts) +
1448 // ", " + exprName(exprArg, opts) + ")";
1449 return exprName(exprArg, opts);
1450 }
1451 case "declRef": {
1452 return zigAnalysis.decls[expr.declRef].name;
1453 }
1454 case "refPath": {
1455 return expr.refPath.map(x => exprName(x, opts)).join(".");
1456 }
1457 case "int": {
1458 return "" + expr.int;
1459 }
1460 case "float": {
1461 return "" + expr.float.toFixed(2);
1462 }
1463 case "float128": {
1464 return "" + expr.float128.toFixed(2);
1465 }
1466 case "undefined": {
1467 return "undefined";
1468 }
1469 case "string": {
1470 return "\"" + escapeHtml(expr.string) + "\"";
1471 }
1472
1473 case "anytype": {
1474 return "anytype";
1475 }
1476
1477 case "this":{
1478 return "@This()";
1479 }
1480
1481 case "type": {
1482 let name = "";
1483
1484 let typeObj = expr.type;
1485 if (typeof typeObj === 'number') typeObj = zigAnalysis.types[typeObj];
1486 switch (typeObj.kind) {
1487 default: throw "TODO";
1488 case typeKinds.Struct:
1489 {
1490 let structObj = (typeObj);
1491 return structObj;
1492 }
1493 case typeKinds.Enum:
1494 {
1495 let enumObj = (typeObj);
1496 return enumObj;
1497 }
1498 case typeKinds.Opaque:
1499 {
1500 let opaqueObj = (typeObj);
1501
1502 return opaqueObj.name;
1503 }
1504 case typeKinds.ComptimeExpr:
1505 {
1506 return "anyopaque";
1507 }
1508 case typeKinds.Array:
1509 {
1510 let arrayObj = typeObj;
1511 let name = "[";
1512 let lenName = exprName(arrayObj.len, opts);
1513 let sentinel = arrayObj.sentinel ? ":"+exprName(arrayObj.sentinel, opts) : "";
1514 // let is_mutable = arrayObj.is_multable ? "const " : "";
1515
1516 if (opts.wantHtml) {
1517 name +=
1518 '<span class="tok-number">' + lenName + sentinel + "</span>";
6621519 } else {
663 return typeObj.name;
1520 name += lenName + sentinel;
6641521 }
665 }
666 case typeKinds.ErrorUnion:
667 var errSetTypeObj = zigAnalysis.types[typeObj.err];
668 var payloadHtml = typeIndexName(typeObj.payload, wantHtml, wantSubLink, null, null, thisTypes);
669 if (fnDecl != null && errSetTypeObj.fn === fnDecl.value) {
670 // function index parameter supplied and this is the inferred error set of it
671 return "!" + payloadHtml;
672 } else {
673 return typeIndexName(typeObj.err, wantHtml, wantSubLink, null, null, thisTypes) + "!" + payloadHtml;
674 }
675 case typeKinds.Fn:
676 var payloadHtml = "";
677 if (wantHtml) {
678 payloadHtml += '<span class="tok-kw">fn</span>';
679 if (fnDecl != null) {
680 payloadHtml += ' <span class="tok-fn">';
681 if (linkFnNameDecl != null) {
682 payloadHtml += '<a href="' + linkFnNameDecl + '">' +
683 escapeHtml(fnDecl.name) + '</a>';
684 } else {
685 payloadHtml += escapeHtml(fnDecl.name);
686 }
687 payloadHtml += '</span>';
688 }
689 } else {
690 payloadHtml += 'fn'
691 }
692 payloadHtml += '(';
693 if (typeObj.args != null) {
694 var fields = null;
695 var isVarArgs = false;
696 if (fnDecl != null) {
697 var fnObj = zigAnalysis.fns[fnDecl.value];
698 var fnNode = zigAnalysis.astNodes[fnObj.src];
699 fields = fnNode.fields;
700 isVarArgs = fnNode.varArgs;
1522 name += "]";
1523 // name += is_mutable;
1524 name += exprName(arrayObj.child, opts);
1525 return name;
1526 }
1527 case typeKinds.Optional:
1528 return "?" + exprName((typeObj).child, opts);
1529 case typeKinds.Pointer:
1530 {
1531 let ptrObj = (typeObj);
1532 let sentinel = ptrObj.sentinel ? ":"+exprName(ptrObj.sentinel, opts) : "";
1533 let is_mutable = !ptrObj.is_mutable ? "const " : "";
1534 let name = "";
1535 switch (ptrObj.size) {
1536 default:
1537 console.log("TODO: implement unhandled pointer size case");
1538 case pointerSizeEnum.One:
1539 name += "*";
1540 name += is_mutable;
1541 break;
1542 case pointerSizeEnum.Many:
1543 name += "[*";
1544 name += sentinel;
1545 name += "]";
1546 name += is_mutable;
1547 break;
1548 case pointerSizeEnum.Slice:
1549 if (ptrObj.is_ref) {
1550 name += "*";
1551 }
1552 name += "[";
1553 name += sentinel;
1554 name += "]";
1555 name += is_mutable;
1556 break;
1557 case pointerSizeEnum.C:
1558 name += "[*c";
1559 name += sentinel;
1560 name += "]";
1561 name += is_mutable;
1562 break;
1563 }
1564 // @check: after the major changes in arrays the consts are came from switch above
1565 // if (!ptrObj.is_mutable) {
1566 // if (opts.wantHtml) {
1567 // name += '<span class="tok-kw">const</span> ';
1568 // } else {
1569 // name += "const ";
1570 // }
1571 // }
1572 if (ptrObj.is_allowzero) {
1573 name += "allowzero ";
1574 }
1575 if (ptrObj.is_volatile) {
1576 name += "volatile ";
1577 }
1578 if (ptrObj.has_addrspace) {
1579 name += "addrspace(";
1580 name += "." + "";
1581 name += ") ";
1582 }
1583 if (ptrObj.has_align) {
1584 let align = exprName(ptrObj.align, opts);
1585 if (opts.wantHtml) {
1586 name += '<span class="tok-kw">align</span>(';
1587 } else {
1588 name += "align(";
1589 }
1590 if (opts.wantHtml) {
1591 name += '<span class="tok-number">' + align + '</span>';
1592 } else {
1593 name += align;
1594 }
1595 if (ptrObj.hostIntBytes != null) {
1596 name += ":";
1597 if (opts.wantHtml) {
1598 name += '<span class="tok-number">' + ptrObj.bitOffsetInHost + '</span>';
1599 } else {
1600 name += ptrObj.bitOffsetInHost;
1601 }
1602 name += ":";
1603 if (opts.wantHtml) {
1604 name += '<span class="tok-number">' + ptrObj.hostIntBytes + '</span>';
1605 } else {
1606 name += ptrObj.hostIntBytes;
1607 }
1608 }
1609 name += ") ";
1610 }
1611 //name += typeValueName(ptrObj.child, wantHtml, wantSubLink, null);
1612 name += exprName(ptrObj.child, opts);
1613 return name;
1614 }
1615 case typeKinds.Float:
1616 {
1617 let floatObj = (typeObj);
1618
1619 if (opts.wantHtml) {
1620 return '<span class="tok-type">' + floatObj.name + '</span>';
1621 } else {
1622 return floatObj.name;
1623 }
1624 }
1625 case typeKinds.Int:
1626 {
1627 let intObj = (typeObj);
1628 let name = intObj.name;
1629 if (opts.wantHtml) {
1630 return '<span class="tok-type">' + name + '</span>';
1631 } else {
1632 return name;
1633 }
1634 }
1635 case typeKinds.ComptimeInt:
1636 if (opts.wantHtml) {
1637 return '<span class="tok-type">comptime_int</span>';
1638 } else {
1639 return "comptime_int";
1640 }
1641 case typeKinds.ComptimeFloat:
1642 if (opts.wantHtml) {
1643 return '<span class="tok-type">comptime_float</span>';
1644 } else {
1645 return "comptime_float";
1646 }
1647 case typeKinds.Type:
1648 if (opts.wantHtml) {
1649 return '<span class="tok-type">type</span>';
1650 } else {
1651 return "type";
1652 }
1653 case typeKinds.Bool:
1654 if (opts.wantHtml) {
1655 return '<span class="tok-type">bool</span>';
1656 } else {
1657 return "bool";
1658 }
1659 case typeKinds.Void:
1660 if (opts.wantHtml) {
1661 return '<span class="tok-type">void</span>';
1662 } else {
1663 return "void";
1664 }
1665 case typeKinds.EnumLiteral:
1666 if (opts.wantHtml) {
1667 return '<span class="tok-type">(enum literal)</span>';
1668 } else {
1669 return "(enum literal)";
1670 }
1671 case typeKinds.NoReturn:
1672 if (opts.wantHtml) {
1673 return '<span class="tok-type">noreturn</span>';
1674 } else {
1675 return "noreturn";
1676 }
1677 case typeKinds.ErrorSet:
1678 {
1679 let errSetObj = (typeObj);
1680 if (errSetObj.fields == null) {
1681 return '<span class="tok-type">anyerror</span>';
1682 } else {
1683 // throw "TODO";
1684 let html = "error{" + errSetObj.fields[0].name + "}";
1685 return html;
1686 }
1687 }
1688
1689 case typeKinds.ErrorUnion:
1690 {
1691 let errUnionObj = (typeObj);
1692 let lhs = exprName(errUnionObj.lhs, opts);
1693 let rhs = exprName(errUnionObj.rhs, opts);
1694 return lhs + "!" + rhs;
1695 }
1696 case typeKinds.Fn:
1697 {
1698 let fnObj = (typeObj);
1699 let payloadHtml = "";
1700 if (opts.wantHtml) {
1701 if (fnObj.is_extern) {
1702 payloadHtml += "pub extern ";
1703 }
1704 if (fnObj.has_lib_name) {
1705 payloadHtml += "\"" + fnObj.lib_name +"\" ";
1706 }
1707 payloadHtml += '<span class="tok-kw">fn</span>';
1708 if (opts.fnDecl) {
1709 payloadHtml += ' <span class="tok-fn">';
1710 if (opts.linkFnNameDecl) {
1711 payloadHtml += '<a href="' + opts.linkFnNameDecl + '">' +
1712 escapeHtml(opts.fnDecl.name) + '</a>';
1713 } else {
1714 payloadHtml += escapeHtml(opts.fnDecl.name);
1715 }
1716 payloadHtml += '</span>';
1717 }
1718 } else {
1719 payloadHtml += 'fn ';
1720 }
1721 payloadHtml += '(';
1722 if (fnObj.params) {
1723 let fields = null;
1724 let isVarArgs = false;
1725 let fnNode = zigAnalysis.astNodes[fnObj.src];
1726 fields = fnNode.fields;
1727 isVarArgs = fnNode.varArgs;
1728
1729 for (let i = 0; i < fnObj.params.length; i += 1) {
1730 if (i != 0) {
1731 payloadHtml += ', ';
1732 }
1733
1734 payloadHtml += "<span class='argBreaker'><br>&nbsp;&nbsp;&nbsp;&nbsp;</span>"
1735 let value = fnObj.params[i];
1736 let paramValue = resolveValue({expr: value});
1737
1738 if (fields != null) {
1739 let paramNode = zigAnalysis.astNodes[fields[i]];
1740
1741 if (paramNode.varArgs) {
1742 payloadHtml += '...';
1743 continue;
1744 }
1745
1746 if (paramNode.noalias) {
1747 if (opts.wantHtml) {
1748 payloadHtml += '<span class="tok-kw">noalias</span> ';
1749 } else {
1750 payloadHtml += 'noalias ';
1751 }
1752 }
1753
1754 if (paramNode.comptime) {
1755 if (opts.wantHtml) {
1756 payloadHtml += '<span class="tok-kw">comptime</span> ';
1757 } else {
1758 payloadHtml += 'comptime ';
1759 }
1760 }
1761
1762 let paramName = paramNode.name;
1763 if (paramName != null) {
1764 // skip if it matches the type name
1765 if (!shouldSkipParamName(paramValue, paramName)) {
1766 payloadHtml += paramName + ': ';
1767 }
1768 }
1769 }
1770
1771 if (isVarArgs && i === fnObj.params.length - 1) {
1772 payloadHtml += '...';
1773 }
1774 else if ("alignOf" in value) {
1775 if (opts.wantHtml) {
1776 payloadHtml += '<a href="">';
1777 payloadHtml +=
1778 '<span class="tok-kw" style="color:lightblue;">'
1779 + exprName(value, opts) + '</span>';
1780 payloadHtml += '</a>';
1781 } else {
1782 payloadHtml += exprName(value, opts);
1783 }
1784
1785 }
1786 else if ("typeOf" in value) {
1787 if (opts.wantHtml) {
1788 payloadHtml += '<a href="">';
1789 payloadHtml +=
1790 '<span class="tok-kw" style="color:lightblue;">'
1791 + exprName(value, opts) + '</span>';
1792 payloadHtml += '</a>';
1793 } else {
1794 payloadHtml += exprName(value, opts);
1795 }
1796
1797 }
1798 else if ("typeOf_peer" in value) {
1799 if (opts.wantHtml) {
1800 payloadHtml += '<a href="">';
1801 payloadHtml +=
1802 '<span class="tok-kw" style="color:lightblue;">'
1803 + exprName(value, opts) + '</span>';
1804 payloadHtml += '</a>';
1805 } else {
1806 payloadHtml += exprName(value, opts);
1807 }
1808
1809 }
1810 else if ("declRef" in value) {
1811 if (opts.wantHtml) {
1812 payloadHtml += '<a href="">';
1813 payloadHtml +=
1814 '<span class="tok-kw" style="color:lightblue;">'
1815 + exprName(value, opts) + '</span>';
1816 payloadHtml += '</a>';
1817 } else {
1818 payloadHtml += exprName(value, opts);
1819 }
1820
1821 }
1822 else if ("call" in value) {
1823 if (opts.wantHtml) {
1824 payloadHtml += '<a href="">';
1825 payloadHtml +=
1826 '<span class="tok-kw" style="color:lightblue;">'
1827 + exprName(value, opts) + '</span>';
1828 payloadHtml += '</a>';
1829 } else {
1830 payloadHtml += exprName(value, opts);
1831 }
1832 }
1833 else if ("refPath" in value) {
1834 if (opts.wantHtml) {
1835 payloadHtml += '<a href="">';
1836 payloadHtml +=
1837 '<span class="tok-kw" style="color:lightblue;">'
1838 + exprName(value, opts) + '</span>';
1839 payloadHtml += '</a>';
1840 } else {
1841 payloadHtml += exprName(value, opts);
1842 }
1843 } else if ("type" in value) {
1844 let name = exprName(value, {
1845 wantHtml: false,
1846 wantLink: false,
1847 fnDecl: opts.fnDecl,
1848 linkFnNameDecl: opts.linkFnNameDecl,
1849 });
1850 payloadHtml += '<span class="tok-kw">' + name + '</span>';
1851 } else if ("binOpIndex" in value) {
1852 payloadHtml += exprName(value, opts);
1853 }else if ("comptimeExpr" in value) {
1854 let comptimeExpr = zigAnalysis.comptimeExprs[value.comptimeExpr].code;
1855 if (opts.wantHtml) {
1856 payloadHtml += '<span class="tok-kw">' + comptimeExpr + '</span>';
1857 } else {
1858 payloadHtml += comptimeExpr;
1859 }
1860 } else if (opts.wantHtml) {
1861 payloadHtml += '<span class="tok-kw">anytype</span>';
1862 } else {
1863 payloadHtml += 'anytype';
1864 }
1865 }
1866 }
1867
1868 payloadHtml += "<span class='argBreaker'>,<br></span>"
1869 payloadHtml += ') ';
1870
1871 if (fnObj.has_align) {
1872 let align = zigAnalysis.exprs[fnObj.align]
1873 payloadHtml += "align(" + exprName(align, opts) + ") ";
7011874 }
702
703 for (var i = 0; i < typeObj.args.length; i += 1) {
704 if (i != 0) {
705 payloadHtml += ', ';
706 }
707
708 var argTypeIndex = typeObj.args[i];
709
710 if (fields != null) {
711 var paramNode = zigAnalysis.astNodes[fields[i]];
712
713 if (paramNode.varArgs) {
714 payloadHtml += '...';
715 continue;
716 }
717
718 if (paramNode.noalias) {
719 payloadHtml += token('noalias', tokenKinds.Keyword, wantHtml) + ' ';
720 }
721
722 if (paramNode.comptime) {
723 payloadHtml += token('comptime', tokenKinds.Keyword, wantHtml) + ' ';
724 }
725
726 var paramName = paramNode.name;
727 if (paramName != null) {
728 // skip if it matches the type name
729 if (argTypeIndex == null || !shouldSkipParamName(argTypeIndex, paramName)) {
730 payloadHtml += paramName + ': ';
731 }
732 }
733 }
734
735 if (isVarArgs && i === typeObj.args.length - 1) {
736 payloadHtml += '...';
737 } else if (argTypeIndex != null) {
738 payloadHtml += typeIndexName(argTypeIndex, wantHtml, wantSubLink, null, null, thisTypes);
739 } else {
740 payloadHtml += token('anytype', tokenKinds.Keyword, wantHtml);
741 }
1875 if (fnObj.has_cc) {
1876 let cc = zigAnalysis.exprs[fnObj.cc]
1877 if (cc) {
1878 payloadHtml += "callconv(." + cc.enumLiteral + ") ";
1879 }
7421880 }
743 }
7441881
745 payloadHtml += ') ';
746 if (typeObj.ret != null) {
747 payloadHtml += typeIndexName(typeObj.ret, wantHtml, wantSubLink, fnDecl, null, thisTypes);
748 } else {
749 payloadHtml += token('anytype', tokenKinds.Keyword, wantHtml);
750 }
751 return payloadHtml;
752 case typeKinds.Frame:
753 var fnObj = zigAnalysis.fns[typeObj.fn];
754 return '@Frame(' + getValueText(fnObj.type, typeObj.fn, wantHtml, wantSubLink) + ')';
755 case typeKinds.AnyFrame:
756 var name = token('anyframe', tokenKinds.Keyword, wantHtml);
757 if (typeObj.result) {
758 name += "->";
759 name += typeIndexName(typeObj.result, wantHtml, wantSubLink, null, null, thisTypes);
760 }
761 return name;
762 default:
763 if (wantHtml) {
764 return escapeHtml(typeObj.name);
765 } else {
766 return typeObj.name;
1882 if (fnObj.is_inferred_error) {
1883 payloadHtml += "!";
1884 }
1885 if (fnObj.ret != null) {
1886 payloadHtml += exprName(fnObj.ret, opts);
1887 } else if (opts.wantHtml) {
1888 payloadHtml += '<span class="tok-kw">anytype</span>';
1889 } else {
1890 payloadHtml += 'anytype';
1891 }
1892 return payloadHtml;
1893 }
1894 // if (wantHtml) {
1895 // return escapeHtml(typeObj.name);
1896 // } else {
1897 // return typeObj.name;
1898 // }
1899 }
1900 }
1901
1902 }
1903 }
1904
1905
1906
1907 function shouldSkipParamName(typeRef, paramName) {
1908 let resolvedTypeRef = resolveValue({expr: typeRef});
1909 if ("type" in resolvedTypeRef) {
1910 let typeObj = zigAnalysis.types[resolvedTypeRef.type];
1911 if (typeObj.kind === typeKinds.Pointer){
1912 let ptrObj = (typeObj);
1913 if (getPtrSize(ptrObj) === pointerSizeEnum.One) {
1914 const value = resolveValue(ptrObj.child);
1915 return typeValueName(value, false, true).toLowerCase() === paramName;
7671916 }
1917 }
7681918 }
1919 return false;
1920 }
1921
1922
1923 function getPtrSize(typeObj) {
1924 return (typeObj.size == null) ? pointerSizeEnum.One : typeObj.size;
7691925 }
7701926
1927
7711928 function renderType(typeObj) {
772 var name;
1929 let name;
7731930 if (rootIsStd && typeObj === zigAnalysis.types[zigAnalysis.packages[zigAnalysis.rootPkg].main]) {
7741931 name = "std";
7751932 } else {
776 name = typeName(typeObj, false, false);
1933 name = exprName({type:typeObj}, false, false);
7771934 }
7781935 if (name != null && name != "") {
7791936 domHdrName.innerText = name + " (" + zigAnalysis.typeKinds[typeObj.kind] + ")";
7801937 domHdrName.classList.remove("hidden");
7811938 }
7821939 if (typeObj.kind == typeKinds.ErrorSet) {
783 renderErrorSet(typeObj);
1940 renderErrorSet((typeObj));
7841941 }
7851942 }
7861943
1944
7871945 function renderErrorSet(errSetType) {
788 if (errSetType.errors == null) {
1946 if (errSetType.fields == null) {
7891947 domFnErrorsAnyError.classList.remove("hidden");
7901948 } else {
791 var errorList = [];
792 for (var i = 0; i < errSetType.errors.length; i += 1) {
793 var errObj = zigAnalysis.errors[errSetType.errors[i]];
794 var srcObj = zigAnalysis.astNodes[errObj.src];
795 errorList.push({
796 err: errObj,
797 docs: srcObj.docs,
798 });
1949 let errorList = [];
1950 for (let i = 0; i < errSetType.fields.length; i += 1) {
1951 let errObj = errSetType.fields[i];
1952 //let srcObj = zigAnalysis.astNodes[errObj.src];
1953 errorList.push(errObj);
7991954 }
8001955 errorList.sort(function(a, b) {
801 return operatorCompare(a.err.name.toLowerCase(), b.err.name.toLowerCase());
1956 return operatorCompare(a.name.toLowerCase(), b.name.toLowerCase());
8021957 });
8031958
804 var domListFnErrorsFragment = createDomListFragment(errorList.length, "<dt></dt><dd></dd>");
805 for (var i = 0; i < errorList.length; i += 1) {
806 var nameTdDom = domListFnErrorsFragment.children[i * 2 + 0];
807 var descTdDom = domListFnErrorsFragment.children[i * 2 + 1];
808 nameTdDom.textContent = errorList[i].err.name;
809 var docs = errorList[i].docs;
1959 resizeDomListDl(domListFnErrors, errorList.length);
1960 for (let i = 0; i < errorList.length; i += 1) {
1961 let nameTdDom = domListFnErrors.children[i * 2 + 0];
1962 let descTdDom = domListFnErrors.children[i * 2 + 1];
1963 nameTdDom.textContent = errorList[i].name;
1964 let docs = errorList[i].docs;
8101965 if (docs != null) {
8111966 descTdDom.innerHTML = markdown(docs);
8121967 } else {
8131968 descTdDom.textContent = "";
8141969 }
8151970 }
816 domListFnErrors.innerHTML = "";
817 domListFnErrors.appendChild(domListFnErrorsFragment);
8181971 domTableFnErrors.classList.remove("hidden");
8191972 }
8201973 domSectFnErrors.classList.remove("hidden");
8211974 }
8221975
823 function allCompTimeFnCallsHaveTypeResult(typeIndex, value) {
824 var srcIndex = zigAnalysis.fns[value].src;
825 var calls = nodesToCallsMap[srcIndex];
826 if (calls == null) return false;
827 for (var i = 0; i < calls.length; i += 1) {
828 var call = zigAnalysis.calls[calls[i]];
829 if (call.result.type !== typeTypeId) return false;
830 }
831 return true;
832 }
833
834 function allCompTimeFnCallsResult(calls) {
835 var firstTypeObj = null;
836 var containerObj = {
837 privDecls: [],
838 };
839 for (var callI = 0; callI < calls.length; callI += 1) {
840 var call = zigAnalysis.calls[calls[callI]];
841 if (call.result.type !== typeTypeId) return null;
842 var typeObj = zigAnalysis.types[call.result.value];
843 if (!typeKindIsContainer(typeObj.kind)) return null;
844 if (firstTypeObj == null) {
845 firstTypeObj = typeObj;
846 containerObj.src = typeObj.src;
847 } else if (firstTypeObj.src !== typeObj.src) {
848 return null;
849 }
850
851 if (containerObj.fields == null) {
852 containerObj.fields = (typeObj.fields || []).concat([]);
853 } else for (var fieldI = 0; fieldI < typeObj.fields.length; fieldI += 1) {
854 var prev = containerObj.fields[fieldI];
855 var next = typeObj.fields[fieldI];
856 if (prev === next) continue;
857 if (typeof(prev) === 'object') {
858 if (prev[next] == null) prev[next] = typeObj;
859 } else {
860 containerObj.fields[fieldI] = {};
861 containerObj.fields[fieldI][prev] = firstTypeObj;
862 containerObj.fields[fieldI][next] = typeObj;
863 }
864 }
865
866 if (containerObj.pubDecls == null) {
867 containerObj.pubDecls = (typeObj.pubDecls || []).concat([]);
868 } else for (var declI = 0; declI < typeObj.pubDecls.length; declI += 1) {
869 var prev = containerObj.pubDecls[declI];
870 var next = typeObj.pubDecls[declI];
871 if (prev === next) continue;
872 // TODO instead of showing "examples" as the public declarations,
873 // do logic like this:
874 //if (typeof(prev) !== 'object') {
875 // var newDeclId = zigAnalysis.decls.length;
876 // prev = clone(zigAnalysis.decls[prev]);
877 // prev.id = newDeclId;
878 // zigAnalysis.decls.push(prev);
879 // containerObj.pubDecls[declI] = prev;
880 //}
881 //mergeDecls(prev, next, firstTypeObj, typeObj);
882 }
883 }
884 for (var declI = 0; declI < containerObj.pubDecls.length; declI += 1) {
885 var decl = containerObj.pubDecls[declI];
886 if (typeof(decl) === 'object') {
887 containerObj.pubDecls[declI] = containerObj.pubDecls[declI].id;
888 }
889 }
890 return containerObj;
891 }
892
893 function mergeDecls(declObj, nextDeclIndex, firstTypeObj, typeObj) {
894 var nextDeclObj = zigAnalysis.decls[nextDeclIndex];
895 if (declObj.type != null && nextDeclObj.type != null && declObj.type !== nextDeclObj.type) {
896 if (typeof(declObj.type) !== 'object') {
897 var prevType = declObj.type;
898 declObj.type = {};
899 declObj.type[prevType] = firstTypeObj;
900 declObj.value = null;
901 }
902 declObj.type[nextDeclObj.type] = typeObj;
903 } else if (declObj.type == null && nextDeclObj != null) {
904 declObj.type = nextDeclObj.type;
905 }
906 if (declObj.value != null && nextDeclObj.value != null && declObj.value !== nextDeclObj.value) {
907 if (typeof(declObj.value) !== 'object') {
908 var prevValue = declObj.value;
909 declObj.value = {};
910 declObj.value[prevValue] = firstTypeObj;
911 }
912 declObj.value[nextDeclObj.value] = typeObj;
913 } else if (declObj.value == null && nextDeclObj.value != null) {
914 declObj.value = nextDeclObj.value;
915 }
916 }
917
1976// function allCompTimeFnCallsHaveTypeResult(typeIndex, value) {
1977// let srcIndex = zigAnalysis.fns[value].src;
1978// let calls = nodesToCallsMap[srcIndex];
1979// if (calls == null) return false;
1980// for (let i = 0; i < calls.length; i += 1) {
1981// let call = zigAnalysis.calls[calls[i]];
1982// if (call.result.type !== typeTypeId) return false;
1983// }
1984// return true;
1985// }
1986//
1987// function allCompTimeFnCallsResult(calls) {
1988// let firstTypeObj = null;
1989// let containerObj = {
1990// privDecls: [],
1991// };
1992// for (let callI = 0; callI < calls.length; callI += 1) {
1993// let call = zigAnalysis.calls[calls[callI]];
1994// if (call.result.type !== typeTypeId) return null;
1995// let typeObj = zigAnalysis.types[call.result.value];
1996// if (!typeKindIsContainer(typeObj.kind)) return null;
1997// if (firstTypeObj == null) {
1998// firstTypeObj = typeObj;
1999// containerObj.src = typeObj.src;
2000// } else if (firstTypeObj.src !== typeObj.src) {
2001// return null;
2002// }
2003//
2004// if (containerObj.fields == null) {
2005// containerObj.fields = (typeObj.fields || []).concat([]);
2006// } else for (let fieldI = 0; fieldI < typeObj.fields.length; fieldI += 1) {
2007// let prev = containerObj.fields[fieldI];
2008// let next = typeObj.fields[fieldI];
2009// if (prev === next) continue;
2010// if (typeof(prev) === 'object') {
2011// if (prev[next] == null) prev[next] = typeObj;
2012// } else {
2013// containerObj.fields[fieldI] = {};
2014// containerObj.fields[fieldI][prev] = firstTypeObj;
2015// containerObj.fields[fieldI][next] = typeObj;
2016// }
2017// }
2018//
2019// if (containerObj.pubDecls == null) {
2020// containerObj.pubDecls = (typeObj.pubDecls || []).concat([]);
2021// } else for (let declI = 0; declI < typeObj.pubDecls.length; declI += 1) {
2022// let prev = containerObj.pubDecls[declI];
2023// let next = typeObj.pubDecls[declI];
2024// if (prev === next) continue;
2025// // TODO instead of showing "examples" as the public declarations,
2026// // do logic like this:
2027// //if (typeof(prev) !== 'object') {
2028// // let newDeclId = zigAnalysis.decls.length;
2029// // prev = clone(zigAnalysis.decls[prev]);
2030// // prev.id = newDeclId;
2031// // zigAnalysis.decls.push(prev);
2032// // containerObj.pubDecls[declI] = prev;
2033// //}
2034// //mergeDecls(prev, next, firstTypeObj, typeObj);
2035// }
2036// }
2037// for (let declI = 0; declI < containerObj.pubDecls.length; declI += 1) {
2038// let decl = containerObj.pubDecls[declI];
2039// if (typeof(decl) === 'object') {
2040// containerObj.pubDecls[declI] = containerObj.pubDecls[declI].id;
2041// }
2042// }
2043// return containerObj;
2044// }
2045
2046
2047
2048
9182049 function renderValue(decl) {
2050 let resolvedValue = resolveValue(decl.value)
2051
2052 if (resolvedValue.expr.fieldRef) {
2053 const declRef = decl.value.expr.refPath[0].declRef;
2054 const type = zigAnalysis.decls[declRef];
2055 domFnProtoCode.innerHTML = '<span class="tok-kw">const</span> ' +
2056 escapeHtml(decl.name) + ': ' + type.name +
2057 " = " + exprName(decl.value.expr, {wantHtml: true, wantLink:true}) + ";";
2058 } else if (resolvedValue.expr.string !== undefined || resolvedValue.expr.call !== undefined || resolvedValue.expr.comptimeExpr) {
2059 domFnProtoCode.innerHTML = '<span class="tok-kw">const</span> ' +
2060 escapeHtml(decl.name) + ': ' + exprName(resolvedValue.expr, {wantHtml: true, wantLink:true}) +
2061 " = " + exprName(decl.value.expr, {wantHtml: true, wantLink:true}) + ";";
2062 } else if (resolvedValue.expr.compileError) {
2063 domFnProtoCode.innerHTML = '<span class="tok-kw">const</span> ' +
2064 escapeHtml(decl.name) + " = " + exprName(decl.value.expr, {wantHtml: true, wantLink:true}) + ";";
2065 }
2066 else {
9192067 domFnProtoCode.innerHTML = '<span class="tok-kw">const</span> ' +
920 escapeHtml(decl.name) + ': ' + typeIndexName(decl.type, true, true);
2068 escapeHtml(decl.name) + ': ' + exprName(resolvedValue.typeRef, {wantHtml: true, wantLink:true}) +
2069 " = " + exprName(decl.value.expr, {wantHtml: true, wantLink:true}) + ";";
2070 }
9212071
922 var docs = zigAnalysis.astNodes[decl.src].docs;
2072 let docs = zigAnalysis.astNodes[decl.src].docs;
9232073 if (docs != null) {
9242074 domTldDocs.innerHTML = markdown(docs);
9252075 domTldDocs.classList.remove("hidden");
......@@ -928,11 +2078,13 @@
9282078 domFnProto.classList.remove("hidden");
9292079 }
9302080
2081
9312082 function renderVar(decl) {
2083 let declTypeRef = typeOfDecl(decl);
9322084 domFnProtoCode.innerHTML = '<span class="tok-kw">var</span> ' +
933 escapeHtml(decl.name) + ': ' + typeIndexName(decl.type, true, true);
2085 escapeHtml(decl.name) + ': ' + typeValueName(declTypeRef, true, true);
9342086
935 var docs = zigAnalysis.astNodes[decl.src].docs;
2087 let docs = zigAnalysis.astNodes[decl.src].docs;
9362088 if (docs != null) {
9372089 domTldDocs.innerHTML = markdown(docs);
9382090 domTldDocs.classList.remove("hidden");
......@@ -941,52 +2093,103 @@
9412093 domFnProto.classList.remove("hidden");
9422094 }
9432095
944 function renderContainer(container, thisTypes) {
945 var typesList = [];
946 var namespacesList = [];
947 var errSetsList = [];
948 var fnsList = [];
949 var varsList = [];
950 var valsList = [];
9512096
952 for (var i = 0; i < container.pubDecls.length; i += 1) {
953 var decl = zigAnalysis.decls[container.pubDecls[i]];
2097
2098 function categorizeDecls(decls,
2099 typesList, namespacesList, errSetsList,
2100 fnsList, varsList, valsList, testsList) {
2101
2102 for (let i = 0; i < decls.length; i += 1) {
2103 let decl = zigAnalysis.decls[decls[i]];
2104 let declValue = resolveValue(decl.value);
2105
2106 if (decl.isTest) {
2107 testsList.push(decl);
2108 continue;
2109 }
9542110
9552111 if (decl.kind === 'var') {
9562112 varsList.push(decl);
9572113 continue;
958 } else if (decl.kind === 'const' && decl.type != null) {
959 if (decl.type === typeTypeId) {
960 if (typeIsErrSet(decl.value)) {
961 errSetsList.push(decl);
962 } else if (typeIsStructWithNoFields(decl.value)) {
963 namespacesList.push(decl);
964 } else {
965 typesList.push(decl);
966 }
967 } else {
968 var typeKind = zigAnalysis.types[decl.type].kind;
969 if (typeKind === typeKinds.Fn) {
970 if (allCompTimeFnCallsHaveTypeResult(decl.type, decl.value)) {
971 typesList.push(decl);
2114 }
2115
2116 if (decl.kind === 'const') {
2117 if ("type" in declValue.expr) {
2118 // We have the actual type expression at hand.
2119 const typeExpr = zigAnalysis.types[declValue.expr.type];
2120 if (typeExpr.kind == typeKinds.Fn) {
2121 const funcRetExpr = resolveValue({
2122 expr: (typeExpr).ret
2123 });
2124 if ("type" in funcRetExpr.expr && funcRetExpr.expr.type == typeTypeId) {
2125 if (typeIsErrSet(declValue.expr.type)) {
2126 errSetsList.push(decl);
2127 } else if (typeIsStructWithNoFields(declValue.expr.type)) {
2128 namespacesList.push(decl);
2129 } else {
2130 typesList.push(decl);
2131 }
9722132 } else {
9732133 fnsList.push(decl);
9742134 }
9752135 } else {
976 valsList.push(decl);
2136 if (typeIsErrSet(declValue.expr.type)) {
2137 errSetsList.push(decl);
2138 } else if (typeIsStructWithNoFields(declValue.expr.type)) {
2139 namespacesList.push(decl);
2140 } else {
2141 typesList.push(decl);
2142 }
9772143 }
2144 } else if ("typeRef" in declValue) {
2145 if ("type" in declValue.typeRef && declValue.typeRef == typeTypeId) {
2146 // We don't know what the type expression is, but we know it's a type.
2147 typesList.push(decl);
2148 } else {
2149 valsList.push(decl);
2150 }
2151 } else {
2152 valsList.push(decl);
9782153 }
9792154 }
9802155 }
2156 }
2157
2158
2159 function renderContainer(container) {
2160
2161 let typesList = [];
2162
2163 let namespacesList = [];
2164
2165 let errSetsList = [];
2166
2167 let fnsList = [];
2168
2169 let varsList = [];
2170
2171 let valsList = [];
2172
2173 let testsList = [];
2174
2175 categorizeDecls(container.pubDecls,
2176 typesList, namespacesList, errSetsList,
2177 fnsList, varsList, valsList, testsList);
2178 if (curNav.showPrivDecls) categorizeDecls(container.privDecls,
2179 typesList, namespacesList, errSetsList,
2180 fnsList, varsList, valsList, testsList);
2181
2182
9812183 typesList.sort(byNameProperty);
9822184 namespacesList.sort(byNameProperty);
9832185 errSetsList.sort(byNameProperty);
9842186 fnsList.sort(byNameProperty);
9852187 varsList.sort(byNameProperty);
9862188 valsList.sort(byNameProperty);
2189 testsList.sort(byNameProperty);
9872190
9882191 if (container.src != null) {
989 var docs = zigAnalysis.astNodes[container.src].docs;
2192 let docs = zigAnalysis.astNodes[container.src].docs;
9902193 if (docs != null) {
9912194 domTldDocs.innerHTML = markdown(docs);
9922195 domTldDocs.classList.remove("hidden");
......@@ -994,163 +2197,193 @@
9942197 }
9952198
9962199 if (typesList.length !== 0) {
997 var domListTypesFragment = createDomListFragment(typesList.length, '<li><a href="#"></a></li>');
998 for (var i = 0; i < typesList.length; i += 1) {
999 var liDom = domListTypesFragment.children[i];
1000 var aDom = liDom.children[0];
1001 var decl = typesList[i];
2200 resizeDomList(domListTypes, typesList.length, '<li><a href="#"></a></li>');
2201 for (let i = 0; i < typesList.length; i += 1) {
2202 let liDom = domListTypes.children[i];
2203 let aDom = liDom.children[0];
2204 let decl = typesList[i];
10022205 aDom.textContent = decl.name;
10032206 aDom.setAttribute('href', navLinkDecl(decl.name));
10042207 }
1005 domListTypes.innerHTML = "";
1006 domListTypes.appendChild(domListTypesFragment);
10072208 domSectTypes.classList.remove("hidden");
10082209 }
10092210 if (namespacesList.length !== 0) {
1010 var domListNamespacesFragment = createDomListFragment(namespacesList.length, '<li><a href="#"></a></li>');
1011 for (var i = 0; i < namespacesList.length; i += 1) {
1012 var liDom = domListNamespacesFragment.children[i];
1013 var aDom = liDom.children[0];
1014 var decl = namespacesList[i];
2211 resizeDomList(domListNamespaces, namespacesList.length, '<li><a href="#"></a></li>');
2212 for (let i = 0; i < namespacesList.length; i += 1) {
2213 let liDom = domListNamespaces.children[i];
2214 let aDom = liDom.children[0];
2215 let decl = namespacesList[i];
10152216 aDom.textContent = decl.name;
10162217 aDom.setAttribute('href', navLinkDecl(decl.name));
10172218 }
1018 domListNamespaces.innerHTML = "";
1019 domListNamespaces.appendChild(domListNamespacesFragment);
10202219 domSectNamespaces.classList.remove("hidden");
10212220 }
10222221
10232222 if (errSetsList.length !== 0) {
1024 var domListErrSetsFragment = createDomListFragment(errSetsList.length, '<li><a href="#"></a></li>');
1025 for (var i = 0; i < errSetsList.length; i += 1) {
1026 var liDom = domListErrSetsFragment.children[i];
1027 var aDom = liDom.children[0];
1028 var decl = errSetsList[i];
2223 resizeDomList(domListErrSets, errSetsList.length, '<li><a href="#"></a></li>');
2224 for (let i = 0; i < errSetsList.length; i += 1) {
2225 let liDom = domListErrSets.children[i];
2226 let aDom = liDom.children[0];
2227 let decl = errSetsList[i];
10292228 aDom.textContent = decl.name;
10302229 aDom.setAttribute('href', navLinkDecl(decl.name));
10312230 }
1032 domListErrSets.innerHTML = "";
1033 domListErrSets.appendChild(domListErrSetsFragment);
10342231 domSectErrSets.classList.remove("hidden");
10352232 }
10362233
10372234 if (fnsList.length !== 0) {
1038 var domListFnsFragment = createDomListFragment(fnsList.length, '<tr><td></td><td></td></tr>');
1039 for (var i = 0; i < fnsList.length; i += 1) {
1040 var decl = fnsList[i];
1041 var trDom = domListFnsFragment.children[i];
2235 resizeDomList(domListFns, fnsList.length, '<div><dt></dt><dd></dd></div>');
2236
2237 window.x = domListFns;
2238 for (let i = 0; i < fnsList.length; i += 1) {
2239 let decl = fnsList[i];
2240 let trDom = domListFns.children[i];
2241
2242 let tdFnCode = trDom.children[0];
2243 let tdDesc = trDom.children[1];
10422244
1043 var tdFnCode = trDom.children[0];
1044 var tdDesc = trDom.children[1];
2245 let declType = resolveValue(decl.value);
2246 console.assert("type" in declType.expr);
10452247
1046 tdFnCode.innerHTML = typeIndexName(decl.type, true, true, decl, navLinkDecl(decl.name), thisTypes);
2248 tdFnCode.innerHTML = exprName(declType.expr,{
2249 wantHtml: true,
2250 wantLink: true,
2251 fnDecl: decl,
2252 linkFnNameDecl: navLinkDecl(decl.name),
2253 });
10472254
1048 var docs = zigAnalysis.astNodes[decl.src].docs;
2255 let docs = zigAnalysis.astNodes[decl.src].docs;
10492256 if (docs != null) {
10502257 tdDesc.innerHTML = shortDescMarkdown(docs);
10512258 } else {
10522259 tdDesc.textContent = "";
10532260 }
10542261 }
1055 domListFns.innerHTML = "";
1056 domListFns.appendChild(domListFnsFragment);
10572262 domSectFns.classList.remove("hidden");
10582263 }
10592264
1060 if (container.fields != null && container.fields.length !== 0) {
1061 var domListFieldsFragment = createDomListFragment(container.fields.length, '<div></div>');
2265 let containerNode = zigAnalysis.astNodes[container.src];
2266 if (containerNode.fields && containerNode.fields.length > 0) {
2267 resizeDomList(domListFields, containerNode.fields.length, '<div></div>');
10622268
1063 var containerNode = zigAnalysis.astNodes[container.src];
1064 for (var i = 0; i < container.fields.length; i += 1) {
1065 var field = container.fields[i];
1066 var fieldNode = zigAnalysis.astNodes[containerNode.fields[i]];
1067 var divDom = domListFieldsFragment.children[i];
2269 for (let i = 0; i < containerNode.fields.length; i += 1) {
2270 let fieldNode = zigAnalysis.astNodes[containerNode.fields[i]];
2271 let divDom = domListFields.children[i];
2272 let fieldName = (fieldNode.name);
10682273
1069 var html = '<div class="mobile-scroll-container"><pre class="scroll-item">' + escapeHtml(fieldNode.name);
2274 let html = '<div class="mobile-scroll-container"><pre class="scroll-item">' + escapeHtml(fieldName);
10702275
10712276 if (container.kind === typeKinds.Enum) {
1072 html += ' = <span class="tok-number">' + field + '</span>';
2277 html += ' = <span class="tok-number">' + fieldName + '</span>';
10732278 } else {
2279 let fieldTypeExpr = container.fields[i];
10742280 html += ": ";
1075 if (typeof(field) === 'object') {
1076 html += '<span class="tok-kw">var</span>';
1077 } else {
1078 html += typeIndexName(field, true, true);
2281 let name = exprName(fieldTypeExpr, false, false);
2282 html += '<span class="tok-kw">'+ name +'</span>';
2283 let tsn = typeShorthandName(fieldTypeExpr);
2284 if (tsn) {
2285 html += '<span> ('+ tsn +')</span>';
2286
10792287 }
10802288 }
10812289
10822290 html += ',</pre></div>';
10832291
1084 var docs = fieldNode.docs;
2292 let docs = fieldNode.docs;
10852293 if (docs != null) {
10862294 html += markdown(docs);
10872295 }
10882296 divDom.innerHTML = html;
10892297 }
1090 domListFields.innerHTML = "";
1091 domListFields.appendChild(domListFieldsFragment);
10922298 domSectFields.classList.remove("hidden");
10932299 }
10942300
10952301 if (varsList.length !== 0) {
1096 var domListGlobalVarsFragment = createDomListFragment(varsList.length,
2302 resizeDomList(domListGlobalVars, varsList.length,
10972303 '<tr><td><a href="#"></a></td><td></td><td></td></tr>');
1098 for (var i = 0; i < varsList.length; i += 1) {
1099 var decl = varsList[i];
1100 var trDom = domListGlobalVarsFragment.children[i];
2304 for (let i = 0; i < varsList.length; i += 1) {
2305 let decl = varsList[i];
2306 let trDom = domListGlobalVars.children[i];
11012307
1102 var tdName = trDom.children[0];
1103 var tdNameA = tdName.children[0];
1104 var tdType = trDom.children[1];
1105 var tdDesc = trDom.children[2];
2308 let tdName = trDom.children[0];
2309 let tdNameA = tdName.children[0];
2310 let tdType = trDom.children[1];
2311 let tdDesc = trDom.children[2];
11062312
11072313 tdNameA.setAttribute('href', navLinkDecl(decl.name));
11082314 tdNameA.textContent = decl.name;
11092315
1110 tdType.innerHTML = typeIndexName(decl.type, true, true);
2316 tdType.innerHTML = typeValueName(typeOfDecl(decl), true, true);
11112317
1112 var docs = zigAnalysis.astNodes[decl.src].docs;
2318 let docs = zigAnalysis.astNodes[decl.src].docs;
11132319 if (docs != null) {
11142320 tdDesc.innerHTML = shortDescMarkdown(docs);
11152321 } else {
11162322 tdDesc.textContent = "";
11172323 }
11182324 }
1119 domListGlobalVars.innerHTML = "";
1120 domListGlobalVars.appendChild(domListGlobalVarsFragment);
11212325 domSectGlobalVars.classList.remove("hidden");
11222326 }
11232327
11242328 if (valsList.length !== 0) {
1125 var domListValuesFragment = createDomListFragment(valsList.length,
2329 resizeDomList(domListValues, valsList.length,
11262330 '<tr><td><a href="#"></a></td><td></td><td></td></tr>');
1127 for (var i = 0; i < valsList.length; i += 1) {
1128 var decl = valsList[i];
1129 var trDom = domListValuesFragment.children[i];
2331 for (let i = 0; i < valsList.length; i += 1) {
2332 let decl = valsList[i];
2333 let trDom = domListValues.children[i];
11302334
1131 var tdName = trDom.children[0];
1132 var tdNameA = tdName.children[0];
1133 var tdType = trDom.children[1];
1134 var tdDesc = trDom.children[2];
2335 let tdName = trDom.children[0];
2336 let tdNameA = tdName.children[0];
2337 let tdType = trDom.children[1];
2338 let tdDesc = trDom.children[2];
11352339
11362340 tdNameA.setAttribute('href', navLinkDecl(decl.name));
11372341 tdNameA.textContent = decl.name;
11382342
1139 tdType.innerHTML = typeIndexName(decl.type, true, true);
2343 tdType.innerHTML = exprName(walkResultTypeRef(decl.value),
2344 {wantHtml:true, wantLink:true});
11402345
1141 var docs = zigAnalysis.astNodes[decl.src].docs;
2346 let docs = zigAnalysis.astNodes[decl.src].docs;
11422347 if (docs != null) {
11432348 tdDesc.innerHTML = shortDescMarkdown(docs);
11442349 } else {
11452350 tdDesc.textContent = "";
11462351 }
11472352 }
1148 domListValues.innerHTML = "";
1149 domListValues.appendChild(domListValuesFragment);
11502353 domSectValues.classList.remove("hidden");
11512354 }
2355
2356 if (testsList.length !== 0) {
2357 resizeDomList(domListTests, testsList.length,
2358 '<tr><td><a href="#"></a></td><td></td><td></td></tr>');
2359 for (let i = 0; i < testsList.length; i += 1) {
2360 let decl = testsList[i];
2361 let trDom = domListTests.children[i];
2362
2363 let tdName = trDom.children[0];
2364 let tdNameA = tdName.children[0];
2365 let tdType = trDom.children[1];
2366 let tdDesc = trDom.children[2];
2367
2368 tdNameA.setAttribute('href', navLinkDecl(decl.name));
2369 tdNameA.textContent = decl.name;
2370
2371 tdType.innerHTML = exprName(walkResultTypeRef(decl.value),
2372 {wantHtml:true, wantLink:true});
2373
2374 let docs = zigAnalysis.astNodes[decl.src].docs;
2375 if (docs != null) {
2376 tdDesc.innerHTML = shortDescMarkdown(docs);
2377 } else {
2378 tdDesc.textContent = "";
2379 }
2380 }
2381 domSectTests.classList.remove("hidden");
2382 }
11522383 }
11532384
2385
2386
11542387 function operatorCompare(a, b) {
11552388 if (a === b) {
11562389 return 0;
......@@ -1162,33 +2395,33 @@
11622395 }
11632396
11642397 function detectRootIsStd() {
1165 var rootPkg = zigAnalysis.packages[zigAnalysis.rootPkg];
2398 let rootPkg = zigAnalysis.packages[zigAnalysis.rootPkg];
11662399 if (rootPkg.table["std"] == null) {
11672400 // no std mapped into the root package
11682401 return false;
11692402 }
1170 var stdPkg = zigAnalysis.packages[rootPkg.table["std"]];
2403 let stdPkg = zigAnalysis.packages[rootPkg.table["std"]];
11712404 if (stdPkg == null) return false;
11722405 return rootPkg.file === stdPkg.file;
11732406 }
11742407
11752408 function indexTypeKinds() {
1176 var map = {};
1177 for (var i = 0; i < zigAnalysis.typeKinds.length; i += 1) {
2409 let map = ({});
2410 for (let i = 0; i < zigAnalysis.typeKinds.length; i += 1) {
11782411 map[zigAnalysis.typeKinds[i]] = i;
11792412 }
11802413 // This is just for debugging purposes, not needed to function
1181 var assertList = ["Type","Void","Bool","NoReturn","Int","Float","Pointer","Array","Struct",
2414 let assertList = ["Type","Void","Bool","NoReturn","Int","Float","Pointer","Array","Struct",
11822415 "ComptimeFloat","ComptimeInt","Undefined","Null","Optional","ErrorUnion","ErrorSet","Enum",
11832416 "Union","Fn","BoundFn","Opaque","Frame","AnyFrame","Vector","EnumLiteral"];
1184 for (var i = 0; i < assertList.length; i += 1) {
2417 for (let i = 0; i < assertList.length; i += 1) {
11852418 if (map[assertList[i]] == null) throw new Error("No type kind '" + assertList[i] + "' found");
11862419 }
11872420 return map;
11882421 }
11892422
11902423 function findTypeTypeId() {
1191 for (var i = 0; i < zigAnalysis.types.length; i += 1) {
2424 for (let i = 0; i < zigAnalysis.types.length; i += 1) {
11922425 if (zigAnalysis.types[i].kind == typeKinds.Type) {
11932426 return i;
11942427 }
......@@ -1197,17 +2430,26 @@
11972430 }
11982431
11992432 function updateCurNav() {
2433
12002434 curNav = {
2435 showPrivDecls: false,
12012436 pkgNames: [],
12022437 pkgObjs: [],
12032438 declNames: [],
12042439 declObjs: [],
2440 callName: null,
12052441 };
12062442 curNavSearch = "";
12072443
12082444 if (location.hash[0] === '#' && location.hash.length > 1) {
1209 var query = location.hash.substring(1);
1210 var qpos = query.indexOf("?");
2445 let query = location.hash.substring(1);
2446 if (query[0] === '*') {
2447 curNav.showPrivDecls = true;
2448 query = query.substring(1);
2449 }
2450
2451 let qpos = query.indexOf("?");
2452 let nonSearchPart;
12112453 if (qpos === -1) {
12122454 nonSearchPart = query;
12132455 } else {
......@@ -1215,16 +2457,12 @@
12152457 curNavSearch = decodeURIComponent(query.substring(qpos + 1));
12162458 }
12172459
1218 var parts = nonSearchPart.split(";");
2460 let parts = nonSearchPart.split(";");
12192461 curNav.pkgNames = decodeURIComponent(parts[0]).split(".");
12202462 if (parts[1] != null) {
12212463 curNav.declNames = decodeURIComponent(parts[1]).split(".");
12222464 }
12232465 }
1224
1225 if (curNav.pkgNames.length === 0 && rootIsStd) {
1226 curNav.pkgNames = ["std"];
1227 }
12282466 }
12292467
12302468 function onHashChange() {
......@@ -1239,43 +2477,65 @@
12392477 }
12402478 }
12412479
2480
12422481 function findSubDecl(parentType, childName) {
1243 if (parentType.pubDecls == null) throw new Error("parent object has no public decls");
1244 for (var i = 0; i < parentType.pubDecls.length; i += 1) {
1245 var declIndex = parentType.pubDecls[i];
1246 var childDecl = zigAnalysis.decls[declIndex];
2482 {
2483 // Generic functions
2484 if ("value" in parentType) {
2485 const rv = resolveValue(parentType.value);
2486 if ("type" in rv.expr) {
2487 const t = zigAnalysis.types[rv.expr.type];
2488 if (t.kind == typeKinds.Fn && t.generic_ret != null) {
2489 const rgr = resolveValue({expr: t.generic_ret});
2490 if ("type" in rgr.expr) {
2491 parentType = zigAnalysis.types[rgr.expr.type];
2492 }
2493 }
2494 }
2495 }
2496 }
2497
2498
2499 if (!parentType.pubDecls) return null;
2500 for (let i = 0; i < parentType.pubDecls.length; i += 1) {
2501 let declIndex = parentType.pubDecls[i];
2502 let childDecl = zigAnalysis.decls[declIndex];
12472503 if (childDecl.name === childName) {
12482504 return childDecl;
12492505 }
12502506 }
1251 return null;
1252 }
1253
1254 function getDeclContainerType(decl) {
1255 if (decl.type === typeTypeId) {
1256 return zigAnalysis.types[decl.value];
2507 if (!parentType.privDecls) return null;
2508 for (let i = 0; i < parentType.privDecls.length; i += 1) {
2509 let declIndex = parentType.privDecls[i];
2510 let childDecl = zigAnalysis.decls[declIndex];
2511 if (childDecl.name === childName) {
2512 return childDecl;
2513 }
12572514 }
12582515 return null;
12592516 }
12602517
2518
2519
2520
12612521 function computeCanonicalPackagePaths() {
1262 var list = new Array(zigAnalysis.packages.length);
2522 let list = new Array(zigAnalysis.packages.length);
12632523 // Now we try to find all the packages from root.
1264 var rootPkg = zigAnalysis.packages[zigAnalysis.rootPkg];
2524 let rootPkg = zigAnalysis.packages[zigAnalysis.rootPkg];
12652525 // Breadth-first to keep the path shortest possible.
1266 var stack = [{
1267 path: [],
2526 let stack = [{
2527 path: ([]),
12682528 pkg: rootPkg,
12692529 }];
12702530 while (stack.length !== 0) {
1271 var item = stack.shift();
1272 for (var key in item.pkg.table) {
1273 var childPkgIndex = item.pkg.table[key];
2531 let item = (stack.shift());
2532 for (let key in item.pkg.table) {
2533 let childPkgIndex = item.pkg.table[key];
12742534 if (list[childPkgIndex] != null) continue;
1275 var childPkg = zigAnalysis.packages[childPkgIndex];
2535 let childPkg = zigAnalysis.packages[childPkgIndex];
12762536 if (childPkg == null) continue;
12772537
1278 var newPath = item.path.concat([key])
2538 let newPath = item.path.concat([key])
12792539 list[childPkgIndex] = newPath;
12802540 stack.push({
12812541 path: newPath,
......@@ -1286,53 +2546,68 @@
12862546 return list;
12872547 }
12882548
1289 function typeKindIsContainer(typeKind) {
1290 return typeKind === typeKinds.Struct ||
1291 typeKind === typeKinds.Union ||
1292 typeKind === typeKinds.Enum;
1293 }
1294
1295 function declCanRepresentTypeKind(typeKind) {
1296 return typeKind === typeKinds.ErrorSet || typeKindIsContainer(typeKind);
1297 }
12982549
2550
12992551 function computeCanonDeclPaths() {
1300 var list = new Array(zigAnalysis.decls.length);
2552 let list = new Array(zigAnalysis.decls.length);
13012553 canonTypeDecls = new Array(zigAnalysis.types.length);
13022554
1303 for (var pkgI = 0; pkgI < zigAnalysis.packages.length; pkgI += 1) {
2555 for (let pkgI = 0; pkgI < zigAnalysis.packages.length; pkgI += 1) {
13042556 if (pkgI === zigAnalysis.rootPkg && rootIsStd) continue;
1305 var pkg = zigAnalysis.packages[pkgI];
1306 var pkgNames = canonPkgPaths[pkgI];
1307 var stack = [{
1308 declNames: [],
2557 let pkg = zigAnalysis.packages[pkgI];
2558 let pkgNames = canonPkgPaths[pkgI];
2559 if (pkgNames === undefined) continue;
2560
2561 let stack = [{
2562 declNames: ([]),
13092563 type: zigAnalysis.types[pkg.main],
13102564 }];
13112565 while (stack.length !== 0) {
1312 var item = stack.shift();
2566 let item = (stack.shift());
2567
2568 if (isContainerType(item.type)) {
2569 let t = (item.type);
13132570
1314 if (item.type.pubDecls != null) {
1315 for (var declI = 0; declI < item.type.pubDecls.length; declI += 1) {
1316 var mainDeclIndex = item.type.pubDecls[declI];
2571 let len = t.pubDecls ? t.pubDecls.length : 0;
2572 for (let declI = 0; declI < len; declI += 1) {
2573 let mainDeclIndex = t.pubDecls[declI];
13172574 if (list[mainDeclIndex] != null) continue;
13182575
1319 var decl = zigAnalysis.decls[mainDeclIndex];
1320 if (decl.type === typeTypeId &&
1321 declCanRepresentTypeKind(zigAnalysis.types[decl.value].kind))
1322 {
1323 canonTypeDecls[decl.value] = mainDeclIndex;
1324 }
1325 var declNames = item.declNames.concat([decl.name]);
2576 let decl = zigAnalysis.decls[mainDeclIndex];
2577 let declVal = decl.value; //resolveValue(decl.value);
2578 let declNames = item.declNames.concat([decl.name]);
13262579 list[mainDeclIndex] = {
13272580 pkgNames: pkgNames,
13282581 declNames: declNames,
13292582 };
1330 var containerType = getDeclContainerType(decl);
1331 if (containerType != null) {
1332 stack.push({
1333 declNames: declNames,
1334 type: containerType,
1335 });
2583 if ("type" in declVal.expr) {
2584 let value = zigAnalysis.types[declVal.expr.type];
2585 if (declCanRepresentTypeKind(value.kind))
2586 {
2587 canonTypeDecls[declVal.type] = mainDeclIndex;
2588 }
2589
2590 if (isContainerType(value)) {
2591 stack.push({
2592 declNames: declNames,
2593 type:value,
2594 });
2595 }
2596
2597
2598 // Generic function
2599 if (value.kind == typeKinds.Fn && value.generic_ret != null) {
2600 let resolvedVal = resolveValue({ expr: value.generic_ret});
2601 if ("type" in resolvedVal.expr) {
2602 let generic_type = zigAnalysis.types[resolvedVal.expr.type];
2603 if (isContainerType(generic_type)){
2604 stack.push({
2605 declNames: declNames,
2606 type: generic_type,
2607 });
2608 }
2609 }
2610 }
13362611 }
13372612 }
13382613 }
......@@ -1341,41 +2616,49 @@
13412616 return list;
13422617 }
13432618
2619
13442620 function getCanonDeclPath(index) {
13452621 if (canonDeclPaths == null) {
13462622 canonDeclPaths = computeCanonDeclPaths();
13472623 }
2624 //let cd = (canonDeclPaths);
13482625 return canonDeclPaths[index];
13492626 }
13502627
2628
13512629 function getCanonTypeDecl(index) {
13522630 getCanonDeclPath(0);
2631 //let ct = (canonTypeDecls);
13532632 return canonTypeDecls[index];
13542633 }
13552634
2635
13562636 function escapeHtml(text) {
13572637 return text.replace(/[&"<>]/g, function (m) {
13582638 return escapeHtmlReplacements[m];
13592639 });
13602640 }
13612641
2642
13622643 function shortDescMarkdown(docs) {
1363 var parts = docs.trim().split("\n");
1364 var firstLine = parts[0];
2644 let parts = docs.trim().split("\n");
2645 let firstLine = parts[0];
13652646 return markdown(firstLine);
13662647 }
13672648
2649
13682650 function markdown(input) {
13692651 const raw_lines = input.split('\n'); // zig allows no '\r', so we don't need to split on CR
2652
13702653 const lines = [];
13712654
13722655 // PHASE 1:
13732656 // Dissect lines and determine the type for each line.
1374 // Also computes indentation level and removes unnecessary whitespace
2657 // Also computes indentation level and removes unnecessary whitespace
13752658
1376 var is_reading_code = false;
1377 var code_indent = 0;
1378 for (var line_no = 0; line_no < raw_lines.length; line_no++) {
2659 let is_reading_code = false;
2660 let code_indent = 0;
2661 for (let line_no = 0; line_no < raw_lines.length; line_no++) {
13792662 const raw_line = raw_lines[line_no];
13802663
13812664 const line = {
......@@ -1383,6 +2666,7 @@
13832666 raw_text: raw_line,
13842667 text: raw_line.trim(),
13852668 type: "p", // p, h1 … h6, code, ul, ol, blockquote, skip, empty
2669 ordered_number: -1, // NOTE: hack to make the type checker happy
13862670 };
13872671
13882672 if (!is_reading_code) {
......@@ -1419,7 +2703,7 @@
14192703 line.text = line.text.substr(1);
14202704 }
14212705 else if (line.text.match(/^\d+\..*$/)) { // if line starts with {number}{dot}
1422 const match = line.text.match(/(\d+)\./);
2706 const match = (line.text.match(/(\d+)\./));
14232707 line.type = "ul";
14242708 line.text = line.text.substr(match[0].length);
14252709 line.ordered_number = Number(match[1].length);
......@@ -1450,21 +2734,24 @@
14502734
14512735 // PHASE 2:
14522736 // Render HTML from markdown lines.
1453 // Look at each line and emit fitting HTML code
2737 // Look at each line and emit fitting HTML code
14542738
1455 function markdownInlines(innerText, stopChar) {
2739
2740 function markdownInlines(innerText) {
14562741
14572742 // inline types:
14582743 // **{INLINE}** : <strong>
1459 // __{INLINE}__ : <u>
1460 // ~~{INLINE}~~ : <s>
1461 // *{INLINE}* : <emph>
1462 // _{INLINE}_ : <emph>
1463 // `{TEXT}` : <code>
1464 // [{INLINE}]({URL}) : <a>
1465 // ![{TEXT}]({URL}) : <img>
1466 // [[std;format.fmt]] : <a> (inner link)
1467
2744 // __{INLINE}__ : <u>
2745 // ~~{INLINE}~~ : <s>
2746 // *{INLINE}* : <emph>
2747 // _{INLINE}_ : <emph>
2748 // `{TEXT}` : <code>
2749 // [{INLINE}]({URL}) : <a>
2750 // ![{TEXT}]({URL}) : <img>
2751 // [[std;format.fmt]] : <a> (inner link)
2752
2753
2754
14682755 const formats = [
14692756 {
14702757 marker: "**",
......@@ -1484,26 +2771,11 @@
14842771 }
14852772 ];
14862773
1487 // Links, images and inner links don't use the same marker to wrap their content.
1488 const linksFormat = [
1489 {
1490 prefix: "[",
1491 regex: /\[([^\]]*)\]\(([^\)]*)\)/,
1492 urlIndex: 2, // Index in the match that contains the link URL
1493 textIndex: 1 // Index in the match that contains the link text
1494 },
1495 {
1496 prefix: "h",
1497 regex: /http[s]?:\/\/[^\s]+/,
1498 urlIndex: 0,
1499 textIndex: 0
1500 }
1501 ];
1502
2774
15032775 const stack = [];
15042776
1505 var innerHTML = "";
1506 var currentRun = "";
2777 let innerHTML = "";
2778 let currentRun = "";
15072779
15082780 function flushRun() {
15092781 if (currentRun != "") {
......@@ -1512,18 +2784,18 @@
15122784 currentRun = "";
15132785 }
15142786
1515 var parsing_code = false;
1516 var codetag = "";
1517 var in_code = false;
2787 let parsing_code = false;
2788 let codetag = "";
2789 let in_code = false;
15182790
1519 for (var i = 0; i < innerText.length; i++) {
2791 for (let i = 0; i < innerText.length; i++) {
15202792
15212793 if (parsing_code && in_code) {
15222794 if (innerText.substr(i, codetag.length) == codetag) {
15232795 // remove leading and trailing whitespace if string both starts and ends with one.
1524 if (currentRun[0] == " " && currentRun[currentRun.length - 1] == " ") {
1525 currentRun = currentRun.substr(1, currentRun.length - 2);
1526 }
2796 if (currentRun[0] == " " && currentRun[currentRun.length - 1] == " ") {
2797 currentRun = currentRun.substr(1, currentRun.length - 2);
2798 }
15272799 flushRun();
15282800 i += codetag.length - 1;
15292801 in_code = false;
......@@ -1550,31 +2822,8 @@
15502822 currentRun += innerText[i];
15512823 in_code = true;
15522824 } else {
1553 var foundMatches = false;
1554
1555 for (var j = 0; j < linksFormat.length; j++) {
1556 const linkFmt = linksFormat[j];
1557
1558 if (linkFmt.prefix == innerText[i]) {
1559 var remaining = innerText.substring(i);
1560 var matches = remaining.match(linkFmt.regex);
1561
1562 if (matches) {
1563 flushRun();
1564 innerHTML += ' <a href="' + matches[linkFmt.urlIndex] + '">' + matches[linkFmt.textIndex] + '</a> ';
1565 i += matches[0].length; // Skip the fragment we just consumed
1566 foundMatches = true;
1567 break;
1568 }
1569 }
1570 }
1571
1572 if (foundMatches) {
1573 continue;
1574 }
1575
1576 var any = false;
1577 for (var idx = (stack.length > 0 ? -1 : 0); idx < formats.length; idx++) {
2825 let any = false;
2826 for (let idx = (stack.length > 0 ? -1 : 0); idx < formats.length; idx++) {
15782827 const fmt = idx >= 0 ? formats[idx] : stack[stack.length - 1];
15792828 if (innerText.substr(i, fmt.marker.length) == fmt.marker) {
15802829 flushRun();
......@@ -1598,48 +2847,54 @@
15982847 flushRun();
15992848
16002849 while (stack.length > 0) {
1601 const fmt = stack.pop();
2850 const fmt = (stack.pop());
16022851 innerHTML += "</" + fmt.tag + ">";
16032852 }
16042853
16052854 return innerHTML;
16062855 }
16072856
1608 var html = "";
1609 for (var line_no = 0; line_no < lines.length; line_no++) {
1610 const line = lines[line_no];
1611
1612 function previousLineIs(type) {
1613 if (line_no > 0) {
1614 return (lines[line_no - 1].type == type);
1615 } else {
1616 return false;
1617 }
2857
2858 function previousLineIs(type, line_no) {
2859 if (line_no > 0) {
2860 return (lines[line_no - 1].type == type);
2861 } else {
2862 return false;
16182863 }
2864 }
16192865
1620 function nextLineIs(type) {
1621 if (line_no < (lines.length - 1)) {
1622 return (lines[line_no + 1].type == type);
1623 } else {
1624 return false;
1625 }
2866
2867 function nextLineIs(type, line_no) {
2868 if (line_no < (lines.length - 1)) {
2869 return (lines[line_no + 1].type == type);
2870 } else {
2871 return false;
16262872 }
2873 }
16272874
1628 function getPreviousLineIndent() {
1629 if (line_no > 0) {
1630 return lines[line_no - 1].indent;
1631 } else {
1632 return 0;
1633 }
2875
2876 function getPreviousLineIndent(line_no) {
2877 if (line_no > 0) {
2878 return lines[line_no - 1].indent;
2879 } else {
2880 return 0;
16342881 }
2882 }
16352883
1636 function getNextLineIndent() {
1637 if (line_no < (lines.length - 1)) {
1638 return lines[line_no + 1].indent;
1639 } else {
1640 return 0;
1641 }
2884
2885 function getNextLineIndent(line_no) {
2886 if (line_no < (lines.length - 1)) {
2887 return lines[line_no + 1].indent;
2888 } else {
2889 return 0;
16422890 }
2891 }
2892
2893 let html = "";
2894 for (let line_no = 0; line_no < lines.length; line_no++) {
2895 const line = lines[line_no];
2896
2897
16432898
16442899 switch (line.type) {
16452900 case "h1":
......@@ -1653,33 +2908,33 @@
16532908
16542909 case "ul":
16552910 case "ol":
1656 if (!previousLineIs("ul") || getPreviousLineIndent() < line.indent) {
2911 if (!previousLineIs("ul", line_no) || getPreviousLineIndent(line_no) < line.indent) {
16572912 html += "<" + line.type + ">\n";
16582913 }
16592914
16602915 html += "<li>" + markdownInlines(line.text) + "</li>\n";
16612916
1662 if (!nextLineIs("ul") || getNextLineIndent() < line.indent) {
2917 if (!nextLineIs("ul", line_no) || getNextLineIndent(line_no) < line.indent) {
16632918 html += "</" + line.type + ">\n";
16642919 }
16652920 break;
16662921
16672922 case "p":
1668 if (!previousLineIs("p")) {
2923 if (!previousLineIs("p", line_no)) {
16692924 html += "<p>\n";
16702925 }
16712926 html += markdownInlines(line.text) + "\n";
1672 if (!nextLineIs("p")) {
2927 if (!nextLineIs("p", line_no)) {
16732928 html += "</p>\n";
16742929 }
16752930 break;
16762931
16772932 case "code":
1678 if (!previousLineIs("code")) {
2933 if (!previousLineIs("code", line_no)) {
16792934 html += "<pre><code>";
16802935 }
16812936 html += escapeHtml(line.text) + "\n";
1682 if (!nextLineIs("code")) {
2937 if (!nextLineIs("code", line_no)) {
16832938 html += "</code></pre>\n";
16842939 }
16852940 break;
......@@ -1694,26 +2949,27 @@
16942949 return;
16952950 }
16962951
1697 var liDom = domListSearchResults.children[curSearchIndex];
2952 let liDom = domListSearchResults.children[curSearchIndex];
16982953 if (liDom == null && domListSearchResults.children.length !== 0) {
16992954 liDom = domListSearchResults.children[0];
17002955 }
17012956 if (liDom != null) {
1702 var aDom = liDom.children[0];
1703 location.href = aDom.getAttribute("href");
2957 let aDom = liDom.children[0];
2958 location.href = (aDom.getAttribute("href"));
17042959 curSearchIndex = -1;
17052960 }
17062961 domSearch.blur();
17072962 }
17082963
2964
17092965 function onSearchKeyDown(ev) {
17102966 switch (getKeyString(ev)) {
17112967 case "Enter":
17122968 // detect if this search changes anything
1713 var terms1 = getSearchTerms();
2969 let terms1 = getSearchTerms();
17142970 startSearch();
17152971 updateCurNav();
1716 var terms2 = getSearchTerms();
2972 let terms2 = getSearchTerms();
17172973 // we might have to wait for onHashChange to trigger
17182974 imFeelingLucky = (terms1.join(' ') !== terms2.join(' '));
17192975 if (!imFeelingLucky) activateSelectedResult();
......@@ -1749,6 +3005,8 @@
17493005 }
17503006 }
17513007
3008
3009
17523010 function moveSearchCursor(dir) {
17533011 if (curSearchIndex < 0 || curSearchIndex >= domListSearchResults.children.length) {
17543012 if (dir > 0) {
......@@ -1768,9 +3026,10 @@
17683026 renderSearchCursor();
17693027 }
17703028
3029
17713030 function getKeyString(ev) {
1772 var name;
1773 var ignoreShift = false;
3031 let name;
3032 let ignoreShift = false;
17743033 switch (ev.which) {
17753034 case 13:
17763035 name = "Enter";
......@@ -1794,6 +3053,7 @@
17943053 return name;
17953054 }
17963055
3056
17973057 function onWindowKeyDown(ev) {
17983058 switch (getKeyString(ev)) {
17993059 case "Esc":
......@@ -1811,214 +3071,160 @@
18113071 startAsyncSearch();
18123072 break;
18133073 case "?":
1814 ev.preventDefault();
3074 ev.preventDefault();
18153075 ev.stopPropagation();
18163076 showHelpModal();
18173077 break;
18183078 }
18193079 }
18203080
1821 function showHelpModal() {
1822 domHelpModal.classList.remove("hidden");
1823 domHelpModal.style.left = (window.innerWidth / 2 - domHelpModal.clientWidth / 2) + "px";
1824 domHelpModal.style.top = (window.innerHeight / 2 - domHelpModal.clientHeight / 2) + "px";
1825 domHelpModal.focus();
1826 }
1827
1828 function onClickSearchShowAllResults(ev) {
1829 ev.preventDefault();
1830 ev.stopPropagation();
1831 searchTrimResults = false;
1832 onHashChange();
1833 }
1834
1835 function clearAsyncSearch() {
1836 if (searchTimer != null) {
1837 clearTimeout(searchTimer);
1838 searchTimer = null;
1839 }
1840 }
1841
1842 function startAsyncSearch() {
1843 clearAsyncSearch();
1844 searchTrimResults = true;
1845 searchTimer = setTimeout(startSearch, 10);
1846 }
1847 function startSearch() {
1848 clearAsyncSearch();
1849 var oldHash = location.hash;
1850 var parts = oldHash.split("?");
1851 var newPart2 = (domSearch.value === "") ? "" : ("?" + domSearch.value);
1852 var newHash = (oldHash === "" ? "#" : parts[0]) + newPart2;
1853 // create a history entry only once per search
1854 if (parts.length === 1) {
1855 location.assign(newHash);
1856 } else {
1857 location.replace(newHash);
1858 }
1859 }
1860 function getSearchTerms() {
1861 var list = curNavSearch.trim().split(/[ \r\n\t]+/);
1862 list.sort();
1863 return list;
1864 }
1865 function renderSearch() {
1866 var matchedItems = [];
1867 var ignoreCase = (curNavSearch.toLowerCase() === curNavSearch);
1868 var terms = getSearchTerms();
1869
1870 decl_loop: for (var declIndex = 0; declIndex < zigAnalysis.decls.length; declIndex += 1) {
1871 var canonPath = getCanonDeclPath(declIndex);
1872 if (canonPath == null) continue;
1873
1874 var decl = zigAnalysis.decls[declIndex];
1875 var lastPkgName = canonPath.pkgNames[canonPath.pkgNames.length - 1];
1876 var fullPathSearchText = lastPkgName + "." + canonPath.declNames.join('.');
1877 var astNode = zigAnalysis.astNodes[decl.src];
1878 var fileAndDocs = zigAnalysis.files[astNode.file];
1879 if (astNode.docs != null) {
1880 fileAndDocs += "\n" + astNode.docs;
1881 }
1882 var fullPathSearchTextLower = fullPathSearchText;
1883 if (ignoreCase) {
1884 fullPathSearchTextLower = fullPathSearchTextLower.toLowerCase();
1885 fileAndDocs = fileAndDocs.toLowerCase();
1886 }
1887
1888 var points = 0;
1889 for (var termIndex = 0; termIndex < terms.length; termIndex += 1) {
1890 var term = terms[termIndex];
1891
1892 // exact, case sensitive match of full decl path
1893 if (fullPathSearchText === term) {
1894 points += 4;
1895 continue;
1896 }
1897 // exact, case sensitive match of just decl name
1898 if (decl.name == term) {
1899 points += 3;
1900 continue;
1901 }
1902 // substring, case insensitive match of full decl path
1903 if (fullPathSearchTextLower.indexOf(term) >= 0) {
1904 points += 2;
1905 continue;
1906 }
1907 if (fileAndDocs.indexOf(term) >= 0) {
1908 points += 1;
1909 continue;
1910 }
1911
1912 continue decl_loop;
3081function showHelpModal() {
3082 domHelpModal.classList.remove("hidden");
3083 domHelpModal.style.left = (window.innerWidth / 2 - domHelpModal.clientWidth / 2) + "px";
3084 domHelpModal.style.top = (window.innerHeight / 2 - domHelpModal.clientHeight / 2) + "px";
3085 domHelpModal.focus();
3086}
3087
3088function clearAsyncSearch() {
3089 if (searchTimer != null) {
3090 clearTimeout(searchTimer);
3091 searchTimer = null;
3092 }
3093}
3094
3095function startAsyncSearch() {
3096 clearAsyncSearch();
3097 searchTimer = setTimeout(startSearch, 100);
3098}
3099function startSearch() {
3100 clearAsyncSearch();
3101 let oldHash = location.hash;
3102 let parts = oldHash.split("?");
3103 let newPart2 = (domSearch.value === "") ? "" : ("?" + domSearch.value);
3104 location.hash = (parts.length === 1) ? (oldHash + newPart2) : (parts[0] + newPart2);
3105}
3106function getSearchTerms() {
3107 let list = curNavSearch.trim().split(/[ \r\n\t]+/);
3108 list.sort();
3109 return list;
3110}
3111function renderSearch() {
3112 let matchedItems = [];
3113 let ignoreCase = (curNavSearch.toLowerCase() === curNavSearch);
3114 let terms = getSearchTerms();
3115
3116 decl_loop: for (let declIndex = 0; declIndex < zigAnalysis.decls.length; declIndex += 1) {
3117 let canonPath = getCanonDeclPath(declIndex);
3118 if (canonPath == null) continue;
3119
3120 let decl = zigAnalysis.decls[declIndex];
3121 let lastPkgName = canonPath.pkgNames[canonPath.pkgNames.length - 1];
3122 let fullPathSearchText = lastPkgName + "." + canonPath.declNames.join('.');
3123 let astNode = zigAnalysis.astNodes[decl.src];
3124 let fileAndDocs = "" //zigAnalysis.files[astNode.file];
3125 // TODO: understand what this piece of code is trying to achieve
3126 // also right now `files` are expressed as a hashmap.
3127 if (astNode.docs != null) {
3128 fileAndDocs += "\n" + astNode.docs;
3129 }
3130 let fullPathSearchTextLower = fullPathSearchText;
3131 if (ignoreCase) {
3132 fullPathSearchTextLower = fullPathSearchTextLower.toLowerCase();
3133 fileAndDocs = fileAndDocs.toLowerCase();
3134 }
3135
3136 let points = 0;
3137 for (let termIndex = 0; termIndex < terms.length; termIndex += 1) {
3138 let term = terms[termIndex];
3139
3140 // exact, case sensitive match of full decl path
3141 if (fullPathSearchText === term) {
3142 points += 4;
3143 continue;
3144 }
3145 // exact, case sensitive match of just decl name
3146 if (decl.name == term) {
3147 points += 3;
3148 continue;
3149 }
3150 // substring, case insensitive match of full decl path
3151 if (fullPathSearchTextLower.indexOf(term) >= 0) {
3152 points += 2;
3153 continue;
3154 }
3155 if (fileAndDocs.indexOf(term) >= 0) {
3156 points += 1;
3157 continue;
19133158 }
19143159
1915 matchedItems.push({
1916 decl: decl,
1917 path: canonPath,
1918 points: points,
1919 });
3160 continue decl_loop;
19203161 }
19213162
1922 if (matchedItems.length !== 0) {
1923 matchedItems.sort(function(a, b) {
1924 var cmp = operatorCompare(b.points, a.points);
1925 if (cmp != 0) return cmp;
1926 return operatorCompare(a.decl.name, b.decl.name);
1927 });
3163 matchedItems.push({
3164 decl: decl,
3165 path: canonPath,
3166 points: points,
3167 });
3168 }
19283169
1929 var searchTrimmed = false
1930 var searchTrimResultsMaxItems = 200
1931 if (searchTrimResults && matchedItems.length > searchTrimResultsMaxItems) {
1932 matchedItems = matchedItems.slice(0, searchTrimResultsMaxItems)
1933 searchTrimmed = true
1934 }
3170 if (matchedItems.length !== 0) {
3171 resizeDomList(domListSearchResults, matchedItems.length, '<li><a href="#"></a></li>');
19353172
1936 var domListSearchResultsFragment = createDomListFragment(matchedItems.length, '<li><a href="#"></a></li>');
1937 for (var i = 0; i < matchedItems.length; i += 1) {
1938 var liDom = domListSearchResultsFragment.children[i];
1939 var aDom = liDom.children[0];
1940 var match = matchedItems[i];
1941 var lastPkgName = match.path.pkgNames[match.path.pkgNames.length - 1];
1942 aDom.textContent = lastPkgName + "." + match.path.declNames.join('.');
1943 aDom.setAttribute('href', navLink(match.path.pkgNames, match.path.declNames));
1944 }
3173 matchedItems.sort(function(a, b) {
3174 let cmp = operatorCompare(b.points, a.points);
3175 if (cmp != 0) return cmp;
3176 return operatorCompare(a.decl.name, b.decl.name);
3177 });
19453178
1946 domListSearchResults.innerHTML = "";
1947 domListSearchResults.appendChild(domListSearchResultsFragment);
1948 domSectSearchResults.classList.remove("hidden");
3179 for (let i = 0; i < matchedItems.length; i += 1) {
3180 let liDom = domListSearchResults.children[i];
3181 let aDom = liDom.children[0];
3182 let match = matchedItems[i];
3183 let lastPkgName = match.path.pkgNames[match.path.pkgNames.length - 1];
3184 aDom.textContent = lastPkgName + "." + match.path.declNames.join('.');
3185 aDom.setAttribute('href', navLink(match.path.pkgNames, match.path.declNames));
3186 }
3187 renderSearchCursor();
19493188
1950 if (searchTrimmed) {
1951 domSectSearchAllResultsLink.classList.remove("hidden");
1952 }
3189 domSectSearchResults.classList.remove("hidden");
3190 } else {
3191 domSectSearchNoResults.classList.remove("hidden");
3192 }
3193}
19533194
1954 renderSearchCursor();
3195function renderSearchCursor() {
3196 for (let i = 0; i < domListSearchResults.children.length; i += 1) {
3197 let liDom = (domListSearchResults.children[i]);
3198 if (curSearchIndex === i) {
3199 liDom.classList.add("selected");
19553200 } else {
1956 domSectSearchNoResults.classList.remove("hidden");
3201 liDom.classList.remove("selected");
19573202 }
19583203 }
3204}
19593205
1960 function renderSearchCursor() {
1961 for (var i = 0; i < domListSearchResults.children.length; i += 1) {
1962 var liDom = domListSearchResults.children[i];
1963 if (curSearchIndex === i) {
1964 liDom.classList.add("selected");
1965 } else {
1966 liDom.classList.remove("selected");
1967 }
1968 }
1969 }
19703206
1971 function indexNodesToFns() {
1972 var map = {};
1973 for (var i = 0; i < zigAnalysis.fns.length; i += 1) {
1974 var fn = zigAnalysis.fns[i];
1975 if (typeIsGenericFn(fn.type)) continue;
1976 if (map[fn.src] == null) {
1977 map[fn.src] = [i];
1978 } else {
1979 map[fn.src].push(i);
1980 }
1981 }
1982 return map;
1983 }
19843207
1985 function indexNodesToCalls() {
1986 var map = {};
1987 for (var i = 0; i < zigAnalysis.calls.length; i += 1) {
1988 var call = zigAnalysis.calls[i];
1989 var fn = zigAnalysis.fns[call.fn];
1990 if (map[fn.src] == null) {
1991 map[fn.src] = [i];
1992 } else {
1993 map[fn.src].push(i);
1994 }
1995 }
1996 return map;
1997 }
3208// function indexNodesToCalls() {
3209// let map = {};
3210// for (let i = 0; i < zigAnalysis.calls.length; i += 1) {
3211// let call = zigAnalysis.calls[i];
3212// let fn = zigAnalysis.fns[call.fn];
3213// if (map[fn.src] == null) {
3214// map[fn.src] = [i];
3215// } else {
3216// map[fn.src].push(i);
3217// }
3218// }
3219// return map;
3220// }
19983221
1999 function byNameProperty(a, b) {
2000 return operatorCompare(a.name, b.name);
2001 }
20023222
2003 function clone(obj) {
2004 var res = {};
2005 for (var key in obj) {
2006 res[key] = obj[key];
2007 }
2008 return res;
2009 }
20103223
2011 function firstObjectKey(obj) {
2012 for (var key in obj) {
2013 return key;
2014 }
2015 }
3224function byNameProperty(a, b) {
3225 return operatorCompare(a.name, b.name);
3226}
3227
3228
20163229
2017 function token(value, tokenClass, wantHtml){
2018 if(wantHtml){
2019 return '<span class="' + tokenClass + '">' + value + '</span>';
2020 } else {
2021 return value + '';
2022 }
2023 }
20243230})();
src/Autodoc.zig created+3890
......@@ -0,0 +1,3890 @@
1const std = @import("std");
2const build_options = @import("build_options");
3const Autodoc = @This();
4const Compilation = @import("Compilation.zig");
5const Module = @import("Module.zig");
6const File = Module.File;
7const Package = @import("Package.zig");
8const Zir = @import("Zir.zig");
9const Ref = Zir.Inst.Ref;
10const log = std.log.scoped(.autodoc);
11
12module: *Module,
13doc_location: Compilation.EmitLoc,
14arena: std.mem.Allocator,
15
16// The goal of autodoc is to fill up these arrays
17// that will then be serialized as JSON and consumed
18// by the JS frontend.
19packages: std.AutoArrayHashMapUnmanaged(*Package, DocData.DocPackage) = .{},
20files: std.AutoArrayHashMapUnmanaged(*File, usize) = .{},
21calls: std.ArrayListUnmanaged(DocData.Call) = .{},
22types: std.ArrayListUnmanaged(DocData.Type) = .{},
23decls: std.ArrayListUnmanaged(DocData.Decl) = .{},
24exprs: std.ArrayListUnmanaged(DocData.Expr) = .{},
25ast_nodes: std.ArrayListUnmanaged(DocData.AstNode) = .{},
26comptime_exprs: std.ArrayListUnmanaged(DocData.ComptimeExpr) = .{},
27
28// These fields hold temporary state of the analysis process
29// and are mainly used by the decl path resolving algorithm.
30pending_ref_paths: std.AutoHashMapUnmanaged(
31 *DocData.Expr, // pointer to declpath tail end (ie `&decl_path[decl_path.len - 1]`)
32 std.ArrayListUnmanaged(RefPathResumeInfo),
33) = .{},
34ref_paths_pending_on_decls: std.AutoHashMapUnmanaged(
35 usize,
36 std.ArrayListUnmanaged(RefPathResumeInfo),
37) = .{},
38ref_paths_pending_on_types: std.AutoHashMapUnmanaged(
39 usize,
40 std.ArrayListUnmanaged(RefPathResumeInfo),
41) = .{},
42
43const RefPathResumeInfo = struct {
44 file: *File,
45 ref_path: []DocData.Expr,
46};
47
48var arena_allocator: std.heap.ArenaAllocator = undefined;
49pub fn init(m: *Module, doc_location: Compilation.EmitLoc) Autodoc {
50 arena_allocator = std.heap.ArenaAllocator.init(m.gpa);
51 return .{
52 .module = m,
53 .doc_location = doc_location,
54 .arena = arena_allocator.allocator(),
55 };
56}
57
58pub fn deinit(_: *Autodoc) void {
59 arena_allocator.deinit();
60}
61
62/// The entry point of the Autodoc generation process.
63pub fn generateZirData(self: *Autodoc) !void {
64 if (self.doc_location.directory) |dir| {
65 if (dir.path) |path| {
66 log.debug("path: {s}", .{path});
67 }
68 }
69
70 const root_src_dir = self.module.main_pkg.root_src_directory;
71 const root_src_path = self.module.main_pkg.root_src_path;
72 const joined_src_path = try root_src_dir.join(self.arena, &.{root_src_path});
73 defer self.arena.free(joined_src_path);
74
75 const abs_root_src_path = try std.fs.path.resolve(self.arena, &.{ ".", joined_src_path });
76 defer self.arena.free(abs_root_src_path);
77
78 const file = self.module.import_table.get(abs_root_src_path).?; // file is expected to be present in the import table
79 // Append all the types in Zir.Inst.Ref.
80 {
81 try self.types.append(self.arena, .{
82 .ComptimeExpr = .{ .name = "ComptimeExpr" },
83 });
84
85 // this skipts Ref.none but it's ok becuse we replaced it with ComptimeExpr
86 var i: u32 = 1;
87 while (i <= @enumToInt(Ref.anyerror_void_error_union_type)) : (i += 1) {
88 var tmpbuf = std.ArrayList(u8).init(self.arena);
89 try Ref.typed_value_map[i].val.fmtDebug().format("", .{}, tmpbuf.writer());
90 try self.types.append(
91 self.arena,
92 switch (@intToEnum(Ref, i)) {
93 else => blk: {
94 // TODO: map the remaining refs to a correct type
95 // instead of just assinging "array" to them.
96 break :blk .{
97 .Array = .{
98 .len = .{
99 .int = .{
100 .value = 1,
101 .negated = false,
102 },
103 },
104 .child = .{ .type = 0 },
105 },
106 };
107 },
108 .u1_type,
109 .u8_type,
110 .i8_type,
111 .u16_type,
112 .i16_type,
113 .u32_type,
114 .i32_type,
115 .u64_type,
116 .i64_type,
117 .u128_type,
118 .i128_type,
119 .usize_type,
120 .isize_type,
121 .c_short_type,
122 .c_ushort_type,
123 .c_int_type,
124 .c_uint_type,
125 .c_long_type,
126 .c_ulong_type,
127 .c_longlong_type,
128 .c_ulonglong_type,
129 .c_longdouble_type,
130 => .{
131 .Int = .{ .name = tmpbuf.toOwnedSlice() },
132 },
133 .f16_type,
134 .f32_type,
135 .f64_type,
136 .f128_type,
137 => .{
138 .Float = .{ .name = tmpbuf.toOwnedSlice() },
139 },
140 .comptime_int_type => .{
141 .ComptimeInt = .{ .name = tmpbuf.toOwnedSlice() },
142 },
143 .comptime_float_type => .{
144 .ComptimeFloat = .{ .name = tmpbuf.toOwnedSlice() },
145 },
146
147 .anyopaque_type => .{
148 .ComptimeExpr = .{ .name = tmpbuf.toOwnedSlice() },
149 },
150 .bool_type => .{
151 .Bool = .{ .name = tmpbuf.toOwnedSlice() },
152 },
153
154 .noreturn_type => .{
155 .NoReturn = .{ .name = tmpbuf.toOwnedSlice() },
156 },
157 .void_type => .{
158 .Void = .{ .name = tmpbuf.toOwnedSlice() },
159 },
160 .type_type => .{
161 .Type = .{ .name = tmpbuf.toOwnedSlice() },
162 },
163 .anyerror_type => .{
164 .ErrorSet = .{ .name = tmpbuf.toOwnedSlice() },
165 },
166 .calling_convention_inline, .calling_convention_c, .calling_convention_type => .{
167 .EnumLiteral = .{ .name = tmpbuf.toOwnedSlice() },
168 },
169 },
170 );
171 }
172 }
173
174 const main_type_index = self.types.items.len;
175 {
176 try self.packages.put(self.arena, self.module.main_pkg, .{
177 .name = "root",
178 .main = main_type_index,
179 .table = .{},
180 });
181 try self.packages.entries.items(.value)[0].table.put(
182 self.arena,
183 self.module.main_pkg,
184 .{
185 .name = "root",
186 .value = 0,
187 },
188 );
189 }
190
191 var root_scope = Scope{ .parent = null, .enclosing_type = main_type_index };
192 try self.ast_nodes.append(self.arena, .{ .name = "(root)" });
193 try self.files.put(self.arena, file, main_type_index);
194 _ = try self.walkInstruction(file, &root_scope, Zir.main_struct_inst, false);
195
196 if (self.ref_paths_pending_on_decls.count() > 0) {
197 @panic("some decl paths were never fully analized (pending on decls)");
198 }
199
200 if (self.ref_paths_pending_on_types.count() > 0) {
201 @panic("some decl paths were never fully analized (pending on types)");
202 }
203
204 if (self.pending_ref_paths.count() > 0) {
205 @panic("some decl paths were never fully analized");
206 }
207
208 const rootName = blk: {
209 const rootName = std.fs.path.basename(self.module.main_pkg.root_src_path);
210 break :blk rootName[0 .. rootName.len - 4];
211 };
212 var data = DocData{
213 .rootPkgName = rootName,
214 .params = .{ .rootName = "root" },
215 .packages = self.packages.values(),
216 .files = self.files,
217 .calls = self.calls.items,
218 .types = self.types.items,
219 .decls = self.decls.items,
220 .exprs = self.exprs.items,
221 .astNodes = self.ast_nodes.items,
222 .comptimeExprs = self.comptime_exprs.items,
223 };
224
225 if (self.doc_location.directory) |d| {
226 d.handle.makeDir(
227 self.doc_location.basename,
228 ) catch |e| switch (e) {
229 error.PathAlreadyExists => {},
230 else => |err| return err,
231 };
232 } else {
233 self.module.zig_cache_artifact_directory.handle.makeDir(
234 self.doc_location.basename,
235 ) catch |e| switch (e) {
236 error.PathAlreadyExists => {},
237 else => |err| return err,
238 };
239 }
240 const output_dir = if (self.doc_location.directory) |d|
241 try d.handle.openDir(self.doc_location.basename, .{})
242 else
243 try self.module.zig_cache_artifact_directory.handle.openDir(self.doc_location.basename, .{});
244 {
245 const data_js_f = try output_dir.createFile("data.js", .{});
246 defer data_js_f.close();
247 var buffer = std.io.bufferedWriter(data_js_f.writer());
248
249 const out = buffer.writer();
250 try out.print(
251 \\ /** @type {{DocData}} */
252 \\ var zigAnalysis=
253 , .{});
254 try std.json.stringify(
255 data,
256 .{
257 .whitespace = .{},
258 .emit_null_optional_fields = false,
259 },
260 out,
261 );
262 try out.print(";", .{});
263
264 // last thing (that can fail) that we do is flush
265 try buffer.flush();
266 }
267
268 // copy main.js, index.html
269 var docs_dir = try self.module.comp.zig_lib_directory.handle.openDir("docs", .{});
270 defer docs_dir.close();
271 try docs_dir.copyFile("main.js", output_dir, "main.js", .{});
272 try docs_dir.copyFile("index.html", output_dir, "index.html", .{});
273}
274
275/// Represents a chain of scopes, used to resolve decl references to the
276/// corresponding entry in `self.decls`.
277const Scope = struct {
278 parent: ?*Scope,
279 map: std.AutoHashMapUnmanaged(u32, usize) = .{}, // index into `decls`
280 enclosing_type: usize, // index into `types`
281
282 /// Assumes all decls in present scope and upper scopes have already
283 /// been either fully resolved or at least reserved.
284 pub fn resolveDeclName(self: Scope, string_table_idx: u32) usize {
285 var cur: ?*const Scope = &self;
286 return while (cur) |s| : (cur = s.parent) {
287 break s.map.get(string_table_idx) orelse continue;
288 } else unreachable;
289 }
290
291 pub fn insertDeclRef(
292 self: *Scope,
293 arena: std.mem.Allocator,
294 decl_name_index: u32, // decl name
295 decls_slot_index: usize,
296 ) !void {
297 try self.map.put(arena, decl_name_index, decls_slot_index);
298 }
299};
300
301/// The output of our analysis process.
302const DocData = struct {
303 typeKinds: []const []const u8 = std.meta.fieldNames(DocTypeKinds),
304 rootPkg: u32 = 0,
305 rootPkgName: []const u8,
306 params: struct {
307 zigId: []const u8 = "arst",
308 zigVersion: []const u8 = build_options.version,
309 target: []const u8 = "arst",
310 rootName: []const u8,
311 builds: []const struct { target: []const u8 } = &.{
312 .{ .target = "arst" },
313 },
314 },
315 packages: []const DocPackage,
316 errors: []struct {} = &.{},
317
318 // non-hardcoded stuff
319 astNodes: []AstNode,
320 calls: []Call,
321 files: std.AutoArrayHashMapUnmanaged(*File, usize),
322 types: []Type,
323 decls: []Decl,
324 exprs: []Expr,
325 comptimeExprs: []ComptimeExpr,
326 const Call = struct {
327 func: Expr,
328 args: []Expr,
329 ret: Expr,
330 };
331
332 pub fn jsonStringify(
333 self: DocData,
334 opts: std.json.StringifyOptions,
335 w: anytype,
336 ) !void {
337 var jsw = std.json.writeStream(w, 15);
338 try jsw.beginObject();
339 inline for (comptime std.meta.tags(std.meta.FieldEnum(DocData))) |f| {
340 const f_name = @tagName(f);
341 try jsw.objectField(f_name);
342 switch (f) {
343 .files => try writeFileTableToJson(self.files, &jsw),
344 else => {
345 try std.json.stringify(@field(self, f_name), opts, w);
346 jsw.state_index -= 1;
347 },
348 }
349 }
350 try jsw.endObject();
351 }
352 /// All the type "families" as described by `std.builtin.TypeId`
353 /// plus a couple extra that are unique to our use case.
354 ///
355 /// `Unanalyzed` is used so that we can refer to types that have started
356 /// analysis but that haven't been fully analyzed yet (in case we find
357 /// self-referential stuff, like `@This()`).
358 ///
359 /// `ComptimeExpr` represents the result of a piece of comptime logic
360 /// that we weren't able to analyze fully. Examples of that are comptime
361 /// function calls and comptime if / switch / ... expressions.
362 const DocTypeKinds = @typeInfo(Type).Union.tag_type.?;
363
364 const ComptimeExpr = struct {
365 code: []const u8,
366 };
367 const DocPackage = struct {
368 name: []const u8 = "(root)",
369 file: usize = 0, // index into `files`
370 main: usize = 0, // index into `types`
371 table: std.AutoHashMapUnmanaged(*Package, TableEntry),
372 pub const TableEntry = struct {
373 name: []const u8,
374 value: usize,
375 };
376
377 pub fn jsonStringify(
378 self: DocPackage,
379 opts: std.json.StringifyOptions,
380 w: anytype,
381 ) !void {
382 var jsw = std.json.writeStream(w, 15);
383 try jsw.beginObject();
384 inline for (comptime std.meta.tags(std.meta.FieldEnum(DocPackage))) |f| {
385 const f_name = @tagName(f);
386 try jsw.objectField(f_name);
387 switch (f) {
388 .table => try writePackageTableToJson(self.table, &jsw),
389 else => {
390 try std.json.stringify(@field(self, f_name), opts, w);
391 jsw.state_index -= 1;
392 },
393 }
394 }
395 try jsw.endObject();
396 }
397 };
398
399 const Decl = struct {
400 name: []const u8,
401 kind: []const u8,
402 isTest: bool,
403 src: usize, // index into astNodes
404 value: WalkResult,
405 // The index in astNodes of the `test declname { }` node
406 decltest: ?usize = null,
407 _analyzed: bool, // omitted in json data
408 };
409
410 const AstNode = struct {
411 file: usize = 0, // index into files
412 line: usize = 0,
413 col: usize = 0,
414 name: ?[]const u8 = null,
415 docs: ?[]const u8 = null,
416 fields: ?[]usize = null, // index into astNodes
417 @"comptime": bool = false,
418 };
419
420 const Type = union(enum) {
421 Unanalyzed: struct {},
422 Type: struct { name: []const u8 },
423 Void: struct { name: []const u8 },
424 Bool: struct { name: []const u8 },
425 NoReturn: struct { name: []const u8 },
426 Int: struct { name: []const u8 },
427 Float: struct { name: []const u8 },
428 Pointer: struct {
429 size: std.builtin.TypeInfo.Pointer.Size,
430 child: Expr,
431 sentinel: ?Expr = null,
432 @"align": ?Expr = null,
433 address_space: ?Expr = null,
434 bit_start: ?Expr = null,
435 host_size: ?Expr = null,
436 is_ref: bool = false,
437 is_allowzero: bool = false,
438 is_mutable: bool = false,
439 is_volatile: bool = false,
440 has_sentinel: bool = false,
441 has_align: bool = false,
442 has_addrspace: bool = false,
443 has_bit_range: bool = false,
444 },
445 Array: struct {
446 len: Expr,
447 child: Expr,
448 sentinel: ?Expr = null,
449 },
450 Struct: struct {
451 name: []const u8,
452 src: usize, // index into astNodes
453 privDecls: []usize = &.{}, // index into decls
454 pubDecls: []usize = &.{}, // index into decls
455 fields: ?[]Expr = null, // (use src->fields to find names)
456 line_number: usize,
457 outer_decl: usize,
458 ast: usize,
459 },
460 ComptimeExpr: struct { name: []const u8 },
461 ComptimeFloat: struct { name: []const u8 },
462 ComptimeInt: struct { name: []const u8 },
463 Undefined: struct { name: []const u8 },
464 Null: struct { name: []const u8 },
465 Optional: struct {
466 name: []const u8,
467 child: Expr,
468 },
469 ErrorUnion: struct { lhs: Expr, rhs: Expr },
470 // ErrorUnion: struct { name: []const u8 },
471 ErrorSet: struct {
472 name: []const u8,
473 fields: ?[]const Field = null,
474 // TODO: fn field for inferred error sets?
475 },
476 Enum: struct {
477 name: []const u8,
478 src: usize, // index into astNodes
479 privDecls: []usize = &.{}, // index into decls
480 pubDecls: []usize = &.{}, // index into decls
481 ast: usize,
482 // (use src->fields to find field names)
483 },
484 Union: struct {
485 name: []const u8,
486 src: usize, // index into astNodes
487 privDecls: []usize = &.{}, // index into decls
488 pubDecls: []usize = &.{}, // index into decls
489 fields: []Expr = &.{}, // (use src->fields to find names)
490 ast: usize,
491 },
492 Fn: struct {
493 name: []const u8,
494 src: ?usize = null, // index into `astNodes`
495 ret: Expr,
496 generic_ret: ?Expr = null,
497 params: ?[]Expr = null, // (use src->fields to find names)
498 lib_name: []const u8 = "",
499 is_var_args: bool = false,
500 is_inferred_error: bool = false,
501 has_lib_name: bool = false,
502 has_cc: bool = false,
503 cc: ?usize = null,
504 @"align": ?usize = null,
505 has_align: bool = false,
506 is_test: bool = false,
507 is_extern: bool = false,
508 },
509 BoundFn: struct { name: []const u8 },
510 Opaque: struct { name: []const u8 },
511 Frame: struct { name: []const u8 },
512 AnyFrame: struct { name: []const u8 },
513 Vector: struct { name: []const u8 },
514 EnumLiteral: struct { name: []const u8 },
515
516 const Field = struct {
517 name: []const u8,
518 docs: []const u8,
519 };
520
521 pub fn jsonStringify(
522 self: Type,
523 opts: std.json.StringifyOptions,
524 w: anytype,
525 ) !void {
526 const active_tag = std.meta.activeTag(self);
527 var jsw = std.json.writeStream(w, 15);
528 try jsw.beginObject();
529 try jsw.objectField("kind");
530 try jsw.emitNumber(@enumToInt(active_tag));
531 inline for (comptime std.meta.fields(Type)) |case| {
532 if (@field(Type, case.name) == active_tag) {
533 const current_value = @field(self, case.name);
534 inline for (comptime std.meta.fields(case.field_type)) |f| {
535 try jsw.objectField(f.name);
536 if (f.field_type == std.builtin.TypeInfo.Pointer.Size) {
537 try jsw.emitNumber(@enumToInt(@field(current_value, f.name)));
538 } else {
539 try std.json.stringify(@field(current_value, f.name), opts, w);
540 jsw.state_index -= 1;
541 }
542 }
543 }
544 }
545 try jsw.endObject();
546 }
547 };
548
549 /// An Expr represents the (untyped) result of analizing instructions.
550 /// The data is normalized, which means that an Expr that results in a
551 /// type definition will hold an index into `self.types`.
552 pub const Expr = union(enum) {
553 comptimeExpr: usize, // index in `comptimeExprs`
554 void: struct {},
555 @"unreachable": struct {},
556 @"null": struct {},
557 @"undefined": struct {},
558 @"struct": []FieldVal,
559 bool: bool,
560 @"anytype": struct {},
561 @"&": usize, // index in `exprs`
562 type: usize, // index in `types`
563 this: usize, // index in `types`
564 declRef: usize, // index in `decls`
565 fieldRef: FieldRef,
566 refPath: []Expr,
567 int: struct {
568 value: u64, // direct value
569 negated: bool = false,
570 },
571 int_big: struct {
572 value: []const u8, // direct value
573 negated: bool = false,
574 },
575 float: f64, // direct value
576 float128: f128, // direct value
577 array: []usize, // index in `exprs`
578 call: usize, // index in `calls`
579 enumLiteral: []const u8, // direct value
580 alignOf: usize, // index in `exprs`
581 typeOf: usize, // index in `exprs`
582 typeOf_peer: []usize,
583 errorUnion: usize, // index in `exprs`
584 as: As,
585 sizeOf: usize, // index in `exprs`
586 bitSizeOf: usize, // index in `exprs`
587 enumToInt: usize, // index in `exprs`
588 compileError: []const u8,
589 errorSets: usize,
590 string: []const u8, // direct value
591 sliceIndex: usize,
592 slice: Slice,
593 cmpxchgIndex: usize,
594 cmpxchg: Cmpxchg,
595 builtin: Builtin,
596 builtinIndex: usize,
597 builtinBin: BuiltinBin,
598 builtinBinIndex: usize,
599 switchIndex: usize, // index in `exprs`
600 switchOp: SwitchOp,
601 binOp: BinOp,
602 binOpIndex: usize,
603 const BinOp = struct {
604 lhs: usize, // index in `exprs`
605 rhs: usize, // index in `exprs`
606 name: []const u8 = "", // tag name
607 };
608 const SwitchOp = struct {
609 cond_index: usize,
610 file_name: []const u8,
611 ast: usize,
612 outer_decl: usize, // index in `types`
613 };
614 const BuiltinBin = struct {
615 name: []const u8 = "", // fn name
616 lhs: usize, // index in `exprs`
617 rhs: usize, // index in `exprs`
618 };
619 const Builtin = struct {
620 name: []const u8 = "", // fn name
621 param: usize, // index in `exprs`
622 };
623 const Slice = struct {
624 lhs: usize, // index in `exprs`
625 start: usize,
626 end: ?usize = null,
627 sentinel: ?usize = null, // index in `exprs`
628 };
629 const Cmpxchg = struct { name: []const u8, type: usize, ptr: usize, expected_value: usize, new_value: usize, success_order: usize, failure_order: usize };
630 const As = struct {
631 typeRefArg: ?usize, // index in `exprs`
632 exprArg: usize, // index in `exprs`
633 };
634 const FieldRef = struct {
635 type: usize, // index in `types`
636 index: usize, // index in type.fields
637 };
638
639 const FieldVal = struct {
640 name: []const u8,
641 val: WalkResult,
642 };
643
644 pub fn jsonStringify(
645 self: Expr,
646 opt: std.json.StringifyOptions,
647 w: anytype,
648 ) !void {
649 const active_tag = std.meta.activeTag(self);
650 var jsw = std.json.writeStream(w, 15);
651 try jsw.beginObject();
652 try jsw.objectField(@tagName(active_tag));
653 inline for (comptime std.meta.fields(Expr)) |case| {
654 if (@field(Expr, case.name) == active_tag) {
655 switch (active_tag) {
656 .int => {
657 if (self.int.negated) try w.writeAll("-");
658 try jsw.emitNumber(self.int.value);
659 },
660 .int_big => {
661
662 //@panic("TODO: json serialization of big ints!");
663 //if (v.negated) try w.writeAll("-");
664 //try jsw.emitNumber(v.value);
665 },
666 else => {
667 try std.json.stringify(@field(self, case.name), opt, w);
668 jsw.state_index -= 1;
669 // TODO: we should not reach into the state of the
670 // json writer, but alas, this is what's
671 // necessary with the current api.
672 // would be nice to have a proper integration
673 // between the json writer and the generic
674 // std.json.stringify implementation
675 },
676 }
677 }
678 }
679 try jsw.endObject();
680 }
681 };
682
683 /// A WalkResult represents the result of the analysis process done to a
684 /// a Zir instruction. Walk results carry type information either inferred
685 /// from the context (eg string literals are pointers to null-terminated
686 /// arrays), or because of @as() instructions.
687 /// Since the type information is only needed in certain contexts, the
688 /// underlying normalized data (Expr) is untyped.
689 const WalkResult = struct {
690 typeRef: ?Expr = null, // index in `exprs`
691 expr: Expr, // index in `exprs`
692 };
693};
694
695const AutodocErrors = error{
696 OutOfMemory,
697 CurrentWorkingDirectoryUnlinked,
698 Unexpected,
699};
700
701/// Called when we need to analyze a Zir instruction.
702/// For example it gets called by `generateZirData` on instruction 0,
703/// which represents the top-level struct corresponding to the root file.
704/// Note that in some situations where we're analyzing code that only allows
705/// for a limited subset of Zig syntax, we don't always resort to calling
706/// `walkInstruction` and instead sometimes we handle Zir directly.
707/// The best example of that are instructions corresponding to function
708/// params, as those can only occur while analyzing a function definition.
709fn walkInstruction(
710 self: *Autodoc,
711 file: *File,
712 parent_scope: *Scope,
713 inst_index: usize,
714 need_type: bool, // true if the caller needs us to provide also a typeRef
715) AutodocErrors!DocData.WalkResult {
716 const tags = file.zir.instructions.items(.tag);
717 const data = file.zir.instructions.items(.data);
718
719 // We assume that the topmost ast_node entry corresponds to our decl
720 const self_ast_node_index = self.ast_nodes.items.len - 1;
721
722 switch (tags[inst_index]) {
723 else => {
724 printWithContext(
725 file,
726 inst_index,
727 "TODO: implement `{s}` for walkInstruction\n\n",
728 .{@tagName(tags[inst_index])},
729 );
730 return self.cteTodo(@tagName(tags[inst_index]));
731 },
732 .import => {
733 const str_tok = data[inst_index].str_tok;
734 var path = str_tok.get(file.zir);
735
736 const maybe_other_package: ?*Package = blk: {
737 if (self.module.main_pkg_in_std and std.mem.eql(u8, path, "std")) {
738 path = "root";
739 break :blk self.module.main_pkg;
740 } else {
741 break :blk file.pkg.table.get(path);
742 }
743 };
744 // importFile cannot error out since all files
745 // are already loaded at this point
746 if (maybe_other_package) |other_package| {
747 const result = try self.packages.getOrPut(self.arena, other_package);
748
749 // Immediately add this package to the import table of our
750 // current package, regardless of wether it's new or not.
751 if (self.packages.getPtr(file.pkg)) |current_package| {
752 // TODO: apparently, in the stdlib a file gets analized before
753 // its package gets added. I guess we're importing a file
754 // that belongs to another package through its file path?
755 // (ie not through its package name).
756 // We're bailing for now, but maybe we shouldn't?
757 _ = try current_package.table.getOrPutValue(
758 self.arena,
759 other_package,
760 .{
761 .name = path,
762 .value = self.packages.getIndex(other_package).?,
763 },
764 );
765 }
766
767 if (result.found_existing) {
768 return DocData.WalkResult{
769 .typeRef = .{ .type = @enumToInt(Ref.type_type) },
770 .expr = .{ .type = result.value_ptr.main },
771 };
772 }
773
774 // create a new package entry
775 const main_type_index = self.types.items.len;
776 result.value_ptr.* = .{
777 .name = path,
778 .main = main_type_index,
779 .table = .{},
780 };
781
782 // TODO: Add this package as a dependency to the current pakcage
783 // TODO: this seems something that could be done in bulk
784 // at the beginning or the end, or something.
785 const root_src_dir = other_package.root_src_directory;
786 const root_src_path = other_package.root_src_path;
787 const joined_src_path = try root_src_dir.join(self.arena, &.{root_src_path});
788 defer self.arena.free(joined_src_path);
789
790 const abs_root_src_path = try std.fs.path.resolve(self.arena, &.{ ".", joined_src_path });
791 defer self.arena.free(abs_root_src_path);
792
793 const new_file = self.module.import_table.get(abs_root_src_path).?;
794
795 var root_scope = Scope{ .parent = null, .enclosing_type = main_type_index };
796 try self.ast_nodes.append(self.arena, .{ .name = "(root)" });
797 try self.files.put(self.arena, new_file, main_type_index);
798 return self.walkInstruction(
799 new_file,
800 &root_scope,
801 Zir.main_struct_inst,
802 false,
803 );
804 }
805
806 const new_file = self.module.importFile(file, path) catch unreachable;
807 const result = try self.files.getOrPut(self.arena, new_file.file);
808 if (result.found_existing) {
809 return DocData.WalkResult{
810 .typeRef = .{ .type = @enumToInt(Ref.type_type) },
811 .expr = .{ .type = result.value_ptr.* },
812 };
813 }
814
815 result.value_ptr.* = self.types.items.len;
816
817 var new_scope = Scope{
818 .parent = null,
819 .enclosing_type = self.types.items.len,
820 };
821
822 return self.walkInstruction(
823 new_file.file,
824 &new_scope,
825 Zir.main_struct_inst,
826 need_type,
827 );
828 },
829 .ret_node => {
830 const un_node = data[inst_index].un_node;
831 return self.walkRef(file, parent_scope, un_node.operand, false);
832 },
833 .ret_load => {
834 const un_node = data[inst_index].un_node;
835 const res_ptr_ref = un_node.operand;
836 const res_ptr_inst = @enumToInt(res_ptr_ref) - Ref.typed_value_map.len;
837 // TODO: this instruction doesn't let us know trivially if there's
838 // branching involved or not. For now here's the strat:
839 // We search backwarts until `ret_ptr` for `store_node`,
840 // if we find only one, then that's our value, if we find more
841 // than one, then it means that there's branching involved.
842 // Maybe.
843
844 var i = inst_index - 1;
845 var result_ref: ?Ref = null;
846 while (i > res_ptr_inst) : (i -= 1) {
847 if (tags[i] == .store_node) {
848 const pl_node = data[i].pl_node;
849 const extra = file.zir.extraData(Zir.Inst.Bin, pl_node.payload_index);
850 if (extra.data.lhs == res_ptr_ref) {
851 // this store_load instruction is indeed pointing at
852 // the result location that we care about!
853 if (result_ref != null) return DocData.WalkResult{
854 .expr = .{ .comptimeExpr = 0 },
855 };
856 result_ref = extra.data.rhs;
857 }
858 }
859 }
860
861 if (result_ref) |rr| {
862 return self.walkRef(file, parent_scope, rr, need_type);
863 }
864
865 return DocData.WalkResult{
866 .expr = .{ .comptimeExpr = 0 },
867 };
868 },
869 .closure_get => {
870 const inst_node = data[inst_index].inst_node;
871 return try self.walkInstruction(file, parent_scope, inst_node.inst, need_type);
872 },
873 .closure_capture => {
874 const un_tok = data[inst_index].un_tok;
875 return try self.walkRef(file, parent_scope, un_tok.operand, need_type);
876 },
877 .cmpxchg_strong, .cmpxchg_weak => {
878 const pl_node = data[inst_index].pl_node;
879 const extra = file.zir.extraData(Zir.Inst.Cmpxchg, pl_node.payload_index);
880
881 const last_type_index = self.exprs.items.len;
882 const last_type = self.exprs.items[last_type_index - 1];
883 const type_index = self.exprs.items.len;
884 try self.exprs.append(self.arena, last_type);
885
886 const ptr_index = self.exprs.items.len;
887 var ptr: DocData.WalkResult = try self.walkRef(
888 file,
889 parent_scope,
890 extra.data.ptr,
891 false,
892 );
893 try self.exprs.append(self.arena, ptr.expr);
894
895 const expected_value_index = self.exprs.items.len;
896 var expected_value: DocData.WalkResult = try self.walkRef(
897 file,
898 parent_scope,
899 extra.data.expected_value,
900 false,
901 );
902 try self.exprs.append(self.arena, expected_value.expr);
903
904 const new_value_index = self.exprs.items.len;
905 var new_value: DocData.WalkResult = try self.walkRef(
906 file,
907 parent_scope,
908 extra.data.new_value,
909 false,
910 );
911 try self.exprs.append(self.arena, new_value.expr);
912
913 const success_order_index = self.exprs.items.len;
914 var success_order: DocData.WalkResult = try self.walkRef(
915 file,
916 parent_scope,
917 extra.data.success_order,
918 false,
919 );
920 try self.exprs.append(self.arena, success_order.expr);
921
922 const failure_order_index = self.exprs.items.len;
923 var failure_order: DocData.WalkResult = try self.walkRef(
924 file,
925 parent_scope,
926 extra.data.failure_order,
927 false,
928 );
929 try self.exprs.append(self.arena, failure_order.expr);
930
931 const cmpxchg_index = self.exprs.items.len;
932 try self.exprs.append(self.arena, .{ .cmpxchg = .{ .name = @tagName(tags[inst_index]), .type = type_index, .ptr = ptr_index, .expected_value = expected_value_index, .new_value = new_value_index, .success_order = success_order_index, .failure_order = failure_order_index } });
933 return DocData.WalkResult{
934 .typeRef = .{ .type = @enumToInt(Ref.type_type) },
935 .expr = .{ .cmpxchgIndex = cmpxchg_index },
936 };
937 },
938 .str => {
939 const str = data[inst_index].str.get(file.zir);
940
941 const tRef: ?DocData.Expr = if (!need_type) null else blk: {
942 const arrTypeId = self.types.items.len;
943 try self.types.append(self.arena, .{
944 .Array = .{
945 .len = .{ .int = .{ .value = str.len } },
946 .child = .{ .type = @enumToInt(Ref.u8_type) },
947 .sentinel = .{ .int = .{
948 .value = 0,
949 .negated = false,
950 } },
951 },
952 });
953 // const sentinel: ?usize = if (ptr.flags.has_sentinel) 0 else null;
954 const ptrTypeId = self.types.items.len;
955 try self.types.append(self.arena, .{
956 .Pointer = .{
957 .size = .One,
958 .child = .{ .type = arrTypeId },
959 .sentinel = .{ .int = .{
960 .value = 0,
961 .negated = false,
962 } },
963 .is_mutable = false,
964 },
965 });
966 break :blk .{ .type = ptrTypeId };
967 };
968
969 return DocData.WalkResult{
970 .typeRef = tRef,
971 .expr = .{ .string = str },
972 };
973 },
974 .compile_error => {
975 const un_node = data[inst_index].un_node;
976 var operand: DocData.WalkResult = try self.walkRef(
977 file,
978 parent_scope,
979 un_node.operand,
980 false,
981 );
982
983 return DocData.WalkResult{
984 .expr = .{
985 .compileError = switch (operand.expr) {
986 .string => |s| s,
987 else => "TODO: non-string @compileError arguments",
988 },
989 },
990 };
991 },
992 .enum_literal => {
993 const str_tok = data[inst_index].str_tok;
994 const literal = file.zir.nullTerminatedString(str_tok.start);
995 const type_index = self.types.items.len;
996 try self.types.append(self.arena, .{
997 .EnumLiteral = .{ .name = "todo enum literal" },
998 });
999
1000 return DocData.WalkResult{
1001 .typeRef = .{ .type = type_index },
1002 .expr = .{ .enumLiteral = literal },
1003 };
1004 },
1005 .int => {
1006 const int = data[inst_index].int;
1007 return DocData.WalkResult{
1008 .typeRef = .{ .type = @enumToInt(Ref.comptime_int_type) },
1009 .expr = .{ .int = .{ .value = int } },
1010 };
1011 },
1012 .int_big => {
1013 // @check
1014 const str = data[inst_index].str.get(file.zir);
1015 _ = str;
1016 printWithContext(
1017 file,
1018 inst_index,
1019 "TODO: implement `{s}` for walkInstruction\n\n",
1020 .{@tagName(tags[inst_index])},
1021 );
1022 return self.cteTodo(@tagName(tags[inst_index]));
1023 },
1024
1025 .slice_start => {
1026 const pl_node = data[inst_index].pl_node;
1027 const extra = file.zir.extraData(Zir.Inst.SliceStart, pl_node.payload_index);
1028
1029 const slice_index = self.exprs.items.len;
1030 try self.exprs.append(self.arena, .{ .slice = .{ .lhs = 0, .start = 0 } });
1031
1032 var lhs: DocData.WalkResult = try self.walkRef(
1033 file,
1034 parent_scope,
1035 extra.data.lhs,
1036 false,
1037 );
1038 var start: DocData.WalkResult = try self.walkRef(
1039 file,
1040 parent_scope,
1041 extra.data.start,
1042 false,
1043 );
1044
1045 const lhs_index = self.exprs.items.len;
1046 try self.exprs.append(self.arena, lhs.expr);
1047 const start_index = self.exprs.items.len;
1048 try self.exprs.append(self.arena, start.expr);
1049 self.exprs.items[slice_index] = .{ .slice = .{ .lhs = lhs_index, .start = start_index } };
1050
1051 return DocData.WalkResult{
1052 .typeRef = self.decls.items[lhs.expr.declRef].value.typeRef,
1053 .expr = .{ .sliceIndex = slice_index },
1054 };
1055 },
1056 .slice_end => {
1057 const pl_node = data[inst_index].pl_node;
1058 const extra = file.zir.extraData(Zir.Inst.SliceEnd, pl_node.payload_index);
1059
1060 const slice_index = self.exprs.items.len;
1061 try self.exprs.append(self.arena, .{ .slice = .{ .lhs = 0, .start = 0 } });
1062
1063 var lhs: DocData.WalkResult = try self.walkRef(
1064 file,
1065 parent_scope,
1066 extra.data.lhs,
1067 false,
1068 );
1069 var start: DocData.WalkResult = try self.walkRef(
1070 file,
1071 parent_scope,
1072 extra.data.start,
1073 false,
1074 );
1075 var end: DocData.WalkResult = try self.walkRef(
1076 file,
1077 parent_scope,
1078 extra.data.end,
1079 false,
1080 );
1081
1082 const lhs_index = self.exprs.items.len;
1083 try self.exprs.append(self.arena, lhs.expr);
1084 const start_index = self.exprs.items.len;
1085 try self.exprs.append(self.arena, start.expr);
1086 const end_index = self.exprs.items.len;
1087 try self.exprs.append(self.arena, end.expr);
1088 self.exprs.items[slice_index] = .{ .slice = .{ .lhs = lhs_index, .start = start_index, .end = end_index } };
1089
1090 return DocData.WalkResult{
1091 .typeRef = self.decls.items[lhs.expr.declRef].value.typeRef,
1092 .expr = .{ .sliceIndex = slice_index },
1093 };
1094 },
1095 .slice_sentinel => {
1096 const pl_node = data[inst_index].pl_node;
1097 const extra = file.zir.extraData(Zir.Inst.SliceSentinel, pl_node.payload_index);
1098
1099 const slice_index = self.exprs.items.len;
1100 try self.exprs.append(self.arena, .{ .slice = .{ .lhs = 0, .start = 0 } });
1101
1102 var lhs: DocData.WalkResult = try self.walkRef(
1103 file,
1104 parent_scope,
1105 extra.data.lhs,
1106 false,
1107 );
1108 var start: DocData.WalkResult = try self.walkRef(
1109 file,
1110 parent_scope,
1111 extra.data.start,
1112 false,
1113 );
1114 var end: DocData.WalkResult = try self.walkRef(
1115 file,
1116 parent_scope,
1117 extra.data.end,
1118 false,
1119 );
1120 var sentinel: DocData.WalkResult = try self.walkRef(
1121 file,
1122 parent_scope,
1123 extra.data.sentinel,
1124 false,
1125 );
1126
1127 const lhs_index = self.exprs.items.len;
1128 try self.exprs.append(self.arena, lhs.expr);
1129 const start_index = self.exprs.items.len;
1130 try self.exprs.append(self.arena, start.expr);
1131 const end_index = self.exprs.items.len;
1132 try self.exprs.append(self.arena, end.expr);
1133 const sentinel_index = self.exprs.items.len;
1134 try self.exprs.append(self.arena, sentinel.expr);
1135 self.exprs.items[slice_index] = .{ .slice = .{ .lhs = lhs_index, .start = start_index, .end = end_index, .sentinel = sentinel_index } };
1136
1137 return DocData.WalkResult{
1138 .typeRef = self.decls.items[lhs.expr.declRef].value.typeRef,
1139 .expr = .{ .sliceIndex = slice_index },
1140 };
1141 },
1142
1143 // @check array_cat and array_mul
1144 .add,
1145 .addwrap,
1146 .add_sat,
1147 .sub,
1148 .subwrap,
1149 .sub_sat,
1150 .mul,
1151 .mulwrap,
1152 .mul_sat,
1153 .div,
1154 .shl,
1155 .shl_sat,
1156 .shr,
1157 .bit_or,
1158 .bit_and,
1159 // @check still not working when applied in std
1160 // .array_cat,
1161 // .array_mul,
1162 => {
1163 const pl_node = data[inst_index].pl_node;
1164 const extra = file.zir.extraData(Zir.Inst.Bin, pl_node.payload_index);
1165
1166 const binop_index = self.exprs.items.len;
1167 try self.exprs.append(self.arena, .{ .binOp = .{ .lhs = 0, .rhs = 0 } });
1168
1169 var lhs: DocData.WalkResult = try self.walkRef(
1170 file,
1171 parent_scope,
1172 extra.data.lhs,
1173 false,
1174 );
1175 var rhs: DocData.WalkResult = try self.walkRef(
1176 file,
1177 parent_scope,
1178 extra.data.rhs,
1179 false,
1180 );
1181
1182 const lhs_index = self.exprs.items.len;
1183 try self.exprs.append(self.arena, lhs.expr);
1184 const rhs_index = self.exprs.items.len;
1185 try self.exprs.append(self.arena, rhs.expr);
1186 self.exprs.items[binop_index] = .{ .binOp = .{
1187 .name = @tagName(tags[inst_index]),
1188 .lhs = lhs_index,
1189 .rhs = rhs_index,
1190 } };
1191
1192 return DocData.WalkResult{
1193 .typeRef = .{ .type = @enumToInt(Ref.type_type) },
1194 .expr = .{ .binOpIndex = binop_index },
1195 };
1196 },
1197
1198 // builtin functions
1199 .align_of,
1200 .bool_to_int,
1201 .embed_file,
1202 .error_name,
1203 .panic,
1204 .set_cold, // @check
1205 .set_runtime_safety, // @check
1206 .sqrt,
1207 .sin,
1208 .cos,
1209 .tan,
1210 .exp,
1211 .exp2,
1212 .log,
1213 .log2,
1214 .log10,
1215 .fabs,
1216 .floor,
1217 .ceil,
1218 .trunc,
1219 .round,
1220 .tag_name,
1221 .reify,
1222 .type_name,
1223 .frame_type,
1224 .frame_size,
1225 .ptr_to_int,
1226 .minimum,
1227 .maximum,
1228 .bit_not,
1229 // @check
1230 .clz,
1231 .ctz,
1232 .pop_count,
1233 .byte_swap,
1234 .bit_reverse,
1235 => {
1236 const un_node = data[inst_index].un_node;
1237 const bin_index = self.exprs.items.len;
1238 try self.exprs.append(self.arena, .{ .builtin = .{ .param = 0 } });
1239 const param = try self.walkRef(file, parent_scope, un_node.operand, false);
1240
1241 const param_index = self.exprs.items.len;
1242 try self.exprs.append(self.arena, param.expr);
1243
1244 self.exprs.items[bin_index] = .{ .builtin = .{ .name = @tagName(tags[inst_index]), .param = param_index } };
1245
1246 return DocData.WalkResult{
1247 .typeRef = param.typeRef orelse .{ .type = @enumToInt(Ref.type_type) },
1248 .expr = .{ .builtinIndex = bin_index },
1249 };
1250 },
1251
1252 .float_to_int,
1253 .int_to_float,
1254 .int_to_ptr,
1255 .int_to_enum,
1256 .float_cast,
1257 .int_cast,
1258 .ptr_cast,
1259 .truncate,
1260 .align_cast,
1261 .has_decl,
1262 .has_field,
1263 .div_exact,
1264 .div_floor,
1265 .div_trunc,
1266 .mod,
1267 .rem,
1268 .mod_rem,
1269 .shl_exact,
1270 .shr_exact,
1271 .bitcast,
1272 .vector_type,
1273 // @check
1274 .bit_offset_of,
1275 .offset_of,
1276 .splat,
1277 .reduce,
1278 => {
1279 const pl_node = data[inst_index].pl_node;
1280 const extra = file.zir.extraData(Zir.Inst.Bin, pl_node.payload_index);
1281
1282 const binop_index = self.exprs.items.len;
1283 try self.exprs.append(self.arena, .{ .builtinBin = .{ .lhs = 0, .rhs = 0 } });
1284
1285 var lhs: DocData.WalkResult = try self.walkRef(
1286 file,
1287 parent_scope,
1288 extra.data.lhs,
1289 false,
1290 );
1291 var rhs: DocData.WalkResult = try self.walkRef(
1292 file,
1293 parent_scope,
1294 extra.data.rhs,
1295 false,
1296 );
1297
1298 const lhs_index = self.exprs.items.len;
1299 try self.exprs.append(self.arena, lhs.expr);
1300 const rhs_index = self.exprs.items.len;
1301 try self.exprs.append(self.arena, rhs.expr);
1302 self.exprs.items[binop_index] = .{ .builtinBin = .{ .name = @tagName(tags[inst_index]), .lhs = lhs_index, .rhs = rhs_index } };
1303
1304 return DocData.WalkResult{
1305 .typeRef = .{ .type = @enumToInt(Ref.type_type) },
1306 .expr = .{ .builtinBinIndex = binop_index },
1307 };
1308 },
1309 .error_union_type => {
1310 const pl_node = data[inst_index].pl_node;
1311 const extra = file.zir.extraData(Zir.Inst.Bin, pl_node.payload_index);
1312
1313 var lhs: DocData.WalkResult = try self.walkRef(
1314 file,
1315 parent_scope,
1316 extra.data.lhs,
1317 false,
1318 );
1319 var rhs: DocData.WalkResult = try self.walkRef(
1320 file,
1321 parent_scope,
1322 extra.data.rhs,
1323 false,
1324 );
1325
1326 const type_slot_index = self.types.items.len;
1327 try self.types.append(self.arena, .{ .ErrorUnion = .{
1328 .lhs = lhs.expr,
1329 .rhs = rhs.expr,
1330 } });
1331
1332 return DocData.WalkResult{
1333 .typeRef = .{ .type = @enumToInt(Ref.type_type) },
1334 .expr = .{ .errorUnion = type_slot_index },
1335 };
1336 },
1337 .merge_error_sets => {
1338 const pl_node = data[inst_index].pl_node;
1339 const extra = file.zir.extraData(Zir.Inst.Bin, pl_node.payload_index);
1340
1341 var lhs: DocData.WalkResult = try self.walkRef(
1342 file,
1343 parent_scope,
1344 extra.data.lhs,
1345 false,
1346 );
1347 var rhs: DocData.WalkResult = try self.walkRef(
1348 file,
1349 parent_scope,
1350 extra.data.rhs,
1351 false,
1352 );
1353 const type_slot_index = self.types.items.len;
1354 try self.types.append(self.arena, .{ .ErrorUnion = .{
1355 .lhs = lhs.expr,
1356 .rhs = rhs.expr,
1357 } });
1358
1359 return DocData.WalkResult{
1360 .typeRef = .{ .type = @enumToInt(Ref.type_type) },
1361 .expr = .{ .errorSets = type_slot_index },
1362 };
1363 },
1364 // .elem_type => {
1365 // const un_node = data[inst_index].un_node;
1366
1367 // var operand: DocData.WalkResult = try self.walkRef(
1368 // file,
1369 // parent_scope,
1370 // un_node.operand,
1371 // false,
1372 // );
1373
1374 // return operand;
1375 // },
1376 .ptr_type_simple => {
1377 const ptr = data[inst_index].ptr_type_simple;
1378 const elem_type_ref = try self.walkRef(file, parent_scope, ptr.elem_type, false);
1379 const type_slot_index = self.types.items.len;
1380 try self.types.append(self.arena, .{
1381 .Pointer = .{ .size = ptr.size, .child = elem_type_ref.expr, .is_mutable = ptr.is_mutable, .is_volatile = ptr.is_volatile, .is_allowzero = ptr.is_allowzero },
1382 });
1383
1384 return DocData.WalkResult{
1385 .typeRef = .{ .type = @enumToInt(Ref.type_type) },
1386 .expr = .{ .type = type_slot_index },
1387 };
1388 },
1389 .ptr_type => {
1390 const ptr = data[inst_index].ptr_type;
1391 const extra = file.zir.extraData(Zir.Inst.PtrType, ptr.payload_index);
1392 var extra_index = extra.end;
1393
1394 const type_slot_index = self.types.items.len;
1395 const elem_type_ref = try self.walkRef(
1396 file,
1397 parent_scope,
1398 extra.data.elem_type,
1399 false,
1400 );
1401
1402 // @check if `addrspace`, `bit_start` and `host_size` really need to be
1403 // present in json
1404 var sentinel: ?DocData.Expr = null;
1405 if (ptr.flags.has_sentinel) {
1406 const ref = @intToEnum(Zir.Inst.Ref, file.zir.extra[extra_index]);
1407 const ref_result = try self.walkRef(file, parent_scope, ref, false);
1408 sentinel = ref_result.expr;
1409 extra_index += 1;
1410 }
1411
1412 var @"align": ?DocData.Expr = null;
1413 if (ptr.flags.has_align) {
1414 const ref = @intToEnum(Zir.Inst.Ref, file.zir.extra[extra_index]);
1415 const ref_result = try self.walkRef(file, parent_scope, ref, false);
1416 @"align" = ref_result.expr;
1417 extra_index += 1;
1418 }
1419 var address_space: ?DocData.Expr = null;
1420 if (ptr.flags.has_addrspace) {
1421 const ref = @intToEnum(Zir.Inst.Ref, file.zir.extra[extra_index]);
1422 const ref_result = try self.walkRef(file, parent_scope, ref, false);
1423 address_space = ref_result.expr;
1424 extra_index += 1;
1425 }
1426 var bit_start: ?DocData.Expr = null;
1427 if (ptr.flags.has_bit_range) {
1428 const ref = @intToEnum(Zir.Inst.Ref, file.zir.extra[extra_index]);
1429 const ref_result = try self.walkRef(file, parent_scope, ref, false);
1430 address_space = ref_result.expr;
1431 extra_index += 1;
1432 }
1433
1434 var host_size: ?DocData.Expr = null;
1435 if (ptr.flags.has_bit_range) {
1436 const ref = @intToEnum(Zir.Inst.Ref, file.zir.extra[extra_index]);
1437 const ref_result = try self.walkRef(file, parent_scope, ref, false);
1438 host_size = ref_result.expr;
1439 }
1440
1441 try self.types.append(self.arena, .{
1442 .Pointer = .{
1443 .size = ptr.size,
1444 .child = elem_type_ref.expr,
1445 .has_align = ptr.flags.has_align,
1446 .@"align" = @"align",
1447 .has_addrspace = ptr.flags.has_addrspace,
1448 .address_space = address_space,
1449 .has_sentinel = ptr.flags.has_sentinel,
1450 .sentinel = sentinel,
1451 .is_mutable = ptr.flags.is_mutable,
1452 .is_volatile = ptr.flags.is_volatile,
1453 .has_bit_range = ptr.flags.has_bit_range,
1454 .bit_start = bit_start,
1455 .host_size = host_size,
1456 },
1457 });
1458 return DocData.WalkResult{
1459 .typeRef = .{ .type = @enumToInt(Ref.type_type) },
1460 .expr = .{ .type = type_slot_index },
1461 };
1462 },
1463 .array_type => {
1464 const pl_node = data[inst_index].pl_node;
1465 const bin = file.zir.extraData(Zir.Inst.Bin, pl_node.payload_index).data;
1466 const len = try self.walkRef(file, parent_scope, bin.lhs, false);
1467 const child = try self.walkRef(file, parent_scope, bin.rhs, false);
1468
1469 const type_slot_index = self.types.items.len;
1470 try self.types.append(self.arena, .{
1471 .Array = .{
1472 .len = len.expr,
1473 .child = child.expr,
1474 },
1475 });
1476
1477 return DocData.WalkResult{
1478 .typeRef = .{ .type = @enumToInt(Ref.type_type) },
1479 .expr = .{ .type = type_slot_index },
1480 };
1481 },
1482 .array_type_sentinel => {
1483 const pl_node = data[inst_index].pl_node;
1484 const extra = file.zir.extraData(Zir.Inst.ArrayTypeSentinel, pl_node.payload_index);
1485 const len = try self.walkRef(file, parent_scope, extra.data.len, false);
1486 const sentinel = try self.walkRef(file, parent_scope, extra.data.sentinel, false);
1487 const elem_type = try self.walkRef(file, parent_scope, extra.data.elem_type, false);
1488
1489 const type_slot_index = self.types.items.len;
1490 try self.types.append(self.arena, .{
1491 .Array = .{
1492 .len = len.expr,
1493 .child = elem_type.expr,
1494 .sentinel = sentinel.expr,
1495 },
1496 });
1497 return DocData.WalkResult{
1498 .typeRef = .{ .type = @enumToInt(Ref.type_type) },
1499 .expr = .{ .type = type_slot_index },
1500 };
1501 },
1502 .array_init => {
1503 const pl_node = data[inst_index].pl_node;
1504 const extra = file.zir.extraData(Zir.Inst.MultiOp, pl_node.payload_index);
1505 const operands = file.zir.refSlice(extra.end, extra.data.operands_len);
1506 const array_data = try self.arena.alloc(usize, operands.len - 1);
1507
1508 std.debug.assert(operands.len > 0);
1509 var array_type = try self.walkRef(file, parent_scope, operands[0], false);
1510
1511 for (operands[1..]) |op, idx| {
1512 const wr = try self.walkRef(file, parent_scope, op, false);
1513 const expr_index = self.exprs.items.len;
1514 try self.exprs.append(self.arena, wr.expr);
1515 array_data[idx] = expr_index;
1516 }
1517
1518 return DocData.WalkResult{
1519 .typeRef = array_type.expr,
1520 .expr = .{ .array = array_data },
1521 };
1522 },
1523 .array_init_anon => {
1524 const pl_node = data[inst_index].pl_node;
1525 const extra = file.zir.extraData(Zir.Inst.MultiOp, pl_node.payload_index);
1526 const operands = file.zir.refSlice(extra.end, extra.data.operands_len);
1527 const array_data = try self.arena.alloc(usize, operands.len);
1528
1529 for (operands) |op, idx| {
1530 const wr = try self.walkRef(file, parent_scope, op, false);
1531 const expr_index = self.exprs.items.len;
1532 try self.exprs.append(self.arena, wr.expr);
1533 array_data[idx] = expr_index;
1534 }
1535
1536 return DocData.WalkResult{
1537 .typeRef = null,
1538 .expr = .{ .array = array_data },
1539 };
1540 },
1541 .array_init_ref => {
1542 const pl_node = data[inst_index].pl_node;
1543 const extra = file.zir.extraData(Zir.Inst.MultiOp, pl_node.payload_index);
1544 const operands = file.zir.refSlice(extra.end, extra.data.operands_len);
1545 const array_data = try self.arena.alloc(usize, operands.len - 1);
1546
1547 std.debug.assert(operands.len > 0);
1548 var array_type = try self.walkRef(file, parent_scope, operands[0], false);
1549
1550 for (operands[1..]) |op, idx| {
1551 const wr = try self.walkRef(file, parent_scope, op, false);
1552 const expr_index = self.exprs.items.len;
1553 try self.exprs.append(self.arena, wr.expr);
1554 array_data[idx] = expr_index;
1555 }
1556
1557 const type_slot_index = self.types.items.len;
1558 try self.types.append(self.arena, .{
1559 .Pointer = .{
1560 .size = .One,
1561 .child = array_type.expr,
1562 },
1563 });
1564
1565 const expr_index = self.exprs.items.len;
1566 try self.exprs.append(self.arena, .{ .array = array_data });
1567
1568 return DocData.WalkResult{
1569 .typeRef = .{ .type = type_slot_index },
1570 .expr = .{ .@"&" = expr_index },
1571 };
1572 },
1573 .array_init_anon_ref => {
1574 const pl_node = data[inst_index].pl_node;
1575 const extra = file.zir.extraData(Zir.Inst.MultiOp, pl_node.payload_index);
1576 const operands = file.zir.refSlice(extra.end, extra.data.operands_len);
1577 const array_data = try self.arena.alloc(usize, operands.len);
1578
1579 for (operands) |op, idx| {
1580 const wr = try self.walkRef(file, parent_scope, op, false);
1581 const expr_index = self.exprs.items.len;
1582 try self.exprs.append(self.arena, wr.expr);
1583 array_data[idx] = expr_index;
1584 }
1585
1586 const expr_index = self.exprs.items.len;
1587 try self.exprs.append(self.arena, .{ .array = array_data });
1588
1589 return DocData.WalkResult{
1590 .typeRef = null,
1591 .expr = .{ .@"&" = expr_index },
1592 };
1593 },
1594 .float => {
1595 const float = data[inst_index].float;
1596 return DocData.WalkResult{
1597 .typeRef = .{ .type = @enumToInt(Ref.comptime_float_type) },
1598 .expr = .{ .float = float },
1599 };
1600 },
1601 // @check: In frontend I'm handling float128 with `.toFixed(2)`
1602 .float128 => {
1603 const pl_node = data[inst_index].pl_node;
1604 const extra = file.zir.extraData(Zir.Inst.Float128, pl_node.payload_index);
1605 return DocData.WalkResult{
1606 .typeRef = .{ .type = @enumToInt(Ref.comptime_float_type) },
1607 .expr = .{ .float128 = extra.data.get() },
1608 };
1609 },
1610 .negate => {
1611 const un_node = data[inst_index].un_node;
1612 var operand: DocData.WalkResult = try self.walkRef(
1613 file,
1614 parent_scope,
1615 un_node.operand,
1616 need_type,
1617 );
1618 switch (operand.expr) {
1619 .int => |*int| int.negated = true,
1620 else => {
1621 printWithContext(
1622 file,
1623 inst_index,
1624 "TODO: support negation for more types",
1625 .{},
1626 );
1627 },
1628 }
1629 return operand;
1630 },
1631 .size_of => {
1632 const un_node = data[inst_index].un_node;
1633 const operand = try self.walkRef(
1634 file,
1635 parent_scope,
1636 un_node.operand,
1637 false,
1638 );
1639 const operand_index = self.exprs.items.len;
1640 try self.exprs.append(self.arena, operand.expr);
1641 return DocData.WalkResult{
1642 .typeRef = .{ .type = @enumToInt(Ref.comptime_int_type) },
1643 .expr = .{ .sizeOf = operand_index },
1644 };
1645 },
1646 .bit_size_of => {
1647 // not working correctly with `align()`
1648 const un_node = data[inst_index].un_node;
1649 const operand = try self.walkRef(
1650 file,
1651 parent_scope,
1652 un_node.operand,
1653 need_type,
1654 );
1655 const operand_index = self.exprs.items.len;
1656 try self.exprs.append(self.arena, operand.expr);
1657
1658 return DocData.WalkResult{
1659 .typeRef = operand.typeRef,
1660 .expr = .{ .bitSizeOf = operand_index },
1661 };
1662 },
1663 .enum_to_int => {
1664 // not working correctly with `align()`
1665 const un_node = data[inst_index].un_node;
1666 const operand = try self.walkRef(
1667 file,
1668 parent_scope,
1669 un_node.operand,
1670 false,
1671 );
1672 const operand_index = self.exprs.items.len;
1673 try self.exprs.append(self.arena, operand.expr);
1674
1675 return DocData.WalkResult{
1676 .typeRef = .{ .type = @enumToInt(Ref.comptime_int_type) },
1677 .expr = .{ .enumToInt = operand_index },
1678 };
1679 },
1680 .switch_block => {
1681 // WIP
1682 const pl_node = data[inst_index].pl_node;
1683 const extra = file.zir.extraData(Zir.Inst.SwitchBlock, pl_node.payload_index);
1684 const cond_index = self.exprs.items.len;
1685 _ = try self.walkRef(file, parent_scope, extra.data.operand, false);
1686
1687 const ast_index = self.ast_nodes.items.len;
1688 const type_index = self.types.items.len - 1;
1689
1690 // const ast_line = self.ast_nodes.items[ast_index - 1];
1691
1692 // const sep = "=" ** 200;
1693 // log.debug("{s}", .{sep});
1694 // log.debug("SWITCH BLOCK", .{});
1695 // log.debug("extra = {any}", .{extra});
1696 // log.debug("outer_decl = {any}", .{self.types.items[type_index]});
1697 // log.debug("ast_lines = {}", .{ast_line});
1698 // log.debug("{s}", .{sep});
1699
1700 const switch_index = self.exprs.items.len;
1701 try self.exprs.append(self.arena, .{ .switchOp = .{ .cond_index = cond_index, .file_name = file.sub_file_path, .ast = ast_index, .outer_decl = type_index } });
1702
1703 return DocData.WalkResult{
1704 .typeRef = .{ .type = @enumToInt(Ref.type_type) },
1705 .expr = .{ .switchIndex = switch_index },
1706 };
1707 },
1708 .switch_cond => {
1709 const un_node = data[inst_index].un_node;
1710 const operand = try self.walkRef(
1711 file,
1712 parent_scope,
1713 un_node.operand,
1714 need_type,
1715 );
1716 const operand_index = self.exprs.items.len;
1717 try self.exprs.append(self.arena, operand.expr);
1718
1719 // const ast_index = self.ast_nodes.items.len;
1720 // const sep = "=" ** 200;
1721 // log.debug("{s}", .{sep});
1722 // log.debug("SWITCH COND", .{});
1723 // log.debug("ast index = {}", .{ast_index});
1724 // log.debug("ast previous = {}", .{self.ast_nodes.items[ast_index - 1]});
1725 // log.debug("{s}", .{sep});
1726
1727 return DocData.WalkResult{
1728 .typeRef = operand.typeRef,
1729 .expr = .{ .typeOf = operand_index },
1730 };
1731 },
1732
1733 .typeof => {
1734 const un_node = data[inst_index].un_node;
1735 const operand = try self.walkRef(
1736 file,
1737 parent_scope,
1738 un_node.operand,
1739 need_type,
1740 );
1741 const operand_index = self.exprs.items.len;
1742 try self.exprs.append(self.arena, operand.expr);
1743
1744 return DocData.WalkResult{
1745 .typeRef = operand.typeRef,
1746 .expr = .{ .typeOf = operand_index },
1747 };
1748 },
1749 .typeof_builtin => {
1750 const pl_node = data[inst_index].pl_node;
1751 const extra = file.zir.extraData(Zir.Inst.Block, pl_node.payload_index);
1752 const body = file.zir.extra[extra.end..][extra.data.body_len - 1];
1753
1754 var operand: DocData.WalkResult = try self.walkRef(
1755 file,
1756 parent_scope,
1757 data[body].@"break".operand,
1758 false,
1759 );
1760
1761 const operand_index = self.exprs.items.len;
1762 try self.exprs.append(self.arena, operand.expr);
1763
1764 return DocData.WalkResult{
1765 .typeRef = operand.typeRef,
1766 .expr = .{ .typeOf = operand_index },
1767 };
1768 },
1769 .type_info => {
1770 // @check
1771 const un_node = data[inst_index].un_node;
1772 const operand = try self.walkRef(
1773 file,
1774 parent_scope,
1775 un_node.operand,
1776 need_type,
1777 );
1778
1779 const operand_index = self.exprs.items.len;
1780 try self.exprs.append(self.arena, operand.expr);
1781
1782 return DocData.WalkResult{
1783 .typeRef = operand.typeRef,
1784 .expr = .{ .typeOf = operand_index },
1785 };
1786 },
1787 .as_node => {
1788 const pl_node = data[inst_index].pl_node;
1789 const extra = file.zir.extraData(Zir.Inst.As, pl_node.payload_index);
1790 const dest_type_walk = try self.walkRef(
1791 file,
1792 parent_scope,
1793 extra.data.dest_type,
1794 false,
1795 );
1796
1797 const operand = try self.walkRef(
1798 file,
1799 parent_scope,
1800 extra.data.operand,
1801 false,
1802 );
1803
1804 const operand_idx = self.exprs.items.len;
1805 try self.exprs.append(self.arena, operand.expr);
1806
1807 const dest_type_idx = self.exprs.items.len;
1808 try self.exprs.append(self.arena, dest_type_walk.expr);
1809
1810 // TODO: there's something wrong with how both `as` and `WalkrResult`
1811 // try to store type information.
1812 return DocData.WalkResult{
1813 .typeRef = dest_type_walk.expr,
1814 .expr = .{
1815 .as = .{
1816 .typeRefArg = dest_type_idx,
1817 .exprArg = operand_idx,
1818 },
1819 },
1820 };
1821 },
1822 .optional_type => {
1823 const un_node = data[inst_index].un_node;
1824 const operand: DocData.WalkResult = try self.walkRef(
1825 file,
1826 parent_scope,
1827 un_node.operand,
1828 false,
1829 );
1830
1831 const operand_idx = self.types.items.len;
1832 try self.types.append(self.arena, .{
1833 .Optional = .{ .name = "?TODO", .child = operand.expr },
1834 });
1835
1836 return DocData.WalkResult{
1837 .typeRef = .{ .type = @enumToInt(Ref.type_type) },
1838 .expr = .{ .type = operand_idx },
1839 };
1840 },
1841 .decl_val, .decl_ref => {
1842 const str_tok = data[inst_index].str_tok;
1843 const decls_slot_index = parent_scope.resolveDeclName(str_tok.start);
1844 // While it would make sense to grab the original decl's typeRef info,
1845 // that decl might not have been analyzed yet! The frontend will have
1846 // to navigate through all declRefs to find the underlying type.
1847 return DocData.WalkResult{
1848 .expr = .{ .declRef = decls_slot_index },
1849 };
1850 },
1851 .field_val, .field_call_bind, .field_ptr, .field_type => {
1852 // TODO: field type uses Zir.Inst.FieldType, it just happens to have the
1853 // same layout as Zir.Inst.Field :^)
1854 const pl_node = data[inst_index].pl_node;
1855 const extra = file.zir.extraData(Zir.Inst.Field, pl_node.payload_index);
1856
1857 var path: std.ArrayListUnmanaged(DocData.Expr) = .{};
1858 var lhs = @enumToInt(extra.data.lhs) - Ref.typed_value_map.len; // underflow = need to handle Refs
1859
1860 try path.append(self.arena, .{
1861 .string = file.zir.nullTerminatedString(extra.data.field_name_start),
1862 });
1863 // Put inside path the starting index of each decl name that
1864 // we encounter as we navigate through all the field_vals
1865 while (tags[lhs] == .field_val or
1866 tags[lhs] == .field_call_bind or
1867 tags[lhs] == .field_ptr or
1868 tags[lhs] == .field_type)
1869 {
1870 const lhs_extra = file.zir.extraData(
1871 Zir.Inst.Field,
1872 data[lhs].pl_node.payload_index,
1873 );
1874
1875 try path.append(self.arena, .{
1876 .string = file.zir.nullTerminatedString(lhs_extra.data.field_name_start),
1877 });
1878 lhs = @enumToInt(lhs_extra.data.lhs) - Ref.typed_value_map.len; // underflow = need to handle Refs
1879 }
1880
1881 // TODO: double check that we really don't need type info here
1882 const wr = try self.walkInstruction(file, parent_scope, lhs, false);
1883 try path.append(self.arena, wr.expr);
1884
1885 // This way the data in `path` has the same ordering that the ref
1886 // path has in the text: most general component first.
1887 std.mem.reverse(DocData.Expr, path.items);
1888
1889 // Righ now, every element of `path` is a string except its first
1890 // element (at index 0). We're now going to attempt to resolve each
1891 // string. If one or more components in this path are not yet fully
1892 // analyzed, the path will only be solved partially, but we expect
1893 // to eventually solve it fully(or give up in case of a
1894 // comptimeExpr). This means that:
1895 // - (1) Paths can be not fully analyzed temporarily, so any code
1896 // that requires to know where a ref path leads to, neeeds to
1897 // implement support for lazyness (see self.pending_ref_paths)
1898 // - (2) Paths can sometimes never resolve fully. This means that
1899 // any value that depends on that will have to become a
1900 // comptimeExpr.
1901 try self.tryResolveRefPath(file, lhs, path.items);
1902 return DocData.WalkResult{ .expr = .{ .refPath = path.items } };
1903 },
1904 .int_type => {
1905 const int_type = data[inst_index].int_type;
1906 const sign = if (int_type.signedness == .unsigned) "u" else "i";
1907 const bits = int_type.bit_count;
1908 const name = try std.fmt.allocPrint(self.arena, "{s}{}", .{ sign, bits });
1909
1910 try self.types.append(self.arena, .{
1911 .Int = .{ .name = name },
1912 });
1913
1914 return DocData.WalkResult{
1915 .typeRef = .{ .type = @enumToInt(Ref.type_type) },
1916 .expr = .{ .type = self.types.items.len - 1 },
1917 };
1918 },
1919 .block => {
1920 const res = DocData.WalkResult{ .expr = .{
1921 .comptimeExpr = self.comptime_exprs.items.len,
1922 } };
1923 try self.comptime_exprs.append(self.arena, .{
1924 .code = "if(banana) 1 else 0",
1925 });
1926 return res;
1927 },
1928 .block_inline => {
1929 return self.walkRef(
1930 file,
1931 parent_scope,
1932 getBlockInlineBreak(file.zir, inst_index),
1933 need_type,
1934 );
1935 },
1936 .struct_init => {
1937 const pl_node = data[inst_index].pl_node;
1938 const extra = file.zir.extraData(Zir.Inst.StructInit, pl_node.payload_index);
1939 const field_vals = try self.arena.alloc(
1940 DocData.Expr.FieldVal,
1941 extra.data.fields_len,
1942 );
1943
1944 var type_ref: DocData.Expr = undefined;
1945 var idx = extra.end;
1946 for (field_vals) |*fv| {
1947 const init_extra = file.zir.extraData(Zir.Inst.StructInit.Item, idx);
1948 defer idx = init_extra.end;
1949
1950 const field_name = blk: {
1951 const field_inst_index = init_extra.data.field_type;
1952 if (tags[field_inst_index] != .field_type) unreachable;
1953 const field_pl_node = data[field_inst_index].pl_node;
1954 const field_extra = file.zir.extraData(
1955 Zir.Inst.FieldType,
1956 field_pl_node.payload_index,
1957 );
1958
1959 // On first iteration use field info to find out the struct type
1960 if (idx == extra.end) {
1961 const wr = try self.walkRef(
1962 file,
1963 parent_scope,
1964 field_extra.data.container_type,
1965 false,
1966 );
1967 type_ref = wr.expr;
1968 }
1969 break :blk file.zir.nullTerminatedString(field_extra.data.name_start);
1970 };
1971 const value = try self.walkRef(
1972 file,
1973 parent_scope,
1974 init_extra.data.init,
1975 need_type,
1976 );
1977 fv.* = .{ .name = field_name, .val = value };
1978 }
1979
1980 return DocData.WalkResult{
1981 .typeRef = type_ref,
1982 .expr = .{ .@"struct" = field_vals },
1983 };
1984 },
1985 .struct_init_empty => {
1986 const un_node = data[inst_index].un_node;
1987 var operand: DocData.WalkResult = try self.walkRef(
1988 file,
1989 parent_scope,
1990 un_node.operand,
1991 false,
1992 );
1993
1994 _ = operand;
1995
1996 // WIP
1997
1998 printWithContext(
1999 file,
2000 inst_index,
2001 "TODO: implement `{s}` for walkInstruction\n\n",
2002 .{@tagName(tags[inst_index])},
2003 );
2004 return self.cteTodo(@tagName(tags[inst_index]));
2005 },
2006 .error_set_decl => {
2007 const pl_node = data[inst_index].pl_node;
2008 const extra = file.zir.extraData(Zir.Inst.ErrorSetDecl, pl_node.payload_index);
2009 const fields = try self.arena.alloc(
2010 DocData.Type.Field,
2011 extra.data.fields_len,
2012 );
2013 var idx = extra.end;
2014 for (fields) |*f| {
2015 const name = file.zir.nullTerminatedString(file.zir.extra[idx]);
2016 idx += 1;
2017
2018 const docs = file.zir.nullTerminatedString(file.zir.extra[idx]);
2019 idx += 1;
2020
2021 f.* = .{
2022 .name = name,
2023 .docs = docs,
2024 };
2025 }
2026
2027 const type_slot_index = self.types.items.len;
2028 try self.types.append(self.arena, .{
2029 .ErrorSet = .{
2030 .name = "todo errset",
2031 .fields = fields,
2032 },
2033 });
2034
2035 return DocData.WalkResult{
2036 .typeRef = .{ .type = @enumToInt(Ref.type_type) },
2037 .expr = .{ .type = type_slot_index },
2038 };
2039 },
2040 .param_anytype, .param_anytype_comptime => {
2041 // @check if .param_anytype_comptime can be here
2042 // Analysis of anytype function params happens in `.func`.
2043 // This switch case handles the case where an expression depends
2044 // on an anytype field. E.g.: `fn foo(bar: anytype) @TypeOf(bar)`.
2045 // This means that we're looking at a generic expression.
2046 const str_tok = data[inst_index].str_tok;
2047 const name = str_tok.get(file.zir);
2048 const cte_slot_index = self.comptime_exprs.items.len;
2049 try self.comptime_exprs.append(self.arena, .{
2050 .code = name,
2051 });
2052 return DocData.WalkResult{ .expr = .{ .comptimeExpr = cte_slot_index } };
2053 },
2054 .param, .param_comptime => {
2055 // See .param_anytype for more information.
2056 const pl_tok = data[inst_index].pl_tok;
2057 const extra = file.zir.extraData(Zir.Inst.Param, pl_tok.payload_index);
2058 const name = file.zir.nullTerminatedString(extra.data.name);
2059
2060 const cte_slot_index = self.comptime_exprs.items.len;
2061 try self.comptime_exprs.append(self.arena, .{
2062 .code = name,
2063 });
2064 return DocData.WalkResult{ .expr = .{ .comptimeExpr = cte_slot_index } };
2065 },
2066 .call => {
2067 const pl_node = data[inst_index].pl_node;
2068 const extra = file.zir.extraData(Zir.Inst.Call, pl_node.payload_index);
2069
2070 const callee = try self.walkRef(file, parent_scope, extra.data.callee, need_type);
2071
2072 const args_len = extra.data.flags.args_len;
2073 var args = try self.arena.alloc(DocData.Expr, args_len);
2074 const arg_refs = file.zir.refSlice(extra.end, args_len);
2075 for (arg_refs) |ref, idx| {
2076 // TODO: consider toggling need_type to true if we ever want
2077 // to show discrepancies between the types of provided
2078 // arguments and the types declared in the function
2079 // signature for its parameters.
2080 const wr = try self.walkRef(file, parent_scope, ref, false);
2081 args[idx] = wr.expr;
2082 }
2083
2084 const cte_slot_index = self.comptime_exprs.items.len;
2085 try self.comptime_exprs.append(self.arena, .{
2086 .code = "func call",
2087 });
2088
2089 const call_slot_index = self.calls.items.len;
2090 try self.calls.append(self.arena, .{
2091 .func = callee.expr,
2092 .args = args,
2093 .ret = .{ .comptimeExpr = cte_slot_index },
2094 });
2095
2096 return DocData.WalkResult{
2097 .typeRef = if (callee.typeRef) |tr| switch (tr) {
2098 .type => |func_type_idx| self.types.items[func_type_idx].Fn.ret,
2099 else => null,
2100 } else null,
2101 .expr = .{ .call = call_slot_index },
2102 };
2103 },
2104 .func, .func_inferred => {
2105 const type_slot_index = self.types.items.len;
2106 try self.types.append(self.arena, .{ .Unanalyzed = .{} });
2107
2108 const result = self.analyzeFunction(
2109 file,
2110 parent_scope,
2111 inst_index,
2112 self_ast_node_index,
2113 type_slot_index,
2114 );
2115
2116 return result;
2117 },
2118 .func_fancy => {
2119 const type_slot_index = self.types.items.len;
2120 try self.types.append(self.arena, .{ .Unanalyzed = .{} });
2121
2122 const result = self.analyzeFancyFunction(
2123 file,
2124 parent_scope,
2125 inst_index,
2126 self_ast_node_index,
2127 type_slot_index,
2128 );
2129
2130 return result;
2131 },
2132 .extended => {
2133 const extended = data[inst_index].extended;
2134 switch (extended.opcode) {
2135 else => {
2136 printWithContext(
2137 file,
2138 inst_index,
2139 "TODO: implement `walkInstruction.extended` for {s}",
2140 .{@tagName(extended.opcode)},
2141 );
2142 return self.cteTodo(@tagName(extended.opcode));
2143 },
2144 .typeof_peer => {
2145 // Zir says it's a NodeMultiOp but in this case it's TypeOfPeer
2146 const extra = file.zir.extraData(Zir.Inst.TypeOfPeer, extended.operand);
2147 const args = file.zir.refSlice(extra.end, extended.small);
2148 const array_data = try self.arena.alloc(usize, args.len);
2149
2150 var array_type: ?DocData.Expr = null;
2151 for (args) |arg, idx| {
2152 const wr = try self.walkRef(file, parent_scope, arg, idx == 0);
2153 if (idx == 0) {
2154 array_type = wr.typeRef;
2155 }
2156
2157 const expr_index = self.exprs.items.len;
2158 try self.exprs.append(self.arena, wr.expr);
2159 array_data[idx] = expr_index;
2160 }
2161
2162 const type_slot_index = self.types.items.len;
2163 try self.types.append(self.arena, .{
2164 .Array = .{
2165 .len = .{
2166 .int = .{
2167 .value = args.len,
2168 .negated = false,
2169 },
2170 },
2171 .child = .{ .type = 0 },
2172 },
2173 });
2174 const result = DocData.WalkResult{
2175 .typeRef = .{ .type = type_slot_index },
2176 .expr = .{ .typeOf_peer = array_data },
2177 };
2178
2179 return result;
2180 },
2181 .opaque_decl => {
2182 const small = @bitCast(Zir.Inst.OpaqueDecl.Small, extended.small);
2183 var extra_index: usize = extended.operand;
2184 const src_node: ?i32 = if (small.has_src_node) blk: {
2185 const src_node = @bitCast(i32, file.zir.extra[extra_index]);
2186 extra_index += 1;
2187 break :blk src_node;
2188 } else null;
2189 _ = src_node;
2190
2191 const decls_len = if (small.has_decls_len) blk: {
2192 const decls_len = file.zir.extra[extra_index];
2193 extra_index += 1;
2194 break :blk decls_len;
2195 } else 0;
2196 _ = decls_len;
2197
2198 const decls_bits = file.zir.extra[extra_index];
2199 _ = decls_bits;
2200
2201 // const sep = "=" ** 200;
2202 // log.debug("{s}", .{sep});
2203 // log.debug("small = {any}", .{small});
2204 // log.debug("src_node = {}", .{src_node});
2205 // log.debug("decls_len = {}", .{decls_len});
2206 // log.debug("decls_bit = {}", .{decls_bits});
2207 // log.debug("{s}", .{sep});
2208 const type_slot_index = self.types.items.len - 1;
2209 try self.types.append(self.arena, .{ .Opaque = .{ .name = "TODO" } });
2210 return DocData.WalkResult{
2211 .typeRef = .{ .type = @enumToInt(Ref.anyopaque_type) },
2212 .expr = .{ .type = type_slot_index },
2213 };
2214 },
2215 .variable => {
2216 const small = @bitCast(Zir.Inst.ExtendedVar.Small, extended.small);
2217 var extra_index: usize = extended.operand;
2218 if (small.has_lib_name) extra_index += 1;
2219 if (small.has_align) extra_index += 1;
2220
2221 const value: DocData.WalkResult = if (small.has_init) .{
2222 .expr = .{ .void = .{} },
2223 } else .{
2224 .expr = .{ .void = .{} },
2225 };
2226
2227 return value;
2228 },
2229 .union_decl => {
2230 const type_slot_index = self.types.items.len;
2231 try self.types.append(self.arena, .{ .Unanalyzed = .{} });
2232
2233 var scope: Scope = .{
2234 .parent = parent_scope,
2235 .enclosing_type = type_slot_index,
2236 };
2237
2238 const small = @bitCast(Zir.Inst.UnionDecl.Small, extended.small);
2239 var extra_index: usize = extended.operand;
2240
2241 const src_node: ?i32 = if (small.has_src_node) blk: {
2242 const src_node = @bitCast(i32, file.zir.extra[extra_index]);
2243 extra_index += 1;
2244 break :blk src_node;
2245 } else null;
2246 _ = src_node;
2247
2248 const tag_type: ?Ref = if (small.has_tag_type) blk: {
2249 const tag_type = file.zir.extra[extra_index];
2250 extra_index += 1;
2251 break :blk @intToEnum(Ref, tag_type);
2252 } else null;
2253 _ = tag_type;
2254
2255 const body_len = if (small.has_body_len) blk: {
2256 const body_len = file.zir.extra[extra_index];
2257 extra_index += 1;
2258 break :blk body_len;
2259 } else 0;
2260
2261 const fields_len = if (small.has_fields_len) blk: {
2262 const fields_len = file.zir.extra[extra_index];
2263 extra_index += 1;
2264 break :blk fields_len;
2265 } else 0;
2266 _ = fields_len;
2267
2268 const decls_len = if (small.has_decls_len) blk: {
2269 const decls_len = file.zir.extra[extra_index];
2270 extra_index += 1;
2271 break :blk decls_len;
2272 } else 0;
2273
2274 var decl_indexes: std.ArrayListUnmanaged(usize) = .{};
2275 var priv_decl_indexes: std.ArrayListUnmanaged(usize) = .{};
2276
2277 const decls_first_index = self.decls.items.len;
2278 // Decl name lookahead for reserving slots in `scope` (and `decls`).
2279 // Done to make sure that all decl refs can be resolved correctly,
2280 // even if we haven't fully analyzed the decl yet.
2281 {
2282 var it = file.zir.declIterator(@intCast(u32, inst_index));
2283 try self.decls.resize(self.arena, decls_first_index + it.decls_len);
2284 for (self.decls.items[decls_first_index..]) |*slot| {
2285 slot._analyzed = false;
2286 }
2287 var decls_slot_index = decls_first_index;
2288 while (it.next()) |d| : (decls_slot_index += 1) {
2289 const decl_name_index = file.zir.extra[d.sub_index + 5];
2290 try scope.insertDeclRef(self.arena, decl_name_index, decls_slot_index);
2291 }
2292 }
2293
2294 extra_index = try self.walkDecls(
2295 file,
2296 &scope,
2297 decls_first_index,
2298 decls_len,
2299 &decl_indexes,
2300 &priv_decl_indexes,
2301 extra_index,
2302 );
2303
2304 extra_index += body_len;
2305
2306 var field_type_refs = try std.ArrayListUnmanaged(DocData.Expr).initCapacity(
2307 self.arena,
2308 fields_len,
2309 );
2310 var field_name_indexes = try std.ArrayListUnmanaged(usize).initCapacity(
2311 self.arena,
2312 fields_len,
2313 );
2314 try self.collectUnionFieldInfo(
2315 file,
2316 &scope,
2317 fields_len,
2318 &field_type_refs,
2319 &field_name_indexes,
2320 extra_index,
2321 );
2322
2323 self.ast_nodes.items[self_ast_node_index].fields = field_name_indexes.items;
2324
2325 self.types.items[type_slot_index] = .{
2326 .Union = .{ .name = "todo_name", .src = self_ast_node_index, .privDecls = priv_decl_indexes.items, .pubDecls = decl_indexes.items, .fields = field_type_refs.items, .ast = self_ast_node_index },
2327 };
2328
2329 if (self.ref_paths_pending_on_types.get(type_slot_index)) |paths| {
2330 for (paths.items) |resume_info| {
2331 try self.tryResolveRefPath(
2332 resume_info.file,
2333 inst_index,
2334 resume_info.ref_path,
2335 );
2336 }
2337
2338 _ = self.ref_paths_pending_on_types.remove(type_slot_index);
2339 // TODO: we should deallocate the arraylist that holds all the
2340 // decl paths. not doing it now since it's arena-allocated
2341 // anyway, but maybe we should put it elsewhere.
2342 }
2343
2344 return DocData.WalkResult{
2345 .typeRef = .{ .type = @enumToInt(Ref.type_type) },
2346 .expr = .{ .type = type_slot_index },
2347 };
2348 },
2349 .enum_decl => {
2350 const type_slot_index = self.types.items.len;
2351 try self.types.append(self.arena, .{ .Unanalyzed = .{} });
2352
2353 var scope: Scope = .{
2354 .parent = parent_scope,
2355 .enclosing_type = type_slot_index,
2356 };
2357
2358 const small = @bitCast(Zir.Inst.EnumDecl.Small, extended.small);
2359 var extra_index: usize = extended.operand;
2360
2361 const src_node: ?i32 = if (small.has_src_node) blk: {
2362 const src_node = @bitCast(i32, file.zir.extra[extra_index]);
2363 extra_index += 1;
2364 break :blk src_node;
2365 } else null;
2366 _ = src_node;
2367
2368 const tag_type: ?Ref = if (small.has_tag_type) blk: {
2369 const tag_type = file.zir.extra[extra_index];
2370 extra_index += 1;
2371 break :blk @intToEnum(Ref, tag_type);
2372 } else null;
2373 _ = tag_type;
2374
2375 const body_len = if (small.has_body_len) blk: {
2376 const body_len = file.zir.extra[extra_index];
2377 extra_index += 1;
2378 break :blk body_len;
2379 } else 0;
2380
2381 const fields_len = if (small.has_fields_len) blk: {
2382 const fields_len = file.zir.extra[extra_index];
2383 extra_index += 1;
2384 break :blk fields_len;
2385 } else 0;
2386 _ = fields_len;
2387
2388 const decls_len = if (small.has_decls_len) blk: {
2389 const decls_len = file.zir.extra[extra_index];
2390 extra_index += 1;
2391 break :blk decls_len;
2392 } else 0;
2393
2394 var decl_indexes: std.ArrayListUnmanaged(usize) = .{};
2395 var priv_decl_indexes: std.ArrayListUnmanaged(usize) = .{};
2396
2397 const decls_first_index = self.decls.items.len;
2398 // Decl name lookahead for reserving slots in `scope` (and `decls`).
2399 // Done to make sure that all decl refs can be resolved correctly,
2400 // even if we haven't fully analyzed the decl yet.
2401 {
2402 var it = file.zir.declIterator(@intCast(u32, inst_index));
2403 try self.decls.resize(self.arena, decls_first_index + it.decls_len);
2404 for (self.decls.items[decls_first_index..]) |*slot| {
2405 slot._analyzed = false;
2406 }
2407 var decls_slot_index = decls_first_index;
2408 while (it.next()) |d| : (decls_slot_index += 1) {
2409 const decl_name_index = file.zir.extra[d.sub_index + 5];
2410 try scope.insertDeclRef(self.arena, decl_name_index, decls_slot_index);
2411 }
2412 }
2413
2414 extra_index = try self.walkDecls(
2415 file,
2416 &scope,
2417 decls_first_index,
2418 decls_len,
2419 &decl_indexes,
2420 &priv_decl_indexes,
2421 extra_index,
2422 );
2423
2424 // const body = file.zir.extra[extra_index..][0..body_len];
2425 extra_index += body_len;
2426
2427 var field_name_indexes: std.ArrayListUnmanaged(usize) = .{};
2428 {
2429 var bit_bag_idx = extra_index;
2430 var cur_bit_bag: u32 = undefined;
2431 extra_index += std.math.divCeil(usize, fields_len, 32) catch unreachable;
2432
2433 var idx: usize = 0;
2434 while (idx < fields_len) : (idx += 1) {
2435 if (idx % 32 == 0) {
2436 cur_bit_bag = file.zir.extra[bit_bag_idx];
2437 bit_bag_idx += 1;
2438 }
2439
2440 const has_value = @truncate(u1, cur_bit_bag) != 0;
2441 cur_bit_bag >>= 1;
2442
2443 const field_name_index = file.zir.extra[extra_index];
2444 extra_index += 1;
2445
2446 const doc_comment_index = file.zir.extra[extra_index];
2447 extra_index += 1;
2448
2449 const value_ref: ?Ref = if (has_value) blk: {
2450 const value_ref = file.zir.extra[extra_index];
2451 extra_index += 1;
2452 break :blk @intToEnum(Ref, value_ref);
2453 } else null;
2454 _ = value_ref;
2455
2456 const field_name = file.zir.nullTerminatedString(field_name_index);
2457
2458 try field_name_indexes.append(self.arena, self.ast_nodes.items.len);
2459 const doc_comment: ?[]const u8 = if (doc_comment_index != 0)
2460 file.zir.nullTerminatedString(doc_comment_index)
2461 else
2462 null;
2463 try self.ast_nodes.append(self.arena, .{
2464 .name = field_name,
2465 .docs = doc_comment,
2466 });
2467 }
2468 }
2469
2470 self.ast_nodes.items[self_ast_node_index].fields = field_name_indexes.items;
2471
2472 self.types.items[type_slot_index] = .{
2473 .Enum = .{ .name = "todo_name", .src = self_ast_node_index, .privDecls = priv_decl_indexes.items, .pubDecls = decl_indexes.items, .ast = self_ast_node_index },
2474 };
2475 if (self.ref_paths_pending_on_types.get(type_slot_index)) |paths| {
2476 for (paths.items) |resume_info| {
2477 try self.tryResolveRefPath(
2478 resume_info.file,
2479 inst_index,
2480 resume_info.ref_path,
2481 );
2482 }
2483
2484 _ = self.ref_paths_pending_on_types.remove(type_slot_index);
2485 // TODO: we should deallocate the arraylist that holds all the
2486 // decl paths. not doing it now since it's arena-allocated
2487 // anyway, but maybe we should put it elsewhere.
2488 }
2489 return DocData.WalkResult{
2490 .typeRef = .{ .type = @enumToInt(Ref.type_type) },
2491 .expr = .{ .type = type_slot_index },
2492 };
2493 },
2494 .struct_decl => {
2495 const type_slot_index = self.types.items.len;
2496 try self.types.append(self.arena, .{ .Unanalyzed = .{} });
2497
2498 var scope: Scope = .{
2499 .parent = parent_scope,
2500 .enclosing_type = type_slot_index,
2501 };
2502
2503 const small = @bitCast(Zir.Inst.StructDecl.Small, extended.small);
2504 var extra_index: usize = extended.operand;
2505
2506 const src_node: ?i32 = if (small.has_src_node) blk: {
2507 const src_node = @bitCast(i32, file.zir.extra[extra_index]);
2508 extra_index += 1;
2509 break :blk src_node;
2510 } else null;
2511 _ = src_node;
2512
2513 const fields_len = if (small.has_fields_len) blk: {
2514 const fields_len = file.zir.extra[extra_index];
2515 extra_index += 1;
2516 break :blk fields_len;
2517 } else 0;
2518 _ = fields_len;
2519
2520 const decls_len = if (small.has_decls_len) blk: {
2521 const decls_len = file.zir.extra[extra_index];
2522 extra_index += 1;
2523 break :blk decls_len;
2524 } else 0;
2525
2526 var decl_indexes: std.ArrayListUnmanaged(usize) = .{};
2527 var priv_decl_indexes: std.ArrayListUnmanaged(usize) = .{};
2528
2529 const decls_first_index = self.decls.items.len;
2530 // Decl name lookahead for reserving slots in `scope` (and `decls`).
2531 // Done to make sure that all decl refs can be resolved correctly,
2532 // even if we haven't fully analyzed the decl yet.
2533 {
2534 var it = file.zir.declIterator(@intCast(u32, inst_index));
2535 try self.decls.resize(self.arena, decls_first_index + it.decls_len);
2536 for (self.decls.items[decls_first_index..]) |*slot| {
2537 slot._analyzed = false;
2538 }
2539 var decls_slot_index = decls_first_index;
2540 while (it.next()) |d| : (decls_slot_index += 1) {
2541 const decl_name_index = file.zir.extra[d.sub_index + 5];
2542 try scope.insertDeclRef(self.arena, decl_name_index, decls_slot_index);
2543 }
2544 }
2545
2546 extra_index = try self.walkDecls(
2547 file,
2548 &scope,
2549 decls_first_index,
2550 decls_len,
2551 &decl_indexes,
2552 &priv_decl_indexes,
2553 extra_index,
2554 );
2555
2556 var field_type_refs: std.ArrayListUnmanaged(DocData.Expr) = .{};
2557 var field_name_indexes: std.ArrayListUnmanaged(usize) = .{};
2558 try self.collectStructFieldInfo(
2559 file,
2560 &scope,
2561 fields_len,
2562 &field_type_refs,
2563 &field_name_indexes,
2564 extra_index,
2565 );
2566
2567 self.ast_nodes.items[self_ast_node_index].fields = field_name_indexes.items;
2568
2569 self.types.items[type_slot_index] = .{
2570 .Struct = .{ .name = "todo_name", .src = self_ast_node_index, .privDecls = priv_decl_indexes.items, .pubDecls = decl_indexes.items, .fields = field_type_refs.items, .line_number = self.ast_nodes.items[self_ast_node_index].line, .outer_decl = type_slot_index - 1, .ast = self_ast_node_index },
2571 };
2572 if (self.ref_paths_pending_on_types.get(type_slot_index)) |paths| {
2573 for (paths.items) |resume_info| {
2574 try self.tryResolveRefPath(
2575 resume_info.file,
2576 inst_index,
2577 resume_info.ref_path,
2578 );
2579 }
2580
2581 _ = self.ref_paths_pending_on_types.remove(type_slot_index);
2582 // TODO: we should deallocate the arraylist that holds all the
2583 // decl paths. not doing it now since it's arena-allocated
2584 // anyway, but maybe we should put it elsewhere.
2585 }
2586 return DocData.WalkResult{
2587 .typeRef = .{ .type = @enumToInt(Ref.type_type) },
2588 .expr = .{ .type = type_slot_index },
2589 };
2590 },
2591 .this => {
2592 return DocData.WalkResult{
2593 .typeRef = .{ .type = @enumToInt(Ref.type_type) },
2594 .expr = .{ .this = parent_scope.enclosing_type },
2595 };
2596 },
2597 .error_to_int,
2598 .int_to_error,
2599 => {
2600 const extra = file.zir.extraData(Zir.Inst.UnNode, extended.operand).data;
2601 const bin_index = self.exprs.items.len;
2602 try self.exprs.append(self.arena, .{ .builtin = .{ .param = 0 } });
2603 const param = try self.walkRef(file, parent_scope, extra.operand, false);
2604
2605 const param_index = self.exprs.items.len;
2606 try self.exprs.append(self.arena, param.expr);
2607
2608 self.exprs.items[bin_index] = .{ .builtin = .{ .name = @tagName(tags[inst_index]), .param = param_index } };
2609
2610 return DocData.WalkResult{
2611 .typeRef = param.typeRef orelse .{ .type = @enumToInt(Ref.type_type) },
2612 .expr = .{ .builtinIndex = bin_index },
2613 };
2614 },
2615 }
2616 },
2617 }
2618}
2619
2620/// Called by `walkInstruction` when encountering a container type.
2621/// Iterates over all decl definitions in its body and it also analyzes each
2622/// decl's body recursively by calling into `walkInstruction`.
2623///
2624/// Does not append to `self.decls` directly because `walkInstruction`
2625/// is expected to look-ahead scan all decls and reserve `body_len`
2626/// slots in `self.decls`, which are then filled out by this function.
2627fn walkDecls(
2628 self: *Autodoc,
2629 file: *File,
2630 scope: *Scope,
2631 decls_first_index: usize,
2632 decls_len: u32,
2633 decl_indexes: *std.ArrayListUnmanaged(usize),
2634 priv_decl_indexes: *std.ArrayListUnmanaged(usize),
2635 extra_start: usize,
2636) AutodocErrors!usize {
2637 const bit_bags_count = std.math.divCeil(usize, decls_len, 8) catch unreachable;
2638 var extra_index = extra_start + bit_bags_count;
2639 var bit_bag_index: usize = extra_start;
2640 var cur_bit_bag: u32 = undefined;
2641 var decl_i: u32 = 0;
2642
2643 while (decl_i < decls_len) : (decl_i += 1) {
2644 const decls_slot_index = decls_first_index + decl_i;
2645
2646 if (decl_i % 8 == 0) {
2647 cur_bit_bag = file.zir.extra[bit_bag_index];
2648 bit_bag_index += 1;
2649 }
2650 const is_pub = @truncate(u1, cur_bit_bag) != 0;
2651 cur_bit_bag >>= 1;
2652 const is_exported = @truncate(u1, cur_bit_bag) != 0;
2653 cur_bit_bag >>= 1;
2654 const has_align = @truncate(u1, cur_bit_bag) != 0;
2655 cur_bit_bag >>= 1;
2656 const has_section_or_addrspace = @truncate(u1, cur_bit_bag) != 0;
2657 cur_bit_bag >>= 1;
2658
2659 // const sub_index = extra_index;
2660
2661 // const hash_u32s = file.zir.extra[extra_index..][0..4];
2662 extra_index += 4;
2663 const line = file.zir.extra[extra_index];
2664 extra_index += 1;
2665 const decl_name_index = file.zir.extra[extra_index];
2666 extra_index += 1;
2667 const value_index = file.zir.extra[extra_index];
2668 extra_index += 1;
2669 const doc_comment_index = file.zir.extra[extra_index];
2670 extra_index += 1;
2671
2672 const align_inst: Zir.Inst.Ref = if (!has_align) .none else inst: {
2673 const inst = @intToEnum(Zir.Inst.Ref, file.zir.extra[extra_index]);
2674 extra_index += 1;
2675 break :inst inst;
2676 };
2677 _ = align_inst;
2678
2679 const section_inst: Zir.Inst.Ref = if (!has_section_or_addrspace) .none else inst: {
2680 const inst = @intToEnum(Zir.Inst.Ref, file.zir.extra[extra_index]);
2681 extra_index += 1;
2682 break :inst inst;
2683 };
2684 _ = section_inst;
2685
2686 const addrspace_inst: Zir.Inst.Ref = if (!has_section_or_addrspace) .none else inst: {
2687 const inst = @intToEnum(Zir.Inst.Ref, file.zir.extra[extra_index]);
2688 extra_index += 1;
2689 break :inst inst;
2690 };
2691 _ = addrspace_inst;
2692
2693 // const pub_str = if (is_pub) "pub " else "";
2694 // const hash_bytes = @bitCast([16]u8, hash_u32s.*);
2695
2696 var is_test = false; // we discover if it's a test by lookin at its name
2697 const name: []const u8 = blk: {
2698 if (decl_name_index == 0) {
2699 break :blk if (is_exported) "usingnamespace" else "comptime";
2700 } else if (decl_name_index == 1) {
2701 is_test = true;
2702 break :blk "test";
2703 } else if (decl_name_index == 2) {
2704 is_test = true;
2705 // TODO: remove temporary hack
2706 break :blk "test";
2707 // // it is a decltest
2708 // const decl_being_tested = scope.resolveDeclName(doc_comment_index);
2709 // const ast_node_index = idx: {
2710 // const idx = self.ast_nodes.items.len;
2711 // const file_source = file.getSource(self.module.gpa) catch unreachable; // TODO fix this
2712 // const source_of_decltest_function = srcloc: {
2713 // const func_index = getBlockInlineBreak(file.zir, value_index);
2714 // // a decltest is always a function
2715 // const tag = file.zir.instructions.items(.tag)[Zir.refToIndex(func_index).?];
2716 // std.debug.assert(tag == .func_extended);
2717
2718 // const pl_node = file.zir.instructions.items(.data)[Zir.refToIndex(func_index).?].pl_node;
2719 // const extra = file.zir.extraData(Zir.Inst.ExtendedFunc, pl_node.payload_index);
2720 // const bits = @bitCast(Zir.Inst.ExtendedFunc.Bits, extra.data.bits);
2721
2722 // var extra_index_for_this_func: usize = extra.end;
2723 // if (bits.has_lib_name) extra_index_for_this_func += 1;
2724 // if (bits.has_cc) extra_index_for_this_func += 1;
2725 // if (bits.has_align) extra_index_for_this_func += 1;
2726
2727 // const ret_ty_body = file.zir.extra[extra_index_for_this_func..][0..extra.data.ret_body_len];
2728 // extra_index_for_this_func += ret_ty_body.len;
2729
2730 // const body = file.zir.extra[extra_index_for_this_func..][0..extra.data.body_len];
2731 // extra_index_for_this_func += body.len;
2732
2733 // var src_locs: Zir.Inst.Func.SrcLocs = undefined;
2734 // if (body.len != 0) {
2735 // src_locs = file.zir.extraData(Zir.Inst.Func.SrcLocs, extra_index_for_this_func).data;
2736 // } else {
2737 // src_locs = .{
2738 // .lbrace_line = line,
2739 // .rbrace_line = line,
2740 // .columns = 0, // TODO get columns when body.len == 0
2741 // };
2742 // }
2743 // break :srcloc src_locs;
2744 // };
2745 // const source_slice = slice: {
2746 // var start_byte_offset: u32 = 0;
2747 // var end_byte_offset: u32 = 0;
2748 // const rbrace_col = @truncate(u16, source_of_decltest_function.columns >> 16);
2749 // var lines: u32 = 0;
2750 // for (file_source.bytes) |b, i| {
2751 // if (b == '\n') {
2752 // lines += 1;
2753 // }
2754 // if (lines == source_of_decltest_function.lbrace_line) {
2755 // start_byte_offset = @intCast(u32, i);
2756 // }
2757 // if (lines == source_of_decltest_function.rbrace_line) {
2758 // end_byte_offset = @intCast(u32, i) + rbrace_col;
2759 // break;
2760 // }
2761 // }
2762 // break :slice file_source.bytes[start_byte_offset..end_byte_offset];
2763 // };
2764 // try self.ast_nodes.append(self.arena, .{
2765 // .file = 0,
2766 // .line = line,
2767 // .col = 0,
2768 // .name = try self.arena.dupe(u8, source_slice),
2769 // });
2770 // break :idx idx;
2771 // };
2772 // self.decls.items[decl_being_tested].decltest = ast_node_index;
2773 // self.decls.items[decls_slot_index] = .{
2774 // ._analyzed = true,
2775 // .name = "test",
2776 // .isTest = true,
2777 // .src = ast_node_index,
2778 // .value = .{ .expr = .{ .type = 0 } },
2779 // .kind = "const",
2780 // };
2781 // continue;
2782 } else {
2783 const raw_decl_name = file.zir.nullTerminatedString(decl_name_index);
2784 if (raw_decl_name.len == 0) {
2785 is_test = true;
2786 break :blk file.zir.nullTerminatedString(decl_name_index + 1);
2787 } else {
2788 break :blk raw_decl_name;
2789 }
2790 }
2791 };
2792
2793 const doc_comment: ?[]const u8 = if (doc_comment_index != 0)
2794 file.zir.nullTerminatedString(doc_comment_index)
2795 else
2796 null;
2797
2798 // astnode
2799 const ast_node_index = idx: {
2800 const idx = self.ast_nodes.items.len;
2801 try self.ast_nodes.append(self.arena, .{
2802 .file = 0,
2803 .line = line,
2804 .col = 0,
2805 .docs = doc_comment,
2806 .fields = null, // walkInstruction will fill `fields` if necessary
2807 });
2808 break :idx idx;
2809 };
2810
2811 const walk_result = if (is_test) // TODO: decide if tests should show up at all
2812 DocData.WalkResult{ .expr = .{ .void = .{} } }
2813 else
2814 try self.walkInstruction(file, scope, value_index, true);
2815
2816 if (is_pub) {
2817 try decl_indexes.append(self.arena, decls_slot_index);
2818 } else {
2819 try priv_decl_indexes.append(self.arena, decls_slot_index);
2820 }
2821
2822 // // decl.typeRef == decl.val...typeRef
2823 // const decl_type_ref: DocData.TypeRef = switch (walk_result) {
2824 // .int => |i| i.typeRef,
2825 // .void => .{ .type = @enumToInt(Ref.void_type) },
2826 // .@"undefined", .@"null" => |v| v,
2827 // .@"unreachable" => .{ .type = @enumToInt(Ref.noreturn_type) },
2828 // .@"struct" => |s| s.typeRef,
2829 // .bool => .{ .type = @enumToInt(Ref.bool_type) },
2830 // .type => .{ .type = @enumToInt(Ref.type_type) },
2831 // // this last case is special becauese it's not pointing
2832 // // at the type of the value, but rather at the value itself
2833 // // the js better be aware ot this!
2834 // .declRef => |d| .{ .declRef = d },
2835 // };
2836
2837 self.decls.items[decls_slot_index] = .{
2838 ._analyzed = true,
2839 .name = name,
2840 .isTest = is_test,
2841 .src = ast_node_index,
2842 //.typeRef = decl_type_ref,
2843 .value = walk_result,
2844 .kind = "const", // find where this information can be found
2845 };
2846
2847 // Unblock any pending decl path that was waiting for this decl.
2848 if (self.ref_paths_pending_on_decls.get(decls_slot_index)) |paths| {
2849 for (paths.items) |resume_info| {
2850 try self.tryResolveRefPath(
2851 resume_info.file,
2852 value_index,
2853 resume_info.ref_path,
2854 );
2855 }
2856
2857 _ = self.ref_paths_pending_on_decls.remove(decls_slot_index);
2858 // TODO: we should deallocate the arraylist that holds all the
2859 // ref paths. not doing it now since it's arena-allocated
2860 // anyway, but maybe we should put it elsewhere.
2861 }
2862 }
2863
2864 return extra_index;
2865}
2866
2867/// An unresolved path has a non-string WalkResult at its beginnig, while every
2868/// other element is a string WalkResult. Resolving means iteratively map each
2869/// string to a Decl / Type / Call / etc.
2870///
2871/// If we encounter an unanalyzed decl during the process, we append the
2872/// unsolved sub-path to `self.ref_paths_pending_on_decls` and bail out.
2873/// Same happens when a decl holds a type definition that hasn't been fully
2874/// analyzed yet (except that we append to `self.ref_paths_pending_on_types`.
2875///
2876/// When walkDecls / walkInstruction finishes analyzing a decl / type, it will
2877/// then check if there's any pending ref path blocked on it and, if any, it
2878/// will progress their resolution by calling tryResolveRefPath again.
2879///
2880/// Ref paths can also depend on other ref paths. See
2881/// `self.pending_ref_paths` for more info.
2882///
2883/// A ref path that has a component that resolves into a comptimeExpr will
2884/// give up its resolution process entirely, leaving the remaining components
2885/// as strings.
2886fn tryResolveRefPath(
2887 self: *Autodoc,
2888 /// File from which the decl path originates.
2889 file: *File,
2890 inst_index: usize, // used only for panicWithContext
2891 path: []DocData.Expr,
2892) AutodocErrors!void {
2893 var i: usize = 0;
2894 outer: while (i < path.len - 1) : (i += 1) {
2895 const parent = path[i];
2896 const child_string = path[i + 1].string; // we expect to find a string union case
2897
2898 var resolved_parent = parent;
2899 var j: usize = 0;
2900 while (j < 10_000) : (j += 1) {
2901 switch (resolved_parent) {
2902 else => break,
2903 .this => |t| resolved_parent = .{ .type = t },
2904 .declRef => |decl_index| {
2905 const decl = self.decls.items[decl_index];
2906 if (decl._analyzed) {
2907 resolved_parent = decl.value.expr;
2908 continue;
2909 }
2910
2911 // This decl path is pending completion
2912 {
2913 const res = try self.pending_ref_paths.getOrPut(
2914 self.arena,
2915 &path[path.len - 1],
2916 );
2917 if (!res.found_existing) res.value_ptr.* = .{};
2918 }
2919
2920 const res = try self.ref_paths_pending_on_decls.getOrPut(
2921 self.arena,
2922 decl_index,
2923 );
2924 if (!res.found_existing) res.value_ptr.* = .{};
2925 try res.value_ptr.*.append(self.arena, .{
2926 .file = file,
2927 .ref_path = path[i..path.len],
2928 });
2929
2930 // We return instead doing `break :outer` to prevent the
2931 // code after the :outer while loop to run, as it assumes
2932 // that the path will have been fully analyzed (or we
2933 // have given up because of a comptimeExpr).
2934 return;
2935 },
2936 .refPath => |rp| {
2937 if (self.pending_ref_paths.getPtr(&rp[rp.len - 1])) |waiter_list| {
2938 try waiter_list.append(self.arena, .{
2939 .file = file,
2940 .ref_path = path[i..path.len],
2941 });
2942
2943 // This decl path is pending completion
2944 {
2945 const res = try self.pending_ref_paths.getOrPut(
2946 self.arena,
2947 &path[path.len - 1],
2948 );
2949 if (!res.found_existing) res.value_ptr.* = .{};
2950 }
2951
2952 return;
2953 }
2954
2955 // If the last element is a string or a CTE, then we give up,
2956 // otherwise we resovle the parent to it and loop again.
2957 // NOTE: we assume that if we find a string, it's because of
2958 // a CTE component somewhere in the path. We know that the path
2959 // is not pending futher evaluation because we just checked!
2960 const last = rp[rp.len - 1];
2961 switch (last) {
2962 .comptimeExpr, .string => break :outer,
2963 else => {
2964 resolved_parent = last;
2965 continue;
2966 },
2967 }
2968 },
2969 }
2970 } else {
2971 panicWithContext(
2972 file,
2973 inst_index,
2974 "exhausted eval quota for `{}`in tryResolveDecl\n",
2975 .{resolved_parent},
2976 );
2977 }
2978
2979 switch (resolved_parent) {
2980 else => {
2981 // NOTE: indirect references to types / decls should be handled
2982 // in the switch above this one!
2983 printWithContext(
2984 file,
2985 inst_index,
2986 "TODO: handle `{s}`in tryResolveRefPath\nInfo: {}",
2987 .{ @tagName(resolved_parent), resolved_parent },
2988 );
2989 path[i + 1] = (try self.cteTodo("match failure")).expr;
2990 continue :outer;
2991 },
2992 .comptimeExpr, .call, .typeOf => {
2993 // Since we hit a cte, we leave the remaining strings unresolved
2994 // and completely give up on resolving this decl path.
2995 //decl_path.hasCte = true;
2996 break :outer;
2997 },
2998 .type => |t_index| switch (self.types.items[t_index]) {
2999 else => {
3000 panicWithContext(
3001 file,
3002 inst_index,
3003 "TODO: handle `{s}` in tryResolveDeclPath.type\nInfo: {}",
3004 .{ @tagName(self.types.items[t_index]), resolved_parent },
3005 );
3006 },
3007 .Unanalyzed => {
3008 // This decl path is pending completion
3009 {
3010 const res = try self.pending_ref_paths.getOrPut(
3011 self.arena,
3012 &path[path.len - 1],
3013 );
3014 if (!res.found_existing) res.value_ptr.* = .{};
3015 }
3016
3017 const res = try self.ref_paths_pending_on_types.getOrPut(
3018 self.arena,
3019 t_index,
3020 );
3021 if (!res.found_existing) res.value_ptr.* = .{};
3022 try res.value_ptr.*.append(self.arena, .{
3023 .file = file,
3024 .ref_path = path[i..path.len],
3025 });
3026
3027 return;
3028 },
3029 .Enum => |t_enum| {
3030 for (t_enum.pubDecls) |d| {
3031 // TODO: this could be improved a lot
3032 // by having our own string table!
3033 const decl = self.decls.items[d];
3034 if (std.mem.eql(u8, decl.name, child_string)) {
3035 path[i + 1] = .{ .declRef = d };
3036 continue :outer;
3037 }
3038 }
3039 for (t_enum.privDecls) |d| {
3040 // TODO: this could be improved a lot
3041 // by having our own string table!
3042 const decl = self.decls.items[d];
3043 if (std.mem.eql(u8, decl.name, child_string)) {
3044 path[i + 1] = .{ .declRef = d };
3045 continue :outer;
3046 }
3047 }
3048
3049 for (self.ast_nodes.items[t_enum.src].fields.?) |ast_node, idx| {
3050 const name = self.ast_nodes.items[ast_node].name.?;
3051 if (std.mem.eql(u8, name, child_string)) {
3052 // TODO: should we really create an artificial
3053 // decl for this type? Probably not.
3054
3055 path[i + 1] = .{
3056 .fieldRef = .{
3057 .type = t_index,
3058 .index = idx,
3059 },
3060 };
3061 continue :outer;
3062 }
3063 }
3064
3065 // if we got here, our search failed
3066 printWithContext(
3067 file,
3068 inst_index,
3069 "failed to match `{s}` in enum",
3070 .{child_string},
3071 );
3072
3073 path[i + 1] = (try self.cteTodo("match failure")).expr;
3074 continue :outer;
3075 },
3076 .Union => |t_union| {
3077 for (t_union.pubDecls) |d| {
3078 // TODO: this could be improved a lot
3079 // by having our own string table!
3080 const decl = self.decls.items[d];
3081 if (std.mem.eql(u8, decl.name, child_string)) {
3082 path[i + 1] = .{ .declRef = d };
3083 continue :outer;
3084 }
3085 }
3086 for (t_union.privDecls) |d| {
3087 // TODO: this could be improved a lot
3088 // by having our own string table!
3089 const decl = self.decls.items[d];
3090 if (std.mem.eql(u8, decl.name, child_string)) {
3091 path[i + 1] = .{ .declRef = d };
3092 continue :outer;
3093 }
3094 }
3095
3096 for (self.ast_nodes.items[t_union.src].fields.?) |ast_node, idx| {
3097 const name = self.ast_nodes.items[ast_node].name.?;
3098 if (std.mem.eql(u8, name, child_string)) {
3099 // TODO: should we really create an artificial
3100 // decl for this type? Probably not.
3101
3102 path[i + 1] = .{
3103 .fieldRef = .{
3104 .type = t_index,
3105 .index = idx,
3106 },
3107 };
3108 continue :outer;
3109 }
3110 }
3111
3112 // if we got here, our search failed
3113 printWithContext(
3114 file,
3115 inst_index,
3116 "failed to match `{s}` in union",
3117 .{child_string},
3118 );
3119 path[i + 1] = (try self.cteTodo("match failure")).expr;
3120 continue :outer;
3121 },
3122
3123 .Struct => |t_struct| {
3124 for (t_struct.pubDecls) |d| {
3125 // TODO: this could be improved a lot
3126 // by having our own string table!
3127 const decl = self.decls.items[d];
3128 if (std.mem.eql(u8, decl.name, child_string)) {
3129 path[i + 1] = .{ .declRef = d };
3130 continue :outer;
3131 }
3132 }
3133 for (t_struct.privDecls) |d| {
3134 // TODO: this could be improved a lot
3135 // by having our own string table!
3136 const decl = self.decls.items[d];
3137 if (std.mem.eql(u8, decl.name, child_string)) {
3138 path[i + 1] = .{ .declRef = d };
3139 continue :outer;
3140 }
3141 }
3142
3143 for (self.ast_nodes.items[t_struct.src].fields.?) |ast_node, idx| {
3144 const name = self.ast_nodes.items[ast_node].name.?;
3145 if (std.mem.eql(u8, name, child_string)) {
3146 // TODO: should we really create an artificial
3147 // decl for this type? Probably not.
3148
3149 path[i + 1] = .{
3150 .fieldRef = .{
3151 .type = t_index,
3152 .index = idx,
3153 },
3154 };
3155 continue :outer;
3156 }
3157 }
3158
3159 // if we got here, our search failed
3160 // printWithContext(
3161 // file,
3162 // inst_index,
3163 // "failed to match `{s}` in struct",
3164 // .{child_string},
3165 // );
3166 // path[i + 1] = (try self.cteTodo("match failure")).expr;
3167 //
3168 // that's working
3169 path[i + 1] = (try self.cteTodo(child_string)).expr;
3170 continue :outer;
3171 },
3172 },
3173 }
3174 }
3175
3176 if (self.pending_ref_paths.get(&path[path.len - 1])) |waiter_list| {
3177 // It's important to de-register oureslves as pending before
3178 // attempting to resolve any other decl.
3179 _ = self.pending_ref_paths.remove(&path[path.len - 1]);
3180
3181 for (waiter_list.items) |resume_info| {
3182 try self.tryResolveRefPath(resume_info.file, inst_index, resume_info.ref_path);
3183 }
3184 // TODO: this is where we should free waiter_list, but its in the arena
3185 // that said, we might want to store it elsewhere and reclaim memory asap
3186 }
3187}
3188fn analyzeFancyFunction(
3189 self: *Autodoc,
3190 file: *File,
3191 scope: *Scope,
3192 inst_index: usize,
3193 self_ast_node_index: usize,
3194 type_slot_index: usize,
3195) AutodocErrors!DocData.WalkResult {
3196 const tags = file.zir.instructions.items(.tag);
3197 const data = file.zir.instructions.items(.data);
3198 const fn_info = file.zir.getFnInfo(@intCast(u32, inst_index));
3199
3200 try self.ast_nodes.ensureUnusedCapacity(self.arena, fn_info.total_params_len);
3201 var param_type_refs = try std.ArrayListUnmanaged(DocData.Expr).initCapacity(
3202 self.arena,
3203 fn_info.total_params_len,
3204 );
3205 var param_ast_indexes = try std.ArrayListUnmanaged(usize).initCapacity(
3206 self.arena,
3207 fn_info.total_params_len,
3208 );
3209
3210 // TODO: handle scope rules for fn parameters
3211 for (fn_info.param_body[0..fn_info.total_params_len]) |param_index| {
3212 switch (tags[param_index]) {
3213 else => {
3214 panicWithContext(
3215 file,
3216 param_index,
3217 "TODO: handle `{s}` in walkInstruction.func\n",
3218 .{@tagName(tags[param_index])},
3219 );
3220 },
3221 .param_anytype, .param_anytype_comptime => {
3222 // TODO: where are the doc comments?
3223 const str_tok = data[param_index].str_tok;
3224
3225 const name = str_tok.get(file.zir);
3226
3227 param_ast_indexes.appendAssumeCapacity(self.ast_nodes.items.len);
3228 self.ast_nodes.appendAssumeCapacity(.{
3229 .name = name,
3230 .docs = "",
3231 .@"comptime" = tags[param_index] == .param_anytype_comptime,
3232 });
3233
3234 param_type_refs.appendAssumeCapacity(
3235 DocData.Expr{ .@"anytype" = .{} },
3236 );
3237 },
3238 .param, .param_comptime => {
3239 const pl_tok = data[param_index].pl_tok;
3240 const extra = file.zir.extraData(Zir.Inst.Param, pl_tok.payload_index);
3241 const doc_comment = if (extra.data.doc_comment != 0)
3242 file.zir.nullTerminatedString(extra.data.doc_comment)
3243 else
3244 "";
3245 const name = file.zir.nullTerminatedString(extra.data.name);
3246
3247 param_ast_indexes.appendAssumeCapacity(self.ast_nodes.items.len);
3248 try self.ast_nodes.append(self.arena, .{
3249 .name = name,
3250 .docs = doc_comment,
3251 .@"comptime" = tags[param_index] == .param_comptime,
3252 });
3253
3254 const break_index = file.zir.extra[extra.end..][extra.data.body_len - 1];
3255 const break_operand = data[break_index].@"break".operand;
3256 const param_type_ref = try self.walkRef(file, scope, break_operand, false);
3257
3258 param_type_refs.appendAssumeCapacity(param_type_ref.expr);
3259 },
3260 }
3261 }
3262
3263 self.ast_nodes.items[self_ast_node_index].fields = param_ast_indexes.items;
3264
3265 const inst_data = data[inst_index].pl_node;
3266 const extra = file.zir.extraData(Zir.Inst.FuncFancy, inst_data.payload_index);
3267
3268 var extra_index: usize = extra.end;
3269
3270 var lib_name: []const u8 = "";
3271 if (extra.data.bits.has_lib_name) {
3272 lib_name = file.zir.nullTerminatedString(file.zir.extra[extra_index]);
3273 extra_index += 1;
3274 }
3275
3276 var align_index: ?usize = null;
3277 if (extra.data.bits.has_align_ref) {
3278 const align_ref = @intToEnum(Zir.Inst.Ref, file.zir.extra[extra_index]);
3279 align_index = self.exprs.items.len;
3280 _ = try self.walkRef(file, scope, align_ref, false);
3281 extra_index += 1;
3282 } else if (extra.data.bits.has_align_body) {
3283 const align_body_len = file.zir.extra[extra_index];
3284 extra_index += 1;
3285 const align_body = file.zir.extra[extra_index .. extra_index + align_body_len];
3286 _ = align_body;
3287 // TODO: analyze the block (or bail with a comptimeExpr)
3288 extra_index += align_body_len;
3289 } else {
3290 // default alignment
3291 }
3292
3293 var addrspace_index: ?usize = null;
3294 if (extra.data.bits.has_addrspace_ref) {
3295 const addrspace_ref = @intToEnum(Zir.Inst.Ref, file.zir.extra[extra_index]);
3296 addrspace_index = self.exprs.items.len;
3297 _ = try self.walkRef(file, scope, addrspace_ref, false);
3298 extra_index += 1;
3299 } else if (extra.data.bits.has_addrspace_body) {
3300 const addrspace_body_len = file.zir.extra[extra_index];
3301 extra_index += 1;
3302 const addrspace_body = file.zir.extra[extra_index .. extra_index + addrspace_body_len];
3303 _ = addrspace_body;
3304 // TODO: analyze the block (or bail with a comptimeExpr)
3305 extra_index += addrspace_body_len;
3306 } else {
3307 // default alignment
3308 }
3309
3310 var section_index: ?usize = null;
3311 if (extra.data.bits.has_section_ref) {
3312 const section_ref = @intToEnum(Zir.Inst.Ref, file.zir.extra[extra_index]);
3313 section_index = self.exprs.items.len;
3314 _ = try self.walkRef(file, scope, section_ref, false);
3315 extra_index += 1;
3316 } else if (extra.data.bits.has_section_body) {
3317 const section_body_len = file.zir.extra[extra_index];
3318 extra_index += 1;
3319 const section_body = file.zir.extra[extra_index .. extra_index + section_body_len];
3320 _ = section_body;
3321 // TODO: analyze the block (or bail with a comptimeExpr)
3322 extra_index += section_body_len;
3323 } else {
3324 // default alignment
3325 }
3326
3327 var cc_index: ?usize = null;
3328 if (extra.data.bits.has_cc_ref) {
3329 const cc_ref = @intToEnum(Zir.Inst.Ref, file.zir.extra[extra_index]);
3330 cc_index = self.exprs.items.len;
3331 _ = try self.walkRef(file, scope, cc_ref, false);
3332 extra_index += 1;
3333 } else if (extra.data.bits.has_cc_body) {
3334 const cc_body_len = file.zir.extra[extra_index];
3335 extra_index += 1;
3336 const cc_body = file.zir.extra[extra_index .. extra_index + cc_body_len];
3337 _ = cc_body;
3338 // TODO: analyze the block (or bail with a comptimeExpr)
3339 extra_index += cc_body_len;
3340 } else {
3341 // auto calling convention
3342 }
3343
3344 // ret
3345 const ret_type_ref: DocData.Expr = switch (fn_info.ret_ty_body.len) {
3346 0 => switch (fn_info.ret_ty_ref) {
3347 .none => DocData.Expr{ .void = .{} },
3348 else => blk: {
3349 const ref = fn_info.ret_ty_ref;
3350 const wr = try self.walkRef(file, scope, ref, false);
3351 break :blk wr.expr;
3352 },
3353 },
3354 else => blk: {
3355 const last_instr_index = fn_info.ret_ty_body[fn_info.ret_ty_body.len - 1];
3356 const break_operand = data[last_instr_index].@"break".operand;
3357 const wr = try self.walkRef(file, scope, break_operand, false);
3358 break :blk wr.expr;
3359 },
3360 };
3361
3362 // TODO: a complete version of this will probably need a scope
3363 // in order to evaluate correctly closures around funcion
3364 // parameters etc.
3365 const generic_ret: ?DocData.Expr = switch (ret_type_ref) {
3366 .type => |t| blk: {
3367 if (fn_info.body.len == 0) break :blk null;
3368 if (t == @enumToInt(Ref.type_type)) {
3369 break :blk try self.getGenericReturnType(
3370 file,
3371 scope,
3372 fn_info.body[fn_info.body.len - 1],
3373 );
3374 } else {
3375 break :blk null;
3376 }
3377 },
3378 else => null,
3379 };
3380
3381 self.types.items[type_slot_index] = .{
3382 .Fn = .{
3383 .name = "todo_name func",
3384 .src = self_ast_node_index,
3385 .params = param_type_refs.items,
3386 .ret = ret_type_ref,
3387 .generic_ret = generic_ret,
3388 .is_extern = extra.data.bits.is_extern,
3389 .has_cc = cc_index != null,
3390 .has_align = align_index != null,
3391 .has_lib_name = extra.data.bits.has_lib_name,
3392 .lib_name = lib_name,
3393 .is_inferred_error = extra.data.bits.is_inferred_error,
3394 .cc = cc_index,
3395 .@"align" = align_index,
3396 },
3397 };
3398
3399 return DocData.WalkResult{
3400 .typeRef = .{ .type = @enumToInt(Ref.type_type) },
3401 .expr = .{ .type = type_slot_index },
3402 };
3403}
3404fn analyzeFunction(
3405 self: *Autodoc,
3406 file: *File,
3407 scope: *Scope,
3408 inst_index: usize,
3409 self_ast_node_index: usize,
3410 type_slot_index: usize,
3411) AutodocErrors!DocData.WalkResult {
3412 const tags = file.zir.instructions.items(.tag);
3413 const data = file.zir.instructions.items(.data);
3414 const fn_info = file.zir.getFnInfo(@intCast(u32, inst_index));
3415
3416 try self.ast_nodes.ensureUnusedCapacity(self.arena, fn_info.total_params_len);
3417 var param_type_refs = try std.ArrayListUnmanaged(DocData.Expr).initCapacity(
3418 self.arena,
3419 fn_info.total_params_len,
3420 );
3421 var param_ast_indexes = try std.ArrayListUnmanaged(usize).initCapacity(
3422 self.arena,
3423 fn_info.total_params_len,
3424 );
3425
3426 // TODO: handle scope rules for fn parameters
3427 for (fn_info.param_body[0..fn_info.total_params_len]) |param_index| {
3428 switch (tags[param_index]) {
3429 else => {
3430 panicWithContext(
3431 file,
3432 param_index,
3433 "TODO: handle `{s}` in walkInstruction.func\n",
3434 .{@tagName(tags[param_index])},
3435 );
3436 },
3437 .param_anytype, .param_anytype_comptime => {
3438 // TODO: where are the doc comments?
3439 const str_tok = data[param_index].str_tok;
3440
3441 const name = str_tok.get(file.zir);
3442
3443 param_ast_indexes.appendAssumeCapacity(self.ast_nodes.items.len);
3444 self.ast_nodes.appendAssumeCapacity(.{
3445 .name = name,
3446 .docs = "",
3447 .@"comptime" = tags[param_index] == .param_anytype_comptime,
3448 });
3449
3450 param_type_refs.appendAssumeCapacity(
3451 DocData.Expr{ .@"anytype" = .{} },
3452 );
3453 },
3454 .param, .param_comptime => {
3455 const pl_tok = data[param_index].pl_tok;
3456 const extra = file.zir.extraData(Zir.Inst.Param, pl_tok.payload_index);
3457 const doc_comment = if (extra.data.doc_comment != 0)
3458 file.zir.nullTerminatedString(extra.data.doc_comment)
3459 else
3460 "";
3461 const name = file.zir.nullTerminatedString(extra.data.name);
3462
3463 param_ast_indexes.appendAssumeCapacity(self.ast_nodes.items.len);
3464 try self.ast_nodes.append(self.arena, .{
3465 .name = name,
3466 .docs = doc_comment,
3467 .@"comptime" = tags[param_index] == .param_comptime,
3468 });
3469
3470 const break_index = file.zir.extra[extra.end..][extra.data.body_len - 1];
3471 const break_operand = data[break_index].@"break".operand;
3472 const param_type_ref = try self.walkRef(file, scope, break_operand, false);
3473
3474 param_type_refs.appendAssumeCapacity(param_type_ref.expr);
3475 },
3476 }
3477 }
3478
3479 // ret
3480 const ret_type_ref: DocData.Expr = switch (fn_info.ret_ty_body.len) {
3481 0 => switch (fn_info.ret_ty_ref) {
3482 .none => DocData.Expr{ .void = .{} },
3483 else => blk: {
3484 const ref = fn_info.ret_ty_ref;
3485 const wr = try self.walkRef(file, scope, ref, false);
3486 break :blk wr.expr;
3487 },
3488 },
3489 else => blk: {
3490 //const last_instr_index = fn_info.ret_ty_body[fn_info.ret_ty_body.len - 1];
3491 //const break_operand = data[last_instr_index].@"break".operand;
3492 //const wr = try self.walkRef(file, scope, break_operand, false);
3493 const wr = try self.walkRef(file, scope, fn_info.ret_ty_ref, false);
3494 break :blk wr.expr;
3495 },
3496 };
3497
3498 // TODO: a complete version of this will probably need a scope
3499 // in order to evaluate correctly closures around funcion
3500 // parameters etc.
3501 const generic_ret: ?DocData.Expr = switch (ret_type_ref) {
3502 .type => |t| blk: {
3503 if (fn_info.body.len == 0) break :blk null;
3504 if (t == @enumToInt(Ref.type_type)) {
3505 break :blk try self.getGenericReturnType(
3506 file,
3507 scope,
3508 fn_info.body[fn_info.body.len - 1],
3509 );
3510 } else {
3511 break :blk null;
3512 }
3513 },
3514 else => null,
3515 };
3516
3517 self.ast_nodes.items[self_ast_node_index].fields = param_ast_indexes.items;
3518 self.types.items[type_slot_index] = .{
3519 .Fn = .{
3520 .name = "todo_name func",
3521 .src = self_ast_node_index,
3522 .params = param_type_refs.items,
3523 .ret = ret_type_ref,
3524 .generic_ret = generic_ret,
3525 },
3526 };
3527
3528 return DocData.WalkResult{
3529 .typeRef = .{ .type = @enumToInt(Ref.type_type) },
3530 .expr = .{ .type = type_slot_index },
3531 };
3532}
3533
3534fn getGenericReturnType(
3535 self: *Autodoc,
3536 file: *File,
3537 scope: *Scope,
3538 body_end: usize,
3539) !DocData.Expr {
3540 const wr = try self.walkInstruction(file, scope, body_end, false);
3541 return wr.expr;
3542}
3543
3544fn collectUnionFieldInfo(
3545 self: *Autodoc,
3546 file: *File,
3547 scope: *Scope,
3548 fields_len: usize,
3549 field_type_refs: *std.ArrayListUnmanaged(DocData.Expr),
3550 field_name_indexes: *std.ArrayListUnmanaged(usize),
3551 ei: usize,
3552) !void {
3553 if (fields_len == 0) return;
3554 var extra_index = ei;
3555
3556 const bits_per_field = 4;
3557 const fields_per_u32 = 32 / bits_per_field;
3558 const bit_bags_count = std.math.divCeil(usize, fields_len, fields_per_u32) catch unreachable;
3559 var bit_bag_index: usize = extra_index;
3560 extra_index += bit_bags_count;
3561
3562 var cur_bit_bag: u32 = undefined;
3563 var field_i: u32 = 0;
3564 while (field_i < fields_len) : (field_i += 1) {
3565 if (field_i % fields_per_u32 == 0) {
3566 cur_bit_bag = file.zir.extra[bit_bag_index];
3567 bit_bag_index += 1;
3568 }
3569 const has_type = @truncate(u1, cur_bit_bag) != 0;
3570 cur_bit_bag >>= 1;
3571 const has_align = @truncate(u1, cur_bit_bag) != 0;
3572 cur_bit_bag >>= 1;
3573 const has_tag = @truncate(u1, cur_bit_bag) != 0;
3574 cur_bit_bag >>= 1;
3575 const unused = @truncate(u1, cur_bit_bag) != 0;
3576 cur_bit_bag >>= 1;
3577 _ = unused;
3578
3579 const field_name = file.zir.nullTerminatedString(file.zir.extra[extra_index]);
3580 extra_index += 1;
3581 const doc_comment_index = file.zir.extra[extra_index];
3582 extra_index += 1;
3583 const field_type = if (has_type)
3584 @intToEnum(Zir.Inst.Ref, file.zir.extra[extra_index])
3585 else
3586 .void_type;
3587 if (has_type) extra_index += 1;
3588
3589 if (has_align) extra_index += 1;
3590 if (has_tag) extra_index += 1;
3591
3592 // type
3593 {
3594 const walk_result = try self.walkRef(file, scope, field_type, false);
3595 try field_type_refs.append(self.arena, walk_result.expr);
3596 }
3597
3598 // ast node
3599 {
3600 try field_name_indexes.append(self.arena, self.ast_nodes.items.len);
3601 const doc_comment: ?[]const u8 = if (doc_comment_index != 0)
3602 file.zir.nullTerminatedString(doc_comment_index)
3603 else
3604 null;
3605 try self.ast_nodes.append(self.arena, .{
3606 .name = field_name,
3607 .docs = doc_comment,
3608 });
3609 }
3610 }
3611}
3612
3613fn collectStructFieldInfo(
3614 self: *Autodoc,
3615 file: *File,
3616 scope: *Scope,
3617 fields_len: usize,
3618 field_type_refs: *std.ArrayListUnmanaged(DocData.Expr),
3619 field_name_indexes: *std.ArrayListUnmanaged(usize),
3620 ei: usize,
3621) !void {
3622 if (fields_len == 0) return;
3623 var extra_index = ei;
3624
3625 const bits_per_field = 4;
3626 const fields_per_u32 = 32 / bits_per_field;
3627 const bit_bags_count = std.math.divCeil(usize, fields_len, fields_per_u32) catch unreachable;
3628
3629 const Field = struct {
3630 field_name: u32,
3631 doc_comment_index: u32,
3632 type_body_len: u32 = 0,
3633 align_body_len: u32 = 0,
3634 init_body_len: u32 = 0,
3635 type_ref: Zir.Inst.Ref = .none,
3636 };
3637 const fields = try self.arena.alloc(Field, fields_len);
3638
3639 var bit_bag_index: usize = extra_index;
3640 extra_index += bit_bags_count;
3641
3642 var cur_bit_bag: u32 = undefined;
3643 var field_i: u32 = 0;
3644 while (field_i < fields_len) : (field_i += 1) {
3645 if (field_i % fields_per_u32 == 0) {
3646 cur_bit_bag = file.zir.extra[bit_bag_index];
3647 bit_bag_index += 1;
3648 }
3649 const has_align = @truncate(u1, cur_bit_bag) != 0;
3650 cur_bit_bag >>= 1;
3651 const has_default = @truncate(u1, cur_bit_bag) != 0;
3652 cur_bit_bag >>= 1;
3653 // const is_comptime = @truncate(u1, cur_bit_bag) != 0;
3654 cur_bit_bag >>= 1;
3655 const has_type_body = @truncate(u1, cur_bit_bag) != 0;
3656 cur_bit_bag >>= 1;
3657
3658 const field_name = file.zir.extra[extra_index];
3659 extra_index += 1;
3660 const doc_comment_index = file.zir.extra[extra_index];
3661 extra_index += 1;
3662
3663 fields[field_i] = .{
3664 .field_name = field_name,
3665 .doc_comment_index = doc_comment_index,
3666 };
3667
3668 if (has_type_body) {
3669 fields[field_i].type_body_len = file.zir.extra[extra_index];
3670 } else {
3671 fields[field_i].type_ref = @intToEnum(Zir.Inst.Ref, file.zir.extra[extra_index]);
3672 }
3673 extra_index += 1;
3674
3675 if (has_align) {
3676 fields[field_i].align_body_len = file.zir.extra[extra_index];
3677 extra_index += 1;
3678 }
3679 if (has_default) {
3680 fields[field_i].init_body_len = file.zir.extra[extra_index];
3681 extra_index += 1;
3682 }
3683 }
3684
3685 const data = file.zir.instructions.items(.data);
3686
3687 for (fields) |field| {
3688 const type_expr = expr: {
3689 if (field.type_ref != .none) {
3690 const walk_result = try self.walkRef(file, scope, field.type_ref, false);
3691 break :expr walk_result.expr;
3692 }
3693
3694 std.debug.assert(field.type_body_len != 0);
3695 const body = file.zir.extra[extra_index..][0..field.type_body_len];
3696 extra_index += body.len;
3697
3698 const break_inst = body[body.len - 1];
3699 const operand = data[break_inst].@"break".operand;
3700 const walk_result = try self.walkRef(file, scope, operand, false);
3701 break :expr walk_result.expr;
3702 };
3703
3704 extra_index += field.align_body_len;
3705 extra_index += field.init_body_len;
3706
3707 try field_type_refs.append(self.arena, type_expr);
3708
3709 // ast node
3710 {
3711 try field_name_indexes.append(self.arena, self.ast_nodes.items.len);
3712 const doc_comment: ?[]const u8 = if (field.doc_comment_index != 0)
3713 file.zir.nullTerminatedString(field.doc_comment_index)
3714 else
3715 null;
3716 try self.ast_nodes.append(self.arena, .{
3717 .name = file.zir.nullTerminatedString(field.field_name),
3718 .docs = doc_comment,
3719 });
3720 }
3721 }
3722}
3723
3724/// A Zir Ref can either refer to common types and values, or to a Zir index.
3725/// WalkRef resolves common cases and delegates to `walkInstruction` otherwise.
3726fn walkRef(
3727 self: *Autodoc,
3728 file: *File,
3729 parent_scope: *Scope,
3730 ref: Ref,
3731 need_type: bool, // true when the caller needs also a typeRef for the return value
3732) AutodocErrors!DocData.WalkResult {
3733 const enum_value = @enumToInt(ref);
3734 if (enum_value <= @enumToInt(Ref.anyerror_void_error_union_type)) {
3735 // We can just return a type that indexes into `types` with the
3736 // enum value because in the beginning we pre-filled `types` with
3737 // the types that are listed in `Ref`.
3738 return DocData.WalkResult{
3739 .typeRef = .{ .type = @enumToInt(std.builtin.TypeId.Type) },
3740 .expr = .{ .type = enum_value },
3741 };
3742 } else if (enum_value < Ref.typed_value_map.len) {
3743 switch (ref) {
3744 else => {
3745 std.debug.panic("TODO: handle {s} in `walkRef`\n", .{
3746 @tagName(ref),
3747 });
3748 },
3749 .undef => {
3750 return DocData.WalkResult{ .expr = .@"undefined" };
3751 },
3752 .zero => {
3753 return DocData.WalkResult{
3754 .typeRef = .{ .type = @enumToInt(Ref.comptime_int_type) },
3755 .expr = .{ .int = .{ .value = 0 } },
3756 };
3757 },
3758 .one => {
3759 return DocData.WalkResult{
3760 .typeRef = .{ .type = @enumToInt(Ref.comptime_int_type) },
3761 .expr = .{ .int = .{ .value = 1 } },
3762 };
3763 },
3764
3765 .void_value => {
3766 return DocData.WalkResult{
3767 .typeRef = .{ .type = @enumToInt(Ref.void_type) },
3768 .expr = .{ .void = .{} },
3769 };
3770 },
3771 .unreachable_value => {
3772 return DocData.WalkResult{
3773 .typeRef = .{ .type = @enumToInt(Ref.noreturn_type) },
3774 .expr = .{ .@"unreachable" = .{} },
3775 };
3776 },
3777 .null_value => {
3778 return DocData.WalkResult{ .expr = .@"null" };
3779 },
3780 .bool_true => {
3781 return DocData.WalkResult{
3782 .typeRef = .{ .type = @enumToInt(Ref.bool_type) },
3783 .expr = .{ .bool = true },
3784 };
3785 },
3786 .bool_false => {
3787 return DocData.WalkResult{
3788 .typeRef = .{ .type = @enumToInt(Ref.bool_type) },
3789 .expr = .{ .bool = false },
3790 };
3791 },
3792 .empty_struct => {
3793 return DocData.WalkResult{ .expr = .{ .@"struct" = &.{} } };
3794 },
3795 .zero_usize => {
3796 return DocData.WalkResult{
3797 .typeRef = .{ .type = @enumToInt(Ref.usize_type) },
3798 .expr = .{ .int = .{ .value = 0 } },
3799 };
3800 },
3801 .one_usize => {
3802 return DocData.WalkResult{
3803 .typeRef = .{ .type = @enumToInt(Ref.usize_type) },
3804 .expr = .{ .int = .{ .value = 1 } },
3805 };
3806 },
3807 // TODO: dunno what to do with those
3808 .calling_convention_type => {
3809 return DocData.WalkResult{
3810 .typeRef = .{ .type = @enumToInt(Ref.calling_convention_type) },
3811 // .typeRef = .{ .type = @enumToInt(Ref.comptime_int_type) },
3812 .expr = .{ .int = .{ .value = 1 } },
3813 };
3814 },
3815 .calling_convention_c => {
3816 return DocData.WalkResult{
3817 .typeRef = .{ .type = @enumToInt(Ref.calling_convention_c) },
3818 // .typeRef = .{ .type = @enumToInt(Ref.comptime_int_type) },
3819 .expr = .{ .int = .{ .value = 1 } },
3820 };
3821 },
3822 .calling_convention_inline => {
3823 return DocData.WalkResult{
3824 .typeRef = .{ .type = @enumToInt(Ref.calling_convention_inline) },
3825 // .typeRef = .{ .type = @enumToInt(Ref.comptime_int_type) },
3826 .expr = .{ .int = .{ .value = 1 } },
3827 };
3828 },
3829 // .generic_poison => {
3830 // return DocData.WalkResult{ .int = .{
3831 // .type = @enumToInt(Ref.comptime_int_type),
3832 // .value = 1,
3833 // } };
3834 // },
3835 }
3836 } else {
3837 const zir_index = enum_value - Ref.typed_value_map.len;
3838 return self.walkInstruction(file, parent_scope, zir_index, need_type);
3839 }
3840}
3841
3842fn getBlockInlineBreak(zir: Zir, inst_index: usize) Zir.Inst.Ref {
3843 const tags = zir.instructions.items(.tag);
3844 const data = zir.instructions.items(.data);
3845 const pl_node = data[inst_index].pl_node;
3846 const extra = zir.extraData(Zir.Inst.Block, pl_node.payload_index);
3847 const break_index = zir.extra[extra.end..][extra.data.body_len - 1];
3848 std.debug.assert(tags[break_index] == .break_inline);
3849 return data[break_index].@"break".operand;
3850}
3851
3852fn printWithContext(file: *File, inst: usize, comptime fmt: []const u8, args: anytype) void {
3853 log.debug("Context [{s}] % {} \n " ++ fmt, .{ file.sub_file_path, inst } ++ args);
3854}
3855
3856fn panicWithContext(file: *File, inst: usize, comptime fmt: []const u8, args: anytype) noreturn {
3857 printWithContext(file, inst, fmt, args);
3858 unreachable;
3859}
3860
3861fn cteTodo(self: *Autodoc, msg: []const u8) error{OutOfMemory}!DocData.WalkResult {
3862 const cte_slot_index = self.comptime_exprs.items.len;
3863 try self.comptime_exprs.append(self.arena, .{
3864 .code = msg,
3865 });
3866 return DocData.WalkResult{ .expr = .{ .comptimeExpr = cte_slot_index } };
3867}
3868
3869fn writeFileTableToJson(map: std.AutoArrayHashMapUnmanaged(*File, usize), jsw: anytype) !void {
3870 try jsw.beginObject();
3871 var it = map.iterator();
3872 while (it.next()) |entry| {
3873 try jsw.objectField(entry.key_ptr.*.sub_file_path);
3874 try jsw.emitNumber(entry.value_ptr.*);
3875 }
3876 try jsw.endObject();
3877}
3878
3879fn writePackageTableToJson(
3880 map: std.AutoHashMapUnmanaged(*Package, DocData.DocPackage.TableEntry),
3881 jsw: anytype,
3882) !void {
3883 try jsw.beginObject();
3884 var it = map.valueIterator();
3885 while (it.next()) |entry| {
3886 try jsw.objectField(entry.name);
3887 try jsw.emitNumber(entry.value);
3888 }
3889 try jsw.endObject();
3890}
src/Compilation.zig+9-6
......@@ -34,6 +34,7 @@ const ThreadPool = @import("ThreadPool.zig");
3434const WaitGroup = @import("WaitGroup.zig");
3535const libtsan = @import("libtsan.zig");
3636const Zir = @import("Zir.zig");
37const Autodoc = @import("Autodoc.zig");
3738const Color = @import("main.zig").Color;
3839
3940/// General-purpose allocator. Used for both temporary and long-term storage.
......@@ -2287,6 +2288,14 @@ pub fn update(comp: *Compilation) !void {
22872288 return;
22882289 }
22892290
2291 if (comp.emit_docs) |doc_location| {
2292 if (comp.bin_file.options.module) |module| {
2293 var autodoc = Autodoc.init(module, doc_location);
2294 defer autodoc.deinit();
2295 try autodoc.generateZirData();
2296 }
2297 }
2298
22902299 // Flush takes care of -femit-bin, but we still have -femit-llvm-ir, -femit-llvm-bc, and
22912300 // -femit-asm to handle, in the case of C objects.
22922301 comp.emitOthers();
......@@ -5160,8 +5169,6 @@ fn updateStage1Module(comp: *Compilation, main_progress_node: *std.Progress.Node
51605169 const emit_asm_path = try stage1LocPath(arena, comp.emit_asm, directory);
51615170 const emit_llvm_ir_path = try stage1LocPath(arena, comp.emit_llvm_ir, directory);
51625171 const emit_llvm_bc_path = try stage1LocPath(arena, comp.emit_llvm_bc, directory);
5163 const emit_analysis_path = try stage1LocPath(arena, comp.emit_analysis, directory);
5164 const emit_docs_path = try stage1LocPath(arena, comp.emit_docs, directory);
51655172 const stage1_pkg = try createStage1Pkg(arena, "root", mod.main_pkg, null);
51665173 const test_filter = comp.test_filter orelse ""[0..0];
51675174 const test_name_prefix = comp.test_name_prefix orelse ""[0..0];
......@@ -5182,10 +5189,6 @@ fn updateStage1Module(comp: *Compilation, main_progress_node: *std.Progress.Node
51825189 .emit_llvm_ir_len = emit_llvm_ir_path.len,
51835190 .emit_bitcode_ptr = emit_llvm_bc_path.ptr,
51845191 .emit_bitcode_len = emit_llvm_bc_path.len,
5185 .emit_analysis_json_ptr = emit_analysis_path.ptr,
5186 .emit_analysis_json_len = emit_analysis_path.len,
5187 .emit_docs_ptr = emit_docs_path.ptr,
5188 .emit_docs_len = emit_docs_path.len,
51895192 .builtin_zig_path_ptr = builtin_zig_path.ptr,
51905193 .builtin_zig_path_len = builtin_zig_path.len,
51915194 .test_filter_ptr = test_filter.ptr,
src/stage1.zig-4
......@@ -96,10 +96,6 @@ pub const Module = extern struct {
9696 emit_llvm_ir_len: usize,
9797 emit_bitcode_ptr: [*]const u8,
9898 emit_bitcode_len: usize,
99 emit_analysis_json_ptr: [*]const u8,
100 emit_analysis_json_len: usize,
101 emit_docs_ptr: [*]const u8,
102 emit_docs_len: usize,
10399 builtin_zig_path_ptr: [*]const u8,
104100 builtin_zig_path_len: usize,
105101 test_filter_ptr: [*]const u8,
src/stage1/all_types.hpp-2
......@@ -2141,8 +2141,6 @@ struct CodeGen {
21412141 Buf asm_file_output_path;
21422142 Buf llvm_ir_file_output_path;
21432143 Buf bitcode_file_output_path;
2144 Buf analysis_json_output_path;
2145 Buf docs_output_path;
21462144
21472145 Buf *builtin_zig_path;
21482146
src/stage1/codegen.cpp-52
......@@ -16,7 +16,6 @@
1616#include "util.hpp"
1717#include "zig_llvm.h"
1818#include "stage2.h"
19#include "dump_analysis.hpp"
2019#include "softfloat.hpp"
2120#include "zigendian.h"
2221
......@@ -10546,57 +10545,6 @@ void codegen_build_object(CodeGen *g) {
1054610545
1054710546 gen_root_source(g);
1054810547
10549 if (buf_len(&g->analysis_json_output_path) != 0) {
10550 const char *analysis_json_filename = buf_ptr(&g->analysis_json_output_path);
10551 FILE *f = fopen(analysis_json_filename, "wb");
10552 if (f == nullptr) {
10553 fprintf(stderr, "Unable to open '%s': %s\n", analysis_json_filename, strerror(errno));
10554 exit(1);
10555 }
10556 zig_print_analysis_dump(g, f, " ", "\n");
10557 if (fclose(f) != 0) {
10558 fprintf(stderr, "Unable to write '%s': %s\n", analysis_json_filename, strerror(errno));
10559 exit(1);
10560 }
10561 }
10562 if (buf_len(&g->docs_output_path) != 0) {
10563 Error err;
10564 Buf *doc_dir_path = &g->docs_output_path;
10565 if ((err = os_make_path(doc_dir_path))) {
10566 fprintf(stderr, "Unable to create directory %s: %s\n", buf_ptr(doc_dir_path), err_str(err));
10567 exit(1);
10568 }
10569 Buf *index_html_src_path = buf_sprintf("%s" OS_SEP "docs" OS_SEP "index.html",
10570 buf_ptr(g->zig_lib_dir));
10571 Buf *index_html_dest_path = buf_sprintf("%s" OS_SEP "index.html", buf_ptr(doc_dir_path));
10572 Buf *main_js_src_path = buf_sprintf("%s" OS_SEP "docs" OS_SEP "main.js",
10573 buf_ptr(g->zig_lib_dir));
10574 Buf *main_js_dest_path = buf_sprintf("%s" OS_SEP "main.js", buf_ptr(doc_dir_path));
10575
10576 if ((err = os_copy_file(index_html_src_path, index_html_dest_path))) {
10577 fprintf(stderr, "Unable to copy %s to %s: %s\n", buf_ptr(index_html_src_path),
10578 buf_ptr(index_html_dest_path), err_str(err));
10579 exit(1);
10580 }
10581 if ((err = os_copy_file(main_js_src_path, main_js_dest_path))) {
10582 fprintf(stderr, "Unable to copy %s to %s: %s\n", buf_ptr(main_js_src_path),
10583 buf_ptr(main_js_dest_path), err_str(err));
10584 exit(1);
10585 }
10586 const char *data_js_filename = buf_ptr(buf_sprintf("%s" OS_SEP "data.js", buf_ptr(doc_dir_path)));
10587 FILE *f = fopen(data_js_filename, "wb");
10588 if (f == nullptr) {
10589 fprintf(stderr, "Unable to open '%s': %s\n", data_js_filename, strerror(errno));
10590 exit(1);
10591 }
10592 fprintf(f, "zigAnalysis=");
10593 zig_print_analysis_dump(g, f, "", "");
10594 fprintf(f, ";");
10595 if (fclose(f) != 0) {
10596 fprintf(stderr, "Unable to write '%s': %s\n", data_js_filename, strerror(errno));
10597 exit(1);
10598 }
10599 }
1060010548
1060110549 codegen_add_time_event(g, "Code Generation");
1060210550 {
src/stage1/dump_analysis.cpp deleted-1431
......@@ -1,1431 +0,0 @@
1/*
2 * Copyright (c) 2019 Andrew Kelley
3 *
4 * This file is part of zig, which is MIT licensed.
5 * See http://opensource.org/licenses/MIT
6 */
7
8#include "dump_analysis.hpp"
9#include "analyze.hpp"
10#include "ir.hpp"
11#include "codegen.hpp"
12#include "os.hpp"
13
14enum JsonWriterState {
15 JsonWriterStateInvalid,
16 JsonWriterStateValue,
17 JsonWriterStateArrayStart,
18 JsonWriterStateArray,
19 JsonWriterStateObjectStart,
20 JsonWriterStateObject,
21};
22
23#define JSON_MAX_DEPTH 10
24
25struct JsonWriter {
26 size_t state_index;
27 FILE *f;
28 const char *one_indent;
29 const char *nl;
30 JsonWriterState state[JSON_MAX_DEPTH];
31};
32
33static void jw_init(JsonWriter *jw, FILE *f, const char *one_indent, const char *nl) {
34 jw->state_index = 1;
35 jw->f = f;
36 jw->one_indent = one_indent;
37 jw->nl = nl;
38 jw->state[0] = JsonWriterStateInvalid;
39 jw->state[1] = JsonWriterStateValue;
40}
41
42static void jw_nl_indent(JsonWriter *jw) {
43 assert(jw->state_index >= 1);
44 fprintf(jw->f, "%s", jw->nl);
45 for (size_t i = 0; i < jw->state_index - 1; i += 1) {
46 fprintf(jw->f, "%s", jw->one_indent);
47 }
48}
49
50static void jw_push_state(JsonWriter *jw, JsonWriterState state) {
51 jw->state_index += 1;
52 assert(jw->state_index < JSON_MAX_DEPTH);
53 jw->state[jw->state_index] = state;
54}
55
56static void jw_pop_state(JsonWriter *jw) {
57 assert(jw->state_index != 0);
58 jw->state_index -= 1;
59}
60
61static void jw_begin_array(JsonWriter *jw) {
62 assert(jw->state[jw->state_index] == JsonWriterStateValue);
63 fprintf(jw->f, "[");
64 jw->state[jw->state_index] = JsonWriterStateArrayStart;
65}
66
67static void jw_begin_object(JsonWriter *jw) {
68 assert(jw->state[jw->state_index] == JsonWriterStateValue);
69 fprintf(jw->f, "{");
70 jw->state[jw->state_index] = JsonWriterStateObjectStart;
71}
72
73static void jw_array_elem(JsonWriter *jw) {
74 switch (jw->state[jw->state_index]) {
75 case JsonWriterStateInvalid:
76 case JsonWriterStateValue:
77 case JsonWriterStateObjectStart:
78 case JsonWriterStateObject:
79 zig_unreachable();
80 case JsonWriterStateArray:
81 fprintf(jw->f, ",");
82 ZIG_FALLTHROUGH;
83 case JsonWriterStateArrayStart:
84 jw->state[jw->state_index] = JsonWriterStateArray;
85 jw_push_state(jw, JsonWriterStateValue);
86 jw_nl_indent(jw);
87 return;
88 }
89 zig_unreachable();
90}
91
92static void jw_write_escaped_string(JsonWriter *jw, const char *s) {
93 fprintf(jw->f, "\"");
94 for (;; s += 1) {
95 switch (*s) {
96 case 0:
97 fprintf(jw->f, "\"");
98 return;
99 case '"':
100 fprintf(jw->f, "\\\"");
101 continue;
102 case '\t':
103 fprintf(jw->f, "\\t");
104 continue;
105 case '\r':
106 fprintf(jw->f, "\\r");
107 continue;
108 case '\n':
109 fprintf(jw->f, "\\n");
110 continue;
111 case '\b':
112 fprintf(jw->f, "\\b");
113 continue;
114 case '\f':
115 fprintf(jw->f, "\\f");
116 continue;
117 case '\\':
118 fprintf(jw->f, "\\\\");
119 continue;
120 default:
121 fprintf(jw->f, "%c", *s);
122 continue;
123 }
124 }
125}
126
127static void jw_object_field(JsonWriter *jw, const char *name) {
128 switch (jw->state[jw->state_index]) {
129 case JsonWriterStateInvalid:
130 case JsonWriterStateValue:
131 case JsonWriterStateArray:
132 case JsonWriterStateArrayStart:
133 zig_unreachable();
134 case JsonWriterStateObject:
135 fprintf(jw->f, ",");
136 ZIG_FALLTHROUGH;
137 case JsonWriterStateObjectStart:
138 jw->state[jw->state_index] = JsonWriterStateObject;
139 jw_push_state(jw, JsonWriterStateValue);
140 jw_nl_indent(jw);
141 jw_write_escaped_string(jw, name);
142 fprintf(jw->f, ": ");
143 return;
144 }
145 zig_unreachable();
146}
147
148static void jw_end_array(JsonWriter *jw) {
149 switch (jw->state[jw->state_index]) {
150 case JsonWriterStateInvalid:
151 case JsonWriterStateValue:
152 case JsonWriterStateObjectStart:
153 case JsonWriterStateObject:
154 zig_unreachable();
155 case JsonWriterStateArrayStart:
156 fprintf(jw->f, "]");
157 jw_pop_state(jw);
158 return;
159 case JsonWriterStateArray:
160 jw_nl_indent(jw);
161 jw_pop_state(jw);
162 fprintf(jw->f, "]");
163 return;
164 }
165 zig_unreachable();
166}
167
168
169static void jw_end_object(JsonWriter *jw) {
170 switch (jw->state[jw->state_index]) {
171 case JsonWriterStateInvalid:
172 zig_unreachable();
173 case JsonWriterStateValue:
174 zig_unreachable();
175 case JsonWriterStateArray:
176 zig_unreachable();
177 case JsonWriterStateArrayStart:
178 zig_unreachable();
179 case JsonWriterStateObjectStart:
180 fprintf(jw->f, "}");
181 jw_pop_state(jw);
182 return;
183 case JsonWriterStateObject:
184 jw_nl_indent(jw);
185 jw_pop_state(jw);
186 fprintf(jw->f, "}");
187 return;
188 }
189 zig_unreachable();
190}
191
192static void jw_null(JsonWriter *jw) {
193 assert(jw->state[jw->state_index] == JsonWriterStateValue);
194 fprintf(jw->f, "null");
195 jw_pop_state(jw);
196}
197
198static void jw_bool(JsonWriter *jw, bool x) {
199 assert(jw->state[jw->state_index] == JsonWriterStateValue);
200 if (x) {
201 fprintf(jw->f, "true");
202 } else {
203 fprintf(jw->f, "false");
204 }
205 jw_pop_state(jw);
206}
207
208static void jw_int(JsonWriter *jw, int64_t x) {
209 assert(jw->state[jw->state_index] == JsonWriterStateValue);
210 if (x > 4503599627370496 || x < -4503599627370496) {
211 fprintf(jw->f, "\"%" ZIG_PRI_i64 "\"", x);
212 } else {
213 fprintf(jw->f, "%" ZIG_PRI_i64, x);
214 }
215 jw_pop_state(jw);
216}
217
218static void jw_bigint(JsonWriter *jw, const BigInt *x) {
219 assert(jw->state[jw->state_index] == JsonWriterStateValue);
220 Buf *str = buf_alloc();
221 bigint_append_buf(str, x, 10);
222
223 if (bigint_fits_in_bits(x, 52, true)) {
224 fprintf(jw->f, "%s", buf_ptr(str));
225 } else {
226 fprintf(jw->f, "\"%s\"", buf_ptr(str));
227 }
228 jw_pop_state(jw);
229
230 buf_destroy(str);
231}
232
233static void jw_string(JsonWriter *jw, const char *s) {
234 assert(jw->state[jw->state_index] == JsonWriterStateValue);
235 jw_write_escaped_string(jw, s);
236 jw_pop_state(jw);
237}
238
239
240static void tree_print(FILE *f, ZigType *ty, size_t indent);
241
242static int compare_type_abi_sizes_desc(const void *a, const void *b) {
243 uint64_t size_a = (*(ZigType * const*)(a))->abi_size;
244 uint64_t size_b = (*(ZigType * const*)(b))->abi_size;
245 if (size_a > size_b)
246 return -1;
247 if (size_a < size_b)
248 return 1;
249 return 0;
250}
251
252static void start_child(FILE *f, size_t indent) {
253 fprintf(f, "\n");
254 for (size_t i = 0; i < indent; i += 1) {
255 fprintf(f, " ");
256 }
257}
258
259static void start_peer(FILE *f, size_t indent) {
260 fprintf(f, ",\n");
261 for (size_t i = 0; i < indent; i += 1) {
262 fprintf(f, " ");
263 }
264}
265
266static void tree_print_struct(FILE *f, ZigType *struct_type, size_t indent) {
267 ZigList<ZigType *> children = {};
268 uint64_t sum_from_fields = 0;
269 for (size_t i = 0; i < struct_type->data.structure.src_field_count; i += 1) {
270 TypeStructField *field = struct_type->data.structure.fields[i];
271 children.append(field->type_entry);
272 sum_from_fields += field->type_entry->abi_size;
273 }
274 qsort(children.items, children.length, sizeof(ZigType *), compare_type_abi_sizes_desc);
275
276 start_peer(f, indent);
277 fprintf(f, "\"padding\": \"%" ZIG_PRI_u64 "\"", struct_type->abi_size - sum_from_fields);
278
279 start_peer(f, indent);
280 fprintf(f, "\"fields\": [");
281
282 for (size_t i = 0; i < children.length; i += 1) {
283 if (i == 0) {
284 start_child(f, indent + 1);
285 } else {
286 start_peer(f, indent + 1);
287 }
288 fprintf(f, "{");
289
290 ZigType *child_type = children.at(i);
291 tree_print(f, child_type, indent + 2);
292
293 start_child(f, indent + 1);
294 fprintf(f, "}");
295 }
296
297 start_child(f, indent);
298 fprintf(f, "]");
299}
300
301static void tree_print(FILE *f, ZigType *ty, size_t indent) {
302 start_child(f, indent);
303 fprintf(f, "\"type\": \"%s\"", buf_ptr(&ty->name));
304
305 start_peer(f, indent);
306 fprintf(f, "\"sizef\": \"");
307 zig_pretty_print_bytes(f, ty->abi_size);
308 fprintf(f, "\"");
309
310 start_peer(f, indent);
311 fprintf(f, "\"size\": \"%" ZIG_PRI_usize "\"", ty->abi_size);
312
313 switch (ty->id) {
314 case ZigTypeIdFnFrame:
315 return tree_print_struct(f, ty->data.frame.locals_struct, indent);
316 case ZigTypeIdStruct:
317 return tree_print_struct(f, ty, indent);
318 default:
319 start_child(f, indent);
320 return;
321 }
322}
323
324void zig_print_stack_report(CodeGen *g, FILE *f) {
325 if (g->largest_frame_fn == nullptr) {
326 fprintf(f, "{\"error\": \"No async function frames in entire compilation.\"}\n");
327 return;
328 }
329 fprintf(f, "{");
330 tree_print(f, g->largest_frame_fn->frame_type, 1);
331
332 start_child(f, 0);
333 fprintf(f, "}\n");
334}
335
336struct AnalDumpCtx {
337 CodeGen *g;
338 JsonWriter jw;
339
340 ZigList<ZigType *> type_list;
341 HashMap<const ZigType *, uint32_t, type_ptr_hash, type_ptr_eql> type_map;
342
343 ZigList<ZigPackage *> pkg_list;
344 HashMap<const ZigPackage *, uint32_t, pkg_ptr_hash, pkg_ptr_eql> pkg_map;
345
346 ZigList<Buf *> file_list;
347 HashMap<Buf *, uint32_t, buf_hash, buf_eql_buf> file_map;
348
349 ZigList<Tld *> decl_list;
350 HashMap<const Tld *, uint32_t, tld_ptr_hash, tld_ptr_eql> decl_map;
351
352 ZigList<ZigFn *> fn_list;
353 HashMap<const ZigFn *, uint32_t, fn_ptr_hash, fn_ptr_eql> fn_map;
354 HashMap<const ZigFn *, uint32_t, fn_ptr_hash, fn_ptr_eql> fn_decl_map;
355
356 ZigList<AstNode *> node_list;
357 HashMap<const AstNode *, uint32_t, node_ptr_hash, node_ptr_eql> node_map;
358
359 ZigList<ErrorTableEntry *> err_list;
360 HashMap<const ErrorTableEntry *, uint32_t, err_ptr_hash, err_ptr_eql> err_map;
361};
362
363static uint32_t anal_dump_get_type_id(AnalDumpCtx *ctx, ZigType *ty);
364static void anal_dump_value(AnalDumpCtx *ctx, AstNode *source_node, ZigType *ty, ZigValue *value);
365
366static void anal_dump_poke_value(AnalDumpCtx *ctx, AstNode *source_node, ZigType *ty, ZigValue *value) {
367 Error err;
368 if (value->type != ty) {
369 return;
370 }
371 if ((err = ir_resolve_lazy(ctx->g, source_node, value))) {
372 codegen_report_errors_and_exit(ctx->g);
373 }
374 if (value->special == ConstValSpecialUndef) {
375 return;
376 }
377 if (value->special == ConstValSpecialRuntime) {
378 return;
379 }
380 switch (ty->id) {
381 case ZigTypeIdMetaType: {
382 ZigType *val_ty = value->data.x_type;
383 (void)anal_dump_get_type_id(ctx, val_ty);
384 return;
385 }
386 default:
387 return;
388 }
389 zig_unreachable();
390}
391
392static uint32_t anal_dump_get_type_id(AnalDumpCtx *ctx, ZigType *ty) {
393 uint32_t type_id = ctx->type_list.length;
394 auto existing_entry = ctx->type_map.put_unique(ty, type_id);
395 if (existing_entry == nullptr) {
396 ctx->type_list.append(ty);
397 } else {
398 type_id = existing_entry->value;
399 }
400 return type_id;
401}
402
403static uint32_t anal_dump_get_pkg_id(AnalDumpCtx *ctx, ZigPackage *pkg) {
404 assert(pkg != nullptr);
405 uint32_t pkg_id = ctx->pkg_list.length;
406 auto existing_entry = ctx->pkg_map.put_unique(pkg, pkg_id);
407 if (existing_entry == nullptr) {
408 ctx->pkg_list.append(pkg);
409 } else {
410 pkg_id = existing_entry->value;
411 }
412 return pkg_id;
413}
414
415static uint32_t anal_dump_get_file_id(AnalDumpCtx *ctx, Buf *file) {
416 uint32_t file_id = ctx->file_list.length;
417 auto existing_entry = ctx->file_map.put_unique(file, file_id);
418 if (existing_entry == nullptr) {
419 ctx->file_list.append(file);
420 } else {
421 file_id = existing_entry->value;
422 }
423 return file_id;
424}
425
426static uint32_t anal_dump_get_node_id(AnalDumpCtx *ctx, AstNode *node) {
427 uint32_t node_id = ctx->node_list.length;
428 auto existing_entry = ctx->node_map.put_unique(node, node_id);
429 if (existing_entry == nullptr) {
430 ctx->node_list.append(node);
431 } else {
432 node_id = existing_entry->value;
433 }
434 return node_id;
435}
436
437static uint32_t anal_dump_get_fn_id(AnalDumpCtx *ctx, ZigFn *fn) {
438 uint32_t fn_id = ctx->fn_list.length;
439 auto existing_entry = ctx->fn_map.put_unique(fn, fn_id);
440 if (existing_entry == nullptr) {
441 ctx->fn_list.append(fn);
442
443 // poke the fn
444 (void)anal_dump_get_type_id(ctx, fn->type_entry);
445 (void)anal_dump_get_node_id(ctx, fn->proto_node);
446 } else {
447 fn_id = existing_entry->value;
448 }
449 return fn_id;
450}
451
452static uint32_t anal_dump_get_err_id(AnalDumpCtx *ctx, ErrorTableEntry *err) {
453 uint32_t err_id = ctx->err_list.length;
454 auto existing_entry = ctx->err_map.put_unique(err, err_id);
455 if (existing_entry == nullptr) {
456 ctx->err_list.append(err);
457 } else {
458 err_id = existing_entry->value;
459 }
460 return err_id;
461}
462
463static uint32_t anal_dump_get_decl_id(AnalDumpCtx *ctx, Tld *tld) {
464 uint32_t decl_id = ctx->decl_list.length;
465 auto existing_entry = ctx->decl_map.put_unique(tld, decl_id);
466 if (existing_entry == nullptr) {
467 ctx->decl_list.append(tld);
468
469 if (tld->import != nullptr) {
470 (void)anal_dump_get_type_id(ctx, tld->import);
471 }
472
473 // poke the types
474 switch (tld->id) {
475 case TldIdVar: {
476 TldVar *tld_var = reinterpret_cast<TldVar *>(tld);
477 ZigVar *var = tld_var->var;
478
479 if (var != nullptr) {
480 (void)anal_dump_get_type_id(ctx, var->var_type);
481
482 if (var->const_value != nullptr) {
483 anal_dump_poke_value(ctx, var->decl_node, var->var_type, var->const_value);
484 }
485 }
486 break;
487 }
488 case TldIdFn: {
489 TldFn *tld_fn = reinterpret_cast<TldFn *>(tld);
490 ZigFn *fn = tld_fn->fn_entry;
491
492 if (fn != nullptr) {
493 (void)anal_dump_get_type_id(ctx, fn->type_entry);
494 ctx->fn_decl_map.put_unique(fn, decl_id);
495 }
496 break;
497 }
498 default:
499 break;
500 }
501
502 } else {
503 decl_id = existing_entry->value;
504 }
505 return decl_id;
506}
507
508static void anal_dump_type_ref(AnalDumpCtx *ctx, ZigType *ty) {
509 uint32_t type_id = anal_dump_get_type_id(ctx, ty);
510 jw_int(&ctx->jw, type_id);
511}
512
513static void anal_dump_pkg_ref(AnalDumpCtx *ctx, ZigPackage *pkg) {
514 uint32_t pkg_id = anal_dump_get_pkg_id(ctx, pkg);
515 jw_int(&ctx->jw, pkg_id);
516}
517
518static void anal_dump_file_ref(AnalDumpCtx *ctx, Buf *file) {
519 uint32_t file_id = anal_dump_get_file_id(ctx, file);
520 jw_int(&ctx->jw, file_id);
521}
522
523static void anal_dump_node_ref(AnalDumpCtx *ctx, AstNode *node) {
524 uint32_t node_id = anal_dump_get_node_id(ctx, node);
525 jw_int(&ctx->jw, node_id);
526}
527
528static void anal_dump_fn_ref(AnalDumpCtx *ctx, ZigFn *fn) {
529 uint32_t fn_id = anal_dump_get_fn_id(ctx, fn);
530 jw_int(&ctx->jw, fn_id);
531}
532
533static void anal_dump_err_ref(AnalDumpCtx *ctx, ErrorTableEntry *err) {
534 uint32_t err_id = anal_dump_get_err_id(ctx, err);
535 jw_int(&ctx->jw, err_id);
536}
537
538static void anal_dump_decl_ref(AnalDumpCtx *ctx, Tld *tld) {
539 uint32_t decl_id = anal_dump_get_decl_id(ctx, tld);
540 jw_int(&ctx->jw, decl_id);
541}
542
543static void anal_dump_pkg(AnalDumpCtx *ctx, ZigPackage *pkg) {
544 JsonWriter *jw = &ctx->jw;
545
546 Buf full_path_buf = BUF_INIT;
547 os_path_join(&pkg->root_src_dir, &pkg->root_src_path, &full_path_buf);
548 Buf *resolve_paths[] = { &full_path_buf, };
549 Buf *resolved_path = buf_alloc();
550 *resolved_path = os_path_resolve(resolve_paths, 1);
551
552 auto import_entry = ctx->g->import_table.maybe_get(resolved_path);
553 if (!import_entry) {
554 return;
555 }
556
557 jw_array_elem(jw);
558 jw_begin_object(jw);
559
560 jw_object_field(jw, "name");
561 jw_string(jw, buf_ptr(&pkg->pkg_path));
562
563 jw_object_field(jw, "file");
564 anal_dump_file_ref(ctx, resolved_path);
565
566 jw_object_field(jw, "main");
567 anal_dump_type_ref(ctx, import_entry->value);
568
569 jw_object_field(jw, "table");
570 jw_begin_object(jw);
571 auto it = pkg->package_table.entry_iterator();
572 for (;;) {
573 auto *entry = it.next();
574 if (!entry)
575 break;
576
577 ZigPackage *child_pkg = entry->value;
578 if (child_pkg != nullptr) {
579 jw_object_field(jw, buf_ptr(entry->key));
580 anal_dump_pkg_ref(ctx, child_pkg);
581 }
582 }
583 jw_end_object(jw);
584
585 jw_end_object(jw);
586}
587
588static void anal_dump_decl(AnalDumpCtx *ctx, Tld *tld) {
589 JsonWriter *jw = &ctx->jw;
590
591 bool make_obj = tld->id == TldIdVar || tld->id == TldIdFn;
592 if (make_obj) {
593 jw_array_elem(jw);
594 jw_begin_object(jw);
595
596 jw_object_field(jw, "import");
597 anal_dump_type_ref(ctx, tld->import);
598
599 jw_object_field(jw, "src");
600 anal_dump_node_ref(ctx, tld->source_node);
601
602 jw_object_field(jw, "name");
603 jw_string(jw, buf_ptr(tld->name));
604 }
605
606 switch (tld->id) {
607 case TldIdVar: {
608 TldVar *tld_var = reinterpret_cast<TldVar *>(tld);
609 ZigVar *var = tld_var->var;
610
611 if (var != nullptr) {
612 jw_object_field(jw, "kind");
613 if (var->src_is_const) {
614 jw_string(jw, "const");
615 } else {
616 jw_string(jw, "var");
617 }
618
619 if (var->is_thread_local) {
620 jw_object_field(jw, "threadlocal");
621 jw_bool(jw, true);
622 }
623
624 jw_object_field(jw, "type");
625 anal_dump_type_ref(ctx, var->var_type);
626
627 if (var->const_value != nullptr) {
628 jw_object_field(jw, "value");
629 anal_dump_value(ctx, var->decl_node, var->var_type, var->const_value);
630 }
631 }
632 break;
633 }
634 case TldIdFn: {
635 TldFn *tld_fn = reinterpret_cast<TldFn *>(tld);
636 ZigFn *fn = tld_fn->fn_entry;
637
638 if (fn != nullptr) {
639 jw_object_field(jw, "kind");
640 jw_string(jw, "const");
641
642 jw_object_field(jw, "type");
643 anal_dump_type_ref(ctx, fn->type_entry);
644
645 jw_object_field(jw, "value");
646 anal_dump_fn_ref(ctx, fn);
647 }
648 break;
649 }
650 default:
651 break;
652 }
653
654 if (make_obj) {
655 jw_end_object(jw);
656 }
657}
658
659static void anal_dump_file(AnalDumpCtx *ctx, Buf *file) {
660 JsonWriter *jw = &ctx->jw;
661 jw_string(jw, buf_ptr(file));
662}
663
664static void anal_dump_value(AnalDumpCtx *ctx, AstNode *source_node, ZigType *ty, ZigValue *value) {
665 Error err;
666
667 if (value->type != ty) {
668 jw_null(&ctx->jw);
669 return;
670 }
671 if ((err = ir_resolve_lazy(ctx->g, source_node, value))) {
672 codegen_report_errors_and_exit(ctx->g);
673 }
674 if (value->special == ConstValSpecialUndef) {
675 jw_string(&ctx->jw, "undefined");
676 return;
677 }
678 if (value->special == ConstValSpecialRuntime) {
679 jw_null(&ctx->jw);
680 return;
681 }
682 switch (ty->id) {
683 case ZigTypeIdMetaType: {
684 ZigType *val_ty = value->data.x_type;
685 anal_dump_type_ref(ctx, val_ty);
686 return;
687 }
688 case ZigTypeIdFn: {
689 if (value->data.x_ptr.special == ConstPtrSpecialFunction) {
690 ZigFn *val_fn = value->data.x_ptr.data.fn.fn_entry;
691 anal_dump_fn_ref(ctx, val_fn);
692 } else {
693 jw_null(&ctx->jw);
694 }
695 return;
696 }
697 case ZigTypeIdOptional: {
698 if(optional_value_is_null(value)){
699 jw_string(&ctx->jw, "null");
700 } else {
701 jw_null(&ctx->jw);
702 }
703 return;
704 }
705 case ZigTypeIdBool: {
706 jw_string(&ctx->jw, value->data.x_bool ? "true" : "false");
707 return;
708 }
709 case ZigTypeIdInt: {
710 jw_bigint(&ctx->jw, &value->data.x_bigint);
711 return;
712 }
713 default:
714 jw_null(&ctx->jw);
715 return;
716 }
717 zig_unreachable();
718}
719
720static void anal_dump_pointer_attrs(AnalDumpCtx *ctx, ZigType *ty) {
721 JsonWriter *jw = &ctx->jw;
722 if (ty->data.pointer.explicit_alignment != 0) {
723 jw_object_field(jw, "align");
724 jw_int(jw, ty->data.pointer.explicit_alignment);
725 }
726 if (ty->data.pointer.is_const) {
727 jw_object_field(jw, "const");
728 jw_bool(jw, true);
729 }
730 if (ty->data.pointer.is_volatile) {
731 jw_object_field(jw, "volatile");
732 jw_bool(jw, true);
733 }
734 if (ty->data.pointer.allow_zero) {
735 jw_object_field(jw, "allowZero");
736 jw_bool(jw, true);
737 }
738 if (ty->data.pointer.host_int_bytes != 0) {
739 jw_object_field(jw, "hostIntBytes");
740 jw_int(jw, ty->data.pointer.host_int_bytes);
741
742 jw_object_field(jw, "bitOffsetInHost");
743 jw_int(jw, ty->data.pointer.bit_offset_in_host);
744 }
745
746 jw_object_field(jw, "elem");
747 anal_dump_type_ref(ctx, ty->data.pointer.child_type);
748}
749
750static void anal_dump_type(AnalDumpCtx *ctx, ZigType *ty) {
751 JsonWriter *jw = &ctx->jw;
752 jw_array_elem(jw);
753 jw_begin_object(jw);
754
755 jw_object_field(jw, "kind");
756 jw_int(jw, type_id_index(ty));
757
758 switch (ty->id) {
759 case ZigTypeIdMetaType:
760 case ZigTypeIdBool:
761 case ZigTypeIdEnumLiteral:
762 break;
763 case ZigTypeIdStruct: {
764 if (ty->data.structure.special == StructSpecialSlice) {
765 jw_object_field(jw, "len");
766 jw_int(jw, 2);
767 anal_dump_pointer_attrs(ctx, ty->data.structure.fields[slice_ptr_index]->type_entry);
768 break;
769 }
770
771 jw_object_field(jw, "name");
772 jw_string(jw, buf_ptr(&ty->name));
773
774 jw_object_field(jw, "src");
775 anal_dump_node_ref(ctx, ty->data.structure.decl_node);
776
777 {
778 jw_object_field(jw, "pubDecls");
779 jw_begin_array(jw);
780
781 ScopeDecls *decls_scope = ty->data.structure.decls_scope;
782 auto it = decls_scope->decl_table.entry_iterator();
783 for (;;) {
784 auto *entry = it.next();
785 if (!entry)
786 break;
787
788 Tld *tld = entry->value;
789 if (tld->visib_mod == VisibModPub) {
790 jw_array_elem(jw);
791 anal_dump_decl_ref(ctx, tld);
792 }
793 }
794 jw_end_array(jw);
795 }
796
797 {
798 jw_object_field(jw, "privDecls");
799 jw_begin_array(jw);
800
801 ScopeDecls *decls_scope = ty->data.structure.decls_scope;
802 auto it = decls_scope->decl_table.entry_iterator();
803 for (;;) {
804 auto *entry = it.next();
805 if (!entry)
806 break;
807
808 Tld *tld = entry->value;
809 if (tld->visib_mod == VisibModPrivate) {
810 jw_array_elem(jw);
811 anal_dump_decl_ref(ctx, tld);
812 }
813 }
814 jw_end_array(jw);
815 }
816
817 if (ty->data.structure.src_field_count != 0) {
818 jw_object_field(jw, "fields");
819 jw_begin_array(jw);
820
821 for(size_t i = 0; i < ty->data.structure.src_field_count; i += 1) {
822 jw_array_elem(jw);
823 anal_dump_type_ref(ctx, ty->data.structure.fields[i]->type_entry);
824 }
825 jw_end_array(jw);
826 }
827
828 if (ty->data.structure.root_struct != nullptr) {
829 Buf *path_buf = ty->data.structure.root_struct->path;
830
831 jw_object_field(jw, "file");
832 anal_dump_file_ref(ctx, path_buf);
833 }
834 break;
835 }
836 case ZigTypeIdUnion: {
837 jw_object_field(jw, "name");
838 jw_string(jw, buf_ptr(&ty->name));
839
840 jw_object_field(jw, "src");
841 anal_dump_node_ref(ctx, ty->data.unionation.decl_node);
842
843 {
844 jw_object_field(jw, "pubDecls");
845 jw_begin_array(jw);
846
847 ScopeDecls *decls_scope = ty->data.unionation.decls_scope;
848 auto it = decls_scope->decl_table.entry_iterator();
849 for (;;) {
850 auto *entry = it.next();
851 if (!entry)
852 break;
853
854 Tld *tld = entry->value;
855 if (tld->visib_mod == VisibModPub) {
856 jw_array_elem(jw);
857 anal_dump_decl_ref(ctx, tld);
858 }
859 }
860 jw_end_array(jw);
861 }
862
863 {
864 jw_object_field(jw, "privDecls");
865 jw_begin_array(jw);
866
867 ScopeDecls *decls_scope = ty->data.unionation.decls_scope;
868 auto it = decls_scope->decl_table.entry_iterator();
869 for (;;) {
870 auto *entry = it.next();
871 if (!entry)
872 break;
873
874 Tld *tld = entry->value;
875 if (tld->visib_mod == VisibModPrivate) {
876 jw_array_elem(jw);
877 anal_dump_decl_ref(ctx, tld);
878 }
879 }
880 jw_end_array(jw);
881 }
882
883 if (ty->data.unionation.src_field_count != 0) {
884 jw_object_field(jw, "fields");
885 jw_begin_array(jw);
886
887 for(size_t i = 0; i < ty->data.unionation.src_field_count; i += 1) {
888 jw_array_elem(jw);
889 anal_dump_type_ref(ctx, ty->data.unionation.fields[i].type_entry);
890 }
891 jw_end_array(jw);
892 }
893 break;
894 }
895 case ZigTypeIdEnum: {
896 jw_object_field(jw, "name");
897 jw_string(jw, buf_ptr(&ty->name));
898
899 jw_object_field(jw, "src");
900 anal_dump_node_ref(ctx, ty->data.enumeration.decl_node);
901
902 {
903 jw_object_field(jw, "pubDecls");
904 jw_begin_array(jw);
905
906 ScopeDecls *decls_scope = ty->data.enumeration.decls_scope;
907 auto it = decls_scope->decl_table.entry_iterator();
908 for (;;) {
909 auto *entry = it.next();
910 if (!entry)
911 break;
912
913 Tld *tld = entry->value;
914 if (tld->visib_mod == VisibModPub) {
915 jw_array_elem(jw);
916 anal_dump_decl_ref(ctx, tld);
917 }
918 }
919 jw_end_array(jw);
920 }
921
922 {
923 jw_object_field(jw, "privDecls");
924 jw_begin_array(jw);
925
926 ScopeDecls *decls_scope = ty->data.enumeration.decls_scope;
927 auto it = decls_scope->decl_table.entry_iterator();
928 for (;;) {
929 auto *entry = it.next();
930 if (!entry)
931 break;
932
933 Tld *tld = entry->value;
934 if (tld->visib_mod == VisibModPrivate) {
935 jw_array_elem(jw);
936 anal_dump_decl_ref(ctx, tld);
937 }
938 }
939 jw_end_array(jw);
940 }
941
942 if (ty->data.enumeration.src_field_count != 0) {
943 jw_object_field(jw, "fields");
944 jw_begin_array(jw);
945
946 for(size_t i = 0; i < ty->data.enumeration.src_field_count; i += 1) {
947 jw_array_elem(jw);
948 jw_bigint(jw, &ty->data.enumeration.fields[i].value);
949 }
950 jw_end_array(jw);
951 }
952 break;
953 }
954 case ZigTypeIdFloat: {
955 jw_object_field(jw, "bits");
956 jw_int(jw, ty->data.floating.bit_count);
957 break;
958 }
959 case ZigTypeIdInt: {
960 if (ty->data.integral.is_signed) {
961 jw_object_field(jw, "i");
962 } else {
963 jw_object_field(jw, "u");
964 }
965 jw_int(jw, ty->data.integral.bit_count);
966 break;
967 }
968 case ZigTypeIdFn: {
969 jw_object_field(jw, "name");
970 jw_string(jw, buf_ptr(&ty->name));
971
972 jw_object_field(jw, "generic");
973 jw_bool(jw, ty->data.fn.is_generic);
974
975 if (ty->data.fn.fn_type_id.return_type != nullptr) {
976 jw_object_field(jw, "ret");
977 anal_dump_type_ref(ctx, ty->data.fn.fn_type_id.return_type);
978 }
979
980 if (ty->data.fn.fn_type_id.param_count != 0) {
981 jw_object_field(jw, "args");
982 jw_begin_array(jw);
983 for (size_t i = 0; i < ty->data.fn.fn_type_id.param_count; i += 1) {
984 jw_array_elem(jw);
985 if (ty->data.fn.fn_type_id.param_info[i].type != nullptr) {
986 anal_dump_type_ref(ctx, ty->data.fn.fn_type_id.param_info[i].type);
987 } else {
988 jw_null(jw);
989 }
990 }
991 jw_end_array(jw);
992 }
993 break;
994 }
995 case ZigTypeIdOptional: {
996 jw_object_field(jw, "child");
997 anal_dump_type_ref(ctx, ty->data.maybe.child_type);
998 break;
999 }
1000 case ZigTypeIdPointer: {
1001 switch (ty->data.pointer.ptr_len) {
1002 case PtrLenSingle:
1003 break;
1004 case PtrLenUnknown:
1005 jw_object_field(jw, "len");
1006 jw_int(jw, 1);
1007 break;
1008 case PtrLenC:
1009 jw_object_field(jw, "len");
1010 jw_int(jw, 3);
1011 break;
1012 }
1013 anal_dump_pointer_attrs(ctx, ty);
1014 break;
1015 }
1016 case ZigTypeIdErrorSet: {
1017 if (type_is_global_error_set(ty)) {
1018 break;
1019 }
1020 jw_object_field(jw, "name");
1021 jw_string(jw, buf_ptr(&ty->name));
1022
1023 if (ty->data.error_set.infer_fn != nullptr) {
1024 jw_object_field(jw, "fn");
1025 anal_dump_fn_ref(ctx, ty->data.error_set.infer_fn);
1026 }
1027 jw_object_field(jw, "errors");
1028 jw_begin_array(jw);
1029 for (uint32_t i = 0; i < ty->data.error_set.err_count; i += 1) {
1030 jw_array_elem(jw);
1031 ErrorTableEntry *err = ty->data.error_set.errors[i];
1032 anal_dump_err_ref(ctx, err);
1033 }
1034 jw_end_array(jw);
1035 break;
1036 }
1037 case ZigTypeIdErrorUnion: {
1038 jw_object_field(jw, "err");
1039 anal_dump_type_ref(ctx, ty->data.error_union.err_set_type);
1040
1041 jw_object_field(jw, "payload");
1042 anal_dump_type_ref(ctx, ty->data.error_union.payload_type);
1043
1044 break;
1045 }
1046 case ZigTypeIdArray: {
1047 jw_object_field(jw, "len");
1048 jw_int(jw, ty->data.array.len);
1049
1050 jw_object_field(jw, "elem");
1051 anal_dump_type_ref(ctx, ty->data.array.child_type);
1052 break;
1053 }
1054 case ZigTypeIdVector: {
1055 jw_object_field(jw, "len");
1056 jw_int(jw, ty->data.vector.len);
1057
1058 jw_object_field(jw, "elem");
1059 anal_dump_type_ref(ctx, ty->data.vector.elem_type);
1060 break;
1061 }
1062 case ZigTypeIdAnyFrame: {
1063 if (ty->data.any_frame.result_type != nullptr) {
1064 jw_object_field(jw, "result");
1065 anal_dump_type_ref(ctx, ty->data.any_frame.result_type);
1066 }
1067 break;
1068 }
1069 case ZigTypeIdFnFrame: {
1070 jw_object_field(jw, "fnName");
1071 jw_string(jw, buf_ptr(&ty->data.frame.fn->symbol_name));
1072
1073 jw_object_field(jw, "fn");
1074 anal_dump_fn_ref(ctx, ty->data.frame.fn);
1075 break;
1076 }
1077 case ZigTypeIdInvalid:
1078 zig_unreachable();
1079 default:
1080 jw_object_field(jw, "name");
1081 jw_string(jw, buf_ptr(&ty->name));
1082 break;
1083 }
1084 jw_end_object(jw);
1085}
1086
1087static Buf *collect_doc_comments(RootStruct *root_struct, TokenIndex first_token) {
1088 if (first_token == 0)
1089 return nullptr;
1090
1091 TokenId *token_ids = root_struct->token_ids;
1092 TokenLoc *token_locs = root_struct->token_locs;
1093 Buf *str = buf_alloc();
1094 const char *source = buf_ptr(root_struct->source_code);
1095 TokenIndex doc_token = first_token;
1096 for (;token_ids[doc_token] == TokenIdDocComment; doc_token += 1) {
1097 // chops off '///' but leaves '\n'
1098 uint32_t start_pos = token_locs[doc_token].offset;
1099 uint32_t token_len = 0;
1100 while (source[start_pos + token_len] != '\n' &&
1101 source[start_pos + token_len] != 0)
1102 {
1103 token_len += 1;
1104 }
1105 buf_append_mem(str, source + start_pos + 3, token_len - 3);
1106 }
1107 return str;
1108}
1109
1110static void anal_dump_node(AnalDumpCtx *ctx, const AstNode *node) {
1111 JsonWriter *jw = &ctx->jw;
1112
1113 jw_begin_object(jw);
1114
1115 jw_object_field(jw, "file");
1116 RootStruct *root_struct = node->owner->data.structure.root_struct;
1117 anal_dump_file_ref(ctx, root_struct->path);
1118
1119 jw_object_field(jw, "line");
1120 jw_int(jw, root_struct->token_locs[node->main_token].line);
1121
1122 jw_object_field(jw, "col");
1123 jw_int(jw, root_struct->token_locs[node->main_token].column);
1124
1125 const Buf *doc_comments_buf = nullptr;
1126 const Buf *name_buf = nullptr;
1127 const ZigList<AstNode *> *field_nodes = nullptr;
1128 bool is_var_args = false;
1129 bool is_noalias = false;
1130 bool is_comptime = false;
1131
1132 switch (node->type) {
1133 case NodeTypeParamDecl:
1134 doc_comments_buf = collect_doc_comments(root_struct, node->data.param_decl.doc_comments);
1135 name_buf = node->data.param_decl.name;
1136 is_var_args = node->data.param_decl.is_var_args;
1137 is_noalias = node->data.param_decl.is_noalias;
1138 is_comptime = node->data.param_decl.is_comptime;
1139 break;
1140 case NodeTypeFnProto:
1141 doc_comments_buf = collect_doc_comments(root_struct, node->data.fn_proto.doc_comments);
1142 field_nodes = &node->data.fn_proto.params;
1143 is_var_args = node->data.fn_proto.is_var_args;
1144 break;
1145 case NodeTypeVariableDeclaration:
1146 doc_comments_buf = collect_doc_comments(root_struct, node->data.variable_declaration.doc_comments);
1147 break;
1148 case NodeTypeErrorSetField:
1149 doc_comments_buf = collect_doc_comments(root_struct, node->data.err_set_field.doc_comments);
1150 break;
1151 case NodeTypeStructField:
1152 doc_comments_buf = collect_doc_comments(root_struct, node->data.struct_field.doc_comments);
1153 name_buf = node->data.struct_field.name;
1154 break;
1155 case NodeTypeContainerDecl:
1156 field_nodes = &node->data.container_decl.fields;
1157 doc_comments_buf = collect_doc_comments(root_struct, node->data.container_decl.doc_comments);
1158 break;
1159 default:
1160 break;
1161 }
1162
1163 if (doc_comments_buf != nullptr && doc_comments_buf->list.length != 0) {
1164 jw_object_field(jw, "docs");
1165 jw_string(jw, buf_ptr(doc_comments_buf));
1166 }
1167
1168 if (name_buf != nullptr) {
1169 jw_object_field(jw, "name");
1170 jw_string(jw, buf_ptr(name_buf));
1171 }
1172
1173 if (field_nodes != nullptr) {
1174 jw_object_field(jw, "fields");
1175 jw_begin_array(jw);
1176 for (size_t i = 0; i < field_nodes->length; i += 1) {
1177 jw_array_elem(jw);
1178 anal_dump_node_ref(ctx, field_nodes->at(i));
1179 }
1180 jw_end_array(jw);
1181 }
1182
1183 if (is_var_args) {
1184 jw_object_field(jw, "varArgs");
1185 jw_bool(jw, true);
1186 }
1187
1188 if (is_comptime) {
1189 jw_object_field(jw, "comptime");
1190 jw_bool(jw, true);
1191 }
1192
1193 if (is_noalias) {
1194 jw_object_field(jw, "noalias");
1195 jw_bool(jw, true);
1196 }
1197
1198 jw_end_object(jw);
1199}
1200
1201static void anal_dump_err(AnalDumpCtx *ctx, const ErrorTableEntry *err) {
1202 JsonWriter *jw = &ctx->jw;
1203
1204 jw_begin_object(jw);
1205
1206 jw_object_field(jw, "src");
1207 anal_dump_node_ref(ctx, err->decl_node);
1208
1209 jw_object_field(jw, "name");
1210 jw_string(jw, buf_ptr(&err->name));
1211
1212 jw_end_object(jw);
1213}
1214
1215static void anal_dump_fn(AnalDumpCtx *ctx, ZigFn *fn) {
1216 JsonWriter *jw = &ctx->jw;
1217
1218 jw_begin_object(jw);
1219
1220 jw_object_field(jw, "src");
1221 anal_dump_node_ref(ctx, fn->proto_node);
1222
1223 jw_object_field(jw, "type");
1224 anal_dump_type_ref(ctx, fn->type_entry);
1225
1226 auto entry = ctx->fn_decl_map.maybe_get(fn);
1227 if (entry != nullptr) {
1228 jw_object_field(jw, "decl");
1229 jw_int(jw, entry->value);
1230 }
1231
1232 jw_end_object(jw);
1233}
1234
1235void zig_print_analysis_dump(CodeGen *g, FILE *f, const char *one_indent, const char *nl) {
1236 AnalDumpCtx ctx = {};
1237 ctx.g = g;
1238 JsonWriter *jw = &ctx.jw;
1239 jw_init(jw, f, one_indent, nl);
1240 ctx.type_map.init(16);
1241 ctx.pkg_map.init(16);
1242 ctx.file_map.init(16);
1243 ctx.decl_map.init(16);
1244 ctx.node_map.init(16);
1245 ctx.fn_map.init(16);
1246 ctx.fn_decl_map.init(16);
1247 ctx.err_map.init(16);
1248
1249 jw_begin_object(jw);
1250
1251 jw_object_field(jw, "typeKinds");
1252 jw_begin_array(jw);
1253 for (size_t i = 0; i < type_id_len(); i += 1) {
1254 jw_array_elem(jw);
1255 jw_string(jw, type_id_name(type_id_at_index(i)));
1256 }
1257 jw_end_array(jw);
1258
1259 jw_object_field(jw, "params");
1260 jw_begin_object(jw);
1261 {
1262 jw_object_field(jw, "zigVersion");
1263 jw_string(jw, stage2_version_string());
1264
1265 jw_object_field(jw, "builds");
1266 jw_begin_array(jw);
1267 jw_array_elem(jw);
1268 jw_begin_object(jw);
1269 jw_object_field(jw, "target");
1270 Buf triple_buf = BUF_INIT;
1271 target_triple_zig(&triple_buf, g->zig_target);
1272 jw_string(jw, buf_ptr(&triple_buf));
1273 jw_end_object(jw);
1274 jw_end_array(jw);
1275
1276 jw_object_field(jw, "rootName");
1277 jw_string(jw, buf_ptr(g->root_out_name));
1278 }
1279 jw_end_object(jw);
1280
1281 jw_object_field(jw, "rootPkg");
1282 anal_dump_pkg_ref(&ctx, g->main_pkg);
1283
1284 // FIXME: Remove this ugly workaround.
1285 // Right now the code in docs/main.js relies on the root of the main package being itself.
1286 g->main_pkg->package_table.put(buf_create_from_str("root"), g->main_pkg);
1287
1288 // Poke the functions
1289 for (size_t i = 0; i < g->fn_defs.length; i += 1) {
1290 ZigFn *fn = g->fn_defs.at(i);
1291 (void)anal_dump_get_fn_id(&ctx, fn);
1292 }
1293
1294 jw_object_field(jw, "calls");
1295 jw_begin_array(jw);
1296 {
1297 ZigList<ZigVar *> var_stack = {};
1298
1299 auto it = g->memoized_fn_eval_table.entry_iterator();
1300 for (;;) {
1301 auto *entry = it.next();
1302 if (!entry)
1303 break;
1304
1305 var_stack.resize(0);
1306 ZigFn *fn = nullptr;
1307
1308 Scope *scope = entry->key;
1309 while (scope != nullptr) {
1310 if (scope->id == ScopeIdVarDecl) {
1311 ZigVar *var = reinterpret_cast<ScopeVarDecl *>(scope)->var;
1312 var_stack.append(var);
1313 } else if (scope->id == ScopeIdFnDef) {
1314 fn = reinterpret_cast<ScopeFnDef *>(scope)->fn_entry;
1315 break;
1316 }
1317 scope = scope->parent;
1318 }
1319 ZigValue *result = entry->value;
1320
1321 assert(fn != nullptr);
1322
1323 jw_array_elem(jw);
1324 jw_begin_object(jw);
1325
1326 jw_object_field(jw, "fn");
1327 anal_dump_fn_ref(&ctx, fn);
1328
1329 jw_object_field(jw, "result");
1330 {
1331 jw_begin_object(jw);
1332
1333 jw_object_field(jw, "type");
1334 anal_dump_type_ref(&ctx, result->type);
1335
1336 jw_object_field(jw, "value");
1337 anal_dump_value(&ctx, scope->source_node, result->type, result);
1338
1339 jw_end_object(jw);
1340 }
1341
1342 if (var_stack.length != 0) {
1343 jw_object_field(jw, "args");
1344 jw_begin_array(jw);
1345
1346 while (var_stack.length != 0) {
1347 ZigVar *var = var_stack.pop();
1348
1349 jw_array_elem(jw);
1350 jw_begin_object(jw);
1351
1352 jw_object_field(jw, "type");
1353 anal_dump_type_ref(&ctx, var->var_type);
1354
1355 jw_object_field(jw, "value");
1356 anal_dump_value(&ctx, scope->source_node, var->var_type, var->const_value);
1357
1358 jw_end_object(jw);
1359 }
1360 jw_end_array(jw);
1361 }
1362
1363 jw_end_object(jw);
1364 }
1365
1366 var_stack.deinit();
1367 }
1368 jw_end_array(jw);
1369
1370 jw_object_field(jw, "packages");
1371 jw_begin_array(jw);
1372 for (uint32_t i = 0; i < ctx.pkg_list.length; i += 1) {
1373 anal_dump_pkg(&ctx, ctx.pkg_list.at(i));
1374 }
1375 jw_end_array(jw);
1376
1377 jw_object_field(jw, "types");
1378 jw_begin_array(jw);
1379
1380 for (uint32_t i = 0; i < ctx.type_list.length; i += 1) {
1381 ZigType *ty = ctx.type_list.at(i);
1382 anal_dump_type(&ctx, ty);
1383 }
1384 jw_end_array(jw);
1385
1386 jw_object_field(jw, "decls");
1387 jw_begin_array(jw);
1388 for (uint32_t i = 0; i < ctx.decl_list.length; i += 1) {
1389 Tld *decl = ctx.decl_list.at(i);
1390 anal_dump_decl(&ctx, decl);
1391 }
1392 jw_end_array(jw);
1393
1394 jw_object_field(jw, "fns");
1395 jw_begin_array(jw);
1396 for (uint32_t i = 0; i < ctx.fn_list.length; i += 1) {
1397 ZigFn *fn = ctx.fn_list.at(i);
1398 jw_array_elem(jw);
1399 anal_dump_fn(&ctx, fn);
1400 }
1401 jw_end_array(jw);
1402
1403 jw_object_field(jw, "errors");
1404 jw_begin_array(jw);
1405 for (uint32_t i = 0; i < ctx.err_list.length; i += 1) {
1406 const ErrorTableEntry *err = ctx.err_list.at(i);
1407 jw_array_elem(jw);
1408 anal_dump_err(&ctx, err);
1409 }
1410 jw_end_array(jw);
1411
1412 jw_object_field(jw, "astNodes");
1413 jw_begin_array(jw);
1414 for (uint32_t i = 0; i < ctx.node_list.length; i += 1) {
1415 const AstNode *node = ctx.node_list.at(i);
1416 jw_array_elem(jw);
1417 anal_dump_node(&ctx, node);
1418 }
1419 jw_end_array(jw);
1420
1421 jw_object_field(jw, "files");
1422 jw_begin_array(jw);
1423 for (uint32_t i = 0; i < ctx.file_list.length; i += 1) {
1424 Buf *file = ctx.file_list.at(i);
1425 jw_array_elem(jw);
1426 anal_dump_file(&ctx, file);
1427 }
1428 jw_end_array(jw);
1429
1430 jw_end_object(jw);
1431}
src/stage1/dump_analysis.hpp deleted-17
......@@ -1,17 +0,0 @@
1/*
2 * Copyright (c) 2019 Andrew Kelley
3 *
4 * This file is part of zig, which is MIT licensed.
5 * See http://opensource.org/licenses/MIT
6 */
7
8#ifndef ZIG_DUMP_ANALYSIS_HPP
9#define ZIG_DUMP_ANALYSIS_HPP
10
11#include "all_types.hpp"
12#include <stdio.h>
13
14void zig_print_stack_report(CodeGen *g, FILE *f);
15void zig_print_analysis_dump(CodeGen *g, FILE *f, const char *one_indent, const char *nl);
16
17#endif
src/stage1/stage1.cpp-2
......@@ -74,8 +74,6 @@ void zig_stage1_build_object(struct ZigStage1 *stage1) {
7474 buf_init_from_mem(&g->asm_file_output_path, stage1->emit_asm_ptr, stage1->emit_asm_len);
7575 buf_init_from_mem(&g->llvm_ir_file_output_path, stage1->emit_llvm_ir_ptr, stage1->emit_llvm_ir_len);
7676 buf_init_from_mem(&g->bitcode_file_output_path, stage1->emit_bitcode_ptr, stage1->emit_bitcode_len);
77 buf_init_from_mem(&g->analysis_json_output_path, stage1->emit_analysis_json_ptr, stage1->emit_analysis_json_len);
78 buf_init_from_mem(&g->docs_output_path, stage1->emit_docs_ptr, stage1->emit_docs_len);
7977
8078 if (stage1->builtin_zig_path_len != 0) {
8179 g->builtin_zig_path = buf_create_from_mem(stage1->builtin_zig_path_ptr, stage1->builtin_zig_path_len);
src/stage1/stage1.h-6
......@@ -161,12 +161,6 @@ struct ZigStage1 {
161161 const char *emit_bitcode_ptr;
162162 size_t emit_bitcode_len;
163163
164 const char *emit_analysis_json_ptr;
165 size_t emit_analysis_json_len;
166
167 const char *emit_docs_ptr;
168 size_t emit_docs_len;
169
170164 const char *builtin_zig_path_ptr;
171165 size_t builtin_zig_path_len;
172166
tools/merge_anal_dumps.zig deleted-454
......@@ -1,454 +0,0 @@
1const builtin = @import("builtin");
2const std = @import("std");
3const json = std.json;
4const mem = std.mem;
5const fieldIndex = std.meta.fieldIndex;
6const TypeId = builtin.TypeId;
7
8pub fn main() anyerror!void {
9 var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
10 defer arena.deinit();
11
12 const allocator = arena.allocator();
13
14 const args = try std.process.argsAlloc(allocator);
15
16 var parser: json.Parser = undefined;
17 var dump = Dump.init(allocator);
18 for (args[1..]) |arg| {
19 parser = json.Parser.init(allocator, false);
20 const json_text = try std.fs.cwd().readFileAlloc(allocator, arg, std.math.maxInt(usize));
21 const tree = try parser.parse(json_text);
22 try dump.mergeJson(tree.root);
23 }
24
25 const stdout = try std.io.getStdOut();
26 try dump.render(stdout.writer());
27}
28
29/// AST source node
30const Node = struct {
31 file: usize,
32 line: usize,
33 col: usize,
34 fields: []usize,
35
36 fn hash(n: Node) u64 {
37 var hasher = std.hash.Wyhash.init(0);
38 std.hash.autoHash(&hasher, n.file);
39 std.hash.autoHash(&hasher, n.line);
40 std.hash.autoHash(&hasher, n.col);
41 return hasher.final();
42 }
43
44 fn eql(a: Node, b: Node) bool {
45 return a.file == b.file and
46 a.line == b.line and
47 a.col == b.col;
48 }
49};
50
51const Error = struct {
52 src: usize,
53 name: []const u8,
54
55 fn hash(n: Error) u64 {
56 var hasher = std.hash.Wyhash.init(0);
57 std.hash.autoHash(&hasher, n.src);
58 return hasher.final();
59 }
60
61 fn eql(a: Error, b: Error) bool {
62 return a.src == b.src;
63 }
64};
65
66const simple_types = [_][]const u8{
67 "Type",
68 "Void",
69 "Bool",
70 "NoReturn",
71 "ComptimeFloat",
72 "ComptimeInt",
73 "Undefined",
74 "Null",
75 "AnyFrame",
76 "EnumLiteral",
77};
78
79const Type = union(builtin.TypeId) {
80 Type,
81 Void,
82 Bool,
83 NoReturn,
84 ComptimeFloat,
85 ComptimeInt,
86 Undefined,
87 Null,
88 AnyFrame,
89 EnumLiteral,
90
91 Int: Int,
92 Float: usize, // bits
93
94 Vector: Array,
95 Optional: usize, // payload type index
96 Pointer: Pointer,
97 Array: Array,
98
99 Struct, // TODO
100 ErrorUnion, // TODO
101 ErrorSet, // TODO
102 Enum, // TODO
103 Union, // TODO
104 Fn, // TODO
105 BoundFn, // TODO
106 Opaque, // TODO
107 Frame, // TODO
108
109 const Int = struct {
110 bits: usize,
111 signed: bool,
112 };
113
114 const Pointer = struct {
115 elem: usize,
116 alignment: usize,
117 is_const: bool,
118 is_volatile: bool,
119 allow_zero: bool,
120 host_int_bytes: usize,
121 bit_offset_in_host: usize,
122 };
123
124 const Array = struct {
125 elem: usize,
126 len: usize,
127 };
128
129 fn hash(t: Type) u64 {
130 var hasher = std.hash.Wyhash.init(0);
131 std.hash.autoHash(&hasher, t);
132 return hasher.final();
133 }
134
135 fn eql(a: Type, b: Type) bool {
136 return std.meta.eql(a, b);
137 }
138};
139
140const Dump = struct {
141 zig_id: ?[]const u8 = null,
142 zig_version: ?[]const u8 = null,
143 root_name: ?[]const u8 = null,
144 targets: std.ArrayList([]const u8),
145
146 file_list: std.ArrayList([]const u8),
147 file_map: FileMap,
148
149 node_list: std.ArrayList(Node),
150 node_map: NodeMap,
151
152 error_list: std.ArrayList(Error),
153 error_map: ErrorMap,
154
155 type_list: std.ArrayList(Type),
156 type_map: TypeMap,
157
158 const FileMap = std.StringHashMap(usize);
159 const NodeMap = std.HashMap(Node, usize, Node.hash, Node.eql, 80);
160 const ErrorMap = std.HashMap(Error, usize, Error.hash, Error.eql, 80);
161 const TypeMap = std.HashMap(Type, usize, Type.hash, Type.eql, 80);
162
163 fn init(allocator: mem.Allocator) Dump {
164 return Dump{
165 .targets = std.ArrayList([]const u8).init(allocator),
166 .file_list = std.ArrayList([]const u8).init(allocator),
167 .file_map = FileMap.init(allocator),
168 .node_list = std.ArrayList(Node).init(allocator),
169 .node_map = NodeMap.init(allocator),
170 .error_list = std.ArrayList(Error).init(allocator),
171 .error_map = ErrorMap.init(allocator),
172 .type_list = std.ArrayList(Type).init(allocator),
173 .type_map = TypeMap.init(allocator),
174 };
175 }
176
177 fn mergeJson(self: *Dump, root: json.Value) !void {
178 const params = &root.Object.get("params").?.value.Object;
179 const zig_id = params.get("zigId").?.value.String;
180 const zig_version = params.get("zigVersion").?.value.String;
181 const root_name = params.get("rootName").?.value.String;
182 try mergeSameStrings(&self.zig_id, zig_id);
183 try mergeSameStrings(&self.zig_version, zig_version);
184 try mergeSameStrings(&self.root_name, root_name);
185
186 for (params.get("builds").?.value.Array.items) |json_build| {
187 const target = json_build.Object.get("target").?.value.String;
188 try self.targets.append(target);
189 }
190
191 // Merge files. If the string matches, it's the same file.
192 const other_files = root.Object.get("files").?.value.Array.items;
193 var other_file_to_mine = std.AutoHashMap(usize, usize).init(self.a());
194 for (other_files) |other_file, i| {
195 const gop = try self.file_map.getOrPut(other_file.String);
196 if (!gop.found_existing) {
197 gop.kv.value = self.file_list.items.len;
198 try self.file_list.append(other_file.String);
199 }
200 try other_file_to_mine.putNoClobber(i, gop.kv.value);
201 }
202
203 // Merge AST nodes. If the file id, line, and column all match, it's the same AST node.
204 const other_ast_nodes = root.Object.get("astNodes").?.value.Array.items;
205 var other_ast_node_to_mine = std.AutoHashMap(usize, usize).init(self.a());
206 for (other_ast_nodes) |other_ast_node_json, i| {
207 const other_file_id = jsonObjInt(other_ast_node_json, "file");
208 const other_node = Node{
209 .line = jsonObjInt(other_ast_node_json, "line"),
210 .col = jsonObjInt(other_ast_node_json, "col"),
211 .file = other_file_to_mine.getValue(other_file_id).?,
212 .fields = ([*]usize)(undefined)[0..0],
213 };
214 const gop = try self.node_map.getOrPut(other_node);
215 if (!gop.found_existing) {
216 gop.kv.value = self.node_list.items.len;
217 try self.node_list.append(other_node);
218 }
219 try other_ast_node_to_mine.putNoClobber(i, gop.kv.value);
220 }
221 // convert fields lists
222 for (other_ast_nodes) |other_ast_node_json, i| {
223 const my_node_index = other_ast_node_to_mine.get(i).?.value;
224 const my_node = &self.node_list.items[my_node_index];
225 if (other_ast_node_json.Object.get("fields")) |fields_json_kv| {
226 const other_fields = fields_json_kv.value.Array.items;
227 my_node.fields = try self.a().alloc(usize, other_fields.len);
228 for (other_fields) |other_field_index, field_i| {
229 const other_index = @intCast(usize, other_field_index.Integer);
230 my_node.fields[field_i] = other_ast_node_to_mine.get(other_index).?.value;
231 }
232 }
233 }
234
235 // Merge errors. If the AST Node matches, it's the same error value.
236 const other_errors = root.Object.get("errors").?.value.Array.items;
237 var other_error_to_mine = std.AutoHashMap(usize, usize).init(self.a());
238 for (other_errors) |other_error_json, i| {
239 const other_src_id = jsonObjInt(other_error_json, "src");
240 const other_error = Error{
241 .src = other_ast_node_to_mine.getValue(other_src_id).?,
242 .name = other_error_json.Object.get("name").?.value.String,
243 };
244 const gop = try self.error_map.getOrPut(other_error);
245 if (!gop.found_existing) {
246 gop.kv.value = self.error_list.items.len;
247 try self.error_list.append(other_error);
248 }
249 try other_error_to_mine.putNoClobber(i, gop.kv.value);
250 }
251
252 // Merge types. Now it starts to get advanced.
253 // First we identify all the simple types and merge those.
254 // Example: void, type, noreturn
255 // We can also do integers and floats.
256 const other_types = root.Object.get("types").?.value.Array.items;
257 var other_types_to_mine = std.AutoHashMap(usize, usize).init(self.a());
258 for (other_types) |other_type_json, i| {
259 const type_kind = jsonObjInt(other_type_json, "kind");
260 switch (type_kind) {
261 fieldIndex(TypeId, "Int").? => {
262 var signed: bool = undefined;
263 var bits: usize = undefined;
264 if (other_type_json.Object.get("i")) |kv| {
265 signed = true;
266 bits = @intCast(usize, kv.value.Integer);
267 } else if (other_type_json.Object.get("u")) |kv| {
268 signed = false;
269 bits = @intCast(usize, kv.value.Integer);
270 } else {
271 unreachable;
272 }
273 const other_type = Type{
274 .Int = Type.Int{
275 .bits = bits,
276 .signed = signed,
277 },
278 };
279 try self.mergeOtherType(other_type, i, &other_types_to_mine);
280 },
281 fieldIndex(TypeId, "Float").? => {
282 const other_type = Type{
283 .Float = jsonObjInt(other_type_json, "bits"),
284 };
285 try self.mergeOtherType(other_type, i, &other_types_to_mine);
286 },
287 else => {},
288 }
289
290 inline for (simple_types) |simple_type_name| {
291 if (type_kind == std.meta.fieldIndex(builtin.TypeId, simple_type_name).?) {
292 const other_type = @unionInit(Type, simple_type_name, {});
293 try self.mergeOtherType(other_type, i, &other_types_to_mine);
294 }
295 }
296 }
297 }
298
299 fn mergeOtherType(
300 self: *Dump,
301 other_type: Type,
302 other_type_index: usize,
303 other_types_to_mine: *std.AutoHashMap(usize, usize),
304 ) !void {
305 const gop = try self.type_map.getOrPut(other_type);
306 if (!gop.found_existing) {
307 gop.kv.value = self.type_list.items.len;
308 try self.type_list.append(other_type);
309 }
310 try other_types_to_mine.putNoClobber(other_type_index, gop.kv.value);
311 }
312
313 fn render(self: *Dump, stream: anytype) !void {
314 var jw = json.WriteStream(@TypeOf(stream).Child, 10).init(stream);
315 try jw.beginObject();
316
317 try jw.objectField("typeKinds");
318 try jw.beginArray();
319 inline for (@typeInfo(builtin.TypeId).Enum.fields) |field| {
320 try jw.arrayElem();
321 try jw.emitString(field.name);
322 }
323 try jw.endArray();
324
325 try jw.objectField("params");
326 try jw.beginObject();
327
328 try jw.objectField("zigId");
329 try jw.emitString(self.zig_id.?);
330
331 try jw.objectField("zigVersion");
332 try jw.emitString(self.zig_version.?);
333
334 try jw.objectField("rootName");
335 try jw.emitString(self.root_name.?);
336
337 try jw.objectField("builds");
338 try jw.beginArray();
339 for (self.targets.items) |target| {
340 try jw.arrayElem();
341 try jw.beginObject();
342 try jw.objectField("target");
343 try jw.emitString(target);
344 try jw.endObject();
345 }
346 try jw.endArray();
347
348 try jw.endObject();
349
350 try jw.objectField("types");
351 try jw.beginArray();
352 for (self.type_list.items) |t| {
353 try jw.arrayElem();
354 try jw.beginObject();
355
356 try jw.objectField("kind");
357 try jw.emitNumber(@enumToInt(builtin.TypeId(t)));
358
359 switch (t) {
360 .Int => |int| {
361 if (int.signed) {
362 try jw.objectField("i");
363 } else {
364 try jw.objectField("u");
365 }
366 try jw.emitNumber(int.bits);
367 },
368 .Float => |bits| {
369 try jw.objectField("bits");
370 try jw.emitNumber(bits);
371 },
372
373 else => {},
374 }
375
376 try jw.endObject();
377 }
378 try jw.endArray();
379
380 try jw.objectField("errors");
381 try jw.beginArray();
382 for (self.error_list.items) |zig_error| {
383 try jw.arrayElem();
384 try jw.beginObject();
385
386 try jw.objectField("src");
387 try jw.emitNumber(zig_error.src);
388
389 try jw.objectField("name");
390 try jw.emitString(zig_error.name);
391
392 try jw.endObject();
393 }
394 try jw.endArray();
395
396 try jw.objectField("astNodes");
397 try jw.beginArray();
398 for (self.node_list.items) |node| {
399 try jw.arrayElem();
400 try jw.beginObject();
401
402 try jw.objectField("file");
403 try jw.emitNumber(node.file);
404
405 try jw.objectField("line");
406 try jw.emitNumber(node.line);
407
408 try jw.objectField("col");
409 try jw.emitNumber(node.col);
410
411 if (node.fields.len != 0) {
412 try jw.objectField("fields");
413 try jw.beginArray();
414
415 for (node.fields) |field_node_index| {
416 try jw.arrayElem();
417 try jw.emitNumber(field_node_index);
418 }
419 try jw.endArray();
420 }
421
422 try jw.endObject();
423 }
424 try jw.endArray();
425
426 try jw.objectField("files");
427 try jw.beginArray();
428 for (self.file_list.items) |file| {
429 try jw.arrayElem();
430 try jw.emitString(file);
431 }
432 try jw.endArray();
433
434 try jw.endObject();
435 }
436
437 fn a(self: Dump) mem.Allocator {
438 return self.targets.allocator;
439 }
440
441 fn mergeSameStrings(opt_dest: *?[]const u8, src: []const u8) !void {
442 if (opt_dest.*) |dest| {
443 if (!mem.eql(u8, dest, src))
444 return error.MismatchedDumps;
445 } else {
446 opt_dest.* = src;
447 }
448 }
449};
450
451fn jsonObjInt(json_val: json.Value, field: []const u8) usize {
452 const uncasted = json_val.Object.get(field).?.value.Integer;
453 return @intCast(usize, uncasted);
454}