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 |