autodoc: add support for anytype and improve semantics for array length

This commit is contained in:
Loris Cro 2022-03-11 18:26:21 +01:00 committed by Andrew Kelley
parent d745dde54f
commit ec7f4d1faa
2 changed files with 187 additions and 77 deletions

View File

@ -187,7 +187,7 @@
i += 1;
console.assert(isDecl(decl));
if ("type" in decl.value) {
return typeTypeId;
return { type: typeTypeId };
}
if ("declPath" in decl.value) {
@ -232,6 +232,10 @@
return fn_type.ret;
}
if ("void" in decl.value) {
return { type: typeTypeId };
}
console.log("TODO: handle in `typeOfDecl` more cases: ", decl);
console.assert(false);
throw {};
@ -472,22 +476,9 @@
var html = '<pre>' + escapeHtml(fieldNode.name) + ": ";
if (isVarArgs && i === typeObj.params.length - 1) {
html += '...';
} else if ("declRef" in value) {
var decl = zigAnalysis.decls[value.declRef];
var val = resolveValue(decl.value);
var valType = zigAnalysis.types[argTypeIndex];
var valTypeName = typeShorthandName(valType);
html += '<a href="'+navLinkDecl(decl.name)+'">';
html += '<span class="tok-kw" style="color:lightblue;">' + escapeHtml(decl.name) + '</span>';
html += '</a>';
html += ' ('+ valTypeName +')';
} else if ("type" in value) {
var name = zigAnalysis.types[value.type].name;
html += '<span class="tok-kw">' + escapeHtml(name) + '</span>';
} else {
html += '<span class="tok-kw">var</span>';
var name = typeValueName(value);
html += '<span class="tok-kw">' + name + '</span>';
}
html += ',</pre>';
@ -657,24 +648,52 @@
}
function typeValueName(typeValue, wantHtml, wantLink, fnDecl, linkFnNameDecl) {
if ("int" in typeValue) {
return typeValue.int.value;
}
if ("call" in typeValue) {
var result = "";
var call = zigAnalysis.calls[typeValue.call];
var functionName = typeValueName(call.func);
result += functionName + "(";
for (var j = 0; j < call.args.length; j += 1) {
result += typeValueName(call.args[j]);
if (j != call.args.length -1) result += ",";
}
return result + ")";
}
if ("comptimeExpr" in typeValue) {
return "[ComptimeExpr]";
}
if ("declPath" in typeValue) {
if (typeValue.hasCte) {
// TODO: find the cte, print it nicely
if (wantLink) {
return '<a href="">[ComptimeExpr]</a>';
} else {
return "[ComptimeExpr]";
}
}
var declIndex = typeValue.declPath[0];
var name = zigAnalysis.decls[declIndex].name;
var declPath = getCanonDeclPath(declIndex);
if (wantLink) {
var nl = navLink(declPath.pkgNames, declPath.declNames);
return '<a href="' + nl + '">' + name + '</a>';
} else {
return name;
var result = "";
for (var j = typeValue.declPath.length - 1; j >= 0; j--) {
var decl = zigAnalysis.decls[typeValue.declPath[j]];
// TODO: handle nested decl paths properly!
if (typeValue.hasCte) {
if (wantHtml)
result += "<a href=\"\">[ComptimeExpr]</a>";
else
result += "[ComptimeExpr]";
break;
}
var name = escapeHtml(decl.name);
if (wantHtml) {
result += '<a href="'+navLinkDecl(decl.name)+'">';
result += '<span class="tok-kw" style="color:lightblue;">' +
name + '</span>';
result += '</a>';
} else {
result += name;
}
if (j != 0) result += ".";
}
return result;
}
console.assert("type" in typeValue)
@ -760,10 +779,11 @@
switch (typeObj.kind) {
case typeKinds.Array:
var name = "[";
var lenName = typeValueName(typeObj.len, wantHtml);
if (wantHtml) {
name += '<span class="tok-number">' + typeObj.len + '</span>';
name += '<span class="tok-number">' + lenName + '</span>';
} else {
name += typeObj.len;
name += lenName;
}
name += "]";
name += typeValueName(typeObj.child, wantHtml, wantSubLink, null);
@ -986,12 +1006,16 @@
} else {
var decl = zigAnalysis.decls[value.declPath[0]];
var val = resolveValue(decl.value);
var valType = zigAnalysis.types[argTypeIndex];
var valTypeName = typeShorthandName(valType);
payloadHtml += '<a href="'+navLinkDecl(decl.name)+'">';
payloadHtml += '<span class="tok-kw" style="color:lightblue;">' + escapeHtml(decl.name) + '</span>';
payloadHtml += '</a>';
if ("comptimeExpr" in val) {
payloadHtml += "[ComptimeExpr]";
} else {
console.assert("type" in val);
var valType = zigAnalysis.types[val.type];
var valTypeName = typeShorthandName(valType);
payloadHtml += '<a href="'+navLinkDecl(decl.name)+'">';
payloadHtml += '<span class="tok-kw" style="color:lightblue;">' + escapeHtml(decl.name) + '</span>';
payloadHtml += '</a>';
}
}
} else if ("type" in value) {
var name = typeValueName(value, false);
@ -1258,6 +1282,43 @@
}
}
}
declLen = container.privDecls ? container.privDecls.length : 0;
for (var i = 0; i < declLen; i += 1) {
var decl = zigAnalysis.decls[container.privDecls[i]];
var declValue = resolveValue(decl.value);
if (decl.kind === 'var') {
varsList.push(decl);
continue;
}
if (decl.kind === 'const') {
if (!("type" in declValue)){
valsList.push(decl);
} else {
var value = zigAnalysis.types[declValue.type];
var kind = value.kind;
if (kind === typeKinds.Fn) {
// 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);
}
} else if (typeIsErrSet(declValue.type)) {
errSetsList.push(decl);
} else if (typeIsStructWithNoFields(declValue.type)) {
namespacesList.push(decl);
} else {
typesList.push(decl);
}
}
}
}
typesList.sort(byNameProperty);
namespacesList.sort(byNameProperty);
errSetsList.sort(byNameProperty);
@ -1349,35 +1410,9 @@
html += ": ";
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]];
// TODO: handle nested decl paths properly!
if (field.hasCte) {
html += "<a href=\"\">[ComptimeExpr]</a>";
break;
}
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 += '<span class="tok-kw">var</span>';
var name = typeValueName(field);
html += '<span class="tok-kw">'+ name +'</span>';
}
}
@ -1544,6 +1579,14 @@
return childDecl;
}
}
if (!parentType.privDecls) return null;
for (var i = 0; i < parentType.privDecls.length; i += 1) {
var declIndex = parentType.privDecls[i];
var childDecl = zigAnalysis.decls[declIndex];
if (childDecl.name === childName) {
return childDecl;
}
}
return null;
}

