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

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

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

Powered by Google App Engine
This is Rietveld 408576698