| import 'package:meta/meta.dart'; |
| |
| import '../core/parser.dart'; |
| import '../parser/action/map.dart'; |
| import '../parser/combinator/sequence.dart'; |
| import '../parser/repeater/possessive.dart'; |
| import '../parser/repeater/separated.dart'; |
| import 'result.dart'; |
| import 'utils.dart'; |
| |
| /// Models a group of operators of the same precedence. |
| class ExpressionGroup<T> { |
| @internal |
| ExpressionGroup(this._loopback); |
| |
| /// Loopback parser used to establish the recursive expressions. |
| final Parser<T> _loopback; |
| |
| /// Defines a new primitive or literal [parser]. |
| @Deprecated('Define primitive parsers directly on the builder using ' |
| '`ExpressionBuilder.primitive`') |
| void primitive(Parser<T> parser) => primitives.add(parser); |
| |
| @internal |
| final List<Parser<T>> primitives = []; |
| |
| /// Defines a new wrapper using [left] and [right] parsers, that are typically |
| /// used for parenthesis. Evaluates the [callback] with the parsed `left` |
| /// delimiter, the `value` and `right` delimiter. |
| void wrapper<L, R>(Parser<L> left, Parser<R> right, |
| T Function(L left, T value, R right) callback) => |
| _wrapper.add(seq3(left, _loopback, right).map3(callback)); |
| |
| Parser<T> _buildWrapper(Parser<T> inner) => buildChoice([..._wrapper, inner]); |
| |
| final List<Parser<T>> _wrapper = []; |
| |
| /// Adds a prefix operator [parser]. Evaluates the [callback] with the parsed |
| /// `operator` and `value`. |
| void prefix<O>(Parser<O> parser, T Function(O operator, T value) callback) => |
| _prefix.add(parser |
| .map((operator) => ExpressionResultPrefix<T, O>(operator, callback))); |
| |
| Parser<T> _buildPrefix(Parser<T> inner) => _prefix.isEmpty |
| ? inner |
| : seq2(buildChoice(_prefix).star(), inner).map2((prefix, value) => |
| prefix.reversed.fold(value, (each, result) => result.call(each))); |
| |
| final List<Parser<ExpressionResultPrefix<T, void>>> _prefix = []; |
| |
| /// Adds a postfix operator [parser]. Evaluates the [callback] with the parsed |
| /// `value` and `operator`. |
| void postfix<O>(Parser<O> parser, T Function(T value, O operator) callback) => |
| _postfix.add(parser.map( |
| (operator) => ExpressionResultPostfix<T, O>(operator, callback))); |
| |
| Parser<T> _buildPostfix(Parser<T> inner) => _postfix.isEmpty |
| ? inner |
| : seq2(inner, buildChoice(_postfix).star()).map2((value, postfix) => |
| postfix.fold(value, (each, result) => result.call(each))); |
| |
| final List<Parser<ExpressionResultPostfix<T, void>>> _postfix = []; |
| |
| /// Adds a right-associative operator [parser]. Evaluates the [callback] with |
| /// the parsed `left` term, `operator`, and `right` term. |
| void right<O>( |
| Parser<O> parser, T Function(T left, O operator, T right) callback) => |
| _right.add(parser |
| .map((operator) => ExpressionResultInfix<T, O>(operator, callback))); |
| |
| Parser<T> _buildRight(Parser<T> inner) => _right.isEmpty |
| ? inner |
| : inner.plusSeparated(buildChoice(_right)).map((sequence) => sequence |
| .foldRight((left, result, right) => result.call(left, right))); |
| |
| final List<Parser<ExpressionResultInfix<T, void>>> _right = []; |
| |
| /// Adds a left-associative operator [parser]. Evaluates the [callback] with |
| /// the parsed `left` term, `operator`, and `right` term. |
| void left<O>( |
| Parser<O> parser, T Function(T left, O operator, T right) callback) => |
| _left.add(parser |
| .map((operator) => ExpressionResultInfix<T, O>(operator, callback))); |
| |
| Parser<T> _buildLeft(Parser<T> inner) => _left.isEmpty |
| ? inner |
| : inner.plusSeparated(buildChoice(_left)).map((sequence) => |
| sequence.foldLeft((left, result, right) => result.call(left, right))); |
| |
| final List<Parser<ExpressionResultInfix<T, void>>> _left = []; |
| |
| // Internal helper to build the group of parsers. |
| @internal |
| Parser<T> build(Parser<T> inner) => _buildLeft( |
| _buildRight(_buildPostfix(_buildPrefix(_buildWrapper(inner))))); |
| } |