Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(18)

Unified Diff: pkg/analyzer/lib/src/generated/constant.dart

Issue 259773005: New analyzer snapshot. Sorted unit members. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 6 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: pkg/analyzer/lib/src/generated/constant.dart
diff --git a/pkg/analyzer/lib/src/generated/constant.dart b/pkg/analyzer/lib/src/generated/constant.dart
index 967a31cbe898eb9d99bea861da9f04cf63c6fd0e..b2dd26104132e7d2f9ff94a4d13e87cc176b1258 100644
--- a/pkg/analyzer/lib/src/generated/constant.dart
+++ b/pkg/analyzer/lib/src/generated/constant.dart
@@ -20,6 +20,128 @@ import 'utilities_dart.dart' show ParameterKind;
import 'utilities_collection.dart';
/**
+ * Instances of the class `BoolState` represent the state of an object representing a boolean
+ * value.
+ */
+class BoolState extends InstanceState {
+ /**
+ * The value of this instance.
+ */
+ final bool value;
+
+ /**
+ * An instance representing the boolean value 'false'.
+ */
+ static BoolState FALSE_STATE = new BoolState(false);
+
+ /**
+ * An instance representing the boolean value 'true'.
+ */
+ static BoolState TRUE_STATE = new BoolState(true);
+
+ /**
+ * A state that can be used to represent a boolean whose value is not known.
+ */
+ static BoolState UNKNOWN_VALUE = new BoolState(null);
+
+ /**
+ * Return the boolean state representing the given boolean value.
+ *
+ * @param value the value to be represented
+ * @return the boolean state representing the given boolean value
+ */
+ static BoolState from(bool value) => value ? BoolState.TRUE_STATE : BoolState.FALSE_STATE;
+
+ /**
+ * Initialize a newly created state to represent the given value.
+ *
+ * @param value the value of this instance
+ */
+ BoolState(this.value);
+
+ @override
+ BoolState convertToBool() => this;
+
+ @override
+ StringState convertToString() {
+ if (value == null) {
+ return StringState.UNKNOWN_VALUE;
+ }
+ return new StringState(value ? "true" : "false");
+ }
+
+ @override
+ BoolState equalEqual(InstanceState rightOperand) {
+ assertBoolNumStringOrNull(rightOperand);
+ if (value == null) {
+ return UNKNOWN_VALUE;
+ }
+ if (rightOperand is BoolState) {
+ bool rightValue = rightOperand.value;
+ if (rightValue == null) {
+ return UNKNOWN_VALUE;
+ }
+ return BoolState.from(identical(value, rightValue));
+ } else if (rightOperand is DynamicState) {
+ return UNKNOWN_VALUE;
+ }
+ return FALSE_STATE;
+ }
+
+ @override
+ bool operator ==(Object object) => object is BoolState && identical(value, object.value);
+
+ @override
+ String get typeName => "bool";
+
+ @override
+ bool get hasExactValue => true;
+
+ @override
+ int get hashCode => value == null ? 0 : (value ? 2 : 3);
+
+ /**
+ * Return `true` if this object represents an object whose type is 'bool'.
+ *
+ * @return `true` if this object represents a boolean value
+ */
+ @override
+ bool get isBool => true;
+
+ @override
+ bool get isBoolNumStringOrNull => true;
+
+ @override
+ BoolState logicalAnd(InstanceState rightOperand) {
+ assertBool(rightOperand);
+ if (value == null) {
+ return UNKNOWN_VALUE;
+ }
+ return value ? rightOperand.convertToBool() : FALSE_STATE;
+ }
+
+ @override
+ BoolState logicalNot() {
+ if (value == null) {
+ return UNKNOWN_VALUE;
+ }
+ return value ? FALSE_STATE : TRUE_STATE;
+ }
+
+ @override
+ BoolState logicalOr(InstanceState rightOperand) {
+ assertBool(rightOperand);
+ if (value == null) {
+ return UNKNOWN_VALUE;
+ }
+ return value ? TRUE_STATE : rightOperand.convertToBool();
+ }
+
+ @override
+ String toString() => value == null ? "-unknown-" : (value ? "true" : "false");
+}
+
+/**
* Instances of the class `ConstantEvaluator` evaluate constant expressions to produce their
* compile-time value. According to the Dart Language Specification: <blockquote> A constant
* expression is one of the following:
@@ -96,257 +218,116 @@ class ConstantEvaluator {
}
/**
- * The interface `DartObject` defines the behavior of objects that represent the state of a
- * Dart object.
+ * Instances of the class `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.
*/
-abstract class DartObject {
+class ConstantFinder extends RecursiveAstVisitor<Object> {
/**
- * Return the boolean value of this object, or `null` if either the value of this object is
- * not known or this object is not of type 'bool'.
- *
- * @return the boolean value of this object
+ * A table mapping constant variable elements to the declarations of those variables.
*/
- bool get boolValue;
+ final Map<VariableElement, VariableDeclaration> variableMap = new Map<VariableElement, VariableDeclaration>();
- /**
- * Return the floating point value of this object, or `null` if either the value of this
- * object is not known or this object is not of type 'double'.
- *
- * @return the floating point value of this object
- */
- double get doubleValue;
+ @override
+ Object visitVariableDeclaration(VariableDeclaration node) {
+ super.visitVariableDeclaration(node);
+ Expression initializer = node.initializer;
+ if (initializer != null && node.isConst) {
+ VariableElement element = node.element;
+ if (element != null) {
+ variableMap[element] = node;
+ }
+ }
+ return null;
+ }
+}
+/**
+ * Instances of the class `ConstantValueComputer` compute the values of constant variables in
+ * one or more compilation units. The expected usage pattern is for the compilation units to be
+ * added to this computer using the method [add] and then for the method
+ * [computeValues] to be invoked exactly once. Any use of an instance after invoking the
+ * method [computeValues] will result in unpredictable behavior.
+ */
+class ConstantValueComputer {
/**
- * Return the integer value of this object, or `null` if either the value of this object is
- * not known or this object is not of type 'int'.
- *
- * @return the integer value of this object
+ * The type provider used to access the known types.
*/
- int get intValue;
+ final TypeProvider _typeProvider;
/**
- * Return the string value of this object, or `null` if either the value of this object is
- * not known or this object is not of type 'String'.
- *
- * @return the string value of this object
+ * The object used to find constant variables in the compilation units that were added.
*/
- String get stringValue;
+ ConstantFinder _constantFinder = new ConstantFinder();
/**
- * Return the run-time type of this object.
- *
- * @return the run-time type of this object
+ * 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.
*/
- InterfaceType get type;
+ DirectedGraph<VariableElement> _referenceGraph = new DirectedGraph<VariableElement>();
/**
- * Return this object's value if it can be represented exactly, or `null` if either the
- * value cannot be represented exactly or if the value is `null`. Clients should use
- * [hasExactValue] to distinguish between these two cases.
- *
- * @return this object's value
+ * A table mapping constant variables to the declarations of those variables.
*/
- Object get value;
+ Map<VariableElement, VariableDeclaration> _declarationMap;
/**
- * Return `true` if this object's value can be represented exactly.
+ * Initialize a newly created constant value computer.
*
- * @return `true` if this object's value can be represented exactly
+ * @param typeProvider the type provider used to access known types
*/
- bool get hasExactValue;
+ ConstantValueComputer(this._typeProvider);
/**
- * Return `true` if this object represents the value 'false'.
+ * Add the constant variables in the given compilation unit to the list of constant variables
+ * whose value needs to be computed.
*
- * @return `true` if this object represents the value 'false'
+ * @param unit the compilation unit defining the constant variables to be added
*/
- bool get isFalse;
+ void add(CompilationUnit unit) {
+ unit.accept(_constantFinder);
+ }
/**
- * Return `true` if this object represents the value 'null'.
- *
- * @return `true` if this object represents the value 'null'
+ * Compute values for all of the constant variables in the compilation units that were added.
*/
- bool get isNull;
+ void computeValues() {
+ _declarationMap = _constantFinder.variableMap;
+ for (MapEntry<VariableElement, VariableDeclaration> entry in getMapEntrySet(_declarationMap)) {
+ VariableElement element = entry.getKey();
+ ReferenceFinder referenceFinder = new ReferenceFinder(element, _referenceGraph);
+ _referenceGraph.addNode(element);
+ entry.getValue().initializer.accept(referenceFinder);
+ }
+ while (!_referenceGraph.isEmpty) {
+ VariableElement element = _referenceGraph.removeSink();
+ while (element != null) {
+ _computeValueFor(element);
+ element = _referenceGraph.removeSink();
+ }
+ if (!_referenceGraph.isEmpty) {
+ List<VariableElement> variablesInCycle = _referenceGraph.findCycle();
+ if (variablesInCycle == null) {
+ //
+ // This should not happen. Either the graph should be empty, or there should be at least
+ // one sink, or there should be a cycle. If this does happen we exit to prevent an
+ // infinite loop.
+ //
+ AnalysisEngine.instance.logger.logError("Exiting constant value computer with ${_referenceGraph.nodeCount} variables that are neither sinks nor in a cycle");
+ return;
+ }
+ for (VariableElement variable in variablesInCycle) {
+ _generateCycleError(variablesInCycle, variable);
+ }
+ _referenceGraph.removeAllNodes(variablesInCycle);
+ }
+ }
+ }
/**
- * Return `true` if this object represents the value 'true'.
+ * Compute a value for the given variable.
*
- * @return `true` if this object represents the value 'true'
- */
- bool get isTrue;
-}
-
-/**
- * Instances of the class `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.
- *
- * @param errors the errors that should be reported for the expression(s) that were evaluated
- * @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.
- *
- * @param value the value of the expression
- * @return the result of evaluating an expression that is a compile-time constant
- */
- static EvaluationResult forValue(DartObject value) => new EvaluationResult(value, null);
-
- /**
- * The value of the expression.
- */
- final DartObject value;
-
- /**
- * The errors that should be reported for the expression(s) that were evaluated.
- */
- final List<AnalysisError> _errors;
-
- /**
- * Initialize a newly created result object with the given state. Clients should use one of the
- * factory methods: [forErrors] and [forValue].
- *
- * @param value the value of the expression
- * @param errors the errors that should be reported for the expression(s) that were evaluated
- */
- EvaluationResult(this.value, this._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
- * the expression is not a valid compile time constant if the errors would have been reported by
- * other parts of the analysis engine.
- */
- List<AnalysisError> get errors => _errors == null ? AnalysisError.NO_ERRORS : _errors;
-
- /**
- * Return `true` if the expression is a compile-time constant expression that would not
- * throw an exception when evaluated.
- *
- * @return `true` if the expression is a valid compile-time constant expression
- */
- bool get isValid => _errors == null;
-}
-
-/**
- * Instances of the class `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.
- */
- final Map<VariableElement, VariableDeclaration> variableMap = new Map<VariableElement, VariableDeclaration>();
-
- @override
- Object visitVariableDeclaration(VariableDeclaration node) {
- super.visitVariableDeclaration(node);
- Expression initializer = node.initializer;
- if (initializer != null && node.isConst) {
- VariableElement element = node.element;
- if (element != null) {
- variableMap[element] = node;
- }
- }
- return null;
- }
-}
-
-/**
- * Instances of the class `ConstantValueComputer` compute the values of constant variables in
- * one or more compilation units. The expected usage pattern is for the compilation units to be
- * added to this computer using the method [add] and then for the method
- * [computeValues] to be invoked exactly once. Any use of an instance after invoking the
- * method [computeValues] will result in unpredictable behavior.
- */
-class ConstantValueComputer {
- /**
- * The type provider used to access the known types.
- */
- final TypeProvider _typeProvider;
-
- /**
- * 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.
- *
- * @param typeProvider the type provider used to access known types
- */
- ConstantValueComputer(this._typeProvider);
-
- /**
- * 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
- */
- void add(CompilationUnit unit) {
- unit.accept(_constantFinder);
- }
-
- /**
- * Compute values for all of the constant variables in the compilation units that were added.
- */
- void computeValues() {
- _declarationMap = _constantFinder.variableMap;
- for (MapEntry<VariableElement, VariableDeclaration> entry in getMapEntrySet(_declarationMap)) {
- VariableElement element = entry.getKey();
- ReferenceFinder referenceFinder = new ReferenceFinder(element, _referenceGraph);
- _referenceGraph.addNode(element);
- entry.getValue().initializer.accept(referenceFinder);
- }
- while (!_referenceGraph.isEmpty) {
- VariableElement element = _referenceGraph.removeSink();
- while (element != null) {
- _computeValueFor(element);
- element = _referenceGraph.removeSink();
- }
- if (!_referenceGraph.isEmpty) {
- List<VariableElement> variablesInCycle = _referenceGraph.findCycle();
- if (variablesInCycle == null) {
- //
- // This should not happen. Either the graph should be empty, or there should be at least
- // one sink, or there should be a cycle. If this does happen we exit to prevent an
- // infinite loop.
- //
- AnalysisEngine.instance.logger.logError("Exiting constant value computer with ${_referenceGraph.nodeCount} variables that are neither sinks nor in a cycle");
- return;
- }
- for (VariableElement variable in variablesInCycle) {
- _generateCycleError(variablesInCycle, variable);
- }
- _referenceGraph.removeAllNodes(variablesInCycle);
- }
- }
- }
-
- /**
- * Compute a value for the given variable.
- *
- * @param variable the variable for which a value is to be computed
+ * @param variable the variable for which a value is to be computed
*/
void _computeValueFor(VariableElement variable) {
VariableDeclaration declaration = _declarationMap[variable];
@@ -883,2744 +864,2757 @@ class ConstantVisitor extends UnifyingAstVisitor<EvaluationResultImpl> {
}
/**
- * Instances of the class `ErrorResult` represent the result of evaluating an expression that
- * is not a valid compile time constant.
+ * The interface `DartObject` defines the behavior of objects that represent the state of a
+ * Dart object.
*/
-class ErrorResult extends EvaluationResultImpl {
+abstract class DartObject {
/**
- * The errors that prevent the expression from being a valid compile time constant.
+ * Return the boolean value of this object, or `null` if either the value of this object is
+ * not known or this object is not of type 'bool'.
+ *
+ * @return the boolean value of this object
*/
- List<ErrorResult_ErrorData> _errors = new List<ErrorResult_ErrorData>();
+ bool get boolValue;
/**
- * Initialize a newly created result representing the error with the given code reported against
- * the given node.
+ * Return the floating point value of this object, or `null` if either the value of this
+ * object is not known or this object is not of type 'double'.
*
- * @param node the node against which the error should be reported
- * @param errorCode the error code for the error to be generated
+ * @return the floating point value of this object
*/
- ErrorResult.con1(AstNode node, ErrorCode errorCode) {
- _errors.add(new ErrorResult_ErrorData(node, errorCode));
- }
+ double get doubleValue;
/**
- * Initialize a newly created result to represent the union of the errors in the given result
- * objects.
+ * Return the integer value of this object, or `null` if either the value of this object is
+ * not known or this object is not of type 'int'.
*
- * @param firstResult the first set of results being merged
- * @param secondResult the second set of results being merged
+ * @return the integer value of this object
*/
- ErrorResult.con2(ErrorResult firstResult, ErrorResult secondResult) {
- _errors.addAll(firstResult._errors);
- _errors.addAll(secondResult._errors);
- }
+ int get intValue;
- @override
- EvaluationResultImpl add(TypeProvider typeProvider, BinaryExpression node, EvaluationResultImpl rightOperand) => rightOperand.addToError(node, this);
+ /**
+ * Return the string value of this object, or `null` if either the value of this object is
+ * not known or this object is not of type 'String'.
+ *
+ * @return the string value of this object
+ */
+ String get stringValue;
- @override
- EvaluationResultImpl applyBooleanConversion(TypeProvider typeProvider, AstNode node) => this;
+ /**
+ * Return the run-time type of this object.
+ *
+ * @return the run-time type of this object
+ */
+ InterfaceType get type;
- @override
- EvaluationResultImpl bitAnd(TypeProvider typeProvider, BinaryExpression node, EvaluationResultImpl rightOperand) => rightOperand.bitAndError(node, this);
+ /**
+ * Return this object's value if it can be represented exactly, or `null` if either the
+ * value cannot be represented exactly or if the value is `null`. Clients should use
+ * [hasExactValue] to distinguish between these two cases.
+ *
+ * @return this object's value
+ */
+ Object get value;
- @override
- EvaluationResultImpl bitNot(TypeProvider typeProvider, Expression node) => this;
+ /**
+ * Return `true` if this object's value can be represented exactly.
+ *
+ * @return `true` if this object's value can be represented exactly
+ */
+ bool get hasExactValue;
- @override
- EvaluationResultImpl bitOr(TypeProvider typeProvider, BinaryExpression node, EvaluationResultImpl rightOperand) => rightOperand.bitOrError(node, this);
+ /**
+ * Return `true` if this object represents the value 'false'.
+ *
+ * @return `true` if this object represents the value 'false'
+ */
+ bool get isFalse;
- @override
- EvaluationResultImpl bitXor(TypeProvider typeProvider, BinaryExpression node, EvaluationResultImpl rightOperand) => rightOperand.bitXorError(node, this);
+ /**
+ * Return `true` if this object represents the value 'null'.
+ *
+ * @return `true` if this object represents the value 'null'
+ */
+ bool get isNull;
- @override
- EvaluationResultImpl concatenate(TypeProvider typeProvider, Expression node, EvaluationResultImpl rightOperand) => rightOperand.concatenateError(node, this);
+ /**
+ * Return `true` if this object represents the value 'true'.
+ *
+ * @return `true` if this object represents the value 'true'
+ */
+ bool get isTrue;
+}
- @override
- EvaluationResultImpl divide(TypeProvider typeProvider, BinaryExpression node, EvaluationResultImpl rightOperand) => rightOperand.divideError(node, this);
+/**
+ * Instances of the class `DartObjectImpl` represent an instance of a Dart class.
+ */
+class DartObjectImpl implements DartObject {
+ /**
+ * The run-time type of this object.
+ */
+ final InterfaceType type;
- @override
- EvaluationResultImpl equalEqual(TypeProvider typeProvider, Expression node, EvaluationResultImpl rightOperand) => rightOperand.equalEqualError(node, this);
+ /**
+ * The state of the object.
+ */
+ final InstanceState _state;
- @override
- bool equalValues(TypeProvider typeProvider, EvaluationResultImpl result) => false;
+ /**
+ * Initialize a newly created object to have the given type and state.
+ *
+ * @param type the run-time type of this object
+ * @param state the state of the object
+ */
+ DartObjectImpl(this.type, this._state);
- List<ErrorResult_ErrorData> get errorData => _errors;
+ /**
+ * Return the result of invoking the '+' operator on this object with the given argument.
+ *
+ * @param typeProvider the type provider used to find known types
+ * @param rightOperand the right-hand operand of the operation
+ * @return the result of invoking the '+' operator on this object with the given argument
+ * @throws EvaluationException if the operator is not appropriate for an object of this kind
+ */
+ DartObjectImpl add(TypeProvider typeProvider, DartObjectImpl rightOperand) {
+ InstanceState result = _state.add(rightOperand._state);
+ if (result is IntState) {
+ return new DartObjectImpl(typeProvider.intType, result);
+ } else if (result is DoubleState) {
+ return new DartObjectImpl(typeProvider.doubleType, result);
+ } else if (result is NumState) {
+ return new DartObjectImpl(typeProvider.numType, result);
+ }
+ // We should never get here.
+ throw new IllegalStateException("add returned a ${result.runtimeType.toString()}");
+ }
- @override
- EvaluationResultImpl greaterThan(TypeProvider typeProvider, BinaryExpression node, EvaluationResultImpl rightOperand) => rightOperand.greaterThanError(node, this);
+ /**
+ * Return the result of invoking the '&' operator on this object with the given argument.
+ *
+ * @param typeProvider the type provider used to find known types
+ * @param rightOperand the right-hand operand of the operation
+ * @return the result of invoking the '&' operator on this object with the given argument
+ * @throws EvaluationException if the operator is not appropriate for an object of this kind
+ */
+ DartObjectImpl bitAnd(TypeProvider typeProvider, DartObjectImpl rightOperand) => new DartObjectImpl(typeProvider.intType, _state.bitAnd(rightOperand._state));
- @override
- EvaluationResultImpl greaterThanOrEqual(TypeProvider typeProvider, BinaryExpression node, EvaluationResultImpl rightOperand) => rightOperand.greaterThanOrEqualError(node, this);
+ /**
+ * Return the result of invoking the '~' operator on this object.
+ *
+ * @param typeProvider the type provider used to find known types
+ * @return the result of invoking the '~' operator on this object
+ * @throws EvaluationException if the operator is not appropriate for an object of this kind
+ */
+ DartObjectImpl bitNot(TypeProvider typeProvider) => new DartObjectImpl(typeProvider.intType, _state.bitNot());
- @override
- EvaluationResultImpl integerDivide(TypeProvider typeProvider, BinaryExpression node, EvaluationResultImpl rightOperand) => rightOperand.integerDivideError(node, this);
+ /**
+ * Return the result of invoking the '|' operator on this object with the given argument.
+ *
+ * @param typeProvider the type provider used to find known types
+ * @param rightOperand the right-hand operand of the operation
+ * @return the result of invoking the '|' operator on this object with the given argument
+ * @throws EvaluationException if the operator is not appropriate for an object of this kind
+ */
+ DartObjectImpl bitOr(TypeProvider typeProvider, DartObjectImpl rightOperand) => new DartObjectImpl(typeProvider.intType, _state.bitOr(rightOperand._state));
- @override
- EvaluationResultImpl integerDivideValid(TypeProvider typeProvider, BinaryExpression node, ValidResult leftOperand) => this;
+ /**
+ * Return the result of invoking the '^' operator on this object with the given argument.
+ *
+ * @param typeProvider the type provider used to find known types
+ * @param rightOperand the right-hand operand of the operation
+ * @return the result of invoking the '^' operator on this object with the given argument
+ * @throws EvaluationException if the operator is not appropriate for an object of this kind
+ */
+ DartObjectImpl bitXor(TypeProvider typeProvider, DartObjectImpl rightOperand) => new DartObjectImpl(typeProvider.intType, _state.bitXor(rightOperand._state));
- @override
- EvaluationResultImpl lessThan(TypeProvider typeProvider, BinaryExpression node, EvaluationResultImpl rightOperand) => rightOperand.lessThanError(node, this);
+ /**
+ * Return the result of invoking the ' ' operator on this object with the given argument.
+ *
+ * @param typeProvider the type provider used to find known types
+ * @param rightOperand the right-hand operand of the operation
+ * @return the result of invoking the ' ' operator on this object with the given argument
+ * @throws EvaluationException if the operator is not appropriate for an object of this kind
+ */
+ DartObjectImpl concatenate(TypeProvider typeProvider, DartObjectImpl rightOperand) => new DartObjectImpl(typeProvider.stringType, _state.concatenate(rightOperand._state));
- @override
- EvaluationResultImpl lessThanOrEqual(TypeProvider typeProvider, BinaryExpression node, EvaluationResultImpl rightOperand) => rightOperand.lessThanOrEqualError(node, this);
+ /**
+ * Return the result of applying boolean conversion to this object.
+ *
+ * @param typeProvider the type provider used to find known types
+ * @return the result of applying boolean conversion to this object
+ * @throws EvaluationException if the operator is not appropriate for an object of this kind
+ */
+ DartObjectImpl convertToBool(TypeProvider typeProvider) {
+ InterfaceType boolType = typeProvider.boolType;
+ if (identical(type, boolType)) {
+ return this;
+ }
+ return new DartObjectImpl(boolType, _state.convertToBool());
+ }
- @override
- EvaluationResultImpl logicalAnd(TypeProvider typeProvider, BinaryExpression node, EvaluationResultImpl rightOperand) => rightOperand.logicalAndError(node, this);
+ /**
+ * Return the result of invoking the '/' operator on this object with the given argument.
+ *
+ * @param typeProvider the type provider used to find known types
+ * @param rightOperand the right-hand operand of the operation
+ * @return the result of invoking the '/' operator on this object with the given argument
+ * @throws EvaluationException if the operator is not appropriate for an object of this kind
+ */
+ DartObjectImpl divide(TypeProvider typeProvider, DartObjectImpl rightOperand) {
+ InstanceState result = _state.divide(rightOperand._state);
+ if (result is IntState) {
+ return new DartObjectImpl(typeProvider.intType, result);
+ } else if (result is DoubleState) {
+ return new DartObjectImpl(typeProvider.doubleType, result);
+ } else if (result is NumState) {
+ return new DartObjectImpl(typeProvider.numType, result);
+ }
+ // We should never get here.
+ throw new IllegalStateException("divide returned a ${result.runtimeType.toString()}");
+ }
- @override
- EvaluationResultImpl logicalNot(TypeProvider typeProvider, Expression node) => this;
+ /**
+ * Return the result of invoking the '==' operator on this object with the given argument.
+ *
+ * @param typeProvider the type provider used to find known types
+ * @param rightOperand the right-hand operand of the operation
+ * @return the result of invoking the '==' operator on this object with the given argument
+ * @throws EvaluationException if the operator is not appropriate for an object of this kind
+ */
+ DartObjectImpl equalEqual(TypeProvider typeProvider, DartObjectImpl rightOperand) {
+ if (type != rightOperand.type) {
+ String typeName = type.name;
+ if (!(typeName == "bool" || typeName == "double" || typeName == "int" || typeName == "num" || typeName == "String" || typeName == "Null" || type.isDynamic)) {
+ throw new EvaluationException(CompileTimeErrorCode.CONST_EVAL_TYPE_BOOL_NUM_STRING);
+ }
+ }
+ return new DartObjectImpl(typeProvider.boolType, _state.equalEqual(rightOperand._state));
+ }
@override
- EvaluationResultImpl logicalOr(TypeProvider typeProvider, BinaryExpression node, EvaluationResultImpl rightOperand) => rightOperand.logicalOrError(node, this);
+ bool operator ==(Object object) {
+ if (object is! DartObjectImpl) {
+ return false;
+ }
+ DartObjectImpl dartObject = object as DartObjectImpl;
+ return type == dartObject.type && _state == dartObject._state;
+ }
@override
- EvaluationResultImpl minus(TypeProvider typeProvider, BinaryExpression node, EvaluationResultImpl rightOperand) => rightOperand.minusError(node, this);
+ bool get boolValue {
+ if (_state is BoolState) {
+ return (_state as BoolState).value;
+ }
+ return null;
+ }
@override
- EvaluationResultImpl negated(TypeProvider typeProvider, Expression node) => this;
+ double get doubleValue {
+ if (_state is DoubleState) {
+ return (_state as DoubleState).value;
+ }
+ return null;
+ }
@override
- EvaluationResultImpl notEqual(TypeProvider typeProvider, BinaryExpression node, EvaluationResultImpl rightOperand) => rightOperand.notEqualError(node, this);
+ int get intValue {
+ if (_state is IntState) {
+ return (_state as IntState).value;
+ }
+ return null;
+ }
@override
- EvaluationResultImpl performToString(TypeProvider typeProvider, AstNode node) => this;
+ String get stringValue {
+ if (_state is StringState) {
+ return (_state as StringState).value;
+ }
+ return null;
+ }
@override
- EvaluationResultImpl remainder(TypeProvider typeProvider, BinaryExpression node, EvaluationResultImpl rightOperand) => rightOperand.remainderError(node, this);
+ Object get value => _state.value;
- @override
- EvaluationResultImpl shiftLeft(TypeProvider typeProvider, BinaryExpression node, EvaluationResultImpl rightOperand) => rightOperand.shiftLeftError(node, this);
+ /**
+ * Return the result of invoking the '&gt;' operator on this object with the given argument.
+ *
+ * @param typeProvider the type provider used to find known types
+ * @param rightOperand the right-hand operand of the operation
+ * @return the result of invoking the '&gt;' operator on this object with the given argument
+ * @throws EvaluationException if the operator is not appropriate for an object of this kind
+ */
+ DartObjectImpl greaterThan(TypeProvider typeProvider, DartObjectImpl rightOperand) => new DartObjectImpl(typeProvider.boolType, _state.greaterThan(rightOperand._state));
- @override
- EvaluationResultImpl shiftRight(TypeProvider typeProvider, BinaryExpression node, EvaluationResultImpl rightOperand) => rightOperand.shiftRightError(node, this);
+ /**
+ * Return the result of invoking the '&gt;=' operator on this object with the given argument.
+ *
+ * @param typeProvider the type provider used to find known types
+ * @param rightOperand the right-hand operand of the operation
+ * @return the result of invoking the '&gt;=' operator on this object with the given argument
+ * @throws EvaluationException if the operator is not appropriate for an object of this kind
+ */
+ DartObjectImpl greaterThanOrEqual(TypeProvider typeProvider, DartObjectImpl rightOperand) => new DartObjectImpl(typeProvider.boolType, _state.greaterThanOrEqual(rightOperand._state));
@override
- EvaluationResultImpl times(TypeProvider typeProvider, BinaryExpression node, EvaluationResultImpl rightOperand) => rightOperand.timesError(node, this);
+ bool get hasExactValue => _state.hasExactValue;
@override
- EvaluationResultImpl addToError(BinaryExpression node, ErrorResult leftOperand) => new ErrorResult.con2(this, leftOperand);
+ int get hashCode => ObjectUtilities.combineHashCodes(type.hashCode, _state.hashCode);
- @override
- EvaluationResultImpl addToValid(TypeProvider typeProvider, BinaryExpression node, ValidResult leftOperand) => this;
+ /**
+ * Return the result of invoking the '~/' operator on this object with the given argument.
+ *
+ * @param typeProvider the type provider used to find known types
+ * @param rightOperand the right-hand operand of the operation
+ * @return the result of invoking the '~/' operator on this object with the given argument
+ * @throws EvaluationException if the operator is not appropriate for an object of this kind
+ */
+ DartObjectImpl integerDivide(TypeProvider typeProvider, DartObjectImpl rightOperand) => new DartObjectImpl(typeProvider.intType, _state.integerDivide(rightOperand._state));
- @override
- EvaluationResultImpl bitAndError(BinaryExpression node, ErrorResult leftOperand) => new ErrorResult.con2(this, leftOperand);
+ /**
+ * Return `true` if this object represents an object whose type is 'bool'.
+ *
+ * @return `true` if this object represents a boolean value
+ */
+ bool get isBool => _state.isBool;
- @override
- EvaluationResultImpl bitAndValid(TypeProvider typeProvider, BinaryExpression node, ValidResult leftOperand) => this;
+ /**
+ * Return `true` if this object represents an object whose type is either 'bool', 'num',
+ * 'String', or 'Null'.
+ *
+ * @return `true` if this object represents either a boolean, numeric, string or null value
+ */
+ bool get isBoolNumStringOrNull => _state.isBoolNumStringOrNull;
@override
- EvaluationResultImpl bitOrError(BinaryExpression node, ErrorResult leftOperand) => new ErrorResult.con2(this, leftOperand);
-
- @override
- EvaluationResultImpl bitOrValid(TypeProvider typeProvider, BinaryExpression node, ValidResult leftOperand) => this;
-
- @override
- EvaluationResultImpl bitXorError(BinaryExpression node, ErrorResult leftOperand) => new ErrorResult.con2(this, leftOperand);
-
- @override
- EvaluationResultImpl bitXorValid(TypeProvider typeProvider, BinaryExpression node, ValidResult leftOperand) => this;
-
- @override
- EvaluationResultImpl concatenateError(Expression node, ErrorResult leftOperand) => new ErrorResult.con2(this, leftOperand);
-
- @override
- EvaluationResultImpl concatenateValid(TypeProvider typeProvider, Expression node, ValidResult leftOperand) => this;
-
- @override
- EvaluationResultImpl divideError(BinaryExpression node, ErrorResult leftOperand) => new ErrorResult.con2(this, leftOperand);
-
- @override
- EvaluationResultImpl divideValid(TypeProvider typeProvider, BinaryExpression node, ValidResult leftOperand) => this;
-
- @override
- EvaluationResultImpl equalEqualError(Expression node, ErrorResult leftOperand) => new ErrorResult.con2(this, leftOperand);
-
- @override
- EvaluationResultImpl equalEqualValid(TypeProvider typeProvider, Expression node, ValidResult leftOperand) => this;
-
- @override
- EvaluationResultImpl greaterThanError(BinaryExpression node, ErrorResult leftOperand) => new ErrorResult.con2(this, leftOperand);
-
- @override
- EvaluationResultImpl greaterThanOrEqualError(BinaryExpression node, ErrorResult leftOperand) => new ErrorResult.con2(this, leftOperand);
-
- @override
- EvaluationResultImpl greaterThanOrEqualValid(TypeProvider typeProvider, BinaryExpression node, ValidResult leftOperand) => this;
-
- @override
- EvaluationResultImpl greaterThanValid(TypeProvider typeProvider, BinaryExpression node, ValidResult leftOperand) => this;
-
- @override
- EvaluationResultImpl integerDivideError(BinaryExpression node, ErrorResult leftOperand) => new ErrorResult.con2(this, leftOperand);
-
- @override
- EvaluationResultImpl lessThanError(BinaryExpression node, ErrorResult leftOperand) => new ErrorResult.con2(this, leftOperand);
-
- @override
- EvaluationResultImpl lessThanOrEqualError(BinaryExpression node, ErrorResult leftOperand) => new ErrorResult.con2(this, leftOperand);
-
- @override
- EvaluationResultImpl lessThanOrEqualValid(TypeProvider typeProvider, BinaryExpression node, ValidResult leftOperand) => this;
-
- @override
- EvaluationResultImpl lessThanValid(TypeProvider typeProvider, BinaryExpression node, ValidResult leftOperand) => this;
-
- @override
- EvaluationResultImpl logicalAndError(BinaryExpression node, ErrorResult leftOperand) => new ErrorResult.con2(this, leftOperand);
-
- @override
- EvaluationResultImpl logicalAndValid(TypeProvider typeProvider, BinaryExpression node, ValidResult leftOperand) => this;
-
- @override
- EvaluationResultImpl logicalOrError(BinaryExpression node, ErrorResult leftOperand) => new ErrorResult.con2(this, leftOperand);
-
- @override
- EvaluationResultImpl logicalOrValid(TypeProvider typeProvider, BinaryExpression node, ValidResult leftOperand) => this;
-
- @override
- EvaluationResultImpl minusError(BinaryExpression node, ErrorResult leftOperand) => new ErrorResult.con2(this, leftOperand);
-
- @override
- EvaluationResultImpl minusValid(TypeProvider typeProvider, BinaryExpression node, ValidResult leftOperand) => this;
-
- @override
- EvaluationResultImpl notEqualError(BinaryExpression node, ErrorResult leftOperand) => new ErrorResult.con2(this, leftOperand);
-
- @override
- EvaluationResultImpl notEqualValid(TypeProvider typeProvider, BinaryExpression node, ValidResult leftOperand) => this;
-
- @override
- EvaluationResultImpl remainderError(BinaryExpression node, ErrorResult leftOperand) => new ErrorResult.con2(this, leftOperand);
-
- @override
- EvaluationResultImpl remainderValid(TypeProvider typeProvider, BinaryExpression node, ValidResult leftOperand) => this;
-
- @override
- EvaluationResultImpl shiftLeftError(BinaryExpression node, ErrorResult leftOperand) => new ErrorResult.con2(this, leftOperand);
+ bool get isFalse => _state is BoolState && identical((_state as BoolState).value, false);
@override
- EvaluationResultImpl shiftLeftValid(TypeProvider typeProvider, BinaryExpression node, ValidResult leftOperand) => this;
+ bool get isNull => _state is NullState;
@override
- EvaluationResultImpl shiftRightError(BinaryExpression node, ErrorResult leftOperand) => new ErrorResult.con2(this, leftOperand);
+ bool get isTrue => _state is BoolState && identical((_state as BoolState).value, true);
- @override
- EvaluationResultImpl shiftRightValid(TypeProvider typeProvider, BinaryExpression node, ValidResult leftOperand) => this;
+ /**
+ * Return `true` if this object represents an instance of a user-defined class.
+ *
+ * @return `true` if this object represents an instance of a user-defined class
+ */
+ bool get isUserDefinedObject => _state is GenericState;
- @override
- EvaluationResultImpl timesError(BinaryExpression node, ErrorResult leftOperand) => new ErrorResult.con2(this, leftOperand);
+ /**
+ * Return the result of invoking the '&lt;' operator on this object with the given argument.
+ *
+ * @param typeProvider the type provider used to find known types
+ * @param rightOperand the right-hand operand of the operation
+ * @return the result of invoking the '&lt;' operator on this object with the given argument
+ * @throws EvaluationException if the operator is not appropriate for an object of this kind
+ */
+ DartObjectImpl lessThan(TypeProvider typeProvider, DartObjectImpl rightOperand) => new DartObjectImpl(typeProvider.boolType, _state.lessThan(rightOperand._state));
- @override
- EvaluationResultImpl timesValid(TypeProvider typeProvider, BinaryExpression node, ValidResult leftOperand) => this;
-}
+ /**
+ * Return the result of invoking the '&lt;=' operator on this object with the given argument.
+ *
+ * @param typeProvider the type provider used to find known types
+ * @param rightOperand the right-hand operand of the operation
+ * @return the result of invoking the '&lt;=' operator on this object with the given argument
+ * @throws EvaluationException if the operator is not appropriate for an object of this kind
+ */
+ DartObjectImpl lessThanOrEqual(TypeProvider typeProvider, DartObjectImpl rightOperand) => new DartObjectImpl(typeProvider.boolType, _state.lessThanOrEqual(rightOperand._state));
-class ErrorResult_ErrorData {
/**
- * The node against which the error should be reported.
+ * Return the result of invoking the '&&' operator on this object with the given argument.
+ *
+ * @param typeProvider the type provider used to find known types
+ * @param rightOperand the right-hand operand of the operation
+ * @return the result of invoking the '&&' operator on this object with the given argument
+ * @throws EvaluationException if the operator is not appropriate for an object of this kind
*/
- final AstNode node;
+ DartObjectImpl logicalAnd(TypeProvider typeProvider, DartObjectImpl rightOperand) => new DartObjectImpl(typeProvider.boolType, _state.logicalAnd(rightOperand._state));
/**
- * The error code for the error to be generated.
+ * Return the result of invoking the '!' operator on this object.
+ *
+ * @param typeProvider the type provider used to find known types
+ * @return the result of invoking the '!' operator on this object
+ * @throws EvaluationException if the operator is not appropriate for an object of this kind
*/
- final ErrorCode errorCode;
+ DartObjectImpl logicalNot(TypeProvider typeProvider) => new DartObjectImpl(typeProvider.boolType, _state.logicalNot());
/**
- * Initialize a newly created data holder to represent the error with the given code reported
- * against the given node.
+ * Return the result of invoking the '||' operator on this object with the given argument.
*
- * @param node the node against which the error should be reported
- * @param errorCode the error code for the error to be generated
+ * @param typeProvider the type provider used to find known types
+ * @param rightOperand the right-hand operand of the operation
+ * @return the result of invoking the '||' operator on this object with the given argument
+ * @throws EvaluationException if the operator is not appropriate for an object of this kind
*/
- ErrorResult_ErrorData(this.node, this.errorCode);
-}
+ DartObjectImpl logicalOr(TypeProvider typeProvider, DartObjectImpl rightOperand) => new DartObjectImpl(typeProvider.boolType, _state.logicalOr(rightOperand._state));
-/**
- * Instances of the class `InternalResult` represent the result of attempting to evaluate a
- * expression.
- */
-abstract class EvaluationResultImpl {
- EvaluationResultImpl add(TypeProvider typeProvider, BinaryExpression node, EvaluationResultImpl rightOperand);
+ /**
+ * Return the result of invoking the '-' operator on this object with the given argument.
+ *
+ * @param typeProvider the type provider used to find known types
+ * @param rightOperand the right-hand operand of the operation
+ * @return the result of invoking the '-' operator on this object with the given argument
+ * @throws EvaluationException if the operator is not appropriate for an object of this kind
+ */
+ DartObjectImpl minus(TypeProvider typeProvider, DartObjectImpl rightOperand) {
+ InstanceState result = _state.minus(rightOperand._state);
+ if (result is IntState) {
+ return new DartObjectImpl(typeProvider.intType, result);
+ } else if (result is DoubleState) {
+ return new DartObjectImpl(typeProvider.doubleType, result);
+ } else if (result is NumState) {
+ return new DartObjectImpl(typeProvider.numType, result);
+ }
+ // We should never get here.
+ throw new IllegalStateException("minus returned a ${result.runtimeType.toString()}");
+ }
/**
- * Return the result of applying boolean conversion to this result.
+ * Return the result of invoking the '-' operator on this object.
*
- * @param typeProvider the type provider used to access known types
- * @param node the node against which errors should be reported
- * @return the result of applying boolean conversion to the given value
+ * @param typeProvider the type provider used to find known types
+ * @return the result of invoking the '-' operator on this object
+ * @throws EvaluationException if the operator is not appropriate for an object of this kind
*/
- EvaluationResultImpl applyBooleanConversion(TypeProvider typeProvider, AstNode node);
+ DartObjectImpl negated(TypeProvider typeProvider) {
+ InstanceState result = _state.negated();
+ if (result is IntState) {
+ return new DartObjectImpl(typeProvider.intType, result);
+ } else if (result is DoubleState) {
+ return new DartObjectImpl(typeProvider.doubleType, result);
+ } else if (result is NumState) {
+ return new DartObjectImpl(typeProvider.numType, result);
+ }
+ // We should never get here.
+ throw new IllegalStateException("negated returned a ${result.runtimeType.toString()}");
+ }
- EvaluationResultImpl bitAnd(TypeProvider typeProvider, BinaryExpression node, EvaluationResultImpl rightOperand);
+ /**
+ * Return the result of invoking the '!=' operator on this object with the given argument.
+ *
+ * @param typeProvider the type provider used to find known types
+ * @param rightOperand the right-hand operand of the operation
+ * @return the result of invoking the '!=' operator on this object with the given argument
+ * @throws EvaluationException if the operator is not appropriate for an object of this kind
+ */
+ DartObjectImpl notEqual(TypeProvider typeProvider, DartObjectImpl rightOperand) {
+ if (type != rightOperand.type) {
+ String typeName = type.name;
+ if (typeName != "bool" && typeName != "double" && typeName != "int" && typeName != "num" && typeName != "String") {
+ return new DartObjectImpl(typeProvider.boolType, BoolState.TRUE_STATE);
+ }
+ }
+ return new DartObjectImpl(typeProvider.boolType, _state.equalEqual(rightOperand._state).logicalNot());
+ }
- EvaluationResultImpl bitNot(TypeProvider typeProvider, Expression node);
+ /**
+ * Return the result of converting this object to a String.
+ *
+ * @param typeProvider the type provider used to find known types
+ * @return the result of converting this object to a String
+ * @throws EvaluationException if the object cannot be converted to a String
+ */
+ DartObjectImpl performToString(TypeProvider typeProvider) {
+ InterfaceType stringType = typeProvider.stringType;
+ if (identical(type, stringType)) {
+ return this;
+ }
+ return new DartObjectImpl(stringType, _state.convertToString());
+ }
- EvaluationResultImpl bitOr(TypeProvider typeProvider, BinaryExpression node, EvaluationResultImpl rightOperand);
+ /**
+ * Return the result of invoking the '%' operator on this object with the given argument.
+ *
+ * @param typeProvider the type provider used to find known types
+ * @param rightOperand the right-hand operand of the operation
+ * @return the result of invoking the '%' operator on this object with the given argument
+ * @throws EvaluationException if the operator is not appropriate for an object of this kind
+ */
+ DartObjectImpl remainder(TypeProvider typeProvider, DartObjectImpl rightOperand) {
+ InstanceState result = _state.remainder(rightOperand._state);
+ if (result is IntState) {
+ return new DartObjectImpl(typeProvider.intType, result);
+ } else if (result is DoubleState) {
+ return new DartObjectImpl(typeProvider.doubleType, result);
+ } else if (result is NumState) {
+ return new DartObjectImpl(typeProvider.numType, result);
+ }
+ // We should never get here.
+ throw new IllegalStateException("remainder returned a ${result.runtimeType.toString()}");
+ }
- EvaluationResultImpl bitXor(TypeProvider typeProvider, BinaryExpression node, EvaluationResultImpl rightOperand);
-
- EvaluationResultImpl concatenate(TypeProvider typeProvider, Expression node, EvaluationResultImpl rightOperand);
-
- EvaluationResultImpl divide(TypeProvider typeProvider, BinaryExpression node, EvaluationResultImpl rightOperand);
-
- EvaluationResultImpl equalEqual(TypeProvider typeProvider, Expression node, EvaluationResultImpl rightOperand);
-
- bool equalValues(TypeProvider typeProvider, EvaluationResultImpl result);
-
- EvaluationResultImpl greaterThan(TypeProvider typeProvider, BinaryExpression node, EvaluationResultImpl rightOperand);
-
- EvaluationResultImpl greaterThanOrEqual(TypeProvider typeProvider, BinaryExpression node, EvaluationResultImpl rightOperand);
-
- EvaluationResultImpl integerDivide(TypeProvider typeProvider, BinaryExpression node, EvaluationResultImpl rightOperand);
-
- EvaluationResultImpl lessThan(TypeProvider typeProvider, BinaryExpression node, EvaluationResultImpl rightOperand);
-
- EvaluationResultImpl lessThanOrEqual(TypeProvider typeProvider, BinaryExpression node, EvaluationResultImpl rightOperand);
-
- EvaluationResultImpl logicalAnd(TypeProvider typeProvider, BinaryExpression node, EvaluationResultImpl rightOperand);
-
- EvaluationResultImpl logicalNot(TypeProvider typeProvider, Expression node);
-
- EvaluationResultImpl logicalOr(TypeProvider typeProvider, BinaryExpression node, EvaluationResultImpl rightOperand);
-
- EvaluationResultImpl minus(TypeProvider typeProvider, BinaryExpression node, EvaluationResultImpl rightOperand);
-
- EvaluationResultImpl negated(TypeProvider typeProvider, Expression node);
-
- EvaluationResultImpl notEqual(TypeProvider typeProvider, BinaryExpression node, EvaluationResultImpl rightOperand);
-
- EvaluationResultImpl performToString(TypeProvider typeProvider, AstNode node);
-
- EvaluationResultImpl remainder(TypeProvider typeProvider, BinaryExpression node, EvaluationResultImpl rightOperand);
-
- EvaluationResultImpl shiftLeft(TypeProvider typeProvider, BinaryExpression node, EvaluationResultImpl rightOperand);
-
- EvaluationResultImpl shiftRight(TypeProvider typeProvider, BinaryExpression node, EvaluationResultImpl rightOperand);
-
- EvaluationResultImpl times(TypeProvider typeProvider, BinaryExpression node, EvaluationResultImpl rightOperand);
-
- EvaluationResultImpl addToError(BinaryExpression node, ErrorResult leftOperand);
-
- EvaluationResultImpl addToValid(TypeProvider typeProvider, BinaryExpression node, ValidResult leftOperand);
-
- EvaluationResultImpl bitAndError(BinaryExpression node, ErrorResult leftOperand);
-
- EvaluationResultImpl bitAndValid(TypeProvider typeProvider, BinaryExpression node, ValidResult leftOperand);
-
- EvaluationResultImpl bitOrError(BinaryExpression node, ErrorResult leftOperand);
-
- EvaluationResultImpl bitOrValid(TypeProvider typeProvider, BinaryExpression node, ValidResult leftOperand);
-
- EvaluationResultImpl bitXorError(BinaryExpression node, ErrorResult leftOperand);
-
- EvaluationResultImpl bitXorValid(TypeProvider typeProvider, BinaryExpression node, ValidResult leftOperand);
-
- EvaluationResultImpl concatenateError(Expression node, ErrorResult leftOperand);
-
- EvaluationResultImpl concatenateValid(TypeProvider typeProvider, Expression node, ValidResult leftOperand);
-
- EvaluationResultImpl divideError(BinaryExpression node, ErrorResult leftOperand);
-
- EvaluationResultImpl divideValid(TypeProvider typeProvider, BinaryExpression node, ValidResult leftOperand);
-
- EvaluationResultImpl equalEqualError(Expression node, ErrorResult leftOperand);
-
- EvaluationResultImpl equalEqualValid(TypeProvider typeProvider, Expression node, ValidResult leftOperand);
-
- EvaluationResultImpl greaterThanError(BinaryExpression node, ErrorResult leftOperand);
-
- EvaluationResultImpl greaterThanOrEqualError(BinaryExpression node, ErrorResult leftOperand);
-
- EvaluationResultImpl greaterThanOrEqualValid(TypeProvider typeProvider, BinaryExpression node, ValidResult leftOperand);
-
- EvaluationResultImpl greaterThanValid(TypeProvider typeProvider, BinaryExpression node, ValidResult leftOperand);
-
- EvaluationResultImpl integerDivideError(BinaryExpression node, ErrorResult leftOperand);
-
- EvaluationResultImpl integerDivideValid(TypeProvider typeProvider, BinaryExpression node, ValidResult leftOperand);
-
- EvaluationResultImpl lessThanError(BinaryExpression node, ErrorResult leftOperand);
-
- EvaluationResultImpl lessThanOrEqualError(BinaryExpression node, ErrorResult leftOperand);
-
- EvaluationResultImpl lessThanOrEqualValid(TypeProvider typeProvider, BinaryExpression node, ValidResult leftOperand);
-
- EvaluationResultImpl lessThanValid(TypeProvider typeProvider, BinaryExpression node, ValidResult leftOperand);
-
- EvaluationResultImpl logicalAndError(BinaryExpression node, ErrorResult leftOperand);
-
- EvaluationResultImpl logicalAndValid(TypeProvider typeProvider, BinaryExpression node, ValidResult leftOperand);
-
- EvaluationResultImpl logicalOrError(BinaryExpression node, ErrorResult leftOperand);
-
- EvaluationResultImpl logicalOrValid(TypeProvider typeProvider, BinaryExpression node, ValidResult leftOperand);
-
- EvaluationResultImpl minusError(BinaryExpression node, ErrorResult leftOperand);
-
- EvaluationResultImpl minusValid(TypeProvider typeProvider, BinaryExpression node, ValidResult leftOperand);
-
- EvaluationResultImpl notEqualError(BinaryExpression node, ErrorResult leftOperand);
-
- EvaluationResultImpl notEqualValid(TypeProvider typeProvider, BinaryExpression node, ValidResult leftOperand);
-
- EvaluationResultImpl remainderError(BinaryExpression node, ErrorResult leftOperand);
-
- EvaluationResultImpl remainderValid(TypeProvider typeProvider, BinaryExpression node, ValidResult leftOperand);
-
- EvaluationResultImpl shiftLeftError(BinaryExpression node, ErrorResult leftOperand);
-
- EvaluationResultImpl shiftLeftValid(TypeProvider typeProvider, BinaryExpression node, ValidResult leftOperand);
-
- EvaluationResultImpl shiftRightError(BinaryExpression node, ErrorResult leftOperand);
-
- EvaluationResultImpl shiftRightValid(TypeProvider typeProvider, BinaryExpression node, ValidResult leftOperand);
-
- EvaluationResultImpl timesError(BinaryExpression node, ErrorResult leftOperand);
-
- EvaluationResultImpl timesValid(TypeProvider typeProvider, BinaryExpression node, ValidResult leftOperand);
-}
-
-/**
- * Instances of the class `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.
+ * Return the result of invoking the '&lt;&lt;' operator on this object with the given argument.
+ *
+ * @param typeProvider the type provider used to find known types
+ * @param rightOperand the right-hand operand of the operation
+ * @return the result of invoking the '&lt;&lt;' operator on this object with the given argument
+ * @throws EvaluationException if the operator is not appropriate for an object of this kind
*/
- final VariableElement _source;
+ DartObjectImpl shiftLeft(TypeProvider typeProvider, DartObjectImpl rightOperand) => new DartObjectImpl(typeProvider.intType, _state.shiftLeft(rightOperand._state));
/**
- * 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.
+ * Return the result of invoking the '&gt;&gt;' operator on this object with the given argument.
+ *
+ * @param typeProvider the type provider used to find known types
+ * @param rightOperand the right-hand operand of the operation
+ * @return the result of invoking the '&gt;&gt;' operator on this object with the given argument
+ * @throws EvaluationException if the operator is not appropriate for an object of this kind
*/
- final DirectedGraph<VariableElement> _referenceGraph;
+ DartObjectImpl shiftRight(TypeProvider typeProvider, DartObjectImpl rightOperand) => new DartObjectImpl(typeProvider.intType, _state.shiftRight(rightOperand._state));
/**
- * 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.
+ * Return the result of invoking the '*' operator on this object with the given argument.
*
- * @param source the element representing the variable whose initializer will be visited
- * @param referenceGraph a graph recording which variables (heads) reference which other variables
- * (tails) in their initializers
+ * @param typeProvider the type provider used to find known types
+ * @param rightOperand the right-hand operand of the operation
+ * @return the result of invoking the '*' operator on this object with the given argument
+ * @throws EvaluationException if the operator is not appropriate for an object of this kind
*/
- ReferenceFinder(this._source, this._referenceGraph);
-
- @override
- Object visitSimpleIdentifier(SimpleIdentifier node) {
- Element element = node.staticElement;
- if (element is PropertyAccessorElement) {
- element = (element as PropertyAccessorElement).variable;
- }
- if (element is VariableElement) {
- VariableElement variable = element as VariableElement;
- if (variable.isConst) {
- _referenceGraph.addEdge(_source, variable);
- }
+ DartObjectImpl times(TypeProvider typeProvider, DartObjectImpl rightOperand) {
+ InstanceState result = _state.times(rightOperand._state);
+ if (result is IntState) {
+ return new DartObjectImpl(typeProvider.intType, result);
+ } else if (result is DoubleState) {
+ return new DartObjectImpl(typeProvider.doubleType, result);
+ } else if (result is NumState) {
+ return new DartObjectImpl(typeProvider.numType, result);
}
- return null;
+ // We should never get here.
+ throw new IllegalStateException("times returned a ${result.runtimeType.toString()}");
}
+
+ @override
+ String toString() => "${type.displayName} (${_state.toString()})";
}
/**
- * Instances of the class `ValidResult` represent the result of attempting to evaluate a valid
- * compile time constant expression.
+ * Instances of the class `DoubleState` represent the state of an object representing a
+ * double.
*/
-class ValidResult extends EvaluationResultImpl {
+class DoubleState extends NumState {
/**
- * The value of the expression.
+ * The value of this instance.
*/
- final DartObjectImpl value;
+ final double value;
/**
- * Initialize a newly created result to represent the given value.
- *
- * @param value the value of the expression
+ * A state that can be used to represent a double whose value is not known.
*/
- ValidResult(this.value);
-
- @override
- EvaluationResultImpl add(TypeProvider typeProvider, BinaryExpression node, EvaluationResultImpl rightOperand) => rightOperand.addToValid(typeProvider, node, this);
+ static DoubleState UNKNOWN_VALUE = new DoubleState(null);
/**
- * Return the result of applying boolean conversion to this result.
+ * Initialize a newly created state to represent a double with the given value.
*
- * @param node the node against which errors should be reported
- * @return the result of applying boolean conversion to the given value
+ * @param value the value of this instance
*/
+ DoubleState(this.value);
+
@override
- EvaluationResultImpl applyBooleanConversion(TypeProvider typeProvider, AstNode node) {
- try {
- return _valueOf(value.convertToBool(typeProvider));
- } on EvaluationException catch (exception) {
- return _error(node, exception.errorCode);
+ NumState add(InstanceState rightOperand) {
+ assertNumOrNull(rightOperand);
+ if (value == null) {
+ return UNKNOWN_VALUE;
+ }
+ if (rightOperand is IntState) {
+ int rightValue = rightOperand.value;
+ if (rightValue == null) {
+ return UNKNOWN_VALUE;
+ }
+ return new DoubleState(value + rightValue.toDouble());
+ } else if (rightOperand is DoubleState) {
+ double rightValue = rightOperand.value;
+ if (rightValue == null) {
+ return UNKNOWN_VALUE;
+ }
+ return new DoubleState(value + rightValue);
+ } else if (rightOperand is DynamicState || rightOperand is NumState) {
+ return UNKNOWN_VALUE;
}
+ throw new EvaluationException(CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION);
}
@override
- EvaluationResultImpl bitAnd(TypeProvider typeProvider, BinaryExpression node, EvaluationResultImpl rightOperand) => rightOperand.bitAndValid(typeProvider, node, this);
-
- @override
- EvaluationResultImpl bitNot(TypeProvider typeProvider, Expression node) {
- try {
- return _valueOf(value.bitNot(typeProvider));
- } on EvaluationException catch (exception) {
- return _error(node, exception.errorCode);
+ StringState convertToString() {
+ if (value == null) {
+ return StringState.UNKNOWN_VALUE;
}
+ return new StringState(value.toString());
}
@override
- EvaluationResultImpl bitOr(TypeProvider typeProvider, BinaryExpression node, EvaluationResultImpl rightOperand) => rightOperand.bitOrValid(typeProvider, node, this);
-
- @override
- EvaluationResultImpl bitXor(TypeProvider typeProvider, BinaryExpression node, EvaluationResultImpl rightOperand) => rightOperand.bitXorValid(typeProvider, node, this);
-
- @override
- EvaluationResultImpl concatenate(TypeProvider typeProvider, Expression node, EvaluationResultImpl rightOperand) => rightOperand.concatenateValid(typeProvider, node, this);
-
- @override
- EvaluationResultImpl divide(TypeProvider typeProvider, BinaryExpression node, EvaluationResultImpl rightOperand) => rightOperand.divideValid(typeProvider, node, this);
-
- @override
- EvaluationResultImpl equalEqual(TypeProvider typeProvider, Expression node, EvaluationResultImpl rightOperand) => rightOperand.equalEqualValid(typeProvider, node, this);
-
- @override
- bool equalValues(TypeProvider typeProvider, EvaluationResultImpl result) {
- if (result is! ValidResult) {
- return false;
+ NumState divide(InstanceState rightOperand) {
+ assertNumOrNull(rightOperand);
+ if (value == null) {
+ return UNKNOWN_VALUE;
}
- return value == (result as ValidResult).value;
+ if (rightOperand is IntState) {
+ int rightValue = rightOperand.value;
+ if (rightValue == null) {
+ return UNKNOWN_VALUE;
+ }
+ return new DoubleState(value / rightValue.toDouble());
+ } else if (rightOperand is DoubleState) {
+ double rightValue = rightOperand.value;
+ if (rightValue == null) {
+ return UNKNOWN_VALUE;
+ }
+ return new DoubleState(value / rightValue);
+ } else if (rightOperand is DynamicState || rightOperand is NumState) {
+ return UNKNOWN_VALUE;
+ }
+ throw new EvaluationException(CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION);
}
@override
- EvaluationResultImpl greaterThan(TypeProvider typeProvider, BinaryExpression node, EvaluationResultImpl rightOperand) => rightOperand.greaterThanValid(typeProvider, node, this);
-
- @override
- EvaluationResultImpl greaterThanOrEqual(TypeProvider typeProvider, BinaryExpression node, EvaluationResultImpl rightOperand) => rightOperand.greaterThanOrEqualValid(typeProvider, node, this);
-
- @override
- EvaluationResultImpl integerDivide(TypeProvider typeProvider, BinaryExpression node, EvaluationResultImpl rightOperand) => rightOperand.integerDivideValid(typeProvider, node, this);
-
- /**
- * Return `true` if this object represents an object whose type is 'bool'.
- *
- * @return `true` if this object represents a boolean value
- */
- bool get isBool => value.isBool;
-
- /**
- * Return `true` if this object represents an object whose type is either 'bool', 'num',
- * 'String', or 'Null'.
- *
- * @return `true` if this object represents either a boolean, numeric, string or null value
- */
- bool get isBoolNumStringOrNull => value.isBoolNumStringOrNull;
-
- /**
- * Return `true` if this result represents the value 'false'.
- *
- * @return `true` if this result represents the value 'false'
- */
- bool get isFalse => value.isFalse;
-
- /**
- * Return `true` if this result represents the value 'null'.
- *
- * @return `true` if this result represents the value 'null'
- */
- bool get isNull => value.isNull;
-
- /**
- * Return `true` if this result represents the value 'true'.
- *
- * @return `true` if this result represents the value 'true'
- */
- bool get isTrue => value.isTrue;
-
- /**
- * Return `true` if this object represents an instance of a user-defined class.
- *
- * @return `true` if this object represents an instance of a user-defined class
- */
- bool get isUserDefinedObject => value.isUserDefinedObject;
-
- @override
- EvaluationResultImpl lessThan(TypeProvider typeProvider, BinaryExpression node, EvaluationResultImpl rightOperand) => rightOperand.lessThanValid(typeProvider, node, this);
-
- @override
- EvaluationResultImpl lessThanOrEqual(TypeProvider typeProvider, BinaryExpression node, EvaluationResultImpl rightOperand) => rightOperand.lessThanOrEqualValid(typeProvider, node, this);
-
- @override
- EvaluationResultImpl logicalAnd(TypeProvider typeProvider, BinaryExpression node, EvaluationResultImpl rightOperand) => rightOperand.logicalAndValid(typeProvider, node, this);
-
- @override
- EvaluationResultImpl logicalNot(TypeProvider typeProvider, Expression node) {
- try {
- return _valueOf(value.logicalNot(typeProvider));
- } on EvaluationException catch (exception) {
- return _error(node, exception.errorCode);
+ BoolState equalEqual(InstanceState rightOperand) {
+ assertBoolNumStringOrNull(rightOperand);
+ if (value == null) {
+ return BoolState.UNKNOWN_VALUE;
+ }
+ if (rightOperand is DoubleState) {
+ double rightValue = rightOperand.value;
+ if (rightValue == null) {
+ return BoolState.UNKNOWN_VALUE;
+ }
+ return BoolState.from(value == rightValue);
+ } else if (rightOperand is IntState) {
+ int rightValue = rightOperand.value;
+ if (rightValue == null) {
+ return BoolState.UNKNOWN_VALUE;
+ }
+ return BoolState.from(value == rightValue.toDouble());
+ } else if (rightOperand is DynamicState || rightOperand is NumState) {
+ return BoolState.UNKNOWN_VALUE;
}
+ return BoolState.FALSE_STATE;
}
@override
- EvaluationResultImpl logicalOr(TypeProvider typeProvider, BinaryExpression node, EvaluationResultImpl rightOperand) => rightOperand.logicalOrValid(typeProvider, node, this);
+ bool operator ==(Object object) => object is DoubleState && (value == object.value);
@override
- EvaluationResultImpl minus(TypeProvider typeProvider, BinaryExpression node, EvaluationResultImpl rightOperand) => rightOperand.minusValid(typeProvider, node, this);
+ String get typeName => "double";
@override
- EvaluationResultImpl negated(TypeProvider typeProvider, Expression node) {
- try {
- return _valueOf(value.negated(typeProvider));
- } on EvaluationException catch (exception) {
- return _error(node, exception.errorCode);
+ BoolState greaterThan(InstanceState rightOperand) {
+ assertNumOrNull(rightOperand);
+ if (value == null) {
+ return BoolState.UNKNOWN_VALUE;
}
+ if (rightOperand is IntState) {
+ int rightValue = rightOperand.value;
+ if (rightValue == null) {
+ return BoolState.UNKNOWN_VALUE;
+ }
+ return BoolState.from(value > rightValue.toDouble());
+ } else if (rightOperand is DoubleState) {
+ double rightValue = rightOperand.value;
+ if (rightValue == null) {
+ return BoolState.UNKNOWN_VALUE;
+ }
+ return BoolState.from(value > rightValue);
+ } else if (rightOperand is DynamicState || rightOperand is NumState) {
+ return BoolState.UNKNOWN_VALUE;
+ }
+ throw new EvaluationException(CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION);
}
@override
- EvaluationResultImpl notEqual(TypeProvider typeProvider, BinaryExpression node, EvaluationResultImpl rightOperand) => rightOperand.notEqualValid(typeProvider, node, this);
-
- @override
- EvaluationResultImpl performToString(TypeProvider typeProvider, AstNode node) {
- try {
- return _valueOf(value.performToString(typeProvider));
- } on EvaluationException catch (exception) {
- return _error(node, exception.errorCode);
+ BoolState greaterThanOrEqual(InstanceState rightOperand) {
+ assertNumOrNull(rightOperand);
+ if (value == null) {
+ return BoolState.UNKNOWN_VALUE;
+ }
+ if (rightOperand is IntState) {
+ int rightValue = rightOperand.value;
+ if (rightValue == null) {
+ return BoolState.UNKNOWN_VALUE;
+ }
+ return BoolState.from(value >= rightValue.toDouble());
+ } else if (rightOperand is DoubleState) {
+ double rightValue = rightOperand.value;
+ if (rightValue == null) {
+ return BoolState.UNKNOWN_VALUE;
+ }
+ return BoolState.from(value >= rightValue);
+ } else if (rightOperand is DynamicState || rightOperand is NumState) {
+ return BoolState.UNKNOWN_VALUE;
}
+ throw new EvaluationException(CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION);
}
@override
- EvaluationResultImpl remainder(TypeProvider typeProvider, BinaryExpression node, EvaluationResultImpl rightOperand) => rightOperand.remainderValid(typeProvider, node, this);
-
- @override
- EvaluationResultImpl shiftLeft(TypeProvider typeProvider, BinaryExpression node, EvaluationResultImpl rightOperand) => rightOperand.shiftLeftValid(typeProvider, node, this);
-
- @override
- EvaluationResultImpl shiftRight(TypeProvider typeProvider, BinaryExpression node, EvaluationResultImpl rightOperand) => rightOperand.shiftRightValid(typeProvider, node, this);
+ bool get hasExactValue => true;
@override
- EvaluationResultImpl times(TypeProvider typeProvider, BinaryExpression node, EvaluationResultImpl rightOperand) => rightOperand.timesValid(typeProvider, node, this);
+ int get hashCode => value == null ? 0 : value.hashCode;
@override
- String toString() {
+ IntState integerDivide(InstanceState rightOperand) {
+ assertNumOrNull(rightOperand);
if (value == null) {
- return "null";
+ return IntState.UNKNOWN_VALUE;
}
- return value.toString();
- }
-
- @override
- EvaluationResultImpl addToError(BinaryExpression node, ErrorResult leftOperand) => leftOperand;
-
- @override
- EvaluationResultImpl addToValid(TypeProvider typeProvider, BinaryExpression node, ValidResult leftOperand) {
- try {
- return _valueOf(leftOperand.value.add(typeProvider, value));
- } on EvaluationException catch (exception) {
- return _error(node, exception.errorCode);
+ if (rightOperand is IntState) {
+ int rightValue = rightOperand.value;
+ if (rightValue == null) {
+ return IntState.UNKNOWN_VALUE;
+ }
+ double result = value / rightValue.toDouble();
+ return new IntState(result.toInt());
+ } else if (rightOperand is DoubleState) {
+ double rightValue = rightOperand.value;
+ if (rightValue == null) {
+ return IntState.UNKNOWN_VALUE;
+ }
+ double result = value / rightValue;
+ return new IntState(result.toInt());
+ } else if (rightOperand is DynamicState || rightOperand is NumState) {
+ return IntState.UNKNOWN_VALUE;
}
+ throw new EvaluationException(CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION);
}
@override
- EvaluationResultImpl bitAndError(BinaryExpression node, ErrorResult leftOperand) => leftOperand;
+ bool get isBoolNumStringOrNull => true;
@override
- EvaluationResultImpl bitAndValid(TypeProvider typeProvider, BinaryExpression node, ValidResult leftOperand) {
- try {
- return _valueOf(leftOperand.value.bitAnd(typeProvider, value));
- } on EvaluationException catch (exception) {
- return _error(node, exception.errorCode);
+ BoolState lessThan(InstanceState rightOperand) {
+ assertNumOrNull(rightOperand);
+ if (value == null) {
+ return BoolState.UNKNOWN_VALUE;
}
- }
-
- @override
- EvaluationResultImpl bitOrError(BinaryExpression node, ErrorResult leftOperand) => leftOperand;
-
- @override
- EvaluationResultImpl bitOrValid(TypeProvider typeProvider, BinaryExpression node, ValidResult leftOperand) {
- try {
- return _valueOf(leftOperand.value.bitOr(typeProvider, value));
- } on EvaluationException catch (exception) {
- return _error(node, exception.errorCode);
+ if (rightOperand is IntState) {
+ int rightValue = rightOperand.value;
+ if (rightValue == null) {
+ return BoolState.UNKNOWN_VALUE;
+ }
+ return BoolState.from(value < rightValue.toDouble());
+ } else if (rightOperand is DoubleState) {
+ double rightValue = rightOperand.value;
+ if (rightValue == null) {
+ return BoolState.UNKNOWN_VALUE;
+ }
+ return BoolState.from(value < rightValue);
+ } else if (rightOperand is DynamicState || rightOperand is NumState) {
+ return BoolState.UNKNOWN_VALUE;
}
+ throw new EvaluationException(CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION);
}
@override
- EvaluationResultImpl bitXorError(BinaryExpression node, ErrorResult leftOperand) => leftOperand;
-
- @override
- EvaluationResultImpl bitXorValid(TypeProvider typeProvider, BinaryExpression node, ValidResult leftOperand) {
- try {
- return _valueOf(leftOperand.value.bitXor(typeProvider, value));
- } on EvaluationException catch (exception) {
- return _error(node, exception.errorCode);
+ BoolState lessThanOrEqual(InstanceState rightOperand) {
+ assertNumOrNull(rightOperand);
+ if (value == null) {
+ return BoolState.UNKNOWN_VALUE;
+ }
+ if (rightOperand is IntState) {
+ int rightValue = rightOperand.value;
+ if (rightValue == null) {
+ return BoolState.UNKNOWN_VALUE;
+ }
+ return BoolState.from(value <= rightValue.toDouble());
+ } else if (rightOperand is DoubleState) {
+ double rightValue = rightOperand.value;
+ if (rightValue == null) {
+ return BoolState.UNKNOWN_VALUE;
+ }
+ return BoolState.from(value <= rightValue);
+ } else if (rightOperand is DynamicState || rightOperand is NumState) {
+ return BoolState.UNKNOWN_VALUE;
}
+ throw new EvaluationException(CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION);
}
@override
- EvaluationResultImpl concatenateError(Expression node, ErrorResult leftOperand) => leftOperand;
+ NumState minus(InstanceState rightOperand) {
+ assertNumOrNull(rightOperand);
+ if (value == null) {
+ return UNKNOWN_VALUE;
+ }
+ if (rightOperand is IntState) {
+ int rightValue = rightOperand.value;
+ if (rightValue == null) {
+ return UNKNOWN_VALUE;
+ }
+ return new DoubleState(value - rightValue.toDouble());
+ } else if (rightOperand is DoubleState) {
+ double rightValue = rightOperand.value;
+ if (rightValue == null) {
+ return UNKNOWN_VALUE;
+ }
+ return new DoubleState(value - rightValue);
+ } else if (rightOperand is DynamicState || rightOperand is NumState) {
+ return UNKNOWN_VALUE;
+ }
+ throw new EvaluationException(CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION);
+ }
@override
- EvaluationResultImpl concatenateValid(TypeProvider typeProvider, Expression node, ValidResult leftOperand) {
- try {
- return _valueOf(leftOperand.value.concatenate(typeProvider, value));
- } on EvaluationException catch (exception) {
- return _error(node, exception.errorCode);
+ NumState negated() {
+ if (value == null) {
+ return UNKNOWN_VALUE;
}
+ return new DoubleState(-(value));
}
@override
- EvaluationResultImpl divideError(BinaryExpression node, ErrorResult leftOperand) => leftOperand;
+ NumState remainder(InstanceState rightOperand) {
+ assertNumOrNull(rightOperand);
+ if (value == null) {
+ return UNKNOWN_VALUE;
+ }
+ if (rightOperand is IntState) {
+ int rightValue = rightOperand.value;
+ if (rightValue == null) {
+ return UNKNOWN_VALUE;
+ }
+ return new DoubleState(value % rightValue.toDouble());
+ } else if (rightOperand is DoubleState) {
+ double rightValue = rightOperand.value;
+ if (rightValue == null) {
+ return UNKNOWN_VALUE;
+ }
+ return new DoubleState(value % rightValue);
+ } else if (rightOperand is DynamicState || rightOperand is NumState) {
+ return UNKNOWN_VALUE;
+ }
+ throw new EvaluationException(CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION);
+ }
@override
- EvaluationResultImpl divideValid(TypeProvider typeProvider, BinaryExpression node, ValidResult leftOperand) {
- try {
- return _valueOf(leftOperand.value.divide(typeProvider, value));
- } on EvaluationException catch (exception) {
- return _error(node, exception.errorCode);
+ NumState times(InstanceState rightOperand) {
+ assertNumOrNull(rightOperand);
+ if (value == null) {
+ return UNKNOWN_VALUE;
+ }
+ if (rightOperand is IntState) {
+ int rightValue = rightOperand.value;
+ if (rightValue == null) {
+ return UNKNOWN_VALUE;
+ }
+ return new DoubleState(value * rightValue.toDouble());
+ } else if (rightOperand is DoubleState) {
+ double rightValue = rightOperand.value;
+ if (rightValue == null) {
+ return UNKNOWN_VALUE;
+ }
+ return new DoubleState(value * rightValue);
+ } else if (rightOperand is DynamicState || rightOperand is NumState) {
+ return UNKNOWN_VALUE;
}
+ throw new EvaluationException(CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION);
}
@override
- EvaluationResultImpl equalEqualError(Expression node, ErrorResult leftOperand) => leftOperand;
+ String toString() => value == null ? "-unknown-" : value.toString();
+}
+
+/**
+ * Instances of the class `DynamicState` represent the state of an object representing a Dart
+ * object for which there is no type information.
+ */
+class DynamicState extends InstanceState {
+ /**
+ * The unique instance of this class.
+ */
+ static DynamicState DYNAMIC_STATE = new DynamicState();
@override
- EvaluationResultImpl equalEqualValid(TypeProvider typeProvider, Expression node, ValidResult leftOperand) {
- try {
- return _valueOf(leftOperand.value.equalEqual(typeProvider, value));
- } on EvaluationException catch (exception) {
- return _error(node, exception.errorCode);
- }
+ NumState add(InstanceState rightOperand) {
+ assertNumOrNull(rightOperand);
+ return _unknownNum(rightOperand);
}
@override
- EvaluationResultImpl greaterThanError(BinaryExpression node, ErrorResult leftOperand) => leftOperand;
+ IntState bitAnd(InstanceState rightOperand) {
+ assertIntOrNull(rightOperand);
+ return IntState.UNKNOWN_VALUE;
+ }
@override
- EvaluationResultImpl greaterThanOrEqualError(BinaryExpression node, ErrorResult leftOperand) => leftOperand;
+ IntState bitNot() => IntState.UNKNOWN_VALUE;
@override
- EvaluationResultImpl greaterThanOrEqualValid(TypeProvider typeProvider, BinaryExpression node, ValidResult leftOperand) {
- try {
- return _valueOf(leftOperand.value.greaterThanOrEqual(typeProvider, value));
- } on EvaluationException catch (exception) {
- return _error(node, exception.errorCode);
- }
+ IntState bitOr(InstanceState rightOperand) {
+ assertIntOrNull(rightOperand);
+ return IntState.UNKNOWN_VALUE;
}
@override
- EvaluationResultImpl greaterThanValid(TypeProvider typeProvider, BinaryExpression node, ValidResult leftOperand) {
- try {
- return _valueOf(leftOperand.value.greaterThan(typeProvider, value));
- } on EvaluationException catch (exception) {
- return _error(node, exception.errorCode);
- }
+ IntState bitXor(InstanceState rightOperand) {
+ assertIntOrNull(rightOperand);
+ return IntState.UNKNOWN_VALUE;
}
@override
- EvaluationResultImpl integerDivideError(BinaryExpression node, ErrorResult leftOperand) => leftOperand;
-
- @override
- EvaluationResultImpl integerDivideValid(TypeProvider typeProvider, BinaryExpression node, ValidResult leftOperand) {
- try {
- return _valueOf(leftOperand.value.integerDivide(typeProvider, value));
- } on EvaluationException catch (exception) {
- return _error(node, exception.errorCode);
- }
+ StringState concatenate(InstanceState rightOperand) {
+ assertString(rightOperand);
+ return StringState.UNKNOWN_VALUE;
}
@override
- EvaluationResultImpl lessThanError(BinaryExpression node, ErrorResult leftOperand) => leftOperand;
+ BoolState convertToBool() => BoolState.UNKNOWN_VALUE;
@override
- EvaluationResultImpl lessThanOrEqualError(BinaryExpression node, ErrorResult leftOperand) => leftOperand;
+ StringState convertToString() => StringState.UNKNOWN_VALUE;
@override
- EvaluationResultImpl lessThanOrEqualValid(TypeProvider typeProvider, BinaryExpression node, ValidResult leftOperand) {
- try {
- return _valueOf(leftOperand.value.lessThanOrEqual(typeProvider, value));
- } on EvaluationException catch (exception) {
- return _error(node, exception.errorCode);
- }
+ NumState divide(InstanceState rightOperand) {
+ assertNumOrNull(rightOperand);
+ return _unknownNum(rightOperand);
}
@override
- EvaluationResultImpl lessThanValid(TypeProvider typeProvider, BinaryExpression node, ValidResult leftOperand) {
- try {
- return _valueOf(leftOperand.value.lessThan(typeProvider, value));
- } on EvaluationException catch (exception) {
- return _error(node, exception.errorCode);
- }
+ BoolState equalEqual(InstanceState rightOperand) {
+ assertBoolNumStringOrNull(rightOperand);
+ return BoolState.UNKNOWN_VALUE;
}
@override
- EvaluationResultImpl logicalAndError(BinaryExpression node, ErrorResult leftOperand) => leftOperand;
+ String get typeName => "dynamic";
@override
- EvaluationResultImpl logicalAndValid(TypeProvider typeProvider, BinaryExpression node, ValidResult leftOperand) {
- try {
- return _valueOf(leftOperand.value.logicalAnd(typeProvider, value));
- } on EvaluationException catch (exception) {
- return _error(node, exception.errorCode);
- }
+ BoolState greaterThan(InstanceState rightOperand) {
+ assertNumOrNull(rightOperand);
+ return BoolState.UNKNOWN_VALUE;
}
@override
- EvaluationResultImpl logicalOrError(BinaryExpression node, ErrorResult leftOperand) => leftOperand;
+ BoolState greaterThanOrEqual(InstanceState rightOperand) {
+ assertNumOrNull(rightOperand);
+ return BoolState.UNKNOWN_VALUE;
+ }
@override
- EvaluationResultImpl logicalOrValid(TypeProvider typeProvider, BinaryExpression node, ValidResult leftOperand) {
- try {
- return _valueOf(leftOperand.value.logicalOr(typeProvider, value));
- } on EvaluationException catch (exception) {
- return _error(node, exception.errorCode);
- }
+ IntState integerDivide(InstanceState rightOperand) {
+ assertNumOrNull(rightOperand);
+ return IntState.UNKNOWN_VALUE;
}
@override
- EvaluationResultImpl minusError(BinaryExpression node, ErrorResult leftOperand) => leftOperand;
+ bool get isBool => true;
@override
- EvaluationResultImpl minusValid(TypeProvider typeProvider, BinaryExpression node, ValidResult leftOperand) {
- try {
- return _valueOf(leftOperand.value.minus(typeProvider, value));
- } on EvaluationException catch (exception) {
- return _error(node, exception.errorCode);
- }
+ bool get isBoolNumStringOrNull => true;
+
+ @override
+ BoolState lessThan(InstanceState rightOperand) {
+ assertNumOrNull(rightOperand);
+ return BoolState.UNKNOWN_VALUE;
}
@override
- EvaluationResultImpl notEqualError(BinaryExpression node, ErrorResult leftOperand) => leftOperand;
+ BoolState lessThanOrEqual(InstanceState rightOperand) {
+ assertNumOrNull(rightOperand);
+ return BoolState.UNKNOWN_VALUE;
+ }
@override
- EvaluationResultImpl notEqualValid(TypeProvider typeProvider, BinaryExpression node, ValidResult leftOperand) {
- try {
- return _valueOf(leftOperand.value.notEqual(typeProvider, value));
- } on EvaluationException catch (exception) {
- return _error(node, exception.errorCode);
- }
+ BoolState logicalAnd(InstanceState rightOperand) {
+ assertBool(rightOperand);
+ return BoolState.UNKNOWN_VALUE;
}
@override
- EvaluationResultImpl remainderError(BinaryExpression node, ErrorResult leftOperand) => leftOperand;
+ BoolState logicalNot() => BoolState.UNKNOWN_VALUE;
@override
- EvaluationResultImpl remainderValid(TypeProvider typeProvider, BinaryExpression node, ValidResult leftOperand) {
- try {
- return _valueOf(leftOperand.value.remainder(typeProvider, value));
- } on EvaluationException catch (exception) {
- return _error(node, exception.errorCode);
- }
+ BoolState logicalOr(InstanceState rightOperand) {
+ assertBool(rightOperand);
+ return rightOperand.convertToBool();
}
@override
- EvaluationResultImpl shiftLeftError(BinaryExpression node, ErrorResult leftOperand) => leftOperand;
+ NumState minus(InstanceState rightOperand) {
+ assertNumOrNull(rightOperand);
+ return _unknownNum(rightOperand);
+ }
@override
- EvaluationResultImpl shiftLeftValid(TypeProvider typeProvider, BinaryExpression node, ValidResult leftOperand) {
- try {
- return _valueOf(leftOperand.value.shiftLeft(typeProvider, value));
- } on EvaluationException catch (exception) {
- return _error(node, exception.errorCode);
- }
- }
+ NumState negated() => NumState.UNKNOWN_VALUE;
@override
- EvaluationResultImpl shiftRightError(BinaryExpression node, ErrorResult leftOperand) => leftOperand;
+ NumState remainder(InstanceState rightOperand) {
+ assertNumOrNull(rightOperand);
+ return _unknownNum(rightOperand);
+ }
@override
- EvaluationResultImpl shiftRightValid(TypeProvider typeProvider, BinaryExpression node, ValidResult leftOperand) {
- try {
- return _valueOf(leftOperand.value.shiftRight(typeProvider, value));
- } on EvaluationException catch (exception) {
- return _error(node, exception.errorCode);
- }
+ IntState shiftLeft(InstanceState rightOperand) {
+ assertIntOrNull(rightOperand);
+ return IntState.UNKNOWN_VALUE;
}
@override
- EvaluationResultImpl timesError(BinaryExpression node, ErrorResult leftOperand) => leftOperand;
+ IntState shiftRight(InstanceState rightOperand) {
+ assertIntOrNull(rightOperand);
+ return IntState.UNKNOWN_VALUE;
+ }
@override
- EvaluationResultImpl timesValid(TypeProvider typeProvider, BinaryExpression node, ValidResult leftOperand) {
- try {
- return _valueOf(leftOperand.value.times(typeProvider, value));
- } on EvaluationException catch (exception) {
- return _error(node, exception.errorCode);
- }
+ NumState times(InstanceState rightOperand) {
+ assertNumOrNull(rightOperand);
+ return _unknownNum(rightOperand);
}
/**
- * Return a result object representing an error associated with the given node.
- *
- * @param node the AST node associated with the error
- * @param code the error code indicating the nature of the error
- * @return a result object representing an error associated with the given node
- */
- ErrorResult _error(AstNode node, ErrorCode code) => new ErrorResult.con1(node, code);
-
- /**
- * Return a result object representing the given value.
+ * Return an object representing an unknown numeric value whose type is based on the type of the
+ * right-hand operand.
*
- * @param value the value to be represented as a result object
- * @return a result object representing the given value
+ * @param rightOperand the operand whose type will determine the type of the result
+ * @return an object representing an unknown numeric value
*/
- ValidResult _valueOf(DartObjectImpl value) => new ValidResult(value);
+ NumState _unknownNum(InstanceState rightOperand) {
+ if (rightOperand is IntState) {
+ return IntState.UNKNOWN_VALUE;
+ } else if (rightOperand is DoubleState) {
+ return DoubleState.UNKNOWN_VALUE;
+ }
+ return NumState.UNKNOWN_VALUE;
+ }
}
/**
- * Instances of the class `BoolState` represent the state of an object representing a boolean
- * value.
+ * Instances of the class `ErrorResult` represent the result of evaluating an expression that
+ * is not a valid compile time constant.
*/
-class BoolState extends InstanceState {
+class ErrorResult extends EvaluationResultImpl {
/**
- * The value of this instance.
+ * The errors that prevent the expression from being a valid compile time constant.
*/
- final bool value;
+ List<ErrorResult_ErrorData> _errors = new List<ErrorResult_ErrorData>();
/**
- * An instance representing the boolean value 'false'.
+ * Initialize a newly created result representing the error with the given code reported against
+ * the given node.
+ *
+ * @param node the node against which the error should be reported
+ * @param errorCode the error code for the error to be generated
*/
- static BoolState FALSE_STATE = new BoolState(false);
+ ErrorResult.con1(AstNode node, ErrorCode errorCode) {
+ _errors.add(new ErrorResult_ErrorData(node, errorCode));
+ }
/**
- * An instance representing the boolean value 'true'.
+ * Initialize a newly created result to represent the union of the errors in the given result
+ * objects.
+ *
+ * @param firstResult the first set of results being merged
+ * @param secondResult the second set of results being merged
*/
- static BoolState TRUE_STATE = new BoolState(true);
+ ErrorResult.con2(ErrorResult firstResult, ErrorResult secondResult) {
+ _errors.addAll(firstResult._errors);
+ _errors.addAll(secondResult._errors);
+ }
- /**
- * A state that can be used to represent a boolean whose value is not known.
- */
- static BoolState UNKNOWN_VALUE = new BoolState(null);
+ @override
+ EvaluationResultImpl add(TypeProvider typeProvider, BinaryExpression node, EvaluationResultImpl rightOperand) => rightOperand.addToError(node, this);
- /**
- * Return the boolean state representing the given boolean value.
- *
- * @param value the value to be represented
- * @return the boolean state representing the given boolean value
- */
- static BoolState from(bool value) => value ? BoolState.TRUE_STATE : BoolState.FALSE_STATE;
+ @override
+ EvaluationResultImpl applyBooleanConversion(TypeProvider typeProvider, AstNode node) => this;
- /**
- * Initialize a newly created state to represent the given value.
- *
- * @param value the value of this instance
- */
- BoolState(this.value);
+ @override
+ EvaluationResultImpl bitAnd(TypeProvider typeProvider, BinaryExpression node, EvaluationResultImpl rightOperand) => rightOperand.bitAndError(node, this);
@override
- BoolState convertToBool() => this;
+ EvaluationResultImpl bitNot(TypeProvider typeProvider, Expression node) => this;
@override
- StringState convertToString() {
- if (value == null) {
- return StringState.UNKNOWN_VALUE;
- }
- return new StringState(value ? "true" : "false");
- }
+ EvaluationResultImpl bitOr(TypeProvider typeProvider, BinaryExpression node, EvaluationResultImpl rightOperand) => rightOperand.bitOrError(node, this);
@override
- BoolState equalEqual(InstanceState rightOperand) {
- assertBoolNumStringOrNull(rightOperand);
- if (value == null) {
- return UNKNOWN_VALUE;
- }
- if (rightOperand is BoolState) {
- bool rightValue = rightOperand.value;
- if (rightValue == null) {
- return UNKNOWN_VALUE;
- }
- return BoolState.from(identical(value, rightValue));
- } else if (rightOperand is DynamicState) {
- return UNKNOWN_VALUE;
- }
- return FALSE_STATE;
- }
+ EvaluationResultImpl bitXor(TypeProvider typeProvider, BinaryExpression node, EvaluationResultImpl rightOperand) => rightOperand.bitXorError(node, this);
@override
- bool operator ==(Object object) => object is BoolState && identical(value, object.value);
+ EvaluationResultImpl concatenate(TypeProvider typeProvider, Expression node, EvaluationResultImpl rightOperand) => rightOperand.concatenateError(node, this);
@override
- String get typeName => "bool";
+ EvaluationResultImpl divide(TypeProvider typeProvider, BinaryExpression node, EvaluationResultImpl rightOperand) => rightOperand.divideError(node, this);
@override
- bool get hasExactValue => true;
+ EvaluationResultImpl equalEqual(TypeProvider typeProvider, Expression node, EvaluationResultImpl rightOperand) => rightOperand.equalEqualError(node, this);
@override
- int get hashCode => value == null ? 0 : (value ? 2 : 3);
+ bool equalValues(TypeProvider typeProvider, EvaluationResultImpl result) => false;
+
+ List<ErrorResult_ErrorData> get errorData => _errors;
- /**
- * Return `true` if this object represents an object whose type is 'bool'.
- *
- * @return `true` if this object represents a boolean value
- */
@override
- bool get isBool => true;
+ EvaluationResultImpl greaterThan(TypeProvider typeProvider, BinaryExpression node, EvaluationResultImpl rightOperand) => rightOperand.greaterThanError(node, this);
@override
- bool get isBoolNumStringOrNull => true;
+ EvaluationResultImpl greaterThanOrEqual(TypeProvider typeProvider, BinaryExpression node, EvaluationResultImpl rightOperand) => rightOperand.greaterThanOrEqualError(node, this);
@override
- BoolState logicalAnd(InstanceState rightOperand) {
- assertBool(rightOperand);
- if (value == null) {
- return UNKNOWN_VALUE;
- }
- return value ? rightOperand.convertToBool() : FALSE_STATE;
- }
+ EvaluationResultImpl integerDivide(TypeProvider typeProvider, BinaryExpression node, EvaluationResultImpl rightOperand) => rightOperand.integerDivideError(node, this);
@override
- BoolState logicalNot() {
- if (value == null) {
- return UNKNOWN_VALUE;
- }
- return value ? FALSE_STATE : TRUE_STATE;
- }
+ EvaluationResultImpl integerDivideValid(TypeProvider typeProvider, BinaryExpression node, ValidResult leftOperand) => this;
@override
- BoolState logicalOr(InstanceState rightOperand) {
- assertBool(rightOperand);
- if (value == null) {
- return UNKNOWN_VALUE;
- }
- return value ? TRUE_STATE : rightOperand.convertToBool();
- }
+ EvaluationResultImpl lessThan(TypeProvider typeProvider, BinaryExpression node, EvaluationResultImpl rightOperand) => rightOperand.lessThanError(node, this);
@override
- String toString() => value == null ? "-unknown-" : (value ? "true" : "false");
-}
+ EvaluationResultImpl lessThanOrEqual(TypeProvider typeProvider, BinaryExpression node, EvaluationResultImpl rightOperand) => rightOperand.lessThanOrEqualError(node, this);
-/**
- * Instances of the class `DartObjectImpl` represent an instance of a Dart class.
- */
-class DartObjectImpl implements DartObject {
- /**
- * The run-time type of this object.
- */
- final InterfaceType type;
+ @override
+ EvaluationResultImpl logicalAnd(TypeProvider typeProvider, BinaryExpression node, EvaluationResultImpl rightOperand) => rightOperand.logicalAndError(node, this);
- /**
- * The state of the object.
- */
- final InstanceState _state;
+ @override
+ EvaluationResultImpl logicalNot(TypeProvider typeProvider, Expression node) => this;
- /**
- * Initialize a newly created object to have the given type and state.
- *
- * @param type the run-time type of this object
- * @param state the state of the object
- */
- DartObjectImpl(this.type, this._state);
+ @override
+ EvaluationResultImpl logicalOr(TypeProvider typeProvider, BinaryExpression node, EvaluationResultImpl rightOperand) => rightOperand.logicalOrError(node, this);
- /**
- * Return the result of invoking the '+' operator on this object with the given argument.
- *
- * @param typeProvider the type provider used to find known types
- * @param rightOperand the right-hand operand of the operation
- * @return the result of invoking the '+' operator on this object with the given argument
- * @throws EvaluationException if the operator is not appropriate for an object of this kind
- */
- DartObjectImpl add(TypeProvider typeProvider, DartObjectImpl rightOperand) {
- InstanceState result = _state.add(rightOperand._state);
- if (result is IntState) {
- return new DartObjectImpl(typeProvider.intType, result);
- } else if (result is DoubleState) {
- return new DartObjectImpl(typeProvider.doubleType, result);
- } else if (result is NumState) {
- return new DartObjectImpl(typeProvider.numType, result);
- }
- // We should never get here.
- throw new IllegalStateException("add returned a ${result.runtimeType.toString()}");
- }
+ @override
+ EvaluationResultImpl minus(TypeProvider typeProvider, BinaryExpression node, EvaluationResultImpl rightOperand) => rightOperand.minusError(node, this);
- /**
- * Return the result of invoking the '&' operator on this object with the given argument.
- *
- * @param typeProvider the type provider used to find known types
- * @param rightOperand the right-hand operand of the operation
- * @return the result of invoking the '&' operator on this object with the given argument
- * @throws EvaluationException if the operator is not appropriate for an object of this kind
- */
- DartObjectImpl bitAnd(TypeProvider typeProvider, DartObjectImpl rightOperand) => new DartObjectImpl(typeProvider.intType, _state.bitAnd(rightOperand._state));
+ @override
+ EvaluationResultImpl negated(TypeProvider typeProvider, Expression node) => this;
- /**
- * Return the result of invoking the '~' operator on this object.
- *
- * @param typeProvider the type provider used to find known types
- * @return the result of invoking the '~' operator on this object
- * @throws EvaluationException if the operator is not appropriate for an object of this kind
- */
- DartObjectImpl bitNot(TypeProvider typeProvider) => new DartObjectImpl(typeProvider.intType, _state.bitNot());
+ @override
+ EvaluationResultImpl notEqual(TypeProvider typeProvider, BinaryExpression node, EvaluationResultImpl rightOperand) => rightOperand.notEqualError(node, this);
- /**
- * Return the result of invoking the '|' operator on this object with the given argument.
- *
- * @param typeProvider the type provider used to find known types
- * @param rightOperand the right-hand operand of the operation
- * @return the result of invoking the '|' operator on this object with the given argument
- * @throws EvaluationException if the operator is not appropriate for an object of this kind
- */
- DartObjectImpl bitOr(TypeProvider typeProvider, DartObjectImpl rightOperand) => new DartObjectImpl(typeProvider.intType, _state.bitOr(rightOperand._state));
+ @override
+ EvaluationResultImpl performToString(TypeProvider typeProvider, AstNode node) => this;
- /**
- * Return the result of invoking the '^' operator on this object with the given argument.
- *
- * @param typeProvider the type provider used to find known types
- * @param rightOperand the right-hand operand of the operation
- * @return the result of invoking the '^' operator on this object with the given argument
- * @throws EvaluationException if the operator is not appropriate for an object of this kind
- */
- DartObjectImpl bitXor(TypeProvider typeProvider, DartObjectImpl rightOperand) => new DartObjectImpl(typeProvider.intType, _state.bitXor(rightOperand._state));
+ @override
+ EvaluationResultImpl remainder(TypeProvider typeProvider, BinaryExpression node, EvaluationResultImpl rightOperand) => rightOperand.remainderError(node, this);
- /**
- * Return the result of invoking the ' ' operator on this object with the given argument.
- *
- * @param typeProvider the type provider used to find known types
- * @param rightOperand the right-hand operand of the operation
- * @return the result of invoking the ' ' operator on this object with the given argument
- * @throws EvaluationException if the operator is not appropriate for an object of this kind
- */
- DartObjectImpl concatenate(TypeProvider typeProvider, DartObjectImpl rightOperand) => new DartObjectImpl(typeProvider.stringType, _state.concatenate(rightOperand._state));
+ @override
+ EvaluationResultImpl shiftLeft(TypeProvider typeProvider, BinaryExpression node, EvaluationResultImpl rightOperand) => rightOperand.shiftLeftError(node, this);
- /**
- * Return the result of applying boolean conversion to this object.
- *
- * @param typeProvider the type provider used to find known types
- * @return the result of applying boolean conversion to this object
- * @throws EvaluationException if the operator is not appropriate for an object of this kind
- */
- DartObjectImpl convertToBool(TypeProvider typeProvider) {
- InterfaceType boolType = typeProvider.boolType;
- if (identical(type, boolType)) {
- return this;
- }
- return new DartObjectImpl(boolType, _state.convertToBool());
- }
+ @override
+ EvaluationResultImpl shiftRight(TypeProvider typeProvider, BinaryExpression node, EvaluationResultImpl rightOperand) => rightOperand.shiftRightError(node, this);
- /**
- * Return the result of invoking the '/' operator on this object with the given argument.
- *
- * @param typeProvider the type provider used to find known types
- * @param rightOperand the right-hand operand of the operation
- * @return the result of invoking the '/' operator on this object with the given argument
- * @throws EvaluationException if the operator is not appropriate for an object of this kind
- */
- DartObjectImpl divide(TypeProvider typeProvider, DartObjectImpl rightOperand) {
- InstanceState result = _state.divide(rightOperand._state);
- if (result is IntState) {
- return new DartObjectImpl(typeProvider.intType, result);
- } else if (result is DoubleState) {
- return new DartObjectImpl(typeProvider.doubleType, result);
- } else if (result is NumState) {
- return new DartObjectImpl(typeProvider.numType, result);
- }
- // We should never get here.
- throw new IllegalStateException("divide returned a ${result.runtimeType.toString()}");
- }
+ @override
+ EvaluationResultImpl times(TypeProvider typeProvider, BinaryExpression node, EvaluationResultImpl rightOperand) => rightOperand.timesError(node, this);
- /**
- * Return the result of invoking the '==' operator on this object with the given argument.
- *
- * @param typeProvider the type provider used to find known types
- * @param rightOperand the right-hand operand of the operation
- * @return the result of invoking the '==' operator on this object with the given argument
- * @throws EvaluationException if the operator is not appropriate for an object of this kind
- */
- DartObjectImpl equalEqual(TypeProvider typeProvider, DartObjectImpl rightOperand) {
- if (type != rightOperand.type) {
- String typeName = type.name;
- if (!(typeName == "bool" || typeName == "double" || typeName == "int" || typeName == "num" || typeName == "String" || typeName == "Null" || type.isDynamic)) {
- throw new EvaluationException(CompileTimeErrorCode.CONST_EVAL_TYPE_BOOL_NUM_STRING);
- }
- }
- return new DartObjectImpl(typeProvider.boolType, _state.equalEqual(rightOperand._state));
- }
+ @override
+ EvaluationResultImpl addToError(BinaryExpression node, ErrorResult leftOperand) => new ErrorResult.con2(this, leftOperand);
@override
- bool operator ==(Object object) {
- if (object is! DartObjectImpl) {
- return false;
- }
- DartObjectImpl dartObject = object as DartObjectImpl;
- return type == dartObject.type && _state == dartObject._state;
- }
+ EvaluationResultImpl addToValid(TypeProvider typeProvider, BinaryExpression node, ValidResult leftOperand) => this;
@override
- bool get boolValue {
- if (_state is BoolState) {
- return (_state as BoolState).value;
- }
- return null;
- }
+ EvaluationResultImpl bitAndError(BinaryExpression node, ErrorResult leftOperand) => new ErrorResult.con2(this, leftOperand);
@override
- double get doubleValue {
- if (_state is DoubleState) {
- return (_state as DoubleState).value;
- }
- return null;
- }
+ EvaluationResultImpl bitAndValid(TypeProvider typeProvider, BinaryExpression node, ValidResult leftOperand) => this;
@override
- int get intValue {
- if (_state is IntState) {
- return (_state as IntState).value;
- }
- return null;
- }
+ EvaluationResultImpl bitOrError(BinaryExpression node, ErrorResult leftOperand) => new ErrorResult.con2(this, leftOperand);
@override
- String get stringValue {
- if (_state is StringState) {
- return (_state as StringState).value;
- }
- return null;
- }
+ EvaluationResultImpl bitOrValid(TypeProvider typeProvider, BinaryExpression node, ValidResult leftOperand) => this;
@override
- Object get value => _state.value;
+ EvaluationResultImpl bitXorError(BinaryExpression node, ErrorResult leftOperand) => new ErrorResult.con2(this, leftOperand);
- /**
- * Return the result of invoking the '&gt;' operator on this object with the given argument.
- *
- * @param typeProvider the type provider used to find known types
- * @param rightOperand the right-hand operand of the operation
- * @return the result of invoking the '&gt;' operator on this object with the given argument
- * @throws EvaluationException if the operator is not appropriate for an object of this kind
- */
- DartObjectImpl greaterThan(TypeProvider typeProvider, DartObjectImpl rightOperand) => new DartObjectImpl(typeProvider.boolType, _state.greaterThan(rightOperand._state));
+ @override
+ EvaluationResultImpl bitXorValid(TypeProvider typeProvider, BinaryExpression node, ValidResult leftOperand) => this;
- /**
- * Return the result of invoking the '&gt;=' operator on this object with the given argument.
- *
- * @param typeProvider the type provider used to find known types
- * @param rightOperand the right-hand operand of the operation
- * @return the result of invoking the '&gt;=' operator on this object with the given argument
- * @throws EvaluationException if the operator is not appropriate for an object of this kind
- */
- DartObjectImpl greaterThanOrEqual(TypeProvider typeProvider, DartObjectImpl rightOperand) => new DartObjectImpl(typeProvider.boolType, _state.greaterThanOrEqual(rightOperand._state));
+ @override
+ EvaluationResultImpl concatenateError(Expression node, ErrorResult leftOperand) => new ErrorResult.con2(this, leftOperand);
@override
- bool get hasExactValue => _state.hasExactValue;
+ EvaluationResultImpl concatenateValid(TypeProvider typeProvider, Expression node, ValidResult leftOperand) => this;
@override
- int get hashCode => ObjectUtilities.combineHashCodes(type.hashCode, _state.hashCode);
+ EvaluationResultImpl divideError(BinaryExpression node, ErrorResult leftOperand) => new ErrorResult.con2(this, leftOperand);
- /**
- * Return the result of invoking the '~/' operator on this object with the given argument.
- *
- * @param typeProvider the type provider used to find known types
- * @param rightOperand the right-hand operand of the operation
- * @return the result of invoking the '~/' operator on this object with the given argument
- * @throws EvaluationException if the operator is not appropriate for an object of this kind
- */
- DartObjectImpl integerDivide(TypeProvider typeProvider, DartObjectImpl rightOperand) => new DartObjectImpl(typeProvider.intType, _state.integerDivide(rightOperand._state));
+ @override
+ EvaluationResultImpl divideValid(TypeProvider typeProvider, BinaryExpression node, ValidResult leftOperand) => this;
- /**
- * Return `true` if this object represents an object whose type is 'bool'.
- *
- * @return `true` if this object represents a boolean value
- */
- bool get isBool => _state.isBool;
+ @override
+ EvaluationResultImpl equalEqualError(Expression node, ErrorResult leftOperand) => new ErrorResult.con2(this, leftOperand);
- /**
- * Return `true` if this object represents an object whose type is either 'bool', 'num',
- * 'String', or 'Null'.
- *
- * @return `true` if this object represents either a boolean, numeric, string or null value
- */
- bool get isBoolNumStringOrNull => _state.isBoolNumStringOrNull;
+ @override
+ EvaluationResultImpl equalEqualValid(TypeProvider typeProvider, Expression node, ValidResult leftOperand) => this;
@override
- bool get isFalse => _state is BoolState && identical((_state as BoolState).value, false);
+ EvaluationResultImpl greaterThanError(BinaryExpression node, ErrorResult leftOperand) => new ErrorResult.con2(this, leftOperand);
@override
- bool get isNull => _state is NullState;
+ EvaluationResultImpl greaterThanOrEqualError(BinaryExpression node, ErrorResult leftOperand) => new ErrorResult.con2(this, leftOperand);
@override
- bool get isTrue => _state is BoolState && identical((_state as BoolState).value, true);
+ EvaluationResultImpl greaterThanOrEqualValid(TypeProvider typeProvider, BinaryExpression node, ValidResult leftOperand) => this;
- /**
- * Return `true` if this object represents an instance of a user-defined class.
- *
- * @return `true` if this object represents an instance of a user-defined class
- */
- bool get isUserDefinedObject => _state is GenericState;
+ @override
+ EvaluationResultImpl greaterThanValid(TypeProvider typeProvider, BinaryExpression node, ValidResult leftOperand) => this;
- /**
- * Return the result of invoking the '&lt;' operator on this object with the given argument.
- *
- * @param typeProvider the type provider used to find known types
- * @param rightOperand the right-hand operand of the operation
- * @return the result of invoking the '&lt;' operator on this object with the given argument
- * @throws EvaluationException if the operator is not appropriate for an object of this kind
- */
- DartObjectImpl lessThan(TypeProvider typeProvider, DartObjectImpl rightOperand) => new DartObjectImpl(typeProvider.boolType, _state.lessThan(rightOperand._state));
+ @override
+ EvaluationResultImpl integerDivideError(BinaryExpression node, ErrorResult leftOperand) => new ErrorResult.con2(this, leftOperand);
- /**
- * Return the result of invoking the '&lt;=' operator on this object with the given argument.
- *
- * @param typeProvider the type provider used to find known types
- * @param rightOperand the right-hand operand of the operation
- * @return the result of invoking the '&lt;=' operator on this object with the given argument
- * @throws EvaluationException if the operator is not appropriate for an object of this kind
- */
- DartObjectImpl lessThanOrEqual(TypeProvider typeProvider, DartObjectImpl rightOperand) => new DartObjectImpl(typeProvider.boolType, _state.lessThanOrEqual(rightOperand._state));
+ @override
+ EvaluationResultImpl lessThanError(BinaryExpression node, ErrorResult leftOperand) => new ErrorResult.con2(this, leftOperand);
- /**
- * Return the result of invoking the '&&' operator on this object with the given argument.
- *
- * @param typeProvider the type provider used to find known types
- * @param rightOperand the right-hand operand of the operation
- * @return the result of invoking the '&&' operator on this object with the given argument
- * @throws EvaluationException if the operator is not appropriate for an object of this kind
- */
- DartObjectImpl logicalAnd(TypeProvider typeProvider, DartObjectImpl rightOperand) => new DartObjectImpl(typeProvider.boolType, _state.logicalAnd(rightOperand._state));
+ @override
+ EvaluationResultImpl lessThanOrEqualError(BinaryExpression node, ErrorResult leftOperand) => new ErrorResult.con2(this, leftOperand);
- /**
- * Return the result of invoking the '!' operator on this object.
- *
- * @param typeProvider the type provider used to find known types
- * @return the result of invoking the '!' operator on this object
- * @throws EvaluationException if the operator is not appropriate for an object of this kind
- */
- DartObjectImpl logicalNot(TypeProvider typeProvider) => new DartObjectImpl(typeProvider.boolType, _state.logicalNot());
+ @override
+ EvaluationResultImpl lessThanOrEqualValid(TypeProvider typeProvider, BinaryExpression node, ValidResult leftOperand) => this;
- /**
- * Return the result of invoking the '||' operator on this object with the given argument.
- *
- * @param typeProvider the type provider used to find known types
- * @param rightOperand the right-hand operand of the operation
- * @return the result of invoking the '||' operator on this object with the given argument
- * @throws EvaluationException if the operator is not appropriate for an object of this kind
- */
- DartObjectImpl logicalOr(TypeProvider typeProvider, DartObjectImpl rightOperand) => new DartObjectImpl(typeProvider.boolType, _state.logicalOr(rightOperand._state));
+ @override
+ EvaluationResultImpl lessThanValid(TypeProvider typeProvider, BinaryExpression node, ValidResult leftOperand) => this;
- /**
- * Return the result of invoking the '-' operator on this object with the given argument.
- *
- * @param typeProvider the type provider used to find known types
- * @param rightOperand the right-hand operand of the operation
- * @return the result of invoking the '-' operator on this object with the given argument
- * @throws EvaluationException if the operator is not appropriate for an object of this kind
- */
- DartObjectImpl minus(TypeProvider typeProvider, DartObjectImpl rightOperand) {
- InstanceState result = _state.minus(rightOperand._state);
- if (result is IntState) {
- return new DartObjectImpl(typeProvider.intType, result);
- } else if (result is DoubleState) {
- return new DartObjectImpl(typeProvider.doubleType, result);
- } else if (result is NumState) {
- return new DartObjectImpl(typeProvider.numType, result);
- }
- // We should never get here.
- throw new IllegalStateException("minus returned a ${result.runtimeType.toString()}");
- }
+ @override
+ EvaluationResultImpl logicalAndError(BinaryExpression node, ErrorResult leftOperand) => new ErrorResult.con2(this, leftOperand);
+
+ @override
+ EvaluationResultImpl logicalAndValid(TypeProvider typeProvider, BinaryExpression node, ValidResult leftOperand) => this;
+
+ @override
+ EvaluationResultImpl logicalOrError(BinaryExpression node, ErrorResult leftOperand) => new ErrorResult.con2(this, leftOperand);
+
+ @override
+ EvaluationResultImpl logicalOrValid(TypeProvider typeProvider, BinaryExpression node, ValidResult leftOperand) => this;
+
+ @override
+ EvaluationResultImpl minusError(BinaryExpression node, ErrorResult leftOperand) => new ErrorResult.con2(this, leftOperand);
+
+ @override
+ EvaluationResultImpl minusValid(TypeProvider typeProvider, BinaryExpression node, ValidResult leftOperand) => this;
+
+ @override
+ EvaluationResultImpl notEqualError(BinaryExpression node, ErrorResult leftOperand) => new ErrorResult.con2(this, leftOperand);
+
+ @override
+ EvaluationResultImpl notEqualValid(TypeProvider typeProvider, BinaryExpression node, ValidResult leftOperand) => this;
+
+ @override
+ EvaluationResultImpl remainderError(BinaryExpression node, ErrorResult leftOperand) => new ErrorResult.con2(this, leftOperand);
+
+ @override
+ EvaluationResultImpl remainderValid(TypeProvider typeProvider, BinaryExpression node, ValidResult leftOperand) => this;
+
+ @override
+ EvaluationResultImpl shiftLeftError(BinaryExpression node, ErrorResult leftOperand) => new ErrorResult.con2(this, leftOperand);
+
+ @override
+ EvaluationResultImpl shiftLeftValid(TypeProvider typeProvider, BinaryExpression node, ValidResult leftOperand) => this;
+
+ @override
+ EvaluationResultImpl shiftRightError(BinaryExpression node, ErrorResult leftOperand) => new ErrorResult.con2(this, leftOperand);
+
+ @override
+ EvaluationResultImpl shiftRightValid(TypeProvider typeProvider, BinaryExpression node, ValidResult leftOperand) => this;
+
+ @override
+ EvaluationResultImpl timesError(BinaryExpression node, ErrorResult leftOperand) => new ErrorResult.con2(this, leftOperand);
+
+ @override
+ EvaluationResultImpl timesValid(TypeProvider typeProvider, BinaryExpression node, ValidResult leftOperand) => this;
+}
+class ErrorResult_ErrorData {
/**
- * Return the result of invoking the '-' operator on this object.
- *
- * @param typeProvider the type provider used to find known types
- * @return the result of invoking the '-' operator on this object
- * @throws EvaluationException if the operator is not appropriate for an object of this kind
+ * The node against which the error should be reported.
*/
- DartObjectImpl negated(TypeProvider typeProvider) {
- InstanceState result = _state.negated();
- if (result is IntState) {
- return new DartObjectImpl(typeProvider.intType, result);
- } else if (result is DoubleState) {
- return new DartObjectImpl(typeProvider.doubleType, result);
- } else if (result is NumState) {
- return new DartObjectImpl(typeProvider.numType, result);
- }
- // We should never get here.
- throw new IllegalStateException("negated returned a ${result.runtimeType.toString()}");
- }
+ final AstNode node;
/**
- * Return the result of invoking the '!=' operator on this object with the given argument.
- *
- * @param typeProvider the type provider used to find known types
- * @param rightOperand the right-hand operand of the operation
- * @return the result of invoking the '!=' operator on this object with the given argument
- * @throws EvaluationException if the operator is not appropriate for an object of this kind
+ * The error code for the error to be generated.
*/
- DartObjectImpl notEqual(TypeProvider typeProvider, DartObjectImpl rightOperand) {
- if (type != rightOperand.type) {
- String typeName = type.name;
- if (typeName != "bool" && typeName != "double" && typeName != "int" && typeName != "num" && typeName != "String") {
- return new DartObjectImpl(typeProvider.boolType, BoolState.TRUE_STATE);
- }
- }
- return new DartObjectImpl(typeProvider.boolType, _state.equalEqual(rightOperand._state).logicalNot());
- }
+ final ErrorCode errorCode;
/**
- * Return the result of converting this object to a String.
+ * Initialize a newly created data holder to represent the error with the given code reported
+ * against the given node.
*
- * @param typeProvider the type provider used to find known types
- * @return the result of converting this object to a String
- * @throws EvaluationException if the object cannot be converted to a String
+ * @param node the node against which the error should be reported
+ * @param errorCode the error code for the error to be generated
*/
- DartObjectImpl performToString(TypeProvider typeProvider) {
- InterfaceType stringType = typeProvider.stringType;
- if (identical(type, stringType)) {
- return this;
- }
- return new DartObjectImpl(stringType, _state.convertToString());
- }
+ ErrorResult_ErrorData(this.node, this.errorCode);
+}
+/**
+ * Instances of the class `EvaluationException` represent a run-time exception that would be
+ * thrown during the evaluation of Dart code.
+ */
+class EvaluationException extends JavaException {
/**
- * Return the result of invoking the '%' operator on this object with the given argument.
- *
- * @param typeProvider the type provider used to find known types
- * @param rightOperand the right-hand operand of the operation
- * @return the result of invoking the '%' operator on this object with the given argument
- * @throws EvaluationException if the operator is not appropriate for an object of this kind
+ * The error code associated with the exception.
*/
- DartObjectImpl remainder(TypeProvider typeProvider, DartObjectImpl rightOperand) {
- InstanceState result = _state.remainder(rightOperand._state);
- if (result is IntState) {
- return new DartObjectImpl(typeProvider.intType, result);
- } else if (result is DoubleState) {
- return new DartObjectImpl(typeProvider.doubleType, result);
- } else if (result is NumState) {
- return new DartObjectImpl(typeProvider.numType, result);
- }
- // We should never get here.
- throw new IllegalStateException("remainder returned a ${result.runtimeType.toString()}");
- }
+ final ErrorCode errorCode;
/**
- * Return the result of invoking the '&lt;&lt;' operator on this object with the given argument.
+ * Initialize a newly created exception to have the given error code.
*
- * @param typeProvider the type provider used to find known types
- * @param rightOperand the right-hand operand of the operation
- * @return the result of invoking the '&lt;&lt;' operator on this object with the given argument
- * @throws EvaluationException if the operator is not appropriate for an object of this kind
+ * @param errorCode the error code associated with the exception
*/
- DartObjectImpl shiftLeft(TypeProvider typeProvider, DartObjectImpl rightOperand) => new DartObjectImpl(typeProvider.intType, _state.shiftLeft(rightOperand._state));
+ EvaluationException(this.errorCode);
+}
+/**
+ * Instances of the class `EvaluationResult` represent the result of attempting to evaluate an
+ * expression.
+ */
+class EvaluationResult {
/**
- * Return the result of invoking the '&gt;&gt;' operator on this object with the given argument.
+ * Return an evaluation result representing the result of evaluating an expression that is not a
+ * compile-time constant because of the given errors.
*
- * @param typeProvider the type provider used to find known types
- * @param rightOperand the right-hand operand of the operation
- * @return the result of invoking the '&gt;&gt;' operator on this object with the given argument
- * @throws EvaluationException if the operator is not appropriate for an object of this kind
+ * @param errors the errors that should be reported for the expression(s) that were evaluated
+ * @return the result of evaluating an expression that is not a compile-time constant
*/
- DartObjectImpl shiftRight(TypeProvider typeProvider, DartObjectImpl rightOperand) => new DartObjectImpl(typeProvider.intType, _state.shiftRight(rightOperand._state));
+ static EvaluationResult forErrors(List<AnalysisError> errors) => new EvaluationResult(null, errors);
/**
- * Return the result of invoking the '*' operator on this object with the given argument.
+ * Return an evaluation result representing the result of evaluating an expression that is a
+ * compile-time constant that evaluates to the given value.
*
- * @param typeProvider the type provider used to find known types
- * @param rightOperand the right-hand operand of the operation
- * @return the result of invoking the '*' operator on this object with the given argument
- * @throws EvaluationException if the operator is not appropriate for an object of this kind
+ * @param value the value of the expression
+ * @return the result of evaluating an expression that is a compile-time constant
*/
- DartObjectImpl times(TypeProvider typeProvider, DartObjectImpl rightOperand) {
- InstanceState result = _state.times(rightOperand._state);
- if (result is IntState) {
- return new DartObjectImpl(typeProvider.intType, result);
- } else if (result is DoubleState) {
- return new DartObjectImpl(typeProvider.doubleType, result);
- } else if (result is NumState) {
- return new DartObjectImpl(typeProvider.numType, result);
- }
- // We should never get here.
- throw new IllegalStateException("times returned a ${result.runtimeType.toString()}");
- }
-
- @override
- String toString() => "${type.displayName} (${_state.toString()})";
-}
+ static EvaluationResult forValue(DartObject value) => new EvaluationResult(value, null);
-/**
- * Instances of the class `DoubleState` represent the state of an object representing a
- * double.
- */
-class DoubleState extends NumState {
/**
- * The value of this instance.
+ * The value of the expression.
*/
- final double value;
+ final DartObject value;
/**
- * A state that can be used to represent a double whose value is not known.
+ * The errors that should be reported for the expression(s) that were evaluated.
*/
- static DoubleState UNKNOWN_VALUE = new DoubleState(null);
+ final List<AnalysisError> _errors;
/**
- * Initialize a newly created state to represent a double with the given value.
+ * Initialize a newly created result object with the given state. Clients should use one of the
+ * factory methods: [forErrors] and [forValue].
*
- * @param value the value of this instance
+ * @param value the value of the expression
+ * @param errors the errors that should be reported for the expression(s) that were evaluated
*/
- DoubleState(this.value);
+ EvaluationResult(this.value, this._errors);
- @override
- NumState add(InstanceState rightOperand) {
- assertNumOrNull(rightOperand);
- if (value == null) {
- return UNKNOWN_VALUE;
- }
- if (rightOperand is IntState) {
- int rightValue = rightOperand.value;
- if (rightValue == null) {
- return UNKNOWN_VALUE;
- }
- return new DoubleState(value + rightValue.toDouble());
- } else if (rightOperand is DoubleState) {
- double rightValue = rightOperand.value;
- if (rightValue == null) {
- return UNKNOWN_VALUE;
- }
- return new DoubleState(value + rightValue);
- } else if (rightOperand is DynamicState || rightOperand is NumState) {
- return UNKNOWN_VALUE;
- }
- throw new EvaluationException(CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION);
- }
+ /**
+ * 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
+ * the expression is not a valid compile time constant if the errors would have been reported by
+ * other parts of the analysis engine.
+ */
+ List<AnalysisError> get errors => _errors == null ? AnalysisError.NO_ERRORS : _errors;
- @override
- StringState convertToString() {
- if (value == null) {
- return StringState.UNKNOWN_VALUE;
- }
- return new StringState(value.toString());
- }
+ /**
+ * Return `true` if the expression is a compile-time constant expression that would not
+ * throw an exception when evaluated.
+ *
+ * @return `true` if the expression is a valid compile-time constant expression
+ */
+ bool get isValid => _errors == null;
+}
- @override
- NumState divide(InstanceState rightOperand) {
- assertNumOrNull(rightOperand);
- if (value == null) {
- return UNKNOWN_VALUE;
- }
- if (rightOperand is IntState) {
- int rightValue = rightOperand.value;
- if (rightValue == null) {
- return UNKNOWN_VALUE;
- }
- return new DoubleState(value / rightValue.toDouble());
- } else if (rightOperand is DoubleState) {
- double rightValue = rightOperand.value;
- if (rightValue == null) {
- return UNKNOWN_VALUE;
- }
- return new DoubleState(value / rightValue);
- } else if (rightOperand is DynamicState || rightOperand is NumState) {
- return UNKNOWN_VALUE;
- }
- throw new EvaluationException(CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION);
- }
+/**
+ * Instances of the class `InternalResult` represent the result of attempting to evaluate a
+ * expression.
+ */
+abstract class EvaluationResultImpl {
+ EvaluationResultImpl add(TypeProvider typeProvider, BinaryExpression node, EvaluationResultImpl rightOperand);
- @override
- BoolState equalEqual(InstanceState rightOperand) {
- assertBoolNumStringOrNull(rightOperand);
- if (value == null) {
- return BoolState.UNKNOWN_VALUE;
- }
- if (rightOperand is DoubleState) {
- double rightValue = rightOperand.value;
- if (rightValue == null) {
- return BoolState.UNKNOWN_VALUE;
- }
- return BoolState.from(value == rightValue);
- } else if (rightOperand is IntState) {
- int rightValue = rightOperand.value;
- if (rightValue == null) {
- return BoolState.UNKNOWN_VALUE;
- }
- return BoolState.from(value == rightValue.toDouble());
- } else if (rightOperand is DynamicState || rightOperand is NumState) {
- return BoolState.UNKNOWN_VALUE;
- }
- return BoolState.FALSE_STATE;
- }
+ /**
+ * Return the result of applying boolean conversion to this result.
+ *
+ * @param typeProvider the type provider used to access known types
+ * @param node the node against which errors should be reported
+ * @return the result of applying boolean conversion to the given value
+ */
+ EvaluationResultImpl applyBooleanConversion(TypeProvider typeProvider, AstNode node);
- @override
- bool operator ==(Object object) => object is DoubleState && (value == object.value);
+ EvaluationResultImpl bitAnd(TypeProvider typeProvider, BinaryExpression node, EvaluationResultImpl rightOperand);
- @override
- String get typeName => "double";
+ EvaluationResultImpl bitNot(TypeProvider typeProvider, Expression node);
- @override
- BoolState greaterThan(InstanceState rightOperand) {
- assertNumOrNull(rightOperand);
- if (value == null) {
- return BoolState.UNKNOWN_VALUE;
- }
- if (rightOperand is IntState) {
- int rightValue = rightOperand.value;
- if (rightValue == null) {
- return BoolState.UNKNOWN_VALUE;
- }
- return BoolState.from(value > rightValue.toDouble());
- } else if (rightOperand is DoubleState) {
- double rightValue = rightOperand.value;
- if (rightValue == null) {
- return BoolState.UNKNOWN_VALUE;
- }
- return BoolState.from(value > rightValue);
- } else if (rightOperand is DynamicState || rightOperand is NumState) {
- return BoolState.UNKNOWN_VALUE;
- }
- throw new EvaluationException(CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION);
- }
+ EvaluationResultImpl bitOr(TypeProvider typeProvider, BinaryExpression node, EvaluationResultImpl rightOperand);
- @override
- BoolState greaterThanOrEqual(InstanceState rightOperand) {
- assertNumOrNull(rightOperand);
- if (value == null) {
- return BoolState.UNKNOWN_VALUE;
- }
- if (rightOperand is IntState) {
- int rightValue = rightOperand.value;
- if (rightValue == null) {
- return BoolState.UNKNOWN_VALUE;
- }
- return BoolState.from(value >= rightValue.toDouble());
- } else if (rightOperand is DoubleState) {
- double rightValue = rightOperand.value;
- if (rightValue == null) {
- return BoolState.UNKNOWN_VALUE;
- }
- return BoolState.from(value >= rightValue);
- } else if (rightOperand is DynamicState || rightOperand is NumState) {
- return BoolState.UNKNOWN_VALUE;
- }
- throw new EvaluationException(CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION);
- }
+ EvaluationResultImpl bitXor(TypeProvider typeProvider, BinaryExpression node, EvaluationResultImpl rightOperand);
- @override
- bool get hasExactValue => true;
+ EvaluationResultImpl concatenate(TypeProvider typeProvider, Expression node, EvaluationResultImpl rightOperand);
- @override
- int get hashCode => value == null ? 0 : value.hashCode;
+ EvaluationResultImpl divide(TypeProvider typeProvider, BinaryExpression node, EvaluationResultImpl rightOperand);
- @override
- IntState integerDivide(InstanceState rightOperand) {
- assertNumOrNull(rightOperand);
- if (value == null) {
- return IntState.UNKNOWN_VALUE;
- }
- if (rightOperand is IntState) {
- int rightValue = rightOperand.value;
- if (rightValue == null) {
- return IntState.UNKNOWN_VALUE;
- }
- double result = value / rightValue.toDouble();
- return new IntState(result.toInt());
- } else if (rightOperand is DoubleState) {
- double rightValue = rightOperand.value;
- if (rightValue == null) {
- return IntState.UNKNOWN_VALUE;
- }
- double result = value / rightValue;
- return new IntState(result.toInt());
- } else if (rightOperand is DynamicState || rightOperand is NumState) {
- return IntState.UNKNOWN_VALUE;
- }
- throw new EvaluationException(CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION);
- }
+ EvaluationResultImpl equalEqual(TypeProvider typeProvider, Expression node, EvaluationResultImpl rightOperand);
- @override
- bool get isBoolNumStringOrNull => true;
+ bool equalValues(TypeProvider typeProvider, EvaluationResultImpl result);
- @override
- BoolState lessThan(InstanceState rightOperand) {
- assertNumOrNull(rightOperand);
- if (value == null) {
- return BoolState.UNKNOWN_VALUE;
- }
- if (rightOperand is IntState) {
- int rightValue = rightOperand.value;
- if (rightValue == null) {
- return BoolState.UNKNOWN_VALUE;
- }
- return BoolState.from(value < rightValue.toDouble());
- } else if (rightOperand is DoubleState) {
- double rightValue = rightOperand.value;
- if (rightValue == null) {
- return BoolState.UNKNOWN_VALUE;
- }
- return BoolState.from(value < rightValue);
- } else if (rightOperand is DynamicState || rightOperand is NumState) {
- return BoolState.UNKNOWN_VALUE;
- }
- throw new EvaluationException(CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION);
- }
+ EvaluationResultImpl greaterThan(TypeProvider typeProvider, BinaryExpression node, EvaluationResultImpl rightOperand);
- @override
- BoolState lessThanOrEqual(InstanceState rightOperand) {
- assertNumOrNull(rightOperand);
- if (value == null) {
- return BoolState.UNKNOWN_VALUE;
- }
- if (rightOperand is IntState) {
- int rightValue = rightOperand.value;
- if (rightValue == null) {
- return BoolState.UNKNOWN_VALUE;
- }
- return BoolState.from(value <= rightValue.toDouble());
- } else if (rightOperand is DoubleState) {
- double rightValue = rightOperand.value;
- if (rightValue == null) {
- return BoolState.UNKNOWN_VALUE;
- }
- return BoolState.from(value <= rightValue);
- } else if (rightOperand is DynamicState || rightOperand is NumState) {
- return BoolState.UNKNOWN_VALUE;
- }
- throw new EvaluationException(CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION);
- }
+ EvaluationResultImpl greaterThanOrEqual(TypeProvider typeProvider, BinaryExpression node, EvaluationResultImpl rightOperand);
- @override
- NumState minus(InstanceState rightOperand) {
- assertNumOrNull(rightOperand);
- if (value == null) {
- return UNKNOWN_VALUE;
- }
- if (rightOperand is IntState) {
- int rightValue = rightOperand.value;
- if (rightValue == null) {
- return UNKNOWN_VALUE;
- }
- return new DoubleState(value - rightValue.toDouble());
- } else if (rightOperand is DoubleState) {
- double rightValue = rightOperand.value;
- if (rightValue == null) {
- return UNKNOWN_VALUE;
- }
- return new DoubleState(value - rightValue);
- } else if (rightOperand is DynamicState || rightOperand is NumState) {
- return UNKNOWN_VALUE;
- }
- throw new EvaluationException(CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION);
- }
+ EvaluationResultImpl integerDivide(TypeProvider typeProvider, BinaryExpression node, EvaluationResultImpl rightOperand);
- @override
- NumState negated() {
- if (value == null) {
- return UNKNOWN_VALUE;
- }
- return new DoubleState(-(value));
- }
+ EvaluationResultImpl lessThan(TypeProvider typeProvider, BinaryExpression node, EvaluationResultImpl rightOperand);
- @override
- NumState remainder(InstanceState rightOperand) {
- assertNumOrNull(rightOperand);
- if (value == null) {
- return UNKNOWN_VALUE;
- }
- if (rightOperand is IntState) {
- int rightValue = rightOperand.value;
- if (rightValue == null) {
- return UNKNOWN_VALUE;
- }
- return new DoubleState(value % rightValue.toDouble());
- } else if (rightOperand is DoubleState) {
- double rightValue = rightOperand.value;
- if (rightValue == null) {
- return UNKNOWN_VALUE;
- }
- return new DoubleState(value % rightValue);
- } else if (rightOperand is DynamicState || rightOperand is NumState) {
- return UNKNOWN_VALUE;
- }
- throw new EvaluationException(CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION);
- }
+ EvaluationResultImpl lessThanOrEqual(TypeProvider typeProvider, BinaryExpression node, EvaluationResultImpl rightOperand);
- @override
- NumState times(InstanceState rightOperand) {
- assertNumOrNull(rightOperand);
- if (value == null) {
- return UNKNOWN_VALUE;
- }
- if (rightOperand is IntState) {
- int rightValue = rightOperand.value;
- if (rightValue == null) {
- return UNKNOWN_VALUE;
- }
- return new DoubleState(value * rightValue.toDouble());
- } else if (rightOperand is DoubleState) {
- double rightValue = rightOperand.value;
- if (rightValue == null) {
- return UNKNOWN_VALUE;
- }
- return new DoubleState(value * rightValue);
- } else if (rightOperand is DynamicState || rightOperand is NumState) {
- return UNKNOWN_VALUE;
- }
- throw new EvaluationException(CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION);
- }
+ EvaluationResultImpl logicalAnd(TypeProvider typeProvider, BinaryExpression node, EvaluationResultImpl rightOperand);
- @override
- String toString() => value == null ? "-unknown-" : value.toString();
-}
+ EvaluationResultImpl logicalNot(TypeProvider typeProvider, Expression node);
-/**
- * Instances of the class `DynamicState` represent the state of an object representing a Dart
- * object for which there is no type information.
- */
-class DynamicState extends InstanceState {
- /**
- * The unique instance of this class.
- */
- static DynamicState DYNAMIC_STATE = new DynamicState();
+ EvaluationResultImpl logicalOr(TypeProvider typeProvider, BinaryExpression node, EvaluationResultImpl rightOperand);
- @override
- NumState add(InstanceState rightOperand) {
- assertNumOrNull(rightOperand);
- return _unknownNum(rightOperand);
- }
+ EvaluationResultImpl minus(TypeProvider typeProvider, BinaryExpression node, EvaluationResultImpl rightOperand);
- @override
- IntState bitAnd(InstanceState rightOperand) {
- assertIntOrNull(rightOperand);
- return IntState.UNKNOWN_VALUE;
- }
+ EvaluationResultImpl negated(TypeProvider typeProvider, Expression node);
- @override
- IntState bitNot() => IntState.UNKNOWN_VALUE;
+ EvaluationResultImpl notEqual(TypeProvider typeProvider, BinaryExpression node, EvaluationResultImpl rightOperand);
- @override
- IntState bitOr(InstanceState rightOperand) {
- assertIntOrNull(rightOperand);
- return IntState.UNKNOWN_VALUE;
- }
+ EvaluationResultImpl performToString(TypeProvider typeProvider, AstNode node);
+
+ EvaluationResultImpl remainder(TypeProvider typeProvider, BinaryExpression node, EvaluationResultImpl rightOperand);
+
+ EvaluationResultImpl shiftLeft(TypeProvider typeProvider, BinaryExpression node, EvaluationResultImpl rightOperand);
+
+ EvaluationResultImpl shiftRight(TypeProvider typeProvider, BinaryExpression node, EvaluationResultImpl rightOperand);
+
+ EvaluationResultImpl times(TypeProvider typeProvider, BinaryExpression node, EvaluationResultImpl rightOperand);
+
+ EvaluationResultImpl addToError(BinaryExpression node, ErrorResult leftOperand);
+
+ EvaluationResultImpl addToValid(TypeProvider typeProvider, BinaryExpression node, ValidResult leftOperand);
+
+ EvaluationResultImpl bitAndError(BinaryExpression node, ErrorResult leftOperand);
+
+ EvaluationResultImpl bitAndValid(TypeProvider typeProvider, BinaryExpression node, ValidResult leftOperand);
+
+ EvaluationResultImpl bitOrError(BinaryExpression node, ErrorResult leftOperand);
+
+ EvaluationResultImpl bitOrValid(TypeProvider typeProvider, BinaryExpression node, ValidResult leftOperand);
+
+ EvaluationResultImpl bitXorError(BinaryExpression node, ErrorResult leftOperand);
+
+ EvaluationResultImpl bitXorValid(TypeProvider typeProvider, BinaryExpression node, ValidResult leftOperand);
+
+ EvaluationResultImpl concatenateError(Expression node, ErrorResult leftOperand);
+
+ EvaluationResultImpl concatenateValid(TypeProvider typeProvider, Expression node, ValidResult leftOperand);
+
+ EvaluationResultImpl divideError(BinaryExpression node, ErrorResult leftOperand);
+
+ EvaluationResultImpl divideValid(TypeProvider typeProvider, BinaryExpression node, ValidResult leftOperand);
+
+ EvaluationResultImpl equalEqualError(Expression node, ErrorResult leftOperand);
+
+ EvaluationResultImpl equalEqualValid(TypeProvider typeProvider, Expression node, ValidResult leftOperand);
+
+ EvaluationResultImpl greaterThanError(BinaryExpression node, ErrorResult leftOperand);
+
+ EvaluationResultImpl greaterThanOrEqualError(BinaryExpression node, ErrorResult leftOperand);
+
+ EvaluationResultImpl greaterThanOrEqualValid(TypeProvider typeProvider, BinaryExpression node, ValidResult leftOperand);
+
+ EvaluationResultImpl greaterThanValid(TypeProvider typeProvider, BinaryExpression node, ValidResult leftOperand);
+
+ EvaluationResultImpl integerDivideError(BinaryExpression node, ErrorResult leftOperand);
+
+ EvaluationResultImpl integerDivideValid(TypeProvider typeProvider, BinaryExpression node, ValidResult leftOperand);
+
+ EvaluationResultImpl lessThanError(BinaryExpression node, ErrorResult leftOperand);
+
+ EvaluationResultImpl lessThanOrEqualError(BinaryExpression node, ErrorResult leftOperand);
+
+ EvaluationResultImpl lessThanOrEqualValid(TypeProvider typeProvider, BinaryExpression node, ValidResult leftOperand);
+
+ EvaluationResultImpl lessThanValid(TypeProvider typeProvider, BinaryExpression node, ValidResult leftOperand);
+
+ EvaluationResultImpl logicalAndError(BinaryExpression node, ErrorResult leftOperand);
+
+ EvaluationResultImpl logicalAndValid(TypeProvider typeProvider, BinaryExpression node, ValidResult leftOperand);
+
+ EvaluationResultImpl logicalOrError(BinaryExpression node, ErrorResult leftOperand);
+
+ EvaluationResultImpl logicalOrValid(TypeProvider typeProvider, BinaryExpression node, ValidResult leftOperand);
+
+ EvaluationResultImpl minusError(BinaryExpression node, ErrorResult leftOperand);
+
+ EvaluationResultImpl minusValid(TypeProvider typeProvider, BinaryExpression node, ValidResult leftOperand);
+
+ EvaluationResultImpl notEqualError(BinaryExpression node, ErrorResult leftOperand);
+
+ EvaluationResultImpl notEqualValid(TypeProvider typeProvider, BinaryExpression node, ValidResult leftOperand);
+
+ EvaluationResultImpl remainderError(BinaryExpression node, ErrorResult leftOperand);
+
+ EvaluationResultImpl remainderValid(TypeProvider typeProvider, BinaryExpression node, ValidResult leftOperand);
+
+ EvaluationResultImpl shiftLeftError(BinaryExpression node, ErrorResult leftOperand);
+
+ EvaluationResultImpl shiftLeftValid(TypeProvider typeProvider, BinaryExpression node, ValidResult leftOperand);
+
+ EvaluationResultImpl shiftRightError(BinaryExpression node, ErrorResult leftOperand);
+
+ EvaluationResultImpl shiftRightValid(TypeProvider typeProvider, BinaryExpression node, ValidResult leftOperand);
+
+ EvaluationResultImpl timesError(BinaryExpression node, ErrorResult leftOperand);
- @override
- IntState bitXor(InstanceState rightOperand) {
- assertIntOrNull(rightOperand);
- return IntState.UNKNOWN_VALUE;
- }
+ EvaluationResultImpl timesValid(TypeProvider typeProvider, BinaryExpression node, ValidResult leftOperand);
+}
- @override
- StringState concatenate(InstanceState rightOperand) {
- assertString(rightOperand);
- return StringState.UNKNOWN_VALUE;
- }
+/**
+ * Instances of the class `FunctionState` represent the state of an object representing a
+ * function.
+ */
+class FunctionState extends InstanceState {
+ /**
+ * The element representing the function being modeled.
+ */
+ final ExecutableElement _element;
- @override
- BoolState convertToBool() => BoolState.UNKNOWN_VALUE;
+ /**
+ * Initialize a newly created state to represent the given function.
+ *
+ * @param element the element representing the function being modeled
+ */
+ FunctionState(this._element);
@override
- StringState convertToString() => StringState.UNKNOWN_VALUE;
+ StringState convertToString() {
+ if (_element == null) {
+ return StringState.UNKNOWN_VALUE;
+ }
+ return new StringState(_element.name);
+ }
@override
- NumState divide(InstanceState rightOperand) {
- assertNumOrNull(rightOperand);
- return _unknownNum(rightOperand);
- }
+ bool operator ==(Object object) => object is FunctionState && (_element == object._element);
@override
BoolState equalEqual(InstanceState rightOperand) {
- assertBoolNumStringOrNull(rightOperand);
- return BoolState.UNKNOWN_VALUE;
+ if (_element == null) {
+ return BoolState.UNKNOWN_VALUE;
+ }
+ if (rightOperand is FunctionState) {
+ ExecutableElement rightElement = rightOperand._element;
+ if (rightElement == null) {
+ return BoolState.UNKNOWN_VALUE;
+ }
+ return BoolState.from(_element == rightElement);
+ } else if (rightOperand is DynamicState) {
+ return BoolState.UNKNOWN_VALUE;
+ }
+ return BoolState.FALSE_STATE;
}
@override
- String get typeName => "dynamic";
+ String get typeName => "Function";
@override
- BoolState greaterThan(InstanceState rightOperand) {
- assertNumOrNull(rightOperand);
- return BoolState.UNKNOWN_VALUE;
- }
+ int get hashCode => _element == null ? 0 : _element.hashCode;
@override
- BoolState greaterThanOrEqual(InstanceState rightOperand) {
- assertNumOrNull(rightOperand);
- return BoolState.UNKNOWN_VALUE;
- }
+ String toString() => _element == null ? "-unknown-" : _element.name;
+}
- @override
- IntState integerDivide(InstanceState rightOperand) {
- assertNumOrNull(rightOperand);
- return IntState.UNKNOWN_VALUE;
- }
+/**
+ * Instances of the class `GenericState` represent the state of an object representing a Dart
+ * object for which there is no more specific state.
+ */
+class GenericState extends InstanceState {
+ /**
+ * The values of the fields of this instance.
+ */
+ final Map<String, DartObjectImpl> _fieldMap;
- @override
- bool get isBool => true;
+ /**
+ * A state that can be used to represent an object whose state is not known.
+ */
+ static GenericState UNKNOWN_VALUE = new GenericState(new Map<String, DartObjectImpl>());
- @override
- bool get isBoolNumStringOrNull => true;
+ /**
+ * Initialize a newly created state to represent a newly created object.
+ *
+ * @param fieldMap the values of the fields of this instance
+ */
+ GenericState(this._fieldMap);
@override
- BoolState lessThan(InstanceState rightOperand) {
- assertNumOrNull(rightOperand);
- return BoolState.UNKNOWN_VALUE;
- }
+ StringState convertToString() => StringState.UNKNOWN_VALUE;
@override
- BoolState lessThanOrEqual(InstanceState rightOperand) {
- assertNumOrNull(rightOperand);
- return BoolState.UNKNOWN_VALUE;
+ bool operator ==(Object object) {
+ if (object is! GenericState) {
+ return false;
+ }
+ GenericState state = object as GenericState;
+ Set<String> otherFields = new Set<String>.from(state._fieldMap.keys.toSet());
+ for (String fieldName in _fieldMap.keys.toSet()) {
+ if (_fieldMap[fieldName] != state._fieldMap[fieldName]) {
+ return false;
+ }
+ otherFields.remove(fieldName);
+ }
+ for (String fieldName in otherFields) {
+ if (state._fieldMap[fieldName] != _fieldMap[fieldName]) {
+ return false;
+ }
+ }
+ return true;
}
@override
- BoolState logicalAnd(InstanceState rightOperand) {
- assertBool(rightOperand);
- return BoolState.UNKNOWN_VALUE;
+ BoolState equalEqual(InstanceState rightOperand) {
+ assertBoolNumStringOrNull(rightOperand);
+ if (rightOperand is DynamicState) {
+ return BoolState.UNKNOWN_VALUE;
+ }
+ return BoolState.from(this == rightOperand);
}
@override
- BoolState logicalNot() => BoolState.UNKNOWN_VALUE;
+ String get typeName => "user defined type";
@override
- BoolState logicalOr(InstanceState rightOperand) {
- assertBool(rightOperand);
- return rightOperand.convertToBool();
+ int get hashCode {
+ int hashCode = 0;
+ for (DartObjectImpl value in _fieldMap.values) {
+ hashCode += value.hashCode;
+ }
+ return hashCode;
}
+}
- @override
- NumState minus(InstanceState rightOperand) {
+/**
+ * The class `InstanceState` defines the behavior of objects representing the state of a Dart
+ * object.
+ */
+abstract class InstanceState {
+ /**
+ * Return the result of invoking the '+' operator on this object with the given argument.
+ *
+ * @param rightOperand the right-hand operand of the operation
+ * @return the result of invoking the '+' operator on this object with the given argument
+ * @throws EvaluationException if the operator is not appropriate for an object of this kind
+ */
+ NumState add(InstanceState rightOperand) {
+ assertNumOrNull(this);
assertNumOrNull(rightOperand);
- return _unknownNum(rightOperand);
+ throw new EvaluationException(CompileTimeErrorCode.INVALID_CONSTANT);
}
- @override
- NumState negated() => NumState.UNKNOWN_VALUE;
+ /**
+ * Return the result of invoking the '&' operator on this object with the given argument.
+ *
+ * @param rightOperand the right-hand operand of the operation
+ * @return the result of invoking the '&' operator on this object with the given argument
+ * @throws EvaluationException if the operator is not appropriate for an object of this kind
+ */
+ IntState bitAnd(InstanceState rightOperand) {
+ assertIntOrNull(this);
+ assertIntOrNull(rightOperand);
+ throw new EvaluationException(CompileTimeErrorCode.INVALID_CONSTANT);
+ }
- @override
- NumState remainder(InstanceState rightOperand) {
- assertNumOrNull(rightOperand);
- return _unknownNum(rightOperand);
+ /**
+ * Return the result of invoking the '~' operator on this object.
+ *
+ * @return the result of invoking the '~' operator on this object
+ * @throws EvaluationException if the operator is not appropriate for an object of this kind
+ */
+ IntState bitNot() {
+ assertIntOrNull(this);
+ throw new EvaluationException(CompileTimeErrorCode.INVALID_CONSTANT);
}
- @override
- IntState shiftLeft(InstanceState rightOperand) {
+ /**
+ * Return the result of invoking the '|' operator on this object with the given argument.
+ *
+ * @param rightOperand the right-hand operand of the operation
+ * @return the result of invoking the '|' operator on this object with the given argument
+ * @throws EvaluationException if the operator is not appropriate for an object of this kind
+ */
+ IntState bitOr(InstanceState rightOperand) {
+ assertIntOrNull(this);
assertIntOrNull(rightOperand);
- return IntState.UNKNOWN_VALUE;
+ throw new EvaluationException(CompileTimeErrorCode.INVALID_CONSTANT);
}
- @override
- IntState shiftRight(InstanceState rightOperand) {
+ /**
+ * Return the result of invoking the '^' operator on this object with the given argument.
+ *
+ * @param rightOperand the right-hand operand of the operation
+ * @return the result of invoking the '^' operator on this object with the given argument
+ * @throws EvaluationException if the operator is not appropriate for an object of this kind
+ */
+ IntState bitXor(InstanceState rightOperand) {
+ assertIntOrNull(this);
assertIntOrNull(rightOperand);
- return IntState.UNKNOWN_VALUE;
+ throw new EvaluationException(CompileTimeErrorCode.INVALID_CONSTANT);
}
- @override
- NumState times(InstanceState rightOperand) {
+ /**
+ * Return the result of invoking the ' ' operator on this object with the given argument.
+ *
+ * @param rightOperand the right-hand operand of the operation
+ * @return the result of invoking the ' ' operator on this object with the given argument
+ * @throws EvaluationException if the operator is not appropriate for an object of this kind
+ */
+ StringState concatenate(InstanceState rightOperand) {
+ throw new EvaluationException(CompileTimeErrorCode.INVALID_CONSTANT);
+ }
+
+ /**
+ * Return the result of applying boolean conversion to this object.
+ *
+ * @param typeProvider the type provider used to find known types
+ * @return the result of applying boolean conversion to this object
+ * @throws EvaluationException if the operator is not appropriate for an object of this kind
+ */
+ BoolState convertToBool() => BoolState.FALSE_STATE;
+
+ /**
+ * Return the result of converting this object to a String.
+ *
+ * @return the result of converting this object to a String
+ * @throws EvaluationException if the operator is not appropriate for an object of this kind
+ */
+ StringState convertToString();
+
+ /**
+ * Return the result of invoking the '/' operator on this object with the given argument.
+ *
+ * @param rightOperand the right-hand operand of the operation
+ * @return the result of invoking the '/' operator on this object with the given argument
+ * @throws EvaluationException if the operator is not appropriate for an object of this kind
+ */
+ NumState divide(InstanceState rightOperand) {
+ assertNumOrNull(this);
assertNumOrNull(rightOperand);
- return _unknownNum(rightOperand);
+ throw new EvaluationException(CompileTimeErrorCode.INVALID_CONSTANT);
}
/**
- * Return an object representing an unknown numeric value whose type is based on the type of the
- * right-hand operand.
+ * Return the result of invoking the '==' operator on this object with the given argument.
*
- * @param rightOperand the operand whose type will determine the type of the result
- * @return an object representing an unknown numeric value
+ * @param rightOperand the right-hand operand of the operation
+ * @return the result of invoking the '==' operator on this object with the given argument
+ * @throws EvaluationException if the operator is not appropriate for an object of this kind
*/
- NumState _unknownNum(InstanceState rightOperand) {
- if (rightOperand is IntState) {
- return IntState.UNKNOWN_VALUE;
- } else if (rightOperand is DoubleState) {
- return DoubleState.UNKNOWN_VALUE;
- }
- return NumState.UNKNOWN_VALUE;
- }
-}
+ BoolState equalEqual(InstanceState rightOperand);
-/**
- * Instances of the class `EvaluationException` represent a run-time exception that would be
- * thrown during the evaluation of Dart code.
- */
-class EvaluationException extends JavaException {
/**
- * The error code associated with the exception.
+ * Return the name of the type of this value.
+ *
+ * @return the name of the type of this value
*/
- final ErrorCode errorCode;
+ String get typeName;
/**
- * Initialize a newly created exception to have the given error code.
+ * Return this object's value if it can be represented exactly, or `null` if either the
+ * value cannot be represented exactly or if the value is `null`. Clients should use
+ * [hasExactValue] to distinguish between these two cases.
*
- * @param errorCode the error code associated with the exception
+ * @return this object's value
*/
- EvaluationException(this.errorCode);
-}
+ Object get value => null;
-/**
- * Instances of the class `FunctionState` represent the state of an object representing a
- * function.
- */
-class FunctionState extends InstanceState {
/**
- * The element representing the function being modeled.
+ * Return the result of invoking the '&gt;' operator on this object with the given argument.
+ *
+ * @param rightOperand the right-hand operand of the operation
+ * @return the result of invoking the '&gt;' operator on this object with the given argument
+ * @throws EvaluationException if the operator is not appropriate for an object of this kind
*/
- final ExecutableElement _element;
+ BoolState greaterThan(InstanceState rightOperand) {
+ assertNumOrNull(this);
+ assertNumOrNull(rightOperand);
+ throw new EvaluationException(CompileTimeErrorCode.INVALID_CONSTANT);
+ }
/**
- * Initialize a newly created state to represent the given function.
+ * Return the result of invoking the '&gt;=' operator on this object with the given argument.
*
- * @param element the element representing the function being modeled
+ * @param rightOperand the right-hand operand of the operation
+ * @return the result of invoking the '&gt;=' operator on this object with the given argument
+ * @throws EvaluationException if the operator is not appropriate for an object of this kind
*/
- FunctionState(this._element);
-
- @override
- StringState convertToString() {
- if (_element == null) {
- return StringState.UNKNOWN_VALUE;
- }
- return new StringState(_element.name);
+ BoolState greaterThanOrEqual(InstanceState rightOperand) {
+ assertNumOrNull(this);
+ assertNumOrNull(rightOperand);
+ throw new EvaluationException(CompileTimeErrorCode.INVALID_CONSTANT);
}
- @override
- bool operator ==(Object object) => object is FunctionState && (_element == object._element);
+ /**
+ * Return `true` if this object's value can be represented exactly.
+ *
+ * @return `true` if this object's value can be represented exactly
+ */
+ bool get hasExactValue => false;
- @override
- BoolState equalEqual(InstanceState rightOperand) {
- if (_element == null) {
- return BoolState.UNKNOWN_VALUE;
- }
- if (rightOperand is FunctionState) {
- ExecutableElement rightElement = rightOperand._element;
- if (rightElement == null) {
- return BoolState.UNKNOWN_VALUE;
- }
- return BoolState.from(_element == rightElement);
- } else if (rightOperand is DynamicState) {
- return BoolState.UNKNOWN_VALUE;
- }
- return BoolState.FALSE_STATE;
+ /**
+ * Return the result of invoking the '~/' operator on this object with the given argument.
+ *
+ * @param rightOperand the right-hand operand of the operation
+ * @return the result of invoking the '~/' operator on this object with the given argument
+ * @throws EvaluationException if the operator is not appropriate for an object of this kind
+ */
+ IntState integerDivide(InstanceState rightOperand) {
+ assertNumOrNull(this);
+ assertNumOrNull(rightOperand);
+ throw new EvaluationException(CompileTimeErrorCode.INVALID_CONSTANT);
}
- @override
- String get typeName => "Function";
-
- @override
- int get hashCode => _element == null ? 0 : _element.hashCode;
-
- @override
- String toString() => _element == null ? "-unknown-" : _element.name;
-}
+ /**
+ * Return `true` if this object represents an object whose type is 'bool'.
+ *
+ * @return `true` if this object represents a boolean value
+ */
+ bool get isBool => false;
-/**
- * Instances of the class `GenericState` represent the state of an object representing a Dart
- * object for which there is no more specific state.
- */
-class GenericState extends InstanceState {
/**
- * The values of the fields of this instance.
+ * Return `true` if this object represents an object whose type is either 'bool', 'num',
+ * 'String', or 'Null'.
+ *
+ * @return `true` if this object represents either a boolean, numeric, string or null value
*/
- final Map<String, DartObjectImpl> _fieldMap;
+ bool get isBoolNumStringOrNull => false;
/**
- * A state that can be used to represent an object whose state is not known.
+ * Return the result of invoking the '&lt;' operator on this object with the given argument.
+ *
+ * @param rightOperand the right-hand operand of the operation
+ * @return the result of invoking the '&lt;' operator on this object with the given argument
+ * @throws EvaluationException if the operator is not appropriate for an object of this kind
*/
- static GenericState UNKNOWN_VALUE = new GenericState(new Map<String, DartObjectImpl>());
+ BoolState lessThan(InstanceState rightOperand) {
+ assertNumOrNull(this);
+ assertNumOrNull(rightOperand);
+ throw new EvaluationException(CompileTimeErrorCode.INVALID_CONSTANT);
+ }
/**
- * Initialize a newly created state to represent a newly created object.
+ * Return the result of invoking the '&lt;=' operator on this object with the given argument.
*
- * @param fieldMap the values of the fields of this instance
+ * @param rightOperand the right-hand operand of the operation
+ * @return the result of invoking the '&lt;=' operator on this object with the given argument
+ * @throws EvaluationException if the operator is not appropriate for an object of this kind
*/
- GenericState(this._fieldMap);
+ BoolState lessThanOrEqual(InstanceState rightOperand) {
+ assertNumOrNull(this);
+ assertNumOrNull(rightOperand);
+ throw new EvaluationException(CompileTimeErrorCode.INVALID_CONSTANT);
+ }
- @override
- StringState convertToString() => StringState.UNKNOWN_VALUE;
+ /**
+ * Return the result of invoking the '&&' operator on this object with the given argument.
+ *
+ * @param rightOperand the right-hand operand of the operation
+ * @return the result of invoking the '&&' operator on this object with the given argument
+ * @throws EvaluationException if the operator is not appropriate for an object of this kind
+ */
+ BoolState logicalAnd(InstanceState rightOperand) {
+ assertBool(this);
+ assertBool(rightOperand);
+ return BoolState.FALSE_STATE;
+ }
- @override
- bool operator ==(Object object) {
- if (object is! GenericState) {
- return false;
- }
- GenericState state = object as GenericState;
- Set<String> otherFields = new Set<String>.from(state._fieldMap.keys.toSet());
- for (String fieldName in _fieldMap.keys.toSet()) {
- if (_fieldMap[fieldName] != state._fieldMap[fieldName]) {
- return false;
- }
- otherFields.remove(fieldName);
- }
- for (String fieldName in otherFields) {
- if (state._fieldMap[fieldName] != _fieldMap[fieldName]) {
- return false;
- }
- }
- return true;
+ /**
+ * Return the result of invoking the '!' operator on this object.
+ *
+ * @return the result of invoking the '!' operator on this object
+ * @throws EvaluationException if the operator is not appropriate for an object of this kind
+ */
+ BoolState logicalNot() {
+ assertBool(this);
+ return BoolState.TRUE_STATE;
}
- @override
- BoolState equalEqual(InstanceState rightOperand) {
- assertBoolNumStringOrNull(rightOperand);
- if (rightOperand is DynamicState) {
- return BoolState.UNKNOWN_VALUE;
- }
- return BoolState.from(this == rightOperand);
+ /**
+ * Return the result of invoking the '||' operator on this object with the given argument.
+ *
+ * @param rightOperand the right-hand operand of the operation
+ * @return the result of invoking the '||' operator on this object with the given argument
+ * @throws EvaluationException if the operator is not appropriate for an object of this kind
+ */
+ BoolState logicalOr(InstanceState rightOperand) {
+ assertBool(this);
+ assertBool(rightOperand);
+ return rightOperand.convertToBool();
}
- @override
- String get typeName => "user defined type";
+ /**
+ * Return the result of invoking the '-' operator on this object with the given argument.
+ *
+ * @param rightOperand the right-hand operand of the operation
+ * @return the result of invoking the '-' operator on this object with the given argument
+ * @throws EvaluationException if the operator is not appropriate for an object of this kind
+ */
+ NumState minus(InstanceState rightOperand) {
+ assertNumOrNull(this);
+ assertNumOrNull(rightOperand);
+ throw new EvaluationException(CompileTimeErrorCode.INVALID_CONSTANT);
+ }
- @override
- int get hashCode {
- int hashCode = 0;
- for (DartObjectImpl value in _fieldMap.values) {
- hashCode += value.hashCode;
- }
- return hashCode;
+ /**
+ * Return the result of invoking the '-' operator on this object.
+ *
+ * @return the result of invoking the '-' operator on this object
+ * @throws EvaluationException if the operator is not appropriate for an object of this kind
+ */
+ NumState negated() {
+ assertNumOrNull(this);
+ throw new EvaluationException(CompileTimeErrorCode.INVALID_CONSTANT);
}
-}
-/**
- * The class `InstanceState` defines the behavior of objects representing the state of a Dart
- * object.
- */
-abstract class InstanceState {
/**
- * Return the result of invoking the '+' operator on this object with the given argument.
+ * Return the result of invoking the '%' operator on this object with the given argument.
*
* @param rightOperand the right-hand operand of the operation
- * @return the result of invoking the '+' operator on this object with the given argument
+ * @return the result of invoking the '%' operator on this object with the given argument
* @throws EvaluationException if the operator is not appropriate for an object of this kind
*/
- NumState add(InstanceState rightOperand) {
+ NumState remainder(InstanceState rightOperand) {
assertNumOrNull(this);
assertNumOrNull(rightOperand);
throw new EvaluationException(CompileTimeErrorCode.INVALID_CONSTANT);
}
/**
- * Return the result of invoking the '&' operator on this object with the given argument.
+ * Return the result of invoking the '&lt;&lt;' operator on this object with the given argument.
*
* @param rightOperand the right-hand operand of the operation
- * @return the result of invoking the '&' operator on this object with the given argument
+ * @return the result of invoking the '&lt;&lt;' operator on this object with the given argument
* @throws EvaluationException if the operator is not appropriate for an object of this kind
*/
- IntState bitAnd(InstanceState rightOperand) {
+ IntState shiftLeft(InstanceState rightOperand) {
assertIntOrNull(this);
assertIntOrNull(rightOperand);
throw new EvaluationException(CompileTimeErrorCode.INVALID_CONSTANT);
}
/**
- * Return the result of invoking the '~' operator on this object.
+ * Return the result of invoking the '&gt;&gt;' operator on this object with the given argument.
*
- * @return the result of invoking the '~' operator on this object
+ * @param rightOperand the right-hand operand of the operation
+ * @return the result of invoking the '&gt;&gt;' operator on this object with the given argument
* @throws EvaluationException if the operator is not appropriate for an object of this kind
*/
- IntState bitNot() {
+ IntState shiftRight(InstanceState rightOperand) {
assertIntOrNull(this);
+ assertIntOrNull(rightOperand);
throw new EvaluationException(CompileTimeErrorCode.INVALID_CONSTANT);
}
/**
- * Return the result of invoking the '|' operator on this object with the given argument.
+ * Return the result of invoking the '*' operator on this object with the given argument.
*
* @param rightOperand the right-hand operand of the operation
- * @return the result of invoking the '|' operator on this object with the given argument
+ * @return the result of invoking the '*' operator on this object with the given argument
* @throws EvaluationException if the operator is not appropriate for an object of this kind
*/
- IntState bitOr(InstanceState rightOperand) {
- assertIntOrNull(this);
- assertIntOrNull(rightOperand);
+ NumState times(InstanceState rightOperand) {
+ assertNumOrNull(this);
+ assertNumOrNull(rightOperand);
throw new EvaluationException(CompileTimeErrorCode.INVALID_CONSTANT);
}
/**
- * Return the result of invoking the '^' operator on this object with the given argument.
+ * Throw an exception if the given state does not represent a boolean value.
*
- * @param rightOperand the right-hand operand of the operation
- * @return the result of invoking the '^' operator on this object with the given argument
- * @throws EvaluationException if the operator is not appropriate for an object of this kind
+ * @param state the state being tested
+ * @throws EvaluationException if the given state does not represent a boolean value
*/
- IntState bitXor(InstanceState rightOperand) {
- assertIntOrNull(this);
- assertIntOrNull(rightOperand);
- throw new EvaluationException(CompileTimeErrorCode.INVALID_CONSTANT);
+ void assertBool(InstanceState state) {
+ if (!(state is BoolState || state is DynamicState)) {
+ throw new EvaluationException(CompileTimeErrorCode.CONST_EVAL_TYPE_BOOL);
+ }
}
/**
- * Return the result of invoking the ' ' operator on this object with the given argument.
+ * Throw an exception if the given state does not represent a boolean, numeric, string or null
+ * value.
*
- * @param rightOperand the right-hand operand of the operation
- * @return the result of invoking the ' ' operator on this object with the given argument
- * @throws EvaluationException if the operator is not appropriate for an object of this kind
+ * @param state the state being tested
+ * @throws EvaluationException if the given state does not represent a boolean, numeric, string or
+ * null value
*/
- StringState concatenate(InstanceState rightOperand) {
- throw new EvaluationException(CompileTimeErrorCode.INVALID_CONSTANT);
+ void assertBoolNumStringOrNull(InstanceState state) {
+ if (!(state is BoolState || state is DoubleState || state is IntState || state is NumState || state is StringState || state is NullState || state is DynamicState)) {
+ throw new EvaluationException(CompileTimeErrorCode.CONST_EVAL_TYPE_BOOL_NUM_STRING);
+ }
}
/**
- * Return the result of applying boolean conversion to this object.
+ * Throw an exception if the given state does not represent an integer or null value.
*
- * @param typeProvider the type provider used to find known types
- * @return the result of applying boolean conversion to this object
- * @throws EvaluationException if the operator is not appropriate for an object of this kind
+ * @param state the state being tested
+ * @throws EvaluationException if the given state does not represent an integer or null value
*/
- BoolState convertToBool() => BoolState.FALSE_STATE;
+ void assertIntOrNull(InstanceState state) {
+ if (!(state is IntState || state is NumState || state is NullState || state is DynamicState)) {
+ throw new EvaluationException(CompileTimeErrorCode.CONST_EVAL_TYPE_INT);
+ }
+ }
/**
- * Return the result of converting this object to a String.
+ * Throw an exception if the given state does not represent a boolean, numeric, string or null
+ * value.
*
- * @return the result of converting this object to a String
- * @throws EvaluationException if the operator is not appropriate for an object of this kind
+ * @param state the state being tested
+ * @throws EvaluationException if the given state does not represent a boolean, numeric, string or
+ * null value
*/
- StringState convertToString();
+ void assertNumOrNull(InstanceState state) {
+ if (!(state is DoubleState || state is IntState || state is NumState || state is NullState || state is DynamicState)) {
+ throw new EvaluationException(CompileTimeErrorCode.CONST_EVAL_TYPE_NUM);
+ }
+ }
/**
- * Return the result of invoking the '/' operator on this object with the given argument.
+ * Throw an exception if the given state does not represent a String value.
*
- * @param rightOperand the right-hand operand of the operation
- * @return the result of invoking the '/' operator on this object with the given argument
- * @throws EvaluationException if the operator is not appropriate for an object of this kind
+ * @param state the state being tested
+ * @throws EvaluationException if the given state does not represent a String value
+ */
+ void assertString(InstanceState state) {
+ if (!(state is StringState || state is DynamicState)) {
+ throw new EvaluationException(CompileTimeErrorCode.CONST_EVAL_TYPE_BOOL);
+ }
+ }
+}
+
+/**
+ * Instances of the class `IntState` represent the state of an object representing an int.
+ */
+class IntState extends NumState {
+ /**
+ * The value of this instance.
+ */
+ final int value;
+
+ /**
+ * A state that can be used to represent an int whose value is not known.
+ */
+ static IntState UNKNOWN_VALUE = new IntState(null);
+
+ /**
+ * Initialize a newly created state to represent an int with the given value.
+ *
+ * @param value the value of this instance
*/
+ IntState(this.value);
+
+ @override
+ NumState add(InstanceState rightOperand) {
+ assertNumOrNull(rightOperand);
+ if (value == null) {
+ if (rightOperand is DoubleState) {
+ return DoubleState.UNKNOWN_VALUE;
+ }
+ return UNKNOWN_VALUE;
+ }
+ if (rightOperand is IntState) {
+ int rightValue = rightOperand.value;
+ if (rightValue == null) {
+ return UNKNOWN_VALUE;
+ }
+ return new IntState(value + rightValue);
+ } else if (rightOperand is DoubleState) {
+ double rightValue = rightOperand.value;
+ if (rightValue == null) {
+ return DoubleState.UNKNOWN_VALUE;
+ }
+ return new DoubleState(value.toDouble() + rightValue);
+ } else if (rightOperand is DynamicState || rightOperand is NumState) {
+ return UNKNOWN_VALUE;
+ }
+ throw new EvaluationException(CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION);
+ }
+
+ @override
+ IntState bitAnd(InstanceState rightOperand) {
+ assertIntOrNull(rightOperand);
+ if (value == null) {
+ return UNKNOWN_VALUE;
+ }
+ if (rightOperand is IntState) {
+ int rightValue = rightOperand.value;
+ if (rightValue == null) {
+ return UNKNOWN_VALUE;
+ }
+ return new IntState(value & rightValue);
+ } else if (rightOperand is DynamicState || rightOperand is NumState) {
+ return UNKNOWN_VALUE;
+ }
+ throw new EvaluationException(CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION);
+ }
+
+ @override
+ IntState bitNot() {
+ if (value == null) {
+ return UNKNOWN_VALUE;
+ }
+ return new IntState(~value);
+ }
+
+ @override
+ IntState bitOr(InstanceState rightOperand) {
+ assertIntOrNull(rightOperand);
+ if (value == null) {
+ return UNKNOWN_VALUE;
+ }
+ if (rightOperand is IntState) {
+ int rightValue = rightOperand.value;
+ if (rightValue == null) {
+ return UNKNOWN_VALUE;
+ }
+ return new IntState(value | rightValue);
+ } else if (rightOperand is DynamicState || rightOperand is NumState) {
+ return UNKNOWN_VALUE;
+ }
+ throw new EvaluationException(CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION);
+ }
+
+ @override
+ IntState bitXor(InstanceState rightOperand) {
+ assertIntOrNull(rightOperand);
+ if (value == null) {
+ return UNKNOWN_VALUE;
+ }
+ if (rightOperand is IntState) {
+ int rightValue = rightOperand.value;
+ if (rightValue == null) {
+ return UNKNOWN_VALUE;
+ }
+ return new IntState(value ^ rightValue);
+ } else if (rightOperand is DynamicState || rightOperand is NumState) {
+ return UNKNOWN_VALUE;
+ }
+ throw new EvaluationException(CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION);
+ }
+
+ @override
+ StringState convertToString() {
+ if (value == null) {
+ return StringState.UNKNOWN_VALUE;
+ }
+ return new StringState(value.toString());
+ }
+
+ @override
NumState divide(InstanceState rightOperand) {
- assertNumOrNull(this);
assertNumOrNull(rightOperand);
- throw new EvaluationException(CompileTimeErrorCode.INVALID_CONSTANT);
+ if (value == null) {
+ if (rightOperand is DoubleState) {
+ return DoubleState.UNKNOWN_VALUE;
+ }
+ return UNKNOWN_VALUE;
+ }
+ if (rightOperand is IntState) {
+ int rightValue = rightOperand.value;
+ if (rightValue == null) {
+ return UNKNOWN_VALUE;
+ } else if (rightValue == 0) {
+ return new DoubleState(value.toDouble() / rightValue.toDouble());
+ }
+ return new IntState(value ~/ rightValue);
+ } else if (rightOperand is DoubleState) {
+ double rightValue = rightOperand.value;
+ if (rightValue == null) {
+ return DoubleState.UNKNOWN_VALUE;
+ }
+ return new DoubleState(value.toDouble() / rightValue);
+ } else if (rightOperand is DynamicState || rightOperand is NumState) {
+ return UNKNOWN_VALUE;
+ }
+ throw new EvaluationException(CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION);
+ }
+
+ @override
+ BoolState equalEqual(InstanceState rightOperand) {
+ assertBoolNumStringOrNull(rightOperand);
+ if (value == null) {
+ return BoolState.UNKNOWN_VALUE;
+ }
+ if (rightOperand is IntState) {
+ int rightValue = rightOperand.value;
+ if (rightValue == null) {
+ return BoolState.UNKNOWN_VALUE;
+ }
+ return BoolState.from(value == rightValue);
+ } else if (rightOperand is DoubleState) {
+ double rightValue = rightOperand.value;
+ if (rightValue == null) {
+ return BoolState.UNKNOWN_VALUE;
+ }
+ return BoolState.from(rightValue == value.toDouble());
+ } else if (rightOperand is DynamicState || rightOperand is NumState) {
+ return BoolState.UNKNOWN_VALUE;
+ }
+ return BoolState.FALSE_STATE;
}
- /**
- * Return the result of invoking the '==' operator on this object with the given argument.
- *
- * @param rightOperand the right-hand operand of the operation
- * @return the result of invoking the '==' operator on this object with the given argument
- * @throws EvaluationException if the operator is not appropriate for an object of this kind
- */
- BoolState equalEqual(InstanceState rightOperand);
-
- /**
- * Return the name of the type of this value.
- *
- * @return the name of the type of this value
- */
- String get typeName;
+ @override
+ bool operator ==(Object object) => object is IntState && (value == object.value);
- /**
- * Return this object's value if it can be represented exactly, or `null` if either the
- * value cannot be represented exactly or if the value is `null`. Clients should use
- * [hasExactValue] to distinguish between these two cases.
- *
- * @return this object's value
- */
- Object get value => null;
+ @override
+ String get typeName => "int";
- /**
- * Return the result of invoking the '&gt;' operator on this object with the given argument.
- *
- * @param rightOperand the right-hand operand of the operation
- * @return the result of invoking the '&gt;' operator on this object with the given argument
- * @throws EvaluationException if the operator is not appropriate for an object of this kind
- */
+ @override
BoolState greaterThan(InstanceState rightOperand) {
- assertNumOrNull(this);
assertNumOrNull(rightOperand);
- throw new EvaluationException(CompileTimeErrorCode.INVALID_CONSTANT);
+ if (value == null) {
+ return BoolState.UNKNOWN_VALUE;
+ }
+ if (rightOperand is IntState) {
+ int rightValue = rightOperand.value;
+ if (rightValue == null) {
+ return BoolState.UNKNOWN_VALUE;
+ }
+ return BoolState.from(value.compareTo(rightValue) > 0);
+ } else if (rightOperand is DoubleState) {
+ double rightValue = rightOperand.value;
+ if (rightValue == null) {
+ return BoolState.UNKNOWN_VALUE;
+ }
+ return BoolState.from(value.toDouble() > rightValue);
+ } else if (rightOperand is DynamicState || rightOperand is NumState) {
+ return BoolState.UNKNOWN_VALUE;
+ }
+ throw new EvaluationException(CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION);
}
- /**
- * Return the result of invoking the '&gt;=' operator on this object with the given argument.
- *
- * @param rightOperand the right-hand operand of the operation
- * @return the result of invoking the '&gt;=' operator on this object with the given argument
- * @throws EvaluationException if the operator is not appropriate for an object of this kind
- */
+ @override
BoolState greaterThanOrEqual(InstanceState rightOperand) {
- assertNumOrNull(this);
assertNumOrNull(rightOperand);
- throw new EvaluationException(CompileTimeErrorCode.INVALID_CONSTANT);
+ if (value == null) {
+ return BoolState.UNKNOWN_VALUE;
+ }
+ if (rightOperand is IntState) {
+ int rightValue = rightOperand.value;
+ if (rightValue == null) {
+ return BoolState.UNKNOWN_VALUE;
+ }
+ return BoolState.from(value.compareTo(rightValue) >= 0);
+ } else if (rightOperand is DoubleState) {
+ double rightValue = rightOperand.value;
+ if (rightValue == null) {
+ return BoolState.UNKNOWN_VALUE;
+ }
+ return BoolState.from(value.toDouble() >= rightValue);
+ } else if (rightOperand is DynamicState || rightOperand is NumState) {
+ return BoolState.UNKNOWN_VALUE;
+ }
+ throw new EvaluationException(CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION);
}
- /**
- * Return `true` if this object's value can be represented exactly.
- *
- * @return `true` if this object's value can be represented exactly
- */
- bool get hasExactValue => false;
+ @override
+ bool get hasExactValue => true;
- /**
- * Return the result of invoking the '~/' operator on this object with the given argument.
- *
- * @param rightOperand the right-hand operand of the operation
- * @return the result of invoking the '~/' operator on this object with the given argument
- * @throws EvaluationException if the operator is not appropriate for an object of this kind
- */
+ @override
+ int get hashCode => value == null ? 0 : value.hashCode;
+
+ @override
IntState integerDivide(InstanceState rightOperand) {
- assertNumOrNull(this);
assertNumOrNull(rightOperand);
- throw new EvaluationException(CompileTimeErrorCode.INVALID_CONSTANT);
+ if (value == null) {
+ return UNKNOWN_VALUE;
+ }
+ if (rightOperand is IntState) {
+ int rightValue = rightOperand.value;
+ if (rightValue == null) {
+ return UNKNOWN_VALUE;
+ } else if (rightValue == 0) {
+ throw new EvaluationException(CompileTimeErrorCode.CONST_EVAL_THROWS_IDBZE);
+ }
+ return new IntState(value ~/ rightValue);
+ } else if (rightOperand is DoubleState) {
+ double rightValue = rightOperand.value;
+ if (rightValue == null) {
+ return UNKNOWN_VALUE;
+ }
+ double result = value.toDouble() / rightValue;
+ return new IntState(result.toInt());
+ } else if (rightOperand is DynamicState || rightOperand is NumState) {
+ return UNKNOWN_VALUE;
+ }
+ throw new EvaluationException(CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION);
}
- /**
- * Return `true` if this object represents an object whose type is 'bool'.
- *
- * @return `true` if this object represents a boolean value
- */
- bool get isBool => false;
-
- /**
- * Return `true` if this object represents an object whose type is either 'bool', 'num',
- * 'String', or 'Null'.
- *
- * @return `true` if this object represents either a boolean, numeric, string or null value
- */
- bool get isBoolNumStringOrNull => false;
+ @override
+ bool get isBoolNumStringOrNull => true;
- /**
- * Return the result of invoking the '&lt;' operator on this object with the given argument.
- *
- * @param rightOperand the right-hand operand of the operation
- * @return the result of invoking the '&lt;' operator on this object with the given argument
- * @throws EvaluationException if the operator is not appropriate for an object of this kind
- */
+ @override
BoolState lessThan(InstanceState rightOperand) {
- assertNumOrNull(this);
assertNumOrNull(rightOperand);
- throw new EvaluationException(CompileTimeErrorCode.INVALID_CONSTANT);
+ if (value == null) {
+ return BoolState.UNKNOWN_VALUE;
+ }
+ if (rightOperand is IntState) {
+ int rightValue = rightOperand.value;
+ if (rightValue == null) {
+ return BoolState.UNKNOWN_VALUE;
+ }
+ return BoolState.from(value.compareTo(rightValue) < 0);
+ } else if (rightOperand is DoubleState) {
+ double rightValue = rightOperand.value;
+ if (rightValue == null) {
+ return BoolState.UNKNOWN_VALUE;
+ }
+ return BoolState.from(value.toDouble() < rightValue);
+ } else if (rightOperand is DynamicState || rightOperand is NumState) {
+ return BoolState.UNKNOWN_VALUE;
+ }
+ throw new EvaluationException(CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION);
}
- /**
- * Return the result of invoking the '&lt;=' operator on this object with the given argument.
- *
- * @param rightOperand the right-hand operand of the operation
- * @return the result of invoking the '&lt;=' operator on this object with the given argument
- * @throws EvaluationException if the operator is not appropriate for an object of this kind
- */
+ @override
BoolState lessThanOrEqual(InstanceState rightOperand) {
- assertNumOrNull(this);
assertNumOrNull(rightOperand);
- throw new EvaluationException(CompileTimeErrorCode.INVALID_CONSTANT);
- }
-
- /**
- * Return the result of invoking the '&&' operator on this object with the given argument.
- *
- * @param rightOperand the right-hand operand of the operation
- * @return the result of invoking the '&&' operator on this object with the given argument
- * @throws EvaluationException if the operator is not appropriate for an object of this kind
- */
- BoolState logicalAnd(InstanceState rightOperand) {
- assertBool(this);
- assertBool(rightOperand);
- return BoolState.FALSE_STATE;
- }
-
- /**
- * Return the result of invoking the '!' operator on this object.
- *
- * @return the result of invoking the '!' operator on this object
- * @throws EvaluationException if the operator is not appropriate for an object of this kind
- */
- BoolState logicalNot() {
- assertBool(this);
- return BoolState.TRUE_STATE;
- }
-
- /**
- * Return the result of invoking the '||' operator on this object with the given argument.
- *
- * @param rightOperand the right-hand operand of the operation
- * @return the result of invoking the '||' operator on this object with the given argument
- * @throws EvaluationException if the operator is not appropriate for an object of this kind
- */
- BoolState logicalOr(InstanceState rightOperand) {
- assertBool(this);
- assertBool(rightOperand);
- return rightOperand.convertToBool();
- }
-
- /**
- * Return the result of invoking the '-' operator on this object with the given argument.
- *
- * @param rightOperand the right-hand operand of the operation
- * @return the result of invoking the '-' operator on this object with the given argument
- * @throws EvaluationException if the operator is not appropriate for an object of this kind
- */
+ if (value == null) {
+ return BoolState.UNKNOWN_VALUE;
+ }
+ if (rightOperand is IntState) {
+ int rightValue = rightOperand.value;
+ if (rightValue == null) {
+ return BoolState.UNKNOWN_VALUE;
+ }
+ return BoolState.from(value.compareTo(rightValue) <= 0);
+ } else if (rightOperand is DoubleState) {
+ double rightValue = rightOperand.value;
+ if (rightValue == null) {
+ return BoolState.UNKNOWN_VALUE;
+ }
+ return BoolState.from(value.toDouble() <= rightValue);
+ } else if (rightOperand is DynamicState || rightOperand is NumState) {
+ return BoolState.UNKNOWN_VALUE;
+ }
+ throw new EvaluationException(CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION);
+ }
+
+ @override
NumState minus(InstanceState rightOperand) {
- assertNumOrNull(this);
assertNumOrNull(rightOperand);
- throw new EvaluationException(CompileTimeErrorCode.INVALID_CONSTANT);
+ if (value == null) {
+ if (rightOperand is DoubleState) {
+ return DoubleState.UNKNOWN_VALUE;
+ }
+ return UNKNOWN_VALUE;
+ }
+ if (rightOperand is IntState) {
+ int rightValue = rightOperand.value;
+ if (rightValue == null) {
+ return UNKNOWN_VALUE;
+ }
+ return new IntState(value - rightValue);
+ } else if (rightOperand is DoubleState) {
+ double rightValue = rightOperand.value;
+ if (rightValue == null) {
+ return DoubleState.UNKNOWN_VALUE;
+ }
+ return new DoubleState(value.toDouble() - rightValue);
+ } else if (rightOperand is DynamicState || rightOperand is NumState) {
+ return UNKNOWN_VALUE;
+ }
+ throw new EvaluationException(CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION);
}
- /**
- * Return the result of invoking the '-' operator on this object.
- *
- * @return the result of invoking the '-' operator on this object
- * @throws EvaluationException if the operator is not appropriate for an object of this kind
- */
+ @override
NumState negated() {
- assertNumOrNull(this);
- throw new EvaluationException(CompileTimeErrorCode.INVALID_CONSTANT);
+ if (value == null) {
+ return UNKNOWN_VALUE;
+ }
+ return new IntState(-value);
}
- /**
- * Return the result of invoking the '%' operator on this object with the given argument.
- *
- * @param rightOperand the right-hand operand of the operation
- * @return the result of invoking the '%' operator on this object with the given argument
- * @throws EvaluationException if the operator is not appropriate for an object of this kind
- */
+ @override
NumState remainder(InstanceState rightOperand) {
- assertNumOrNull(this);
assertNumOrNull(rightOperand);
- throw new EvaluationException(CompileTimeErrorCode.INVALID_CONSTANT);
+ if (value == null) {
+ if (rightOperand is DoubleState) {
+ return DoubleState.UNKNOWN_VALUE;
+ }
+ return UNKNOWN_VALUE;
+ }
+ if (rightOperand is IntState) {
+ int rightValue = rightOperand.value;
+ if (rightValue == null) {
+ return UNKNOWN_VALUE;
+ } else if (rightValue == 0) {
+ return new DoubleState(value.toDouble() % rightValue.toDouble());
+ }
+ return new IntState(value.remainder(rightValue));
+ } else if (rightOperand is DoubleState) {
+ double rightValue = rightOperand.value;
+ if (rightValue == null) {
+ return DoubleState.UNKNOWN_VALUE;
+ }
+ return new DoubleState(value.toDouble() % rightValue);
+ } else if (rightOperand is DynamicState || rightOperand is NumState) {
+ return UNKNOWN_VALUE;
+ }
+ throw new EvaluationException(CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION);
}
- /**
- * Return the result of invoking the '&lt;&lt;' operator on this object with the given argument.
- *
- * @param rightOperand the right-hand operand of the operation
- * @return the result of invoking the '&lt;&lt;' operator on this object with the given argument
- * @throws EvaluationException if the operator is not appropriate for an object of this kind
- */
+ @override
IntState shiftLeft(InstanceState rightOperand) {
- assertIntOrNull(this);
assertIntOrNull(rightOperand);
- throw new EvaluationException(CompileTimeErrorCode.INVALID_CONSTANT);
+ if (value == null) {
+ return UNKNOWN_VALUE;
+ }
+ if (rightOperand is IntState) {
+ int rightValue = rightOperand.value;
+ if (rightValue == null) {
+ return UNKNOWN_VALUE;
+ } else if (rightValue.bitLength > 31) {
+ return UNKNOWN_VALUE;
+ }
+ return new IntState(value << rightValue);
+ } else if (rightOperand is DynamicState || rightOperand is NumState) {
+ return UNKNOWN_VALUE;
+ }
+ throw new EvaluationException(CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION);
}
- /**
- * Return the result of invoking the '&gt;&gt;' operator on this object with the given argument.
- *
- * @param rightOperand the right-hand operand of the operation
- * @return the result of invoking the '&gt;&gt;' operator on this object with the given argument
- * @throws EvaluationException if the operator is not appropriate for an object of this kind
- */
+ @override
IntState shiftRight(InstanceState rightOperand) {
- assertIntOrNull(this);
assertIntOrNull(rightOperand);
- throw new EvaluationException(CompileTimeErrorCode.INVALID_CONSTANT);
+ if (value == null) {
+ return UNKNOWN_VALUE;
+ }
+ if (rightOperand is IntState) {
+ int rightValue = rightOperand.value;
+ if (rightValue == null) {
+ return UNKNOWN_VALUE;
+ } else if (rightValue.bitLength > 31) {
+ return UNKNOWN_VALUE;
+ }
+ return new IntState(value >> rightValue);
+ } else if (rightOperand is DynamicState || rightOperand is NumState) {
+ return UNKNOWN_VALUE;
+ }
+ throw new EvaluationException(CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION);
}
- /**
- * Return the result of invoking the '*' operator on this object with the given argument.
- *
- * @param rightOperand the right-hand operand of the operation
- * @return the result of invoking the '*' operator on this object with the given argument
- * @throws EvaluationException if the operator is not appropriate for an object of this kind
- */
+ @override
NumState times(InstanceState rightOperand) {
- assertNumOrNull(this);
assertNumOrNull(rightOperand);
- throw new EvaluationException(CompileTimeErrorCode.INVALID_CONSTANT);
+ if (value == null) {
+ if (rightOperand is DoubleState) {
+ return DoubleState.UNKNOWN_VALUE;
+ }
+ return UNKNOWN_VALUE;
+ }
+ if (rightOperand is IntState) {
+ int rightValue = rightOperand.value;
+ if (rightValue == null) {
+ return UNKNOWN_VALUE;
+ }
+ return new IntState(value * rightValue);
+ } else if (rightOperand is DoubleState) {
+ double rightValue = rightOperand.value;
+ if (rightValue == null) {
+ return DoubleState.UNKNOWN_VALUE;
+ }
+ return new DoubleState(value.toDouble() * rightValue);
+ } else if (rightOperand is DynamicState || rightOperand is NumState) {
+ return UNKNOWN_VALUE;
+ }
+ throw new EvaluationException(CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION);
}
+ @override
+ String toString() => value == null ? "-unknown-" : value.toString();
+}
+
+/**
+ * The unique instance of the class `ListState` represents the state of an object representing
+ * a list.
+ */
+class ListState extends InstanceState {
/**
- * Throw an exception if the given state does not represent a boolean value.
- *
- * @param state the state being tested
- * @throws EvaluationException if the given state does not represent a boolean value
+ * The elements of the list.
*/
- void assertBool(InstanceState state) {
- if (!(state is BoolState || state is DynamicState)) {
- throw new EvaluationException(CompileTimeErrorCode.CONST_EVAL_TYPE_BOOL);
- }
- }
+ final List<DartObjectImpl> _elements;
/**
- * Throw an exception if the given state does not represent a boolean, numeric, string or null
- * value.
+ * Initialize a newly created state to represent a list with the given elements.
*
- * @param state the state being tested
- * @throws EvaluationException if the given state does not represent a boolean, numeric, string or
- * null value
+ * @param elements the elements of the list
*/
- void assertBoolNumStringOrNull(InstanceState state) {
- if (!(state is BoolState || state is DoubleState || state is IntState || state is NumState || state is StringState || state is NullState || state is DynamicState)) {
- throw new EvaluationException(CompileTimeErrorCode.CONST_EVAL_TYPE_BOOL_NUM_STRING);
+ ListState(this._elements);
+
+ @override
+ StringState convertToString() => StringState.UNKNOWN_VALUE;
+
+ @override
+ BoolState equalEqual(InstanceState rightOperand) {
+ assertBoolNumStringOrNull(rightOperand);
+ if (rightOperand is DynamicState) {
+ return BoolState.UNKNOWN_VALUE;
}
+ return BoolState.from(this == rightOperand);
}
- /**
- * Throw an exception if the given state does not represent an integer or null value.
- *
- * @param state the state being tested
- * @throws EvaluationException if the given state does not represent an integer or null value
- */
- void assertIntOrNull(InstanceState state) {
- if (!(state is IntState || state is NumState || state is NullState || state is DynamicState)) {
- throw new EvaluationException(CompileTimeErrorCode.CONST_EVAL_TYPE_INT);
+ @override
+ bool operator ==(Object object) {
+ if (object is! ListState) {
+ return false;
+ }
+ List<DartObjectImpl> otherElements = (object as ListState)._elements;
+ int count = _elements.length;
+ if (otherElements.length != count) {
+ return false;
+ } else if (count == 0) {
+ return true;
+ }
+ for (int i = 0; i < count; i++) {
+ if (_elements[i] != otherElements[i]) {
+ return false;
+ }
}
+ return true;
}
- /**
- * Throw an exception if the given state does not represent a boolean, numeric, string or null
- * value.
- *
- * @param state the state being tested
- * @throws EvaluationException if the given state does not represent a boolean, numeric, string or
- * null value
- */
- void assertNumOrNull(InstanceState state) {
- if (!(state is DoubleState || state is IntState || state is NumState || state is NullState || state is DynamicState)) {
- throw new EvaluationException(CompileTimeErrorCode.CONST_EVAL_TYPE_NUM);
+ @override
+ String get typeName => "List";
+
+ @override
+ List<Object> get value {
+ int count = _elements.length;
+ List<Object> result = new List<Object>(count);
+ for (int i = 0; i < count; i++) {
+ DartObjectImpl element = _elements[i];
+ if (!element.hasExactValue) {
+ return null;
+ }
+ result[i] = element.value;
+ }
+ return result;
+ }
+
+ @override
+ bool get hasExactValue {
+ int count = _elements.length;
+ for (int i = 0; i < count; i++) {
+ if (!_elements[i].hasExactValue) {
+ return false;
+ }
}
+ return true;
}
- /**
- * Throw an exception if the given state does not represent a String value.
- *
- * @param state the state being tested
- * @throws EvaluationException if the given state does not represent a String value
- */
- void assertString(InstanceState state) {
- if (!(state is StringState || state is DynamicState)) {
- throw new EvaluationException(CompileTimeErrorCode.CONST_EVAL_TYPE_BOOL);
+ @override
+ int get hashCode {
+ int value = 0;
+ int count = _elements.length;
+ for (int i = 0; i < count; i++) {
+ value = (value << 3) ^ _elements[i].hashCode;
}
+ return value;
}
}
/**
- * Instances of the class `IntState` represent the state of an object representing an int.
+ * The unique instance of the class `ListState` represents the state of an object representing
+ * a map.
*/
-class IntState extends NumState {
- /**
- * The value of this instance.
- */
- final int value;
-
+class MapState extends InstanceState {
/**
- * A state that can be used to represent an int whose value is not known.
+ * The entries in the map.
*/
- static IntState UNKNOWN_VALUE = new IntState(null);
+ final Map<DartObjectImpl, DartObjectImpl> _entries;
/**
- * Initialize a newly created state to represent an int with the given value.
+ * Initialize a newly created state to represent a map with the given entries.
*
- * @param value the value of this instance
+ * @param entries the entries in the map
*/
- IntState(this.value);
+ MapState(this._entries);
@override
- NumState add(InstanceState rightOperand) {
- assertNumOrNull(rightOperand);
- if (value == null) {
- if (rightOperand is DoubleState) {
- return DoubleState.UNKNOWN_VALUE;
- }
- return UNKNOWN_VALUE;
- }
- if (rightOperand is IntState) {
- int rightValue = rightOperand.value;
- if (rightValue == null) {
- return UNKNOWN_VALUE;
- }
- return new IntState(value + rightValue);
- } else if (rightOperand is DoubleState) {
- double rightValue = rightOperand.value;
- if (rightValue == null) {
- return DoubleState.UNKNOWN_VALUE;
- }
- return new DoubleState(value.toDouble() + rightValue);
- } else if (rightOperand is DynamicState || rightOperand is NumState) {
- return UNKNOWN_VALUE;
+ StringState convertToString() => StringState.UNKNOWN_VALUE;
+
+ @override
+ BoolState equalEqual(InstanceState rightOperand) {
+ assertBoolNumStringOrNull(rightOperand);
+ if (rightOperand is DynamicState) {
+ return BoolState.UNKNOWN_VALUE;
}
- throw new EvaluationException(CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION);
+ return BoolState.from(this == rightOperand);
}
@override
- IntState bitAnd(InstanceState rightOperand) {
- assertIntOrNull(rightOperand);
- if (value == null) {
- return UNKNOWN_VALUE;
+ bool operator ==(Object object) {
+ if (object is! MapState) {
+ return false;
}
- if (rightOperand is IntState) {
- int rightValue = rightOperand.value;
- if (rightValue == null) {
- return UNKNOWN_VALUE;
+ Map<DartObjectImpl, DartObjectImpl> otherElements = (object as MapState)._entries;
+ int count = _entries.length;
+ if (otherElements.length != count) {
+ return false;
+ } else if (count == 0) {
+ return true;
+ }
+ for (MapEntry<DartObjectImpl, DartObjectImpl> entry in getMapEntrySet(_entries)) {
+ DartObjectImpl key = entry.getKey();
+ DartObjectImpl value = entry.getValue();
+ DartObjectImpl otherValue = otherElements[key];
+ if (value != otherValue) {
+ return false;
}
- return new IntState(value & rightValue);
- } else if (rightOperand is DynamicState || rightOperand is NumState) {
- return UNKNOWN_VALUE;
}
- throw new EvaluationException(CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION);
+ return true;
}
@override
- IntState bitNot() {
- if (value == null) {
- return UNKNOWN_VALUE;
- }
- return new IntState(~value);
- }
+ String get typeName => "Map";
@override
- IntState bitOr(InstanceState rightOperand) {
- assertIntOrNull(rightOperand);
- if (value == null) {
- return UNKNOWN_VALUE;
- }
- if (rightOperand is IntState) {
- int rightValue = rightOperand.value;
- if (rightValue == null) {
- return UNKNOWN_VALUE;
+ Map<Object, Object> get value {
+ Map<Object, Object> result = new Map<Object, Object>();
+ for (MapEntry<DartObjectImpl, DartObjectImpl> entry in getMapEntrySet(_entries)) {
+ DartObjectImpl key = entry.getKey();
+ DartObjectImpl value = entry.getValue();
+ if (!key.hasExactValue || !value.hasExactValue) {
+ return null;
}
- return new IntState(value | rightValue);
- } else if (rightOperand is DynamicState || rightOperand is NumState) {
- return UNKNOWN_VALUE;
+ result[key.value] = value.value;
}
- throw new EvaluationException(CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION);
+ return result;
}
@override
- IntState bitXor(InstanceState rightOperand) {
- assertIntOrNull(rightOperand);
- if (value == null) {
- return UNKNOWN_VALUE;
- }
- if (rightOperand is IntState) {
- int rightValue = rightOperand.value;
- if (rightValue == null) {
- return UNKNOWN_VALUE;
+ bool get hasExactValue {
+ for (MapEntry<DartObjectImpl, DartObjectImpl> entry in getMapEntrySet(_entries)) {
+ if (!entry.getKey().hasExactValue || !entry.getValue().hasExactValue) {
+ return false;
}
- return new IntState(value ^ rightValue);
- } else if (rightOperand is DynamicState || rightOperand is NumState) {
- return UNKNOWN_VALUE;
}
- throw new EvaluationException(CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION);
+ return true;
}
@override
- StringState convertToString() {
- if (value == null) {
- return StringState.UNKNOWN_VALUE;
+ int get hashCode {
+ int value = 0;
+ for (DartObjectImpl key in _entries.keys.toSet()) {
+ value = (value << 3) ^ key.hashCode;
}
- return new StringState(value.toString());
+ return value;
}
+}
+
+/**
+ * The unique instance of the class `NullState` represents the state of the value 'null'.
+ */
+class NullState extends InstanceState {
+ /**
+ * An instance representing the boolean value 'true'.
+ */
+ static NullState NULL_STATE = new NullState();
@override
- NumState divide(InstanceState rightOperand) {
- assertNumOrNull(rightOperand);
- if (value == null) {
- if (rightOperand is DoubleState) {
- return DoubleState.UNKNOWN_VALUE;
- }
- return UNKNOWN_VALUE;
- }
- if (rightOperand is IntState) {
- int rightValue = rightOperand.value;
- if (rightValue == null) {
- return UNKNOWN_VALUE;
- } else if (rightValue == 0) {
- return new DoubleState(value.toDouble() / rightValue.toDouble());
- }
- return new IntState(value ~/ rightValue);
- } else if (rightOperand is DoubleState) {
- double rightValue = rightOperand.value;
- if (rightValue == null) {
- return DoubleState.UNKNOWN_VALUE;
- }
- return new DoubleState(value.toDouble() / rightValue);
- } else if (rightOperand is DynamicState || rightOperand is NumState) {
- return UNKNOWN_VALUE;
- }
+ BoolState convertToBool() {
throw new EvaluationException(CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION);
}
@override
+ StringState convertToString() => new StringState("null");
+
+ @override
BoolState equalEqual(InstanceState rightOperand) {
assertBoolNumStringOrNull(rightOperand);
- if (value == null) {
- return BoolState.UNKNOWN_VALUE;
- }
- if (rightOperand is IntState) {
- int rightValue = rightOperand.value;
- if (rightValue == null) {
- return BoolState.UNKNOWN_VALUE;
- }
- return BoolState.from(value == rightValue);
- } else if (rightOperand is DoubleState) {
- double rightValue = rightOperand.value;
- if (rightValue == null) {
- return BoolState.UNKNOWN_VALUE;
- }
- return BoolState.from(rightValue == value.toDouble());
- } else if (rightOperand is DynamicState || rightOperand is NumState) {
+ if (rightOperand is DynamicState) {
return BoolState.UNKNOWN_VALUE;
}
- return BoolState.FALSE_STATE;
+ return BoolState.from(rightOperand is NullState);
+ }
+
+ @override
+ bool operator ==(Object object) => object is NullState;
+
+ @override
+ String get typeName => "Null";
+
+ @override
+ bool get hasExactValue => true;
+
+ @override
+ int get hashCode => 0;
+
+ @override
+ bool get isBoolNumStringOrNull => true;
+
+ @override
+ BoolState logicalNot() {
+ throw new EvaluationException(CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION);
+ }
+
+ @override
+ String toString() => "null";
+}
+
+/**
+ * Instances of the class `NumState` represent the state of an object representing a number of
+ * an unknown type (a 'num').
+ */
+class NumState extends InstanceState {
+ /**
+ * A state that can be used to represent a number whose value is not known.
+ */
+ static NumState UNKNOWN_VALUE = new NumState();
+
+ @override
+ NumState add(InstanceState rightOperand) {
+ assertNumOrNull(rightOperand);
+ return UNKNOWN_VALUE;
}
@override
- bool operator ==(Object object) => object is IntState && (value == object.value);
+ StringState convertToString() => StringState.UNKNOWN_VALUE;
@override
- String get typeName => "int";
+ NumState divide(InstanceState rightOperand) {
+ assertNumOrNull(rightOperand);
+ return UNKNOWN_VALUE;
+ }
+
+ @override
+ bool operator ==(Object object) => object is NumState;
+
+ @override
+ BoolState equalEqual(InstanceState rightOperand) {
+ assertBoolNumStringOrNull(rightOperand);
+ return BoolState.UNKNOWN_VALUE;
+ }
+
+ @override
+ String get typeName => "num";
@override
BoolState greaterThan(InstanceState rightOperand) {
assertNumOrNull(rightOperand);
- if (value == null) {
- return BoolState.UNKNOWN_VALUE;
- }
- if (rightOperand is IntState) {
- int rightValue = rightOperand.value;
- if (rightValue == null) {
- return BoolState.UNKNOWN_VALUE;
- }
- return BoolState.from(value.compareTo(rightValue) > 0);
- } else if (rightOperand is DoubleState) {
- double rightValue = rightOperand.value;
- if (rightValue == null) {
- return BoolState.UNKNOWN_VALUE;
- }
- return BoolState.from(value.toDouble() > rightValue);
- } else if (rightOperand is DynamicState || rightOperand is NumState) {
- return BoolState.UNKNOWN_VALUE;
- }
- throw new EvaluationException(CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION);
+ return BoolState.UNKNOWN_VALUE;
}
@override
BoolState greaterThanOrEqual(InstanceState rightOperand) {
assertNumOrNull(rightOperand);
- if (value == null) {
- return BoolState.UNKNOWN_VALUE;
- }
- if (rightOperand is IntState) {
- int rightValue = rightOperand.value;
- if (rightValue == null) {
- return BoolState.UNKNOWN_VALUE;
- }
- return BoolState.from(value.compareTo(rightValue) >= 0);
- } else if (rightOperand is DoubleState) {
- double rightValue = rightOperand.value;
- if (rightValue == null) {
- return BoolState.UNKNOWN_VALUE;
- }
- return BoolState.from(value.toDouble() >= rightValue);
- } else if (rightOperand is DynamicState || rightOperand is NumState) {
- return BoolState.UNKNOWN_VALUE;
- }
- throw new EvaluationException(CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION);
+ return BoolState.UNKNOWN_VALUE;
}
@override
- bool get hasExactValue => true;
-
- @override
- int get hashCode => value == null ? 0 : value.hashCode;
+ int get hashCode => 7;
@override
IntState integerDivide(InstanceState rightOperand) {
assertNumOrNull(rightOperand);
- if (value == null) {
- return UNKNOWN_VALUE;
- }
if (rightOperand is IntState) {
int rightValue = rightOperand.value;
if (rightValue == null) {
- return UNKNOWN_VALUE;
+ return IntState.UNKNOWN_VALUE;
} else if (rightValue == 0) {
throw new EvaluationException(CompileTimeErrorCode.CONST_EVAL_THROWS_IDBZE);
}
- return new IntState(value ~/ rightValue);
- } else if (rightOperand is DoubleState) {
- double rightValue = rightOperand.value;
- if (rightValue == null) {
- return UNKNOWN_VALUE;
- }
- double result = value.toDouble() / rightValue;
- return new IntState(result.toInt());
- } else if (rightOperand is DynamicState || rightOperand is NumState) {
- return UNKNOWN_VALUE;
+ } else if (rightOperand is DynamicState) {
+ return IntState.UNKNOWN_VALUE;
}
- throw new EvaluationException(CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION);
+ return IntState.UNKNOWN_VALUE;
}
@override
@@ -3629,710 +3623,716 @@ class IntState extends NumState {
@override
BoolState lessThan(InstanceState rightOperand) {
assertNumOrNull(rightOperand);
- if (value == null) {
- return BoolState.UNKNOWN_VALUE;
- }
- if (rightOperand is IntState) {
- int rightValue = rightOperand.value;
- if (rightValue == null) {
- return BoolState.UNKNOWN_VALUE;
- }
- return BoolState.from(value.compareTo(rightValue) < 0);
- } else if (rightOperand is DoubleState) {
- double rightValue = rightOperand.value;
- if (rightValue == null) {
- return BoolState.UNKNOWN_VALUE;
- }
- return BoolState.from(value.toDouble() < rightValue);
- } else if (rightOperand is DynamicState || rightOperand is NumState) {
- return BoolState.UNKNOWN_VALUE;
- }
- throw new EvaluationException(CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION);
+ return BoolState.UNKNOWN_VALUE;
}
@override
BoolState lessThanOrEqual(InstanceState rightOperand) {
assertNumOrNull(rightOperand);
- if (value == null) {
- return BoolState.UNKNOWN_VALUE;
- }
- if (rightOperand is IntState) {
- int rightValue = rightOperand.value;
- if (rightValue == null) {
- return BoolState.UNKNOWN_VALUE;
- }
- return BoolState.from(value.compareTo(rightValue) <= 0);
- } else if (rightOperand is DoubleState) {
- double rightValue = rightOperand.value;
- if (rightValue == null) {
- return BoolState.UNKNOWN_VALUE;
- }
- return BoolState.from(value.toDouble() <= rightValue);
- } else if (rightOperand is DynamicState || rightOperand is NumState) {
- return BoolState.UNKNOWN_VALUE;
- }
- throw new EvaluationException(CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION);
+ return BoolState.UNKNOWN_VALUE;
}
@override
NumState minus(InstanceState rightOperand) {
assertNumOrNull(rightOperand);
- if (value == null) {
- if (rightOperand is DoubleState) {
- return DoubleState.UNKNOWN_VALUE;
- }
- return UNKNOWN_VALUE;
- }
- if (rightOperand is IntState) {
- int rightValue = rightOperand.value;
- if (rightValue == null) {
- return UNKNOWN_VALUE;
- }
- return new IntState(value - rightValue);
- } else if (rightOperand is DoubleState) {
- double rightValue = rightOperand.value;
- if (rightValue == null) {
- return DoubleState.UNKNOWN_VALUE;
- }
- return new DoubleState(value.toDouble() - rightValue);
- } else if (rightOperand is DynamicState || rightOperand is NumState) {
- return UNKNOWN_VALUE;
- }
- throw new EvaluationException(CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION);
+ return UNKNOWN_VALUE;
}
@override
- NumState negated() {
- if (value == null) {
- return UNKNOWN_VALUE;
- }
- return new IntState(-value);
- }
+ NumState negated() => UNKNOWN_VALUE;
@override
NumState remainder(InstanceState rightOperand) {
assertNumOrNull(rightOperand);
- if (value == null) {
- if (rightOperand is DoubleState) {
- return DoubleState.UNKNOWN_VALUE;
- }
- return UNKNOWN_VALUE;
- }
- if (rightOperand is IntState) {
- int rightValue = rightOperand.value;
- if (rightValue == null) {
- return UNKNOWN_VALUE;
- } else if (rightValue == 0) {
- return new DoubleState(value.toDouble() % rightValue.toDouble());
- }
- return new IntState(value.remainder(rightValue));
- } else if (rightOperand is DoubleState) {
- double rightValue = rightOperand.value;
- if (rightValue == null) {
- return DoubleState.UNKNOWN_VALUE;
- }
- return new DoubleState(value.toDouble() % rightValue);
- } else if (rightOperand is DynamicState || rightOperand is NumState) {
- return UNKNOWN_VALUE;
- }
- throw new EvaluationException(CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION);
+ return UNKNOWN_VALUE;
}
@override
- IntState shiftLeft(InstanceState rightOperand) {
- assertIntOrNull(rightOperand);
- if (value == null) {
- return UNKNOWN_VALUE;
+ NumState times(InstanceState rightOperand) {
+ assertNumOrNull(rightOperand);
+ return UNKNOWN_VALUE;
+ }
+
+ @override
+ String toString() => "-unknown-";
+}
+
+/**
+ * Instances of the class `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.
+ */
+ final 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.
+ */
+ final 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.
+ *
+ * @param source the element representing the variable whose initializer will be visited
+ * @param referenceGraph a graph recording which variables (heads) reference which other variables
+ * (tails) in their initializers
+ */
+ ReferenceFinder(this._source, this._referenceGraph);
+
+ @override
+ Object visitSimpleIdentifier(SimpleIdentifier node) {
+ Element element = node.staticElement;
+ if (element is PropertyAccessorElement) {
+ element = (element as PropertyAccessorElement).variable;
}
- if (rightOperand is IntState) {
- int rightValue = rightOperand.value;
- if (rightValue == null) {
- return UNKNOWN_VALUE;
- } else if (rightValue.bitLength > 31) {
- return UNKNOWN_VALUE;
+ if (element is VariableElement) {
+ VariableElement variable = element as VariableElement;
+ if (variable.isConst) {
+ _referenceGraph.addEdge(_source, variable);
}
- return new IntState(value << rightValue);
- } else if (rightOperand is DynamicState || rightOperand is NumState) {
- return UNKNOWN_VALUE;
}
- throw new EvaluationException(CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION);
+ return null;
}
+}
+
+/**
+ * Instances of the class `StringState` represent the state of an object representing a
+ * string.
+ */
+class StringState extends InstanceState {
+ /**
+ * The value of this instance.
+ */
+ final String value;
+
+ /**
+ * A state that can be used to represent a double whose value is not known.
+ */
+ static StringState UNKNOWN_VALUE = new StringState(null);
+
+ /**
+ * Initialize a newly created state to represent the given value.
+ *
+ * @param value the value of this instance
+ */
+ StringState(this.value);
@override
- IntState shiftRight(InstanceState rightOperand) {
- assertIntOrNull(rightOperand);
+ StringState concatenate(InstanceState rightOperand) {
if (value == null) {
return UNKNOWN_VALUE;
}
- if (rightOperand is IntState) {
- int rightValue = rightOperand.value;
+ if (rightOperand is StringState) {
+ String rightValue = rightOperand.value;
if (rightValue == null) {
return UNKNOWN_VALUE;
- } else if (rightValue.bitLength > 31) {
- return UNKNOWN_VALUE;
}
- return new IntState(value >> rightValue);
- } else if (rightOperand is DynamicState || rightOperand is NumState) {
+ return new StringState("${value}${rightValue}");
+ } else if (rightOperand is DynamicState) {
return UNKNOWN_VALUE;
}
- throw new EvaluationException(CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION);
+ return super.concatenate(rightOperand);
}
@override
- NumState times(InstanceState rightOperand) {
- assertNumOrNull(rightOperand);
+ StringState convertToString() => this;
+
+ @override
+ BoolState equalEqual(InstanceState rightOperand) {
+ assertBoolNumStringOrNull(rightOperand);
if (value == null) {
- if (rightOperand is DoubleState) {
- return DoubleState.UNKNOWN_VALUE;
- }
- return UNKNOWN_VALUE;
+ return BoolState.UNKNOWN_VALUE;
}
- if (rightOperand is IntState) {
- int rightValue = rightOperand.value;
- if (rightValue == null) {
- return UNKNOWN_VALUE;
- }
- return new IntState(value * rightValue);
- } else if (rightOperand is DoubleState) {
- double rightValue = rightOperand.value;
+ if (rightOperand is StringState) {
+ String rightValue = rightOperand.value;
if (rightValue == null) {
- return DoubleState.UNKNOWN_VALUE;
+ return BoolState.UNKNOWN_VALUE;
}
- return new DoubleState(value.toDouble() * rightValue);
- } else if (rightOperand is DynamicState || rightOperand is NumState) {
- return UNKNOWN_VALUE;
+ return BoolState.from(value == rightValue);
+ } else if (rightOperand is DynamicState) {
+ return BoolState.UNKNOWN_VALUE;
}
- throw new EvaluationException(CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION);
+ return BoolState.FALSE_STATE;
}
@override
- String toString() => value == null ? "-unknown-" : value.toString();
+ bool operator ==(Object object) => object is StringState && (value == object.value);
+
+ @override
+ String get typeName => "String";
+
+ @override
+ bool get hasExactValue => true;
+
+ @override
+ int get hashCode => value == null ? 0 : value.hashCode;
+
+ @override
+ bool get isBoolNumStringOrNull => true;
+
+ @override
+ String toString() => value == null ? "-unknown-" : "'${value}'";
}
/**
- * The unique instance of the class `ListState` represents the state of an object representing
- * a list.
+ * Instances of the class `StringState` represent the state of an object representing a
+ * symbol.
*/
-class ListState extends InstanceState {
+class SymbolState extends InstanceState {
/**
- * The elements of the list.
+ * The value of this instance.
*/
- final List<DartObjectImpl> _elements;
+ final String value;
/**
- * Initialize a newly created state to represent a list with the given elements.
+ * Initialize a newly created state to represent the given value.
*
- * @param elements the elements of the list
+ * @param value the value of this instance
*/
- ListState(this._elements);
+ SymbolState(this.value);
@override
- StringState convertToString() => StringState.UNKNOWN_VALUE;
+ StringState convertToString() {
+ if (value == null) {
+ return StringState.UNKNOWN_VALUE;
+ }
+ return new StringState(value);
+ }
@override
BoolState equalEqual(InstanceState rightOperand) {
assertBoolNumStringOrNull(rightOperand);
- if (rightOperand is DynamicState) {
+ if (value == null) {
return BoolState.UNKNOWN_VALUE;
}
- return BoolState.from(this == rightOperand);
- }
-
- @override
- bool operator ==(Object object) {
- if (object is! ListState) {
- return false;
- }
- List<DartObjectImpl> otherElements = (object as ListState)._elements;
- int count = _elements.length;
- if (otherElements.length != count) {
- return false;
- } else if (count == 0) {
- return true;
- }
- for (int i = 0; i < count; i++) {
- if (_elements[i] != otherElements[i]) {
- return false;
+ if (rightOperand is SymbolState) {
+ String rightValue = rightOperand.value;
+ if (rightValue == null) {
+ return BoolState.UNKNOWN_VALUE;
}
+ return BoolState.from(value == rightValue);
+ } else if (rightOperand is DynamicState) {
+ return BoolState.UNKNOWN_VALUE;
}
- return true;
+ return BoolState.FALSE_STATE;
}
@override
- String get typeName => "List";
+ bool operator ==(Object object) => object is SymbolState && (value == object.value);
@override
- List<Object> get value {
- int count = _elements.length;
- List<Object> result = new List<Object>(count);
- for (int i = 0; i < count; i++) {
- DartObjectImpl element = _elements[i];
- if (!element.hasExactValue) {
- return null;
- }
- result[i] = element.value;
- }
- return result;
- }
+ String get typeName => "Symbol";
@override
- bool get hasExactValue {
- int count = _elements.length;
- for (int i = 0; i < count; i++) {
- if (!_elements[i].hasExactValue) {
- return false;
- }
- }
- return true;
- }
+ bool get hasExactValue => true;
@override
- int get hashCode {
- int value = 0;
- int count = _elements.length;
- for (int i = 0; i < count; i++) {
- value = (value << 3) ^ _elements[i].hashCode;
- }
- return value;
- }
+ int get hashCode => value == null ? 0 : value.hashCode;
+
+ @override
+ String toString() => value == null ? "-unknown-" : "#${value}";
}
/**
- * The unique instance of the class `ListState` represents the state of an object representing
- * a map.
+ * Instances of the class `TypeState` represent the state of an object representing a type.
*/
-class MapState extends InstanceState {
+class TypeState extends InstanceState {
/**
- * The entries in the map.
+ * The element representing the type being modeled.
*/
- final Map<DartObjectImpl, DartObjectImpl> _entries;
+ final Element _element;
/**
- * Initialize a newly created state to represent a map with the given entries.
+ * Initialize a newly created state to represent the given value.
*
- * @param entries the entries in the map
+ * @param element the element representing the type being modeled
*/
- MapState(this._entries);
+ TypeState(this._element);
@override
- StringState convertToString() => StringState.UNKNOWN_VALUE;
+ StringState convertToString() {
+ if (_element == null) {
+ return StringState.UNKNOWN_VALUE;
+ }
+ return new StringState(_element.name);
+ }
+
+ @override
+ bool operator ==(Object object) => object is TypeState && (_element == object._element);
@override
BoolState equalEqual(InstanceState rightOperand) {
assertBoolNumStringOrNull(rightOperand);
- if (rightOperand is DynamicState) {
+ if (_element == null) {
return BoolState.UNKNOWN_VALUE;
}
- return BoolState.from(this == rightOperand);
- }
-
- @override
- bool operator ==(Object object) {
- if (object is! MapState) {
- return false;
- }
- Map<DartObjectImpl, DartObjectImpl> otherElements = (object as MapState)._entries;
- int count = _entries.length;
- if (otherElements.length != count) {
- return false;
- } else if (count == 0) {
- return true;
- }
- for (MapEntry<DartObjectImpl, DartObjectImpl> entry in getMapEntrySet(_entries)) {
- DartObjectImpl key = entry.getKey();
- DartObjectImpl value = entry.getValue();
- DartObjectImpl otherValue = otherElements[key];
- if (value != otherValue) {
- return false;
+ if (rightOperand is TypeState) {
+ Element rightElement = rightOperand._element;
+ if (rightElement == null) {
+ return BoolState.UNKNOWN_VALUE;
}
+ return BoolState.from(_element == rightElement);
+ } else if (rightOperand is DynamicState) {
+ return BoolState.UNKNOWN_VALUE;
}
- return true;
+ return BoolState.FALSE_STATE;
}
@override
- String get typeName => "Map";
+ String get typeName => "Type";
@override
- Map<Object, Object> get value {
- Map<Object, Object> result = new Map<Object, Object>();
- for (MapEntry<DartObjectImpl, DartObjectImpl> entry in getMapEntrySet(_entries)) {
- DartObjectImpl key = entry.getKey();
- DartObjectImpl value = entry.getValue();
- if (!key.hasExactValue || !value.hasExactValue) {
- return null;
- }
- result[key.value] = value.value;
- }
- return result;
- }
+ int get hashCode => _element == null ? 0 : _element.hashCode;
@override
- bool get hasExactValue {
- for (MapEntry<DartObjectImpl, DartObjectImpl> entry in getMapEntrySet(_entries)) {
- if (!entry.getKey().hasExactValue || !entry.getValue().hasExactValue) {
- return false;
- }
- }
- return true;
- }
+ String toString() => _element == null ? "-unknown-" : _element.name;
+}
+
+/**
+ * Instances of the class `ValidResult` represent the result of attempting to evaluate a valid
+ * compile time constant expression.
+ */
+class ValidResult extends EvaluationResultImpl {
+ /**
+ * The value of the expression.
+ */
+ final DartObjectImpl value;
+
+ /**
+ * Initialize a newly created result to represent the given value.
+ *
+ * @param value the value of the expression
+ */
+ ValidResult(this.value);
@override
- int get hashCode {
- int value = 0;
- for (DartObjectImpl key in _entries.keys.toSet()) {
- value = (value << 3) ^ key.hashCode;
- }
- return value;
- }
-}
+ EvaluationResultImpl add(TypeProvider typeProvider, BinaryExpression node, EvaluationResultImpl rightOperand) => rightOperand.addToValid(typeProvider, node, this);
-/**
- * The unique instance of the class `NullState` represents the state of the value 'null'.
- */
-class NullState extends InstanceState {
/**
- * An instance representing the boolean value 'true'.
+ * Return the result of applying boolean conversion to this result.
+ *
+ * @param node the node against which errors should be reported
+ * @return the result of applying boolean conversion to the given value
*/
- static NullState NULL_STATE = new NullState();
-
@override
- BoolState convertToBool() {
- throw new EvaluationException(CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION);
+ EvaluationResultImpl applyBooleanConversion(TypeProvider typeProvider, AstNode node) {
+ try {
+ return _valueOf(value.convertToBool(typeProvider));
+ } on EvaluationException catch (exception) {
+ return _error(node, exception.errorCode);
+ }
}
@override
- StringState convertToString() => new StringState("null");
+ EvaluationResultImpl bitAnd(TypeProvider typeProvider, BinaryExpression node, EvaluationResultImpl rightOperand) => rightOperand.bitAndValid(typeProvider, node, this);
@override
- BoolState equalEqual(InstanceState rightOperand) {
- assertBoolNumStringOrNull(rightOperand);
- if (rightOperand is DynamicState) {
- return BoolState.UNKNOWN_VALUE;
+ EvaluationResultImpl bitNot(TypeProvider typeProvider, Expression node) {
+ try {
+ return _valueOf(value.bitNot(typeProvider));
+ } on EvaluationException catch (exception) {
+ return _error(node, exception.errorCode);
}
- return BoolState.from(rightOperand is NullState);
}
@override
- bool operator ==(Object object) => object is NullState;
+ EvaluationResultImpl bitOr(TypeProvider typeProvider, BinaryExpression node, EvaluationResultImpl rightOperand) => rightOperand.bitOrValid(typeProvider, node, this);
@override
- String get typeName => "Null";
+ EvaluationResultImpl bitXor(TypeProvider typeProvider, BinaryExpression node, EvaluationResultImpl rightOperand) => rightOperand.bitXorValid(typeProvider, node, this);
@override
- bool get hasExactValue => true;
+ EvaluationResultImpl concatenate(TypeProvider typeProvider, Expression node, EvaluationResultImpl rightOperand) => rightOperand.concatenateValid(typeProvider, node, this);
@override
- int get hashCode => 0;
+ EvaluationResultImpl divide(TypeProvider typeProvider, BinaryExpression node, EvaluationResultImpl rightOperand) => rightOperand.divideValid(typeProvider, node, this);
@override
- bool get isBoolNumStringOrNull => true;
+ EvaluationResultImpl equalEqual(TypeProvider typeProvider, Expression node, EvaluationResultImpl rightOperand) => rightOperand.equalEqualValid(typeProvider, node, this);
@override
- BoolState logicalNot() {
- throw new EvaluationException(CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION);
+ bool equalValues(TypeProvider typeProvider, EvaluationResultImpl result) {
+ if (result is! ValidResult) {
+ return false;
+ }
+ return value == (result as ValidResult).value;
}
@override
- String toString() => "null";
-}
+ EvaluationResultImpl greaterThan(TypeProvider typeProvider, BinaryExpression node, EvaluationResultImpl rightOperand) => rightOperand.greaterThanValid(typeProvider, node, this);
+
+ @override
+ EvaluationResultImpl greaterThanOrEqual(TypeProvider typeProvider, BinaryExpression node, EvaluationResultImpl rightOperand) => rightOperand.greaterThanOrEqualValid(typeProvider, node, this);
+
+ @override
+ EvaluationResultImpl integerDivide(TypeProvider typeProvider, BinaryExpression node, EvaluationResultImpl rightOperand) => rightOperand.integerDivideValid(typeProvider, node, this);
-/**
- * Instances of the class `NumState` represent the state of an object representing a number of
- * an unknown type (a 'num').
- */
-class NumState extends InstanceState {
/**
- * A state that can be used to represent a number whose value is not known.
+ * Return `true` if this object represents an object whose type is 'bool'.
+ *
+ * @return `true` if this object represents a boolean value
*/
- static NumState UNKNOWN_VALUE = new NumState();
+ bool get isBool => value.isBool;
- @override
- NumState add(InstanceState rightOperand) {
- assertNumOrNull(rightOperand);
- return UNKNOWN_VALUE;
- }
+ /**
+ * Return `true` if this object represents an object whose type is either 'bool', 'num',
+ * 'String', or 'Null'.
+ *
+ * @return `true` if this object represents either a boolean, numeric, string or null value
+ */
+ bool get isBoolNumStringOrNull => value.isBoolNumStringOrNull;
+
+ /**
+ * Return `true` if this result represents the value 'false'.
+ *
+ * @return `true` if this result represents the value 'false'
+ */
+ bool get isFalse => value.isFalse;
+
+ /**
+ * Return `true` if this result represents the value 'null'.
+ *
+ * @return `true` if this result represents the value 'null'
+ */
+ bool get isNull => value.isNull;
+
+ /**
+ * Return `true` if this result represents the value 'true'.
+ *
+ * @return `true` if this result represents the value 'true'
+ */
+ bool get isTrue => value.isTrue;
+
+ /**
+ * Return `true` if this object represents an instance of a user-defined class.
+ *
+ * @return `true` if this object represents an instance of a user-defined class
+ */
+ bool get isUserDefinedObject => value.isUserDefinedObject;
@override
- StringState convertToString() => StringState.UNKNOWN_VALUE;
+ EvaluationResultImpl lessThan(TypeProvider typeProvider, BinaryExpression node, EvaluationResultImpl rightOperand) => rightOperand.lessThanValid(typeProvider, node, this);
@override
- NumState divide(InstanceState rightOperand) {
- assertNumOrNull(rightOperand);
- return UNKNOWN_VALUE;
- }
+ EvaluationResultImpl lessThanOrEqual(TypeProvider typeProvider, BinaryExpression node, EvaluationResultImpl rightOperand) => rightOperand.lessThanOrEqualValid(typeProvider, node, this);
@override
- bool operator ==(Object object) => object is NumState;
+ EvaluationResultImpl logicalAnd(TypeProvider typeProvider, BinaryExpression node, EvaluationResultImpl rightOperand) => rightOperand.logicalAndValid(typeProvider, node, this);
@override
- BoolState equalEqual(InstanceState rightOperand) {
- assertBoolNumStringOrNull(rightOperand);
- return BoolState.UNKNOWN_VALUE;
+ EvaluationResultImpl logicalNot(TypeProvider typeProvider, Expression node) {
+ try {
+ return _valueOf(value.logicalNot(typeProvider));
+ } on EvaluationException catch (exception) {
+ return _error(node, exception.errorCode);
+ }
}
@override
- String get typeName => "num";
+ EvaluationResultImpl logicalOr(TypeProvider typeProvider, BinaryExpression node, EvaluationResultImpl rightOperand) => rightOperand.logicalOrValid(typeProvider, node, this);
@override
- BoolState greaterThan(InstanceState rightOperand) {
- assertNumOrNull(rightOperand);
- return BoolState.UNKNOWN_VALUE;
- }
+ EvaluationResultImpl minus(TypeProvider typeProvider, BinaryExpression node, EvaluationResultImpl rightOperand) => rightOperand.minusValid(typeProvider, node, this);
@override
- BoolState greaterThanOrEqual(InstanceState rightOperand) {
- assertNumOrNull(rightOperand);
- return BoolState.UNKNOWN_VALUE;
+ EvaluationResultImpl negated(TypeProvider typeProvider, Expression node) {
+ try {
+ return _valueOf(value.negated(typeProvider));
+ } on EvaluationException catch (exception) {
+ return _error(node, exception.errorCode);
+ }
}
@override
- int get hashCode => 7;
+ EvaluationResultImpl notEqual(TypeProvider typeProvider, BinaryExpression node, EvaluationResultImpl rightOperand) => rightOperand.notEqualValid(typeProvider, node, this);
@override
- IntState integerDivide(InstanceState rightOperand) {
- assertNumOrNull(rightOperand);
- if (rightOperand is IntState) {
- int rightValue = rightOperand.value;
- if (rightValue == null) {
- return IntState.UNKNOWN_VALUE;
- } else if (rightValue == 0) {
- throw new EvaluationException(CompileTimeErrorCode.CONST_EVAL_THROWS_IDBZE);
- }
- } else if (rightOperand is DynamicState) {
- return IntState.UNKNOWN_VALUE;
+ EvaluationResultImpl performToString(TypeProvider typeProvider, AstNode node) {
+ try {
+ return _valueOf(value.performToString(typeProvider));
+ } on EvaluationException catch (exception) {
+ return _error(node, exception.errorCode);
}
- return IntState.UNKNOWN_VALUE;
}
@override
- bool get isBoolNumStringOrNull => true;
+ EvaluationResultImpl remainder(TypeProvider typeProvider, BinaryExpression node, EvaluationResultImpl rightOperand) => rightOperand.remainderValid(typeProvider, node, this);
@override
- BoolState lessThan(InstanceState rightOperand) {
- assertNumOrNull(rightOperand);
- return BoolState.UNKNOWN_VALUE;
- }
+ EvaluationResultImpl shiftLeft(TypeProvider typeProvider, BinaryExpression node, EvaluationResultImpl rightOperand) => rightOperand.shiftLeftValid(typeProvider, node, this);
@override
- BoolState lessThanOrEqual(InstanceState rightOperand) {
- assertNumOrNull(rightOperand);
- return BoolState.UNKNOWN_VALUE;
- }
+ EvaluationResultImpl shiftRight(TypeProvider typeProvider, BinaryExpression node, EvaluationResultImpl rightOperand) => rightOperand.shiftRightValid(typeProvider, node, this);
@override
- NumState minus(InstanceState rightOperand) {
- assertNumOrNull(rightOperand);
- return UNKNOWN_VALUE;
+ EvaluationResultImpl times(TypeProvider typeProvider, BinaryExpression node, EvaluationResultImpl rightOperand) => rightOperand.timesValid(typeProvider, node, this);
+
+ @override
+ String toString() {
+ if (value == null) {
+ return "null";
+ }
+ return value.toString();
}
@override
- NumState negated() => UNKNOWN_VALUE;
+ EvaluationResultImpl addToError(BinaryExpression node, ErrorResult leftOperand) => leftOperand;
@override
- NumState remainder(InstanceState rightOperand) {
- assertNumOrNull(rightOperand);
- return UNKNOWN_VALUE;
+ EvaluationResultImpl addToValid(TypeProvider typeProvider, BinaryExpression node, ValidResult leftOperand) {
+ try {
+ return _valueOf(leftOperand.value.add(typeProvider, value));
+ } on EvaluationException catch (exception) {
+ return _error(node, exception.errorCode);
+ }
}
@override
- NumState times(InstanceState rightOperand) {
- assertNumOrNull(rightOperand);
- return UNKNOWN_VALUE;
+ EvaluationResultImpl bitAndError(BinaryExpression node, ErrorResult leftOperand) => leftOperand;
+
+ @override
+ EvaluationResultImpl bitAndValid(TypeProvider typeProvider, BinaryExpression node, ValidResult leftOperand) {
+ try {
+ return _valueOf(leftOperand.value.bitAnd(typeProvider, value));
+ } on EvaluationException catch (exception) {
+ return _error(node, exception.errorCode);
+ }
}
@override
- String toString() => "-unknown-";
-}
+ EvaluationResultImpl bitOrError(BinaryExpression node, ErrorResult leftOperand) => leftOperand;
-/**
- * Instances of the class `StringState` represent the state of an object representing a
- * string.
- */
-class StringState extends InstanceState {
- /**
- * The value of this instance.
- */
- final String value;
+ @override
+ EvaluationResultImpl bitOrValid(TypeProvider typeProvider, BinaryExpression node, ValidResult leftOperand) {
+ try {
+ return _valueOf(leftOperand.value.bitOr(typeProvider, value));
+ } on EvaluationException catch (exception) {
+ return _error(node, exception.errorCode);
+ }
+ }
- /**
- * A state that can be used to represent a double whose value is not known.
- */
- static StringState UNKNOWN_VALUE = new StringState(null);
+ @override
+ EvaluationResultImpl bitXorError(BinaryExpression node, ErrorResult leftOperand) => leftOperand;
- /**
- * Initialize a newly created state to represent the given value.
- *
- * @param value the value of this instance
- */
- StringState(this.value);
+ @override
+ EvaluationResultImpl bitXorValid(TypeProvider typeProvider, BinaryExpression node, ValidResult leftOperand) {
+ try {
+ return _valueOf(leftOperand.value.bitXor(typeProvider, value));
+ } on EvaluationException catch (exception) {
+ return _error(node, exception.errorCode);
+ }
+ }
@override
- StringState concatenate(InstanceState rightOperand) {
- if (value == null) {
- return UNKNOWN_VALUE;
- }
- if (rightOperand is StringState) {
- String rightValue = rightOperand.value;
- if (rightValue == null) {
- return UNKNOWN_VALUE;
- }
- return new StringState("${value}${rightValue}");
- } else if (rightOperand is DynamicState) {
- return UNKNOWN_VALUE;
+ EvaluationResultImpl concatenateError(Expression node, ErrorResult leftOperand) => leftOperand;
+
+ @override
+ EvaluationResultImpl concatenateValid(TypeProvider typeProvider, Expression node, ValidResult leftOperand) {
+ try {
+ return _valueOf(leftOperand.value.concatenate(typeProvider, value));
+ } on EvaluationException catch (exception) {
+ return _error(node, exception.errorCode);
}
- return super.concatenate(rightOperand);
}
@override
- StringState convertToString() => this;
+ EvaluationResultImpl divideError(BinaryExpression node, ErrorResult leftOperand) => leftOperand;
@override
- BoolState equalEqual(InstanceState rightOperand) {
- assertBoolNumStringOrNull(rightOperand);
- if (value == null) {
- return BoolState.UNKNOWN_VALUE;
+ EvaluationResultImpl divideValid(TypeProvider typeProvider, BinaryExpression node, ValidResult leftOperand) {
+ try {
+ return _valueOf(leftOperand.value.divide(typeProvider, value));
+ } on EvaluationException catch (exception) {
+ return _error(node, exception.errorCode);
}
- if (rightOperand is StringState) {
- String rightValue = rightOperand.value;
- if (rightValue == null) {
- return BoolState.UNKNOWN_VALUE;
- }
- return BoolState.from(value == rightValue);
- } else if (rightOperand is DynamicState) {
- return BoolState.UNKNOWN_VALUE;
+ }
+
+ @override
+ EvaluationResultImpl equalEqualError(Expression node, ErrorResult leftOperand) => leftOperand;
+
+ @override
+ EvaluationResultImpl equalEqualValid(TypeProvider typeProvider, Expression node, ValidResult leftOperand) {
+ try {
+ return _valueOf(leftOperand.value.equalEqual(typeProvider, value));
+ } on EvaluationException catch (exception) {
+ return _error(node, exception.errorCode);
}
- return BoolState.FALSE_STATE;
}
@override
- bool operator ==(Object object) => object is StringState && (value == object.value);
+ EvaluationResultImpl greaterThanError(BinaryExpression node, ErrorResult leftOperand) => leftOperand;
@override
- String get typeName => "String";
+ EvaluationResultImpl greaterThanOrEqualError(BinaryExpression node, ErrorResult leftOperand) => leftOperand;
@override
- bool get hasExactValue => true;
+ EvaluationResultImpl greaterThanOrEqualValid(TypeProvider typeProvider, BinaryExpression node, ValidResult leftOperand) {
+ try {
+ return _valueOf(leftOperand.value.greaterThanOrEqual(typeProvider, value));
+ } on EvaluationException catch (exception) {
+ return _error(node, exception.errorCode);
+ }
+ }
@override
- int get hashCode => value == null ? 0 : value.hashCode;
+ EvaluationResultImpl greaterThanValid(TypeProvider typeProvider, BinaryExpression node, ValidResult leftOperand) {
+ try {
+ return _valueOf(leftOperand.value.greaterThan(typeProvider, value));
+ } on EvaluationException catch (exception) {
+ return _error(node, exception.errorCode);
+ }
+ }
@override
- bool get isBoolNumStringOrNull => true;
+ EvaluationResultImpl integerDivideError(BinaryExpression node, ErrorResult leftOperand) => leftOperand;
@override
- String toString() => value == null ? "-unknown-" : "'${value}'";
-}
+ EvaluationResultImpl integerDivideValid(TypeProvider typeProvider, BinaryExpression node, ValidResult leftOperand) {
+ try {
+ return _valueOf(leftOperand.value.integerDivide(typeProvider, value));
+ } on EvaluationException catch (exception) {
+ return _error(node, exception.errorCode);
+ }
+ }
-/**
- * Instances of the class `StringState` represent the state of an object representing a
- * symbol.
- */
-class SymbolState extends InstanceState {
- /**
- * The value of this instance.
- */
- final String value;
+ @override
+ EvaluationResultImpl lessThanError(BinaryExpression node, ErrorResult leftOperand) => leftOperand;
- /**
- * Initialize a newly created state to represent the given value.
- *
- * @param value the value of this instance
- */
- SymbolState(this.value);
+ @override
+ EvaluationResultImpl lessThanOrEqualError(BinaryExpression node, ErrorResult leftOperand) => leftOperand;
@override
- StringState convertToString() {
- if (value == null) {
- return StringState.UNKNOWN_VALUE;
+ EvaluationResultImpl lessThanOrEqualValid(TypeProvider typeProvider, BinaryExpression node, ValidResult leftOperand) {
+ try {
+ return _valueOf(leftOperand.value.lessThanOrEqual(typeProvider, value));
+ } on EvaluationException catch (exception) {
+ return _error(node, exception.errorCode);
}
- return new StringState(value);
}
@override
- BoolState equalEqual(InstanceState rightOperand) {
- assertBoolNumStringOrNull(rightOperand);
- if (value == null) {
- return BoolState.UNKNOWN_VALUE;
- }
- if (rightOperand is SymbolState) {
- String rightValue = rightOperand.value;
- if (rightValue == null) {
- return BoolState.UNKNOWN_VALUE;
- }
- return BoolState.from(value == rightValue);
- } else if (rightOperand is DynamicState) {
- return BoolState.UNKNOWN_VALUE;
+ EvaluationResultImpl lessThanValid(TypeProvider typeProvider, BinaryExpression node, ValidResult leftOperand) {
+ try {
+ return _valueOf(leftOperand.value.lessThan(typeProvider, value));
+ } on EvaluationException catch (exception) {
+ return _error(node, exception.errorCode);
}
- return BoolState.FALSE_STATE;
}
@override
- bool operator ==(Object object) => object is SymbolState && (value == object.value);
+ EvaluationResultImpl logicalAndError(BinaryExpression node, ErrorResult leftOperand) => leftOperand;
@override
- String get typeName => "Symbol";
+ EvaluationResultImpl logicalAndValid(TypeProvider typeProvider, BinaryExpression node, ValidResult leftOperand) {
+ try {
+ return _valueOf(leftOperand.value.logicalAnd(typeProvider, value));
+ } on EvaluationException catch (exception) {
+ return _error(node, exception.errorCode);
+ }
+ }
@override
- bool get hasExactValue => true;
+ EvaluationResultImpl logicalOrError(BinaryExpression node, ErrorResult leftOperand) => leftOperand;
@override
- int get hashCode => value == null ? 0 : value.hashCode;
+ EvaluationResultImpl logicalOrValid(TypeProvider typeProvider, BinaryExpression node, ValidResult leftOperand) {
+ try {
+ return _valueOf(leftOperand.value.logicalOr(typeProvider, value));
+ } on EvaluationException catch (exception) {
+ return _error(node, exception.errorCode);
+ }
+ }
@override
- String toString() => value == null ? "-unknown-" : "#${value}";
-}
+ EvaluationResultImpl minusError(BinaryExpression node, ErrorResult leftOperand) => leftOperand;
-/**
- * Instances of the class `TypeState` represent the state of an object representing a type.
- */
-class TypeState extends InstanceState {
- /**
- * The element representing the type being modeled.
- */
- final Element _element;
+ @override
+ EvaluationResultImpl minusValid(TypeProvider typeProvider, BinaryExpression node, ValidResult leftOperand) {
+ try {
+ return _valueOf(leftOperand.value.minus(typeProvider, value));
+ } on EvaluationException catch (exception) {
+ return _error(node, exception.errorCode);
+ }
+ }
- /**
- * Initialize a newly created state to represent the given value.
- *
- * @param element the element representing the type being modeled
- */
- TypeState(this._element);
+ @override
+ EvaluationResultImpl notEqualError(BinaryExpression node, ErrorResult leftOperand) => leftOperand;
@override
- StringState convertToString() {
- if (_element == null) {
- return StringState.UNKNOWN_VALUE;
+ EvaluationResultImpl notEqualValid(TypeProvider typeProvider, BinaryExpression node, ValidResult leftOperand) {
+ try {
+ return _valueOf(leftOperand.value.notEqual(typeProvider, value));
+ } on EvaluationException catch (exception) {
+ return _error(node, exception.errorCode);
}
- return new StringState(_element.name);
}
@override
- bool operator ==(Object object) => object is TypeState && (_element == object._element);
+ EvaluationResultImpl remainderError(BinaryExpression node, ErrorResult leftOperand) => leftOperand;
@override
- BoolState equalEqual(InstanceState rightOperand) {
- assertBoolNumStringOrNull(rightOperand);
- if (_element == null) {
- return BoolState.UNKNOWN_VALUE;
+ EvaluationResultImpl remainderValid(TypeProvider typeProvider, BinaryExpression node, ValidResult leftOperand) {
+ try {
+ return _valueOf(leftOperand.value.remainder(typeProvider, value));
+ } on EvaluationException catch (exception) {
+ return _error(node, exception.errorCode);
}
- if (rightOperand is TypeState) {
- Element rightElement = rightOperand._element;
- if (rightElement == null) {
- return BoolState.UNKNOWN_VALUE;
- }
- return BoolState.from(_element == rightElement);
- } else if (rightOperand is DynamicState) {
- return BoolState.UNKNOWN_VALUE;
+ }
+
+ @override
+ EvaluationResultImpl shiftLeftError(BinaryExpression node, ErrorResult leftOperand) => leftOperand;
+
+ @override
+ EvaluationResultImpl shiftLeftValid(TypeProvider typeProvider, BinaryExpression node, ValidResult leftOperand) {
+ try {
+ return _valueOf(leftOperand.value.shiftLeft(typeProvider, value));
+ } on EvaluationException catch (exception) {
+ return _error(node, exception.errorCode);
}
- return BoolState.FALSE_STATE;
}
@override
- String get typeName => "Type";
+ EvaluationResultImpl shiftRightError(BinaryExpression node, ErrorResult leftOperand) => leftOperand;
@override
- int get hashCode => _element == null ? 0 : _element.hashCode;
+ EvaluationResultImpl shiftRightValid(TypeProvider typeProvider, BinaryExpression node, ValidResult leftOperand) {
+ try {
+ return _valueOf(leftOperand.value.shiftRight(typeProvider, value));
+ } on EvaluationException catch (exception) {
+ return _error(node, exception.errorCode);
+ }
+ }
@override
- String toString() => _element == null ? "-unknown-" : _element.name;
+ EvaluationResultImpl timesError(BinaryExpression node, ErrorResult leftOperand) => leftOperand;
+
+ @override
+ EvaluationResultImpl timesValid(TypeProvider typeProvider, BinaryExpression node, ValidResult leftOperand) {
+ try {
+ return _valueOf(leftOperand.value.times(typeProvider, value));
+ } on EvaluationException catch (exception) {
+ return _error(node, exception.errorCode);
+ }
+ }
+
+ /**
+ * Return a result object representing an error associated with the given node.
+ *
+ * @param node the AST node associated with the error
+ * @param code the error code indicating the nature of the error
+ * @return a result object representing an error associated with the given node
+ */
+ ErrorResult _error(AstNode node, ErrorCode code) => new ErrorResult.con1(node, code);
+
+ /**
+ * 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(DartObjectImpl value) => new ValidResult(value);
}

Powered by Google App Engine
This is Rietveld 408576698