16 |
16 |
17 new |
17 new |
18 ^ self basicNew initialize |
18 ^ self basicNew initialize |
19 ! ! |
19 ! ! |
20 |
20 |
|
21 !PPParser methodsFor:'*petitanalyzer-enumerating'! |
|
22 |
|
23 allParsers |
|
24 "Answer all the parse nodes of the receiver." |
|
25 |
|
26 | result | |
|
27 result := OrderedCollection new. |
|
28 self allParsersDo: [ :parser | result addLast: parser ]. |
|
29 ^ result |
|
30 ! |
|
31 |
|
32 allParsersDo: aBlock |
|
33 "Iterate over all the parse nodes of the receiver." |
|
34 |
|
35 self allParsersDo: aBlock seen: IdentitySet new |
|
36 ! |
|
37 |
|
38 allParsersDo: aBlock seen: aSet |
|
39 "Iterate over all the parse nodes of the receiver, do not visit and follow the ones contained in aSet." |
|
40 |
|
41 (aSet includes: self) |
|
42 ifTrue: [ ^ self ]. |
|
43 aSet add: self. |
|
44 aBlock value: self. |
|
45 self children |
|
46 do: [ :each | each allParsersDo: aBlock seen: aSet ] |
|
47 ! ! |
|
48 |
|
49 !PPParser methodsFor:'*petitanalyzer-matching'! |
|
50 |
|
51 copyInContext: aDictionary |
|
52 ^ self copyInContext: aDictionary seen: IdentityDictionary new |
|
53 ! |
|
54 |
|
55 copyInContext: aDictionary seen: aSeenDictionary |
|
56 | copy | |
|
57 aSeenDictionary |
|
58 at: self |
|
59 ifPresent: [ :value | ^ value ]. |
|
60 copy := aSeenDictionary |
|
61 at: self |
|
62 put: self copy. |
|
63 copy children do: [ :each | |
|
64 copy |
|
65 replace: each |
|
66 with: (each copyInContext: aDictionary seen: aSeenDictionary) ]. |
|
67 ^ copy |
|
68 ! |
|
69 |
|
70 match: aParser inContext: aDictionary |
|
71 ^ self match: aParser inContext: aDictionary seen: IdentitySet new |
|
72 ! |
|
73 |
|
74 match: aParser inContext: aDictionary seen: anIdentitySet |
|
75 "This is the default implementation to match two parsers. This code can properly handle recursion. This is code is supposed to be overridden in subclasses that add new state." |
|
76 |
|
77 (self == aParser or: [ anIdentitySet includes: self ]) |
|
78 ifTrue: [ ^ true ]. |
|
79 anIdentitySet add: self. |
|
80 ^ self class = aParser class and: [ self matchList: self children against: aParser children inContext: aDictionary seen: anIdentitySet ] |
|
81 ! |
|
82 |
|
83 matchList: matchList against: parserList inContext: aDictionary seen: aSet |
|
84 ^ self matchList: matchList index: 1 against: parserList index: 1 inContext: aDictionary seen: aSet |
|
85 ! |
|
86 |
|
87 matchList: matchList index: matchIndex against: parserList index: parserIndex inContext: aDictionary seen: aSet |
|
88 | parser currentIndex currentDictionary currentSeen parsers | |
|
89 matchList size < matchIndex |
|
90 ifTrue: [ ^ parserList size < parserIndex ]. |
|
91 parser := matchList at: matchIndex. |
|
92 parser class = PPListPattern ifTrue: [ |
|
93 currentIndex := parserIndex - 1. |
|
94 [ currentDictionary := aDictionary copy. |
|
95 currentSeen := aSet copy. |
|
96 parserList size < currentIndex or: [ |
|
97 parsers := parserList copyFrom: parserIndex to: currentIndex. |
|
98 (currentDictionary at: parser ifAbsentPut: [ parsers ]) = parsers and: [ |
|
99 (self |
|
100 matchList: matchList |
|
101 index: matchIndex + 1 |
|
102 against: parserList |
|
103 index: currentIndex + 1 |
|
104 inContext: currentDictionary |
|
105 seen: currentSeen) |
|
106 ifTrue: [ |
|
107 currentDictionary keysAndValuesDo: [ :key :value | aDictionary at: key put: value ]. |
|
108 ^ true ]. |
|
109 false ] ] ] whileFalse: [ currentIndex := currentIndex + 1 ]. |
|
110 ^ false ]. |
|
111 parserList size < parserIndex |
|
112 ifTrue: [ ^ false ]. |
|
113 (parser match: (parserList at: parserIndex) inContext: aDictionary seen: aSet) |
|
114 ifFalse: [ ^ false ]. |
|
115 ^ self |
|
116 matchList: matchList |
|
117 index: matchIndex + 1 |
|
118 against: parserList |
|
119 index: parserIndex + 1 |
|
120 inContext: aDictionary |
|
121 seen: aSet |
|
122 ! ! |
|
123 |
|
124 !PPParser methodsFor:'*petitanalyzer-named'! |
|
125 |
|
126 allNamedParsers |
|
127 "Answer all the named parse nodes of the receiver." |
|
128 |
|
129 | result | |
|
130 result := OrderedCollection new. |
|
131 self allNamedParsersDo: [ :parser | result addLast: parser ]. |
|
132 ^ result |
|
133 ! |
|
134 |
|
135 allNamedParsersDo: aBlock |
|
136 "Iterate over all the named parse nodes of the receiver." |
|
137 |
|
138 self allParsersDo: [ :each | |
|
139 each name notNil |
|
140 ifTrue: [ aBlock value: each ] ] |
|
141 ! |
|
142 |
|
143 innerChildren |
|
144 "Answer the inner children of the receiver." |
|
145 |
|
146 | result | |
|
147 result := OrderedCollection new. |
|
148 self innerChildrenDo: [ :parser | result addLast: parser ]. |
|
149 ^ result |
|
150 ! |
|
151 |
|
152 innerChildrenDo: aBlock |
|
153 "Iterate over the inner children of the receiver." |
|
154 |
|
155 self innerChildrenDo: aBlock seen: IdentitySet new |
|
156 ! |
|
157 |
|
158 innerChildrenDo: aBlock seen: aSet |
|
159 "Iterate over the inner children of the receiver." |
|
160 |
|
161 self children do: [ :each | |
|
162 (aSet includes: each) |
|
163 ifTrue: [ ^ self ]. |
|
164 aSet add: each. |
|
165 each name isNil ifTrue: [ |
|
166 aBlock value: each. |
|
167 each innerChildrenDo: aBlock seen: aSet ] ] |
|
168 ! |
|
169 |
|
170 namedChildren |
|
171 "Answer the named children of the receiver." |
|
172 |
|
173 | result | |
|
174 result := OrderedCollection new. |
|
175 self namedChildrenDo: [ :parser | result addLast: parser ]. |
|
176 ^ result |
|
177 ! |
|
178 |
|
179 namedChildrenDo: aBlock |
|
180 "Iterate over the named children of the receiver." |
|
181 |
|
182 self namedChildrenDo: aBlock seen: IdentitySet new |
|
183 ! |
|
184 |
|
185 namedChildrenDo: aBlock seen: aSet |
|
186 "Iterate over the named children of the receiver." |
|
187 |
|
188 self children do: [ :each | |
|
189 (aSet includes: each) |
|
190 ifTrue: [ ^ self ]. |
|
191 aSet add: each. |
|
192 each name isNil |
|
193 ifTrue: [ each namedChildrenDo: aBlock seen: aSet ] |
|
194 ifFalse: [ aBlock value: each ] ] |
|
195 ! ! |
|
196 |
|
197 !PPParser methodsFor:'*petitanalyzer-private'! |
|
198 |
|
199 cycleSet: aDictionary |
|
200 "PRIVATE: Answer the children that could be part of a cycle-set with the receiver, subclasses might restrict the number of children returned. aDictionary is pre-calcualted first-sets." |
|
201 |
|
202 ^ self children |
|
203 ! |
|
204 |
|
205 cycleSet: aStack firstSets: aDictionary into: aSet |
|
206 "PRIVATE: Try to find a cycle, where aStack contains the previously visited parsers. The method returns quickly when the receiver is a terminal, terminals cannot be part of a cycle. If aStack already contains the receiver, then we are in a cycle. In this case we don't process the children further and add the nodes to aSet." |
|
207 |
|
208 | index | |
|
209 self isTerminal |
|
210 ifTrue: [ ^ self ]. |
|
211 (index := aStack indexOf: self) > 0 |
|
212 ifTrue: [ ^ aSet addAll: (aStack copyFrom: index to: aStack size) ]. |
|
213 aStack addLast: self. |
|
214 (self cycleSet: aDictionary) |
|
215 do: [ :each | each cycleSet: aStack firstSets: aDictionary into: aSet ]. |
|
216 aStack removeLast |
|
217 ! |
|
218 |
|
219 firstSets: aFirstDictionary into: aSet |
|
220 "PRIVATE: Try to add additional elements to the first-set aSet of the receiver, use the incomplete aFirstDictionary." |
|
221 |
|
222 self children do: [ :parser | aSet addAll: (aFirstDictionary at: parser) ] |
|
223 ! |
|
224 |
|
225 followSets: aFollowDictionary firstSets: aFirstDictionary into: aSet |
|
226 "PRIVATE: Try to add additional elements to the follow-set aSet of the receiver, use the incomplete aFollowDictionary and the complete aFirstDictionary." |
|
227 |
|
228 self children do: [ :parser | (aFollowDictionary at: parser) addAll: aSet ] |
|
229 ! ! |
|
230 |
|
231 !PPParser methodsFor:'*petitanalyzer-querying'! |
|
232 |
|
233 cycleSet |
|
234 "Answer a set of all nodes that are within one or more cycles of left-recursion. This is generally not a problem if at least one of the nodes is memoized, but it might make the grammar very inefficient and should be avoided if possible." |
|
235 |
|
236 | cycles | |
|
237 cycles := IdentitySet new. |
|
238 self cycleSet: OrderedCollection new firstSets: self firstSets into: cycles. |
|
239 ^ cycles |
|
240 ! |
|
241 |
|
242 firstSet |
|
243 "Answer the first-set of the receiver. Note, this implementation is inefficient when called on different receivers of the same grammar, instead use #firstSets to calculate the first-sets at once." |
|
244 |
|
245 ^ self firstSets at: self |
|
246 ! |
|
247 |
|
248 firstSets |
|
249 "Answer a dictionary with all the parsers reachable from the receiver as key and their first-set as value. The first-set of a parser is the list of terminal parsers that begin the parser derivable from that parser." |
|
250 |
|
251 | firstSets | |
|
252 firstSets := IdentityDictionary new. |
|
253 self allParsersDo: [ :each | |
|
254 firstSets at: each put: (each isTerminal |
|
255 ifTrue: [ IdentitySet with: each ] |
|
256 ifFalse: [ IdentitySet new ]). |
|
257 each isNullable |
|
258 ifTrue: [ (firstSets at: each) add: PPSentinel instance ] ]. |
|
259 [ | changed tally | |
|
260 changed := false. |
|
261 firstSets keysAndValuesDo: [ :parser :first | |
|
262 tally := first size. |
|
263 parser firstSets: firstSets into: first. |
|
264 changed := changed or: [ tally ~= first size ] ]. |
|
265 changed ] whileTrue. |
|
266 ^ firstSets |
|
267 ! |
|
268 |
|
269 followSet |
|
270 "Answer the follow-set of the receiver starting at the receiver. Note, this implementation is inefficient when called on different receivers of the same grammar, instead use #followSets to calculate the follow-sets at once." |
|
271 |
|
272 ^ self followSets at: self |
|
273 ! |
|
274 |
|
275 followSets |
|
276 "Answer a dictionary with all the parsers reachable from the receiver as key and their follow-set as value. The follow-set of a parser is the list of terminal parsers that can appear immediately to the right of that parser." |
|
277 |
|
278 | current previous continue firstSets followSets | |
|
279 current := previous := 0. |
|
280 firstSets := self firstSets. |
|
281 followSets := IdentityDictionary new. |
|
282 self allParsersDo: [ :each | followSets at: each put: IdentitySet new ]. |
|
283 (followSets at: self) add: PPSentinel instance. |
|
284 [ followSets keysAndValuesDo: [ :parser :follow | |
|
285 parser |
|
286 followSets: followSets |
|
287 firstSets: firstSets |
|
288 into: follow ]. |
|
289 current := followSets |
|
290 inject: 0 |
|
291 into: [ :result :each | result + each size ]. |
|
292 continue := previous < current. |
|
293 previous := current. |
|
294 continue ] whileTrue. |
|
295 ^ followSets |
|
296 ! ! |
|
297 |
|
298 !PPParser methodsFor:'*petitanalyzer-testing'! |
|
299 |
|
300 isNullable |
|
301 "Answer true if the receiver is a nullable parser, e.g. it can successfully parse nothing." |
|
302 |
|
303 ^ false |
|
304 ! |
|
305 |
|
306 isTerminal |
|
307 "Answer true if the receiver is a terminal or leaf parser, that means it does not delegate to any other parser." |
|
308 |
|
309 ^ self children isEmpty |
|
310 ! ! |
|
311 |
|
312 !PPParser methodsFor:'*petitanalyzer-transforming'! |
|
313 |
|
314 replace: aParser with: anotherParser |
|
315 "Replace the references of the receiver pointing to aParser with anotherParser." |
|
316 ! |
|
317 |
|
318 transform: aBlock |
|
319 "Answer a copy of all parsers reachable from the receiver transformed using aBlock." |
|
320 |
|
321 | mapping root | |
|
322 mapping := IdentityDictionary new. |
|
323 self allParsersDo: [ :each | |
|
324 mapping |
|
325 at: each |
|
326 put: (aBlock value: each copy) ]. |
|
327 root := mapping at: self. |
|
328 [ | changed | |
|
329 changed := false. |
|
330 root allParsersDo: [ :each | |
|
331 each children do: [ :old | |
|
332 mapping at: old ifPresent: [ :new | |
|
333 each replace: old with: new. |
|
334 changed := true ] ] ]. |
|
335 changed ] whileTrue. |
|
336 ^ root |
|
337 ! ! |
|
338 |
21 !PPParser methodsFor:'accessing'! |
339 !PPParser methodsFor:'accessing'! |
22 |
340 |
23 children |
341 children |
24 "Answer a set of child parsers that could follow the receiver." |
342 "Answer a set of child parsers that could follow the receiver." |
25 |
343 |
290 "Answer a new parser that flattens the underlying collection." |
546 "Answer a new parser that flattens the underlying collection." |
291 |
547 |
292 ^ PPFlattenParser on: self |
548 ^ PPFlattenParser on: self |
293 ! |
549 ! |
294 |
550 |
|
551 token |
|
552 "Answer a new parser that transforms the input to a token." |
|
553 |
|
554 ^ PPTokenParser on: self |
|
555 ! |
|
556 |
|
557 token: aTokenClass |
|
558 "Answer a new parser that transforms the input to a token of class aTokenClass." |
|
559 |
|
560 ^ self token tokenClass: aTokenClass |
|
561 ! |
|
562 |
|
563 trim |
|
564 "Answer a new parser that consumes spaces before and after the receiving parser." |
|
565 |
|
566 ^ self trimSpaces |
|
567 ! ! |
|
568 |
|
569 !PPParser methodsFor:'operators-convenience'! |
|
570 |
|
571 withoutSeparators |
|
572 "Filters out the separators from a parse result produced by one of the productions #delimitedBy: or #separatedBy:." |
|
573 |
|
574 ^ self ==> [ :items | |
|
575 | result | |
|
576 result := Array new: items size + 1 // 2. |
|
577 1 to: result size do: [ :index | result at: index put: (items at: 2 * index - 1) ]. |
|
578 result ] |
|
579 ! ! |
|
580 |
|
581 !PPParser methodsFor:'operators-mapping'! |
|
582 |
295 foldLeft: aBlock |
583 foldLeft: aBlock |
296 "Answer a new parser that that folds the result of the receiver from left-to-right into aBlock. The argument aBlock must take two or more arguments." |
584 "Answer a new parser that that folds the result of the receiver from left-to-right into aBlock. The argument aBlock must take two or more arguments." |
297 |
585 |
298 | size args | |
586 | size args | |
299 size := aBlock numArgs. |
587 size := aBlock numArgs. |
300 args := Array new: size. |
588 args := Array new: size. |
301 ^ self ==> [ :nodes | |
589 ^ self ==> [ :nodes | |
302 args at: 1 put: (nodes at: 1). |
590 args at: 1 put: nodes first. |
303 2 to: nodes size by: size - 1 do: [ :index | |
591 2 to: nodes size by: size - 1 do: [ :index | |
304 args |
592 args |
305 replaceFrom: 2 to: size with: nodes startingAt: index; |
593 replaceFrom: 2 to: size with: nodes startingAt: index; |
306 at: 1 put: (aBlock valueWithArguments: args) ]. |
594 at: 1 put: (aBlock valueWithArguments: args) ]. |
307 args at: 1 ] |
595 args first ] |
308 ! |
596 ! |
309 |
597 |
310 foldRight: aBlock |
598 foldRight: aBlock |
311 "Answer a new parser that that folds the result of the receiver from right-to-left into aBlock. The argument aBlock must take two or more arguments." |
599 "Answer a new parser that that folds the result of the receiver from right-to-left into aBlock. The argument aBlock must take two or more arguments." |
312 |
600 |
313 | size args | |
601 | size args | |
314 size := aBlock numArgs. |
602 size := aBlock numArgs. |
315 args := Array new: size. |
603 args := Array new: size. |
316 ^ self ==> [ :nodes | |
604 ^ self ==> [ :nodes | |
317 args at: size put: (nodes at: nodes size). |
605 args at: size put: nodes last. |
318 nodes size - size + 1 to: 1 by: 1 - size do: [ :index | |
606 nodes size - size + 1 to: 1 by: 1 - size do: [ :index | |
319 args |
607 args |
320 replaceFrom: 1 to: size - 1 with: nodes startingAt: index; |
608 replaceFrom: 1 to: size - 1 with: nodes startingAt: index; |
321 at: size put: (aBlock valueWithArguments: args) ]. |
609 at: size put: (aBlock valueWithArguments: args) ]. |
322 args at: size ] |
610 args at: size ] |
323 ! |
611 ! |
324 |
612 |
325 map: aBlock |
613 map: aBlock |
326 "Answer a new parser that works on the receiving sequence an passes in each element as a block argument." |
614 "Answer a new parser that works on the receiving sequence an passes in each element as a block argument." |
327 |
615 |
328 ^ self ==> aBlock |
616 ^ aBlock numArgs = 1 |
329 ! |
617 ifTrue: [ self ==> aBlock ] |
330 |
618 ifFalse: [ self error: aBlock numArgs asString , ' arguments expected.' ] |
331 token |
619 ! |
332 "Answer a new parser that transforms the input to a token." |
620 |
333 |
621 trim: aParser |
334 ^ PPTokenParser on: self |
622 "Answer a new parser that consumes and ignores aParser repeatedly before and after the receiving parser." |
335 ! |
623 |
336 |
624 ^ PPTrimmingParser on: self trimmer: aParser |
337 token: aTokenClass |
|
338 "Answer a new parser that transforms the input to a token of class aTokenClass." |
|
339 |
|
340 ^ self token tokenClass: aTokenClass |
|
341 ! |
|
342 |
|
343 trim |
|
344 "Answer a new parser that consumes spaces before and after the receiving parser." |
|
345 |
|
346 ^ self trimSpaces |
|
347 ! |
625 ! |
348 |
626 |
349 trimBlanks |
627 trimBlanks |
350 "Answer a new parser that consumes blanks before and after the receiving parser." |
628 "Answer a new parser that consumes blanks before and after the receiving parser." |
351 |
629 |
352 ^ PPTrimmingParser on: self trimmer: #blank asParser |
630 ^ self trim: #blank asParser |
353 ! |
631 ! |
354 |
632 |
355 trimSpaces |
633 trimSpaces |
356 "Answer a new parser that consumes spaces before and after the receiving parser." |
634 "Answer a new parser that consumes spaces before and after the receiving parser." |
357 |
635 |
358 ^ PPTrimmingParser on: self trimmer: #space asParser |
636 ^ self trim: #space asParser |
|
637 ! ! |
|
638 |
|
639 !PPParser methodsFor:'operators-repeating'! |
|
640 |
|
641 max: anInteger |
|
642 "Answer a new parser that parses the receiver at most anInteger times." |
|
643 |
|
644 ^ self star setMax: anInteger |
|
645 ! |
|
646 |
|
647 max: anInteger greedy: aParser |
|
648 "Answer a new parser that parses the receiver at most anInteger times until it reaches aParser. This is a greedy non-blind implementation. aParser is not consumed." |
|
649 |
|
650 ^ (self starGreedy: aParser) setMax: anInteger |
|
651 ! |
|
652 |
|
653 max: anInteger lazy: aParser |
|
654 "Answer a new parser that parses the receiver at most anInteger times until it reaches aParser. This is a lazy non-blind implementation. aParser is not consumed." |
|
655 |
|
656 ^ (self starLazy: aParser) setMax: anInteger |
|
657 ! |
|
658 |
|
659 min: anInteger |
|
660 "Answer a new parser that parses the receiver at least anInteger times." |
|
661 |
|
662 ^ self star setMin: anInteger |
|
663 ! |
|
664 |
|
665 min: anInteger greedy: aParser |
|
666 "Answer a new parser that parses the receiver at least anInteger times until it reaches aParser. This is a greedy non-blind implementation. aParser is not consumed." |
|
667 |
|
668 ^ (self starGreedy: aParser) setMin: anInteger |
|
669 ! |
|
670 |
|
671 min: anInteger lazy: aParser |
|
672 "Answer a new parser that parses the receiver at least anInteger times until it reaches aParser. This is a lazy non-blind implementation. aParser is not consumed." |
|
673 |
|
674 ^ (self starLazy: aParser) setMin: anInteger |
|
675 ! |
|
676 |
|
677 min: aMinInteger max: aMaxInteger |
|
678 "Answer a new parser that parses the receiver at least aMinInteger and at most aMaxInteger times." |
|
679 |
|
680 ^ self star setMin: aMinInteger; setMax: aMaxInteger |
|
681 ! |
|
682 |
|
683 min: aMinInteger max: aMaxInteger greedy: aParser |
|
684 "Answer a new parser that parses the receiver at least aMinInteger and at most aMaxInteger times until it reaches aParser. This is a greedy non-blind implementation. aParser is not consumed." |
|
685 |
|
686 ^ (self starGreedy: aParser) setMin: aMinInteger; setMax: aMaxInteger |
|
687 ! |
|
688 |
|
689 min: aMinInteger max: aMaxInteger lazy: aParser |
|
690 "Answer a new parser that parses the receiver at least aMinInteger and at most aMaxInteger times until it reaches aParser. This is a greedy non-blind implementation. aParser is not consumed." |
|
691 |
|
692 ^ (self starLazy: aParser) setMin: aMinInteger; setMax: aMaxInteger |
|
693 ! |
|
694 |
|
695 plus |
|
696 "Answer a new parser that parses the receiver one or more times." |
|
697 |
|
698 ^ self star setMin: 1 |
|
699 ! |
|
700 |
|
701 plusGreedy: aParser |
|
702 "Answer a new parser that parses the receiver one or more times until it reaches aParser. This is a greedy non-blind implementation of the star operator. aParser is not consumed." |
|
703 |
|
704 ^ (self starGreedy: aParser) setMin: 1 |
|
705 ! |
|
706 |
|
707 plusLazy: aParser |
|
708 "Answer a new parser that parses the receiver one or more times until it reaches aParser. This is a lazy non-blind implementation of the star operator. aParser is not consumed." |
|
709 |
|
710 ^ (self starLazy: aParser) setMin: 1 |
|
711 ! |
|
712 |
|
713 star |
|
714 "Answer a new parser that parses the receiver zero or more times. This is a greedy and blind implementation that tries to consume as much input as possible and it does not consider what comes afterwards." |
|
715 |
|
716 ^ PPPossessiveRepeatingParser on: self |
|
717 ! |
|
718 |
|
719 starGreedy: aParser |
|
720 "Answer a new parser that parses the receiver zero or more times until it reaches aParser. This is a greedy non-blind implementation of the star operator. aParser is not consumed." |
|
721 |
|
722 ^ PPGreedyRepeatingParser on: self limit: aParser |
|
723 ! |
|
724 |
|
725 starLazy: aParser |
|
726 "Answer a new parser that parses the receiver zero or more times until it reaches aParser. This is a lazy non-blind implementation of the star operator. aParser is not consumed." |
|
727 |
|
728 ^ PPLazyRepeatingParser on: self limit: aParser |
359 ! ! |
729 ! ! |
360 |
730 |
361 !PPParser methodsFor:'parsing'! |
731 !PPParser methodsFor:'parsing'! |
362 |
732 |
363 matches: anObject |
733 matches: anObject |
381 "Search anObject repeatedly for the matches of the receiver. Evaluate aBlock for each match with the matched parse-tree as the argument. Make sure to always consume exactly one character with each step, to not miss any match." |
751 "Search anObject repeatedly for the matches of the receiver. Evaluate aBlock for each match with the matched parse-tree as the argument. Make sure to always consume exactly one character with each step, to not miss any match." |
382 |
752 |
383 ((self and ==> aBlock , #any asParser) / #any asParser) star parse: anObject |
753 ((self and ==> aBlock , #any asParser) / #any asParser) star parse: anObject |
384 ! |
754 ! |
385 |
755 |
|
756 matchesSkipIn: anObject |
|
757 "Search anObject repeatedly for the matches of the receiver. Answer an OrderedCollection of the matched parse-trees. Skip over matches." |
|
758 |
|
759 | result | |
|
760 result := OrderedCollection new. |
|
761 self |
|
762 matchesSkipIn: anObject |
|
763 do: [ :each | result addLast: each ]. |
|
764 ^ result |
|
765 ! |
|
766 |
|
767 matchesSkipIn: anObject do: aBlock |
|
768 "Search anObject repeatedly for the matches of the receiver. Evaluate aBlock for each match with the matched parse-tree as the argument. Skip over matches." |
|
769 |
|
770 (self ==> aBlock / #any asParser) star parse: anObject |
|
771 ! |
|
772 |
386 matchingRangesIn: anObject |
773 matchingRangesIn: anObject |
387 "Search anObject repeatedly for the matches of the receiver. Answer an OrderedCollection of ranges of each match (index of first character to: index of last character)." |
774 "Search anObject repeatedly for the matches of the receiver. Answer an OrderedCollection of ranges of each match (index of first character to: index of last character)." |
388 |
775 |
389 | result | |
776 | result | |
390 result := OrderedCollection new. |
777 result := OrderedCollection new. |
391 self |
778 self |
392 matchingRangesIn: anObject |
779 matchingRangesIn: anObject |
393 do: [ :value | result addLast: value ]. |
780 do: [ :value | result addLast: value ]. |
394 ^ result |
781 ^ result |
395 ! |
782 ! |
396 |
783 |
397 matchingRangesIn: anObject do: aBlock |
784 matchingRangesIn: anObject do: aBlock |
398 "Search anObject repeatedly for the matches of the receiver. Answer an OrderedCollection of ranges of each match (index of first character to: index of last character)." |
785 "Search anObject repeatedly for the matches of the receiver. Evaluate aBlock with the range of each match (index of first character to: index of last character)." |
|
786 |
|
787 self token |
|
788 matchesIn: anObject |
|
789 do: [ :token | aBlock value: (token start to: token stop) ] |
|
790 ! |
|
791 |
|
792 matchingSkipRangesIn: anObject |
|
793 "Search anObject repeatedly for the matches of the receiver. Skip over matches. Answer an OrderedCollection of ranges of each match (index of first character to: index of last character)." |
399 |
794 |
400 | result | |
795 | result | |
401 result := OrderedCollection new. |
796 result := OrderedCollection new. |
402 [ :stream | stream position + 1 ] asParser , self , [ :stream | stream position ] asParser |
797 self |
403 matchesIn: anObject |
798 matchingSkipRangesIn: anObject |
404 do: [ :value | aBlock value: (value first to: value last) ]. |
799 do: [ :value | result addLast: value ]. |
405 ^ result |
800 ^ result |
|
801 ! |
|
802 |
|
803 matchingSkipRangesIn: anObject do: aBlock |
|
804 "Search anObject repeatedly for the matches of the receiver. Skip over matches. Evaluate aBlock with the range of each match (index of first character to: index of last character)." |
|
805 |
|
806 self token |
|
807 matchesSkipIn: anObject |
|
808 do: [ :token | aBlock value: (token start to: token stop) ] |
406 ! |
809 ! |
407 |
810 |
408 parse: anObject |
811 parse: anObject |
409 "Parse anObject with the receiving parser and answer the parse-result or an instance of PPFailure." |
812 "Parse anObject with the receiving parser and answer the parse-result or an instance of PPFailure." |
410 |
813 |