View File

@ -92,7 +92,15 @@ pub fn generateZirData(self: *Autodoc) !void {
// instead of just assinging "array" to them.
break :blk .{
.Array = .{
.len = 1,
.len = .{
.int = .{
.typeRef = .{
.type = @enumToInt(Ref.usize_type),
},
.value = 1,
.negated = false,
},
},
.child = .{ .type = 0 },
},
};
@ -374,7 +382,7 @@ const DocData = struct {
child: TypeRef,
},
Array: struct {
len: usize,
len: WalkResult,
child: TypeRef,
},
Struct: struct {
@ -516,6 +524,7 @@ const DocData = struct {
/// An example of indidirectness is `const bar = foo;`.
const TypeRef = union(enum) {
unspecified,
@"anytype",
declPath: DeclPath,
type: usize, // index in `types`
comptimeExpr: usize, // index in `comptimeExprs`
@ -530,10 +539,10 @@ const DocData = struct {
w: anytype,
) !void {
switch (self) {
.unspecified => {
.unspecified, .@"anytype" => {
try w.print(
\\{{ "unspecified":{{}} }}
, .{});
\\{{ "{s}":{{}} }}
, .{@tagName(self)});
},
.type, .comptimeExpr, .call => |v| {
@ -566,6 +575,7 @@ const DocData = struct {
@"undefined": TypeRef,
@"struct": Struct,
bool: bool,
@"anytype",
type: usize, // index in `types`
declPath: DeclPath,
int: struct {
@ -600,7 +610,7 @@ const DocData = struct {
w: anytype,
) !void {
switch (self) {
.void, .@"unreachable" => {
.void, .@"unreachable", .@"anytype" => {
try w.print(
\\{{ "{s}":{{}} }}
, .{@tagName(self)});
@ -755,6 +765,13 @@ fn walkInstruction(
},
};
},
.error_union_type => {
const pl_node = data[inst_index].pl_node;
const extra = file.zir.extraData(Zir.Inst.Bin, pl_node.payload_index);
// TODO: return the actual error union instread of cheating
return self.walkRef(file, parent_scope, extra.data.rhs);
},
.ptr_type_simple => {
const ptr = data[inst_index].ptr_type_simple;
const type_slot_index = self.types.items.len;
@ -768,6 +785,20 @@ fn walkInstruction(
return DocData.WalkResult{ .type = type_slot_index };
},
.array_type => {
const bin = data[inst_index].bin;
const len = try self.walkRef(file, parent_scope, bin.lhs);
const child = walkResultToTypeRef(try self.walkRef(file, parent_scope, bin.rhs));
const type_slot_index = self.types.items.len;
try self.types.append(self.arena, .{
.Array = .{
.len = len,
.child = child,
},
});
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);
@ -780,7 +811,13 @@ fn walkInstruction(
const type_slot_index = self.types.items.len;
try self.types.append(self.arena, .{
.Array = .{
.len = operands.len,
.len = .{
.int = .{
.typeRef = .{ .type = @enumToInt(Ref.usize_type) },
.value = operands.len,
.negated = false,
},
},
.child = typeOfWalkResult(array_data[0]),
},
});
@ -1017,6 +1054,23 @@ fn walkInstruction(
.{@tagName(tags[param_index])},
);
},
.param_anytype => {
// 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" = true,
});
param_type_refs.appendAssumeCapacity(
DocData.TypeRef{ .@"anytype" = {} },
);
},
.param, .param_comptime => {
const pl_tok = data[param_index].pl_tok;
const extra = file.zir.extraData(Zir.Inst.Param, pl_tok.payload_index);
@ -1024,10 +1078,11 @@ fn walkInstruction(
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);
self.ast_nodes.appendAssumeCapacity(.{
.name = file.zir.nullTerminatedString(extra.data.name),
.name = name,
.docs = doc_comment,
.@"comptime" = tags[param_index] == .param_comptime,
});
@ -1094,6 +1149,18 @@ fn walkInstruction(
.{@tagName(extended.opcode)},
);
},
.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)
.{ .void = {} } else .{ .void = {} };
return value;
},
.union_decl => {
var scope: Scope = .{
.parent = parent_scope,
@ -1887,7 +1954,7 @@ fn collectUnionFieldInfo(
@intToEnum(Zir.Inst.Ref, file.zir.extra[extra_index])
else
.void_type;
extra_index += 1;
if (has_type) extra_index += 1;
if (has_align) extra_index += 1;
if (has_tag) extra_index += 1;