OLD | NEW |
| (Empty) |
1 part of petitparser; | |
2 | |
3 /** | |
4 * An [int] used to mark an unbounded maximum repetition. | |
5 */ | |
6 const int unbounded = -1; | |
7 | |
8 /** | |
9 * An abstract parser that repeatedly parses between 'min' and 'max' instances o
f | |
10 * its delegate. | |
11 */ | |
12 abstract class RepeatingParser extends DelegateParser { | |
13 final int _min; | |
14 final int _max; | |
15 | |
16 RepeatingParser(Parser parser, this._min, this._max) : super(parser) { | |
17 assert(0 <= _min); | |
18 assert(_max == unbounded || _min <= _max); | |
19 } | |
20 | |
21 @override | |
22 String toString() { | |
23 var max = _max == unbounded ? '*' : _max; | |
24 return '${super.toString()}[$_min..$max]'; | |
25 } | |
26 | |
27 @override | |
28 bool hasEqualProperties(Parser other) { | |
29 return other is RepeatingParser | |
30 && super.hasEqualProperties(other) | |
31 && _min == other._min | |
32 && _max == other._max; | |
33 } | |
34 } | |
35 | |
36 /** | |
37 * A greedy parser that repeatedly parses between 'min' and 'max' instances of | |
38 * its delegate. | |
39 */ | |
40 class PossessiveRepeatingParser extends RepeatingParser { | |
41 PossessiveRepeatingParser(Parser parser, int min, int max) | |
42 : super(parser, min, max); | |
43 | |
44 @override | |
45 Result parseOn(Context context) { | |
46 var current = context; | |
47 var elements = new List(); | |
48 while (elements.length < _min) { | |
49 var result = _delegate.parseOn(current); | |
50 if (result.isFailure) { | |
51 return result; | |
52 } | |
53 elements.add(result.value); | |
54 current = result; | |
55 } | |
56 while (_max == unbounded || elements.length < _max) { | |
57 var result = _delegate.parseOn(current); | |
58 if (result.isFailure) { | |
59 return current.success(elements); | |
60 } | |
61 elements.add(result.value); | |
62 current = result; | |
63 } | |
64 return current.success(elements); | |
65 } | |
66 | |
67 @override | |
68 Parser copy() => new PossessiveRepeatingParser(_delegate, _min, _max); | |
69 } | |
70 | |
71 /** | |
72 * An abstract parser that repeatedly parses between 'min' and 'max' instances o
f | |
73 * its delegate and that requires the input to be completed with a specified par
ser | |
74 * 'limit'. Subclasses provide repeating behavior as typically seen in regular | |
75 * expression implementations (non-blind). | |
76 */ | |
77 abstract class LimitedRepeatingParser extends RepeatingParser { | |
78 Parser _limit; | |
79 | |
80 LimitedRepeatingParser(Parser parser, this._limit, int min, int max) | |
81 : super(parser, min, max); | |
82 | |
83 @override | |
84 List<Parser> get children => [_delegate, _limit]; | |
85 | |
86 @override | |
87 void replace(Parser source, Parser target) { | |
88 super.replace(source, target); | |
89 if (_limit == source) { | |
90 _limit = target; | |
91 } | |
92 } | |
93 } | |
94 | |
95 /** | |
96 * A greedy repeating parser, commonly seen in regular expression implementation
s. It | |
97 * aggressively consumes as much input as possible and then backtracks to meet t
he | |
98 * 'limit' condition. | |
99 */ | |
100 class GreedyRepeatingParser extends LimitedRepeatingParser { | |
101 GreedyRepeatingParser(Parser parser, Parser limit, int min, int max) | |
102 : super(parser, limit, min, max); | |
103 | |
104 @override | |
105 Result parseOn(Context context) { | |
106 var current = context; | |
107 var elements = new List(); | |
108 while (elements.length < _min) { | |
109 var result = _delegate.parseOn(current); | |
110 if (result.isFailure) { | |
111 return result; | |
112 } | |
113 elements.add(result.value); | |
114 current = result; | |
115 } | |
116 var contexts = new List.from([current]); | |
117 while (_max == unbounded || elements.length < _max) { | |
118 var result = _delegate.parseOn(current); | |
119 if (result.isFailure) { | |
120 break; | |
121 } | |
122 elements.add(result.value); | |
123 contexts.add(current = result); | |
124 } | |
125 while (true) { | |
126 var limit = _limit.parseOn(contexts.last); | |
127 if (limit.isSuccess) { | |
128 return contexts.last.success(elements); | |
129 } | |
130 if (elements.isEmpty) { | |
131 return limit; | |
132 } | |
133 contexts.removeLast(); | |
134 elements.removeLast(); | |
135 if (contexts.isEmpty) { | |
136 return limit; | |
137 } | |
138 } | |
139 } | |
140 | |
141 @override | |
142 Parser copy() => new GreedyRepeatingParser(_delegate, _limit, _min, _max); | |
143 } | |
144 | |
145 /** | |
146 * A lazy repeating parser, commonly seen in regular expression implementations.
It | |
147 * limits its consumption to meet the 'limit' condition as early as possible. | |
148 */ | |
149 class LazyRepeatingParser extends LimitedRepeatingParser { | |
150 LazyRepeatingParser(Parser parser, Parser limit, int min, int max) | |
151 : super(parser, limit, min, max); | |
152 | |
153 @override | |
154 Result parseOn(Context context) { | |
155 var current = context; | |
156 var elements = new List(); | |
157 while (elements.length < _min) { | |
158 var result = _delegate.parseOn(current); | |
159 if (result.isFailure) { | |
160 return result; | |
161 } | |
162 elements.add(result.value); | |
163 current = result; | |
164 } | |
165 while (true) { | |
166 var limit = _limit.parseOn(current); | |
167 if (limit.isSuccess) { | |
168 return current.success(elements); | |
169 } else { | |
170 if (_max != unbounded && elements.length >= _max) { | |
171 return limit; | |
172 } | |
173 var result = _delegate.parseOn(current); | |
174 if (result.isFailure) { | |
175 return limit; | |
176 } | |
177 elements.add(result.value); | |
178 current = result; | |
179 } | |
180 } | |
181 } | |
182 | |
183 @override | |
184 Parser copy() => new LazyRepeatingParser(_delegate, _limit, _min, _max); | |
185 } | |
OLD | NEW |