Skip to content

Instantly share code, notes, and snippets.

@mpeterv
Created September 27, 2014 08:18
Show Gist options
  • Save mpeterv/d1741738876e9923e77c to your computer and use it in GitHub Desktop.
Save mpeterv/d1741738876e9923e77c to your computer and use it in GitHub Desktop.
Program flow graph printer using luacheck.flow
-- Requires luacheck scm-6
-- Reads a Lua program from stdin, prints program flow graph for top level closure.
-- Format: node id: (ids of previous nodes) -> ast node tag:line:column -> (ids of next nodes)
-- Crashes on `break` or `goto` or labels.
local flow = require "luacheck.flow"
local parser = require "metalua.compiler".new()
local src = assert(io.stdin:read("*a"))
local ast = assert(parser:src_to_ast(src))
local intel = {closures = {{stmts = ast}}, gotos = {}}
flow(intel)
local node_to_i = {}
for i=1, #intel.flow_nodes do
local node = intel.flow_nodes[i]
node_to_i[node] = i
if node.ast_node then
node.ast_node = ("%s:%d:%d"):format(node.ast_node.tag or "Block",
node.ast_node.lineinfo.first.line,
node.ast_node.lineinfo.first.column)
end
end
local function pad(s, l)
return s .. (" "):rep(math.max(l-#s, 0))
end
local function tuple(t)
return "("..table.concat(t, ",")..")"
end
for i, node in ipairs(intel.flow_nodes) do
local prevs = {}
for _, prev in ipairs(node.prevs) do
table.insert(prevs, tostring(node_to_i[prev]))
end
local nexts = {}
for _, next_ in ipairs(node.nexts) do
table.insert(nexts, tostring(node_to_i[next_]))
end
print(("%s %s -> %s -> %s"):format(
pad(i..":", 4),
pad(tuple(prevs), 10),
pad(node.ast_node or "Virtual", 15),
pad(tuple(nexts), 10)
))
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment