seafoam 0.10 → 0.11

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f8665fe768d4900820ca676269cd25028306e8253c2109c71ff4cb31dd7c6e44
4
- data.tar.gz: fd8c52e5cf3daafa9b2673265067b743cc644755c3772c02904c2b815b3a93d2
3
+ metadata.gz: bc92671f5ea437e5afccf98c5874434251e6df05fde08e325e0b8b4a60d5d2b0
4
+ data.tar.gz: 77a8f71d631be2c02674784598a97d7da4b83c4556f2fc21c5d66496678b3792
5
5
  SHA512:
6
- metadata.gz: 815e7031027718cea7a933b7fc5ad822f754f05e3ae5bdc2066775183a9ca98c841b54e682a148c4437a29b1f95c4ede5833a2a1f2995d2c55296a800e71b269
7
- data.tar.gz: 462aaad5134c8b6cce229e8456742151354333c5e7c02283e2e90917fa7ad238f3f4f71770519357117f42b1579928ddb0bba3f04b31ddef68d7e41e92f8c016
6
+ metadata.gz: 2c9d7b5ccea117d2b1b686d66fffbeebe4282dde52f5c9880125f57911f4da4ed2e7660f1957597931e5bf714258b0c1a08e6c9fc0bfbc822915b2ae22c08964
7
+ data.tar.gz: 2c991ed3d87e80ccdb92630dfc3d2283b01ed2125c70883eec7b5e0cd6031d55acbb8930feb7cf6ef6e029b0e58ff2b01b2d2c81c0a2a0bca266070a2c28ba2c
@@ -162,8 +162,7 @@ module Seafoam
162
162
  count += 1
163
163
  arg
164
164
  end
165
- components = groups_names + [name]
166
- components.join('/')
165
+ groups_names + [name]
167
166
  end
168
167
 
169
168
  private
@@ -11,6 +11,14 @@ module Seafoam
11
11
  # Run the general seafoam command.
12
12
  def seafoam(*args)
13
13
  first, *args = args
14
+
15
+ if first == '--json'
16
+ formatter_module = Seafoam::Formatters::Json
17
+ first, *args = args
18
+ else
19
+ formatter_module = Seafoam::Formatters::Text
20
+ end
21
+
14
22
  case first
15
23
  when nil, 'help', '-h', '--help', '-help'
16
24
  raise ArgumentError, "unexpected arguments #{args.join(' ')}" unless args.empty?
@@ -25,23 +33,23 @@ module Seafoam
25
33
  when nil
26
34
  help(*args)
27
35
  when 'info'
28
- info name, *args
36
+ info name, formatter_module, *args
29
37
  when 'list'
30
- list name, *args
38
+ list name, formatter_module, *args
31
39
  when 'search'
32
40
  search name, *args
33
41
  when 'edges'
34
- edges name, *args
42
+ edges name, formatter_module, *args
35
43
  when 'props'
36
44
  props name, *args
37
45
  when 'source'
38
- source name, *args
46
+ source name, formatter_module, *args
39
47
  when 'render'
40
48
  render name, *args
41
49
  when 'debug'
42
50
  debug name, *args
43
51
  when 'describe'
44
- describe name, *args
52
+ describe name, formatter_module, *args
45
53
  else
46
54
  raise ArgumentError, "unknown command #{command}"
47
55
  end
@@ -186,35 +194,39 @@ module Seafoam
186
194
  private
187
195
 
188
196
  # seafoam file.bgv info
189
- def info(name, *args)
197
+ def info(name, formatter_module, *args)
190
198
  file, *rest = parse_name(name)
191
199
  raise ArgumentError, 'info only works with a file' unless rest == [nil, nil, nil]
192
-
193
200
  raise ArgumentError, 'info does not take arguments' unless args.empty?
194
201
 
195
202
  parser = BGV::BGVParser.new(file)
196
203
  major, minor = parser.read_file_header(version_check: false)
197
- @out.puts "BGV #{major}.#{minor}"
204
+ formatter = formatter_module::InfoFormatter.new(major, minor)
205
+
206
+ @out.puts formatter.format
198
207
  end
199
208
 
200
209
  # seafoam file.bgv list
201
- def list(name, *args)
210
+ def list(name, formatter_module, *args)
202
211
  file, *rest = parse_name(name)
203
212
  raise ArgumentError, 'list only works with a file' unless rest == [nil, nil, nil]
204
-
205
213
  raise ArgumentError, 'list does not take arguments' unless args.empty?
206
214
 
207
215
  parser = BGV::BGVParser.new(file)
208
216
  parser.read_file_header
209
217
  parser.skip_document_props
