seafoam 0.11 → 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 +210 -202
- 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 +10 -3
- 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 +18 -0
- data/lib/seafoam/mermaid_writer.rb +52 -0
- 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 +9 -40
- data/bin/cfg2asm +0 -20
- data/lib/seafoam/cfg/cfg_parser.rb +0 -93
- data/lib/seafoam/cfg/disassembler.rb +0 -70
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,53 +143,9 @@ module Seafoam
|
|
141
143
|
name = parser.graph_name(graph_header)
|
142
144
|
graph = parser.read_graph
|
143
145
|
|
144
|
-
writer.write
|
145
|
-
end
|
146
|
-
end
|
147
|
-
end
|
148
|
-
end
|
149
|
-
|
150
|
-
def cfg2asm(*args)
|
151
|
-
case args.first
|
152
|
-
when nil, 'help', '-h', '--help', '-help'
|
153
|
-
args = args.drop(1)
|
154
|
-
raise ArgumentError, "unexpected arguments #{args.join(' ')}" unless args.empty?
|
155
|
-
|
156
|
-
@out.puts 'cfg2asm file.bgv...'
|
157
|
-
@out.puts ' --no-comments'
|
158
|
-
@out.puts ' --help'
|
159
|
-
@out.puts ' --version'
|
160
|
-
when 'version', '-v', '-version', '--version'
|
161
|
-
args = args.drop(1)
|
162
|
-
version(*args)
|
163
|
-
else
|
164
|
-
comments = true
|
165
|
-
files = []
|
166
|
-
|
167
|
-
until args.empty?
|
168
|
-
arg = args.shift
|
169
|
-
if arg.start_with?('-')
|
170
|
-
case arg
|
171
|
-
when '--no-comments'
|
172
|
-
comments = false
|
173
|
-
else
|
174
|
-
raise ArgumentError, "unknown option #{arg}"
|
175
|
-
end
|
176
|
-
else
|
177
|
-
files.push arg
|
146
|
+
writer.write(name, graph)
|
178
147
|
end
|
179
148
|
end
|
180
|
-
|
181
|
-
files.each_with_index do |file, n|
|
182
|
-
parser = Seafoam::CFG::CFGParser.new(@out, file)
|
183
|
-
parser.skip_over_cfg 'After code installation'
|
184
|
-
nmethod = parser.read_nmethod
|
185
|
-
|
186
|
-
disassembler = Seafoam::CFG::Disassembler.new(@out)
|
187
|
-
@out.puts if n.positive?
|
188
|
-
@out.puts "[#{file}]"
|
189
|
-
disassembler.disassemble(nmethod, comments)
|
190
|
-
end
|
191
149
|
end
|
192
150
|
end
|
193
151
|
|
@@ -196,8 +154,8 @@ module Seafoam
|
|
196
154
|
# seafoam file.bgv info
|
197
155
|
def info(name, formatter_module, *args)
|
198
156
|
file, *rest = parse_name(name)
|
199
|
-
raise ArgumentError,
|
200
|
-
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?
|
201
159
|
|
202
160
|
parser = BGV::BGVParser.new(file)
|
203
161
|
major, minor = parser.read_file_header(version_check: false)
|
@@ -209,8 +167,8 @@ module Seafoam
|
|
209
167
|
# seafoam file.bgv list
|
210
168
|
def list(name, formatter_module, *args)
|
211
169
|
file, *rest = parse_name(name)
|
212
|
-
raise ArgumentError,
|
213
|
-
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?
|
214
172
|
|
215
173
|
parser = BGV::BGVParser.new(file)
|
216
174
|
parser.read_file_header
|
@@ -232,7 +190,7 @@ module Seafoam
|
|
232
190
|
# seafoam file.bgv:n... search term...
|
233
191
|
def search(name, *terms)
|
234
192
|
file, graph_index, node_id, = parse_name(name)
|
235
|
-
raise ArgumentError,
|
193
|
+
raise ArgumentError, "search only works with a file or graph" if node_id
|
236
194
|
|
237
195
|
parser = BGV::BGVParser.new(file)
|
238
196
|
parser.read_file_header
|
@@ -243,13 +201,13 @@ module Seafoam
|
|
243
201
|
|
244
202
|
if !graph_index || index == graph_index
|
245
203
|
header = parser.read_graph_header
|
246
|
-
search_object
|
204
|
+
search_object("#{file}:#{index}", header, terms)
|
247
205
|
graph = parser.read_graph
|
248
206
|
graph.nodes.each_value do |node|
|
249
|
-
search_object
|
207
|
+
search_object("#{file}:#{index}:#{node.id}", node.props, terms)
|
250
208
|
end
|
251
209
|
graph.edges.each do |edge|
|
252
|
-
search_object
|
210
|
+
search_object("#{file}:#{index}:#{edge.from.id}-#{edge.to.id}", edge.props, terms)
|
253
211
|
end
|
254
212
|
else
|
255
213
|
parser.skip_graph_header
|
@@ -275,8 +233,8 @@ module Seafoam
|
|
275
233
|
highlight_on = "\033[1m"
|
276
234
|
highlight_off = "\033[0m"
|
277
235
|
else
|
278
|
-
highlight_on =
|
279
|
-
highlight_off =
|
236
|
+
highlight_on = ""
|
237
|
+
highlight_off = ""
|
280
238
|
end
|
281
239
|
@out.puts "#{tag} ...#{before}#{highlight_on}#{match}#{highlight_off}#{after}..."
|
282
240
|
start = index + t.size
|
@@ -287,8 +245,8 @@ module Seafoam
|
|
287
245
|
# seafoam file.bgv:n... edges
|
288
246
|
def edges(name, formatter_module, *args)
|
289
247
|
file, graph_index, node_id, edge_id = parse_name(name)
|
290
|
-
raise ArgumentError,
|
291
|
-
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?
|
292
250
|
|
293
251
|
entry = nil
|
294
252
|
|
@@ -296,16 +254,16 @@ module Seafoam
|
|
296
254
|
parser.read_graph_header
|
297
255
|
graph = parser.read_graph
|
298
256
|
if node_id
|
299
|
-
Passes.apply
|
257
|
+
Passes.apply(graph)
|
300
258
|
node = graph.nodes[node_id]
|
301
|
-
raise ArgumentError,
|
259
|
+
raise ArgumentError, "node not found" unless node
|
302
260
|
|
303
261
|
if edge_id
|
304
262
|
to = graph.nodes[edge_id]
|
305
|
-
raise ArgumentError,
|
263
|
+
raise ArgumentError, "edge node not found" unless to
|
306
264
|
|
307
265
|
edges = node.outputs.select { |edge| edge.to == to }
|
308
|
-
raise ArgumentError,
|
266
|
+
raise ArgumentError, "edge not found" if edges.empty?
|
309
267
|
|
310
268
|
entry = formatter_module::EdgesFormatter::EdgesEntry.new(edges)
|
311
269
|
else
|
@@ -323,8 +281,10 @@ module Seafoam
|
|
323
281
|
|
324
282
|
# seafoam file.bgv... props
|
325
283
|
def props(name, *args)
|
284
|
+
# rubocop:disable Metrics/BlockNesting
|
285
|
+
|
326
286
|
file, graph_index, node_id, edge_id = parse_name(name)
|
327
|
-
raise ArgumentError,
|
287
|
+
raise ArgumentError, "props does not take arguments" unless args.empty?
|
328
288
|
|
329
289
|
if graph_index
|
330
290
|
with_graph(file, graph_index) do |parser|
|
@@ -332,29 +292,29 @@ module Seafoam
|
|
332
292
|
if node_id
|
333
293
|
graph = parser.read_graph
|
334
294
|
node = graph.nodes[node_id]
|
335
|
-
raise ArgumentError,
|
295
|
+
raise ArgumentError, "node not found" unless node
|
336
296
|
|
337
297
|
if edge_id
|
338
298
|
to = graph.nodes[edge_id]
|
339
|
-
raise ArgumentError,
|
299
|
+
raise ArgumentError, "edge node not found" unless to
|
340
300
|
|
341
301
|
edges = node.outputs.select { |edge| edge.to == to }
|
342
|
-
raise ArgumentError,
|
302
|
+
raise ArgumentError, "edge not found" if edges.empty?
|
343
303
|
|
344
304
|
if edges.size > 1
|
345
305
|
edges.each do |edge|
|
346
|
-
pretty_print
|
306
|
+
pretty_print(edge.props)
|
347
307
|
@out.puts
|
348
308
|
end
|
349
309
|
else
|
350
|
-
pretty_print
|
310
|
+
pretty_print(edges.first.props)
|
351
311
|
end
|
352
312
|
else
|
353
|
-
pretty_print
|
313
|
+
pretty_print(node.props)
|
354
314
|
end
|
355
315
|
break
|
356
316
|
else
|
357
|
-
pretty_print
|
317
|
+
pretty_print(graph_header)
|
358
318
|
parser.skip_graph
|
359
319
|
end
|
360
320
|
end
|
@@ -362,24 +322,26 @@ module Seafoam
|
|
362
322
|
parser = BGV::BGVParser.new(file)
|
363
323
|
parser.read_file_header
|
364
324
|
document_props = parser.read_document_props
|
365
|
-
pretty_print
|
325
|
+
pretty_print(document_props || {})
|
366
326
|
end
|
327
|
+
|
328
|
+
# rubocop:enable Metrics/BlockNesting
|
367
329
|
end
|
368
330
|
|
369
331
|
# seafoam file.bgv:n:n source
|
370
332
|
def source(name, formatter_module, *args)
|
371
333
|
file, graph_index, node_id, edge_id = parse_name(name)
|
372
|
-
raise ArgumentError,
|
373
|
-
raise ArgumentError,
|
374
|
-
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?
|
375
337
|
|
376
338
|
with_graph(file, graph_index) do |parser|
|
377
339
|
parser.read_graph_header
|
378
340
|
graph = parser.read_graph
|
379
341
|
node = graph.nodes[node_id]
|
380
|
-
raise ArgumentError,
|
342
|
+
raise ArgumentError, "node not found" unless node
|
381
343
|
|
382
|
-
formatter = formatter_module::SourceFormatter.new(node.props[
|
344
|
+
formatter = formatter_module::SourceFormatter.new(node.props["nodeSourcePosition"])
|
383
345
|
@out.puts formatter.format
|
384
346
|
end
|
385
347
|
end
|
@@ -389,9 +351,9 @@ module Seafoam
|
|
389
351
|
file, graph_index, *rest = parse_name(name)
|
390
352
|
|
391
353
|
if graph_index.nil? || !rest.all?(&:nil?)
|
392
|
-
raise ArgumentError,
|
354
|
+
raise ArgumentError, "describe only works with a graph"
|
393
355
|
end
|
394
|
-
raise ArgumentError,
|
356
|
+
raise ArgumentError, "describe does not take arguments" unless args.empty?
|
395
357
|
|
396
358
|
parser = BGV::BGVParser.new(file)
|
397
359
|
parser.read_file_header
|
@@ -412,19 +374,23 @@ module Seafoam
|
|
412
374
|
description = Seafoam::Graal::GraphDescription.new
|
413
375
|
|
414
376
|
graph.nodes.each_value do |node|
|
415
|
-
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
|
+
|
416
382
|
case node_class
|
417
|
-
when
|
383
|
+
when "org.graalvm.compiler.nodes.IfNode"
|
418
384
|
description.branches = true
|
419
|
-
when
|
385
|
+
when "org.graalvm.compiler.nodes.LoopBeginNode"
|
420
386
|
description.loops = true
|
421
|
-
when
|
387
|
+
when "org.graalvm.compiler.nodes.InvokeNode", "org.graalvm.compiler.nodes.InvokeWithExceptionNode"
|
422
388
|
description.calls = true
|
423
389
|
end
|
424
390
|
end
|
425
391
|
|
426
392
|
description.deopts = graph.nodes[0].outputs.map(&:to)
|
427
|
-
|
393
|
+
.all? { |t| t.node_class == "org.graalvm.compiler.nodes.DeoptimizeNode" }
|
428
394
|
|
429
395
|
formatter = formatter_module::DescribeFormatter.new(graph, description)
|
430
396
|
@out.puts formatter.format
|
@@ -436,15 +402,18 @@ module Seafoam
|
|
436
402
|
# seafoam file.bgv:n render options...
|
437
403
|
def render(name, *args)
|
438
404
|
file, graph_index, *rest = parse_name(name)
|
439
|
-
raise ArgumentError,
|
440
|
-
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]
|
441
407
|
|
442
408
|
pass_options = {
|
443
409
|
simplify_truffle_args: true,
|
444
410
|
hide_frame_state: true,
|
445
411
|
hide_pi: true,
|
412
|
+
hide_begin_end: true,
|
446
413
|
hide_floating: false,
|
447
|
-
reduce_edges: true
|
414
|
+
reduce_edges: true,
|
415
|
+
simplify_alloc: true,
|
416
|
+
hide_null_fields: true,
|
448
417
|
}
|
449
418
|
spotlight_nodes = nil
|
450
419
|
args = args.dup
|
@@ -454,85 +423,119 @@ module Seafoam
|
|
454
423
|
until args.empty?
|
455
424
|
arg = args.shift
|
456
425
|
case arg
|
457
|
-
when
|
426
|
+
when "--out"
|
458
427
|
out_file = args.shift
|
459
428
|
explicit_out_file = true
|
460
|
-
raise ArgumentError,
|
461
|
-
|
429
|
+
raise ArgumentError, "no file for --out" unless out_file
|
430
|
+
|
431
|
+
out_ext = File.extname(out_file).downcase
|
432
|
+
case out_ext
|
433
|
+
when ".pdf"
|
434
|
+
out_format = :pdf
|
435
|
+
when ".svg"
|
436
|
+
out_format = :svg
|
437
|
+
when ".png"
|
438
|
+
out_format = :png
|
439
|
+
when ".dot"
|
440
|
+
out_format = :dot
|
441
|
+
when ".mmd"
|
442
|
+
out_format = :mmd
|
443
|
+
when ".md"
|
444
|
+
out_format = :md
|
445
|
+
else
|
446
|
+
raise ArgumentError, "unknown render format #{out_ext}"
|
447
|
+
end
|
448
|
+
when "--md"
|
449
|
+
out_file = @out
|
450
|
+
out_format = :md
|
451
|
+
explicit_out_file = true
|
452
|
+
when "--spotlight"
|
462
453
|
spotlight_arg = args.shift
|
463
|
-
raise ArgumentError,
|
454
|
+
raise ArgumentError, "no list for --spotlight" unless spotlight_arg
|
464
455
|
|
465
|
-
spotlight_nodes = spotlight_arg.split(
|
466
|
-
when
|
456
|
+
spotlight_nodes = spotlight_arg.split(",").map { |n| Integer(n) }
|
457
|
+
when "--full-truffle-args"
|
467
458
|
pass_options[:simplify_truffle_args] = false
|
468
|
-
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"
|
469
464
|
pass_options[:hide_frame_state] = false
|
470
|
-
when
|
465
|
+
when "--show-pi"
|
471
466
|
pass_options[:hide_pi] = false
|
472
|
-
when
|
467
|
+
when "--show-begin-end"
|
468
|
+
pass_options[:hide_begin_end] = false
|
469
|
+
when "--hide-floating"
|
473
470
|
pass_options[:hide_floating] = true
|
474
|
-
when
|
471
|
+
when "--no-reduce-edges"
|
475
472
|
pass_options[:reduce_edges] = false
|
476
|
-
when
|
473
|
+
when "--draw-blocks"
|
477
474
|
draw_blocks = true
|
478
|
-
when
|
475
|
+
when "--option"
|
479
476
|
key = args.shift
|
480
|
-
raise ArgumentError,
|
477
|
+
raise ArgumentError, "no key for --option" unless key
|
481
478
|
|
482
479
|
value = args.shift
|
483
480
|
raise ArgumentError, "no value for --option #{key}" unless out_file
|
484
481
|
|
485
|
-
value = {
|
482
|
+
value = { "true" => true, "false" => "false" }.fetch(key, value)
|
486
483
|
pass_options[key.to_sym] = value
|
487
484
|
else
|
488
485
|
raise ArgumentError, "unexpected option #{arg}"
|
489
486
|
end
|
490
487
|
end
|
491
|
-
out_file ||=
|
492
|
-
|
493
|
-
case out_ext
|
494
|
-
when '.pdf'
|
495
|
-
out_format = :pdf
|
496
|
-
when '.svg'
|
497
|
-
out_format = :svg
|
498
|
-
when '.png'
|
499
|
-
out_format = :png
|
500
|
-
when '.dot'
|
501
|
-
out_format = :dot
|
502
|
-
else
|
503
|
-
raise ArgumentError, "unknown render format #{out_ext}"
|
504
|
-
end
|
505
|
-
|
488
|
+
out_file ||= "graph.pdf"
|
489
|
+
out_format ||= :pdf
|
506
490
|
with_graph(file, graph_index) do |parser|
|
507
491
|
parser.skip_graph_header
|
508
492
|
graph = parser.read_graph
|
509
|
-
Passes.apply
|
493
|
+
Passes.apply(graph, pass_options)
|
510
494
|
if spotlight_nodes
|
511
495
|
spotlight = Spotlight.new(graph)
|
512
496
|
spotlight_nodes.each do |node_id|
|
513
497
|
node = graph.nodes[node_id]
|
514
|
-
raise ArgumentError,
|
498
|
+
raise ArgumentError, "node not found" unless node
|
515
499
|
|
516
|
-
spotlight.light
|
500
|
+
spotlight.light(node)
|
517
501
|
end
|
518
502
|
spotlight.shade
|
519
503
|
end
|
520
|
-
|
521
|
-
|
522
|
-
|
523
|
-
|
504
|
+
case out_format
|
505
|
+
when :dot, :mmd, :md
|
506
|
+
action = lambda do |stream|
|
507
|
+
case out_format
|
508
|
+
when :dot
|
509
|
+
writer = GraphvizWriter.new(stream)
|
510
|
+
writer.write_graph(graph, false, draw_blocks)
|
511
|
+
when :mmd
|
512
|
+
writer = MermaidWriter.new(stream)
|
513
|
+
writer.write_graph(graph, false, draw_blocks)
|
514
|
+
when :md
|
515
|
+
writer = MarkdownWriter.new(stream)
|
516
|
+
writer.write_graph(graph)
|
517
|
+
else
|
518
|
+
raise
|
519
|
+
end
|
520
|
+
end
|
521
|
+
if out_file.is_a?(String)
|
522
|
+
File.open(out_file, "w") do |stream|
|
523
|
+
action.call(stream)
|
524
|
+
end
|
525
|
+
else
|
526
|
+
action.call(out_file)
|
524
527
|
end
|
525
528
|
else
|
526
529
|
begin
|
527
|
-
IO.popen([
|
530
|
+
IO.popen(["dot", "-T#{out_format}", "-o", out_file], "w") do |stream|
|
528
531
|
writer = GraphvizWriter.new(stream)
|
529
532
|
hidpi = out_format == :png
|
530
|
-
writer.write_graph
|
533
|
+
writer.write_graph(graph, hidpi, draw_blocks)
|
531
534
|
end
|
532
535
|
rescue Errno::ENOENT
|
533
|
-
raise
|
536
|
+
raise "Could not run Graphviz - is it installed?"
|
534
537
|
end
|
535
|
-
autoopen
|
538
|
+
autoopen(out_file) unless explicit_out_file
|
536
539
|
end
|
537
540
|
end
|
538
541
|
end
|
@@ -540,12 +543,12 @@ module Seafoam
|
|
540
543
|
# seafoam file.bgv debug options...
|
541
544
|
def debug(name, *args)
|
542
545
|
file, *rest = parse_name(name)
|
543
|
-
raise ArgumentError,
|
546
|
+
raise ArgumentError, "debug only works with a file" unless rest == [nil, nil, nil]
|
544
547
|
|
545
548
|
skip = false
|
546
549
|
args.each do |arg|
|
547
550
|
case arg
|
548
|
-
when
|
551
|
+
when "--skip"
|
549
552
|
skip = true
|
550
553
|
else
|
551
554
|
raise ArgumentError, "unexpected option #{arg}"
|
@@ -555,10 +558,10 @@ module Seafoam
|
|
555
558
|
File.open(file) do |stream|
|
556
559
|
parser = BGVDebugParser.new(@out, stream)
|
557
560
|
begin
|
558
|
-
pretty_print
|
561
|
+
pretty_print(parser.read_file_header)
|
559
562
|
document_props = parser.read_document_props
|
560
563
|
if document_props
|
561
|
-
pretty_print
|
564
|
+
pretty_print(document_props)
|
562
565
|
end
|
563
566
|
loop do
|
564
567
|
index, id = parser.read_graph_preheader
|
@@ -569,8 +572,8 @@ module Seafoam
|
|
569
572
|
parser.skip_graph_header
|
570
573
|
parser.skip_graph
|
571
574
|
else
|
572
|
-
pretty_print
|
573
|
-
pretty_print
|
575
|
+
pretty_print(parser.read_graph_header)
|
576
|
+
pretty_print(parser.read_graph)
|
574
577
|
end
|
575
578
|
end
|
576
579
|
rescue StandardError => e
|
@@ -613,53 +616,58 @@ module Seafoam
|
|
613
616
|
parser.skip_graph
|
614
617
|
end
|
615
618
|
end
|
616
|
-
raise ArgumentError,
|
619
|
+
raise ArgumentError, "graph not found" unless graph_found
|
617
620
|
end
|
618
621
|
|
619
622
|
# Prints help.
|
620
623
|
def help(*_args)
|
621
|
-
@out.puts
|
622
|
-
@out.puts
|
623
|
-
@out.puts
|
624
|
-
@out.puts
|
625
|
-
@out.puts
|
626
|
-
@out.puts
|
627
|
-
@out.puts
|
628
|
-
@out.puts
|
629
|
-
@out.puts
|
630
|
-
@out.puts
|
631
|
-
@out.puts
|
632
|
-
@out.puts
|
633
|
-
@out.puts
|
634
|
-
@out.puts
|
635
|
-
@out.puts
|
636
|
-
@out.puts
|
637
|
-
@out.puts
|
638
|
-
@out.puts
|
639
|
-
@out.puts
|
640
|
-
@out.puts
|
641
|
-
@out.puts
|
642
|
-
@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"
|
643
651
|
end
|
644
652
|
|
645
653
|
# Prints the version.
|
646
654
|
def version(*args)
|
647
|
-
raise ArgumentError, "unexpected arguments #{args.join(
|
655
|
+
raise ArgumentError, "unexpected arguments #{args.join(" ")}" unless args.empty?
|
648
656
|
|
649
657
|
@out.puts "seafoam #{VERSION}"
|
650
658
|
end
|
651
659
|
|
652
660
|
# Parse a name like file.bgv:g:n-e to [file.bgv, g, n, e].
|
653
661
|
def parse_name(name)
|
654
|
-
*pre, post = name.split(
|
662
|
+
*pre, post = name.split(".")
|
655
663
|
|
656
|
-
file_ext, graph, node, *rest = post.split(
|
664
|
+
file_ext, graph, node, *rest = post.split(":")
|
657
665
|
raise ArgumentError, "too many parts to .ext:g:n-e in #{name}" unless rest.empty?
|
658
666
|
|
659
|
-
file = [*pre, file_ext].join(
|
667
|
+
file = [*pre, file_ext].join(".")
|
660
668
|
|
661
669
|
if node
|
662
|
-
node, edge, *rest = node.split(
|
670
|
+
node, edge, *rest = node.split("-")
|
663
671
|
raise ArgumentError, "too many parts to edge name in #{name}" unless rest.empty?
|
664
672
|
else
|
665
673
|
node = nil
|
@@ -679,9 +687,9 @@ module Seafoam
|
|
679
687
|
|
680
688
|
case RUBY_PLATFORM
|
681
689
|
when /darwin/
|
682
|
-
system
|
690
|
+
system("open", file)
|
683
691
|
when /linux/
|
684
|
-
system
|
692
|
+
system("xdg-open", file)
|
685
693
|
end
|
686
694
|
# Don't worry if it fails.
|
687
695
|
end
|