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