218
+ entries = []
210
219
  loop do
211
220
  index, = parser.read_graph_preheader
212
221
  break unless index
213
222
 
214
223
  graph_header = parser.read_graph_header
215
- @out.puts "#{file}:#{index} #{parser.graph_name(graph_header)}"
224
+ entries << formatter_module::ListFormatter::Entry.new(file, parser.graph_name(graph_header), index)
216
225
  parser.skip_graph
217
226
  end
227
+
228
+ formatter = formatter_module::ListFormatter.new(entries)
229
+ @out.puts formatter.format
218
230
  end
219
231
 
220
232
  # seafoam file.bgv:n... search term...
@@ -273,12 +285,13 @@ module Seafoam
273
285
  end
274
286
 
275
287
  # seafoam file.bgv:n... edges
276
- def edges(name, *args)
288
+ def edges(name, formatter_module, *args)
277
289
  file, graph_index, node_id, edge_id = parse_name(name)
278
290
  raise ArgumentError, 'edges needs at least a graph' unless graph_index
279
-
280
291
  raise ArgumentError, 'edges does not take arguments' unless args.empty?
281
292
 
293
+ entry = nil
294
+
282
295
  with_graph(file, graph_index) do |parser|
283
296
  parser.read_graph_header
284
297
  graph = parser.read_graph
@@ -294,24 +307,18 @@ module Seafoam
294
307
  edges = node.outputs.select { |edge| edge.to == to }
295
308
  raise ArgumentError, 'edge not found' if edges.empty?
296
309
 
297
- edges.each do |edge|
298
- @out.puts "#{edge.from.id_and_label} ->(#{edge.props[:label]}) #{edge.to.id_and_label}"
299
- end
310
+ entry = formatter_module::EdgesFormatter::EdgesEntry.new(edges)
300
311
  else
301
- @out.puts 'Input:'
302
- node.inputs.each do |input|
303
- @out.puts " #{node.id_and_label} <-(#{input.props[:label]}) #{input.from.id_and_label}"
304
- end
305
- @out.puts 'Output:'
306
- node.outputs.each do |output|
307
- @out.puts " #{node.id_and_label} ->(#{output.props[:label]}) #{output.to.id_and_label}"
308
- end
312
+ entry = formatter_module::EdgesFormatter::NodeEntry.new(node)
309
313
  end
310
314
  break
311
315
  else
312
- @out.puts "#{graph.nodes.count} nodes, #{graph.edges.count} edges"
316
+ entry = formatter_module::EdgesFormatter::SummaryEntry.new(graph.nodes.count, graph.edges.count)
313
317
  end
314
318
  end
319
+
320
+ formatter = formatter_module::EdgesFormatter.new(entry)
321
+ @out.puts formatter.format
315
322
  end
316
323
 
317
324
  # seafoam file.bgv... props
@@ -360,7 +367,7 @@ module Seafoam
360
367
  end
361
368
 
362
369
  # seafoam file.bgv:n:n source
363
- def source(name, *args)
370
+ def source(name, formatter_module, *args)
364
371
  file, graph_index, node_id, edge_id = parse_name(name)
365
372
  raise ArgumentError, 'source needs a node' unless node_id
366
373
  raise ArgumentError, 'source only works with a node' if edge_id
@@ -372,12 +379,13 @@ module Seafoam
372
379
  node = graph.nodes[node_id]
373
380
  raise ArgumentError, 'node not found' unless node
374
381
 
375
- @out.puts Graal::Source.render(node.props['nodeSourcePosition'])
382
+ formatter = formatter_module::SourceFormatter.new(node.props['nodeSourcePosition'])
383
+ @out.puts formatter.format
376
384
  end
377
385
  end
378
386
 
379
387
  # seafoam file.bgv:n describe
380
- def describe(name, *args)
388
+ def describe(name, formatter_module, *args)
381
389
  file, graph_index, *rest = parse_name(name)
382
390
 
383
391
  if graph_index.nil? || !rest.all?(&:nil?)
@@ -401,26 +409,25 @@ module Seafoam
401
409
  end
402
410
 
403
411
  graph = parser.read_graph
404
- notes = Set.new
412
+ description = Seafoam::Graal::GraphDescription.new
405
413
 
406
414
  graph.nodes.each_value do |node|
407
415
  node_class = node.props.dig(:node_class, :node_class)
408
416
  case node_class
409
417
  when 'org.graalvm.compiler.nodes.IfNode'
410
- notes.add 'branches'
418
+ description.branches = true
411
419
  when 'org.graalvm.compiler.nodes.LoopBeginNode'
