| author | |
| committer | |
| log | 1014cfdf3b60faf9af5b062d198f4f44976cb1bc |
| tree | cfa5bff2c520b70c510e3a6ca44b35588417be38 |
| parent | 47dfaf3d175ebea63b169a373b4dec4af6af7001 |
| signature |
See #34066 files changed, 527 insertions(+), 85 deletions(-)
lib/std/hash_map.zig+2-1| ... | ... | @@ -36,7 +36,8 @@ pub fn HashMap(comptime K: type, comptime V: type, comptime hash: fn (key: K) u3 |
| 36 | 36 | size: usize, |
| 37 | 37 | max_distance_from_start_index: usize, |
| 38 | 38 | allocator: *Allocator, |
| 39 | // this is used to detect bugs where a hashtable is edited while an iterator is running. | |
| 39 | ||
| 40 | /// This is used to detect bugs where a hashtable is edited while an iterator is running. | |
| 40 | 41 | modification_count: debug_u32, |
| 41 | 42 | |
| 42 | 43 | const Self = @This(); |
lib/std/meta.zig+10| ... | ... | @@ -542,3 +542,13 @@ pub fn intToEnum(comptime Tag: type, tag_int: var) IntToEnumError!Tag { |
| 542 | 542 | } |
| 543 | 543 | return error.InvalidEnumTag; |
| 544 | 544 | } |
| 545 | ||
| 546 | /// Given a type and a name, return the field index according to source order. | |
| 547 | /// Returns `null` if the field is not found. | |
| 548 | pub fn fieldIndex(comptime T: type, comptime name: []const u8) ?comptime_int { | |
| 549 | inline for (fields(T)) |field, i| { | |
| 550 | if (mem.eql(u8, field.name, name)) | |
| 551 | return comptime_int(i); | |
| 552 | } | |
| 553 | return null; | |
| 554 | } |
lib/std/special/docs/index.html+14-1| ... | ... | @@ -104,6 +104,16 @@ |
| 104 | 104 | background-color: #FFBB4D; |
| 105 | 105 | color: #000; |
| 106 | 106 | } |
| 107 | #listFnExamples { | |
| 108 | list-style-type: none; | |
| 109 | margin: 0; | |
| 110 | padding: 0; | |
| 111 | } | |
| 112 | #listFnExamples li { | |
| 113 | padding: 0.5em 0; | |
| 114 | white-space: nowrap; | |
| 115 | overflow-x: auto; | |
| 116 | } | |
| 107 | 117 | #logo { |
| 108 | 118 | width: 8em; |
| 109 | 119 | padding: 0.5em 1em; |
| ... | ... | @@ -289,7 +299,6 @@ |
| 289 | 299 | <pre id="fnProtoCode"></pre> |
| 290 | 300 | </div> |
| 291 | 301 | <h1 id="hdrName" class="hidden"></h1> |
| 292 | <div id="fnExamples" class="hidden"></div> | |
| 293 | 302 | <div id="fnNoExamples" class="hidden"> |
| 294 | 303 | <p>This function is not tested or referenced.</p> |
| 295 | 304 | </div> |
| ... | ... | @@ -357,6 +366,10 @@ |
| 357 | 366 | <ul id="listErrSets"> |
| 358 | 367 | </ul> |
| 359 | 368 | </div> |
| 369 | <div id="fnExamples" class="hidden"> | |
| 370 | <h2>Examples</h2> | |
| 371 | <ul id="listFnExamples"></ul> | |
| 372 | </div> | |
| 360 | 373 | </section> |
| 361 | 374 | <div id="helpDialog" class="hidden"> |
| 362 | 375 | <h1>Keyboard Shortcuts</h1> |
lib/std/special/docs/main.js+230-19| ... | ... | @@ -26,6 +26,7 @@ |
| 26 | 26 | var domTableFnErrors = document.getElementById("tableFnErrors"); |
| 27 | 27 | var domFnErrorsAnyError = document.getElementById("fnErrorsAnyError"); |
| 28 | 28 | var domFnExamples = document.getElementById("fnExamples"); |
| 29 | var domListFnExamples = document.getElementById("listFnExamples"); | |
| 29 | 30 | var domFnNoExamples = document.getElementById("fnNoExamples"); |
| 30 | 31 | var domDeclNoRef = document.getElementById("declNoRef"); |
| 31 | 32 | var domSearch = document.getElementById("search"); |
| ... | ... | @@ -64,6 +65,9 @@ |
| 64 | 65 | declNames: [], |
| 65 | 66 | // these will be all types, except the last one may be a type or a decl |
| 66 | 67 | declObjs: [], |
| 68 | ||
| 69 | // (a, b, c, d) comptime call; result is the value the docs refer to | |
| 70 | callName: null, | |
| 67 | 71 | }; |
| 68 | 72 | var curNavSearch = ""; |
| 69 | 73 | var curSearchIndex = -1; |
| ... | ... | @@ -237,20 +241,29 @@ |
| 237 | 241 | renderErrorSet(errSetType); |
| 238 | 242 | } |
| 239 | 243 | |
| 240 | var protoSrcIndex; | |
| 244 | var fnObj = zigAnalysis.fns[fnDecl.value]; | |
| 245 | var protoSrcIndex = fnObj.src; | |
| 241 | 246 | if (typeIsGenericFn(fnDecl.type)) { |
| 242 | protoSrcIndex = fnDecl.value; | |
| 243 | ||
| 244 | 247 | var instantiations = nodesToFnsMap[protoSrcIndex]; |
| 245 | 248 | var calls = nodesToCallsMap[protoSrcIndex]; |
| 246 | 249 | if (instantiations == null && calls == null) { |
| 247 | 250 | domFnNoExamples.classList.remove("hidden"); |
| 248 | } else { | |
| 249 | // TODO show examples | |
| 251 | } else if (calls != null) { | |
| 252 | if (fnObj.combined === undefined) fnObj.combined = allCompTimeFnCallsResult(calls); | |
| 253 | if (fnObj.combined != null) renderContainer(fnObj.combined); | |
| 254 | ||
| 255 | resizeDomList(domListFnExamples, calls.length, '<li></li>'); | |
| 256 | ||
| 257 | for (var callI = 0; callI < calls.length; callI += 1) { | |
| 258 | var liDom = domListFnExamples.children[callI]; | |
| 259 | liDom.innerHTML = getCallHtml(fnDecl, calls[callI]); | |
| 260 | } | |
| 261 | ||
| 250 | 262 | domFnExamples.classList.remove("hidden"); |
| 263 | } else if (instantiations != null) { | |
| 264 | // TODO | |
| 251 | 265 | } |
| 252 | 266 | } else { |
| 253 | protoSrcIndex = zigAnalysis.fns[fnDecl.value].src; | |
| 254 | 267 | |
| 255 | 268 | domFnExamples.classList.add("hidden"); |
| 256 | 269 | domFnNoExamples.classList.add("hidden"); |
| ... | ... | @@ -349,13 +362,15 @@ |
| 349 | 362 | } |
| 350 | 363 | } |
| 351 | 364 | |
| 352 | function navLink(pkgNames, declNames) { | |
| 365 | function navLink(pkgNames, declNames, callName) { | |
| 353 | 366 | if (pkgNames.length === 0 && declNames.length === 0) { |
| 354 | 367 | return '#'; |
| 355 | } else if (declNames.length === 0) { | |
| 368 | } else if (declNames.length === 0 && callName == null) { | |
| 356 | 369 | return '#' + pkgNames.join('.'); |
| 357 | } else { | |
| 370 | } else if (callName == null) { | |
| 358 | 371 | return '#' + pkgNames.join('.') + ';' + declNames.join('.'); |
| 372 | } else { | |
| 373 | return '#' + pkgNames.join('.') + ';' + declNames.join('.') + ';' + callName; | |
| 359 | 374 | } |
| 360 | 375 | } |
| 361 | 376 | |
| ... | ... | @@ -367,6 +382,22 @@ |
| 367 | 382 | return navLink(curNav.pkgNames, curNav.declNames.concat([childName])); |
| 368 | 383 | } |
| 369 | 384 | |
| 385 | function navLinkCall(callObj) { | |
| 386 | var declNamesCopy = curNav.declNames.concat([]); | |
| 387 | var callName = declNamesCopy.pop(); | |
| 388 | ||
| 389 | callName += '('; | |
| 390 | for (var arg_i = 0; arg_i < callObj.args.length; arg_i += 1) { | |
| 391 | if (arg_i !== 0) callName += ','; | |
| 392 | var argObj = callObj.args[arg_i]; | |
| 393 | callName += getValueText(argObj.type, argObj.value, false, false); | |
| 394 | } | |
| 395 | callName += ')'; | |
| 396 | ||
| 397 | declNamesCopy.push(callName); | |
| 398 | return navLink(curNav.pkgNames, declNamesCopy); | |
| 399 | } | |
| 400 | ||
| 370 | 401 | function resizeDomListDl(dlDom, desiredLen) { |
| 371 | 402 | // add the missing dom entries |
| 372 | 403 | var i, ev; |
| ... | ... | @@ -426,6 +457,40 @@ |
| 426 | 457 | return (typeObj.len == null) ? pointerSizeEnum.One : typeObj.len; |
| 427 | 458 | } |
| 428 | 459 | |
| 460 | function getCallHtml(fnDecl, callIndex) { | |
| 461 | var callObj = zigAnalysis.calls[callIndex]; | |
| 462 | ||
| 463 | // TODO make these links work | |
| 464 | //var html = '<a href="' + navLinkCall(callObj) + '">' + escapeHtml(fnDecl.name) + '</a>('; | |
| 465 | var html = escapeHtml(fnDecl.name) + '('; | |
| 466 | for (var arg_i = 0; arg_i < callObj.args.length; arg_i += 1) { | |
| 467 | if (arg_i !== 0) html += ', '; | |
| 468 | var argObj = callObj.args[arg_i]; | |
| 469 | html += getValueText(argObj.type, argObj.value, true, true); | |
| 470 | } | |
| 471 | html += ')'; | |
| 472 | return html; | |
| 473 | } | |
| 474 | ||
| 475 | function getValueText(typeIndex, value, wantHtml, wantLink) { | |
| 476 | var typeObj = zigAnalysis.types[typeIndex]; | |
| 477 | switch (typeObj.kind) { | |
| 478 | case typeKinds.Type: | |
| 479 | return typeIndexName(value, wantHtml, wantLink); | |
| 480 | case typeKinds.Fn: | |
| 481 | var fnObj = zigAnalysis.fns[value]; | |
| 482 | return typeIndexName(fnObj.type, wantHtml, wantLink); | |
| 483 | case typeKinds.Int: | |
| 484 | if (wantHtml) { | |
| 485 | return '<span class="tok-number">' + value + '</span>'; | |
| 486 | } else { | |
| 487 | return value + ""; | |
| 488 | } | |
| 489 | default: | |
| 490 | throw new Error("TODO implement getValueText for this type"); | |
| 491 | } | |
| 492 | } | |
| 493 | ||
| 429 | 494 | function typeName(typeObj, wantHtml, wantSubLink, fnDecl, linkFnNameDecl) { |
| 430 | 495 | switch (typeObj.kind) { |
| 431 | 496 | case typeKinds.Array: |
| ... | ... | @@ -544,6 +609,12 @@ |
| 544 | 609 | } else { |
| 545 | 610 | return "void"; |
| 546 | 611 | } |
| 612 | case typeKinds.EnumLiteral: | |
| 613 | if (wantHtml) { | |
| 614 | return '<span class="tok-type">(enum literal)</span>'; | |
| 615 | } else { | |
| 616 | return "(enum literal)"; | |
| 617 | } | |
| 547 | 618 | case typeKinds.NoReturn: |
| 548 | 619 | if (wantHtml) { |
| 549 | 620 | return '<span class="tok-type">noreturn</span>'; |
| ... | ... | @@ -592,6 +663,15 @@ |
| 592 | 663 | } |
| 593 | 664 | payloadHtml += '('; |
| 594 | 665 | if (typeObj.args != null) { |
| 666 | var fields = null; | |
| 667 | var isVarArgs = false; | |
| 668 | if (fnDecl != null) { | |
| 669 | var fnObj = zigAnalysis.fns[fnDecl.value]; | |
| 670 | var fnNode = zigAnalysis.astNodes[fnObj.src]; | |
| 671 | fields = fnNode.fields; | |
| 672 | isVarArgs = fnNode.varArgs; | |
| 673 | } | |
| 674 | ||
| 595 | 675 | for (var i = 0; i < typeObj.args.length; i += 1) { |
| 596 | 676 | if (i != 0) { |
| 597 | 677 | payloadHtml += ', '; |
| ... | ... | @@ -599,10 +679,31 @@ |
| 599 | 679 | |
| 600 | 680 | var argTypeIndex = typeObj.args[i]; |
| 601 | 681 | |
| 602 | if (fnDecl != null && zigAnalysis.astNodes[fnDecl.src].fields != null) { | |
| 603 | var paramDeclIndex = zigAnalysis.astNodes[fnDecl.src].fields[i]; | |
| 604 | var paramName = zigAnalysis.astNodes[paramDeclIndex].name; | |
| 682 | if (fields != null) { | |
| 683 | var paramNode = zigAnalysis.astNodes[fields[i]]; | |
| 684 | ||
| 685 | if (paramNode.varArgs) { | |
| 686 | payloadHtml += '...'; | |
| 687 | continue; | |
| 688 | } | |
| 689 | ||
| 690 | if (paramNode.noalias) { | |
| 691 | if (wantHtml) { | |
| 692 | payloadHtml += '<span class="tok-kw">noalias</span> '; | |
| 693 | } else { | |
| 694 | payloadHtml += 'noalias '; | |
| 695 | } | |
| 696 | } | |
| 697 | ||
| 698 | if (paramNode.comptime) { | |
| 699 | if (wantHtml) { | |
| 700 | payloadHtml += '<span class="tok-kw">comptime</span> '; | |
| 701 | } else { | |
| 702 | payloadHtml += 'comptime '; | |
| 703 | } | |
| 704 | } | |
| 605 | 705 | |
| 706 | var paramName = paramNode.name; | |
| 606 | 707 | if (paramName != null) { |
| 607 | 708 | // skip if it matches the type name |
| 608 | 709 | if (argTypeIndex == null || !shouldSkipParamName(argTypeIndex, paramName)) { |
| ... | ... | @@ -611,7 +712,9 @@ |
| 611 | 712 | } |
| 612 | 713 | } |
| 613 | 714 | |
| 614 | if (argTypeIndex != null) { | |
| 715 | if (isVarArgs && i === typeObj.args.length - 1) { | |
| 716 | payloadHtml += '...'; | |
| 717 | } else if (argTypeIndex != null) { | |
| 615 | 718 | payloadHtml += typeIndexName(argTypeIndex, wantHtml, wantSubLink); |
| 616 | 719 | } else if (wantHtml) { |
| 617 | 720 | payloadHtml += '<span class="tok-kw">var</span>'; |
| ... | ... | @@ -690,7 +793,7 @@ |
| 690 | 793 | } |
| 691 | 794 | |
| 692 | 795 | function allCompTimeFnCallsHaveTypeResult(typeIndex, value) { |
| 693 | var srcIndex = typeIsGenericFn(typeIndex) ? value : zigAnalysis.fns[value].src; | |
| 796 | var srcIndex = zigAnalysis.fns[value].src; | |
| 694 | 797 | var calls = nodesToCallsMap[srcIndex]; |
| 695 | 798 | if (calls == null) return false; |
| 696 | 799 | for (var i = 0; i < calls.length; i += 1) { |
| ... | ... | @@ -700,6 +803,90 @@ |
| 700 | 803 | return true; |
| 701 | 804 | } |
| 702 | 805 | |
| 806 | function allCompTimeFnCallsResult(calls) { | |
| 807 | var firstTypeObj = null; | |
| 808 | var containerObj = { | |
| 809 | privDecls: [], | |
| 810 | }; | |
| 811 | for (var callI = 0; callI < calls.length; callI += 1) { | |
| 812 | var call = zigAnalysis.calls[calls[callI]]; | |
| 813 | if (call.result.type !== typeTypeId) return null; | |
| 814 | var typeObj = zigAnalysis.types[call.result.value]; | |
| 815 | if (!typeKindIsContainer(typeObj.kind)) return null; | |
| 816 | if (firstTypeObj == null) { | |
| 817 | firstTypeObj = typeObj; | |
| 818 | containerObj.src = typeObj.src; | |
| 819 | } else if (firstTypeObj.src !== typeObj.src) { | |
| 820 | return null; | |
| 821 | } | |
| 822 | ||
| 823 | if (containerObj.fields == null) { | |
| 824 | containerObj.fields = (typeObj.fields || []).concat([]); | |
| 825 | } else for (var fieldI = 0; fieldI < typeObj.fields.length; fieldI += 1) { | |
| 826 | var prev = containerObj.fields[fieldI]; | |
| 827 | var next = typeObj.fields[fieldI]; | |
| 828 | if (prev === next) continue; | |
| 829 | if (typeof(prev) === 'object') { | |
| 830 | if (prev[next] == null) prev[next] = typeObj; | |
| 831 | } else { | |
| 832 | containerObj.fields[fieldI] = {}; | |
| 833 | containerObj.fields[fieldI][prev] = firstTypeObj; | |
| 834 | containerObj.fields[fieldI][next] = typeObj; | |
| 835 | } | |
| 836 | } | |
| 837 | ||
| 838 | if (containerObj.pubDecls == null) { | |
| 839 | containerObj.pubDecls = (typeObj.pubDecls || []).concat([]); | |
| 840 | } else for (var declI = 0; declI < typeObj.pubDecls.length; declI += 1) { | |
| 841 | var prev = containerObj.pubDecls[declI]; | |
| 842 | var next = typeObj.pubDecls[declI]; | |
| 843 | if (prev === next) continue; | |
| 844 | // TODO instead of showing "examples" as the public declarations, | |
| 845 | // do logic like this: | |
| 846 | //if (typeof(prev) !== 'object') { | |
| 847 | // var newDeclId = zigAnalysis.decls.length; | |
| 848 | // prev = clone(zigAnalysis.decls[prev]); | |
| 849 | // prev.id = newDeclId; | |
| 850 | // zigAnalysis.decls.push(prev); | |
| 851 | // containerObj.pubDecls[declI] = prev; | |
| 852 | //} | |
| 853 | //mergeDecls(prev, next, firstTypeObj, typeObj); | |
| 854 | } | |
| 855 | } | |
| 856 | for (var declI = 0; declI < containerObj.pubDecls.length; declI += 1) { | |
| 857 | var decl = containerObj.pubDecls[declI]; | |
| 858 | if (typeof(decl) === 'object') { | |
| 859 | containerObj.pubDecls[declI] = containerObj.pubDecls[declI].id; | |
| 860 | } | |
| 861 | } | |
| 862 | return containerObj; | |
| 863 | } | |
| 864 | ||
| 865 | function mergeDecls(declObj, nextDeclIndex, firstTypeObj, typeObj) { | |
| 866 | var nextDeclObj = zigAnalysis.decls[nextDeclIndex]; | |
| 867 | if (declObj.type != null && nextDeclObj.type != null && declObj.type !== nextDeclObj.type) { | |
| 868 | if (typeof(declObj.type) !== 'object') { | |
| 869 | var prevType = declObj.type; | |
| 870 | declObj.type = {}; | |
| 871 | declObj.type[prevType] = firstTypeObj; | |
| 872 | declObj.value = null; | |
| 873 | } | |
| 874 | declObj.type[nextDeclObj.type] = typeObj; | |
| 875 | } else if (declObj.type == null && nextDeclObj != null) { | |
| 876 | declObj.type = nextDeclObj.type; | |
| 877 | } | |
| 878 | if (declObj.value != null && nextDeclObj.value != null && declObj.value !== nextDeclObj.value) { | |
| 879 | if (typeof(declObj.value) !== 'object') { | |
| 880 | var prevValue = declObj.value; | |
| 881 | declObj.value = {}; | |
| 882 | declObj.value[prevValue] = firstTypeObj; | |
| 883 | } | |
| 884 | declObj.value[nextDeclObj.value] = typeObj; | |
| 885 | } else if (declObj.value == null && nextDeclObj.value != null) { | |
| 886 | declObj.value = nextDeclObj.value; | |
| 887 | } | |
| 888 | } | |
| 889 | ||
| 703 | 890 | function renderValue(decl) { |
| 704 | 891 | domFnProtoCode.innerHTML = '<span class="tok-kw">const</span> ' + |
| 705 | 892 | escapeHtml(decl.name) + ': ' + typeIndexName(decl.type, true, true); |
| ... | ... | @@ -733,13 +920,15 @@ |
| 733 | 920 | var fnsList = []; |
| 734 | 921 | var varsList = []; |
| 735 | 922 | var valsList = []; |
| 923 | ||
| 736 | 924 | for (var i = 0; i < container.pubDecls.length; i += 1) { |
| 737 | 925 | var decl = zigAnalysis.decls[container.pubDecls[i]]; |
| 926 | ||
| 738 | 927 | if (decl.kind === 'var') { |
| 739 | 928 | varsList.push(decl); |
| 740 | 929 | continue; |
| 741 | 930 | } else if (decl.kind === 'const' && decl.type != null) { |
| 742 | if (decl.type == typeTypeId) { | |
| 931 | if (decl.type === typeTypeId) { | |
| 743 | 932 | if (typeIsErrSet(decl.value)) { |
| 744 | 933 | errSetsList.push(decl); |
| 745 | 934 | } else if (typeIsStructWithNoFields(decl.value)) { |
| ... | ... | @@ -838,7 +1027,12 @@ |
| 838 | 1027 | if (container.kind === typeKinds.Enum) { |
| 839 | 1028 | html += ' = <span class="tok-number">' + field + '</span>'; |
| 840 | 1029 | } else { |
| 841 | html += ": " + typeIndexName(field, true, true); | |
| 1030 | html += ": "; | |
| 1031 | if (typeof(field) === 'object') { | |
| 1032 | html += '<span class="tok-kw">var</span>'; | |
| 1033 | } else { | |
| 1034 | html += typeIndexName(field, true, true); | |
| 1035 | } | |
| 842 | 1036 | } |
| 843 | 1037 | |
| 844 | 1038 | html += ',</pre>'; |
| ... | ... | @@ -1042,13 +1236,16 @@ |
| 1042 | 1236 | return list; |
| 1043 | 1237 | } |
| 1044 | 1238 | |
| 1045 | function declCanRepresentTypeKind(typeKind) { | |
| 1046 | return typeKind === typeKinds.ErrorSet || | |
| 1047 | typeKind === typeKinds.Struct || | |
| 1239 | function typeKindIsContainer(typeKind) { | |
| 1240 | return typeKind === typeKinds.Struct || | |
| 1048 | 1241 | typeKind === typeKinds.Union || |
| 1049 | 1242 | typeKind === typeKinds.Enum; |
| 1050 | 1243 | } |
| 1051 | 1244 | |
| 1245 | function declCanRepresentTypeKind(typeKind) { | |
| 1246 | return typeKind === typeKinds.ErrorSet || typeKindIsContainer(typeKind); | |
| 1247 | } | |
| 1248 | ||
| 1052 | 1249 | function computeCanonDeclPaths() { |
| 1053 | 1250 | var list = new Array(zigAnalysis.decls.length); |
| 1054 | 1251 | canonTypeDecls = new Array(zigAnalysis.types.length); |
| ... | ... | @@ -1406,4 +1603,18 @@ |
| 1406 | 1603 | function byNameProperty(a, b) { |
| 1407 | 1604 | return operatorCompare(a.name, b.name); |
| 1408 | 1605 | } |
| 1606 | ||
| 1607 | function clone(obj) { | |
| 1608 | var res = {}; | |
| 1609 | for (var key in obj) { | |
| 1610 | res[key] = obj[key]; | |
| 1611 | } | |
| 1612 | return res; | |
| 1613 | } | |
| 1614 | ||
| 1615 | function firstObjectKey(obj) { | |
| 1616 | for (var key in obj) { | |
| 1617 | return key; | |
| 1618 | } | |
| 1619 | } | |
| 1409 | 1620 | })(); |
src/dump_analysis.cpp+98-64| ... | ... | @@ -456,6 +456,10 @@ static uint32_t anal_dump_get_fn_id(AnalDumpCtx *ctx, ZigFn *fn) { |
| 456 | 456 | auto existing_entry = ctx->fn_map.put_unique(fn, fn_id); |
| 457 | 457 | if (existing_entry == nullptr) { |
| 458 | 458 | ctx->fn_list.append(fn); |
| 459 | ||
| 460 | // poke the fn | |
| 461 | (void)anal_dump_get_type_id(ctx, fn->type_entry); | |
| 462 | (void)anal_dump_get_node_id(ctx, fn->proto_node); | |
| 459 | 463 | } else { |
| 460 | 464 | fn_id = existing_entry->value; |
| 461 | 465 | } |
| ... | ... | @@ -700,11 +704,7 @@ static void anal_dump_value(AnalDumpCtx *ctx, AstNode *source_node, ZigType *ty, |
| 700 | 704 | case ZigTypeIdFn: { |
| 701 | 705 | if (value->data.x_ptr.special == ConstPtrSpecialFunction) { |
| 702 | 706 | ZigFn *val_fn = value->data.x_ptr.data.fn.fn_entry; |
| 703 | if (val_fn->type_entry->data.fn.is_generic) { | |
| 704 | anal_dump_node_ref(ctx, val_fn->proto_node); | |
| 705 | } else { | |
| 706 | anal_dump_fn_ref(ctx, val_fn); | |
| 707 | } | |
| 707 | anal_dump_fn_ref(ctx, val_fn); | |
| 708 | 708 | } else { |
| 709 | 709 | jw_null(&ctx->jw); |
| 710 | 710 | } |
| ... | ... | @@ -758,6 +758,7 @@ static void anal_dump_type(AnalDumpCtx *ctx, ZigType *ty) { |
| 758 | 758 | switch (ty->id) { |
| 759 | 759 | case ZigTypeIdMetaType: |
| 760 | 760 | case ZigTypeIdBool: |
| 761 | case ZigTypeIdEnumLiteral: | |
| 761 | 762 | break; |
| 762 | 763 | case ZigTypeIdStruct: { |
| 763 | 764 | if (ty->data.structure.is_slice) { |
| ... | ... | @@ -1072,13 +1073,25 @@ static void anal_dump_node(AnalDumpCtx *ctx, const AstNode *node) { |
| 1072 | 1073 | jw_object_field(jw, "col"); |
| 1073 | 1074 | jw_int(jw, node->column); |
| 1074 | 1075 | |
| 1075 | const Buf *doc_comments_buf; | |
| 1076 | const Buf *doc_comments_buf = nullptr; | |
| 1077 | const Buf *name_buf = nullptr; | |
| 1078 | const ZigList<AstNode *> *field_nodes = nullptr; | |
| 1079 | bool is_var_args = false; | |
| 1080 | bool is_noalias = false; | |
| 1081 | bool is_comptime = false; | |
| 1082 | ||
| 1076 | 1083 | switch (node->type) { |
| 1077 | 1084 | case NodeTypeParamDecl: |
| 1078 | 1085 | doc_comments_buf = &node->data.param_decl.doc_comments; |
| 1086 | name_buf = node->data.param_decl.name; | |
| 1087 | is_var_args = node->data.param_decl.is_var_args; | |
| 1088 | is_noalias = node->data.param_decl.is_noalias; | |
| 1089 | is_comptime = node->data.param_decl.is_comptime; | |
| 1079 | 1090 | break; |
| 1080 | 1091 | case NodeTypeFnProto: |
| 1081 | 1092 | doc_comments_buf = &node->data.fn_proto.doc_comments; |
| 1093 | field_nodes = &node->data.fn_proto.params; | |
| 1094 | is_var_args = node->data.fn_proto.is_var_args; | |
| 1082 | 1095 | break; |
| 1083 | 1096 | case NodeTypeVariableDeclaration: |
| 1084 | 1097 | doc_comments_buf = &node->data.variable_declaration.doc_comments; |
| ... | ... | @@ -1088,55 +1101,50 @@ static void anal_dump_node(AnalDumpCtx *ctx, const AstNode *node) { |
| 1088 | 1101 | break; |
| 1089 | 1102 | case NodeTypeStructField: |
| 1090 | 1103 | doc_comments_buf = &node->data.struct_field.doc_comments; |
| 1104 | name_buf = node->data.struct_field.name; | |
| 1105 | break; | |
| 1106 | case NodeTypeContainerDecl: | |
| 1107 | field_nodes = &node->data.container_decl.fields; | |
| 1091 | 1108 | break; |
| 1092 | 1109 | default: |
| 1093 | doc_comments_buf = nullptr; | |
| 1094 | 1110 | break; |
| 1095 | 1111 | } |
| 1112 | ||
| 1096 | 1113 | if (doc_comments_buf != nullptr && doc_comments_buf->list.length != 0) { |
| 1097 | 1114 | jw_object_field(jw, "docs"); |
| 1098 | 1115 | jw_string(jw, buf_ptr(doc_comments_buf)); |
| 1099 | 1116 | } |
| 1100 | 1117 | |
| 1101 | const Buf *name_buf; | |
| 1102 | switch (node->type) { | |
| 1103 | case NodeTypeStructField: | |
| 1104 | name_buf = node->data.struct_field.name; | |
| 1105 | break; | |
| 1106 | case NodeTypeParamDecl: | |
| 1107 | name_buf = node->data.param_decl.name; | |
| 1108 | break; | |
| 1109 | default: | |
| 1110 | name_buf = nullptr; | |
| 1111 | break; | |
| 1112 | } | |
| 1113 | 1118 | if (name_buf != nullptr) { |
| 1114 | 1119 | jw_object_field(jw, "name"); |
| 1115 | 1120 | jw_string(jw, buf_ptr(name_buf)); |
| 1116 | 1121 | } |
| 1117 | 1122 | |
| 1118 | const ZigList<AstNode *> *fieldNodes; | |
| 1119 | switch (node->type) { | |
| 1120 | case NodeTypeContainerDecl: | |
| 1121 | fieldNodes = &node->data.container_decl.fields; | |
| 1122 | break; | |
| 1123 | case NodeTypeFnProto: | |
| 1124 | fieldNodes = &node->data.fn_proto.params; | |
| 1125 | break; | |
| 1126 | default: | |
| 1127 | fieldNodes = nullptr; | |
| 1128 | break; | |
| 1129 | } | |
| 1130 | if (fieldNodes != nullptr) { | |
| 1123 | if (field_nodes != nullptr) { | |
| 1131 | 1124 | jw_object_field(jw, "fields"); |
| 1132 | 1125 | jw_begin_array(jw); |
| 1133 | for (size_t i = 0; i < fieldNodes->length; i += 1) { | |
| 1126 | for (size_t i = 0; i < field_nodes->length; i += 1) { | |
| 1134 | 1127 | jw_array_elem(jw); |
| 1135 | anal_dump_node_ref(ctx, fieldNodes->at(i)); | |
| 1128 | anal_dump_node_ref(ctx, field_nodes->at(i)); | |
| 1136 | 1129 | } |
| 1137 | 1130 | jw_end_array(jw); |
| 1138 | 1131 | } |
| 1139 | 1132 | |
| 1133 | if (is_var_args) { | |
| 1134 | jw_object_field(jw, "varArgs"); | |
| 1135 | jw_bool(jw, true); | |
| 1136 | } | |
| 1137 | ||
| 1138 | if (is_comptime) { | |
| 1139 | jw_object_field(jw, "comptime"); | |
| 1140 | jw_bool(jw, true); | |
| 1141 | } | |
| 1142 | ||
| 1143 | if (is_noalias) { | |
| 1144 | jw_object_field(jw, "noalias"); | |
| 1145 | jw_bool(jw, true); | |
| 1146 | } | |
| 1147 | ||
| 1140 | 1148 | jw_end_object(jw); |
| 1141 | 1149 | } |
| 1142 | 1150 | |
| ... | ... | @@ -1235,59 +1243,76 @@ void zig_print_analysis_dump(CodeGen *g, FILE *f, const char *one_indent, const |
| 1235 | 1243 | jw_object_field(jw, "calls"); |
| 1236 | 1244 | jw_begin_array(jw); |
| 1237 | 1245 | { |
| 1246 | ZigList<ZigVar *> var_stack = {}; | |
| 1247 | ||
| 1238 | 1248 | auto it = g->memoized_fn_eval_table.entry_iterator(); |
| 1239 | 1249 | for (;;) { |
| 1240 | 1250 | auto *entry = it.next(); |
| 1241 | 1251 | if (!entry) |
| 1242 | 1252 | break; |
| 1243 | 1253 | |
| 1244 | jw_array_elem(jw); | |
| 1245 | jw_begin_object(jw); | |
| 1246 | ||
| 1247 | jw_object_field(jw, "args"); | |
| 1248 | jw_begin_object(jw); | |
| 1254 | var_stack.resize(0); | |
| 1255 | ZigFn *fn = nullptr; | |
| 1249 | 1256 | |
| 1250 | 1257 | Scope *scope = entry->key; |
| 1251 | 1258 | while (scope != nullptr) { |
| 1252 | 1259 | if (scope->id == ScopeIdVarDecl) { |
| 1253 | 1260 | ZigVar *var = reinterpret_cast<ScopeVarDecl *>(scope)->var; |
| 1254 | jw_object_field(jw, var->name); | |
| 1255 | jw_begin_object(jw); | |
| 1256 | jw_object_field(jw, "type"); | |
| 1257 | anal_dump_type_ref(&ctx, var->var_type); | |
| 1258 | jw_object_field(jw, "value"); | |
| 1259 | anal_dump_value(&ctx, scope->source_node, var->var_type, var->const_value); | |
| 1260 | jw_end_object(jw); | |
| 1261 | var_stack.append(var); | |
| 1261 | 1262 | } else if (scope->id == ScopeIdFnDef) { |
| 1262 | jw_end_object(jw); | |
| 1263 | fn = reinterpret_cast<ScopeFnDef *>(scope)->fn_entry; | |
| 1264 | break; | |
| 1265 | } | |
| 1266 | scope = scope->parent; | |
| 1267 | } | |
| 1268 | ConstExprValue *result = entry->value; | |
| 1269 | ||
| 1270 | assert(fn != nullptr); | |
| 1271 | ||
| 1272 | jw_array_elem(jw); | |
| 1273 | jw_begin_object(jw); | |
| 1274 | ||
| 1275 | jw_object_field(jw, "fn"); | |
| 1276 | anal_dump_fn_ref(&ctx, fn); | |
| 1277 | ||
| 1278 | jw_object_field(jw, "result"); | |
| 1279 | { | |
| 1280 | jw_begin_object(jw); | |
| 1281 | ||
| 1282 | jw_object_field(jw, "type"); | |
| 1283 | anal_dump_type_ref(&ctx, result->type); | |
| 1284 | ||
| 1285 | jw_object_field(jw, "value"); | |
| 1286 | anal_dump_value(&ctx, scope->source_node, result->type, result); | |
| 1287 | ||
| 1288 | jw_end_object(jw); | |
| 1289 | } | |
| 1290 | ||
| 1291 | if (var_stack.length != 0) { | |
| 1292 | jw_object_field(jw, "args"); | |
| 1293 | jw_begin_array(jw); | |
| 1263 | 1294 | |
| 1264 | jw_object_field(jw, "fn"); | |
| 1265 | ZigFn *fn = reinterpret_cast<ScopeFnDef *>(scope)->fn_entry; | |
| 1266 | anal_dump_fn_ref(&ctx, fn); | |
| 1295 | while (var_stack.length != 0) { | |
| 1296 | ZigVar *var = var_stack.pop(); | |
| 1267 | 1297 | |
| 1268 | ConstExprValue *result = entry->value; | |
| 1269 | jw_object_field(jw, "result"); | |
| 1298 | jw_array_elem(jw); | |
| 1270 | 1299 | jw_begin_object(jw); |
| 1300 | ||
| 1271 | 1301 | jw_object_field(jw, "type"); |
| 1272 | anal_dump_type_ref(&ctx, result->type); | |
| 1302 | anal_dump_type_ref(&ctx, var->var_type); | |
| 1303 | ||
| 1273 | 1304 | jw_object_field(jw, "value"); |
| 1274 | anal_dump_value(&ctx, scope->source_node, result->type, result); | |
| 1305 | anal_dump_value(&ctx, scope->source_node, var->var_type, var->const_value); | |
| 1306 | ||
| 1275 | 1307 | jw_end_object(jw); |
| 1276 | break; | |
| 1277 | 1308 | } |
| 1278 | scope = scope->parent; | |
| 1309 | jw_end_array(jw); | |
| 1279 | 1310 | } |
| 1311 | ||
| 1280 | 1312 | jw_end_object(jw); |
| 1281 | 1313 | } |
| 1282 | } | |
| 1283 | jw_end_array(jw); | |
| 1284 | 1314 | |
| 1285 | jw_object_field(jw, "fns"); | |
| 1286 | jw_begin_array(jw); | |
| 1287 | for (uint32_t i = 0; i < ctx.fn_list.length; i += 1) { | |
| 1288 | ZigFn *fn = ctx.fn_list.at(i); | |
| 1289 | jw_array_elem(jw); | |
| 1290 | anal_dump_fn(&ctx, fn); | |
| 1315 | var_stack.deinit(); | |
| 1291 | 1316 | } |
| 1292 | 1317 | jw_end_array(jw); |
| 1293 | 1318 | |
| ... | ... | @@ -1315,6 +1340,15 @@ void zig_print_analysis_dump(CodeGen *g, FILE *f, const char *one_indent, const |
| 1315 | 1340 | } |
| 1316 | 1341 | jw_end_array(jw); |
| 1317 | 1342 | |
| 1343 | jw_object_field(jw, "fns"); | |
| 1344 | jw_begin_array(jw); | |
| 1345 | for (uint32_t i = 0; i < ctx.fn_list.length; i += 1) { | |
| 1346 | ZigFn *fn = ctx.fn_list.at(i); | |
| 1347 | jw_array_elem(jw); | |
| 1348 | anal_dump_fn(&ctx, fn); | |
| 1349 | } | |
| 1350 | jw_end_array(jw); | |
| 1351 | ||
| 1318 | 1352 | jw_object_field(jw, "errors"); |
| 1319 | 1353 | jw_begin_array(jw); |
| 1320 | 1354 | for (uint32_t i = 0; i < ctx.err_list.length; i += 1) { |
tools/merge_anal_dumps.zig+173| ... | ... | @@ -2,6 +2,8 @@ const builtin = @import("builtin"); |
| 2 | 2 | const std = @import("std"); |
| 3 | 3 | const json = std.json; |
| 4 | 4 | const mem = std.mem; |
| 5 | const fieldIndex = std.meta.fieldIndex; | |
| 6 | const TypeId = builtin.TypeId; | |
| 5 | 7 | |
| 6 | 8 | pub fn main() anyerror!void { |
| 7 | 9 | var arena = std.heap.ArenaAllocator.init(std.heap.direct_allocator); |
| ... | ... | @@ -61,6 +63,81 @@ const Error = struct { |
| 61 | 63 | } |
| 62 | 64 | }; |
| 63 | 65 | |
| 66 | const simple_types = [_][]const u8{ | |
| 67 | "Type", | |
| 68 | "Void", | |
| 69 | "Bool", | |
| 70 | "NoReturn", | |
| 71 | "ComptimeFloat", | |
| 72 | "ComptimeInt", | |
| 73 | "Undefined", | |
| 74 | "Null", | |
| 75 | "AnyFrame", | |
| 76 | "EnumLiteral", | |
| 77 | }; | |
| 78 | ||
| 79 | const Type = union(builtin.TypeId) { | |
| 80 | Type, | |
| 81 | Void, | |
| 82 | Bool, | |
| 83 | NoReturn, | |
| 84 | ComptimeFloat, | |
| 85 | ComptimeInt, | |
| 86 | Undefined, | |
| 87 | Null, | |
| 88 | AnyFrame, | |
| 89 | EnumLiteral, | |
| 90 | ||
| 91 | Int: Int, | |
| 92 | Float: usize, // bits | |
| 93 | ||
| 94 | Vector: Array, | |
| 95 | Optional: usize, // payload type index | |
| 96 | Pointer: Pointer, | |
| 97 | Array: Array, | |
| 98 | ||
| 99 | Struct, // TODO | |
| 100 | ErrorUnion, // TODO | |
| 101 | ErrorSet, // TODO | |
| 102 | Enum, // TODO | |
| 103 | Union, // TODO | |
| 104 | Fn, // TODO | |
| 105 | BoundFn, // TODO | |
| 106 | ArgTuple, // TODO | |
| 107 | Opaque, // TODO | |
| 108 | Frame, // TODO | |
| 109 | ||
| 110 | const Int = struct { | |
| 111 | bits: usize, | |
| 112 | signed: bool, | |
| 113 | }; | |
| 114 | ||
| 115 | const Pointer = struct { | |
| 116 | elem: usize, | |
| 117 | alignment: usize, | |
| 118 | is_const: bool, | |
| 119 | is_volatile: bool, | |
| 120 | allow_zero: bool, | |
| 121 | host_int_bytes: usize, | |
| 122 | bit_offset_in_host: usize, | |
| 123 | }; | |
| 124 | ||
| 125 | const Array = struct { | |
| 126 | elem: usize, | |
| 127 | len: usize, | |
| 128 | }; | |
| 129 | ||
| 130 | fn hash(t: Type) u32 { | |
| 131 | var hasher = std.hash.Wyhash.init(0); | |
| 132 | std.hash.autoHash(&hasher, builtin.TypeId(t)); | |
| 133 | return @truncate(u32, hasher.final()); | |
| 134 | } | |
| 135 | ||
| 136 | fn eql(a: Type, b: Type) bool { | |
| 137 | return std.meta.eql(a, b); | |
| 138 | } | |
| 139 | }; | |
| 140 | ||
| 64 | 141 | const Dump = struct { |
| 65 | 142 | zig_id: ?[]const u8 = null, |
| 66 | 143 | zig_version: ?[]const u8 = null, |
| ... | ... | @@ -79,6 +156,10 @@ const Dump = struct { |
| 79 | 156 | error_list: std.ArrayList(Error), |
| 80 | 157 | error_map: ErrorMap, |
| 81 | 158 | |
| 159 | const TypeMap = std.HashMap(Type, usize, Type.hash, Type.eql); | |
| 160 | type_list: std.ArrayList(Type), | |
| 161 | type_map: TypeMap, | |
| 162 | ||
| 82 | 163 | fn init(allocator: *mem.Allocator) Dump { |
| 83 | 164 | return Dump{ |
| 84 | 165 | .targets = std.ArrayList([]const u8).init(allocator), |
| ... | ... | @@ -88,6 +169,8 @@ const Dump = struct { |
| 88 | 169 | .node_map = NodeMap.init(allocator), |
| 89 | 170 | .error_list = std.ArrayList(Error).init(allocator), |
| 90 | 171 | .error_map = ErrorMap.init(allocator), |
| 172 | .type_list = std.ArrayList(Type).init(allocator), | |
| 173 | .type_map = TypeMap.init(allocator), | |
| 91 | 174 | }; |
| 92 | 175 | } |
| 93 | 176 | |
| ... | ... | @@ -165,6 +248,66 @@ const Dump = struct { |
| 165 | 248 | } |
| 166 | 249 | try other_error_to_mine.putNoClobber(i, gop.kv.value); |
| 167 | 250 | } |
| 251 | ||
| 252 | // Merge types. Now it starts to get advanced. | |
| 253 | // First we identify all the simple types and merge those. | |
| 254 | // Example: void, type, noreturn | |
| 255 | // We can also do integers and floats. | |
| 256 | const other_types = root.Object.get("types").?.value.Array.toSliceConst(); | |
| 257 | var other_types_to_mine = std.AutoHashMap(usize, usize).init(self.a()); | |
| 258 | for (other_types) |other_type_json, i| { | |
| 259 | const type_kind = jsonObjInt(other_type_json, "kind"); | |
| 260 | switch (type_kind) { | |
| 261 | fieldIndex(TypeId, "Int").? => { | |
| 262 | var signed: bool = undefined; | |
| 263 | var bits: usize = undefined; | |
| 264 | if (other_type_json.Object.get("i")) |kv| { | |
| 265 | signed = true; | |
| 266 | bits = @intCast(usize, kv.value.Integer); | |
| 267 | } else if (other_type_json.Object.get("u")) |kv| { | |
| 268 | signed = false; | |
| 269 | bits = @intCast(usize, kv.value.Integer); | |
| 270 | } else { | |
| 271 | unreachable; | |
| 272 | } | |
| 273 | const other_type = Type{ | |
| 274 | .Int = Type.Int{ | |
| 275 | .bits = bits, | |
| 276 | .signed = signed, | |
| 277 | }, | |
| 278 | }; | |
| 279 | try self.mergeOtherType(other_type, i, &other_types_to_mine); | |
| 280 | }, | |
| 281 | fieldIndex(TypeId, "Float").? => { | |
| 282 | const other_type = Type{ | |
| 283 | .Float = jsonObjInt(other_type_json, "bits"), | |
| 284 | }; | |
| 285 | try self.mergeOtherType(other_type, i, &other_types_to_mine); | |
| 286 | }, | |
| 287 | else => {}, | |
| 288 | } | |
| 289 | ||
| 290 | inline for (simple_types) |simple_type_name| { | |
| 291 | if (type_kind == std.meta.fieldIndex(builtin.TypeId, simple_type_name).?) { | |
| 292 | const other_type = @unionInit(Type, simple_type_name, {}); | |
| 293 | try self.mergeOtherType(other_type, i, &other_types_to_mine); | |
| 294 | } | |
| 295 | } | |
| 296 | } | |
| 297 | } | |
| 298 | ||
| 299 | fn mergeOtherType( | |
| 300 | self: *Dump, | |
| 301 | other_type: Type, | |
| 302 | other_type_index: usize, | |
| 303 | other_types_to_mine: *std.AutoHashMap(usize, usize), | |
| 304 | ) !void { | |
| 305 | const gop = try self.type_map.getOrPut(other_type); | |
| 306 | if (!gop.found_existing) { | |
| 307 | gop.kv.value = self.type_list.len; | |
| 308 | try self.type_list.append(other_type); | |
| 309 | } | |
| 310 | try other_types_to_mine.putNoClobber(other_type_index, gop.kv.value); | |
| 168 | 311 | } |
| 169 | 312 | |
| 170 | 313 | fn render(self: *Dump, stream: var) !void { |
| ... | ... | @@ -204,6 +347,36 @@ const Dump = struct { |
| 204 | 347 | |
| 205 | 348 | try jw.endObject(); |
| 206 | 349 | |
| 350 | try jw.objectField("types"); | |
| 351 | try jw.beginArray(); | |
| 352 | for (self.type_list.toSliceConst()) |t| { | |
| 353 | try jw.arrayElem(); | |
| 354 | try jw.beginObject(); | |
| 355 | ||
| 356 | try jw.objectField("kind"); | |
| 357 | try jw.emitNumber(@enumToInt(builtin.TypeId(t))); | |
| 358 | ||
| 359 | switch (t) { | |
| 360 | .Int => |int| { | |
| 361 | if (int.signed) { | |
| 362 | try jw.objectField("i"); | |
| 363 | } else { | |
| 364 | try jw.objectField("u"); | |
| 365 | } | |
| 366 | try jw.emitNumber(int.bits); | |
| 367 | }, | |
| 368 | .Float => |bits| { | |
| 369 | try jw.objectField("bits"); | |
| 370 | try jw.emitNumber(bits); | |
| 371 | }, | |
| 372 | ||
| 373 | else => {}, | |
| 374 | } | |
| 375 | ||
| 376 | try jw.endObject(); | |
| 377 | } | |
| 378 | try jw.endArray(); | |
| 379 | ||
| 207 | 380 | try jw.objectField("errors"); |
| 208 | 381 | try jw.beginArray(); |
| 209 | 382 | for (self.error_list.toSliceConst()) |zig_error| { |