seafoam 0.13 → 0.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/bin/bgv2isabelle +3 -2
- data/bin/bgv2json +3 -2
- data/bin/seafoam +3 -2
- data/lib/seafoam/bgv/bgv_parser.rb +58 -50
- data/lib/seafoam/binary/io_binary_reader.rb +19 -17
- data/lib/seafoam/colors.rb +17 -11
- data/lib/seafoam/commands.rb +177 -153
- data/lib/seafoam/formatters/base.rb +2 -0
- data/lib/seafoam/formatters/formatters.rb +5 -3
- data/lib/seafoam/formatters/json.rb +8 -5
- data/lib/seafoam/formatters/text.rb +7 -4
- data/lib/seafoam/graal/graph_description.rb +9 -1
- data/lib/seafoam/graal/pi.rb +10 -6
- data/lib/seafoam/graal/source.rb +13 -9
- data/lib/seafoam/graph.rb +15 -9
- data/lib/seafoam/graphviz_writer.rb +129 -99
- data/lib/seafoam/isabelle_writer.rb +9 -7
- data/lib/seafoam/json_writer.rb +17 -13
- data/lib/seafoam/markdown_writer.rb +5 -3
- data/lib/seafoam/mermaid_writer.rb +36 -24
- data/lib/seafoam/passes/fallback.rb +10 -6
- data/lib/seafoam/passes/graal.rb +189 -161
- data/lib/seafoam/passes/truffle.rb +120 -22
- data/lib/seafoam/passes.rb +36 -29
- data/lib/seafoam/spotlight.rb +4 -2
- data/lib/seafoam/version.rb +3 -1
- data/lib/seafoam.rb +22 -20
- metadata +12 -12
@@ -1,8 +1,10 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Seafoam
|
2
4
|
# Formatters are the mechanism by which `seafoam` command output is presented to the user.
|
3
5
|
module Formatters
|
4
|
-
autoload :Base,
|
5
|
-
autoload :Json,
|
6
|
-
autoload :Text,
|
6
|
+
autoload :Base, "seafoam/formatters/base"
|
7
|
+
autoload :Json, "seafoam/formatters/json"
|
8
|
+
autoload :Text, "seafoam/formatters/text"
|
7
9
|
end
|
8
10
|
end
|
@@ -1,4 +1,6 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "json"
|
2
4
|
|
3
5
|
module Seafoam
|
4
6
|
module Formatters
|
@@ -8,6 +10,7 @@ module Seafoam
|
|
8
10
|
def format
|
9
11
|
ret = Seafoam::Graal::GraphDescription::ATTRIBUTES.map { |attr| [attr, description.send(attr)] }.to_h
|
10
12
|
ret[:node_count] = graph.nodes.size
|
13
|
+
ret[:node_counts] = description.sorted_node_counts
|
11
14
|
|
12
15
|
ret.to_json
|
13
16
|
end
|
@@ -22,7 +25,7 @@ module Seafoam
|
|
22
25
|
def render_node_entry(node)
|
23
26
|
{
|
24
27
|
input: node.inputs.map { |input| build_edge(input) },
|
25
|
-
output: node.outputs.map { |output| build_edge(output) }
|
28
|
+
output: node.outputs.map { |output| build_edge(output) },
|
26
29
|
}.to_json
|
27
30
|
end
|
28
31
|
|
@@ -44,7 +47,7 @@ module Seafoam
|
|
44
47
|
def format
|
45
48
|
{
|
46
49
|
major_version: major_version,
|
47
|
-
minor_version: minor_version
|
50
|
+
minor_version: minor_version,
|
48
51
|
}.to_json
|
49
52
|
end
|
50
53
|
end
|
@@ -56,7 +59,7 @@ module Seafoam
|
|
56
59
|
{
|
57
60
|
graph_index: entry.index,
|
58
61
|
graph_file: entry.file,
|
59
|
-
graph_name_components: entry.graph_name_components
|
62
|
+
graph_name_components: entry.graph_name_components,
|
60
63
|
}
|
61
64
|
end.to_json
|
62
65
|
end
|
@@ -73,7 +76,7 @@ module Seafoam
|
|
73
76
|
name = method[:method_name]
|
74
77
|
{
|
75
78
|
class: declaring_class,
|
76
|
-
method: name
|
79
|
+
method: name,
|
77
80
|
}
|
78
81
|
end
|
79
82
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Seafoam
|
2
4
|
module Formatters
|
3
5
|
module Text
|
@@ -5,8 +7,9 @@ module Seafoam
|
|
5
7
|
class DescribeFormatter < Seafoam::Formatters::Base::DescribeFormatter
|
6
8
|
def format
|
7
9
|
notes = Seafoam::Graal::GraphDescription::ATTRIBUTES.select { |attr| description.send(attr) }
|
10
|
+
node_counts = description.sorted_node_counts.map { |node_class, count| "#{node_class}: #{count}" }.join("\n")
|
8
11
|
|
9
|
-
["#{graph.nodes.size} nodes", *notes].join(
|
12
|
+
["#{graph.nodes.size} nodes", *notes].join(", ") + "\n#{node_counts}"
|
10
13
|
end
|
11
14
|
end
|
12
15
|
|
@@ -19,12 +22,12 @@ module Seafoam
|
|
19
22
|
end
|
20
23
|
|
21
24
|
def render_node_entry(node)
|
22
|
-
ret = [
|
25
|
+
ret = ["Input:"]
|
23
26
|
ret += node.inputs.map do |input|
|
24
27
|
" #{node.id_and_label} <-(#{input.props[:label]}) #{input.from.id_and_label}"
|
25
28
|
end
|
26
29
|
|
27
|
-
ret <<
|
30
|
+
ret << "Output:"
|
28
31
|
ret += node.outputs.map do |output|
|
29
32
|
" #{node.id_and_label} ->(#{output.props[:label]}) #{output.to.id_and_label}"
|
30
33
|
end
|
@@ -48,7 +51,7 @@ module Seafoam
|
|
48
51
|
class ListFormatter < Seafoam::Formatters::Base::ListFormatter
|
49
52
|
def format
|
50
53
|
entries.map do |entry|
|
51
|
-
"#{entry.file}:#{entry.index} #{entry.graph_name_components.join(
|
54
|
+
"#{entry.file}:#{entry.index} #{entry.graph_name_components.join("/")}"
|
52
55
|
end.join("\n")
|
53
56
|
end
|
54
57
|
end
|
@@ -1,21 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Seafoam
|
2
4
|
module Graal
|
3
5
|
# Provides a high level description of a Graal graph's features.
|
4
6
|
class GraphDescription
|
5
|
-
ATTRIBUTES =
|
7
|
+
ATTRIBUTES = [:branches, :calls, :deopts, :linear, :loops]
|
6
8
|
|
7
9
|
ATTRIBUTES.each { |attr| attr_accessor(attr) unless attr == :linear }
|
10
|
+
attr_reader :node_counts
|
8
11
|
|
9
12
|
def initialize
|
10
13
|
@branches = false
|
11
14
|
@calls = false
|
12
15
|
@deopts = false
|
13
16
|
@loops = false
|
17
|
+
@node_counts = Hash.new(0)
|
14
18
|
end
|
15
19
|
|
16
20
|
def linear
|
17
21
|
!branches && !loops
|
18
22
|
end
|
23
|
+
|
24
|
+
def sorted_node_counts
|
25
|
+
@node_counts.to_a.sort_by { |node_class, count| [-count, node_class] }.to_h
|
26
|
+
end
|
19
27
|
end
|
20
28
|
end
|
21
29
|
end
|
data/lib/seafoam/graal/pi.rb
CHANGED
@@ -1,17 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Seafoam
|
2
4
|
module Graal
|
3
5
|
# Routines for understanding pi nodes in Graal.
|
4
6
|
module Pi
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
7
|
+
class << self
|
8
|
+
# Find the actual value behind potentially a chain of pi nodes.
|
9
|
+
def follow_pi_object(node)
|
10
|
+
node = node.edges.find { |edge| edge.props[:name] == "object" }.from while PI_NODES.include?(node.node_class)
|
11
|
+
node
|
12
|
+
end
|
9
13
|
end
|
10
14
|
|
11
15
|
# Pi nodes add type information.
|
12
16
|
PI_NODES = [
|
13
|
-
|
14
|
-
|
17
|
+
"org.graalvm.compiler.nodes.PiNode",
|
18
|
+
"org.graalvm.compiler.nodes.PiArrayNode",
|
15
19
|
]
|
16
20
|
end
|
17
21
|
end
|
data/lib/seafoam/graal/source.rb
CHANGED
@@ -1,18 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Seafoam
|
2
4
|
module Graal
|
3
5
|
# Routines for understanding source positions in Graal.
|
4
6
|
module Source
|
5
|
-
|
6
|
-
|
7
|
+
class << self
|
8
|
+
def walk(source_position, &block)
|
9
|
+
results = []
|
7
10
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
11
|
+
caller = source_position
|
12
|
+
while caller
|
13
|
+
method = caller[:method]
|
14
|
+
results.push(block.call(method))
|
15
|
+
caller = caller[:caller]
|
16
|
+
end
|
14
17
|
|
15
|
-
|
18
|
+
results
|
19
|
+
end
|
16
20
|
end
|
17
21
|
end
|
18
22
|
end
|
data/lib/seafoam/graph.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Seafoam
|
2
4
|
# A graph, with properties, nodes, and edges. We don't encapsulate the graph
|
3
5
|
# too much - be careful.
|
@@ -25,24 +27,24 @@ module Seafoam
|
|
25
27
|
def create_edge(from, to, props = nil)
|
26
28
|
props ||= {}
|
27
29
|
edge = Edge.new(from, to, props)
|
28
|
-
@edges.push
|
29
|
-
from.outputs.push
|
30
|
-
to.inputs.push
|
30
|
+
@edges.push(edge)
|
31
|
+
from.outputs.push(edge)
|
32
|
+
to.inputs.push(edge)
|
31
33
|
edge
|
32
34
|
end
|
33
35
|
|
34
36
|
# Add a new basic block with given id and node id list.
|
35
37
|
def create_block(id, node_ids)
|
36
|
-
nodes = node_ids.select { |n| @nodes.key?
|
38
|
+
nodes = node_ids.select { |n| @nodes.key?(n) }.map { |n| @nodes[n] }
|
37
39
|
block = Block.new(id, nodes)
|
38
|
-
@blocks.push
|
40
|
+
@blocks.push(block)
|
39
41
|
block
|
40
42
|
end
|
41
43
|
|
42
44
|
def remove_edge(edge)
|
43
|
-
edge.from.outputs.delete
|
44
|
-
edge.to.inputs.delete
|
45
|
-
edges.delete
|
45
|
+
edge.from.outputs.delete(edge)
|
46
|
+
edge.to.inputs.delete(edge)
|
47
|
+
edges.delete(edge)
|
46
48
|
end
|
47
49
|
end
|
48
50
|
|
@@ -58,6 +60,10 @@ module Seafoam
|
|
58
60
|
@props = props
|
59
61
|
end
|
60
62
|
|
63
|
+
def node_class
|
64
|
+
@props.dig(:node_class, :node_class)
|
65
|
+
end
|
66
|
+
|
61
67
|
# All edges - input and output.
|
62
68
|
def edges
|
63
69
|
inputs + outputs
|
@@ -79,7 +85,7 @@ module Seafoam
|
|
79
85
|
|
80
86
|
# Inspect.
|
81
87
|
def inspect
|
82
|
-
"<Node #{id}>"
|
88
|
+
"<Node #{id} #{node_class}>"
|
83
89
|
end
|
84
90
|
end
|
85
91
|
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Seafoam
|
2
4
|
# A writer from graphs to the Graphviz DOT format, including all the
|
3
5
|
# formatting.
|
@@ -11,25 +13,64 @@ module Seafoam
|
|
11
13
|
inline_attrs = {}
|
12
14
|
attrs = {}
|
13
15
|
attrs[:dpi] = 200 if hidpi
|
14
|
-
attrs[:bgcolor] =
|
15
|
-
|
16
|
+
attrs[:bgcolor] = "white"
|
17
|
+
start_graph(attrs)
|
18
|
+
write_nodes(inline_attrs, graph, draw_blocks)
|
19
|
+
write_edges(inline_attrs, graph)
|
20
|
+
end_graph
|
21
|
+
end
|
22
|
+
|
23
|
+
def start_graph(attrs)
|
24
|
+
@stream.puts "digraph G {"
|
16
25
|
@stream.puts " graph #{write_attrs(attrs)};"
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
@stream.puts
|
26
|
+
end
|
27
|
+
|
28
|
+
def end_graph
|
29
|
+
@stream.puts "}"
|
21
30
|
end
|
22
31
|
|
23
32
|
private
|
24
33
|
|
25
34
|
# Write node declarations.
|
26
|
-
def write_nodes(inline_attrs, graph)
|
27
|
-
|
28
|
-
|
35
|
+
def write_nodes(inline_attrs, graph, draw_blocks)
|
36
|
+
drawn_in_blocks = []
|
37
|
+
|
38
|
+
if draw_blocks
|
39
|
+
graph.blocks.each do |block|
|
40
|
+
next if block.nodes.all? { |n| n.props[:hidden] || n.props[:inlined] }
|
41
|
+
|
42
|
+
start_subgraph(block.id)
|
43
|
+
|
44
|
+
block.nodes.each do |node|
|
45
|
+
next if node.props[:hidden] || node.props[:inlined]
|
46
|
+
|
47
|
+
write_node(" ", inline_attrs, node)
|
48
|
+
drawn_in_blocks.push(node)
|
49
|
+
end
|
50
|
+
|
51
|
+
end_subgraph
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
(graph.nodes.values - drawn_in_blocks).each do |node|
|
56
|
+
write_node(" ", inline_attrs, node)
|
29
57
|
end
|
30
58
|
end
|
31
59
|
|
32
|
-
def
|
60
|
+
def start_subgraph(id)
|
61
|
+
@stream.puts " subgraph cluster_block#{id} {"
|
62
|
+
@stream.puts ' fontname = "Arial";'
|
63
|
+
@stream.puts " label = \"B#{id}\";"
|
64
|
+
@stream.puts " style = filled;"
|
65
|
+
@stream.puts " color = #{DARK_YELLOW.inspect};"
|
66
|
+
@stream.puts " fillcolor = #{LIGHT_YELLOW.inspect};"
|
67
|
+
end
|
68
|
+
|
69
|
+
def end_subgraph
|
70
|
+
@stream.puts " }"
|
71
|
+
end
|
72
|
+
|
73
|
+
def write_node(indent, inline_attrs, node)
|
33
74
|
# We're going to build up a hash of Graphviz drawing attributes.
|
34
75
|
attrs = {}
|
35
76
|
|
@@ -39,71 +80,75 @@ module Seafoam
|
|
39
80
|
# If the node has any adjacent nodes that are not hidden, and are
|
40
81
|
# shaded, then we need to declare the node but make it invisible so
|
41
82
|
# the edge appears, pointing off into space, but the node does not.
|
42
|
-
if node.adjacent.any? { |a| !a.props[:hidden] && a.props[:spotlight] ==
|
43
|
-
attrs[:style] =
|
44
|
-
attrs[:label] =
|
45
|
-
|
83
|
+
if node.adjacent.any? { |a| !a.props[:hidden] && a.props[:spotlight] == "shaded" }
|
84
|
+
attrs[:style] = "invis"
|
85
|
+
attrs[:label] = ""
|
86
|
+
output_node(indent, "node#{node.id}", attrs)
|
46
87
|
end
|
47
88
|
else
|
48
89
|
# This is a visible node.
|
49
90
|
|
50
91
|
# Give it a label.
|
51
|
-
if node.props[:label]
|
52
|
-
|
92
|
+
attrs[:label] = if node.props[:label]
|
93
|
+
"#{node.id} #{node.props[:label]}"
|
53
94
|
else
|
54
95
|
# If we really still don't have a label, just use the ID.
|
55
|
-
|
96
|
+
node.id.to_s
|
56
97
|
end
|
57
98
|
|
58
99
|
# Basic attributes for a node.
|
59
|
-
attrs[:shape] =
|
60
|
-
attrs[:fontname] =
|
61
|
-
attrs[:style] =
|
62
|
-
attrs[:color] =
|
100
|
+
attrs[:shape] = "rectangle"
|
101
|
+
attrs[:fontname] = "Arial"
|
102
|
+
attrs[:style] = "filled"
|
103
|
+
attrs[:color] = "black"
|
63
104
|
|
64
105
|
# Color depends on the kind of node.
|
65
106
|
back_color, fore_color = NODE_COLORS[node.props[:kind]]
|
66
107
|
attrs[:fillcolor] = back_color
|
67
108
|
attrs[:fontcolor] = fore_color
|
68
109
|
|
110
|
+
# If the node is shaded, convert the attributes to the shaded
|
111
|
+
# version.
|
112
|
+
attrs = shade(attrs) if node.props[:spotlight] == "shaded"
|
113
|
+
|
69
114
|
if node.props[:inlined]
|
70
115
|
# If the node is to be inlined then draw it smaller and a different
|
71
116
|
# shape.
|
72
|
-
attrs[:shape] =
|
73
|
-
attrs[:fontsize] =
|
117
|
+
attrs[:shape] = "oval"
|
118
|
+
attrs[:fontsize] = "8"
|
74
119
|
|
75
120
|
# Just record these attributes for where it's used by other nodes
|
76
121
|
# so it can be drawn above them - don't actually declare a node.
|
77
122
|
inline_attrs[node.id] = attrs
|
78
123
|
else
|
79
|
-
attrs[:shape] =
|
80
|
-
|
81
|
-
# If the node is shaded, convert the attributes to the shaded
|
82
|
-
# version.
|
83
|
-
attrs = shade(attrs) if node.props[:spotlight] == 'shaded'
|
124
|
+
attrs[:shape] = "diamond" if node.props[:kind] == "calc"
|
84
125
|
|
85
126
|
# Declare the node.
|
86
|
-
|
127
|
+
output_node(indent, "node#{node.id}", attrs)
|
87
128
|
end
|
88
129
|
end
|
89
130
|
end
|
90
131
|
|
132
|
+
def output_node(indent, id, attrs)
|
133
|
+
@stream.puts "#{indent}#{id} #{write_attrs(attrs)};"
|
134
|
+
end
|
135
|
+
|
91
136
|
# Write edge declarations.
|
92
137
|
|
93
138
|
def write_edges(inline_attrs, graph)
|
94
139
|
graph.edges.each do |edge|
|
95
140
|
# Skip the edge if it's from a node that is hidden and it doesn't point
|
96
141
|
# to a shaded node.
|
97
|
-
next if edge.from.props[:hidden] && edge.to.props[:spotlight] !=
|
142
|
+
next if edge.from.props[:hidden] && edge.to.props[:spotlight] != "shaded"
|
98
143
|
|
99
144
|
# Skip the edge if it's to a node that is hidden and it doesn't come
|
100
145
|
# from a shaded node.
|
101
|
-
next if edge.to.props[:hidden] && edge.from.props[:spotlight] !=
|
146
|
+
next if edge.to.props[:hidden] && edge.from.props[:spotlight] != "shaded"
|
102
147
|
|
103
148
|
# Skip the edge if it's hidden itself
|
104
149
|
next if edge.props[:hidden]
|
105
150
|
|
106
|
-
write_edge
|
151
|
+
write_edge(inline_attrs, edge)
|
107
152
|
end
|
108
153
|
end
|
109
154
|
|
@@ -118,74 +163,64 @@ module Seafoam
|
|
118
163
|
attrs[:label] = label
|
119
164
|
|
120
165
|
# Basic edge attributes.
|
121
|
-
attrs[:fontname] =
|
166
|
+
attrs[:fontname] = "arial"
|
122
167
|
color = EDGE_COLORS[edge.props[:kind]]
|
123
168
|
attrs[:color] = EDGE_COLORS[edge.props[:kind]]
|
124
169
|
attrs[:fontcolor] = color
|
125
170
|
|
126
171
|
# Properties depending on the kind of edge.
|
127
172
|
case edge.props[:kind]
|
128
|
-
when
|
173
|
+
when "control"
|
129
174
|
attrs[:penwidth] = 2
|
130
|
-
when
|
175
|
+
when "loop"
|
131
176
|
attrs[:penwidth] = 4
|
132
|
-
when
|
133
|
-
attrs[:style] =
|
177
|
+
when "info"
|
178
|
+
attrs[:style] = "dashed"
|
134
179
|
end
|
135
180
|
|
136
181
|
# Reversed edges.
|
137
|
-
attrs[:dir] =
|
182
|
+
attrs[:dir] = "back" if edge.props[:reverse]
|
138
183
|
|
139
184
|
# Convert attributes to shaded if any edges involved are shaded.
|
140
|
-
attrs = shade(attrs) if edge.nodes.any? { |n| n.props[:spotlight] ==
|
185
|
+
attrs = shade(attrs) if edge.nodes.any? { |n| n.props[:spotlight] == "shaded" }
|
141
186
|
|
142
187
|
# Does this edge come from an inlined node?
|
143
188
|
|
144
189
|
if edge.from.props[:inlined]
|
145
|
-
#
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
#
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
190
|
+
# Don't draw inlined nodes to hidden nodes.
|
191
|
+
unless edge.to.props[:hidden]
|
192
|
+
|
193
|
+
# An inlined edge is drawn as a new version of the from-node and an
|
194
|
+
# edge from that new version directly to the to-node. With only one
|
195
|
+
# user it's a short edge and the from-node is show directly above the
|
196
|
+
# to-node.
|
197
|
+
|
198
|
+
node_attrs = if edge.to.props[:spotlight] == "shaded"
|
199
|
+
# Draw inlined edges to shaded nodes as invisible.
|
200
|
+
{ label: "", style: "invis" }
|
201
|
+
else
|
202
|
+
# Get attributes from when we went through nodes earlier.
|
203
|
+
inline_attrs[edge.from.id]
|
204
|
+
end
|
205
|
+
|
206
|
+
# Inlined nodes skip the arrow for simplicity.
|
207
|
+
attrs[:arrowhead] = "none"
|
208
|
+
attrs[:fontsize] = "8"
|
209
|
+
|
210
|
+
# Declare a new node just for this user.
|
211
|
+
output_node(" ", "inline#{edge.from.id}x#{edge.to.id}", node_attrs)
|
212
|
+
|
213
|
+
# Declare the edge.
|
214
|
+
output_edge("inline#{edge.from.id}x#{edge.to.id}", "node#{edge.to.id}", attrs)
|
156
215
|
end
|
157
|
-
|
158
|
-
# Inlined nodes skip the arrow for simplicity.
|
159
|
-
attrs[:arrowhead] = 'none'
|
160
|
-
attrs[:fontsize] = '8'
|
161
|
-
|
162
|
-
# Declare a new node just for this user.
|
163
|
-
@stream.puts " inline#{edge.from.id}x#{edge.to.id} #{write_attrs(node_attrs)};"
|
164
|
-
|
165
|
-
# Declare the edge.
|
166
|
-
@stream.puts " inline#{edge.from.id}x#{edge.to.id} -> node#{edge.to.id} #{write_attrs(attrs)};"
|
167
216
|
else
|
168
217
|
# Declare the edge.
|
169
|
-
|
218
|
+
output_edge("node#{edge.from.id}", "node#{edge.to.id}", attrs)
|
170
219
|
end
|
171
220
|
end
|
172
221
|
|
173
|
-
|
174
|
-
|
175
|
-
graph.blocks.each do |block|
|
176
|
-
@stream.puts " subgraph cluster_block#{block.id} {"
|
177
|
-
@stream.puts ' fontname = "Arial";'
|
178
|
-
@stream.puts " label = \"B#{block.id}\";"
|
179
|
-
@stream.puts ' style=dotted;'
|
180
|
-
|
181
|
-
block.nodes.each do |node|
|
182
|
-
next if node.props[:hidden] || node.props[:inlined]
|
183
|
-
|
184
|
-
@stream.puts " node#{node.id};"
|
185
|
-
end
|
186
|
-
|
187
|
-
@stream.puts ' }'
|
188
|
-
end
|
222
|
+
def output_edge(from, to, attrs)
|
223
|
+
@stream.puts " #{from} -> #{to} #{write_attrs(attrs)};"
|
189
224
|
end
|
190
225
|
|
191
226
|
# Return attributes for a node or edge modified to 'shade' them in terms
|
@@ -200,36 +235,31 @@ module Seafoam
|
|
200
235
|
|
201
236
|
# Write a hash of key-value attributes into the DOT format.
|
202
237
|
def write_attrs(attrs)
|
203
|
-
|
204
|
-
end
|
205
|
-
|
206
|
-
# Quote and escape a string.
|
207
|
-
def quote(string)
|
208
|
-
string = string.to_s
|
209
|
-
string = string.gsub('\\', '\\\\')
|
210
|
-
string = string.gsub('"', '\\"')
|
211
|
-
"\"#{string}\""
|
238
|
+
"[" + attrs.reject { |_k, v| v.nil? }.map { |k, v| "#{k}=#{v.inspect}" }.join(",") + "]"
|
212
239
|
end
|
213
240
|
|
214
241
|
# Color theme.
|
215
242
|
|
216
243
|
EDGE_COLORS = {
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
244
|
+
"info" => BIG_STONE,
|
245
|
+
"control" => AMARANTH,
|
246
|
+
"loop" => AMARANTH,
|
247
|
+
"data" => KEPPEL,
|
248
|
+
"other" => BLACK,
|
222
249
|
}
|
223
250
|
|
224
251
|
NODE_COLORS = {
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
252
|
+
"info" => [DUST, BLACK],
|
253
|
+
"input" => [WHITE_ICE, BLACK],
|
254
|
+
"control" => [CARISSMA, BLACK],
|
255
|
+
"memory" => [LIGHT_PURPLE, BLACK],
|
256
|
+
"call" => [AMARANTH, WHITE],
|
257
|
+
"sync" => [AMARANTH, WHITE],
|
258
|
+
"alloc" => [AMARANTH, WHITE],
|
259
|
+
"virtual" => [BIG_STONE, WHITE],
|
260
|
+
"guard" => [ORANGE, BLACK],
|
261
|
+
"calc" => [KEPPEL, BLACK],
|
262
|
+
"other" => [DUST, BLACK],
|
233
263
|
}
|
234
264
|
end
|
235
265
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Seafoam
|
2
4
|
# Write graphs in the Isabelle file format.
|
3
5
|
class IsabelleWriter
|
@@ -28,19 +30,19 @@ module Seafoam
|
|
28
30
|
|
29
31
|
graph.nodes.each_value do |node|
|
30
32
|
node_class = node.props[:node_class][:node_class]
|
31
|
-
case node_class
|
32
|
-
when
|
33
|
-
|
34
|
-
when
|
35
|
-
|
33
|
+
desc = case node_class
|
34
|
+
when "org.graalvm.compiler.nodes.ConstantNode"
|
35
|
+
"(ConstantNode #{node.props["rawvalue"]})"
|
36
|
+
when "org.graalvm.compiler.nodes.ParameterNode"
|
37
|
+
"(ParameterNode #{node.props["index"]})"
|
36
38
|
else
|
37
|
-
|
39
|
+
node_class.split(".").last
|
38
40
|
end
|
39
41
|
inputs = node.inputs.map(&:from).map(&:id)
|
40
42
|
outputs = node.outputs.map(&:to).map(&:id)
|
41
43
|
@out.puts " (add_node #{node.id} #{desc} #{inputs.inspect} #{outputs.inspect}"
|
42
44
|
end
|
43
|
-
@out.puts
|
45
|
+
@out.puts " empty_graph" + (")" * graph.nodes.size)
|
44
46
|
end
|
45
47
|
end
|
46
48
|
end
|