OLD | NEW |
| (Empty) |
1 // This code was auto-generated, is not intended to be edited, and is subject to | |
2 // significant change. Please see the README file for more information. | |
3 library engine.constant; | |
4 import 'java_core.dart'; | |
5 import 'source.dart' show Source; | |
6 import 'error.dart' show AnalysisError, ErrorCode, CompileTimeErrorCode; | |
7 import 'scanner.dart' show TokenType; | |
8 import 'ast.dart'; | |
9 import 'element.dart'; | |
10 import 'engine.dart' show AnalysisEngine; | |
11 /** | |
12 * Instances of the class `ConstantEvaluator` evaluate constant expressions to p
roduce their | |
13 * compile-time value. According to the Dart Language Specification: <blockquote
> A constant | |
14 * expression is one of the following: | |
15 * | |
16 * * A literal number. | |
17 * * A literal boolean. | |
18 * * A literal string where any interpolated expression is a compile-time consta
nt that evaluates | |
19 * to a numeric, string or boolean value or to `null`. | |
20 * * `null`. | |
21 * * A reference to a static constant variable. | |
22 * * An identifier expression that denotes a constant variable, a class or a typ
e parameter. | |
23 * * A constant constructor invocation. | |
24 * * A constant list literal. | |
25 * * A constant map literal. | |
26 * * A simple or qualified identifier denoting a top-level function or a static
method. | |
27 * * A parenthesized expression `(e)` where `e` is a constant expression. | |
28 * * An expression of one of the forms `identical(e1, e2)`, `e1 == e2`, | |
29 * `e1 != e2` where `e1` and `e2` are constant expressions that evaluate to a | |
30 * numeric, string or boolean value or to `null`. | |
31 * * An expression of one of the forms `!e`, `e1 && e2` or `e1 || e2`, where | |
32 * `e`, `e1` and `e2` are constant expressions that evaluate to a boolean value
or | |
33 * to `null`. | |
34 * * An expression of one of the forms `~e`, `e1 ^ e2`, `e1 & e2`, | |
35 * `e1 | e2`, `e1 >> e2` or `e1 << e2`, where `e`, `e1` and `e2` | |
36 * are constant expressions that evaluate to an integer value or to `null`. | |
37 * * An expression of one of the forms `-e`, `e1 + e2`, `e1 - e2`, | |
38 * `e1 * e2`, `e1 / e2`, `e1 ~/ e2`, `e1 > e2`, `e1 < e2`, | |
39 * `e1 >= e2`, `e1 <= e2` or `e1 % e2`, where `e`, `e1` and `e2` | |
40 * are constant expressions that evaluate to a numeric value or to `null`. | |
41 * | |
42 * </blockquote> The values returned by instances of this class are therefore `n
ull` and | |
43 * instances of the classes `Boolean`, `BigInteger`, `Double`, `String`, and | |
44 * `DartObject`. | |
45 * | |
46 * In addition, this class defines several values that can be returned to indica
te various | |
47 * conditions encountered during evaluation. These are documented with the stati
c field that define | |
48 * those values. | |
49 */ | |
50 class ConstantEvaluator { | |
51 | |
52 /** | |
53 * The source containing the expression(s) that will be evaluated. | |
54 */ | |
55 Source _source; | |
56 | |
57 /** | |
58 * Initialize a newly created evaluator to evaluate expressions in the given s
ource. | |
59 * | |
60 * @param source the source containing the expression(s) that will be evaluate
d | |
61 */ | |
62 ConstantEvaluator(Source source) { | |
63 this._source = source; | |
64 } | |
65 EvaluationResult evaluate(Expression expression) { | |
66 EvaluationResultImpl result = expression.accept(new ConstantVisitor()); | |
67 if (result is ValidResult) { | |
68 return EvaluationResult.forValue(((result as ValidResult)).value); | |
69 } | |
70 List<AnalysisError> errors = new List<AnalysisError>(); | |
71 for (ErrorResult_ErrorData data in ((result as ErrorResult)).errorData) { | |
72 ASTNode node = data.node; | |
73 errors.add(new AnalysisError.con2(_source, node.offset, node.length, data.
errorCode, [])); | |
74 } | |
75 return EvaluationResult.forErrors(new List.from(errors)); | |
76 } | |
77 } | |
78 /** | |
79 * Instances of the class `EvaluationResult` represent the result of attempting
to evaluate an | |
80 * expression. | |
81 */ | |
82 class EvaluationResult { | |
83 | |
84 /** | |
85 * Return an evaluation result representing the result of evaluating an expres
sion that is not a | |
86 * compile-time constant because of the given errors. | |
87 * | |
88 * @param errors the errors that should be reported for the expression(s) that
were evaluated | |
89 * @return the result of evaluating an expression that is not a compile-time c
onstant | |
90 */ | |
91 static EvaluationResult forErrors(List<AnalysisError> errors) => new Evaluatio
nResult(null, errors); | |
92 | |
93 /** | |
94 * Return an evaluation result representing the result of evaluating an expres
sion that is a | |
95 * compile-time constant that evaluates to the given value. | |
96 * | |
97 * @param value the value of the expression | |
98 * @return the result of evaluating an expression that is a compile-time const
ant | |
99 */ | |
100 static EvaluationResult forValue(Object value) => new EvaluationResult(value,
null); | |
101 | |
102 /** | |
103 * The value of the expression. | |
104 */ | |
105 Object value; | |
106 | |
107 /** | |
108 * The errors that should be reported for the expression(s) that were evaluate
d. | |
109 */ | |
110 List<AnalysisError> _errors; | |
111 | |
112 /** | |
113 * Initialize a newly created result object with the given state. Clients shou
ld use one of the | |
114 * factory methods: [forErrors] and [forValue]. | |
115 * | |
116 * @param value the value of the expression | |
117 * @param errors the errors that should be reported for the expression(s) that
were evaluated | |
118 */ | |
119 EvaluationResult(Object value, List<AnalysisError> errors) { | |
120 this.value = value; | |
121 this._errors = errors; | |
122 } | |
123 | |
124 /** | |
125 * Return an array containing the errors that should be reported for the expre
ssion(s) that were | |
126 * evaluated. If there are no such errors, the array will be empty. The array
can be empty even if | |
127 * the expression is not a valid compile time constant if the errors would hav
e been reported by | |
128 * other parts of the analysis engine. | |
129 */ | |
130 List<AnalysisError> get errors => _errors == null ? AnalysisError.NO_ERRORS :
_errors; | |
131 | |
132 /** | |
133 * Return `true` if the expression is a compile-time constant expression that
would not | |
134 * throw an exception when evaluated. | |
135 * | |
136 * @return `true` if the expression is a valid compile-time constant expressio
n | |
137 */ | |
138 bool get isValid => _errors == null; | |
139 } | |
140 /** | |
141 * Instances of the class `ConstantFinder` are used to traverse the AST structur
es of all of | |
142 * the compilation units being resolved and build a table mapping constant varia
ble elements to the | |
143 * declarations of those variables. | |
144 */ | |
145 class ConstantFinder extends RecursiveASTVisitor<Object> { | |
146 | |
147 /** | |
148 * A table mapping constant variable elements to the declarations of those var
iables. | |
149 */ | |
150 final Map<VariableElement, VariableDeclaration> variableMap = new Map<Variable
Element, VariableDeclaration>(); | |
151 Object visitVariableDeclaration(VariableDeclaration node) { | |
152 super.visitVariableDeclaration(node); | |
153 Expression initializer = node.initializer; | |
154 if (initializer != null && node.isConst) { | |
155 VariableElement element = node.element; | |
156 if (element != null) { | |
157 variableMap[element] = node; | |
158 } | |
159 } | |
160 return null; | |
161 } | |
162 } | |
163 /** | |
164 * Instances of the class `ConstantValueComputer` compute the values of constant
variables in | |
165 * one or more compilation units. The expected usage pattern is for the compilat
ion units to be | |
166 * added to this computer using the method [add] and then for the method | |
167 * [computeValues] to invoked exactly once. Any use of an instance after invokin
g the | |
168 * method [computeValues] will result in unpredictable behavior. | |
169 */ | |
170 class ConstantValueComputer { | |
171 | |
172 /** | |
173 * The object used to find constant variables in the compilation units that we
re added. | |
174 */ | |
175 ConstantFinder _constantFinder = new ConstantFinder(); | |
176 | |
177 /** | |
178 * A graph in which the nodes are the constant variables and the edges are fro
m each variable to | |
179 * the other constant variables that are referenced in the head's initializer. | |
180 */ | |
181 DirectedGraph<VariableElement> _referenceGraph = new DirectedGraph<VariableEle
ment>(); | |
182 | |
183 /** | |
184 * A table mapping constant variables to the declarations of those variables. | |
185 */ | |
186 Map<VariableElement, VariableDeclaration> _declarationMap; | |
187 | |
188 /** | |
189 * Add the constant variables in the given compilation unit to the list of con
stant variables | |
190 * whose value needs to be computed. | |
191 * | |
192 * @param unit the compilation unit defining the constant variables to be adde
d | |
193 */ | |
194 void add(CompilationUnit unit) { | |
195 unit.accept(_constantFinder); | |
196 } | |
197 | |
198 /** | |
199 * Compute values for all of the constant variables in the compilation units t
hat were added. | |
200 */ | |
201 void computeValues() { | |
202 _declarationMap = _constantFinder.variableMap; | |
203 for (MapEntry<VariableElement, VariableDeclaration> entry in getMapEntrySet(
_declarationMap)) { | |
204 VariableElement element = entry.getKey(); | |
205 ReferenceFinder referenceFinder = new ReferenceFinder(element, _referenceG
raph); | |
206 _referenceGraph.addNode(element); | |
207 entry.getValue().initializer.accept(referenceFinder); | |
208 } | |
209 while (!_referenceGraph.isEmpty) { | |
210 VariableElement element = _referenceGraph.removeSink(); | |
211 while (element != null) { | |
212 computeValueFor(element); | |
213 element = _referenceGraph.removeSink(); | |
214 } | |
215 if (!_referenceGraph.isEmpty) { | |
216 List<VariableElement> variablesInCycle = _referenceGraph.findCycle(); | |
217 if (variablesInCycle == null) { | |
218 AnalysisEngine.instance.logger.logError("Exiting constant value comput
er with ${_referenceGraph.nodeCount} variables that are neither sinks no in a cy
cle"); | |
219 return; | |
220 } | |
221 for (VariableElement variable in variablesInCycle) { | |
222 generateCycleError(variablesInCycle, variable); | |
223 } | |
224 _referenceGraph.removeAllNodes(variablesInCycle); | |
225 } | |
226 } | |
227 } | |
228 | |
229 /** | |
230 * Compute a value for the given variable. | |
231 * | |
232 * @param variable the variable for which a value is to be computed | |
233 */ | |
234 void computeValueFor(VariableElement variable) { | |
235 VariableDeclaration declaration = _declarationMap[variable]; | |
236 if (declaration == null) { | |
237 return; | |
238 } | |
239 EvaluationResultImpl result = declaration.initializer.accept(new ConstantVis
itor()); | |
240 ((variable as VariableElementImpl)).evaluationResult = result; | |
241 if (result is ErrorResult) { | |
242 List<AnalysisError> errors = new List<AnalysisError>(); | |
243 for (ErrorResult_ErrorData data in ((result as ErrorResult)).errorData) { | |
244 ASTNode node = data.node; | |
245 Source source = variable.getAncestor(CompilationUnitElement).source; | |
246 errors.add(new AnalysisError.con2(source, node.offset, node.length, data
.errorCode, [])); | |
247 } | |
248 } | |
249 } | |
250 | |
251 /** | |
252 * Generate an error indicating that the given variable is not a valid compile
-time constant | |
253 * because it references at least one of the variables in the given cycle, eac
h of which directly | |
254 * or indirectly references the variable. | |
255 * | |
256 * @param variablesInCycle the variables in the cycle that includes the given
variable | |
257 * @param variable the variable that is not a valid compile-time constant | |
258 */ | |
259 void generateCycleError(List<VariableElement> variablesInCycle, VariableElemen
t variable) { | |
260 } | |
261 } | |
262 /** | |
263 * Instances of the class `ConstantVisitor` evaluate constant expressions to pro
duce their | |
264 * compile-time value. According to the Dart Language Specification: <blockquote
> A constant | |
265 * expression is one of the following: | |
266 * | |
267 * * A literal number. | |
268 * * A literal boolean. | |
269 * * A literal string where any interpolated expression is a compile-time consta
nt that evaluates | |
270 * to a numeric, string or boolean value or to `null`. | |
271 * * `null`. | |
272 * * A reference to a static constant variable. | |
273 * * An identifier expression that denotes a constant variable, a class or a typ
e parameter. | |
274 * * A constant constructor invocation. | |
275 * * A constant list literal. | |
276 * * A constant map literal. | |
277 * * A simple or qualified identifier denoting a top-level function or a static
method. | |
278 * * A parenthesized expression `(e)` where `e` is a constant expression. | |
279 * * An expression of one of the forms `identical(e1, e2)`, `e1 == e2`, | |
280 * `e1 != e2` where `e1` and `e2` are constant expressions that evaluate to a | |
281 * numeric, string or boolean value or to `null`. | |
282 * * An expression of one of the forms `!e`, `e1 && e2` or `e1 || e2`, where | |
283 * `e`, `e1` and `e2` are constant expressions that evaluate to a boolean value
or | |
284 * to `null`. | |
285 * * An expression of one of the forms `~e`, `e1 ^ e2`, `e1 & e2`, | |
286 * `e1 | e2`, `e1 >> e2` or `e1 << e2`, where `e`, `e1` and `e2` | |
287 * are constant expressions that evaluate to an integer value or to `null`. | |
288 * * An expression of one of the forms `-e`, `e1 + e2`, `e1 - e2`, | |
289 * `e1 * e2`, `e1 / e2`, `e1 ~/ e2`, `e1 > e2`, `e1 < e2`, | |
290 * `e1 >= e2`, `e1 <= e2` or `e1 % e2`, where `e`, `e1` and `e2` | |
291 * are constant expressions that evaluate to a numeric value or to `null`. | |
292 * | |
293 * </blockquote> | |
294 */ | |
295 class ConstantVisitor extends UnifyingASTVisitor<EvaluationResultImpl> { | |
296 EvaluationResultImpl visitAdjacentStrings(AdjacentStrings node) { | |
297 EvaluationResultImpl result = null; | |
298 for (StringLiteral string in node.strings) { | |
299 if (result == null) { | |
300 result = string.accept(this); | |
301 } else { | |
302 result = result.concatenate(node, string.accept(this)); | |
303 } | |
304 } | |
305 return result; | |
306 } | |
307 EvaluationResultImpl visitBinaryExpression(BinaryExpression node) { | |
308 EvaluationResultImpl leftResult = node.leftOperand.accept(this); | |
309 EvaluationResultImpl rightResult = node.rightOperand.accept(this); | |
310 TokenType operatorType = node.operator.type; | |
311 if (operatorType != TokenType.BANG_EQ && operatorType != TokenType.EQ_EQ) { | |
312 if (leftResult is ValidResult && ((leftResult as ValidResult)).isNull || r
ightResult is ValidResult && ((rightResult as ValidResult)).isNull) { | |
313 return error(node, CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION); | |
314 } | |
315 } | |
316 while (true) { | |
317 if (operatorType == TokenType.AMPERSAND) { | |
318 return leftResult.bitAnd(node, rightResult); | |
319 } else if (operatorType == TokenType.AMPERSAND_AMPERSAND) { | |
320 return leftResult.logicalAnd(node, rightResult); | |
321 } else if (operatorType == TokenType.BANG_EQ) { | |
322 return leftResult.notEqual(node, rightResult); | |
323 } else if (operatorType == TokenType.BAR) { | |
324 return leftResult.bitOr(node, rightResult); | |
325 } else if (operatorType == TokenType.BAR_BAR) { | |
326 return leftResult.logicalOr(node, rightResult); | |
327 } else if (operatorType == TokenType.CARET) { | |
328 return leftResult.bitXor(node, rightResult); | |
329 } else if (operatorType == TokenType.EQ_EQ) { | |
330 return leftResult.equalEqual(node, rightResult); | |
331 } else if (operatorType == TokenType.GT) { | |
332 return leftResult.greaterThan(node, rightResult); | |
333 } else if (operatorType == TokenType.GT_EQ) { | |
334 return leftResult.greaterThanOrEqual(node, rightResult); | |
335 } else if (operatorType == TokenType.GT_GT) { | |
336 return leftResult.shiftRight(node, rightResult); | |
337 } else if (operatorType == TokenType.LT) { | |
338 return leftResult.lessThan(node, rightResult); | |
339 } else if (operatorType == TokenType.LT_EQ) { | |
340 return leftResult.lessThanOrEqual(node, rightResult); | |
341 } else if (operatorType == TokenType.LT_LT) { | |
342 return leftResult.shiftLeft(node, rightResult); | |
343 } else if (operatorType == TokenType.MINUS) { | |
344 return leftResult.minus(node, rightResult); | |
345 } else if (operatorType == TokenType.PERCENT) { | |
346 return leftResult.remainder(node, rightResult); | |
347 } else if (operatorType == TokenType.PLUS) { | |
348 return leftResult.add(node, rightResult); | |
349 } else if (operatorType == TokenType.STAR) { | |
350 return leftResult.times(node, rightResult); | |
351 } else if (operatorType == TokenType.SLASH) { | |
352 return leftResult.divide(node, rightResult); | |
353 } else if (operatorType == TokenType.TILDE_SLASH) { | |
354 return leftResult.integerDivide(node, rightResult); | |
355 } | |
356 break; | |
357 } | |
358 return error(node, null); | |
359 } | |
360 EvaluationResultImpl visitBooleanLiteral(BooleanLiteral node) => node.value ?
ValidResult.RESULT_TRUE : ValidResult.RESULT_FALSE; | |
361 EvaluationResultImpl visitConditionalExpression(ConditionalExpression node) { | |
362 Expression condition = node.condition; | |
363 EvaluationResultImpl conditionResult = condition.accept(this); | |
364 conditionResult = conditionResult.applyBooleanConversion(condition); | |
365 if (conditionResult is ErrorResult) { | |
366 return conditionResult; | |
367 } | |
368 EvaluationResultImpl thenResult = node.thenExpression.accept(this); | |
369 if (thenResult is ErrorResult) { | |
370 return thenResult; | |
371 } | |
372 EvaluationResultImpl elseResult = node.elseExpression.accept(this); | |
373 if (elseResult is ErrorResult) { | |
374 return elseResult; | |
375 } | |
376 return (identical(conditionResult, ValidResult.RESULT_TRUE)) ? thenResult :
elseResult; | |
377 } | |
378 EvaluationResultImpl visitDoubleLiteral(DoubleLiteral node) => new ValidResult
(node.value); | |
379 EvaluationResultImpl visitInstanceCreationExpression(InstanceCreationExpressio
n node) { | |
380 if (!node.isConst) { | |
381 return error(node, null); | |
382 } | |
383 ConstructorElement constructor = node.staticElement; | |
384 if (constructor != null && constructor.isConst) { | |
385 node.argumentList.accept(this); | |
386 return ValidResult.RESULT_OBJECT; | |
387 } | |
388 return error(node, null); | |
389 } | |
390 EvaluationResultImpl visitIntegerLiteral(IntegerLiteral node) => new ValidResu
lt(node.value); | |
391 EvaluationResultImpl visitInterpolationExpression(InterpolationExpression node
) { | |
392 EvaluationResultImpl result = node.expression.accept(this); | |
393 return result.performToString(node); | |
394 } | |
395 EvaluationResultImpl visitInterpolationString(InterpolationString node) => new
ValidResult(node.value); | |
396 EvaluationResultImpl visitListLiteral(ListLiteral node) { | |
397 if (node.constKeyword == null) { | |
398 return new ErrorResult.con1(node, CompileTimeErrorCode.MISSING_CONST_IN_LI
ST_LITERAL); | |
399 } | |
400 ErrorResult result = null; | |
401 for (Expression element in node.elements) { | |
402 result = union(result, element.accept(this)); | |
403 } | |
404 if (result != null) { | |
405 return result; | |
406 } | |
407 return ValidResult.RESULT_OBJECT; | |
408 } | |
409 EvaluationResultImpl visitMapLiteral(MapLiteral node) { | |
410 if (node.constKeyword == null) { | |
411 return new ErrorResult.con1(node, CompileTimeErrorCode.MISSING_CONST_IN_MA
P_LITERAL); | |
412 } | |
413 ErrorResult result = null; | |
414 for (MapLiteralEntry entry in node.entries) { | |
415 result = union(result, entry.key.accept(this)); | |
416 result = union(result, entry.value.accept(this)); | |
417 } | |
418 if (result != null) { | |
419 return result; | |
420 } | |
421 return ValidResult.RESULT_OBJECT; | |
422 } | |
423 EvaluationResultImpl visitMethodInvocation(MethodInvocation node) { | |
424 Element element = node.methodName.staticElement; | |
425 if (element is FunctionElement) { | |
426 FunctionElement function = element as FunctionElement; | |
427 if (function.name == "identical") { | |
428 NodeList<Expression> arguments = node.argumentList.arguments; | |
429 if (arguments.length == 2) { | |
430 Element enclosingElement = function.enclosingElement; | |
431 if (enclosingElement is CompilationUnitElement) { | |
432 LibraryElement library = ((enclosingElement as CompilationUnitElemen
t)).library; | |
433 if (library.isDartCore) { | |
434 EvaluationResultImpl leftArgument = arguments[0].accept(this); | |
435 EvaluationResultImpl rightArgument = arguments[1].accept(this); | |
436 return leftArgument.equalEqual(node, rightArgument); | |
437 } | |
438 } | |
439 } | |
440 } | |
441 } | |
442 return error(node, null); | |
443 } | |
444 EvaluationResultImpl visitNamedExpression(NamedExpression node) => node.expres
sion.accept(this); | |
445 EvaluationResultImpl visitNode(ASTNode node) => error(node, null); | |
446 EvaluationResultImpl visitNullLiteral(NullLiteral node) => ValidResult.RESULT_
NULL; | |
447 EvaluationResultImpl visitParenthesizedExpression(ParenthesizedExpression node
) => node.expression.accept(this); | |
448 EvaluationResultImpl visitPrefixedIdentifier(PrefixedIdentifier node) { | |
449 SimpleIdentifier prefixNode = node.prefix; | |
450 Element prefixElement = prefixNode.staticElement; | |
451 if (prefixElement is! PrefixElement) { | |
452 EvaluationResultImpl prefixResult = prefixNode.accept(this); | |
453 if (prefixResult is! ValidResult) { | |
454 return error(node, null); | |
455 } | |
456 } | |
457 return getConstantValue(node, node.staticElement); | |
458 } | |
459 EvaluationResultImpl visitPrefixExpression(PrefixExpression node) { | |
460 EvaluationResultImpl operand = node.operand.accept(this); | |
461 if (operand is ValidResult && ((operand as ValidResult)).isNull) { | |
462 return error(node, CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION); | |
463 } | |
464 while (true) { | |
465 if (node.operator.type == TokenType.BANG) { | |
466 return operand.logicalNot(node); | |
467 } else if (node.operator.type == TokenType.TILDE) { | |
468 return operand.bitNot(node); | |
469 } else if (node.operator.type == TokenType.MINUS) { | |
470 return operand.negated(node); | |
471 } | |
472 break; | |
473 } | |
474 return error(node, null); | |
475 } | |
476 EvaluationResultImpl visitPropertyAccess(PropertyAccess node) => getConstantVa
lue(node, node.propertyName.staticElement); | |
477 EvaluationResultImpl visitSimpleIdentifier(SimpleIdentifier node) => getConsta
ntValue(node, node.staticElement); | |
478 EvaluationResultImpl visitSimpleStringLiteral(SimpleStringLiteral node) => new
ValidResult(node.value); | |
479 EvaluationResultImpl visitStringInterpolation(StringInterpolation node) { | |
480 EvaluationResultImpl result = null; | |
481 for (InterpolationElement element in node.elements) { | |
482 if (result == null) { | |
483 result = element.accept(this); | |
484 } else { | |
485 result = result.concatenate(node, element.accept(this)); | |
486 } | |
487 } | |
488 return result; | |
489 } | |
490 EvaluationResultImpl visitSymbolLiteral(SymbolLiteral node) => ValidResult.RES
ULT_SYMBOL; | |
491 | |
492 /** | |
493 * Return a result object representing an error associated with the given node
. | |
494 * | |
495 * @param node the AST node associated with the error | |
496 * @param code the error code indicating the nature of the error | |
497 * @return a result object representing an error associated with the given nod
e | |
498 */ | |
499 ErrorResult error(ASTNode node, ErrorCode code) => new ErrorResult.con1(node,
code == null ? CompileTimeErrorCode.INVALID_CONSTANT : code); | |
500 | |
501 /** | |
502 * Return the constant value of the static constant represented by the given e
lement. | |
503 * | |
504 * @param node the node to be used if an error needs to be reported | |
505 * @param element the element whose value is to be returned | |
506 * @return the constant value of the static constant | |
507 */ | |
508 EvaluationResultImpl getConstantValue(ASTNode node, Element element) { | |
509 if (element is PropertyAccessorElement) { | |
510 element = ((element as PropertyAccessorElement)).variable; | |
511 } | |
512 if (element is VariableElementImpl) { | |
513 VariableElementImpl variableElementImpl = element as VariableElementImpl; | |
514 EvaluationResultImpl value = variableElementImpl.evaluationResult; | |
515 if (variableElementImpl.isConst && value != null) { | |
516 return value; | |
517 } | |
518 } else if (element is ExecutableElement) { | |
519 if (((element as ExecutableElement)).isStatic) { | |
520 return new ValidResult(element); | |
521 } | |
522 } else if (element is ClassElement) { | |
523 return ValidResult.RESULT_OBJECT; | |
524 } | |
525 return error(node, null); | |
526 } | |
527 | |
528 /** | |
529 * Return the union of the errors encoded in the given results. | |
530 * | |
531 * @param leftResult the first set of errors, or `null` if there was no previo
us collection | |
532 * of errors | |
533 * @param rightResult the errors to be added to the collection, or a valid res
ult if there are no | |
534 * errors to be added | |
535 * @return the union of the errors encoded in the given results | |
536 */ | |
537 ErrorResult union(ErrorResult leftResult, EvaluationResultImpl rightResult) { | |
538 if (rightResult is ErrorResult) { | |
539 if (leftResult != null) { | |
540 return new ErrorResult.con2(leftResult, rightResult as ErrorResult); | |
541 } else { | |
542 return rightResult as ErrorResult; | |
543 } | |
544 } | |
545 return leftResult; | |
546 } | |
547 } | |
548 /** | |
549 * Instances of the class `DirectedGraph` implement a directed graph in which th
e nodes are | |
550 * arbitrary (client provided) objects and edges are represented implicitly. The
graph will allow an | |
551 * edge from any node to any other node, including itself, but will not represen
t multiple edges | |
552 * between the same pair of nodes. | |
553 * | |
554 * @param N the type of the nodes in the graph | |
555 */ | |
556 class DirectedGraph<N> { | |
557 | |
558 /** | |
559 * The table encoding the edges in the graph. An edge is represented by an ent
ry mapping the head | |
560 * to a set of tails. Nodes that are not the head of any edge are represented
by an entry mapping | |
561 * the node to an empty set of tails. | |
562 */ | |
563 Map<N, Set<N>> _edges = new Map<N, Set<N>>(); | |
564 | |
565 /** | |
566 * Add an edge from the given head node to the given tail node. Both nodes wil
l be a part of the | |
567 * graph after this method is invoked, whether or not they were before. | |
568 * | |
569 * @param head the node at the head of the edge | |
570 * @param tail the node at the tail of the edge | |
571 */ | |
572 void addEdge(N head, N tail) { | |
573 Set<N> tails = _edges[tail]; | |
574 if (tails == null) { | |
575 _edges[tail] = new Set<N>(); | |
576 } | |
577 tails = _edges[head]; | |
578 if (tails == null) { | |
579 tails = new Set<N>(); | |
580 _edges[head] = tails; | |
581 } | |
582 javaSetAdd(tails, tail); | |
583 } | |
584 | |
585 /** | |
586 * Add the given node to the set of nodes in the graph. | |
587 * | |
588 * @param node the node to be added | |
589 */ | |
590 void addNode(N node) { | |
591 Set<N> tails = _edges[node]; | |
592 if (tails == null) { | |
593 _edges[node] = new Set<N>(); | |
594 } | |
595 } | |
596 | |
597 /** | |
598 * Return a list of nodes that form a cycle, or `null` if there are no cycles
in this graph. | |
599 * | |
600 * @return a list of nodes that form a cycle | |
601 */ | |
602 List<N> findCycle() => null; | |
603 | |
604 /** | |
605 * Return the number of nodes in this graph. | |
606 * | |
607 * @return the number of nodes in this graph | |
608 */ | |
609 int get nodeCount => _edges.length; | |
610 | |
611 /** | |
612 * Return a set containing the tails of edges that have the given node as thei
r head. The set will | |
613 * be empty if there are no such edges or if the node is not part of the graph
. Clients must not | |
614 * modify the returned set. | |
615 * | |
616 * @param head the node at the head of all of the edges whose tails are to be
returned | |
617 * @return a set containing the tails of edges that have the given node as the
ir head | |
618 */ | |
619 Set<N> getTails(N head) { | |
620 Set<N> tails = _edges[head]; | |
621 if (tails == null) { | |
622 return new Set<N>(); | |
623 } | |
624 return tails; | |
625 } | |
626 | |
627 /** | |
628 * Return `true` if this graph is empty. | |
629 * | |
630 * @return `true` if this graph is empty | |
631 */ | |
632 bool get isEmpty => _edges.isEmpty; | |
633 | |
634 /** | |
635 * Remove all of the given nodes from this graph. As a consequence, any edges
for which those | |
636 * nodes were either a head or a tail will also be removed. | |
637 * | |
638 * @param nodes the nodes to be removed | |
639 */ | |
640 void removeAllNodes(List<N> nodes) { | |
641 for (N node in nodes) { | |
642 removeNode(node); | |
643 } | |
644 } | |
645 | |
646 /** | |
647 * Remove the edge from the given head node to the given tail node. If there w
as no such edge then | |
648 * the graph will be unmodified: the number of edges will be the same and the
set of nodes will be | |
649 * the same (neither node will either be added or removed). | |
650 * | |
651 * @param head the node at the head of the edge | |
652 * @param tail the node at the tail of the edge | |
653 * @return `true` if the graph was modified as a result of this operation | |
654 */ | |
655 void removeEdge(N head, N tail) { | |
656 Set<N> tails = _edges[head]; | |
657 if (tails != null) { | |
658 tails.remove(tail); | |
659 } | |
660 } | |
661 | |
662 /** | |
663 * Remove the given node from this graph. As a consequence, any edges for whic
h that node was | |
664 * either a head or a tail will also be removed. | |
665 * | |
666 * @param node the node to be removed | |
667 */ | |
668 void removeNode(N node) { | |
669 _edges.remove(node); | |
670 for (Set<N> tails in _edges.values) { | |
671 tails.remove(node); | |
672 } | |
673 } | |
674 | |
675 /** | |
676 * Find one node (referred to as a sink node) that has no outgoing edges (that
is, for which there | |
677 * are no edges that have that node as the head of the edge) and remove it fro
m this graph. Return | |
678 * the node that was removed, or `null` if there are no such nodes either beca
use the graph | |
679 * is empty or because every node in the graph has at least one outgoing edge.
As a consequence of | |
680 * removing the node from the graph any edges for which that node was a tail w
ill also be removed. | |
681 * | |
682 * @return the sink node that was removed | |
683 */ | |
684 N removeSink() { | |
685 N sink = findSink(); | |
686 if (sink == null) { | |
687 return null; | |
688 } | |
689 removeNode(sink); | |
690 return sink; | |
691 } | |
692 | |
693 /** | |
694 * Return one node that has no outgoing edges (that is, for which there are no
edges that have | |
695 * that node as the head of the edge), or `null` if there are no such nodes. | |
696 * | |
697 * @return a sink node | |
698 */ | |
699 N findSink() { | |
700 for (N key in _edges.keys) { | |
701 if (_edges[key].isEmpty) return key; | |
702 } | |
703 return null; | |
704 } | |
705 } | |
706 /** | |
707 * Instances of the class `ErrorResult` represent the result of evaluating an ex
pression that | |
708 * is not a valid compile time constant. | |
709 */ | |
710 class ErrorResult extends EvaluationResultImpl { | |
711 | |
712 /** | |
713 * The errors that prevent the expression from being a valid compile time cons
tant. | |
714 */ | |
715 final List<ErrorResult_ErrorData> errorData = new List<ErrorResult_ErrorData>(
); | |
716 | |
717 /** | |
718 * Initialize a newly created result representing the error with the given cod
e reported against | |
719 * the given node. | |
720 * | |
721 * @param node the node against which the error should be reported | |
722 * @param errorCode the error code for the error to be generated | |
723 */ | |
724 ErrorResult.con1(ASTNode node, ErrorCode errorCode) { | |
725 errorData.add(new ErrorResult_ErrorData(node, errorCode)); | |
726 } | |
727 | |
728 /** | |
729 * Initialize a newly created result to represent the union of the errors in t
he given result | |
730 * objects. | |
731 * | |
732 * @param firstResult the first set of results being merged | |
733 * @param secondResult the second set of results being merged | |
734 */ | |
735 ErrorResult.con2(ErrorResult firstResult, ErrorResult secondResult) { | |
736 errorData.addAll(firstResult.errorData); | |
737 errorData.addAll(secondResult.errorData); | |
738 } | |
739 EvaluationResultImpl add(BinaryExpression node, EvaluationResultImpl rightOper
and) => rightOperand.addToError(node, this); | |
740 EvaluationResultImpl applyBooleanConversion(ASTNode node) => this; | |
741 EvaluationResultImpl bitAnd(BinaryExpression node, EvaluationResultImpl rightO
perand) => rightOperand.bitAndError(node, this); | |
742 EvaluationResultImpl bitNot(Expression node) => this; | |
743 EvaluationResultImpl bitOr(BinaryExpression node, EvaluationResultImpl rightOp
erand) => rightOperand.bitOrError(node, this); | |
744 EvaluationResultImpl bitXor(BinaryExpression node, EvaluationResultImpl rightO
perand) => rightOperand.bitXorError(node, this); | |
745 EvaluationResultImpl concatenate(Expression node, EvaluationResultImpl rightOp
erand) => rightOperand.concatenateError(node, this); | |
746 EvaluationResultImpl divide(BinaryExpression node, EvaluationResultImpl rightO
perand) => rightOperand.divideError(node, this); | |
747 EvaluationResultImpl equalEqual(Expression node, EvaluationResultImpl rightOpe
rand) => rightOperand.equalEqualError(node, this); | |
748 bool equalValues(EvaluationResultImpl result) => false; | |
749 EvaluationResultImpl greaterThan(BinaryExpression node, EvaluationResultImpl r
ightOperand) => rightOperand.greaterThanError(node, this); | |
750 EvaluationResultImpl greaterThanOrEqual(BinaryExpression node, EvaluationResul
tImpl rightOperand) => rightOperand.greaterThanOrEqualError(node, this); | |
751 EvaluationResultImpl integerDivide(BinaryExpression node, EvaluationResultImpl
rightOperand) => rightOperand.integerDivideError(node, this); | |
752 EvaluationResultImpl integerDivideValid(BinaryExpression node, ValidResult lef
tOperand) => this; | |
753 EvaluationResultImpl lessThan(BinaryExpression node, EvaluationResultImpl righ
tOperand) => rightOperand.lessThanError(node, this); | |
754 EvaluationResultImpl lessThanOrEqual(BinaryExpression node, EvaluationResultIm
pl rightOperand) => rightOperand.lessThanOrEqualError(node, this); | |
755 EvaluationResultImpl logicalAnd(BinaryExpression node, EvaluationResultImpl ri
ghtOperand) => rightOperand.logicalAndError(node, this); | |
756 EvaluationResultImpl logicalNot(Expression node) => this; | |
757 EvaluationResultImpl logicalOr(BinaryExpression node, EvaluationResultImpl rig
htOperand) => rightOperand.logicalOrError(node, this); | |
758 EvaluationResultImpl minus(BinaryExpression node, EvaluationResultImpl rightOp
erand) => rightOperand.minusError(node, this); | |
759 EvaluationResultImpl negated(Expression node) => this; | |
760 EvaluationResultImpl notEqual(BinaryExpression node, EvaluationResultImpl righ
tOperand) => rightOperand.notEqualError(node, this); | |
761 EvaluationResultImpl performToString(ASTNode node) => this; | |
762 EvaluationResultImpl remainder(BinaryExpression node, EvaluationResultImpl rig
htOperand) => rightOperand.remainderError(node, this); | |
763 EvaluationResultImpl shiftLeft(BinaryExpression node, EvaluationResultImpl rig
htOperand) => rightOperand.shiftLeftError(node, this); | |
764 EvaluationResultImpl shiftRight(BinaryExpression node, EvaluationResultImpl ri
ghtOperand) => rightOperand.shiftRightError(node, this); | |
765 EvaluationResultImpl times(BinaryExpression node, EvaluationResultImpl rightOp
erand) => rightOperand.timesError(node, this); | |
766 EvaluationResultImpl addToError(BinaryExpression node, ErrorResult leftOperand
) => new ErrorResult.con2(this, leftOperand); | |
767 EvaluationResultImpl addToValid(BinaryExpression node, ValidResult leftOperand
) => this; | |
768 EvaluationResultImpl bitAndError(BinaryExpression node, ErrorResult leftOperan
d) => new ErrorResult.con2(this, leftOperand); | |
769 EvaluationResultImpl bitAndValid(BinaryExpression node, ValidResult leftOperan
d) => this; | |
770 EvaluationResultImpl bitOrError(BinaryExpression node, ErrorResult leftOperand
) => new ErrorResult.con2(this, leftOperand); | |
771 EvaluationResultImpl bitOrValid(BinaryExpression node, ValidResult leftOperand
) => this; | |
772 EvaluationResultImpl bitXorError(BinaryExpression node, ErrorResult leftOperan
d) => new ErrorResult.con2(this, leftOperand); | |
773 EvaluationResultImpl bitXorValid(BinaryExpression node, ValidResult leftOperan
d) => this; | |
774 EvaluationResultImpl concatenateError(Expression node, ErrorResult leftOperand
) => new ErrorResult.con2(this, leftOperand); | |
775 EvaluationResultImpl concatenateValid(Expression node, ValidResult leftOperand
) => this; | |
776 EvaluationResultImpl divideError(BinaryExpression node, ErrorResult leftOperan
d) => new ErrorResult.con2(this, leftOperand); | |
777 EvaluationResultImpl divideValid(BinaryExpression node, ValidResult leftOperan
d) => this; | |
778 EvaluationResultImpl equalEqualError(Expression node, ErrorResult leftOperand)
=> new ErrorResult.con2(this, leftOperand); | |
779 EvaluationResultImpl equalEqualValid(Expression node, ValidResult leftOperand)
=> this; | |
780 EvaluationResultImpl greaterThanError(BinaryExpression node, ErrorResult leftO
perand) => new ErrorResult.con2(this, leftOperand); | |
781 EvaluationResultImpl greaterThanOrEqualError(BinaryExpression node, ErrorResul
t leftOperand) => new ErrorResult.con2(this, leftOperand); | |
782 EvaluationResultImpl greaterThanOrEqualValid(BinaryExpression node, ValidResul
t leftOperand) => this; | |
783 EvaluationResultImpl greaterThanValid(BinaryExpression node, ValidResult leftO
perand) => this; | |
784 EvaluationResultImpl integerDivideError(BinaryExpression node, ErrorResult lef
tOperand) => new ErrorResult.con2(this, leftOperand); | |
785 EvaluationResultImpl lessThanError(BinaryExpression node, ErrorResult leftOper
and) => new ErrorResult.con2(this, leftOperand); | |
786 EvaluationResultImpl lessThanOrEqualError(BinaryExpression node, ErrorResult l
eftOperand) => new ErrorResult.con2(this, leftOperand); | |
787 EvaluationResultImpl lessThanOrEqualValid(BinaryExpression node, ValidResult l
eftOperand) => this; | |
788 EvaluationResultImpl lessThanValid(BinaryExpression node, ValidResult leftOper
and) => this; | |
789 EvaluationResultImpl logicalAndError(BinaryExpression node, ErrorResult leftOp
erand) => new ErrorResult.con2(this, leftOperand); | |
790 EvaluationResultImpl logicalAndValid(BinaryExpression node, ValidResult leftOp
erand) => this; | |
791 EvaluationResultImpl logicalOrError(BinaryExpression node, ErrorResult leftOpe
rand) => new ErrorResult.con2(this, leftOperand); | |
792 EvaluationResultImpl logicalOrValid(BinaryExpression node, ValidResult leftOpe
rand) => this; | |
793 EvaluationResultImpl minusError(BinaryExpression node, ErrorResult leftOperand
) => new ErrorResult.con2(this, leftOperand); | |
794 EvaluationResultImpl minusValid(BinaryExpression node, ValidResult leftOperand
) => this; | |
795 EvaluationResultImpl notEqualError(BinaryExpression node, ErrorResult leftOper
and) => new ErrorResult.con2(this, leftOperand); | |
796 EvaluationResultImpl notEqualValid(BinaryExpression node, ValidResult leftOper
and) => this; | |
797 EvaluationResultImpl remainderError(BinaryExpression node, ErrorResult leftOpe
rand) => new ErrorResult.con2(this, leftOperand); | |
798 EvaluationResultImpl remainderValid(BinaryExpression node, ValidResult leftOpe
rand) => this; | |
799 EvaluationResultImpl shiftLeftError(BinaryExpression node, ErrorResult leftOpe
rand) => new ErrorResult.con2(this, leftOperand); | |
800 EvaluationResultImpl shiftLeftValid(BinaryExpression node, ValidResult leftOpe
rand) => this; | |
801 EvaluationResultImpl shiftRightError(BinaryExpression node, ErrorResult leftOp
erand) => new ErrorResult.con2(this, leftOperand); | |
802 EvaluationResultImpl shiftRightValid(BinaryExpression node, ValidResult leftOp
erand) => this; | |
803 EvaluationResultImpl timesError(BinaryExpression node, ErrorResult leftOperand
) => new ErrorResult.con2(this, leftOperand); | |
804 EvaluationResultImpl timesValid(BinaryExpression node, ValidResult leftOperand
) => this; | |
805 } | |
806 class ErrorResult_ErrorData { | |
807 | |
808 /** | |
809 * The node against which the error should be reported. | |
810 */ | |
811 ASTNode node; | |
812 | |
813 /** | |
814 * The error code for the error to be generated. | |
815 */ | |
816 ErrorCode errorCode; | |
817 | |
818 /** | |
819 * Initialize a newly created data holder to represent the error with the give
n code reported | |
820 * against the given node. | |
821 * | |
822 * @param node the node against which the error should be reported | |
823 * @param errorCode the error code for the error to be generated | |
824 */ | |
825 ErrorResult_ErrorData(ASTNode node, ErrorCode errorCode) { | |
826 this.node = node; | |
827 this.errorCode = errorCode; | |
828 } | |
829 } | |
830 /** | |
831 * Instances of the class `InternalResult` represent the result of attempting to
evaluate a | |
832 * expression. | |
833 */ | |
834 abstract class EvaluationResultImpl { | |
835 EvaluationResultImpl add(BinaryExpression node, EvaluationResultImpl rightOper
and); | |
836 | |
837 /** | |
838 * Return the result of applying boolean conversion to this result. | |
839 * | |
840 * @param node the node against which errors should be reported | |
841 * @return the result of applying boolean conversion to the given value | |
842 */ | |
843 EvaluationResultImpl applyBooleanConversion(ASTNode node); | |
844 EvaluationResultImpl bitAnd(BinaryExpression node, EvaluationResultImpl rightO
perand); | |
845 EvaluationResultImpl bitNot(Expression node); | |
846 EvaluationResultImpl bitOr(BinaryExpression node, EvaluationResultImpl rightOp
erand); | |
847 EvaluationResultImpl bitXor(BinaryExpression node, EvaluationResultImpl rightO
perand); | |
848 EvaluationResultImpl concatenate(Expression node, EvaluationResultImpl rightOp
erand); | |
849 EvaluationResultImpl divide(BinaryExpression node, EvaluationResultImpl rightO
perand); | |
850 EvaluationResultImpl equalEqual(Expression node, EvaluationResultImpl rightOpe
rand); | |
851 bool equalValues(EvaluationResultImpl result); | |
852 EvaluationResultImpl greaterThan(BinaryExpression node, EvaluationResultImpl r
ightOperand); | |
853 EvaluationResultImpl greaterThanOrEqual(BinaryExpression node, EvaluationResul
tImpl rightOperand); | |
854 EvaluationResultImpl integerDivide(BinaryExpression node, EvaluationResultImpl
rightOperand); | |
855 EvaluationResultImpl lessThan(BinaryExpression node, EvaluationResultImpl righ
tOperand); | |
856 EvaluationResultImpl lessThanOrEqual(BinaryExpression node, EvaluationResultIm
pl rightOperand); | |
857 EvaluationResultImpl logicalAnd(BinaryExpression node, EvaluationResultImpl ri
ghtOperand); | |
858 EvaluationResultImpl logicalNot(Expression node); | |
859 EvaluationResultImpl logicalOr(BinaryExpression node, EvaluationResultImpl rig
htOperand); | |
860 EvaluationResultImpl minus(BinaryExpression node, EvaluationResultImpl rightOp
erand); | |
861 EvaluationResultImpl negated(Expression node); | |
862 EvaluationResultImpl notEqual(BinaryExpression node, EvaluationResultImpl righ
tOperand); | |
863 EvaluationResultImpl performToString(ASTNode node); | |
864 EvaluationResultImpl remainder(BinaryExpression node, EvaluationResultImpl rig
htOperand); | |
865 EvaluationResultImpl shiftLeft(BinaryExpression node, EvaluationResultImpl rig
htOperand); | |
866 EvaluationResultImpl shiftRight(BinaryExpression node, EvaluationResultImpl ri
ghtOperand); | |
867 EvaluationResultImpl times(BinaryExpression node, EvaluationResultImpl rightOp
erand); | |
868 EvaluationResultImpl addToError(BinaryExpression node, ErrorResult leftOperand
); | |
869 EvaluationResultImpl addToValid(BinaryExpression node, ValidResult leftOperand
); | |
870 EvaluationResultImpl bitAndError(BinaryExpression node, ErrorResult leftOperan
d); | |
871 EvaluationResultImpl bitAndValid(BinaryExpression node, ValidResult leftOperan
d); | |
872 EvaluationResultImpl bitOrError(BinaryExpression node, ErrorResult leftOperand
); | |
873 EvaluationResultImpl bitOrValid(BinaryExpression node, ValidResult leftOperand
); | |
874 EvaluationResultImpl bitXorError(BinaryExpression node, ErrorResult leftOperan
d); | |
875 EvaluationResultImpl bitXorValid(BinaryExpression node, ValidResult leftOperan
d); | |
876 EvaluationResultImpl concatenateError(Expression node, ErrorResult leftOperand
); | |
877 EvaluationResultImpl concatenateValid(Expression node, ValidResult leftOperand
); | |
878 EvaluationResultImpl divideError(BinaryExpression node, ErrorResult leftOperan
d); | |
879 EvaluationResultImpl divideValid(BinaryExpression node, ValidResult leftOperan
d); | |
880 EvaluationResultImpl equalEqualError(Expression node, ErrorResult leftOperand)
; | |
881 EvaluationResultImpl equalEqualValid(Expression node, ValidResult leftOperand)
; | |
882 EvaluationResultImpl greaterThanError(BinaryExpression node, ErrorResult leftO
perand); | |
883 EvaluationResultImpl greaterThanOrEqualError(BinaryExpression node, ErrorResul
t leftOperand); | |
884 EvaluationResultImpl greaterThanOrEqualValid(BinaryExpression node, ValidResul
t leftOperand); | |
885 EvaluationResultImpl greaterThanValid(BinaryExpression node, ValidResult leftO
perand); | |
886 EvaluationResultImpl integerDivideError(BinaryExpression node, ErrorResult lef
tOperand); | |
887 EvaluationResultImpl integerDivideValid(BinaryExpression node, ValidResult lef
tOperand); | |
888 EvaluationResultImpl lessThanError(BinaryExpression node, ErrorResult leftOper
and); | |
889 EvaluationResultImpl lessThanOrEqualError(BinaryExpression node, ErrorResult l
eftOperand); | |
890 EvaluationResultImpl lessThanOrEqualValid(BinaryExpression node, ValidResult l
eftOperand); | |
891 EvaluationResultImpl lessThanValid(BinaryExpression node, ValidResult leftOper
and); | |
892 EvaluationResultImpl logicalAndError(BinaryExpression node, ErrorResult leftOp
erand); | |
893 EvaluationResultImpl logicalAndValid(BinaryExpression node, ValidResult leftOp
erand); | |
894 EvaluationResultImpl logicalOrError(BinaryExpression node, ErrorResult leftOpe
rand); | |
895 EvaluationResultImpl logicalOrValid(BinaryExpression node, ValidResult leftOpe
rand); | |
896 EvaluationResultImpl minusError(BinaryExpression node, ErrorResult leftOperand
); | |
897 EvaluationResultImpl minusValid(BinaryExpression node, ValidResult leftOperand
); | |
898 EvaluationResultImpl notEqualError(BinaryExpression node, ErrorResult leftOper
and); | |
899 EvaluationResultImpl notEqualValid(BinaryExpression node, ValidResult leftOper
and); | |
900 EvaluationResultImpl remainderError(BinaryExpression node, ErrorResult leftOpe
rand); | |
901 EvaluationResultImpl remainderValid(BinaryExpression node, ValidResult leftOpe
rand); | |
902 EvaluationResultImpl shiftLeftError(BinaryExpression node, ErrorResult leftOpe
rand); | |
903 EvaluationResultImpl shiftLeftValid(BinaryExpression node, ValidResult leftOpe
rand); | |
904 EvaluationResultImpl shiftRightError(BinaryExpression node, ErrorResult leftOp
erand); | |
905 EvaluationResultImpl shiftRightValid(BinaryExpression node, ValidResult leftOp
erand); | |
906 EvaluationResultImpl timesError(BinaryExpression node, ErrorResult leftOperand
); | |
907 EvaluationResultImpl timesValid(BinaryExpression node, ValidResult leftOperand
); | |
908 } | |
909 /** | |
910 * Instances of the class `ReferenceFinder` add reference information for a give
n variable to | |
911 * the bi-directional mapping used to order the evaluation of constants. | |
912 */ | |
913 class ReferenceFinder extends RecursiveASTVisitor<Object> { | |
914 | |
915 /** | |
916 * The element representing the variable whose initializer will be visited. | |
917 */ | |
918 VariableElement _source; | |
919 | |
920 /** | |
921 * A graph in which the nodes are the constant variables and the edges are fro
m each variable to | |
922 * the other constant variables that are referenced in the head's initializer. | |
923 */ | |
924 DirectedGraph<VariableElement> _referenceGraph; | |
925 | |
926 /** | |
927 * Initialize a newly created reference finder to find references from the giv
en variable to other | |
928 * variables and to add those references to the given graph. | |
929 * | |
930 * @param source the element representing the variable whose initializer will
be visited | |
931 * @param referenceGraph a graph recording which variables (heads) reference w
hich other variables | |
932 * (tails) in their initializers | |
933 */ | |
934 ReferenceFinder(VariableElement source, DirectedGraph<VariableElement> referen
ceGraph) { | |
935 this._source = source; | |
936 this._referenceGraph = referenceGraph; | |
937 } | |
938 Object visitSimpleIdentifier(SimpleIdentifier node) { | |
939 Element element = node.staticElement; | |
940 if (element is PropertyAccessorElement) { | |
941 element = ((element as PropertyAccessorElement)).variable; | |
942 } | |
943 if (element is VariableElement) { | |
944 VariableElement variable = element as VariableElement; | |
945 if (variable.isConst) { | |
946 _referenceGraph.addEdge(_source, variable); | |
947 } | |
948 } | |
949 return null; | |
950 } | |
951 } | |
952 /** | |
953 * Instances of the class `ValidResult` represent the result of attempting to ev
aluate a valid | |
954 * compile time constant expression. | |
955 */ | |
956 class ValidResult extends EvaluationResultImpl { | |
957 | |
958 /** | |
959 * A result object representing the value 'false'. | |
960 */ | |
961 static ValidResult RESULT_FALSE = new ValidResult(false); | |
962 | |
963 /** | |
964 * A result object representing the an object without specific type on which n
o further operations | |
965 * can be performed. | |
966 */ | |
967 static ValidResult RESULT_DYNAMIC = new ValidResult(null); | |
968 | |
969 /** | |
970 * A result object representing the an arbitrary integer on which no further o
perations can be | |
971 * performed. | |
972 */ | |
973 static ValidResult RESULT_INT = new ValidResult(0); | |
974 | |
975 /** | |
976 * A result object representing the `null` value. | |
977 */ | |
978 static ValidResult RESULT_NULL = new ValidResult(null); | |
979 | |
980 /** | |
981 * A result object representing the an arbitrary numeric on which no further o
perations can be | |
982 * performed. | |
983 */ | |
984 static ValidResult RESULT_NUM = new ValidResult(null); | |
985 | |
986 /** | |
987 * A result object representing the an arbitrary boolean on which no further o
perations can be | |
988 * performed. | |
989 */ | |
990 static ValidResult RESULT_BOOL = new ValidResult(null); | |
991 | |
992 /** | |
993 * A result object representing the an arbitrary object on which no further op
erations can be | |
994 * performed. | |
995 */ | |
996 static ValidResult RESULT_OBJECT = new ValidResult(new Object()); | |
997 | |
998 /** | |
999 * A result object representing the an arbitrary symbol on which no further op
erations can be | |
1000 * performed. | |
1001 */ | |
1002 static ValidResult RESULT_SYMBOL = new ValidResult(new Object()); | |
1003 | |
1004 /** | |
1005 * A result object representing the an arbitrary string on which no further op
erations can be | |
1006 * performed. | |
1007 */ | |
1008 static ValidResult RESULT_STRING = new ValidResult("<string>"); | |
1009 | |
1010 /** | |
1011 * A result object representing the value 'true'. | |
1012 */ | |
1013 static ValidResult RESULT_TRUE = new ValidResult(true); | |
1014 | |
1015 /** | |
1016 * The value of the expression. | |
1017 */ | |
1018 Object value; | |
1019 | |
1020 /** | |
1021 * Initialize a newly created result to represent the given value. | |
1022 * | |
1023 * @param value the value of the expression | |
1024 */ | |
1025 ValidResult(Object value) { | |
1026 this.value = value; | |
1027 } | |
1028 EvaluationResultImpl add(BinaryExpression node, EvaluationResultImpl rightOper
and) => rightOperand.addToValid(node, this); | |
1029 | |
1030 /** | |
1031 * Return the result of applying boolean conversion to this result. | |
1032 * | |
1033 * @param node the node against which errors should be reported | |
1034 * @return the result of applying boolean conversion to the given value | |
1035 */ | |
1036 EvaluationResultImpl applyBooleanConversion(ASTNode node) => booleanConversion
(node, value); | |
1037 EvaluationResultImpl bitAnd(BinaryExpression node, EvaluationResultImpl rightO
perand) => rightOperand.bitAndValid(node, this); | |
1038 EvaluationResultImpl bitNot(Expression node) { | |
1039 if (isSomeInt) { | |
1040 return RESULT_INT; | |
1041 } | |
1042 if (value == null) { | |
1043 return error(node); | |
1044 } else if (value is int) { | |
1045 return valueOf(~((value as int))); | |
1046 } | |
1047 return error(node); | |
1048 } | |
1049 EvaluationResultImpl bitOr(BinaryExpression node, EvaluationResultImpl rightOp
erand) => rightOperand.bitOrValid(node, this); | |
1050 EvaluationResultImpl bitXor(BinaryExpression node, EvaluationResultImpl rightO
perand) => rightOperand.bitXorValid(node, this); | |
1051 EvaluationResultImpl concatenate(Expression node, EvaluationResultImpl rightOp
erand) => rightOperand.concatenateValid(node, this); | |
1052 EvaluationResultImpl divide(BinaryExpression node, EvaluationResultImpl rightO
perand) => rightOperand.divideValid(node, this); | |
1053 EvaluationResultImpl equalEqual(Expression node, EvaluationResultImpl rightOpe
rand) => rightOperand.equalEqualValid(node, this); | |
1054 bool equalValues(EvaluationResultImpl result) => identical(equalEqual(null, re
sult), RESULT_TRUE); | |
1055 EvaluationResultImpl greaterThan(BinaryExpression node, EvaluationResultImpl r
ightOperand) => rightOperand.greaterThanValid(node, this); | |
1056 EvaluationResultImpl greaterThanOrEqual(BinaryExpression node, EvaluationResul
tImpl rightOperand) => rightOperand.greaterThanOrEqualValid(node, this); | |
1057 EvaluationResultImpl integerDivide(BinaryExpression node, EvaluationResultImpl
rightOperand) => rightOperand.integerDivideValid(node, this); | |
1058 EvaluationResultImpl lessThan(BinaryExpression node, EvaluationResultImpl righ
tOperand) => rightOperand.lessThanValid(node, this); | |
1059 EvaluationResultImpl lessThanOrEqual(BinaryExpression node, EvaluationResultIm
pl rightOperand) => rightOperand.lessThanOrEqualValid(node, this); | |
1060 EvaluationResultImpl logicalAnd(BinaryExpression node, EvaluationResultImpl ri
ghtOperand) => rightOperand.logicalAndValid(node, this); | |
1061 EvaluationResultImpl logicalNot(Expression node) { | |
1062 if (isSomeBool) { | |
1063 return RESULT_BOOL; | |
1064 } | |
1065 if (value == null) { | |
1066 return RESULT_TRUE; | |
1067 } else if (value is bool) { | |
1068 return ((value as bool)) ? RESULT_FALSE : RESULT_TRUE; | |
1069 } | |
1070 return error(node); | |
1071 } | |
1072 EvaluationResultImpl logicalOr(BinaryExpression node, EvaluationResultImpl rig
htOperand) => rightOperand.logicalOrValid(node, this); | |
1073 EvaluationResultImpl minus(BinaryExpression node, EvaluationResultImpl rightOp
erand) => rightOperand.minusValid(node, this); | |
1074 EvaluationResultImpl negated(Expression node) { | |
1075 if (isSomeNum) { | |
1076 return RESULT_INT; | |
1077 } | |
1078 if (value == null) { | |
1079 return error(node); | |
1080 } else if (value is int) { | |
1081 return valueOf(-((value as int))); | |
1082 } else if (value is double) { | |
1083 return valueOf3(-((value as double))); | |
1084 } | |
1085 return error(node); | |
1086 } | |
1087 EvaluationResultImpl notEqual(BinaryExpression node, EvaluationResultImpl righ
tOperand) => rightOperand.notEqualValid(node, this); | |
1088 EvaluationResultImpl performToString(ASTNode node) { | |
1089 if (value == null) { | |
1090 return valueOf4("null"); | |
1091 } else if (value is bool) { | |
1092 return valueOf4(((value as bool)).toString()); | |
1093 } else if (value is int) { | |
1094 return valueOf4(((value as int)).toString()); | |
1095 } else if (value is double) { | |
1096 return valueOf4(((value as double)).toString()); | |
1097 } else if (value is String) { | |
1098 return this; | |
1099 } else if (isSomeBool) { | |
1100 return valueOf4("<some bool>"); | |
1101 } else if (isSomeInt) { | |
1102 return valueOf4("<some int>"); | |
1103 } else if (isSomeNum) { | |
1104 return valueOf4("<some num>"); | |
1105 } | |
1106 return error(node); | |
1107 } | |
1108 EvaluationResultImpl remainder(BinaryExpression node, EvaluationResultImpl rig
htOperand) => rightOperand.remainderValid(node, this); | |
1109 EvaluationResultImpl shiftLeft(BinaryExpression node, EvaluationResultImpl rig
htOperand) => rightOperand.shiftLeftValid(node, this); | |
1110 EvaluationResultImpl shiftRight(BinaryExpression node, EvaluationResultImpl ri
ghtOperand) => rightOperand.shiftRightValid(node, this); | |
1111 EvaluationResultImpl times(BinaryExpression node, EvaluationResultImpl rightOp
erand) => rightOperand.timesValid(node, this); | |
1112 String toString() { | |
1113 if (value == null) { | |
1114 return "null"; | |
1115 } | |
1116 return value.toString(); | |
1117 } | |
1118 EvaluationResultImpl addToError(BinaryExpression node, ErrorResult leftOperand
) => leftOperand; | |
1119 EvaluationResultImpl addToValid(BinaryExpression node, ValidResult leftOperand
) { | |
1120 if (!isAnyNum || !leftOperand.isAnyNum) { | |
1121 return error2(node, CompileTimeErrorCode.CONST_EVAL_TYPE_NUM); | |
1122 } | |
1123 if (isSomeInt || leftOperand.isSomeInt) { | |
1124 return RESULT_INT; | |
1125 } else if (isSomeNum || leftOperand.isSomeNum) { | |
1126 return RESULT_NUM; | |
1127 } | |
1128 Object leftValue = leftOperand.value; | |
1129 if (leftValue == null) { | |
1130 return error(node.leftOperand); | |
1131 } else if (value == null) { | |
1132 return error(node.rightOperand); | |
1133 } else if (leftValue is int) { | |
1134 if (value is int) { | |
1135 return valueOf(((leftValue as int)) + (value as int)); | |
1136 } else if (value is double) { | |
1137 return valueOf3(((leftValue as int)).toDouble() + ((value as double))); | |
1138 } | |
1139 } else if (leftValue is double) { | |
1140 if (value is int) { | |
1141 return valueOf3(((leftValue as double)) + ((value as int)).toDouble()); | |
1142 } else if (value is double) { | |
1143 return valueOf3(((leftValue as double)) + ((value as double))); | |
1144 } | |
1145 } else if (leftValue is String) { | |
1146 if (value is String) { | |
1147 return valueOf4("${((leftValue as String))}${((value as String))}"); | |
1148 } | |
1149 } | |
1150 return error(node); | |
1151 } | |
1152 EvaluationResultImpl bitAndError(BinaryExpression node, ErrorResult leftOperan
d) => leftOperand; | |
1153 EvaluationResultImpl bitAndValid(BinaryExpression node, ValidResult leftOperan
d) { | |
1154 if (!isAnyInt || !leftOperand.isAnyInt) { | |
1155 return error2(node, CompileTimeErrorCode.CONST_EVAL_TYPE_INT); | |
1156 } | |
1157 if (isSomeInt || leftOperand.isSomeInt) { | |
1158 return RESULT_INT; | |
1159 } | |
1160 Object leftValue = leftOperand.value; | |
1161 if (leftValue == null) { | |
1162 return error(node.leftOperand); | |
1163 } else if (value == null) { | |
1164 return error(node.rightOperand); | |
1165 } else if (leftValue is int) { | |
1166 if (value is int) { | |
1167 return valueOf(((leftValue as int)) & (value as int)); | |
1168 } | |
1169 return error(node.leftOperand); | |
1170 } | |
1171 if (value is int) { | |
1172 return error(node.rightOperand); | |
1173 } | |
1174 return union(error(node.leftOperand), error(node.rightOperand)); | |
1175 } | |
1176 EvaluationResultImpl bitOrError(BinaryExpression node, ErrorResult leftOperand
) => leftOperand; | |
1177 EvaluationResultImpl bitOrValid(BinaryExpression node, ValidResult leftOperand
) { | |
1178 if (!isAnyInt || !leftOperand.isAnyInt) { | |
1179 return error2(node, CompileTimeErrorCode.CONST_EVAL_TYPE_INT); | |
1180 } | |
1181 if (isSomeInt || leftOperand.isSomeInt) { | |
1182 return RESULT_INT; | |
1183 } | |
1184 Object leftValue = leftOperand.value; | |
1185 if (leftValue == null) { | |
1186 return error(node.leftOperand); | |
1187 } else if (value == null) { | |
1188 return error(node.rightOperand); | |
1189 } else if (leftValue is int) { | |
1190 if (value is int) { | |
1191 return valueOf(((leftValue as int)) | (value as int)); | |
1192 } | |
1193 return error(node.leftOperand); | |
1194 } | |
1195 if (value is int) { | |
1196 return error(node.rightOperand); | |
1197 } | |
1198 return union(error(node.leftOperand), error(node.rightOperand)); | |
1199 } | |
1200 EvaluationResultImpl bitXorError(BinaryExpression node, ErrorResult leftOperan
d) => leftOperand; | |
1201 EvaluationResultImpl bitXorValid(BinaryExpression node, ValidResult leftOperan
d) { | |
1202 if (!isAnyInt || !leftOperand.isAnyInt) { | |
1203 return error2(node, CompileTimeErrorCode.CONST_EVAL_TYPE_INT); | |
1204 } | |
1205 if (isSomeInt || leftOperand.isSomeInt) { | |
1206 return RESULT_INT; | |
1207 } | |
1208 Object leftValue = leftOperand.value; | |
1209 if (leftValue == null) { | |
1210 return error(node.leftOperand); | |
1211 } else if (value == null) { | |
1212 return error(node.rightOperand); | |
1213 } else if (leftValue is int) { | |
1214 if (value is int) { | |
1215 return valueOf(((leftValue as int)) ^ (value as int)); | |
1216 } | |
1217 return error(node.leftOperand); | |
1218 } | |
1219 if (value is int) { | |
1220 return error(node.rightOperand); | |
1221 } | |
1222 return union(error(node.leftOperand), error(node.rightOperand)); | |
1223 } | |
1224 EvaluationResultImpl concatenateError(Expression node, ErrorResult leftOperand
) => leftOperand; | |
1225 EvaluationResultImpl concatenateValid(Expression node, ValidResult leftOperand
) { | |
1226 Object leftValue = leftOperand.value; | |
1227 if (leftValue is String && value is String) { | |
1228 return valueOf4("${((leftValue as String))}${((value as String))}"); | |
1229 } | |
1230 return error(node); | |
1231 } | |
1232 EvaluationResultImpl divideError(BinaryExpression node, ErrorResult leftOperan
d) => leftOperand; | |
1233 EvaluationResultImpl divideValid(BinaryExpression node, ValidResult leftOperan
d) { | |
1234 if (!isAnyNum || !leftOperand.isAnyNum) { | |
1235 return error2(node, CompileTimeErrorCode.CONST_EVAL_TYPE_NUM); | |
1236 } | |
1237 if (isSomeNum || leftOperand.isSomeNum) { | |
1238 return RESULT_NUM; | |
1239 } | |
1240 Object leftValue = leftOperand.value; | |
1241 if (leftValue == null) { | |
1242 return error(node.leftOperand); | |
1243 } else if (value == null) { | |
1244 return error(node.rightOperand); | |
1245 } else if (leftValue is int) { | |
1246 if (value is int) { | |
1247 if (((value as int)) == 0) { | |
1248 return valueOf3(((leftValue as int)).toDouble() / ((value as int)).toD
ouble()); | |
1249 } | |
1250 return valueOf(((leftValue as int)) ~/ (value as int)); | |
1251 } else if (value is double) { | |
1252 return valueOf3(((leftValue as int)).toDouble() / ((value as double))); | |
1253 } | |
1254 } else if (leftValue is double) { | |
1255 if (value is int) { | |
1256 return valueOf3(((leftValue as double)) / ((value as int)).toDouble()); | |
1257 } else if (value is double) { | |
1258 return valueOf3(((leftValue as double)) / ((value as double))); | |
1259 } | |
1260 } | |
1261 return error(node); | |
1262 } | |
1263 EvaluationResultImpl equalEqualError(Expression node, ErrorResult leftOperand)
=> leftOperand; | |
1264 EvaluationResultImpl equalEqualValid(Expression node, ValidResult leftOperand)
{ | |
1265 if (node is BinaryExpression) { | |
1266 if (!isAnyNullBoolNumString || !leftOperand.isAnyNullBoolNumString) { | |
1267 return error2(node, CompileTimeErrorCode.CONST_EVAL_TYPE_BOOL_NUM_STRING
); | |
1268 } | |
1269 } | |
1270 Object leftValue = leftOperand.value; | |
1271 if (leftValue == null) { | |
1272 return valueOf2(value == null); | |
1273 } else if (leftValue is bool) { | |
1274 if (value is bool) { | |
1275 return valueOf2(identical(leftValue as bool, value as bool)); | |
1276 } | |
1277 return RESULT_FALSE; | |
1278 } else if (leftValue is int) { | |
1279 if (value is int) { | |
1280 return valueOf2(((leftValue as int)) == value); | |
1281 } else if (value is double) { | |
1282 return valueOf2(toDouble(leftValue as int) == value); | |
1283 } | |
1284 return RESULT_FALSE; | |
1285 } else if (leftValue is double) { | |
1286 if (value is int) { | |
1287 return valueOf2(((leftValue as double)) == toDouble(value as int)); | |
1288 } else if (value is double) { | |
1289 return valueOf2(((leftValue as double)) == value); | |
1290 } | |
1291 return RESULT_FALSE; | |
1292 } else if (leftValue is String) { | |
1293 if (value is String) { | |
1294 return valueOf2(((leftValue as String)) == value); | |
1295 } | |
1296 return RESULT_FALSE; | |
1297 } | |
1298 return RESULT_FALSE; | |
1299 } | |
1300 EvaluationResultImpl greaterThanError(BinaryExpression node, ErrorResult leftO
perand) => leftOperand; | |
1301 EvaluationResultImpl greaterThanOrEqualError(BinaryExpression node, ErrorResul
t leftOperand) => leftOperand; | |
1302 EvaluationResultImpl greaterThanOrEqualValid(BinaryExpression node, ValidResul
t leftOperand) { | |
1303 if (!isAnyNum || !leftOperand.isAnyNum) { | |
1304 return error2(node, CompileTimeErrorCode.CONST_EVAL_TYPE_NUM); | |
1305 } | |
1306 if (isSomeNum || leftOperand.isSomeNum) { | |
1307 return RESULT_BOOL; | |
1308 } | |
1309 Object leftValue = leftOperand.value; | |
1310 if (leftValue == null) { | |
1311 return error(node.leftOperand); | |
1312 } else if (value == null) { | |
1313 return error(node.rightOperand); | |
1314 } else if (leftValue is int) { | |
1315 if (value is int) { | |
1316 return valueOf2(((leftValue as int)).compareTo(value as int) >= 0); | |
1317 } else if (value is double) { | |
1318 return valueOf2(((leftValue as int)).toDouble() >= ((value as double))); | |
1319 } | |
1320 } else if (leftValue is double) { | |
1321 if (value is int) { | |
1322 return valueOf2(((leftValue as double)) >= ((value as int)).toDouble()); | |
1323 } else if (value is double) { | |
1324 return valueOf2(((leftValue as double)) >= ((value as double))); | |
1325 } | |
1326 } | |
1327 return error(node); | |
1328 } | |
1329 EvaluationResultImpl greaterThanValid(BinaryExpression node, ValidResult leftO
perand) { | |
1330 if (!isAnyNum || !leftOperand.isAnyNum) { | |
1331 return error2(node, CompileTimeErrorCode.CONST_EVAL_TYPE_NUM); | |
1332 } | |
1333 if (isSomeNum || leftOperand.isSomeNum) { | |
1334 return RESULT_BOOL; | |
1335 } | |
1336 Object leftValue = leftOperand.value; | |
1337 if (leftValue == null) { | |
1338 return error(node.leftOperand); | |
1339 } else if (value == null) { | |
1340 return error(node.rightOperand); | |
1341 } else if (leftValue is int) { | |
1342 if (value is int) { | |
1343 return valueOf2(((leftValue as int)).compareTo(value as int) > 0); | |
1344 } else if (value is double) { | |
1345 return valueOf2(((leftValue as int)).toDouble() > ((value as double))); | |
1346 } | |
1347 } else if (leftValue is double) { | |
1348 if (value is int) { | |
1349 return valueOf2(((leftValue as double)) > ((value as int)).toDouble()); | |
1350 } else if (value is double) { | |
1351 return valueOf2(((leftValue as double)) > ((value as double))); | |
1352 } | |
1353 } | |
1354 return error(node); | |
1355 } | |
1356 EvaluationResultImpl integerDivideError(BinaryExpression node, ErrorResult lef
tOperand) => leftOperand; | |
1357 EvaluationResultImpl integerDivideValid(BinaryExpression node, ValidResult lef
tOperand) { | |
1358 if (!isAnyNum || !leftOperand.isAnyNum) { | |
1359 return error2(node, CompileTimeErrorCode.CONST_EVAL_TYPE_NUM); | |
1360 } | |
1361 if (isSomeNum || leftOperand.isSomeNum) { | |
1362 return RESULT_INT; | |
1363 } | |
1364 Object leftValue = leftOperand.value; | |
1365 if (leftValue == null) { | |
1366 return error(node.leftOperand); | |
1367 } else if (value == null) { | |
1368 return error(node.rightOperand); | |
1369 } else if (leftValue is int) { | |
1370 if (value is int) { | |
1371 if (((value as int)) == 0) { | |
1372 return error2(node, CompileTimeErrorCode.CONST_EVAL_THROWS_IDBZE); | |
1373 } | |
1374 return valueOf(((leftValue as int)) ~/ (value as int)); | |
1375 } else if (value is double) { | |
1376 double result = ((leftValue as int)).toDouble() / ((value as double)); | |
1377 return valueOf(result.toInt()); | |
1378 } | |
1379 } else if (leftValue is double) { | |
1380 if (value is int) { | |
1381 double result = ((leftValue as double)) / ((value as int)).toDouble(); | |
1382 return valueOf(result.toInt()); | |
1383 } else if (value is double) { | |
1384 double result = ((leftValue as double)) / ((value as double)); | |
1385 return valueOf(result.toInt()); | |
1386 } | |
1387 } | |
1388 return error(node); | |
1389 } | |
1390 EvaluationResultImpl lessThanError(BinaryExpression node, ErrorResult leftOper
and) => leftOperand; | |
1391 EvaluationResultImpl lessThanOrEqualError(BinaryExpression node, ErrorResult l
eftOperand) => leftOperand; | |
1392 EvaluationResultImpl lessThanOrEqualValid(BinaryExpression node, ValidResult l
eftOperand) { | |
1393 if (!isAnyNum || !leftOperand.isAnyNum) { | |
1394 return error2(node, CompileTimeErrorCode.CONST_EVAL_TYPE_NUM); | |
1395 } | |
1396 if (isSomeNum || leftOperand.isSomeNum) { | |
1397 return RESULT_BOOL; | |
1398 } | |
1399 Object leftValue = leftOperand.value; | |
1400 if (leftValue == null) { | |
1401 return error(node.leftOperand); | |
1402 } else if (value == null) { | |
1403 return error(node.rightOperand); | |
1404 } else if (leftValue is int) { | |
1405 if (value is int) { | |
1406 return valueOf2(((leftValue as int)).compareTo(value as int) <= 0); | |
1407 } else if (value is double) { | |
1408 return valueOf2(((leftValue as int)).toDouble() <= ((value as double))); | |
1409 } | |
1410 } else if (leftValue is double) { | |
1411 if (value is int) { | |
1412 return valueOf2(((leftValue as double)) <= ((value as int)).toDouble()); | |
1413 } else if (value is double) { | |
1414 return valueOf2(((leftValue as double)) <= ((value as double))); | |
1415 } | |
1416 } | |
1417 return error(node); | |
1418 } | |
1419 EvaluationResultImpl lessThanValid(BinaryExpression node, ValidResult leftOper
and) { | |
1420 if (!isAnyNum || !leftOperand.isAnyNum) { | |
1421 return error2(node, CompileTimeErrorCode.CONST_EVAL_TYPE_NUM); | |
1422 } | |
1423 if (isSomeNum || leftOperand.isSomeNum) { | |
1424 return RESULT_BOOL; | |
1425 } | |
1426 Object leftValue = leftOperand.value; | |
1427 if (leftValue == null) { | |
1428 return error(node.leftOperand); | |
1429 } else if (value == null) { | |
1430 return error(node.rightOperand); | |
1431 } else if (leftValue is int) { | |
1432 if (value is int) { | |
1433 return valueOf2(((leftValue as int)).compareTo(value as int) < 0); | |
1434 } else if (value is double) { | |
1435 return valueOf2(((leftValue as int)).toDouble() < ((value as double))); | |
1436 } | |
1437 } else if (leftValue is double) { | |
1438 if (value is int) { | |
1439 return valueOf2(((leftValue as double)) < ((value as int)).toDouble()); | |
1440 } else if (value is double) { | |
1441 return valueOf2(((leftValue as double)) < ((value as double))); | |
1442 } | |
1443 } | |
1444 return error(node); | |
1445 } | |
1446 EvaluationResultImpl logicalAndError(BinaryExpression node, ErrorResult leftOp
erand) => leftOperand; | |
1447 EvaluationResultImpl logicalAndValid(BinaryExpression node, ValidResult leftOp
erand) { | |
1448 if (!isAnyBool || !leftOperand.isAnyBool) { | |
1449 return error2(node, CompileTimeErrorCode.CONST_EVAL_TYPE_BOOL); | |
1450 } | |
1451 if (isSomeBool || leftOperand.isSomeBool) { | |
1452 return RESULT_BOOL; | |
1453 } | |
1454 Object leftValue = leftOperand.value; | |
1455 if (leftValue is bool) { | |
1456 if (leftValue as bool) { | |
1457 return booleanConversion(node.rightOperand, value); | |
1458 } | |
1459 return RESULT_FALSE; | |
1460 } | |
1461 return error(node); | |
1462 } | |
1463 EvaluationResultImpl logicalOrError(BinaryExpression node, ErrorResult leftOpe
rand) => leftOperand; | |
1464 EvaluationResultImpl logicalOrValid(BinaryExpression node, ValidResult leftOpe
rand) { | |
1465 if (!isAnyBool || !leftOperand.isAnyBool) { | |
1466 return error2(node, CompileTimeErrorCode.CONST_EVAL_TYPE_BOOL); | |
1467 } | |
1468 if (isSomeBool || leftOperand.isSomeBool) { | |
1469 return RESULT_BOOL; | |
1470 } | |
1471 Object leftValue = leftOperand.value; | |
1472 if (leftValue is bool && ((leftValue as bool))) { | |
1473 return RESULT_TRUE; | |
1474 } | |
1475 return booleanConversion(node.rightOperand, value); | |
1476 } | |
1477 EvaluationResultImpl minusError(BinaryExpression node, ErrorResult leftOperand
) => leftOperand; | |
1478 EvaluationResultImpl minusValid(BinaryExpression node, ValidResult leftOperand
) { | |
1479 if (!isAnyNum || !leftOperand.isAnyNum) { | |
1480 return error2(node, CompileTimeErrorCode.CONST_EVAL_TYPE_NUM); | |
1481 } | |
1482 if (isSomeInt || leftOperand.isSomeInt) { | |
1483 return RESULT_INT; | |
1484 } else if (isSomeNum || leftOperand.isSomeNum) { | |
1485 return RESULT_NUM; | |
1486 } | |
1487 Object leftValue = leftOperand.value; | |
1488 if (leftValue == null) { | |
1489 return error(node.leftOperand); | |
1490 } else if (value == null) { | |
1491 return error(node.rightOperand); | |
1492 } else if (leftValue is int) { | |
1493 if (value is int) { | |
1494 return valueOf(((leftValue as int)) - (value as int)); | |
1495 } else if (value is double) { | |
1496 return valueOf3(((leftValue as int)).toDouble() - ((value as double))); | |
1497 } | |
1498 } else if (leftValue is double) { | |
1499 if (value is int) { | |
1500 return valueOf3(((leftValue as double)) - ((value as int)).toDouble()); | |
1501 } else if (value is double) { | |
1502 return valueOf3(((leftValue as double)) - ((value as double))); | |
1503 } | |
1504 } | |
1505 return error(node); | |
1506 } | |
1507 EvaluationResultImpl notEqualError(BinaryExpression node, ErrorResult leftOper
and) => leftOperand; | |
1508 EvaluationResultImpl notEqualValid(BinaryExpression node, ValidResult leftOper
and) { | |
1509 if (!isAnyNullBoolNumString || !leftOperand.isAnyNullBoolNumString) { | |
1510 return error2(node, CompileTimeErrorCode.CONST_EVAL_TYPE_BOOL_NUM_STRING); | |
1511 } | |
1512 Object leftValue = leftOperand.value; | |
1513 if (leftValue == null) { | |
1514 return valueOf2(value != null); | |
1515 } else if (leftValue is bool) { | |
1516 if (value is bool) { | |
1517 return valueOf2(((leftValue as bool)) != ((value as bool))); | |
1518 } | |
1519 return RESULT_TRUE; | |
1520 } else if (leftValue is int) { | |
1521 if (value is int) { | |
1522 return valueOf2(((leftValue as int)) != value); | |
1523 } else if (value is double) { | |
1524 return valueOf2(toDouble(leftValue as int) != value); | |
1525 } | |
1526 return RESULT_TRUE; | |
1527 } else if (leftValue is double) { | |
1528 if (value is int) { | |
1529 return valueOf2(((leftValue as double)) != toDouble(value as int)); | |
1530 } else if (value is double) { | |
1531 return valueOf2(((leftValue as double)) != value); | |
1532 } | |
1533 return RESULT_TRUE; | |
1534 } else if (leftValue is String) { | |
1535 if (value is String) { | |
1536 return valueOf2(((leftValue as String)) != value); | |
1537 } | |
1538 return RESULT_TRUE; | |
1539 } | |
1540 return RESULT_TRUE; | |
1541 } | |
1542 EvaluationResultImpl remainderError(BinaryExpression node, ErrorResult leftOpe
rand) => leftOperand; | |
1543 EvaluationResultImpl remainderValid(BinaryExpression node, ValidResult leftOpe
rand) { | |
1544 if (!isAnyNum || !leftOperand.isAnyNum) { | |
1545 return error2(node, CompileTimeErrorCode.CONST_EVAL_TYPE_NUM); | |
1546 } | |
1547 if (isSomeInt || leftOperand.isSomeInt) { | |
1548 return RESULT_INT; | |
1549 } else if (isSomeNum || leftOperand.isSomeNum) { | |
1550 return RESULT_NUM; | |
1551 } | |
1552 Object leftValue = leftOperand.value; | |
1553 if (leftValue == null) { | |
1554 return error(node.leftOperand); | |
1555 } else if (value == null) { | |
1556 return error(node.rightOperand); | |
1557 } else if (leftValue is int) { | |
1558 if (value is int) { | |
1559 if (((value as int)) == 0) { | |
1560 return valueOf3(((leftValue as int)).toDouble() % ((value as int)).toD
ouble()); | |
1561 } | |
1562 return valueOf(((leftValue as int)).remainder(value as int)); | |
1563 } else if (value is double) { | |
1564 return valueOf3(((leftValue as int)).toDouble() % ((value as double))); | |
1565 } | |
1566 } else if (leftValue is double) { | |
1567 if (value is int) { | |
1568 return valueOf3(((leftValue as double)) % ((value as int)).toDouble()); | |
1569 } else if (value is double) { | |
1570 return valueOf3(((leftValue as double)) % ((value as double))); | |
1571 } | |
1572 } | |
1573 return error(node); | |
1574 } | |
1575 EvaluationResultImpl shiftLeftError(BinaryExpression node, ErrorResult leftOpe
rand) => leftOperand; | |
1576 EvaluationResultImpl shiftLeftValid(BinaryExpression node, ValidResult leftOpe
rand) { | |
1577 if (!isAnyInt || !leftOperand.isAnyInt) { | |
1578 return error2(node, CompileTimeErrorCode.CONST_EVAL_TYPE_INT); | |
1579 } | |
1580 if (isSomeInt || leftOperand.isSomeInt) { | |
1581 return RESULT_INT; | |
1582 } | |
1583 Object leftValue = leftOperand.value; | |
1584 if (leftValue == null) { | |
1585 return error(node.leftOperand); | |
1586 } else if (value == null) { | |
1587 return error(node.rightOperand); | |
1588 } else if (leftValue is int) { | |
1589 if (value is int) { | |
1590 return RESULT_INT; | |
1591 } | |
1592 return error(node.rightOperand); | |
1593 } | |
1594 if (value is int) { | |
1595 return error(node.leftOperand); | |
1596 } | |
1597 return union(error(node.leftOperand), error(node.rightOperand)); | |
1598 } | |
1599 EvaluationResultImpl shiftRightError(BinaryExpression node, ErrorResult leftOp
erand) => leftOperand; | |
1600 EvaluationResultImpl shiftRightValid(BinaryExpression node, ValidResult leftOp
erand) { | |
1601 if (!isAnyInt || !leftOperand.isAnyInt) { | |
1602 return error2(node, CompileTimeErrorCode.CONST_EVAL_TYPE_INT); | |
1603 } | |
1604 if (isSomeInt || leftOperand.isSomeInt) { | |
1605 return RESULT_INT; | |
1606 } | |
1607 Object leftValue = leftOperand.value; | |
1608 if (leftValue == null) { | |
1609 return error(node.leftOperand); | |
1610 } else if (value == null) { | |
1611 return error(node.rightOperand); | |
1612 } else if (leftValue is int) { | |
1613 if (value is int) { | |
1614 return valueOf(((leftValue as int)) >> ((value as int))); | |
1615 } | |
1616 return error(node.rightOperand); | |
1617 } | |
1618 if (value is int) { | |
1619 return error(node.leftOperand); | |
1620 } | |
1621 return union(error(node.leftOperand), error(node.rightOperand)); | |
1622 } | |
1623 EvaluationResultImpl timesError(BinaryExpression node, ErrorResult leftOperand
) => leftOperand; | |
1624 EvaluationResultImpl timesValid(BinaryExpression node, ValidResult leftOperand
) { | |
1625 if (!isAnyNum || !leftOperand.isAnyNum) { | |
1626 return error2(node, CompileTimeErrorCode.CONST_EVAL_TYPE_NUM); | |
1627 } | |
1628 if (isSomeInt || leftOperand.isSomeInt) { | |
1629 return RESULT_INT; | |
1630 } else if (isSomeNum || leftOperand.isSomeNum) { | |
1631 return RESULT_NUM; | |
1632 } | |
1633 Object leftValue = leftOperand.value; | |
1634 if (leftValue == null) { | |
1635 return error(node.leftOperand); | |
1636 } else if (value == null) { | |
1637 return error(node.rightOperand); | |
1638 } else if (leftValue is int) { | |
1639 if (value is int) { | |
1640 return valueOf(((leftValue as int)) * (value as int)); | |
1641 } else if (value is double) { | |
1642 return valueOf3(((leftValue as int)).toDouble() * ((value as double))); | |
1643 } | |
1644 } else if (leftValue is double) { | |
1645 if (value is int) { | |
1646 return valueOf3(((leftValue as double)) * ((value as int)).toDouble()); | |
1647 } else if (value is double) { | |
1648 return valueOf3(((leftValue as double)) * ((value as double))); | |
1649 } | |
1650 } | |
1651 return error(node); | |
1652 } | |
1653 bool get isNull => identical(this, RESULT_NULL); | |
1654 | |
1655 /** | |
1656 * Return the result of applying boolean conversion to the given value. | |
1657 * | |
1658 * @param node the node against which errors should be reported | |
1659 * @param value the value to be converted to a boolean | |
1660 * @return the result of applying boolean conversion to the given value | |
1661 */ | |
1662 EvaluationResultImpl booleanConversion(ASTNode node, Object value) { | |
1663 if (value is bool) { | |
1664 if (value as bool) { | |
1665 return RESULT_TRUE; | |
1666 } else { | |
1667 return RESULT_FALSE; | |
1668 } | |
1669 } | |
1670 return error(node); | |
1671 } | |
1672 ErrorResult error(ASTNode node) => error2(node, CompileTimeErrorCode.INVALID_C
ONSTANT); | |
1673 | |
1674 /** | |
1675 * Return a result object representing an error associated with the given node
. | |
1676 * | |
1677 * @param node the AST node associated with the error | |
1678 * @param code the error code indicating the nature of the error | |
1679 * @return a result object representing an error associated with the given nod
e | |
1680 */ | |
1681 ErrorResult error2(ASTNode node, ErrorCode code) => new ErrorResult.con1(node,
code); | |
1682 | |
1683 /** | |
1684 * Checks if this result has type "bool", with known or unknown value. | |
1685 */ | |
1686 bool get isAnyBool => isSomeBool || identical(this, RESULT_TRUE) || identical(
this, RESULT_FALSE); | |
1687 | |
1688 /** | |
1689 * Checks if this result has type "int", with known or unknown value. | |
1690 */ | |
1691 bool get isAnyInt => identical(this, RESULT_INT) || value is int; | |
1692 | |
1693 /** | |
1694 * Checks if this result has one of the types - "bool", "num" or "string"; or
may be `null`. | |
1695 */ | |
1696 bool get isAnyNullBoolNumString => isNull || isAnyBool || isAnyNum || value is
String; | |
1697 | |
1698 /** | |
1699 * Checks if this result has type "num", with known or unknown value. | |
1700 */ | |
1701 bool get isAnyNum => isSomeNum || value is num; | |
1702 | |
1703 /** | |
1704 * Checks if this result has type "bool", exact value of which we don't know. | |
1705 */ | |
1706 bool get isSomeBool => identical(this, RESULT_BOOL); | |
1707 | |
1708 /** | |
1709 * Checks if this result has type "int", exact value of which we don't know. | |
1710 */ | |
1711 bool get isSomeInt => identical(this, RESULT_INT); | |
1712 | |
1713 /** | |
1714 * Checks if this result has type "num" (or "int"), exact value of which we do
n't know. | |
1715 */ | |
1716 bool get isSomeNum => identical(this, RESULT_DYNAMIC) || identical(this, RESUL
T_INT) || identical(this, RESULT_NUM); | |
1717 double toDouble(int value) => value.toDouble(); | |
1718 | |
1719 /** | |
1720 * Return an error result that is the union of the two given error results. | |
1721 * | |
1722 * @param firstError the first error to be combined | |
1723 * @param secondError the second error to be combined | |
1724 * @return an error result that is the union of the two given error results | |
1725 */ | |
1726 ErrorResult union(ErrorResult firstError, ErrorResult secondError) => new Erro
rResult.con2(firstError, secondError); | |
1727 | |
1728 /** | |
1729 * Return a result object representing the given value. | |
1730 * | |
1731 * @param value the value to be represented as a result object | |
1732 * @return a result object representing the given value | |
1733 */ | |
1734 ValidResult valueOf(int value) => new ValidResult(value); | |
1735 | |
1736 /** | |
1737 * Return a result object representing the given value. | |
1738 * | |
1739 * @param value the value to be represented as a result object | |
1740 * @return a result object representing the given value | |
1741 */ | |
1742 ValidResult valueOf2(bool value) => value ? RESULT_TRUE : RESULT_FALSE; | |
1743 | |
1744 /** | |
1745 * Return a result object representing the given value. | |
1746 * | |
1747 * @param value the value to be represented as a result object | |
1748 * @return a result object representing the given value | |
1749 */ | |
1750 ValidResult valueOf3(double value) => new ValidResult(value); | |
1751 | |
1752 /** | |
1753 * Return a result object representing the given value. | |
1754 * | |
1755 * @param value the value to be represented as a result object | |
1756 * @return a result object representing the given value | |
1757 */ | |
1758 ValidResult valueOf4(String value) => new ValidResult(value); | |
1759 } | |
OLD | NEW |