412
- notes.add 'loops'
420
+ description.loops = true
413
421
  when 'org.graalvm.compiler.nodes.InvokeNode', 'org.graalvm.compiler.nodes.InvokeWithExceptionNode'
414
- notes.add 'calls'
422
+ description.calls = true
415
423
  end
416
424
  end
417
425
 
418
- notes.add 'deopts' if graph.nodes[0].outputs.map(&:to)
419
- .all? { |t| t.props.dig(:node_class, :node_class) == 'org.graalvm.compiler.nodes.DeoptimizeNode' }
420
-
421
- notes.add 'linear' unless notes.include?('branches') || notes.include?('loops')
426
+ description.deopts = graph.nodes[0].outputs.map(&:to)
427
+ .all? { |t| t.props.dig(:node_class, :node_class) == 'org.graalvm.compiler.nodes.DeoptimizeNode' }
422
428
 
423
- @out.puts ["#{graph.nodes.size} nodes", *notes].join(', ')
429
+ formatter = formatter_module::DescribeFormatter.new(graph, description)
430
+ @out.puts formatter.format
424
431
 
425
432
  break
426
433
  end
@@ -0,0 +1,88 @@
1
+ module Seafoam
2
+ module Formatters
3
+ module Base
4
+ # Formats the output of the `describe` command.
5
+ class DescribeFormatter
6
+ attr_reader :graph, :description
7
+
8
+ def initialize(graph, description)
9
+ @graph = graph
10
+ @description = description
11
+ end
12
+ end
13
+
14
+ # Formats the output of the `edges` command.
15
+ class EdgesFormatter
16
+ EdgesEntry = Struct.new(:edges) do
17
+ def render(formatter)
18
+ formatter.render_edges_entry(edges)
19
+ end
20
+ end
21
+
22
+ NodeEntry = Struct.new(:node) do
23
+ def render(formatter)
24
+ formatter.render_node_entry(node)
25
+ end
26
+ end
27
+
28
+ SummaryEntry = Struct.new(:node_count, :edge_count) do
29
+ def render(formatter)
30
+ formatter.render_summary_entry(node_count, edge_count)
31
+ end
32
+ end
33
+
34
+ attr_reader :entry
35
+
36
+ def initialize(entry)
37
+ @entry = entry
38
+ end
39
+
40
+ def format
41
+ entry.render(self)
42
+ end
43
+
44
+ def render_edges_entry(edges)
45
+ raise NotImplementedError
46
+ end
47
+
48
+ def render_node_entry(node)
49
+ raise NotImplementedError
50
+ end
51
+
52
+ def render_summary_entry(node_count, edge_count)
53
+ raise NotImplementedError
54
+ end
55
+ end
56
+
57
+ # Formats the output of the `info` command.
58
+ class InfoFormatter
59
+ attr_reader :major_version, :minor_version
60
+
61
+ def initialize(major_version, minor_version)
62
+ @major_version = major_version
63
+ @minor_version = minor_version
64
+ end
65
+ end
66
+
67
+ # Formats the output of the `list` command.
68
+ class ListFormatter
69
+ Entry = Struct.new(:file, :graph_name_components, :index)
70
+
71
+ attr_reader :entries
72
+
73
+ def initialize(entries)
74
+ @entries = entries
75
+ end
76
+ end
77
+
78
+ # Formats the output of the `source` command.
79
+ class SourceFormatter
80
+ attr_reader :source_position
81
+
82
+ def initialize(source_position)
83
+ @source_position = source_position
84
+ end
85
+ end
86
+ end
87
+ end
88
+ end
@@ -0,0 +1,8 @@
1
+ module Seafoam
2
+ # Formatters are the mechanism by which `seafoam` command output is presented to the user.
3
+ module Formatters
4
+ autoload :Base, 'seafoam/formatters/base'
5
+ autoload :Json, 'seafoam/formatters/json'
6
+ autoload :Text, 'seafoam/formatters/text'
7
+ end
8
+ end
@@ -0,0 +1,82 @@
1
+ require 'json'
2
+
3
+ module Seafoam
4
+ module Formatters
5
+ module Json
6
+ # A JSON-based formatter for the `describe` command.
7
+ class DescribeFormatter < Seafoam::Formatters::Base::DescribeFormatter
8
+ def format
9
+ ret = Seafoam::Graal::GraphDescription::ATTRIBUTES.map { |attr| [attr, description.send(attr)] }.to_h
10
+ ret[:node_count] = graph.nodes.size
11
+
12
+ ret.to_json
13
+ end
14
+ end
15
+
16
+ # A JSON-based formatter for the `edges` command.
17
+ class EdgesFormatter < Seafoam::Formatters::Base::EdgesFormatter
18
+ def render_edges_entry(edges)
19
+ edges.map { |edge| build_edge(edge) }.to_json
20
+ end
21
+
22
+ def render_node_entry(node)
23
+ {
24
+ input: node.inputs.map { |input| build_edge(input) },
25
+ output: node.outputs.map { |output| build_edge(output) }
26
+ }.to_json
27
+ end
28
+
29
+ def render_summary_entry(node_count, edge_count)
30
+ { node_count: node_count, edge_count: edge_count }.to_json
31
+ end
32
+
33
+ def build_node(node)
34
+ { id: node.id.to_s, label: node.props[:label] }
35
+ end
36
+
37
+ def build_edge(edge)
38
+ { from: build_node(edge.from), to: build_node(edge.to), label: edge.props[:label] }
39
+ end
40
+ end
41
+
42
+ # A JSON-based formatter for the `info` command.
43
+ class InfoFormatter < Seafoam::Formatters::Base::InfoFormatter
44
+ def format
45
+ {
46
+ major_version: major_version,
47
+ minor_version: minor_version
48
+ }.to_json
49
+ end
50
+ end
51
+
52
+ # A JSON-based formatter for the `list` command.
53
+ class ListFormatter < Seafoam::Formatters::Base::ListFormatter
54
+ def format
55
+ entries.map do |entry|
56
+ {
57
+ graph_index: entry.index,
58
+ graph_file: entry.file,
59
+ graph_name_components: entry.graph_name_components
60
+ }
61
+ end.to_json
62
+ end
63
+ end
64
+
65
+ # A JSON-based formatter for the `source` command.
66
+ class SourceFormatter < Seafoam::Formatters::Base::SourceFormatter
67
+ def format
68
+ Seafoam::Graal::Source.walk(source_position, &method(:render_method)).to_json
69
+ end
70
+
71
+ def render_method(method)
72
+ declaring_class = method[:declaring_class]
73
+ name = method[:method_name]
74
+ {
75
+ class: declaring_class,
76
+ method: name
77
+ }
78
+ end
79
+ end
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,70 @@
1
+ module Seafoam
2
+ module Formatters
3
+ module Text
4
+ # A plain-text formatter for the `describe` command.
5
+ class DescribeFormatter < Seafoam::Formatters::Base::DescribeFormatter
6
+ def format
7
+ notes = Seafoam::Graal::GraphDescription::ATTRIBUTES.select { |attr| description.send(attr) }
8
+
9
+ ["#{graph.nodes.size} nodes", *notes].join(', ')
10
+ end
11
+ end
12
+
13
+ # A plain-text formatter for the `edges` command.
14
+ class EdgesFormatter < Seafoam::Formatters::Base::EdgesFormatter
15
+ def render_edges_entry(edges)
16
+ edges.map do |edge|
17
+ "#{edge.from.id_and_label} ->(#{edge.props[:label]}) #{edge.to.id_and_label}"
18
+ end.join("\n")
19
+ end
20
+
21
+ def render_node_entry(node)
22
+ ret = ['Input:']
23
+ ret += node.inputs.map do |input|
24
+ " #{node.id_and_label} <-(#{input.props[:label]}) #{input.from.id_and_label}"
25
+ end
26
+
27
+ ret << 'Output:'
28
+ ret += node.outputs.map do |output|
29
+ " #{node.id_and_label} ->(#{output.props[:label]}) #{output.to.id_and_label}"
30
+ end
31
+
32
+ ret.join("\n")
33
+ end
34
+
35
+ def render_summary_entry(node_count, edge_count)
36
+ "#{node_count} nodes, #{edge_count} edges"
37
+ end
38
+ end
39
+
40
+ # A plain-text formatter for the `info` command.
41
+ class InfoFormatter < Seafoam::Formatters::Base::InfoFormatter
42
+ def format
43
+ "BGV #{major_version}.#{minor_version}"
44
+ end
45
+ end
46
+
47
+ # A plain-text formatter for the `list` command.
48
+ class ListFormatter < Seafoam::Formatters::Base::ListFormatter
49
+ def format
50
+ entries.map do |entry|
51
+ "#{entry.file}:#{entry.index} #{entry.graph_name_components.join('/')}"
52
+ end.join("\n")
53
+ end
54
+ end
55
+
56
+ # A plain-text formatter for the `source` command.
57
+ class SourceFormatter < Seafoam::Formatters::Base::SourceFormatter
58
+ def format
59
+ Seafoam::Graal::Source.walk(source_position, &method(:render_method)).join("\n")
60
+ end
61
+
62
+ def render_method(method)
63
+ declaring_class = method[:declaring_class]
64
+ name = method[:method_name]
65
+ "#{declaring_class}##{name}"
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,22 @@
1
+ module Seafoam
2
+ module Graal
3
+ # Provides a high level description of a Graal graph's features.
4
+ class GraphDescription
5
+ ATTRIBUTES = %i[branches calls deopts linear loops]
6
+
7
+ ATTRIBUTES.each { |attr| attr_accessor(attr) }
8
+
9
+ def initialize
10
+ @branches = false
11
+ @calls = false
12
+ @deopts = false
13
+ @linear = false
14
+ @loops = false
15
+ end
16
+
17
+ def linear
18
+ !branches && !loops
19
+ end
20
+ end
21
+ end
22
+ end
@@ -2,21 +2,17 @@ module Seafoam
2
2
  module Graal
