Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 103236b

Browse files
committed
Render CFG using new mermaid code
1 parent 7f4fe77 commit 103236b

File tree

4 files changed

+74
-43
lines changed

4 files changed

+74
-43
lines changed

lib/syntax_tree.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
require_relative "syntax_tree/visitor/environment"
2424
require_relative "syntax_tree/visitor/with_environment"
2525

26+
require_relative "syntax_tree/mermaid"
2627
require_relative "syntax_tree/parser"
2728
require_relative "syntax_tree/pattern"
2829
require_relative "syntax_tree/search"

lib/syntax_tree/mermaid.rb

Lines changed: 52 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ module SyntaxTree
66
# This module is responsible for rendering mermaid flow charts.
77
module Mermaid
88
class Node
9-
SHAPES = %i[circle rectangle stadium].freeze
9+
SHAPES = %i[circle rectangle rounded stadium].freeze
1010

1111
attr_reader :id, :label, :shape
1212

@@ -19,17 +19,23 @@ def initialize(id, label, shape)
1919
end
2020

2121
def render
22-
left_bound, right_bound =
23-
case shape
24-
when :circle
25-
["((", "))"]
26-
when :rectangle
27-
["[", "]"]
28-
when :stadium
29-
["([", "])"]
30-
end
22+
left_bound, right_bound = bounds
23+
"#{id}#{left_bound}\"#{CGI.escapeHTML(label)}\"#{right_bound}"
24+
end
3125

32-
" #{id}#{left_bound}\"#{CGI.escapeHTML(label)}\"#{right_bound}"
26+
private
27+
28+
def bounds
29+
case shape
30+
when :circle
31+
["((", "))"]
32+
when :rectangle
33+
["[", "]"]
34+
when :rounded
35+
["(", ")"]
36+
when :stadium
37+
["([", "])"]
38+
end
3339
end
3440
end
3541

@@ -50,34 +56,57 @@ def initialize(from, to, label, type)
5056
def render
5157
case type
5258
when :directed
53-
" #{from.id} -- \"#{CGI.escapeHTML(label)}\" --> #{to.id}"
59+
if label
60+
"#{from.id} -- \"#{CGI.escapeHTML(label)}\" --> #{to.id}"
61+
else
62+
"#{from.id} --> #{to.id}"
63+
end
5464
end
5565
end
5666
end
5767

5868
class FlowChart
59-
attr_reader :nodes, :edges
69+
attr_reader :output, :prefix, :nodes
6070

6171
def initialize
72+
@output = StringIO.new
73+
@output.puts("flowchart TD")
74+
@prefix = " "
6275
@nodes = {}
63-
@edges = []
6476
end
6577

66-
def edge(from, to, label, type = :directed)
67-
edges << Edge.new(from, to, label, type)
78+
def edge(from, to, label = nil, type: :directed)
79+
edge = Edge.new(from, to, label, type)
80+
output.puts("#{prefix}#{edge.render}")
6881
end
6982

70-
def node(id, label, shape = :rectangle)
71-
nodes[id] = Node.new(id, label, shape)
83+
def fetch(id)
84+
nodes.fetch(id)
7285
end
7386

74-
def render
75-
output = StringIO.new
76-
output.puts("flowchart TD")
87+
def node(id, label, shape: :rectangle)
88+
node = Node.new(id, label, shape)
89+
nodes[id] = node
90+
91+
output.puts("#{prefix}#{nodes[id].render}")
92+
node
93+
end
94+
95+
def subgraph(id)
96+
output.puts("#{prefix}subgraph #{id}")
97+
98+
previous = prefix
99+
@prefix = "#{prefix} "
77100

78-
nodes.each_value { |node| output.puts(node.render) }
79-
edges.each { |edge| output.puts(edge.render) }
101+
begin
102+
yield
103+
ensure
104+
@prefix = previous
105+
output.puts("#{prefix}end")
106+
end
107+
end
80108

109+
def render
81110
output.string
82111
end
83112
end

lib/syntax_tree/visitor/mermaid_visitor.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ def field(name, value)
2929
when Node
3030
flowchart.edge(target, visit(value), name)
3131
else
32-
to = flowchart.node("#{target.id}_#{name}", value.inspect, :stadium)
32+
to = flowchart.node("#{target.id}_#{name}", value.inspect, shape: :stadium)
3333
flowchart.edge(target, to, name)
3434
end
3535
end
@@ -54,7 +54,7 @@ def node(node, type)
5454

5555
def pairs(name, values)
5656
values.each_with_index do |(key, value), index|
57-
to = flowchart.node("#{target.id}_#{name}_#{index}", " ", :circle)
57+
to = flowchart.node("#{target.id}_#{name}_#{index}", " ", shape: :circle)
5858

5959
flowchart.edge(target, to, "#{name}[#{index}]")
6060
flowchart.edge(to, visit(key), "[0]")

lib/syntax_tree/yarv/control_flow_graph.rb

Lines changed: 19 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -208,25 +208,24 @@ def to_son
208208
end
209209

210210
def to_mermaid
211-
output = StringIO.new
212-
output.puts("flowchart TD")
211+
flowchart = Mermaid::FlowChart.new
212+
disasm = Disassembler::Mermaid.new
213213

214-
fmt = Disassembler::Mermaid.new
215214
blocks.each do |block|
216-
output.puts(" subgraph #{block.id}")
217-
previous = nil
218-
219-
block.each_with_length do |insn, length|
220-
node_id = "node_#{length}"
221-
label = "%04d %s" % [length, insn.disasm(fmt)]
222-
223-
output.puts(" #{node_id}(\"#{CGI.escapeHTML(label)}\")")
224-
output.puts(" #{previous} --> #{node_id}") if previous
225-
226-
previous = node_id
215+
flowchart.subgraph(block.id) do
216+
previous = nil
217+
218+
block.each_with_length do |insn, length|
219+
node =
220+
flowchart.node(
221+
"node_#{length}",
222+
"%04d %s" % [length, insn.disasm(disasm)]
223+
)
224+
225+
flowchart.edge(previous, node) if previous
226+
previous = node
227+
end
227228
end
228-
229-
output.puts(" end")
230229
end
231230

232231
blocks.each do |block|
@@ -235,11 +234,13 @@ def to_mermaid
235234
block.block_start + block.insns.sum(&:length) -
236235
block.insns.last.length
237236

238-
output.puts(" node_#{offset} --> node_#{outgoing.block_start}")
237+
from = flowchart.fetch("node_#{offset}")
238+
to = flowchart.fetch("node_#{outgoing.block_start}")
239+
flowchart.edge(from, to)
239240
end
240241
end
241242

242-
output.string
243+
flowchart.render
243244
end
244245

245246
# This method is used to verify that the control flow graph is well

0 commit comments

Comments
 (0)