antlr3 1.2.3

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.
Files changed (85) hide show
  1. data/ANTLR-LICENSE.txt +26 -0
  2. data/History.txt +66 -0
  3. data/README.txt +139 -0
  4. data/bin/antlr4ruby +33 -0
  5. data/java/RubyTarget.java +524 -0
  6. data/java/antlr-full-3.2.1.jar +0 -0
  7. data/lib/antlr3.rb +176 -0
  8. data/lib/antlr3/constants.rb +88 -0
  9. data/lib/antlr3/debug.rb +701 -0
  10. data/lib/antlr3/debug/event-hub.rb +210 -0
  11. data/lib/antlr3/debug/record-event-listener.rb +25 -0
  12. data/lib/antlr3/debug/rule-tracer.rb +55 -0
  13. data/lib/antlr3/debug/socket.rb +360 -0
  14. data/lib/antlr3/debug/trace-event-listener.rb +92 -0
  15. data/lib/antlr3/dfa.rb +247 -0
  16. data/lib/antlr3/dot.rb +174 -0
  17. data/lib/antlr3/error.rb +657 -0
  18. data/lib/antlr3/main.rb +561 -0
  19. data/lib/antlr3/modes/ast-builder.rb +41 -0
  20. data/lib/antlr3/modes/filter.rb +56 -0
  21. data/lib/antlr3/profile.rb +322 -0
  22. data/lib/antlr3/recognizers.rb +1280 -0
  23. data/lib/antlr3/streams.rb +985 -0
  24. data/lib/antlr3/streams/interactive.rb +91 -0
  25. data/lib/antlr3/streams/rewrite.rb +412 -0
  26. data/lib/antlr3/test/call-stack.rb +57 -0
  27. data/lib/antlr3/test/config.rb +23 -0
  28. data/lib/antlr3/test/core-extensions.rb +269 -0
  29. data/lib/antlr3/test/diff.rb +165 -0
  30. data/lib/antlr3/test/functional.rb +207 -0
  31. data/lib/antlr3/test/grammar.rb +371 -0
  32. data/lib/antlr3/token.rb +592 -0
  33. data/lib/antlr3/tree.rb +1415 -0
  34. data/lib/antlr3/tree/debug.rb +163 -0
  35. data/lib/antlr3/tree/visitor.rb +84 -0
  36. data/lib/antlr3/tree/wizard.rb +481 -0
  37. data/lib/antlr3/util.rb +149 -0
  38. data/lib/antlr3/version.rb +27 -0
  39. data/samples/ANTLRv3Grammar.g +621 -0
  40. data/samples/Cpp.g +749 -0
  41. data/templates/AST.stg +335 -0
  42. data/templates/ASTDbg.stg +40 -0
  43. data/templates/ASTParser.stg +153 -0
  44. data/templates/ASTTreeParser.stg +272 -0
  45. data/templates/Dbg.stg +192 -0
  46. data/templates/Ruby.stg +1514 -0
  47. data/test/functional/ast-output/auto-ast.rb +797 -0
  48. data/test/functional/ast-output/construction.rb +555 -0
  49. data/test/functional/ast-output/hetero-nodes.rb +753 -0
  50. data/test/functional/ast-output/rewrites.rb +1327 -0
  51. data/test/functional/ast-output/tree-rewrite.rb +1662 -0
  52. data/test/functional/debugging/debug-mode.rb +689 -0
  53. data/test/functional/debugging/profile-mode.rb +165 -0
  54. data/test/functional/debugging/rule-tracing.rb +74 -0
  55. data/test/functional/delegation/import.rb +379 -0
  56. data/test/functional/lexer/basic.rb +559 -0
  57. data/test/functional/lexer/filter-mode.rb +245 -0
  58. data/test/functional/lexer/nuances.rb +47 -0
  59. data/test/functional/lexer/properties.rb +104 -0
  60. data/test/functional/lexer/syn-pred.rb +32 -0
  61. data/test/functional/lexer/xml.rb +206 -0
  62. data/test/functional/main/main-scripts.rb +245 -0
  63. data/test/functional/parser/actions.rb +224 -0
  64. data/test/functional/parser/backtracking.rb +244 -0
  65. data/test/functional/parser/basic.rb +282 -0
  66. data/test/functional/parser/calc.rb +98 -0
  67. data/test/functional/parser/ll-star.rb +143 -0
  68. data/test/functional/parser/nuances.rb +165 -0
  69. data/test/functional/parser/predicates.rb +103 -0
  70. data/test/functional/parser/properties.rb +242 -0
  71. data/test/functional/parser/rule-methods.rb +132 -0
  72. data/test/functional/parser/scopes.rb +274 -0
  73. data/test/functional/token-rewrite/basic.rb +318 -0
  74. data/test/functional/token-rewrite/via-parser.rb +100 -0
  75. data/test/functional/tree-parser/basic.rb +750 -0
  76. data/test/unit/sample-input/file-stream-1 +2 -0
  77. data/test/unit/sample-input/teststreams.input2 +2 -0
  78. data/test/unit/test-dfa.rb +52 -0
  79. data/test/unit/test-exceptions.rb +44 -0
  80. data/test/unit/test-recognizers.rb +55 -0
  81. data/test/unit/test-scheme.rb +62 -0
  82. data/test/unit/test-streams.rb +459 -0
  83. data/test/unit/test-tree-wizard.rb +535 -0
  84. data/test/unit/test-trees.rb +854 -0
  85. metadata +205 -0
