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