authorgravatar for kappaloris@gmail.comLoris Cro <kappaloris@gmail.com> 2022-03-08 19:57:22+01:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-07-19 19:10:11-07:00
log3eb90a110f2c4b6eea82b0fcd7c8cab386594437
tree09250a534089ae7ecd8dcbb0291cec5cd9fe55fa
parent03d392923208550c21f2f3813379830b76c54133

autodoc: add support for pointers and comptime expressions in decl paths


2 files changed, 184 insertions(+), 122 deletions(-)

lib/docs/main.js+105-88
...@@ -144,13 +144,33 @@...@@ -144,13 +144,33 @@
144 return typeKind === typeKinds.ErrorSet || typeKindIsContainer(typeKind);144 return typeKind === typeKinds.ErrorSet || typeKindIsContainer(typeKind);
145 }145 }
146146
147 function findCteInDeclPath(path) {
148 for (var i = path.length - 1; i >= 0; i -= 1) {
149 const decl = zigAnalysis.decls[path[i]];
150 if ("comptimeExpr" in decl.value) {
151 return decl;
152 }
153
154 if ("declPath" in decl.value) {
155 const res = findCteInDeclPath(decl.value.declPath);
156 if (res !== null) {
157 return res;
158 }
159 }
160 }
161
162 return null;
163 }
164
147 function resolveValue(value) {165 function resolveValue(value) {
148 var i = 0;166 var i = 0;
149 while(i < 1000) {167 while(i < 1000) {
150 i += 1;168 i += 1;
151169
152 if ("declPath" in value) {170 if ("declPath" in value) {
153 console.assert(value.declPath.length == 1); // only support declRefs for now171 if (value.hasCte) {
172 return findCteInDeclPath(value.declPath).value;
173 }
154 value = zigAnalysis.decls[value.declPath[0]].value;174 value = zigAnalysis.decls[value.declPath[0]].value;
155 continue;175 continue;
156 }176 }
...@@ -171,30 +191,34 @@...@@ -171,30 +191,34 @@
171 }191 }
172192
173 if ("declPath" in decl.value) {193 if ("declPath" in decl.value) {
174 console.assert(decl.value.declPath.length == 1); // only support declRefs for now194 if (decl.value.hasCte) {
175 decl = zigAnalysis.decls[decl.value.declPath[0]];195 decl = findCteInDeclPath(decl.value.declPath);
196 } else {
197 decl = zigAnalysis.decls[decl.value.declPath[0]];
198 }
199
176 continue;200 continue;
177 }201 }
178202
179 if ("int" in decl.value) {203 if ("int" in decl.value) {
180 return resolveTypeRefToTypeId(decl.value.int.typeRef);204 return decl.value.int.typeRef;
181 }205 }
182206
183 if ("float" in decl.value) {207 if ("float" in decl.value) {
184 return resolveTypeRefToTypeId(decl.value.float.typeRef);208 return decl.value.float.typeRef;
185 }209 }
186210
187 if ("array" in decl.value) {211 if ("array" in decl.value) {
188 return resolveTypeRefToTypeId(decl.value.array.typeRef);212 return decl.value.array.typeRef;
189 }213 }
190214
191 if ("struct" in decl.value) {215 if ("struct" in decl.value) {
192 return resolveTypeRefToTypeId(decl.value.struct.typeRef);216 return decl.value.struct.typeRef;
193 }217 }
194218
195 if ("comptimeExpr" in decl.value) {219 if ("comptimeExpr" in decl.value) {
196 const cte = zigAnalysis.comptimeExprs[decl.value.comptimeExpr];220 const cte = zigAnalysis.comptimeExprs[decl.value.comptimeExpr];
197 return resolveTypeRefToTypeId(cte.typeRef);221 return cte.typeRef;
198 }222 }
199223
200 if ("call" in decl.value) {224 if ("call" in decl.value) {
...@@ -205,7 +229,7 @@...@@ -205,7 +229,7 @@
205 console.assert("type" in fn_decl_value); //TODO handle comptimeExpr229 console.assert("type" in fn_decl_value); //TODO handle comptimeExpr
206 const fn_type = zigAnalysis.types[fn_decl_value.type];230 const fn_type = zigAnalysis.types[fn_decl_value.type];
207 console.assert(fn_type.kind === typeKinds.Fn);231 console.assert(fn_type.kind === typeKinds.Fn);
208 return resolveTypeRefToTypeId(fn_type.ret);232 return fn_type.ret;
209 }233 }
210234
211 console.log("TODO: handle in `typeOfDecl` more cases: ", decl);235 console.log("TODO: handle in `typeOfDecl` more cases: ", decl);
...@@ -215,23 +239,6 @@...@@ -215,23 +239,6 @@
215 console.assert(false);239 console.assert(false);
216 }240 }
217241
218 function resolveTypeRefToTypeId(ref) {
219 if ("unspecified" in ref) {
220 console.log("found an unspecified type!")
221 return -1;
222 }
223
224 if ("declRef" in ref) {
225 return typeOfDecl(ref.declRef);
226 }
227
228 if ("type" in ref) {
229 return ref.type;
230 }
231
232 console.assert(false);
233 }
234
235 function render() {242 function render() {
236 domStatus.classList.add("hidden");243 domStatus.classList.add("hidden");
237 domFnProto.classList.add("hidden");244 domFnProto.classList.add("hidden");
...@@ -369,7 +376,7 @@...@@ -369,7 +376,7 @@
369 console.assert("type" in value);376 console.assert("type" in value);
370 var typeObj = zigAnalysis.types[value.type];377 var typeObj = zigAnalysis.types[value.type];
371378
372 domFnProtoCode.innerHTML = typeIndexName(value.type, true, true, fnDecl);379 domFnProtoCode.innerHTML = typeValueName(value, true, true, fnDecl);
373380
374 var docsSource = null;381 var docsSource = null;
375 var srcNode = zigAnalysis.astNodes[fnDecl.src];382 var srcNode = zigAnalysis.astNodes[fnDecl.src];
...@@ -462,9 +469,6 @@...@@ -462,9 +469,6 @@
462469
463470
464 var value = typeObj.params[i];471 var value = typeObj.params[i];
465 var valueType = resolveValue(value);
466 console.assert("type" in valueType);
467 var argTypeIndex = valueType.type;
468 var html = '<pre>' + escapeHtml(fieldNode.name) + ": ";472 var html = '<pre>' + escapeHtml(fieldNode.name) + ": ";
469 if (isVarArgs && i === typeObj.params.length - 1) {473 if (isVarArgs && i === typeObj.params.length - 1) {
470 html += '...';474 html += '...';
...@@ -482,8 +486,6 @@...@@ -482,8 +486,6 @@
482 } else if ("type" in value) {486 } else if ("type" in value) {
483 var name = zigAnalysis.types[value.type].name;487 var name = zigAnalysis.types[value.type].name;
484 html += '<span class="tok-kw">' + escapeHtml(name) + '</span>';488 html += '<span class="tok-kw">' + escapeHtml(name) + '</span>';
485 } else if (argTypeIndex != null) {
486 html += typeIndexName(argTypeIndex, true, true);
487 } else {489 } else {
488 html += '<span class="tok-kw">var</span>';490 html += '<span class="tok-kw">var</span>';
489 }491 }
...@@ -654,13 +656,16 @@...@@ -654,13 +656,16 @@
654 }656 }
655 }657 }
656658
657 function typeIndexName(typeIndex, wantHtml, wantLink, fnDecl, linkFnNameDecl) {
658 return typeValueName({ type: typeIndex }, wantHtml, wantLink, fnDecl, linkFnNameDecl);
659 }
660
661 function typeValueName(typeValue, wantHtml, wantLink, fnDecl, linkFnNameDecl) {659 function typeValueName(typeValue, wantHtml, wantLink, fnDecl, linkFnNameDecl) {
662 if ("declPath" in typeValue) {660 if ("declPath" in typeValue) {
663 console.assert(typeValue.declPath.length == 1);661 if (typeValue.hasCte) {
662 // TODO: find the cte, print it nicely
663 if (wantLink) {
664 return '<a href=""># CTE TODO #</a>';
665 } else {
666 return "# CTE TODO #";
667 }
668 }
664 var declIndex = typeValue.declPath[0];669 var declIndex = typeValue.declPath[0];
665 var name = zigAnalysis.decls[declIndex].name;670 var name = zigAnalysis.decls[declIndex].name;
666 var declPath = getCanonDeclPath(declIndex);671 var declPath = getCanonDeclPath(declIndex);
...@@ -695,12 +700,17 @@...@@ -695,12 +700,17 @@
695 }700 }
696 }701 }
697702
698 function shouldSkipParamName(typeIndex, paramName) {703 function shouldSkipParamName(typeRef, paramName) {
699 var typeObj = zigAnalysis.types[typeIndex];704 var resolvedTypeRef = resolveValue(typeRef);
700 if (typeObj.kind === typeKinds.Pointer && getPtrSize(typeObj) === pointerSizeEnum.One) {705 if ("type" in resolvedTypeRef) {
701 typeIndex = typeObj.child;706 var typeObj = zigAnalysis.types[resolvedTypeRef.type];
707 if (typeObj.kind === typeKinds.Pointer &&
708 getPtrSize(typeObj) === pointerSizeEnum.One) {
709 const value = resolveValue(typeObj.child);
710 return typeValueName(value, false, true).toLowerCase() === paramName;
711 }
702 }712 }
703 return typeIndexName(typeIndex, false, true).toLowerCase() === paramName;713 return false;
704 }714 }
705715
706 function getPtrSize(typeObj) {716 function getPtrSize(typeObj) {
...@@ -716,20 +726,25 @@...@@ -716,20 +726,25 @@
716 for (var arg_i = 0; arg_i < callObj.args.length; arg_i += 1) {726 for (var arg_i = 0; arg_i < callObj.args.length; arg_i += 1) {
717 if (arg_i !== 0) html += ', ';727 if (arg_i !== 0) html += ', ';
718 var argObj = callObj.args[arg_i];728 var argObj = callObj.args[arg_i];
719 html += getValueText(argObj.type, argObj.value, true, true);729 html += getValueText(argObj, argObj.value, true, true);
720 }730 }
721 html += ')';731 html += ')';
722 return html;732 return html;
723 }733 }
724734
725 function getValueText(typeIndex, value, wantHtml, wantLink) {735 function getValueText(typeRef, value, wantHtml, wantLink) {
726 var typeObj = zigAnalysis.types[typeIndex];736 var resolvedTypeRef = resolveValue(typeRef);
737 if ("comptimeExpr" in resolvedTypeRef) {
738 return "# CTE TODO #";
739 }
740 console.assert("type" in resolvedTypeRef);
741 var typeObj = zigAnalysis.types[typeRef.type];
727 switch (typeObj.kind) {742 switch (typeObj.kind) {
728 case typeKinds.Type:743 case typeKinds.Type:
729 return typeIndexName(value, wantHtml, wantLink);744 return typeIndexName(value, wantHtml, wantLink);
730 case typeKinds.Fn:745 case typeKinds.Fn:
731 var fnObj = zigAnalysis.fns[value];746 var fnObj = zigAnalysis.fns[value];
732 return typeIndexName(fnObj.type, wantHtml, wantLink);747 return typeValueName(fnObj, wantHtml, wantLink);
733 case typeKinds.Int:748 case typeKinds.Int:
734 if (wantHtml) {749 if (wantHtml) {
735 return '<span class="tok-number">' + value + '</span>';750 return '<span class="tok-number">' + value + '</span>';
...@@ -923,11 +938,10 @@...@@ -923,11 +938,10 @@
923 if (i != 0) {938 if (i != 0) {
924 payloadHtml += ', ';939 payloadHtml += ', ';
925 }940 }
941
926 var value = typeObj.params[i];942 var value = typeObj.params[i];
927 var paramValue = resolveValue(value);943 var paramValue = resolveValue(value);
928 console.assert("type" in paramValue);944 var isCte = "comptimeExpr" in paramValue;
929 var argTypeIndex = paramValue.type;
930
931945
932 if (fields != null) {946 if (fields != null) {
933 var paramNode = zigAnalysis.astNodes[fields[i]];947 var paramNode = zigAnalysis.astNodes[fields[i]];
...@@ -956,7 +970,7 @@...@@ -956,7 +970,7 @@
956 var paramName = paramNode.name;970 var paramName = paramNode.name;
957 if (paramName != null) {971 if (paramName != null) {
958 // skip if it matches the type name972 // skip if it matches the type name
959 if (argTypeIndex == null || !shouldSkipParamName(argTypeIndex, paramName)) {973 if (!shouldSkipParamName(paramValue, paramName)) {
960 payloadHtml += paramName + ': ';974 payloadHtml += paramName + ': ';
961 }975 }
962 }976 }
...@@ -975,10 +989,10 @@...@@ -975,10 +989,10 @@
975 payloadHtml += '<span class="tok-kw" style="color:lightblue;">' + escapeHtml(decl.name) + '</span>';989 payloadHtml += '<span class="tok-kw" style="color:lightblue;">' + escapeHtml(decl.name) + '</span>';
976 payloadHtml += '</a>';990 payloadHtml += '</a>';
977 } else if ("type" in value) {991 } else if ("type" in value) {
978 var name = zigAnalysis.types[value.type].name;992 var name = typeValueName(value, false);
979 payloadHtml += '<span class="tok-kw">' + escapeHtml(name) + '</span>';993 payloadHtml += '<span class="tok-kw">' + escapeHtml(name) + '</span>';
980 } else if (argTypeIndex != null) {994 } else if ("comptimeExpr" in value) {
981 payloadHtml += typeIndexName(argTypeIndex, wantHtml, wantSubLink);995 payloadHtml += '<span class="tok-kw"> # CTE TODO #</span>';
982 } else if (wantHtml) {996 } else if (wantHtml) {
983 payloadHtml += '<span class="tok-kw">var</span>';997 payloadHtml += '<span class="tok-kw">var</span>';
984 } else {998 } else {
...@@ -1152,7 +1166,7 @@...@@ -1152,7 +1166,7 @@
11521166
1153 function renderValue(decl) {1167 function renderValue(decl) {
11541168
1155 var declTypeId = typeOfDecl(decl);1169 var declTypeRef = typeOfDecl(decl);
1156 var declValueText = "";1170 var declValueText = "";
1157 switch(Object.keys(decl.value)[0]) {1171 switch(Object.keys(decl.value)[0]) {
1158 case "int":1172 case "int":
...@@ -1170,7 +1184,7 @@...@@ -1170,7 +1184,7 @@
1170 }1184 }
11711185
1172 domFnProtoCode.innerHTML = '<span class="tok-kw">const</span> ' +1186 domFnProtoCode.innerHTML = '<span class="tok-kw">const</span> ' +
1173 escapeHtml(decl.name) + ': ' + typeIndexName(declTypeId, true, true) +1187 escapeHtml(decl.name) + ': ' + typeValueName(declTypeRef, true, true) +
1174 " = " + declValueText;1188 " = " + declValueText;
11751189
1176 var docs = zigAnalysis.astNodes[decl.src].docs;1190 var docs = zigAnalysis.astNodes[decl.src].docs;
...@@ -1183,9 +1197,9 @@...@@ -1183,9 +1197,9 @@
1183 }1197 }
11841198
1185 function renderVar(decl) {1199 function renderVar(decl) {
1186 var declTypeId = typeOfDecl(decl);1200 var declTypeRef = typeOfDecl(decl);
1187 domFnProtoCode.innerHTML = '<span class="tok-kw">var</span> ' +1201 domFnProtoCode.innerHTML = '<span class="tok-kw">var</span> ' +
1188 escapeHtml(decl.name) + ': ' + typeIndexName(declTypeId, true, true);1202 escapeHtml(decl.name) + ': ' + typeValueName(declTypeRef, true, true);
11891203
1190 var docs = zigAnalysis.astNodes[decl.src].docs;1204 var docs = zigAnalysis.astNodes[decl.src].docs;
1191 if (docs != null) {1205 if (docs != null) {
...@@ -1221,8 +1235,9 @@...@@ -1221,8 +1235,9 @@
1221 var value = zigAnalysis.types[declValue.type];1235 var value = zigAnalysis.types[declValue.type];
1222 var kind = value.kind;1236 var kind = value.kind;
1223 if (kind === typeKinds.Fn) {1237 if (kind === typeKinds.Fn) {
1224 //if (allCompTimeFnCallsHaveTypeResult(decl.type, declTypeId)) {1238 // TODO: handle CTE return types when we know their type.
1225 if (resolveTypeRefToTypeId(value.ret) == typeTypeId) {1239 const resVal = resolveValue(value.ret);
1240 if ("type" in resVal && resVal.type == typeTypeId) {
1226 typesList.push(decl);1241 typesList.push(decl);
1227 } else {1242 } else {
1228 fnsList.push(decl);1243 fnsList.push(decl);
...@@ -1300,7 +1315,7 @@...@@ -1300,7 +1315,7 @@
1300 var declType = resolveValue(decl.value);1315 var declType = resolveValue(decl.value);
1301 console.assert("type" in declType);1316 console.assert("type" in declType);
13021317
1303 tdFnCode.innerHTML = typeIndexName(declType.type, true, true, decl, navLinkDecl(decl.name));1318 tdFnCode.innerHTML = typeValueName(declType, true, true, decl, navLinkDecl(decl.name));
13041319
1305 var docs = zigAnalysis.astNodes[decl.src].docs;1320 var docs = zigAnalysis.astNodes[decl.src].docs;
1306 if (docs != null) {1321 if (docs != null) {
...@@ -1327,35 +1342,37 @@...@@ -1327,35 +1342,37 @@
1327 } else {1342 } else {
1328 var field = container.fields[i];1343 var field = container.fields[i];
1329 html += ": ";1344 html += ": ";
1330 if (typeof(field) === 'object') {1345 if (field.failure === true) {
1331 if (field.failure === true) {1346 html += '<span class="tok-kw" style="color:red;">#FAILURE#</span>';
1332 html += '<span class="tok-kw" style="color:red;">#FAILURE#</span>';1347 } else if ("declPath" in field) {
1333 } else if ("declPath" in field) {1348 for (var j = field.declPath.length - 1; j >= 0; j--) {
1334 for (var j = field.declPath.length - 1; j >= 0; j--) {1349 var decl = zigAnalysis.decls[field.declPath[j]];
1335 var decl = zigAnalysis.decls[field.declPath[j]];1350
13361351 // TODO: handle nested decl paths properly!
1337 html += '<a href="'+navLinkDecl(decl.name)+'">';1352 if (field.hasCte) {
1338 html += '<span class="tok-kw" style="color:lightblue;">' +1353 html += "<a href=\"\"># CTE TODO #</a>";
1339 escapeHtml(decl.name) + '</span>';1354 break;
1340 html += '</a>';
1341 if (j != 0) html += ".";
1342 }1355 }
1343 // at the end of the for loop this is the value of `decl`1356
1344 //decl = zigAnalysis.decls[field.declPath[0]];1357 html += '<a href="'+navLinkDecl(decl.name)+'">';
13451358 html += '<span class="tok-kw" style="color:lightblue;">' +
1346 var val = resolveValue(decl.value);1359 escapeHtml(decl.name) + '</span>';
1347 console.assert("type" in val);1360 html += '</a>';
1348 var valType = zigAnalysis.types[val.type];1361 if (j != 0) html += ".";
1349 var valTypeName = typeShorthandName(valType);
1350 html += ' ('+ valTypeName +')';
1351 } else if ("type" in field) {
1352 var name = zigAnalysis.types[field.type].name;
1353 html += '<span class="tok-kw">' + escapeHtml(name) + '</span>';
1354 } else {
1355 html += '<span class="tok-kw">var</span>';
1356 }1362 }
1363 // at the end of the for loop this is the value of `decl`
1364 //decl = zigAnalysis.decls[field.declPath[0]];
1365
1366 var val = resolveValue(decl.value);
1367 console.assert("type" in val);
1368 var valType = zigAnalysis.types[val.type];
1369 var valTypeName = typeShorthandName(valType);
1370 html += ' ('+ valTypeName +')';
1371 } else if ("type" in field) {
1372 var name = zigAnalysis.types[field.type].name;
1373 html += '<span class="tok-kw">' + escapeHtml(name) + '</span>';
1357 } else {1374 } else {
1358 html += typeIndexName(field, true, true);1375 html += '<span class="tok-kw">var</span>';
1359 }1376 }
1360 }1377 }
13611378
...@@ -1385,7 +1402,7 @@...@@ -1385,7 +1402,7 @@
1385 tdNameA.setAttribute('href', navLinkDecl(decl.name));1402 tdNameA.setAttribute('href', navLinkDecl(decl.name));
1386 tdNameA.textContent = decl.name;1403 tdNameA.textContent = decl.name;
13871404
1388 tdType.innerHTML = typeIndexName(typeOfDecl(decl), true, true);1405 tdType.innerHTML = typeValueName(typeOfDecl(decl), true, true);
13891406
1390 var docs = zigAnalysis.astNodes[decl.src].docs;1407 var docs = zigAnalysis.astNodes[decl.src].docs;
1391 if (docs != null) {1408 if (docs != null) {
...@@ -1412,7 +1429,7 @@...@@ -1412,7 +1429,7 @@
1412 tdNameA.setAttribute('href', navLinkDecl(decl.name));1429 tdNameA.setAttribute('href', navLinkDecl(decl.name));
1413 tdNameA.textContent = decl.name;1430 tdNameA.textContent = decl.name;
14141431
1415 tdType.innerHTML = typeIndexName(typeOfDecl(decl), true, true);1432 tdType.innerHTML = typeValueName(typeOfDecl(decl), true, true);
14161433
1417 var docs = zigAnalysis.astNodes[decl.src].docs;1434 var docs = zigAnalysis.astNodes[decl.src].docs;
1418 if (docs != null) {1435 if (docs != null) {
src/Autodoc.zig+79-34
...@@ -30,7 +30,7 @@ decl_paths_pending_on_types: std.AutoHashMapUnmanaged(...@@ -30,7 +30,7 @@ decl_paths_pending_on_types: std.AutoHashMapUnmanaged(
3030
31const DeclPathResumeInfo = struct {31const DeclPathResumeInfo = struct {
32 file: *File,32 file: *File,
33 path: []usize,33 decl_path: DocData.DeclPath,
34};34};
3535
36var arena_allocator: std.heap.ArenaAllocator = undefined;36var arena_allocator: std.heap.ArenaAllocator = undefined;
...@@ -347,7 +347,7 @@ const DocData = struct {...@@ -347,7 +347,7 @@ const DocData = struct {
347 Int: struct { name: []const u8 },347 Int: struct { name: []const u8 },
348 Float: struct { name: []const u8 },348 Float: struct { name: []const u8 },
349 Pointer: struct {349 Pointer: struct {
350 name: []const u8,350 size: std.builtin.TypeInfo.Pointer.Size,
351 child: TypeRef,351 child: TypeRef,
352 },352 },
353 Array: struct {353 Array: struct {
...@@ -427,6 +427,20 @@ const DocData = struct {...@@ -427,6 +427,20 @@ const DocData = struct {
427 .Int => |v| try printTypeBody(v, options, w),427 .Int => |v| try printTypeBody(v, options, w),
428 .Float => |v| try printTypeBody(v, options, w),428 .Float => |v| try printTypeBody(v, options, w),
429 .Type => |v| try printTypeBody(v, options, w),429 .Type => |v| try printTypeBody(v, options, w),
430 .Pointer => |v| {
431 if (options.whitespace) |ws| try ws.outputIndent(w);
432 try w.print(
433 \\"size": {},
434 \\
435 , .{@enumToInt(v.size)});
436 if (options.whitespace) |ws| try ws.outputIndent(w);
437 try w.print(
438 \\"child":
439 , .{});
440
441 if (options.whitespace) |*ws| ws.indent_level += 1;
442 try v.child.jsonStringify(options, w);
443 },
430 else => {444 else => {
431 std.debug.print(445 std.debug.print(
432 "TODO: add {s} to `DocData.Type.jsonStringify`\n",446 "TODO: add {s} to `DocData.Type.jsonStringify`\n",
...@@ -458,9 +472,14 @@ const DocData = struct {...@@ -458,9 +472,14 @@ const DocData = struct {
458 }472 }
459 };473 };
460474
475 const DeclPath = struct {
476 path: []usize, // indexes in `decls`
477 hasCte: bool = false, // a prefix of this path could not be resolved
478 };
479
461 const TypeRef = union(enum) {480 const TypeRef = union(enum) {
462 unspecified,481 unspecified,
463 declPath: []usize, // indexes in `decls`482 declPath: DeclPath,
464 type: usize, // index in `types`483 type: usize, // index in `types`
465 comptimeExpr: usize, // index in `comptimeExprs`484 comptimeExpr: usize, // index in `comptimeExprs`
466485
...@@ -490,9 +509,9 @@ const DocData = struct {...@@ -490,9 +509,9 @@ const DocData = struct {
490 , .{ @tagName(self), v });509 , .{ @tagName(self), v });
491 },510 },
492 .declPath => |v| {511 .declPath => |v| {
493 try w.print("{{ \"declPath\": [", .{});512 try w.print("{{ \"hasCte\": {}, \"declPath\": [", .{v.hasCte});
494 for (v) |d, i| {513 for (v.path) |d, i| {
495 const comma = if (i == v.len - 1) "]}" else ",";514 const comma = if (i == v.path.len - 1) "]}" else ",";
496 try w.print("{d}{s}", .{ d, comma });515 try w.print("{d}{s}", .{ d, comma });
497 }516 }
498 },517 },
...@@ -509,7 +528,7 @@ const DocData = struct {...@@ -509,7 +528,7 @@ const DocData = struct {
509 @"struct": Struct,528 @"struct": Struct,
510 bool: bool,529 bool: bool,
511 type: usize, // index in `types`530 type: usize, // index in `types`
512 declPath: []usize, // indices in `decl`531 declPath: DeclPath,
513 int: struct {532 int: struct {
514 typeRef: TypeRef,533 typeRef: TypeRef,
515 value: usize, // direct value534 value: usize, // direct value
...@@ -584,9 +603,9 @@ const DocData = struct {...@@ -584,9 +603,9 @@ const DocData = struct {
584 w,603 w,
585 ),604 ),
586 .declPath => |v| {605 .declPath => |v| {
587 try w.print("{{ \"declPath\": [", .{});606 try w.print("{{ \"hasCte\": {}, \"declPath\": [", .{v.hasCte});
588 for (v) |d, i| {607 for (v.path) |d, i| {
589 const comma = if (i == v.len - 1) "]}" else ",";608 const comma = if (i == v.path.len - 1) "]}" else ",";
590 try w.print("{d}{s}", .{ d, comma });609 try w.print("{d}{s}", .{ d, comma });
591 }610 }
592 },611 },
...@@ -676,6 +695,19 @@ fn walkInstruction(...@@ -676,6 +695,19 @@ fn walkInstruction(
676 },695 },
677 };696 };
678 },697 },
698 .ptr_type_simple => {
699 const ptr = data[inst_index].ptr_type_simple;
700 const type_slot_index = self.types.items.len;
701 const elem_type_ref = try self.walkRef(file, parent_scope, ptr.elem_type);
702 try self.types.append(self.arena, .{
703 .Pointer = .{
704 .size = ptr.size,
705 .child = walkResultToTypeRef(elem_type_ref),
706 },
707 });
708
709 return DocData.WalkResult{ .type = type_slot_index };
710 },
679 .array_init => {711 .array_init => {
680 const pl_node = data[inst_index].pl_node;712 const pl_node = data[inst_index].pl_node;
681 const extra = file.zir.extraData(Zir.Inst.MultiOp, pl_node.payload_index);713 const extra = file.zir.extraData(Zir.Inst.MultiOp, pl_node.payload_index);
...@@ -770,7 +802,7 @@ fn walkInstruction(...@@ -770,7 +802,7 @@ fn walkInstruction(
770 const decls_slot_index = parent_scope.resolveDeclName(str_tok.start);802 const decls_slot_index = parent_scope.resolveDeclName(str_tok.start);
771 var path = try self.arena.alloc(usize, 1);803 var path = try self.arena.alloc(usize, 1);
772 path[0] = decls_slot_index;804 path[0] = decls_slot_index;
773 return DocData.WalkResult{ .declPath = path };805 return DocData.WalkResult{ .declPath = .{ .path = path } };
774 },806 },
775 .field_val, .field_call_bind, .field_ptr => {807 .field_val, .field_call_bind, .field_ptr => {
776 const pl_node = data[inst_index].pl_node;808 const pl_node = data[inst_index].pl_node;
...@@ -844,8 +876,9 @@ fn walkInstruction(...@@ -844,8 +876,9 @@ fn walkInstruction(
844 // the analyzed data corresponding to the top-most decl of this path.876 // the analyzed data corresponding to the top-most decl of this path.
845 // We are now going to reverse loop over `path` to resolve each name877 // We are now going to reverse loop over `path` to resolve each name
846 // to its corresponding index in `decls`.878 // to its corresponding index in `decls`.
847 try self.tryResolveDeclPath(file, path.items);879 var decl_path: DocData.DeclPath = .{ .path = path.items };
848 return DocData.WalkResult{ .declPath = path.items };880 try self.tryResolveDeclPath(file, &decl_path);
881 return DocData.WalkResult{ .declPath = decl_path };
849 },882 },
850 .int_type => {883 .int_type => {
851 const int_type = data[inst_index].int_type;884 const int_type = data[inst_index].int_type;
...@@ -893,7 +926,7 @@ fn walkInstruction(...@@ -893,7 +926,7 @@ fn walkInstruction(
893926
894 return DocData.WalkResult{ .call = call_slot_index };927 return DocData.WalkResult{ .call = call_slot_index };
895 },928 },
896 .func => {929 .func, .func_inferred => {
897 const fn_info = file.zir.getFnInfo(@intCast(u32, inst_index));930 const fn_info = file.zir.getFnInfo(@intCast(u32, inst_index));
898931
899 try self.ast_nodes.ensureUnusedCapacity(self.arena, fn_info.total_params_len);932 try self.ast_nodes.ensureUnusedCapacity(self.arena, fn_info.total_params_len);
...@@ -960,18 +993,18 @@ fn walkInstruction(...@@ -960,18 +993,18 @@ fn walkInstruction(
960 return DocData.WalkResult{ .type = self.types.items.len - 1 };993 return DocData.WalkResult{ .type = self.types.items.len - 1 };
961 },994 },
962 .extended => {995 .extended => {
963 // TODO: this assumes that we always return a type when analyzing996 // NOTE: this code + the subsequent defer block are working towards
964 // an extended instruction. Also we willingfully not reserve997 // solving pending decl paths that depend on a type to be analyzed.
965 // a slot for functions (handled right above) despite them998 // When we don't find a type, the defer will run anyway but shouldn't
966 // being stored in `types`. The reason why we reserve a slot999 // ever be able to find a match inside `decl_paths_pending_on_types`
967 // in here, is for decl paths and their resolution system.1000 // TODO: extract this logic into a function and only call it when appropriate.
968 const type_slot_index = self.types.items.len;1001 const type_slot_index = self.types.items.len;
969 try self.types.append(self.arena, .{ .Unanalyzed = {} });1002 try self.types.append(self.arena, .{ .Unanalyzed = {} });
9701003
971 defer {1004 defer {
972 if (self.decl_paths_pending_on_types.get(type_slot_index)) |paths| {1005 if (self.decl_paths_pending_on_types.get(type_slot_index)) |paths| {
973 for (paths.items) |resume_info| {1006 for (paths.items) |*resume_info| {
974 self.tryResolveDeclPath(resume_info.file, resume_info.path) catch {1007 self.tryResolveDeclPath(resume_info.file, &resume_info.decl_path) catch {
975 @panic("Out of memory");1008 @panic("Out of memory");
976 };1009 };
977 }1010 }
...@@ -1537,8 +1570,8 @@ fn walkDecls(...@@ -1537,8 +1570,8 @@ fn walkDecls(
15371570
1538 // Unblock any pending decl path that was waiting for this decl.1571 // Unblock any pending decl path that was waiting for this decl.
1539 if (self.decl_paths_pending_on_decls.get(decls_slot_index)) |paths| {1572 if (self.decl_paths_pending_on_decls.get(decls_slot_index)) |paths| {
1540 for (paths.items) |resume_info| {1573 for (paths.items) |*resume_info| {
1541 try self.tryResolveDeclPath(resume_info.file, resume_info.path);1574 try self.tryResolveDeclPath(resume_info.file, &resume_info.decl_path);
1542 }1575 }
15431576
1544 _ = self.decl_paths_pending_on_decls.remove(decls_slot_index);1577 _ = self.decl_paths_pending_on_decls.remove(decls_slot_index);
...@@ -1560,10 +1593,12 @@ fn tryResolveDeclPath(...@@ -1560,10 +1593,12 @@ fn tryResolveDeclPath(
1560 self: *Autodoc,1593 self: *Autodoc,
1561 /// File from which the decl path originates.1594 /// File from which the decl path originates.
1562 file: *File,1595 file: *File,
1563 path: []usize,1596 decl_path: *DocData.DeclPath,
1564) error{OutOfMemory}!void {1597) error{OutOfMemory}!void {
1598 const path: []usize = decl_path.path;
1599
1565 var i: usize = path.len;1600 var i: usize = path.len;
1566 while (i > 1) {1601 outer: while (i > 1) {
1567 i -= 1;1602 i -= 1;
1568 const decl_index = path[i];1603 const decl_index = path[i];
1569 const string_index = path[i - 1];1604 const string_index = path[i - 1];
...@@ -1580,7 +1615,7 @@ fn tryResolveDeclPath(...@@ -1580,7 +1615,7 @@ fn tryResolveDeclPath(
1580 if (!res.found_existing) res.value_ptr.* = .{};1615 if (!res.found_existing) res.value_ptr.* = .{};
1581 try res.value_ptr.*.append(self.arena, .{1616 try res.value_ptr.*.append(self.arena, .{
1582 .file = file,1617 .file = file,
1583 .path = path[0 .. i + 1],1618 .decl_path = .{ .path = path[0 .. i + 1] },
1584 });1619 });
15851620
1586 return;1621 return;
...@@ -1590,15 +1625,25 @@ fn tryResolveDeclPath(...@@ -1590,15 +1625,25 @@ fn tryResolveDeclPath(
1590 switch (parent.value) {1625 switch (parent.value) {
1591 else => {1626 else => {
1592 std.debug.panic(1627 std.debug.panic(
1593 "TODO: handle `{s}`in walkInstruction.field_val\n \"{s}\":{}",1628 "TODO: handle `{s}`in tryResolveDecl.field_val\n \"{s}\":{}",
1594 .{ @tagName(parent.value), parent.name, parent.value },1629 .{ @tagName(parent.value), parent.name, parent.value },
1595 );1630 );
1596 },1631 },
1632 .comptimeExpr => {
1633 // Since we hit a cte, we leave the remaining strings unresolved
1634 // and completely give up on resolving this decl path.
1635 decl_path.hasCte = true;
1636 break :outer;
1637 },
1597 .declPath => |dp| {1638 .declPath => |dp| {
1598 if (self.pending_decl_paths.getPtr(&dp[0])) |waiter_list| {1639 if (dp.hasCte) {
1640 decl_path.hasCte = true;
1641 break :outer;
1642 }
1643 if (self.pending_decl_paths.getPtr(&dp.path[0])) |waiter_list| {
1599 try waiter_list.append(self.arena, .{1644 try waiter_list.append(self.arena, .{
1600 .file = file,1645 .file = file,
1601 .path = path[0 .. i + 1],1646 .decl_path = .{ .path = path[0 .. i + 1] },
1602 });1647 });
16031648
1604 // This decl path is pending completion1649 // This decl path is pending completion
...@@ -1610,7 +1655,7 @@ fn tryResolveDeclPath(...@@ -1610,7 +1655,7 @@ fn tryResolveDeclPath(
1610 return;1655 return;
1611 }1656 }
16121657
1613 const final_decl_index = dp[0];1658 const final_decl_index = dp.path[0];
1614 // For the purpose of being able to call tryResolveDeclPath again,1659 // For the purpose of being able to call tryResolveDeclPath again,
1615 // we momentarily replace the decl index present in `path[i]`1660 // we momentarily replace the decl index present in `path[i]`
1616 // with the final decl in `dp`.1661 // with the final decl in `dp`.
...@@ -1619,7 +1664,7 @@ fn tryResolveDeclPath(...@@ -1619,7 +1664,7 @@ fn tryResolveDeclPath(
1619 // will not get fully resolved (also in the case that final_decl is1664 // will not get fully resolved (also in the case that final_decl is
1620 // not resolved yet).1665 // not resolved yet).
1621 path[i] = final_decl_index;1666 path[i] = final_decl_index;
1622 try self.tryResolveDeclPath(file, path);1667 try self.tryResolveDeclPath(file, decl_path);
1623 path[i] = decl_index;1668 path[i] = decl_index;
1624 },1669 },
1625 .type => |t_index| switch (self.types.items[t_index]) {1670 .type => |t_index| switch (self.types.items[t_index]) {
...@@ -1643,7 +1688,7 @@ fn tryResolveDeclPath(...@@ -1643,7 +1688,7 @@ fn tryResolveDeclPath(
1643 if (!res.found_existing) res.value_ptr.* = .{};1688 if (!res.found_existing) res.value_ptr.* = .{};
1644 try res.value_ptr.*.append(self.arena, .{1689 try res.value_ptr.*.append(self.arena, .{
1645 .file = file,1690 .file = file,
1646 .path = path[0 .. i + 1],1691 .decl_path = .{ .path = path[0 .. i + 1] },
1647 });1692 });
16481693
1649 return;1694 return;
...@@ -1677,8 +1722,8 @@ fn tryResolveDeclPath(...@@ -1677,8 +1722,8 @@ fn tryResolveDeclPath(
1677 // attempting to resolve any other decl.1722 // attempting to resolve any other decl.
1678 _ = self.pending_decl_paths.remove(&path[0]);1723 _ = self.pending_decl_paths.remove(&path[0]);
16791724
1680 for (waiter_list.items) |resume_info| {1725 for (waiter_list.items) |*resume_info| {
1681 try self.tryResolveDeclPath(resume_info.file, resume_info.path);1726 try self.tryResolveDeclPath(resume_info.file, &resume_info.decl_path);
1682 }1727 }
1683 // TODO: this is where we should free waiter_list, but its in the arena1728 // TODO: this is where we should free waiter_list, but its in the arena
1684 // that said, we might want to store it elsewhere and reclaim memory asap1729 // that said, we might want to store it elsewhere and reclaim memory asap