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