Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(7)

Side by Side Diff: petitparser/lib/src/core/definition.dart

Issue 1400473008: Roll Observatory packages and add a roll script (Closed) Base URL: git@github.com:dart-lang/observatory_pub_packages.git@master
Patch Set: Created 5 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « petitparser/lib/src/core/context.dart ('k') | petitparser/lib/src/core/expression.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 part of petitparser;
2
3 /**
4 * Helper to conveniently define and build complex, recursive grammars using
5 * plain Dart code.
6 *
7 * To create a new grammar definition subclass [GrammarDefinition]. For every
8 * production create a new method returning the primitive parser defining it.
9 * The method called [start] is supposed to return the start production of the
10 * grammar. To refer to a production defined in the same definition use [ref]
11 * with the function reference as the first argument.
12 *
13 * Consider the following example to parse a list of numbers:
14 *
15 * class ListGrammarDefinition extends GrammarDefinition {
16 * start() => ref(list).end();
17 * list() => ref(element) & char(',') & ref(list)
18 * | ref(element);
19 * element() => digit().plus().flatten();
20 * }
21 *
22 * Since this is plain Dart code, common refactorings such as renaming a product ion
23 * updates all references correctly. Also code navigation and code completion
24 * works as expected.
25 *
26 * To attach custom production actions you might want to further subclass your
27 * grammar definition and override overriding the necessary productions defined
28 * in the superclass:
29 *
30 * class ListParserDefinition extends ListGrammarDefinition {
31 * element() => super.element().map((value) => int.parse(value));
32 * }
33 *
34 * Note that productions can be parametrized. Define such productions with posit ional
35 * arguments and reference to multiple instances by passing the arguments to [re f].
36 *
37 * Consider extending the above grammar with a parametrized token production:
38 *
39 * class TokenizedListGrammarDefinition extends GrammarDefinition {
40 * start() => ref(list).end();
41 * list() => ref(element) & ref(token, char(',')) & ref(list)
42 * | ref(element);
43 * element() => ref(token, digit().plus());
44 * token(p) => p.token().trim();
45 * }
46 */
47 abstract class GrammarDefinition {
48 const GrammarDefinition();
49
50 /**
51 * The starting production of this definition.
52 */
53 Parser start();
54
55 /**
56 * Returns a parser reference to a production defined by a [function].
57 *
58 * The optional arguments parametrize the called production.
59 */
60 Parser ref(Function function, [arg1, arg2, arg3, arg4, arg5, arg6]) {
61 var arguments = [arg1, arg2, arg3, arg4, arg5, arg6]
62 .takeWhile((each) => each != null)
63 .toList(growable: false);
64 return new _Reference(function, arguments);
65 }
66
67 /**
68 * Builds a composite parser from this definition.
69 *
70 * The optional [start] reference specifies a different starting production in to
71 * the grammar. The optional [arguments] list parametrizes the called producti on.
72 */
73 Parser build({Function start: null, List arguments: const []}) {
74 return _resolve(
75 new _Reference(start != null ? start : this.start, arguments));
76 }
77
78 /**
79 * Internal helper to resolve a complete parser graph.
80 */
81 Parser _resolve(_Reference reference) {
82 var mapping = new Map();
83
84 Parser _dereference(_Reference reference) {
85 var parser = mapping[reference];
86 if (parser == null) {
87 var references = [reference];
88 parser = reference.resolve();
89 while (parser is _Reference) {
90 if (references.contains(parser)) {
91 throw new StateError('Recursive references detected: $references');
92 }
93 references.add(parser);
94 parser = parser.resolve();
95 }
96 for (var each in references) {
97 mapping[each] = parser;
98 }
99 }
100 return parser;
101 }
102
103 var todo = [_dereference(reference)];
104 var seen = new Set.from(todo);
105
106 while (todo.isNotEmpty) {
107 var parent = todo.removeLast();
108 for (var child in parent.children) {
109 if (child is _Reference) {
110 var referenced = _dereference(child);
111 parent.replace(child, referenced);
112 child = referenced;
113 }
114 if (!seen.contains(child)) {
115 seen.add(child);
116 todo.add(child);
117 }
118 }
119 }
120
121 return mapping[reference];
122 }
123 }
124
125 /**
126 * A helper to build a parser from a {@link GrammarDefinition}.
127 */
128 class GrammarParser extends DelegateParser {
129 GrammarParser(GrammarDefinition definition) : super(definition.build());
130 }
131
132 class _Reference extends Parser {
133 final Function function;
134 final List arguments;
135
136 _Reference(this.function, this.arguments);
137
138 Parser resolve() => Function.apply(function, arguments);
139
140 @override
141 bool operator ==(other) {
142 if (other is! _Reference ||
143 other.function != function ||
144 other.arguments.length != arguments.length) {
145 return false;
146 }
147 for (var i = 0; i < arguments.length; i++) {
148 var a = arguments[i],
149 b = other.arguments[i];
150 if (a is Parser && a is! _Reference && b is Parser && b is! _Reference) {
151 // for parsers do a deep equality check
152 if (!a.isEqualTo(b)) {
153 return false;
154 }
155 } else {
156 // for everything else just do standard equality
157 if (a != b) {
158 return false;
159 }
160 }
161 }
162 return true;
163 }
164
165 @override
166 int get hashCode => function.hashCode;
167
168 @override
169 Parser copy() => throw new UnsupportedError('References cannot be copied.');
170
171 @override
172 Result parseOn(Context context) => throw new UnsupportedError('References cann ot be parsed.');
173 }
OLDNEW
« no previous file with comments | « petitparser/lib/src/core/context.dart ('k') | petitparser/lib/src/core/expression.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698