demangle 0.5.2__tar.gz → 0.7.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (327) hide show
  1. {demangle-0.5.2 → demangle-0.7.0}/.gitignore +3 -0
  2. {demangle-0.5.2 → demangle-0.7.0}/ARCHITECTURE.md +3 -1
  3. {demangle-0.5.2 → demangle-0.7.0}/CHANGELOG.md +127 -1
  4. {demangle-0.5.2 → demangle-0.7.0}/CITATION.cff +1 -1
  5. {demangle-0.5.2 → demangle-0.7.0}/CONFORMANCE.md +1 -1
  6. {demangle-0.5.2 → demangle-0.7.0}/CONTRIBUTING.md +54 -7
  7. {demangle-0.5.2 → demangle-0.7.0}/PKG-INFO +17 -2
  8. {demangle-0.5.2 → demangle-0.7.0}/README.md +16 -1
  9. {demangle-0.5.2 → demangle-0.7.0}/SECURITY.md +2 -2
  10. demangle-0.7.0/benchmarks/audit_signature.py +106 -0
  11. demangle-0.7.0/benchmarks/baseline.json +68 -0
  12. {demangle-0.5.2 → demangle-0.7.0}/benchmarks/bench.py +79 -8
  13. demangle-0.7.0/benchmarks/bench_playground_bridge.py +179 -0
  14. demangle-0.7.0/benchmarks/bench_playground_browser.py +461 -0
  15. demangle-0.7.0/benchmarks/compare.py +536 -0
  16. demangle-0.7.0/benchmarks/end_to_end.py +182 -0
  17. demangle-0.7.0/benchmarks/performance.md +156 -0
  18. demangle-0.7.0/benchmarks/results/library-after.json +184 -0
  19. demangle-0.7.0/benchmarks/results/library-before.json +184 -0
  20. demangle-0.7.0/benchmarks/results/playground-bridge-after.json +79 -0
  21. demangle-0.7.0/benchmarks/results/playground-browser-after-0.26.4.json +211 -0
  22. demangle-0.7.0/benchmarks/results/playground-browser-current-dom-cleanup.json +125 -0
  23. demangle-0.7.0/benchmarks/results/playground-browser-pristine-0.26.4.json +211 -0
  24. demangle-0.7.0/benchmarks/results/playground-browser-pristine-dom-cleanup.json +125 -0
  25. demangle-0.7.0/benchmarks/results/playground-browser-trial-0.29.3.json +211 -0
  26. demangle-0.7.0/benchmarks/results/signature-paired.json +223 -0
  27. {demangle-0.5.2 → demangle-0.7.0}/docs/adding-a-scheme.md +7 -6
  28. demangle-0.7.0/docs/comparison.md +294 -0
  29. demangle-0.7.0/docs/hooks.py +80 -0
  30. demangle-0.7.0/docs/integrations.md +372 -0
  31. demangle-0.7.0/docs/playground.md +37 -0
  32. {demangle-0.5.2 → demangle-0.7.0}/docs/reference/core.md +1 -0
  33. {demangle-0.5.2 → demangle-0.7.0}/docs/reference/schemes.md +1 -0
  34. {demangle-0.5.2 → demangle-0.7.0}/docs/testing.md +76 -2
  35. demangle-0.7.0/integrations/demangle_binja.py +210 -0
  36. demangle-0.7.0/integrations/demangle_ghidra.py +191 -0
  37. demangle-0.7.0/integrations/demangle_ida.py +210 -0
  38. demangle-0.7.0/integrations/demangle_labels.py +245 -0
  39. {demangle-0.5.2 → demangle-0.7.0}/mkdocs.yml +6 -0
  40. demangle-0.7.0/playground/README.md +62 -0
  41. demangle-0.7.0/playground/index.html +284 -0
  42. demangle-0.7.0/playground/playground-worker.js +49 -0
  43. demangle-0.7.0/playground/playground.js +773 -0
  44. demangle-0.7.0/playground/playground_bridge.py +179 -0
  45. demangle-0.7.0/playground/style.css +1030 -0
  46. {demangle-0.5.2 → demangle-0.7.0}/pyproject.toml +24 -4
  47. {demangle-0.5.2 → demangle-0.7.0}/src/demangle/__init__.py +1 -1
  48. {demangle-0.5.2 → demangle-0.7.0}/src/demangle/_signature.py +19 -6
  49. {demangle-0.5.2 → demangle-0.7.0}/src/demangle/core/cache.py +2 -0
  50. {demangle-0.5.2 → demangle-0.7.0}/src/demangle/core/decorations.py +7 -1
  51. {demangle-0.5.2 → demangle-0.7.0}/src/demangle/core/errors.py +10 -0
  52. {demangle-0.5.2 → demangle-0.7.0}/src/demangle/core/limits.py +2 -0
  53. {demangle-0.5.2 → demangle-0.7.0}/src/demangle/core/plugin.py +6 -2
  54. {demangle-0.5.2 → demangle-0.7.0}/src/demangle/core/reader.py +8 -0
  55. {demangle-0.5.2 → demangle-0.7.0}/src/demangle/core/registry.py +26 -8
  56. {demangle-0.5.2 → demangle-0.7.0}/src/demangle/core/spelling.py +10 -0
  57. {demangle-0.5.2 → demangle-0.7.0}/src/demangle/core/style.py +8 -0
  58. {demangle-0.5.2 → demangle-0.7.0}/src/demangle/schemes/go/__init__.py +10 -1
  59. {demangle-0.5.2 → demangle-0.7.0}/src/demangle/schemes/itanium/options.py +2 -0
  60. {demangle-0.5.2 → demangle-0.7.0}/src/demangle/schemes/msvc/__init__.py +17 -17
  61. {demangle-0.5.2 → demangle-0.7.0}/src/demangle/schemes/msvc/_parser.py +320 -136
  62. {demangle-0.5.2 → demangle-0.7.0}/src/demangle/schemes/msvc/nodes.py +35 -6
  63. {demangle-0.5.2 → demangle-0.7.0}/src/demangle/schemes/nim/__init__.py +3 -1
  64. {demangle-0.5.2 → demangle-0.7.0}/src/demangle/schemes/nim/_parser.py +10 -1
  65. {demangle-0.5.2 → demangle-0.7.0}/src/demangle/schemes/pascal/__init__.py +4 -1
  66. {demangle-0.5.2 → demangle-0.7.0}/src/demangle/schemes/pascal/_parser.py +11 -2
  67. {demangle-0.5.2 → demangle-0.7.0}/src/demangle/schemes/rust/__init__.py +11 -1
  68. {demangle-0.5.2 → demangle-0.7.0}/src/demangle/schemes/swift/__init__.py +1 -1
  69. {demangle-0.5.2 → demangle-0.7.0}/src/demangle/schemes/swift/_demangler.py +173 -71
  70. {demangle-0.5.2 → demangle-0.7.0}/src/demangle/schemes/swift/_node.py +17 -24
  71. {demangle-0.5.2 → demangle-0.7.0}/src/demangle/schemes/swift/_printer.py +149 -61
  72. {demangle-0.5.2 → demangle-0.7.0}/src/demangle/schemes/swift/nodes.py +3 -2
  73. demangle-0.7.0/tests/browser/test_playground_browser.py +801 -0
  74. {demangle-0.5.2 → demangle-0.7.0}/tests/conformance/swift-upstream.txt +16 -12
  75. {demangle-0.5.2 → demangle-0.7.0}/tests/test_benchmarks.py +16 -0
  76. demangle-0.7.0/tests/test_compare.py +185 -0
  77. {demangle-0.5.2 → demangle-0.7.0}/tests/test_conformance.py +7 -8
  78. {demangle-0.5.2 → demangle-0.7.0}/tests/test_core.py +30 -1
  79. demangle-0.7.0/tests/test_integrations.py +455 -0
  80. demangle-0.7.0/tests/test_integrations_ghidra_live.py +136 -0
  81. demangle-0.7.0/tests/test_integrations_hosts.py +854 -0
  82. demangle-0.7.0/tests/test_llvm_oracle.py +240 -0
  83. {demangle-0.5.2 → demangle-0.7.0}/tests/test_msvc.py +116 -1
  84. demangle-0.7.0/tests/test_msvc_instantiations.py +426 -0
  85. demangle-0.7.0/tests/test_playground.py +273 -0
  86. demangle-0.7.0/tests/test_prepare_release.py +109 -0
  87. demangle-0.7.0/tests/test_release_publish.py +155 -0
  88. {demangle-0.5.2 → demangle-0.7.0}/tests/test_signature.py +31 -0
  89. {demangle-0.5.2 → demangle-0.7.0}/tests/test_swift.py +81 -8
  90. demangle-0.7.0/tests/test_swift_fast_paths.py +718 -0
  91. demangle-0.7.0/tests/test_upstream_drift.py +409 -0
  92. demangle-0.7.0/tests/test_upstream_workflow.py +470 -0
  93. demangle-0.7.0/tools/ensure_release_publish.py +81 -0
  94. {demangle-0.5.2 → demangle-0.7.0}/tools/enumerate.py +8 -0
  95. demangle-0.7.0/tools/llvm-oracle-requirements.txt +18 -0
  96. demangle-0.7.0/tools/llvm_oracle.py +307 -0
  97. demangle-0.7.0/tools/prepare_release.py +149 -0
  98. {demangle-0.5.2 → demangle-0.7.0}/tools/swift-demangle-reference/README.md +17 -11
  99. {demangle-0.5.2 → demangle-0.7.0}/tools/swift-demangle-reference/build.sh +1 -1
  100. {demangle-0.5.2 → demangle-0.7.0}/tools/upstream_drift.py +126 -12
  101. demangle-0.5.2/benchmarks/baseline.json +0 -38
  102. demangle-0.5.2/tests/test_upstream_drift.py +0 -205
  103. {demangle-0.5.2 → demangle-0.7.0}/CODE_OF_CONDUCT.md +0 -0
  104. {demangle-0.5.2 → demangle-0.7.0}/LICENSE +0 -0
  105. {demangle-0.5.2 → demangle-0.7.0}/NOTICE +0 -0
  106. {demangle-0.5.2 → demangle-0.7.0}/benchmarks/audit_api.py +0 -0
  107. {demangle-0.5.2 → demangle-0.7.0}/benchmarks/audit_api_results.json +0 -0
  108. {demangle-0.5.2 → demangle-0.7.0}/benchmarks/audit_ast_optimization_results.json +0 -0
  109. {demangle-0.5.2 → demangle-0.7.0}/benchmarks/audit_cli_results.json +0 -0
  110. {demangle-0.5.2 → demangle-0.7.0}/benchmarks/audit_core.py +0 -0
  111. {demangle-0.5.2 → demangle-0.7.0}/benchmarks/audit_followup_results.json +0 -0
  112. {demangle-0.5.2 → demangle-0.7.0}/benchmarks/audit_graph.py +0 -0
  113. {demangle-0.5.2 → demangle-0.7.0}/benchmarks/audit_integrated_results.json +0 -0
  114. {demangle-0.5.2 → demangle-0.7.0}/benchmarks/audit_jni.py +0 -0
  115. {demangle-0.5.2 → demangle-0.7.0}/benchmarks/audit_nim.py +0 -0
  116. {demangle-0.5.2 → demangle-0.7.0}/benchmarks/audit_nim_optimization_results.json +0 -0
  117. {demangle-0.5.2 → demangle-0.7.0}/benchmarks/audit_objc.py +0 -0
  118. {demangle-0.5.2 → demangle-0.7.0}/benchmarks/audit_results.json +0 -0
  119. {demangle-0.5.2 → demangle-0.7.0}/benchmarks/audit_rust.py +0 -0
  120. {demangle-0.5.2 → demangle-0.7.0}/benchmarks/audit_rust_optimization_results.json +0 -0
  121. {demangle-0.5.2 → demangle-0.7.0}/benchmarks/audit_stream.py +0 -0
  122. {demangle-0.5.2 → demangle-0.7.0}/benchmarks/audit_swift.py +0 -0
  123. {demangle-0.5.2 → demangle-0.7.0}/benchmarks/audit_swift_unicode_results.json +0 -0
  124. {demangle-0.5.2 → demangle-0.7.0}/docs/ARCHITECTURE.md +0 -0
  125. {demangle-0.5.2 → demangle-0.7.0}/docs/CHANGELOG.md +0 -0
  126. {demangle-0.5.2 → demangle-0.7.0}/docs/CONFORMANCE.md +0 -0
  127. {demangle-0.5.2 → demangle-0.7.0}/docs/CONTRIBUTING.md +0 -0
  128. {demangle-0.5.2 → demangle-0.7.0}/docs/SECURITY.md +0 -0
  129. {demangle-0.5.2 → demangle-0.7.0}/docs/analysing-a-binary.md +0 -0
  130. {demangle-0.5.2 → demangle-0.7.0}/docs/index.md +0 -0
  131. {demangle-0.5.2 → demangle-0.7.0}/docs/labelling-a-symbol-table.md +0 -0
  132. {demangle-0.5.2 → demangle-0.7.0}/docs/reference/api.md +0 -0
  133. {demangle-0.5.2 → demangle-0.7.0}/docs/specs/itanium-grammar.txt +0 -0
  134. {demangle-0.5.2 → demangle-0.7.0}/src/demangle/__main__.py +0 -0
  135. {demangle-0.5.2 → demangle-0.7.0}/src/demangle/api.py +0 -0
  136. {demangle-0.5.2 → demangle-0.7.0}/src/demangle/cli.py +0 -0
  137. {demangle-0.5.2 → demangle-0.7.0}/src/demangle/core/__init__.py +0 -0
  138. {demangle-0.5.2 → demangle-0.7.0}/src/demangle/core/ast.py +0 -0
  139. {demangle-0.5.2 → demangle-0.7.0}/src/demangle/core/builder.py +0 -0
  140. {demangle-0.5.2 → demangle-0.7.0}/src/demangle/filter.py +0 -0
  141. {demangle-0.5.2 → demangle-0.7.0}/src/demangle/py.typed +0 -0
  142. {demangle-0.5.2 → demangle-0.7.0}/src/demangle/schemes/__init__.py +0 -0
  143. {demangle-0.5.2 → demangle-0.7.0}/src/demangle/schemes/ada/__init__.py +0 -0
  144. {demangle-0.5.2 → demangle-0.7.0}/src/demangle/schemes/ada/_parser.py +0 -0
  145. {demangle-0.5.2 → demangle-0.7.0}/src/demangle/schemes/ada/nodes.py +0 -0
  146. {demangle-0.5.2 → demangle-0.7.0}/src/demangle/schemes/codewarrior/__init__.py +0 -0
  147. {demangle-0.5.2 → demangle-0.7.0}/src/demangle/schemes/codewarrior/_parser.py +0 -0
  148. {demangle-0.5.2 → demangle-0.7.0}/src/demangle/schemes/codewarrior/nodes.py +0 -0
  149. {demangle-0.5.2 → demangle-0.7.0}/src/demangle/schemes/codewarrior/options.py +0 -0
  150. {demangle-0.5.2 → demangle-0.7.0}/src/demangle/schemes/d/__init__.py +0 -0
  151. {demangle-0.5.2 → demangle-0.7.0}/src/demangle/schemes/d/_parser.py +0 -0
  152. {demangle-0.5.2 → demangle-0.7.0}/src/demangle/schemes/d/nodes.py +0 -0
  153. {demangle-0.5.2 → demangle-0.7.0}/src/demangle/schemes/delphi/__init__.py +0 -0
  154. {demangle-0.5.2 → demangle-0.7.0}/src/demangle/schemes/delphi/_parser.py +0 -0
  155. {demangle-0.5.2 → demangle-0.7.0}/src/demangle/schemes/delphi/nodes.py +0 -0
  156. {demangle-0.5.2 → demangle-0.7.0}/src/demangle/schemes/gnuv2/__init__.py +0 -0
  157. {demangle-0.5.2 → demangle-0.7.0}/src/demangle/schemes/gnuv2/_parser.py +0 -0
  158. {demangle-0.5.2 → demangle-0.7.0}/src/demangle/schemes/gnuv2/nodes.py +0 -0
  159. {demangle-0.5.2 → demangle-0.7.0}/src/demangle/schemes/gnuv2/options.py +0 -0
  160. {demangle-0.5.2 → demangle-0.7.0}/src/demangle/schemes/go/_parser.py +0 -0
  161. {demangle-0.5.2 → demangle-0.7.0}/src/demangle/schemes/go/nodes.py +0 -0
  162. {demangle-0.5.2 → demangle-0.7.0}/src/demangle/schemes/itanium/__init__.py +0 -0
  163. {demangle-0.5.2 → demangle-0.7.0}/src/demangle/schemes/itanium/parser.py +0 -0
  164. {demangle-0.5.2 → demangle-0.7.0}/src/demangle/schemes/itanium/substitutions.py +0 -0
  165. {demangle-0.5.2 → demangle-0.7.0}/src/demangle/schemes/itanium/tables.py +0 -0
  166. {demangle-0.5.2 → demangle-0.7.0}/src/demangle/schemes/jni/__init__.py +0 -0
  167. {demangle-0.5.2 → demangle-0.7.0}/src/demangle/schemes/jni/_parser.py +0 -0
  168. {demangle-0.5.2 → demangle-0.7.0}/src/demangle/schemes/jni/nodes.py +0 -0
  169. {demangle-0.5.2 → demangle-0.7.0}/src/demangle/schemes/msvc/options.py +0 -0
  170. {demangle-0.5.2 → demangle-0.7.0}/src/demangle/schemes/nim/nodes.py +0 -0
  171. {demangle-0.5.2 → demangle-0.7.0}/src/demangle/schemes/objc/__init__.py +0 -0
  172. {demangle-0.5.2 → demangle-0.7.0}/src/demangle/schemes/objc/_parser.py +0 -0
  173. {demangle-0.5.2 → demangle-0.7.0}/src/demangle/schemes/objc/nodes.py +0 -0
  174. {demangle-0.5.2 → demangle-0.7.0}/src/demangle/schemes/pascal/nodes.py +0 -0
  175. {demangle-0.5.2 → demangle-0.7.0}/src/demangle/schemes/rust/_dispatch.py +0 -0
  176. {demangle-0.5.2 → demangle-0.7.0}/src/demangle/schemes/rust/_legacy.py +0 -0
  177. {demangle-0.5.2 → demangle-0.7.0}/src/demangle/schemes/rust/_v0.py +0 -0
  178. {demangle-0.5.2 → demangle-0.7.0}/src/demangle/schemes/rust/nodes.py +0 -0
  179. {demangle-0.5.2 → demangle-0.7.0}/src/demangle/schemes/rust/options.py +0 -0
  180. {demangle-0.5.2 → demangle-0.7.0}/src/demangle/schemes/swift/_old_demangler.py +0 -0
  181. {demangle-0.5.2 → demangle-0.7.0}/src/demangle/schemes/swift/_punycode.py +0 -0
  182. {demangle-0.5.2 → demangle-0.7.0}/src/demangle/schemes/swift/options.py +0 -0
  183. {demangle-0.5.2 → demangle-0.7.0}/src/demangle/schemes/swift/resolve.py +0 -0
  184. {demangle-0.5.2 → demangle-0.7.0}/src/demangle/schemes/swift/symbolic.py +0 -0
  185. {demangle-0.5.2 → demangle-0.7.0}/tests/__init__.py +0 -0
  186. {demangle-0.5.2 → demangle-0.7.0}/tests/conformance/ada-libiberty.txt +0 -0
  187. {demangle-0.5.2 → demangle-0.7.0}/tests/conformance/ada-real-world.txt +0 -0
  188. {demangle-0.5.2 → demangle-0.7.0}/tests/conformance/codewarrior-cwdemangle.txt +0 -0
  189. {demangle-0.5.2 → demangle-0.7.0}/tests/conformance/d-libiberty.txt +0 -0
  190. {demangle-0.5.2 → demangle-0.7.0}/tests/conformance/d-real-world.txt +0 -0
  191. {demangle-0.5.2 → demangle-0.7.0}/tests/conformance/delphi-constructs.txt +0 -0
  192. {demangle-0.5.2 → demangle-0.7.0}/tests/conformance/delphi-real-world.txt +0 -0
  193. {demangle-0.5.2 → demangle-0.7.0}/tests/conformance/delphi-refusals.txt +0 -0
  194. {demangle-0.5.2 → demangle-0.7.0}/tests/conformance/delphi-tdump.txt +0 -0
  195. {demangle-0.5.2 → demangle-0.7.0}/tests/conformance/gnuv2-libiberty.txt +0 -0
  196. {demangle-0.5.2 → demangle-0.7.0}/tests/conformance/gnuv2-real-world.txt +0 -0
  197. {demangle-0.5.2 → demangle-0.7.0}/tests/conformance/go-real-world.txt +0 -0
  198. {demangle-0.5.2 → demangle-0.7.0}/tests/conformance/itanium-libcxxabi.txt.gz +0 -0
  199. {demangle-0.5.2 → demangle-0.7.0}/tests/conformance/itanium-libstdcxx.txt +0 -0
  200. {demangle-0.5.2 → demangle-0.7.0}/tests/conformance/itanium-real-world-gnu.txt +0 -0
  201. {demangle-0.5.2 → demangle-0.7.0}/tests/conformance/itanium-real-world.txt +0 -0
  202. {demangle-0.5.2 → demangle-0.7.0}/tests/conformance/itanium-reference-defects.txt +0 -0
  203. {demangle-0.5.2 → demangle-0.7.0}/tests/conformance/itanium-types-llvm.txt +0 -0
  204. {demangle-0.5.2 → demangle-0.7.0}/tests/conformance/itanium-types.txt +0 -0
  205. {demangle-0.5.2 → demangle-0.7.0}/tests/conformance/jni-real-world.txt +0 -0
  206. {demangle-0.5.2 → demangle-0.7.0}/tests/conformance/msvc-arm64ec.txt +0 -0
  207. {demangle-0.5.2 → demangle-0.7.0}/tests/conformance/msvc-boost.txt +0 -0
  208. {demangle-0.5.2 → demangle-0.7.0}/tests/conformance/msvc-clang.txt +0 -0
  209. {demangle-0.5.2 → demangle-0.7.0}/tests/conformance/msvc-dbghelp.txt +0 -0
  210. {demangle-0.5.2 → demangle-0.7.0}/tests/conformance/msvc-llvm-corpus.txt +0 -0
  211. {demangle-0.5.2 → demangle-0.7.0}/tests/conformance/msvc-name-only.txt +0 -0
  212. {demangle-0.5.2 → demangle-0.7.0}/tests/conformance/msvc-reference-defects.txt +0 -0
  213. {demangle-0.5.2 → demangle-0.7.0}/tests/conformance/msvc-suppressions.txt +0 -0
  214. {demangle-0.5.2 → demangle-0.7.0}/tests/conformance/msvc-type-descriptors.txt +0 -0
  215. {demangle-0.5.2 → demangle-0.7.0}/tests/conformance/nim-lossy.txt +0 -0
  216. {demangle-0.5.2 → demangle-0.7.0}/tests/conformance/nim-real-world.txt +0 -0
  217. {demangle-0.5.2 → demangle-0.7.0}/tests/conformance/objc-lossy.txt +0 -0
  218. {demangle-0.5.2 → demangle-0.7.0}/tests/conformance/objc-real-world.txt +0 -0
  219. {demangle-0.5.2 → demangle-0.7.0}/tests/conformance/objc-refusals.txt +0 -0
  220. {demangle-0.5.2 → demangle-0.7.0}/tests/conformance/pascal-real-world.txt +0 -0
  221. {demangle-0.5.2 → demangle-0.7.0}/tests/conformance/pascal-refusals.txt +0 -0
  222. {demangle-0.5.2 → demangle-0.7.0}/tests/conformance/reported/d-gnu.txt +0 -0
  223. {demangle-0.5.2 → demangle-0.7.0}/tests/conformance/reported/gnuv2-gnu.txt +0 -0
  224. {demangle-0.5.2 → demangle-0.7.0}/tests/conformance/reported/itanium-gnu.txt +0 -0
  225. {demangle-0.5.2 → demangle-0.7.0}/tests/conformance/reported/itanium.txt +0 -0
  226. {demangle-0.5.2 → demangle-0.7.0}/tests/conformance/reported/rust.txt +0 -0
  227. {demangle-0.5.2 → demangle-0.7.0}/tests/conformance/reported/swift.txt +0 -0
  228. {demangle-0.5.2 → demangle-0.7.0}/tests/conformance/rust-real-world.txt +0 -0
  229. {demangle-0.5.2 → demangle-0.7.0}/tests/conformance/rust-toolchain.txt +0 -0
  230. {demangle-0.5.2 → demangle-0.7.0}/tests/conformance/rustc-upstream.txt +0 -0
  231. {demangle-0.5.2 → demangle-0.7.0}/tests/conformance/swift-real-world.txt +0 -0
  232. {demangle-0.5.2 → demangle-0.7.0}/tests/conformance/swift-reference-defects.txt +0 -0
  233. {demangle-0.5.2 → demangle-0.7.0}/tests/conformance/swift-refusals.txt +0 -0
  234. {demangle-0.5.2 → demangle-0.7.0}/tests/conformance/swift-simplified.txt +0 -0
  235. {demangle-0.5.2 → demangle-0.7.0}/tests/conformance/swift-symbolic.txt +0 -0
  236. {demangle-0.5.2 → demangle-0.7.0}/tests/conftest.py +0 -0
  237. {demangle-0.5.2 → demangle-0.7.0}/tests/test_ada.py +0 -0
  238. {demangle-0.5.2 → demangle-0.7.0}/tests/test_address_of.py +0 -0
  239. {demangle-0.5.2 → demangle-0.7.0}/tests/test_api.py +0 -0
  240. {demangle-0.5.2 → demangle-0.7.0}/tests/test_api_surface.py +0 -0
  241. {demangle-0.5.2 → demangle-0.7.0}/tests/test_architecture.py +0 -0
  242. {demangle-0.5.2 → demangle-0.7.0}/tests/test_cli.py +0 -0
  243. {demangle-0.5.2 → demangle-0.7.0}/tests/test_codewarrior.py +0 -0
  244. {demangle-0.5.2 → demangle-0.7.0}/tests/test_concurrency.py +0 -0
  245. {demangle-0.5.2 → demangle-0.7.0}/tests/test_d.py +0 -0
  246. {demangle-0.5.2 → demangle-0.7.0}/tests/test_delphi.py +0 -0
  247. {demangle-0.5.2 → demangle-0.7.0}/tests/test_differential.py +0 -0
  248. {demangle-0.5.2 → demangle-0.7.0}/tests/test_docs.py +0 -0
  249. {demangle-0.5.2 → demangle-0.7.0}/tests/test_expressions.py +0 -0
  250. {demangle-0.5.2 → demangle-0.7.0}/tests/test_gnu_expressions.py +0 -0
  251. {demangle-0.5.2 → demangle-0.7.0}/tests/test_gnuv2.py +0 -0
  252. {demangle-0.5.2 → demangle-0.7.0}/tests/test_go.py +0 -0
  253. {demangle-0.5.2 → demangle-0.7.0}/tests/test_invariants.py +0 -0
  254. {demangle-0.5.2 → demangle-0.7.0}/tests/test_itanium_apple_auto.py +0 -0
  255. {demangle-0.5.2 → demangle-0.7.0}/tests/test_itanium_closure_prefix.py +0 -0
  256. {demangle-0.5.2 → demangle-0.7.0}/tests/test_itanium_import_thunk.py +0 -0
  257. {demangle-0.5.2 → demangle-0.7.0}/tests/test_itanium_utf8.py +0 -0
  258. {demangle-0.5.2 → demangle-0.7.0}/tests/test_jni.py +0 -0
  259. {demangle-0.5.2 → demangle-0.7.0}/tests/test_limits.py +0 -0
  260. {demangle-0.5.2 → demangle-0.7.0}/tests/test_local_names.py +0 -0
  261. {demangle-0.5.2 → demangle-0.7.0}/tests/test_msvc_arm64ec.py +0 -0
  262. {demangle-0.5.2 → demangle-0.7.0}/tests/test_msvc_ast.py +0 -0
  263. {demangle-0.5.2 → demangle-0.7.0}/tests/test_msvc_descriptors.py +0 -0
  264. {demangle-0.5.2 → demangle-0.7.0}/tests/test_msvc_options.py +0 -0
  265. {demangle-0.5.2 → demangle-0.7.0}/tests/test_nim.py +0 -0
  266. {demangle-0.5.2 → demangle-0.7.0}/tests/test_objc.py +0 -0
  267. {demangle-0.5.2 → demangle-0.7.0}/tests/test_parity.py +0 -0
  268. {demangle-0.5.2 → demangle-0.7.0}/tests/test_pascal.py +0 -0
  269. {demangle-0.5.2 → demangle-0.7.0}/tests/test_readme.py +0 -0
  270. {demangle-0.5.2 → demangle-0.7.0}/tests/test_repro.py +0 -0
  271. {demangle-0.5.2 → demangle-0.7.0}/tests/test_robustness.py +0 -0
  272. {demangle-0.5.2 → demangle-0.7.0}/tests/test_rust.py +0 -0
  273. {demangle-0.5.2 → demangle-0.7.0}/tests/test_rust_ast.py +0 -0
  274. {demangle-0.5.2 → demangle-0.7.0}/tests/test_rust_consts.py +0 -0
  275. {demangle-0.5.2 → demangle-0.7.0}/tests/test_special_names.py +0 -0
  276. {demangle-0.5.2 → demangle-0.7.0}/tests/test_substitution_parameters.py +0 -0
  277. {demangle-0.5.2 → demangle-0.7.0}/tests/test_swift_simplified.py +0 -0
  278. {demangle-0.5.2 → demangle-0.7.0}/tests/test_swift_symbolic.py +0 -0
  279. {demangle-0.5.2 → demangle-0.7.0}/tests/test_types.py +0 -0
  280. {demangle-0.5.2 → demangle-0.7.0}/tools/corpus_sources/features.cpp +0 -0
  281. {demangle-0.5.2 → demangle-0.7.0}/tools/corpus_sources/go/go.mod +0 -0
  282. {demangle-0.5.2 → demangle-0.7.0}/tools/corpus_sources/go/main.go +0 -0
  283. {demangle-0.5.2 → demangle-0.7.0}/tools/corpus_sources/go/plain/lib.go +0 -0
  284. {demangle-0.5.2 → demangle-0.7.0}/tools/corpus_sources/go/v2.5/lib.go +0 -0
  285. {demangle-0.5.2 → demangle-0.7.0}/tools/corpus_sources/go/weird.pkg.name/lib.go +0 -0
  286. {demangle-0.5.2 → demangle-0.7.0}/tools/corpus_sources/modern.cpp +0 -0
  287. {demangle-0.5.2 → demangle-0.7.0}/tools/corpus_sources/modern23.cpp +0 -0
  288. {demangle-0.5.2 → demangle-0.7.0}/tools/corpus_sources/msvc/modern.cpp +0 -0
  289. {demangle-0.5.2 → demangle-0.7.0}/tools/corpus_sources/msvc/msvc.cpp +0 -0
  290. {demangle-0.5.2 → demangle-0.7.0}/tools/corpus_sources/reference_defects/README.md +0 -0
  291. {demangle-0.5.2 → demangle-0.7.0}/tools/corpus_sources/reference_defects/auto_marshall.cpp +0 -0
  292. {demangle-0.5.2 → demangle-0.7.0}/tools/corpus_sources/reference_defects/closure_prefix.cpp +0 -0
  293. {demangle-0.5.2 → demangle-0.7.0}/tools/corpus_sources/reference_defects/division.cpp +0 -0
  294. {demangle-0.5.2 → demangle-0.7.0}/tools/corpus_sources/reference_defects/generic_lambda.cpp +0 -0
  295. {demangle-0.5.2 → demangle-0.7.0}/tools/corpus_sources/reference_defects/inheriting_constructor.cpp +0 -0
  296. {demangle-0.5.2 → demangle-0.7.0}/tools/corpus_sources/reference_defects/insort.cpp +0 -0
  297. {demangle-0.5.2 → demangle-0.7.0}/tools/corpus_sources/reference_defects/insort_composite.cpp +0 -0
  298. {demangle-0.5.2 → demangle-0.7.0}/tools/corpus_sources/reference_defects/member_template_lambda.cpp +0 -0
  299. {demangle-0.5.2 → demangle-0.7.0}/tools/corpus_sources/reference_defects/prepare_execution.cpp +0 -0
  300. {demangle-0.5.2 → demangle-0.7.0}/tools/corpus_sources/reference_defects/template_template_param.cpp +0 -0
  301. {demangle-0.5.2 → demangle-0.7.0}/tools/corpus_sources/reference_defects/value_init_new.cpp +0 -0
  302. {demangle-0.5.2 → demangle-0.7.0}/tools/corpus_sources/rust/consts.rs +0 -0
  303. {demangle-0.5.2 → demangle-0.7.0}/tools/corpus_sources/rust/features.rs +0 -0
  304. {demangle-0.5.2 → demangle-0.7.0}/tools/corpus_sources/rust/library.rs +0 -0
  305. {demangle-0.5.2 → demangle-0.7.0}/tools/corpus_sources/rust/types.rs +0 -0
  306. {demangle-0.5.2 → demangle-0.7.0}/tools/cplus-dem-reference/README.md +0 -0
  307. {demangle-0.5.2 → demangle-0.7.0}/tools/cplus-dem-reference/SHA256SUMS +0 -0
  308. {demangle-0.5.2 → demangle-0.7.0}/tools/cplus-dem-reference/build.sh +0 -0
  309. {demangle-0.5.2 → demangle-0.7.0}/tools/cplus-dem-reference/main.c +0 -0
  310. {demangle-0.5.2 → demangle-0.7.0}/tools/differential.py +0 -0
  311. {demangle-0.5.2 → demangle-0.7.0}/tools/generate_ada_corpus.py +0 -0
  312. {demangle-0.5.2 → demangle-0.7.0}/tools/generate_corpus.py +0 -0
  313. {demangle-0.5.2 → demangle-0.7.0}/tools/generate_d_corpus.py +0 -0
  314. {demangle-0.5.2 → demangle-0.7.0}/tools/generate_delphi_corpus.py +0 -0
  315. {demangle-0.5.2 → demangle-0.7.0}/tools/generate_go_corpus.py +0 -0
  316. {demangle-0.5.2 → demangle-0.7.0}/tools/generate_msvc_dbghelp_corpus.py +0 -0
  317. {demangle-0.5.2 → demangle-0.7.0}/tools/generate_rust_corpus.py +0 -0
  318. {demangle-0.5.2 → demangle-0.7.0}/tools/invariants.py +0 -0
  319. {demangle-0.5.2 → demangle-0.7.0}/tools/mutate.py +0 -0
  320. {demangle-0.5.2 → demangle-0.7.0}/tools/probe_substitutions.py +0 -0
  321. {demangle-0.5.2 → demangle-0.7.0}/tools/repro.py +0 -0
  322. {demangle-0.5.2 → demangle-0.7.0}/tools/rustc-demangle-reference/Cargo.lock +0 -0
  323. {demangle-0.5.2 → demangle-0.7.0}/tools/rustc-demangle-reference/Cargo.toml +0 -0
  324. {demangle-0.5.2 → demangle-0.7.0}/tools/rustc-demangle-reference/README.md +0 -0
  325. {demangle-0.5.2 → demangle-0.7.0}/tools/rustc-demangle-reference/src/main.rs +0 -0
  326. {demangle-0.5.2 → demangle-0.7.0}/tools/sweep_rust_chars.py +0 -0
  327. {demangle-0.5.2 → demangle-0.7.0}/tools/swift-demangle-reference/main.cpp +0 -0
