Commit cf685c1132
Changed files (2)
lib
docs
src
lib/docs/main.js
@@ -494,6 +494,8 @@ var zigAnalysis;
* @return {WalkResult}
*/
function typeOfDecl(decl){
+ return decl.value.typeRef;
+
let i = 0;
while(i < 1000) {
i += 1;
@@ -502,6 +504,13 @@ var zigAnalysis;
return /** @type {WalkResult} */({ type: typeTypeId });
}
+// if ("string" in decl.value) {
+// return /** @type {WalkResult} */({ type: {
+// kind: typeKinds.Pointer,
+// size: pointerSizeEnum.One,
+// child: });
+// }
+
if ("refPath" in decl.value) {
decl = /** @type {Decl} */({
value: decl.value.refPath[decl.value.refPath.length -1]
@@ -1009,6 +1018,327 @@ var zigAnalysis;
}
}
+ /**
+ * @typedef {{
+ wantHtml: boolean,
+ }} RenderWrOptions
+ * @param {WalkResult} wr,
+ * @param {RenderWrOptions} opts,
+ * @return {string}
+ */
+
+ function exprName(expr, opts) {
+ const activeField = Object.keys(expr)[0];
+ switch (activeField) {
+ case "int": {
+ return "" + expr.int;
+ }
+ case "string": {
+ return "\"" + escapeHtml(expr.string) + "\"";
+ }
+
+ case "anytype": {
+ return "anytype";
+ }
+
+ case "this":{
+ return "this";
+ }
+
+ case "type": {
+ let name = "";
+ const typeObj = zigAnalysis.types[expr.type];
+ switch (typeObj.kind) {
+ case typeKinds.Array:
+ {
+ let arrayObj = /** @type {ArrayType} */(typeObj);
+ let name = "[";
+ let lenName = exprName(arrayObj.len, opts);
+ if (opts.wantHtml) {
+ name += '<span class="tok-number">' + lenName + '</span>';
+ } else {
+ name += lenName;
+ }
+ name += "]";
+ name += exprName(arrayObj.child, opts);
+ return name;
+ }
+ case typeKinds.Optional:
+
+ return "?" + typeValueName(/**@type {OptionalType} */(typeObj).child, wantHtml, wantSubLink, fnDecl, linkFnNameDecl);
+ case typeKinds.Pointer:
+ {
+ let ptrObj = /** @type {PointerType} */(typeObj);
+ let name = "";
+ switch (ptrObj.size) {
+ default:
+ console.log("TODO: implement unhandled pointer size case");
+ case pointerSizeEnum.One:
+ name += "*";
+ break;
+ case pointerSizeEnum.Many:
+ name += "[*]";
+ break;
+ case pointerSizeEnum.Slice:
+ name += "[]";
+ break;
+ case pointerSizeEnum.C:
+ name += "[*c]";
+ break;
+ }
+ if (ptrObj['const']) {
+ if (opts.wantHtml) {
+ name += '<span class="tok-kw">const</span> ';
+ } else {
+ name += "const ";
+ }
+ }
+ if (ptrObj['volatile']) {
+ if (opts.wantHtml) {
+ name += '<span class="tok-kw">volatile</span> ';
+ } else {
+ name += "volatile ";
+ }
+ }
+ if (ptrObj.align != null) {
+ if (opts.wantHtml) {
+ name += '<span class="tok-kw">align</span>(';
+ } else {
+ name += "align(";
+ }
+ if (opts.wantHtml) {
+ name += '<span class="tok-number">' + ptrObj.align + '</span>';
+ } else {
+ name += ptrObj.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 = /** @type {NumberType} */ (typeObj);
+
+ if (wantHtml) {
+ return '<span class="tok-type">' + floatObj.name + '</span>';
+ } else {
+ return floatObj.name;
+ }
+ }
+ case typeKinds.Int:
+ {
+ let intObj = /** @type {NumberType} */(typeObj);
+ let name = intObj.name;
+ if (opts.wantHtml) {
+ return '<span class="tok-type">' + name + '</span>';
+ } else {
+ return name;
+ }
+ }
+ case typeKinds.ComptimeInt:
+ if (wantHtml) {
+ return '<span class="tok-type">comptime_int</span>';
+ } else {
+ return "comptime_int";
+ }
+ case typeKinds.ComptimeFloat:
+ if (wantHtml) {
+ return '<span class="tok-type">comptime_float</span>';
+ } else {
+ return "comptime_float";
+ }
+ case typeKinds.Type:
+ if (wantHtml) {
+ return '<span class="tok-type">type</span>';
+ } else {
+ return "type";
+ }
+ case typeKinds.Bool:
+ if (wantHtml) {
+ return '<span class="tok-type">bool</span>';
+ } else {
+ return "bool";
+ }
+ case typeKinds.Void:
+ if (wantHtml) {
+ return '<span class="tok-type">void</span>';
+ } else {
+ return "void";
+ }
+ case typeKinds.EnumLiteral:
+ if (wantHtml) {
+ return '<span class="tok-type">(enum literal)</span>';
+ } else {
+ return "(enum literal)";
+ }
+ case typeKinds.NoReturn:
+ if (wantHtml) {
+ return '<span class="tok-type">noreturn</span>';
+ } else {
+ return "noreturn";
+ }
+ case typeKinds.ErrorSet:
+ {
+ let errSetObj = /** @type {ErrSetType} */(typeObj);
+ if (errSetObj.fields == null) {
+ if (wantHtml) {
+ return '<span class="tok-type">anyerror</span>';
+ } else {
+ return "anyerror";
+ }
+ } else {
+ throw "TODO";
+ // if (wantHtml) {
+ // return escapeHtml(typeObj.name);
+ // } else {
+ // return typeObj.name;
+ // }
+ }
+ }
+ case typeKinds.ErrorUnion:
+ {
+ throw "TODO";
+ // TODO: implement error union printing assuming that both
+ // payload and error union are walk results!
+ // let errUnionObj = /** @type {ErrUnionType} */(typeObj);
+ // let errSetTypeObj = /** @type {ErrSetType} */ (zigAnalysis.types[errUnionObj.err]);
+ // let payloadHtml = typeValueName(errUnionObj.payload, wantHtml, wantSubLink, null);
+ // if (fnDecl != null && errSetTypeObj.fn === fnDecl.value.type) {
+ // // function index parameter supplied and this is the inferred error set of it
+ // return "!" + payloadHtml;
+ // } else {
+ // return typeValueName(errUnionObj.err, wantHtml, wantSubLink, null) + "!" + payloadHtml;
+ // }
+ }
+ case typeKinds.Fn:
+ {
+ let fnObj = /** @type {Fn} */(typeObj);
+ let 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 (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 += ', ';
+ }
+
+ let value = fnObj.params[i];
+ let paramValue = resolveValue(value);
+
+ if (fields != null) {
+ let paramNode = zigAnalysis.astNodes[fields[i]];
+
+ if (paramNode.varArgs) {
+ payloadHtml += '...';
+ continue;
+ }
+
+ if (paramNode.noalias) {
+ if (wantHtml) {
+ payloadHtml += '<span class="tok-kw">noalias</span> ';
+ } else {
+ payloadHtml += 'noalias ';
+ }
+ }
+
+ if (paramNode.comptime) {
+ if (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 ("refPath" in value) {
+ payloadHtml += '<a href="">';
+ payloadHtml += '<span class="tok-kw" style="color:lightblue;">[Ref Path]</span>';
+ payloadHtml += '</a>';
+
+ } else if ("type" in value) {
+ let name = typeValueName(value, false, false, fnDecl, linkFnNameDecl);
+ payloadHtml += '<span class="tok-kw">' + escapeHtml(name) + '</span>';
+ } else if ("comptimeExpr" in value) {
+ payloadHtml += '<span class="tok-kw">[ComptimeExpr]</span>';
+ } else if (wantHtml) {
+ payloadHtml += '<span class="tok-kw">var</span>';
+ } else {
+ payloadHtml += 'var';
+ }
+ }
+ }
+
+ payloadHtml += ') ';
+ if (fnObj.ret != null) {
+ payloadHtml += typeValueName(fnObj.ret, wantHtml, wantSubLink, fnDecl);
+ } else if (wantHtml) {
+ payloadHtml += '<span class="tok-kw">anytype</span>';
+ } else {
+ payloadHtml += 'anytype';
+ }
+ return payloadHtml;
+ }
+ default:
+ throw "TODO";
+ // if (wantHtml) {
+ // return escapeHtml(typeObj.name);
+ // } else {
+ // return typeObj.name;
+ // }
+ }
+ }
+
+ default: throw "oh no";
+ }
+ }
+
+
/**
* @param {WalkResult} typeValue,
* @param {boolean} wantHtml,
@@ -1174,289 +1504,6 @@ var zigAnalysis;
* @return {string}
*/
function typeName(typeObj, wantHtml, wantSubLink, fnDecl, linkFnNameDecl) {
- switch (typeObj.kind) {
- case typeKinds.Array:
- {
- let arrayObj = /** @type {ArrayType} */(typeObj);
- let name = "[";
- let lenName = typeValueName(arrayObj.len, wantHtml, wantSubLink);
- if (wantHtml) {
- name += '<span class="tok-number">' + lenName + '</span>';
- } else {
- name += lenName;
- }
- name += "]";
- name += typeValueName(arrayObj.child, wantHtml, wantSubLink, null);
- return name;
- }
- case typeKinds.Optional:
-
- return "?" + typeValueName(/**@type {OptionalType} */(typeObj).child, wantHtml, wantSubLink, fnDecl, linkFnNameDecl);
- case typeKinds.Pointer:
- {
- let ptrObj = /** @type {PointerType} */(typeObj);
- let name = "";
- switch (ptrObj.size) {
- default:
- console.log("TODO: implement unhandled pointer size case");
- case pointerSizeEnum.One:
- name += "*";
- break;
- case pointerSizeEnum.Many:
- name += "[*]";
- break;
- case pointerSizeEnum.Slice:
- name += "[]";
- break;
- case pointerSizeEnum.C:
- name += "[*c]";
- break;
- }
- if (ptrObj['const']) {
- if (wantHtml) {
- name += '<span class="tok-kw">const</span> ';
- } else {
- name += "const ";
- }
- }
- if (ptrObj['volatile']) {
- if (wantHtml) {
- name += '<span class="tok-kw">volatile</span> ';
- } else {
- name += "volatile ";
- }
- }
- if (ptrObj.align != null) {
- if (wantHtml) {
- name += '<span class="tok-kw">align</span>(';
- } else {
- name += "align(";
- }
- if (wantHtml) {
- name += '<span class="tok-number">' + ptrObj.align + '</span>';
- } else {
- name += ptrObj.align;
- }
- if (ptrObj.hostIntBytes != null) {
- name += ":";
- if (wantHtml) {
- name += '<span class="tok-number">' + ptrObj.bitOffsetInHost + '</span>';
- } else {
- name += ptrObj.bitOffsetInHost;
- }
- name += ":";
- if (wantHtml) {
- name += '<span class="tok-number">' + ptrObj.hostIntBytes + '</span>';
- } else {
- name += ptrObj.hostIntBytes;
- }
- }
- name += ") ";
- }
- name += typeValueName(ptrObj.child, wantHtml, wantSubLink, null);
- return name;
- }
- case typeKinds.Float:
- {
- let floatObj = /** @type {NumberType} */ (typeObj);
-
- if (wantHtml) {
- return '<span class="tok-type">' + floatObj.name + '</span>';
- } else {
- return floatObj.name;
- }
- }
- case typeKinds.Int:
- {
- let intObj = /** @type {NumberType} */(typeObj);
- let name = intObj.name;
- if (wantHtml) {
- return '<span class="tok-type">' + name + '</span>';
- } else {
- return name;
- }
- }
- case typeKinds.ComptimeInt:
- if (wantHtml) {
- return '<span class="tok-type">comptime_int</span>';
- } else {
- return "comptime_int";
- }
- case typeKinds.ComptimeFloat:
- if (wantHtml) {
- return '<span class="tok-type">comptime_float</span>';
- } else {
- return "comptime_float";
- }
- case typeKinds.Type:
- if (wantHtml) {
- return '<span class="tok-type">type</span>';
- } else {
- return "type";
- }
- case typeKinds.Bool:
- if (wantHtml) {
- return '<span class="tok-type">bool</span>';
- } else {
- return "bool";
- }
- case typeKinds.Void:
- if (wantHtml) {
- return '<span class="tok-type">void</span>';
- } else {
- return "void";
- }
- case typeKinds.EnumLiteral:
- if (wantHtml) {
- return '<span class="tok-type">(enum literal)</span>';
- } else {
- return "(enum literal)";
- }
- case typeKinds.NoReturn:
- if (wantHtml) {
- return '<span class="tok-type">noreturn</span>';
- } else {
- return "noreturn";
- }
- case typeKinds.ErrorSet:
- {
- let errSetObj = /** @type {ErrSetType} */(typeObj);
- if (errSetObj.fields == null) {
- if (wantHtml) {
- return '<span class="tok-type">anyerror</span>';
- } else {
- return "anyerror";
- }
- } else {
- throw "TODO";
- // if (wantHtml) {
- // return escapeHtml(typeObj.name);
- // } else {
- // return typeObj.name;
- // }
- }
- }
- case typeKinds.ErrorUnion:
- {
- throw "TODO";
- // TODO: implement error union printing assuming that both
- // payload and error union are walk results!
- // let errUnionObj = /** @type {ErrUnionType} */(typeObj);
- // let errSetTypeObj = /** @type {ErrSetType} */ (zigAnalysis.types[errUnionObj.err]);
- // let payloadHtml = typeValueName(errUnionObj.payload, wantHtml, wantSubLink, null);
- // if (fnDecl != null && errSetTypeObj.fn === fnDecl.value.type) {
- // // function index parameter supplied and this is the inferred error set of it
- // return "!" + payloadHtml;
- // } else {
- // return typeValueName(errUnionObj.err, wantHtml, wantSubLink, null) + "!" + payloadHtml;
- // }
- }
- case typeKinds.Fn:
- {
- let fnObj = /** @type {Fn} */(typeObj);
- let 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 (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 += ', ';
- }
-
- let value = fnObj.params[i];
- let paramValue = resolveValue(value);
-
- if (fields != null) {
- let paramNode = zigAnalysis.astNodes[fields[i]];
-
- if (paramNode.varArgs) {
- payloadHtml += '...';
- continue;
- }
-
- if (paramNode.noalias) {
- if (wantHtml) {
- payloadHtml += '<span class="tok-kw">noalias</span> ';
- } else {
- payloadHtml += 'noalias ';
- }
- }
-
- if (paramNode.comptime) {
- if (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 ("refPath" in value) {
- payloadHtml += '<a href="">';
- payloadHtml += '<span class="tok-kw" style="color:lightblue;">[Ref Path]</span>';
- payloadHtml += '</a>';
-
- } else if ("type" in value) {
- let name = typeValueName(value, false, false, fnDecl, linkFnNameDecl);
- payloadHtml += '<span class="tok-kw">' + escapeHtml(name) + '</span>';
- } else if ("comptimeExpr" in value) {
- payloadHtml += '<span class="tok-kw">[ComptimeExpr]</span>';
- } else if (wantHtml) {
- payloadHtml += '<span class="tok-kw">var</span>';
- } else {
- payloadHtml += 'var';
- }
- }
- }
-
- payloadHtml += ') ';
- if (fnObj.ret != null) {
- payloadHtml += typeValueName(fnObj.ret, wantHtml, wantSubLink, fnDecl);
- } else if (wantHtml) {
- payloadHtml += '<span class="tok-kw">anytype</span>';
- } else {
- payloadHtml += 'anytype';
- }
- return payloadHtml;
- }
- default:
- throw "TODO";
- // if (wantHtml) {
- // return escapeHtml(typeObj.name);
- // } else {
- // return typeObj.name;
- // }
- }
}
/** @param {Type} typeObj */
@@ -1607,25 +1654,25 @@ var zigAnalysis;
/** @param {Decl} decl */
function renderValue(decl) {
- let declTypeRef = typeOfDecl(decl);
- let declValueText = "";
- switch(Object.keys(decl.value)[0]) {
- case "int":
- declValueText += /** @type {{int: {value: number}}} */(decl.value).int.value;
- break;
- case "float":
- declValueText += /** @type {{float: {value: number}}} */(decl.value).float.value;
- break;
- case "comptimeExpr":
- declValueText += "[ComptimeExpr]";
- break;
- default:
- console.log("TODO: renderValue for ", Object.keys(decl.value)[0]);
- declValueText += "#TODO#";
- }
+ let declTypeRef = decl.value.typeRef;
+ let declValueText = exprName(decl.value.expr);
+// switch(Object.keys(decl.value)[0]) {
+// case "int":
+// declValueText += /** @type {{int: {value: number}}} */(decl.value).int.value;
+// break;
+// case "float":
+// declValueText += /** @type {{float: {value: number}}} */(decl.value).float.value;
+// break;
+// case "comptimeExpr":
+// declValueText += "[ComptimeExpr]";
+// break;
+// default:
+// console.log("TODO: renderValue for ", Object.keys(decl.value)[0]);
+// declValueText += "#TODO#";
+// }
domFnProtoCode.innerHTML = '<span class="tok-kw">const</span> ' +
- escapeHtml(decl.name) + ': ' + typeValueName(declTypeRef, true, true) +
+ escapeHtml(decl.name) + ': ' + exprName(declTypeRef, {wantHtml: true}) +
" = " + declValueText;
let docs = zigAnalysis.astNodes[decl.src].docs;
src/Autodoc.zig
@@ -17,13 +17,14 @@ files: std.AutoHashMapUnmanaged(*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.WalkResult, // pointer to declpath tail end (ie `&decl_path[decl_path.len - 1]`)
+ *DocData.Expr, // pointer to declpath tail end (ie `&decl_path[decl_path.len - 1]`)
std.ArrayListUnmanaged(RefPathResumeInfo),
) = .{},
ref_paths_pending_on_decls: std.AutoHashMapUnmanaged(
@@ -37,7 +38,7 @@ ref_paths_pending_on_types: std.AutoHashMapUnmanaged(
const RefPathResumeInfo = struct {
file: *File,
- ref_path: []DocData.WalkResult,
+ ref_path: []DocData.Expr,
};
var arena_allocator: std.heap.ArenaAllocator = undefined;
@@ -80,7 +81,6 @@ pub fn generateZirData(self: *Autodoc) !void {
.ComptimeExpr = .{ .name = "ComptimeExpr" },
});
- var tr = DocData.WalkResult{ .type = @enumToInt(Ref.usize_type) };
// 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) {
@@ -96,7 +96,6 @@ pub fn generateZirData(self: *Autodoc) !void {
.Array = .{
.len = .{
.int = .{
- .typeRef = &tr,
.value = 1,
.negated = false,
},
@@ -163,7 +162,7 @@ pub fn generateZirData(self: *Autodoc) !void {
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);
+ _ = 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)");
@@ -182,6 +181,7 @@ pub fn generateZirData(self: *Autodoc) !void {
.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,
};
@@ -305,11 +305,12 @@ const DocData = struct {
},
types: []Type,
decls: []Decl,
+ exprs: []Expr,
comptimeExprs: []ComptimeExpr,
const Call = struct {
- func: WalkResult,
- args: []WalkResult,
- ret: WalkResult,
+ func: Expr,
+ args: []Expr,
+ ret: Expr,
};
/// All the type "families" as described by `std.builtin.TypeId`
@@ -340,7 +341,6 @@ const DocData = struct {
const ComptimeExpr = struct {
code: []const u8,
- typeRef: WalkResult,
};
const Package = struct {
name: []const u8 = "root",
@@ -356,7 +356,6 @@ const DocData = struct {
kind: []const u8,
isTest: bool,
src: usize, // index into astNodes
- // typeRef: TypeRef,
value: WalkResult,
// The index in astNodes of the `test declname { }` node
decltest: ?usize = null,
@@ -383,18 +382,18 @@ const DocData = struct {
Float: struct { name: []const u8 },
Pointer: struct {
size: std.builtin.TypeInfo.Pointer.Size,
- child: WalkResult,
+ child: Expr,
},
Array: struct {
- len: WalkResult,
- child: WalkResult,
+ len: Expr,
+ child: Expr,
},
Struct: struct {
name: []const u8,
src: usize, // index into astNodes
privDecls: []usize = &.{}, // index into decls
pubDecls: []usize = &.{}, // index into decls
- fields: ?[]WalkResult = null, // (use src->fields to find names)
+ fields: ?[]Expr = null, // (use src->fields to find names)
},
ComptimeExpr: struct { name: []const u8 },
ComptimeFloat: struct { name: []const u8 },
@@ -403,7 +402,7 @@ const DocData = struct {
Null: struct { name: []const u8 },
Optional: struct {
name: []const u8,
- child: WalkResult,
+ child: Expr,
},
ErrorUnion: struct { name: []const u8 },
ErrorSet: struct {
@@ -423,13 +422,13 @@ const DocData = struct {
src: usize, // index into astNodes
privDecls: []usize = &.{}, // index into decls
pubDecls: []usize = &.{}, // index into decls
- fields: []WalkResult = &.{}, // (use src->fields to find names)
+ fields: []Expr = &.{}, // (use src->fields to find names)
},
Fn: struct {
name: []const u8,
src: ?usize = null, // index into astNodes
- ret: WalkResult,
- params: ?[]WalkResult = null, // (use src->fields to find names)
+ ret: Expr,
+ params: ?[]Expr = null, // (use src->fields to find names)
},
BoundFn: struct { name: []const u8 },
Opaque: struct { name: []const u8 },
@@ -517,75 +516,61 @@ const DocData = struct {
}
};
- /// A WalkResult represents the result of the analysis process done to a
- /// declaration. This includes: decls, fields, etc.
- ///
- /// The data in WalkResult is mostly normalized, which means that a
- /// WalkResult that results in a type definition will hold an index into
- /// `self.types`.
- const WalkResult = union(enum) {
+ /// 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,
@"unreachable",
- @"null": *WalkResult,
- @"undefined": *WalkResult,
- @"struct": Struct,
+ @"null",
+ @"undefined",
+ @"struct": []FieldVal,
bool: bool,
@"anytype",
type: usize, // index in `types`
this: usize, // index in `types`
declRef: usize, // index in `decls`
fieldRef: FieldRef,
- refPath: []WalkResult,
+ refPath: []Expr,
int: struct {
- typeRef: *WalkResult,
value: usize, // direct value
negated: bool = false,
},
- float: struct {
- typeRef: *WalkResult,
- value: f64, // direct value
- negated: bool = false,
- },
- array: Array,
+ float: f64, // direct value
+ array: []usize, // index in `exprs`
call: usize, // index in `calls`
- enumLiteral: []const u8,
- typeOf: *WalkResult,
- sizeOf: *WalkResult,
+ enumLiteral: []const u8, // direct value
+ typeOf: usize, // index in `exprs`
+ as: struct {
+ typeRefArg: ?usize, // index in `exprs`
+ exprArg: usize, // index in `exprs`
+ },
+ sizeOf: usize, // index in `exprs`
compileError: []const u8,
- string: []const u8,
-
+ string: []const u8, // direct value
const FieldRef = struct {
type: usize, // index in `types`
index: usize, // index in type.fields
};
- const Struct = struct {
- typeRef: *WalkResult,
- fieldVals: []FieldVal,
-
- const FieldVal = struct {
- name: []const u8,
- val: WalkResult,
- };
- };
- const Array = struct {
- typeRef: *WalkResult,
- data: []WalkResult,
+ const FieldVal = struct {
+ name: []const u8,
+ val: WalkResult,
};
pub fn jsonStringify(
- self: WalkResult,
+ self: Expr,
options: std.json.StringifyOptions,
w: anytype,
) std.os.WriteError!void {
switch (self) {
- .void, .@"unreachable", .@"anytype" => {
+ .void, .@"unreachable", .@"anytype", .@"null", .@"undefined" => {
try w.print(
\\{{ "{s}":{{}} }}
, .{@tagName(self)});
},
- .type, .comptimeExpr, .call, .this, .declRef => |v| {
+ .type, .comptimeExpr, .call, .this, .declRef, .typeOf => |v| {
try w.print(
\\{{ "{s}":{} }}
, .{ @tagName(self), v });
@@ -593,43 +578,28 @@ const DocData = struct {
.int => |v| {
const neg = if (v.negated) "-" else "";
try w.print(
- \\{{ "int": {{ "typeRef":
- , .{});
- try v.typeRef.jsonStringify(options, w);
- try w.print(
- \\, "value": {s}{} }} }}
+ \\{{ "int": {s}{} }}
, .{ neg, v.value });
},
.float => |v| {
- const neg = if (v.negated) "-" else "";
- try w.print(
- \\{{ "float": {{ "typeRef":
- , .{});
- try v.typeRef.jsonStringify(options, w);
try w.print(
- \\, "value": {s}1 }} }}
- , .{neg});
- // TODO: uncomment once float panic is fixed in stdlib
- // See: https://github.com/ziglang/zig/issues/11283
- // try w.print(
- // \\, "value": {s}{e} }} }}
- // , .{ neg, v.value });
+ \\{{ "float": {} }}
+ , .{v});
},
.bool => |v| {
try w.print(
\\{{ "bool":{} }}
, .{v});
},
- .@"undefined" => |v| try std.json.stringify(v, options, w),
- .@"null" => |v| try std.json.stringify(v, options, w),
- .typeOf, .sizeOf => |v| try std.json.stringify(v, options, w),
+ .sizeOf => |v| try std.json.stringify(v, options, w),
+ .as => |v| try std.json.stringify(v, options, w),
.fieldRef => |v| try std.json.stringify(
struct { fieldRef: FieldRef }{ .fieldRef = v },
options,
w,
),
.@"struct" => |v| try std.json.stringify(
- struct { @"struct": Struct }{ .@"struct" = v },
+ struct { @"struct": []FieldVal }{ .@"struct" = v },
options,
w,
),
@@ -642,7 +612,7 @@ const DocData = struct {
}
},
.array => |v| try std.json.stringify(
- struct { @"array": Array }{ .@"array" = v },
+ struct { @"array": []usize }{ .@"array" = v },
options,
w,
),
@@ -677,6 +647,17 @@ const DocData = struct {
}
}
};
+
+ /// 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`
+ };
};
/// Called when we need to analyze a Zir instruction.
@@ -692,6 +673,7 @@ fn walkInstruction(
file: *File,
parent_scope: *Scope,
inst_index: usize,
+ need_type: bool, // true if the caller needs us to provide also a typeRef
) error{OutOfMemory}!DocData.WalkResult {
const tags = file.zir.instructions.items(.tag);
const data = file.zir.instructions.items(.data);
@@ -711,11 +693,11 @@ fn walkInstruction(
},
.closure_get => {
const inst_node = data[inst_index].inst_node;
- return try self.walkInstruction(file, parent_scope, inst_node.inst);
+ 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);
+ return try self.walkRef(file, parent_scope, un_tok.operand, need_type);
},
.import => {
const str_tok = data[inst_index].str_tok;
@@ -726,17 +708,20 @@ fn walkInstruction(
const cte_slot_index = self.comptime_exprs.items.len;
try self.comptime_exprs.append(self.arena, .{
.code = path,
- .typeRef = .{ .type = @enumToInt(DocData.DocTypeKinds.Type) },
});
return DocData.WalkResult{
- .comptimeExpr = cte_slot_index,
+ .typeRef = .{ .type = @enumToInt(Ref.type_type) },
+ .expr = .{ .comptimeExpr = cte_slot_index },
};
}
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{ .type = result.value_ptr.* };
+ return DocData.WalkResult{
+ .typeRef = .{ .type = @enumToInt(Ref.type_type) },
+ .expr = .{ .type = result.value_ptr.* },
+ };
}
result.value_ptr.* = self.types.items.len;
@@ -745,18 +730,38 @@ fn walkInstruction(
.parent = null,
.enclosing_type = self.types.items.len,
};
- const new_file_walk_result = self.walkInstruction(
+
+ return self.walkInstruction(
new_file.file,
&new_scope,
Zir.main_struct_inst,
+ need_type,
);
-
- return new_file_walk_result;
},
.str => {
- const str = data[inst_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) },
+ },
+ });
+ const ptrTypeId = self.types.items.len;
+ try self.types.append(self.arena, .{
+ .Pointer = .{
+ .size = .One,
+ .child = .{ .type = arrTypeId },
+ // TODO: add sentinel!
+ },
+ });
+ break :blk .{ .type = ptrTypeId };
+ };
return DocData.WalkResult{
- .string = str.get(file.zir),
+ .typeRef = tRef,
+ .expr = .{ .string = str },
};
},
.compile_error => {
@@ -765,24 +770,23 @@ fn walkInstruction(
file,
parent_scope,
un_node.operand,
+ false,
);
- return DocData.WalkResult{ .compileError = operand.string };
+ return DocData.WalkResult{
+ .expr = .{ .compileError = operand.expr.string },
+ };
},
.enum_literal => {
const str_tok = data[inst_index].str_tok;
const literal = file.zir.nullTerminatedString(str_tok.start);
- return DocData.WalkResult{ .enumLiteral = literal };
+ return DocData.WalkResult{ .expr = .{ .enumLiteral = literal } };
},
.int => {
const int = data[inst_index].int;
- const t = try self.arena.create(DocData.WalkResult);
- t.* = .{ .type = @enumToInt(Ref.comptime_int_type) };
return DocData.WalkResult{
- .int = .{
- .typeRef = t,
- .value = int,
- },
+ .typeRef = .{ .type = @enumToInt(Ref.comptime_int_type) },
+ .expr = .{ .int = .{ .value = int } },
};
},
.error_union_type => {
@@ -790,20 +794,23 @@ fn walkInstruction(
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);
+ return self.walkRef(file, parent_scope, extra.data.rhs, need_type);
},
.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);
+ const elem_type_ref = try self.walkRef(file, parent_scope, ptr.elem_type, false);
try self.types.append(self.arena, .{
.Pointer = .{
.size = ptr.size,
- .child = elem_type_ref,
+ .child = elem_type_ref.expr,
},
});
- return DocData.WalkResult{ .type = type_slot_index };
+ return DocData.WalkResult{
+ .typeRef = .{ .type = @enumToInt(Ref.type_type) },
+ .expr = .{ .type = type_slot_index },
+ };
},
.ptr_type => {
const ptr = data[inst_index].ptr_type;
@@ -814,74 +821,84 @@ fn walkInstruction(
file,
parent_scope,
extra.data.elem_type,
+ false,
);
try self.types.append(self.arena, .{
.Pointer = .{
.size = ptr.size,
- .child = elem_type_ref,
+ .child = elem_type_ref.expr,
},
});
-
- return DocData.WalkResult{ .type = type_slot_index };
+ return DocData.WalkResult{
+ .typeRef = .{ .type = @enumToInt(Ref.type_type) },
+ .expr = .{ .type = type_slot_index },
+ };
},
.array_type => {
const bin = data[inst_index].bin;
- const len = try self.walkRef(file, parent_scope, bin.lhs);
- const child = try self.walkRef(file, parent_scope, bin.rhs);
+ 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,
- .child = child,
+ .len = len.expr,
+ .child = child.expr,
},
});
- return DocData.WalkResult{ .type = type_slot_index };
+ 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(DocData.WalkResult, operands.len);
+ const array_data = try self.arena.alloc(usize, operands.len);
+
+ // TODO: make sure that you want the array to be fully normalized for real
+ // then update this code to conform to your choice.
+
+ var array_type: ?DocData.Expr = null;
for (operands) |op, idx| {
- array_data[idx] = try self.walkRef(file, parent_scope, op);
- }
+ // we only ask to figure out type info for the first element
+ // as it will be used later on to find out the array type!
+ const wr = try self.walkRef(file, parent_scope, op, idx == 0);
+
+ if (idx == 0) {
+ array_type = wr.typeRef;
+ }
- const at = try self.arena.create(DocData.WalkResult);
- at.* = .{ .type = @enumToInt(Ref.usize_type) };
+ // We know that Zir wraps every operand in an @as expression
+ // so we want to peel it away and only save the target type
+ // once, since we need it later to define the array type.
+ array_data[idx] = wr.expr.as.exprArg;
+ }
const type_slot_index = self.types.items.len;
try self.types.append(self.arena, .{
.Array = .{
.len = .{
.int = .{
- .typeRef = at,
.value = operands.len,
.negated = false,
},
},
- .child = try self.typeOfWalkResult(array_data[0]),
+ .child = array_type.?,
},
});
- const t = try self.arena.create(DocData.WalkResult);
- t.* = .{ .type = type_slot_index };
- return DocData.WalkResult{ .array = .{
- .typeRef = t,
- .data = array_data,
- } };
+ return DocData.WalkResult{
+ .typeRef = .{ .type = type_slot_index },
+ .expr = .{ .array = array_data },
+ };
},
.float => {
const float = data[inst_index].float;
-
- const t = try self.arena.create(DocData.WalkResult);
- t.* = .{ .type = @enumToInt(Ref.comptime_float_type) };
-
return DocData.WalkResult{
- .float = .{
- .typeRef = t,
- .value = float,
- },
+ .typeRef = .{ .type = @enumToInt(Ref.comptime_float_type) },
+ .expr = .{ .float = float },
};
},
.negate => {
@@ -890,8 +907,9 @@ fn walkInstruction(
file,
parent_scope,
un_node.operand,
+ need_type,
);
- switch (operand) {
+ switch (operand.expr) {
.int => |*int| int.negated = true,
else => {
printWithContext(
@@ -906,75 +924,93 @@ fn walkInstruction(
},
.size_of => {
const un_node = data[inst_index].un_node;
- var operand = try self.arena.create(DocData.WalkResult);
- operand.* = try self.walkRef(
+ const operand = try self.walkRef(
file,
parent_scope,
un_node.operand,
+ false,
);
- return DocData.WalkResult{ .sizeOf = operand };
+ 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 },
+ };
},
.typeof => {
const un_node = data[inst_index].un_node;
- var operand = try self.arena.create(DocData.WalkResult);
- operand.* = try self.walkRef(
+ const operand = try self.walkRef(
file,
parent_scope,
un_node.operand,
+ need_type,
);
- return DocData.WalkResult{ .typeOf = operand };
+ 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);
- const dest_type_ref = dest_type_walk;
+ const dest_type_walk = try self.walkRef(
+ file,
+ parent_scope,
+ extra.data.dest_type,
+ false,
+ );
- var operand = try self.walkRef(file, parent_scope, extra.data.operand);
+ 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);
- switch (operand) {
- else => printWithContext(
- file,
- inst_index,
- "TODO: handle {s} in `walkInstruction.as_node`",
- .{@tagName(operand)},
- ),
- .declRef, .refPath, .type, .string, .call, .enumLiteral => {},
- // we don't do anything because up until now,
- // I've only seen this used as such:
- // @as(@as(type, Baz), .{})
- // and we don't want to toss away the
- // decl_val information (eg by replacing it with
- // a WalkResult.type).
- .comptimeExpr => {
- self.comptime_exprs.items[operand.comptimeExpr].typeRef = dest_type_ref;
- },
- .int => operand.int.typeRef.* = dest_type_ref,
- .@"struct" => operand.@"struct".typeRef.* = dest_type_ref,
- .@"undefined" => operand.@"undefined".* = dest_type_ref,
- }
+ const dest_type_idx = self.exprs.items.len;
+ try self.exprs.append(self.arena, dest_type_walk.expr);
- return operand;
+ // 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;
- var operand: DocData.WalkResult = try self.walkRef(
+ const operand: DocData.WalkResult = try self.walkRef(
file,
parent_scope,
un_node.operand,
+ false,
);
- const type_ref = operand;
- const res = DocData.WalkResult{ .type = self.types.items.len };
+
+ const operand_idx = self.types.items.len;
try self.types.append(self.arena, .{
- .Optional = .{ .name = "?TODO", .child = type_ref },
+ .Optional = .{ .name = "?TODO", .child = operand.expr },
});
- return res;
+
+ 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);
- return DocData.WalkResult{ .declRef = decls_slot_index };
+ 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
@@ -982,7 +1018,7 @@ fn walkInstruction(
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.WalkResult) = .{};
+ 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, .{
@@ -1006,12 +1042,13 @@ fn walkInstruction(
lhs = @enumToInt(lhs_extra.data.lhs) - Ref.typed_value_map.len; // underflow = need to handle Refs
}
- const wr = try self.walkInstruction(file, parent_scope, lhs);
- try path.append(self.arena, wr);
+ // 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.WalkResult, path.items);
+ 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
@@ -1026,7 +1063,7 @@ fn walkInstruction(
// any value that depends on that will have to become a
// comptimeExpr.
try self.tryResolveRefPath(file, lhs, path.items);
- return DocData.WalkResult{ .refPath = path.items };
+ return DocData.WalkResult{ .expr = .{ .refPath = path.items } };
},
.int_type => {
const int_type = data[inst_index].int_type;
@@ -1037,28 +1074,37 @@ fn walkInstruction(
try self.types.append(self.arena, .{
.Int = .{ .name = name },
});
- return DocData.WalkResult{ .type = self.types.items.len - 1 };
+ return DocData.WalkResult{
+ .typeRef = .{ .type = @enumToInt(Ref.type_type) },
+ .expr = .{ .type = self.types.items.len - 1 },
+ };
},
.block => {
- const res = DocData.WalkResult{ .comptimeExpr = self.comptime_exprs.items.len };
+ const res = DocData.WalkResult{ .expr = .{
+ .comptimeExpr = self.comptime_exprs.items.len,
+ } };
try self.comptime_exprs.append(self.arena, .{
.code = "if(banana) 1 else 0",
- .typeRef = .{ .type = 0 },
});
return res;
},
.block_inline => {
- return self.walkRef(file, parent_scope, getBlockInlineBreak(file.zir, inst_index));
+ 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.WalkResult.Struct.FieldVal,
+ DocData.Expr.FieldVal,
extra.data.fields_len,
);
- const type_ref = try self.arena.create(DocData.WalkResult);
+ 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);
@@ -1079,19 +1125,25 @@ fn walkInstruction(
file,
parent_scope,
field_extra.data.container_type,
+ false,
);
- type_ref.* = wr;
+ 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);
+ const value = try self.walkRef(
+ file,
+ parent_scope,
+ init_extra.data.init,
+ need_type,
+ );
fv.* = .{ .name = field_name, .val = value };
}
- return DocData.WalkResult{ .@"struct" = .{
+ return DocData.WalkResult{
.typeRef = type_ref,
- .fieldVals = field_vals,
- } };
+ .expr = .{ .@"struct" = field_vals },
+ };
},
.error_set_decl => {
const pl_node = data[inst_index].pl_node;
@@ -1122,7 +1174,10 @@ fn walkInstruction(
},
});
- return DocData.WalkResult{ .type = type_slot_index };
+ return DocData.WalkResult{
+ .typeRef = .{ .type = @enumToInt(Ref.type_type) },
+ .expr = .{ .type = type_slot_index },
+ };
},
.param_anytype => {
// Analysis of anytype function params happens in `.func`.
@@ -1134,9 +1189,8 @@ fn walkInstruction(
const cte_slot_index = self.comptime_exprs.items.len;
try self.comptime_exprs.append(self.arena, .{
.code = name,
- .typeRef = .{ .type = @enumToInt(DocData.DocTypeKinds.ComptimeExpr) },
});
- return DocData.WalkResult{ .comptimeExpr = cte_slot_index };
+ return DocData.WalkResult{ .expr = .{ .comptimeExpr = cte_slot_index } };
},
.param, .param_comptime => {
// See .param_anytype for more information.
@@ -1146,41 +1200,46 @@ fn walkInstruction(
const cte_slot_index = self.comptime_exprs.items.len;
try self.comptime_exprs.append(self.arena, .{
.code = name,
- .typeRef = .{ .type = @enumToInt(DocData.DocTypeKinds.ComptimeExpr) },
});
- return DocData.WalkResult{ .comptimeExpr = cte_slot_index };
+ 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);
+ 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.WalkResult, 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| {
- args[idx] = try self.walkRef(file, parent_scope, ref);
+ // 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;
}
- // TODO: see if we can ever do something better than just always
- // resolve function calls to a comptimeExpr.
const cte_slot_index = self.comptime_exprs.items.len;
try self.comptime_exprs.append(self.arena, .{
.code = "func call",
- .typeRef = .{
- .type = @enumToInt(DocData.DocTypeKinds.ComptimeExpr),
- }, // TODO: extract return type from callee when available
});
const call_slot_index = self.calls.items.len;
try self.calls.append(self.arena, .{
- .func = callee,
+ .func = callee.expr,
.args = args,
.ret = .{ .comptimeExpr = cte_slot_index },
});
- return DocData.WalkResult{ .call = call_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;
@@ -1208,42 +1267,13 @@ fn walkInstruction(
},
.opaque_decl => return self.cteTodo("opaque {...}"),
- // .func => {
- // const type_slot_index = self.types.items.len;
- // try self.types.append(self.arena, .{ .Unanalyzed = {} });
- //
- // const result = try self.analyzeFunction(
- // file,
- // parent_scope,
- // inst_index,
- // self_ast_node_index,
- // type_slot_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 result;
- // },
.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 = {} };
+ const value: DocData.WalkResult = if (small.has_init) .{ .expr = .{ .void = {} } } else .{ .expr = .{ .void = {} } };
return value;
},
@@ -1322,10 +1352,9 @@ fn walkInstruction(
extra_index,
);
- // const body = file.zir.extra[extra_index..][0..body_len];
extra_index += body_len;
- var field_type_refs = try std.ArrayListUnmanaged(DocData.WalkResult).initCapacity(
+ var field_type_refs = try std.ArrayListUnmanaged(DocData.Expr).initCapacity(
self.arena,
fields_len,
);
@@ -1369,7 +1398,10 @@ fn walkInstruction(
// anyway, but maybe we should put it elsewhere.
}
- return DocData.WalkResult{ .type = type_slot_index };
+ return DocData.WalkResult{
+ .typeRef = .{ .type = @enumToInt(Ref.type_type) },
+ .expr = .{ .type = type_slot_index },
+ };
},
.enum_decl => {
const type_slot_index = self.types.items.len;
@@ -1516,8 +1548,10 @@ fn walkInstruction(
// decl paths. not doing it now since it's arena-allocated
// anyway, but maybe we should put it elsewhere.
}
-
- return DocData.WalkResult{ .type = type_slot_index };
+ return DocData.WalkResult{
+ .typeRef = .{ .type = @enumToInt(Ref.type_type) },
+ .expr = .{ .type = type_slot_index },
+ };
},
.struct_decl => {
const type_slot_index = self.types.items.len;
@@ -1590,7 +1624,7 @@ fn walkInstruction(
// const body = file.zir.extra[extra_index..][0..body_len];
extra_index += body_len;
- var field_type_refs: std.ArrayListUnmanaged(DocData.WalkResult) = .{};
+ var field_type_refs: std.ArrayListUnmanaged(DocData.Expr) = .{};
var field_name_indexes: std.ArrayListUnmanaged(usize) = .{};
try self.collectStructFieldInfo(
file,
@@ -1626,11 +1660,16 @@ fn walkInstruction(
// decl paths. not doing it now since it's arena-allocated
// anyway, but maybe we should put it elsewhere.
}
-
- return DocData.WalkResult{ .type = type_slot_index };
+ return DocData.WalkResult{
+ .typeRef = .{ .type = @enumToInt(Ref.type_type) },
+ .expr = .{ .type = type_slot_index },
+ };
},
.this => {
- return DocData.WalkResult{ .this = parent_scope.enclosing_type };
+ return DocData.WalkResult{
+ .typeRef = .{ .type = @enumToInt(Ref.type_type) },
+ .expr = .{ .this = parent_scope.enclosing_type },
+ };
},
}
},
@@ -1793,7 +1832,7 @@ fn walkDecls(
.name = "test",
.isTest = true,
.src = ast_node_index,
- .value = .{ .type = 0 },
+ .value = .{ .expr = .{ .type = 0 } },
.kind = "const",
};
continue;
@@ -1827,9 +1866,9 @@ fn walkDecls(
};
const walk_result = if (is_test) // TODO: decide if tests should show up at all
- DocData.WalkResult{ .void = {} }
+ DocData.WalkResult{ .expr = .{ .void = {} } }
else
- try self.walkInstruction(file, scope, value_index);
+ try self.walkInstruction(file, scope, value_index, true);
if (is_pub) {
try decl_indexes.append(self.arena, decls_slot_index);
@@ -1857,7 +1896,7 @@ fn walkDecls(
.name = name,
.isTest = is_test,
.src = ast_node_index,
- // .typeRef = decl_type_ref,
+ //.typeRef = decl_type_ref,
.value = walk_result,
.kind = "const", // find where this information can be found
};
@@ -1906,7 +1945,7 @@ fn tryResolveRefPath(
/// File from which the decl path originates.
file: *File,
inst_index: usize, // used only for panicWithContext
- path: []DocData.WalkResult,
+ path: []DocData.Expr,
) error{OutOfMemory}!void {
var i: usize = 0;
outer: while (i < path.len - 1) : (i += 1) {
@@ -1922,7 +1961,7 @@ fn tryResolveRefPath(
.declRef => |decl_index| {
const decl = self.decls.items[decl_index];
if (decl._analyzed) {
- resolved_parent = decl.value;
+ resolved_parent = decl.value.expr;
continue;
}
@@ -2004,7 +2043,7 @@ fn tryResolveRefPath(
"TODO: handle `{s}`in tryResolveRefPath\nInfo: {}",
.{ @tagName(resolved_parent), resolved_parent },
);
- path[i + 1] = try self.cteTodo("match failure");
+ path[i + 1] = (try self.cteTodo("match failure")).expr;
continue :outer;
},
.comptimeExpr, .call => {
@@ -2088,7 +2127,7 @@ fn tryResolveRefPath(
.{child_string},
);
- path[i + 1] = try self.cteTodo("match failure");
+ path[i + 1] = (try self.cteTodo("match failure")).expr;
continue :outer;
},
.Union => |t_union| {
@@ -2134,7 +2173,7 @@ fn tryResolveRefPath(
"failed to match `{s}` in union",
.{child_string},
);
- path[i + 1] = try self.cteTodo("match failure");
+ path[i + 1] = (try self.cteTodo("match failure")).expr;
continue :outer;
},
@@ -2181,7 +2220,7 @@ fn tryResolveRefPath(
"failed to match `{s}` in struct",
.{child_string},
);
- path[i + 1] = try self.cteTodo("match failure");
+ path[i + 1] = (try self.cteTodo("match failure")).expr;
continue :outer;
},
},
@@ -2214,7 +2253,7 @@ fn analyzeFunction(
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.WalkResult).initCapacity(
+ var param_type_refs = try std.ArrayListUnmanaged(DocData.Expr).initCapacity(
self.arena,
fn_info.total_params_len,
);
@@ -2246,7 +2285,7 @@ fn analyzeFunction(
});
param_type_refs.appendAssumeCapacity(
- DocData.WalkResult{ .@"anytype" = {} },
+ DocData.Expr{ .@"anytype" = {} },
);
},
.param, .param_comptime => {
@@ -2267,9 +2306,9 @@ fn analyzeFunction(
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);
+ const param_type_ref = try self.walkRef(file, scope, break_operand, false);
- param_type_refs.appendAssumeCapacity(param_type_ref);
+ param_type_refs.appendAssumeCapacity(param_type_ref.expr);
},
}
}
@@ -2278,7 +2317,7 @@ fn analyzeFunction(
const ret_type_ref = 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);
+ const wr = try self.walkRef(file, scope, break_operand, false);
break :blk wr;
};
@@ -2288,10 +2327,13 @@ fn analyzeFunction(
.name = "todo_name func",
.src = self_ast_node_index,
.params = param_type_refs.items,
- .ret = ret_type_ref,
+ .ret = ret_type_ref.expr,
},
};
- return DocData.WalkResult{ .type = type_slot_index };
+ return DocData.WalkResult{
+ .typeRef = .{ .type = @enumToInt(Ref.type_type) },
+ .expr = .{ .type = type_slot_index },
+ };
}
fn collectUnionFieldInfo(
@@ -2299,7 +2341,7 @@ fn collectUnionFieldInfo(
file: *File,
scope: *Scope,
fields_len: usize,
- field_type_refs: *std.ArrayListUnmanaged(DocData.WalkResult),
+ field_type_refs: *std.ArrayListUnmanaged(DocData.Expr),
field_name_indexes: *std.ArrayListUnmanaged(usize),
ei: usize,
) !void {
@@ -2344,8 +2386,8 @@ fn collectUnionFieldInfo(
// type
{
- const walk_result = try self.walkRef(file, scope, field_type);
- try field_type_refs.append(self.arena, walk_result);
+ const walk_result = try self.walkRef(file, scope, field_type, false);
+ try field_type_refs.append(self.arena, walk_result.expr);
}
// ast node
@@ -2368,7 +2410,7 @@ fn collectStructFieldInfo(
file: *File,
scope: *Scope,
fields_len: usize,
- field_type_refs: *std.ArrayListUnmanaged(DocData.WalkResult),
+ field_type_refs: *std.ArrayListUnmanaged(DocData.Expr),
field_name_indexes: *std.ArrayListUnmanaged(usize),
ei: usize,
) !void {
@@ -2410,8 +2452,8 @@ fn collectStructFieldInfo(
// type
{
- const walk_result = try self.walkRef(file, scope, field_type);
- try field_type_refs.append(self.arena, walk_result);
+ const walk_result = try self.walkRef(file, scope, field_type, false);
+ try field_type_refs.append(self.arena, walk_result.expr);
}
// ast node
@@ -2436,13 +2478,17 @@ fn walkRef(
file: *File,
parent_scope: *Scope,
ref: Ref,
+ need_type: bool, // true when the caller needs also a typeRef for the return value
) !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{ .type = enum_value };
+ 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 => {
@@ -2451,69 +2497,62 @@ fn walkRef(
});
},
.undef => {
- var t = try self.arena.create(DocData.WalkResult);
- t.* = .void;
-
- return DocData.WalkResult{ .@"undefined" = t };
+ return DocData.WalkResult{ .expr = .@"undefined" };
},
.zero => {
- var t = try self.arena.create(DocData.WalkResult);
- t.* = .{ .type = @enumToInt(Ref.comptime_int_type) };
- return DocData.WalkResult{ .int = .{
- .typeRef = t,
- .value = 0,
- } };
+ return DocData.WalkResult{
+ .typeRef = .{ .type = @enumToInt(Ref.comptime_int_type) },
+ .expr = .{ .int = .{ .value = 0 } },
+ };
},
.one => {
- var t = try self.arena.create(DocData.WalkResult);
- t.* = .{ .type = @enumToInt(Ref.comptime_int_type) };
- return DocData.WalkResult{ .int = .{
- .typeRef = t,
- .value = 1,
- } };
+ return DocData.WalkResult{
+ .typeRef = .{ .type = @enumToInt(Ref.comptime_int_type) },
+ .expr = .{ .int = .{ .value = 1 } },
+ };
},
.void_value => {
- return DocData.WalkResult{ .void = {} };
+ return DocData.WalkResult{
+ .typeRef = .{ .type = @enumToInt(Ref.void_type) },
+ .expr = .{ .void = {} },
+ };
},
.unreachable_value => {
- return DocData.WalkResult{ .@"unreachable" = {} };
+ return DocData.WalkResult{
+ .typeRef = .{ .type = @enumToInt(Ref.noreturn_type) },
+ .expr = .{ .@"unreachable" = {} },
+ };
},
.null_value => {
- var t = try self.arena.create(DocData.WalkResult);
- t.* = .void;
- return DocData.WalkResult{ .@"null" = t };
+ return DocData.WalkResult{ .expr = .@"null" };
},
.bool_true => {
- return DocData.WalkResult{ .bool = true };
+ return DocData.WalkResult{
+ .typeRef = .{ .type = @enumToInt(Ref.bool_type) },
+ .expr = .{ .bool = true },
+ };
},
.bool_false => {
- return DocData.WalkResult{ .bool = false };
+ return DocData.WalkResult{
+ .typeRef = .{ .type = @enumToInt(Ref.bool_type) },
+ .expr = .{ .bool = false },
+ };
},
.empty_struct => {
- var t = try self.arena.create(DocData.WalkResult);
- t.* = .void;
-
- return DocData.WalkResult{ .@"struct" = .{
- .typeRef = t,
- .fieldVals = &.{},
- } };
+ return DocData.WalkResult{ .expr = .{ .@"struct" = &.{} } };
},
.zero_usize => {
- var t = try self.arena.create(DocData.WalkResult);
- t.* = .{ .type = @enumToInt(Ref.usize_type) };
- return DocData.WalkResult{ .int = .{
- .typeRef = t,
- .value = 0,
- } };
+ return DocData.WalkResult{
+ .typeRef = .{ .type = @enumToInt(Ref.usize_type) },
+ .expr = .{ .int = .{ .value = 0 } },
+ };
},
.one_usize => {
- var t = try self.arena.create(DocData.WalkResult);
- t.* = .{ .type = @enumToInt(Ref.usize_type) };
- return DocData.WalkResult{ .int = .{
- .typeRef = t,
- .value = 1,
- } };
+ return DocData.WalkResult{
+ .typeRef = .{ .type = @enumToInt(Ref.usize_type) },
+ .expr = .{ .int = .{ .value = 1 } },
+ };
},
// TODO: dunno what to do with those
// .calling_convention_c => {
@@ -2537,29 +2576,10 @@ fn walkRef(
}
} else {
const zir_index = enum_value - Ref.typed_value_map.len;
- return self.walkInstruction(file, parent_scope, zir_index);
+ return self.walkInstruction(file, parent_scope, zir_index, need_type);
}
}
-/// Given a WalkResult, tries to find its type.
-/// Used to analyze instructions like `array_init`, which require us to
-/// inspect its first element to find out the array type.
-fn typeOfWalkResult(self: *Autodoc, wr: DocData.WalkResult) !DocData.WalkResult {
- return switch (wr) {
- else => {
- std.debug.print(
- "TODO: handle `{s}` in typeOfWalkResult\n",
- .{@tagName(wr)},
- );
- return self.cteTodo(@tagName(wr));
- },
- .type => .{ .type = @enumToInt(DocData.DocTypeKinds.Type) },
- .int => |v| v.typeRef.*,
- .float => |v| v.typeRef.*,
- .array => |v| v.typeRef.*,
- };
-}
-
fn getBlockInlineBreak(zir: Zir, inst_index: usize) Zir.Inst.Ref {
const tags = zir.instructions.items(.tag);
const data = zir.instructions.items(.data);
@@ -2585,7 +2605,6 @@ fn cteTodo(self: *Autodoc, msg: []const u8) error{OutOfMemory}!DocData.WalkResul
const cte_slot_index = self.comptime_exprs.items.len;
try self.comptime_exprs.append(self.arena, .{
.code = msg,
- .typeRef = .{ .type = @enumToInt(DocData.DocTypeKinds.ComptimeExpr) },
});
- return DocData.WalkResult{ .comptimeExpr = cte_slot_index };
+ return DocData.WalkResult{ .expr = .{ .comptimeExpr = cte_slot_index } };
}