makepad/libs/relax/compiler/bench_rt/demangle_v0.py
Admin b22a714840 makepad run: the Rust JIT (libs/relax) and makepad-remote
The JIT that runs makepad apps from source: lexer, front end, type checker,
lazy borrow checker (Gandalf; `--check-first` opts in), codegen, session and
warm/cold caches keyed by compiler stamp, provided crates bound late,
startup images, live patching. User-facing name is `makepad run` (binary
`makepad`, MAKEPAD_RUN_* env, ~/.makepad-run); libs/relax stays the internal
library name. `makepad check` reports rustc-style diagnostics with rustc
error codes and checks a whole workspace (`--workspace`). Runs on macOS,
Linux, Windows and Android. makepad-remote: one tool schema for apps and the
WM (app/1): grabs, captures, traces, frame profiles and tweaks.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-13 12:26:21 +02:00

194 lines
5.4 KiB
Python

"""Minimal Rust v0 symbol demangler (rustc's `_R` mangling; RFC 2603) for asmdiff/rank: paths, impls,
generic args and types; enough to name functions like rustc-demangle does (no hashes)."""
BASIC = {"a": "i8", "b": "bool", "c": "char", "d": "f64", "e": "str", "f": "f32", "h": "u8", "i": "isize", "j": "usize",
"l": "i32", "m": "u32", "n": "i128", "o": "u128", "s": "i16", "t": "u16", "u": "()", "v": "...", "x": "i64",
"y": "u64", "z": "!", "p": "_"}
class P:
def __init__(self, s):
self.s = s
self.i = 0
def peek(self):
return self.s[self.i] if self.i < len(self.s) else ""
def eat(self, c):
if self.peek() == c:
self.i += 1
return True
return False
def next(self):
c = self.s[self.i]
self.i += 1
return c
def b62(self):
# base-62 number terminated by '_' ("_" alone = 0)
if self.eat("_"):
return 0
n = 0
while True:
c = self.next()
if c == "_":
return n + 1
if c.isdigit():
d = ord(c) - 48
elif c.islower():
d = ord(c) - 97 + 10
else:
d = ord(c) - 65 + 36
n = n * 62 + d
def dec(self):
j = self.i
while self.peek().isdigit():
self.i += 1
return int(self.s[j:self.i])
def ident(self):
if self.eat("s"):
self.b62()
puny = self.eat("u")
n = self.dec()
if n > 0:
self.eat("_")
t = self.s[self.i:self.i + n]
self.i += n
return t
def backref(self, f):
pos = self.b62()
save = self.i
self.i = pos # positions count from after "_R"
r = f()
self.i = save
return r
def path(self):
c = self.next()
if c == "C":
return self.ident()
if c == "M":
self.impl_path()
return "<" + self.type() + ">"
if c == "X":
self.impl_path()
t = self.type()
return "<" + t + " as " + self.path() + ">"
if c == "Y":
t = self.type()
return "<" + t + " as " + self.path() + ">"
if c == "N":
ns = self.next()
p = self.path()
name = self.ident()
if ns == "C":
return p + "::{closure}"
if ns.isupper():
return p + "::{" + ns.lower() + "}" + ("" if not name else name)
return p + "::" + name
if c == "I":
p = self.path()
args = []
while not self.eat("E"):
args.append(self.generic_arg())
args = [a for a in args if a is not None]
return p + ("<" + ", ".join(args) + ">" if args else "")
if c == "B":
return self.backref(self.path)
raise ValueError("path " + c)
def impl_path(self):
if self.eat("s"):
self.b62()
return self.path()
def generic_arg(self):
if self.eat("L"):
self.b62()
return None
if self.eat("K"):
return self.const()
return self.type()
def const(self):
if self.eat("p"):
return "_"
if self.eat("B"):
return self.backref(self.const)
t = self.next()
neg = self.eat("n")
j = self.i
while self.peek() != "_":
self.i += 1
h = self.s[j:self.i]
self.i += 1
return ("-" if neg else "") + str(int(h, 16) if h else 0)
def type(self):
c = self.peek()
if c in BASIC:
self.i += 1
return BASIC[c]
self.i += 1
if c == "A":
t = self.type()
return "[%s; %s]" % (t, self.const())
if c == "S":
return "[" + self.type() + "]"
if c == "T":
ts = []
while not self.eat("E"):
ts.append(self.type())
return "(" + ", ".join(ts) + ("," if len(ts) == 1 else "") + ")"
if c in "RQ":
if self.eat("L"):
self.b62()
return ("&" if c == "R" else "&mut ") + self.type()
if c in "PO":
return ("*const " if c == "P" else "*mut ") + self.type()
if c == "F":
if self.eat("G"):
self.b62()
self.eat("U")
if self.eat("K"):
if not self.eat("C"):
self.ident()
ts = []
while not self.eat("E"):
ts.append(self.type())
r = self.type()
return "fn(" + ", ".join(ts) + ") -> " + r
if c == "D":
if self.eat("G"):
self.b62()
bs = []
while not self.eat("E"):
p = self.path()
while self.eat("p"):
self.ident()
self.type()
bs.append(p)
if self.eat("L"):
self.b62()
return "dyn " + " + ".join(bs)
if c == "B":
return self.backref(self.type)
self.i -= 1
return self.path()
def demangle(sym):
s = sym.lstrip("_")
if not s.startswith("R"):
return None
try:
p = P(s[1:])
if p.peek().isdigit():
p.dec()
return p.path()
except (ValueError, IndexError):
return None