@@ -19,3 +19,6 @@ tools/swift-demangle-reference/swift/
19
19
  tools/swift-demangle-reference/build/
20
20
  tools/cplus-dem-reference/gcc/
21
21
  tools/cplus-dem-reference/build/
22
+ .agents/
23
+ docs/assets/demangle.zip
24
+ playground/assets/
@@ -169,7 +169,9 @@ scheme with a fixed first character declares it (`first_characters`), and a name
169
169
  starting with anything else never reaches it. A scheme whose names are ordinary C
170
170
  identifiers has none, so it declares a `DETECT_SCREEN`: the markers and openings that a
171
171
  name must hold for its `detect` to say yes, and a name with none of them is not offered
172
- to it. The schemes whose names carry no marker at all -- Ada and the two pre-Itanium
172
+ to it. Both can apply: Nim and Free Pascal names are identifiers, so they also declare
173
+ the letters and `_` as first characters, which keeps them off MSVC's `?` and Swift's
174
+ `$s` names even though those hold the `__` and `$` they screen on. The schemes whose names carry no marker at all -- Ada and the two pre-Itanium
173
175
  C++ manglings, whose `detect` has to parse -- are offered last, behind everything a
174
176
  prefix settles.
175
177
 
@@ -8,6 +8,130 @@ the reference demanglers, and a **Performance** section.
8
8
 