@@ -0,0 +1,92 @@
1
+ #!/usr/bin/ruby
2
+ # encoding: utf-8
3
+
4
+ module ANTLR3
5
+ module Debug
6
+ =begin rdoc ANTLR3::Debug::EventListener
7
+
8
+ A listener that simply records text representations of the events.
9
+ Useful for debugging the debugging facility ;)
10
+ Subclasses can override the record() method (which defaults to printing to
11
+ stdout) to record the events in a different way.
12
+
13
+ =end
14
+ class TraceEventListener
15
+ include EventListener
16
+
17
+ def initialize(adaptor = nil, device = $stderr)
18
+ super()
19
+ @device = device
20
+ @adaptor = adaptor ||= ANTLR3::AST::CommonTreeAdaptor.new
21
+ end
22
+
23
+ def record(event_message, *interpolation_arguments)
24
+ event_message = event_message.to_s << "\n"
25
+ @device.printf(event_message, *interpolation_arguments)
26
+ end
27
+
28
+ def enter_alternative( alt_number )
29
+ record "(%s): number=%s", __method__, alt_number
30
+ end
31
+
32
+ def enter_rule( grammar_file_name, rule_name )
33
+ record "(%s): rule=%s", __method__, rule_name
34
+ end
35
+
36
+ def exit_rule( grammar_file_name, rule_name )
37
+ record "(%s): rule=%s", __method__, rule_name
38
+ end
39
+
40
+ def enter_subrule( decision_number )
41
+ record "(%s): decision=%s", __method__, decision_number
42
+ end
43
+
44
+ def exit_subrule( decision_number )
45
+ record "(%s): decision=%s", __method__, decision_number
46
+ end
47
+
48
+ def location( line, position )
49
+ record '(%s): line=%s position=%s', __method__, line, position
50
+ end
51
+
52
+ def consume_node( tree )
53
+ record '(%s) unique_id=%s text=%p type=%s[%s]', __method__, @adaptor.unique_id(tree),
54
+ @adaptor.text_of(tree), @adaptor.type_name( tree ), @adaptor.type_of(tree)
55
+ end
56
+
57
+ def look(i, tree)
58
+ record '(%s): k=%s unique_id=%s text=%p type=%s[%s]', __method__, i, @adaptor.unique_id( tree ),
59
+ @adaptor.text_of( tree ), @adaptor.type_name( tree ), @adaptor.type_of( tree )
60
+ end
61
+
62
+ def flat_node( tree )
63
+ record '(%s): unique_id=%s', __method__, @adaptor.unique_id( tree )
64
+ end
65
+
66
+ def create_node(tree, token = nil)
67
+ unless token
68
+ record '(%s): unique_id=%s text=%p type=%s[%s]', __method__, @adaptor.unique_id( tree ),
69
+ @adaptor.text_of( tree ), @adaptor.type_name( tree ), @adaptor.type_of( tree )
70
+ else
71
+ record '(%s): unique_id=%s type=%s[%s]', __method__, @adaptor.unique_id( tree ),
72
+ @adaptor.type_of( tree ), @adaptor.type_name( tree ), @adaptor.type_of( tree )
73
+ end
74
+ end
75
+
76
+ def become_root( new_root, old_root )
77
+ record '(%s): old_root_id=%s new_root_id=%s', __method__, @adaptor.unique_id( new_root ),
78
+ @adaptor.unique_id( old_root )
79
+ end
80
+
81
+ def add_child( root, child )
82
+ record '(%s): root_id=%s child_id=%s', __method__, @adaptor.unique_id( root ),
83
+ @adaptor.unique_id( child )
84
+ end
85
+
86
+ def set_token_boundaries( tree, token_start_index, token_stop_index )
87
+ record '(%s): unique_id=%s index_range=%s..%s', __method__, @adaptor.unique_id( tree ),
88
+ token_start_index, token_stop_index
89
+ end
90
+ end # class TraceEventListener
91
+ end # module Debug
92
+ end # module ANTLR3
@@ -0,0 +1,247 @@
1
+ #!/usr/bin/ruby
2
+ # encoding: utf-8
3
+
4
+ =begin LICENSE
5
+
6
+ [The "BSD licence"]
7
+ Copyright (c) 2009 Kyle Yetter
8
+ All rights reserved.
9
+
10
+ Redistribution and use in source and binary forms, with or without
11
+ modification, are permitted provided that the following conditions
12
+ are met:
13
+
14
+ 1. Redistributions of source code must retain the above copyright
15
+ notice, this list of conditions and the following disclaimer.
16
+ 2. Redistributions in binary form must reproduce the above copyright
17
+ notice, this list of conditions and the following disclaimer in the
18
+ documentation and/or other materials provided with the distribution.
19
+ 3. The name of the author may not be used to endorse or promote products
20
+ derived from this software without specific prior written permission.
21
+
22
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
23
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
26
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
27
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
31
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32
+
33
+ =end
34
+
35
+ module ANTLR3
36
+
37
+ =begin rdoc ANTLR3::DFA
38
+
39
+ DFA is a class that implements a finite state machine that chooses between
40
+ alternatives in a rule based upon lookahead symbols from an input stream.
41
+
42
+ Deterministic Finite Automata (DFA) are finite state machines that are capable
43
+ of recognizing <i>regular languages</i>. For more background on the subject,
44
+ check out http://en.wikipedia.org/wiki/Deterministic_finite-state_machine or
45
+ check out general ANTLR documentation at http://www.antlr.org
46
+
47
+ ANTLR implements most of its decision logic directly using code branching
48
+ structures in methods. However, for certain types of decisions, ANTLR will
49
+ generate a special DFA class definition to implement a decision.
50
+
51
+ Conceptually, these state machines are defined by a number of states, each state
52
+ represented by an integer indexed upward from zero. State number +0+ is the
53
+ <i>start state</i> of the machine; every prediction will begin in state +0+. At
54
+ each step, the machine examines the next symbol on the input stream, checks the
55
+ value against the transition parameters associated with the current state, and
56
+ either moves to a new state number to repeat the process or decides that the
57
+ machine cannot transition any further. If the machine cannot transition any
58
+ further and the current state is defined as an <i>accept state</i>, an
59
+ alternative has been chosen successfully and the prediction procedure ends. If
60
+ the current state is not an <i>accept state</i>, the prediction has failed and
61
+ there is <i>no viable alternative</i>.
62
+
63
+ In generated code, ANTLR defines DFA states using seven parameters, each defined
64
+ as a member of seven seperate array constants -- +MIN+, +MAX+, +EOT+, +EOF+,
65
+ +SPECIAL+, +ACCEPT+, and +TRANSITION+. The parameters that characterize state
66
+ +s+ are defined by the value of these lists at index +s+.
67
+
68
+ MIN[s]::
69
+ The smallest value of the next input symbol that has
70
+ a transition for state +s+
71
+ MAX[s]::
72
+ The largest value of the next input symbol that has
73
+ a transition for state +s+
74
+ TRANSITION[s]::
75
+ A list that defines the next state number based upon
76
+ the current input symbol.
77
+ EOT[s]::
78
+ If positive, it specifies a state transition in
79
+ situations where a non-matching input symbol does
80
+ not indicate failure.
81
+ SPECIAL[s]::
82
+ If positive, it indicates that the prediction
83
+ algorithm must defer to a special code block
84
+ to determine the next state. The value is used
85
+ by the special state code to determine the next
86
+ state.
87
+ ACCEPT[s]::
88
+ If positive and there are no possible state
89
+ transitions, this is the alternative number
90
+ that has been predicted
91
+ EOF[s]::
92
+ If positive and the input stream has been exhausted,
93
+ this is the alternative number that has been predicted.
94
+
95
+ For more information on the prediction algorithm, check out the #predict method
96
+ below.
97
+
98
+ =end
99
+
100
+ class DFA
101
+ include Constants
102
+ include Error
103
+
104
+ attr_reader :recognizer, :decision_number, :eot, :eof, :min, :max,
105
+ :accept, :special, :transition, :special_block
106
+
107
+ class << self
108
+ attr_reader :decision
109
+
110
+ def unpack(*data)
111
+ data.empty? and return [].freeze
112
+
113
+ n = data.length / 2
114
+ size = 0
115
+ n.times { |i| size += data[2*i] }
116
+ if size > 1024
117
+ values = Hash.new(0)
118
+ data.each_slice(2) do |count, value|
119
+ values[value] += count
120
+ end
121
+ default = values.keys.max_by { |v| values[v] }
122
+
123
+ unpacked = Hash.new(default)
124
+ position = 0
125
+ data.each_slice(2) do |count, value|
126
+ unless value == default
127
+ count.times { |i| unpacked[position + i] = value }
128
+ end
129
+ position += count
130
+ end
131
+ else
132
+ unpacked = []
133
+ data.each_slice(2) do |count, value|
134
+ unpacked.concat Array.new(count, value)
135
+ end
136
+ end
137
+
138
+ return unpacked.freeze
139
+ end
140
+ end
141
+
142
+ def initialize(recognizer, decision_number = nil, eot = nil, eof = nil,
143
+ min = nil, max = nil, accept = nil, special = nil,
144
+ transition = nil, &special_block)
145
+ @recognizer = recognizer
146
+ @decision_number = decision_number || self.class.decision
147
+ @eot = eot || self.class::EOT
148
+ @eof = eof || self.class::EOF
149
+ @min = min || self.class::MIN
150
+ @max = max || self.class::MAX
151
+ @accept = accept || self.class::ACCEPT
152
+ @special = special || self.class::SPECIAL
153
+ @transition = transition || self.class::TRANSITION
154
+ @special_block = special_block
155
+ rescue NameError => e
156
+ raise unless e.message =~ /uninitialized constant/
157
+ constant = e.name
158
+ message = Util.tidy( <<-END )
159
+ | No #{constant} information provided.
160
+ | DFA cannot be instantiated without providing state array information.
161
+ | When DFAs are generated by ANTLR, this information should already be
162
+ | provided in the DFA subclass constants.
163
+ END
164
+ end
165
+
166
+ def predict(input)
167
+ mark = input.mark
168
+ state = 0
169
+
170
+ 50000.times do
171
+ special_state = @special[state]
172
+ if special_state >= 0
173
+ state = @special_block.call(special_state)
174
+ if state == -1
175
+ no_viable_alternative(state, input)
176
+ return 0
177
+ end
178
+ input.consume
179
+ next
180
+ end
181
+ @accept[state] >= 1 and return @accept[state]
182
+
183
+ # look for a normal char transition
184
+
185
+ c = input.peek
186
+ # the @min and @max arrays contain the bounds of the character (or token type)
187
+ # ranges for the transition decisions
188
+ if c.between?(@min[state], @max[state])
189
+ # c - @min[state] is the position of the character within the range
190
+ # so for a range like ?a..?z, a match of ?a would be 0,
191
+ # ?c would be 2, and ?z would be 25
192
+ next_state = @transition[state][c - @min[state]]
193
+ if next_state < 0
194
+ if @eot[state] >= 0
195
+ state = @eot[state]
196
+ input.consume
197
+ next
198
+ end
199
+ no_viable_alternative(state, input)
200
+ return 0
201
+ end
202
+
203
+ state = next_state
204
+ input.consume()
205
+ next
206
+ end
207
+ if @eot[state] >= 0
208
+ state = @eot[state]
209
+ input.consume()
210
+ next
211
+ end
212
+ (c == EOF && @eof[state] >= 0) and return @accept[@eof[state]]
213
+ no_viable_alternative(state, input)
214
+ return 0
215
+ end
216
+
217
+ ANTLR3.bug!( Util.tidy(<<-END) )
218
+ | DFA BANG!
219
+ | The prediction loop has exceeded a maximum limit of 50000 iterations
220
+ | ----
221
+ | decision: #@decision_number
222
+ | description: #{description}
223
+ END
224
+ ensure
225
+ input.rewind(mark)
226
+ end
227
+
228
+ def no_viable_alternative(state, input)
229
+ raise(BacktrackingFailed) if @recognizer.state.backtracking > 0
230
+ except = NoViableAlternative.new(description, @decision_number, state, input)
231
+ error(except)
232
+ raise(except)
233
+ end
234
+
235
+ def error(except)
236
+ # overridable debugging hook
237
+ end
238
+
239
+ def special_state_transition(state, input)
240
+ return -1
241
+ end
242
+
243
+ def description
244
+ return "n/a"
245
+ end
246
+ end
247
+ end
@@ -0,0 +1,174 @@
1
+ #!/usr/bin/ruby
2
+ # encoding: utf-8
3
+
4
+ =begin LICENSE
5
+
6
+ [The "BSD licence"]
7
+ Copyright (c) 2009 Kyle Yetter
8
+ All rights reserved.
9
+
10
+ Redistribution and use in source and binary forms, with or without
11
+ modification, are permitted provided that the following conditions
12
+ are met:
13
+
14
+ 1. Redistributions of source code must retain the above copyright
15
+ notice, this list of conditions and the following disclaimer.
16
+ 2. Redistributions in binary form must reproduce the above copyright
17
+ notice, this list of conditions and the following disclaimer in the
18
+ documentation and/or other materials provided with the distribution.
19
+ 3. The name of the author may not be used to endorse or promote products
20
+ derived from this software without specific prior written permission.
21
+
22
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
23
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
26
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
27
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
31
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32
+
33
+ =end
34
+
35
+ require 'antlr3'
36
+ require 'erb'
37
+
38
+ module ANTLR3
39
+
40
+ =begin rdoc ANTLR3::DOT
41
+
42
+ An extra utility for generating graphviz DOT file representations of ANTLR
43
+ Abstract Syntax Tree nodes.
44
+
45
+ This module has been directly ported to Ruby from the ANTLR Python runtime
46
+ library.
47
+
48
+ =end
49
+
50
+ module DOT
51
+ class Context
52
+ def []=(var, value)
53
+ instance_variable_set(:"@#{var}", value)
54
+ end
55
+ def [](var)
56
+ instance_variable_get(:"@#{var}")
57
+ end
58
+
59
+ def initialize(template, vars = {})
60
+ @__template__ = template
61
+ vars.each do |var, value|
62
+ self[var] = value
63
+ end
64
+ end
65
+
66
+ def to_s
67
+ @__template__.result(binding)
68
+ end
69
+ end
70
+ class TreeGenerator
71
+ TREE_TEMPLATE = ERB.new( Util.tidy(<<-END) )
72
+ | digraph {
73
+ | ordering=out;
74
+ | ranksep=.4;
75
+ | node [shape=plaintext, fixedsize=true, fontsize=11, fontname="Courier",
76
+ | width=.25, height=.25];
77
+ | edge [arrowsize=.5];
78
+ | <%= @nodes.join("\n ") %>
79
+ | <%= @edges.join("\n ") %>
80
+ | }
81
+ END
82
+
83
+ NODE_TEMPLATE = ERB.new( Util.tidy(<<-END) )
84
+ | <%= @name %> [label="<%= @text %>"];
85
+ END
86
+
87
+ EDGE_TEMPLATE = ERB.new( Util.tidy(<<-END) )
88
+ | <%= @parent %> -> <%= @child %>; // "<%= @parent_text %>" -> "<%= @child_text %>"
89
+ END
90
+
91
+ def self.generate(tree, adaptor = nil, tree_template = TREE_TEMPLATE,
92
+ edge_template = EDGE_TEMPLATE)
93
+ new.to_dot(tree, adaptor, tree_template, edge_template)
94
+ end
95
+
96
+ def initialize
97
+ @node_number = 0
98
+ @node_to_number_map = Hash.new do |map, node|
99
+ map[node] = @node_number
100
+ @node_number += 1
101
+ @node_number - 1
102
+ end
103
+ end
104
+
105
+ def to_dot(tree, adaptor = nil, tree_template = TREE_TEMPLATE,
106
+ edge_template = EDGE_TEMPLATE)
107
+ adaptor ||= AST::CommonTreeAdaptor.new
108
+ @node_number = 0
109
+ tree_template = Context.new(tree_template, :nodes => [], :edges => [])
110
+ define_nodes( tree, adaptor, tree_template )
111
+
112
+ @node_number = 0
113
+ define_edges( tree, adaptor, tree_template, edge_template )
114
+ return tree_template.to_s
115
+ end
116
+
117
+ def define_nodes( tree, adaptor, tree_template, known_nodes = nil)
118
+ known_nodes ||= Set.new
119
+ tree.nil? and return
120
+ n = adaptor.child_count( tree )
121
+ n == 0 and return
122
+ number = node_number( tree )
123
+ unless known_nodes.include?( number )
124
+ parent_node_template = node_template_for(adaptor, child)
125
+ tree_template[:nodes] << parent_node_template
126
+ known_nodes.add( number )
127
+ end
128
+
129
+ n.times do |index|
130
+ child = adaptor.child_of( tree, index )
131
+ number = @node_to_number_map[ child ]
132
+ unless known_nodes.include?(number)
133
+ node_template = node_template_for( adaptor, child )
134
+ tree_template[:nodes] << node_template
135
+ known_nodes.add( number )
136
+ end
137
+
138
+ define_nodes(child, adaptor, tree_template, edge_template)
139
+ end
140
+ end
141
+
142
+ def define_edges( tree, adaptor, tree_template, edge_template )
143
+ tree.nil? or return
144
+
145
+ n = adaptor.child_count( tree )
146
+ n == 0 and return
147
+
148
+ parent_name = 'n%i' % @node_to_number_map[ tree ]
149
+ parent_text = adaptor.text_of( tree )
150
+ n.times do |index|
151
+ child = adaptor.child_of( tree, index )
152
+ child_text = adaptor.text_of( child )
153
+ child_name = 'n%i' % @node_to_number_map[ tree ]
154
+ edge_template = Context.new(edge_template,
155
+ :parent => parent_name, :child => child_name,
156
+ :parent_text => parent_text, :child_text => child_text
157
+ )
158
+ tree_template[:edges] << edge_template
159
+ define_edges( child, adaptor, tree_template, edge_template )
160
+ end
161
+ end
162
+
163
+ def node_template_for(adaptor, tree)
164
+ text = adaptor.text_of( tree )
165
+ node_template = Context.new(NODE_TEMPLATE)
166
+ unique_name = 'n%i' % @node_to_number_map[ tree ]
167
+ node_template[:name] = unique_name
168
+ text and text = text.gsub(/"/, '\\"')
169
+ node_template[:text] = text
170
+ return node_template
171
+ end
172
+ end
173
+ end
174
+ end