3
3
  # Routines for understanding source positions in Graal.
4
4
  module Source
5
- def self.render(source_position)
6
- lines = []
5
+ def self.walk(source_position, &block)
6
+ results = []
7
+
7
8
  caller = source_position
8
9
  while caller
9
10
  method = caller[:method]
10
- lines.push render_method(method)
11
+ results.push block.call(method)
11
12
  caller = caller[:caller]
12
13
  end
13
- lines.join("\n")
14
- end
15
14
 
16
- def self.render_method(method)
17
- declaring_class = method[:declaring_class]
18
- name = method[:method_name]
19
- "#{declaring_class}##{name}"
15
+ results
20
16
  end
21
17
  end
22
18
  end
@@ -1,5 +1,5 @@
1
1
  module Seafoam
2
2
  MAJOR_VERSION = 0
3
- MINOR_VERSION = 10
3
+ MINOR_VERSION = 11
4
4
  VERSION = "#{MAJOR_VERSION}.#{MINOR_VERSION}"
5
5
  end
data/lib/seafoam.rb CHANGED
@@ -5,6 +5,7 @@ require 'seafoam/cfg/cfg_parser'
5
5
  require 'seafoam/cfg/disassembler'
6
6
  require 'seafoam/colors'
7
7
  require 'seafoam/graph'