9
9
  ## [Unreleased]
10
10
 
11
+ ## [0.7.0] - 2026-11-12
12
+
13
+ ### Fixed
14
+
15
+ - **The IDA, Binary Ninja and Ghidra scripts read Mach-O names without their leading
16
+ underscore.** Mach-O puts one underscore in front of every symbol, and the tools keep
17
+ it, so Nim's `_area__mymod_u10` came out as `mymod._area`, JNI's `_Java_...` was not
18
+ read, and Free Pascal, Ada and GCC 2 names were read with the underscore as part of the
19
+ name. On a Mach-O file a name is now read without it, except where C++, Swift, Rust, D
20
+ or Objective-C reads it as it stands (`__Z`, `_$s`, `__D`, ...), which those schemes do
21
+ already and which keeps Apple's C++ rules. `demangle_labels.Options` has a
22
+ `leading_underscore` field for it, and each script a `LEADING_UNDERSCORE` setting that
23
+ overrides the file type. Checked in IDA 9.5, Binary Ninja 6.0 and Ghidra 12.2 on a
24
+ Mach-O arm64 dylib.
25
+ - **The Binary Ninja plugin leaves alone an address holding several user symbols.**
26
+ Binary Ninja's DWARF import defines a user symbol for each function the linker
27
+ discarded, all at the image base beside `__elf_header`. With
28
+ `ONLY_LEFT_MANGLED = False` on a Rust program the plugin relabelled one of them, which
29
+ dropped `__elf_header`, and Undo did not bring it back. Such an address is now skipped
30
+ and counted in the summary line. Found running the plugin live in Binary Ninja 6.0 on
31
+ Linux; the IDA script was run live in IDA 9.5, through idalib and `idat -S`, with
32
+ nothing to fix. Both were then run from their windows, the Plugins menu of Binary Ninja
33
+ 6.0.10905 and File > Script file in IDA 9.5, with Cancel, Undo and Redo behaving as
34
+ documented.
35
+ - **An MSVC name holding `_$$_` or a `/` is no longer read as Free Pascal or Go.**
36
+ `?A_$$_B@@3HA` read as a Free Pascal routine `B@@3HA` in a unit `?A`, where it is
37
+ MSVC's `int A_$$_B`, and an MSVC string literal with a `/` in it was claimed by Go and
38
+ left as it was. Neither scheme writes a name opening `?`.
39
+ - **Swift follows upstream's renames (weekly drift report #70).** The called-once
40
+ function conventions are `@once` (`XO`) and `@callable(once)` (`XOo`), where they were
41
+ `@called(exactlyOnce)` and `@called(atMostOnce)`, and `Twa` after a type metadata
42
+ accessor reads as `back deployment copy of type metadata accessor for ...`, where it
43
+ was refused. The Swift reference build moves to swiftlang/swift `main` @ `4f010677`
44
+ (2026-11-12), which reproduces the corpora: 531 / 531, 217 / 217, 71 / 71. Rust's
45
+ `#[rustc_splat]` is not followed yet: it is on rustc-demangle's `main` only, and the
46
+ released 0.1.28 that the reference builds still prints `#[splat]`.
47
+ - **MSVC: a conversion operator used as an alias template's argument is declined
48
+ cleanly.** `?f@@YAXV?$A@$$Y?$?BH@@@@V?$A@$$Y?$?BH@@@@@Z` failed on an internal
49
+ `ValueError`, because the placeholder for a conversion operator's name and the mark
50
+ for a function type's calling convention shared a delimiter. They are now distinct,
51
+ and the name is refused as `llvm-undname` refuses it.
52
+ - **Swift reads a propagated `@differentiable` function argument.** A function
53
+ signature specialization parameter `a` (`...Tf1na_n`) carries the original function
54
+ and its JVP and VJP, each as a name and a type, and prints as `[Differentiable
55
+ Function Propagated, Components : [...]]`; it was refused. That was the last vector of
56
+ the drift report this library did not read. `swift-upstream.txt` now holds it and the
57
+ three `Twa` rows: 535 / 535 against the reference build at `4f010677`.
58
+ - Playground navigation, presets, and cards share centered page gutters and a bounded
59
+ content width. Inner padding, control sizing, and responsive option rows stay aligned
60
+ on desktop, narrow screens, and with enlarged text; overflow is contained locally.
61
+ - Release recovery resumes publishing when a tag and release already exist. Active
62
+ or successful publishing runs are preserved; failed runs retry only failed jobs.
63
+ - Playground theme settings no longer prevent startup when browser storage is blocked.
64
+ The theme toggle follows the system preference until the user selects a theme.
65
+ - Automatic and manual release runs require successful push CI for the commit being tagged.
66
+
67
+ ### Added
68
+
69
+ - Playground batch results preserve line order and blank lines, show individual errors,
70
+ cache duplicate symbols, and support copying or downloading the selected output view.
71
+ - Share links restore batch mode and validate options, with a size limit and explicit
72
+ clipboard feedback. Result states distinguish unrecognized, invalid, and unchanged
73
+ symbols; keyboard focus and live announcements cover batch controls and results.
74
+ - A release-preparation command updates package and citation versions, release notes,
75
+ and comparison links together, with metadata checks and rollback on failure.
76
+ - Browser checks for theme persistence, keyboard shortcuts, and stalled-worker recovery.
77
+ - IDA Pro, Binary Ninja and Ghidra scripts that label the symbols each tool leaves
78
+ mangled, in `integrations/`, with a "Disassembler integrations" page. They stay out of
79
+ the wheel.
80
+ - `benchmarks/compare.py` and a "Comparison with other demanglers" page that measure this
81
+ package against LLVM's demangler, `cpp-demangle`, `itanium_demangler` and the `c++filt`
82
+ tools on the same names.
83
+ - The weekly upstream drift job also reads every checked-in corpus with the newest LLVM,
84
+ through `llvm-demangle-fxti` pinned by hash, in a job that holds no token
85
+ (`tools/llvm_oracle.py`; `tools/upstream_drift.py --source llvm-*`, `--llvm-version`,
86
+ `--require-llvm` and `--no-llvm`).
87
+
88
+ ### Changed
89
+
90
+ - An MSVC name nested deep enough to reach Python's own recursion limit before
91
+ `max_depth` can now be read, where 0.6.0 reported `LimitExceeded`. `max_depth` itself is
92
+ unchanged.
93
+
94
+ ### Performance
95
+
96
+ - MSVC names read about 7% faster cold, Swift names about 5% and Delphi names about
97
+ 12%. Go, Nim and Free Pascal are asked about a name before these schemes, and the
98
+ `$`, `__` and `/` they look for are in most such names. Nim and Free Pascal names
99
+ open with a letter or `_`, which both now declare as their first characters, and Go's
100
+ `detect` turns away a name opening `?` or `$` before looking for a path: no import
101
+ path holds either, and Go's own `$` constants were never claimed. Output over every
102
+ corpus is unchanged.
103
+ - Swift names read about 1.3 times as fast cold: identifiers are split into words only
104
+ when a substitution needs them, and the commonest parser and printer steps make about
105
+ 40% fewer calls.
106
+ - Template-heavy MSVC names read about 1.5 times as fast cold: each template
107
+ instantiation is read once per name, and the control-character scan runs once.
108
+
109
+ ## [0.6.0] - 2026-10-11
110
+
111
+ ### Fixed
112
+
113
+ - Preserve playground input and selected settings while its runtime loads. Scheme
114
+ selectors and output controls stay inside their columns on narrow screens and with
115
+ enlarged text. AST references reveal collapsed ancestors and support keyboard use.
116
+
117
+ ### Added
118
+
119
+ - MSVC C++20 three-way comparison (`operator<=>`) and ARM64e pointer authentication
120
+ qualifiers, including their structured AST representation.
121
+ - Swift inverse conformance to `~Deinitable`, with module-name display options respected.
122
+ - A standalone browser playground with theme switching and keyboard shortcuts.
123
+ - Shareable playground links and the loaded library version, runtime retry controls,
124
+ and browser regression tests including a real Pyodide smoke test in CI.
125
+ - Bounded Swift and cross-scheme signature benchmarks with successful-work checks.
126
+
127
+ ### Performance
128
+
129
+ - Run playground parsing in a worker and derive signature and AST data from one parse.
130
+ Output view changes reuse the result; AST expansion is lazy and paged with a display
131
+ budget while raw JSON remains complete.
132
+ - Deliver a deterministic, zipimportable source archive instead of a synthetic wheel
133
+ and duplicate base64 bundle.
134
+
11
135
  ## [0.5.2] - 2026-10-10
