This PR replaces three independent name demangling implementations
(Lean, C++, Python) with a single source of truth in
`Lean.Compiler.NameDemangling`. The new module handles the full
pipeline: prefix parsing (`l_`, `lp_`, `_init_`, `initialize_`,
`lean_apply_N`, `_lean_main`), postprocessing (suffix flags, private
name stripping, hygienic suffix stripping, specialization contexts),
backtrace line parsing, and C exports via `@[export]`.
The C++ runtime backtrace handler now calls the Lean-exported functions
instead of its own 792-line reimplementation. This is safe because
`print_backtrace` is only called from `lean_panic_impl` (soft panics),
not `lean_internal_panic`.
The Python profiler demangler (`script/profiler/lean_demangle.py`) is
replaced with a thin subprocess wrapper around a Lean CLI tool,
preserving the `demangle_lean_name` API so downstream scripts work
unchanged.
**New files:**
- `src/Lean/Compiler/NameDemangling.lean` — single source of truth (483
lines)
- `tests/lean/run/demangling.lean` — comprehensive tests (281 lines)
- `script/profiler/lean_demangle_cli.lean` — `c++filt`-style CLI tool
**Deleted files:**
- `src/runtime/demangle.cpp` (792 lines)
- `src/runtime/demangle.h` (26 lines)
- `script/profiler/test_demangle.py` (670 lines)
Net: −1,381 lines of duplicated C++/Python code.
🤖 Prepared with Claude Code
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
89 lines
2.6 KiB
Text
89 lines
2.6 KiB
Text
/-
|
||
Copyright (c) 2020 Microsoft Corporation. All rights reserved.
|
||
Released under Apache 2.0 license as described in the file LICENSE.
|
||
Authors: Leonardo de Moura
|
||
-/
|
||
module
|
||
|
||
prelude
|
||
public import Lean.Data.PrefixTree
|
||
import Init.Data.Ord.String
|
||
|
||
public section
|
||
|
||
namespace Lean
|
||
|
||
inductive NamePart
|
||
| str (s : String)
|
||
| num (n : Nat)
|
||
deriving BEq, Inhabited
|
||
|
||
instance : ToString NamePart where
|
||
toString
|
||
| NamePart.str s => s
|
||
| NamePart.num n => toString n
|
||
|
||
def NamePart.cmp : NamePart → NamePart → Ordering
|
||
| NamePart.str a, NamePart.str b => compare a b
|
||
| NamePart.num a, NamePart.num b => compare a b
|
||
| NamePart.num _, NamePart.str _ => Ordering.lt
|
||
| _, _ => Ordering.gt
|
||
|
||
def NamePart.lt : NamePart → NamePart → Bool
|
||
| NamePart.str a, NamePart.str b => a < b
|
||
| NamePart.num a, NamePart.num b => a < b
|
||
| NamePart.num _, NamePart.str _ => true
|
||
| _, _ => false
|
||
|
||
@[expose] def NameTrie (β : Type u) := PrefixTree NamePart β NamePart.cmp
|
||
|
||
private def toKey (n : Name) : List NamePart :=
|
||
loop n []
|
||
where
|
||
loop
|
||
| Name.str p s, parts => loop p (NamePart.str s :: parts)
|
||
| Name.num p n, parts => loop p (NamePart.num n :: parts)
|
||
| Name.anonymous, parts => parts
|
||
|
||
def NameTrie.insert (t : NameTrie β) (n : Name) (b : β) : NameTrie β :=
|
||
PrefixTree.insert t (toKey n) b
|
||
|
||
def NameTrie.empty : NameTrie β :=
|
||
PrefixTree.empty
|
||
|
||
instance : Inhabited (NameTrie β) where
|
||
default := NameTrie.empty
|
||
|
||
instance : EmptyCollection (NameTrie β) where
|
||
emptyCollection := NameTrie.empty
|
||
|
||
def NameTrie.find? (t : NameTrie β) (k : Name) : Option β :=
|
||
PrefixTree.find? t (toKey k)
|
||
|
||
@[inline, inherit_doc PrefixTree.findLongestPrefix?]
|
||
def NameTrie.findLongestPrefix? (t : NameTrie β) (k : Name) : Option β :=
|
||
PrefixTree.findLongestPrefix? t (toKey k)
|
||
|
||
@[inline]
|
||
def NameTrie.foldMatchingM [Monad m] (t : NameTrie β) (k : Name) (init : σ) (f : β → σ → m σ) : m σ :=
|
||
PrefixTree.foldMatchingM t (toKey k) init f
|
||
|
||
@[inline]
|
||
def NameTrie.foldM [Monad m] (t : NameTrie β) (init : σ) (f : β → σ → m σ) : m σ :=
|
||
t.foldMatchingM Name.anonymous init f
|
||
|
||
@[inline]
|
||
def NameTrie.forMatchingM [Monad m] (t : NameTrie β) (k : Name) (f : β → m Unit) : m Unit :=
|
||
PrefixTree.forMatchingM t (toKey k) f
|
||
|
||
@[inline]
|
||
def NameTrie.forM [Monad m] (t : NameTrie β) (f : β → m Unit) : m Unit :=
|
||
t.forMatchingM Name.anonymous f
|
||
|
||
def NameTrie.matchingToArray (t : NameTrie β) (k : Name) : Array β :=
|
||
Id.run <| t.foldMatchingM k #[] fun v acc => return acc.push v
|
||
|
||
def NameTrie.toArray (t : NameTrie β) : Array β :=
|
||
Id.run <| t.foldM #[] fun v acc => return acc.push v
|
||
|
||
end Lean
|