| 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 | 
|---|