12
136
 
13
137
  ### Fixed
@@ -4037,7 +4161,9 @@ substitution table contents, pinned by name.
4037
4161
  faster by doing less work.
4038
4162
  - API reference published from docstrings at <https://r0ny123.github.io/demangle/>.
4039
4163
 
4040
- [Unreleased]: https://github.com/r0ny123/demangle/compare/v0.5.2...HEAD
4164
+ [Unreleased]: https://github.com/r0ny123/demangle/compare/v0.7.0...HEAD
4165
+ [0.7.0]: https://github.com/r0ny123/demangle/compare/v0.6.0...v0.7.0
4166
+ [0.6.0]: https://github.com/r0ny123/demangle/compare/v0.5.2...v0.6.0
4041
4167
  [0.5.2]: https://github.com/r0ny123/demangle/compare/v0.5.1...v0.5.2
4042
4168
  [0.5.1]: https://github.com/r0ny123/demangle/compare/v0.5.0...v0.5.1
4043
4169
  [0.5.0]: https://github.com/r0ny123/demangle/compare/v0.4.0...v0.5.0
@@ -5,4 +5,4 @@ authors:
5
5
  - name: demangle contributors
6
6
  license: MIT
7
7
  repository-code: "https://github.com/r0ny123/demangle"
8
- version: "0.5.2"
8
+ version: "0.7.0"
@@ -37,7 +37,7 @@ Replayed by the test suite. No compiler and no reference demangler needed.
37
37
  | Bare `<type>` encodings, llvm style | `llvm-cxxfilt --types` 18.1.3 | **1076 / 1076** |
