babel_bridge 0.2.0 → 0.3.0

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.
@@ -1,278 +1,9 @@
1
- =begin
2
- Copyright 2011 Shane Brinkman-Davis
3
- See README for licence information.
4
- http://babel-bridge.rubyforge.org/
5
- =end
6
-
7
- module BabelBridge
8
-
9
- # this is just so we can distinguish between normal arrays and arrays of matches
10
- # - since a match can be an Array in the case of Poly-matches
11
- class MultiMatchesArray < Array
12
- end
13
-
14
- # base class for all parse-tree nodes
15
- class Node
16
- attr_accessor :src,:offset,:match_length,:parent,:parser
17
-
18
- def to_s
19
- text
20
- end
21
-
22
- def node_init(parent_or_parser)
23
- self.match_length=0
24
- case parent_or_parser
25
- when Parser then
26
- self.parser=parent_or_parser
27
- self.offset=0
28
- self.src=parser.src
29
- when Node then
30
- self.parent=parent_or_parser
31
- self.parser=parent.parser
32
- self.offset=parent.next
33
- self.src=parent.src
34
- raise "parent node does not have parser set" unless parser
35
- else
36
- raise "parent_or_parser(#{parent_or_parser.class}) must be a Node or a Parser"
37
- end
38
- end
39
-
40
- def initialize(parent)
41
- node_init(parent)
42
- end
43
-
44
- #********************
45
- # info methods
46
- #********************
47
- def next; offset+match_length end # index of first character after match
48
- def text; src[offset,match_length] end # the substring in src matched
49
-
50
- # length returns the number of sub-nodes
51
- def length
52
- 0
53
- end
54
-
55
- def parent_list
56
- return parent ? parent.parent_list+[parent] : []
57
- end
58
-
59
- def node_path
60
- "#{parent && (parent.node_path+' > ')}#{self.class}(#{offset})"
61
- end
62
-
63
- #*****************************
64
- # Array interface implementation
65
- #*****************************
66
- def matches # override this with function that returns array of matches to be used for Array indexing and iteration
67
- []
68
- end
69
-
70
- include Enumerable
71
- def length
72
- matches.length
73
- end
74
-
75
- def <<(node)
76
- matches<<node
77
- end
78
-
79
- def add_delimiter(node)
80
- delimiter_matches<<node
81
- end
82
-
83
- def [](i)
84
- matches[i]
85
- end
86
-
87
- def each(&block)
88
- matches.each(&block)
89
- end
90
- end
91
-
92
- class RootNode < Node
93
- end
94
-
95
- # non-terminal node
96
- # subclassed automatically by parser.rule for each unique non-terminal
97
- class NonTerminalNode < Node
98
- attr_accessor :matches,:match_names
99
-
100
- def match_names
101
- @match_names ||= []
102
- end
103
- def matches
104
- @matches ||= []
105
- end
106
-
107
- # length returns the number of sub-nodes
108
- def length
109
- matches.length
110
- end
111
-
112
- def matches_by_name
113
- @matches_by_name||= begin
114
- raise "matches.length #{matches.length} != match_names.length #{match_names.length}" unless matches.length==match_names.length
115
- mbn={}
116
- mn=match_names
117
- matches.each_with_index do |match,i|
118
- name=mn[i]
119
- next unless name
120
- if current=mbn[name] # name already used
121
- # convert to MultiMatchesArray if not already
122
- mbn[name]=MultiMatchesArray.new([current]) if !current.kind_of? MultiMatchesArray
123
- # add to array
124
- mbn[name]<<match
125
- else
126
- mbn[name]=match
127
- end
128
- end
129
- mbn
130
- end
131
- end
132
-
133
- def inspect(options={})
134
- return "#{self.class}" if matches.length==0
135
- matches_inspected=matches.collect{|a|a.inspect(options)}.compact
136
- if matches_inspected.length==0 then nil
137
- elsif matches_inspected.length==1
138
- m=matches_inspected[0]
139
- ret="#{self.class} > "+matches_inspected[0]
140
- if options[:simple]
141
- ret=if m["\n"] then m
142
- else
143
- # just show the first and last nodes in the chain
144
- ret.gsub(/( > [A-Z][a-zA-Z0-9:]+ > (\.\.\. > )?)/," > ... > ")
145
- end
146
- end
147
- ret
148
- else
149
- (["#{self.class}"]+matches_inspected).join("\n").gsub("\n","\n ")
150
- end
151
- end
152
-
153
- #********************
154
- # alter methods
155
- #********************
156
- def reset_matches_by_name
157
- @matches_by_name=nil
158
- end
159
-
160
- # defines where to forward missing methods to; override for custom behavior
161
- def forward_to
162
- matches[0]
163
- end
164
-
165
- def method_missing(method_name, *args) #method_name is a symbol
166
- unless matches_by_name.has_key? method_name
167
- if f=forward_to
168
- return f.send(method_name,*args)
169
- end
170
- raise "#{self.class}: missing method #{method_name.inspect} / doesn't match named pattern element: #{matches_by_name.keys.inspect}"
171
- end
172
- case ret=matches_by_name[method_name]
173
- when EmptyNode then nil
174
- else ret
175
- end
176
- end
177
-
178
- # adds a match with name (optional)
179
- # returns self so you can chain add_match or concat methods
180
- def add_match(match,name=nil)
181
- reset_matches_by_name
182
- matches<<match
183
- match_names<<name
184
-
185
- self.match_length=match.next - offset
186
- self
187
- end
188
-
189
- # concatinate all matches from another node
190
- # returns self so you can chain add_match or concat methods
191
- def concat(node)
192
- names=node.match_names
193
- node.matches.each_with_index { |match,i| add_match(match,names[i])}
194
- self
195
- end
196
- end
197
-
198
- # generated by a :poly PatternElement
199
- # Not subclassed
200
- class ManyNode < Node
201
- attr_accessor :matches,:delimiter_matches
202
- def initialize(parent)
203
- node_init(parent)
204
- self.matches=[]
205
- self.delimiter_matches=[]
206
- end
207
-
208
- def match_length; self.next-offset end
209
-
210
- def next
211
- if m=matches[-1]
212
- m_next=m.next
213
- if d=delimiter_matches[-1]
214
- d_next=d.next
215
- m_next > d_next ? m_next : d_next
216
- else
217
- m_next
218
- end
219
- else
220
- parent.next
221
- end
222
- end
223
-
224
- def inspect_helper(list,options)
225
- simple=options[:simple]
226
- ret=list.collect {|a|a.inspect(options)}.compact
227
- ret= if ret.length==0 then simple ? nil : "[]"
228
- elsif ret.length==1 && !ret[0]["\n"] then (simple ? ret[0] : "[#{ret[0]}]")
229
- else (simple ? ret : ["[",ret,"]"]).flatten.join("\n") #.gsub("\n","\n ")
230
- end
231
- ret
232
- end
233
-
234
- def inspect(options={})
235
- if options[:simple]
236
- c=[]
237
- matches.each_with_index {|n,i| c<<n;c<<delimiter_matches[i]}
238
- c=c.compact
239
- inspect_helper(c,options)
240
- else
241
- ret=inspect_helper(matches,options)
242
- ret+=" delimiters="+inspect_helper(delimiter_matches,options) if delimiter_matches.length>0
243
- ret
244
- end
245
- end
246
-
247
- def method_missing(method_name, *args) #method_name is a symbol
248
- self.map {|match| match.send(method_name,*args)}
249
- end
250
-
251
- end
252
-
253
- # used for String and Regexp PatternElements
254
- # not subclassed
255
- class TerminalNode < Node
256
- attr_accessor :pattern
257
- def initialize(parent,match_length,pattern)
258
- node_init(parent)
259
- self.match_length=match_length
260
- self.pattern=pattern
261
- end
262
-
263
- def inspect(options={})
264
- "#{text.inspect}" unless options[:simple] && text[/^\s*$/] # if simple && node only matched white-space, return nil
265
- end
266
-
267
- def matches; [self]; end
268
- end
269
-
270
- # used when a PatternElement matchs the empty string
271
- # Example: when the PatternElement is optional and doesn't match
272
- # not subclassed
273
- class EmptyNode < Node
274
- def inspect(options={})
275
- "EmptyNode" unless options[:simple]
276
- end
277
- end
278
- end
1
+ %w{
2
+ node
3
+ empty_node
4
+ terminal_node
5
+ non_terminal_node
6
+ many_node
7
+ }.each do |file|
8
+ require File.join(File.dirname(__FILE__),"nodes",file)
9
+ end
@@ -0,0 +1,17 @@
1
+ =begin
2
+ Copyright 2011 Shane Brinkman-Davis
3
+ See README for licence information.
4
+ http://babel-bridge.rubyforge.org/
5
+ =end
6
+
7
+ module BabelBridge
8
+
9
+ # used when a PatternElement matchs the empty string
10
+ # Example: when the PatternElement is optional and doesn't match
11
+ # not subclassed
12
+ class EmptyNode < Node
13
+ def inspect(options={})
14
+ "EmptyNode" unless options[:simple]
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,62 @@
1
+ =begin
2
+ Copyright 2011 Shane Brinkman-Davis
3
+ See README for licence information.
4
+ http://babel-bridge.rubyforge.org/
5
+ =end
6
+
7
+ module BabelBridge
8
+ # generated by a :poly PatternElement
9
+ # Not subclassed
10
+ class ManyNode < Node
11
+ attr_accessor :matches,:delimiter_matches
12
+ def initialize(parent)
13
+ node_init(parent)
14
+ self.matches=[]
15
+ self.delimiter_matches=[]
16
+ end
17
+
18
+ def match_length; self.next-offset end
19
+
20
+ def next
21
+ if m=matches[-1]
22
+ m_next=m.next
23
+ if d=delimiter_matches[-1]
24
+ d_next=d.next
25
+ m_next > d_next ? m_next : d_next
26
+ else
27
+ m_next
28
+ end
29
+ else
30
+ parent.next
31
+ end
32
+ end
33
+
34
+ def inspect_helper(list,options)
35
+ simple=options[:simple]
36
+ ret=list.collect {|a|a.inspect(options)}.compact
37
+ ret= if ret.length==0 then simple ? nil : "[]"
38
+ elsif ret.length==1 && !ret[0]["\n"] then (simple ? ret[0] : "[#{ret[0]}]")
39
+ else (simple ? ret : ["[",ret,"]"]).flatten.join("\n") #.gsub("\n","\n ")
40
+ end
41
+ ret
42
+ end
43
+
44
+ def inspect(options={})
45
+ if options[:simple]
46
+ c=[]
47
+ matches.each_with_index {|n,i| c<<n;c<<delimiter_matches[i]}
48
+ c=c.compact
49
+ inspect_helper(c,options)
50
+ else
51
+ ret=inspect_helper(matches,options)
52
+ ret+=" delimiters="+inspect_helper(delimiter_matches,options) if delimiter_matches.length>0
53
+ ret
54
+ end
55
+ end
56
+
57
+ def method_missing(method_name, *args) #method_name is a symbol
58
+ self.map {|match| match.send(method_name,*args)}
59
+ end
60
+
61
+ end
62
+ end
@@ -0,0 +1,94 @@
1
+ module BabelBridge
2
+
3
+ # this is just so we can distinguish between normal arrays and arrays of matches
4
+ # - since a match can be an Array in the case of Poly-matches
5
+ class MultiMatchesArray < Array
6
+ end
7
+
8
+ # base class for all parse-tree nodes
9
+ class Node
10
+ attr_accessor :src,:offset,:match_length,:parent,:parser
11
+
12
+ def to_s
13
+ text
14
+ end
15
+
16
+ def node_init(parent_or_parser)
17
+ self.match_length=0
18
+ case parent_or_parser
19
+ when Parser then
20
+ self.parser=parent_or_parser
21
+ self.offset=0
22
+ self.src=parser.src
23
+ when Node then
24
+ self.parent=parent_or_parser
25
+ self.parser=parent.parser
26
+ self.offset=parent.next
27
+ self.src=parent.src
28
+ raise "parent node does not have parser set" unless parser
29
+ else
30
+ raise "parent_or_parser(#{parent_or_parser.class}) must be a Node or a Parser"
31
+ end
32
+ end
33
+
34
+ def initialize(parent)
35
+ node_init(parent)
36
+ end
37
+
38
+ # after a node has been matched, the node will get this called on itself
39
+ # It can then rewrite itself however it wishes
40
+ def post_match
41
+ self
42
+ end
43
+
44
+ #********************
45
+ # info methods
46
+ #********************
47
+ def next; offset+match_length end # index of first character after match
48
+ def text; src[offset,match_length] end # the substring in src matched
49
+
50
+ # length returns the number of sub-nodes
51
+ def length
52
+ 0
53
+ end
54
+
55
+ def parent_list
56
+ return parent ? parent.parent_list+[parent] : []
57
+ end
58
+
59
+ def node_path
60
+ "#{parent && (parent.node_path+' > ')}#{self.class}(#{offset})"
61
+ end
62
+
63
+ #*****************************
64
+ # Array interface implementation
65
+ #*****************************
66
+ def matches # override this with function that returns array of matches to be used for Array indexing and iteration
67
+ []
68
+ end
69
+
70
+ include Enumerable
71
+ def length
72
+ matches.length
73
+ end
74
+
75
+ def <<(node)
76
+ matches<<node
77
+ end
78
+
79
+ def add_delimiter(node)
80
+ delimiter_matches<<node
81
+ end
82
+
83
+ def [](i)
84
+ matches[i]
85
+ end
86
+
87
+ def each(&block)
88
+ matches.each(&block)
89
+ end
90
+ end
91
+
92
+ class RootNode < Node
93
+ end
94
+ end