diff --git a/lib/docs/main.js b/lib/docs/main.js index ffa5a8b1ff..07055cf570 100644 --- a/lib/docs/main.js +++ b/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 = '
' + 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 += '' + escapeHtml(name) + '';
- } else if (argTypeIndex != null) {
- html += typeIndexName(argTypeIndex, true, true);
} else {
html += 'var';
}
@@ -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 '# CTE TODO #';
+ } 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 '' + value + '';
@@ -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 += '' + escapeHtml(decl.name) + '';
payloadHtml += '';
} else if ("type" in value) {
- var name = zigAnalysis.types[value.type].name;
+ var name = typeValueName(value, false);
payloadHtml += '' + escapeHtml(name) + '';
- } else if (argTypeIndex != null) {
- payloadHtml += typeIndexName(argTypeIndex, wantHtml, wantSubLink);
+ } else if ("comptimeExpr" in value) {
+ payloadHtml += ' # CTE TODO #';
} else if (wantHtml) {
payloadHtml += 'var';
} 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 = 'const ' +
- 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 = 'var ' +
- 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 += '#FAILURE#';
- } 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 += '#FAILURE#';
+ } else if ("declPath" in field) {
+ for (var j = field.declPath.length - 1; j >= 0; j--) {
+ var decl = zigAnalysis.decls[field.declPath[j]];
- html += '';
- html += '' +
- escapeHtml(decl.name) + '';
- html += '';
- if (j != 0) html += ".";
+ // TODO: handle nested decl paths properly!
+ if (field.hasCte) {
+ html += "# CTE TODO #";
+ 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 += '' + escapeHtml(name) + '';
- } else {
- html += 'var';
+ html += '';
+ html += '' +
+ escapeHtml(decl.name) + '';
+ html += '';
+ 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 += '' + escapeHtml(name) + '';
} else {
- html += typeIndexName(field, true, true);
+ html += 'var';
}
}
@@ -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) {
diff --git a/src/Autodoc.zig b/src/Autodoc.zig
index 774f732e0f..eb9c490d95 100644
--- a/src/Autodoc.zig
+++ b/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