From 413cfd4066c547ec1cf3c7b81b0ca34e9eddb82a Mon Sep 17 00:00:00 2001 From: Loris Cro Date: Mon, 30 May 2022 21:48:46 +0200 Subject: [PATCH] autodoc: init generic function support --- lib/docs/main.js | 35 ++++++++++++++++++++++++++-------- src/Autodoc.zig | 49 +++++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 73 insertions(+), 11 deletions(-) diff --git a/lib/docs/main.js b/lib/docs/main.js index 520457c3d11daf2be1aeabe5f04d6e8ba357dbf6..d37dea52004e0f1d178ecb51681caa31e711f9a3 100644 --- a/lib/docs/main.js +++ b/lib/docs/main.js @@ -724,7 +724,7 @@ var zigAnalysis; if (typeObj.kind !== typeKinds.Fn) { return false; } - return /** @type {Fn} */(typeObj).generic; + return /** @type {Fn} */(typeObj).generic_ret != null; } /** @param {Decl} fnDecl */ @@ -772,7 +772,26 @@ var zigAnalysis; let protoSrcIndex = fnDecl.src; if (typeIsGenericFn(value.expr.type)) { - throw "TODO"; + // does the generic_ret contain a container? + var resolvedGenericRet = resolveValue({expr: typeObj.generic_ret}); + // TODO: see if unwrapping the `as` here is a good idea or not. + if ("as" in resolvedGenericRet.expr) { + resolvedGenericRet = { + expr: zigAnalysis.exprs[resolvedGenericRet.expr.as.exprArg] + }; + } + + if (!("type" in resolvedGenericRet.expr)) return; + const genericType = zigAnalysis.types[resolvedGenericRet.expr.type]; + if (isContainerType(genericType)) { + renderContainer(genericType) + } + + + + + + // old code // let instantiations = nodesToFnsMap[protoSrcIndex]; // let calls = nodesToCallsMap[protoSrcIndex]; // if (instantiations == null && calls == null) { @@ -1530,7 +1549,7 @@ var zigAnalysis; return html; } } - + case typeKinds.ErrorUnion: { let errUnionObj = /** @type {ErrUnionType} */(typeObj); @@ -1614,7 +1633,7 @@ var zigAnalysis; if (isVarArgs && i === fnObj.params.length - 1) { payloadHtml += '...'; - } + } else if ("typeOf" in value) { if (opts.wantHtml) { payloadHtml += ''; @@ -1626,7 +1645,7 @@ var zigAnalysis; payloadHtml += exprName(value, opts); } - } + } else if ("typeOf_peer" in value) { if (opts.wantHtml) { payloadHtml += ''; @@ -1638,7 +1657,7 @@ var zigAnalysis; payloadHtml += exprName(value, opts); } - } + } else if ("declRef" in value) { if (opts.wantHtml) { payloadHtml += ''; @@ -1650,7 +1669,7 @@ var zigAnalysis; payloadHtml += exprName(value, opts); } - } + } else if ("call" in value) { if (opts.wantHtml) { payloadHtml += ''; @@ -1661,7 +1680,7 @@ var zigAnalysis; } else { payloadHtml += exprName(value, opts); } - } + } else if ("refPath" in value) { if (opts.wantHtml) { payloadHtml += ''; diff --git a/src/Autodoc.zig b/src/Autodoc.zig index 44234d31db616b1e85aae816eaf74c71278529a9..9ff2010bf652cf86d86cdd35e2440b3be58ac0d5 100644 --- a/src/Autodoc.zig +++ b/src/Autodoc.zig @@ -476,8 +476,9 @@ const DocData = struct { }, Fn: struct { name: []const u8, - src: ?usize = null, // index into astNodes + src: ?usize = null, // index into `astNodes` ret: Expr, + generic_ret: ?Expr = null, params: ?[]Expr = null, // (use src->fields to find names) lib_name: []const u8 = "", is_var_args: bool = false, @@ -522,7 +523,6 @@ const DocData = struct { .ComptimeFloat => |v| try printTypeBody(v, options, w), .Null => |v| try printTypeBody(v, options, w), .Optional => |v| try printTypeBody(v, options, w), - .Struct => |v| try printTypeBody(v, options, w), .Fn => |v| try printTypeBody(v, options, w), .Union => |v| try printTypeBody(v, options, w), @@ -886,6 +886,10 @@ fn walkInstruction( ); return self.cteTodo(@tagName(tags[inst_index])); }, + .ret_node => { + const un_node = data[inst_index].un_node; + return self.walkRef(file, parent_scope, un_node.operand, false); + }, .closure_get => { const inst_node = data[inst_index].inst_node; return try self.walkInstruction(file, parent_scope, inst_node.inst, need_type); @@ -3882,7 +3886,20 @@ fn analyzeFunctionExtended( } self.types.items[type_slot_index] = .{ - .Fn = .{ .name = "todo_name func", .src = self_ast_node_index, .params = param_type_refs.items, .ret = ret_type_ref.expr, .is_extern = extra.data.bits.is_extern, .has_cc = extra.data.bits.has_cc, .has_align = extra.data.bits.has_align, .has_lib_name = extra.data.bits.has_lib_name, .lib_name = lib_name, .is_inferred_error = extra.data.bits.is_inferred_error, .cc = cc_index, .@"align" = align_index }, + .Fn = .{ + .name = "todo_name func", + .src = self_ast_node_index, + .params = param_type_refs.items, + .ret = ret_type_ref.expr, + .is_extern = extra.data.bits.is_extern, + .has_cc = extra.data.bits.has_cc, + .has_align = extra.data.bits.has_align, + .has_lib_name = extra.data.bits.has_lib_name, + .lib_name = lib_name, + .is_inferred_error = extra.data.bits.is_inferred_error, + .cc = cc_index, + .@"align" = align_index, + }, }; return DocData.WalkResult{ @@ -3974,6 +3991,21 @@ fn analyzeFunction( break :blk wr; }; + // TODO: a complete version of this will probably need a scope + // in order to evaluate correctly closures around funcion + // parameters etc. + const generic_ret: ?DocData.Expr = switch (ret_type_ref.expr) { + .type => |t| if (t == @enumToInt(Ref.type_type)) + try self.getGenericReturnType( + file, + scope, + fn_info.body[fn_info.body.len - 1], + ) + else + null, + else => null, + }; + self.ast_nodes.items[self_ast_node_index].fields = param_ast_indexes.items; self.types.items[type_slot_index] = .{ .Fn = .{ @@ -3981,6 +4013,7 @@ fn analyzeFunction( .src = self_ast_node_index, .params = param_type_refs.items, .ret = ret_type_ref.expr, + .generic_ret = generic_ret, }, }; @@ -3990,6 +4023,16 @@ fn analyzeFunction( }; } +fn getGenericReturnType( + self: *Autodoc, + file: *File, + scope: *Scope, + body_end: usize, +) !DocData.Expr { + const wr = try self.walkInstruction(file, scope, body_end, false); + return wr.expr; +} + fn collectUnionFieldInfo( self: *Autodoc, file: *File, -- 2.54.0