xref: /aosp_15_r20/external/antlr/runtime/Ruby/lib/antlr3/dot.rb (revision 16467b971bd3e2009fad32dd79016f2c7e421deb)
1*16467b97STreehugger Robot#!/usr/bin/ruby
2*16467b97STreehugger Robot# encoding: utf-8
3*16467b97STreehugger Robot
4*16467b97STreehugger Robot=begin LICENSE
5*16467b97STreehugger Robot
6*16467b97STreehugger Robot[The "BSD licence"]
7*16467b97STreehugger RobotCopyright (c) 2009-2010 Kyle Yetter
8*16467b97STreehugger RobotAll rights reserved.
9*16467b97STreehugger Robot
10*16467b97STreehugger RobotRedistribution and use in source and binary forms, with or without
11*16467b97STreehugger Robotmodification, are permitted provided that the following conditions
12*16467b97STreehugger Robotare met:
13*16467b97STreehugger Robot
14*16467b97STreehugger Robot 1. Redistributions of source code must retain the above copyright
15*16467b97STreehugger Robot    notice, this list of conditions and the following disclaimer.
16*16467b97STreehugger Robot 2. Redistributions in binary form must reproduce the above copyright
17*16467b97STreehugger Robot    notice, this list of conditions and the following disclaimer in the
18*16467b97STreehugger Robot    documentation and/or other materials provided with the distribution.
19*16467b97STreehugger Robot 3. The name of the author may not be used to endorse or promote products
20*16467b97STreehugger Robot    derived from this software without specific prior written permission.
21*16467b97STreehugger Robot
22*16467b97STreehugger RobotTHIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
23*16467b97STreehugger RobotIMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24*16467b97STreehugger RobotOF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25*16467b97STreehugger RobotIN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
26*16467b97STreehugger RobotINCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
27*16467b97STreehugger RobotNOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28*16467b97STreehugger RobotDATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29*16467b97STreehugger RobotTHEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30*16467b97STreehugger Robot(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
31*16467b97STreehugger RobotTHIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32*16467b97STreehugger Robot
33*16467b97STreehugger Robot=end
34*16467b97STreehugger Robot
35*16467b97STreehugger Robotrequire 'antlr3'
36*16467b97STreehugger Robotrequire 'erb'
37*16467b97STreehugger Robot
38*16467b97STreehugger Robotmodule ANTLR3
39*16467b97STreehugger Robot
40*16467b97STreehugger Robot=begin rdoc ANTLR3::DOT
41*16467b97STreehugger Robot
42*16467b97STreehugger RobotAn extra utility for generating graphviz DOT file representations of ANTLR
43*16467b97STreehugger RobotAbstract Syntax Tree nodes.
44*16467b97STreehugger Robot
45*16467b97STreehugger RobotThis module has been directly ported to Ruby from the ANTLR Python runtime
46*16467b97STreehugger Robotlibrary.
47*16467b97STreehugger Robot
48*16467b97STreehugger Robot=end
49*16467b97STreehugger Robot
50*16467b97STreehugger Robotmodule DOT
51*16467b97STreehugger Robot  class Context
52*16467b97STreehugger Robot    def []=( var, value )
53*16467b97STreehugger Robot      instance_variable_set( :"@#{ var }", value )
54*16467b97STreehugger Robot    end
55*16467b97STreehugger Robot    def []( var )
56*16467b97STreehugger Robot      instance_variable_get( :"@#{ var }" )
57*16467b97STreehugger Robot    end
58*16467b97STreehugger Robot
59*16467b97STreehugger Robot    def initialize( template, vars = {} )
60*16467b97STreehugger Robot      @__template__ = template
61*16467b97STreehugger Robot      vars.each do |var, value|
62*16467b97STreehugger Robot        self[ var ] = value
63*16467b97STreehugger Robot      end
64*16467b97STreehugger Robot    end
65*16467b97STreehugger Robot
66*16467b97STreehugger Robot    def to_s
67*16467b97STreehugger Robot      @__template__.result( binding )
68*16467b97STreehugger Robot    end
69*16467b97STreehugger Robot  end
70*16467b97STreehugger Robot  class TreeGenerator
71*16467b97STreehugger Robot    TREE_TEMPLATE = ERB.new( Util.tidy( <<-END ) )
72*16467b97STreehugger Robot    | digraph {
73*16467b97STreehugger Robot    |   ordering=out;
74*16467b97STreehugger Robot    |   ranksep=.4;
75*16467b97STreehugger Robot    |   node [shape=plaintext, fixedsize=true, fontsize=11, fontname="Courier",
76*16467b97STreehugger Robot    |         width=.25, height=.25];
77*16467b97STreehugger Robot    |   edge [arrowsize=.5];
78*16467b97STreehugger Robot    |   <%= @nodes.join("\n  ") %>
79*16467b97STreehugger Robot    |   <%= @edges.join("\n  ") %>
80*16467b97STreehugger Robot    | }
81*16467b97STreehugger Robot    END
82*16467b97STreehugger Robot
83*16467b97STreehugger Robot    NODE_TEMPLATE = ERB.new( Util.tidy( <<-END ) )
84*16467b97STreehugger Robot    | <%= @name %> [label="<%= @text %>"];
85*16467b97STreehugger Robot    END
86*16467b97STreehugger Robot
87*16467b97STreehugger Robot    EDGE_TEMPLATE = ERB.new( Util.tidy( <<-END ) )
88*16467b97STreehugger Robot    | <%= @parent %> -> <%= @child %>; // "<%= @parent_text %>" -> "<%= @child_text %>"
89*16467b97STreehugger Robot    END
90*16467b97STreehugger Robot
91*16467b97STreehugger Robot    def self.generate( tree, adaptor = nil, tree_template = TREE_TEMPLATE,
92*16467b97STreehugger Robot                      edge_template = EDGE_TEMPLATE )
93*16467b97STreehugger Robot      new.to_dot( tree, adaptor, tree_template, edge_template )
94*16467b97STreehugger Robot    end
95*16467b97STreehugger Robot
96*16467b97STreehugger Robot    def initialize
97*16467b97STreehugger Robot      @node_number = 0
98*16467b97STreehugger Robot      @node_to_number_map = Hash.new do |map, node|
99*16467b97STreehugger Robot        map[ node ] = @node_number
100*16467b97STreehugger Robot        @node_number += 1
101*16467b97STreehugger Robot        @node_number - 1
102*16467b97STreehugger Robot      end
103*16467b97STreehugger Robot    end
104*16467b97STreehugger Robot
105*16467b97STreehugger Robot    def to_dot( tree, adaptor = nil, tree_template = TREE_TEMPLATE,
106*16467b97STreehugger Robot               edge_template = EDGE_TEMPLATE )
107*16467b97STreehugger Robot      adaptor ||= AST::CommonTreeAdaptor.new
108*16467b97STreehugger Robot      @node_number = 0
109*16467b97STreehugger Robot      tree_template = Context.new( tree_template, :nodes => [], :edges => [] )
110*16467b97STreehugger Robot      define_nodes( tree, adaptor, tree_template )
111*16467b97STreehugger Robot
112*16467b97STreehugger Robot      @node_number = 0
113*16467b97STreehugger Robot      define_edges( tree, adaptor, tree_template, edge_template )
114*16467b97STreehugger Robot      return tree_template.to_s
115*16467b97STreehugger Robot    end
116*16467b97STreehugger Robot
117*16467b97STreehugger Robot    def define_nodes( tree, adaptor, tree_template, known_nodes = nil )
118*16467b97STreehugger Robot      known_nodes ||= Set.new
119*16467b97STreehugger Robot      tree.nil? and return
120*16467b97STreehugger Robot      n = adaptor.child_count( tree )
121*16467b97STreehugger Robot      n == 0 and return
122*16467b97STreehugger Robot      number = node_number( tree )
123*16467b97STreehugger Robot      unless known_nodes.include?( number )
124*16467b97STreehugger Robot        parent_node_template = node_template_for( adaptor, child )
125*16467b97STreehugger Robot        tree_template[ :nodes ] << parent_node_template
126*16467b97STreehugger Robot        known_nodes.add( number )
127*16467b97STreehugger Robot      end
128*16467b97STreehugger Robot
129*16467b97STreehugger Robot      n.times do |index|
130*16467b97STreehugger Robot        child = adaptor.child_of( tree, index )
131*16467b97STreehugger Robot        number = @node_to_number_map[ child ]
132*16467b97STreehugger Robot        unless known_nodes.include?( number )
133*16467b97STreehugger Robot          node_template = node_template_for( adaptor, child )
134*16467b97STreehugger Robot          tree_template[ :nodes ] << node_template
135*16467b97STreehugger Robot          known_nodes.add( number )
136*16467b97STreehugger Robot        end
137*16467b97STreehugger Robot
138*16467b97STreehugger Robot        define_nodes( child, adaptor, tree_template, edge_template )
139*16467b97STreehugger Robot      end
140*16467b97STreehugger Robot    end
141*16467b97STreehugger Robot
142*16467b97STreehugger Robot    def define_edges( tree, adaptor, tree_template, edge_template )
143*16467b97STreehugger Robot      tree.nil? or return
144*16467b97STreehugger Robot
145*16467b97STreehugger Robot      n = adaptor.child_count( tree )
146*16467b97STreehugger Robot      n == 0 and return
147*16467b97STreehugger Robot
148*16467b97STreehugger Robot      parent_name = 'n%i' % @node_to_number_map[ tree ]
149*16467b97STreehugger Robot      parent_text = adaptor.text_of( tree )
150*16467b97STreehugger Robot      n.times do |index|
151*16467b97STreehugger Robot        child = adaptor.child_of( tree, index )
152*16467b97STreehugger Robot        child_text = adaptor.text_of( child )
153*16467b97STreehugger Robot        child_name = 'n%i' % @node_to_number_map[ tree ]
154*16467b97STreehugger Robot        edge_template = Context.new( edge_template,
155*16467b97STreehugger Robot          :parent => parent_name, :child => child_name,
156*16467b97STreehugger Robot          :parent_text => parent_text, :child_text => child_text
157*16467b97STreehugger Robot        )
158*16467b97STreehugger Robot        tree_template[ :edges ] << edge_template
159*16467b97STreehugger Robot        define_edges( child, adaptor, tree_template, edge_template )
160*16467b97STreehugger Robot      end
161*16467b97STreehugger Robot    end
162*16467b97STreehugger Robot
163*16467b97STreehugger Robot    def node_template_for( adaptor, tree )
164*16467b97STreehugger Robot      text = adaptor.text_of( tree )
165*16467b97STreehugger Robot      node_template = Context.new( NODE_TEMPLATE )
166*16467b97STreehugger Robot      unique_name = 'n%i' % @node_to_number_map[ tree ]
167*16467b97STreehugger Robot      node_template[ :name ] = unique_name
168*16467b97STreehugger Robot      text and text = text.gsub( /"/, '\\"' )
169*16467b97STreehugger Robot      node_template[ :text ] = text
170*16467b97STreehugger Robot      return node_template
171*16467b97STreehugger Robot    end
172*16467b97STreehugger Robot  end
173*16467b97STreehugger Robotend
174*16467b97STreehugger Robotend
175