seafoam 0.13 → 0.14
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 +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
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
|
@@ -345,9 +351,9 @@ module Seafoam
|
|
345
351
|
file, graph_index, *rest = parse_name(name)
|
346
352
|
|
347
353
|
if graph_index.nil? || !rest.all?(&:nil?)
|
348
|
-
raise ArgumentError,
|
354
|
+
raise ArgumentError, "describe only works with a graph"
|
349
355
|
end
|
350
|
-
raise ArgumentError,
|
356
|
+
raise ArgumentError, "describe does not take arguments" unless args.empty?
|
351
357
|
|
352
358
|
parser = BGV::BGVParser.new(file)
|
353
359
|
parser.read_file_header
|
@@ -368,19 +374,23 @@ module Seafoam
|
|
368
374
|
description = Seafoam::Graal::GraphDescription.new
|
369
375
|
|
370
376
|
graph.nodes.each_value do |node|
|
371
|
-
node_class = node.
|
377
|
+
node_class = node.node_class
|
378
|
+
|
379
|
+
simple_node_class = node_class[/([^.]+)$/, 1]
|
380
|
+
description.node_counts[simple_node_class] += 1
|
381
|
+
|
372
382
|
case node_class
|
373
|
-
when
|
383
|
+
when "org.graalvm.compiler.nodes.IfNode"
|
374
384
|
description.branches = true
|
375
|
-
when
|
385
|
+
when "org.graalvm.compiler.nodes.LoopBeginNode"
|
376
386
|
description.loops = true
|
377
|
-
when
|
387
|
+
when "org.graalvm.compiler.nodes.InvokeNode", "org.graalvm.compiler.nodes.InvokeWithExceptionNode"
|
378
388
|
description.calls = true
|
379
389
|
end
|
380
390
|
end
|
381
391
|
|
382
392
|
description.deopts = graph.nodes[0].outputs.map(&:to)
|
383
|
-
|
393
|
+
.all? { |t| t.node_class == "org.graalvm.compiler.nodes.DeoptimizeNode" }
|
384
394
|
|
385
395
|
formatter = formatter_module::DescribeFormatter.new(graph, description)
|
386
396
|
@out.puts formatter.format
|
@@ -392,15 +402,18 @@ module Seafoam
|
|
392
402
|
# seafoam file.bgv:n render options...
|
393
403
|
def render(name, *args)
|
394
404
|
file, graph_index, *rest = parse_name(name)
|
395
|
-
raise ArgumentError,
|
396
|
-
raise ArgumentError,
|
405
|
+
raise ArgumentError, "render needs at least a graph" unless graph_index
|
406
|
+
raise ArgumentError, "render only works with a graph" unless rest == [nil, nil]
|
397
407
|
|
398
408
|
pass_options = {
|
399
409
|
simplify_truffle_args: true,
|
400
410
|
hide_frame_state: true,
|
401
411
|
hide_pi: true,
|
412
|
+
hide_begin_end: true,
|
402
413
|
hide_floating: false,
|
403
|
-
reduce_edges: true
|
414
|
+
reduce_edges: true,
|
415
|
+
simplify_alloc: true,
|
416
|
+
hide_null_fields: true,
|
404
417
|
}
|
405
418
|
spotlight_nodes = nil
|
406
419
|
args = args.dup
|
@@ -410,75 +423,81 @@ module Seafoam
|
|
410
423
|
until args.empty?
|
411
424
|
arg = args.shift
|
412
425
|
case arg
|
413
|
-
when
|
426
|
+
when "--out"
|
414
427
|
out_file = args.shift
|
415
428
|
explicit_out_file = true
|
416
|
-
raise ArgumentError,
|
429
|
+
raise ArgumentError, "no file for --out" unless out_file
|
417
430
|
|
418
431
|
out_ext = File.extname(out_file).downcase
|
419
432
|
case out_ext
|
420
|
-
when
|
433
|
+
when ".pdf"
|
421
434
|
out_format = :pdf
|
422
|
-
when
|
435
|
+
when ".svg"
|
423
436
|
out_format = :svg
|
424
|
-
when
|
437
|
+
when ".png"
|
425
438
|
out_format = :png
|
426
|
-
when
|
439
|
+
when ".dot"
|
427
440
|
out_format = :dot
|
428
|
-
when
|
441
|
+
when ".mmd"
|
429
442
|
out_format = :mmd
|
430
|
-
when
|
443
|
+
when ".md"
|
431
444
|
out_format = :md
|
432
445
|
else
|
433
446
|
raise ArgumentError, "unknown render format #{out_ext}"
|
434
447
|
end
|
435
|
-
when
|
448
|
+
when "--md"
|
436
449
|
out_file = @out
|
437
450
|
out_format = :md
|
438
451
|
explicit_out_file = true
|
439
|
-
when
|
452
|
+
when "--spotlight"
|
440
453
|
spotlight_arg = args.shift
|
441
|
-
raise ArgumentError,
|
454
|
+
raise ArgumentError, "no list for --spotlight" unless spotlight_arg
|
442
455
|
|
443
|
-
spotlight_nodes = spotlight_arg.split(
|
444
|
-
when
|
456
|
+
spotlight_nodes = spotlight_arg.split(",").map { |n| Integer(n) }
|
457
|
+
when "--full-truffle-args"
|
445
458
|
pass_options[:simplify_truffle_args] = false
|
446
|
-
when
|
459
|
+
when "--no-simplify-alloc"
|
460
|
+
pass_options[:simplify_alloc] = false
|
461
|
+
when "--show-null-fields"
|
462
|
+
pass_options[:hide_null_fields] = false
|
463
|
+
when "--show-frame-state"
|
447
464
|
pass_options[:hide_frame_state] = false
|
448
|
-
when
|
465
|
+
when "--show-pi"
|
449
466
|
pass_options[:hide_pi] = false
|
450
|
-
when
|
467
|
+
when "--show-begin-end"
|
468
|
+
pass_options[:hide_begin_end] = false
|
469
|
+
when "--hide-floating"
|
451
470
|
pass_options[:hide_floating] = true
|
452
|
-
when
|
471
|
+
when "--no-reduce-edges"
|
453
472
|
pass_options[:reduce_edges] = false
|
454
|
-
when
|
473
|
+
when "--draw-blocks"
|
455
474
|
draw_blocks = true
|
456
|
-
when
|
475
|
+
when "--option"
|
457
476
|
key = args.shift
|
458
|
-
raise ArgumentError,
|
477
|
+
raise ArgumentError, "no key for --option" unless key
|
459
478
|
|
460
479
|
value = args.shift
|
461
480
|
raise ArgumentError, "no value for --option #{key}" unless out_file
|
462
481
|
|
463
|
-
value = {
|
482
|
+
value = { "true" => true, "false" => "false" }.fetch(key, value)
|
464
483
|
pass_options[key.to_sym] = value
|
465
484
|
else
|
466
485
|
raise ArgumentError, "unexpected option #{arg}"
|
467
486
|
end
|
468
487
|
end
|
469
|
-
out_file ||=
|
488
|
+
out_file ||= "graph.pdf"
|
470
489
|
out_format ||= :pdf
|
471
490
|
with_graph(file, graph_index) do |parser|
|
472
491
|
parser.skip_graph_header
|
473
492
|
graph = parser.read_graph
|
474
|
-
Passes.apply
|
493
|
+
Passes.apply(graph, pass_options)
|
475
494
|
if spotlight_nodes
|
476
495
|
spotlight = Spotlight.new(graph)
|
477
496
|
spotlight_nodes.each do |node_id|
|
478
497
|
node = graph.nodes[node_id]
|
479
|
-
raise ArgumentError,
|
498
|
+
raise ArgumentError, "node not found" unless node
|
480
499
|
|
481
|
-
spotlight.light
|
500
|
+
spotlight.light(node)
|
482
501
|
end
|
483
502
|
spotlight.shade
|
484
503
|
end
|
@@ -488,35 +507,35 @@ module Seafoam
|
|
488
507
|
case out_format
|
489
508
|
when :dot
|
490
509
|
writer = GraphvizWriter.new(stream)
|
491
|
-
writer.write_graph
|
510
|
+
writer.write_graph(graph, false, draw_blocks)
|
492
511
|
when :mmd
|
493
512
|
writer = MermaidWriter.new(stream)
|
494
|
-
writer.write_graph
|
513
|
+
writer.write_graph(graph, false, draw_blocks)
|
495
514
|
when :md
|
496
515
|
writer = MarkdownWriter.new(stream)
|
497
|
-
writer.write_graph
|
516
|
+
writer.write_graph(graph)
|
498
517
|
else
|
499
518
|
raise
|
500
519
|
end
|
501
520
|
end
|
502
521
|
if out_file.is_a?(String)
|
503
|
-
File.open(out_file,
|
504
|
-
action.call
|
522
|
+
File.open(out_file, "w") do |stream|
|
523
|
+
action.call(stream)
|
505
524
|
end
|
506
525
|
else
|
507
|
-
action.call
|
526
|
+
action.call(out_file)
|
508
527
|
end
|
509
528
|
else
|
510
529
|
begin
|
511
|
-
IO.popen([
|
530
|
+
IO.popen(["dot", "-T#{out_format}", "-o", out_file], "w") do |stream|
|
512
531
|
writer = GraphvizWriter.new(stream)
|
513
532
|
hidpi = out_format == :png
|
514
|
-
writer.write_graph
|
533
|
+
writer.write_graph(graph, hidpi, draw_blocks)
|
515
534
|
end
|
516
535
|
rescue Errno::ENOENT
|
517
|
-
raise
|
536
|
+
raise "Could not run Graphviz - is it installed?"
|
518
537
|
end
|
519
|
-
autoopen
|
538
|
+
autoopen(out_file) unless explicit_out_file
|
520
539
|
end
|
521
540
|
end
|
522
541
|
end
|
@@ -524,12 +543,12 @@ module Seafoam
|
|
524
543
|
# seafoam file.bgv debug options...
|
525
544
|
def debug(name, *args)
|
526
545
|
file, *rest = parse_name(name)
|
527
|
-
raise ArgumentError,
|
546
|
+
raise ArgumentError, "debug only works with a file" unless rest == [nil, nil, nil]
|
528
547
|
|
529
548
|
skip = false
|
530
549
|
args.each do |arg|
|
531
550
|
case arg
|
532
|
-
when
|
551
|
+
when "--skip"
|
533
552
|
skip = true
|
534
553
|
else
|
535
554
|
raise ArgumentError, "unexpected option #{arg}"
|
@@ -539,10 +558,10 @@ module Seafoam
|
|
539
558
|
File.open(file) do |stream|
|
540
559
|
parser = BGVDebugParser.new(@out, stream)
|
541
560
|
begin
|
542
|
-
pretty_print
|
561
|
+
pretty_print(parser.read_file_header)
|
543
562
|
document_props = parser.read_document_props
|
544
563
|
if document_props
|
545
|
-
pretty_print
|
564
|
+
pretty_print(document_props)
|
546
565
|
end
|
547
566
|
loop do
|
548
567
|
index, id = parser.read_graph_preheader
|
@@ -553,8 +572,8 @@ module Seafoam
|
|
553
572
|
parser.skip_graph_header
|
554
573
|
parser.skip_graph
|
555
574
|
else
|
556
|
-
pretty_print
|
557
|
-
pretty_print
|
575
|
+
pretty_print(parser.read_graph_header)
|
576
|
+
pretty_print(parser.read_graph)
|
558
577
|
end
|
559
578
|
end
|
560
579
|
rescue StandardError => e
|
@@ -597,53 +616,58 @@ module Seafoam
|
|
597
616
|
parser.skip_graph
|
598
617
|
end
|
599
618
|
end
|
600
|
-
raise ArgumentError,
|
619
|
+
raise ArgumentError, "graph not found" unless graph_found
|
601
620
|
end
|
602
621
|
|
603
622
|
# Prints help.
|
604
623
|
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
|
624
|
+
@out.puts "seafoam file.bgv info"
|
625
|
+
@out.puts " file.bgv list"
|
626
|
+
@out.puts " file.bgv[:graph][:node[-edge]] search term..."
|
627
|
+
@out.puts " file.bgv[:graph][:node[-edge]] edges"
|
628
|
+
@out.puts " file.bgv[:graph][:node[-edge]] props"
|
629
|
+
@out.puts " file.bgv:graph:node source"
|
630
|
+
@out.puts " file.bgv:graph describe"
|
631
|
+
@out.puts " file.bgv:graph render"
|
632
|
+
@out.puts " --spotlight n,n,n..."
|
633
|
+
@out.puts " --out graph.pdf"
|
634
|
+
@out.puts " graph.svg"
|
635
|
+
@out.puts " graph.png"
|
636
|
+
@out.puts " graph.dot (Graphviz)"
|
637
|
+
@out.puts " graph.mmd (Mermaid)"
|
638
|
+
@out.puts " graph.md (Markdown)"
|
639
|
+
@out.puts " --full-truffle-args"
|
640
|
+
@out.puts " --show-frame-state"
|
641
|
+
@out.puts " --no-simplify-alloc"
|
642
|
+
@out.puts " --show-null-fields"
|
643
|
+
@out.puts " --show-pi"
|
644
|
+
@out.puts " --show-begin-end"
|
645
|
+
@out.puts " --hide-floating"
|
646
|
+
@out.puts " --no-reduce-edges"
|
647
|
+
@out.puts " --draw-blocks"
|
648
|
+
@out.puts " --option key value"
|
649
|
+
@out.puts " --help"
|
650
|
+
@out.puts " --version"
|
627
651
|
end
|
628
652
|
|
629
653
|
# Prints the version.
|
630
654
|
def version(*args)
|
631
|
-
raise ArgumentError, "unexpected arguments #{args.join(
|
655
|
+
raise ArgumentError, "unexpected arguments #{args.join(" ")}" unless args.empty?
|
632
656
|
|
633
657
|
@out.puts "seafoam #{VERSION}"
|
634
658
|
end
|
635
659
|
|
636
660
|
# Parse a name like file.bgv:g:n-e to [file.bgv, g, n, e].
|
637
661
|
def parse_name(name)
|
638
|
-
*pre, post = name.split(
|
662
|
+
*pre, post = name.split(".")
|
639
663
|
|
640
|
-
file_ext, graph, node, *rest = post.split(
|
664
|
+
file_ext, graph, node, *rest = post.split(":")
|
641
665
|
raise ArgumentError, "too many parts to .ext:g:n-e in #{name}" unless rest.empty?
|
642
666
|
|
643
|
-
file = [*pre, file_ext].join(
|
667
|
+
file = [*pre, file_ext].join(".")
|
644
668
|
|
645
669
|
if node
|
646
|
-
node, edge, *rest = node.split(
|
670
|
+
node, edge, *rest = node.split("-")
|
647
671
|
raise ArgumentError, "too many parts to edge name in #{name}" unless rest.empty?
|
648
672
|
else
|
649
673
|
node = nil
|
@@ -663,9 +687,9 @@ module Seafoam
|
|
663
687
|
|
664
688
|
case RUBY_PLATFORM
|
665
689
|
when /darwin/
|
666
|
-
system
|
690
|
+
system("open", file)
|
667
691
|
when /linux/
|
668
|
-
system
|
692
|
+
system("xdg-open", file)
|
669
693
|
end
|
670
694
|
# Don't worry if it fails.
|
671
695
|
end
|