| ... | @@ -210,7 +210,7 @@ const DocData = struct { | ... | @@ -210,7 +210,7 @@ const DocData = struct { |
| 210 | name: []const u8, | 210 | name: []const u8, |
| 211 | kind: []const u8, // TODO: where do we find this info? | 211 | kind: []const u8, // TODO: where do we find this info? |
| 212 | src: usize, // index into astNodes | 212 | src: usize, // index into astNodes |
| 213 | type: usize, // index into types | 213 | // typeRef: TypeRef, |
| 214 | value: WalkResult, | 214 | value: WalkResult, |
| 215 | }; | 215 | }; |
| 216 | | 216 | |
| ... | @@ -231,28 +231,65 @@ const DocData = struct { | ... | @@ -231,28 +231,65 @@ const DocData = struct { |
| 231 | pubDecls: ?[]usize = null, // index into decls | 231 | pubDecls: ?[]usize = null, // index into decls |
| 232 | fields: ?[]WalkResult = null, // (use src->fields to find names) | 232 | fields: ?[]WalkResult = null, // (use src->fields to find names) |
| 233 | }; | 233 | }; |
| | 234 | const TypeRef = union(enum) { |
| | 235 | unspecified, |
| | 236 | declRef: usize, // index in `decls` |
| | 237 | type: usize, // index in `types` |
| | 238 | pub fn jsonStringify( |
| | 239 | self: TypeRef, |
| | 240 | _: std.json.StringifyOptions, |
| | 241 | w: anytype, |
| | 242 | ) !void { |
| | 243 | switch (self) { |
| | 244 | .unspecified => { |
| | 245 | try w.print( |
| | 246 | \\{{ "unspecified":{{}} }} |
| | 247 | , .{}); |
| | 248 | }, |
| | 249 | .declRef, .type => |v| { |
| | 250 | try w.print( |
| | 251 | \\{{ "{s}":{} }} |
| | 252 | , .{ @tagName(self), v }); |
| | 253 | }, |
| | 254 | } |
| | 255 | } |
| | 256 | }; |
| 234 | | 257 | |
| 235 | const WalkResult = union(enum) { | 258 | const WalkResult = union(enum) { |
| 236 | failure: bool, | 259 | void, |
| | 260 | @"unreachable", |
| | 261 | @"null": TypeRef, |
| | 262 | @"undefined": TypeRef, |
| | 263 | @"struct": struct { |
| | 264 | typeRef: TypeRef, |
| | 265 | fieldVals: []struct { |
| | 266 | name: []const u8, |
| | 267 | val: WalkResult, |
| | 268 | }, |
| | 269 | }, |
| | 270 | bool: bool, |
| 237 | type: usize, // index in `types` | 271 | type: usize, // index in `types` |
| 238 | decl_ref: usize, // index in `decls` | 272 | declRef: usize, // index in `decls` |
| 239 | int: struct { | 273 | int: struct { |
| 240 | type: usize, // index in `types` | 274 | typeRef: TypeRef, |
| 241 | value: usize, // direct value | 275 | value: usize, // direct value |
| 242 | negated: bool = false, | 276 | negated: bool = false, |
| 243 | }, | 277 | }, |
| | 278 | |
| 244 | pub fn jsonStringify( | 279 | pub fn jsonStringify( |
| 245 | self: WalkResult, | 280 | self: WalkResult, |
| 246 | _: std.json.StringifyOptions, | 281 | options: std.json.StringifyOptions, |
| 247 | w: anytype, | 282 | w: anytype, |
| 248 | ) !void { | 283 | ) !void { |
| 249 | switch (self) { | 284 | switch (self) { |
| 250 | .failure => |v| { | 285 | .void, |
| | 286 | .@"unreachable", |
| | 287 | => { |
| 251 | try w.print( | 288 | try w.print( |
| 252 | \\{{ "failure":{} }} | 289 | \\{{ "{s}":{{}} }} |
| 253 | , .{v}); | 290 | , .{@tagName(self)}); |
| 254 | }, | 291 | }, |
| 255 | .type, .decl_ref => |v| { | 292 | .type, .declRef => |v| { |
| 256 | try w.print( | 293 | try w.print( |
| 257 | \\{{ "{s}":{} }} | 294 | \\{{ "{s}":{} }} |
| 258 | , .{ @tagName(self), v }); | 295 | , .{ @tagName(self), v }); |
| ... | @@ -260,10 +297,21 @@ const DocData = struct { | ... | @@ -260,10 +297,21 @@ const DocData = struct { |
| 260 | .int => |v| { | 297 | .int => |v| { |
| 261 | const neg = if (v.negated) "-" else ""; | 298 | const neg = if (v.negated) "-" else ""; |
| 262 | try w.print( | 299 | try w.print( |
| 263 | \\{{ "int": {{ "type": {}, "value": {s}{} }} }} | 300 | \\{{ "int": {{ "typeRef": |
| 264 | , .{ v.type, neg, v.value }); | 301 | , .{}); |
| | 302 | try v.typeRef.jsonStringify(options, w); |
| | 303 | try w.print( |
| | 304 | \\, "value": {s}{} }} }} |
| | 305 | , .{ neg, v.value }); |
| 265 | }, | 306 | }, |
| 266 | | 307 | .bool => |v| { |
| | 308 | try w.print( |
| | 309 | \\{{ "bool":{} }} |
| | 310 | , .{v}); |
| | 311 | }, |
| | 312 | .@"undefined" => |v| try std.json.stringify(v, options, w), |
| | 313 | .@"null" => |v| try std.json.stringify(v, options, w), |
| | 314 | .@"struct" => |v| try std.json.stringify(v, options, w), |
| 267 | // .decl_ref => |v| { | 315 | // .decl_ref => |v| { |
| 268 | // try w.print( | 316 | // try w.print( |
| 269 | // \\{{ "{s}":"{s}" }} | 317 | // \\{{ "{s}":"{s}" }} |
| ... | @@ -288,17 +336,16 @@ fn walkInstruction( | ... | @@ -288,17 +336,16 @@ fn walkInstruction( |
| 288 | | 336 | |
| 289 | switch (tags[inst_index]) { | 337 | switch (tags[inst_index]) { |
| 290 | else => { | 338 | else => { |
| 291 | std.debug.print( | 339 | std.debug.panic( |
| 292 | "TODO: implement `walkInstruction` for {s}\n\n", | 340 | "TODO: implement `walkInstruction` for {s}\n\n", |
| 293 | .{@tagName(tags[inst_index])}, | 341 | .{@tagName(tags[inst_index])}, |
| 294 | ); | 342 | ); |
| 295 | return DocData.WalkResult{ .failure = true }; | | |
| 296 | }, | 343 | }, |
| 297 | .int => { | 344 | .int => { |
| 298 | const int = data[inst_index].int; | 345 | const int = data[inst_index].int; |
| 299 | return DocData.WalkResult{ | 346 | return DocData.WalkResult{ |
| 300 | .int = .{ | 347 | .int = .{ |
| 301 | .type = @enumToInt(Ref.comptime_int_type), | 348 | .typeRef = .{ .type = @enumToInt(Ref.comptime_int_type) }, |
| 302 | .value = int, | 349 | .value = int, |
| 303 | }, | 350 | }, |
| 304 | }; | 351 | }; |
| ... | @@ -313,16 +360,34 @@ fn walkInstruction( | ... | @@ -313,16 +360,34 @@ fn walkInstruction( |
| 313 | const pl_node = data[inst_index].pl_node; | 360 | const pl_node = data[inst_index].pl_node; |
| 314 | const extra = zir.extraData(Zir.Inst.As, pl_node.payload_index); | 361 | const extra = zir.extraData(Zir.Inst.As, pl_node.payload_index); |
| 315 | const dest_type_walk = try self.walkRef(zir, parent_scope, extra.data.dest_type); | 362 | const dest_type_walk = try self.walkRef(zir, parent_scope, extra.data.dest_type); |
| 316 | const dest_type = dest_type_walk.type; // asserts that we got a type | 363 | const dest_type_ref = walkResultToTypeRef(dest_type_walk); |
| 317 | | 364 | |
| 318 | var operand = try self.walkRef(zir, parent_scope, extra.data.operand); | 365 | var operand = try self.walkRef(zir, parent_scope, extra.data.operand); |
| 319 | operand.int.type = dest_type; // only support ints for now | 366 | |
| | 367 | switch (operand) { |
| | 368 | else => std.debug.panic( |
| | 369 | "TODO: handle {s} in `walkInstruction.as_node`\n", |
| | 370 | .{@tagName(operand)}, |
| | 371 | ), |
| | 372 | .declRef => {}, |
| | 373 | // we don't do anything because up until now, |
| | 374 | // I've only seen this used as such: |
| | 375 | // @as(@as(type, Baz), .{}) |
| | 376 | // and we don't want to toss away the |
| | 377 | // decl_val information (eg by replacing it with |
| | 378 | // a WalkResult.type). |
| | 379 | |
| | 380 | .int => operand.int.typeRef = dest_type_ref, |
| | 381 | .@"struct" => operand.@"struct".typeRef = dest_type_ref, |
| | 382 | .@"undefined" => operand.@"undefined" = dest_type_ref, |
| | 383 | } |
| | 384 | |
| 320 | return operand; | 385 | return operand; |
| 321 | }, | 386 | }, |
| 322 | .decl_val => { | 387 | .decl_val => { |
| 323 | const str_tok = data[inst_index].str_tok; | 388 | const str_tok = data[inst_index].str_tok; |
| 324 | const decls_slot_index = parent_scope.resolveDeclName(str_tok.start); | 389 | const decls_slot_index = parent_scope.resolveDeclName(str_tok.start); |
| 325 | return DocData.WalkResult{ .decl_ref = decls_slot_index }; | 390 | return DocData.WalkResult{ .declRef = decls_slot_index }; |
| 326 | }, | 391 | }, |
| 327 | .int_type => { | 392 | .int_type => { |
| 328 | const int_type = data[inst_index].int_type; | 393 | const int_type = data[inst_index].int_type; |
| ... | @@ -348,23 +413,16 @@ fn walkInstruction( | ... | @@ -348,23 +413,16 @@ fn walkInstruction( |
| 348 | }); | 413 | }); |
| 349 | | 414 | |
| 350 | const break_operand = data[break_index].@"break".operand; | 415 | const break_operand = data[break_index].@"break".operand; |
| 351 | return if (Zir.refToIndex(break_operand)) |bi| | 416 | return self.walkRef(zir, parent_scope, break_operand); |
| 352 | self.walkInstruction(zir, parent_scope, bi) | | |
| 353 | else if (@enumToInt(break_operand) <= @enumToInt(Ref.anyerror_void_error_union_type)) | | |
| 354 | // we append all the types in ref first, so we can just do this if we encounter a ref that is a type | | |
| 355 | return DocData.WalkResult{ .type = @enumToInt(break_operand) } | | |
| 356 | else | | |
| 357 | std.debug.todo("generate WalkResults for refs that are not types"); | | |
| 358 | }, | 417 | }, |
| 359 | .extended => { | 418 | .extended => { |
| 360 | const extended = data[inst_index].extended; | 419 | const extended = data[inst_index].extended; |
| 361 | switch (extended.opcode) { | 420 | switch (extended.opcode) { |
| 362 | else => { | 421 | else => { |
| 363 | std.debug.print( | 422 | std.debug.panic( |
| 364 | "TODO: implement `walkInstruction` (inside .extended case) for {s}\n\n", | 423 | "TODO: implement `walkInstruction` (inside .extended case) for {s}\n\n", |
| 365 | .{@tagName(extended.opcode)}, | 424 | .{@tagName(extended.opcode)}, |
| 366 | ); | 425 | ); |
| 367 | return DocData.WalkResult{ .failure = true }; | | |
| 368 | }, | 426 | }, |
| 369 | .struct_decl => { | 427 | .struct_decl => { |
| 370 | var scope: Scope = .{ .parent = parent_scope }; | 428 | var scope: Scope = .{ .parent = parent_scope }; |
| ... | @@ -457,6 +515,13 @@ fn walkInstruction( | ... | @@ -457,6 +515,13 @@ fn walkInstruction( |
| 457 | } | 515 | } |
| 458 | } | 516 | } |
| 459 | | 517 | |
| | 518 | /// Called by `walkInstruction` when encountering a container type, |
| | 519 | /// iterates over all decl definitions in its body. |
| | 520 | /// It also analyzes each decl's body recursively. |
| | 521 | /// |
| | 522 | /// Does not append to `self.decls` directly because `walkInstruction` |
| | 523 | /// is expected to (look-ahead) scan all decls and reserve `body_len` |
| | 524 | /// slots in `self.decls`, which are then filled out by `walkDecls`. |
| 460 | fn walkDecls( | 525 | fn walkDecls( |
| 461 | self: *Autodoc, | 526 | self: *Autodoc, |
| 462 | zir: Zir, | 527 | zir: Zir, |
| ... | @@ -562,15 +627,25 @@ fn walkDecls( | ... | @@ -562,15 +627,25 @@ fn walkDecls( |
| 562 | try priv_decl_indexes.append(self.arena, decls_slot_index); | 627 | try priv_decl_indexes.append(self.arena, decls_slot_index); |
| 563 | } | 628 | } |
| 564 | | 629 | |
| 565 | const decl_type = switch (walk_result) { | 630 | // // decl.typeRef == decl.val...typeRef |
| 566 | .int => |i| i.type, | 631 | // const decl_type_ref: DocData.TypeRef = switch (walk_result) { |
| 567 | else => @enumToInt(Ref.type_type), | 632 | // .int => |i| i.typeRef, |
| 568 | }; | 633 | // .void => .{ .type = @enumToInt(Ref.void_type) }, |
| | 634 | // .@"undefined", .@"null" => |v| v, |
| | 635 | // .@"unreachable" => .{ .type = @enumToInt(Ref.noreturn_type) }, |
| | 636 | // .@"struct" => |s| s.typeRef, |
| | 637 | // .bool => .{ .type = @enumToInt(Ref.bool_type) }, |
| | 638 | // .type => .{ .type = @enumToInt(Ref.type_type) }, |
| | 639 | // // this last case is special becauese it's not pointing |
| | 640 | // // at the type of the value, but rather at the value itself |
| | 641 | // // the js better be aware ot this! |
| | 642 | // .declRef => |d| .{ .declRef = d }, |
| | 643 | // }; |
| 569 | | 644 | |
| 570 | self.decls.items[decls_slot_index] = .{ | 645 | self.decls.items[decls_slot_index] = .{ |
| 571 | .name = name, | 646 | .name = name, |
| 572 | .src = ast_node_index, | 647 | .src = ast_node_index, |
| 573 | .type = decl_type, | 648 | // .typeRef = decl_type_ref, |
| 574 | .value = walk_result, | 649 | .value = walk_result, |
| 575 | .kind = "const", // find where this information can be found | 650 | .kind = "const", // find where this information can be found |
| 576 | }; | 651 | }; |
| ... | @@ -649,11 +724,101 @@ fn walkRef( | ... | @@ -649,11 +724,101 @@ fn walkRef( |
| 649 | ref: Ref, | 724 | ref: Ref, |
| 650 | ) !DocData.WalkResult { | 725 | ) !DocData.WalkResult { |
| 651 | const enum_value = @enumToInt(ref); | 726 | const enum_value = @enumToInt(ref); |
| 652 | if (enum_value < Zir.Inst.Ref.typed_value_map.len) { | 727 | if (enum_value <= @enumToInt(Ref.anyerror_void_error_union_type)) { |
| 653 | // TODO: well... Refs are not all types | 728 | // We can just return a type that indexes into `types` with the |
| | 729 | // enum value because in the beginning we pre-filled `types` with |
| | 730 | // the types that are listed in `Ref`. |
| 654 | return DocData.WalkResult{ .type = enum_value }; | 731 | return DocData.WalkResult{ .type = enum_value }; |
| | 732 | } else if (enum_value < Ref.typed_value_map.len) { |
| | 733 | switch (ref) { |
| | 734 | else => { |
| | 735 | std.debug.panic("TODO: handle {s} in `walkRef`\n", .{ |
| | 736 | @tagName(ref), |
| | 737 | }); |
| | 738 | }, |
| | 739 | .undef => { |
| | 740 | return DocData.WalkResult{ .@"undefined" = .unspecified }; |
| | 741 | }, |
| | 742 | .zero => { |
| | 743 | return DocData.WalkResult{ .int = .{ |
| | 744 | .typeRef = .{ .type = @enumToInt(Ref.comptime_int_type) }, |
| | 745 | .value = 0, |
| | 746 | } }; |
| | 747 | }, |
| | 748 | .one => { |
| | 749 | return DocData.WalkResult{ .int = .{ |
| | 750 | .typeRef = .{ .type = @enumToInt(Ref.comptime_int_type) }, |
| | 751 | .value = 1, |
| | 752 | } }; |
| | 753 | }, |
| | 754 | |
| | 755 | .void_value => { |
| | 756 | return DocData.WalkResult{ .void = {} }; |
| | 757 | }, |
| | 758 | .unreachable_value => { |
| | 759 | return DocData.WalkResult{ .@"unreachable" = {} }; |
| | 760 | }, |
| | 761 | .null_value => { |
| | 762 | return DocData.WalkResult{ .@"null" = .unspecified }; |
| | 763 | }, |
| | 764 | .bool_true => { |
| | 765 | return DocData.WalkResult{ .bool = true }; |
| | 766 | }, |
| | 767 | .bool_false => { |
| | 768 | return DocData.WalkResult{ .bool = false }; |
| | 769 | }, |
| | 770 | .empty_struct => { |
| | 771 | return DocData.WalkResult{ .@"struct" = .{ |
| | 772 | .typeRef = .unspecified, |
| | 773 | .fieldVals = &.{}, |
| | 774 | } }; |
| | 775 | }, |
| | 776 | .zero_usize => { |
| | 777 | return DocData.WalkResult{ .int = .{ |
| | 778 | .typeRef = .{ .type = @enumToInt(Ref.usize_type) }, |
| | 779 | .value = 0, |
| | 780 | } }; |
| | 781 | }, |
| | 782 | .one_usize => { |
| | 783 | return DocData.WalkResult{ .int = .{ |
| | 784 | .typeRef = .{ .type = @enumToInt(Ref.usize_type) }, |
| | 785 | .value = 1, |
| | 786 | } }; |
| | 787 | }, |
| | 788 | // TODO: dunno what to do with those |
| | 789 | // .calling_convention_c => { |
| | 790 | // return DocData.WalkResult{ .int = .{ |
| | 791 | // .type = @enumToInt(Ref.comptime_int_type), |
| | 792 | // .value = 1, |
| | 793 | // } }; |
| | 794 | // }, |
| | 795 | // .calling_convention_inline => { |
| | 796 | // return DocData.WalkResult{ .int = .{ |
| | 797 | // .type = @enumToInt(Ref.comptime_int_type), |
| | 798 | // .value = 1, |
| | 799 | // } }; |
| | 800 | // }, |
| | 801 | // .generic_poison => { |
| | 802 | // return DocData.WalkResult{ .int = .{ |
| | 803 | // .type = @enumToInt(Ref.comptime_int_type), |
| | 804 | // .value = 1, |
| | 805 | // } }; |
| | 806 | // }, |
| | 807 | } |
| 655 | } else { | 808 | } else { |
| 656 | const zir_index = enum_value - Ref.typed_value_map.len; | 809 | const zir_index = enum_value - Ref.typed_value_map.len; |
| 657 | return self.walkInstruction(zir, parent_scope, zir_index); | 810 | return self.walkInstruction(zir, parent_scope, zir_index); |
| 658 | } | 811 | } |
| 659 | } | 812 | } |
| | 813 | |
| | 814 | fn walkResultToTypeRef(wr: DocData.WalkResult) DocData.TypeRef { |
| | 815 | return switch (wr) { |
| | 816 | else => std.debug.panic( |
| | 817 | "TODO: handle `{s}` in `walkInstruction.as_node.dest_type`\n", |
| | 818 | .{@tagName(wr)}, |
| | 819 | ), |
| | 820 | |
| | 821 | .declRef => |v| .{ .declRef = v }, |
| | 822 | .type => |v| .{ .type = v }, |
| | 823 | }; |
| | 824 | } |