Index: pkg/analyzer_experimental/lib/src/generated/constant.dart |
=================================================================== |
--- pkg/analyzer_experimental/lib/src/generated/constant.dart (revision 23549) |
+++ pkg/analyzer_experimental/lib/src/generated/constant.dart (working copy) |
@@ -11,6 +11,7 @@ |
import 'element.dart'; |
import 'engine.dart' show AnalysisEngine; |
+ |
/** |
* Instances of the class {@code ConstantEvaluator} evaluate constant expressions to produce their |
* compile-time value. According to the Dart Language Specification: <blockquote> A constant |
@@ -43,10 +44,12 @@ |
* those values. |
*/ |
class ConstantEvaluator { |
+ |
/** |
* The source containing the expression(s) that will be evaluated. |
*/ |
Source _source; |
+ |
/** |
* Initialize a newly created evaluator to evaluate expressions in the given source. |
* @param source the source containing the expression(s) that will be evaluated |
@@ -67,11 +70,13 @@ |
return EvaluationResult.forErrors(new List.from(errors)); |
} |
} |
+ |
/** |
* Instances of the class {@code EvaluationResult} represent the result of attempting to evaluate an |
* expression. |
*/ |
class EvaluationResult { |
+ |
/** |
* Return an evaluation result representing the result of evaluating an expression that is not a |
* compile-time constant because of the given errors. |
@@ -79,6 +84,7 @@ |
* @return the result of evaluating an expression that is not a compile-time constant |
*/ |
static EvaluationResult forErrors(List<AnalysisError> errors) => new EvaluationResult(null, errors); |
+ |
/** |
* Return an evaluation result representing the result of evaluating an expression that is a |
* compile-time constant that evaluates to the given value. |
@@ -86,14 +92,17 @@ |
* @return the result of evaluating an expression that is a compile-time constant |
*/ |
static EvaluationResult forValue(Object value) => new EvaluationResult(value, null); |
+ |
/** |
* The value of the expression. |
*/ |
Object _value; |
+ |
/** |
* The errors that should be reported for the expression(s) that were evaluated. |
*/ |
List<AnalysisError> _errors; |
+ |
/** |
* Initialize a newly created result object with the given state. Clients should use one of the |
* factory methods: {@link #forErrors(AnalysisError\[\])} and {@link #forValue(Object)}. |
@@ -104,6 +113,7 @@ |
this._value = value; |
this._errors = errors; |
} |
+ |
/** |
* Return an array containing the errors that should be reported for the expression(s) that were |
* evaluated. If there are no such errors, the array will be empty. The array can be empty even if |
@@ -111,12 +121,14 @@ |
* other parts of the analysis engine. |
*/ |
List<AnalysisError> get errors => _errors == null ? AnalysisError.NO_ERRORS : _errors; |
+ |
/** |
* Return the value of the expression, or {@code null} if the expression evaluated to {@code null}or if the expression could not be evaluated, either because it was not a compile-time constant |
* expression or because it would throw an exception when evaluated. |
* @return the value of the expression |
*/ |
Object get value => _value; |
+ |
/** |
* Return {@code true} if the expression is a compile-time constant expression that would not |
* throw an exception when evaluated. |
@@ -124,22 +136,20 @@ |
*/ |
bool isValid() => _errors == null; |
} |
+ |
/** |
* Instances of the class {@code ConstantFinder} are used to traverse the AST structures of all of |
* the compilation units being resolved and build a table mapping constant variable elements to the |
* declarations of those variables. |
*/ |
class ConstantFinder extends RecursiveASTVisitor<Object> { |
+ |
/** |
* A table mapping constant variable elements to the declarations of those variables. |
*/ |
Map<VariableElement, VariableDeclaration> _variableMap = new Map<VariableElement, VariableDeclaration>(); |
+ |
/** |
- * Initialize a newly created constant finder. |
- */ |
- ConstantFinder() : super() { |
- } |
- /** |
* Return a table mapping constant variable elements to the declarations of those variables. |
* @return a table mapping constant variable elements to the declarations of those variables |
*/ |
@@ -156,6 +166,7 @@ |
return null; |
} |
} |
+ |
/** |
* Instances of the class {@code ConstantValueComputer} compute the values of constant variables in |
* one or more compilation units. The expected usage pattern is for the compilation units to be |
@@ -163,25 +174,24 @@ |
* method {@link #computeValues()} will result in unpredictable behavior. |
*/ |
class ConstantValueComputer { |
+ |
/** |
* The object used to find constant variables in the compilation units that were added. |
*/ |
ConstantFinder _constantFinder = new ConstantFinder(); |
+ |
/** |
* A graph in which the nodes are the constant variables and the edges are from each variable to |
* the other constant variables that are referenced in the head's initializer. |
*/ |
DirectedGraph<VariableElement> _referenceGraph = new DirectedGraph<VariableElement>(); |
+ |
/** |
* A table mapping constant variables to the declarations of those variables. |
*/ |
Map<VariableElement, VariableDeclaration> _declarationMap; |
+ |
/** |
- * Initialize a newly created constant value computer. |
- */ |
- ConstantValueComputer() : super() { |
- } |
- /** |
* Add the constant variables in the given compilation unit to the list of constant variables |
* whose value needs to be computed. |
* @param unit the compilation unit defining the constant variables to be added |
@@ -189,6 +199,7 @@ |
void add(CompilationUnit unit) { |
unit.accept(_constantFinder); |
} |
+ |
/** |
* Compute values for all of the constant variables in the compilation units that were added. |
*/ |
@@ -219,6 +230,7 @@ |
} |
} |
} |
+ |
/** |
* Compute a value for the given variable. |
* @param variable the variable for which a value is to be computed |
@@ -239,6 +251,7 @@ |
} |
} |
} |
+ |
/** |
* Generate an error indicating that the given variable is not a valid compile-time constant |
* because it references at least one of the variables in the given cycle, each of which directly |
@@ -249,6 +262,7 @@ |
void generateCycleError(List<VariableElement> variablesInCycle, VariableElement variable) { |
} |
} |
+ |
/** |
* Instances of the class {@code ConstantVisitor} evaluate constant expressions to produce their |
* compile-time value. According to the Dart Language Specification: <blockquote> A constant |
@@ -276,11 +290,6 @@ |
* </blockquote> |
*/ |
class ConstantVisitor extends GeneralizingASTVisitor<EvaluationResultImpl> { |
- /** |
- * Initialize a newly created constant visitor. |
- */ |
- ConstantVisitor() : super() { |
- } |
EvaluationResultImpl visitAdjacentStrings(AdjacentStrings node) { |
EvaluationResultImpl result = null; |
for (StringLiteral string in node.strings) { |
@@ -295,44 +304,50 @@ |
EvaluationResultImpl visitBinaryExpression(BinaryExpression node) { |
EvaluationResultImpl leftResult = node.leftOperand.accept(this); |
EvaluationResultImpl rightResult = node.rightOperand.accept(this); |
+ TokenType operatorType = node.operator.type; |
+ if (operatorType != TokenType.BANG_EQ && operatorType != TokenType.EQ_EQ) { |
+ if (leftResult is ValidResult && ((leftResult as ValidResult)).isNull() || rightResult is ValidResult && ((rightResult as ValidResult)).isNull()) { |
+ return error(node, CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION); |
+ } |
+ } |
while (true) { |
- if (node.operator.type == TokenType.AMPERSAND) { |
+ if (operatorType == TokenType.AMPERSAND) { |
return leftResult.bitAnd(node, rightResult); |
- } else if (node.operator.type == TokenType.AMPERSAND_AMPERSAND) { |
+ } else if (operatorType == TokenType.AMPERSAND_AMPERSAND) { |
return leftResult.logicalAnd(node, rightResult); |
- } else if (node.operator.type == TokenType.BANG_EQ) { |
+ } else if (operatorType == TokenType.BANG_EQ) { |
return leftResult.notEqual(node, rightResult); |
- } else if (node.operator.type == TokenType.BAR) { |
+ } else if (operatorType == TokenType.BAR) { |
return leftResult.bitOr(node, rightResult); |
- } else if (node.operator.type == TokenType.BAR_BAR) { |
+ } else if (operatorType == TokenType.BAR_BAR) { |
return leftResult.logicalOr(node, rightResult); |
- } else if (node.operator.type == TokenType.CARET) { |
+ } else if (operatorType == TokenType.CARET) { |
return leftResult.bitXor(node, rightResult); |
- } else if (node.operator.type == TokenType.EQ_EQ) { |
+ } else if (operatorType == TokenType.EQ_EQ) { |
return leftResult.equalEqual(node, rightResult); |
- } else if (node.operator.type == TokenType.GT) { |
+ } else if (operatorType == TokenType.GT) { |
return leftResult.greaterThan(node, rightResult); |
- } else if (node.operator.type == TokenType.GT_EQ) { |
+ } else if (operatorType == TokenType.GT_EQ) { |
return leftResult.greaterThanOrEqual(node, rightResult); |
- } else if (node.operator.type == TokenType.GT_GT) { |
+ } else if (operatorType == TokenType.GT_GT) { |
return leftResult.shiftRight(node, rightResult); |
- } else if (node.operator.type == TokenType.LT) { |
+ } else if (operatorType == TokenType.LT) { |
return leftResult.lessThan(node, rightResult); |
- } else if (node.operator.type == TokenType.LT_EQ) { |
+ } else if (operatorType == TokenType.LT_EQ) { |
return leftResult.lessThanOrEqual(node, rightResult); |
- } else if (node.operator.type == TokenType.LT_LT) { |
+ } else if (operatorType == TokenType.LT_LT) { |
return leftResult.shiftLeft(node, rightResult); |
- } else if (node.operator.type == TokenType.MINUS) { |
+ } else if (operatorType == TokenType.MINUS) { |
return leftResult.minus(node, rightResult); |
- } else if (node.operator.type == TokenType.PERCENT) { |
+ } else if (operatorType == TokenType.PERCENT) { |
return leftResult.remainder(node, rightResult); |
- } else if (node.operator.type == TokenType.PLUS) { |
+ } else if (operatorType == TokenType.PLUS) { |
return leftResult.add(node, rightResult); |
- } else if (node.operator.type == TokenType.STAR) { |
+ } else if (operatorType == TokenType.STAR) { |
return leftResult.times(node, rightResult); |
- } else if (node.operator.type == TokenType.SLASH) { |
+ } else if (operatorType == TokenType.SLASH) { |
return leftResult.divide(node, rightResult); |
- } else if (node.operator.type == TokenType.TILDE_SLASH) { |
+ } else if (operatorType == TokenType.TILDE_SLASH) { |
return leftResult.integerDivide(node, rightResult); |
} |
break; |
@@ -398,11 +413,14 @@ |
return error(node, null); |
} |
EvaluationResultImpl visitNode(ASTNode node) => error(node, null); |
- EvaluationResultImpl visitNullLiteral(NullLiteral node) => new ValidResult(null); |
+ EvaluationResultImpl visitNullLiteral(NullLiteral node) => ValidResult.RESULT_NULL; |
EvaluationResultImpl visitParenthesizedExpression(ParenthesizedExpression node) => node.expression.accept(this); |
EvaluationResultImpl visitPrefixedIdentifier(PrefixedIdentifier node) => getConstantValue(node, node.element); |
EvaluationResultImpl visitPrefixExpression(PrefixExpression node) { |
EvaluationResultImpl operand2 = node.operand.accept(this); |
+ if (operand2 is ValidResult && ((operand2 as ValidResult)).isNull()) { |
+ return error(node, CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION); |
+ } |
while (true) { |
if (node.operator.type == TokenType.BANG) { |
return operand2.logicalNot(node); |
@@ -429,6 +447,7 @@ |
} |
return result; |
} |
+ |
/** |
* Return a result object representing an error associated with the given node. |
* @param node the AST node associated with the error |
@@ -436,6 +455,7 @@ |
* @return a result object representing an error associated with the given node |
*/ |
ErrorResult error(ASTNode node, ErrorCode code) => new ErrorResult.con1(node, code == null ? CompileTimeErrorCode.INVALID_CONSTANT : code); |
+ |
/** |
* Return the constant value of the static constant represented by the given element. |
* @param node the node to be used if an error needs to be reported |
@@ -453,9 +473,12 @@ |
} |
} else if (element is ExecutableElement) { |
return new ValidResult(element); |
+ } else if (element is ClassElement) { |
+ return ValidResult.RESULT_OBJECT; |
} |
return error(node, null); |
} |
+ |
/** |
* Return the union of the errors encoded in the given results. |
* @param leftResult the first set of errors, or {@code null} if there was no previous collection |
@@ -475,6 +498,7 @@ |
return leftResult; |
} |
} |
+ |
/** |
* Instances of the class {@code DirectedGraph} implement a directed graph in which the nodes are |
* arbitrary (client provided) objects and edges are represented implicitly. The graph will allow an |
@@ -483,18 +507,15 @@ |
* @param N the type of the nodes in the graph |
*/ |
class DirectedGraph<N> { |
+ |
/** |
* The table encoding the edges in the graph. An edge is represented by an entry mapping the head |
* to a set of tails. Nodes that are not the head of any edge are represented by an entry mapping |
* the node to an empty set of tails. |
*/ |
Map<N, Set<N>> _edges = new Map<N, Set<N>>(); |
+ |
/** |
- * Initialize a newly create directed graph to be empty. |
- */ |
- DirectedGraph() : super() { |
- } |
- /** |
* Add an edge from the given head node to the given tail node. Both nodes will be a part of the |
* graph after this method is invoked, whether or not they were before. |
* @param head the node at the head of the edge |
@@ -512,6 +533,7 @@ |
} |
javaSetAdd(tails, tail); |
} |
+ |
/** |
* Add the given node to the set of nodes in the graph. |
* @param node the node to be added |
@@ -522,16 +544,19 @@ |
_edges[node] = new Set<N>(); |
} |
} |
+ |
/** |
* Return a list of nodes that form a cycle, or {@code null} if there are no cycles in this graph. |
* @return a list of nodes that form a cycle |
*/ |
List<N> findCycle() => null; |
+ |
/** |
* Return the number of nodes in this graph. |
* @return the number of nodes in this graph |
*/ |
int get nodeCount => _edges.length; |
+ |
/** |
* Return a set containing the tails of edges that have the given node as their head. The set will |
* be empty if there are no such edges or if the node is not part of the graph. Clients must not |
@@ -546,11 +571,13 @@ |
} |
return tails; |
} |
+ |
/** |
* Return {@code true} if this graph is empty. |
* @return {@code true} if this graph is empty |
*/ |
bool isEmpty() => _edges.isEmpty; |
+ |
/** |
* Remove all of the given nodes from this graph. As a consequence, any edges for which those |
* nodes were either a head or a tail will also be removed. |
@@ -561,6 +588,7 @@ |
removeNode(node); |
} |
} |
+ |
/** |
* Remove the edge from the given head node to the given tail node. If there was no such edge then |
* the graph will be unmodified: the number of edges will be the same and the set of nodes will be |
@@ -575,6 +603,7 @@ |
tails.remove(tail); |
} |
} |
+ |
/** |
* Remove the given node from this graph. As a consequence, any edges for which that node was |
* either a head or a tail will also be removed. |
@@ -586,6 +615,7 @@ |
tails.remove(node); |
} |
} |
+ |
/** |
* Find one node (referred to as a sink node) that has no outgoing edges (that is, for which there |
* are no edges that have that node as the head of the edge) and remove it from this graph. Return |
@@ -602,6 +632,7 @@ |
removeNode(sink); |
return sink; |
} |
+ |
/** |
* Return one node that has no outgoing edges (that is, for which there are no edges that have |
* that node as the head of the edge), or {@code null} if there are no such nodes. |
@@ -616,15 +647,18 @@ |
return null; |
} |
} |
+ |
/** |
* Instances of the class {@code ErrorResult} represent the result of evaluating an expression that |
* is not a valid compile time constant. |
*/ |
class ErrorResult extends EvaluationResultImpl { |
+ |
/** |
* The errors that prevent the expression from being a valid compile time constant. |
*/ |
List<ErrorResult_ErrorData> _errors = new List<ErrorResult_ErrorData>(); |
+ |
/** |
* Initialize a newly created result representing the error with the given code reported against |
* the given node. |
@@ -632,11 +666,12 @@ |
* @param errorCode the error code for the error to be generated |
*/ |
ErrorResult.con1(ASTNode node, ErrorCode errorCode) { |
- _jtd_constructor_168_impl(node, errorCode); |
+ _jtd_constructor_171_impl(node, errorCode); |
} |
- _jtd_constructor_168_impl(ASTNode node, ErrorCode errorCode) { |
+ _jtd_constructor_171_impl(ASTNode node, ErrorCode errorCode) { |
_errors.add(new ErrorResult_ErrorData(node, errorCode)); |
} |
+ |
/** |
* Initialize a newly created result to represent the union of the errors in the given result |
* objects. |
@@ -644,9 +679,9 @@ |
* @param secondResult the second set of results being merged |
*/ |
ErrorResult.con2(ErrorResult firstResult, ErrorResult secondResult) { |
- _jtd_constructor_169_impl(firstResult, secondResult); |
+ _jtd_constructor_172_impl(firstResult, secondResult); |
} |
- _jtd_constructor_169_impl(ErrorResult firstResult, ErrorResult secondResult) { |
+ _jtd_constructor_172_impl(ErrorResult firstResult, ErrorResult secondResult) { |
_errors.addAll(firstResult._errors); |
_errors.addAll(secondResult._errors); |
} |
@@ -717,14 +752,17 @@ |
EvaluationResultImpl timesValid(BinaryExpression node, ValidResult leftOperand) => this; |
} |
class ErrorResult_ErrorData { |
+ |
/** |
* The node against which the error should be reported. |
*/ |
ASTNode _node; |
+ |
/** |
* The error code for the error to be generated. |
*/ |
ErrorCode _errorCode; |
+ |
/** |
* Initialize a newly created data holder to represent the error with the given code reported |
* against the given node. |
@@ -735,17 +773,20 @@ |
this._node = node; |
this._errorCode = errorCode; |
} |
+ |
/** |
* Return the error code for the error to be generated. |
* @return the error code for the error to be generated |
*/ |
ErrorCode get errorCode => _errorCode; |
+ |
/** |
* Return the node against which the error should be reported. |
* @return the node against which the error should be reported |
*/ |
ASTNode get node => _node; |
} |
+ |
/** |
* Instances of the class {@code InternalResult} represent the result of attempting to evaluate a |
* expression. |
@@ -816,20 +857,24 @@ |
EvaluationResultImpl timesError(BinaryExpression node, ErrorResult leftOperand); |
EvaluationResultImpl timesValid(BinaryExpression node, ValidResult leftOperand); |
} |
+ |
/** |
* Instances of the class {@code ReferenceFinder} add reference information for a given variable to |
* the bi-directional mapping used to order the evaluation of constants. |
*/ |
class ReferenceFinder extends RecursiveASTVisitor<Object> { |
+ |
/** |
* The element representing the variable whose initializer will be visited. |
*/ |
VariableElement _source; |
+ |
/** |
* A graph in which the nodes are the constant variables and the edges are from each variable to |
* the other constant variables that are referenced in the head's initializer. |
*/ |
DirectedGraph<VariableElement> _referenceGraph; |
+ |
/** |
* Initialize a newly created reference finder to find references from the given variable to other |
* variables and to add those references to the given graph. |
@@ -855,28 +900,69 @@ |
return null; |
} |
} |
+ |
/** |
* Instances of the class {@code ValidResult} represent the result of attempting to evaluate a valid |
* compile time constant expression. |
*/ |
class ValidResult extends EvaluationResultImpl { |
+ |
/** |
* A result object representing the value 'false'. |
*/ |
static ValidResult RESULT_FALSE = new ValidResult(false); |
+ |
/** |
+ * A result object representing the an object without specific type on which no further operations |
+ * can be performed. |
+ */ |
+ static ValidResult RESULT_DYNAMIC = new ValidResult(null); |
+ |
+ /** |
+ * A result object representing the an arbitrary integer on which no further operations can be |
+ * performed. |
+ */ |
+ static ValidResult RESULT_INT = new ValidResult(null); |
+ |
+ /** |
+ * A result object representing the {@code null} value. |
+ */ |
+ static ValidResult RESULT_NULL = new ValidResult(null); |
+ |
+ /** |
+ * A result object representing the an arbitrary numeric on which no further operations can be |
+ * performed. |
+ */ |
+ static ValidResult RESULT_NUM = new ValidResult(null); |
+ |
+ /** |
+ * A result object representing the an arbitrary boolean on which no further operations can be |
+ * performed. |
+ */ |
+ static ValidResult RESULT_BOOL = new ValidResult(null); |
+ |
+ /** |
* A result object representing the an arbitrary object on which no further operations can be |
* performed. |
*/ |
static ValidResult RESULT_OBJECT = new ValidResult(new Object()); |
+ |
/** |
+ * A result object representing the an arbitrary string on which no further operations can be |
+ * performed. |
+ */ |
+ static ValidResult RESULT_STRING = new ValidResult("<string>"); |
+ |
+ /** |
* A result object representing the value 'true'. |
*/ |
static ValidResult RESULT_TRUE = new ValidResult(true); |
+ |
/** |
* The value of the expression. |
*/ |
Object _value; |
+ |
/** |
* Initialize a newly created result to represent the given value. |
* @param value the value of the expression |
@@ -887,6 +973,9 @@ |
EvaluationResultImpl add(BinaryExpression node, EvaluationResultImpl rightOperand) => rightOperand.addToValid(node, this); |
EvaluationResultImpl bitAnd(BinaryExpression node, EvaluationResultImpl rightOperand) => rightOperand.bitAndValid(node, this); |
EvaluationResultImpl bitNot(Expression node) { |
+ if (isSomeInt()) { |
+ return RESULT_INT; |
+ } |
if (_value == null) { |
return error(node); |
} else if (_value is int) { |
@@ -907,6 +996,9 @@ |
EvaluationResultImpl lessThanOrEqual(BinaryExpression node, EvaluationResultImpl rightOperand) => rightOperand.lessThanOrEqualValid(node, this); |
EvaluationResultImpl logicalAnd(BinaryExpression node, EvaluationResultImpl rightOperand) => rightOperand.logicalAndValid(node, this); |
EvaluationResultImpl logicalNot(Expression node) { |
+ if (isSomeBool()) { |
+ return RESULT_BOOL; |
+ } |
if (_value == null) { |
return RESULT_TRUE; |
} else if (_value is bool) { |
@@ -917,6 +1009,9 @@ |
EvaluationResultImpl logicalOr(BinaryExpression node, EvaluationResultImpl rightOperand) => rightOperand.logicalOrValid(node, this); |
EvaluationResultImpl minus(BinaryExpression node, EvaluationResultImpl rightOperand) => rightOperand.minusValid(node, this); |
EvaluationResultImpl negated(Expression node) { |
+ if (isSomeNum()) { |
+ return RESULT_INT; |
+ } |
if (_value == null) { |
return error(node); |
} else if (_value is int) { |
@@ -953,6 +1048,12 @@ |
} |
EvaluationResultImpl addToError(BinaryExpression node, ErrorResult leftOperand) => leftOperand; |
EvaluationResultImpl addToValid(BinaryExpression node, ValidResult leftOperand2) { |
+ if (isSomeNum() || leftOperand2.isSomeNum()) { |
+ if (isAnyNum() && leftOperand2.isAnyNum()) { |
+ return RESULT_NUM; |
+ } |
+ return error2(node, CompileTimeErrorCode.CONST_EVAL_TYPE_NUM); |
+ } |
Object leftValue = leftOperand2.value; |
if (leftValue == null) { |
return error(node.leftOperand); |
@@ -979,6 +1080,12 @@ |
} |
EvaluationResultImpl bitAndError(BinaryExpression node, ErrorResult leftOperand) => leftOperand; |
EvaluationResultImpl bitAndValid(BinaryExpression node, ValidResult leftOperand2) { |
+ if (isSomeInt() || leftOperand2.isSomeInt()) { |
+ if (isAnyInt() && leftOperand2.isAnyInt()) { |
+ return RESULT_INT; |
+ } |
+ return error2(node, CompileTimeErrorCode.CONST_EVAL_TYPE_INT); |
+ } |
Object leftValue = leftOperand2.value; |
if (leftValue == null) { |
return error(node.leftOperand); |
@@ -997,6 +1104,12 @@ |
} |
EvaluationResultImpl bitOrError(BinaryExpression node, ErrorResult leftOperand) => leftOperand; |
EvaluationResultImpl bitOrValid(BinaryExpression node, ValidResult leftOperand2) { |
+ if (isSomeInt() || leftOperand2.isSomeInt()) { |
+ if (isAnyInt() && leftOperand2.isAnyInt()) { |
+ return RESULT_INT; |
+ } |
+ return error2(node, CompileTimeErrorCode.CONST_EVAL_TYPE_INT); |
+ } |
Object leftValue = leftOperand2.value; |
if (leftValue == null) { |
return error(node.leftOperand); |
@@ -1015,6 +1128,12 @@ |
} |
EvaluationResultImpl bitXorError(BinaryExpression node, ErrorResult leftOperand) => leftOperand; |
EvaluationResultImpl bitXorValid(BinaryExpression node, ValidResult leftOperand2) { |
+ if (isSomeInt() || leftOperand2.isSomeInt()) { |
+ if (isAnyInt() && leftOperand2.isAnyInt()) { |
+ return RESULT_INT; |
+ } |
+ return error2(node, CompileTimeErrorCode.CONST_EVAL_TYPE_INT); |
+ } |
Object leftValue = leftOperand2.value; |
if (leftValue == null) { |
return error(node.leftOperand); |
@@ -1041,6 +1160,12 @@ |
} |
EvaluationResultImpl divideError(BinaryExpression node, ErrorResult leftOperand) => leftOperand; |
EvaluationResultImpl divideValid(BinaryExpression node, ValidResult leftOperand2) { |
+ if (isSomeNum() || leftOperand2.isSomeNum()) { |
+ if (isAnyNum() && leftOperand2.isAnyNum()) { |
+ return RESULT_NUM; |
+ } |
+ return error2(node, CompileTimeErrorCode.CONST_EVAL_TYPE_NUM); |
+ } |
Object leftValue = leftOperand2.value; |
if (leftValue == null) { |
return error(node.leftOperand); |
@@ -1066,6 +1191,11 @@ |
} |
EvaluationResultImpl equalEqualError(Expression node, ErrorResult leftOperand) => leftOperand; |
EvaluationResultImpl equalEqualValid(Expression node, ValidResult leftOperand) { |
+ if (node is BinaryExpression) { |
+ if (!isAnyNullBoolNumString() || !leftOperand.isAnyNullBoolNumString()) { |
+ return error2(node, CompileTimeErrorCode.CONST_EVAL_TYPE_BOOL_NUM_STRING); |
+ } |
+ } |
Object leftValue = leftOperand.value; |
if (leftValue == null) { |
return valueOf2(_value == null); |
@@ -1099,6 +1229,12 @@ |
EvaluationResultImpl greaterThanError(BinaryExpression node, ErrorResult leftOperand) => leftOperand; |
EvaluationResultImpl greaterThanOrEqualError(BinaryExpression node, ErrorResult leftOperand) => leftOperand; |
EvaluationResultImpl greaterThanOrEqualValid(BinaryExpression node, ValidResult leftOperand2) { |
+ if (isSomeNum() || leftOperand2.isSomeNum()) { |
+ if (isAnyNum() && leftOperand2.isAnyNum()) { |
+ return RESULT_BOOL; |
+ } |
+ return error2(node, CompileTimeErrorCode.CONST_EVAL_TYPE_NUM); |
+ } |
Object leftValue = leftOperand2.value; |
if (leftValue == null) { |
return error(node.leftOperand); |
@@ -1120,6 +1256,12 @@ |
return error(node); |
} |
EvaluationResultImpl greaterThanValid(BinaryExpression node, ValidResult leftOperand2) { |
+ if (isSomeNum() || leftOperand2.isSomeNum()) { |
+ if (isAnyNum() && leftOperand2.isAnyNum()) { |
+ return RESULT_BOOL; |
+ } |
+ return error2(node, CompileTimeErrorCode.CONST_EVAL_TYPE_NUM); |
+ } |
Object leftValue = leftOperand2.value; |
if (leftValue == null) { |
return error(node.leftOperand); |
@@ -1142,6 +1284,12 @@ |
} |
EvaluationResultImpl integerDivideError(BinaryExpression node, ErrorResult leftOperand) => leftOperand; |
EvaluationResultImpl integerDivideValid(BinaryExpression node, ValidResult leftOperand2) { |
+ if (isSomeNum() || leftOperand2.isSomeNum()) { |
+ if (isAnyNum() && leftOperand2.isAnyNum()) { |
+ return RESULT_INT; |
+ } |
+ return error2(node, CompileTimeErrorCode.CONST_EVAL_TYPE_NUM); |
+ } |
Object leftValue = leftOperand2.value; |
if (leftValue == null) { |
return error(node.leftOperand); |
@@ -1171,6 +1319,12 @@ |
EvaluationResultImpl lessThanError(BinaryExpression node, ErrorResult leftOperand) => leftOperand; |
EvaluationResultImpl lessThanOrEqualError(BinaryExpression node, ErrorResult leftOperand) => leftOperand; |
EvaluationResultImpl lessThanOrEqualValid(BinaryExpression node, ValidResult leftOperand2) { |
+ if (isSomeNum() || leftOperand2.isSomeNum()) { |
+ if (isAnyNum() && leftOperand2.isAnyNum()) { |
+ return RESULT_BOOL; |
+ } |
+ return error2(node, CompileTimeErrorCode.CONST_EVAL_TYPE_NUM); |
+ } |
Object leftValue = leftOperand2.value; |
if (leftValue == null) { |
return error(node.leftOperand); |
@@ -1192,6 +1346,12 @@ |
return error(node); |
} |
EvaluationResultImpl lessThanValid(BinaryExpression node, ValidResult leftOperand2) { |
+ if (isSomeNum() || leftOperand2.isSomeNum()) { |
+ if (isAnyNum() && leftOperand2.isAnyNum()) { |
+ return RESULT_BOOL; |
+ } |
+ return error2(node, CompileTimeErrorCode.CONST_EVAL_TYPE_NUM); |
+ } |
Object leftValue = leftOperand2.value; |
if (leftValue == null) { |
return error(node.leftOperand); |
@@ -1214,14 +1374,29 @@ |
} |
EvaluationResultImpl logicalAndError(BinaryExpression node, ErrorResult leftOperand) => leftOperand; |
EvaluationResultImpl logicalAndValid(BinaryExpression node, ValidResult leftOperand) { |
+ if (isSomeBool() || leftOperand.isSomeBool()) { |
+ if (isAnyBool() && leftOperand.isAnyBool()) { |
+ return RESULT_BOOL; |
+ } |
+ return error2(node, CompileTimeErrorCode.CONST_EVAL_TYPE_BOOL); |
+ } |
Object leftValue = leftOperand.value; |
- if (leftValue is bool && ((leftValue as bool))) { |
- return booleanConversion(node.rightOperand, _value); |
+ if (leftValue is bool) { |
+ if (((leftValue as bool))) { |
+ return booleanConversion(node.rightOperand, _value); |
+ } |
+ return RESULT_FALSE; |
} |
- return RESULT_FALSE; |
+ return error(node); |
} |
EvaluationResultImpl logicalOrError(BinaryExpression node, ErrorResult leftOperand) => leftOperand; |
EvaluationResultImpl logicalOrValid(BinaryExpression node, ValidResult leftOperand) { |
+ if (isSomeBool() || leftOperand.isSomeBool()) { |
+ if (isAnyBool() && leftOperand.isAnyBool()) { |
+ return RESULT_BOOL; |
+ } |
+ return error2(node, CompileTimeErrorCode.CONST_EVAL_TYPE_BOOL); |
+ } |
Object leftValue = leftOperand.value; |
if (leftValue is bool && ((leftValue as bool))) { |
return RESULT_TRUE; |
@@ -1230,6 +1405,12 @@ |
} |
EvaluationResultImpl minusError(BinaryExpression node, ErrorResult leftOperand) => leftOperand; |
EvaluationResultImpl minusValid(BinaryExpression node, ValidResult leftOperand2) { |
+ if (isSomeNum() || leftOperand2.isSomeNum()) { |
+ if (isAnyNum() && leftOperand2.isAnyNum()) { |
+ return RESULT_NUM; |
+ } |
+ return error2(node, CompileTimeErrorCode.CONST_EVAL_TYPE_NUM); |
+ } |
Object leftValue = leftOperand2.value; |
if (leftValue == null) { |
return error(node.leftOperand); |
@@ -1252,6 +1433,9 @@ |
} |
EvaluationResultImpl notEqualError(BinaryExpression node, ErrorResult leftOperand) => leftOperand; |
EvaluationResultImpl notEqualValid(BinaryExpression node, ValidResult leftOperand) { |
+ if (!isAnyNullBoolNumString() || !leftOperand.isAnyNullBoolNumString()) { |
+ return error2(node, CompileTimeErrorCode.CONST_EVAL_TYPE_BOOL_NUM_STRING); |
+ } |
Object leftValue = leftOperand.value; |
if (leftValue == null) { |
return valueOf2(_value != null); |
@@ -1284,6 +1468,12 @@ |
} |
EvaluationResultImpl remainderError(BinaryExpression node, ErrorResult leftOperand) => leftOperand; |
EvaluationResultImpl remainderValid(BinaryExpression node, ValidResult leftOperand2) { |
+ if (isSomeNum() || leftOperand2.isSomeNum()) { |
+ if (isAnyNum() && leftOperand2.isAnyNum()) { |
+ return RESULT_NUM; |
+ } |
+ return error2(node, CompileTimeErrorCode.CONST_EVAL_TYPE_NUM); |
+ } |
Object leftValue = leftOperand2.value; |
if (leftValue == null) { |
return error(node.leftOperand); |
@@ -1309,6 +1499,12 @@ |
} |
EvaluationResultImpl shiftLeftError(BinaryExpression node, ErrorResult leftOperand) => leftOperand; |
EvaluationResultImpl shiftLeftValid(BinaryExpression node, ValidResult leftOperand2) { |
+ if (isSomeInt() || leftOperand2.isSomeInt()) { |
+ if (isAnyInt() && leftOperand2.isAnyInt()) { |
+ return RESULT_INT; |
+ } |
+ return error2(node, CompileTimeErrorCode.CONST_EVAL_TYPE_INT); |
+ } |
Object leftValue = leftOperand2.value; |
if (leftValue == null) { |
return error(node.leftOperand); |
@@ -1327,6 +1523,12 @@ |
} |
EvaluationResultImpl shiftRightError(BinaryExpression node, ErrorResult leftOperand) => leftOperand; |
EvaluationResultImpl shiftRightValid(BinaryExpression node, ValidResult leftOperand2) { |
+ if (isSomeInt() || leftOperand2.isSomeInt()) { |
+ if (isAnyInt() && leftOperand2.isAnyInt()) { |
+ return RESULT_INT; |
+ } |
+ return error2(node, CompileTimeErrorCode.CONST_EVAL_TYPE_INT); |
+ } |
Object leftValue = leftOperand2.value; |
if (leftValue == null) { |
return error(node.leftOperand); |
@@ -1345,6 +1547,12 @@ |
} |
EvaluationResultImpl timesError(BinaryExpression node, ErrorResult leftOperand) => leftOperand; |
EvaluationResultImpl timesValid(BinaryExpression node, ValidResult leftOperand2) { |
+ if (isSomeNum() || leftOperand2.isSomeNum()) { |
+ if (isAnyNum() && leftOperand2.isAnyNum()) { |
+ return RESULT_NUM; |
+ } |
+ return error2(node, CompileTimeErrorCode.CONST_EVAL_TYPE_NUM); |
+ } |
Object leftValue = leftOperand2.value; |
if (leftValue == null) { |
return error(node.leftOperand); |
@@ -1365,6 +1573,8 @@ |
} |
return error(node); |
} |
+ bool isNull() => identical(this, RESULT_NULL); |
+ |
/** |
* Return the result of applying boolean conversion to the given value. |
* @param node the node against which errors should be reported |
@@ -1372,14 +1582,17 @@ |
* @return the result of applying boolean conversion to the given value |
*/ |
EvaluationResultImpl booleanConversion(ASTNode node, Object value) { |
- if (value == null) { |
- return error(node); |
- } else if (value is bool && ((value as bool))) { |
- return RESULT_TRUE; |
+ if (value is bool) { |
+ if (((value as bool))) { |
+ return RESULT_TRUE; |
+ } else { |
+ return RESULT_FALSE; |
+ } |
} |
- return RESULT_FALSE; |
+ return error(node); |
} |
ErrorResult error(ASTNode node) => error2(node, CompileTimeErrorCode.INVALID_CONSTANT); |
+ |
/** |
* Return a result object representing an error associated with the given node. |
* @param node the AST node associated with the error |
@@ -1387,7 +1600,43 @@ |
* @return a result object representing an error associated with the given node |
*/ |
ErrorResult error2(ASTNode node, ErrorCode code) => new ErrorResult.con1(node, code); |
+ |
+ /** |
+ * Checks if this result has type "bool", with known or unknown value. |
+ */ |
+ bool isAnyBool() => isSomeBool() || identical(this, RESULT_TRUE) || identical(this, RESULT_FALSE); |
+ |
+ /** |
+ * Checks if this result has type "int", with known or unknown value. |
+ */ |
+ bool isAnyInt() => identical(this, RESULT_INT) || _value is int; |
+ |
+ /** |
+ * Checks if this result has one of the types - "bool", "num" or "string"; or may be {@code null}. |
+ */ |
+ bool isAnyNullBoolNumString() => isNull() || isAnyBool() || isAnyNum() || _value is String; |
+ |
+ /** |
+ * Checks if this result has type "num", with known or unknown value. |
+ */ |
+ bool isAnyNum() => isSomeNum() || _value is num; |
+ |
+ /** |
+ * Checks if this result has type "bool", exact value of which we don't know. |
+ */ |
+ bool isSomeBool() => identical(this, RESULT_BOOL); |
+ |
+ /** |
+ * Checks if this result has type "int", exact value of which we don't know. |
+ */ |
+ bool isSomeInt() => identical(this, RESULT_INT); |
+ |
+ /** |
+ * Checks if this result has type "num" (or "int"), exact value of which we don't know. |
+ */ |
+ bool isSomeNum() => identical(this, RESULT_DYNAMIC) || identical(this, RESULT_INT) || identical(this, RESULT_NUM); |
double toDouble(int value) => value.toDouble(); |
+ |
/** |
* Return an error result that is the union of the two given error results. |
* @param firstError the first error to be combined |
@@ -1395,24 +1644,28 @@ |
* @return an error result that is the union of the two given error results |
*/ |
ErrorResult union(ErrorResult firstError, ErrorResult secondError) => new ErrorResult.con2(firstError, secondError); |
+ |
/** |
* Return a result object representing the given value. |
* @param value the value to be represented as a result object |
* @return a result object representing the given value |
*/ |
ValidResult valueOf(int value) => new ValidResult(value); |
+ |
/** |
* Return a result object representing the given value. |
* @param value the value to be represented as a result object |
* @return a result object representing the given value |
*/ |
ValidResult valueOf2(bool value) => value ? RESULT_TRUE : RESULT_FALSE; |
+ |
/** |
* Return a result object representing the given value. |
* @param value the value to be represented as a result object |
* @return a result object representing the given value |
*/ |
ValidResult valueOf3(double value) => new ValidResult(value); |
+ |
/** |
* Return a result object representing the given value. |
* @param value the value to be represented as a result object |