OLD | NEW |
1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 library Peg Parser; | 5 library PegParser; |
6 | 6 |
7 /* | 7 /* |
8 * The following functions are combinators for building Rules. | 8 * The following functions are combinators for building Rules. |
9 * | 9 * |
10 * A rule is one of the following | 10 * A rule is one of the following |
11 * - A String which matches the string literally. | 11 * - A String which matches the string literally. |
12 * - A Symbol which matches the symbol's definition. | 12 * - A Symbol which matches the symbol's definition. |
13 * - A list of rules with an optional reducing function, which matches a sequenc
e. | 13 * - A list of rules with an optional reducing function, which matches a sequenc
e. |
14 * - The result of calling one of the combinators. | 14 * - The result of calling one of the combinators. |
15 * | 15 * |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
55 * CHAR does not generate a value. | 55 * CHAR does not generate a value. |
56 */ | 56 */ |
57 _Rule CHAR([characters]) { | 57 _Rule CHAR([characters]) { |
58 if (characters == null) | 58 if (characters == null) |
59 return const _AnyCharRule(); | 59 return const _AnyCharRule(); |
60 if (characters is int) | 60 if (characters is int) |
61 return CHARCODE(characters); | 61 return CHARCODE(characters); |
62 | 62 |
63 // Find the range of character codes and construct an array of flags for codes | 63 // Find the range of character codes and construct an array of flags for codes |
64 // within the range. | 64 // within the range. |
65 List<int> codes = characters.codeUnits; | 65 List<int> codes = characters.codeUnits.toList(); |
66 codes.sort((a, b) => a < b ? -1 : a > b ? 1 : 0); | 66 codes.sort((a, b) => a < b ? -1 : a > b ? 1 : 0); |
67 int lo = codes[0]; | 67 int lo = codes[0]; |
68 int hi = codes[codes.length - 1]; | 68 int hi = codes[codes.length - 1]; |
69 if (lo == hi) | 69 if (lo == hi) |
70 return CHARCODE(lo); | 70 return CHARCODE(lo); |
71 int len = hi - lo + 1; | 71 int len = hi - lo + 1; |
72 var flags = new List<bool>(len); | 72 var flags = new List<bool>(len); |
73 for (int i = 0; i < len; ++i) | 73 for (int i = 0; i < len; ++i) |
74 flags[i] = false; | 74 flags[i] = false; |
75 for (int code in codes) | 75 for (int code in codes) |
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
158 | 158 |
159 /** | 159 /** |
160 * MANY(rule) matches [rule] [min] or more times. | 160 * MANY(rule) matches [rule] [min] or more times. |
161 * [min] must be 0 or 1. | 161 * [min] must be 0 or 1. |
162 * If [separator] is provided it is used to match a separator between matches of | 162 * If [separator] is provided it is used to match a separator between matches of |
163 * [rule]. | 163 * [rule]. |
164 * | 164 * |
165 * MANY is a value generating matcher. The value is a list of the matches of | 165 * MANY is a value generating matcher. The value is a list of the matches of |
166 * [rule]. The list may be empty if [:min == 0:]. | 166 * [rule]. The list may be empty if [:min == 0:]. |
167 */ | 167 */ |
168 _Rule MANY(rule, [separator = null, int min = 1]) { | 168 _Rule MANY(rule, {separator: null, int min: 1}) { |
169 assert(0 <= min && min <= 1); | 169 assert(0 <= min && min <= 1); |
170 return new _RepeatRule(_compile(rule), _compileOptional(separator), min); | 170 return new _RepeatRule(_compile(rule), _compileOptional(separator), min); |
171 } | 171 } |
172 | 172 |
173 /** | 173 /** |
174 * Matches [rule] zero or more times. Shorthand for [:MANY(rule, min:0):] | 174 * Matches [rule] zero or more times. Shorthand for [:MANY(rule, min:0):] |
175 * TODO: retire min: parameter? | 175 * TODO: retire min: parameter? |
176 * | 176 * |
177 * MANY0 is a value generating matcher. | 177 * MANY0 is a value generating matcher. |
178 */ | 178 */ |
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
267 diagnose(state) { | 267 diagnose(state) { |
268 var message = 'unexpected error'; | 268 var message = 'unexpected error'; |
269 if (!state.max_rule.isEmpty) { | 269 if (!state.max_rule.isEmpty) { |
270 var s = new Set(); | 270 var s = new Set(); |
271 for (var rule in state.max_rule) | 271 for (var rule in state.max_rule) |
272 s.add(rule.description()); | 272 s.add(rule.description()); |
273 var tokens = new List<String>.from(s); | 273 var tokens = new List<String>.from(s); |
274 tokens.sort((a, b) => | 274 tokens.sort((a, b) => |
275 a.startsWith("'") == b.startsWith("'") | 275 a.startsWith("'") == b.startsWith("'") |
276 ? a.compareTo(b) | 276 ? a.compareTo(b) |
277 : a.startsWith("'") ? +1 : -1); | 277 : a.startsWith("'") ? 1 : -1); |
278 var expected = tokens.join(' or '); | 278 var expected = tokens.join(' or '); |
279 var found = state.max_pos == state._end ? 'end of file' | 279 var found = state.max_pos == state._end ? 'end of file' |
280 : "'${state._text[state.max_pos]}'"; | 280 : "'${state._text[state.max_pos]}'"; |
281 message = 'Expected $expected but found $found'; | 281 message = 'Expected $expected but found $found'; |
282 } | 282 } |
283 int start = state.max_pos; | 283 int start = state.max_pos; |
284 int end = start; | 284 int end = start; |
285 while (start >= 1 && state._text[start - 1] != '\n') --start; | 285 while (start >= 1 && state._text[start - 1] != '\n') --start; |
286 while (end < state._text.length && state._text[end] != '\n') ++end; | 286 while (end < state._text.length && state._text[end] != '\n') ++end; |
287 var line = state._text.substring(start, end); | 287 var line = state._text.substring(start, end); |
(...skipping 19 matching lines...) Expand all Loading... |
307 void set def(rule) { | 307 void set def(rule) { |
308 assert(_rule == null); // Assign once. | 308 assert(_rule == null); // Assign once. |
309 _rule = _compile(rule); | 309 _rule = _compile(rule); |
310 } | 310 } |
311 | 311 |
312 toString() => _rule == null ? '<$name>' : '<$name = $_rule>'; | 312 toString() => _rule == null ? '<$name>' : '<$name = $_rule>'; |
313 } | 313 } |
314 | 314 |
315 | 315 |
316 class _ParserState { | 316 class _ParserState { |
317 _ParserState(this._text, [_Rule whitespace = null]) { | 317 _ParserState(this._text, {_Rule whitespace}) { |
318 _end = this._text.length; | 318 _end = this._text.length; |
319 whitespaceRule = whitespace; | 319 whitespaceRule = whitespace; |
320 max_rule = []; | 320 max_rule = []; |
321 } | 321 } |
322 | 322 |
323 String _text; | 323 String _text; |
324 int _end; | 324 int _end; |
325 | 325 |
326 // | 326 // |
327 bool inWhitespaceMode = false; | 327 bool inWhitespaceMode = false; |
(...skipping 521 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
849 add(s); | 849 add(s); |
850 add(t); | 850 add(t); |
851 add(u); | 851 add(u); |
852 add(v); | 852 add(v); |
853 add(w); | 853 add(w); |
854 add(x); | 854 add(x); |
855 add(y); | 855 add(y); |
856 add(z); | 856 add(z); |
857 return list; | 857 return list; |
858 } | 858 } |
OLD | NEW |