mirror of
https://github.com/nim-lang/Nim.git
synced 2025-12-28 17:04:41 +00:00
151 lines
4.1 KiB
Nim
151 lines
4.1 KiB
Nim
|
|
include prelude
|
|
import intsets
|
|
|
|
type
|
|
NodeKind = enum
|
|
internal, local, localInvalid, global, globalInvalid
|
|
Color = enum
|
|
white, grey, black
|
|
Node = ref object
|
|
id, rc: int
|
|
kids: seq[int]
|
|
k: NodeKind
|
|
col: Color
|
|
Graph = object
|
|
nodes: Table[int, Node]
|
|
roots: Table[int, NodeKind]
|
|
|
|
proc add(father: Node; son: int) =
|
|
if father.kids.isNil: father.kids = @[]
|
|
father.kids.add(son)
|
|
|
|
proc renderNode(g: Graph; id: int) =
|
|
let n = g.nodes[id]
|
|
echo n[]
|
|
|
|
proc toNodeId(aliases: var Table[string,int]; s: string): int =
|
|
result = aliases.getOrDefault(s)
|
|
if result == 0:
|
|
if s.startsWith("x"):
|
|
discard s.parseHex(result, 1)
|
|
else:
|
|
result = s.parseInt
|
|
|
|
proc parseHex(s: string): int =
|
|
discard parseutils.parseHex(s, result, 0)
|
|
|
|
proc reachable(g: Graph; stack: var seq[int]; goal: int): bool =
|
|
var t = initIntSet()
|
|
while stack.len > 0:
|
|
let it = stack.pop
|
|
if not t.containsOrIncl(it):
|
|
if it == goal: return true
|
|
if it in g.nodes:
|
|
for kid in g.nodes[it].kids:
|
|
stack.add(kid)
|
|
|
|
const Help = """
|
|
quit -- quits this REPL
|
|
locals, l -- output the list of local stack roots
|
|
globals, g -- output the list of global roots
|
|
alias name addr -- give addr a name. start 'addr' with 'x' for hexidecimal
|
|
notation
|
|
print name|addr -- print a node by name or address
|
|
reachable,r l|g|node dest -- outputs TRUE or FALSE depending on whether
|
|
dest is reachable by (l)ocals, (g)lobals or by the
|
|
other given node. Nodes can be node names or node
|
|
addresses.
|
|
"""
|
|
|
|
proc repl(g: Graph) =
|
|
var aliases = initTable[string,int]()
|
|
while true:
|
|
let line = stdin.readLine()
|
|
let data = line.split()
|
|
if data.len == 0: continue
|
|
case data[0]
|
|
of "quit":
|
|
break
|
|
of "help":
|
|
echo Help
|
|
of "locals", "l":
|
|
for k,v in g.roots:
|
|
if v == local: renderNode(g, k)
|
|
of "globals", "g":
|
|
for k,v in g.roots:
|
|
if v == global: renderNode(g, k)
|
|
of "alias", "a":
|
|
# generate alias
|
|
if data.len == 3:
|
|
aliases[data[1]] = toNodeId(aliases, data[2])
|
|
of "print", "p":
|
|
if data.len == 2:
|
|
renderNode(g, toNodeId(aliases, data[1]))
|
|
of "reachable", "r":
|
|
if data.len == 3:
|
|
var stack: seq[int] = @[]
|
|
case data[1]
|
|
of "locals", "l":
|
|
for k,v in g.roots:
|
|
if v == local: stack.add k
|
|
of "globals", "g":
|
|
for k,v in g.roots:
|
|
if v == global: stack.add k
|
|
else:
|
|
stack.add(toNodeId(aliases, data[1]))
|
|
let goal = toNodeId(aliases, data[2])
|
|
echo reachable(g, stack, goal)
|
|
else: discard
|
|
|
|
proc importData(input: string): Graph =
|
|
#c_fprintf(file, "%s %p %d rc=%ld color=%c\n",
|
|
# msg, c, kind, c.refcount shr rcShift, col)
|
|
# cell 0x10a908190 22 rc=2 color=w
|
|
var i: File
|
|
var
|
|
nodes = initTable[int, Node]()
|
|
roots = initTable[int, NodeKind]()
|
|
if open(i, input):
|
|
var currNode: Node
|
|
for line in lines(i):
|
|
let data = line.split()
|
|
if data.len == 0: continue
|
|
case data[0]
|
|
of "end":
|
|
currNode = nil
|
|
of "cell":
|
|
let rc = parseInt(data[3].substr("rc=".len))
|
|
let col = case data[4].substr("color=".len)
|
|
of "b": black
|
|
of "w": white
|
|
of "g": grey
|
|
else: (assert(false); grey)
|
|
let id = parseHex(data[1])
|
|
currNode = Node(id: id,
|
|
k: roots.getOrDefault(id),
|
|
rc: rc, col: col)
|
|
nodes[currNode.id] = currNode
|
|
of "child":
|
|
assert currNode != nil
|
|
currNode.add parseHex(data[1])
|
|
of "global_root":
|
|
roots[data[1].parseHex] = global
|
|
of "global_root_invalid":
|
|
roots[data[1].parseHex] = globalInvalid
|
|
of "onstack":
|
|
roots[data[1].parseHex] = local
|
|
of "onstack_invalid":
|
|
roots[data[1].parseHex] = localInvalid
|
|
else: discard
|
|
close(i)
|
|
else:
|
|
quit "error: cannot open " & input
|
|
shallowCopy(result.nodes, nodes)
|
|
shallowCopy(result.roots, roots)
|
|
|
|
if paramCount() == 1:
|
|
repl(importData(paramStr(1)))
|
|
else:
|
|
quit "usage: heapdumprepl inputfile"
|