lean4-htt/src/Lean/Data/NameTrie.lean
Kim Morrison 5f3ca3ac3d
feat: unify name demangling with single Lean implementation (#12539)
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>
2026-03-06 12:29:35 +00:00

89 lines
2.6 KiB
Text
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/-
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