| Index: tools/testing/dart/status_expression.dart
|
| diff --git a/tools/testing/dart/status_expression.dart b/tools/testing/dart/status_expression.dart
|
| index 10b30953096af0f6f634f6f8c94c6e36e9b3c645..e4713ba7c2a7f38247e576649bc2aff3b0ed27af 100644
|
| --- a/tools/testing/dart/status_expression.dart
|
| +++ b/tools/testing/dart/status_expression.dart
|
| @@ -13,7 +13,8 @@ abstract class Expression {
|
| /// expression := or
|
| /// or := and ( "||" and )*
|
| /// and := primary ( "&&" primary )*
|
| - /// primary := "$" identifier ( ( "==" | "!=" ) identifier )? |
|
| + /// primary := "$" identifier ( "==" | "!=" ) identifier |
|
| + /// "!"? "$" identifier |
|
| /// "(" expression ")"
|
| /// identifier := regex "\w+"
|
| ///
|
| @@ -44,6 +45,7 @@ class _Token {
|
| static const notEqual = "!=";
|
| static const and = "&&";
|
| static const or = "||";
|
| + static const not = "!";
|
| }
|
|
|
| /// A reference to a variable.
|
| @@ -70,8 +72,10 @@ class _Variable {
|
| }
|
|
|
| /// Tests whether a given variable is or is not equal some literal value, as in:
|
| -///
|
| -/// $variable == someValue
|
| +/// ```
|
| +/// $variable == someValue
|
| +/// ```
|
| +/// Negate the result if [negate] is true.
|
| class _ComparisonExpression implements Expression {
|
| final _Variable left;
|
| final String right;
|
| @@ -92,12 +96,26 @@ class _ComparisonExpression implements Expression {
|
|
|
| /// A reference to a variable defined in the environment. The expression
|
| /// evaluates to true if the variable's stringified value is "true".
|
| -///
|
| +/// ```
|
| /// $variable
|
| +/// ```
|
| +/// is equivalent to
|
| +/// ```
|
| +/// $variable == true
|
| +/// ```
|
| +/// Negates result if [negate] is true, so
|
| +/// ```
|
| +/// !$variable
|
| +/// ```
|
| +/// is equivalent to
|
| +/// ```
|
| +/// $variable != true
|
| +/// ```
|
| class _VariableExpression implements Expression {
|
| final _Variable variable;
|
| + final bool negate;
|
|
|
| - _VariableExpression(this.variable);
|
| + _VariableExpression(this.variable, {this.negate = false});
|
|
|
| void validate(List<String> errors) {
|
| // It must be a Boolean, so it should allow either Boolean value.
|
| @@ -105,9 +123,9 @@ class _VariableExpression implements Expression {
|
| }
|
|
|
| bool evaluate(Environment environment) =>
|
| - variable.lookup(environment) == "true";
|
| + negate != (variable.lookup(environment) == "true");
|
|
|
| - String toString() => "(bool \$${variable.name})";
|
| + String toString() => "(bool ${negate ? "! " : ""}\$${variable.name})";
|
| }
|
|
|
| /// A logical `||` or `&&` expression.
|
| @@ -179,6 +197,11 @@ class _ExpressionParser {
|
| return value;
|
| }
|
|
|
| + var negate = false;
|
| + if (_scanner.match(_Token.not)) {
|
| + negate = true;
|
| + }
|
| +
|
| // The only atomic booleans are of the form $variable == value or
|
| // of the form $variable.
|
| if (!_scanner.match(_Token.dollar)) {
|
| @@ -194,9 +217,10 @@ class _ExpressionParser {
|
| var left = new _Variable(_scanner.current);
|
| _scanner.advance();
|
|
|
| - if (_scanner.current == _Token.equals ||
|
| - _scanner.current == _Token.notEqual) {
|
| - var negate = _scanner.advance() == _Token.notEqual;
|
| + if (!negate &&
|
| + (_scanner.current == _Token.equals ||
|
| + _scanner.current == _Token.notEqual)) {
|
| + var isNotEquals = _scanner.advance() == _Token.notEqual;
|
|
|
| if (!_scanner.isIdentifier) {
|
| throw new FormatException(
|
| @@ -204,22 +228,24 @@ class _ExpressionParser {
|
| }
|
|
|
| var right = _scanner.advance();
|
| - return new _ComparisonExpression(left, right, negate);
|
| + return new _ComparisonExpression(left, right, isNotEquals);
|
| } else {
|
| - return new _VariableExpression(left);
|
| + return new _VariableExpression(left, negate: negate);
|
| }
|
| }
|
| }
|
|
|
| /// An iterator that allows peeking at the current token.
|
| class _Scanner {
|
| - /// Tokens are "(", ")", "$", "&&", "||", "==", "!=", and (maximal) \w+.
|
| - static final _testPattern =
|
| - new RegExp(r"^([()$\w\s]|(\&\&)|(\|\|)|(\=\=)|(\!\=))+$");
|
| - static final _tokenPattern =
|
| - new RegExp(r"[()$]|(\&\&)|(\|\|)|(\=\=)|(\!\=)|\w+");
|
| + /// Tokens are "(", ")", "$", "&&", "||", "!", ==", "!=", and (maximal) \w+.
|
| + static final _testPattern = new RegExp(r"^(?:[()$\w\s]|&&|\|\||==|!=?)+$");
|
| + static final _tokenPattern = new RegExp(r"[()$]|&&|\|\||==|!=?|\w+");
|
|
|
| - static final _identifierPattern = new RegExp(r"^\w+$");
|
| + /// Pattern that recognizes identifier tokens.
|
| + ///
|
| + /// Only checks the first character, since no non-identifier token can start
|
| + /// with a word character.
|
| + static final _identifierPattern = new RegExp(r"^\w");
|
|
|
| /// The token strings being iterated.
|
| final Iterator<String> tokenIterator;
|
| @@ -244,7 +270,10 @@ class _Scanner {
|
| bool get hasMore => current != null;
|
|
|
| /// Returns `true` if the current token is an identifier.
|
| - bool get isIdentifier => _identifierPattern.hasMatch(current);
|
| + // All non-identifier tokens are one or two characters,
|
| + // so a longer token must be an identifier.
|
| + bool get isIdentifier =>
|
| + current.length > 2 || _identifierPattern.hasMatch(current);
|
|
|
| /// If the current token is [token], consumes it and returns `true`.
|
| bool match(String token) {
|
|
|