1 # Copyright 2007-2010 Wincent Colaiuta. All rights reserved.
2 # Redistribution and use in source and binary forms, with or without
3 # modification, are permitted provided that the following conditions are met:
5 # 1. Redistributions of source code must retain the above copyright notice,
6 # this list of conditions and the following disclaimer.
7 # 2. Redistributions in binary form must reproduce the above copyright notice,
8 # this list of conditions and the following disclaimer in the documentation
9 # and/or other materials provided with the distribution.
11 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
12 # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
13 # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
14 # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
15 # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
16 # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
17 # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
18 # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
19 # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
20 # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
21 # POSSIBILITY OF SUCH DAMAGE.
26 # The ParsletCombining module, together with the ParsletCombination class and
27 # its subclasses, provides simple container classes for encapsulating
28 # relationships among Parslets. By storing this information outside of the
29 # Parslet objects themselves their design is kept clean and they can become
30 # immutable objects which are much more easily copied and shared among
31 # multiple rules in a Grammar.
32 module ParsletCombining
34 def memoizing_parse string, options = {}
35 self.to_parseable.memoizing_parse string, options
39 def parse string, options = {}
40 self.to_parseable.parse string, options
43 # Defines a sequence of Parslets (or ParsletCombinations).
44 # Returns a ParsletSequence instance.
45 def sequence first, second, *others
46 Walrat::ParsletSequence.new first.to_parseable,
47 second.to_parseable, *others
50 # Shorthand for ParsletCombining.sequence(first, second).
52 self.sequence self, next_parslet
55 # Defines a sequence of Parslets similar to the sequence method but with
56 # the difference that the contents of array results from the component
57 # parslets will be merged into a single array rather than being added as
58 # arrays. To illustrate:
60 # 'foo' & 'bar'.one_or_more # returns results like ['foo', ['bar', 'bar', 'bar']]
61 # 'foo' >> 'bar'.one_or_more # returns results like ['foo', 'bar', 'bar', 'bar']
63 def merge first, second, *others
64 Walrat::ParsletMerge.new first.to_parseable,
65 second.to_parseable, *others
68 # Shorthand for ParsletCombining.sequence(first, second)
70 self.merge self, next_parslet
73 # Defines a choice of Parslets (or ParsletCombinations).
74 # Returns a ParsletChoice instance.
75 def choice left, right, *others
76 Walrat::ParsletChoice.new left.to_parseable,
77 right.to_parseable, *others
80 # Shorthand for ParsletCombining.choice(left, right)
81 def |(alternative_parslet)
82 self.choice self, alternative_parslet
85 # Defines a repetition of the supplied Parslet (or ParsletCombination).
86 # Returns a ParsletRepetition instance.
87 def repetition parslet, min, max
88 Walrat::ParsletRepetition.new parslet.to_parseable, min, max
91 # Shorthand for ParsletCombining.repetition.
92 def repeat min = nil, max = nil
93 self.repetition self, min, max
96 def repetition_with_default parslet, min, max, default
97 Walrat::ParsletRepetitionDefault.new parslet.to_parseable, min,
101 def repeat_with_default min = nil, max = nil, default = nil
102 self.repetition_with_default self, min, max, default
105 # Shorthand for ParsletCombining.repetition(0, 1).
106 # This method optionally takes a single parameter specifying what object
107 # should be returned as a placeholder when there are no matches; this is
108 # useful for packing into ASTs where it may be better to parse an empty
109 # Array rather than nil. The specified object is cloned and returned in the
110 # event that there are no matches. As a convenience, the specified object
111 # is automatically extended using the LocationTracking module (this is a
112 # convenience so that you can specify empty Arrays, "[]", rather than
113 # explicitly passing an "ArrayResult.new")
114 def optional default_return_value = NoParameterMarker.instance
115 if default_return_value == NoParameterMarker.instance
116 self.repeat 0, 1 # default behaviour
118 self.repeat_with_default 0, 1, default_return_value
122 # Alternative to optional.
127 # possible synonym "star"
128 def zero_or_more default_return_value = NoParameterMarker.instance
129 if default_return_value == NoParameterMarker.instance
130 self.repeat 0 # default behaviour
132 self.repeat_with_default 0, nil, default_return_value
136 # possible synonym "plus"
141 # Parsing Expression Grammar support.
142 # Succeeds if parslet succeeds but consumes no input (throws an
143 # :AndPredicateSuccess symbol).
144 def and_predicate parslet
145 Walrat::AndPredicate.new parslet.to_parseable
148 # Shorthand for and_predicate
149 # Strictly speaking, this shorthand breaks with established Ruby practice
150 # that "?" at the end of a method name should indicate a method that
151 # returns true or false.
153 self.and_predicate self
156 # Parsing Expression Grammar support.
157 # Succeeds if parslet fails (throws a :NotPredicateSuccess symbol).
158 # Fails if parslet succeeds (raise a ParseError).
159 # Consumes no output.
160 # This method will almost invariably be used in conjuntion with the &
161 # operator, like this:
162 # rule :foo, :p1 & :p2.not_predicate
163 # rule :foo, :p1 & :p2.not!
164 def not_predicate parslet
165 Walrat::NotPredicate.new parslet.to_parseable
168 # Shorthand for not_predicate.
169 # Strictly speaking, this shorthand breaks with established Ruby practice
170 # that "!" at the end of a method name should indicate a destructive
171 # behaviour on (mutation of) the receiver.
173 self.not_predicate self
176 # Succeeds if parsing succeeds, consuming the output, but doesn't actually
179 # This is for elements which are required but which shouldn't appear in the
182 Walrat::ParsletOmission.new parslet.to_parseable
185 # Shorthand for ParsletCombining.omission
189 end # module ParsletCombining