mirror of
https://github.com/ziglang/zig.git
synced 2026-02-12 12:27:41 +00:00
autodoc: add support for pointers and comptime expressions in decl paths
This commit is contained in:
parent
03d3929232
commit
3eb90a110f
189
lib/docs/main.js
189
lib/docs/main.js
@ -144,13 +144,33 @@
|
||||
return typeKind === typeKinds.ErrorSet || typeKindIsContainer(typeKind);
|
||||
}
|
||||
|
||||
function findCteInDeclPath(path) {
|
||||
for (var i = path.length - 1; i >= 0; i -= 1) {
|
||||
const decl = zigAnalysis.decls[path[i]];
|
||||
if ("comptimeExpr" in decl.value) {
|
||||
return decl;
|
||||
}
|
||||
|
||||
if ("declPath" in decl.value) {
|
||||
const res = findCteInDeclPath(decl.value.declPath);
|
||||
if (res !== null) {
|
||||
return res;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
function resolveValue(value) {
|
||||
var i = 0;
|
||||
while(i < 1000) {
|
||||
i += 1;
|
||||
|
||||
if ("declPath" in value) {
|
||||
console.assert(value.declPath.length == 1); // only support declRefs for now
|
||||
if (value.hasCte) {
|
||||
return findCteInDeclPath(value.declPath).value;
|
||||
}
|
||||
value = zigAnalysis.decls[value.declPath[0]].value;
|
||||
continue;
|
||||
}
|
||||
@ -171,30 +191,34 @@
|
||||
}
|
||||
|
||||
if ("declPath" in decl.value) {
|
||||
console.assert(decl.value.declPath.length == 1); // only support declRefs for now
|
||||
decl = zigAnalysis.decls[decl.value.declPath[0]];
|
||||
if (decl.value.hasCte) {
|
||||
decl = findCteInDeclPath(decl.value.declPath);
|
||||
} else {
|
||||
decl = zigAnalysis.decls[decl.value.declPath[0]];
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if ("int" in decl.value) {
|
||||
return resolveTypeRefToTypeId(decl.value.int.typeRef);
|
||||
return decl.value.int.typeRef;
|
||||
}
|
||||
|
||||
if ("float" in decl.value) {
|
||||
return resolveTypeRefToTypeId(decl.value.float.typeRef);
|
||||
return decl.value.float.typeRef;
|
||||
}
|
||||
|
||||
if ("array" in decl.value) {
|
||||
return resolveTypeRefToTypeId(decl.value.array.typeRef);
|
||||
return decl.value.array.typeRef;
|
||||
}
|
||||
|
||||
if ("struct" in decl.value) {
|
||||
return resolveTypeRefToTypeId(decl.value.struct.typeRef);
|
||||
return decl.value.struct.typeRef;
|
||||
}
|
||||
|
||||
if ("comptimeExpr" in decl.value) {
|
||||
const cte = zigAnalysis.comptimeExprs[decl.value.comptimeExpr];
|
||||
return resolveTypeRefToTypeId(cte.typeRef);
|
||||
return cte.typeRef;
|
||||
}
|
||||
|
||||
if ("call" in decl.value) {
|
||||
@ -205,7 +229,7 @@
|
||||
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 resolveTypeRefToTypeId(fn_type.ret);
|
||||
return fn_type.ret;
|
||||
}
|
||||
|
||||
console.log("TODO: handle in `typeOfDecl` more cases: ", decl);
|
||||
@ -215,23 +239,6 @@
|
||||
console.assert(false);
|
||||
}
|
||||
|
||||
function resolveTypeRefToTypeId(ref) {
|
||||
if ("unspecified" in ref) {
|
||||
console.log("found an unspecified type!")
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ("declRef" in ref) {
|
||||
return typeOfDecl(ref.declRef);
|
||||
}
|
||||
|
||||
if ("type" in ref) {
|
||||
return ref.type;
|
||||
}
|
||||
|
||||
console.assert(false);
|
||||
}
|
||||
|
||||
function render() {
|
||||
domStatus.classList.add("hidden");
|
||||
domFnProto.classList.add("hidden");
|
||||
@ -369,7 +376,7 @@
|
||||
console.assert("type" in value);
|
||||
var typeObj = zigAnalysis.types[value.type];
|
||||
|
||||
domFnProtoCode.innerHTML = typeIndexName(value.type, true, true, fnDecl);
|
||||
domFnProtoCode.innerHTML = typeValueName(value, true, true, fnDecl);
|
||||
|
||||
var docsSource = null;
|
||||
var srcNode = zigAnalysis.astNodes[fnDecl.src];
|
||||
@ -462,9 +469,6 @@
|
||||
|
||||
|
||||
var value = typeObj.params[i];
|
||||
var valueType = resolveValue(value);
|
||||
console.assert("type" in valueType);
|
||||
var argTypeIndex = valueType.type;
|
||||
var html = '<pre>' + escapeHtml(fieldNode.name) + ": ";
|
||||
if (isVarArgs && i === typeObj.params.length - 1) {
|
||||
html += '...';
|
||||
@ -482,8 +486,6 @@
|
||||
} else if ("type" in value) {
|
||||
var name = zigAnalysis.types[value.type].name;
|
||||
html += '<span class="tok-kw">' + escapeHtml(name) + '</span>';
|
||||
} else if (argTypeIndex != null) {
|
||||
html += typeIndexName(argTypeIndex, true, true);
|
||||
} else {
|
||||
html += '<span class="tok-kw">var</span>';
|
||||
}
|
||||
@ -654,13 +656,16 @@
|
||||
}
|
||||
}
|
||||
|
||||
function typeIndexName(typeIndex, wantHtml, wantLink, fnDecl, linkFnNameDecl) {
|
||||
return typeValueName({ type: typeIndex }, wantHtml, wantLink, fnDecl, linkFnNameDecl);
|
||||
}
|
||||
|
||||
function typeValueName(typeValue, wantHtml, wantLink, fnDecl, linkFnNameDecl) {
|
||||
if ("declPath" in typeValue) {
|
||||
console.assert(typeValue.declPath.length == 1);
|
||||
if (typeValue.hasCte) {
|
||||
// TODO: find the cte, print it nicely
|
||||
if (wantLink) {
|
||||
return '<a href=""># CTE TODO #</a>';
|
||||
} else {
|
||||
return "# CTE TODO #";
|
||||
}
|
||||
}
|
||||
var declIndex = typeValue.declPath[0];
|
||||
var name = zigAnalysis.decls[declIndex].name;
|
||||
var declPath = getCanonDeclPath(declIndex);
|
||||
@ -695,12 +700,17 @@
|
||||
}
|
||||
}
|
||||
|
||||
function shouldSkipParamName(typeIndex, paramName) {
|
||||
var typeObj = zigAnalysis.types[typeIndex];
|
||||
if (typeObj.kind === typeKinds.Pointer && getPtrSize(typeObj) === pointerSizeEnum.One) {
|
||||
typeIndex = typeObj.child;
|
||||
function shouldSkipParamName(typeRef, paramName) {
|
||||
var resolvedTypeRef = resolveValue(typeRef);
|
||||
if ("type" in resolvedTypeRef) {
|
||||
var typeObj = zigAnalysis.types[resolvedTypeRef.type];
|
||||
if (typeObj.kind === typeKinds.Pointer &&
|
||||
getPtrSize(typeObj) === pointerSizeEnum.One) {
|
||||
const value = resolveValue(typeObj.child);
|
||||
return typeValueName(value, false, true).toLowerCase() === paramName;
|
||||
}
|
||||
}
|
||||
return typeIndexName(typeIndex, false, true).toLowerCase() === paramName;
|
||||
return false;
|
||||
}
|
||||
|
||||
function getPtrSize(typeObj) {
|
||||
@ -716,20 +726,25 @@
|
||||
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 += getValueText(argObj, argObj.value, true, true);
|
||||
}
|
||||
html += ')';
|
||||
return html;
|
||||
}
|
||||
|
||||
function getValueText(typeIndex, value, wantHtml, wantLink) {
|
||||
var typeObj = zigAnalysis.types[typeIndex];
|
||||
function getValueText(typeRef, value, wantHtml, wantLink) {
|
||||
var resolvedTypeRef = resolveValue(typeRef);
|
||||
if ("comptimeExpr" in resolvedTypeRef) {
|
||||
return "# CTE TODO #";
|
||||
}
|
||||
console.assert("type" in resolvedTypeRef);
|
||||
var typeObj = zigAnalysis.types[typeRef.type];
|
||||
switch (typeObj.kind) {
|
||||
case typeKinds.Type:
|
||||
return typeIndexName(value, wantHtml, wantLink);
|
||||
case typeKinds.Fn:
|
||||
var fnObj = zigAnalysis.fns[value];
|
||||
return typeIndexName(fnObj.type, wantHtml, wantLink);
|
||||
return typeValueName(fnObj, wantHtml, wantLink);
|
||||
case typeKinds.Int:
|
||||
if (wantHtml) {
|
||||
return '<span class="tok-number">' + value + '</span>';
|
||||
@ -923,11 +938,10 @@
|
||||
if (i != 0) {
|
||||
payloadHtml += ', ';
|
||||
}
|
||||
|
||||
var value = typeObj.params[i];
|
||||
var paramValue = resolveValue(value);
|
||||
console.assert("type" in paramValue);
|
||||
var argTypeIndex = paramValue.type;
|
||||
|
||||
var isCte = "comptimeExpr" in paramValue;
|
||||
|
||||
if (fields != null) {
|
||||
var paramNode = zigAnalysis.astNodes[fields[i]];
|
||||
@ -956,7 +970,7 @@
|
||||
var paramName = paramNode.name;
|
||||
if (paramName != null) {
|
||||
// skip if it matches the type name
|
||||
if (argTypeIndex == null || !shouldSkipParamName(argTypeIndex, paramName)) {
|
||||
if (!shouldSkipParamName(paramValue, paramName)) {
|
||||
payloadHtml += paramName + ': ';
|
||||
}
|
||||
}
|
||||
@ -975,10 +989,10 @@
|
||||
payloadHtml += '<span class="tok-kw" style="color:lightblue;">' + escapeHtml(decl.name) + '</span>';
|
||||
payloadHtml += '</a>';
|
||||
} else if ("type" in value) {
|
||||
var name = zigAnalysis.types[value.type].name;
|
||||
var name = typeValueName(value, false);
|
||||
payloadHtml += '<span class="tok-kw">' + escapeHtml(name) + '</span>';
|
||||
} else if (argTypeIndex != null) {
|
||||
payloadHtml += typeIndexName(argTypeIndex, wantHtml, wantSubLink);
|
||||
} else if ("comptimeExpr" in value) {
|
||||
payloadHtml += '<span class="tok-kw"> # CTE TODO #</span>';
|
||||
} else if (wantHtml) {
|
||||
payloadHtml += '<span class="tok-kw">var</span>';
|
||||
} else {
|
||||
@ -1152,7 +1166,7 @@
|
||||
|
||||
function renderValue(decl) {
|
||||
|
||||
var declTypeId = typeOfDecl(decl);
|
||||
var declTypeRef = typeOfDecl(decl);
|
||||
var declValueText = "";
|
||||
switch(Object.keys(decl.value)[0]) {
|
||||
case "int":
|
||||
@ -1170,7 +1184,7 @@
|
||||
}
|
||||
|
||||
domFnProtoCode.innerHTML = '<span class="tok-kw">const</span> ' +
|
||||
escapeHtml(decl.name) + ': ' + typeIndexName(declTypeId, true, true) +
|
||||
escapeHtml(decl.name) + ': ' + typeValueName(declTypeRef, true, true) +
|
||||
" = " + declValueText;
|
||||
|
||||
var docs = zigAnalysis.astNodes[decl.src].docs;
|
||||
@ -1183,9 +1197,9 @@
|
||||
}
|
||||
|
||||
function renderVar(decl) {
|
||||
var declTypeId = typeOfDecl(decl);
|
||||
var declTypeRef = typeOfDecl(decl);
|
||||
domFnProtoCode.innerHTML = '<span class="tok-kw">var</span> ' +
|
||||
escapeHtml(decl.name) + ': ' + typeIndexName(declTypeId, true, true);
|
||||
escapeHtml(decl.name) + ': ' + typeValueName(declTypeRef, true, true);
|
||||
|
||||
var docs = zigAnalysis.astNodes[decl.src].docs;
|
||||
if (docs != null) {
|
||||
@ -1221,8 +1235,9 @@
|
||||
var value = zigAnalysis.types[declValue.type];
|
||||
var kind = value.kind;
|
||||
if (kind === typeKinds.Fn) {
|
||||
//if (allCompTimeFnCallsHaveTypeResult(decl.type, declTypeId)) {
|
||||
if (resolveTypeRefToTypeId(value.ret) == typeTypeId) {
|
||||
// TODO: handle CTE return types when we know their type.
|
||||
const resVal = resolveValue(value.ret);
|
||||
if ("type" in resVal && resVal.type == typeTypeId) {
|
||||
typesList.push(decl);
|
||||
} else {
|
||||
fnsList.push(decl);
|
||||
@ -1300,7 +1315,7 @@
|
||||
var declType = resolveValue(decl.value);
|
||||
console.assert("type" in declType);
|
||||
|
||||
tdFnCode.innerHTML = typeIndexName(declType.type, true, true, decl, navLinkDecl(decl.name));
|
||||
tdFnCode.innerHTML = typeValueName(declType, true, true, decl, navLinkDecl(decl.name));
|
||||
|
||||
var docs = zigAnalysis.astNodes[decl.src].docs;
|
||||
if (docs != null) {
|
||||
@ -1327,35 +1342,37 @@
|
||||
} else {
|
||||
var field = container.fields[i];
|
||||
html += ": ";
|
||||
if (typeof(field) === 'object') {
|
||||
if (field.failure === true) {
|
||||
html += '<span class="tok-kw" style="color:red;">#FAILURE#</span>';
|
||||
} else if ("declPath" in field) {
|
||||
for (var j = field.declPath.length - 1; j >= 0; j--) {
|
||||
var decl = zigAnalysis.decls[field.declPath[j]];
|
||||
if (field.failure === true) {
|
||||
html += '<span class="tok-kw" style="color:red;">#FAILURE#</span>';
|
||||
} else if ("declPath" in field) {
|
||||
for (var j = field.declPath.length - 1; j >= 0; j--) {
|
||||
var decl = zigAnalysis.decls[field.declPath[j]];
|
||||
|
||||
html += '<a href="'+navLinkDecl(decl.name)+'">';
|
||||
html += '<span class="tok-kw" style="color:lightblue;">' +
|
||||
escapeHtml(decl.name) + '</span>';
|
||||
html += '</a>';
|
||||
if (j != 0) html += ".";
|
||||
// TODO: handle nested decl paths properly!
|
||||
if (field.hasCte) {
|
||||
html += "<a href=\"\"># CTE TODO #</a>";
|
||||
break;
|
||||
}
|
||||
// at the end of the for loop this is the value of `decl`
|
||||
//decl = zigAnalysis.decls[field.declPath[0]];
|
||||
|
||||
var val = resolveValue(decl.value);
|
||||
console.assert("type" in val);
|
||||
var valType = zigAnalysis.types[val.type];
|
||||
var valTypeName = typeShorthandName(valType);
|
||||
html += ' ('+ valTypeName +')';
|
||||
} else if ("type" in field) {
|
||||
var name = zigAnalysis.types[field.type].name;
|
||||
html += '<span class="tok-kw">' + escapeHtml(name) + '</span>';
|
||||
} else {
|
||||
html += '<span class="tok-kw">var</span>';
|
||||
html += '<a href="'+navLinkDecl(decl.name)+'">';
|
||||
html += '<span class="tok-kw" style="color:lightblue;">' +
|
||||
escapeHtml(decl.name) + '</span>';
|
||||
html += '</a>';
|
||||
if (j != 0) html += ".";
|
||||
}
|
||||
// at the end of the for loop this is the value of `decl`
|
||||
//decl = zigAnalysis.decls[field.declPath[0]];
|
||||
|
||||
var val = resolveValue(decl.value);
|
||||
console.assert("type" in val);
|
||||
var valType = zigAnalysis.types[val.type];
|
||||
var valTypeName = typeShorthandName(valType);
|
||||
html += ' ('+ valTypeName +')';
|
||||
} else if ("type" in field) {
|
||||
var name = zigAnalysis.types[field.type].name;
|
||||
html += '<span class="tok-kw">' + escapeHtml(name) + '</span>';
|
||||
} else {
|
||||
html += typeIndexName(field, true, true);
|
||||
html += '<span class="tok-kw">var</span>';
|
||||
}
|
||||
}
|
||||
|
||||
@ -1385,7 +1402,7 @@
|
||||
tdNameA.setAttribute('href', navLinkDecl(decl.name));
|
||||
tdNameA.textContent = decl.name;
|
||||
|
||||
tdType.innerHTML = typeIndexName(typeOfDecl(decl), true, true);
|
||||
tdType.innerHTML = typeValueName(typeOfDecl(decl), true, true);
|
||||
|
||||
var docs = zigAnalysis.astNodes[decl.src].docs;
|
||||
if (docs != null) {
|
||||
@ -1412,7 +1429,7 @@
|
||||
tdNameA.setAttribute('href', navLinkDecl(decl.name));
|
||||
tdNameA.textContent = decl.name;
|
||||
|
||||
tdType.innerHTML = typeIndexName(typeOfDecl(decl), true, true);
|
||||
tdType.innerHTML = typeValueName(typeOfDecl(decl), true, true);
|
||||
|
||||
var docs = zigAnalysis.astNodes[decl.src].docs;
|
||||
if (docs != null) {
|
||||
|
||||
113
src/Autodoc.zig
113
src/Autodoc.zig
@ -30,7 +30,7 @@ decl_paths_pending_on_types: std.AutoHashMapUnmanaged(
|
||||
|
||||
const DeclPathResumeInfo = struct {
|
||||
file: *File,
|
||||
path: []usize,
|
||||
decl_path: DocData.DeclPath,
|
||||
};
|
||||
|
||||
var arena_allocator: std.heap.ArenaAllocator = undefined;
|
||||
@ -347,7 +347,7 @@ const DocData = struct {
|
||||
Int: struct { name: []const u8 },
|
||||
Float: struct { name: []const u8 },
|
||||
Pointer: struct {
|
||||
name: []const u8,
|
||||
size: std.builtin.TypeInfo.Pointer.Size,
|
||||
child: TypeRef,
|
||||
},
|
||||
Array: struct {
|
||||
@ -427,6 +427,20 @@ const DocData = struct {
|
||||
.Int => |v| try printTypeBody(v, options, w),
|
||||
.Float => |v| try printTypeBody(v, options, w),
|
||||
.Type => |v| try printTypeBody(v, options, w),
|
||||
.Pointer => |v| {
|
||||
if (options.whitespace) |ws| try ws.outputIndent(w);
|
||||
try w.print(
|
||||
\\"size": {},
|
||||
\\
|
||||
, .{@enumToInt(v.size)});
|
||||
if (options.whitespace) |ws| try ws.outputIndent(w);
|
||||
try w.print(
|
||||
\\"child":
|
||||
, .{});
|
||||
|
||||
if (options.whitespace) |*ws| ws.indent_level += 1;
|
||||
try v.child.jsonStringify(options, w);
|
||||
},
|
||||
else => {
|
||||
std.debug.print(
|
||||
"TODO: add {s} to `DocData.Type.jsonStringify`\n",
|
||||
@ -458,9 +472,14 @@ const DocData = struct {
|
||||
}
|
||||
};
|
||||
|
||||
const DeclPath = struct {
|
||||
path: []usize, // indexes in `decls`
|
||||
hasCte: bool = false, // a prefix of this path could not be resolved
|
||||
};
|
||||
|
||||
const TypeRef = union(enum) {
|
||||
unspecified,
|
||||
declPath: []usize, // indexes in `decls`
|
||||
declPath: DeclPath,
|
||||
type: usize, // index in `types`
|
||||
comptimeExpr: usize, // index in `comptimeExprs`
|
||||
|
||||
@ -490,9 +509,9 @@ const DocData = struct {
|
||||
, .{ @tagName(self), v });
|
||||
},
|
||||
.declPath => |v| {
|
||||
try w.print("{{ \"declPath\": [", .{});
|
||||
for (v) |d, i| {
|
||||
const comma = if (i == v.len - 1) "]}" else ",";
|
||||
try w.print("{{ \"hasCte\": {}, \"declPath\": [", .{v.hasCte});
|
||||
for (v.path) |d, i| {
|
||||
const comma = if (i == v.path.len - 1) "]}" else ",";
|
||||
try w.print("{d}{s}", .{ d, comma });
|
||||
}
|
||||
},
|
||||
@ -509,7 +528,7 @@ const DocData = struct {
|
||||
@"struct": Struct,
|
||||
bool: bool,
|
||||
type: usize, // index in `types`
|
||||
declPath: []usize, // indices in `decl`
|
||||
declPath: DeclPath,
|
||||
int: struct {
|
||||
typeRef: TypeRef,
|
||||
value: usize, // direct value
|
||||
@ -584,9 +603,9 @@ const DocData = struct {
|
||||
w,
|
||||
),
|
||||
.declPath => |v| {
|
||||
try w.print("{{ \"declPath\": [", .{});
|
||||
for (v) |d, i| {
|
||||
const comma = if (i == v.len - 1) "]}" else ",";
|
||||
try w.print("{{ \"hasCte\": {}, \"declPath\": [", .{v.hasCte});
|
||||
for (v.path) |d, i| {
|
||||
const comma = if (i == v.path.len - 1) "]}" else ",";
|
||||
try w.print("{d}{s}", .{ d, comma });
|
||||
}
|
||||
},
|
||||
@ -676,6 +695,19 @@ fn walkInstruction(
|
||||
},
|
||||
};
|
||||
},
|
||||
.ptr_type_simple => {
|
||||
const ptr = data[inst_index].ptr_type_simple;
|
||||
const type_slot_index = self.types.items.len;
|
||||
const elem_type_ref = try self.walkRef(file, parent_scope, ptr.elem_type);
|
||||
try self.types.append(self.arena, .{
|
||||
.Pointer = .{
|
||||
.size = ptr.size,
|
||||
.child = walkResultToTypeRef(elem_type_ref),
|
||||
},
|
||||
});
|
||||
|
||||
return DocData.WalkResult{ .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);
|
||||
@ -770,7 +802,7 @@ fn walkInstruction(
|
||||
const decls_slot_index = parent_scope.resolveDeclName(str_tok.start);
|
||||
var path = try self.arena.alloc(usize, 1);
|
||||
path[0] = decls_slot_index;
|
||||
return DocData.WalkResult{ .declPath = path };
|
||||
return DocData.WalkResult{ .declPath = .{ .path = path } };
|
||||
},
|
||||
.field_val, .field_call_bind, .field_ptr => {
|
||||
const pl_node = data[inst_index].pl_node;
|
||||
@ -844,8 +876,9 @@ fn walkInstruction(
|
||||
// the analyzed data corresponding to the top-most decl of this path.
|
||||
// We are now going to reverse loop over `path` to resolve each name
|
||||
// to its corresponding index in `decls`.
|
||||
try self.tryResolveDeclPath(file, path.items);
|
||||
return DocData.WalkResult{ .declPath = path.items };
|
||||
var decl_path: DocData.DeclPath = .{ .path = path.items };
|
||||
try self.tryResolveDeclPath(file, &decl_path);
|
||||
return DocData.WalkResult{ .declPath = decl_path };
|
||||
},
|
||||
.int_type => {
|
||||
const int_type = data[inst_index].int_type;
|
||||
@ -893,7 +926,7 @@ fn walkInstruction(
|
||||
|
||||
return DocData.WalkResult{ .call = call_slot_index };
|
||||
},
|
||||
.func => {
|
||||
.func, .func_inferred => {
|
||||
const fn_info = file.zir.getFnInfo(@intCast(u32, inst_index));
|
||||
|
||||
try self.ast_nodes.ensureUnusedCapacity(self.arena, fn_info.total_params_len);
|
||||
@ -960,18 +993,18 @@ fn walkInstruction(
|
||||
return DocData.WalkResult{ .type = self.types.items.len - 1 };
|
||||
},
|
||||
.extended => {
|
||||
// TODO: this assumes that we always return a type when analyzing
|
||||
// an extended instruction. Also we willingfully not reserve
|
||||
// a slot for functions (handled right above) despite them
|
||||
// being stored in `types`. The reason why we reserve a slot
|
||||
// in here, is for decl paths and their resolution system.
|
||||
// NOTE: this code + the subsequent defer block are working towards
|
||||
// solving pending decl paths that depend on a type to be analyzed.
|
||||
// When we don't find a type, the defer will run anyway but shouldn't
|
||||
// ever be able to find a match inside `decl_paths_pending_on_types`
|
||||
// TODO: extract this logic into a function and only call it when appropriate.
|
||||
const type_slot_index = self.types.items.len;
|
||||
try self.types.append(self.arena, .{ .Unanalyzed = {} });
|
||||
|
||||
defer {
|
||||
if (self.decl_paths_pending_on_types.get(type_slot_index)) |paths| {
|
||||
for (paths.items) |resume_info| {
|
||||
self.tryResolveDeclPath(resume_info.file, resume_info.path) catch {
|
||||
for (paths.items) |*resume_info| {
|
||||
self.tryResolveDeclPath(resume_info.file, &resume_info.decl_path) catch {
|
||||
@panic("Out of memory");
|
||||
};
|
||||
}
|
||||
@ -1537,8 +1570,8 @@ fn walkDecls(
|
||||
|
||||
// Unblock any pending decl path that was waiting for this decl.
|
||||
if (self.decl_paths_pending_on_decls.get(decls_slot_index)) |paths| {
|
||||
for (paths.items) |resume_info| {
|
||||
try self.tryResolveDeclPath(resume_info.file, resume_info.path);
|
||||
for (paths.items) |*resume_info| {
|
||||
try self.tryResolveDeclPath(resume_info.file, &resume_info.decl_path);
|
||||
}
|
||||
|
||||
_ = self.decl_paths_pending_on_decls.remove(decls_slot_index);
|
||||
@ -1560,10 +1593,12 @@ fn tryResolveDeclPath(
|
||||
self: *Autodoc,
|
||||
/// File from which the decl path originates.
|
||||
file: *File,
|
||||
path: []usize,
|
||||
decl_path: *DocData.DeclPath,
|
||||
) error{OutOfMemory}!void {
|
||||
const path: []usize = decl_path.path;
|
||||
|
||||
var i: usize = path.len;
|
||||
while (i > 1) {
|
||||
outer: while (i > 1) {
|
||||
i -= 1;
|
||||
const decl_index = path[i];
|
||||
const string_index = path[i - 1];
|
||||
@ -1580,7 +1615,7 @@ fn tryResolveDeclPath(
|
||||
if (!res.found_existing) res.value_ptr.* = .{};
|
||||
try res.value_ptr.*.append(self.arena, .{
|
||||
.file = file,
|
||||
.path = path[0 .. i + 1],
|
||||
.decl_path = .{ .path = path[0 .. i + 1] },
|
||||
});
|
||||
|
||||
return;
|
||||
@ -1590,15 +1625,25 @@ fn tryResolveDeclPath(
|
||||
switch (parent.value) {
|
||||
else => {
|
||||
std.debug.panic(
|
||||
"TODO: handle `{s}`in walkInstruction.field_val\n \"{s}\":{}",
|
||||
"TODO: handle `{s}`in tryResolveDecl.field_val\n \"{s}\":{}",
|
||||
.{ @tagName(parent.value), parent.name, parent.value },
|
||||
);
|
||||
},
|
||||
.comptimeExpr => {
|
||||
// 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;
|
||||
},
|
||||
.declPath => |dp| {
|
||||
if (self.pending_decl_paths.getPtr(&dp[0])) |waiter_list| {
|
||||
if (dp.hasCte) {
|
||||
decl_path.hasCte = true;
|
||||
break :outer;
|
||||
}
|
||||
if (self.pending_decl_paths.getPtr(&dp.path[0])) |waiter_list| {
|
||||
try waiter_list.append(self.arena, .{
|
||||
.file = file,
|
||||
.path = path[0 .. i + 1],
|
||||
.decl_path = .{ .path = path[0 .. i + 1] },
|
||||
});
|
||||
|
||||
// This decl path is pending completion
|
||||
@ -1610,7 +1655,7 @@ fn tryResolveDeclPath(
|
||||
return;
|
||||
}
|
||||
|
||||
const final_decl_index = dp[0];
|
||||
const final_decl_index = dp.path[0];
|
||||
// For the purpose of being able to call tryResolveDeclPath again,
|
||||
// we momentarily replace the decl index present in `path[i]`
|
||||
// with the final decl in `dp`.
|
||||
@ -1619,7 +1664,7 @@ fn tryResolveDeclPath(
|
||||
// will not get fully resolved (also in the case that final_decl is
|
||||
// not resolved yet).
|
||||
path[i] = final_decl_index;
|
||||
try self.tryResolveDeclPath(file, path);
|
||||
try self.tryResolveDeclPath(file, decl_path);
|
||||
path[i] = decl_index;
|
||||
},
|
||||
.type => |t_index| switch (self.types.items[t_index]) {
|
||||
@ -1643,7 +1688,7 @@ fn tryResolveDeclPath(
|
||||
if (!res.found_existing) res.value_ptr.* = .{};
|
||||
try res.value_ptr.*.append(self.arena, .{
|
||||
.file = file,
|
||||
.path = path[0 .. i + 1],
|
||||
.decl_path = .{ .path = path[0 .. i + 1] },
|
||||
});
|
||||
|
||||
return;
|
||||
@ -1677,8 +1722,8 @@ fn tryResolveDeclPath(
|
||||
// attempting to resolve any other decl.
|
||||
_ = self.pending_decl_paths.remove(&path[0]);
|
||||
|
||||
for (waiter_list.items) |resume_info| {
|
||||
try self.tryResolveDeclPath(resume_info.file, resume_info.path);
|
||||
for (waiter_list.items) |*resume_info| {
|
||||
try self.tryResolveDeclPath(resume_info.file, &resume_info.decl_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
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user