seafoam 0.13 → 0.15
Sign up to get free protection for your applications and to get access to all the features.
- 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 +226 -167
- data/lib/seafoam/formatters/base.rb +2 -0
- data/lib/seafoam/formatters/formatters.rb +5 -3
- data/lib/seafoam/formatters/json.rb +9 -6
- data/lib/seafoam/formatters/text.rb +8 -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 +29 -9
- data/lib/seafoam/graphviz_writer.rb +129 -99
- data/lib/seafoam/isabelle_writer.rb +9 -7
- data/lib/seafoam/json_writer.rb +19 -15
- 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 +194 -160
- data/lib/seafoam/passes/truffle.rb +152 -22
- data/lib/seafoam/passes/truffle_translators/default.rb +13 -0
- data/lib/seafoam/passes/truffle_translators/translators.rb +39 -0
- data/lib/seafoam/passes/truffle_translators/truffleruby.rb +24 -0
- data/lib/seafoam/passes.rb +36 -29
- data/lib/seafoam/search.rb +33 -0
- data/lib/seafoam/spotlight.rb +4 -2
- data/lib/seafoam/version.rb +3 -1
- data/lib/seafoam.rb +24 -20
- metadata +21 -14
data/lib/seafoam/commands.rb
CHANGED
@@ -1,5 +1,7 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "json"
|
4
|
+
require "set"
|
3
5
|
|
4
6
|
module Seafoam
|
5
7
|
# Implementations of the command-line commands that you can run in Seafoam.
|
@@ -12,7 +14,7 @@ module Seafoam
|
|
12
14
|
def seafoam(*args)
|
13
15
|
first, *args = args
|
14
16
|
|
15
|
-
if first ==
|
17
|
+
if first == "--json"
|
16
18
|
formatter_module = Seafoam::Formatters::Json
|
17
19
|
first, *args = args
|
18
20
|
else
|
@@ -20,11 +22,11 @@ module Seafoam
|
|
20
22
|
end
|
21
23
|
|
22
24
|
case first
|
23
|
-
when nil,
|
24
|
-
raise ArgumentError, "unexpected arguments #{args.join(
|
25
|
+
when nil, "help", "-h", "--help", "-help"
|
26
|
+
raise ArgumentError, "unexpected arguments #{args.join(" ")}" unless args.empty?
|
25
27
|
|
26
28
|
help(*args)
|
27
|
-
when
|
29
|
+
when "version", "-v", "-version", "--version"
|
28
30
|
version(*args)
|
29
31
|
else
|
30
32
|
name = first
|
@@ -32,24 +34,24 @@ module Seafoam
|
|
32
34
|
case command
|
33
35
|
when nil
|
34
36
|
help(*args)
|
35
|
-
when
|
36
|
-
info
|
37
|
-
when
|
38
|
-
list
|
39
|
-
when
|
40
|
-
search
|
41
|
-
when
|
42
|
-
edges
|
43
|
-
when
|
44
|
-
props
|
45
|
-
when
|
46
|
-
source
|
47
|
-
when
|
48
|
-
render
|
49
|
-
when
|
50
|
-
debug
|
51
|
-
when
|
52
|
-
describe
|
37
|
+
when "info"
|
38
|
+
info(name, formatter_module, *args)
|
39
|
+
when "list"
|
40
|
+
list(name, formatter_module, *args)
|
41
|
+
when "search"
|
42
|
+
search(name, *args)
|
43
|
+
when "edges"
|
44
|
+
edges(name, formatter_module, *args)
|
45
|
+
when "props"
|
46
|
+
props(name, *args)
|
47
|
+
when "source"
|
48
|
+
source(name, formatter_module, *args)
|
49
|
+
when "render"
|
50
|
+
render(name, *args)
|
51
|
+
when "debug"
|
52
|
+
debug(name, *args)
|
53
|
+
when "describe"
|
54
|
+
describe(name, formatter_module, *args)
|
53
55
|
else
|
54
56
|
raise ArgumentError, "unknown command #{command}"
|
55
57
|
end
|
@@ -59,14 +61,14 @@ module Seafoam
|
|
59
61
|
# Run the bgv2isabelle command.
|
60
62
|
def bgv2isabelle(*args)
|
61
63
|
case args.first
|
62
|
-
when nil,
|
64
|
+
when nil, "help", "-h", "--help", "-help"
|
63
65
|
args = args.drop(1)
|
64
|
-
raise ArgumentError, "unexpected arguments #{args.join(
|
66
|
+
raise ArgumentError, "unexpected arguments #{args.join(" ")}" unless args.empty?
|
65
67
|
|
66
|
-
@out.puts
|
67
|
-
@out.puts
|
68
|
-
@out.puts
|
69
|
-
when
|
68
|
+
@out.puts "bgv2isabelle file.bgv..."
|
69
|
+
@out.puts " --help"
|
70
|
+
@out.puts " --version"
|
71
|
+
when "version", "-v", "-version", "--version"
|
70
72
|
args = args.drop(1)
|
71
73
|
version(*args)
|
72
74
|
else
|
@@ -74,10 +76,10 @@ module Seafoam
|
|
74
76
|
|
75
77
|
until args.empty?
|
76
78
|
arg = args.shift
|
77
|
-
if arg.start_with?(
|
79
|
+
if arg.start_with?("-")
|
78
80
|
raise ArgumentError, "unknown option #{arg}"
|
79
81
|
else
|
80
|
-
files.push
|
82
|
+
files.push(arg)
|
81
83
|
end
|
82
84
|
end
|
83
85
|
|
@@ -96,7 +98,7 @@ module Seafoam
|
|
96
98
|
name = parser.graph_name(graph_header)
|
97
99
|
graph = parser.read_graph
|
98
100
|
|
99
|
-
writer.write
|
101
|
+
writer.write(index, name, graph)
|
100
102
|
end
|
101
103
|
end
|
102
104
|
end
|
@@ -104,14 +106,14 @@ module Seafoam
|
|
104
106
|
|
105
107
|
def bgv2json(*args)
|
106
108
|
case args.first
|
107
|
-
when nil,
|
109
|
+
when nil, "help", "-h", "--help", "-help"
|
108
110
|
args = args.drop(1)
|
109
|
-
raise ArgumentError, "unexpected arguments #{args.join(
|
111
|
+
raise ArgumentError, "unexpected arguments #{args.join(" ")}" unless args.empty?
|
110
112
|
|
111
|
-
@out.puts
|
112
|
-
@out.puts
|
113
|
-
@out.puts
|
114
|
-
when
|
113
|
+
@out.puts "bgv2json file.bgv..."
|
114
|
+
@out.puts " --help"
|
115
|
+
@out.puts " --version"
|
116
|
+
when "version", "-v", "-version", "--version"
|
115
117
|
args = args.drop(1)
|
116
118
|
version(*args)
|
117
119
|
else
|
@@ -119,10 +121,10 @@ module Seafoam
|
|
119
121
|
|
120
122
|
until args.empty?
|
121
123
|
arg = args.shift
|
122
|
-
if arg.start_with?(
|
124
|
+
if arg.start_with?("-")
|
123
125
|
raise ArgumentError, "unknown option #{arg}"
|
124
126
|
else
|
125
|
-
files.push
|
127
|
+
files.push(arg)
|
126
128
|
end
|
127
129
|
end
|
128
130
|
|
@@ -141,7 +143,7 @@ module Seafoam
|
|
141
143
|
name = parser.graph_name(graph_header)
|
142
144
|
graph = parser.read_graph
|
143
145
|
|
144
|
-
writer.write
|
146
|
+
writer.write(name, graph)
|
145
147
|
end
|
146
148
|
end
|
147
149
|
end
|
@@ -152,8 +154,8 @@ module Seafoam
|
|
152
154
|
# seafoam file.bgv info
|
153
155
|
def info(name, formatter_module, *args)
|
154
156
|
file, *rest = parse_name(name)
|
155
|
-
raise ArgumentError,
|
156
|
-
raise ArgumentError,
|
157
|
+
raise ArgumentError, "info only works with a file" unless rest == [nil, nil, nil]
|
158
|
+
raise ArgumentError, "info does not take arguments" unless args.empty?
|
157
159
|
|
158
160
|
parser = BGV::BGVParser.new(file)
|
159
161
|
major, minor = parser.read_file_header(version_check: false)
|
@@ -165,8 +167,8 @@ module Seafoam
|
|
165
167
|
# seafoam file.bgv list
|
166
168
|
def list(name, formatter_module, *args)
|
167
169
|
file, *rest = parse_name(name)
|
168
|
-
raise ArgumentError,
|
169
|
-
raise ArgumentError,
|
170
|
+
raise ArgumentError, "list only works with a file" unless rest == [nil, nil, nil]
|
171
|
+
raise ArgumentError, "list does not take arguments" unless args.empty?
|
170
172
|
|
171
173
|
parser = BGV::BGVParser.new(file)
|
172
174
|
parser.read_file_header
|
@@ -188,7 +190,7 @@ module Seafoam
|
|
188
190
|
# seafoam file.bgv:n... search term...
|
189
191
|
def search(name, *terms)
|
190
192
|
file, graph_index, node_id, = parse_name(name)
|
191
|
-
raise ArgumentError,
|
193
|
+
raise ArgumentError, "search only works with a file or graph" if node_id
|
192
194
|
|
193
195
|
parser = BGV::BGVParser.new(file)
|
194
196
|
parser.read_file_header
|
@@ -199,13 +201,13 @@ module Seafoam
|
|
199
201
|
|
200
202
|
if !graph_index || index == graph_index
|
201
203
|
header = parser.read_graph_header
|
202
|
-
search_object
|
204
|
+
search_object("#{file}:#{index}", header, terms)
|
203
205
|
graph = parser.read_graph
|
204
206
|
graph.nodes.each_value do |node|
|
205
|
-
search_object
|
207
|
+
search_object("#{file}:#{index}:#{node.id}", node.props, terms)
|
206
208
|
end
|
207
209
|
graph.edges.each do |edge|
|
208
|
-
search_object
|
210
|
+
search_object("#{file}:#{index}:#{edge.from.id}-#{edge.to.id}", edge.props, terms)
|
209
211
|
end
|
210
212
|
else
|
211
213
|
parser.skip_graph_header
|
@@ -231,8 +233,8 @@ module Seafoam
|
|
231
233
|
highlight_on = "\033[1m"
|
232
234
|
highlight_off = "\033[0m"
|
233
235
|
else
|
234
|
-
highlight_on =
|
235
|
-
highlight_off =
|
236
|
+
highlight_on = ""
|
237
|
+
highlight_off = ""
|
236
238
|
end
|
237
239
|
@out.puts "#{tag} ...#{before}#{highlight_on}#{match}#{highlight_off}#{after}..."
|
238
240
|
start = index + t.size
|
@@ -243,8 +245,8 @@ module Seafoam
|
|
243
245
|
# seafoam file.bgv:n... edges
|
244
246
|
def edges(name, formatter_module, *args)
|
245
247
|
file, graph_index, node_id, edge_id = parse_name(name)
|
246
|
-
raise ArgumentError,
|
247
|
-
raise ArgumentError,
|
248
|
+
raise ArgumentError, "edges needs at least a graph" unless graph_index
|
249
|
+
raise ArgumentError, "edges does not take arguments" unless args.empty?
|
248
250
|
|
249
251
|
entry = nil
|
250
252
|
|
@@ -252,16 +254,16 @@ module Seafoam
|
|
252
254
|
parser.read_graph_header
|
253
255
|
graph = parser.read_graph
|
254
256
|
if node_id
|
255
|
-
Passes.apply
|
257
|
+
Passes.apply(graph)
|
256
258
|
node = graph.nodes[node_id]
|
257
|
-
raise ArgumentError,
|
259
|
+
raise ArgumentError, "node not found" unless node
|
258
260
|
|
259
261
|
if edge_id
|
260
262
|
to = graph.nodes[edge_id]
|
261
|
-
raise ArgumentError,
|
263
|
+
raise ArgumentError, "edge node not found" unless to
|
262
264
|
|
263
265
|
edges = node.outputs.select { |edge| edge.to == to }
|
264
|
-
raise ArgumentError,
|
266
|
+
raise ArgumentError, "edge not found" if edges.empty?
|
265
267
|
|
266
268
|
entry = formatter_module::EdgesFormatter::EdgesEntry.new(edges)
|
267
269
|
else
|
@@ -279,8 +281,10 @@ module Seafoam
|
|
279
281
|
|
280
282
|
# seafoam file.bgv... props
|
281
283
|
def props(name, *args)
|
284
|
+
# rubocop:disable Metrics/BlockNesting
|
285
|
+
|
282
286
|
file, graph_index, node_id, edge_id = parse_name(name)
|
283
|
-
raise ArgumentError,
|
287
|
+
raise ArgumentError, "props does not take arguments" unless args.empty?
|
284
288
|
|
285
289
|
if graph_index
|
286
290
|
with_graph(file, graph_index) do |parser|
|
@@ -288,29 +292,29 @@ module Seafoam
|
|
288
292
|
if node_id
|
289
293
|
graph = parser.read_graph
|
290
294
|
node = graph.nodes[node_id]
|
291
|
-
raise ArgumentError,
|
295
|
+
raise ArgumentError, "node not found" unless node
|
292
296
|
|
293
297
|
if edge_id
|
294
298
|
to = graph.nodes[edge_id]
|
295
|
-
raise ArgumentError,
|
299
|
+
raise ArgumentError, "edge node not found" unless to
|
296
300
|
|
297
301
|
edges = node.outputs.select { |edge| edge.to == to }
|
298
|
-
raise ArgumentError,
|
302
|
+
raise ArgumentError, "edge not found" if edges.empty?
|
299
303
|
|
300
304
|
if edges.size > 1
|
301
305
|
edges.each do |edge|
|
302
|
-
pretty_print
|
306
|
+
pretty_print(edge.props)
|
303
307
|
@out.puts
|
304
308
|
end
|
305
309
|
else
|
306
|
-
pretty_print
|
310
|
+
pretty_print(edges.first.props)
|
307
311
|
end
|
308
312
|
else
|
309
|
-
pretty_print
|
313
|
+
pretty_print(node.props)
|
310
314
|
end
|
311
315
|
break
|
312
316
|
else
|
313
|
-
pretty_print
|
317
|
+
pretty_print(graph_header)
|
314
318
|
parser.skip_graph
|
315
319
|
end
|
316
320
|
end
|
@@ -318,24 +322,26 @@ module Seafoam
|
|
318
322
|
parser = BGV::BGVParser.new(file)
|
319
323
|
parser.read_file_header
|
320
324
|
document_props = parser.read_document_props
|
321
|
-
pretty_print
|
325
|
+
pretty_print(document_props || {})
|
322
326
|
end
|
327
|
+
|
328
|
+
# rubocop:enable Metrics/BlockNesting
|
323
329
|
end
|
324
330
|
|
325
331
|
# seafoam file.bgv:n:n source
|
326
332
|
def source(name, formatter_module, *args)
|
327
333
|
file, graph_index, node_id, edge_id = parse_name(name)
|
328
|
-
raise ArgumentError,
|
329
|
-
raise ArgumentError,
|
330
|
-
raise ArgumentError,
|
334
|
+
raise ArgumentError, "source needs a node" unless node_id
|
335
|
+
raise ArgumentError, "source only works with a node" if edge_id
|
336
|
+
raise ArgumentError, "source does not take arguments" unless args.empty?
|
331
337
|
|
332
338
|
with_graph(file, graph_index) do |parser|
|
333
339
|
parser.read_graph_header
|
334
340
|
graph = parser.read_graph
|
335
341
|
node = graph.nodes[node_id]
|
336
|
-
raise ArgumentError,
|
342
|
+
raise ArgumentError, "node not found" unless node
|
337
343
|
|
338
|
-
formatter = formatter_module::SourceFormatter.new(node.props[
|
344
|
+
formatter = formatter_module::SourceFormatter.new(node.props["nodeSourcePosition"])
|
339
345
|
@out.puts formatter.format
|
340
346
|
end
|
341
347
|
end
|
@@ -344,10 +350,20 @@ module Seafoam
|
|
344
350
|
def describe(name, formatter_module, *args)
|
345
351
|
file, graph_index, *rest = parse_name(name)
|
346
352
|
|
353
|
+
pass_options = DEFAULT_PASS_OPTIONS.dup
|
354
|
+
until args.empty?
|
355
|
+
arg = args.shift
|
356
|
+
case arg
|
357
|
+
when "--no-simplify"
|
358
|
+
pass_options.merge!(NO_SIMPLIFY_PASS_OPTIONS)
|
359
|
+
else
|
360
|
+
raise ArgumentError, "unexpected option #{arg}"
|
361
|
+
end
|
362
|
+
end
|
363
|
+
|
347
364
|
if graph_index.nil? || !rest.all?(&:nil?)
|
348
|
-
raise ArgumentError,
|
365
|
+
raise ArgumentError, "describe only works with a graph"
|
349
366
|
end
|
350
|
-
raise ArgumentError, 'describe does not take arguments' unless args.empty?
|
351
367
|
|
352
368
|
parser = BGV::BGVParser.new(file)
|
353
369
|
parser.read_file_header
|
@@ -365,22 +381,33 @@ module Seafoam
|
|
365
381
|
end
|
366
382
|
|
367
383
|
graph = parser.read_graph
|
384
|
+
Passes.apply(graph, pass_options)
|
385
|
+
|
368
386
|
description = Seafoam::Graal::GraphDescription.new
|
369
387
|
|
370
388
|
graph.nodes.each_value do |node|
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
description.
|
377
|
-
|
378
|
-
|
389
|
+
next if node.props[:hidden]
|
390
|
+
|
391
|
+
node_class = node.node_class
|
392
|
+
if node_class
|
393
|
+
simple_node_class = node_class[/([^.]+)$/, 1]
|
394
|
+
description.node_counts[simple_node_class] += 1
|
395
|
+
|
396
|
+
case node_class
|
397
|
+
when "org.graalvm.compiler.nodes.IfNode"
|
398
|
+
description.branches = true
|
399
|
+
when "org.graalvm.compiler.nodes.LoopBeginNode"
|
400
|
+
description.loops = true
|
401
|
+
when "org.graalvm.compiler.nodes.InvokeNode", "org.graalvm.compiler.nodes.InvokeWithExceptionNode"
|
402
|
+
description.calls = true
|
403
|
+
end
|
404
|
+
elsif node.props[:synthetic_class]
|
405
|
+
description.node_counts["*" + node.props[:synthetic_class]] += 1
|
379
406
|
end
|
380
|
-
end
|
381
407
|
|
382
|
-
|
383
|
-
|
408
|
+
description.deopts = graph.nodes[0].outputs.map(&:to)
|
409
|
+
.all? { |t| t.node_class == "org.graalvm.compiler.nodes.DeoptimizeNode" }
|
410
|
+
end
|
384
411
|
|
385
412
|
formatter = formatter_module::DescribeFormatter.new(graph, description)
|
386
413
|
@out.puts formatter.format
|
@@ -392,16 +419,10 @@ module Seafoam
|
|
392
419
|
# seafoam file.bgv:n render options...
|
393
420
|
def render(name, *args)
|
394
421
|
file, graph_index, *rest = parse_name(name)
|
395
|
-
raise ArgumentError,
|
396
|
-
raise ArgumentError,
|
397
|
-
|
398
|
-
pass_options =
|
399
|
-
simplify_truffle_args: true,
|
400
|
-
hide_frame_state: true,
|
401
|
-
hide_pi: true,
|
402
|
-
hide_floating: false,
|
403
|
-
reduce_edges: true
|
404
|
-
}
|
422
|
+
raise ArgumentError, "render needs at least a graph" unless graph_index
|
423
|
+
raise ArgumentError, "render only works with a graph" unless rest == [nil, nil]
|
424
|
+
|
425
|
+
pass_options = DEFAULT_PASS_OPTIONS.dup
|
405
426
|
spotlight_nodes = nil
|
406
427
|
args = args.dup
|
407
428
|
out_file = nil
|
@@ -410,75 +431,85 @@ module Seafoam
|
|
410
431
|
until args.empty?
|
411
432
|
arg = args.shift
|
412
433
|
case arg
|
413
|
-
when
|
434
|
+
when "--out"
|
414
435
|
out_file = args.shift
|
415
436
|
explicit_out_file = true
|
416
|
-
raise ArgumentError,
|
437
|
+
raise ArgumentError, "no file for --out" unless out_file
|
417
438
|
|
418
439
|
out_ext = File.extname(out_file).downcase
|
419
440
|
case out_ext
|
420
|
-
when
|
441
|
+
when ".pdf"
|
421
442
|
out_format = :pdf
|
422
|
-
when
|
443
|
+
when ".svg"
|
423
444
|
out_format = :svg
|
424
|
-
when
|
445
|
+
when ".png"
|
425
446
|
out_format = :png
|
426
|
-
when
|
447
|
+
when ".dot"
|
427
448
|
out_format = :dot
|
428
|
-
when
|
449
|
+
when ".mmd"
|
429
450
|
out_format = :mmd
|
430
|
-
when
|
451
|
+
when ".md"
|
431
452
|
out_format = :md
|
432
453
|
else
|
433
454
|
raise ArgumentError, "unknown render format #{out_ext}"
|
434
455
|
end
|
435
|
-
when
|
456
|
+
when "--md"
|
436
457
|
out_file = @out
|
437
458
|
out_format = :md
|
438
459
|
explicit_out_file = true
|
439
|
-
when
|
460
|
+
when "--spotlight"
|
440
461
|
spotlight_arg = args.shift
|
441
|
-
raise ArgumentError,
|
462
|
+
raise ArgumentError, "no list for --spotlight" unless spotlight_arg
|
442
463
|
|
443
|
-
spotlight_nodes = spotlight_arg.split(
|
444
|
-
when
|
464
|
+
spotlight_nodes = spotlight_arg.split(",").map { |n| Integer(n) }
|
465
|
+
when "--full-truffle-args"
|
445
466
|
pass_options[:simplify_truffle_args] = false
|
446
|
-
when
|
467
|
+
when "--show-reachability-fences"
|
468
|
+
pass_options[:hide_reachability_fences] = false
|
469
|
+
when "--no-simplify-alloc"
|
470
|
+
pass_options[:simplify_alloc] = false
|
471
|
+
when "--show-null-fields"
|
472
|
+
pass_options[:hide_null_fields] = false
|
473
|
+
when "--show-frame-state"
|
447
474
|
pass_options[:hide_frame_state] = false
|
448
|
-
when
|
475
|
+
when "--show-pi"
|
449
476
|
pass_options[:hide_pi] = false
|
450
|
-
when
|
477
|
+
when "--show-begin-end"
|
478
|
+
pass_options[:hide_begin_end] = false
|
479
|
+
when "--hide-floating"
|
451
480
|
pass_options[:hide_floating] = true
|
452
|
-
when
|
481
|
+
when "--no-reduce-edges"
|
453
482
|
pass_options[:reduce_edges] = false
|
454
|
-
when
|
483
|
+
when "--no-simplify"
|
484
|
+
pass_options.merge!(NO_SIMPLIFY_PASS_OPTIONS)
|
485
|
+
when "--draw-blocks"
|
455
486
|
draw_blocks = true
|
456
|
-
when
|
487
|
+
when "--option"
|
457
488
|
key = args.shift
|
458
|
-
raise ArgumentError,
|
489
|
+
raise ArgumentError, "no key for --option" unless key
|
459
490
|
|
460
491
|
value = args.shift
|
461
|
-
raise ArgumentError, "no value for --option #{key}" unless
|
492
|
+
raise ArgumentError, "no value for --option #{key}" unless value
|
462
493
|
|
463
|
-
value = {
|
494
|
+
value = { "true" => true, "false" => "false" }.fetch(key, value)
|
464
495
|
pass_options[key.to_sym] = value
|
465
496
|
else
|
466
497
|
raise ArgumentError, "unexpected option #{arg}"
|
467
498
|
end
|
468
499
|
end
|
469
|
-
out_file ||=
|
500
|
+
out_file ||= "graph.pdf"
|
470
501
|
out_format ||= :pdf
|
471
502
|
with_graph(file, graph_index) do |parser|
|
472
503
|
parser.skip_graph_header
|
473
504
|
graph = parser.read_graph
|
474
|
-
Passes.apply
|
505
|
+
Passes.apply(graph, pass_options)
|
475
506
|
if spotlight_nodes
|
476
507
|
spotlight = Spotlight.new(graph)
|
477
508
|
spotlight_nodes.each do |node_id|
|
478
509
|
node = graph.nodes[node_id]
|
479
|
-
raise ArgumentError,
|
510
|
+
raise ArgumentError, "node not found" unless node
|
480
511
|
|
481
|
-
spotlight.light
|
512
|
+
spotlight.light(node)
|
482
513
|
end
|
483
514
|
spotlight.shade
|
484
515
|
end
|
@@ -488,35 +519,35 @@ module Seafoam
|
|
488
519
|
case out_format
|
489
520
|
when :dot
|
490
521
|
writer = GraphvizWriter.new(stream)
|
491
|
-
writer.write_graph
|
522
|
+
writer.write_graph(graph, false, draw_blocks)
|
492
523
|
when :mmd
|
493
524
|
writer = MermaidWriter.new(stream)
|
494
|
-
writer.write_graph
|
525
|
+
writer.write_graph(graph, false, draw_blocks)
|
495
526
|
when :md
|
496
527
|
writer = MarkdownWriter.new(stream)
|
497
|
-
writer.write_graph
|
528
|
+
writer.write_graph(graph)
|
498
529
|
else
|
499
530
|
raise
|
500
531
|
end
|
501
532
|
end
|
502
533
|
if out_file.is_a?(String)
|
503
|
-
File.open(out_file,
|
504
|
-
action.call
|
534
|
+
File.open(out_file, "w") do |stream|
|
535
|
+
action.call(stream)
|
505
536
|
end
|
506
537
|
else
|
507
|
-
action.call
|
538
|
+
action.call(out_file)
|
508
539
|
end
|
509
540
|
else
|
510
541
|
begin
|
511
|
-
IO.popen([
|
542
|
+
IO.popen(["dot", "-T#{out_format}", "-o", out_file], "w") do |stream|
|
512
543
|
writer = GraphvizWriter.new(stream)
|
513
544
|
hidpi = out_format == :png
|
514
|
-
writer.write_graph
|
545
|
+
writer.write_graph(graph, hidpi, draw_blocks)
|
515
546
|
end
|
516
547
|
rescue Errno::ENOENT
|
517
|
-
raise
|
548
|
+
raise "Could not run Graphviz - is it installed?"
|
518
549
|
end
|
519
|
-
autoopen
|
550
|
+
autoopen(out_file) unless explicit_out_file
|
520
551
|
end
|
521
552
|
end
|
522
553
|
end
|
@@ -524,12 +555,12 @@ module Seafoam
|
|
524
555
|
# seafoam file.bgv debug options...
|
525
556
|
def debug(name, *args)
|
526
557
|
file, *rest = parse_name(name)
|
527
|
-
raise ArgumentError,
|
558
|
+
raise ArgumentError, "debug only works with a file" unless rest == [nil, nil, nil]
|
528
559
|
|
529
560
|
skip = false
|
530
561
|
args.each do |arg|
|
531
562
|
case arg
|
532
|
-
when
|
563
|
+
when "--skip"
|
533
564
|
skip = true
|
534
565
|
else
|
535
566
|
raise ArgumentError, "unexpected option #{arg}"
|
@@ -539,10 +570,10 @@ module Seafoam
|
|
539
570
|
File.open(file) do |stream|
|
540
571
|
parser = BGVDebugParser.new(@out, stream)
|
541
572
|
begin
|
542
|
-
pretty_print
|
573
|
+
pretty_print(parser.read_file_header)
|
543
574
|
document_props = parser.read_document_props
|
544
575
|
if document_props
|
545
|
-
pretty_print
|
576
|
+
pretty_print(document_props)
|
546
577
|
end
|
547
578
|
loop do
|
548
579
|
index, id = parser.read_graph_preheader
|
@@ -553,8 +584,8 @@ module Seafoam
|
|
553
584
|
parser.skip_graph_header
|
554
585
|
parser.skip_graph
|
555
586
|
else
|
556
|
-
pretty_print
|
557
|
-
pretty_print
|
587
|
+
pretty_print(parser.read_graph_header)
|
588
|
+
pretty_print(parser.read_graph)
|
558
589
|
end
|
559
590
|
end
|
560
591
|
rescue StandardError => e
|
@@ -597,53 +628,59 @@ module Seafoam
|
|
597
628
|
parser.skip_graph
|
598
629
|
end
|
599
630
|
end
|
600
|
-
raise ArgumentError,
|
631
|
+
raise ArgumentError, "graph not found" unless graph_found
|
601
632
|
end
|
602
633
|
|
603
634
|
# Prints help.
|
604
635
|
def help(*_args)
|
605
|
-
@out.puts
|
606
|
-
@out.puts
|
607
|
-
@out.puts
|
608
|
-
@out.puts
|
609
|
-
@out.puts
|
610
|
-
@out.puts
|
611
|
-
@out.puts
|
612
|
-
@out.puts
|
613
|
-
@out.puts
|
614
|
-
@out.puts
|
615
|
-
@out.puts
|
616
|
-
@out.puts
|
617
|
-
@out.puts
|
618
|
-
@out.puts
|
619
|
-
@out.puts
|
620
|
-
@out.puts
|
621
|
-
@out.puts
|
622
|
-
@out.puts
|
623
|
-
@out.puts
|
624
|
-
@out.puts
|
625
|
-
@out.puts
|
626
|
-
@out.puts
|
636
|
+
@out.puts "seafoam file.bgv info"
|
637
|
+
@out.puts " file.bgv list"
|
638
|
+
@out.puts " file.bgv[:graph][:node[-edge]] search term..."
|
639
|
+
@out.puts " file.bgv[:graph][:node[-edge]] edges"
|
640
|
+
@out.puts " file.bgv[:graph][:node[-edge]] props"
|
641
|
+
@out.puts " file.bgv:graph:node source"
|
642
|
+
@out.puts " file.bgv:graph describe"
|
643
|
+
@out.puts " file.bgv:graph render"
|
644
|
+
@out.puts " --spotlight n,n,n..."
|
645
|
+
@out.puts " --out graph.pdf"
|
646
|
+
@out.puts " graph.svg"
|
647
|
+
@out.puts " graph.png"
|
648
|
+
@out.puts " graph.dot (Graphviz)"
|
649
|
+
@out.puts " graph.mmd (Mermaid)"
|
650
|
+
@out.puts " graph.md (Markdown)"
|
651
|
+
@out.puts " --full-truffle-args"
|
652
|
+
@out.puts " --show-frame-state"
|
653
|
+
@out.puts " --no-simplify-alloc"
|
654
|
+
@out.puts " --show-null-fields"
|
655
|
+
@out.puts " --show-pi"
|
656
|
+
@out.puts " --show-begin-end"
|
657
|
+
@out.puts " --hide-floating"
|
658
|
+
@out.puts " --no-reduce-edges"
|
659
|
+
@out.puts " --no-simplify"
|
660
|
+
@out.puts " --draw-blocks"
|
661
|
+
@out.puts " --option key value"
|
662
|
+
@out.puts " --help"
|
663
|
+
@out.puts " --version"
|
627
664
|
end
|
628
665
|
|
629
666
|
# Prints the version.
|
630
667
|
def version(*args)
|
631
|
-
raise ArgumentError, "unexpected arguments #{args.join(
|
668
|
+
raise ArgumentError, "unexpected arguments #{args.join(" ")}" unless args.empty?
|
632
669
|
|
633
670
|
@out.puts "seafoam #{VERSION}"
|
634
671
|
end
|
635
672
|
|
636
673
|
# Parse a name like file.bgv:g:n-e to [file.bgv, g, n, e].
|
637
674
|
def parse_name(name)
|
638
|
-
*pre, post = name.split(
|
675
|
+
*pre, post = name.split(".")
|
639
676
|
|
640
|
-
file_ext, graph, node, *rest = post.split(
|
677
|
+
file_ext, graph, node, *rest = post.split(":")
|
641
678
|
raise ArgumentError, "too many parts to .ext:g:n-e in #{name}" unless rest.empty?
|
642
679
|
|
643
|
-
file = [*pre, file_ext].join(
|
680
|
+
file = [*pre, file_ext].join(".")
|
644
681
|
|
645
682
|
if node
|
646
|
-
node, edge, *rest = node.split(
|
683
|
+
node, edge, *rest = node.split("-")
|
647
684
|
raise ArgumentError, "too many parts to edge name in #{name}" unless rest.empty?
|
648
685
|
else
|
649
686
|
node = nil
|
@@ -663,11 +700,33 @@ module Seafoam
|
|
663
700
|
|
664
701
|
case RUBY_PLATFORM
|
665
702
|
when /darwin/
|
666
|
-
system
|
703
|
+
system("open", file)
|
667
704
|
when /linux/
|
668
|
-
system
|
705
|
+
system("xdg-open", file)
|
669
706
|
end
|
670
707
|
# Don't worry if it fails.
|
671
708
|
end
|
709
|
+
|
710
|
+
DEFAULT_PASS_OPTIONS = {
|
711
|
+
simplify_truffle_args: true,
|
712
|
+
hide_reachability_fences: true,
|
713
|
+
hide_frame_state: true,
|
714
|
+
hide_pi: true,
|
715
|
+
hide_begin_end: true,
|
716
|
+
hide_floating: false,
|
717
|
+
reduce_edges: true,
|
718
|
+
simplify_alloc: true,
|
719
|
+
hide_null_fields: true,
|
720
|
+
}
|
721
|
+
|
722
|
+
NO_SIMPLIFY_PASS_OPTIONS = {
|
723
|
+
simplify_truffle_args: false,
|
724
|
+
hide_reachability_fences: false,
|
725
|
+
simplify_alloc: false,
|
726
|
+
hide_null_fields: false,
|
727
|
+
hide_pi: false,
|
728
|
+
hide_begin_end: false,
|
729
|
+
reduce_edges: false,
|
730
|
+
}
|
672
731
|
end
|
673
732
|
end
|