38
38
  | Bare `<type>` encodings, gnu style | GNU `c++filt -t` 2.42 | **1076 / 1076** <sup>[3](#3-bare-types-under-both-references)</sup> |
39
39
  | Swift runtime + the compiler's own test corpus | `swift-demangle`, built from source <sup>[6](#6-the-swift-reference-is-built-here)</sup> | **8494 / 8494** |
40
- | Swift — the compiler's own demangler vectors | `swift-demangle`, built from source <sup>[6](#6-the-swift-reference-is-built-here)</sup> | **531 / 531** |
40
+ | Swift — the compiler's own demangler vectors | `swift-demangle`, built from source <sup>[6](#6-the-swift-reference-is-built-here)</sup> | **535 / 535** |
41
41
  | Nim 1.6 and 2.2, against the compiler's own record <sup>[14](#14-nim)</sup> | `.ndi` debug mapping | **2115 / 2115** |
42
42
  | Free Pascal 3.2.2 runtime and packages <sup>[5](#5-free-pascal)</sup> | re-assembly + `ppudump` | **3899 / 3899** |
43
43
  | Go, from the shipped toolchain | round trip <sup>[16](#16-go)</sup> | **1517 / 1517** |
@@ -40,7 +40,35 @@ Development requirements are [dependency groups](https://peps.python.org/pep-073
40
40
  not extras. An extra is a *published* feature of the distribution -- `pip install
41
41
  demangle[dev]` would appear on PyPI as something users are invited to install -- and a
42
42
  linter is not a feature of a demangler. The groups are `test`, `format`, `lint`, `docs`,
43
- and `dev`, which includes the first three.
43
+ `browser`, and `dev`, which includes the first three.
44
+
45
+ The browser suite is opt-in: it needs the browser dependency group, a built docs site,
46
+ and Chromium. It uses a deterministic fake worker for UI regressions; the real Pyodide
47
+ CDN smoke test is separately opt-in.
48
+
49
+ ```console
50
+ uv pip install -e . --group browser --group docs --group test
51
+ python -m playwright install chromium
52
+ mkdocs build --strict
53
+ DEMANGLE_BROWSER_TESTS=1 python -m pytest -q tests/browser/test_playground_browser.py
54
+
55
+ # Also exercise Pyodide from its CDN, as the browser CI job does.
56
+ DEMANGLE_BROWSER_TESTS=1 DEMANGLE_PYODIDE_SMOKE=1 \
57
+ python -m pytest -q tests/browser/test_playground_browser.py
58
+ ```
59
+
60
+ So is the Ghidra test, which runs `integrations/demangle_ghidra.py` in a real headless
61
+ Ghidra: it compiles a small C++ program, imports it with analysis off, runs the script
62
+ twice, and checks the symbol table after each run. It needs Ghidra 11.3 or later with a
63
+ JDK it runs on, the `pyghidra` package for that Ghidra in the same environment as
64
+ `demangle`, and `g++`, `c++` or `clang++` on PATH; without any of them, or without both
65
+ variables below, it is skipped.
66
+
67
+ ```console
68
+ pip install pyghidra
69
+ GHIDRA_INSTALL_DIR=/path/to/ghidra DEMANGLE_GHIDRA_TESTS=1 \
70
+ python -m pytest -q tests/test_integrations_ghidra_live.py
71
+ ```
44
72
 
45
73
  The toolchain is deliberately the fast one: **ruff** for linting and formatting (it
46
74
  replaces black, isort, flake8 and pyupgrade), **ty** for type checking (it replaces
@@ -152,6 +180,23 @@ it accepts -- has been through `tools/enumerate.py`, `tools/mutate.py` and
152
180
  has why, what each asks, and how to build the references for Rust, Swift and
153
181
  pre-Itanium C++ that no distribution ships.
154
182
 
183
+ ## Preparing a release
184
+
185
+ After the Unreleased section has notes ready to publish, prepare the release metadata with
186
+ its stable semantic version. The command defaults the date to today; pass `--date` for a
187
+ specific `YYYY-MM-DD` date. It updates the package and citation versions, moves the notes
188
+ under the dated changelog heading, refreshes comparison links, then runs the documentation
189
+ metadata checks. If those checks fail, it restores the original files. Commit and push
190
+ that change to `main`; `tag-release.yml` creates the tag and release only after push CI
191
+ passes for that exact commit. It then starts the PyPI publishing workflow. If starting
192
+ publishing fails, rerun the tag-release job: an existing release no longer stops recovery.
193
+ Active or successful publishing runs are left alone; failed runs retry only failed jobs.
194
+ Cancelled runs require an explicit manual restart.
195
+
196
+ ```console
197
+ python tools/prepare_release.py 0.7.0 --date 2026-10-12
198
+ ```
199
+
155
200
  ## How changes get merged
156
201
 
157
202
  Leave `CHANGELOG.md` alone: the maintainer writes the entry when merging. A first-time
@@ -163,13 +208,15 @@ while before any checks appear. The easiest first contribution is a
163
208
  ## CI and workflows
164
209
 
165
210
  Workflows run with `permissions: contents: read` and grant more only where a job needs
166
- it: the weekly `upstream.yml` has `issues: write`, because its one job files the issue
167
- that says a reference's vectors moved ahead of a scheme. Checkout uses
211
+ it: the weekly `upstream.yml` gives `issues: write` to its `drift` job alone, because that
212
+ job files the issue that says a reference's vectors moved ahead of a scheme; its `llvm`
213
+ job, which runs a third party's native wheel, has `contents: read` and no secret, and its
214
+ wheel is pinned by hash. Checkout uses
168
215
  `persist-credentials: false`, because nothing in CI pushes and a token left in
169
- `.git/config` is readable by every later step. A release is cut by `tag-release.yml`
170
- when `__version__` changes on `main`, through the API with `contents: write` and
171
- `actions: write` on that one job; it starts `release.yml`, which publishes through PyPI
172
- Trusted Publishing, so there is no long-lived API token in repository secrets. The
216
+ `.git/config` is readable by every later step. `tag-release.yml` cuts a release after
217
+ push CI succeeds on `main` for the exact commit, through the API with `contents: write`
218
+ and `actions: write` on that one job; it starts `release.yml`, which publishes through
219
+ PyPI Trusted Publishing, so there is no long-lived API token in repository secrets. The
173
220
  `pypi` environment still waits for a maintainer to approve.
174
221
 
175
222
  The test matrix is deliberately not a cross product. Every supported version runs on
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: demangle
3
- Version: 0.5.2
3
+ Version: 0.7.0
4
4
  Summary: Read mangled symbol names -- Itanium C++, MSVC, Rust, Swift, Objective-C, Go, D, Nim, Free Pascal, Delphi, Ada/GNAT, JNI and pre-Itanium C++ (g++ 2.x, cfront/ARM, Lucid, HP aCC, CodeWarrior) -- in pure Python, with no dependencies.
5
5
  Project-URL: Homepage, https://github.com/r0ny123/demangle
6
6
  Project-URL: Documentation, https://r0ny123.github.io/demangle/
@@ -37,6 +37,7 @@ Description-Content-Type: text/markdown
37
37
  [![Python](https://img.shields.io/badge/python-3.11%2B-blue)](https://www.python.org/downloads/)
38
38
  [![Licence](https://img.shields.io/badge/licence-MIT-green)](https://github.com/r0ny123/demangle/blob/main/LICENSE)
39
39
  [![Docs](https://img.shields.io/badge/docs-r0ny123.github.io-blue)](https://r0ny123.github.io/demangle/)
40
+ [![Open Playground](https://img.shields.io/badge/Open%20Playground-r0ny123.github.io-2ea44f?logo=googlechrome&logoColor=white)](https://r0ny123.github.io/demangle/playground/)
40
41
 
41
42
  **Read mangled symbol names in pure Python** — Itanium C++ (GCC/Clang), MSVC, Rust,
42
43
  Swift, Objective-C, Go, D, Nim, Free Pascal, Delphi, Ada/GNAT, JNI, and the pre-Itanium
@@ -89,7 +90,8 @@ pip install demangle
89
90
  Python 3.11 or newer, on CPython or PyPy. That is the whole dependency list.
90
91
 
91
92
  The documentation, API reference included, is published at
92
- <https://r0ny123.github.io/demangle/>.
93
+ <https://r0ny123.github.io/demangle/>. An interactive in-browser playground is available
94
+ at <https://r0ny123.github.io/demangle/playground/>.
93
95
 
94
96
  ## Use
95
97
 
@@ -320,6 +322,9 @@ Swift's own 217 vectors:
320
322
  ```console
321
323
  $ nm -a libfoo.so | demangle
322
324
  $ demangle _ZNSt6vectorIiSaIiEE9push_backERKi
325
+ $ demangle -b _ZN3foo3barEv # `mangled ==> demangled`
326
+ $ demangle -m _ZN3foo3barEv # only print successfully demangled symbols
327
+ $ demangle -s gnu _ZNSt6vectorIiSaIiEE9push_backERKi # choose output style (llvm, gnu)
323
328
  $ demangle --tree _Z1fPKc
324
329
  $ demangle --detect _RNvC6_123foo3bar
325
330
  $ demangle --detect --strict _ZN3Foo # the scheme that reads it, or an error
@@ -338,6 +343,7 @@ $ demangle --json _Z1fPi # the parse tree as JSON
338
343
  $ nm -a libfoo.so | demangle --json-lines # a JSON object per symbol
339
344
  $ demangle --json-lines --signature _Z1fPi # ... with the parts of the name
340
345
  $ printf '%s\0' "$name" | demangle -0 # whole names ended by NUL, in and out
346
+ $ demangle --list-languages # list supported schemes and aliases
341
347
  ```
342
348
 
343
349
  `--json-lines` writes one object per name, `{"mangled": ..., "demangled": ...,
@@ -396,6 +402,15 @@ Taken from `benchmarks/baseline.json`; treat them as ratios rather than absolute
396
402
  gap between cold and warm is the point: symbol tables repeat themselves relentlessly, and
397
403
  results are cached.
398
404
 
405
+ On names it has not seen, a native demangler is faster than this one by an order of
406
+ magnitude or more: LLVM's, through its Python binding `llvm-demangle-fxti`, reads the
407
+ Itanium names libstdc++ exports about 50 times as fast as this package does cold. This
408
+ package is fast enough in practice because a symbol table repeats its names, and a name
409
+ read once costs a dictionary lookup afterwards. [Comparison with other
410
+ demanglers](https://r0ny123.github.io/demangle/comparison/) has the measurements against it
411
+ and other tools, what each one covers, and what this one offers instead;
412
+ `benchmarks/compare.py` reproduces them.
413
+
399
414
  `bench.py --check` gates CI against the committed baseline. It compares figures
400
415
  normalised against a calibration workload measured in the same run, so the gate reports
401
416
  a slower *demangler* rather than a slower *machine*.
@@ -4,6 +4,7 @@
4
4
  [![Python](https://img.shields.io/badge/python-3.11%2B-blue)](https://www.python.org/downloads/)
5
5
  [![Licence](https://img.shields.io/badge/licence-MIT-green)](https://github.com/r0ny123/demangle/blob/main/LICENSE)
6
6
  [![Docs](https://img.shields.io/badge/docs-r0ny123.github.io-blue)](https://r0ny123.github.io/demangle/)
7
+ [![Open Playground](https://img.shields.io/badge/Open%20Playground-r0ny123.github.io-2ea44f?logo=googlechrome&logoColor=white)](https://r0ny123.github.io/demangle/playground/)
7
8
 
8
9
  **Read mangled symbol names in pure Python** — Itanium C++ (GCC/Clang), MSVC, Rust,
9
10
  Swift, Objective-C, Go, D, Nim, Free Pascal, Delphi, Ada/GNAT, JNI, and the pre-Itanium
@@ -56,7 +57,8 @@ pip install demangle
56
57
  Python 3.11 or newer, on CPython or PyPy. That is the whole dependency list.
57
58
 
58
59
  The documentation, API reference included, is published at
59
- <https://r0ny123.github.io/demangle/>.
60
+ <https://r0ny123.github.io/demangle/>. An interactive in-browser playground is available
61
+ at <https://r0ny123.github.io/demangle/playground/>.
60
62
 
61
63
  ## Use
62
64
 
@@ -287,6 +289,9 @@ Swift's own 217 vectors:
287
289
  ```console
288
290
  $ nm -a libfoo.so | demangle
289
291
  $ demangle _ZNSt6vectorIiSaIiEE9push_backERKi
292
+ $ demangle -b _ZN3foo3barEv # `mangled ==> demangled`
293
+ $ demangle -m _ZN3foo3barEv # only print successfully demangled symbols
294
+ $ demangle -s gnu _ZNSt6vectorIiSaIiEE9push_backERKi # choose output style (llvm, gnu)
290
295
  $ demangle --tree _Z1fPKc
291
296
  $ demangle --detect _RNvC6_123foo3bar
292
297
  $ demangle --detect --strict _ZN3Foo # the scheme that reads it, or an error
@@ -305,6 +310,7 @@ $ demangle --json _Z1fPi # the parse tree as JSON
305
310
  $ nm -a libfoo.so | demangle --json-lines # a JSON object per symbol
306
311
  $ demangle --json-lines --signature _Z1fPi # ... with the parts of the name
307
312
  $ printf '%s\0' "$name" | demangle -0 # whole names ended by NUL, in and out
313
+ $ demangle --list-languages # list supported schemes and aliases
308
314
  ```
309
315
 
310
316
  `--json-lines` writes one object per name, `{"mangled": ..., "demangled": ...,
@@ -363,6 +369,15 @@ Taken from `benchmarks/baseline.json`; treat them as ratios rather than absolute
363
369
  gap between cold and warm is the point: symbol tables repeat themselves relentlessly, and
364
370
  results are cached.
365
371
 
372
+ On names it has not seen, a native demangler is faster than this one by an order of
373
+ magnitude or more: LLVM's, through its Python binding `llvm-demangle-fxti`, reads the
374
+ Itanium names libstdc++ exports about 50 times as fast as this package does cold. This
375
+ package is fast enough in practice because a symbol table repeats its names, and a name
376
+ read once costs a dictionary lookup afterwards. [Comparison with other
377
+ demanglers](https://r0ny123.github.io/demangle/comparison/) has the measurements against it
378
+ and other tools, what each one covers, and what this one offers instead;
379
+ `benchmarks/compare.py` reproduces them.
380
+
366
381
  `bench.py --check` gates CI against the committed baseline. It compares figures
367
382
  normalised against a calibration workload measured in the same run, so the gate reports
368
383
  a slower *demangler* rather than a slower *machine*.
@@ -91,8 +91,8 @@ name that caused it rather than being killed.
91
91
 
92
92
  | Version | Supported |
93
93
  | --- | --- |
94
- | 0.3.x | yes |
95
- | < 0.3 | no |
94
+ | 0.7.x | yes |
95
+ | < 0.7 | no |
96
96
 
97
97
  Until 1.0, security fixes land on the latest released minor version only. There is no
98
98
  long-term support branch and no backporting; upgrading to the current minor version is
@@ -0,0 +1,106 @@
1
+ """Paired signature audit using the same parser and corpus in both versions.
2
+
3
+ Uses the source-module comparison protocol of audit_api.py/audit_core.py. Alternating
4
+ trials reduce process/runner drift; full field parity gates every retained result.
5
+ """
6
+
7
+ import argparse
8
+ import dataclasses
9
+ import gc
10
+ import json
11
+ import statistics
12
+ import subprocess
13
+ import sys
14
+ import time
15
+ import tracemalloc
16
+ import types
17
+ from pathlib import Path
18
+
19
+ import bench
20
+
21
+ from demangle import _signature
22
+ from demangle.core.ast import Function, Name, Pointer
23
+
24
+
25
+ def main():
26
+ parser = argparse.ArgumentParser(description=__doc__)
27
+ parser.add_argument("--before", default="03bd234e6684a7b42672bd962da3f21cfa3e1adb")
28
+ parser.add_argument("--trials", type=int, default=9)
29
+ parser.add_argument("--output", type=Path, required=True)
30
+ args = parser.parse_args()
31
+ if args.trials < 3:
32
+ parser.error("at least three trials are required")
33
+ source = subprocess.check_output(
34
+ ["git", "show", f"{args.before}:src/demangle/_signature.py"], cwd=bench.ROOT, text=True
35
+ )
36
+ old = types.ModuleType("demangle._signature")
37
+ old.__package__ = "demangle"
38
+ exec(compile(source, "baseline_signature.py", "exec"), old.__dict__)
39
+ groups = {
40
+ language: [(language, name) for name in bench.corpus_sample(corpus, 256)]
41
+ for language, corpus in (
42
+ ("itanium", "itanium-real-world.txt"),
43
+ ("msvc", "msvc-llvm-corpus.txt"),
44
+ ("rust", "rust-real-world.txt"),
45
+ ("go", "go-real-world.txt"),
46
+ ("swift", "swift-real-world.txt"),
47
+ )
48
+ }
49
+ groups["mixed"] = [item for group in groups.values() for item in group]
50
+ results = {}
51
+ for group, inputs in groups.items():
52
+ assert [dataclasses.asdict(old.signature(name, language=language)) for language, name in inputs] == [
53
+ dataclasses.asdict(_signature.signature(name, language=language)) for language, name in inputs
54
+ ], group
55
+ samples = {"before": [], "after": []}
56
+ functions = [("before", old.signature), ("after", _signature.signature)]
57
+ for trial in range(args.trials):
58
+ for label, function in functions if trial % 2 else reversed(functions):
59
+ gc.collect()
60
+ start = time.perf_counter()
61
+ for language, name in inputs:
62
+ function(name, language=language)
63
+ samples[label].append((time.perf_counter() - start) * 1000)
64
+ medians = {label: statistics.median(values) for label, values in samples.items()}
65
+ results[group] = {
66
+ "names": len(inputs),
67
+ "samples_ms": samples,
68
+ "medians_ms": medians,
69
+ "change_percent": 100 * (medians["after"] / medians["before"] - 1),
70
+ }
71
+ graphs = {}
72
+ for depth in (40, 120, 400):
73
+ parameter = Name("item")
74
+ for _ in range(depth):
75
+ parameter = Pointer(parameter)
76
+ tree = Function(None, (parameter,) * 32, name=Name("f"))
77
+ peaks = {}
78
+ fields = []
79
+ for label, module in (("before", old), ("after", _signature)):
80
+ gc.collect()
81
+ tracemalloc.start()
82
+ result = module._extract(module._Reading("itanium", "::", "gnu"), tree)
83
+ peaks[label] = tracemalloc.get_traced_memory()[1]
84
+ tracemalloc.stop()
85
+ fields.append(dataclasses.asdict(result))
86
+ assert fields[0] == fields[1], depth
87
+ graphs[depth] = {"shared_parameters": 32, "peak_bytes": peaks}
88
+ args.output.write_text(
89
+ json.dumps(
90
+ {
91
+ "baseline": args.before,
92
+ "python": sys.version,
93
+ "trials": args.trials,
94
+ "shared_current_parsers": True,
95
+ "groups": results,
96
+ "constructed_graphs": graphs,
97
+ },
98
+ indent=2,
99
+ )
100
+ + "\n"
101
+ )
102
+ print(args.output)
103
+
104
+
105
+ if __name__ == "__main__":
106
+ main()
@@ -0,0 +1,68 @@
1
+ {
2
+ "cold": {
3
+ "names": 14101,
4
+ "seconds": 0.648513,
5
+ "per_second": 21744,
6
+ "microseconds_each": 45.991,
7
+ "normalised": 1329.407,
8
+ "relative_to_pivot": 123.19
9
+ },
10
+ "warm": {
11
+ "names": 42303,
12
+ "seconds": 0.015793,
13
+ "per_second": 2678592,
14
+ "microseconds_each": 0.373,
15
+ "normalised": 10.792
16
+ },
17
+ "negative": {
18
+ "names": 14101,
19
+ "seconds": 0.011647,
20
+ "per_second": 1210698,
21
+ "microseconds_each": 0.826,
22
+ "normalised": 23.876,
23
+ "relative_to_pivot": 2.2124
24
+ },
25
+ "structured": {
26
+ "names": 636,
27
+ "seconds": 0.035171,
28
+ "per_second": 18083,
29
+ "microseconds_each": 55.3,
30
+ "parsed": 636,
31
+ "normalised": 1598.062,
32
+ "relative_to_pivot": 148.0849
33
+ },
34
+ "calibration": {
35
+ "seconds": 0.034605,
36
+ "rounds": 200000
37
+ },
38
+ "swift": {
39
+ "names": 256,
40
+ "seconds": 0.0181,
41
+ "per_second": 14174,
42
+ "microseconds_each": 70.55,
43
+ "succeeded": 256,
44
+ "normalised": 2303.46,
45
+ "relative_to_pivot": 336.776,
46
+ "recorded_on": "GitHub Actions ubuntu-24.04, CPython 3.13.16; run 38108232827"
47
+ },
48
+ "swift_parse": {
49
+ "names": 256,
50
+ "seconds": 0.0213,
51
+ "per_second": 12046,
52
+ "microseconds_each": 83.02,
53
+ "succeeded": 256,
54
+ "normalised": 2710.43,
55
+ "relative_to_pivot": 396.277,
56
+ "recorded_on": "GitHub Actions ubuntu-24.04, CPython 3.13.16; run 38108232827"
57
+ },
58
+ "signature": {
59
+ "names": 1280,
60
+ "seconds": 0.0963,
61
+ "per_second": 13289,
62
+ "microseconds_each": 75.25,
63
+ "succeeded": 1280,
64
+ "normalised": 2456.81,
65
+ "relative_to_pivot": 359.197,
66
+ "recorded_on": "GitHub Actions ubuntu-24.04, CPython 3.13.16; run 38108232827"
67
+ }
68
+ }