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

Side by Side Diff: packages/petitparser/lib/src/petitparser/expression.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 /// A builder that allows the simple definition of expression grammars with
4 /// prefix, postfix, and left- and right-associative infix operators.
5 ///
6 /// The following code creates the empty expression builder:
7 ///
8 /// var builder = new ExpressionBuilder();
9 ///
10 /// Then we define the operator-groups in descending precedence. The highest
11 /// precedence have the literal numbers themselves:
12 ///
13 /// builder.group()
14 /// ..primitive(digit().plus()
15 /// .seq(char('.').seq(digit().plus()).optional())
16 /// .flatten().trim().map((a) => double.parse(a)));
17 ///
18 /// Then come the normal arithmetic operators. Note, that the action blocks rece ive
19 /// both, the terms and the parsed operator in the order they appear in the pars ed
20 /// input.
21 ///
22 /// // negation is a prefix operator
23 /// builder.group()
24 /// ..prefix(char('-').trim(), (op, a) => -a);
25 ///
26 /// // power is right-associative
27 /// builder.group()
28 /// ..right(char('^').trim(), (a, op, b) => math.pow(a, b));
29 ///
30 /// // multiplication and addition is left-associative
31 /// builder.group()
32 /// ..left(char('*').trim(), (a, op, b) => a * b)
33 /// ..left(char('/').trim(), (a, op, b) => a / b);
34 /// builder.group()
35 /// ..left(char('+').trim(), (a, op, b) => a + b)
36 /// ..left(char('-').trim(), (a, op, b) => a - b);
37 ///
38 /// Finally we can build the parser:
39 ///
40 /// var parser = builder.build();
41 ///
42 /// After executing the above code we get an efficient parser that correctly
43 /// evaluates expressions like:
44 ///
45 /// parser.parse('-8'); // -8
46 /// parser.parse('1+2*3'); // 7
47 /// parser.parse('1*2+3'); // 5
48 /// parser.parse('8/4/2'); // 2
49 /// parser.parse('2^2^3'); // 256
50 class ExpressionBuilder {
51 final List<ExpressionGroup> _groups = new List();
52
53 /// Creates a new group of operators that share the same priority.
54 ExpressionGroup group() {
55 var group = new ExpressionGroup();
56 _groups.add(group);
57 return group;
58 }
59
60 /// Builds the expression parser.
61 Parser build() => _groups.fold(
62 failure('Highest priority group should define a primitive parser.'),
63 (a, b) => b._build(a));
64 }
65
66 /// Models a group of operators of the same precedence.
67 class ExpressionGroup {
68
69 /// Defines a new primitive or literal [parser].
70 void primitive(Parser parser) {
71 _primitives.add(parser);
72 }
73
74 Parser _buildPrimitive(Parser inner) {
75 return _buildChoice(_primitives, inner);
76 }
77
78 final List<Parser> _primitives = new List();
79
80 /// Adds a prefix operator [parser]. Evaluates the optional [action] with the
81 /// parsed `operator` and `value`.
82 void prefix(Parser parser, [action(operator, value)]) {
83 if (action == null) {
84 action = (operator, value) => [operator, value];
85 }
86 _prefix.add(parser.map((operator) => new _ExpressionResult(operator, action) ));
87 }
88
89 Parser _buildPrefix(Parser inner) {
90 if (_prefix.isEmpty) {
91 return inner;
92 } else {
93 return new SequenceParser([_buildChoice(_prefix).star(), inner]).map(
94 (tuple) {
95 return tuple.first.reversed.fold(tuple.last, (value, result) {
96 return result.action(result.operator, value);
97 });
98 });
99 }
100 }
101
102 final List<Parser> _prefix = new List();
103
104 /// Adds a postfix operator [parser]. Evaluates the optional [action] with the
105 /// parsed `value` and `operator`.
106 void postfix(Parser parser, [action(value, operator)]) {
107 if (action == null) {
108 action = (value, operator) => [value, operator];
109 }
110 _postfix.add(parser.map((operator) => new _ExpressionResult(operator, action )));
111 }
112
113 Parser _buildPostfix(Parser inner) {
114 if (_postfix.isEmpty) {
115 return inner;
116 } else {
117 return new SequenceParser([inner, _buildChoice(_postfix).star()]).map(
118 (tuple) {
119 return tuple.last.fold(tuple.first, (value, result) {
120 return result.action(value, result.operator);
121 });
122 });
123 }
124 }
125
126 final List<Parser> _postfix = new List();
127
128 /// Adds a right-associative operator [parser]. Evaluates the optional [action ] with
129 /// the parsed `left` term, `operator`, and `right` term.
130 void right(Parser parser, [action(left, operator, right)]) {
131 if (action == null) {
132 action = (left, operator, right) => [left, operator, right];
133 }
134 _right.add(parser.map((operator) => new _ExpressionResult(operator, action)) );
135 }
136
137 Parser _buildRight(Parser inner) {
138 if (_right.isEmpty) {
139 return inner;
140 } else {
141 return inner.separatedBy(_buildChoice(_right)).map((sequence) {
142 var result = sequence.last;
143 for (var i = sequence.length - 2; i > 0; i -= 2) {
144 result =
145 sequence[i].action(sequence[i - 1], sequence[i].operator, result);
146 }
147 return result;
148 });
149 }
150 }
151
152 final List<Parser> _right = new List();
153
154 /// Adds a left-associative operator [parser]. Evaluates the optional [action] with
155 /// the parsed `left` term, `operator`, and `right` term.
156 void left(Parser parser, [action(left, operator, right)]) {
157 if (action == null) {
158 action = (left, operator, right) => [left, operator, right];
159 }
160 _left.add(parser.map((operator) => new _ExpressionResult(operator, action))) ;
161 }
162
163 Parser _buildLeft(Parser inner) {
164 if (_left.isEmpty) {
165 return inner;
166 } else {
167 return inner.separatedBy(_buildChoice(_left)).map((sequence) {
168 var result = sequence.first;
169 for (var i = 1; i < sequence.length; i += 2) {
170 result =
171 sequence[i].action(result, sequence[i].operator, sequence[i + 1]);
172 }
173 return result;
174 });
175 }
176 }
177
178 final List<Parser> _left = new List();
179
180 // helper to build an optimal choice parser
181 Parser _buildChoice(List<Parser> parsers, [Parser otherwise]) {
182 if (parsers.isEmpty) {
183 return otherwise;
184 } else if (parsers.length == 1) {
185 return parsers.first;
186 } else {
187 return new ChoiceParser(parsers);
188 }
189 }
190
191 // helper to build the group of parsers
192 Parser _build(Parser inner) {
193 return _buildLeft(_buildRight(_buildPostfix(_buildPrefix(_buildPrimitive(inn er)))));
194 }
195 }
196
197 // helper class to associate operators and actions
198 class _ExpressionResult {
199 final operator;
200 final Function action;
201 _ExpressionResult(this.operator, this.action);
202 }
OLDNEW
« no previous file with comments | « packages/petitparser/lib/src/petitparser/definition.dart ('k') | packages/petitparser/lib/src/petitparser/parser.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698