vendored parslet, deemed stable enough and better without dependency
This commit is contained in:
97
lib/parslet/graphviz.rb
Normal file
97
lib/parslet/graphviz.rb
Normal file
@@ -0,0 +1,97 @@
|
||||
|
||||
# Paints a graphviz graph of your parser.
|
||||
|
||||
begin
|
||||
require 'ruby-graphviz'
|
||||
rescue LoadError
|
||||
puts "Please install the 'ruby-graphviz' gem first."
|
||||
fail
|
||||
end
|
||||
|
||||
require 'set'
|
||||
require 'parslet/atoms/visitor'
|
||||
|
||||
module Parslet
|
||||
class GraphvizVisitor
|
||||
def initialize g
|
||||
@graph = g
|
||||
@known_links = Set.new
|
||||
@visited = Set.new
|
||||
end
|
||||
|
||||
attr_reader :parent
|
||||
|
||||
def visit_parser(root)
|
||||
recurse root, node('parser')
|
||||
end
|
||||
def visit_entity(name, block)
|
||||
s = node(name)
|
||||
|
||||
downwards s
|
||||
|
||||
return if @visited.include?(name)
|
||||
@visited << name
|
||||
|
||||
recurse block.call, s
|
||||
end
|
||||
def visit_named(name, atom)
|
||||
recurse atom, parent
|
||||
end
|
||||
def visit_repetition(tag, min, max, atom)
|
||||
recurse atom, parent
|
||||
end
|
||||
def visit_alternative(alternatives)
|
||||
p = parent
|
||||
alternatives.each do |atom|
|
||||
recurse atom, p
|
||||
end
|
||||
end
|
||||
def visit_sequence(sequence)
|
||||
p = parent
|
||||
sequence.each do |atom|
|
||||
recurse atom, p
|
||||
end
|
||||
end
|
||||
def visit_lookahead(positive, atom)
|
||||
recurse atom, parent
|
||||
end
|
||||
def visit_re(regexp)
|
||||
# downwards node(regexp.object_id, label: escape("re(#{regexp.inspect})"))
|
||||
end
|
||||
def visit_str(str)
|
||||
# downwards node(str.object_id, label: escape("#{str.inspect}"))
|
||||
end
|
||||
|
||||
def escape str
|
||||
str.gsub('"', "'")
|
||||
end
|
||||
def node name, opts={}
|
||||
@graph.add_nodes name.to_s, opts
|
||||
end
|
||||
def downwards child
|
||||
if @parent && !@known_links.include?([@parent, child])
|
||||
@graph.add_edges(@parent, child)
|
||||
@known_links << [@parent, child]
|
||||
end
|
||||
end
|
||||
def recurse node, current
|
||||
@parent = current
|
||||
node.accept(self)
|
||||
end
|
||||
end
|
||||
|
||||
module Graphable
|
||||
def graph opts
|
||||
g = GraphViz.new(:G, type: :digraph)
|
||||
visitor = GraphvizVisitor.new(g)
|
||||
|
||||
new.accept(visitor)
|
||||
|
||||
g.output opts
|
||||
end
|
||||
end
|
||||
|
||||
class Parser # reopen for introducing the .graph method
|
||||
extend Graphable
|
||||
end
|
||||
end
|
Reference in New Issue
Block a user