seafoam 0.10 → 0.11

Sign up to get free protection for your applications and to get access to all the features.
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: []