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
         |