| OLD | NEW |
| 1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 import 'environment.dart'; | |
| 6 | |
| 7 /// A parsed Boolean expression AST. | 5 /// A parsed Boolean expression AST. |
| 8 abstract class Expression { | 6 abstract class Expression { |
| 9 /// Parses Boolean expressions in a .status file for Dart. | 7 /// Parses Boolean expressions in a .status file for Dart. |
| 10 /// | 8 /// |
| 11 /// The grammar is: | 9 /// The grammar is: |
| 12 /// | 10 /// |
| 13 /// expression := or | 11 /// expression := or |
| 14 /// or := and ( "||" and )* | 12 /// or := and ( "||" and )* |
| 15 /// and := primary ( "&&" primary )* | 13 /// and := primary ( "&&" primary )* |
| 16 /// primary := "$" identifier ( ( "==" | "!=" ) identifier )? | | 14 /// primary := "$" identifier ( ( "==" | "!=" ) identifier )? | |
| 17 /// "(" expression ")" | 15 /// "(" expression ")" |
| 18 /// identifier := regex "\w+" | 16 /// identifier := regex "\w+" |
| 19 /// | 17 /// |
| 20 /// Expressions evaluate as expected, with values of variables found in an | 18 /// Expressions evaluate as expected, with values of variables found in an |
| 21 /// environment passed to the evaluator. | 19 /// environment passed to the evaluator. |
| 22 static Expression parse(String expression) => | 20 static Expression parse(String expression) => |
| 23 new _ExpressionParser(expression).parse(); | 21 new _ExpressionParser(expression).parse(); |
| 24 | 22 |
| 25 /// Validates that this expression does not contain any invalid uses of | |
| 26 /// variables. | |
| 27 /// | |
| 28 /// Ensures that any variable names are known and that any literal values are | |
| 29 /// allowed for their corresponding variable. If an invalid variable or value | |
| 30 /// is found, adds appropriate error messages to [errors]. | |
| 31 void validate(List<String> errors); | |
| 32 | |
| 33 /// Evaluates the expression where all variables are defined by the given | 23 /// Evaluates the expression where all variables are defined by the given |
| 34 /// [environment]. | 24 /// [environment]. |
| 35 bool evaluate(Environment environment); | 25 bool evaluate(Map<String, dynamic> environment); |
| 36 } | 26 } |
| 37 | 27 |
| 38 /// Keyword token strings. | 28 /// Keyword token strings. |
| 39 class _Token { | 29 class _Token { |
| 40 static const leftParen = "("; | 30 static const leftParen = "("; |
| 41 static const rightParen = ")"; | 31 static const rightParen = ")"; |
| 42 static const dollar = r"$"; | 32 static const dollar = r"$"; |
| 43 static const equals = "=="; | 33 static const equals = "=="; |
| 44 static const notEqual = "!="; | 34 static const notEqual = "!="; |
| 45 static const and = "&&"; | 35 static const and = "&&"; |
| 46 static const or = "||"; | 36 static const or = "||"; |
| 47 } | 37 } |
| 48 | 38 |
| 49 /// A reference to a variable. | 39 /// A reference to a variable. |
| 50 class _Variable { | 40 class _Variable { |
| 51 final String name; | 41 final String name; |
| 52 | 42 |
| 53 _Variable(this.name); | 43 _Variable(this.name); |
| 54 | 44 |
| 55 String lookup(Environment environment) { | 45 String lookup(Map<String, dynamic> environment) { |
| 56 var value = environment.lookUp(name); | 46 var value = environment[name]; |
| 57 if (value == null) { | 47 if (value == null) { |
| 58 throw new Exception("Could not find '$name' in environment " | 48 throw new Exception("Could not find '$name' in environment " |
| 59 "while evaluating status file expression."); | 49 "while evaluating status file expression."); |
| 60 } | 50 } |
| 61 | 51 |
| 62 // Explicitly stringify all values so that things like: | 52 // Explicitly stringify all values so that things like: |
| 63 // | 53 // |
| 64 // $strong == true | 54 // $strong == true |
| 65 // | 55 // |
| 66 // work correctly even though "true" is treated as a string here. | 56 // work correctly even though "true" is treated as a string here. |
| 67 // TODO(rnystrom): Is there a cleaner/safer way to do this? | 57 // TODO(rnystrom): Is there a cleaner/safer way to do this? |
| 68 return value.toString(); | 58 return value.toString(); |
| 69 } | 59 } |
| 70 } | 60 } |
| 71 | 61 |
| 72 /// Tests whether a given variable is or is not equal some literal value, as in: | 62 /// Tests whether a given variable is or is not equal some literal value, as in: |
| 73 /// | 63 /// |
| 74 /// $variable == someValue | 64 /// $variable == someValue |
| 75 class _ComparisonExpression implements Expression { | 65 class _ComparisonExpression implements Expression { |
| 76 final _Variable left; | 66 final _Variable left; |
| 77 final String right; | 67 final String right; |
| 78 final bool negate; | 68 final bool negate; |
| 79 | 69 |
| 80 _ComparisonExpression(this.left, this.right, this.negate); | 70 _ComparisonExpression(this.left, this.right, this.negate); |
| 81 | 71 |
| 82 void validate(List<String> errors) { | 72 bool evaluate(Map<String, dynamic> environment) { |
| 83 Environment.validate(left.name, right, errors); | |
| 84 } | |
| 85 | |
| 86 bool evaluate(Environment environment) { | |
| 87 return negate != (left.lookup(environment) == right); | 73 return negate != (left.lookup(environment) == right); |
| 88 } | 74 } |
| 89 | 75 |
| 90 String toString() => "(\$${left.name} ${negate ? '!=' : '=='} $right)"; | 76 String toString() => "(\$${left.name} ${negate ? '!=' : '=='} $right)"; |
| 91 } | 77 } |
| 92 | 78 |
| 93 /// A reference to a variable defined in the environment. The expression | 79 /// A reference to a variable defined in the environment. The expression |
| 94 /// evaluates to true if the variable's stringified value is "true". | 80 /// evaluates to true if the variable's stringified value is "true". |
| 95 /// | 81 /// |
| 96 /// $variable | 82 /// $variable |
| 97 class _VariableExpression implements Expression { | 83 class _VariableExpression implements Expression { |
| 98 final _Variable variable; | 84 final _Variable variable; |
| 99 | 85 |
| 100 _VariableExpression(this.variable); | 86 _VariableExpression(this.variable); |
| 101 | 87 |
| 102 void validate(List<String> errors) { | 88 bool evaluate(Map<String, dynamic> environment) => |
| 103 // It must be a Boolean, so it should allow either Boolean value. | |
| 104 Environment.validate(variable.name, "true", errors); | |
| 105 } | |
| 106 | |
| 107 bool evaluate(Environment environment) => | |
| 108 variable.lookup(environment) == "true"; | 89 variable.lookup(environment) == "true"; |
| 109 | 90 |
| 110 String toString() => "(bool \$${variable.name})"; | 91 String toString() => "(bool \$${variable.name})"; |
| 111 } | 92 } |
| 112 | 93 |
| 113 /// A logical `||` or `&&` expression. | 94 /// A logical `||` or `&&` expression. |
| 114 class _LogicExpression implements Expression { | 95 class _LogicExpression implements Expression { |
| 115 /// The operator, `||` or `&&`. | 96 /// The operator, `||` or `&&`. |
| 116 final String op; | 97 final String op; |
| 117 | 98 |
| 118 final Expression left; | 99 final Expression left; |
| 119 final Expression right; | 100 final Expression right; |
| 120 | 101 |
| 121 _LogicExpression(this.op, this.left, this.right); | 102 _LogicExpression(this.op, this.left, this.right); |
| 122 | 103 |
| 123 void validate(List<String> errors) { | 104 bool evaluate(Map<String, dynamic> environment) => (op == _Token.and) |
| 124 left.validate(errors); | |
| 125 right.validate(errors); | |
| 126 } | |
| 127 | |
| 128 bool evaluate(Environment environment) => (op == _Token.and) | |
| 129 ? left.evaluate(environment) && right.evaluate(environment) | 105 ? left.evaluate(environment) && right.evaluate(environment) |
| 130 : left.evaluate(environment) || right.evaluate(environment); | 106 : left.evaluate(environment) || right.evaluate(environment); |
| 131 | 107 |
| 132 String toString() => "($left $op $right)"; | 108 String toString() => "($left $op $right)"; |
| 133 } | 109 } |
| 134 | 110 |
| 135 /// Parser for Boolean expressions in a .status file for Dart. | 111 /// Parser for Boolean expressions in a .status file for Dart. |
| 136 class _ExpressionParser { | 112 class _ExpressionParser { |
| 137 final _Scanner _scanner; | 113 final _Scanner _scanner; |
| 138 | 114 |
| (...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 254 return true; | 230 return true; |
| 255 } | 231 } |
| 256 | 232 |
| 257 /// Consumes the current token and returns it. | 233 /// Consumes the current token and returns it. |
| 258 String advance() { | 234 String advance() { |
| 259 var previous = current; | 235 var previous = current; |
| 260 current = tokenIterator.moveNext() ? tokenIterator.current : null; | 236 current = tokenIterator.moveNext() ? tokenIterator.current : null; |
| 261 return previous; | 237 return previous; |
| 262 } | 238 } |
| 263 } | 239 } |
| OLD | NEW |