commit 7502e490cb83a91133aa696e4ec0936022bee0c6 (tree)
parent f591936480730a279d55a051f92806e19834faf7
Author: Andrew Kelley <andrew@ziglang.org>
Date: Fri, 22 Jul 2022 20:56:59 -0700
Merge pull request #12173 from ziglang/autodocs-rebased
New Autodocs!
Diffstat:
15 files changed, 6295 insertions(+), 3113 deletions(-)
diff --git a/CMakeLists.txt b/CMakeLists.txt
@@ -340,7 +340,6 @@ set(STAGE1_SOURCES
"${CMAKE_SOURCE_DIR}/src/stage1/bigint.cpp"
"${CMAKE_SOURCE_DIR}/src/stage1/buffer.cpp"
"${CMAKE_SOURCE_DIR}/src/stage1/codegen.cpp"
- "${CMAKE_SOURCE_DIR}/src/stage1/dump_analysis.cpp"
"${CMAKE_SOURCE_DIR}/src/stage1/errmsg.cpp"
"${CMAKE_SOURCE_DIR}/src/stage1/error.cpp"
"${CMAKE_SOURCE_DIR}/src/stage1/heap.cpp"
diff --git a/build.zig b/build.zig
@@ -936,7 +936,6 @@ const stage1_sources = [_][]const u8{
"src/stage1/bigint.cpp",
"src/stage1/buffer.cpp",
"src/stage1/codegen.cpp",
- "src/stage1/dump_analysis.cpp",
"src/stage1/errmsg.cpp",
"src/stage1/error.cpp",
"src/stage1/heap.cpp",
diff --git a/ci/azure/build.zig b/ci/azure/build.zig
@@ -745,7 +745,6 @@ const stage1_sources = [_][]const u8{
"src/stage1/bigint.cpp",
"src/stage1/buffer.cpp",
"src/stage1/codegen.cpp",
- "src/stage1/dump_analysis.cpp",
"src/stage1/errmsg.cpp",
"src/stage1/error.cpp",
"src/stage1/heap.cpp",
diff --git a/lib/docs/index.html b/lib/docs/index.html
@@ -26,25 +26,23 @@
--search-sh-color: rgba(0, 0, 0, 0.18);
--help-sh-color: rgba(0, 0, 0, 0.75);
}
-
+
html, body { margin: 0; padding:0; height: 100%; }
a {
text-decoration: none;
}
-
+
a:hover {
text-decoration: underline;
}
-
+
.hidden {
display: none;
}
/* layout */
.canvas {
- display: flex;
- flex-direction: column;
width: 100vw;
height: 100vh;
overflow: hidden;
@@ -55,21 +53,12 @@
background-color: var(--bg-color);
}
- .banner {
- background-color: darkred;
- text-align: center;
- color: white;
- padding: 15px 5px;
- }
-
- .banner a {
- color: bisque;
- text-decoration: underline;
- }
-
.flex-main {
display: flex;
- overflow-y: hidden;
+ width: 100%;
+ height: 100%;
+ justify-content: center;
+
z-index: 100;
}
@@ -87,7 +76,7 @@
overflow-wrap: break-word;
flex-shrink: 0;
flex-grow: 0;
-
+
z-index: 300;
}
@@ -97,7 +86,7 @@
-webkit-overflow-scrolling: touch;
flex-grow: 1;
flex-shrink: 1;
-
+
z-index: 200;
}
@@ -106,44 +95,44 @@
max-width: 85vw;
flex-shrink: 1;
}
-
+
.help-modal {
z-index: 400;
}
-
+
/* sidebar */
.sidebar {
font-size: 1rem;
background-color: var(--bg-color);
box-shadow: 0 0 1rem var(--sidebar-sh-color);
}
-
+
.sidebar .logo {
padding: 1rem 0.35rem 0.35rem 0.35rem;
}
-
+
.sidebar .logo > svg {
display: block;
overflow: visible;
}
-
+
.sidebar h2 {
margin: 0.5rem;
padding: 0;
font-size: 1.2rem;
}
-
+
.sidebar h2 > span {
border-bottom: 0.125rem dotted var(--tx-color);
}
-
+
.sidebar .packages {
list-style-type: none;
margin: 0;
padding: 0;
background-color: var(--sidebar-pkg-bg-color);
}
-
+
.sidebar .packages > li > a {
display: block;
padding: 0.5rem 1rem;
@@ -151,17 +140,17 @@
background-color: var(--sidebar-pkglnk-bg-color);
text-decoration: none;
}
-
+
.sidebar .packages > li > a:hover {
color: var(--sidebar-pkglnk-tx-color-hover);
background-color: var(--sidebar-pkglnk-bg-color-hover);
}
-
+
.sidebar .packages > li > a.active {
color: var(--sidebar-pkglnk-tx-color-active);
background-color: var(--sidebar-pkglnk-bg-color-active);
}
-
+
.sidebar p.str {
margin: 0.5rem;
font-family: var(--mono);
@@ -194,28 +183,28 @@
border-radius: 0;
-webkit-appearance: none;
}
-
+
.docs .search:focus {
background-color: var(--search-bg-color-focus);
border-bottom-color: #ffbb4d;
box-shadow: 0 0.3em 1em 0.125em var(--search-sh-color);
}
-
+
.docs .search::placeholder {
font-size: 1rem;
font-family: var(--ui);
color: var(--tx-color);
opacity: 0.5;
}
-
+
.docs a {
color: var(--link-color);
}
-
+
.docs p {
margin: 0.8rem 0;
}
-
+
.docs pre {
font-family: var(--mono);
font-size:1em;
@@ -223,19 +212,19 @@
padding:1em;
overflow-x: auto;
}
-
+
.docs code {
font-family: var(--mono);
font-size: 1em;
}
-
+
.docs h1 {
font-size: 1.4em;
margin: 0.8em 0;
padding: 0;
border-bottom: 0.0625rem dashed;
}
-
+
.docs h2 {
font-size: 1.3em;
margin: 0.5em 0;
@@ -275,7 +264,7 @@
#tableFnErrors dt {
font-weight: bold;
}
-
+
.examples {
list-style-type: none;
margin: 0;
@@ -286,7 +275,7 @@
white-space: nowrap;
overflow-x: auto;
}
-
+
.docs td {
margin: 0;
padding: 0.5em;
@@ -294,7 +283,7 @@
text-overflow: ellipsis;
overflow-x: hidden;
}
-
+
/* help dialog */
.help-modal {
display: flex;
@@ -319,23 +308,23 @@
border: 0.125rem solid #000;
box-shadow: 0 0.5rem 2.5rem 0.3rem var(--help-sh-color);
}
-
+
.help-modal h1 {
margin: 0.75em 2.5em 1em 2.5em;
font-size: 1.5em;
text-align: center;
}
-
+
.help-modal dt, .help-modal dd {
display: inline;
margin: 0 0.2em;
}
-
+
.help-modal dl {
margin-left: 0.5em;
margin-right: 0.5em;
}
-
+
.help-modal kbd {
display: inline-block;
padding: 0.3em 0.2em;
@@ -352,7 +341,14 @@
box-shadow: inset 0 -0.0625em 0 #c6cbd1;
cursor: default;
}
-
+
+ #listFns dt {
+ font-family: var(--mono);
+ }
+ .argBreaker {
+ display: none;
+ }
+
/* tokens */
.tok-kw {
color: #333;
@@ -382,10 +378,10 @@
color: #458;
font-weight: bold;
}
-
+
/* dark mode */
@media (prefers-color-scheme: dark) {
-
+
:root {
--tx-color: #bbb;
--bg-color: #111;
@@ -403,7 +399,7 @@
--search-sh-color: rgba(255, 255, 255, 0.28);
--help-sh-color: rgba(142, 142, 142, 0.5);
}
-
+
.docs pre {
background-color:#2A2A2A;
}
@@ -451,7 +447,7 @@
.tok-type {
color: #68f;
}
-
+
}
@media only screen and (max-width: 750px) {
@@ -523,34 +519,87 @@
min-width: calc(100% - 2.8rem);
}
}
+ .banner {
+ background-color: orange;
+ text-align: center;
+ color: black;
+ padding: 5px 5px;
+ }
+ .banner a {
+ color: black;
+ text-decoration: underline;
+ }
</style>
</head>
<body class="canvas">
- <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>
+ <div class="banner">
+ This is a beta autodoc build; expect bugs and missing information.
+ <a href="https://github.com/ziglang/zig/wiki/How-to-contribute-to-Autodoc">Report an Issue</a>,
+ <a href="https://github.com/ziglang/zig/wiki/How-to-contribute-to-Autodoc">Contribute</a>,
+ <a href="https://github.com/ziglang/zig/wiki/How-to-read-the-standard-library-source-code">Learn more about stdlib source code</a>.
+ </div>
<div class="flex-main">
<div class="flex-filler"></div>
<div class="flex-left sidebar">
<nav>
<div class="logo">
- <svg version="1.1" viewBox="0 0 150 80" xmlns="http://www.w3.org/2000/svg">
- <g fill="#f7a41d">
- <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>
- <path d="m37,59.91101l-18,20l0,-15l18,-5z"></path>
- <path d="m113,19.91101l18,-20l0,15l-18,5z"></path>
- <path d="m96.98,0.54101l36.28,-10.4l-80.29,89.17l-36.28,10.4l80.29,-89.17z"></path>
- </g>
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 400 140">
+ <g fill="#F7A41D">
+ <g>
+ <polygon points="46,22 28,44 19,30"/>
+ <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"/>
+ <polygon points="31,95 12,117 4,106"/>
+ </g>
+ <g>
+ <polygon points="56,22 62,36 37,44"/>
+ <polygon points="56,22 111,22 111,44 37,44 56,32" shape-rendering="crispEdges"/>
+ <polygon points="116,95 97,117 90,104"/>
+ <polygon points="116,95 100,104 97,117 42,117 42,95" shape-rendering="crispEdges"/>
+ <polygon points="150,0 52,117 3,140 101,22"/>
+ </g>
+ <g>
+ <polygon points="141,22 140,40 122,45"/>
+ <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"/>
+ <polygon points="125,95 130,110 106,117"/>
+ </g>
+ </g>
+ <style>
+ #text { fill: #121212 }
+ @media (prefers-color-scheme: dark) { #text { fill: #f2f2f2 } }
+ </style>
+ <g id="text">
+ <g>
+ <polygon points="260,22 260,37 229,40 177,40 177,22" shape-rendering="crispEdges"/>
+ <polygon points="260,37 207,99 207,103 176,103 229,40 229,37"/>
+ <polygon points="261,99 261,117 176,117 176,103 206,99" shape-rendering="crispEdges"/>
+ </g>
+ <rect x="272" y="22" shape-rendering="crispEdges" width="22" height="95"/>
+ <g>
+ <polygon points="394,67 394,106 376,106 376,81 360,70 346,67" shape-rendering="crispEdges"/>
+ <polygon points="360,68 376,81 346,67"/>
+ <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"/>
+ </g>
+ </g>
</svg>
+ </div>
+ <div id="sectMainPkg" class="hidden">
+ <h2><span>Main Package</span></h2>
+ <ul class="packages">
+ <li><a id="mainPkg" class="" href=""></a></li>
+ </ul>
</div>
<div id="sectPkgs" class="hidden">
- <h2><span>Packages</span></h2>
+ <h2><span>Dependencies</span></h2>
<ul id="listPkgs" class="packages"></ul>
</div>
<div id="sectInfo" class="hidden">
<h2><span>Zig Version</span></h2>
<p class="str" id="tdZigVer"></p>
- <h2><span>Target</span></h2>
- <p class="str" id="tdTarget"></p>
</div>
+ <div>
+ <input id="privDeclsBox" type="checkbox"/>
+ <label for="privDeclsBox">Internal Doc Mode</label>
+ </div>
</nav>
</div>
<div class="flex-right">
@@ -588,7 +637,6 @@
<div id="sectSearchResults" class="hidden">
<h2>Search Results</h2>
<ul id="listSearchResults"></ul>
- <p id="sectSearchAllResultsLink" class="hidden"><a href="">show all results</a></p>
</div>
<div id="sectSearchNoResults" class="hidden">
<h2>No Results Found</h2>
@@ -617,9 +665,7 @@
<div id="sectFns" class="hidden">
<h2>Functions</h2>
<div class="table-container">
- <table>
- <tbody id="listFns"></tbody>
- </table>
+ <dl id="listFns"></dl>
</div>
</div>
<div id="sectValues" class="hidden">
@@ -638,7 +684,15 @@
<h2>Examples</h2>
<ul id="listFnExamples" class="examples"></ul>
</div>
- </section>
+ <div id="sectTests" class="hidden">
+ <h2>Tests</h2>
+ <div class="table-container">
+ <table>
+ <tbody id="listTests"></tbody>
+ </table>
+ </div>
+ </div>
+ </section>
</div>
<div class="flex-filler"></div>
</div>
diff --git a/lib/docs/main.js b/lib/docs/main.js
@@ -1,73 +1,83 @@
+'use strict';
+
+var zigAnalysis;
+
(function() {
- var domStatus = document.getElementById("status");
- var domSectNav = document.getElementById("sectNav");
- var domListNav = document.getElementById("listNav");
- var domSectPkgs = document.getElementById("sectPkgs");
- var domListPkgs = document.getElementById("listPkgs");
- var domSectTypes = document.getElementById("sectTypes");
- var domListTypes = document.getElementById("listTypes");
- var domSectNamespaces = document.getElementById("sectNamespaces");
- var domListNamespaces = document.getElementById("listNamespaces");
- var domSectErrSets = document.getElementById("sectErrSets");
- var domListErrSets = document.getElementById("listErrSets");
- var domSectFns = document.getElementById("sectFns");
- var domListFns = document.getElementById("listFns");
- var domSectFields = document.getElementById("sectFields");
- var domListFields = document.getElementById("listFields");
- var domSectGlobalVars = document.getElementById("sectGlobalVars");
- var domListGlobalVars = document.getElementById("listGlobalVars");
- var domSectValues = document.getElementById("sectValues");
- var domListValues = document.getElementById("listValues");
- var domFnProto = document.getElementById("fnProto");
- var domFnProtoCode = document.getElementById("fnProtoCode");
- var domSectParams = document.getElementById("sectParams");
- var domListParams = document.getElementById("listParams");
- var domTldDocs = document.getElementById("tldDocs");
- var domSectFnErrors = document.getElementById("sectFnErrors");
- var domListFnErrors = document.getElementById("listFnErrors");
- var domTableFnErrors = document.getElementById("tableFnErrors");
- var domFnErrorsAnyError = document.getElementById("fnErrorsAnyError");
- var domFnExamples = document.getElementById("fnExamples");
- var domListFnExamples = document.getElementById("listFnExamples");
- var domFnNoExamples = document.getElementById("fnNoExamples");
- var domDeclNoRef = document.getElementById("declNoRef");
- var domSearch = document.getElementById("search");
- var domSectSearchResults = document.getElementById("sectSearchResults");
- var domListSearchResults = document.getElementById("listSearchResults");
- var domSectSearchNoResults = document.getElementById("sectSearchNoResults");
- var domSectSearchAllResultsLink = document.getElementById("sectSearchAllResultsLink");
- var domSectInfo = document.getElementById("sectInfo");
- var domTdTarget = document.getElementById("tdTarget");
- var domTdZigVer = document.getElementById("tdZigVer");
- var domHdrName = document.getElementById("hdrName");
- var domHelpModal = document.getElementById("helpDialog");
-
- var searchTimer = null;
- var searchTrimResults = true;
- var escapeHtmlReplacements = { "&": "&", '"': """, "<": "<", ">": ">" };
-
- var typeKinds = indexTypeKinds();
- var typeTypeId = findTypeTypeId();
- var pointerSizeEnum = { One: 0, Many: 1, Slice: 2, C: 3 };
- var tokenKinds = {
- Keyword: 'tok-kw',
- String: 'tok-str',
- Builtin: 'tok-builtin',
- Comment: 'tok-comment',
- Function: 'tok-fn',
- Null: 'tok-null',
- Number: 'tok-number',
- Type: 'tok-type',
- };
+ let domStatus = (document.getElementById("status"));
+ let domSectNav = (document.getElementById("sectNav"));
+ let domListNav = (document.getElementById("listNav"));
+ let domSectMainPkg = (document.getElementById("sectMainPkg"));
+ let domSectPkgs = (document.getElementById("sectPkgs"));
+ let domListPkgs = (document.getElementById("listPkgs"));
+ let domSectTypes = (document.getElementById("sectTypes"));
+ let domListTypes = (document.getElementById("listTypes"));
+ let domSectTests = (document.getElementById("sectTests"));
+ let domListTests = (document.getElementById("listTests"));
+ let domSectNamespaces = (document.getElementById("sectNamespaces"));
+ let domListNamespaces = (document.getElementById("listNamespaces"));
+ let domSectErrSets = (document.getElementById("sectErrSets"));
+ let domListErrSets = (document.getElementById("listErrSets"));
+ let domSectFns = (document.getElementById("sectFns"));
+ let domListFns = (document.getElementById("listFns"));
+ let domSectFields = (document.getElementById("sectFields"));
+ let domListFields = (document.getElementById("listFields"));
+ let domSectGlobalVars = (document.getElementById("sectGlobalVars"));
+ let domListGlobalVars = (document.getElementById("listGlobalVars"));
+ let domSectValues = (document.getElementById("sectValues"));
+ let domListValues = (document.getElementById("listValues"));
+ let domFnProto = (document.getElementById("fnProto"));
+ let domFnProtoCode = (document.getElementById("fnProtoCode"));
+ let domSectParams = (document.getElementById("sectParams"));
+ let domListParams = (document.getElementById("listParams"));
+ let domTldDocs = (document.getElementById("tldDocs"));
+ let domSectFnErrors = (document.getElementById("sectFnErrors"));
+ let domListFnErrors = (document.getElementById("listFnErrors"));
+ let domTableFnErrors =(document.getElementById("tableFnErrors"));
+ let domFnErrorsAnyError = (document.getElementById("fnErrorsAnyError"));
+ let domFnExamples = (document.getElementById("fnExamples"));
+ // let domListFnExamples = (document.getElementById("listFnExamples"));
+ let domFnNoExamples = (document.getElementById("fnNoExamples"));
+ let domDeclNoRef = (document.getElementById("declNoRef"));
+ let domSearch = (document.getElementById("search"));
+ let domSectSearchResults = (document.getElementById("sectSearchResults"));
+
+ let domListSearchResults = (document.getElementById("listSearchResults"));
+ let domSectSearchNoResults = (document.getElementById("sectSearchNoResults"));
+ let domSectInfo = (document.getElementById("sectInfo"));
+ // let domTdTarget = (document.getElementById("tdTarget"));
+ let domPrivDeclsBox = (document.getElementById("privDeclsBox"));
+ let domTdZigVer = (document.getElementById("tdZigVer"));
+ let domHdrName = (document.getElementById("hdrName"));
+ let domHelpModal = (document.getElementById("helpDialog"));
+
+
+ let searchTimer = null;
+
+
+ let escapeHtmlReplacements = { "&": "&", '"': """, "<": "<", ">": ">" };
+
+ let typeKinds = (indexTypeKinds());
+ let typeTypeId = (findTypeTypeId());
+ let pointerSizeEnum = { One: 0, Many: 1, Slice: 2, C: 3 };
// for each package, is an array with packages to get to this one
- var canonPkgPaths = computeCanonicalPackagePaths();
+ let canonPkgPaths = computeCanonicalPackagePaths();
+
+
+
// for each decl, is an array with {declNames, pkgNames} to get to this one
- var canonDeclPaths = null; // lazy; use getCanonDeclPath
+
+ let canonDeclPaths = null; // lazy; use getCanonDeclPath
+
// for each type, is an array with {declNames, pkgNames} to get to this one
- var canonTypeDecls = null; // lazy; use getCanonTypeDecl
+
+ let canonTypeDecls = null; // lazy; use getCanonTypeDecl
- var curNav = {
+
+
+
+ let curNav = {
+ showPrivDecls: false,
// each element is a package name, e.g. @import("a") then within there @import("b")
// starting implicitly from root package
pkgNames: [],
@@ -82,27 +92,43 @@
// (a, b, c, d) comptime call; result is the value the docs refer to
callName: null,
};
- var curNavSearch = "";
- var curSearchIndex = -1;
- var imFeelingLucky = false;
- var rootIsStd = detectRootIsStd();
+ let curNavSearch = "";
+ let curSearchIndex = -1;
+ let imFeelingLucky = false;
+
+ let rootIsStd = detectRootIsStd();
// map of decl index to list of non-generic fn indexes
- var nodesToFnsMap = indexNodesToFns();
+ // let nodesToFnsMap = indexNodesToFns();
// map of decl index to list of comptime fn calls
- var nodesToCallsMap = indexNodesToCalls();
+ // let nodesToCallsMap = indexNodesToCalls();
domSearch.addEventListener('keydown', onSearchKeyDown, false);
- domSectSearchAllResultsLink.addEventListener('click', onClickSearchShowAllResults, false);
-
+ domPrivDeclsBox.addEventListener('change', function() {
+ if (this.checked != curNav.showPrivDecls) {
+ if (this.checked && location.hash.length > 1 && location.hash[1] != '*'){
+ location.hash = "#*" + location.hash.substring(1);
+ return;
+ }
+ if (!this.checked && location.hash.length > 1 && location.hash[1] == '*') {
+ location.hash = "#" + location.hash.substring(2);
+ return;
+ }
+ }
+ }, false);
+
+ if (location.hash == "") {
+ location.hash = "#root";
+ }
+
window.addEventListener('hashchange', onHashChange, false);
window.addEventListener('keydown', onWindowKeyDown, false);
onHashChange();
function renderTitle() {
- var list = curNav.pkgNames.concat(curNav.declNames);
- var suffix = " - Zig";
+ let list = curNav.pkgNames.concat(curNav.declNames);
+ let suffix = " - Zig";
if (list.length === 0) {
if (rootIsStd) {
document.title = "std" + suffix;
@@ -114,20 +140,221 @@
}
}
+
+ function isDecl(x) {
+ return "value" in x;
+ }
+
+
+ function isType(x) {
+ return "kind" in x && !("value" in x);
+ }
+
+
+ function isContainerType(x) {
+ return isType(x) && typeKindIsContainer((x).kind) ;
+ }
+
+
+ function typeShorthandName(expr) {
+ let resolvedExpr = resolveValue({expr: expr});
+ if (!("type" in resolvedExpr)) {
+ return null;
+ }
+ let type = (zigAnalysis.types[resolvedExpr.type]);
+
+ outer: for (let i = 0; i < 10000; i += 1) {
+ switch (type.kind) {
+ case typeKinds.Optional:
+ case typeKinds.Pointer:
+ let child = (type).child;
+ let resolvedChild = resolveValue(child);
+ if ("type" in resolvedChild) {
+ type = zigAnalysis.types[resolvedChild.type];
+ continue;
+ } else {
+ return null;
+ }
+ default:
+ break outer;
+ }
+
+ if (i == 9999) throw "Exhausted typeShorthandName quota";
+ }
+
+
+
+ let name = undefined;
+ if (type.kind === typeKinds.Struct) {
+ name = "struct";
+ } else if (type.kind === typeKinds.Enum) {
+ name = "enum";
+ } else if (type.kind === typeKinds.Union) {
+ name = "union";
+ } else {
+ console.log("TODO: unhalndled case in typeShortName");
+ return null;
+ }
+
+ return escapeHtml(name);
+ }
+
+
+ function typeKindIsContainer(typeKind) {
+ return typeKind === typeKinds.Struct ||
+ typeKind === typeKinds.Union ||
+ typeKind === typeKinds.Enum;
+ }
+
+
+ function declCanRepresentTypeKind(typeKind) {
+ return typeKind === typeKinds.ErrorSet || typeKindIsContainer(typeKind);
+ }
+
+ //
+ // function findCteInRefPath(path) {
+ // for (let i = path.length - 1; i >= 0; i -= 1) {
+ // const ref = path[i];
+ // if ("string" in ref) continue;
+ // if ("comptimeExpr" in ref) return ref;
+ // if ("refPath" in ref) return findCteInRefPath(ref.refPath);
+ // return null;
+ // }
+
+ // return null;
+ // }
+
+
+ function resolveValue(value) {
+ let i = 0;
+ while(i < 1000) {
+ i += 1;
+
+ if ("refPath" in value.expr) {
+ value = {expr: value.expr.refPath[value.expr.refPath.length -1]};
+ continue;
+ }
+
+ if ("declRef" in value.expr) {
+ value = zigAnalysis.decls[value.expr.declRef].value;
+ continue;
+ }
+
+ if ("as" in value.expr) {
+ value = {
+ typeRef: zigAnalysis.exprs[value.expr.as.typeRefArg],
+ expr: zigAnalysis.exprs[value.expr.as.exprArg],
+ };
+ continue;
+ }
+
+ return value;
+
+ }
+ console.assert(false);
+ return ({});
+ }
+
+
+// function typeOfDecl(decl){
+// return decl.value.typeRef;
+//
+// let i = 0;
+// while(i < 1000) {
+// i += 1;
+// console.assert(isDecl(decl));
+// if ("type" in decl.value) {
+// return ({ type: typeTypeId });
+// }
+//
+//// if ("string" in decl.value) {
+//// return ({ type: {
+//// kind: typeKinds.Pointer,
+//// size: pointerSizeEnum.One,
+//// child: });
+//// }
+//
+// if ("refPath" in decl.value) {
+// decl = ({
+// value: decl.value.refPath[decl.value.refPath.length -1]
+// });
+// continue;
+// }
+//
+// if ("declRef" in decl.value) {
+// decl = zigAnalysis.decls[decl.value.declRef];
+// continue;
+// }
+//
+// if ("int" in decl.value) {
+// return decl.value.int.typeRef;
+// }
+//
+// if ("float" in decl.value) {
+// return decl.value.float.typeRef;
+// }
+//
+// if ("array" in decl.value) {
+// return decl.value.array.typeRef;
+// }
+//
+// if ("struct" in decl.value) {
+// return decl.value.struct.typeRef;
+// }
+//
+// if ("comptimeExpr" in decl.value) {
+// const cte = zigAnalysis.comptimeExprs[decl.value.comptimeExpr];
+// return cte.typeRef;
+// }
+//
+// if ("call" in decl.value) {
+// const fn_call = zigAnalysis.calls[decl.value.call];
+// let fn_decl = undefined;
+// if ("declRef" in fn_call.func) {
+// fn_decl = zigAnalysis.decls[fn_call.func.declRef];
+// } else if ("refPath" in fn_call.func) {
+// console.assert("declRef" in fn_call.func.refPath[fn_call.func.refPath.length -1]);
+// fn_decl = zigAnalysis.decls[fn_call.func.refPath[fn_call.func.refPath.length -1].declRef];
+// } else throw {};
+//
+// const fn_decl_value = resolveValue(fn_decl.value);
+// console.assert("type" in fn_decl_value); //TODO handle comptimeExpr
+// const fn_type = (zigAnalysis.types[fn_decl_value.type]);
+// console.assert(fn_type.kind === typeKinds.Fn);
+// return fn_type.ret;
+// }
+//
+// if ("void" in decl.value) {
+// return ({ type: typeTypeId });
+// }
+//
+// if ("bool" in decl.value) {
+// return ({ type: typeKinds.Bool });
+// }
+//
+// console.log("TODO: handle in `typeOfDecl` more cases: ", decl);
+// console.assert(false);
+// throw {};
+// }
+// console.assert(false);
+// return ({});
+// }
+
function render() {
domStatus.classList.add("hidden");
domFnProto.classList.add("hidden");
domSectParams.classList.add("hidden");
domTldDocs.classList.add("hidden");
+ domSectMainPkg.classList.add("hidden");
domSectPkgs.classList.add("hidden");
domSectTypes.classList.add("hidden");
+ domSectTests.classList.add("hidden");
domSectNamespaces.classList.add("hidden");
domSectErrSets.classList.add("hidden");
domSectFns.classList.add("hidden");
domSectFields.classList.add("hidden");
domSectSearchResults.classList.add("hidden");
domSectSearchNoResults.classList.add("hidden");
- domSectSearchAllResultsLink.classList.add("hidden");
domSectInfo.classList.add("hidden");
domHdrName.classList.add("hidden");
domSectNav.classList.add("hidden");
@@ -144,15 +371,17 @@
renderInfo();
renderPkgList();
+ domPrivDeclsBox.checked = curNav.showPrivDecls;
+
if (curNavSearch !== "") {
return renderSearch();
}
- var rootPkg = zigAnalysis.packages[zigAnalysis.rootPkg];
- var pkg = rootPkg;
+ let rootPkg = zigAnalysis.packages[zigAnalysis.rootPkg];
+ let pkg = rootPkg;
curNav.pkgObjs = [pkg];
- for (var i = 0; i < curNav.pkgNames.length; i += 1) {
- var childPkg = zigAnalysis.packages[pkg.table[curNav.pkgNames[i]]];
+ for (let i = 0; i < curNav.pkgNames.length; i += 1) {
+ let childPkg = zigAnalysis.packages[pkg.table[curNav.pkgNames[i]]];
if (childPkg == null) {
return render404();
}
@@ -160,52 +389,68 @@
curNav.pkgObjs.push(pkg);
}
- var decl = zigAnalysis.types[pkg.main];
- curNav.declObjs = [decl];
- for (var i = 0; i < curNav.declNames.length; i += 1) {
- var childDecl = findSubDecl(decl, curNav.declNames[i]);
+
+ let currentType = zigAnalysis.types[pkg.main];
+ curNav.declObjs = [currentType];
+ for (let i = 0; i < curNav.declNames.length; i += 1) {
+
+
+ let childDecl = findSubDecl((currentType), curNav.declNames[i]);
if (childDecl == null) {
return render404();
}
- var container = getDeclContainerType(childDecl);
- if (container == null) {
- if (i + 1 === curNav.declNames.length) {
- curNav.declObjs.push(childDecl);
- break;
- } else {
- return render404();
+
+ let childDeclValue = resolveValue((childDecl).value).expr;
+ if ("type" in childDeclValue) {
+
+ const t = zigAnalysis.types[childDeclValue.type];
+ if (t.kind != typeKinds.Fn) {
+ childDecl = t;
}
}
- decl = container;
- curNav.declObjs.push(decl);
+
+ currentType = (childDecl);
+ curNav.declObjs.push(currentType);
}
renderNav();
- var lastDecl = curNav.declObjs[curNav.declObjs.length - 1];
- if (lastDecl.pubDecls != null) {
- renderContainer(lastDecl);
- }
- if (lastDecl.kind == null) {
- return renderUnknownDecl(lastDecl);
- } else if (lastDecl.kind === 'var') {
- return renderVar(lastDecl);
- } else if (lastDecl.kind === 'const' && lastDecl.type != null) {
- var typeObj = zigAnalysis.types[lastDecl.type];
- if (typeObj.kind === typeKinds.Fn) {
- return renderFn(lastDecl);
- } else {
- return renderValue(lastDecl);
+ let last = curNav.declObjs[curNav.declObjs.length - 1];
+ let lastIsDecl = isDecl(last);
+ let lastIsType = isType(last);
+ let lastIsContainerType = isContainerType(last);
+
+ if (lastIsContainerType) {
+ return renderContainer((last));
+ }
+
+ if (!lastIsDecl && !lastIsType) {
+ return renderUnknownDecl((last));
+ }
+
+ if (lastIsType) {
+ return renderType((last));
+ }
+
+ if (lastIsDecl && last.kind === 'var') {
+ return renderVar((last));
+ }
+
+ if (lastIsDecl && last.kind === 'const') {
+ let typeObj = zigAnalysis.types[resolveValue((last).value).expr.type];
+ if (typeObj && typeObj.kind === typeKinds.Fn) {
+ return renderFn((last));
}
- } else {
- renderType(lastDecl);
+
+ return renderValue((last));
}
}
+
function renderUnknownDecl(decl) {
domDeclNoRef.classList.remove("hidden");
- var docs = zigAnalysis.astNodes[decl.src].docs;
+ let docs = zigAnalysis.astNodes[decl.src].docs;
if (docs != null) {
domTldDocs.innerHTML = markdown(docs);
} else {
@@ -214,85 +459,130 @@
domTldDocs.classList.remove("hidden");
}
+
function typeIsErrSet(typeIndex) {
- var typeObj = zigAnalysis.types[typeIndex];
+ let typeObj = zigAnalysis.types[typeIndex];
return typeObj.kind === typeKinds.ErrorSet;
}
+
function typeIsStructWithNoFields(typeIndex) {
- var typeObj = zigAnalysis.types[typeIndex];
+ let typeObj = zigAnalysis.types[typeIndex];
if (typeObj.kind !== typeKinds.Struct)
return false;
- return typeObj.fields == null || typeObj.fields.length === 0;
+ return (typeObj).fields.length == 0;
}
+
function typeIsGenericFn(typeIndex) {
- var typeObj = zigAnalysis.types[typeIndex];
+ let typeObj = zigAnalysis.types[typeIndex];
if (typeObj.kind !== typeKinds.Fn) {
return false;
}
- return typeObj.generic;
+ return (typeObj).generic_ret != null;
}
+
function renderFn(fnDecl) {
- domFnProtoCode.innerHTML = typeIndexName(fnDecl.type, true, true, fnDecl);
+ if ("refPath" in fnDecl.value.expr) {
+ let last = fnDecl.value.expr.refPath.length - 1;
+ let lastExpr = fnDecl.value.expr.refPath[last];
+ console.assert("declRef" in lastExpr);
+ fnDecl = zigAnalysis.decls[lastExpr.declRef];
+ }
- var docsSource = null;
- var srcNode = zigAnalysis.astNodes[fnDecl.src];
+ let value = resolveValue(fnDecl.value);
+ console.assert("type" in value.expr);
+ let typeObj = (zigAnalysis.types[value.expr.type]);
+
+ domFnProtoCode.innerHTML = exprName(value.expr, {
+ wantHtml: true,
+ wantLink: true,
+ fnDecl,
+ });
+
+ let docsSource = null;
+ let srcNode = zigAnalysis.astNodes[fnDecl.src];
if (srcNode.docs != null) {
docsSource = srcNode.docs;
}
- var typeObj = zigAnalysis.types[fnDecl.type];
renderFnParamDocs(fnDecl, typeObj);
- var errSetTypeIndex = null;
- if (typeObj.ret != null) {
- var retType = zigAnalysis.types[typeObj.ret];
+ let retExpr = resolveValue({expr:typeObj.ret}).expr;
+ if ("type" in retExpr) {
+ let retIndex = retExpr.type;
+ let errSetTypeIndex = (null);
+ let retType = zigAnalysis.types[retIndex];
if (retType.kind === typeKinds.ErrorSet) {
- errSetTypeIndex = typeObj.ret;
+ errSetTypeIndex = retIndex;
} else if (retType.kind === typeKinds.ErrorUnion) {
- errSetTypeIndex = retType.err;
+ errSetTypeIndex = (retType).err.type;
+ }
+ if (errSetTypeIndex != null) {
+ let errSetType = (zigAnalysis.types[errSetTypeIndex]);
+ renderErrorSet(errSetType);
}
}
- if (errSetTypeIndex != null) {
- var errSetType = zigAnalysis.types[errSetTypeIndex];
- renderErrorSet(errSetType);
- }
-
- var fnObj = zigAnalysis.fns[fnDecl.value];
- var protoSrcIndex = fnObj.src;
- if (typeIsGenericFn(fnDecl.type)) {
- var instantiations = nodesToFnsMap[protoSrcIndex];
- var calls = nodesToCallsMap[protoSrcIndex];
- if (instantiations == null && calls == null) {
- domFnNoExamples.classList.remove("hidden");
- } else if (calls != null) {
- if (fnObj.combined === undefined) fnObj.combined = allCompTimeFnCallsResult(calls);
- if (fnObj.combined != null) {
- renderContainer(fnObj.combined, calls.map(function (call) { return zigAnalysis.calls[call].result.value }));
- }
- var domListFnExamplesFragment = createDomListFragment(calls.length, '<li></li>');
+ let protoSrcIndex = fnDecl.src;
+ if (typeIsGenericFn(value.expr.type)) {
+ // does the generic_ret contain a container?
+ var resolvedGenericRet = resolveValue({expr: typeObj.generic_ret});
+
+ if ("call" in resolvedGenericRet.expr){
+ let call = zigAnalysis.calls[resolvedGenericRet.expr.call];
+ let resolvedFunc = resolveValue({expr: call.func});
+ if (!("type" in resolvedFunc.expr)) return;
+ let callee = zigAnalysis.types[resolvedFunc.expr.type];
+ if (!callee.generic_ret) return;
+ resolvedGenericRet = resolveValue({expr: callee.generic_ret});
+ }
- for (var callI = 0; callI < calls.length; callI += 1) {
- var liDom = domListFnExamplesFragment.children[callI];
- liDom.innerHTML = getCallHtml(fnDecl, calls[callI]);
- }
+ // TODO: see if unwrapping the `as` here is a good idea or not.
+ if ("as" in resolvedGenericRet.expr) {
+ resolvedGenericRet = {
+ expr: zigAnalysis.exprs[resolvedGenericRet.expr.as.exprArg]
+ };
+ }
- domListFnExamples.innerHTML = "";
- domListFnExamples.appendChild(domListFnExamplesFragment);
- domFnExamples.classList.remove("hidden");
- } else if (instantiations != null) {
- // TODO
+ if (!("type" in resolvedGenericRet.expr)) return;
+ const genericType = zigAnalysis.types[resolvedGenericRet.expr.type];
+ if (isContainerType(genericType)) {
+ renderContainer(genericType)
}
+
+
+
+
+
+ // old code
+ // let instantiations = nodesToFnsMap[protoSrcIndex];
+ // let calls = nodesToCallsMap[protoSrcIndex];
+ // if (instantiations == null && calls == null) {
+ // domFnNoExamples.classList.remove("hidden");
+ // } else if (calls != null) {
+ // // if (fnObj.combined === undefined) fnObj.combined = allCompTimeFnCallsResult(calls);
+ // if (fnObj.combined != null) renderContainer(fnObj.combined);
+
+ // resizeDomList(domListFnExamples, calls.length, '<li></li>');
+
+ // for (let callI = 0; callI < calls.length; callI += 1) {
+ // let liDom = domListFnExamples.children[callI];
+ // liDom.innerHTML = getCallHtml(fnDecl, calls[callI]);
+ // }
+
+ // domFnExamples.classList.remove("hidden");
+ // } else if (instantiations != null) {
+ // // TODO
+ // }
} else {
domFnExamples.classList.add("hidden");
domFnNoExamples.classList.add("hidden");
}
- var protoSrcNode = zigAnalysis.astNodes[protoSrcIndex];
+ let protoSrcNode = zigAnalysis.astNodes[protoSrcIndex];
if (docsSource == null && protoSrcNode != null && protoSrcNode.docs != null) {
docsSource = protoSrcNode.docs;
}
@@ -303,17 +593,17 @@
domFnProto.classList.remove("hidden");
}
+
function renderFnParamDocs(fnDecl, typeObj) {
- var docCount = 0;
+ let docCount = 0;
- var fnObj = zigAnalysis.fns[fnDecl.value];
- var fnNode = zigAnalysis.astNodes[fnObj.src];
- var fields = fnNode.fields;
- var isVarArgs = fnNode.varArgs;
+ let fnNode = zigAnalysis.astNodes[fnDecl.src];
+ let fields = (fnNode.fields);
+ let isVarArgs = fnNode.varArgs;
- for (var i = 0; i < fields.length; i += 1) {
- var field = fields[i];
- var fieldNode = zigAnalysis.astNodes[field];
+ for (let i = 0; i < fields.length; i += 1) {
+ let field = fields[i];
+ let fieldNode = zigAnalysis.astNodes[field];
if (fieldNode.docs != null) {
docCount += 1;
}
@@ -322,56 +612,55 @@
return;
}
- var domListParamsFragment = createDomListFragment(docCount, '<div></div>');
- var domIndex = 0;
+ resizeDomList(domListParams, docCount, '<div></div>');
+ let domIndex = 0;
- for (var i = 0; i < fields.length; i += 1) {
- var field = fields[i];
- var fieldNode = zigAnalysis.astNodes[field];
+ for (let i = 0; i < fields.length; i += 1) {
+ let field = fields[i];
+ let fieldNode = zigAnalysis.astNodes[field];
if (fieldNode.docs == null) {
continue;
}
- var divDom = domListParamsFragment.children[domIndex];
+ let divDom = domListParams.children[domIndex];
domIndex += 1;
- var argTypeIndex = typeObj.args[i];
- var html = '<pre>' + escapeHtml(fieldNode.name) + ": ";
- if (isVarArgs && i === typeObj.args.length - 1) {
+
+ let value = typeObj.params[i];
+ let html = '<pre>' + escapeHtml((fieldNode.name)) + ": ";
+ if (isVarArgs && i === typeObj.params.length - 1) {
html += '...';
- } else if (argTypeIndex != null) {
- html += typeIndexName(argTypeIndex, true, true);
} else {
- html += '<span class="tok-kw">var</span>';
+ let name = exprName(value, {wantHtml: false, wantLink: false});
+ html += '<span class="tok-kw">' + name + '</span>';
}
html += ',</pre>';
- var docs = fieldNode.docs;
+ let docs = fieldNode.docs;
if (docs != null) {
html += markdown(docs);
}
divDom.innerHTML = html;
}
-
- domListParams.innerHTML = "";
- domListParams.appendChild(domListParamsFragment);
domSectParams.classList.remove("hidden");
}
function renderNav() {
- var len = curNav.pkgNames.length + curNav.declNames.length;
- var domListNavFragment = createDomListFragment(len, '<li><a href="#"></a></li>');
- var list = [];
- var hrefPkgNames = [];
- var hrefDeclNames = [];
- for (var i = 0; i < curNav.pkgNames.length; i += 1) {
+ let len = curNav.pkgNames.length + curNav.declNames.length;
+ resizeDomList(domListNav, len, '<li><a href="#"></a></li>');
+ let list = [];
+ let hrefPkgNames = [];
+ let hrefDeclNames = ([]);
+ for (let i = 0; i < curNav.pkgNames.length; i += 1) {
hrefPkgNames.push(curNav.pkgNames[i]);
+ let name = curNav.pkgNames[i];
+ if (name == "root") name = zigAnalysis.rootPkgName;
list.push({
- name: curNav.pkgNames[i],
+ name: name,
link: navLink(hrefPkgNames, hrefDeclNames),
});
}
- for (var i = 0; i < curNav.declNames.length; i += 1) {
+ for (let i = 0; i < curNav.declNames.length; i += 1) {
hrefDeclNames.push(curNav.declNames[i]);
list.push({
name: curNav.declNames[i],
@@ -379,9 +668,9 @@
});
}
- for (var i = 0; i < list.length; i += 1) {
- var liDom = domListNavFragment.children[i];
- var aDom = liDom.children[0];
+ for (let i = 0; i < list.length; i += 1) {
+ let liDom = domListNav.children[i];
+ let aDom = liDom.children[0];
aDom.textContent = list[i].name;
aDom.setAttribute('href', list[i].link);
if (i + 1 == list.length) {
@@ -391,14 +680,12 @@
}
}
- domListNav.innerHTML = "";
- domListNav.appendChild(domListNavFragment);
domSectNav.classList.remove("hidden");
}
function renderInfo() {
domTdZigVer.textContent = zigAnalysis.params.zigVersion;
- domTdTarget.textContent = zigAnalysis.params.builds[0].target;
+ //domTdTarget.textContent = zigAnalysis.params.builds[0].target;
domSectInfo.classList.remove("hidden");
}
@@ -409,26 +696,39 @@
}
function renderPkgList() {
- var rootPkg = zigAnalysis.packages[zigAnalysis.rootPkg];
- var list = [];
- for (var key in rootPkg.table) {
- if (key === "root" && rootIsStd) continue;
- var pkgIndex = rootPkg.table[key];
+ let rootPkg = zigAnalysis.packages[zigAnalysis.rootPkg];
+ let list = [];
+ for (let key in rootPkg.table) {
+ let pkgIndex = rootPkg.table[key];
if (zigAnalysis.packages[pkgIndex] == null) continue;
+ if (key == zigAnalysis.params.rootName) continue;
list.push({
name: key,
pkg: pkgIndex,
});
}
+
+ {
+ let aDom = domSectMainPkg.children[1].children[0].children[0];
+ aDom.textContent = zigAnalysis.rootPkgName;
+ aDom.setAttribute('href', navLinkPkg(zigAnalysis.rootPkg));
+ if (zigAnalysis.params.rootName === curNav.pkgNames[0]) {
+ aDom.classList.add("active");
+ } else {
+ aDom.classList.remove("active");
+ }
+ domSectMainPkg.classList.remove("hidden");
+ }
+
list.sort(function(a, b) {
return operatorCompare(a.name.toLowerCase(), b.name.toLowerCase());
});
if (list.length !== 0) {
- var domListPkgsFragment = createDomListFragment(list.length, '<li><a href="#"></a></li>');
- for (var i = 0; i < list.length; i += 1) {
- var liDom = domListPkgsFragment.children[i];
- var aDom = liDom.children[0];
+ resizeDomList(domListPkgs, list.length, '<li><a href="#"></a></li>');
+ for (let i = 0; i < list.length; i += 1) {
+ let liDom = domListPkgs.children[i];
+ let aDom = liDom.children[0];
aDom.textContent = list[i].name;
aDom.setAttribute('href', navLinkPkg(list[i].pkg));
if (list[i].name === curNav.pkgNames[0]) {
@@ -438,488 +738,1338 @@
}
}
- domListPkgs.innerHTML = "";
- domListPkgs.appendChild(domListPkgsFragment);
domSectPkgs.classList.remove("hidden");
}
}
+
+
function navLink(pkgNames, declNames, callName) {
+ let base = '#';
+ if (curNav.showPrivDecls) {
+ base += "*";
+ }
+
if (pkgNames.length === 0 && declNames.length === 0) {
- return '#';
+ return base;
} else if (declNames.length === 0 && callName == null) {
- return '#' + pkgNames.join('.');
+ return base + pkgNames.join('.');
} else if (callName == null) {
- return '#' + pkgNames.join('.') + ';' + declNames.join('.');
+ return base + pkgNames.join('.') + ';' + declNames.join('.');
} else {
- return '#' + pkgNames.join('.') + ';' + declNames.join('.') + ';' + callName;
+ return base + pkgNames.join('.') + ';' + declNames.join('.') + ';' + callName;
}
}
+
function navLinkPkg(pkgIndex) {
return navLink(canonPkgPaths[pkgIndex], []);
}
+
function navLinkDecl(childName) {
return navLink(curNav.pkgNames, curNav.declNames.concat([childName]));
}
- function navLinkCall(callObj) {
- var declNamesCopy = curNav.declNames.concat([]);
- var callName = declNamesCopy.pop();
-
- callName += '(';
- for (var arg_i = 0; arg_i < callObj.args.length; arg_i += 1) {
- if (arg_i !== 0) callName += ',';
- var argObj = callObj.args[arg_i];
- callName += getValueText(argObj.type, argObj.value, false, false);
- }
- callName += ')';
-
- declNamesCopy.push(callName);
- return navLink(curNav.pkgNames, declNamesCopy);
- }
-
- function createDomListFragment(desiredLen, templateHtml) {
- var domTemplate = document.createElement("template");
- domTemplate.innerHTML = templateHtml.repeat(desiredLen);
- return domTemplate.content;
- }
-
- function typeIndexName(typeIndex, wantHtml, wantLink, fnDecl, linkFnNameDecl, thisTypes) {
- if(thisTypes && thisTypes.includes(typeIndex)){
- return token('@This', tokenKinds.Builtin, wantHtml) + '()';
- }
- var typeObj = zigAnalysis.types[typeIndex];
- var declNameOk = declCanRepresentTypeKind(typeObj.kind);
- if (wantLink) {
- var declIndex = getCanonTypeDecl(typeIndex);
- var declPath = getCanonDeclPath(declIndex);
- if (declPath == null) {
- return typeName(typeObj, wantHtml, wantLink, fnDecl, linkFnNameDecl, thisTypes);
- }
- var name = (wantLink && declCanRepresentTypeKind(typeObj.kind)) ?
- declPath.declNames[declPath.declNames.length - 1] :
- typeName(typeObj, wantHtml, false, fnDecl, linkFnNameDecl, thisTypes);
- if (wantLink && wantHtml) {
- return '<a href="' + navLink(declPath.pkgNames, declPath.declNames) + '">' + name + '</a>';
+ //
+ // function navLinkCall(callObj) {
+ // let declNamesCopy = curNav.declNames.concat([]);
+ // let callName = (declNamesCopy.pop());
+
+ // callName += '(';
+ // for (let arg_i = 0; arg_i < callObj.args.length; arg_i += 1) {
+ // if (arg_i !== 0) callName += ',';
+ // let argObj = callObj.args[arg_i];
+ // callName += getValueText(argObj, argObj, false, false);
+ // }
+ // callName += ')';
+
+ // declNamesCopy.push(callName);
+ // return navLink(curNav.pkgNames, declNamesCopy);
+ // }
+
+
+ function resizeDomListDl(dlDom, desiredLen) {
+ // add the missing dom entries
+ for (let i = dlDom.childElementCount / 2; i < desiredLen; i += 1) {
+ dlDom.insertAdjacentHTML('beforeend', '<dt></dt><dd></dd>');
+ }
+ // remove extra dom entries
+ while (desiredLen < dlDom.childElementCount / 2) {
+ dlDom.removeChild(dlDom.lastChild);
+ dlDom.removeChild(dlDom.lastChild);
+ }
+ }
+
+
+ function resizeDomList(listDom, desiredLen, templateHtml) {
+ // add the missing dom entries
+ for (let i = listDom.childElementCount; i < desiredLen; i += 1) {
+ listDom.insertAdjacentHTML('beforeend', templateHtml);
+ }
+ // remove extra dom entries
+ while (desiredLen < listDom.childElementCount) {
+ listDom.removeChild(listDom.lastChild);
+ }
+ }
+
+ function walkResultTypeRef(wr) {
+ if (wr.typeRef) return wr.typeRef;
+ let resolved = resolveValue(wr);
+ if (wr === resolved) {
+ return {type: 0};
+ }
+ return walkResultTypeRef(resolved);
+ }
+
+ function exprName(expr, opts) {
+ switch (Object.keys(expr)[0]) {
+ default: throw "oh no";
+ case "&": {
+ return "&" + exprName(zigAnalysis.exprs[expr["&"]]);
+ }
+ case "compileError": {
+ let compileError = expr.compileError;
+ return compileError;
+ }
+ case "enumLiteral": {
+ let literal = expr.enumLiteral;
+ return "." + literal;
+ }
+ case "void": {
+ return "void";
+ }
+ case "slice":{
+ let payloadHtml = "";
+ const lhsExpr = zigAnalysis.exprs[expr.slice.lhs];
+ const startExpr = zigAnalysis.exprs[expr.slice.start];
+ let decl = exprName(lhsExpr);
+ let start = exprName(startExpr);
+ let end = "";
+ let sentinel = "";
+ if (expr.slice['end']) {
+ const endExpr = zigAnalysis.exprs[expr.slice.end];
+ let end_ = exprName(endExpr);
+ end += end_;
+ }
+ if (expr.slice['sentinel']) {
+ const sentinelExpr = zigAnalysis.exprs[expr.slice.sentinel];
+ let sentinel_ = exprName(sentinelExpr);
+ sentinel += " :" + sentinel_;
+ }
+ payloadHtml += decl + "["+ start + ".." + end + sentinel + "]";
+ return payloadHtml;
+ }
+ case "sliceIndex": {
+ const sliceIndex = zigAnalysis.exprs[expr.sliceIndex];
+ return exprName(sliceIndex, opts);
+ }
+ case "cmpxchg":{
+ const typeIndex = zigAnalysis.exprs[expr.cmpxchg.type];
+ const ptrIndex = zigAnalysis.exprs[expr.cmpxchg.ptr];
+ const expectedValueIndex = zigAnalysis.exprs[expr.cmpxchg.expected_value];
+ const newValueIndex = zigAnalysis.exprs[expr.cmpxchg.new_value];
+ const successOrderIndex = zigAnalysis.exprs[expr.cmpxchg.success_order];
+ const failureOrderIndex = zigAnalysis.exprs[expr.cmpxchg.failure_order];
+
+ const type = exprName(typeIndex, opts);
+ const ptr = exprName(ptrIndex, opts);
+ const expectedValue = exprName(expectedValueIndex, opts);
+ const newValue = exprName(newValueIndex, opts);
+ const successOrder = exprName(successOrderIndex, opts);
+ const failureOrder = exprName(failureOrderIndex, opts);
+
+ let fnName = "@";
+
+ switch (expr.cmpxchg.name) {
+ case "cmpxchg_strong": {
+ fnName += "cmpxchgStrong"
+ break;
+ }
+ case "cmpxchg_weak": {
+ fnName += "cmpxchgWeak"
+ break;
+ }
+ default: {
+ console.log("There's only cmpxchg_strong and cmpxchg_weak");
+ }
+ }
+
+ return fnName + "(" + type + ", " + ptr + ", " + expectedValue + ", "+ newValue + ", "+"." +successOrder + ", "+ "." +failureOrder + ")";
+ }
+ case "cmpxchgIndex": {
+ const cmpxchgIndex = zigAnalysis.exprs[expr.cmpxchgIndex];
+ return exprName(cmpxchgIndex, opts);
+ }
+ case "switchOp":{
+ let condExpr = zigAnalysis.exprs[expr.switchOp.cond_index];
+ let ast = zigAnalysis.astNodes[expr.switchOp.ast];
+ let file_name = expr.switchOp.file_name;
+ let outer_decl_index = expr.switchOp.outer_decl;
+ let outer_decl = zigAnalysis.types[outer_decl_index];
+ let line = 0;
+ // console.log(expr.switchOp)
+ // console.log(outer_decl)
+ while (outer_decl_index !== 0 && outer_decl.line_number > 0) {
+ line += outer_decl.line_number;
+ outer_decl_index = outer_decl.outer_decl;
+ outer_decl = zigAnalysis.types[outer_decl_index];
+ // console.log(outer_decl)
+ }
+ line += ast.line + 1;
+ let payloadHtml = "";
+ let cond = exprName(condExpr, opts);
+
+ payloadHtml += "</br>" + "node_name: " + ast.name + "</br>" + "file: " + file_name + "</br>" + "line: " + line + "</br>";
+ payloadHtml += "switch(" + cond + ") {" + "<a href=\"https://github.com/ziglang/zig/tree/master/lib/std/" + file_name + "#L" + line + "\">" +"..." + "</a>}";
+ return payloadHtml;
+ }
+ case "switchIndex": {
+ const switchIndex = zigAnalysis.exprs[expr.switchIndex];
+ return exprName(switchIndex, opts);
+ }
+ case "refPath" : {
+ const declRef = expr.refPath[0].declRef;
+ let name = zigAnalysis.decls[declRef].name;
+ for (let i = 1; i < expr.refPath.length; i++) {
+ let component = undefined;
+ if ("string" in expr.refPath[i]) {
+ component = expr.refPath[i].string;
+ } else {
+ component = exprName(expr.refPath[i]);
+ }
+ name += "." + component;
+ }
+ return name;
+ }
+ case "fieldRef" : {
+ const enumObj = exprName({"type":expr.fieldRef.type} ,opts);
+ const field = zigAnalysis.astNodes[enumObj.ast].fields[expr.fieldRef.index];
+ const name = zigAnalysis.astNodes[field].name;
+ return name
+ }
+ case "enumToInt" : {
+ const enumToInt = zigAnalysis.exprs[expr.enumToInt];
+ return "@enumToInt(" + exprName(enumToInt, opts) + ")";
+ }
+ case "bitSizeOf" : {
+ const bitSizeOf = zigAnalysis.exprs[expr.bitSizeOf];
+ return "@bitSizeOf(" + exprName(bitSizeOf, opts) + ")";
+ }
+ case "sizeOf" : {
+ const sizeOf = zigAnalysis.exprs[expr.sizeOf];
+ return "@sizeOf(" + exprName(sizeOf, opts) + ")";
+ }
+ case "builtinIndex" : {
+ const builtinIndex = zigAnalysis.exprs[expr.builtinIndex];
+ return exprName(builtinIndex, opts);
+ }
+ case "builtin": {
+ const param_expr = zigAnalysis.exprs[expr.builtin.param];
+ let param = exprName(param_expr, opts);
+
+
+ let payloadHtml = "@";
+ switch (expr.builtin.name) {
+ case "align_of": {
+ payloadHtml += "alignOf";
+ break;
+ }
+ case "bool_to_int": {
+ payloadHtml += "boolToInt";
+ break;
+ }
+ case "embed_file": {
+ payloadHtml += "embedFile";
+ break;
+ }
+ case "error_name": {
+ payloadHtml += "errorName";
+ break;
+ }
+ case "panic": {
+ payloadHtml += "panic";
+ break;
+ }
+ case "set_cold": {
+ payloadHtml += "setCold";
+ break;
+ }
+ case "set_runtime_safety": {
+ payloadHtml += "setRuntimeSafety";
+ break;
+ }
+ case "sqrt": {
+ payloadHtml += "sqrt";
+ break;
+ }
+ case "sin": {
+ payloadHtml += "sin";
+ break;
+ }
+ case "cos": {
+ payloadHtml += "cos";
+ break;
+ }
+ case "tan": {
+ payloadHtml += "tan";
+ break;
+ }
+ case "exp": {
+ payloadHtml += "exp";
+ break;
+ }
+ case "exp2": {
+ payloadHtml += "exp2";
+ break;
+ }
+ case "log": {
+ payloadHtml += "log";
+ break;
+ }
+ case "log2": {
+ payloadHtml += "log2";
+ break;
+ }
+ case "log10": {
+ payloadHtml += "log10";
+ break;
+ }
+ case "fabs": {
+ payloadHtml += "fabs";
+ break;
+ }
+ case "floor": {
+ payloadHtml += "floor";
+ break;
+ }
+ case "ceil": {
+ payloadHtml += "ceil";
+ break;
+ }
+ case "trunc": {
+ payloadHtml += "trunc";
+ break;
+ }
+ case "round": {
+ payloadHtml += "round";
+ break;
+ }
+ case "tag_name": {
+ payloadHtml += "tagName";
+ break;
+ }
+ case "reify": {
+ payloadHtml += "Type";
+ break;
+ }
+ case "type_name": {
+ payloadHtml += "typeName";
+ break;
+ }
+ case "frame_type": {
+ payloadHtml += "Frame";
+ break;
+ }
+ case "frame_size": {
+ payloadHtml += "frameSize";
+ break;
+ }
+ case "ptr_to_int": {
+ payloadHtml += "ptrToInt";
+ break;
+ }
+ case "error_to_int": {
+ payloadHtml += "errorToInt";
+ break;
+ }
+ case "int_to_error": {
+ payloadHtml += "intToError";
+ break;
+ }
+ case "maximum": {
+ payloadHtml += "maximum";
+ break;
+ }
+ case "minimum": {
+ payloadHtml += "minimum";
+ break;
+ }
+ case "bit_not": {
+ return "~" + param;
+ }
+ case "clz": {
+ return "@clz(T" + ", " + param + ")";
+ }
+ case "ctz": {
+ return "@ctz(T" + ", " + param + ")";
+ }
+ case "pop_count": {
+ return "@popCount(T" + ", " + param + ")";
+ }
+ case "byte_swap": {
+ return "@byteSwap(T" + ", " + param + ")";
+ }
+ case "bit_reverse": {
+ return "@bitReverse(T" + ", " + param + ")";
+ }
+ default: console.log("builtin function not handled yet or doesn't exist!");
+ };
+ return payloadHtml + "(" + param + ")";
+
+ }
+ case "builtinBinIndex" : {
+ const builtinBinIndex = zigAnalysis.exprs[expr.builtinBinIndex];
+ return exprName(builtinBinIndex, opts);
+ }
+ case "builtinBin": {
+ const lhsOp = zigAnalysis.exprs[expr.builtinBin.lhs];
+ const rhsOp = zigAnalysis.exprs[expr.builtinBin.rhs];
+ let lhs = exprName(lhsOp, opts);
+ let rhs = exprName(rhsOp, opts);
+
+ let payloadHtml = "@";
+ switch (expr.builtinBin.name) {
+ case "float_to_int": {
+ payloadHtml += "floatToInt";
+ break;
+ }
+ case "int_to_float": {
+ payloadHtml += "intToFloat";
+ break;
+ }
+ case "int_to_ptr": {
+ payloadHtml += "intToPtr";
+ break;
+ }
+ case "int_to_enum": {
+ payloadHtml += "intToEnum";
+ break;
+ }
+ case "float_cast": {
+ payloadHtml += "floatCast";
+ break;
+ }
+ case "int_cast": {
+ payloadHtml += "intCast";
+ break;
+ }
+ case "ptr_cast": {
+ payloadHtml += "ptrCast";
+ break;
+ }
+ case "truncate": {
+ payloadHtml += "truncate";
+ break;
+ }
+ case "align_cast": {
+ payloadHtml += "alignCast";
+ break;
+ }
+ case "has_decl": {
+ payloadHtml += "hasDecl";
+ break;
+ }
+ case "has_field": {
+ payloadHtml += "hasField";
+ break;
+ }
+ case "bit_reverse": {
+ payloadHtml += "bitReverse";
+ break;
+ }
+ case "div_exact": {
+ payloadHtml += "divExact";
+ break;
+ }
+ case "div_floor": {
+ payloadHtml += "divFloor";
+ break;
+ }
+ case "div_trunc": {
+ payloadHtml += "divTrunc";
+ break;
+ }
+ case "mod": {
+ payloadHtml += "mod";
+ break;
+ }
+ case "rem": {
+ payloadHtml += "rem";
+ break;
+ }
+ case "mod_rem": {
+ payloadHtml += "rem";
+ break;
+ }
+ case "shl_exact": {
+ payloadHtml += "shlExact";
+ break;
+ }
+ case "shr_exact": {
+ payloadHtml += "shrExact";
+ break;
+ }
+ case "bitcast" : {
+ payloadHtml += "bitCast";
+ break;
+ }
+ case "align_cast" : {
+ payloadHtml += "alignCast";
+ break;
+ }
+ case "vector_type" : {
+ payloadHtml += "Vector";
+ break;
+ }
+ case "reduce": {
+ payloadHtml += "reduce";
+ break;
+ }
+ case "splat": {
+ payloadHtml += "splat";
+ break;
+ }
+ case "offset_of": {
+ payloadHtml += "offsetOf";
+ break;
+ }
+ case "bit_offset_of": {
+ payloadHtml += "bitOffsetOf";
+ break;
+ }
+ default: console.log("builtin function not handled yet or doesn't exist!");
+ };
+ return payloadHtml + "(" + lhs + ", " + rhs + ")";
+
+ }
+ case "binOpIndex" : {
+ const binOpIndex = zigAnalysis.exprs[expr.binOpIndex];
+ return exprName(binOpIndex, opts);
+ }
+ case "binOp": {
+ const lhsOp = zigAnalysis.exprs[expr.binOp.lhs];
+ const rhsOp = zigAnalysis.exprs[expr.binOp.rhs];
+ let lhs = exprName(lhsOp, opts);
+ let rhs = exprName(rhsOp, opts);
+
+ let print_lhs = "";
+ let print_rhs = "";
+
+ if (lhsOp['binOpIndex']) {
+ print_lhs = "(" + lhs + ")";
} else {
- return name;
+ print_lhs = lhs;
+ }
+ if (rhsOp['binOpIndex']) {
+ print_rhs = "(" + rhs + ")";
+ } else {
+ print_rhs = rhs;
}
- } else {
- return typeName(typeObj, wantHtml, false, fnDecl, linkFnNameDecl, thisTypes);
- }
- }
-
- function shouldSkipParamName(typeIndex, paramName) {
- var typeObj = zigAnalysis.types[typeIndex];
- if (typeObj.kind === typeKinds.Pointer && getPtrSize(typeObj) === pointerSizeEnum.One) {
- typeIndex = typeObj.elem;
- }
- return typeIndexName(typeIndex, false, true).toLowerCase() === paramName;
- }
-
- function getPtrSize(typeObj) {
- return (typeObj.len == null) ? pointerSizeEnum.One : typeObj.len;
- }
-
- function getCallHtml(fnDecl, callIndex) {
- var callObj = zigAnalysis.calls[callIndex];
-
- // TODO make these links work
- //var html = '<a href="' + navLinkCall(callObj) + '">' + escapeHtml(fnDecl.name) + '</a>(';
- var html = escapeHtml(fnDecl.name) + '(';
- for (var arg_i = 0; arg_i < callObj.args.length; arg_i += 1) {
- if (arg_i !== 0) html += ', ';
- var argObj = callObj.args[arg_i];
- html += getValueText(argObj.type, argObj.value, true, true);
- }
- html += ')';
- return html;
- }
- function getValueText(typeIndex, value, wantHtml, wantLink) {
- var typeObj = zigAnalysis.types[typeIndex];
- switch (typeObj.kind) {
- case typeKinds.Type:
- return typeIndexName(value, wantHtml, wantLink);
- case typeKinds.Fn:
- var fnObj = zigAnalysis.fns[value];
- var declPath = fnObj.decl && getCanonDeclPath(fnObj.decl);
- var fnName = declPath ? declPath.declNames.join('.') : '(unknown)';
-
- if (!wantHtml) {
- return fnName;
- }
+ let operator = "";
- var str = '<span class="tok-fn">';
- if (wantLink && declPath != null) {
- str += '<a href="' + navLink(declPath.pkgNames, declPath.declNames) + '">';
- str += escapeHtml(fnName);
- str += '</a>';
- } else {
- str += escapeHtml(fnName);
- }
- str += '</span>';
- return str;
- case typeKinds.Int:
- return token(value, tokenKinds.Number, wantHtml);
- case typeKinds.Optional:
- if(value === 'null'){
- return token(value, tokenKinds.Null, wantHtml);
- } else {
- console.trace("TODO non-null optional value printing");
- return "TODO";
- }
- case typeKinds.Bool:
- return token(value, tokenKinds.Null, wantHtml);
- default:
- console.trace("TODO implement getValueText for this type:", zigAnalysis.typeKinds[typeObj.kind]);
- return "TODO";
- }
- }
+ switch (expr.binOp.name) {
+ case "add": {
+ operator += "+";
+ break;
+ }
+ case "addwrap": {
+ operator += "+%";
+ break;
+ }
+ case "add_sat": {
+ operator += "+|";
+ break;
+ }
+ case "sub": {
+ operator += "-";
+ break;
+ }
+ case "subwrap": {
+ operator += "-%";
+ break;
+ }
+ case "sub_sat": {
+ operator += "-|";
+ break;
+ }
+ case "mul": {
+ operator += "*";
+ break;
+ }
+ case "mulwrap": {
+ operator += "*%";
+ break;
+ }
+ case "mul_sat": {
+ operator += "*|";
+ break;
+ }
+ case "div": {
+ operator += "/";
+ break;
+ }
+ case "shl": {
+ operator += "<<";
+ break;
+ }
+ case "shl_sat": {
+ operator += "<<|";
+ break;
+ }
+ case "shr": {
+ operator += ">>";
+ break;
+ }
+ case "bit_or" : {
+ operator += "|";
+ break;
+ }
+ case "bit_and" : {
+ operator += "&";
+ break;
+ }
+ case "array_cat" : {
+ operator += "++";
+ break;
+ }
+ case "array_mul" : {
+ operator += "**";
+ break;
+ }
+ default: console.log("operator not handled yet or doesn't exist!");
+ };
- function typeName(typeObj, wantHtml, wantSubLink, fnDecl, linkFnNameDecl, thisTypes) {
- switch (typeObj.kind) {
- case typeKinds.Array:
- var name = "[";
- name += token(typeObj.len, tokenKinds.Number, wantHtml);
- name += "]";
- name += typeIndexName(typeObj.elem, wantHtml, wantSubLink, null, null, thisTypes);
- return name;
- case typeKinds.Vector:
- var name = "Vector(";
- name += token(typeObj.len, tokenKinds.Number, wantHtml);
- name += ", ";
- name += typeIndexName(typeObj.elem, wantHtml, wantSubLink, null, null, thisTypes);
- name += ")";
- return name;
- case typeKinds.Optional:
- return "?" + typeIndexName(typeObj.child, wantHtml, wantSubLink, fnDecl, linkFnNameDecl, thisTypes);
- case typeKinds.Pointer:
- var name = "";
- switch (typeObj.len) {
- case pointerSizeEnum.One:
- default:
- name += "*";
- break;
- case pointerSizeEnum.Many:
- name += "[*]";
- break;
- case pointerSizeEnum.Slice:
- name += "[]";
- break;
- case pointerSizeEnum.C:
- name += "[*c]";
- break;
- }
- if (typeObj['const']) {
- name += token('const', tokenKinds.Keyword, wantHtml) + ' ';
- }
- if (typeObj['volatile']) {
- name += token('volatile', tokenKinds.Keyword, wantHtml) + ' ';
- }
- if (typeObj.align != null) {
- name += token('align', tokenKinds.Keyword, wantHtml) + '(';
- name += token(typeObj.align, tokenKinds.Number, wantHtml);
-
- if (typeObj.hostIntBytes != null) {
- name += ":";
- name += token(typeObj.bitOffsetInHost, tokenKinds.Number, wantHtml);
- name += ":";
- name += token(typeObj.hostIntBytes, tokenKinds.Number, wantHtml);
- }
- name += ") ";
+ return print_lhs + " " + operator + " " + print_rhs;
+
+ }
+ case "errorSets": {
+ const errUnionObj = zigAnalysis.types[expr.errorSets];
+ let lhs = exprName(errUnionObj.lhs, opts);
+ let rhs = exprName(errUnionObj.rhs, opts);
+ return lhs + " || " + rhs;
+
+ }
+ case "errorUnion": {
+ const errUnionObj = zigAnalysis.types[expr.errorUnion];
+ let lhs = exprName(errUnionObj.lhs, opts);
+ let rhs = exprName(errUnionObj.rhs, opts);
+ return lhs + "!" + rhs;
+
+ }
+ case "struct": {
+ const struct_name = zigAnalysis.decls[expr.struct[0].val.typeRef.refPath[0].declRef].name;
+ let struct_body = "";
+ struct_body += struct_name + "{ ";
+ for (let i = 0; i < expr.struct.length; i++) {
+ const val = expr.struct[i].name
+ const exprArg = zigAnalysis.exprs[expr.struct[i].val.expr.as.exprArg];
+ let value_field = exprArg[Object.keys(exprArg)[0]];
+ if (value_field instanceof Object) {
+ value_field = zigAnalysis.decls[value_field[0].val.typeRef.refPath[0].declRef].name;
+ };
+ struct_body += "." + val + " = " + value_field;
+ if (i !== expr.struct.length - 1) {
+ struct_body += ", ";
+ } else {
+ struct_body += " ";
+ }
+ }
+ struct_body += "}";
+ return struct_body;
+ }
+ case "typeOf_peer": {
+ let payloadHtml = "@TypeOf("
+ for (let i = 0; i < expr.typeOf_peer.length; i++) {
+ let elem = zigAnalysis.exprs[expr.typeOf_peer[i]];
+ payloadHtml += exprName(elem, {wantHtml: true, wantLink:true});
+ if (i !== expr.typeOf_peer.length - 1) {
+ payloadHtml += ", ";
+ }
+ }
+ payloadHtml += ")";
+ return payloadHtml;
+
+ }
+ case "alignOf": {
+ const alignRefArg = zigAnalysis.exprs[expr.alignOf];
+ let payloadHtml = "@alignOf(" + exprName(alignRefArg, {wantHtml: true, wantLink:true}) + ")";
+ return payloadHtml;
+ }
+ case "typeOf": {
+ const typeRefArg = zigAnalysis.exprs[expr.typeOf];
+ let payloadHtml = "@TypeOf(" + exprName(typeRefArg, {wantHtml: true, wantLink:true}) + ")";
+ return payloadHtml;
+ }
+ case "null": {
+ return "null";
+ }
+ case "array": {
+ let payloadHtml = ".{";
+ for (let i = 0; i < expr.array.length; i++) {
+ if (i != 0) payloadHtml += ", ";
+ let elem = zigAnalysis.exprs[expr.array[i]];
+ payloadHtml += exprName(elem, opts);
+ }
+ return payloadHtml + "}";
+ }
+ case "comptimeExpr": {
+ return zigAnalysis.comptimeExprs[expr.comptimeExpr].code;
+ }
+ case "call": {
+ let call = zigAnalysis.calls[expr.call];
+ let payloadHtml = "";
+
+
+ switch(Object.keys(call.func)[0]){
+ default: throw "TODO";
+ case "declRef":
+ case "refPath": {
+ payloadHtml += exprName(call.func, opts);
+ break;
}
- name += typeIndexName(typeObj.elem, wantHtml, wantSubLink, null, null, thisTypes);
- return name;
- case typeKinds.Float:
- return token('f' + typeObj.bits, tokenKinds.Type, wantHtml);
- case typeKinds.Int:
- var signed = (typeObj.i != null) ? 'i' : 'u';
- var bits = typeObj[signed];
- return token(signed + bits, tokenKinds.Type, wantHtml);
- case typeKinds.ComptimeInt:
- return token('comptime_int', tokenKinds.Type, wantHtml);
- case typeKinds.ComptimeFloat:
- return token('comptime_float', tokenKinds.Type, wantHtml);
- case typeKinds.Type:
- return token('type', tokenKinds.Type, wantHtml);
- case typeKinds.Bool:
- return token('bool', tokenKinds.Type, wantHtml);
- case typeKinds.Void:
- return token('void', tokenKinds.Type, wantHtml);
- case typeKinds.EnumLiteral:
- return token('(enum literal)', tokenKinds.Type, wantHtml);
- case typeKinds.NoReturn:
- return token('noreturn', tokenKinds.Type, wantHtml);
- case typeKinds.ErrorSet:
- if (typeObj.errors == null) {
- return token('anyerror', tokenKinds.Type, wantHtml);
- } else {
- if (wantHtml) {
- return escapeHtml(typeObj.name);
+ }
+ payloadHtml += "(";
+
+ for (let i = 0; i < call.args.length; i++) {
+ if (i != 0) payloadHtml += ", ";
+ payloadHtml += exprName(call.args[i], opts);
+ }
+
+ payloadHtml += ")";
+ return payloadHtml;
+ }
+ case "as": {
+ // @Check : this should be done in backend because there are legit @as() calls
+ // const typeRefArg = zigAnalysis.exprs[expr.as.typeRefArg];
+ const exprArg = zigAnalysis.exprs[expr.as.exprArg];
+ // return "@as(" + exprName(typeRefArg, opts) +
+ // ", " + exprName(exprArg, opts) + ")";
+ return exprName(exprArg, opts);
+ }
+ case "declRef": {
+ return zigAnalysis.decls[expr.declRef].name;
+ }
+ case "refPath": {
+ return expr.refPath.map(x => exprName(x, opts)).join(".");
+ }
+ case "int": {
+ return "" + expr.int;
+ }
+ case "float": {
+ return "" + expr.float.toFixed(2);
+ }
+ case "float128": {
+ return "" + expr.float128.toFixed(2);
+ }
+ case "undefined": {
+ return "undefined";
+ }
+ case "string": {
+ return "\"" + escapeHtml(expr.string) + "\"";
+ }
+
+ case "anytype": {
+ return "anytype";
+ }
+
+ case "this":{
+ return "@This()";
+ }
+
+ case "type": {
+ let name = "";
+
+ let typeObj = expr.type;
+ if (typeof typeObj === 'number') typeObj = zigAnalysis.types[typeObj];
+ switch (typeObj.kind) {
+ default: throw "TODO";
+ case typeKinds.Struct:
+ {
+ let structObj = (typeObj);
+ return structObj;
+ }
+ case typeKinds.Enum:
+ {
+ let enumObj = (typeObj);
+ return enumObj;
+ }
+ case typeKinds.Opaque:
+ {
+ let opaqueObj = (typeObj);
+
+ return opaqueObj.name;
+ }
+ case typeKinds.ComptimeExpr:
+ {
+ return "anyopaque";
+ }
+ case typeKinds.Array:
+ {
+ let arrayObj = typeObj;
+ let name = "[";
+ let lenName = exprName(arrayObj.len, opts);
+ let sentinel = arrayObj.sentinel ? ":"+exprName(arrayObj.sentinel, opts) : "";
+ // let is_mutable = arrayObj.is_multable ? "const " : "";
+
+ if (opts.wantHtml) {
+ name +=
+ '<span class="tok-number">' + lenName + sentinel + "</span>";
} else {
- return typeObj.name;
+ name += lenName + sentinel;
}
- }
- case typeKinds.ErrorUnion:
- var errSetTypeObj = zigAnalysis.types[typeObj.err];
- var payloadHtml = typeIndexName(typeObj.payload, wantHtml, wantSubLink, null, null, thisTypes);
- if (fnDecl != null && errSetTypeObj.fn === fnDecl.value) {
- // function index parameter supplied and this is the inferred error set of it
- return "!" + payloadHtml;
- } else {
- return typeIndexName(typeObj.err, wantHtml, wantSubLink, null, null, thisTypes) + "!" + payloadHtml;
- }
- case typeKinds.Fn:
- var payloadHtml = "";
- if (wantHtml) {
- payloadHtml += '<span class="tok-kw">fn</span>';
- if (fnDecl != null) {
- payloadHtml += ' <span class="tok-fn">';
- if (linkFnNameDecl != null) {
- payloadHtml += '<a href="' + linkFnNameDecl + '">' +
- escapeHtml(fnDecl.name) + '</a>';
- } else {
- payloadHtml += escapeHtml(fnDecl.name);
- }
- payloadHtml += '</span>';
- }
- } else {
- payloadHtml += 'fn'
- }
- payloadHtml += '(';
- if (typeObj.args != null) {
- var fields = null;
- var isVarArgs = false;
- if (fnDecl != null) {
- var fnObj = zigAnalysis.fns[fnDecl.value];
- var fnNode = zigAnalysis.astNodes[fnObj.src];
- fields = fnNode.fields;
- isVarArgs = fnNode.varArgs;
+ name += "]";
+ // name += is_mutable;
+ name += exprName(arrayObj.child, opts);
+ return name;
+ }
+ case typeKinds.Optional:
+ return "?" + exprName((typeObj).child, opts);
+ case typeKinds.Pointer:
+ {
+ let ptrObj = (typeObj);
+ let sentinel = ptrObj.sentinel ? ":"+exprName(ptrObj.sentinel, opts) : "";
+ let is_mutable = !ptrObj.is_mutable ? "const " : "";
+ let name = "";
+ switch (ptrObj.size) {
+ default:
+ console.log("TODO: implement unhandled pointer size case");
+ case pointerSizeEnum.One:
+ name += "*";
+ name += is_mutable;
+ break;
+ case pointerSizeEnum.Many:
+ name += "[*";
+ name += sentinel;
+ name += "]";
+ name += is_mutable;
+ break;
+ case pointerSizeEnum.Slice:
+ if (ptrObj.is_ref) {
+ name += "*";
+ }
+ name += "[";
+ name += sentinel;
+ name += "]";
+ name += is_mutable;
+ break;
+ case pointerSizeEnum.C:
+ name += "[*c";
+ name += sentinel;
+ name += "]";
+ name += is_mutable;
+ break;
+ }
+ // @check: after the major changes in arrays the consts are came from switch above
+ // if (!ptrObj.is_mutable) {
+ // if (opts.wantHtml) {
+ // name += '<span class="tok-kw">const</span> ';
+ // } else {
+ // name += "const ";
+ // }
+ // }
+ if (ptrObj.is_allowzero) {
+ name += "allowzero ";
+ }
+ if (ptrObj.is_volatile) {
+ name += "volatile ";
+ }
+ if (ptrObj.has_addrspace) {
+ name += "addrspace(";
+ name += "." + "";
+ name += ") ";
+ }
+ if (ptrObj.has_align) {
+ let align = exprName(ptrObj.align, opts);
+ if (opts.wantHtml) {
+ name += '<span class="tok-kw">align</span>(';
+ } else {
+ name += "align(";
+ }
+ if (opts.wantHtml) {
+ name += '<span class="tok-number">' + align + '</span>';
+ } else {
+ name += align;
+ }
+ if (ptrObj.hostIntBytes != null) {
+ name += ":";
+ if (opts.wantHtml) {
+ name += '<span class="tok-number">' + ptrObj.bitOffsetInHost + '</span>';
+ } else {
+ name += ptrObj.bitOffsetInHost;
+ }
+ name += ":";
+ if (opts.wantHtml) {
+ name += '<span class="tok-number">' + ptrObj.hostIntBytes + '</span>';
+ } else {
+ name += ptrObj.hostIntBytes;
+ }
+ }
+ name += ") ";
+ }
+ //name += typeValueName(ptrObj.child, wantHtml, wantSubLink, null);
+ name += exprName(ptrObj.child, opts);
+ return name;
+ }
+ case typeKinds.Float:
+ {
+ let floatObj = (typeObj);
+
+ if (opts.wantHtml) {
+ return '<span class="tok-type">' + floatObj.name + '</span>';
+ } else {
+ return floatObj.name;
+ }
+ }
+ case typeKinds.Int:
+ {
+ let intObj = (typeObj);
+ let name = intObj.name;
+ if (opts.wantHtml) {
+ return '<span class="tok-type">' + name + '</span>';
+ } else {
+ return name;
+ }
+ }
+ case typeKinds.ComptimeInt:
+ if (opts.wantHtml) {
+ return '<span class="tok-type">comptime_int</span>';
+ } else {
+ return "comptime_int";
+ }
+ case typeKinds.ComptimeFloat:
+ if (opts.wantHtml) {
+ return '<span class="tok-type">comptime_float</span>';
+ } else {
+ return "comptime_float";
+ }
+ case typeKinds.Type:
+ if (opts.wantHtml) {
+ return '<span class="tok-type">type</span>';
+ } else {
+ return "type";
+ }
+ case typeKinds.Bool:
+ if (opts.wantHtml) {
+ return '<span class="tok-type">bool</span>';
+ } else {
+ return "bool";
+ }
+ case typeKinds.Void:
+ if (opts.wantHtml) {
+ return '<span class="tok-type">void</span>';
+ } else {
+ return "void";
+ }
+ case typeKinds.EnumLiteral:
+ if (opts.wantHtml) {
+ return '<span class="tok-type">(enum literal)</span>';
+ } else {
+ return "(enum literal)";
+ }
+ case typeKinds.NoReturn:
+ if (opts.wantHtml) {
+ return '<span class="tok-type">noreturn</span>';
+ } else {
+ return "noreturn";
+ }
+ case typeKinds.ErrorSet:
+ {
+ let errSetObj = (typeObj);
+ if (errSetObj.fields == null) {
+ return '<span class="tok-type">anyerror</span>';
+ } else {
+ // throw "TODO";
+ let html = "error{" + errSetObj.fields[0].name + "}";
+ return html;
+ }
+ }
+
+ case typeKinds.ErrorUnion:
+ {
+ let errUnionObj = (typeObj);
+ let lhs = exprName(errUnionObj.lhs, opts);
+ let rhs = exprName(errUnionObj.rhs, opts);
+ return lhs + "!" + rhs;
+ }
+ case typeKinds.Fn:
+ {
+ let fnObj = (typeObj);
+ let payloadHtml = "";
+ if (opts.wantHtml) {
+ if (fnObj.is_extern) {
+ payloadHtml += "pub extern ";
+ }
+ if (fnObj.has_lib_name) {
+ payloadHtml += "\"" + fnObj.lib_name +"\" ";
+ }
+ payloadHtml += '<span class="tok-kw">fn</span>';
+ if (opts.fnDecl) {
+ payloadHtml += ' <span class="tok-fn">';
+ if (opts.linkFnNameDecl) {
+ payloadHtml += '<a href="' + opts.linkFnNameDecl + '">' +
+ escapeHtml(opts.fnDecl.name) + '</a>';
+ } else {
+ payloadHtml += escapeHtml(opts.fnDecl.name);
+ }
+ payloadHtml += '</span>';
+ }
+ } else {
+ payloadHtml += 'fn ';
+ }
+ payloadHtml += '(';
+ if (fnObj.params) {
+ let fields = null;
+ let isVarArgs = false;
+ let fnNode = zigAnalysis.astNodes[fnObj.src];
+ fields = fnNode.fields;
+ isVarArgs = fnNode.varArgs;
+
+ for (let i = 0; i < fnObj.params.length; i += 1) {
+ if (i != 0) {
+ payloadHtml += ', ';
+ }
+
+ payloadHtml += "<span class='argBreaker'><br> </span>"
+ let value = fnObj.params[i];
+ let paramValue = resolveValue({expr: value});
+
+ if (fields != null) {
+ let paramNode = zigAnalysis.astNodes[fields[i]];
+
+ if (paramNode.varArgs) {
+ payloadHtml += '...';
+ continue;
+ }
+
+ if (paramNode.noalias) {
+ if (opts.wantHtml) {
+ payloadHtml += '<span class="tok-kw">noalias</span> ';
+ } else {
+ payloadHtml += 'noalias ';
+ }
+ }
+
+ if (paramNode.comptime) {
+ if (opts.wantHtml) {
+ payloadHtml += '<span class="tok-kw">comptime</span> ';
+ } else {
+ payloadHtml += 'comptime ';
+ }
+ }
+
+ let paramName = paramNode.name;
+ if (paramName != null) {
+ // skip if it matches the type name
+ if (!shouldSkipParamName(paramValue, paramName)) {
+ payloadHtml += paramName + ': ';
+ }
+ }
+ }
+
+ if (isVarArgs && i === fnObj.params.length - 1) {
+ payloadHtml += '...';
+ }
+ else if ("alignOf" in value) {
+ if (opts.wantHtml) {
+ payloadHtml += '<a href="">';
+ payloadHtml +=
+ '<span class="tok-kw" style="color:lightblue;">'
+ + exprName(value, opts) + '</span>';
+ payloadHtml += '</a>';
+ } else {
+ payloadHtml += exprName(value, opts);
+ }
+
+ }
+ else if ("typeOf" in value) {
+ if (opts.wantHtml) {
+ payloadHtml += '<a href="">';
+ payloadHtml +=
+ '<span class="tok-kw" style="color:lightblue;">'
+ + exprName(value, opts) + '</span>';
+ payloadHtml += '</a>';
+ } else {
+ payloadHtml += exprName(value, opts);
+ }
+
+ }
+ else if ("typeOf_peer" in value) {
+ if (opts.wantHtml) {
+ payloadHtml += '<a href="">';
+ payloadHtml +=
+ '<span class="tok-kw" style="color:lightblue;">'
+ + exprName(value, opts) + '</span>';
+ payloadHtml += '</a>';
+ } else {
+ payloadHtml += exprName(value, opts);
+ }
+
+ }
+ else if ("declRef" in value) {
+ if (opts.wantHtml) {
+ payloadHtml += '<a href="">';
+ payloadHtml +=
+ '<span class="tok-kw" style="color:lightblue;">'
+ + exprName(value, opts) + '</span>';
+ payloadHtml += '</a>';
+ } else {
+ payloadHtml += exprName(value, opts);
+ }
+
+ }
+ else if ("call" in value) {
+ if (opts.wantHtml) {
+ payloadHtml += '<a href="">';
+ payloadHtml +=
+ '<span class="tok-kw" style="color:lightblue;">'
+ + exprName(value, opts) + '</span>';
+ payloadHtml += '</a>';
+ } else {
+ payloadHtml += exprName(value, opts);
+ }
+ }
+ else if ("refPath" in value) {
+ if (opts.wantHtml) {
+ payloadHtml += '<a href="">';
+ payloadHtml +=
+ '<span class="tok-kw" style="color:lightblue;">'
+ + exprName(value, opts) + '</span>';
+ payloadHtml += '</a>';
+ } else {
+ payloadHtml += exprName(value, opts);
+ }
+ } else if ("type" in value) {
+ let name = exprName(value, {
+ wantHtml: false,
+ wantLink: false,
+ fnDecl: opts.fnDecl,
+ linkFnNameDecl: opts.linkFnNameDecl,
+ });
+ payloadHtml += '<span class="tok-kw">' + name + '</span>';
+ } else if ("binOpIndex" in value) {
+ payloadHtml += exprName(value, opts);
+ }else if ("comptimeExpr" in value) {
+ let comptimeExpr = zigAnalysis.comptimeExprs[value.comptimeExpr].code;
+ if (opts.wantHtml) {
+ payloadHtml += '<span class="tok-kw">' + comptimeExpr + '</span>';
+ } else {
+ payloadHtml += comptimeExpr;
+ }
+ } else if (opts.wantHtml) {
+ payloadHtml += '<span class="tok-kw">anytype</span>';
+ } else {
+ payloadHtml += 'anytype';
+ }
+ }
+ }
+
+ payloadHtml += "<span class='argBreaker'>,<br></span>"
+ payloadHtml += ') ';
+
+ if (fnObj.has_align) {
+ let align = zigAnalysis.exprs[fnObj.align]
+ payloadHtml += "align(" + exprName(align, opts) + ") ";
}
-
- for (var i = 0; i < typeObj.args.length; i += 1) {
- if (i != 0) {
- payloadHtml += ', ';
- }
-
- var argTypeIndex = typeObj.args[i];
-
- if (fields != null) {
- var paramNode = zigAnalysis.astNodes[fields[i]];
-
- if (paramNode.varArgs) {
- payloadHtml += '...';
- continue;
- }
-
- if (paramNode.noalias) {
- payloadHtml += token('noalias', tokenKinds.Keyword, wantHtml) + ' ';
- }
-
- if (paramNode.comptime) {
- payloadHtml += token('comptime', tokenKinds.Keyword, wantHtml) + ' ';
- }
-
- var paramName = paramNode.name;
- if (paramName != null) {
- // skip if it matches the type name
- if (argTypeIndex == null || !shouldSkipParamName(argTypeIndex, paramName)) {
- payloadHtml += paramName + ': ';
- }
- }
- }
-
- if (isVarArgs && i === typeObj.args.length - 1) {
- payloadHtml += '...';
- } else if (argTypeIndex != null) {
- payloadHtml += typeIndexName(argTypeIndex, wantHtml, wantSubLink, null, null, thisTypes);
- } else {
- payloadHtml += token('anytype', tokenKinds.Keyword, wantHtml);
- }
+ if (fnObj.has_cc) {
+ let cc = zigAnalysis.exprs[fnObj.cc]
+ if (cc) {
+ payloadHtml += "callconv(." + cc.enumLiteral + ") ";
+ }
}
- }
- payloadHtml += ') ';
- if (typeObj.ret != null) {
- payloadHtml += typeIndexName(typeObj.ret, wantHtml, wantSubLink, fnDecl, null, thisTypes);
- } else {
- payloadHtml += token('anytype', tokenKinds.Keyword, wantHtml);
- }
- return payloadHtml;
- case typeKinds.Frame:
- var fnObj = zigAnalysis.fns[typeObj.fn];
- return '@Frame(' + getValueText(fnObj.type, typeObj.fn, wantHtml, wantSubLink) + ')';
- case typeKinds.AnyFrame:
- var name = token('anyframe', tokenKinds.Keyword, wantHtml);
- if (typeObj.result) {
- name += "->";
- name += typeIndexName(typeObj.result, wantHtml, wantSubLink, null, null, thisTypes);
- }
- return name;
- default:
- if (wantHtml) {
- return escapeHtml(typeObj.name);
- } else {
- return typeObj.name;
+ if (fnObj.is_inferred_error) {
+ payloadHtml += "!";
+ }
+ if (fnObj.ret != null) {
+ payloadHtml += exprName(fnObj.ret, opts);
+ } else if (opts.wantHtml) {
+ payloadHtml += '<span class="tok-kw">anytype</span>';
+ } else {
+ payloadHtml += 'anytype';
+ }
+ return payloadHtml;
+ }
+ // if (wantHtml) {
+ // return escapeHtml(typeObj.name);
+ // } else {
+ // return typeObj.name;
+ // }
+ }
+ }
+
+ }
+ }
+
+
+
+ function shouldSkipParamName(typeRef, paramName) {
+ let resolvedTypeRef = resolveValue({expr: typeRef});
+ if ("type" in resolvedTypeRef) {
+ let typeObj = zigAnalysis.types[resolvedTypeRef.type];
+ if (typeObj.kind === typeKinds.Pointer){
+ let ptrObj = (typeObj);
+ if (getPtrSize(ptrObj) === pointerSizeEnum.One) {
+ const value = resolveValue(ptrObj.child);
+ return typeValueName(value, false, true).toLowerCase() === paramName;
}
+ }
}
+ return false;
+ }
+
+
+ function getPtrSize(typeObj) {
+ return (typeObj.size == null) ? pointerSizeEnum.One : typeObj.size;
}
+
function renderType(typeObj) {
- var name;
+ let name;
if (rootIsStd && typeObj === zigAnalysis.types[zigAnalysis.packages[zigAnalysis.rootPkg].main]) {
name = "std";
} else {
- name = typeName(typeObj, false, false);
+ name = exprName({type:typeObj}, false, false);
}
if (name != null && name != "") {
domHdrName.innerText = name + " (" + zigAnalysis.typeKinds[typeObj.kind] + ")";
domHdrName.classList.remove("hidden");
}
if (typeObj.kind == typeKinds.ErrorSet) {
- renderErrorSet(typeObj);
+ renderErrorSet((typeObj));
}
}
+
function renderErrorSet(errSetType) {
- if (errSetType.errors == null) {
+ if (errSetType.fields == null) {
domFnErrorsAnyError.classList.remove("hidden");
} else {
- var errorList = [];
- for (var i = 0; i < errSetType.errors.length; i += 1) {
- var errObj = zigAnalysis.errors[errSetType.errors[i]];
- var srcObj = zigAnalysis.astNodes[errObj.src];
- errorList.push({
- err: errObj,
- docs: srcObj.docs,
- });
+ let errorList = [];
+ for (let i = 0; i < errSetType.fields.length; i += 1) {
+ let errObj = errSetType.fields[i];
+ //let srcObj = zigAnalysis.astNodes[errObj.src];
+ errorList.push(errObj);
}
errorList.sort(function(a, b) {
- return operatorCompare(a.err.name.toLowerCase(), b.err.name.toLowerCase());
+ return operatorCompare(a.name.toLowerCase(), b.name.toLowerCase());
});
- var domListFnErrorsFragment = createDomListFragment(errorList.length, "<dt></dt><dd></dd>");
- for (var i = 0; i < errorList.length; i += 1) {
- var nameTdDom = domListFnErrorsFragment.children[i * 2 + 0];
- var descTdDom = domListFnErrorsFragment.children[i * 2 + 1];
- nameTdDom.textContent = errorList[i].err.name;
- var docs = errorList[i].docs;
+ resizeDomListDl(domListFnErrors, errorList.length);
+ for (let i = 0; i < errorList.length; i += 1) {
+ let nameTdDom = domListFnErrors.children[i * 2 + 0];
+ let descTdDom = domListFnErrors.children[i * 2 + 1];
+ nameTdDom.textContent = errorList[i].name;
+ let docs = errorList[i].docs;
if (docs != null) {
descTdDom.innerHTML = markdown(docs);
} else {
descTdDom.textContent = "";
}
}
- domListFnErrors.innerHTML = "";
- domListFnErrors.appendChild(domListFnErrorsFragment);
domTableFnErrors.classList.remove("hidden");
}
domSectFnErrors.classList.remove("hidden");
}
- function allCompTimeFnCallsHaveTypeResult(typeIndex, value) {
- var srcIndex = zigAnalysis.fns[value].src;
- var calls = nodesToCallsMap[srcIndex];
- if (calls == null) return false;
- for (var i = 0; i < calls.length; i += 1) {
- var call = zigAnalysis.calls[calls[i]];
- if (call.result.type !== typeTypeId) return false;
- }
- return true;
- }
-
- function allCompTimeFnCallsResult(calls) {
- var firstTypeObj = null;
- var containerObj = {
- privDecls: [],
- };
- for (var callI = 0; callI < calls.length; callI += 1) {
- var call = zigAnalysis.calls[calls[callI]];
- if (call.result.type !== typeTypeId) return null;
- var typeObj = zigAnalysis.types[call.result.value];
- if (!typeKindIsContainer(typeObj.kind)) return null;
- if (firstTypeObj == null) {
- firstTypeObj = typeObj;
- containerObj.src = typeObj.src;
- } else if (firstTypeObj.src !== typeObj.src) {
- return null;
- }
-
- if (containerObj.fields == null) {
- containerObj.fields = (typeObj.fields || []).concat([]);
- } else for (var fieldI = 0; fieldI < typeObj.fields.length; fieldI += 1) {
- var prev = containerObj.fields[fieldI];
- var next = typeObj.fields[fieldI];
- if (prev === next) continue;
- if (typeof(prev) === 'object') {
- if (prev[next] == null) prev[next] = typeObj;
- } else {
- containerObj.fields[fieldI] = {};
- containerObj.fields[fieldI][prev] = firstTypeObj;
- containerObj.fields[fieldI][next] = typeObj;
- }
- }
-
- if (containerObj.pubDecls == null) {
- containerObj.pubDecls = (typeObj.pubDecls || []).concat([]);
- } else for (var declI = 0; declI < typeObj.pubDecls.length; declI += 1) {
- var prev = containerObj.pubDecls[declI];
- var next = typeObj.pubDecls[declI];
- if (prev === next) continue;
- // TODO instead of showing "examples" as the public declarations,
- // do logic like this:
- //if (typeof(prev) !== 'object') {
- // var newDeclId = zigAnalysis.decls.length;
- // prev = clone(zigAnalysis.decls[prev]);
- // prev.id = newDeclId;
- // zigAnalysis.decls.push(prev);
- // containerObj.pubDecls[declI] = prev;
- //}
- //mergeDecls(prev, next, firstTypeObj, typeObj);
- }
- }
- for (var declI = 0; declI < containerObj.pubDecls.length; declI += 1) {
- var decl = containerObj.pubDecls[declI];
- if (typeof(decl) === 'object') {
- containerObj.pubDecls[declI] = containerObj.pubDecls[declI].id;
- }
- }
- return containerObj;
- }
-
- function mergeDecls(declObj, nextDeclIndex, firstTypeObj, typeObj) {
- var nextDeclObj = zigAnalysis.decls[nextDeclIndex];
- if (declObj.type != null && nextDeclObj.type != null && declObj.type !== nextDeclObj.type) {
- if (typeof(declObj.type) !== 'object') {
- var prevType = declObj.type;
- declObj.type = {};
- declObj.type[prevType] = firstTypeObj;
- declObj.value = null;
- }
- declObj.type[nextDeclObj.type] = typeObj;
- } else if (declObj.type == null && nextDeclObj != null) {
- declObj.type = nextDeclObj.type;
- }
- if (declObj.value != null && nextDeclObj.value != null && declObj.value !== nextDeclObj.value) {
- if (typeof(declObj.value) !== 'object') {
- var prevValue = declObj.value;
- declObj.value = {};
- declObj.value[prevValue] = firstTypeObj;
- }
- declObj.value[nextDeclObj.value] = typeObj;
- } else if (declObj.value == null && nextDeclObj.value != null) {
- declObj.value = nextDeclObj.value;
- }
- }
-
+// function allCompTimeFnCallsHaveTypeResult(typeIndex, value) {
+// let srcIndex = zigAnalysis.fns[value].src;
+// let calls = nodesToCallsMap[srcIndex];
+// if (calls == null) return false;
+// for (let i = 0; i < calls.length; i += 1) {
+// let call = zigAnalysis.calls[calls[i]];
+// if (call.result.type !== typeTypeId) return false;
+// }
+// return true;
+// }
+//
+// function allCompTimeFnCallsResult(calls) {
+// let firstTypeObj = null;
+// let containerObj = {
+// privDecls: [],
+// };
+// for (let callI = 0; callI < calls.length; callI += 1) {
+// let call = zigAnalysis.calls[calls[callI]];
+// if (call.result.type !== typeTypeId) return null;
+// let typeObj = zigAnalysis.types[call.result.value];
+// if (!typeKindIsContainer(typeObj.kind)) return null;
+// if (firstTypeObj == null) {
+// firstTypeObj = typeObj;
+// containerObj.src = typeObj.src;
+// } else if (firstTypeObj.src !== typeObj.src) {
+// return null;
+// }
+//
+// if (containerObj.fields == null) {
+// containerObj.fields = (typeObj.fields || []).concat([]);
+// } else for (let fieldI = 0; fieldI < typeObj.fields.length; fieldI += 1) {
+// let prev = containerObj.fields[fieldI];
+// let next = typeObj.fields[fieldI];
+// if (prev === next) continue;
+// if (typeof(prev) === 'object') {
+// if (prev[next] == null) prev[next] = typeObj;
+// } else {
+// containerObj.fields[fieldI] = {};
+// containerObj.fields[fieldI][prev] = firstTypeObj;
+// containerObj.fields[fieldI][next] = typeObj;
+// }
+// }
+//
+// if (containerObj.pubDecls == null) {
+// containerObj.pubDecls = (typeObj.pubDecls || []).concat([]);
+// } else for (let declI = 0; declI < typeObj.pubDecls.length; declI += 1) {
+// let prev = containerObj.pubDecls[declI];
+// let next = typeObj.pubDecls[declI];
+// if (prev === next) continue;
+// // TODO instead of showing "examples" as the public declarations,
+// // do logic like this:
+// //if (typeof(prev) !== 'object') {
+// // let newDeclId = zigAnalysis.decls.length;
+// // prev = clone(zigAnalysis.decls[prev]);
+// // prev.id = newDeclId;
+// // zigAnalysis.decls.push(prev);
+// // containerObj.pubDecls[declI] = prev;
+// //}
+// //mergeDecls(prev, next, firstTypeObj, typeObj);
+// }
+// }
+// for (let declI = 0; declI < containerObj.pubDecls.length; declI += 1) {
+// let decl = containerObj.pubDecls[declI];
+// if (typeof(decl) === 'object') {
+// containerObj.pubDecls[declI] = containerObj.pubDecls[declI].id;
+// }
+// }
+// return containerObj;
+// }
+
+
+
+
function renderValue(decl) {
+ let resolvedValue = resolveValue(decl.value)
+
+ if (resolvedValue.expr.fieldRef) {
+ const declRef = decl.value.expr.refPath[0].declRef;
+ const type = zigAnalysis.decls[declRef];
+ domFnProtoCode.innerHTML = '<span class="tok-kw">const</span> ' +
+ escapeHtml(decl.name) + ': ' + type.name +
+ " = " + exprName(decl.value.expr, {wantHtml: true, wantLink:true}) + ";";
+ } else if (resolvedValue.expr.string !== undefined || resolvedValue.expr.call !== undefined || resolvedValue.expr.comptimeExpr) {
+ domFnProtoCode.innerHTML = '<span class="tok-kw">const</span> ' +
+ escapeHtml(decl.name) + ': ' + exprName(resolvedValue.expr, {wantHtml: true, wantLink:true}) +
+ " = " + exprName(decl.value.expr, {wantHtml: true, wantLink:true}) + ";";
+ } else if (resolvedValue.expr.compileError) {
+ domFnProtoCode.innerHTML = '<span class="tok-kw">const</span> ' +
+ escapeHtml(decl.name) + " = " + exprName(decl.value.expr, {wantHtml: true, wantLink:true}) + ";";
+ }
+ else {
domFnProtoCode.innerHTML = '<span class="tok-kw">const</span> ' +
- escapeHtml(decl.name) + ': ' + typeIndexName(decl.type, true, true);
+ escapeHtml(decl.name) + ': ' + exprName(resolvedValue.typeRef, {wantHtml: true, wantLink:true}) +
+ " = " + exprName(decl.value.expr, {wantHtml: true, wantLink:true}) + ";";
+ }
- var docs = zigAnalysis.astNodes[decl.src].docs;
+ let docs = zigAnalysis.astNodes[decl.src].docs;
if (docs != null) {
domTldDocs.innerHTML = markdown(docs);
domTldDocs.classList.remove("hidden");
@@ -928,11 +2078,13 @@
domFnProto.classList.remove("hidden");
}
+
function renderVar(decl) {
+ let declTypeRef = typeOfDecl(decl);
domFnProtoCode.innerHTML = '<span class="tok-kw">var</span> ' +
- escapeHtml(decl.name) + ': ' + typeIndexName(decl.type, true, true);
+ escapeHtml(decl.name) + ': ' + typeValueName(declTypeRef, true, true);
- var docs = zigAnalysis.astNodes[decl.src].docs;
+ let docs = zigAnalysis.astNodes[decl.src].docs;
if (docs != null) {
domTldDocs.innerHTML = markdown(docs);
domTldDocs.classList.remove("hidden");
@@ -941,52 +2093,103 @@
domFnProto.classList.remove("hidden");
}
- function renderContainer(container, thisTypes) {
- var typesList = [];
- var namespacesList = [];
- var errSetsList = [];
- var fnsList = [];
- var varsList = [];
- var valsList = [];
- for (var i = 0; i < container.pubDecls.length; i += 1) {
- var decl = zigAnalysis.decls[container.pubDecls[i]];
+
+ function categorizeDecls(decls,
+ typesList, namespacesList, errSetsList,
+ fnsList, varsList, valsList, testsList) {
+
+ for (let i = 0; i < decls.length; i += 1) {
+ let decl = zigAnalysis.decls[decls[i]];
+ let declValue = resolveValue(decl.value);
+
+ if (decl.isTest) {
+ testsList.push(decl);
+ continue;
+ }
if (decl.kind === 'var') {
varsList.push(decl);
continue;
- } else if (decl.kind === 'const' && decl.type != null) {
- if (decl.type === typeTypeId) {
- if (typeIsErrSet(decl.value)) {
- errSetsList.push(decl);
- } else if (typeIsStructWithNoFields(decl.value)) {
- namespacesList.push(decl);
- } else {
- typesList.push(decl);
- }
- } else {
- var typeKind = zigAnalysis.types[decl.type].kind;
- if (typeKind === typeKinds.Fn) {
- if (allCompTimeFnCallsHaveTypeResult(decl.type, decl.value)) {
- typesList.push(decl);
+ }
+
+ if (decl.kind === 'const') {
+ if ("type" in declValue.expr) {
+ // We have the actual type expression at hand.
+ const typeExpr = zigAnalysis.types[declValue.expr.type];
+ if (typeExpr.kind == typeKinds.Fn) {
+ const funcRetExpr = resolveValue({
+ expr: (typeExpr).ret
+ });
+ if ("type" in funcRetExpr.expr && funcRetExpr.expr.type == typeTypeId) {
+ if (typeIsErrSet(declValue.expr.type)) {
+ errSetsList.push(decl);
+ } else if (typeIsStructWithNoFields(declValue.expr.type)) {
+ namespacesList.push(decl);
+ } else {
+ typesList.push(decl);
+ }
} else {
fnsList.push(decl);
}
} else {
- valsList.push(decl);
+ if (typeIsErrSet(declValue.expr.type)) {
+ errSetsList.push(decl);
+ } else if (typeIsStructWithNoFields(declValue.expr.type)) {
+ namespacesList.push(decl);
+ } else {
+ typesList.push(decl);
+ }
}
+ } else if ("typeRef" in declValue) {
+ if ("type" in declValue.typeRef && declValue.typeRef == typeTypeId) {
+ // We don't know what the type expression is, but we know it's a type.
+ typesList.push(decl);
+ } else {
+ valsList.push(decl);
+ }
+ } else {
+ valsList.push(decl);
}
}
}
+ }
+
+
+ function renderContainer(container) {
+
+ let typesList = [];
+
+ let namespacesList = [];
+
+ let errSetsList = [];
+
+ let fnsList = [];
+
+ let varsList = [];
+
+ let valsList = [];
+
+ let testsList = [];
+
+ categorizeDecls(container.pubDecls,
+ typesList, namespacesList, errSetsList,
+ fnsList, varsList, valsList, testsList);
+ if (curNav.showPrivDecls) categorizeDecls(container.privDecls,
+ typesList, namespacesList, errSetsList,
+ fnsList, varsList, valsList, testsList);
+
+
typesList.sort(byNameProperty);
namespacesList.sort(byNameProperty);
errSetsList.sort(byNameProperty);
fnsList.sort(byNameProperty);
varsList.sort(byNameProperty);
valsList.sort(byNameProperty);
+ testsList.sort(byNameProperty);
if (container.src != null) {
- var docs = zigAnalysis.astNodes[container.src].docs;
+ let docs = zigAnalysis.astNodes[container.src].docs;
if (docs != null) {
domTldDocs.innerHTML = markdown(docs);
domTldDocs.classList.remove("hidden");
@@ -994,163 +2197,193 @@
}
if (typesList.length !== 0) {
- var domListTypesFragment = createDomListFragment(typesList.length, '<li><a href="#"></a></li>');
- for (var i = 0; i < typesList.length; i += 1) {
- var liDom = domListTypesFragment.children[i];
- var aDom = liDom.children[0];
- var decl = typesList[i];
+ resizeDomList(domListTypes, typesList.length, '<li><a href="#"></a></li>');
+ for (let i = 0; i < typesList.length; i += 1) {
+ let liDom = domListTypes.children[i];
+ let aDom = liDom.children[0];
+ let decl = typesList[i];
aDom.textContent = decl.name;
aDom.setAttribute('href', navLinkDecl(decl.name));
}
- domListTypes.innerHTML = "";
- domListTypes.appendChild(domListTypesFragment);
domSectTypes.classList.remove("hidden");
}
if (namespacesList.length !== 0) {
- var domListNamespacesFragment = createDomListFragment(namespacesList.length, '<li><a href="#"></a></li>');
- for (var i = 0; i < namespacesList.length; i += 1) {
- var liDom = domListNamespacesFragment.children[i];
- var aDom = liDom.children[0];
- var decl = namespacesList[i];
+ resizeDomList(domListNamespaces, namespacesList.length, '<li><a href="#"></a></li>');
+ for (let i = 0; i < namespacesList.length; i += 1) {
+ let liDom = domListNamespaces.children[i];
+ let aDom = liDom.children[0];
+ let decl = namespacesList[i];
aDom.textContent = decl.name;
aDom.setAttribute('href', navLinkDecl(decl.name));
}
- domListNamespaces.innerHTML = "";
- domListNamespaces.appendChild(domListNamespacesFragment);
domSectNamespaces.classList.remove("hidden");
}
if (errSetsList.length !== 0) {
- var domListErrSetsFragment = createDomListFragment(errSetsList.length, '<li><a href="#"></a></li>');
- for (var i = 0; i < errSetsList.length; i += 1) {
- var liDom = domListErrSetsFragment.children[i];
- var aDom = liDom.children[0];
- var decl = errSetsList[i];
+ resizeDomList(domListErrSets, errSetsList.length, '<li><a href="#"></a></li>');
+ for (let i = 0; i < errSetsList.length; i += 1) {
+ let liDom = domListErrSets.children[i];
+ let aDom = liDom.children[0];
+ let decl = errSetsList[i];
aDom.textContent = decl.name;
aDom.setAttribute('href', navLinkDecl(decl.name));
}
- domListErrSets.innerHTML = "";
- domListErrSets.appendChild(domListErrSetsFragment);
domSectErrSets.classList.remove("hidden");
}
if (fnsList.length !== 0) {
- var domListFnsFragment = createDomListFragment(fnsList.length, '<tr><td></td><td></td></tr>');
- for (var i = 0; i < fnsList.length; i += 1) {
- var decl = fnsList[i];
- var trDom = domListFnsFragment.children[i];
+ resizeDomList(domListFns, fnsList.length, '<div><dt></dt><dd></dd></div>');
+
+ window.x = domListFns;
+ for (let i = 0; i < fnsList.length; i += 1) {
+ let decl = fnsList[i];
+ let trDom = domListFns.children[i];
+
+ let tdFnCode = trDom.children[0];
+ let tdDesc = trDom.children[1];
- var tdFnCode = trDom.children[0];
- var tdDesc = trDom.children[1];
+ let declType = resolveValue(decl.value);
+ console.assert("type" in declType.expr);
- tdFnCode.innerHTML = typeIndexName(decl.type, true, true, decl, navLinkDecl(decl.name), thisTypes);
+ tdFnCode.innerHTML = exprName(declType.expr,{
+ wantHtml: true,
+ wantLink: true,
+ fnDecl: decl,
+ linkFnNameDecl: navLinkDecl(decl.name),
+ });
- var docs = zigAnalysis.astNodes[decl.src].docs;
+ let docs = zigAnalysis.astNodes[decl.src].docs;
if (docs != null) {
tdDesc.innerHTML = shortDescMarkdown(docs);
} else {
tdDesc.textContent = "";
}
}
- domListFns.innerHTML = "";
- domListFns.appendChild(domListFnsFragment);
domSectFns.classList.remove("hidden");
}
- if (container.fields != null && container.fields.length !== 0) {
- var domListFieldsFragment = createDomListFragment(container.fields.length, '<div></div>');
+ let containerNode = zigAnalysis.astNodes[container.src];
+ if (containerNode.fields && containerNode.fields.length > 0) {
+ resizeDomList(domListFields, containerNode.fields.length, '<div></div>');
- var containerNode = zigAnalysis.astNodes[container.src];
- for (var i = 0; i < container.fields.length; i += 1) {
- var field = container.fields[i];
- var fieldNode = zigAnalysis.astNodes[containerNode.fields[i]];
- var divDom = domListFieldsFragment.children[i];
+ for (let i = 0; i < containerNode.fields.length; i += 1) {
+ let fieldNode = zigAnalysis.astNodes[containerNode.fields[i]];
+ let divDom = domListFields.children[i];
+ let fieldName = (fieldNode.name);
- var html = '<div class="mobile-scroll-container"><pre class="scroll-item">' + escapeHtml(fieldNode.name);
+ let html = '<div class="mobile-scroll-container"><pre class="scroll-item">' + escapeHtml(fieldName);
if (container.kind === typeKinds.Enum) {
- html += ' = <span class="tok-number">' + field + '</span>';
+ html += ' = <span class="tok-number">' + fieldName + '</span>';
} else {
+ let fieldTypeExpr = container.fields[i];
html += ": ";
- if (typeof(field) === 'object') {
- html += '<span class="tok-kw">var</span>';
- } else {
- html += typeIndexName(field, true, true);
+ let name = exprName(fieldTypeExpr, false, false);
+ html += '<span class="tok-kw">'+ name +'</span>';
+ let tsn = typeShorthandName(fieldTypeExpr);
+ if (tsn) {
+ html += '<span> ('+ tsn +')</span>';
+
}
}
html += ',</pre></div>';
- var docs = fieldNode.docs;
+ let docs = fieldNode.docs;
if (docs != null) {
html += markdown(docs);
}
divDom.innerHTML = html;
}
- domListFields.innerHTML = "";
- domListFields.appendChild(domListFieldsFragment);
domSectFields.classList.remove("hidden");
}
if (varsList.length !== 0) {
- var domListGlobalVarsFragment = createDomListFragment(varsList.length,
+ resizeDomList(domListGlobalVars, varsList.length,
'<tr><td><a href="#"></a></td><td></td><td></td></tr>');
- for (var i = 0; i < varsList.length; i += 1) {
- var decl = varsList[i];
- var trDom = domListGlobalVarsFragment.children[i];
+ for (let i = 0; i < varsList.length; i += 1) {
+ let decl = varsList[i];
+ let trDom = domListGlobalVars.children[i];
- var tdName = trDom.children[0];
- var tdNameA = tdName.children[0];
- var tdType = trDom.children[1];
- var tdDesc = trDom.children[2];
+ let tdName = trDom.children[0];
+ let tdNameA = tdName.children[0];
+ let tdType = trDom.children[1];
+ let tdDesc = trDom.children[2];
tdNameA.setAttribute('href', navLinkDecl(decl.name));
tdNameA.textContent = decl.name;
- tdType.innerHTML = typeIndexName(decl.type, true, true);
+ tdType.innerHTML = typeValueName(typeOfDecl(decl), true, true);
- var docs = zigAnalysis.astNodes[decl.src].docs;
+ let docs = zigAnalysis.astNodes[decl.src].docs;
if (docs != null) {
tdDesc.innerHTML = shortDescMarkdown(docs);
} else {
tdDesc.textContent = "";
}
}
- domListGlobalVars.innerHTML = "";
- domListGlobalVars.appendChild(domListGlobalVarsFragment);
domSectGlobalVars.classList.remove("hidden");
}
if (valsList.length !== 0) {
- var domListValuesFragment = createDomListFragment(valsList.length,
+ resizeDomList(domListValues, valsList.length,
'<tr><td><a href="#"></a></td><td></td><td></td></tr>');
- for (var i = 0; i < valsList.length; i += 1) {
- var decl = valsList[i];
- var trDom = domListValuesFragment.children[i];
+ for (let i = 0; i < valsList.length; i += 1) {
+ let decl = valsList[i];
+ let trDom = domListValues.children[i];
- var tdName = trDom.children[0];
- var tdNameA = tdName.children[0];
- var tdType = trDom.children[1];
- var tdDesc = trDom.children[2];
+ let tdName = trDom.children[0];
+ let tdNameA = tdName.children[0];
+ let tdType = trDom.children[1];
+ let tdDesc = trDom.children[2];
tdNameA.setAttribute('href', navLinkDecl(decl.name));
tdNameA.textContent = decl.name;
- tdType.innerHTML = typeIndexName(decl.type, true, true);
+ tdType.innerHTML = exprName(walkResultTypeRef(decl.value),
+ {wantHtml:true, wantLink:true});
- var docs = zigAnalysis.astNodes[decl.src].docs;
+ let docs = zigAnalysis.astNodes[decl.src].docs;
if (docs != null) {
tdDesc.innerHTML = shortDescMarkdown(docs);
} else {
tdDesc.textContent = "";
}
}
- domListValues.innerHTML = "";
- domListValues.appendChild(domListValuesFragment);
domSectValues.classList.remove("hidden");
}
+
+ if (testsList.length !== 0) {
+ resizeDomList(domListTests, testsList.length,
+ '<tr><td><a href="#"></a></td><td></td><td></td></tr>');
+ for (let i = 0; i < testsList.length; i += 1) {
+ let decl = testsList[i];
+ let trDom = domListTests.children[i];
+
+ let tdName = trDom.children[0];
+ let tdNameA = tdName.children[0];
+ let tdType = trDom.children[1];
+ let tdDesc = trDom.children[2];
+
+ tdNameA.setAttribute('href', navLinkDecl(decl.name));
+ tdNameA.textContent = decl.name;
+
+ tdType.innerHTML = exprName(walkResultTypeRef(decl.value),
+ {wantHtml:true, wantLink:true});
+
+ let docs = zigAnalysis.astNodes[decl.src].docs;
+ if (docs != null) {
+ tdDesc.innerHTML = shortDescMarkdown(docs);
+ } else {
+ tdDesc.textContent = "";
+ }
+ }
+ domSectTests.classList.remove("hidden");
+ }
}
+
+
function operatorCompare(a, b) {
if (a === b) {
return 0;
@@ -1162,33 +2395,33 @@
}
function detectRootIsStd() {
- var rootPkg = zigAnalysis.packages[zigAnalysis.rootPkg];
+ let rootPkg = zigAnalysis.packages[zigAnalysis.rootPkg];
if (rootPkg.table["std"] == null) {
// no std mapped into the root package
return false;
}
- var stdPkg = zigAnalysis.packages[rootPkg.table["std"]];
+ let stdPkg = zigAnalysis.packages[rootPkg.table["std"]];
if (stdPkg == null) return false;
return rootPkg.file === stdPkg.file;
}
function indexTypeKinds() {
- var map = {};
- for (var i = 0; i < zigAnalysis.typeKinds.length; i += 1) {
+ let map = ({});
+ for (let i = 0; i < zigAnalysis.typeKinds.length; i += 1) {
map[zigAnalysis.typeKinds[i]] = i;
}
// This is just for debugging purposes, not needed to function
- var assertList = ["Type","Void","Bool","NoReturn","Int","Float","Pointer","Array","Struct",
+ let assertList = ["Type","Void","Bool","NoReturn","Int","Float","Pointer","Array","Struct",
"ComptimeFloat","ComptimeInt","Undefined","Null","Optional","ErrorUnion","ErrorSet","Enum",
"Union","Fn","BoundFn","Opaque","Frame","AnyFrame","Vector","EnumLiteral"];
- for (var i = 0; i < assertList.length; i += 1) {
+ for (let i = 0; i < assertList.length; i += 1) {
if (map[assertList[i]] == null) throw new Error("No type kind '" + assertList[i] + "' found");
}
return map;
}
function findTypeTypeId() {
- for (var i = 0; i < zigAnalysis.types.length; i += 1) {
+ for (let i = 0; i < zigAnalysis.types.length; i += 1) {
if (zigAnalysis.types[i].kind == typeKinds.Type) {
return i;
}
@@ -1197,17 +2430,26 @@
}
function updateCurNav() {
+
curNav = {
+ showPrivDecls: false,
pkgNames: [],
pkgObjs: [],
declNames: [],
declObjs: [],
+ callName: null,
};
curNavSearch = "";
if (location.hash[0] === '#' && location.hash.length > 1) {
- var query = location.hash.substring(1);
- var qpos = query.indexOf("?");
+ let query = location.hash.substring(1);
+ if (query[0] === '*') {
+ curNav.showPrivDecls = true;
+ query = query.substring(1);
+ }
+
+ let qpos = query.indexOf("?");
+ let nonSearchPart;
if (qpos === -1) {
nonSearchPart = query;
} else {
@@ -1215,16 +2457,12 @@
curNavSearch = decodeURIComponent(query.substring(qpos + 1));
}
- var parts = nonSearchPart.split(";");
+ let parts = nonSearchPart.split(";");
curNav.pkgNames = decodeURIComponent(parts[0]).split(".");
if (parts[1] != null) {
curNav.declNames = decodeURIComponent(parts[1]).split(".");
}
}
-
- if (curNav.pkgNames.length === 0 && rootIsStd) {
- curNav.pkgNames = ["std"];
- }
}
function onHashChange() {
@@ -1239,43 +2477,65 @@
}
}
+
function findSubDecl(parentType, childName) {
- if (parentType.pubDecls == null) throw new Error("parent object has no public decls");
- for (var i = 0; i < parentType.pubDecls.length; i += 1) {
- var declIndex = parentType.pubDecls[i];
- var childDecl = zigAnalysis.decls[declIndex];
+ {
+ // Generic functions
+ if ("value" in parentType) {
+ const rv = resolveValue(parentType.value);
+ if ("type" in rv.expr) {
+ const t = zigAnalysis.types[rv.expr.type];
+ if (t.kind == typeKinds.Fn && t.generic_ret != null) {
+ const rgr = resolveValue({expr: t.generic_ret});
+ if ("type" in rgr.expr) {
+ parentType = zigAnalysis.types[rgr.expr.type];
+ }
+ }
+ }
+ }
+ }
+
+
+ if (!parentType.pubDecls) return null;
+ for (let i = 0; i < parentType.pubDecls.length; i += 1) {
+ let declIndex = parentType.pubDecls[i];
+ let childDecl = zigAnalysis.decls[declIndex];
if (childDecl.name === childName) {
return childDecl;
}
}
- return null;
- }
-
- function getDeclContainerType(decl) {
- if (decl.type === typeTypeId) {
- return zigAnalysis.types[decl.value];
+ if (!parentType.privDecls) return null;
+ for (let i = 0; i < parentType.privDecls.length; i += 1) {
+ let declIndex = parentType.privDecls[i];
+ let childDecl = zigAnalysis.decls[declIndex];
+ if (childDecl.name === childName) {
+ return childDecl;
+ }
}
return null;
}
+
+
+
function computeCanonicalPackagePaths() {
- var list = new Array(zigAnalysis.packages.length);
+ let list = new Array(zigAnalysis.packages.length);
// Now we try to find all the packages from root.
- var rootPkg = zigAnalysis.packages[zigAnalysis.rootPkg];
+ let rootPkg = zigAnalysis.packages[zigAnalysis.rootPkg];
// Breadth-first to keep the path shortest possible.
- var stack = [{
- path: [],
+ let stack = [{
+ path: ([]),
pkg: rootPkg,
}];
while (stack.length !== 0) {
- var item = stack.shift();
- for (var key in item.pkg.table) {
- var childPkgIndex = item.pkg.table[key];
+ let item = (stack.shift());
+ for (let key in item.pkg.table) {
+ let childPkgIndex = item.pkg.table[key];
if (list[childPkgIndex] != null) continue;
- var childPkg = zigAnalysis.packages[childPkgIndex];
+ let childPkg = zigAnalysis.packages[childPkgIndex];
if (childPkg == null) continue;
- var newPath = item.path.concat([key])
+ let newPath = item.path.concat([key])
list[childPkgIndex] = newPath;
stack.push({
path: newPath,
@@ -1286,53 +2546,68 @@
return list;
}
- function typeKindIsContainer(typeKind) {
- return typeKind === typeKinds.Struct ||
- typeKind === typeKinds.Union ||
- typeKind === typeKinds.Enum;
- }
-
- function declCanRepresentTypeKind(typeKind) {
- return typeKind === typeKinds.ErrorSet || typeKindIsContainer(typeKind);
- }
+
function computeCanonDeclPaths() {
- var list = new Array(zigAnalysis.decls.length);
+ let list = new Array(zigAnalysis.decls.length);
canonTypeDecls = new Array(zigAnalysis.types.length);
- for (var pkgI = 0; pkgI < zigAnalysis.packages.length; pkgI += 1) {
+ for (let pkgI = 0; pkgI < zigAnalysis.packages.length; pkgI += 1) {
if (pkgI === zigAnalysis.rootPkg && rootIsStd) continue;
- var pkg = zigAnalysis.packages[pkgI];
- var pkgNames = canonPkgPaths[pkgI];
- var stack = [{
- declNames: [],
+ let pkg = zigAnalysis.packages[pkgI];
+ let pkgNames = canonPkgPaths[pkgI];
+ if (pkgNames === undefined) continue;
+
+ let stack = [{
+ declNames: ([]),
type: zigAnalysis.types[pkg.main],
}];
while (stack.length !== 0) {
- var item = stack.shift();
+ let item = (stack.shift());
+
+ if (isContainerType(item.type)) {
+ let t = (item.type);
- if (item.type.pubDecls != null) {
- for (var declI = 0; declI < item.type.pubDecls.length; declI += 1) {
- var mainDeclIndex = item.type.pubDecls[declI];
+ let len = t.pubDecls ? t.pubDecls.length : 0;
+ for (let declI = 0; declI < len; declI += 1) {
+ let mainDeclIndex = t.pubDecls[declI];
if (list[mainDeclIndex] != null) continue;
- var decl = zigAnalysis.decls[mainDeclIndex];
- if (decl.type === typeTypeId &&
- declCanRepresentTypeKind(zigAnalysis.types[decl.value].kind))
- {
- canonTypeDecls[decl.value] = mainDeclIndex;
- }
- var declNames = item.declNames.concat([decl.name]);
+ let decl = zigAnalysis.decls[mainDeclIndex];
+ let declVal = decl.value; //resolveValue(decl.value);
+ let declNames = item.declNames.concat([decl.name]);
list[mainDeclIndex] = {
pkgNames: pkgNames,
declNames: declNames,
};
- var containerType = getDeclContainerType(decl);
- if (containerType != null) {
- stack.push({
- declNames: declNames,
- type: containerType,
- });
+ if ("type" in declVal.expr) {
+ let value = zigAnalysis.types[declVal.expr.type];
+ if (declCanRepresentTypeKind(value.kind))
+ {
+ canonTypeDecls[declVal.type] = mainDeclIndex;
+ }
+
+ if (isContainerType(value)) {
+ stack.push({
+ declNames: declNames,
+ type:value,
+ });
+ }
+
+
+ // Generic function
+ if (value.kind == typeKinds.Fn && value.generic_ret != null) {
+ let resolvedVal = resolveValue({ expr: value.generic_ret});
+ if ("type" in resolvedVal.expr) {
+ let generic_type = zigAnalysis.types[resolvedVal.expr.type];
+ if (isContainerType(generic_type)){
+ stack.push({
+ declNames: declNames,
+ type: generic_type,
+ });
+ }
+ }
+ }
}
}
}
@@ -1341,41 +2616,49 @@
return list;
}
+
function getCanonDeclPath(index) {
if (canonDeclPaths == null) {
canonDeclPaths = computeCanonDeclPaths();
}
+ //let cd = (canonDeclPaths);
return canonDeclPaths[index];
}
+
function getCanonTypeDecl(index) {
getCanonDeclPath(0);
+ //let ct = (canonTypeDecls);
return canonTypeDecls[index];
}
+
function escapeHtml(text) {
return text.replace(/[&"<>]/g, function (m) {
return escapeHtmlReplacements[m];
});
}
+
function shortDescMarkdown(docs) {
- var parts = docs.trim().split("\n");
- var firstLine = parts[0];
+ let parts = docs.trim().split("\n");
+ let firstLine = parts[0];
return markdown(firstLine);
}
+
function markdown(input) {
const raw_lines = input.split('\n'); // zig allows no '\r', so we don't need to split on CR
+
const lines = [];
// PHASE 1:
// Dissect lines and determine the type for each line.
- // Also computes indentation level and removes unnecessary whitespace
+ // Also computes indentation level and removes unnecessary whitespace
- var is_reading_code = false;
- var code_indent = 0;
- for (var line_no = 0; line_no < raw_lines.length; line_no++) {
+ let is_reading_code = false;
+ let code_indent = 0;
+ for (let line_no = 0; line_no < raw_lines.length; line_no++) {
const raw_line = raw_lines[line_no];
const line = {
@@ -1383,6 +2666,7 @@
raw_text: raw_line,
text: raw_line.trim(),
type: "p", // p, h1 … h6, code, ul, ol, blockquote, skip, empty
+ ordered_number: -1, // NOTE: hack to make the type checker happy
};
if (!is_reading_code) {
@@ -1419,7 +2703,7 @@
line.text = line.text.substr(1);
}
else if (line.text.match(/^\d+\..*$/)) { // if line starts with {number}{dot}
- const match = line.text.match(/(\d+)\./);
+ const match = (line.text.match(/(\d+)\./));
line.type = "ul";
line.text = line.text.substr(match[0].length);
line.ordered_number = Number(match[1].length);
@@ -1450,21 +2734,24 @@
// PHASE 2:
// Render HTML from markdown lines.
- // Look at each line and emit fitting HTML code
+ // Look at each line and emit fitting HTML code
- function markdownInlines(innerText, stopChar) {
+
+ function markdownInlines(innerText) {
// inline types:
// **{INLINE}** : <strong>
- // __{INLINE}__ : <u>
- // ~~{INLINE}~~ : <s>
- // *{INLINE}* : <emph>
- // _{INLINE}_ : <emph>
- // `{TEXT}` : <code>
- // [{INLINE}]({URL}) : <a>
- //  : <img>
- // [[std;format.fmt]] : <a> (inner link)
-
+ // __{INLINE}__ : <u>
+ // ~~{INLINE}~~ : <s>
+ // *{INLINE}* : <emph>
+ // _{INLINE}_ : <emph>
+ // `{TEXT}` : <code>
+ // [{INLINE}]({URL}) : <a>
+ //  : <img>
+ // [[std;format.fmt]] : <a> (inner link)
+
+
+
const formats = [
{
marker: "**",
@@ -1484,26 +2771,11 @@
}
];
- // Links, images and inner links don't use the same marker to wrap their content.
- const linksFormat = [
- {
- prefix: "[",
- regex: /\[([^\]]*)\]\(([^\)]*)\)/,
- urlIndex: 2, // Index in the match that contains the link URL
- textIndex: 1 // Index in the match that contains the link text
- },
- {
- prefix: "h",
- regex: /http[s]?:\/\/[^\s]+/,
- urlIndex: 0,
- textIndex: 0
- }
- ];
-
+
const stack = [];
- var innerHTML = "";
- var currentRun = "";
+ let innerHTML = "";
+ let currentRun = "";
function flushRun() {
if (currentRun != "") {
@@ -1512,18 +2784,18 @@
currentRun = "";
}
- var parsing_code = false;
- var codetag = "";
- var in_code = false;
+ let parsing_code = false;
+ let codetag = "";
+ let in_code = false;
- for (var i = 0; i < innerText.length; i++) {
+ for (let i = 0; i < innerText.length; i++) {
if (parsing_code && in_code) {
if (innerText.substr(i, codetag.length) == codetag) {
// remove leading and trailing whitespace if string both starts and ends with one.
- if (currentRun[0] == " " && currentRun[currentRun.length - 1] == " ") {
- currentRun = currentRun.substr(1, currentRun.length - 2);
- }
+ if (currentRun[0] == " " && currentRun[currentRun.length - 1] == " ") {
+ currentRun = currentRun.substr(1, currentRun.length - 2);
+ }
flushRun();
i += codetag.length - 1;
in_code = false;
@@ -1550,31 +2822,8 @@
currentRun += innerText[i];
in_code = true;
} else {
- var foundMatches = false;
-
- for (var j = 0; j < linksFormat.length; j++) {
- const linkFmt = linksFormat[j];
-
- if (linkFmt.prefix == innerText[i]) {
- var remaining = innerText.substring(i);
- var matches = remaining.match(linkFmt.regex);
-
- if (matches) {
- flushRun();
- innerHTML += ' <a href="' + matches[linkFmt.urlIndex] + '">' + matches[linkFmt.textIndex] + '</a> ';
- i += matches[0].length; // Skip the fragment we just consumed
- foundMatches = true;
- break;
- }
- }
- }
-
- if (foundMatches) {
- continue;
- }
-
- var any = false;
- for (var idx = (stack.length > 0 ? -1 : 0); idx < formats.length; idx++) {
+ let any = false;
+ for (let idx = (stack.length > 0 ? -1 : 0); idx < formats.length; idx++) {
const fmt = idx >= 0 ? formats[idx] : stack[stack.length - 1];
if (innerText.substr(i, fmt.marker.length) == fmt.marker) {
flushRun();
@@ -1598,48 +2847,54 @@
flushRun();
while (stack.length > 0) {
- const fmt = stack.pop();
+ const fmt = (stack.pop());
innerHTML += "</" + fmt.tag + ">";
}
return innerHTML;
}
- var html = "";
- for (var line_no = 0; line_no < lines.length; line_no++) {
- const line = lines[line_no];
-
- function previousLineIs(type) {
- if (line_no > 0) {
- return (lines[line_no - 1].type == type);
- } else {
- return false;
- }
+
+ function previousLineIs(type, line_no) {
+ if (line_no > 0) {
+ return (lines[line_no - 1].type == type);
+ } else {
+ return false;
}
+ }
- function nextLineIs(type) {
- if (line_no < (lines.length - 1)) {
- return (lines[line_no + 1].type == type);
- } else {
- return false;
- }
+
+ function nextLineIs(type, line_no) {
+ if (line_no < (lines.length - 1)) {
+ return (lines[line_no + 1].type == type);
+ } else {
+ return false;
}
+ }
- function getPreviousLineIndent() {
- if (line_no > 0) {
- return lines[line_no - 1].indent;
- } else {
- return 0;
- }
+
+ function getPreviousLineIndent(line_no) {
+ if (line_no > 0) {
+ return lines[line_no - 1].indent;
+ } else {
+ return 0;
}
+ }
- function getNextLineIndent() {
- if (line_no < (lines.length - 1)) {
- return lines[line_no + 1].indent;
- } else {
- return 0;
- }
+
+ function getNextLineIndent(line_no) {
+ if (line_no < (lines.length - 1)) {
+ return lines[line_no + 1].indent;
+ } else {
+ return 0;
}
+ }
+
+ let html = "";
+ for (let line_no = 0; line_no < lines.length; line_no++) {
+ const line = lines[line_no];
+
+
switch (line.type) {
case "h1":
@@ -1653,33 +2908,33 @@
case "ul":
case "ol":
- if (!previousLineIs("ul") || getPreviousLineIndent() < line.indent) {
+ if (!previousLineIs("ul", line_no) || getPreviousLineIndent(line_no) < line.indent) {
html += "<" + line.type + ">\n";
}
html += "<li>" + markdownInlines(line.text) + "</li>\n";
- if (!nextLineIs("ul") || getNextLineIndent() < line.indent) {
+ if (!nextLineIs("ul", line_no) || getNextLineIndent(line_no) < line.indent) {
html += "</" + line.type + ">\n";
}
break;
case "p":
- if (!previousLineIs("p")) {
+ if (!previousLineIs("p", line_no)) {
html += "<p>\n";
}
html += markdownInlines(line.text) + "\n";
- if (!nextLineIs("p")) {
+ if (!nextLineIs("p", line_no)) {
html += "</p>\n";
}
break;
case "code":
- if (!previousLineIs("code")) {
+ if (!previousLineIs("code", line_no)) {
html += "<pre><code>";
}
html += escapeHtml(line.text) + "\n";
- if (!nextLineIs("code")) {
+ if (!nextLineIs("code", line_no)) {
html += "</code></pre>\n";
}
break;
@@ -1694,26 +2949,27 @@
return;
}
- var liDom = domListSearchResults.children[curSearchIndex];
+ let liDom = domListSearchResults.children[curSearchIndex];
if (liDom == null && domListSearchResults.children.length !== 0) {
liDom = domListSearchResults.children[0];
}
if (liDom != null) {
- var aDom = liDom.children[0];
- location.href = aDom.getAttribute("href");
+ let aDom = liDom.children[0];
+ location.href = (aDom.getAttribute("href"));
curSearchIndex = -1;
}
domSearch.blur();
}
+
function onSearchKeyDown(ev) {
switch (getKeyString(ev)) {
case "Enter":
// detect if this search changes anything
- var terms1 = getSearchTerms();
+ let terms1 = getSearchTerms();
startSearch();
updateCurNav();
- var terms2 = getSearchTerms();
+ let terms2 = getSearchTerms();
// we might have to wait for onHashChange to trigger
imFeelingLucky = (terms1.join(' ') !== terms2.join(' '));
if (!imFeelingLucky) activateSelectedResult();
@@ -1749,6 +3005,8 @@
}
}
+
+
function moveSearchCursor(dir) {
if (curSearchIndex < 0 || curSearchIndex >= domListSearchResults.children.length) {
if (dir > 0) {
@@ -1768,9 +3026,10 @@
renderSearchCursor();
}
+
function getKeyString(ev) {
- var name;
- var ignoreShift = false;
+ let name;
+ let ignoreShift = false;
switch (ev.which) {
case 13:
name = "Enter";
@@ -1794,6 +3053,7 @@
return name;
}
+
function onWindowKeyDown(ev) {
switch (getKeyString(ev)) {
case "Esc":
@@ -1811,214 +3071,160 @@
startAsyncSearch();
break;
case "?":
- ev.preventDefault();
+ ev.preventDefault();
ev.stopPropagation();
showHelpModal();
break;
}
}
- function showHelpModal() {
- domHelpModal.classList.remove("hidden");
- domHelpModal.style.left = (window.innerWidth / 2 - domHelpModal.clientWidth / 2) + "px";
- domHelpModal.style.top = (window.innerHeight / 2 - domHelpModal.clientHeight / 2) + "px";
- domHelpModal.focus();
- }
-
- function onClickSearchShowAllResults(ev) {
- ev.preventDefault();
- ev.stopPropagation();
- searchTrimResults = false;
- onHashChange();
- }
-
- function clearAsyncSearch() {
- if (searchTimer != null) {
- clearTimeout(searchTimer);
- searchTimer = null;
- }
- }
-
- function startAsyncSearch() {
- clearAsyncSearch();
- searchTrimResults = true;
- searchTimer = setTimeout(startSearch, 10);
- }
- function startSearch() {
- clearAsyncSearch();
- var oldHash = location.hash;
- var parts = oldHash.split("?");
- var newPart2 = (domSearch.value === "") ? "" : ("?" + domSearch.value);
- var newHash = (oldHash === "" ? "#" : parts[0]) + newPart2;
- // create a history entry only once per search
- if (parts.length === 1) {
- location.assign(newHash);
- } else {
- location.replace(newHash);
- }
- }
- function getSearchTerms() {
- var list = curNavSearch.trim().split(/[ \r\n\t]+/);
- list.sort();
- return list;
- }
- function renderSearch() {
- var matchedItems = [];
- var ignoreCase = (curNavSearch.toLowerCase() === curNavSearch);
- var terms = getSearchTerms();
-
- decl_loop: for (var declIndex = 0; declIndex < zigAnalysis.decls.length; declIndex += 1) {
- var canonPath = getCanonDeclPath(declIndex);
- if (canonPath == null) continue;
-
- var decl = zigAnalysis.decls[declIndex];
- var lastPkgName = canonPath.pkgNames[canonPath.pkgNames.length - 1];
- var fullPathSearchText = lastPkgName + "." + canonPath.declNames.join('.');
- var astNode = zigAnalysis.astNodes[decl.src];
- var fileAndDocs = zigAnalysis.files[astNode.file];
- if (astNode.docs != null) {
- fileAndDocs += "\n" + astNode.docs;
- }
- var fullPathSearchTextLower = fullPathSearchText;
- if (ignoreCase) {
- fullPathSearchTextLower = fullPathSearchTextLower.toLowerCase();
- fileAndDocs = fileAndDocs.toLowerCase();
- }
-
- var points = 0;
- for (var termIndex = 0; termIndex < terms.length; termIndex += 1) {
- var term = terms[termIndex];
-
- // exact, case sensitive match of full decl path
- if (fullPathSearchText === term) {
- points += 4;
- continue;
- }
- // exact, case sensitive match of just decl name
- if (decl.name == term) {
- points += 3;
- continue;
- }
- // substring, case insensitive match of full decl path
- if (fullPathSearchTextLower.indexOf(term) >= 0) {
- points += 2;
- continue;
- }
- if (fileAndDocs.indexOf(term) >= 0) {
- points += 1;
- continue;
- }
-
- continue decl_loop;
+function showHelpModal() {
+ domHelpModal.classList.remove("hidden");
+ domHelpModal.style.left = (window.innerWidth / 2 - domHelpModal.clientWidth / 2) + "px";
+ domHelpModal.style.top = (window.innerHeight / 2 - domHelpModal.clientHeight / 2) + "px";
+ domHelpModal.focus();
+}
+
+function clearAsyncSearch() {
+ if (searchTimer != null) {
+ clearTimeout(searchTimer);
+ searchTimer = null;
+ }
+}
+
+function startAsyncSearch() {
+ clearAsyncSearch();
+ searchTimer = setTimeout(startSearch, 100);
+}
+function startSearch() {
+ clearAsyncSearch();
+ let oldHash = location.hash;
+ let parts = oldHash.split("?");
+ let newPart2 = (domSearch.value === "") ? "" : ("?" + domSearch.value);
+ location.hash = (parts.length === 1) ? (oldHash + newPart2) : (parts[0] + newPart2);
+}
+function getSearchTerms() {
+ let list = curNavSearch.trim().split(/[ \r\n\t]+/);
+ list.sort();
+ return list;
+}
+function renderSearch() {
+ let matchedItems = [];
+ let ignoreCase = (curNavSearch.toLowerCase() === curNavSearch);
+ let terms = getSearchTerms();
+
+ decl_loop: for (let declIndex = 0; declIndex < zigAnalysis.decls.length; declIndex += 1) {
+ let canonPath = getCanonDeclPath(declIndex);
+ if (canonPath == null) continue;
+
+ let decl = zigAnalysis.decls[declIndex];
+ let lastPkgName = canonPath.pkgNames[canonPath.pkgNames.length - 1];
+ let fullPathSearchText = lastPkgName + "." + canonPath.declNames.join('.');
+ let astNode = zigAnalysis.astNodes[decl.src];
+ let fileAndDocs = "" //zigAnalysis.files[astNode.file];
+ // TODO: understand what this piece of code is trying to achieve
+ // also right now `files` are expressed as a hashmap.
+ if (astNode.docs != null) {
+ fileAndDocs += "\n" + astNode.docs;
+ }
+ let fullPathSearchTextLower = fullPathSearchText;
+ if (ignoreCase) {
+ fullPathSearchTextLower = fullPathSearchTextLower.toLowerCase();
+ fileAndDocs = fileAndDocs.toLowerCase();
+ }
+
+ let points = 0;
+ for (let termIndex = 0; termIndex < terms.length; termIndex += 1) {
+ let term = terms[termIndex];
+
+ // exact, case sensitive match of full decl path
+ if (fullPathSearchText === term) {
+ points += 4;
+ continue;
+ }
+ // exact, case sensitive match of just decl name
+ if (decl.name == term) {
+ points += 3;
+ continue;
+ }
+ // substring, case insensitive match of full decl path
+ if (fullPathSearchTextLower.indexOf(term) >= 0) {
+ points += 2;
+ continue;
+ }
+ if (fileAndDocs.indexOf(term) >= 0) {
+ points += 1;
+ continue;
}
- matchedItems.push({
- decl: decl,
- path: canonPath,
- points: points,
- });
+ continue decl_loop;
}
- if (matchedItems.length !== 0) {
- matchedItems.sort(function(a, b) {
- var cmp = operatorCompare(b.points, a.points);
- if (cmp != 0) return cmp;
- return operatorCompare(a.decl.name, b.decl.name);
- });
+ matchedItems.push({
+ decl: decl,
+ path: canonPath,
+ points: points,
+ });
+ }
- var searchTrimmed = false
- var searchTrimResultsMaxItems = 200
- if (searchTrimResults && matchedItems.length > searchTrimResultsMaxItems) {
- matchedItems = matchedItems.slice(0, searchTrimResultsMaxItems)
- searchTrimmed = true
- }
+ if (matchedItems.length !== 0) {
+ resizeDomList(domListSearchResults, matchedItems.length, '<li><a href="#"></a></li>');
- var domListSearchResultsFragment = createDomListFragment(matchedItems.length, '<li><a href="#"></a></li>');
- for (var i = 0; i < matchedItems.length; i += 1) {
- var liDom = domListSearchResultsFragment.children[i];
- var aDom = liDom.children[0];
- var match = matchedItems[i];
- var lastPkgName = match.path.pkgNames[match.path.pkgNames.length - 1];
- aDom.textContent = lastPkgName + "." + match.path.declNames.join('.');
- aDom.setAttribute('href', navLink(match.path.pkgNames, match.path.declNames));
- }
+ matchedItems.sort(function(a, b) {
+ let cmp = operatorCompare(b.points, a.points);
+ if (cmp != 0) return cmp;
+ return operatorCompare(a.decl.name, b.decl.name);
+ });
- domListSearchResults.innerHTML = "";
- domListSearchResults.appendChild(domListSearchResultsFragment);
- domSectSearchResults.classList.remove("hidden");
+ for (let i = 0; i < matchedItems.length; i += 1) {
+ let liDom = domListSearchResults.children[i];
+ let aDom = liDom.children[0];
+ let match = matchedItems[i];
+ let lastPkgName = match.path.pkgNames[match.path.pkgNames.length - 1];
+ aDom.textContent = lastPkgName + "." + match.path.declNames.join('.');
+ aDom.setAttribute('href', navLink(match.path.pkgNames, match.path.declNames));
+ }
+ renderSearchCursor();
- if (searchTrimmed) {
- domSectSearchAllResultsLink.classList.remove("hidden");
- }
+ domSectSearchResults.classList.remove("hidden");
+ } else {
+ domSectSearchNoResults.classList.remove("hidden");
+ }
+}
- renderSearchCursor();
+function renderSearchCursor() {
+ for (let i = 0; i < domListSearchResults.children.length; i += 1) {
+ let liDom = (domListSearchResults.children[i]);
+ if (curSearchIndex === i) {
+ liDom.classList.add("selected");
} else {
- domSectSearchNoResults.classList.remove("hidden");
+ liDom.classList.remove("selected");
}
}
+}
- function renderSearchCursor() {
- for (var i = 0; i < domListSearchResults.children.length; i += 1) {
- var liDom = domListSearchResults.children[i];
- if (curSearchIndex === i) {
- liDom.classList.add("selected");
- } else {
- liDom.classList.remove("selected");
- }
- }
- }
- function indexNodesToFns() {
- var map = {};
- for (var i = 0; i < zigAnalysis.fns.length; i += 1) {
- var fn = zigAnalysis.fns[i];
- if (typeIsGenericFn(fn.type)) continue;
- if (map[fn.src] == null) {
- map[fn.src] = [i];
- } else {
- map[fn.src].push(i);
- }
- }
- return map;
- }
- function indexNodesToCalls() {
- var map = {};
- for (var i = 0; i < zigAnalysis.calls.length; i += 1) {
- var call = zigAnalysis.calls[i];
- var fn = zigAnalysis.fns[call.fn];
- if (map[fn.src] == null) {
- map[fn.src] = [i];
- } else {
- map[fn.src].push(i);
- }
- }
- return map;
- }
+// function indexNodesToCalls() {
+// let map = {};
+// for (let i = 0; i < zigAnalysis.calls.length; i += 1) {
+// let call = zigAnalysis.calls[i];
+// let fn = zigAnalysis.fns[call.fn];
+// if (map[fn.src] == null) {
+// map[fn.src] = [i];
+// } else {
+// map[fn.src].push(i);
+// }
+// }
+// return map;
+// }
- function byNameProperty(a, b) {
- return operatorCompare(a.name, b.name);
- }
- function clone(obj) {
- var res = {};
- for (var key in obj) {
- res[key] = obj[key];
- }
- return res;
- }
- function firstObjectKey(obj) {
- for (var key in obj) {
- return key;
- }
- }
+function byNameProperty(a, b) {
+ return operatorCompare(a.name, b.name);
+}
+
+
- function token(value, tokenClass, wantHtml){
- if(wantHtml){
- return '<span class="' + tokenClass + '">' + value + '</span>';
- } else {
- return value + '';
- }
- }
})();
diff --git a/src/Autodoc.zig b/src/Autodoc.zig
@@ -0,0 +1,3890 @@
+const std = @import("std");
+const build_options = @import("build_options");
+const Autodoc = @This();
+const Compilation = @import("Compilation.zig");
+const Module = @import("Module.zig");
+const File = Module.File;
+const Package = @import("Package.zig");
+const Zir = @import("Zir.zig");
+const Ref = Zir.Inst.Ref;
+const log = std.log.scoped(.autodoc);
+
+module: *Module,
+doc_location: Compilation.EmitLoc,
+arena: std.mem.Allocator,
+
+// The goal of autodoc is to fill up these arrays
+// that will then be serialized as JSON and consumed
+// by the JS frontend.
+packages: std.AutoArrayHashMapUnmanaged(*Package, DocData.DocPackage) = .{},
+files: std.AutoArrayHashMapUnmanaged(*File, usize) = .{},
+calls: std.ArrayListUnmanaged(DocData.Call) = .{},
+types: std.ArrayListUnmanaged(DocData.Type) = .{},
+decls: std.ArrayListUnmanaged(DocData.Decl) = .{},
+exprs: std.ArrayListUnmanaged(DocData.Expr) = .{},
+ast_nodes: std.ArrayListUnmanaged(DocData.AstNode) = .{},
+comptime_exprs: std.ArrayListUnmanaged(DocData.ComptimeExpr) = .{},
+
+// These fields hold temporary state of the analysis process
+// and are mainly used by the decl path resolving algorithm.
+pending_ref_paths: std.AutoHashMapUnmanaged(
+ *DocData.Expr, // pointer to declpath tail end (ie `&decl_path[decl_path.len - 1]`)
+ std.ArrayListUnmanaged(RefPathResumeInfo),
+) = .{},
+ref_paths_pending_on_decls: std.AutoHashMapUnmanaged(
+ usize,
+ std.ArrayListUnmanaged(RefPathResumeInfo),
+) = .{},
+ref_paths_pending_on_types: std.AutoHashMapUnmanaged(
+ usize,
+ std.ArrayListUnmanaged(RefPathResumeInfo),
+) = .{},
+
+const RefPathResumeInfo = struct {
+ file: *File,
+ ref_path: []DocData.Expr,
+};
+
+var arena_allocator: std.heap.ArenaAllocator = undefined;
+pub fn init(m: *Module, doc_location: Compilation.EmitLoc) Autodoc {
+ arena_allocator = std.heap.ArenaAllocator.init(m.gpa);
+ return .{
+ .module = m,
+ .doc_location = doc_location,
+ .arena = arena_allocator.allocator(),
+ };
+}
+
+pub fn deinit(_: *Autodoc) void {
+ arena_allocator.deinit();
+}
+
+/// The entry point of the Autodoc generation process.
+pub fn generateZirData(self: *Autodoc) !void {
+ if (self.doc_location.directory) |dir| {
+ if (dir.path) |path| {
+ log.debug("path: {s}", .{path});
+ }
+ }
+
+ const root_src_dir = self.module.main_pkg.root_src_directory;
+ const root_src_path = self.module.main_pkg.root_src_path;
+ const joined_src_path = try root_src_dir.join(self.arena, &.{root_src_path});
+ defer self.arena.free(joined_src_path);
+
+ const abs_root_src_path = try std.fs.path.resolve(self.arena, &.{ ".", joined_src_path });
+ defer self.arena.free(abs_root_src_path);
+
+ const file = self.module.import_table.get(abs_root_src_path).?; // file is expected to be present in the import table
+ // Append all the types in Zir.Inst.Ref.
+ {
+ try self.types.append(self.arena, .{
+ .ComptimeExpr = .{ .name = "ComptimeExpr" },
+ });
+
+ // this skipts Ref.none but it's ok becuse we replaced it with ComptimeExpr
+ var i: u32 = 1;
+ while (i <= @enumToInt(Ref.anyerror_void_error_union_type)) : (i += 1) {
+ var tmpbuf = std.ArrayList(u8).init(self.arena);
+ try Ref.typed_value_map[i].val.fmtDebug().format("", .{}, tmpbuf.writer());
+ try self.types.append(
+ self.arena,
+ switch (@intToEnum(Ref, i)) {
+ else => blk: {
+ // TODO: map the remaining refs to a correct type
+ // instead of just assinging "array" to them.
+ break :blk .{
+ .Array = .{
+ .len = .{
+ .int = .{
+ .value = 1,
+ .negated = false,
+ },
+ },
+ .child = .{ .type = 0 },
+ },
+ };
+ },
+ .u1_type,
+ .u8_type,
+ .i8_type,
+ .u16_type,
+ .i16_type,
+ .u32_type,
+ .i32_type,
+ .u64_type,
+ .i64_type,
+ .u128_type,
+ .i128_type,
+ .usize_type,
+ .isize_type,
+ .c_short_type,
+ .c_ushort_type,
+ .c_int_type,
+ .c_uint_type,
+ .c_long_type,
+ .c_ulong_type,
+ .c_longlong_type,
+ .c_ulonglong_type,
+ .c_longdouble_type,
+ => .{
+ .Int = .{ .name = tmpbuf.toOwnedSlice() },
+ },
+ .f16_type,
+ .f32_type,
+ .f64_type,
+ .f128_type,
+ => .{
+ .Float = .{ .name = tmpbuf.toOwnedSlice() },
+ },
+ .comptime_int_type => .{
+ .ComptimeInt = .{ .name = tmpbuf.toOwnedSlice() },
+ },
+ .comptime_float_type => .{
+ .ComptimeFloat = .{ .name = tmpbuf.toOwnedSlice() },
+ },
+
+ .anyopaque_type => .{
+ .ComptimeExpr = .{ .name = tmpbuf.toOwnedSlice() },
+ },
+ .bool_type => .{
+ .Bool = .{ .name = tmpbuf.toOwnedSlice() },
+ },
+
+ .noreturn_type => .{
+ .NoReturn = .{ .name = tmpbuf.toOwnedSlice() },
+ },
+ .void_type => .{
+ .Void = .{ .name = tmpbuf.toOwnedSlice() },
+ },
+ .type_type => .{
+ .Type = .{ .name = tmpbuf.toOwnedSlice() },
+ },
+ .anyerror_type => .{
+ .ErrorSet = .{ .name = tmpbuf.toOwnedSlice() },
+ },
+ .calling_convention_inline, .calling_convention_c, .calling_convention_type => .{
+ .EnumLiteral = .{ .name = tmpbuf.toOwnedSlice() },
+ },
+ },
+ );
+ }
+ }
+
+ const main_type_index = self.types.items.len;
+ {
+ try self.packages.put(self.arena, self.module.main_pkg, .{
+ .name = "root",
+ .main = main_type_index,
+ .table = .{},
+ });
+ try self.packages.entries.items(.value)[0].table.put(
+ self.arena,
+ self.module.main_pkg,
+ .{
+ .name = "root",
+ .value = 0,
+ },
+ );
+ }
+
+ var root_scope = Scope{ .parent = null, .enclosing_type = main_type_index };
+ try self.ast_nodes.append(self.arena, .{ .name = "(root)" });
+ try self.files.put(self.arena, file, main_type_index);
+ _ = try self.walkInstruction(file, &root_scope, Zir.main_struct_inst, false);
+
+ if (self.ref_paths_pending_on_decls.count() > 0) {
+ @panic("some decl paths were never fully analized (pending on decls)");
+ }
+
+ if (self.ref_paths_pending_on_types.count() > 0) {
+ @panic("some decl paths were never fully analized (pending on types)");
+ }
+
+ if (self.pending_ref_paths.count() > 0) {
+ @panic("some decl paths were never fully analized");
+ }
+
+ const rootName = blk: {
+ const rootName = std.fs.path.basename(self.module.main_pkg.root_src_path);
+ break :blk rootName[0 .. rootName.len - 4];
+ };
+ var data = DocData{
+ .rootPkgName = rootName,
+ .params = .{ .rootName = "root" },
+ .packages = self.packages.values(),
+ .files = self.files,
+ .calls = self.calls.items,
+ .types = self.types.items,
+ .decls = self.decls.items,
+ .exprs = self.exprs.items,
+ .astNodes = self.ast_nodes.items,
+ .comptimeExprs = self.comptime_exprs.items,
+ };
+
+ if (self.doc_location.directory) |d| {
+ d.handle.makeDir(
+ self.doc_location.basename,
+ ) catch |e| switch (e) {
+ error.PathAlreadyExists => {},
+ else => |err| return err,
+ };
+ } else {
+ self.module.zig_cache_artifact_directory.handle.makeDir(
+ self.doc_location.basename,
+ ) catch |e| switch (e) {
+ error.PathAlreadyExists => {},
+ else => |err| return err,
+ };
+ }
+ const output_dir = if (self.doc_location.directory) |d|
+ try d.handle.openDir(self.doc_location.basename, .{})
+ else
+ try self.module.zig_cache_artifact_directory.handle.openDir(self.doc_location.basename, .{});
+ {
+ const data_js_f = try output_dir.createFile("data.js", .{});
+ defer data_js_f.close();
+ var buffer = std.io.bufferedWriter(data_js_f.writer());
+
+ const out = buffer.writer();
+ try out.print(
+ \\ /** @type {{DocData}} */
+ \\ var zigAnalysis=
+ , .{});
+ try std.json.stringify(
+ data,
+ .{
+ .whitespace = .{},
+ .emit_null_optional_fields = false,
+ },
+ out,
+ );
+ try out.print(";", .{});
+
+ // last thing (that can fail) that we do is flush
+ try buffer.flush();
+ }
+
+ // copy main.js, index.html
+ var docs_dir = try self.module.comp.zig_lib_directory.handle.openDir("docs", .{});
+ defer docs_dir.close();
+ try docs_dir.copyFile("main.js", output_dir, "main.js", .{});
+ try docs_dir.copyFile("index.html", output_dir, "index.html", .{});
+}
+
+/// Represents a chain of scopes, used to resolve decl references to the
+/// corresponding entry in `self.decls`.
+const Scope = struct {
+ parent: ?*Scope,
+ map: std.AutoHashMapUnmanaged(u32, usize) = .{}, // index into `decls`
+ enclosing_type: usize, // index into `types`
+
+ /// Assumes all decls in present scope and upper scopes have already
+ /// been either fully resolved or at least reserved.
+ pub fn resolveDeclName(self: Scope, string_table_idx: u32) usize {
+ var cur: ?*const Scope = &self;
+ return while (cur) |s| : (cur = s.parent) {
+ break s.map.get(string_table_idx) orelse continue;
+ } else unreachable;
+ }
+
+ pub fn insertDeclRef(
+ self: *Scope,
+ arena: std.mem.Allocator,
+ decl_name_index: u32, // decl name
+ decls_slot_index: usize,
+ ) !void {
+ try self.map.put(arena, decl_name_index, decls_slot_index);
+ }
+};
+
+/// The output of our analysis process.
+const DocData = struct {
+ typeKinds: []const []const u8 = std.meta.fieldNames(DocTypeKinds),
+ rootPkg: u32 = 0,
+ rootPkgName: []const u8,
+ params: struct {
+ zigId: []const u8 = "arst",
+ zigVersion: []const u8 = build_options.version,
+ target: []const u8 = "arst",
+ rootName: []const u8,
+ builds: []const struct { target: []const u8 } = &.{
+ .{ .target = "arst" },
+ },
+ },
+ packages: []const DocPackage,
+ errors: []struct {} = &.{},
+
+ // non-hardcoded stuff
+ astNodes: []AstNode,
+ calls: []Call,
+ files: std.AutoArrayHashMapUnmanaged(*File, usize),
+ types: []Type,
+ decls: []Decl,
+ exprs: []Expr,
+ comptimeExprs: []ComptimeExpr,
+ const Call = struct {
+ func: Expr,
+ args: []Expr,
+ ret: Expr,
+ };
+
+ pub fn jsonStringify(
+ self: DocData,
+ opts: std.json.StringifyOptions,
+ w: anytype,
+ ) !void {
+ var jsw = std.json.writeStream(w, 15);
+ try jsw.beginObject();
+ inline for (comptime std.meta.tags(std.meta.FieldEnum(DocData))) |f| {
+ const f_name = @tagName(f);
+ try jsw.objectField(f_name);
+ switch (f) {
+ .files => try writeFileTableToJson(self.files, &jsw),
+ else => {
+ try std.json.stringify(@field(self, f_name), opts, w);
+ jsw.state_index -= 1;
+ },
+ }
+ }
+ try jsw.endObject();
+ }
+ /// All the type "families" as described by `std.builtin.TypeId`
+ /// plus a couple extra that are unique to our use case.
+ ///
+ /// `Unanalyzed` is used so that we can refer to types that have started
+ /// analysis but that haven't been fully analyzed yet (in case we find
+ /// self-referential stuff, like `@This()`).
+ ///
+ /// `ComptimeExpr` represents the result of a piece of comptime logic
+ /// that we weren't able to analyze fully. Examples of that are comptime
+ /// function calls and comptime if / switch / ... expressions.
+ const DocTypeKinds = @typeInfo(Type).Union.tag_type.?;
+
+ const ComptimeExpr = struct {
+ code: []const u8,
+ };
+ const DocPackage = struct {
+ name: []const u8 = "(root)",
+ file: usize = 0, // index into `files`
+ main: usize = 0, // index into `types`
+ table: std.AutoHashMapUnmanaged(*Package, TableEntry),
+ pub const TableEntry = struct {
+ name: []const u8,
+ value: usize,
+ };
+
+ pub fn jsonStringify(
+ self: DocPackage,
+ opts: std.json.StringifyOptions,
+ w: anytype,
+ ) !void {
+ var jsw = std.json.writeStream(w, 15);
+ try jsw.beginObject();
+ inline for (comptime std.meta.tags(std.meta.FieldEnum(DocPackage))) |f| {
+ const f_name = @tagName(f);
+ try jsw.objectField(f_name);
+ switch (f) {
+ .table => try writePackageTableToJson(self.table, &jsw),
+ else => {
+ try std.json.stringify(@field(self, f_name), opts, w);
+ jsw.state_index -= 1;
+ },
+ }
+ }
+ try jsw.endObject();
+ }
+ };
+
+ const Decl = struct {
+ name: []const u8,
+ kind: []const u8,
+ isTest: bool,
+ src: usize, // index into astNodes
+ value: WalkResult,
+ // The index in astNodes of the `test declname { }` node
+ decltest: ?usize = null,
+ _analyzed: bool, // omitted in json data
+ };
+
+ const AstNode = struct {
+ file: usize = 0, // index into files
+ line: usize = 0,
+ col: usize = 0,
+ name: ?[]const u8 = null,
+ docs: ?[]const u8 = null,
+ fields: ?[]usize = null, // index into astNodes
+ @"comptime": bool = false,
+ };
+
+ const Type = union(enum) {
+ Unanalyzed: struct {},
+ Type: struct { name: []const u8 },
+ Void: struct { name: []const u8 },
+ Bool: struct { name: []const u8 },
+ NoReturn: struct { name: []const u8 },
+ Int: struct { name: []const u8 },
+ Float: struct { name: []const u8 },
+ Pointer: struct {
+ size: std.builtin.TypeInfo.Pointer.Size,
+ child: Expr,
+ sentinel: ?Expr = null,
+ @"align": ?Expr = null,
+ address_space: ?Expr = null,
+ bit_start: ?Expr = null,
+ host_size: ?Expr = null,
+ is_ref: bool = false,
+ is_allowzero: bool = false,
+ is_mutable: bool = false,
+ is_volatile: bool = false,
+ has_sentinel: bool = false,
+ has_align: bool = false,
+ has_addrspace: bool = false,
+ has_bit_range: bool = false,
+ },
+ Array: struct {
+ len: Expr,
+ child: Expr,
+ sentinel: ?Expr = null,
+ },
+ Struct: struct {
+ name: []const u8,
+ src: usize, // index into astNodes
+ privDecls: []usize = &.{}, // index into decls
+ pubDecls: []usize = &.{}, // index into decls
+ fields: ?[]Expr = null, // (use src->fields to find names)
+ line_number: usize,
+ outer_decl: usize,
+ ast: usize,
+ },
+ ComptimeExpr: struct { name: []const u8 },
+ ComptimeFloat: struct { name: []const u8 },
+ ComptimeInt: struct { name: []const u8 },
+ Undefined: struct { name: []const u8 },
+ Null: struct { name: []const u8 },
+ Optional: struct {
+ name: []const u8,
+ child: Expr,
+ },
+ ErrorUnion: struct { lhs: Expr, rhs: Expr },
+ // ErrorUnion: struct { name: []const u8 },
+ ErrorSet: struct {
+ name: []const u8,
+ fields: ?[]const Field = null,
+ // TODO: fn field for inferred error sets?
+ },
+ Enum: struct {
+ name: []const u8,
+ src: usize, // index into astNodes
+ privDecls: []usize = &.{}, // index into decls
+ pubDecls: []usize = &.{}, // index into decls
+ ast: usize,
+ // (use src->fields to find field names)
+ },
+ Union: struct {
+ name: []const u8,
+ src: usize, // index into astNodes
+ privDecls: []usize = &.{}, // index into decls
+ pubDecls: []usize = &.{}, // index into decls
+ fields: []Expr = &.{}, // (use src->fields to find names)
+ ast: usize,
+ },
+ Fn: struct {
+ name: []const u8,
+ src: ?usize = null, // index into `astNodes`
+ ret: Expr,
+ generic_ret: ?Expr = null,
+ params: ?[]Expr = null, // (use src->fields to find names)
+ lib_name: []const u8 = "",
+ is_var_args: bool = false,
+ is_inferred_error: bool = false,
+ has_lib_name: bool = false,
+ has_cc: bool = false,
+ cc: ?usize = null,
+ @"align": ?usize = null,
+ has_align: bool = false,
+ is_test: bool = false,
+ is_extern: bool = false,
+ },
+ BoundFn: struct { name: []const u8 },
+ Opaque: struct { name: []const u8 },
+ Frame: struct { name: []const u8 },
+ AnyFrame: struct { name: []const u8 },
+ Vector: struct { name: []const u8 },
+ EnumLiteral: struct { name: []const u8 },
+
+ const Field = struct {
+ name: []const u8,
+ docs: []const u8,
+ };
+
+ pub fn jsonStringify(
+ self: Type,
+ opts: std.json.StringifyOptions,
+ w: anytype,
+ ) !void {
+ const active_tag = std.meta.activeTag(self);
+ var jsw = std.json.writeStream(w, 15);
+ try jsw.beginObject();
+ try jsw.objectField("kind");
+ try jsw.emitNumber(@enumToInt(active_tag));
+ inline for (comptime std.meta.fields(Type)) |case| {
+ if (@field(Type, case.name) == active_tag) {
+ const current_value = @field(self, case.name);
+ inline for (comptime std.meta.fields(case.field_type)) |f| {
+ try jsw.objectField(f.name);
+ if (f.field_type == std.builtin.TypeInfo.Pointer.Size) {
+ try jsw.emitNumber(@enumToInt(@field(current_value, f.name)));
+ } else {
+ try std.json.stringify(@field(current_value, f.name), opts, w);
+ jsw.state_index -= 1;
+ }
+ }
+ }
+ }
+ try jsw.endObject();
+ }
+ };
+
+ /// An Expr represents the (untyped) result of analizing instructions.
+ /// The data is normalized, which means that an Expr that results in a
+ /// type definition will hold an index into `self.types`.
+ pub const Expr = union(enum) {
+ comptimeExpr: usize, // index in `comptimeExprs`
+ void: struct {},
+ @"unreachable": struct {},
+ @"null": struct {},
+ @"undefined": struct {},
+ @"struct": []FieldVal,
+ bool: bool,
+ @"anytype": struct {},
+ @"&": usize, // index in `exprs`
+ type: usize, // index in `types`
+ this: usize, // index in `types`
+ declRef: usize, // index in `decls`
+ fieldRef: FieldRef,
+ refPath: []Expr,
+ int: struct {
+ value: u64, // direct value
+ negated: bool = false,
+ },
+ int_big: struct {
+ value: []const u8, // direct value
+ negated: bool = false,
+ },
+ float: f64, // direct value
+ float128: f128, // direct value
+ array: []usize, // index in `exprs`
+ call: usize, // index in `calls`
+ enumLiteral: []const u8, // direct value
+ alignOf: usize, // index in `exprs`
+ typeOf: usize, // index in `exprs`
+ typeOf_peer: []usize,
+ errorUnion: usize, // index in `exprs`
+ as: As,
+ sizeOf: usize, // index in `exprs`
+ bitSizeOf: usize, // index in `exprs`
+ enumToInt: usize, // index in `exprs`
+ compileError: []const u8,
+ errorSets: usize,
+ string: []const u8, // direct value
+ sliceIndex: usize,
+ slice: Slice,
+ cmpxchgIndex: usize,
+ cmpxchg: Cmpxchg,
+ builtin: Builtin,
+ builtinIndex: usize,
+ builtinBin: BuiltinBin,
+ builtinBinIndex: usize,
+ switchIndex: usize, // index in `exprs`
+ switchOp: SwitchOp,
+ binOp: BinOp,
+ binOpIndex: usize,
+ const BinOp = struct {
+ lhs: usize, // index in `exprs`
+ rhs: usize, // index in `exprs`
+ name: []const u8 = "", // tag name
+ };
+ const SwitchOp = struct {
+ cond_index: usize,
+ file_name: []const u8,
+ ast: usize,
+ outer_decl: usize, // index in `types`
+ };
+ const BuiltinBin = struct {
+ name: []const u8 = "", // fn name
+ lhs: usize, // index in `exprs`
+ rhs: usize, // index in `exprs`
+ };
+ const Builtin = struct {
+ name: []const u8 = "", // fn name
+ param: usize, // index in `exprs`
+ };
+ const Slice = struct {
+ lhs: usize, // index in `exprs`
+ start: usize,
+ end: ?usize = null,
+ sentinel: ?usize = null, // index in `exprs`
+ };
+ const Cmpxchg = struct { name: []const u8, type: usize, ptr: usize, expected_value: usize, new_value: usize, success_order: usize, failure_order: usize };
+ const As = struct {
+ typeRefArg: ?usize, // index in `exprs`
+ exprArg: usize, // index in `exprs`
+ };
+ const FieldRef = struct {
+ type: usize, // index in `types`
+ index: usize, // index in type.fields
+ };
+
+ const FieldVal = struct {
+ name: []const u8,
+ val: WalkResult,
+ };
+
+ pub fn jsonStringify(
+ self: Expr,
+ opt: std.json.StringifyOptions,
+ w: anytype,
+ ) !void {
+ const active_tag = std.meta.activeTag(self);
+ var jsw = std.json.writeStream(w, 15);
+ try jsw.beginObject();
+ try jsw.objectField(@tagName(active_tag));
+ inline for (comptime std.meta.fields(Expr)) |case| {
+ if (@field(Expr, case.name) == active_tag) {
+ switch (active_tag) {
+ .int => {
+ if (self.int.negated) try w.writeAll("-");
+ try jsw.emitNumber(self.int.value);
+ },
+ .int_big => {
+
+ //@panic("TODO: json serialization of big ints!");
+ //if (v.negated) try w.writeAll("-");
+ //try jsw.emitNumber(v.value);
+ },
+ else => {
+ try std.json.stringify(@field(self, case.name), opt, w);
+ jsw.state_index -= 1;
+ // TODO: we should not reach into the state of the
+ // json writer, but alas, this is what's
+ // necessary with the current api.
+ // would be nice to have a proper integration
+ // between the json writer and the generic
+ // std.json.stringify implementation
+ },
+ }
+ }
+ }
+ try jsw.endObject();
+ }
+ };
+
+ /// A WalkResult represents the result of the analysis process done to a
+ /// a Zir instruction. Walk results carry type information either inferred
+ /// from the context (eg string literals are pointers to null-terminated
+ /// arrays), or because of @as() instructions.
+ /// Since the type information is only needed in certain contexts, the
+ /// underlying normalized data (Expr) is untyped.
+ const WalkResult = struct {
+ typeRef: ?Expr = null, // index in `exprs`
+ expr: Expr, // index in `exprs`
+ };
+};
+
+const AutodocErrors = error{
+ OutOfMemory,
+ CurrentWorkingDirectoryUnlinked,
+ Unexpected,
+};
+
+/// Called when we need to analyze a Zir instruction.
+/// For example it gets called by `generateZirData` on instruction 0,
+/// which represents the top-level struct corresponding to the root file.
+/// Note that in some situations where we're analyzing code that only allows
+/// for a limited subset of Zig syntax, we don't always resort to calling
+/// `walkInstruction` and instead sometimes we handle Zir directly.
+/// The best example of that are instructions corresponding to function
+/// params, as those can only occur while analyzing a function definition.
+fn walkInstruction(
+ self: *Autodoc,
+ file: *File,
+ parent_scope: *Scope,
+ inst_index: usize,
+ need_type: bool, // true if the caller needs us to provide also a typeRef
+) AutodocErrors!DocData.WalkResult {
+ const tags = file.zir.instructions.items(.tag);
+ const data = file.zir.instructions.items(.data);
+
+ // We assume that the topmost ast_node entry corresponds to our decl
+ const self_ast_node_index = self.ast_nodes.items.len - 1;
+
+ switch (tags[inst_index]) {
+ else => {
+ printWithContext(
+ file,
+ inst_index,
+ "TODO: implement `{s}` for walkInstruction\n\n",
+ .{@tagName(tags[inst_index])},
+ );
+ return self.cteTodo(@tagName(tags[inst_index]));
+ },
+ .import => {
+ const str_tok = data[inst_index].str_tok;
+ var path = str_tok.get(file.zir);
+
+ const maybe_other_package: ?*Package = blk: {
+ if (self.module.main_pkg_in_std and std.mem.eql(u8, path, "std")) {
+ path = "root";
+ break :blk self.module.main_pkg;
+ } else {
+ break :blk file.pkg.table.get(path);
+ }
+ };
+ // importFile cannot error out since all files
+ // are already loaded at this point
+ if (maybe_other_package) |other_package| {
+ const result = try self.packages.getOrPut(self.arena, other_package);
+
+ // Immediately add this package to the import table of our
+ // current package, regardless of wether it's new or not.
+ if (self.packages.getPtr(file.pkg)) |current_package| {
+ // TODO: apparently, in the stdlib a file gets analized before
+ // its package gets added. I guess we're importing a file
+ // that belongs to another package through its file path?
+ // (ie not through its package name).
+ // We're bailing for now, but maybe we shouldn't?
+ _ = try current_package.table.getOrPutValue(
+ self.arena,
+ other_package,
+ .{
+ .name = path,
+ .value = self.packages.getIndex(other_package).?,
+ },
+ );
+ }
+
+ if (result.found_existing) {
+ return DocData.WalkResult{
+ .typeRef = .{ .type = @enumToInt(Ref.type_type) },
+ .expr = .{ .type = result.value_ptr.main },
+ };
+ }
+
+ // create a new package entry
+ const main_type_index = self.types.items.len;
+ result.value_ptr.* = .{
+ .name = path,
+ .main = main_type_index,
+ .table = .{},
+ };
+
+ // TODO: Add this package as a dependency to the current pakcage
+ // TODO: this seems something that could be done in bulk
+ // at the beginning or the end, or something.
+ const root_src_dir = other_package.root_src_directory;
+ const root_src_path = other_package.root_src_path;
+ const joined_src_path = try root_src_dir.join(self.arena, &.{root_src_path});
+ defer self.arena.free(joined_src_path);
+
+ const abs_root_src_path = try std.fs.path.resolve(self.arena, &.{ ".", joined_src_path });
+ defer self.arena.free(abs_root_src_path);
+
+ const new_file = self.module.import_table.get(abs_root_src_path).?;
+
+ var root_scope = Scope{ .parent = null, .enclosing_type = main_type_index };
+ try self.ast_nodes.append(self.arena, .{ .name = "(root)" });
+ try self.files.put(self.arena, new_file, main_type_index);
+ return self.walkInstruction(
+ new_file,
+ &root_scope,
+ Zir.main_struct_inst,
+ false,
+ );
+ }
+
+ const new_file = self.module.importFile(file, path) catch unreachable;
+ const result = try self.files.getOrPut(self.arena, new_file.file);
+ if (result.found_existing) {
+ return DocData.WalkResult{
+ .typeRef = .{ .type = @enumToInt(Ref.type_type) },
+ .expr = .{ .type = result.value_ptr.* },
+ };
+ }
+
+ result.value_ptr.* = self.types.items.len;
+
+ var new_scope = Scope{
+ .parent = null,
+ .enclosing_type = self.types.items.len,
+ };
+
+ return self.walkInstruction(
+ new_file.file,
+ &new_scope,
+ Zir.main_struct_inst,
+ need_type,
+ );
+ },
+ .ret_node => {
+ const un_node = data[inst_index].un_node;
+ return self.walkRef(file, parent_scope, un_node.operand, false);
+ },
+ .ret_load => {
+ const un_node = data[inst_index].un_node;
+ const res_ptr_ref = un_node.operand;
+ const res_ptr_inst = @enumToInt(res_ptr_ref) - Ref.typed_value_map.len;
+ // TODO: this instruction doesn't let us know trivially if there's
+ // branching involved or not. For now here's the strat:
+ // We search backwarts until `ret_ptr` for `store_node`,
+ // if we find only one, then that's our value, if we find more
+ // than one, then it means that there's branching involved.
+ // Maybe.
+
+ var i = inst_index - 1;
+ var result_ref: ?Ref = null;
+ while (i > res_ptr_inst) : (i -= 1) {
+ if (tags[i] == .store_node) {
+ const pl_node = data[i].pl_node;
+ const extra = file.zir.extraData(Zir.Inst.Bin, pl_node.payload_index);
+ if (extra.data.lhs == res_ptr_ref) {
+ // this store_load instruction is indeed pointing at
+ // the result location that we care about!
+ if (result_ref != null) return DocData.WalkResult{
+ .expr = .{ .comptimeExpr = 0 },
+ };
+ result_ref = extra.data.rhs;
+ }
+ }
+ }
+
+ if (result_ref) |rr| {
+ return self.walkRef(file, parent_scope, rr, need_type);
+ }
+
+ return DocData.WalkResult{
+ .expr = .{ .comptimeExpr = 0 },
+ };
+ },
+ .closure_get => {
+ const inst_node = data[inst_index].inst_node;
+ return try self.walkInstruction(file, parent_scope, inst_node.inst, need_type);
+ },
+ .closure_capture => {
+ const un_tok = data[inst_index].un_tok;
+ return try self.walkRef(file, parent_scope, un_tok.operand, need_type);
+ },
+ .cmpxchg_strong, .cmpxchg_weak => {
+ const pl_node = data[inst_index].pl_node;
+ const extra = file.zir.extraData(Zir.Inst.Cmpxchg, pl_node.payload_index);
+
+ const last_type_index = self.exprs.items.len;
+ const last_type = self.exprs.items[last_type_index - 1];
+ const type_index = self.exprs.items.len;
+ try self.exprs.append(self.arena, last_type);
+
+ const ptr_index = self.exprs.items.len;
+ var ptr: DocData.WalkResult = try self.walkRef(
+ file,
+ parent_scope,
+ extra.data.ptr,
+ false,
+ );
+ try self.exprs.append(self.arena, ptr.expr);
+
+ const expected_value_index = self.exprs.items.len;
+ var expected_value: DocData.WalkResult = try self.walkRef(
+ file,
+ parent_scope,
+ extra.data.expected_value,
+ false,
+ );
+ try self.exprs.append(self.arena, expected_value.expr);
+
+ const new_value_index = self.exprs.items.len;
+ var new_value: DocData.WalkResult = try self.walkRef(
+ file,
+ parent_scope,
+ extra.data.new_value,
+ false,
+ );
+ try self.exprs.append(self.arena, new_value.expr);
+
+ const success_order_index = self.exprs.items.len;
+ var success_order: DocData.WalkResult = try self.walkRef(
+ file,
+ parent_scope,
+ extra.data.success_order,
+ false,
+ );
+ try self.exprs.append(self.arena, success_order.expr);
+
+ const failure_order_index = self.exprs.items.len;
+ var failure_order: DocData.WalkResult = try self.walkRef(
+ file,
+ parent_scope,
+ extra.data.failure_order,
+ false,
+ );
+ try self.exprs.append(self.arena, failure_order.expr);
+
+ const cmpxchg_index = self.exprs.items.len;
+ 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 } });
+ return DocData.WalkResult{
+ .typeRef = .{ .type = @enumToInt(Ref.type_type) },
+ .expr = .{ .cmpxchgIndex = cmpxchg_index },
+ };
+ },
+ .str => {
+ const str = data[inst_index].str.get(file.zir);
+
+ const tRef: ?DocData.Expr = if (!need_type) null else blk: {
+ const arrTypeId = self.types.items.len;
+ try self.types.append(self.arena, .{
+ .Array = .{
+ .len = .{ .int = .{ .value = str.len } },
+ .child = .{ .type = @enumToInt(Ref.u8_type) },
+ .sentinel = .{ .int = .{
+ .value = 0,
+ .negated = false,
+ } },
+ },
+ });
+ // const sentinel: ?usize = if (ptr.flags.has_sentinel) 0 else null;
+ const ptrTypeId = self.types.items.len;
+ try self.types.append(self.arena, .{
+ .Pointer = .{
+ .size = .One,
+ .child = .{ .type = arrTypeId },
+ .sentinel = .{ .int = .{
+ .value = 0,
+ .negated = false,
+ } },
+ .is_mutable = false,
+ },
+ });
+ break :blk .{ .type = ptrTypeId };
+ };
+
+ return DocData.WalkResult{
+ .typeRef = tRef,
+ .expr = .{ .string = str },
+ };
+ },
+ .compile_error => {
+ const un_node = data[inst_index].un_node;
+ var operand: DocData.WalkResult = try self.walkRef(
+ file,
+ parent_scope,
+ un_node.operand,
+ false,
+ );
+
+ return DocData.WalkResult{
+ .expr = .{
+ .compileError = switch (operand.expr) {
+ .string => |s| s,
+ else => "TODO: non-string @compileError arguments",
+ },
+ },
+ };
+ },
+ .enum_literal => {
+ const str_tok = data[inst_index].str_tok;
+ const literal = file.zir.nullTerminatedString(str_tok.start);
+ const type_index = self.types.items.len;
+ try self.types.append(self.arena, .{
+ .EnumLiteral = .{ .name = "todo enum literal" },
+ });
+
+ return DocData.WalkResult{
+ .typeRef = .{ .type = type_index },
+ .expr = .{ .enumLiteral = literal },
+ };
+ },
+ .int => {
+ const int = data[inst_index].int;
+ return DocData.WalkResult{
+ .typeRef = .{ .type = @enumToInt(Ref.comptime_int_type) },
+ .expr = .{ .int = .{ .value = int } },
+ };
+ },
+ .int_big => {
+ // @check
+ const str = data[inst_index].str.get(file.zir);
+ _ = str;
+ printWithContext(
+ file,
+ inst_index,
+ "TODO: implement `{s}` for walkInstruction\n\n",
+ .{@tagName(tags[inst_index])},
+ );
+ return self.cteTodo(@tagName(tags[inst_index]));
+ },
+
+ .slice_start => {
+ const pl_node = data[inst_index].pl_node;
+ const extra = file.zir.extraData(Zir.Inst.SliceStart, pl_node.payload_index);
+
+ const slice_index = self.exprs.items.len;
+ try self.exprs.append(self.arena, .{ .slice = .{ .lhs = 0, .start = 0 } });
+
+ var lhs: DocData.WalkResult = try self.walkRef(
+ file,
+ parent_scope,
+ extra.data.lhs,
+ false,
+ );
+ var start: DocData.WalkResult = try self.walkRef(
+ file,
+ parent_scope,
+ extra.data.start,
+ false,
+ );
+
+ const lhs_index = self.exprs.items.len;
+ try self.exprs.append(self.arena, lhs.expr);
+ const start_index = self.exprs.items.len;
+ try self.exprs.append(self.arena, start.expr);
+ self.exprs.items[slice_index] = .{ .slice = .{ .lhs = lhs_index, .start = start_index } };
+
+ return DocData.WalkResult{
+ .typeRef = self.decls.items[lhs.expr.declRef].value.typeRef,
+ .expr = .{ .sliceIndex = slice_index },
+ };
+ },
+ .slice_end => {
+ const pl_node = data[inst_index].pl_node;
+ const extra = file.zir.extraData(Zir.Inst.SliceEnd, pl_node.payload_index);
+
+ const slice_index = self.exprs.items.len;
+ try self.exprs.append(self.arena, .{ .slice = .{ .lhs = 0, .start = 0 } });
+
+ var lhs: DocData.WalkResult = try self.walkRef(
+ file,
+ parent_scope,
+ extra.data.lhs,
+ false,
+ );
+ var start: DocData.WalkResult = try self.walkRef(
+ file,
+ parent_scope,
+ extra.data.start,
+ false,
+ );
+ var end: DocData.WalkResult = try self.walkRef(
+ file,
+ parent_scope,
+ extra.data.end,
+ false,
+ );
+
+ const lhs_index = self.exprs.items.len;
+ try self.exprs.append(self.arena, lhs.expr);
+ const start_index = self.exprs.items.len;
+ try self.exprs.append(self.arena, start.expr);
+ const end_index = self.exprs.items.len;
+ try self.exprs.append(self.arena, end.expr);
+ self.exprs.items[slice_index] = .{ .slice = .{ .lhs = lhs_index, .start = start_index, .end = end_index } };
+
+ return DocData.WalkResult{
+ .typeRef = self.decls.items[lhs.expr.declRef].value.typeRef,
+ .expr = .{ .sliceIndex = slice_index },
+ };
+ },
+ .slice_sentinel => {
+ const pl_node = data[inst_index].pl_node;
+ const extra = file.zir.extraData(Zir.Inst.SliceSentinel, pl_node.payload_index);
+
+ const slice_index = self.exprs.items.len;
+ try self.exprs.append(self.arena, .{ .slice = .{ .lhs = 0, .start = 0 } });
+
+ var lhs: DocData.WalkResult = try self.walkRef(
+ file,
+ parent_scope,
+ extra.data.lhs,
+ false,
+ );
+ var start: DocData.WalkResult = try self.walkRef(
+ file,
+ parent_scope,
+ extra.data.start,
+ false,
+ );
+ var end: DocData.WalkResult = try self.walkRef(
+ file,
+ parent_scope,
+ extra.data.end,
+ false,
+ );
+ var sentinel: DocData.WalkResult = try self.walkRef(
+ file,
+ parent_scope,
+ extra.data.sentinel,
+ false,
+ );
+
+ const lhs_index = self.exprs.items.len;
+ try self.exprs.append(self.arena, lhs.expr);
+ const start_index = self.exprs.items.len;
+ try self.exprs.append(self.arena, start.expr);
+ const end_index = self.exprs.items.len;
+ try self.exprs.append(self.arena, end.expr);
+ const sentinel_index = self.exprs.items.len;
+ try self.exprs.append(self.arena, sentinel.expr);
+ self.exprs.items[slice_index] = .{ .slice = .{ .lhs = lhs_index, .start = start_index, .end = end_index, .sentinel = sentinel_index } };
+
+ return DocData.WalkResult{
+ .typeRef = self.decls.items[lhs.expr.declRef].value.typeRef,
+ .expr = .{ .sliceIndex = slice_index },
+ };
+ },
+
+ // @check array_cat and array_mul
+ .add,
+ .addwrap,
+ .add_sat,
+ .sub,
+ .subwrap,
+ .sub_sat,
+ .mul,
+ .mulwrap,
+ .mul_sat,
+ .div,
+ .shl,
+ .shl_sat,
+ .shr,
+ .bit_or,
+ .bit_and,
+ // @check still not working when applied in std
+ // .array_cat,
+ // .array_mul,
+ => {
+ const pl_node = data[inst_index].pl_node;
+ const extra = file.zir.extraData(Zir.Inst.Bin, pl_node.payload_index);
+
+ const binop_index = self.exprs.items.len;
+ try self.exprs.append(self.arena, .{ .binOp = .{ .lhs = 0, .rhs = 0 } });
+
+ var lhs: DocData.WalkResult = try self.walkRef(
+ file,
+ parent_scope,
+ extra.data.lhs,
+ false,
+ );
+ var rhs: DocData.WalkResult = try self.walkRef(
+ file,
+ parent_scope,
+ extra.data.rhs,
+ false,
+ );
+
+ const lhs_index = self.exprs.items.len;
+ try self.exprs.append(self.arena, lhs.expr);
+ const rhs_index = self.exprs.items.len;
+ try self.exprs.append(self.arena, rhs.expr);
+ self.exprs.items[binop_index] = .{ .binOp = .{
+ .name = @tagName(tags[inst_index]),
+ .lhs = lhs_index,
+ .rhs = rhs_index,
+ } };
+
+ return DocData.WalkResult{
+ .typeRef = .{ .type = @enumToInt(Ref.type_type) },
+ .expr = .{ .binOpIndex = binop_index },
+ };
+ },
+
+ // builtin functions
+ .align_of,
+ .bool_to_int,
+ .embed_file,
+ .error_name,
+ .panic,
+ .set_cold, // @check
+ .set_runtime_safety, // @check
+ .sqrt,
+ .sin,
+ .cos,
+ .tan,
+ .exp,
+ .exp2,
+ .log,
+ .log2,
+ .log10,
+ .fabs,
+ .floor,
+ .ceil,
+ .trunc,
+ .round,
+ .tag_name,
+ .reify,
+ .type_name,
+ .frame_type,
+ .frame_size,
+ .ptr_to_int,
+ .minimum,
+ .maximum,
+ .bit_not,
+ // @check
+ .clz,
+ .ctz,
+ .pop_count,
+ .byte_swap,
+ .bit_reverse,
+ => {
+ const un_node = data[inst_index].un_node;
+ const bin_index = self.exprs.items.len;
+ try self.exprs.append(self.arena, .{ .builtin = .{ .param = 0 } });
+ const param = try self.walkRef(file, parent_scope, un_node.operand, false);
+
+ const param_index = self.exprs.items.len;
+ try self.exprs.append(self.arena, param.expr);
+
+ self.exprs.items[bin_index] = .{ .builtin = .{ .name = @tagName(tags[inst_index]), .param = param_index } };
+
+ return DocData.WalkResult{
+ .typeRef = param.typeRef orelse .{ .type = @enumToInt(Ref.type_type) },
+ .expr = .{ .builtinIndex = bin_index },
+ };
+ },
+
+ .float_to_int,
+ .int_to_float,
+ .int_to_ptr,
+ .int_to_enum,
+ .float_cast,
+ .int_cast,
+ .ptr_cast,
+ .truncate,
+ .align_cast,
+ .has_decl,
+ .has_field,
+ .div_exact,
+ .div_floor,
+ .div_trunc,
+ .mod,
+ .rem,
+ .mod_rem,
+ .shl_exact,
+ .shr_exact,
+ .bitcast,
+ .vector_type,
+ // @check
+ .bit_offset_of,
+ .offset_of,
+ .splat,
+ .reduce,
+ => {
+ const pl_node = data[inst_index].pl_node;
+ const extra = file.zir.extraData(Zir.Inst.Bin, pl_node.payload_index);
+
+ const binop_index = self.exprs.items.len;
+ try self.exprs.append(self.arena, .{ .builtinBin = .{ .lhs = 0, .rhs = 0 } });
+
+ var lhs: DocData.WalkResult = try self.walkRef(
+ file,
+ parent_scope,
+ extra.data.lhs,
+ false,
+ );
+ var rhs: DocData.WalkResult = try self.walkRef(
+ file,
+ parent_scope,
+ extra.data.rhs,
+ false,
+ );
+
+ const lhs_index = self.exprs.items.len;
+ try self.exprs.append(self.arena, lhs.expr);
+ const rhs_index = self.exprs.items.len;
+ try self.exprs.append(self.arena, rhs.expr);
+ self.exprs.items[binop_index] = .{ .builtinBin = .{ .name = @tagName(tags[inst_index]), .lhs = lhs_index, .rhs = rhs_index } };
+
+ return DocData.WalkResult{
+ .typeRef = .{ .type = @enumToInt(Ref.type_type) },
+ .expr = .{ .builtinBinIndex = binop_index },
+ };
+ },
+ .error_union_type => {
+ const pl_node = data[inst_index].pl_node;
+ const extra = file.zir.extraData(Zir.Inst.Bin, pl_node.payload_index);
+
+ var lhs: DocData.WalkResult = try self.walkRef(
+ file,
+ parent_scope,
+ extra.data.lhs,
+ false,
+ );
+ var rhs: DocData.WalkResult = try self.walkRef(
+ file,
+ parent_scope,
+ extra.data.rhs,
+ false,
+ );
+
+ const type_slot_index = self.types.items.len;
+ try self.types.append(self.arena, .{ .ErrorUnion = .{
+ .lhs = lhs.expr,
+ .rhs = rhs.expr,
+ } });
+
+ return DocData.WalkResult{
+ .typeRef = .{ .type = @enumToInt(Ref.type_type) },
+ .expr = .{ .errorUnion = type_slot_index },
+ };
+ },
+ .merge_error_sets => {
+ const pl_node = data[inst_index].pl_node;
+ const extra = file.zir.extraData(Zir.Inst.Bin, pl_node.payload_index);
+
+ var lhs: DocData.WalkResult = try self.walkRef(
+ file,
+ parent_scope,
+ extra.data.lhs,
+ false,
+ );
+ var rhs: DocData.WalkResult = try self.walkRef(
+ file,
+ parent_scope,
+ extra.data.rhs,
+ false,
+ );
+ const type_slot_index = self.types.items.len;
+ try self.types.append(self.arena, .{ .ErrorUnion = .{
+ .lhs = lhs.expr,
+ .rhs = rhs.expr,
+ } });
+
+ return DocData.WalkResult{
+ .typeRef = .{ .type = @enumToInt(Ref.type_type) },
+ .expr = .{ .errorSets = type_slot_index },
+ };
+ },
+ // .elem_type => {
+ // const un_node = data[inst_index].un_node;
+
+ // var operand: DocData.WalkResult = try self.walkRef(
+ // file,
+ // parent_scope,
+ // un_node.operand,
+ // false,
+ // );
+
+ // return operand;
+ // },
+ .ptr_type_simple => {
+ const ptr = data[inst_index].ptr_type_simple;
+ const elem_type_ref = try self.walkRef(file, parent_scope, ptr.elem_type, false);
+ const type_slot_index = self.types.items.len;
+ try self.types.append(self.arena, .{
+ .Pointer = .{ .size = ptr.size, .child = elem_type_ref.expr, .is_mutable = ptr.is_mutable, .is_volatile = ptr.is_volatile, .is_allowzero = ptr.is_allowzero },
+ });
+
+ return DocData.WalkResult{
+ .typeRef = .{ .type = @enumToInt(Ref.type_type) },
+ .expr = .{ .type = type_slot_index },
+ };
+ },
+ .ptr_type => {
+ const ptr = data[inst_index].ptr_type;
+ const extra = file.zir.extraData(Zir.Inst.PtrType, ptr.payload_index);
+ var extra_index = extra.end;
+
+ const type_slot_index = self.types.items.len;
+ const elem_type_ref = try self.walkRef(
+ file,
+ parent_scope,
+ extra.data.elem_type,
+ false,
+ );
+
+ // @check if `addrspace`, `bit_start` and `host_size` really need to be
+ // present in json
+ var sentinel: ?DocData.Expr = null;
+ if (ptr.flags.has_sentinel) {
+ const ref = @intToEnum(Zir.Inst.Ref, file.zir.extra[extra_index]);
+ const ref_result = try self.walkRef(file, parent_scope, ref, false);
+ sentinel = ref_result.expr;
+ extra_index += 1;
+ }
+
+ var @"align": ?DocData.Expr = null;
+ if (ptr.flags.has_align) {
+ const ref = @intToEnum(Zir.Inst.Ref, file.zir.extra[extra_index]);
+ const ref_result = try self.walkRef(file, parent_scope, ref, false);
+ @"align" = ref_result.expr;
+ extra_index += 1;
+ }
+ var address_space: ?DocData.Expr = null;
+ if (ptr.flags.has_addrspace) {
+ const ref = @intToEnum(Zir.Inst.Ref, file.zir.extra[extra_index]);
+ const ref_result = try self.walkRef(file, parent_scope, ref, false);
+ address_space = ref_result.expr;
+ extra_index += 1;
+ }
+ var bit_start: ?DocData.Expr = null;
+ if (ptr.flags.has_bit_range) {
+ const ref = @intToEnum(Zir.Inst.Ref, file.zir.extra[extra_index]);
+ const ref_result = try self.walkRef(file, parent_scope, ref, false);
+ address_space = ref_result.expr;
+ extra_index += 1;
+ }
+
+ var host_size: ?DocData.Expr = null;
+ if (ptr.flags.has_bit_range) {
+ const ref = @intToEnum(Zir.Inst.Ref, file.zir.extra[extra_index]);
+ const ref_result = try self.walkRef(file, parent_scope, ref, false);
+ host_size = ref_result.expr;
+ }
+
+ try self.types.append(self.arena, .{
+ .Pointer = .{
+ .size = ptr.size,
+ .child = elem_type_ref.expr,
+ .has_align = ptr.flags.has_align,
+ .@"align" = @"align",
+ .has_addrspace = ptr.flags.has_addrspace,
+ .address_space = address_space,
+ .has_sentinel = ptr.flags.has_sentinel,
+ .sentinel = sentinel,
+ .is_mutable = ptr.flags.is_mutable,
+ .is_volatile = ptr.flags.is_volatile,
+ .has_bit_range = ptr.flags.has_bit_range,
+ .bit_start = bit_start,
+ .host_size = host_size,
+ },
+ });
+ return DocData.WalkResult{
+ .typeRef = .{ .type = @enumToInt(Ref.type_type) },
+ .expr = .{ .type = type_slot_index },
+ };
+ },
+ .array_type => {
+ const pl_node = data[inst_index].pl_node;
+ const bin = file.zir.extraData(Zir.Inst.Bin, pl_node.payload_index).data;
+ const len = try self.walkRef(file, parent_scope, bin.lhs, false);
+ const child = try self.walkRef(file, parent_scope, bin.rhs, false);
+
+ const type_slot_index = self.types.items.len;
+ try self.types.append(self.arena, .{
+ .Array = .{
+ .len = len.expr,
+ .child = child.expr,
+ },
+ });
+
+ return DocData.WalkResult{
+ .typeRef = .{ .type = @enumToInt(Ref.type_type) },
+ .expr = .{ .type = type_slot_index },
+ };
+ },
+ .array_type_sentinel => {
+ const pl_node = data[inst_index].pl_node;
+ const extra = file.zir.extraData(Zir.Inst.ArrayTypeSentinel, pl_node.payload_index);
+ const len = try self.walkRef(file, parent_scope, extra.data.len, false);
+ const sentinel = try self.walkRef(file, parent_scope, extra.data.sentinel, false);
+ const elem_type = try self.walkRef(file, parent_scope, extra.data.elem_type, false);
+
+ const type_slot_index = self.types.items.len;
+ try self.types.append(self.arena, .{
+ .Array = .{
+ .len = len.expr,
+ .child = elem_type.expr,
+ .sentinel = sentinel.expr,
+ },
+ });
+ return DocData.WalkResult{
+ .typeRef = .{ .type = @enumToInt(Ref.type_type) },
+ .expr = .{ .type = type_slot_index },
+ };
+ },
+ .array_init => {
+ const pl_node = data[inst_index].pl_node;
+ const extra = file.zir.extraData(Zir.Inst.MultiOp, pl_node.payload_index);
+ const operands = file.zir.refSlice(extra.end, extra.data.operands_len);
+ const array_data = try self.arena.alloc(usize, operands.len - 1);
+
+ std.debug.assert(operands.len > 0);
+ var array_type = try self.walkRef(file, parent_scope, operands[0], false);
+
+ for (operands[1..]) |op, idx| {
+ const wr = try self.walkRef(file, parent_scope, op, false);
+ const expr_index = self.exprs.items.len;
+ try self.exprs.append(self.arena, wr.expr);
+ array_data[idx] = expr_index;
+ }
+
+ return DocData.WalkResult{
+ .typeRef = array_type.expr,
+ .expr = .{ .array = array_data },
+ };
+ },
+ .array_init_anon => {
+ const pl_node = data[inst_index].pl_node;
+ const extra = file.zir.extraData(Zir.Inst.MultiOp, pl_node.payload_index);
+ const operands = file.zir.refSlice(extra.end, extra.data.operands_len);
+ const array_data = try self.arena.alloc(usize, operands.len);
+
+ for (operands) |op, idx| {
+ const wr = try self.walkRef(file, parent_scope, op, false);
+ const expr_index = self.exprs.items.len;
+ try self.exprs.append(self.arena, wr.expr);
+ array_data[idx] = expr_index;
+ }
+
+ return DocData.WalkResult{
+ .typeRef = null,
+ .expr = .{ .array = array_data },
+ };
+ },
+ .array_init_ref => {
+ const pl_node = data[inst_index].pl_node;
+ const extra = file.zir.extraData(Zir.Inst.MultiOp, pl_node.payload_index);
+ const operands = file.zir.refSlice(extra.end, extra.data.operands_len);
+ const array_data = try self.arena.alloc(usize, operands.len - 1);
+
+ std.debug.assert(operands.len > 0);
+ var array_type = try self.walkRef(file, parent_scope, operands[0], false);
+
+ for (operands[1..]) |op, idx| {
+ const wr = try self.walkRef(file, parent_scope, op, false);
+ const expr_index = self.exprs.items.len;
+ try self.exprs.append(self.arena, wr.expr);
+ array_data[idx] = expr_index;
+ }
+
+ const type_slot_index = self.types.items.len;
+ try self.types.append(self.arena, .{
+ .Pointer = .{
+ .size = .One,
+ .child = array_type.expr,
+ },
+ });
+
+ const expr_index = self.exprs.items.len;
+ try self.exprs.append(self.arena, .{ .array = array_data });
+
+ return DocData.WalkResult{
+ .typeRef = .{ .type = type_slot_index },
+ .expr = .{ .@"&" = expr_index },
+ };
+ },
+ .array_init_anon_ref => {
+ const pl_node = data[inst_index].pl_node;
+ const extra = file.zir.extraData(Zir.Inst.MultiOp, pl_node.payload_index);
+ const operands = file.zir.refSlice(extra.end, extra.data.operands_len);
+ const array_data = try self.arena.alloc(usize, operands.len);
+
+ for (operands) |op, idx| {
+ const wr = try self.walkRef(file, parent_scope, op, false);
+ const expr_index = self.exprs.items.len;
+ try self.exprs.append(self.arena, wr.expr);
+ array_data[idx] = expr_index;
+ }
+
+ const expr_index = self.exprs.items.len;
+ try self.exprs.append(self.arena, .{ .array = array_data });
+
+ return DocData.WalkResult{
+ .typeRef = null,
+ .expr = .{ .@"&" = expr_index },
+ };
+ },
+ .float => {
+ const float = data[inst_index].float;
+ return DocData.WalkResult{
+ .typeRef = .{ .type = @enumToInt(Ref.comptime_float_type) },
+ .expr = .{ .float = float },
+ };
+ },
+ // @check: In frontend I'm handling float128 with `.toFixed(2)`
+ .float128 => {
+ const pl_node = data[inst_index].pl_node;
+ const extra = file.zir.extraData(Zir.Inst.Float128, pl_node.payload_index);
+ return DocData.WalkResult{
+ .typeRef = .{ .type = @enumToInt(Ref.comptime_float_type) },
+ .expr = .{ .float128 = extra.data.get() },
+ };
+ },
+ .negate => {
+ const un_node = data[inst_index].un_node;
+ var operand: DocData.WalkResult = try self.walkRef(
+ file,
+ parent_scope,
+ un_node.operand,
+ need_type,
+ );
+ switch (operand.expr) {
+ .int => |*int| int.negated = true,
+ else => {
+ printWithContext(
+ file,
+ inst_index,
+ "TODO: support negation for more types",
+ .{},
+ );
+ },
+ }
+ return operand;
+ },
+ .size_of => {
+ const un_node = data[inst_index].un_node;
+ const operand = try self.walkRef(
+ file,
+ parent_scope,
+ un_node.operand,
+ false,
+ );
+ const operand_index = self.exprs.items.len;
+ try self.exprs.append(self.arena, operand.expr);
+ return DocData.WalkResult{
+ .typeRef = .{ .type = @enumToInt(Ref.comptime_int_type) },
+ .expr = .{ .sizeOf = operand_index },
+ };
+ },
+ .bit_size_of => {
+ // not working correctly with `align()`
+ const un_node = data[inst_index].un_node;
+ const operand = try self.walkRef(
+ file,
+ parent_scope,
+ un_node.operand,
+ need_type,
+ );
+ const operand_index = self.exprs.items.len;
+ try self.exprs.append(self.arena, operand.expr);
+
+ return DocData.WalkResult{
+ .typeRef = operand.typeRef,
+ .expr = .{ .bitSizeOf = operand_index },
+ };
+ },
+ .enum_to_int => {
+ // not working correctly with `align()`
+ const un_node = data[inst_index].un_node;
+ const operand = try self.walkRef(
+ file,
+ parent_scope,
+ un_node.operand,
+ false,
+ );
+ const operand_index = self.exprs.items.len;
+ try self.exprs.append(self.arena, operand.expr);
+
+ return DocData.WalkResult{
+ .typeRef = .{ .type = @enumToInt(Ref.comptime_int_type) },
+ .expr = .{ .enumToInt = operand_index },
+ };
+ },
+ .switch_block => {
+ // WIP
+ const pl_node = data[inst_index].pl_node;
+ const extra = file.zir.extraData(Zir.Inst.SwitchBlock, pl_node.payload_index);
+ const cond_index = self.exprs.items.len;
+ _ = try self.walkRef(file, parent_scope, extra.data.operand, false);
+
+ const ast_index = self.ast_nodes.items.len;
+ const type_index = self.types.items.len - 1;
+
+ // const ast_line = self.ast_nodes.items[ast_index - 1];
+
+ // const sep = "=" ** 200;
+ // log.debug("{s}", .{sep});
+ // log.debug("SWITCH BLOCK", .{});
+ // log.debug("extra = {any}", .{extra});
+ // log.debug("outer_decl = {any}", .{self.types.items[type_index]});
+ // log.debug("ast_lines = {}", .{ast_line});
+ // log.debug("{s}", .{sep});
+
+ const switch_index = self.exprs.items.len;
+ try self.exprs.append(self.arena, .{ .switchOp = .{ .cond_index = cond_index, .file_name = file.sub_file_path, .ast = ast_index, .outer_decl = type_index } });
+
+ return DocData.WalkResult{
+ .typeRef = .{ .type = @enumToInt(Ref.type_type) },
+ .expr = .{ .switchIndex = switch_index },
+ };
+ },
+ .switch_cond => {
+ const un_node = data[inst_index].un_node;
+ const operand = try self.walkRef(
+ file,
+ parent_scope,
+ un_node.operand,
+ need_type,
+ );
+ const operand_index = self.exprs.items.len;
+ try self.exprs.append(self.arena, operand.expr);
+
+ // const ast_index = self.ast_nodes.items.len;
+ // const sep = "=" ** 200;
+ // log.debug("{s}", .{sep});
+ // log.debug("SWITCH COND", .{});
+ // log.debug("ast index = {}", .{ast_index});
+ // log.debug("ast previous = {}", .{self.ast_nodes.items[ast_index - 1]});
+ // log.debug("{s}", .{sep});
+
+ return DocData.WalkResult{
+ .typeRef = operand.typeRef,
+ .expr = .{ .typeOf = operand_index },
+ };
+ },
+
+ .typeof => {
+ const un_node = data[inst_index].un_node;
+ const operand = try self.walkRef(
+ file,
+ parent_scope,
+ un_node.operand,
+ need_type,
+ );
+ const operand_index = self.exprs.items.len;
+ try self.exprs.append(self.arena, operand.expr);
+
+ return DocData.WalkResult{
+ .typeRef = operand.typeRef,
+ .expr = .{ .typeOf = operand_index },
+ };
+ },
+ .typeof_builtin => {
+ const pl_node = data[inst_index].pl_node;
+ const extra = file.zir.extraData(Zir.Inst.Block, pl_node.payload_index);
+ const body = file.zir.extra[extra.end..][extra.data.body_len - 1];
+
+ var operand: DocData.WalkResult = try self.walkRef(
+ file,
+ parent_scope,
+ data[body].@"break".operand,
+ false,
+ );
+
+ const operand_index = self.exprs.items.len;
+ try self.exprs.append(self.arena, operand.expr);
+
+ return DocData.WalkResult{
+ .typeRef = operand.typeRef,
+ .expr = .{ .typeOf = operand_index },
+ };
+ },
+ .type_info => {
+ // @check
+ const un_node = data[inst_index].un_node;
+ const operand = try self.walkRef(
+ file,
+ parent_scope,
+ un_node.operand,
+ need_type,
+ );
+
+ const operand_index = self.exprs.items.len;
+ try self.exprs.append(self.arena, operand.expr);
+
+ return DocData.WalkResult{
+ .typeRef = operand.typeRef,
+ .expr = .{ .typeOf = operand_index },
+ };
+ },
+ .as_node => {
+ const pl_node = data[inst_index].pl_node;
+ const extra = file.zir.extraData(Zir.Inst.As, pl_node.payload_index);
+ const dest_type_walk = try self.walkRef(
+ file,
+ parent_scope,
+ extra.data.dest_type,
+ false,
+ );
+
+ const operand = try self.walkRef(
+ file,
+ parent_scope,
+ extra.data.operand,
+ false,
+ );
+
+ const operand_idx = self.exprs.items.len;
+ try self.exprs.append(self.arena, operand.expr);
+
+ const dest_type_idx = self.exprs.items.len;
+ try self.exprs.append(self.arena, dest_type_walk.expr);
+
+ // TODO: there's something wrong with how both `as` and `WalkrResult`
+ // try to store type information.
+ return DocData.WalkResult{
+ .typeRef = dest_type_walk.expr,
+ .expr = .{
+ .as = .{
+ .typeRefArg = dest_type_idx,
+ .exprArg = operand_idx,
+ },
+ },
+ };
+ },
+ .optional_type => {
+ const un_node = data[inst_index].un_node;
+ const operand: DocData.WalkResult = try self.walkRef(
+ file,
+ parent_scope,
+ un_node.operand,
+ false,
+ );
+
+ const operand_idx = self.types.items.len;
+ try self.types.append(self.arena, .{
+ .Optional = .{ .name = "?TODO", .child = operand.expr },
+ });
+
+ return DocData.WalkResult{
+ .typeRef = .{ .type = @enumToInt(Ref.type_type) },
+ .expr = .{ .type = operand_idx },
+ };
+ },
+ .decl_val, .decl_ref => {
+ const str_tok = data[inst_index].str_tok;
+ const decls_slot_index = parent_scope.resolveDeclName(str_tok.start);
+ // While it would make sense to grab the original decl's typeRef info,
+ // that decl might not have been analyzed yet! The frontend will have
+ // to navigate through all declRefs to find the underlying type.
+ return DocData.WalkResult{
+ .expr = .{ .declRef = decls_slot_index },
+ };
+ },
+ .field_val, .field_call_bind, .field_ptr, .field_type => {
+ // TODO: field type uses Zir.Inst.FieldType, it just happens to have the
+ // same layout as Zir.Inst.Field :^)
+ const pl_node = data[inst_index].pl_node;
+ const extra = file.zir.extraData(Zir.Inst.Field, pl_node.payload_index);
+
+ var path: std.ArrayListUnmanaged(DocData.Expr) = .{};
+ var lhs = @enumToInt(extra.data.lhs) - Ref.typed_value_map.len; // underflow = need to handle Refs
+
+ try path.append(self.arena, .{
+ .string = file.zir.nullTerminatedString(extra.data.field_name_start),
+ });
+ // Put inside path the starting index of each decl name that
+ // we encounter as we navigate through all the field_vals
+ while (tags[lhs] == .field_val or
+ tags[lhs] == .field_call_bind or
+ tags[lhs] == .field_ptr or
+ tags[lhs] == .field_type)
+ {
+ const lhs_extra = file.zir.extraData(
+ Zir.Inst.Field,
+ data[lhs].pl_node.payload_index,
+ );
+
+ try path.append(self.arena, .{
+ .string = file.zir.nullTerminatedString(lhs_extra.data.field_name_start),
+ });
+ lhs = @enumToInt(lhs_extra.data.lhs) - Ref.typed_value_map.len; // underflow = need to handle Refs
+ }
+
+ // TODO: double check that we really don't need type info here
+ const wr = try self.walkInstruction(file, parent_scope, lhs, false);
+ try path.append(self.arena, wr.expr);
+
+ // This way the data in `path` has the same ordering that the ref
+ // path has in the text: most general component first.
+ std.mem.reverse(DocData.Expr, path.items);
+
+ // Righ now, every element of `path` is a string except its first
+ // element (at index 0). We're now going to attempt to resolve each
+ // string. If one or more components in this path are not yet fully
+ // analyzed, the path will only be solved partially, but we expect
+ // to eventually solve it fully(or give up in case of a
+ // comptimeExpr). This means that:
+ // - (1) Paths can be not fully analyzed temporarily, so any code
+ // that requires to know where a ref path leads to, neeeds to
+ // implement support for lazyness (see self.pending_ref_paths)
+ // - (2) Paths can sometimes never resolve fully. This means that
+ // any value that depends on that will have to become a
+ // comptimeExpr.
+ try self.tryResolveRefPath(file, lhs, path.items);
+ return DocData.WalkResult{ .expr = .{ .refPath = path.items } };
+ },
+ .int_type => {
+ const int_type = data[inst_index].int_type;
+ const sign = if (int_type.signedness == .unsigned) "u" else "i";
+ const bits = int_type.bit_count;
+ const name = try std.fmt.allocPrint(self.arena, "{s}{}", .{ sign, bits });
+
+ try self.types.append(self.arena, .{
+ .Int = .{ .name = name },
+ });
+
+ return DocData.WalkResult{
+ .typeRef = .{ .type = @enumToInt(Ref.type_type) },
+ .expr = .{ .type = self.types.items.len - 1 },
+ };
+ },
+ .block => {
+ const res = DocData.WalkResult{ .expr = .{
+ .comptimeExpr = self.comptime_exprs.items.len,
+ } };
+ try self.comptime_exprs.append(self.arena, .{
+ .code = "if(banana) 1 else 0",
+ });
+ return res;
+ },
+ .block_inline => {
+ return self.walkRef(
+ file,
+ parent_scope,
+ getBlockInlineBreak(file.zir, inst_index),
+ need_type,
+ );
+ },
+ .struct_init => {
+ const pl_node = data[inst_index].pl_node;
+ const extra = file.zir.extraData(Zir.Inst.StructInit, pl_node.payload_index);
+ const field_vals = try self.arena.alloc(
+ DocData.Expr.FieldVal,
+ extra.data.fields_len,
+ );
+
+ var type_ref: DocData.Expr = undefined;
+ var idx = extra.end;
+ for (field_vals) |*fv| {
+ const init_extra = file.zir.extraData(Zir.Inst.StructInit.Item, idx);
+ defer idx = init_extra.end;
+
+ const field_name = blk: {
+ const field_inst_index = init_extra.data.field_type;
+ if (tags[field_inst_index] != .field_type) unreachable;
+ const field_pl_node = data[field_inst_index].pl_node;
+ const field_extra = file.zir.extraData(
+ Zir.Inst.FieldType,
+ field_pl_node.payload_index,
+ );
+
+ // On first iteration use field info to find out the struct type
+ if (idx == extra.end) {
+ const wr = try self.walkRef(
+ file,
+ parent_scope,
+ field_extra.data.container_type,
+ false,
+ );
+ type_ref = wr.expr;
+ }
+ break :blk file.zir.nullTerminatedString(field_extra.data.name_start);
+ };
+ const value = try self.walkRef(
+ file,
+ parent_scope,
+ init_extra.data.init,
+ need_type,
+ );
+ fv.* = .{ .name = field_name, .val = value };
+ }
+
+ return DocData.WalkResult{
+ .typeRef = type_ref,
+ .expr = .{ .@"struct" = field_vals },
+ };
+ },
+ .struct_init_empty => {
+ const un_node = data[inst_index].un_node;
+ var operand: DocData.WalkResult = try self.walkRef(
+ file,
+ parent_scope,
+ un_node.operand,
+ false,
+ );
+
+ _ = operand;
+
+ // WIP
+
+ printWithContext(
+ file,
+ inst_index,
+ "TODO: implement `{s}` for walkInstruction\n\n",
+ .{@tagName(tags[inst_index])},
+ );
+ return self.cteTodo(@tagName(tags[inst_index]));
+ },
+ .error_set_decl => {
+ const pl_node = data[inst_index].pl_node;
+ const extra = file.zir.extraData(Zir.Inst.ErrorSetDecl, pl_node.payload_index);
+ const fields = try self.arena.alloc(
+ DocData.Type.Field,
+ extra.data.fields_len,
+ );
+ var idx = extra.end;
+ for (fields) |*f| {
+ const name = file.zir.nullTerminatedString(file.zir.extra[idx]);
+ idx += 1;
+
+ const docs = file.zir.nullTerminatedString(file.zir.extra[idx]);
+ idx += 1;
+
+ f.* = .{
+ .name = name,
+ .docs = docs,
+ };
+ }
+
+ const type_slot_index = self.types.items.len;
+ try self.types.append(self.arena, .{
+ .ErrorSet = .{
+ .name = "todo errset",
+ .fields = fields,
+ },
+ });
+
+ return DocData.WalkResult{
+ .typeRef = .{ .type = @enumToInt(Ref.type_type) },
+ .expr = .{ .type = type_slot_index },
+ };
+ },
+ .param_anytype, .param_anytype_comptime => {
+ // @check if .param_anytype_comptime can be here
+ // Analysis of anytype function params happens in `.func`.
+ // This switch case handles the case where an expression depends
+ // on an anytype field. E.g.: `fn foo(bar: anytype) @TypeOf(bar)`.
+ // This means that we're looking at a generic expression.
+ const str_tok = data[inst_index].str_tok;
+ const name = str_tok.get(file.zir);
+ const cte_slot_index = self.comptime_exprs.items.len;
+ try self.comptime_exprs.append(self.arena, .{
+ .code = name,
+ });
+ return DocData.WalkResult{ .expr = .{ .comptimeExpr = cte_slot_index } };
+ },
+ .param, .param_comptime => {
+ // See .param_anytype for more information.
+ const pl_tok = data[inst_index].pl_tok;
+ const extra = file.zir.extraData(Zir.Inst.Param, pl_tok.payload_index);
+ const name = file.zir.nullTerminatedString(extra.data.name);
+
+ const cte_slot_index = self.comptime_exprs.items.len;
+ try self.comptime_exprs.append(self.arena, .{
+ .code = name,
+ });
+ return DocData.WalkResult{ .expr = .{ .comptimeExpr = cte_slot_index } };
+ },
+ .call => {
+ const pl_node = data[inst_index].pl_node;
+ const extra = file.zir.extraData(Zir.Inst.Call, pl_node.payload_index);
+
+ const callee = try self.walkRef(file, parent_scope, extra.data.callee, need_type);
+
+ const args_len = extra.data.flags.args_len;
+ var args = try self.arena.alloc(DocData.Expr, args_len);
+ const arg_refs = file.zir.refSlice(extra.end, args_len);
+ for (arg_refs) |ref, idx| {
+ // TODO: consider toggling need_type to true if we ever want
+ // to show discrepancies between the types of provided
+ // arguments and the types declared in the function
+ // signature for its parameters.
+ const wr = try self.walkRef(file, parent_scope, ref, false);
+ args[idx] = wr.expr;
+ }
+
+ const cte_slot_index = self.comptime_exprs.items.len;
+ try self.comptime_exprs.append(self.arena, .{
+ .code = "func call",
+ });
+
+ const call_slot_index = self.calls.items.len;
+ try self.calls.append(self.arena, .{
+ .func = callee.expr,
+ .args = args,
+ .ret = .{ .comptimeExpr = cte_slot_index },
+ });
+
+ return DocData.WalkResult{
+ .typeRef = if (callee.typeRef) |tr| switch (tr) {
+ .type => |func_type_idx| self.types.items[func_type_idx].Fn.ret,
+ else => null,
+ } else null,
+ .expr = .{ .call = call_slot_index },
+ };
+ },
+ .func, .func_inferred => {
+ const type_slot_index = self.types.items.len;
+ try self.types.append(self.arena, .{ .Unanalyzed = .{} });
+
+ const result = self.analyzeFunction(
+ file,
+ parent_scope,
+ inst_index,
+ self_ast_node_index,
+ type_slot_index,
+ );
+
+ return result;
+ },
+ .func_fancy => {
+ const type_slot_index = self.types.items.len;
+ try self.types.append(self.arena, .{ .Unanalyzed = .{} });
+
+ const result = self.analyzeFancyFunction(
+ file,
+ parent_scope,
+ inst_index,
+ self_ast_node_index,
+ type_slot_index,
+ );
+
+ return result;
+ },
+ .extended => {
+ const extended = data[inst_index].extended;
+ switch (extended.opcode) {
+ else => {
+ printWithContext(
+ file,
+ inst_index,
+ "TODO: implement `walkInstruction.extended` for {s}",
+ .{@tagName(extended.opcode)},
+ );
+ return self.cteTodo(@tagName(extended.opcode));
+ },
+ .typeof_peer => {
+ // Zir says it's a NodeMultiOp but in this case it's TypeOfPeer
+ const extra = file.zir.extraData(Zir.Inst.TypeOfPeer, extended.operand);
+ const args = file.zir.refSlice(extra.end, extended.small);
+ const array_data = try self.arena.alloc(usize, args.len);
+
+ var array_type: ?DocData.Expr = null;
+ for (args) |arg, idx| {
+ const wr = try self.walkRef(file, parent_scope, arg, idx == 0);
+ if (idx == 0) {
+ array_type = wr.typeRef;
+ }
+
+ const expr_index = self.exprs.items.len;
+ try self.exprs.append(self.arena, wr.expr);
+ array_data[idx] = expr_index;
+ }
+
+ const type_slot_index = self.types.items.len;
+ try self.types.append(self.arena, .{
+ .Array = .{
+ .len = .{
+ .int = .{
+ .value = args.len,
+ .negated = false,
+ },
+ },
+ .child = .{ .type = 0 },
+ },
+ });
+ const result = DocData.WalkResult{
+ .typeRef = .{ .type = type_slot_index },
+ .expr = .{ .typeOf_peer = array_data },
+ };
+
+ return result;
+ },
+ .opaque_decl => {
+ const small = @bitCast(Zir.Inst.OpaqueDecl.Small, extended.small);
+ var extra_index: usize = extended.operand;
+ const src_node: ?i32 = if (small.has_src_node) blk: {
+ const src_node = @bitCast(i32, file.zir.extra[extra_index]);
+ extra_index += 1;
+ break :blk src_node;
+ } else null;
+ _ = src_node;
+
+ const decls_len = if (small.has_decls_len) blk: {
+ const decls_len = file.zir.extra[extra_index];
+ extra_index += 1;
+ break :blk decls_len;
+ } else 0;
+ _ = decls_len;
+
+ const decls_bits = file.zir.extra[extra_index];
+ _ = decls_bits;
+
+ // const sep = "=" ** 200;
+ // log.debug("{s}", .{sep});
+ // log.debug("small = {any}", .{small});
+ // log.debug("src_node = {}", .{src_node});
+ // log.debug("decls_len = {}", .{decls_len});
+ // log.debug("decls_bit = {}", .{decls_bits});
+ // log.debug("{s}", .{sep});
+ const type_slot_index = self.types.items.len - 1;
+ try self.types.append(self.arena, .{ .Opaque = .{ .name = "TODO" } });
+ return DocData.WalkResult{
+ .typeRef = .{ .type = @enumToInt(Ref.anyopaque_type) },
+ .expr = .{ .type = type_slot_index },
+ };
+ },
+ .variable => {
+ const small = @bitCast(Zir.Inst.ExtendedVar.Small, extended.small);
+ var extra_index: usize = extended.operand;
+ if (small.has_lib_name) extra_index += 1;
+ if (small.has_align) extra_index += 1;
+
+ const value: DocData.WalkResult = if (small.has_init) .{
+ .expr = .{ .void = .{} },
+ } else .{
+ .expr = .{ .void = .{} },
+ };
+
+ return value;
+ },
+ .union_decl => {
+ const type_slot_index = self.types.items.len;
+ try self.types.append(self.arena, .{ .Unanalyzed = .{} });
+
+ var scope: Scope = .{
+ .parent = parent_scope,
+ .enclosing_type = type_slot_index,
+ };
+
+ const small = @bitCast(Zir.Inst.UnionDecl.Small, extended.small);
+ var extra_index: usize = extended.operand;
+
+ const src_node: ?i32 = if (small.has_src_node) blk: {
+ const src_node = @bitCast(i32, file.zir.extra[extra_index]);
+ extra_index += 1;
+ break :blk src_node;
+ } else null;
+ _ = src_node;
+
+ const tag_type: ?Ref = if (small.has_tag_type) blk: {
+ const tag_type = file.zir.extra[extra_index];
+ extra_index += 1;
+ break :blk @intToEnum(Ref, tag_type);
+ } else null;
+ _ = tag_type;
+
+ const body_len = if (small.has_body_len) blk: {
+ const body_len = file.zir.extra[extra_index];
+ extra_index += 1;
+ break :blk body_len;
+ } else 0;
+
+ const fields_len = if (small.has_fields_len) blk: {
+ const fields_len = file.zir.extra[extra_index];
+ extra_index += 1;
+ break :blk fields_len;
+ } else 0;
+ _ = fields_len;
+
+ const decls_len = if (small.has_decls_len) blk: {
+ const decls_len = file.zir.extra[extra_index];
+ extra_index += 1;
+ break :blk decls_len;
+ } else 0;
+
+ var decl_indexes: std.ArrayListUnmanaged(usize) = .{};
+ var priv_decl_indexes: std.ArrayListUnmanaged(usize) = .{};
+
+ const decls_first_index = self.decls.items.len;
+ // Decl name lookahead for reserving slots in `scope` (and `decls`).
+ // Done to make sure that all decl refs can be resolved correctly,
+ // even if we haven't fully analyzed the decl yet.
+ {
+ var it = file.zir.declIterator(@intCast(u32, inst_index));
+ try self.decls.resize(self.arena, decls_first_index + it.decls_len);
+ for (self.decls.items[decls_first_index..]) |*slot| {
+ slot._analyzed = false;
+ }
+ var decls_slot_index = decls_first_index;
+ while (it.next()) |d| : (decls_slot_index += 1) {
+ const decl_name_index = file.zir.extra[d.sub_index + 5];
+ try scope.insertDeclRef(self.arena, decl_name_index, decls_slot_index);
+ }
+ }
+
+ extra_index = try self.walkDecls(
+ file,
+ &scope,
+ decls_first_index,
+ decls_len,
+ &decl_indexes,
+ &priv_decl_indexes,
+ extra_index,
+ );
+
+ extra_index += body_len;
+
+ var field_type_refs = try std.ArrayListUnmanaged(DocData.Expr).initCapacity(
+ self.arena,
+ fields_len,
+ );
+ var field_name_indexes = try std.ArrayListUnmanaged(usize).initCapacity(
+ self.arena,
+ fields_len,
+ );
+ try self.collectUnionFieldInfo(
+ file,
+ &scope,
+ fields_len,
+ &field_type_refs,
+ &field_name_indexes,
+ extra_index,
+ );
+
+ self.ast_nodes.items[self_ast_node_index].fields = field_name_indexes.items;
+
+ self.types.items[type_slot_index] = .{
+ .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 },
+ };
+
+ if (self.ref_paths_pending_on_types.get(type_slot_index)) |paths| {
+ for (paths.items) |resume_info| {
+ try self.tryResolveRefPath(
+ resume_info.file,
+ inst_index,
+ resume_info.ref_path,
+ );
+ }
+
+ _ = self.ref_paths_pending_on_types.remove(type_slot_index);
+ // TODO: we should deallocate the arraylist that holds all the
+ // decl paths. not doing it now since it's arena-allocated
+ // anyway, but maybe we should put it elsewhere.
+ }
+
+ return DocData.WalkResult{
+ .typeRef = .{ .type = @enumToInt(Ref.type_type) },
+ .expr = .{ .type = type_slot_index },
+ };
+ },
+ .enum_decl => {
+ const type_slot_index = self.types.items.len;
+ try self.types.append(self.arena, .{ .Unanalyzed = .{} });
+
+ var scope: Scope = .{
+ .parent = parent_scope,
+ .enclosing_type = type_slot_index,
+ };
+
+ const small = @bitCast(Zir.Inst.EnumDecl.Small, extended.small);
+ var extra_index: usize = extended.operand;
+
+ const src_node: ?i32 = if (small.has_src_node) blk: {
+ const src_node = @bitCast(i32, file.zir.extra[extra_index]);
+ extra_index += 1;
+ break :blk src_node;
+ } else null;
+ _ = src_node;
+
+ const tag_type: ?Ref = if (small.has_tag_type) blk: {
+ const tag_type = file.zir.extra[extra_index];
+ extra_index += 1;
+ break :blk @intToEnum(Ref, tag_type);
+ } else null;
+ _ = tag_type;
+
+ const body_len = if (small.has_body_len) blk: {
+ const body_len = file.zir.extra[extra_index];
+ extra_index += 1;
+ break :blk body_len;
+ } else 0;
+
+ const fields_len = if (small.has_fields_len) blk: {
+ const fields_len = file.zir.extra[extra_index];
+ extra_index += 1;
+ break :blk fields_len;
+ } else 0;
+ _ = fields_len;
+
+ const decls_len = if (small.has_decls_len) blk: {
+ const decls_len = file.zir.extra[extra_index];
+ extra_index += 1;
+ break :blk decls_len;
+ } else 0;
+
+ var decl_indexes: std.ArrayListUnmanaged(usize) = .{};
+ var priv_decl_indexes: std.ArrayListUnmanaged(usize) = .{};
+
+ const decls_first_index = self.decls.items.len;
+ // Decl name lookahead for reserving slots in `scope` (and `decls`).
+ // Done to make sure that all decl refs can be resolved correctly,
+ // even if we haven't fully analyzed the decl yet.
+ {
+ var it = file.zir.declIterator(@intCast(u32, inst_index));
+ try self.decls.resize(self.arena, decls_first_index + it.decls_len);
+ for (self.decls.items[decls_first_index..]) |*slot| {
+ slot._analyzed = false;
+ }
+ var decls_slot_index = decls_first_index;
+ while (it.next()) |d| : (decls_slot_index += 1) {
+ const decl_name_index = file.zir.extra[d.sub_index + 5];
+ try scope.insertDeclRef(self.arena, decl_name_index, decls_slot_index);
+ }
+ }
+
+ extra_index = try self.walkDecls(
+ file,
+ &scope,
+ decls_first_index,
+ decls_len,
+ &decl_indexes,
+ &priv_decl_indexes,
+ extra_index,
+ );
+
+ // const body = file.zir.extra[extra_index..][0..body_len];
+ extra_index += body_len;
+
+ var field_name_indexes: std.ArrayListUnmanaged(usize) = .{};
+ {
+ var bit_bag_idx = extra_index;
+ var cur_bit_bag: u32 = undefined;
+ extra_index += std.math.divCeil(usize, fields_len, 32) catch unreachable;
+
+ var idx: usize = 0;
+ while (idx < fields_len) : (idx += 1) {
+ if (idx % 32 == 0) {
+ cur_bit_bag = file.zir.extra[bit_bag_idx];
+ bit_bag_idx += 1;
+ }
+
+ const has_value = @truncate(u1, cur_bit_bag) != 0;
+ cur_bit_bag >>= 1;
+
+ const field_name_index = file.zir.extra[extra_index];
+ extra_index += 1;
+
+ const doc_comment_index = file.zir.extra[extra_index];
+ extra_index += 1;
+
+ const value_ref: ?Ref = if (has_value) blk: {
+ const value_ref = file.zir.extra[extra_index];
+ extra_index += 1;
+ break :blk @intToEnum(Ref, value_ref);
+ } else null;
+ _ = value_ref;
+
+ const field_name = file.zir.nullTerminatedString(field_name_index);
+
+ try field_name_indexes.append(self.arena, self.ast_nodes.items.len);
+ const doc_comment: ?[]const u8 = if (doc_comment_index != 0)
+ file.zir.nullTerminatedString(doc_comment_index)
+ else
+ null;
+ try self.ast_nodes.append(self.arena, .{
+ .name = field_name,
+ .docs = doc_comment,
+ });
+ }
+ }
+
+ self.ast_nodes.items[self_ast_node_index].fields = field_name_indexes.items;
+
+ self.types.items[type_slot_index] = .{
+ .Enum = .{ .name = "todo_name", .src = self_ast_node_index, .privDecls = priv_decl_indexes.items, .pubDecls = decl_indexes.items, .ast = self_ast_node_index },
+ };
+ if (self.ref_paths_pending_on_types.get(type_slot_index)) |paths| {
+ for (paths.items) |resume_info| {
+ try self.tryResolveRefPath(
+ resume_info.file,
+ inst_index,
+ resume_info.ref_path,
+ );
+ }
+
+ _ = self.ref_paths_pending_on_types.remove(type_slot_index);
+ // TODO: we should deallocate the arraylist that holds all the
+ // decl paths. not doing it now since it's arena-allocated
+ // anyway, but maybe we should put it elsewhere.
+ }
+ return DocData.WalkResult{
+ .typeRef = .{ .type = @enumToInt(Ref.type_type) },
+ .expr = .{ .type = type_slot_index },
+ };
+ },
+ .struct_decl => {
+ const type_slot_index = self.types.items.len;
+ try self.types.append(self.arena, .{ .Unanalyzed = .{} });
+
+ var scope: Scope = .{
+ .parent = parent_scope,
+ .enclosing_type = type_slot_index,
+ };
+
+ const small = @bitCast(Zir.Inst.StructDecl.Small, extended.small);
+ var extra_index: usize = extended.operand;
+
+ const src_node: ?i32 = if (small.has_src_node) blk: {
+ const src_node = @bitCast(i32, file.zir.extra[extra_index]);
+ extra_index += 1;
+ break :blk src_node;
+ } else null;
+ _ = src_node;
+
+ const fields_len = if (small.has_fields_len) blk: {
+ const fields_len = file.zir.extra[extra_index];
+ extra_index += 1;
+ break :blk fields_len;
+ } else 0;
+ _ = fields_len;
+
+ const decls_len = if (small.has_decls_len) blk: {
+ const decls_len = file.zir.extra[extra_index];
+ extra_index += 1;
+ break :blk decls_len;
+ } else 0;
+
+ var decl_indexes: std.ArrayListUnmanaged(usize) = .{};
+ var priv_decl_indexes: std.ArrayListUnmanaged(usize) = .{};
+
+ const decls_first_index = self.decls.items.len;
+ // Decl name lookahead for reserving slots in `scope` (and `decls`).
+ // Done to make sure that all decl refs can be resolved correctly,
+ // even if we haven't fully analyzed the decl yet.
+ {
+ var it = file.zir.declIterator(@intCast(u32, inst_index));
+ try self.decls.resize(self.arena, decls_first_index + it.decls_len);
+ for (self.decls.items[decls_first_index..]) |*slot| {
+ slot._analyzed = false;
+ }
+ var decls_slot_index = decls_first_index;
+ while (it.next()) |d| : (decls_slot_index += 1) {
+ const decl_name_index = file.zir.extra[d.sub_index + 5];
+ try scope.insertDeclRef(self.arena, decl_name_index, decls_slot_index);
+ }
+ }
+
+ extra_index = try self.walkDecls(
+ file,
+ &scope,
+ decls_first_index,
+ decls_len,
+ &decl_indexes,
+ &priv_decl_indexes,
+ extra_index,
+ );
+
+ var field_type_refs: std.ArrayListUnmanaged(DocData.Expr) = .{};
+ var field_name_indexes: std.ArrayListUnmanaged(usize) = .{};
+ try self.collectStructFieldInfo(
+ file,
+ &scope,
+ fields_len,
+ &field_type_refs,
+ &field_name_indexes,
+ extra_index,
+ );
+
+ self.ast_nodes.items[self_ast_node_index].fields = field_name_indexes.items;
+
+ self.types.items[type_slot_index] = .{
+ .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 },
+ };
+ if (self.ref_paths_pending_on_types.get(type_slot_index)) |paths| {
+ for (paths.items) |resume_info| {
+ try self.tryResolveRefPath(
+ resume_info.file,
+ inst_index,
+ resume_info.ref_path,
+ );
+ }
+
+ _ = self.ref_paths_pending_on_types.remove(type_slot_index);
+ // TODO: we should deallocate the arraylist that holds all the
+ // decl paths. not doing it now since it's arena-allocated
+ // anyway, but maybe we should put it elsewhere.
+ }
+ return DocData.WalkResult{
+ .typeRef = .{ .type = @enumToInt(Ref.type_type) },
+ .expr = .{ .type = type_slot_index },
+ };
+ },
+ .this => {
+ return DocData.WalkResult{
+ .typeRef = .{ .type = @enumToInt(Ref.type_type) },
+ .expr = .{ .this = parent_scope.enclosing_type },
+ };
+ },
+ .error_to_int,
+ .int_to_error,
+ => {
+ const extra = file.zir.extraData(Zir.Inst.UnNode, extended.operand).data;
+ const bin_index = self.exprs.items.len;
+ try self.exprs.append(self.arena, .{ .builtin = .{ .param = 0 } });
+ const param = try self.walkRef(file, parent_scope, extra.operand, false);
+
+ const param_index = self.exprs.items.len;
+ try self.exprs.append(self.arena, param.expr);
+
+ self.exprs.items[bin_index] = .{ .builtin = .{ .name = @tagName(tags[inst_index]), .param = param_index } };
+
+ return DocData.WalkResult{
+ .typeRef = param.typeRef orelse .{ .type = @enumToInt(Ref.type_type) },
+ .expr = .{ .builtinIndex = bin_index },
+ };
+ },
+ }
+ },
+ }
+}
+
+/// Called by `walkInstruction` when encountering a container type.
+/// Iterates over all decl definitions in its body and it also analyzes each
+/// decl's body recursively by calling into `walkInstruction`.
+///
+/// Does not append to `self.decls` directly because `walkInstruction`
+/// is expected to look-ahead scan all decls and reserve `body_len`
+/// slots in `self.decls`, which are then filled out by this function.
+fn walkDecls(
+ self: *Autodoc,
+ file: *File,
+ scope: *Scope,
+ decls_first_index: usize,
+ decls_len: u32,
+ decl_indexes: *std.ArrayListUnmanaged(usize),
+ priv_decl_indexes: *std.ArrayListUnmanaged(usize),
+ extra_start: usize,
+) AutodocErrors!usize {
+ const bit_bags_count = std.math.divCeil(usize, decls_len, 8) catch unreachable;
+ var extra_index = extra_start + bit_bags_count;
+ var bit_bag_index: usize = extra_start;
+ var cur_bit_bag: u32 = undefined;
+ var decl_i: u32 = 0;
+
+ while (decl_i < decls_len) : (decl_i += 1) {
+ const decls_slot_index = decls_first_index + decl_i;
+
+ if (decl_i % 8 == 0) {
+ cur_bit_bag = file.zir.extra[bit_bag_index];
+ bit_bag_index += 1;
+ }
+ const is_pub = @truncate(u1, cur_bit_bag) != 0;
+ cur_bit_bag >>= 1;
+ const is_exported = @truncate(u1, cur_bit_bag) != 0;
+ cur_bit_bag >>= 1;
+ const has_align = @truncate(u1, cur_bit_bag) != 0;
+ cur_bit_bag >>= 1;
+ const has_section_or_addrspace = @truncate(u1, cur_bit_bag) != 0;
+ cur_bit_bag >>= 1;
+
+ // const sub_index = extra_index;
+
+ // const hash_u32s = file.zir.extra[extra_index..][0..4];
+ extra_index += 4;
+ const line = file.zir.extra[extra_index];
+ extra_index += 1;
+ const decl_name_index = file.zir.extra[extra_index];
+ extra_index += 1;
+ const value_index = file.zir.extra[extra_index];
+ extra_index += 1;
+ const doc_comment_index = file.zir.extra[extra_index];
+ extra_index += 1;
+
+ const align_inst: Zir.Inst.Ref = if (!has_align) .none else inst: {
+ const inst = @intToEnum(Zir.Inst.Ref, file.zir.extra[extra_index]);
+ extra_index += 1;
+ break :inst inst;
+ };
+ _ = align_inst;
+
+ const section_inst: Zir.Inst.Ref = if (!has_section_or_addrspace) .none else inst: {
+ const inst = @intToEnum(Zir.Inst.Ref, file.zir.extra[extra_index]);
+ extra_index += 1;
+ break :inst inst;
+ };
+ _ = section_inst;
+
+ const addrspace_inst: Zir.Inst.Ref = if (!has_section_or_addrspace) .none else inst: {
+ const inst = @intToEnum(Zir.Inst.Ref, file.zir.extra[extra_index]);
+ extra_index += 1;
+ break :inst inst;
+ };
+ _ = addrspace_inst;
+
+ // const pub_str = if (is_pub) "pub " else "";
+ // const hash_bytes = @bitCast([16]u8, hash_u32s.*);
+
+ var is_test = false; // we discover if it's a test by lookin at its name
+ const name: []const u8 = blk: {
+ if (decl_name_index == 0) {
+ break :blk if (is_exported) "usingnamespace" else "comptime";
+ } else if (decl_name_index == 1) {
+ is_test = true;
+ break :blk "test";
+ } else if (decl_name_index == 2) {
+ is_test = true;
+ // TODO: remove temporary hack
+ break :blk "test";
+ // // it is a decltest
+ // const decl_being_tested = scope.resolveDeclName(doc_comment_index);
+ // const ast_node_index = idx: {
+ // const idx = self.ast_nodes.items.len;
+ // const file_source = file.getSource(self.module.gpa) catch unreachable; // TODO fix this
+ // const source_of_decltest_function = srcloc: {
+ // const func_index = getBlockInlineBreak(file.zir, value_index);
+ // // a decltest is always a function
+ // const tag = file.zir.instructions.items(.tag)[Zir.refToIndex(func_index).?];
+ // std.debug.assert(tag == .func_extended);
+
+ // const pl_node = file.zir.instructions.items(.data)[Zir.refToIndex(func_index).?].pl_node;
+ // const extra = file.zir.extraData(Zir.Inst.ExtendedFunc, pl_node.payload_index);
+ // const bits = @bitCast(Zir.Inst.ExtendedFunc.Bits, extra.data.bits);
+
+ // var extra_index_for_this_func: usize = extra.end;
+ // if (bits.has_lib_name) extra_index_for_this_func += 1;
+ // if (bits.has_cc) extra_index_for_this_func += 1;
+ // if (bits.has_align) extra_index_for_this_func += 1;
+
+ // const ret_ty_body = file.zir.extra[extra_index_for_this_func..][0..extra.data.ret_body_len];
+ // extra_index_for_this_func += ret_ty_body.len;
+
+ // const body = file.zir.extra[extra_index_for_this_func..][0..extra.data.body_len];
+ // extra_index_for_this_func += body.len;
+
+ // var src_locs: Zir.Inst.Func.SrcLocs = undefined;
+ // if (body.len != 0) {
+ // src_locs = file.zir.extraData(Zir.Inst.Func.SrcLocs, extra_index_for_this_func).data;
+ // } else {
+ // src_locs = .{
+ // .lbrace_line = line,
+ // .rbrace_line = line,
+ // .columns = 0, // TODO get columns when body.len == 0
+ // };
+ // }
+ // break :srcloc src_locs;
+ // };
+ // const source_slice = slice: {
+ // var start_byte_offset: u32 = 0;
+ // var end_byte_offset: u32 = 0;
+ // const rbrace_col = @truncate(u16, source_of_decltest_function.columns >> 16);
+ // var lines: u32 = 0;
+ // for (file_source.bytes) |b, i| {
+ // if (b == '\n') {
+ // lines += 1;
+ // }
+ // if (lines == source_of_decltest_function.lbrace_line) {
+ // start_byte_offset = @intCast(u32, i);
+ // }
+ // if (lines == source_of_decltest_function.rbrace_line) {
+ // end_byte_offset = @intCast(u32, i) + rbrace_col;
+ // break;
+ // }
+ // }
+ // break :slice file_source.bytes[start_byte_offset..end_byte_offset];
+ // };
+ // try self.ast_nodes.append(self.arena, .{
+ // .file = 0,
+ // .line = line,
+ // .col = 0,
+ // .name = try self.arena.dupe(u8, source_slice),
+ // });
+ // break :idx idx;
+ // };
+ // self.decls.items[decl_being_tested].decltest = ast_node_index;
+ // self.decls.items[decls_slot_index] = .{
+ // ._analyzed = true,
+ // .name = "test",
+ // .isTest = true,
+ // .src = ast_node_index,
+ // .value = .{ .expr = .{ .type = 0 } },
+ // .kind = "const",
+ // };
+ // continue;
+ } else {
+ const raw_decl_name = file.zir.nullTerminatedString(decl_name_index);
+ if (raw_decl_name.len == 0) {
+ is_test = true;
+ break :blk file.zir.nullTerminatedString(decl_name_index + 1);
+ } else {
+ break :blk raw_decl_name;
+ }
+ }
+ };
+
+ const doc_comment: ?[]const u8 = if (doc_comment_index != 0)
+ file.zir.nullTerminatedString(doc_comment_index)
+ else
+ null;
+
+ // astnode
+ const ast_node_index = idx: {
+ const idx = self.ast_nodes.items.len;
+ try self.ast_nodes.append(self.arena, .{
+ .file = 0,
+ .line = line,
+ .col = 0,
+ .docs = doc_comment,
+ .fields = null, // walkInstruction will fill `fields` if necessary
+ });
+ break :idx idx;
+ };
+
+ const walk_result = if (is_test) // TODO: decide if tests should show up at all
+ DocData.WalkResult{ .expr = .{ .void = .{} } }
+ else
+ try self.walkInstruction(file, scope, value_index, true);
+
+ if (is_pub) {
+ try decl_indexes.append(self.arena, decls_slot_index);
+ } else {
+ try priv_decl_indexes.append(self.arena, decls_slot_index);
+ }
+
+ // // decl.typeRef == decl.val...typeRef
+ // const decl_type_ref: DocData.TypeRef = switch (walk_result) {
+ // .int => |i| i.typeRef,
+ // .void => .{ .type = @enumToInt(Ref.void_type) },
+ // .@"undefined", .@"null" => |v| v,
+ // .@"unreachable" => .{ .type = @enumToInt(Ref.noreturn_type) },
+ // .@"struct" => |s| s.typeRef,
+ // .bool => .{ .type = @enumToInt(Ref.bool_type) },
+ // .type => .{ .type = @enumToInt(Ref.type_type) },
+ // // this last case is special becauese it's not pointing
+ // // at the type of the value, but rather at the value itself
+ // // the js better be aware ot this!
+ // .declRef => |d| .{ .declRef = d },
+ // };
+
+ self.decls.items[decls_slot_index] = .{
+ ._analyzed = true,
+ .name = name,
+ .isTest = is_test,
+ .src = ast_node_index,
+ //.typeRef = decl_type_ref,
+ .value = walk_result,
+ .kind = "const", // find where this information can be found
+ };
+
+ // Unblock any pending decl path that was waiting for this decl.
+ if (self.ref_paths_pending_on_decls.get(decls_slot_index)) |paths| {
+ for (paths.items) |resume_info| {
+ try self.tryResolveRefPath(
+ resume_info.file,
+ value_index,
+ resume_info.ref_path,
+ );
+ }
+
+ _ = self.ref_paths_pending_on_decls.remove(decls_slot_index);
+ // TODO: we should deallocate the arraylist that holds all the
+ // ref paths. not doing it now since it's arena-allocated
+ // anyway, but maybe we should put it elsewhere.
+ }
+ }
+
+ return extra_index;
+}
+
+/// An unresolved path has a non-string WalkResult at its beginnig, while every
+/// other element is a string WalkResult. Resolving means iteratively map each
+/// string to a Decl / Type / Call / etc.
+///
+/// If we encounter an unanalyzed decl during the process, we append the
+/// unsolved sub-path to `self.ref_paths_pending_on_decls` and bail out.
+/// Same happens when a decl holds a type definition that hasn't been fully
+/// analyzed yet (except that we append to `self.ref_paths_pending_on_types`.
+///
+/// When walkDecls / walkInstruction finishes analyzing a decl / type, it will
+/// then check if there's any pending ref path blocked on it and, if any, it
+/// will progress their resolution by calling tryResolveRefPath again.
+///
+/// Ref paths can also depend on other ref paths. See
+/// `self.pending_ref_paths` for more info.
+///
+/// A ref path that has a component that resolves into a comptimeExpr will
+/// give up its resolution process entirely, leaving the remaining components
+/// as strings.
+fn tryResolveRefPath(
+ self: *Autodoc,
+ /// File from which the decl path originates.
+ file: *File,
+ inst_index: usize, // used only for panicWithContext
+ path: []DocData.Expr,
+) AutodocErrors!void {
+ var i: usize = 0;
+ outer: while (i < path.len - 1) : (i += 1) {
+ const parent = path[i];
+ const child_string = path[i + 1].string; // we expect to find a string union case
+
+ var resolved_parent = parent;
+ var j: usize = 0;
+ while (j < 10_000) : (j += 1) {
+ switch (resolved_parent) {
+ else => break,
+ .this => |t| resolved_parent = .{ .type = t },
+ .declRef => |decl_index| {
+ const decl = self.decls.items[decl_index];
+ if (decl._analyzed) {
+ resolved_parent = decl.value.expr;
+ continue;
+ }
+
+ // This decl path is pending completion
+ {
+ const res = try self.pending_ref_paths.getOrPut(
+ self.arena,
+ &path[path.len - 1],
+ );
+ if (!res.found_existing) res.value_ptr.* = .{};
+ }
+
+ const res = try self.ref_paths_pending_on_decls.getOrPut(
+ self.arena,
+ decl_index,
+ );
+ if (!res.found_existing) res.value_ptr.* = .{};
+ try res.value_ptr.*.append(self.arena, .{
+ .file = file,
+ .ref_path = path[i..path.len],
+ });
+
+ // We return instead doing `break :outer` to prevent the
+ // code after the :outer while loop to run, as it assumes
+ // that the path will have been fully analyzed (or we
+ // have given up because of a comptimeExpr).
+ return;
+ },
+ .refPath => |rp| {
+ if (self.pending_ref_paths.getPtr(&rp[rp.len - 1])) |waiter_list| {
+ try waiter_list.append(self.arena, .{
+ .file = file,
+ .ref_path = path[i..path.len],
+ });
+
+ // This decl path is pending completion
+ {
+ const res = try self.pending_ref_paths.getOrPut(
+ self.arena,
+ &path[path.len - 1],
+ );
+ if (!res.found_existing) res.value_ptr.* = .{};
+ }
+
+ return;
+ }
+
+ // If the last element is a string or a CTE, then we give up,
+ // otherwise we resovle the parent to it and loop again.
+ // NOTE: we assume that if we find a string, it's because of
+ // a CTE component somewhere in the path. We know that the path
+ // is not pending futher evaluation because we just checked!
+ const last = rp[rp.len - 1];
+ switch (last) {
+ .comptimeExpr, .string => break :outer,
+ else => {
+ resolved_parent = last;
+ continue;
+ },
+ }
+ },
+ }
+ } else {
+ panicWithContext(
+ file,
+ inst_index,
+ "exhausted eval quota for `{}`in tryResolveDecl\n",
+ .{resolved_parent},
+ );
+ }
+
+ switch (resolved_parent) {
+ else => {
+ // NOTE: indirect references to types / decls should be handled
+ // in the switch above this one!
+ printWithContext(
+ file,
+ inst_index,
+ "TODO: handle `{s}`in tryResolveRefPath\nInfo: {}",
+ .{ @tagName(resolved_parent), resolved_parent },
+ );
+ path[i + 1] = (try self.cteTodo("match failure")).expr;
+ continue :outer;
+ },
+ .comptimeExpr, .call, .typeOf => {
+ // Since we hit a cte, we leave the remaining strings unresolved
+ // and completely give up on resolving this decl path.
+ //decl_path.hasCte = true;
+ break :outer;
+ },
+ .type => |t_index| switch (self.types.items[t_index]) {
+ else => {
+ panicWithContext(
+ file,
+ inst_index,
+ "TODO: handle `{s}` in tryResolveDeclPath.type\nInfo: {}",
+ .{ @tagName(self.types.items[t_index]), resolved_parent },
+ );
+ },
+ .Unanalyzed => {
+ // This decl path is pending completion
+ {
+ const res = try self.pending_ref_paths.getOrPut(
+ self.arena,
+ &path[path.len - 1],
+ );
+ if (!res.found_existing) res.value_ptr.* = .{};
+ }
+
+ const res = try self.ref_paths_pending_on_types.getOrPut(
+ self.arena,
+ t_index,
+ );
+ if (!res.found_existing) res.value_ptr.* = .{};
+ try res.value_ptr.*.append(self.arena, .{
+ .file = file,
+ .ref_path = path[i..path.len],
+ });
+
+ return;
+ },
+ .Enum => |t_enum| {
+ for (t_enum.pubDecls) |d| {
+ // TODO: this could be improved a lot
+ // by having our own string table!
+ const decl = self.decls.items[d];
+ if (std.mem.eql(u8, decl.name, child_string)) {
+ path[i + 1] = .{ .declRef = d };
+ continue :outer;
+ }
+ }
+ for (t_enum.privDecls) |d| {
+ // TODO: this could be improved a lot
+ // by having our own string table!
+ const decl = self.decls.items[d];
+ if (std.mem.eql(u8, decl.name, child_string)) {
+ path[i + 1] = .{ .declRef = d };
+ continue :outer;
+ }
+ }
+
+ for (self.ast_nodes.items[t_enum.src].fields.?) |ast_node, idx| {
+ const name = self.ast_nodes.items[ast_node].name.?;
+ if (std.mem.eql(u8, name, child_string)) {
+ // TODO: should we really create an artificial
+ // decl for this type? Probably not.
+
+ path[i + 1] = .{
+ .fieldRef = .{
+ .type = t_index,
+ .index = idx,
+ },
+ };
+ continue :outer;
+ }
+ }
+
+ // if we got here, our search failed
+ printWithContext(
+ file,
+ inst_index,
+ "failed to match `{s}` in enum",
+ .{child_string},
+ );
+
+ path[i + 1] = (try self.cteTodo("match failure")).expr;
+ continue :outer;
+ },
+ .Union => |t_union| {
+ for (t_union.pubDecls) |d| {
+ // TODO: this could be improved a lot
+ // by having our own string table!
+ const decl = self.decls.items[d];
+ if (std.mem.eql(u8, decl.name, child_string)) {
+ path[i + 1] = .{ .declRef = d };
+ continue :outer;
+ }
+ }
+ for (t_union.privDecls) |d| {
+ // TODO: this could be improved a lot
+ // by having our own string table!
+ const decl = self.decls.items[d];
+ if (std.mem.eql(u8, decl.name, child_string)) {
+ path[i + 1] = .{ .declRef = d };
+ continue :outer;
+ }
+ }
+
+ for (self.ast_nodes.items[t_union.src].fields.?) |ast_node, idx| {
+ const name = self.ast_nodes.items[ast_node].name.?;
+ if (std.mem.eql(u8, name, child_string)) {
+ // TODO: should we really create an artificial
+ // decl for this type? Probably not.
+
+ path[i + 1] = .{
+ .fieldRef = .{
+ .type = t_index,
+ .index = idx,
+ },
+ };
+ continue :outer;
+ }
+ }
+
+ // if we got here, our search failed
+ printWithContext(
+ file,
+ inst_index,
+ "failed to match `{s}` in union",
+ .{child_string},
+ );
+ path[i + 1] = (try self.cteTodo("match failure")).expr;
+ continue :outer;
+ },
+
+ .Struct => |t_struct| {
+ for (t_struct.pubDecls) |d| {
+ // TODO: this could be improved a lot
+ // by having our own string table!
+ const decl = self.decls.items[d];
+ if (std.mem.eql(u8, decl.name, child_string)) {
+ path[i + 1] = .{ .declRef = d };
+ continue :outer;
+ }
+ }
+ for (t_struct.privDecls) |d| {
+ // TODO: this could be improved a lot
+ // by having our own string table!
+ const decl = self.decls.items[d];
+ if (std.mem.eql(u8, decl.name, child_string)) {
+ path[i + 1] = .{ .declRef = d };
+ continue :outer;
+ }
+ }
+
+ for (self.ast_nodes.items[t_struct.src].fields.?) |ast_node, idx| {
+ const name = self.ast_nodes.items[ast_node].name.?;
+ if (std.mem.eql(u8, name, child_string)) {
+ // TODO: should we really create an artificial
+ // decl for this type? Probably not.
+
+ path[i + 1] = .{
+ .fieldRef = .{
+ .type = t_index,
+ .index = idx,
+ },
+ };
+ continue :outer;
+ }
+ }
+
+ // if we got here, our search failed
+ // printWithContext(
+ // file,
+ // inst_index,
+ // "failed to match `{s}` in struct",
+ // .{child_string},
+ // );
+ // path[i + 1] = (try self.cteTodo("match failure")).expr;
+ //
+ // that's working
+ path[i + 1] = (try self.cteTodo(child_string)).expr;
+ continue :outer;
+ },
+ },
+ }
+ }
+
+ if (self.pending_ref_paths.get(&path[path.len - 1])) |waiter_list| {
+ // It's important to de-register oureslves as pending before
+ // attempting to resolve any other decl.
+ _ = self.pending_ref_paths.remove(&path[path.len - 1]);
+
+ for (waiter_list.items) |resume_info| {
+ try self.tryResolveRefPath(resume_info.file, inst_index, resume_info.ref_path);
+ }
+ // TODO: this is where we should free waiter_list, but its in the arena
+ // that said, we might want to store it elsewhere and reclaim memory asap
+ }
+}
+fn analyzeFancyFunction(
+ self: *Autodoc,
+ file: *File,
+ scope: *Scope,
+ inst_index: usize,
+ self_ast_node_index: usize,
+ type_slot_index: usize,
+) AutodocErrors!DocData.WalkResult {
+ const tags = file.zir.instructions.items(.tag);
+ const data = file.zir.instructions.items(.data);
+ const fn_info = file.zir.getFnInfo(@intCast(u32, inst_index));
+
+ try self.ast_nodes.ensureUnusedCapacity(self.arena, fn_info.total_params_len);
+ var param_type_refs = try std.ArrayListUnmanaged(DocData.Expr).initCapacity(
+ self.arena,
+ fn_info.total_params_len,
+ );
+ var param_ast_indexes = try std.ArrayListUnmanaged(usize).initCapacity(
+ self.arena,
+ fn_info.total_params_len,
+ );
+
+ // TODO: handle scope rules for fn parameters
+ for (fn_info.param_body[0..fn_info.total_params_len]) |param_index| {
+ switch (tags[param_index]) {
+ else => {
+ panicWithContext(
+ file,
+ param_index,
+ "TODO: handle `{s}` in walkInstruction.func\n",
+ .{@tagName(tags[param_index])},
+ );
+ },
+ .param_anytype, .param_anytype_comptime => {
+ // TODO: where are the doc comments?
+ const str_tok = data[param_index].str_tok;
+
+ const name = str_tok.get(file.zir);
+
+ param_ast_indexes.appendAssumeCapacity(self.ast_nodes.items.len);
+ self.ast_nodes.appendAssumeCapacity(.{
+ .name = name,
+ .docs = "",
+ .@"comptime" = tags[param_index] == .param_anytype_comptime,
+ });
+
+ param_type_refs.appendAssumeCapacity(
+ DocData.Expr{ .@"anytype" = .{} },
+ );
+ },
+ .param, .param_comptime => {
+ const pl_tok = data[param_index].pl_tok;
+ const extra = file.zir.extraData(Zir.Inst.Param, pl_tok.payload_index);
+ const doc_comment = if (extra.data.doc_comment != 0)
+ file.zir.nullTerminatedString(extra.data.doc_comment)
+ else
+ "";
+ const name = file.zir.nullTerminatedString(extra.data.name);
+
+ param_ast_indexes.appendAssumeCapacity(self.ast_nodes.items.len);
+ try self.ast_nodes.append(self.arena, .{
+ .name = name,
+ .docs = doc_comment,
+ .@"comptime" = tags[param_index] == .param_comptime,
+ });
+
+ const break_index = file.zir.extra[extra.end..][extra.data.body_len - 1];
+ const break_operand = data[break_index].@"break".operand;
+ const param_type_ref = try self.walkRef(file, scope, break_operand, false);
+
+ param_type_refs.appendAssumeCapacity(param_type_ref.expr);
+ },
+ }
+ }
+
+ self.ast_nodes.items[self_ast_node_index].fields = param_ast_indexes.items;
+
+ const inst_data = data[inst_index].pl_node;
+ const extra = file.zir.extraData(Zir.Inst.FuncFancy, inst_data.payload_index);
+
+ var extra_index: usize = extra.end;
+
+ var lib_name: []const u8 = "";
+ if (extra.data.bits.has_lib_name) {
+ lib_name = file.zir.nullTerminatedString(file.zir.extra[extra_index]);
+ extra_index += 1;
+ }
+
+ var align_index: ?usize = null;
+ if (extra.data.bits.has_align_ref) {
+ const align_ref = @intToEnum(Zir.Inst.Ref, file.zir.extra[extra_index]);
+ align_index = self.exprs.items.len;
+ _ = try self.walkRef(file, scope, align_ref, false);
+ extra_index += 1;
+ } else if (extra.data.bits.has_align_body) {
+ const align_body_len = file.zir.extra[extra_index];
+ extra_index += 1;
+ const align_body = file.zir.extra[extra_index .. extra_index + align_body_len];
+ _ = align_body;
+ // TODO: analyze the block (or bail with a comptimeExpr)
+ extra_index += align_body_len;
+ } else {
+ // default alignment
+ }
+
+ var addrspace_index: ?usize = null;
+ if (extra.data.bits.has_addrspace_ref) {
+ const addrspace_ref = @intToEnum(Zir.Inst.Ref, file.zir.extra[extra_index]);
+ addrspace_index = self.exprs.items.len;
+ _ = try self.walkRef(file, scope, addrspace_ref, false);
+ extra_index += 1;
+ } else if (extra.data.bits.has_addrspace_body) {
+ const addrspace_body_len = file.zir.extra[extra_index];
+ extra_index += 1;
+ const addrspace_body = file.zir.extra[extra_index .. extra_index + addrspace_body_len];
+ _ = addrspace_body;
+ // TODO: analyze the block (or bail with a comptimeExpr)
+ extra_index += addrspace_body_len;
+ } else {
+ // default alignment
+ }
+
+ var section_index: ?usize = null;
+ if (extra.data.bits.has_section_ref) {
+ const section_ref = @intToEnum(Zir.Inst.Ref, file.zir.extra[extra_index]);
+ section_index = self.exprs.items.len;
+ _ = try self.walkRef(file, scope, section_ref, false);
+ extra_index += 1;
+ } else if (extra.data.bits.has_section_body) {
+ const section_body_len = file.zir.extra[extra_index];
+ extra_index += 1;
+ const section_body = file.zir.extra[extra_index .. extra_index + section_body_len];
+ _ = section_body;
+ // TODO: analyze the block (or bail with a comptimeExpr)
+ extra_index += section_body_len;
+ } else {
+ // default alignment
+ }
+
+ var cc_index: ?usize = null;
+ if (extra.data.bits.has_cc_ref) {
+ const cc_ref = @intToEnum(Zir.Inst.Ref, file.zir.extra[extra_index]);
+ cc_index = self.exprs.items.len;
+ _ = try self.walkRef(file, scope, cc_ref, false);
+ extra_index += 1;
+ } else if (extra.data.bits.has_cc_body) {
+ const cc_body_len = file.zir.extra[extra_index];
+ extra_index += 1;
+ const cc_body = file.zir.extra[extra_index .. extra_index + cc_body_len];
+ _ = cc_body;
+ // TODO: analyze the block (or bail with a comptimeExpr)
+ extra_index += cc_body_len;
+ } else {
+ // auto calling convention
+ }
+
+ // ret
+ const ret_type_ref: DocData.Expr = switch (fn_info.ret_ty_body.len) {
+ 0 => switch (fn_info.ret_ty_ref) {
+ .none => DocData.Expr{ .void = .{} },
+ else => blk: {
+ const ref = fn_info.ret_ty_ref;
+ const wr = try self.walkRef(file, scope, ref, false);
+ break :blk wr.expr;
+ },
+ },
+ else => blk: {
+ const last_instr_index = fn_info.ret_ty_body[fn_info.ret_ty_body.len - 1];
+ const break_operand = data[last_instr_index].@"break".operand;
+ const wr = try self.walkRef(file, scope, break_operand, false);
+ break :blk wr.expr;
+ },
+ };
+
+ // TODO: a complete version of this will probably need a scope
+ // in order to evaluate correctly closures around funcion
+ // parameters etc.
+ const generic_ret: ?DocData.Expr = switch (ret_type_ref) {
+ .type => |t| blk: {
+ if (fn_info.body.len == 0) break :blk null;
+ if (t == @enumToInt(Ref.type_type)) {
+ break :blk try self.getGenericReturnType(
+ file,
+ scope,
+ fn_info.body[fn_info.body.len - 1],
+ );
+ } else {
+ break :blk null;
+ }
+ },
+ else => null,
+ };
+
+ self.types.items[type_slot_index] = .{
+ .Fn = .{
+ .name = "todo_name func",
+ .src = self_ast_node_index,
+ .params = param_type_refs.items,
+ .ret = ret_type_ref,
+ .generic_ret = generic_ret,
+ .is_extern = extra.data.bits.is_extern,
+ .has_cc = cc_index != null,
+ .has_align = align_index != null,
+ .has_lib_name = extra.data.bits.has_lib_name,
+ .lib_name = lib_name,
+ .is_inferred_error = extra.data.bits.is_inferred_error,
+ .cc = cc_index,
+ .@"align" = align_index,
+ },
+ };
+
+ return DocData.WalkResult{
+ .typeRef = .{ .type = @enumToInt(Ref.type_type) },
+ .expr = .{ .type = type_slot_index },
+ };
+}
+fn analyzeFunction(
+ self: *Autodoc,
+ file: *File,
+ scope: *Scope,
+ inst_index: usize,
+ self_ast_node_index: usize,
+ type_slot_index: usize,
+) AutodocErrors!DocData.WalkResult {
+ const tags = file.zir.instructions.items(.tag);
+ const data = file.zir.instructions.items(.data);
+ const fn_info = file.zir.getFnInfo(@intCast(u32, inst_index));
+
+ try self.ast_nodes.ensureUnusedCapacity(self.arena, fn_info.total_params_len);
+ var param_type_refs = try std.ArrayListUnmanaged(DocData.Expr).initCapacity(
+ self.arena,
+ fn_info.total_params_len,
+ );
+ var param_ast_indexes = try std.ArrayListUnmanaged(usize).initCapacity(
+ self.arena,
+ fn_info.total_params_len,
+ );
+
+ // TODO: handle scope rules for fn parameters
+ for (fn_info.param_body[0..fn_info.total_params_len]) |param_index| {
+ switch (tags[param_index]) {
+ else => {
+ panicWithContext(
+ file,
+ param_index,
+ "TODO: handle `{s}` in walkInstruction.func\n",
+ .{@tagName(tags[param_index])},
+ );
+ },
+ .param_anytype, .param_anytype_comptime => {
+ // TODO: where are the doc comments?
+ const str_tok = data[param_index].str_tok;
+
+ const name = str_tok.get(file.zir);
+
+ param_ast_indexes.appendAssumeCapacity(self.ast_nodes.items.len);
+ self.ast_nodes.appendAssumeCapacity(.{
+ .name = name,
+ .docs = "",
+ .@"comptime" = tags[param_index] == .param_anytype_comptime,
+ });
+
+ param_type_refs.appendAssumeCapacity(
+ DocData.Expr{ .@"anytype" = .{} },
+ );
+ },
+ .param, .param_comptime => {
+ const pl_tok = data[param_index].pl_tok;
+ const extra = file.zir.extraData(Zir.Inst.Param, pl_tok.payload_index);
+ const doc_comment = if (extra.data.doc_comment != 0)
+ file.zir.nullTerminatedString(extra.data.doc_comment)
+ else
+ "";
+ const name = file.zir.nullTerminatedString(extra.data.name);
+
+ param_ast_indexes.appendAssumeCapacity(self.ast_nodes.items.len);
+ try self.ast_nodes.append(self.arena, .{
+ .name = name,
+ .docs = doc_comment,
+ .@"comptime" = tags[param_index] == .param_comptime,
+ });
+
+ const break_index = file.zir.extra[extra.end..][extra.data.body_len - 1];
+ const break_operand = data[break_index].@"break".operand;
+ const param_type_ref = try self.walkRef(file, scope, break_operand, false);
+
+ param_type_refs.appendAssumeCapacity(param_type_ref.expr);
+ },
+ }
+ }
+
+ // ret
+ const ret_type_ref: DocData.Expr = switch (fn_info.ret_ty_body.len) {
+ 0 => switch (fn_info.ret_ty_ref) {
+ .none => DocData.Expr{ .void = .{} },
+ else => blk: {
+ const ref = fn_info.ret_ty_ref;
+ const wr = try self.walkRef(file, scope, ref, false);
+ break :blk wr.expr;
+ },
+ },
+ else => blk: {
+ //const last_instr_index = fn_info.ret_ty_body[fn_info.ret_ty_body.len - 1];
+ //const break_operand = data[last_instr_index].@"break".operand;
+ //const wr = try self.walkRef(file, scope, break_operand, false);
+ const wr = try self.walkRef(file, scope, fn_info.ret_ty_ref, false);
+ break :blk wr.expr;
+ },
+ };
+
+ // TODO: a complete version of this will probably need a scope
+ // in order to evaluate correctly closures around funcion
+ // parameters etc.
+ const generic_ret: ?DocData.Expr = switch (ret_type_ref) {
+ .type => |t| blk: {
+ if (fn_info.body.len == 0) break :blk null;
+ if (t == @enumToInt(Ref.type_type)) {
+ break :blk try self.getGenericReturnType(
+ file,
+ scope,
+ fn_info.body[fn_info.body.len - 1],
+ );
+ } else {
+ break :blk null;
+ }
+ },
+ else => null,
+ };
+
+ self.ast_nodes.items[self_ast_node_index].fields = param_ast_indexes.items;
+ self.types.items[type_slot_index] = .{
+ .Fn = .{
+ .name = "todo_name func",
+ .src = self_ast_node_index,
+ .params = param_type_refs.items,
+ .ret = ret_type_ref,
+ .generic_ret = generic_ret,
+ },
+ };
+
+ return DocData.WalkResult{
+ .typeRef = .{ .type = @enumToInt(Ref.type_type) },
+ .expr = .{ .type = type_slot_index },
+ };
+}
+
+fn getGenericReturnType(
+ self: *Autodoc,
+ file: *File,
+ scope: *Scope,
+ body_end: usize,
+) !DocData.Expr {
+ const wr = try self.walkInstruction(file, scope, body_end, false);
+ return wr.expr;
+}
+
+fn collectUnionFieldInfo(
+ self: *Autodoc,
+ file: *File,
+ scope: *Scope,
+ fields_len: usize,
+ field_type_refs: *std.ArrayListUnmanaged(DocData.Expr),
+ field_name_indexes: *std.ArrayListUnmanaged(usize),
+ ei: usize,
+) !void {
+ if (fields_len == 0) return;
+ var extra_index = ei;
+
+ const bits_per_field = 4;
+ const fields_per_u32 = 32 / bits_per_field;
+ const bit_bags_count = std.math.divCeil(usize, fields_len, fields_per_u32) catch unreachable;
+ var bit_bag_index: usize = extra_index;
+ extra_index += bit_bags_count;
+
+ var cur_bit_bag: u32 = undefined;
+ var field_i: u32 = 0;
+ while (field_i < fields_len) : (field_i += 1) {
+ if (field_i % fields_per_u32 == 0) {
+ cur_bit_bag = file.zir.extra[bit_bag_index];
+ bit_bag_index += 1;
+ }
+ const has_type = @truncate(u1, cur_bit_bag) != 0;
+ cur_bit_bag >>= 1;
+ const has_align = @truncate(u1, cur_bit_bag) != 0;
+ cur_bit_bag >>= 1;
+ const has_tag = @truncate(u1, cur_bit_bag) != 0;
+ cur_bit_bag >>= 1;
+ const unused = @truncate(u1, cur_bit_bag) != 0;
+ cur_bit_bag >>= 1;
+ _ = unused;
+
+ const field_name = file.zir.nullTerminatedString(file.zir.extra[extra_index]);
+ extra_index += 1;
+ const doc_comment_index = file.zir.extra[extra_index];
+ extra_index += 1;
+ const field_type = if (has_type)
+ @intToEnum(Zir.Inst.Ref, file.zir.extra[extra_index])
+ else
+ .void_type;
+ if (has_type) extra_index += 1;
+
+ if (has_align) extra_index += 1;
+ if (has_tag) extra_index += 1;
+
+ // type
+ {
+ const walk_result = try self.walkRef(file, scope, field_type, false);
+ try field_type_refs.append(self.arena, walk_result.expr);
+ }
+
+ // ast node
+ {
+ try field_name_indexes.append(self.arena, self.ast_nodes.items.len);
+ const doc_comment: ?[]const u8 = if (doc_comment_index != 0)
+ file.zir.nullTerminatedString(doc_comment_index)
+ else
+ null;
+ try self.ast_nodes.append(self.arena, .{
+ .name = field_name,
+ .docs = doc_comment,
+ });
+ }
+ }
+}
+
+fn collectStructFieldInfo(
+ self: *Autodoc,
+ file: *File,
+ scope: *Scope,
+ fields_len: usize,
+ field_type_refs: *std.ArrayListUnmanaged(DocData.Expr),
+ field_name_indexes: *std.ArrayListUnmanaged(usize),
+ ei: usize,
+) !void {
+ if (fields_len == 0) return;
+ var extra_index = ei;
+
+ const bits_per_field = 4;
+ const fields_per_u32 = 32 / bits_per_field;
+ const bit_bags_count = std.math.divCeil(usize, fields_len, fields_per_u32) catch unreachable;
+
+ const Field = struct {
+ field_name: u32,
+ doc_comment_index: u32,
+ type_body_len: u32 = 0,
+ align_body_len: u32 = 0,
+ init_body_len: u32 = 0,
+ type_ref: Zir.Inst.Ref = .none,
+ };
+ const fields = try self.arena.alloc(Field, fields_len);
+
+ var bit_bag_index: usize = extra_index;
+ extra_index += bit_bags_count;
+
+ var cur_bit_bag: u32 = undefined;
+ var field_i: u32 = 0;
+ while (field_i < fields_len) : (field_i += 1) {
+ if (field_i % fields_per_u32 == 0) {
+ cur_bit_bag = file.zir.extra[bit_bag_index];
+ bit_bag_index += 1;
+ }
+ const has_align = @truncate(u1, cur_bit_bag) != 0;
+ cur_bit_bag >>= 1;
+ const has_default = @truncate(u1, cur_bit_bag) != 0;
+ cur_bit_bag >>= 1;
+ // const is_comptime = @truncate(u1, cur_bit_bag) != 0;
+ cur_bit_bag >>= 1;
+ const has_type_body = @truncate(u1, cur_bit_bag) != 0;
+ cur_bit_bag >>= 1;
+
+ const field_name = file.zir.extra[extra_index];
+ extra_index += 1;
+ const doc_comment_index = file.zir.extra[extra_index];
+ extra_index += 1;
+
+ fields[field_i] = .{
+ .field_name = field_name,
+ .doc_comment_index = doc_comment_index,
+ };
+
+ if (has_type_body) {
+ fields[field_i].type_body_len = file.zir.extra[extra_index];
+ } else {
+ fields[field_i].type_ref = @intToEnum(Zir.Inst.Ref, file.zir.extra[extra_index]);
+ }
+ extra_index += 1;
+
+ if (has_align) {
+ fields[field_i].align_body_len = file.zir.extra[extra_index];
+ extra_index += 1;
+ }
+ if (has_default) {
+ fields[field_i].init_body_len = file.zir.extra[extra_index];
+ extra_index += 1;
+ }
+ }
+
+ const data = file.zir.instructions.items(.data);
+
+ for (fields) |field| {
+ const type_expr = expr: {
+ if (field.type_ref != .none) {
+ const walk_result = try self.walkRef(file, scope, field.type_ref, false);
+ break :expr walk_result.expr;
+ }
+
+ std.debug.assert(field.type_body_len != 0);
+ const body = file.zir.extra[extra_index..][0..field.type_body_len];
+ extra_index += body.len;
+
+ const break_inst = body[body.len - 1];
+ const operand = data[break_inst].@"break".operand;
+ const walk_result = try self.walkRef(file, scope, operand, false);
+ break :expr walk_result.expr;
+ };
+
+ extra_index += field.align_body_len;
+ extra_index += field.init_body_len;
+
+ try field_type_refs.append(self.arena, type_expr);
+
+ // ast node
+ {
+ try field_name_indexes.append(self.arena, self.ast_nodes.items.len);
+ const doc_comment: ?[]const u8 = if (field.doc_comment_index != 0)
+ file.zir.nullTerminatedString(field.doc_comment_index)
+ else
+ null;
+ try self.ast_nodes.append(self.arena, .{
+ .name = file.zir.nullTerminatedString(field.field_name),
+ .docs = doc_comment,
+ });
+ }
+ }
+}
+
+/// A Zir Ref can either refer to common types and values, or to a Zir index.
+/// WalkRef resolves common cases and delegates to `walkInstruction` otherwise.
+fn walkRef(
+ self: *Autodoc,
+ file: *File,
+ parent_scope: *Scope,
+ ref: Ref,
+ need_type: bool, // true when the caller needs also a typeRef for the return value
+) AutodocErrors!DocData.WalkResult {
+ const enum_value = @enumToInt(ref);
+ if (enum_value <= @enumToInt(Ref.anyerror_void_error_union_type)) {
+ // We can just return a type that indexes into `types` with the
+ // enum value because in the beginning we pre-filled `types` with
+ // the types that are listed in `Ref`.
+ return DocData.WalkResult{
+ .typeRef = .{ .type = @enumToInt(std.builtin.TypeId.Type) },
+ .expr = .{ .type = enum_value },
+ };
+ } else if (enum_value < Ref.typed_value_map.len) {
+ switch (ref) {
+ else => {
+ std.debug.panic("TODO: handle {s} in `walkRef`\n", .{
+ @tagName(ref),
+ });
+ },
+ .undef => {
+ return DocData.WalkResult{ .expr = .@"undefined" };
+ },
+ .zero => {
+ return DocData.WalkResult{
+ .typeRef = .{ .type = @enumToInt(Ref.comptime_int_type) },
+ .expr = .{ .int = .{ .value = 0 } },
+ };
+ },
+ .one => {
+ return DocData.WalkResult{
+ .typeRef = .{ .type = @enumToInt(Ref.comptime_int_type) },
+ .expr = .{ .int = .{ .value = 1 } },
+ };
+ },
+
+ .void_value => {
+ return DocData.WalkResult{
+ .typeRef = .{ .type = @enumToInt(Ref.void_type) },
+ .expr = .{ .void = .{} },
+ };
+ },
+ .unreachable_value => {
+ return DocData.WalkResult{
+ .typeRef = .{ .type = @enumToInt(Ref.noreturn_type) },
+ .expr = .{ .@"unreachable" = .{} },
+ };
+ },
+ .null_value => {
+ return DocData.WalkResult{ .expr = .@"null" };
+ },
+ .bool_true => {
+ return DocData.WalkResult{
+ .typeRef = .{ .type = @enumToInt(Ref.bool_type) },
+ .expr = .{ .bool = true },
+ };
+ },
+ .bool_false => {
+ return DocData.WalkResult{
+ .typeRef = .{ .type = @enumToInt(Ref.bool_type) },
+ .expr = .{ .bool = false },
+ };
+ },
+ .empty_struct => {
+ return DocData.WalkResult{ .expr = .{ .@"struct" = &.{} } };
+ },
+ .zero_usize => {
+ return DocData.WalkResult{
+ .typeRef = .{ .type = @enumToInt(Ref.usize_type) },
+ .expr = .{ .int = .{ .value = 0 } },
+ };
+ },
+ .one_usize => {
+ return DocData.WalkResult{
+ .typeRef = .{ .type = @enumToInt(Ref.usize_type) },
+ .expr = .{ .int = .{ .value = 1 } },
+ };
+ },
+ // TODO: dunno what to do with those
+ .calling_convention_type => {
+ return DocData.WalkResult{
+ .typeRef = .{ .type = @enumToInt(Ref.calling_convention_type) },
+ // .typeRef = .{ .type = @enumToInt(Ref.comptime_int_type) },
+ .expr = .{ .int = .{ .value = 1 } },
+ };
+ },
+ .calling_convention_c => {
+ return DocData.WalkResult{
+ .typeRef = .{ .type = @enumToInt(Ref.calling_convention_c) },
+ // .typeRef = .{ .type = @enumToInt(Ref.comptime_int_type) },
+ .expr = .{ .int = .{ .value = 1 } },
+ };
+ },
+ .calling_convention_inline => {
+ return DocData.WalkResult{
+ .typeRef = .{ .type = @enumToInt(Ref.calling_convention_inline) },
+ // .typeRef = .{ .type = @enumToInt(Ref.comptime_int_type) },
+ .expr = .{ .int = .{ .value = 1 } },
+ };
+ },
+ // .generic_poison => {
+ // return DocData.WalkResult{ .int = .{
+ // .type = @enumToInt(Ref.comptime_int_type),
+ // .value = 1,
+ // } };
+ // },
+ }
+ } else {
+ const zir_index = enum_value - Ref.typed_value_map.len;
+ return self.walkInstruction(file, parent_scope, zir_index, need_type);
+ }
+}
+
+fn getBlockInlineBreak(zir: Zir, inst_index: usize) Zir.Inst.Ref {
+ const tags = zir.instructions.items(.tag);
+ const data = zir.instructions.items(.data);
+ const pl_node = data[inst_index].pl_node;
+ const extra = zir.extraData(Zir.Inst.Block, pl_node.payload_index);
+ const break_index = zir.extra[extra.end..][extra.data.body_len - 1];
+ std.debug.assert(tags[break_index] == .break_inline);
+ return data[break_index].@"break".operand;
+}
+
+fn printWithContext(file: *File, inst: usize, comptime fmt: []const u8, args: anytype) void {
+ log.debug("Context [{s}] % {} \n " ++ fmt, .{ file.sub_file_path, inst } ++ args);
+}
+
+fn panicWithContext(file: *File, inst: usize, comptime fmt: []const u8, args: anytype) noreturn {
+ printWithContext(file, inst, fmt, args);
+ unreachable;
+}
+
+fn cteTodo(self: *Autodoc, msg: []const u8) error{OutOfMemory}!DocData.WalkResult {
+ const cte_slot_index = self.comptime_exprs.items.len;
+ try self.comptime_exprs.append(self.arena, .{
+ .code = msg,
+ });
+ return DocData.WalkResult{ .expr = .{ .comptimeExpr = cte_slot_index } };
+}
+
+fn writeFileTableToJson(map: std.AutoArrayHashMapUnmanaged(*File, usize), jsw: anytype) !void {
+ try jsw.beginObject();
+ var it = map.iterator();
+ while (it.next()) |entry| {
+ try jsw.objectField(entry.key_ptr.*.sub_file_path);
+ try jsw.emitNumber(entry.value_ptr.*);
+ }
+ try jsw.endObject();
+}
+
+fn writePackageTableToJson(
+ map: std.AutoHashMapUnmanaged(*Package, DocData.DocPackage.TableEntry),
+ jsw: anytype,
+) !void {
+ try jsw.beginObject();
+ var it = map.valueIterator();
+ while (it.next()) |entry| {
+ try jsw.objectField(entry.name);
+ try jsw.emitNumber(entry.value);
+ }
+ try jsw.endObject();
+}
diff --git a/src/Compilation.zig b/src/Compilation.zig
@@ -34,6 +34,7 @@ const ThreadPool = @import("ThreadPool.zig");
const WaitGroup = @import("WaitGroup.zig");
const libtsan = @import("libtsan.zig");
const Zir = @import("Zir.zig");
+const Autodoc = @import("Autodoc.zig");
const Color = @import("main.zig").Color;
/// General-purpose allocator. Used for both temporary and long-term storage.
@@ -2287,6 +2288,14 @@ pub fn update(comp: *Compilation) !void {
return;
}
+ if (comp.emit_docs) |doc_location| {
+ if (comp.bin_file.options.module) |module| {
+ var autodoc = Autodoc.init(module, doc_location);
+ defer autodoc.deinit();
+ try autodoc.generateZirData();
+ }
+ }
+
// Flush takes care of -femit-bin, but we still have -femit-llvm-ir, -femit-llvm-bc, and
// -femit-asm to handle, in the case of C objects.
comp.emitOthers();
@@ -5160,8 +5169,6 @@ fn updateStage1Module(comp: *Compilation, main_progress_node: *std.Progress.Node
const emit_asm_path = try stage1LocPath(arena, comp.emit_asm, directory);
const emit_llvm_ir_path = try stage1LocPath(arena, comp.emit_llvm_ir, directory);
const emit_llvm_bc_path = try stage1LocPath(arena, comp.emit_llvm_bc, directory);
- const emit_analysis_path = try stage1LocPath(arena, comp.emit_analysis, directory);
- const emit_docs_path = try stage1LocPath(arena, comp.emit_docs, directory);
const stage1_pkg = try createStage1Pkg(arena, "root", mod.main_pkg, null);
const test_filter = comp.test_filter orelse ""[0..0];
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
.emit_llvm_ir_len = emit_llvm_ir_path.len,
.emit_bitcode_ptr = emit_llvm_bc_path.ptr,
.emit_bitcode_len = emit_llvm_bc_path.len,
- .emit_analysis_json_ptr = emit_analysis_path.ptr,
- .emit_analysis_json_len = emit_analysis_path.len,
- .emit_docs_ptr = emit_docs_path.ptr,
- .emit_docs_len = emit_docs_path.len,
.builtin_zig_path_ptr = builtin_zig_path.ptr,
.builtin_zig_path_len = builtin_zig_path.len,
.test_filter_ptr = test_filter.ptr,
diff --git a/src/stage1.zig b/src/stage1.zig
@@ -96,10 +96,6 @@ pub const Module = extern struct {
emit_llvm_ir_len: usize,
emit_bitcode_ptr: [*]const u8,
emit_bitcode_len: usize,
- emit_analysis_json_ptr: [*]const u8,
- emit_analysis_json_len: usize,
- emit_docs_ptr: [*]const u8,
- emit_docs_len: usize,
builtin_zig_path_ptr: [*]const u8,
builtin_zig_path_len: usize,
test_filter_ptr: [*]const u8,
diff --git a/src/stage1/all_types.hpp b/src/stage1/all_types.hpp
@@ -2141,8 +2141,6 @@ struct CodeGen {
Buf asm_file_output_path;
Buf llvm_ir_file_output_path;
Buf bitcode_file_output_path;
- Buf analysis_json_output_path;
- Buf docs_output_path;
Buf *builtin_zig_path;
diff --git a/src/stage1/codegen.cpp b/src/stage1/codegen.cpp
@@ -16,7 +16,6 @@
#include "util.hpp"
#include "zig_llvm.h"
#include "stage2.h"
-#include "dump_analysis.hpp"
#include "softfloat.hpp"
#include "zigendian.h"
@@ -10546,57 +10545,6 @@ void codegen_build_object(CodeGen *g) {
gen_root_source(g);
- if (buf_len(&g->analysis_json_output_path) != 0) {
- const char *analysis_json_filename = buf_ptr(&g->analysis_json_output_path);
- FILE *f = fopen(analysis_json_filename, "wb");
- if (f == nullptr) {
- fprintf(stderr, "Unable to open '%s': %s\n", analysis_json_filename, strerror(errno));
- exit(1);
- }
- zig_print_analysis_dump(g, f, " ", "\n");
- if (fclose(f) != 0) {
- fprintf(stderr, "Unable to write '%s': %s\n", analysis_json_filename, strerror(errno));
- exit(1);
- }
- }
- if (buf_len(&g->docs_output_path) != 0) {
- Error err;
- Buf *doc_dir_path = &g->docs_output_path;
- if ((err = os_make_path(doc_dir_path))) {
- fprintf(stderr, "Unable to create directory %s: %s\n", buf_ptr(doc_dir_path), err_str(err));
- exit(1);
- }
- Buf *index_html_src_path = buf_sprintf("%s" OS_SEP "docs" OS_SEP "index.html",
- buf_ptr(g->zig_lib_dir));
- Buf *index_html_dest_path = buf_sprintf("%s" OS_SEP "index.html", buf_ptr(doc_dir_path));
- Buf *main_js_src_path = buf_sprintf("%s" OS_SEP "docs" OS_SEP "main.js",
- buf_ptr(g->zig_lib_dir));
- Buf *main_js_dest_path = buf_sprintf("%s" OS_SEP "main.js", buf_ptr(doc_dir_path));
-
- if ((err = os_copy_file(index_html_src_path, index_html_dest_path))) {
- fprintf(stderr, "Unable to copy %s to %s: %s\n", buf_ptr(index_html_src_path),
- buf_ptr(index_html_dest_path), err_str(err));
- exit(1);
- }
- if ((err = os_copy_file(main_js_src_path, main_js_dest_path))) {
- fprintf(stderr, "Unable to copy %s to %s: %s\n", buf_ptr(main_js_src_path),
- buf_ptr(main_js_dest_path), err_str(err));
- exit(1);
- }
- const char *data_js_filename = buf_ptr(buf_sprintf("%s" OS_SEP "data.js", buf_ptr(doc_dir_path)));
- FILE *f = fopen(data_js_filename, "wb");
- if (f == nullptr) {
- fprintf(stderr, "Unable to open '%s': %s\n", data_js_filename, strerror(errno));
- exit(1);
- }
- fprintf(f, "zigAnalysis=");
- zig_print_analysis_dump(g, f, "", "");
- fprintf(f, ";");
- if (fclose(f) != 0) {
- fprintf(stderr, "Unable to write '%s': %s\n", data_js_filename, strerror(errno));
- exit(1);
- }
- }
codegen_add_time_event(g, "Code Generation");
{
diff --git a/src/stage1/dump_analysis.cpp b/src/stage1/dump_analysis.cpp
@@ -1,1431 +0,0 @@
-/*
- * Copyright (c) 2019 Andrew Kelley
- *
- * This file is part of zig, which is MIT licensed.
- * See http://opensource.org/licenses/MIT
- */
-
-#include "dump_analysis.hpp"
-#include "analyze.hpp"
-#include "ir.hpp"
-#include "codegen.hpp"
-#include "os.hpp"
-
-enum JsonWriterState {
- JsonWriterStateInvalid,
- JsonWriterStateValue,
- JsonWriterStateArrayStart,
- JsonWriterStateArray,
- JsonWriterStateObjectStart,
- JsonWriterStateObject,
-};
-
-#define JSON_MAX_DEPTH 10
-
-struct JsonWriter {
- size_t state_index;
- FILE *f;
- const char *one_indent;
- const char *nl;
- JsonWriterState state[JSON_MAX_DEPTH];
-};
-
-static void jw_init(JsonWriter *jw, FILE *f, const char *one_indent, const char *nl) {
- jw->state_index = 1;
- jw->f = f;
- jw->one_indent = one_indent;
- jw->nl = nl;
- jw->state[0] = JsonWriterStateInvalid;
- jw->state[1] = JsonWriterStateValue;
-}
-
-static void jw_nl_indent(JsonWriter *jw) {
- assert(jw->state_index >= 1);
- fprintf(jw->f, "%s", jw->nl);
- for (size_t i = 0; i < jw->state_index - 1; i += 1) {
- fprintf(jw->f, "%s", jw->one_indent);
- }
-}
-
-static void jw_push_state(JsonWriter *jw, JsonWriterState state) {
- jw->state_index += 1;
- assert(jw->state_index < JSON_MAX_DEPTH);
- jw->state[jw->state_index] = state;
-}
-
-static void jw_pop_state(JsonWriter *jw) {
- assert(jw->state_index != 0);
- jw->state_index -= 1;
-}
-
-static void jw_begin_array(JsonWriter *jw) {
- assert(jw->state[jw->state_index] == JsonWriterStateValue);
- fprintf(jw->f, "[");
- jw->state[jw->state_index] = JsonWriterStateArrayStart;
-}
-
-static void jw_begin_object(JsonWriter *jw) {
- assert(jw->state[jw->state_index] == JsonWriterStateValue);
- fprintf(jw->f, "{");
- jw->state[jw->state_index] = JsonWriterStateObjectStart;
-}
-
-static void jw_array_elem(JsonWriter *jw) {
- switch (jw->state[jw->state_index]) {
- case JsonWriterStateInvalid:
- case JsonWriterStateValue:
- case JsonWriterStateObjectStart:
- case JsonWriterStateObject:
- zig_unreachable();
- case JsonWriterStateArray:
- fprintf(jw->f, ",");
- ZIG_FALLTHROUGH;
- case JsonWriterStateArrayStart:
- jw->state[jw->state_index] = JsonWriterStateArray;
- jw_push_state(jw, JsonWriterStateValue);
- jw_nl_indent(jw);
- return;
- }
- zig_unreachable();
-}
-
-static void jw_write_escaped_string(JsonWriter *jw, const char *s) {
- fprintf(jw->f, "\"");
- for (;; s += 1) {
- switch (*s) {
- case 0:
- fprintf(jw->f, "\"");
- return;
- case '"':
- fprintf(jw->f, "\\\"");
- continue;
- case '\t':
- fprintf(jw->f, "\\t");
- continue;
- case '\r':
- fprintf(jw->f, "\\r");
- continue;
- case '\n':
- fprintf(jw->f, "\\n");
- continue;
- case '\b':
- fprintf(jw->f, "\\b");
- continue;
- case '\f':
- fprintf(jw->f, "\\f");
- continue;
- case '\\':
- fprintf(jw->f, "\\\\");
- continue;
- default:
- fprintf(jw->f, "%c", *s);
- continue;
- }
- }
-}
-
-static void jw_object_field(JsonWriter *jw, const char *name) {
- switch (jw->state[jw->state_index]) {
- case JsonWriterStateInvalid:
- case JsonWriterStateValue:
- case JsonWriterStateArray:
- case JsonWriterStateArrayStart:
- zig_unreachable();
- case JsonWriterStateObject:
- fprintf(jw->f, ",");
- ZIG_FALLTHROUGH;
- case JsonWriterStateObjectStart:
- jw->state[jw->state_index] = JsonWriterStateObject;
- jw_push_state(jw, JsonWriterStateValue);
- jw_nl_indent(jw);
- jw_write_escaped_string(jw, name);
- fprintf(jw->f, ": ");
- return;
- }
- zig_unreachable();
-}
-
-static void jw_end_array(JsonWriter *jw) {
- switch (jw->state[jw->state_index]) {
- case JsonWriterStateInvalid:
- case JsonWriterStateValue:
- case JsonWriterStateObjectStart:
- case JsonWriterStateObject:
- zig_unreachable();
- case JsonWriterStateArrayStart:
- fprintf(jw->f, "]");
- jw_pop_state(jw);
- return;
- case JsonWriterStateArray:
- jw_nl_indent(jw);
- jw_pop_state(jw);
- fprintf(jw->f, "]");
- return;
- }
- zig_unreachable();
-}
-
-
-static void jw_end_object(JsonWriter *jw) {
- switch (jw->state[jw->state_index]) {
- case JsonWriterStateInvalid:
- zig_unreachable();
- case JsonWriterStateValue:
- zig_unreachable();
- case JsonWriterStateArray:
- zig_unreachable();
- case JsonWriterStateArrayStart:
- zig_unreachable();
- case JsonWriterStateObjectStart:
- fprintf(jw->f, "}");
- jw_pop_state(jw);
- return;
- case JsonWriterStateObject:
- jw_nl_indent(jw);
- jw_pop_state(jw);
- fprintf(jw->f, "}");
- return;
- }
- zig_unreachable();
-}
-
-static void jw_null(JsonWriter *jw) {
- assert(jw->state[jw->state_index] == JsonWriterStateValue);
- fprintf(jw->f, "null");
- jw_pop_state(jw);
-}
-
-static void jw_bool(JsonWriter *jw, bool x) {
- assert(jw->state[jw->state_index] == JsonWriterStateValue);
- if (x) {
- fprintf(jw->f, "true");
- } else {
- fprintf(jw->f, "false");
- }
- jw_pop_state(jw);
-}
-
-static void jw_int(JsonWriter *jw, int64_t x) {
- assert(jw->state[jw->state_index] == JsonWriterStateValue);
- if (x > 4503599627370496 || x < -4503599627370496) {
- fprintf(jw->f, "\"%" ZIG_PRI_i64 "\"", x);
- } else {
- fprintf(jw->f, "%" ZIG_PRI_i64, x);
- }
- jw_pop_state(jw);
-}
-
-static void jw_bigint(JsonWriter *jw, const BigInt *x) {
- assert(jw->state[jw->state_index] == JsonWriterStateValue);
- Buf *str = buf_alloc();
- bigint_append_buf(str, x, 10);
-
- if (bigint_fits_in_bits(x, 52, true)) {
- fprintf(jw->f, "%s", buf_ptr(str));
- } else {
- fprintf(jw->f, "\"%s\"", buf_ptr(str));
- }
- jw_pop_state(jw);
-
- buf_destroy(str);
-}
-
-static void jw_string(JsonWriter *jw, const char *s) {
- assert(jw->state[jw->state_index] == JsonWriterStateValue);
- jw_write_escaped_string(jw, s);
- jw_pop_state(jw);
-}
-
-
-static void tree_print(FILE *f, ZigType *ty, size_t indent);
-
-static int compare_type_abi_sizes_desc(const void *a, const void *b) {
- uint64_t size_a = (*(ZigType * const*)(a))->abi_size;
- uint64_t size_b = (*(ZigType * const*)(b))->abi_size;
- if (size_a > size_b)
- return -1;
- if (size_a < size_b)
- return 1;
- return 0;
-}
-
-static void start_child(FILE *f, size_t indent) {
- fprintf(f, "\n");
- for (size_t i = 0; i < indent; i += 1) {
- fprintf(f, " ");
- }
-}
-
-static void start_peer(FILE *f, size_t indent) {
- fprintf(f, ",\n");
- for (size_t i = 0; i < indent; i += 1) {
- fprintf(f, " ");
- }
-}
-
-static void tree_print_struct(FILE *f, ZigType *struct_type, size_t indent) {
- ZigList<ZigType *> children = {};
- uint64_t sum_from_fields = 0;
- for (size_t i = 0; i < struct_type->data.structure.src_field_count; i += 1) {
- TypeStructField *field = struct_type->data.structure.fields[i];
- children.append(field->type_entry);
- sum_from_fields += field->type_entry->abi_size;
- }
- qsort(children.items, children.length, sizeof(ZigType *), compare_type_abi_sizes_desc);
-
- start_peer(f, indent);
- fprintf(f, "\"padding\": \"%" ZIG_PRI_u64 "\"", struct_type->abi_size - sum_from_fields);
-
- start_peer(f, indent);
- fprintf(f, "\"fields\": [");
-
- for (size_t i = 0; i < children.length; i += 1) {
- if (i == 0) {
- start_child(f, indent + 1);
- } else {
- start_peer(f, indent + 1);
- }
- fprintf(f, "{");
-
- ZigType *child_type = children.at(i);
- tree_print(f, child_type, indent + 2);
-
- start_child(f, indent + 1);
- fprintf(f, "}");
- }
-
- start_child(f, indent);
- fprintf(f, "]");
-}
-
-static void tree_print(FILE *f, ZigType *ty, size_t indent) {
- start_child(f, indent);
- fprintf(f, "\"type\": \"%s\"", buf_ptr(&ty->name));
-
- start_peer(f, indent);
- fprintf(f, "\"sizef\": \"");
- zig_pretty_print_bytes(f, ty->abi_size);
- fprintf(f, "\"");
-
- start_peer(f, indent);
- fprintf(f, "\"size\": \"%" ZIG_PRI_usize "\"", ty->abi_size);
-
- switch (ty->id) {
- case ZigTypeIdFnFrame:
- return tree_print_struct(f, ty->data.frame.locals_struct, indent);
- case ZigTypeIdStruct:
- return tree_print_struct(f, ty, indent);
- default:
- start_child(f, indent);
- return;
- }
-}
-
-void zig_print_stack_report(CodeGen *g, FILE *f) {
- if (g->largest_frame_fn == nullptr) {
- fprintf(f, "{\"error\": \"No async function frames in entire compilation.\"}\n");
- return;
- }
- fprintf(f, "{");
- tree_print(f, g->largest_frame_fn->frame_type, 1);
-
- start_child(f, 0);
- fprintf(f, "}\n");
-}
-
-struct AnalDumpCtx {
- CodeGen *g;
- JsonWriter jw;
-
- ZigList<ZigType *> type_list;
- HashMap<const ZigType *, uint32_t, type_ptr_hash, type_ptr_eql> type_map;
-
- ZigList<ZigPackage *> pkg_list;
- HashMap<const ZigPackage *, uint32_t, pkg_ptr_hash, pkg_ptr_eql> pkg_map;
-
- ZigList<Buf *> file_list;
- HashMap<Buf *, uint32_t, buf_hash, buf_eql_buf> file_map;
-
- ZigList<Tld *> decl_list;
- HashMap<const Tld *, uint32_t, tld_ptr_hash, tld_ptr_eql> decl_map;
-
- ZigList<ZigFn *> fn_list;
- HashMap<const ZigFn *, uint32_t, fn_ptr_hash, fn_ptr_eql> fn_map;
- HashMap<const ZigFn *, uint32_t, fn_ptr_hash, fn_ptr_eql> fn_decl_map;
-
- ZigList<AstNode *> node_list;
- HashMap<const AstNode *, uint32_t, node_ptr_hash, node_ptr_eql> node_map;
-
- ZigList<ErrorTableEntry *> err_list;
- HashMap<const ErrorTableEntry *, uint32_t, err_ptr_hash, err_ptr_eql> err_map;
-};
-
-static uint32_t anal_dump_get_type_id(AnalDumpCtx *ctx, ZigType *ty);
-static void anal_dump_value(AnalDumpCtx *ctx, AstNode *source_node, ZigType *ty, ZigValue *value);
-
-static void anal_dump_poke_value(AnalDumpCtx *ctx, AstNode *source_node, ZigType *ty, ZigValue *value) {
- Error err;
- if (value->type != ty) {
- return;
- }
- if ((err = ir_resolve_lazy(ctx->g, source_node, value))) {
- codegen_report_errors_and_exit(ctx->g);
- }
- if (value->special == ConstValSpecialUndef) {
- return;
- }
- if (value->special == ConstValSpecialRuntime) {
- return;
- }
- switch (ty->id) {
- case ZigTypeIdMetaType: {
- ZigType *val_ty = value->data.x_type;
- (void)anal_dump_get_type_id(ctx, val_ty);
- return;
- }
- default:
- return;
- }
- zig_unreachable();
-}
-
-static uint32_t anal_dump_get_type_id(AnalDumpCtx *ctx, ZigType *ty) {
- uint32_t type_id = ctx->type_list.length;
- auto existing_entry = ctx->type_map.put_unique(ty, type_id);
- if (existing_entry == nullptr) {
- ctx->type_list.append(ty);
- } else {
- type_id = existing_entry->value;
- }
- return type_id;
-}
-
-static uint32_t anal_dump_get_pkg_id(AnalDumpCtx *ctx, ZigPackage *pkg) {
- assert(pkg != nullptr);
- uint32_t pkg_id = ctx->pkg_list.length;
- auto existing_entry = ctx->pkg_map.put_unique(pkg, pkg_id);
- if (existing_entry == nullptr) {
- ctx->pkg_list.append(pkg);
- } else {
- pkg_id = existing_entry->value;
- }
- return pkg_id;
-}
-
-static uint32_t anal_dump_get_file_id(AnalDumpCtx *ctx, Buf *file) {
- uint32_t file_id = ctx->file_list.length;
- auto existing_entry = ctx->file_map.put_unique(file, file_id);
- if (existing_entry == nullptr) {
- ctx->file_list.append(file);
- } else {
- file_id = existing_entry->value;
- }
- return file_id;
-}
-
-static uint32_t anal_dump_get_node_id(AnalDumpCtx *ctx, AstNode *node) {
- uint32_t node_id = ctx->node_list.length;
- auto existing_entry = ctx->node_map.put_unique(node, node_id);
- if (existing_entry == nullptr) {
- ctx->node_list.append(node);
- } else {
- node_id = existing_entry->value;
- }
- return node_id;
-}
-
-static uint32_t anal_dump_get_fn_id(AnalDumpCtx *ctx, ZigFn *fn) {
- uint32_t fn_id = ctx->fn_list.length;
- auto existing_entry = ctx->fn_map.put_unique(fn, fn_id);
- if (existing_entry == nullptr) {
- ctx->fn_list.append(fn);
-
- // poke the fn
- (void)anal_dump_get_type_id(ctx, fn->type_entry);
- (void)anal_dump_get_node_id(ctx, fn->proto_node);
- } else {
- fn_id = existing_entry->value;
- }
- return fn_id;
-}
-
-static uint32_t anal_dump_get_err_id(AnalDumpCtx *ctx, ErrorTableEntry *err) {
- uint32_t err_id = ctx->err_list.length;
- auto existing_entry = ctx->err_map.put_unique(err, err_id);
- if (existing_entry == nullptr) {
- ctx->err_list.append(err);
- } else {
- err_id = existing_entry->value;
- }
- return err_id;
-}
-
-static uint32_t anal_dump_get_decl_id(AnalDumpCtx *ctx, Tld *tld) {
- uint32_t decl_id = ctx->decl_list.length;
- auto existing_entry = ctx->decl_map.put_unique(tld, decl_id);
- if (existing_entry == nullptr) {
- ctx->decl_list.append(tld);
-
- if (tld->import != nullptr) {
- (void)anal_dump_get_type_id(ctx, tld->import);
- }
-
- // poke the types
- switch (tld->id) {
- case TldIdVar: {
- TldVar *tld_var = reinterpret_cast<TldVar *>(tld);
- ZigVar *var = tld_var->var;
-
- if (var != nullptr) {
- (void)anal_dump_get_type_id(ctx, var->var_type);
-
- if (var->const_value != nullptr) {
- anal_dump_poke_value(ctx, var->decl_node, var->var_type, var->const_value);
- }
- }
- break;
- }
- case TldIdFn: {
- TldFn *tld_fn = reinterpret_cast<TldFn *>(tld);
- ZigFn *fn = tld_fn->fn_entry;
-
- if (fn != nullptr) {
- (void)anal_dump_get_type_id(ctx, fn->type_entry);
- ctx->fn_decl_map.put_unique(fn, decl_id);
- }
- break;
- }
- default:
- break;
- }
-
- } else {
- decl_id = existing_entry->value;
- }
- return decl_id;
-}
-
-static void anal_dump_type_ref(AnalDumpCtx *ctx, ZigType *ty) {
- uint32_t type_id = anal_dump_get_type_id(ctx, ty);
- jw_int(&ctx->jw, type_id);
-}
-
-static void anal_dump_pkg_ref(AnalDumpCtx *ctx, ZigPackage *pkg) {
- uint32_t pkg_id = anal_dump_get_pkg_id(ctx, pkg);
- jw_int(&ctx->jw, pkg_id);
-}
-
-static void anal_dump_file_ref(AnalDumpCtx *ctx, Buf *file) {
- uint32_t file_id = anal_dump_get_file_id(ctx, file);
- jw_int(&ctx->jw, file_id);
-}
-
-static void anal_dump_node_ref(AnalDumpCtx *ctx, AstNode *node) {
- uint32_t node_id = anal_dump_get_node_id(ctx, node);
- jw_int(&ctx->jw, node_id);
-}
-
-static void anal_dump_fn_ref(AnalDumpCtx *ctx, ZigFn *fn) {
- uint32_t fn_id = anal_dump_get_fn_id(ctx, fn);
- jw_int(&ctx->jw, fn_id);
-}
-
-static void anal_dump_err_ref(AnalDumpCtx *ctx, ErrorTableEntry *err) {
- uint32_t err_id = anal_dump_get_err_id(ctx, err);
- jw_int(&ctx->jw, err_id);
-}
-
-static void anal_dump_decl_ref(AnalDumpCtx *ctx, Tld *tld) {
- uint32_t decl_id = anal_dump_get_decl_id(ctx, tld);
- jw_int(&ctx->jw, decl_id);
-}
-
-static void anal_dump_pkg(AnalDumpCtx *ctx, ZigPackage *pkg) {
- JsonWriter *jw = &ctx->jw;
-
- Buf full_path_buf = BUF_INIT;
- os_path_join(&pkg->root_src_dir, &pkg->root_src_path, &full_path_buf);
- Buf *resolve_paths[] = { &full_path_buf, };
- Buf *resolved_path = buf_alloc();
- *resolved_path = os_path_resolve(resolve_paths, 1);
-
- auto import_entry = ctx->g->import_table.maybe_get(resolved_path);
- if (!import_entry) {
- return;
- }
-
- jw_array_elem(jw);
- jw_begin_object(jw);
-
- jw_object_field(jw, "name");
- jw_string(jw, buf_ptr(&pkg->pkg_path));
-
- jw_object_field(jw, "file");
- anal_dump_file_ref(ctx, resolved_path);
-
- jw_object_field(jw, "main");
- anal_dump_type_ref(ctx, import_entry->value);
-
- jw_object_field(jw, "table");
- jw_begin_object(jw);
- auto it = pkg->package_table.entry_iterator();
- for (;;) {
- auto *entry = it.next();
- if (!entry)
- break;
-
- ZigPackage *child_pkg = entry->value;
- if (child_pkg != nullptr) {
- jw_object_field(jw, buf_ptr(entry->key));
- anal_dump_pkg_ref(ctx, child_pkg);
- }
- }
- jw_end_object(jw);
-
- jw_end_object(jw);
-}
-
-static void anal_dump_decl(AnalDumpCtx *ctx, Tld *tld) {
- JsonWriter *jw = &ctx->jw;
-
- bool make_obj = tld->id == TldIdVar || tld->id == TldIdFn;
- if (make_obj) {
- jw_array_elem(jw);
- jw_begin_object(jw);
-
- jw_object_field(jw, "import");
- anal_dump_type_ref(ctx, tld->import);
-
- jw_object_field(jw, "src");
- anal_dump_node_ref(ctx, tld->source_node);
-
- jw_object_field(jw, "name");
- jw_string(jw, buf_ptr(tld->name));
- }
-
- switch (tld->id) {
- case TldIdVar: {
- TldVar *tld_var = reinterpret_cast<TldVar *>(tld);
- ZigVar *var = tld_var->var;
-
- if (var != nullptr) {
- jw_object_field(jw, "kind");
- if (var->src_is_const) {
- jw_string(jw, "const");
- } else {
- jw_string(jw, "var");
- }
-
- if (var->is_thread_local) {
- jw_object_field(jw, "threadlocal");
- jw_bool(jw, true);
- }
-
- jw_object_field(jw, "type");
- anal_dump_type_ref(ctx, var->var_type);
-
- if (var->const_value != nullptr) {
- jw_object_field(jw, "value");
- anal_dump_value(ctx, var->decl_node, var->var_type, var->const_value);
- }
- }
- break;
- }
- case TldIdFn: {
- TldFn *tld_fn = reinterpret_cast<TldFn *>(tld);
- ZigFn *fn = tld_fn->fn_entry;
-
- if (fn != nullptr) {
- jw_object_field(jw, "kind");
- jw_string(jw, "const");
-
- jw_object_field(jw, "type");
- anal_dump_type_ref(ctx, fn->type_entry);
-
- jw_object_field(jw, "value");
- anal_dump_fn_ref(ctx, fn);
- }
- break;
- }
- default:
- break;
- }
-
- if (make_obj) {
- jw_end_object(jw);
- }
-}
-
-static void anal_dump_file(AnalDumpCtx *ctx, Buf *file) {
- JsonWriter *jw = &ctx->jw;
- jw_string(jw, buf_ptr(file));
-}
-
-static void anal_dump_value(AnalDumpCtx *ctx, AstNode *source_node, ZigType *ty, ZigValue *value) {
- Error err;
-
- if (value->type != ty) {
- jw_null(&ctx->jw);
- return;
- }
- if ((err = ir_resolve_lazy(ctx->g, source_node, value))) {
- codegen_report_errors_and_exit(ctx->g);
- }
- if (value->special == ConstValSpecialUndef) {
- jw_string(&ctx->jw, "undefined");
- return;
- }
- if (value->special == ConstValSpecialRuntime) {
- jw_null(&ctx->jw);
- return;
- }
- switch (ty->id) {
- case ZigTypeIdMetaType: {
- ZigType *val_ty = value->data.x_type;
- anal_dump_type_ref(ctx, val_ty);
- return;
- }
- case ZigTypeIdFn: {
- if (value->data.x_ptr.special == ConstPtrSpecialFunction) {
- ZigFn *val_fn = value->data.x_ptr.data.fn.fn_entry;
- anal_dump_fn_ref(ctx, val_fn);
- } else {
- jw_null(&ctx->jw);
- }
- return;
- }
- case ZigTypeIdOptional: {
- if(optional_value_is_null(value)){
- jw_string(&ctx->jw, "null");
- } else {
- jw_null(&ctx->jw);
- }
- return;
- }
- case ZigTypeIdBool: {
- jw_string(&ctx->jw, value->data.x_bool ? "true" : "false");
- return;
- }
- case ZigTypeIdInt: {
- jw_bigint(&ctx->jw, &value->data.x_bigint);
- return;
- }
- default:
- jw_null(&ctx->jw);
- return;
- }
- zig_unreachable();
-}
-
-static void anal_dump_pointer_attrs(AnalDumpCtx *ctx, ZigType *ty) {
- JsonWriter *jw = &ctx->jw;
- if (ty->data.pointer.explicit_alignment != 0) {
- jw_object_field(jw, "align");
- jw_int(jw, ty->data.pointer.explicit_alignment);
- }
- if (ty->data.pointer.is_const) {
- jw_object_field(jw, "const");
- jw_bool(jw, true);
- }
- if (ty->data.pointer.is_volatile) {
- jw_object_field(jw, "volatile");
- jw_bool(jw, true);
- }
- if (ty->data.pointer.allow_zero) {
- jw_object_field(jw, "allowZero");
- jw_bool(jw, true);
- }
- if (ty->data.pointer.host_int_bytes != 0) {
- jw_object_field(jw, "hostIntBytes");
- jw_int(jw, ty->data.pointer.host_int_bytes);
-
- jw_object_field(jw, "bitOffsetInHost");
- jw_int(jw, ty->data.pointer.bit_offset_in_host);
- }
-
- jw_object_field(jw, "elem");
- anal_dump_type_ref(ctx, ty->data.pointer.child_type);
-}
-
-static void anal_dump_type(AnalDumpCtx *ctx, ZigType *ty) {
- JsonWriter *jw = &ctx->jw;
- jw_array_elem(jw);
- jw_begin_object(jw);
-
- jw_object_field(jw, "kind");
- jw_int(jw, type_id_index(ty));
-
- switch (ty->id) {
- case ZigTypeIdMetaType:
- case ZigTypeIdBool:
- case ZigTypeIdEnumLiteral:
- break;
- case ZigTypeIdStruct: {
- if (ty->data.structure.special == StructSpecialSlice) {
- jw_object_field(jw, "len");
- jw_int(jw, 2);
- anal_dump_pointer_attrs(ctx, ty->data.structure.fields[slice_ptr_index]->type_entry);
- break;
- }
-
- jw_object_field(jw, "name");
- jw_string(jw, buf_ptr(&ty->name));
-
- jw_object_field(jw, "src");
- anal_dump_node_ref(ctx, ty->data.structure.decl_node);
-
- {
- jw_object_field(jw, "pubDecls");
- jw_begin_array(jw);
-
- ScopeDecls *decls_scope = ty->data.structure.decls_scope;
- auto it = decls_scope->decl_table.entry_iterator();
- for (;;) {
- auto *entry = it.next();
- if (!entry)
- break;
-
- Tld *tld = entry->value;
- if (tld->visib_mod == VisibModPub) {
- jw_array_elem(jw);
- anal_dump_decl_ref(ctx, tld);
- }
- }
- jw_end_array(jw);
- }
-
- {
- jw_object_field(jw, "privDecls");
- jw_begin_array(jw);
-
- ScopeDecls *decls_scope = ty->data.structure.decls_scope;
- auto it = decls_scope->decl_table.entry_iterator();
- for (;;) {
- auto *entry = it.next();
- if (!entry)
- break;
-
- Tld *tld = entry->value;
- if (tld->visib_mod == VisibModPrivate) {
- jw_array_elem(jw);
- anal_dump_decl_ref(ctx, tld);
- }
- }
- jw_end_array(jw);
- }
-
- if (ty->data.structure.src_field_count != 0) {
- jw_object_field(jw, "fields");
- jw_begin_array(jw);
-
- for(size_t i = 0; i < ty->data.structure.src_field_count; i += 1) {
- jw_array_elem(jw);
- anal_dump_type_ref(ctx, ty->data.structure.fields[i]->type_entry);
- }
- jw_end_array(jw);
- }
-
- if (ty->data.structure.root_struct != nullptr) {
- Buf *path_buf = ty->data.structure.root_struct->path;
-
- jw_object_field(jw, "file");
- anal_dump_file_ref(ctx, path_buf);
- }
- break;
- }
- case ZigTypeIdUnion: {
- jw_object_field(jw, "name");
- jw_string(jw, buf_ptr(&ty->name));
-
- jw_object_field(jw, "src");
- anal_dump_node_ref(ctx, ty->data.unionation.decl_node);
-
- {
- jw_object_field(jw, "pubDecls");
- jw_begin_array(jw);
-
- ScopeDecls *decls_scope = ty->data.unionation.decls_scope;
- auto it = decls_scope->decl_table.entry_iterator();
- for (;;) {
- auto *entry = it.next();
- if (!entry)
- break;
-
- Tld *tld = entry->value;
- if (tld->visib_mod == VisibModPub) {
- jw_array_elem(jw);
- anal_dump_decl_ref(ctx, tld);
- }
- }
- jw_end_array(jw);
- }
-
- {
- jw_object_field(jw, "privDecls");
- jw_begin_array(jw);
-
- ScopeDecls *decls_scope = ty->data.unionation.decls_scope;
- auto it = decls_scope->decl_table.entry_iterator();
- for (;;) {
- auto *entry = it.next();
- if (!entry)
- break;
-
- Tld *tld = entry->value;
- if (tld->visib_mod == VisibModPrivate) {
- jw_array_elem(jw);
- anal_dump_decl_ref(ctx, tld);
- }
- }
- jw_end_array(jw);
- }
-
- if (ty->data.unionation.src_field_count != 0) {
- jw_object_field(jw, "fields");
- jw_begin_array(jw);
-
- for(size_t i = 0; i < ty->data.unionation.src_field_count; i += 1) {
- jw_array_elem(jw);
- anal_dump_type_ref(ctx, ty->data.unionation.fields[i].type_entry);
- }
- jw_end_array(jw);
- }
- break;
- }
- case ZigTypeIdEnum: {
- jw_object_field(jw, "name");
- jw_string(jw, buf_ptr(&ty->name));
-
- jw_object_field(jw, "src");
- anal_dump_node_ref(ctx, ty->data.enumeration.decl_node);
-
- {
- jw_object_field(jw, "pubDecls");
- jw_begin_array(jw);
-
- ScopeDecls *decls_scope = ty->data.enumeration.decls_scope;
- auto it = decls_scope->decl_table.entry_iterator();
- for (;;) {
- auto *entry = it.next();
- if (!entry)
- break;
-
- Tld *tld = entry->value;
- if (tld->visib_mod == VisibModPub) {
- jw_array_elem(jw);
- anal_dump_decl_ref(ctx, tld);
- }
- }
- jw_end_array(jw);
- }
-
- {
- jw_object_field(jw, "privDecls");
- jw_begin_array(jw);
-
- ScopeDecls *decls_scope = ty->data.enumeration.decls_scope;
- auto it = decls_scope->decl_table.entry_iterator();
- for (;;) {
- auto *entry = it.next();
- if (!entry)
- break;
-
- Tld *tld = entry->value;
- if (tld->visib_mod == VisibModPrivate) {
- jw_array_elem(jw);
- anal_dump_decl_ref(ctx, tld);
- }
- }
- jw_end_array(jw);
- }
-
- if (ty->data.enumeration.src_field_count != 0) {
- jw_object_field(jw, "fields");
- jw_begin_array(jw);
-
- for(size_t i = 0; i < ty->data.enumeration.src_field_count; i += 1) {
- jw_array_elem(jw);
- jw_bigint(jw, &ty->data.enumeration.fields[i].value);
- }
- jw_end_array(jw);
- }
- break;
- }
- case ZigTypeIdFloat: {
- jw_object_field(jw, "bits");
- jw_int(jw, ty->data.floating.bit_count);
- break;
- }
- case ZigTypeIdInt: {
- if (ty->data.integral.is_signed) {
- jw_object_field(jw, "i");
- } else {
- jw_object_field(jw, "u");
- }
- jw_int(jw, ty->data.integral.bit_count);
- break;
- }
- case ZigTypeIdFn: {
- jw_object_field(jw, "name");
- jw_string(jw, buf_ptr(&ty->name));
-
- jw_object_field(jw, "generic");
- jw_bool(jw, ty->data.fn.is_generic);
-
- if (ty->data.fn.fn_type_id.return_type != nullptr) {
- jw_object_field(jw, "ret");
- anal_dump_type_ref(ctx, ty->data.fn.fn_type_id.return_type);
- }
-
- if (ty->data.fn.fn_type_id.param_count != 0) {
- jw_object_field(jw, "args");
- jw_begin_array(jw);
- for (size_t i = 0; i < ty->data.fn.fn_type_id.param_count; i += 1) {
- jw_array_elem(jw);
- if (ty->data.fn.fn_type_id.param_info[i].type != nullptr) {
- anal_dump_type_ref(ctx, ty->data.fn.fn_type_id.param_info[i].type);
- } else {
- jw_null(jw);
- }
- }
- jw_end_array(jw);
- }
- break;
- }
- case ZigTypeIdOptional: {
- jw_object_field(jw, "child");
- anal_dump_type_ref(ctx, ty->data.maybe.child_type);
- break;
- }
- case ZigTypeIdPointer: {
- switch (ty->data.pointer.ptr_len) {
- case PtrLenSingle:
- break;
- case PtrLenUnknown:
- jw_object_field(jw, "len");
- jw_int(jw, 1);
- break;
- case PtrLenC:
- jw_object_field(jw, "len");
- jw_int(jw, 3);
- break;
- }
- anal_dump_pointer_attrs(ctx, ty);
- break;
- }
- case ZigTypeIdErrorSet: {
- if (type_is_global_error_set(ty)) {
- break;
- }
- jw_object_field(jw, "name");
- jw_string(jw, buf_ptr(&ty->name));
-
- if (ty->data.error_set.infer_fn != nullptr) {
- jw_object_field(jw, "fn");
- anal_dump_fn_ref(ctx, ty->data.error_set.infer_fn);
- }
- jw_object_field(jw, "errors");
- jw_begin_array(jw);
- for (uint32_t i = 0; i < ty->data.error_set.err_count; i += 1) {
- jw_array_elem(jw);
- ErrorTableEntry *err = ty->data.error_set.errors[i];
- anal_dump_err_ref(ctx, err);
- }
- jw_end_array(jw);
- break;
- }
- case ZigTypeIdErrorUnion: {
- jw_object_field(jw, "err");
- anal_dump_type_ref(ctx, ty->data.error_union.err_set_type);
-
- jw_object_field(jw, "payload");
- anal_dump_type_ref(ctx, ty->data.error_union.payload_type);
-
- break;
- }
- case ZigTypeIdArray: {
- jw_object_field(jw, "len");
- jw_int(jw, ty->data.array.len);
-
- jw_object_field(jw, "elem");
- anal_dump_type_ref(ctx, ty->data.array.child_type);
- break;
- }
- case ZigTypeIdVector: {
- jw_object_field(jw, "len");
- jw_int(jw, ty->data.vector.len);
-
- jw_object_field(jw, "elem");
- anal_dump_type_ref(ctx, ty->data.vector.elem_type);
- break;
- }
- case ZigTypeIdAnyFrame: {
- if (ty->data.any_frame.result_type != nullptr) {
- jw_object_field(jw, "result");
- anal_dump_type_ref(ctx, ty->data.any_frame.result_type);
- }
- break;
- }
- case ZigTypeIdFnFrame: {
- jw_object_field(jw, "fnName");
- jw_string(jw, buf_ptr(&ty->data.frame.fn->symbol_name));
-
- jw_object_field(jw, "fn");
- anal_dump_fn_ref(ctx, ty->data.frame.fn);
- break;
- }
- case ZigTypeIdInvalid:
- zig_unreachable();
- default:
- jw_object_field(jw, "name");
- jw_string(jw, buf_ptr(&ty->name));
- break;
- }
- jw_end_object(jw);
-}
-
-static Buf *collect_doc_comments(RootStruct *root_struct, TokenIndex first_token) {
- if (first_token == 0)
- return nullptr;
-
- TokenId *token_ids = root_struct->token_ids;
- TokenLoc *token_locs = root_struct->token_locs;
- Buf *str = buf_alloc();
- const char *source = buf_ptr(root_struct->source_code);
- TokenIndex doc_token = first_token;
- for (;token_ids[doc_token] == TokenIdDocComment; doc_token += 1) {
- // chops off '///' but leaves '\n'
- uint32_t start_pos = token_locs[doc_token].offset;
- uint32_t token_len = 0;
- while (source[start_pos + token_len] != '\n' &&
- source[start_pos + token_len] != 0)
- {
- token_len += 1;
- }
- buf_append_mem(str, source + start_pos + 3, token_len - 3);
- }
- return str;
-}
-
-static void anal_dump_node(AnalDumpCtx *ctx, const AstNode *node) {
- JsonWriter *jw = &ctx->jw;
-
- jw_begin_object(jw);
-
- jw_object_field(jw, "file");
- RootStruct *root_struct = node->owner->data.structure.root_struct;
- anal_dump_file_ref(ctx, root_struct->path);
-
- jw_object_field(jw, "line");
- jw_int(jw, root_struct->token_locs[node->main_token].line);
-
- jw_object_field(jw, "col");
- jw_int(jw, root_struct->token_locs[node->main_token].column);
-
- const Buf *doc_comments_buf = nullptr;
- const Buf *name_buf = nullptr;
- const ZigList<AstNode *> *field_nodes = nullptr;
- bool is_var_args = false;
- bool is_noalias = false;
- bool is_comptime = false;
-
- switch (node->type) {
- case NodeTypeParamDecl:
- doc_comments_buf = collect_doc_comments(root_struct, node->data.param_decl.doc_comments);
- name_buf = node->data.param_decl.name;
- is_var_args = node->data.param_decl.is_var_args;
- is_noalias = node->data.param_decl.is_noalias;
- is_comptime = node->data.param_decl.is_comptime;
- break;
- case NodeTypeFnProto:
- doc_comments_buf = collect_doc_comments(root_struct, node->data.fn_proto.doc_comments);
- field_nodes = &node->data.fn_proto.params;
- is_var_args = node->data.fn_proto.is_var_args;
- break;
- case NodeTypeVariableDeclaration:
- doc_comments_buf = collect_doc_comments(root_struct, node->data.variable_declaration.doc_comments);
- break;
- case NodeTypeErrorSetField:
- doc_comments_buf = collect_doc_comments(root_struct, node->data.err_set_field.doc_comments);
- break;
- case NodeTypeStructField:
- doc_comments_buf = collect_doc_comments(root_struct, node->data.struct_field.doc_comments);
- name_buf = node->data.struct_field.name;
- break;
- case NodeTypeContainerDecl:
- field_nodes = &node->data.container_decl.fields;
- doc_comments_buf = collect_doc_comments(root_struct, node->data.container_decl.doc_comments);
- break;
- default:
- break;
- }
-
- if (doc_comments_buf != nullptr && doc_comments_buf->list.length != 0) {
- jw_object_field(jw, "docs");
- jw_string(jw, buf_ptr(doc_comments_buf));
- }
-
- if (name_buf != nullptr) {
- jw_object_field(jw, "name");
- jw_string(jw, buf_ptr(name_buf));
- }
-
- if (field_nodes != nullptr) {
- jw_object_field(jw, "fields");
- jw_begin_array(jw);
- for (size_t i = 0; i < field_nodes->length; i += 1) {
- jw_array_elem(jw);
- anal_dump_node_ref(ctx, field_nodes->at(i));
- }
- jw_end_array(jw);
- }
-
- if (is_var_args) {
- jw_object_field(jw, "varArgs");
- jw_bool(jw, true);
- }
-
- if (is_comptime) {
- jw_object_field(jw, "comptime");
- jw_bool(jw, true);
- }
-
- if (is_noalias) {
- jw_object_field(jw, "noalias");
- jw_bool(jw, true);
- }
-
- jw_end_object(jw);
-}
-
-static void anal_dump_err(AnalDumpCtx *ctx, const ErrorTableEntry *err) {
- JsonWriter *jw = &ctx->jw;
-
- jw_begin_object(jw);
-
- jw_object_field(jw, "src");
- anal_dump_node_ref(ctx, err->decl_node);
-
- jw_object_field(jw, "name");
- jw_string(jw, buf_ptr(&err->name));
-
- jw_end_object(jw);
-}
-
-static void anal_dump_fn(AnalDumpCtx *ctx, ZigFn *fn) {
- JsonWriter *jw = &ctx->jw;
-
- jw_begin_object(jw);
-
- jw_object_field(jw, "src");
- anal_dump_node_ref(ctx, fn->proto_node);
-
- jw_object_field(jw, "type");
- anal_dump_type_ref(ctx, fn->type_entry);
-
- auto entry = ctx->fn_decl_map.maybe_get(fn);
- if (entry != nullptr) {
- jw_object_field(jw, "decl");
- jw_int(jw, entry->value);
- }
-
- jw_end_object(jw);
-}
-
-void zig_print_analysis_dump(CodeGen *g, FILE *f, const char *one_indent, const char *nl) {
- AnalDumpCtx ctx = {};
- ctx.g = g;
- JsonWriter *jw = &ctx.jw;
- jw_init(jw, f, one_indent, nl);
- ctx.type_map.init(16);
- ctx.pkg_map.init(16);
- ctx.file_map.init(16);
- ctx.decl_map.init(16);
- ctx.node_map.init(16);
- ctx.fn_map.init(16);
- ctx.fn_decl_map.init(16);
- ctx.err_map.init(16);
-
- jw_begin_object(jw);
-
- jw_object_field(jw, "typeKinds");
- jw_begin_array(jw);
- for (size_t i = 0; i < type_id_len(); i += 1) {
- jw_array_elem(jw);
- jw_string(jw, type_id_name(type_id_at_index(i)));
- }
- jw_end_array(jw);
-
- jw_object_field(jw, "params");
- jw_begin_object(jw);
- {
- jw_object_field(jw, "zigVersion");
- jw_string(jw, stage2_version_string());
-
- jw_object_field(jw, "builds");
- jw_begin_array(jw);
- jw_array_elem(jw);
- jw_begin_object(jw);
- jw_object_field(jw, "target");
- Buf triple_buf = BUF_INIT;
- target_triple_zig(&triple_buf, g->zig_target);
- jw_string(jw, buf_ptr(&triple_buf));
- jw_end_object(jw);
- jw_end_array(jw);
-
- jw_object_field(jw, "rootName");
- jw_string(jw, buf_ptr(g->root_out_name));
- }
- jw_end_object(jw);
-
- jw_object_field(jw, "rootPkg");
- anal_dump_pkg_ref(&ctx, g->main_pkg);
-
- // FIXME: Remove this ugly workaround.
- // Right now the code in docs/main.js relies on the root of the main package being itself.
- g->main_pkg->package_table.put(buf_create_from_str("root"), g->main_pkg);
-
- // Poke the functions
- for (size_t i = 0; i < g->fn_defs.length; i += 1) {
- ZigFn *fn = g->fn_defs.at(i);
- (void)anal_dump_get_fn_id(&ctx, fn);
- }
-
- jw_object_field(jw, "calls");
- jw_begin_array(jw);
- {
- ZigList<ZigVar *> var_stack = {};
-
- auto it = g->memoized_fn_eval_table.entry_iterator();
- for (;;) {
- auto *entry = it.next();
- if (!entry)
- break;
-
- var_stack.resize(0);
- ZigFn *fn = nullptr;
-
- Scope *scope = entry->key;
- while (scope != nullptr) {
- if (scope->id == ScopeIdVarDecl) {
- ZigVar *var = reinterpret_cast<ScopeVarDecl *>(scope)->var;
- var_stack.append(var);
- } else if (scope->id == ScopeIdFnDef) {
- fn = reinterpret_cast<ScopeFnDef *>(scope)->fn_entry;
- break;
- }
- scope = scope->parent;
- }
- ZigValue *result = entry->value;
-
- assert(fn != nullptr);
-
- jw_array_elem(jw);
- jw_begin_object(jw);
-
- jw_object_field(jw, "fn");
- anal_dump_fn_ref(&ctx, fn);
-
- jw_object_field(jw, "result");
- {
- jw_begin_object(jw);
-
- jw_object_field(jw, "type");
- anal_dump_type_ref(&ctx, result->type);
-
- jw_object_field(jw, "value");
- anal_dump_value(&ctx, scope->source_node, result->type, result);
-
- jw_end_object(jw);
- }
-
- if (var_stack.length != 0) {
- jw_object_field(jw, "args");
- jw_begin_array(jw);
-
- while (var_stack.length != 0) {
- ZigVar *var = var_stack.pop();
-
- jw_array_elem(jw);
- jw_begin_object(jw);
-
- jw_object_field(jw, "type");
- anal_dump_type_ref(&ctx, var->var_type);
-
- jw_object_field(jw, "value");
- anal_dump_value(&ctx, scope->source_node, var->var_type, var->const_value);
-
- jw_end_object(jw);
- }
- jw_end_array(jw);
- }
-
- jw_end_object(jw);
- }
-
- var_stack.deinit();
- }
- jw_end_array(jw);
-
- jw_object_field(jw, "packages");
- jw_begin_array(jw);
- for (uint32_t i = 0; i < ctx.pkg_list.length; i += 1) {
- anal_dump_pkg(&ctx, ctx.pkg_list.at(i));
- }
- jw_end_array(jw);
-
- jw_object_field(jw, "types");
- jw_begin_array(jw);
-
- for (uint32_t i = 0; i < ctx.type_list.length; i += 1) {
- ZigType *ty = ctx.type_list.at(i);
- anal_dump_type(&ctx, ty);
- }
- jw_end_array(jw);
-
- jw_object_field(jw, "decls");
- jw_begin_array(jw);
- for (uint32_t i = 0; i < ctx.decl_list.length; i += 1) {
- Tld *decl = ctx.decl_list.at(i);
- anal_dump_decl(&ctx, decl);
- }
- jw_end_array(jw);
-
- jw_object_field(jw, "fns");
- jw_begin_array(jw);
- for (uint32_t i = 0; i < ctx.fn_list.length; i += 1) {
- ZigFn *fn = ctx.fn_list.at(i);
- jw_array_elem(jw);
- anal_dump_fn(&ctx, fn);
- }
- jw_end_array(jw);
-
- jw_object_field(jw, "errors");
- jw_begin_array(jw);
- for (uint32_t i = 0; i < ctx.err_list.length; i += 1) {
- const ErrorTableEntry *err = ctx.err_list.at(i);
- jw_array_elem(jw);
- anal_dump_err(&ctx, err);
- }
- jw_end_array(jw);
-
- jw_object_field(jw, "astNodes");
- jw_begin_array(jw);
- for (uint32_t i = 0; i < ctx.node_list.length; i += 1) {
- const AstNode *node = ctx.node_list.at(i);
- jw_array_elem(jw);
- anal_dump_node(&ctx, node);
- }
- jw_end_array(jw);
-
- jw_object_field(jw, "files");
- jw_begin_array(jw);
- for (uint32_t i = 0; i < ctx.file_list.length; i += 1) {
- Buf *file = ctx.file_list.at(i);
- jw_array_elem(jw);
- anal_dump_file(&ctx, file);
- }
- jw_end_array(jw);
-
- jw_end_object(jw);
-}
diff --git a/src/stage1/dump_analysis.hpp b/src/stage1/dump_analysis.hpp
@@ -1,17 +0,0 @@
-/*
- * Copyright (c) 2019 Andrew Kelley
- *
- * This file is part of zig, which is MIT licensed.
- * See http://opensource.org/licenses/MIT
- */
-
-#ifndef ZIG_DUMP_ANALYSIS_HPP
-#define ZIG_DUMP_ANALYSIS_HPP
-
-#include "all_types.hpp"
-#include <stdio.h>
-
-void zig_print_stack_report(CodeGen *g, FILE *f);
-void zig_print_analysis_dump(CodeGen *g, FILE *f, const char *one_indent, const char *nl);
-
-#endif
diff --git a/src/stage1/stage1.cpp b/src/stage1/stage1.cpp
@@ -74,8 +74,6 @@ void zig_stage1_build_object(struct ZigStage1 *stage1) {
buf_init_from_mem(&g->asm_file_output_path, stage1->emit_asm_ptr, stage1->emit_asm_len);
buf_init_from_mem(&g->llvm_ir_file_output_path, stage1->emit_llvm_ir_ptr, stage1->emit_llvm_ir_len);
buf_init_from_mem(&g->bitcode_file_output_path, stage1->emit_bitcode_ptr, stage1->emit_bitcode_len);
- buf_init_from_mem(&g->analysis_json_output_path, stage1->emit_analysis_json_ptr, stage1->emit_analysis_json_len);
- buf_init_from_mem(&g->docs_output_path, stage1->emit_docs_ptr, stage1->emit_docs_len);
if (stage1->builtin_zig_path_len != 0) {
g->builtin_zig_path = buf_create_from_mem(stage1->builtin_zig_path_ptr, stage1->builtin_zig_path_len);
diff --git a/src/stage1/stage1.h b/src/stage1/stage1.h
@@ -161,12 +161,6 @@ struct ZigStage1 {
const char *emit_bitcode_ptr;
size_t emit_bitcode_len;
- const char *emit_analysis_json_ptr;
- size_t emit_analysis_json_len;
-
- const char *emit_docs_ptr;
- size_t emit_docs_len;
-
const char *builtin_zig_path_ptr;
size_t builtin_zig_path_len;
diff --git a/tools/merge_anal_dumps.zig b/tools/merge_anal_dumps.zig
@@ -1,454 +0,0 @@
-const builtin = @import("builtin");
-const std = @import("std");
-const json = std.json;
-const mem = std.mem;
-const fieldIndex = std.meta.fieldIndex;
-const TypeId = builtin.TypeId;
-
-pub fn main() anyerror!void {
- var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
- defer arena.deinit();
-
- const allocator = arena.allocator();
-
- const args = try std.process.argsAlloc(allocator);
-
- var parser: json.Parser = undefined;
- var dump = Dump.init(allocator);
- for (args[1..]) |arg| {
- parser = json.Parser.init(allocator, false);
- const json_text = try std.fs.cwd().readFileAlloc(allocator, arg, std.math.maxInt(usize));
- const tree = try parser.parse(json_text);
- try dump.mergeJson(tree.root);
- }
-
- const stdout = try std.io.getStdOut();
- try dump.render(stdout.writer());
-}
-
-/// AST source node
-const Node = struct {
- file: usize,
- line: usize,
- col: usize,
- fields: []usize,
-
- fn hash(n: Node) u64 {
- var hasher = std.hash.Wyhash.init(0);
- std.hash.autoHash(&hasher, n.file);
- std.hash.autoHash(&hasher, n.line);
- std.hash.autoHash(&hasher, n.col);
- return hasher.final();
- }
-
- fn eql(a: Node, b: Node) bool {
- return a.file == b.file and
- a.line == b.line and
- a.col == b.col;
- }
-};
-
-const Error = struct {
- src: usize,
- name: []const u8,
-
- fn hash(n: Error) u64 {
- var hasher = std.hash.Wyhash.init(0);
- std.hash.autoHash(&hasher, n.src);
- return hasher.final();
- }
-
- fn eql(a: Error, b: Error) bool {
- return a.src == b.src;
- }
-};
-
-const simple_types = [_][]const u8{
- "Type",
- "Void",
- "Bool",
- "NoReturn",
- "ComptimeFloat",
- "ComptimeInt",
- "Undefined",
- "Null",
- "AnyFrame",
- "EnumLiteral",
-};
-
-const Type = union(builtin.TypeId) {
- Type,
- Void,
- Bool,
- NoReturn,
- ComptimeFloat,
- ComptimeInt,
- Undefined,
- Null,
- AnyFrame,
- EnumLiteral,
-
- Int: Int,
- Float: usize, // bits
-
- Vector: Array,
- Optional: usize, // payload type index
- Pointer: Pointer,
- Array: Array,
-
- Struct, // TODO
- ErrorUnion, // TODO
- ErrorSet, // TODO
- Enum, // TODO
- Union, // TODO
- Fn, // TODO
- BoundFn, // TODO
- Opaque, // TODO
- Frame, // TODO
-
- const Int = struct {
- bits: usize,
- signed: bool,
- };
-
- const Pointer = struct {
- elem: usize,
- alignment: usize,
- is_const: bool,
- is_volatile: bool,
- allow_zero: bool,
- host_int_bytes: usize,
- bit_offset_in_host: usize,
- };
-
- const Array = struct {
- elem: usize,
- len: usize,
- };
-
- fn hash(t: Type) u64 {
- var hasher = std.hash.Wyhash.init(0);
- std.hash.autoHash(&hasher, t);
- return hasher.final();
- }
-
- fn eql(a: Type, b: Type) bool {
- return std.meta.eql(a, b);
- }
-};
-
-const Dump = struct {
- zig_id: ?[]const u8 = null,
- zig_version: ?[]const u8 = null,
- root_name: ?[]const u8 = null,
- targets: std.ArrayList([]const u8),
-
- file_list: std.ArrayList([]const u8),
- file_map: FileMap,
-
- node_list: std.ArrayList(Node),
- node_map: NodeMap,
-
- error_list: std.ArrayList(Error),
- error_map: ErrorMap,
-
- type_list: std.ArrayList(Type),
- type_map: TypeMap,
-
- const FileMap = std.StringHashMap(usize);
- const NodeMap = std.HashMap(Node, usize, Node.hash, Node.eql, 80);
- const ErrorMap = std.HashMap(Error, usize, Error.hash, Error.eql, 80);
- const TypeMap = std.HashMap(Type, usize, Type.hash, Type.eql, 80);
-
- fn init(allocator: mem.Allocator) Dump {
- return Dump{
- .targets = std.ArrayList([]const u8).init(allocator),
- .file_list = std.ArrayList([]const u8).init(allocator),
- .file_map = FileMap.init(allocator),
- .node_list = std.ArrayList(Node).init(allocator),
- .node_map = NodeMap.init(allocator),
- .error_list = std.ArrayList(Error).init(allocator),
- .error_map = ErrorMap.init(allocator),
- .type_list = std.ArrayList(Type).init(allocator),
- .type_map = TypeMap.init(allocator),
- };
- }
-
- fn mergeJson(self: *Dump, root: json.Value) !void {
- const params = &root.Object.get("params").?.value.Object;
- const zig_id = params.get("zigId").?.value.String;
- const zig_version = params.get("zigVersion").?.value.String;
- const root_name = params.get("rootName").?.value.String;
- try mergeSameStrings(&self.zig_id, zig_id);
- try mergeSameStrings(&self.zig_version, zig_version);
- try mergeSameStrings(&self.root_name, root_name);
-
- for (params.get("builds").?.value.Array.items) |json_build| {
- const target = json_build.Object.get("target").?.value.String;
- try self.targets.append(target);
- }
-
- // Merge files. If the string matches, it's the same file.
- const other_files = root.Object.get("files").?.value.Array.items;
- var other_file_to_mine = std.AutoHashMap(usize, usize).init(self.a());
- for (other_files) |other_file, i| {
- const gop = try self.file_map.getOrPut(other_file.String);
- if (!gop.found_existing) {
- gop.kv.value = self.file_list.items.len;
- try self.file_list.append(other_file.String);
- }
- try other_file_to_mine.putNoClobber(i, gop.kv.value);
- }
-
- // Merge AST nodes. If the file id, line, and column all match, it's the same AST node.
- const other_ast_nodes = root.Object.get("astNodes").?.value.Array.items;
- var other_ast_node_to_mine = std.AutoHashMap(usize, usize).init(self.a());
- for (other_ast_nodes) |other_ast_node_json, i| {
- const other_file_id = jsonObjInt(other_ast_node_json, "file");
- const other_node = Node{
- .line = jsonObjInt(other_ast_node_json, "line"),
- .col = jsonObjInt(other_ast_node_json, "col"),
- .file = other_file_to_mine.getValue(other_file_id).?,
- .fields = ([*]usize)(undefined)[0..0],
- };
- const gop = try self.node_map.getOrPut(other_node);
- if (!gop.found_existing) {
- gop.kv.value = self.node_list.items.len;
- try self.node_list.append(other_node);
- }
- try other_ast_node_to_mine.putNoClobber(i, gop.kv.value);
- }
- // convert fields lists
- for (other_ast_nodes) |other_ast_node_json, i| {
- const my_node_index = other_ast_node_to_mine.get(i).?.value;
- const my_node = &self.node_list.items[my_node_index];
- if (other_ast_node_json.Object.get("fields")) |fields_json_kv| {
- const other_fields = fields_json_kv.value.Array.items;
- my_node.fields = try self.a().alloc(usize, other_fields.len);
- for (other_fields) |other_field_index, field_i| {
- const other_index = @intCast(usize, other_field_index.Integer);
- my_node.fields[field_i] = other_ast_node_to_mine.get(other_index).?.value;
- }
- }
- }
-
- // Merge errors. If the AST Node matches, it's the same error value.
- const other_errors = root.Object.get("errors").?.value.Array.items;
- var other_error_to_mine = std.AutoHashMap(usize, usize).init(self.a());
- for (other_errors) |other_error_json, i| {
- const other_src_id = jsonObjInt(other_error_json, "src");
- const other_error = Error{
- .src = other_ast_node_to_mine.getValue(other_src_id).?,
- .name = other_error_json.Object.get("name").?.value.String,
- };
- const gop = try self.error_map.getOrPut(other_error);
- if (!gop.found_existing) {
- gop.kv.value = self.error_list.items.len;
- try self.error_list.append(other_error);
- }
- try other_error_to_mine.putNoClobber(i, gop.kv.value);
- }
-
- // Merge types. Now it starts to get advanced.
- // First we identify all the simple types and merge those.
- // Example: void, type, noreturn
- // We can also do integers and floats.
- const other_types = root.Object.get("types").?.value.Array.items;
- var other_types_to_mine = std.AutoHashMap(usize, usize).init(self.a());
- for (other_types) |other_type_json, i| {
- const type_kind = jsonObjInt(other_type_json, "kind");
- switch (type_kind) {
- fieldIndex(TypeId, "Int").? => {
- var signed: bool = undefined;
- var bits: usize = undefined;
- if (other_type_json.Object.get("i")) |kv| {
- signed = true;
- bits = @intCast(usize, kv.value.Integer);
- } else if (other_type_json.Object.get("u")) |kv| {
- signed = false;
- bits = @intCast(usize, kv.value.Integer);
- } else {
- unreachable;
- }
- const other_type = Type{
- .Int = Type.Int{
- .bits = bits,
- .signed = signed,
- },
- };
- try self.mergeOtherType(other_type, i, &other_types_to_mine);
- },
- fieldIndex(TypeId, "Float").? => {
- const other_type = Type{
- .Float = jsonObjInt(other_type_json, "bits"),
- };
- try self.mergeOtherType(other_type, i, &other_types_to_mine);
- },
- else => {},
- }
-
- inline for (simple_types) |simple_type_name| {
- if (type_kind == std.meta.fieldIndex(builtin.TypeId, simple_type_name).?) {
- const other_type = @unionInit(Type, simple_type_name, {});
- try self.mergeOtherType(other_type, i, &other_types_to_mine);
- }
- }
- }
- }
-
- fn mergeOtherType(
- self: *Dump,
- other_type: Type,
- other_type_index: usize,
- other_types_to_mine: *std.AutoHashMap(usize, usize),
- ) !void {
- const gop = try self.type_map.getOrPut(other_type);
- if (!gop.found_existing) {
- gop.kv.value = self.type_list.items.len;
- try self.type_list.append(other_type);
- }
- try other_types_to_mine.putNoClobber(other_type_index, gop.kv.value);
- }
-
- fn render(self: *Dump, stream: anytype) !void {
- var jw = json.WriteStream(@TypeOf(stream).Child, 10).init(stream);
- try jw.beginObject();
-
- try jw.objectField("typeKinds");
- try jw.beginArray();
- inline for (@typeInfo(builtin.TypeId).Enum.fields) |field| {
- try jw.arrayElem();
- try jw.emitString(field.name);
- }
- try jw.endArray();
-
- try jw.objectField("params");
- try jw.beginObject();
-
- try jw.objectField("zigId");
- try jw.emitString(self.zig_id.?);
-
- try jw.objectField("zigVersion");
- try jw.emitString(self.zig_version.?);
-
- try jw.objectField("rootName");
- try jw.emitString(self.root_name.?);
-
- try jw.objectField("builds");
- try jw.beginArray();
- for (self.targets.items) |target| {
- try jw.arrayElem();
- try jw.beginObject();
- try jw.objectField("target");
- try jw.emitString(target);
- try jw.endObject();
- }
- try jw.endArray();
-
- try jw.endObject();
-
- try jw.objectField("types");
- try jw.beginArray();
- for (self.type_list.items) |t| {
- try jw.arrayElem();
- try jw.beginObject();
-
- try jw.objectField("kind");
- try jw.emitNumber(@enumToInt(builtin.TypeId(t)));
-
- switch (t) {
- .Int => |int| {
- if (int.signed) {
- try jw.objectField("i");
- } else {
- try jw.objectField("u");
- }
- try jw.emitNumber(int.bits);
- },
- .Float => |bits| {
- try jw.objectField("bits");
- try jw.emitNumber(bits);
- },
-
- else => {},
- }
-
- try jw.endObject();
- }
- try jw.endArray();
-
- try jw.objectField("errors");
- try jw.beginArray();
- for (self.error_list.items) |zig_error| {
- try jw.arrayElem();
- try jw.beginObject();
-
- try jw.objectField("src");
- try jw.emitNumber(zig_error.src);
-
- try jw.objectField("name");
- try jw.emitString(zig_error.name);
-
- try jw.endObject();
- }
- try jw.endArray();
-
- try jw.objectField("astNodes");
- try jw.beginArray();
- for (self.node_list.items) |node| {
- try jw.arrayElem();
- try jw.beginObject();
-
- try jw.objectField("file");
- try jw.emitNumber(node.file);
-
- try jw.objectField("line");
- try jw.emitNumber(node.line);
-
- try jw.objectField("col");
- try jw.emitNumber(node.col);
-
- if (node.fields.len != 0) {
- try jw.objectField("fields");
- try jw.beginArray();
-
- for (node.fields) |field_node_index| {
- try jw.arrayElem();
- try jw.emitNumber(field_node_index);
- }
- try jw.endArray();
- }
-
- try jw.endObject();
- }
- try jw.endArray();
-
- try jw.objectField("files");
- try jw.beginArray();
- for (self.file_list.items) |file| {
- try jw.arrayElem();
- try jw.emitString(file);
- }
- try jw.endArray();
-
- try jw.endObject();
- }
-
- fn a(self: Dump) mem.Allocator {
- return self.targets.allocator;
- }
-
- fn mergeSameStrings(opt_dest: *?[]const u8, src: []const u8) !void {
- if (opt_dest.*) |dest| {
- if (!mem.eql(u8, dest, src))
- return error.MismatchedDumps;
- } else {
- opt_dest.* = src;
- }
- }
-};
-
-fn jsonObjInt(json_val: json.Value, field: []const u8) usize {
- const uncasted = json_val.Object.get(field).?.value.Integer;
- return @intCast(usize, uncasted);
-}