8
+ require 'seafoam/graal/graph_description'
8
9
  require 'seafoam/graal/source'
9
10
  require 'seafoam/graal/pi'
10
11
  require 'seafoam/passes'
@@ -16,3 +17,4 @@ require 'seafoam/isabelle_writer'
16
17
  require 'seafoam/json_writer'
17
18
  require 'seafoam/graphviz_writer'
18
19
  require 'seafoam/commands'
20
+ require 'seafoam/formatters/formatters'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: seafoam
3
3
  version: !ruby/object:Gem::Version
4
- version: '0.10'
4
+ version: '0.11'
5
5
  platform: ruby
6
6
  authors:
7
7
  - Chris Seaton
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-12-10 00:00:00.000000000 Z
11
+ date: 2022-01-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: crabstone
@@ -80,8 +80,8 @@ dependencies:
80
80
  - - "~>"
81
81
  - !ruby/object:Gem::Version
82
82
  version: '0.74'
83
- description:
84
- email:
83
+ description:
84
+ email:
85
85
  executables:
86
86
  - seafoam
87
87
  - bgv2json
@@ -101,6 +101,11 @@ files:
101
101
  - lib/seafoam/cfg/disassembler.rb
102
102
  - lib/seafoam/colors.rb
103
103
  - lib/seafoam/commands.rb
104
+ - lib/seafoam/formatters/base.rb
105
+ - lib/seafoam/formatters/formatters.rb
106
+ - lib/seafoam/formatters/json.rb
107
+ - lib/seafoam/formatters/text.rb
108
+ - lib/seafoam/graal/graph_description.rb
104
109
  - lib/seafoam/graal/pi.rb
105
110
  - lib/seafoam/graal/source.rb
106
111
  - lib/seafoam/graph.rb
@@ -117,7 +122,7 @@ homepage: https://github.com/Shopify/seafoam
117
122
  licenses:
118
123
  - MIT
119
124
  metadata: {}
120
- post_install_message:
125
+ post_install_message:
121
126
  rdoc_options: []
122
127
  require_paths:
123
128
  - lib
@@ -132,8 +137,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
132
137
  - !ruby/object:Gem::Version
133
138
  version: '0'
134
139
  requirements: []
135
- rubygems_version: 3.2.22
136
- signing_key:
140
+ rubyforge_project:
141
+ rubygems_version: 2.7.6.3
142
+ signing_key:
137
143
  specification_version: 4
138
144
  summary: A tool for working with compiler graphs
139
145
  test_files: []