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
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
|