Index: analyzer/lib/src/generated/constant.dart |
diff --git a/analyzer/lib/src/generated/constant.dart b/analyzer/lib/src/generated/constant.dart |
deleted file mode 100644 |
index 572caab8e0fff2200e8ff794b35ed9de9155d7d0..0000000000000000000000000000000000000000 |
--- a/analyzer/lib/src/generated/constant.dart |
+++ /dev/null |
@@ -1,5281 +0,0 @@ |
-// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file |
-// for details. All rights reserved. Use of this source code is governed by a |
-// BSD-style license that can be found in the LICENSE file. |
- |
-// This code was auto-generated, is not intended to be edited, and is subject to |
-// significant change. Please see the README file for more information. |
- |
-library engine.constant; |
- |
-import 'dart:collection'; |
- |
-import 'package:analyzer/src/generated/engine.dart'; |
-import 'package:analyzer/src/generated/utilities_general.dart'; |
-import 'package:analyzer/src/task/dart.dart'; |
- |
-import 'ast.dart'; |
-import 'element.dart'; |
-import 'engine.dart' show AnalysisEngine, RecordingErrorListener; |
-import 'error.dart'; |
-import 'java_core.dart'; |
-import 'resolver.dart' show TypeProvider, TypeSystem, TypeSystemImpl; |
-import 'scanner.dart' show Token, TokenType; |
-import 'source.dart' show Source; |
-import 'utilities_collection.dart'; |
-import 'utilities_dart.dart' show ParameterKind; |
- |
-/** |
- * Callback used by [ReferenceFinder] to report that a dependency was found. |
- */ |
-typedef void ReferenceFinderCallback(ConstantEvaluationTarget dependency); |
- |
-/** |
- * The state of an object representing a boolean value. |
- */ |
-class BoolState extends InstanceState { |
- /** |
- * 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); |
- |
- /** |
- * The value of this instance. |
- */ |
- final bool value; |
- |
- /** |
- * Initialize a newly created state to represent the given [value]. |
- */ |
- BoolState(this.value); |
- |
- @override |
- bool get hasExactValue => true; |
- |
- @override |
- int get hashCode => value == null ? 0 : (value ? 2 : 3); |
- |
- @override |
- bool get isBool => true; |
- |
- @override |
- bool get isBoolNumStringOrNull => true; |
- |
- @override |
- bool get isUnknown => value == null; |
- |
- @override |
- String get typeName => "bool"; |
- |
- @override |
- bool operator ==(Object object) => |
- object is BoolState && identical(value, object.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); |
- return isIdentical(rightOperand); |
- } |
- |
- @override |
- BoolState isIdentical(InstanceState 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 |
- 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"); |
- |
- /** |
- * Return the boolean state representing the given boolean [value]. |
- */ |
- static BoolState from(bool value) => |
- value ? BoolState.TRUE_STATE : BoolState.FALSE_STATE; |
-} |
- |
-/** |
- * An [AstCloner] that copies the necessary information from the AST to allow |
- * constants to be evaluated. |
- */ |
-class ConstantAstCloner extends AstCloner { |
- ConstantAstCloner() : super(true); |
- |
- @override |
- InstanceCreationExpression visitInstanceCreationExpression( |
- InstanceCreationExpression node) { |
- InstanceCreationExpression expression = |
- super.visitInstanceCreationExpression(node); |
- expression.staticElement = node.staticElement; |
- return expression; |
- } |
- |
- @override |
- RedirectingConstructorInvocation visitRedirectingConstructorInvocation( |
- RedirectingConstructorInvocation node) { |
- RedirectingConstructorInvocation invocation = |
- super.visitRedirectingConstructorInvocation(node); |
- invocation.staticElement = node.staticElement; |
- return invocation; |
- } |
- |
- @override |
- SimpleIdentifier visitSimpleIdentifier(SimpleIdentifier node) { |
- SimpleIdentifier identifier = super.visitSimpleIdentifier(node); |
- identifier.staticElement = node.staticElement; |
- return identifier; |
- } |
- |
- @override |
- SuperConstructorInvocation visitSuperConstructorInvocation( |
- SuperConstructorInvocation node) { |
- SuperConstructorInvocation invocation = |
- super.visitSuperConstructorInvocation(node); |
- invocation.staticElement = node.staticElement; |
- return invocation; |
- } |
-} |
- |
-/** |
- * Helper class encapsulating the methods for evaluating constants and |
- * constant instance creation expressions. |
- */ |
-class ConstantEvaluationEngine { |
- /** |
- * Parameter to "fromEnvironment" methods that denotes the default value. |
- */ |
- static String _DEFAULT_VALUE_PARAM = "defaultValue"; |
- |
- /** |
- * Source of RegExp matching any public identifier. |
- * From sdk/lib/internal/symbol.dart. |
- */ |
- static String _PUBLIC_IDENTIFIER_RE = |
- "(?!${ConstantValueComputer._RESERVED_WORD_RE}\\b(?!\\\$))[a-zA-Z\$][\\w\$]*"; |
- |
- /** |
- * RegExp that validates a non-empty non-private symbol. |
- * From sdk/lib/internal/symbol.dart. |
- */ |
- static RegExp _PUBLIC_SYMBOL_PATTERN = new RegExp( |
- "^(?:${ConstantValueComputer._OPERATOR_RE}\$|$_PUBLIC_IDENTIFIER_RE(?:=?\$|[.](?!\$)))+?\$"); |
- |
- /** |
- * The type system. This is used to gues the types of constants when their |
- * exact value is unknown. |
- */ |
- final TypeSystem typeSystem; |
- |
- /** |
- * The set of variables declared on the command line using '-D'. |
- */ |
- final DeclaredVariables _declaredVariables; |
- |
- /** |
- * Validator used to verify correct dependency analysis when running unit |
- * tests. |
- */ |
- final ConstantEvaluationValidator validator; |
- |
- /** |
- * Initialize a newly created [ConstantEvaluationEngine]. The [typeProvider] |
- * is used to access known types. [_declaredVariables] is the set of |
- * variables declared on the command line using '-D'. The [validator], if |
- * given, is used to verify correct dependency analysis when running unit |
- * tests. |
- */ |
- ConstantEvaluationEngine(TypeProvider typeProvider, this._declaredVariables, |
- {ConstantEvaluationValidator validator}) |
- : validator = validator != null |
- ? validator |
- : new ConstantEvaluationValidator_ForProduction(), |
- typeSystem = new TypeSystemImpl(typeProvider); |
- |
- /** |
- * The type provider used to access the known types. |
- */ |
- TypeProvider get typeProvider => typeSystem.typeProvider; |
- |
- /** |
- * Check that the arguments to a call to fromEnvironment() are correct. The |
- * [arguments] are the AST nodes of the arguments. The [argumentValues] are |
- * the values of the unnamed arguments. The [namedArgumentValues] are the |
- * values of the named arguments. The [expectedDefaultValueType] is the |
- * allowed type of the "defaultValue" parameter (if present). Note: |
- * "defaultValue" is always allowed to be null. Return `true` if the arguments |
- * are correct, `false` if there is an error. |
- */ |
- bool checkFromEnvironmentArguments(NodeList<Expression> arguments, |
- List<DartObjectImpl> argumentValues, |
- HashMap<String, DartObjectImpl> namedArgumentValues, |
- InterfaceType expectedDefaultValueType) { |
- int argumentCount = arguments.length; |
- if (argumentCount < 1 || argumentCount > 2) { |
- return false; |
- } |
- if (arguments[0] is NamedExpression) { |
- return false; |
- } |
- if (!identical(argumentValues[0].type, typeProvider.stringType)) { |
- return false; |
- } |
- if (argumentCount == 2) { |
- if (arguments[1] is! NamedExpression) { |
- return false; |
- } |
- if (!((arguments[1] as NamedExpression).name.label.name == |
- _DEFAULT_VALUE_PARAM)) { |
- return false; |
- } |
- ParameterizedType defaultValueType = |
- namedArgumentValues[_DEFAULT_VALUE_PARAM].type; |
- if (!(identical(defaultValueType, expectedDefaultValueType) || |
- identical(defaultValueType, typeProvider.nullType))) { |
- return false; |
- } |
- } |
- return true; |
- } |
- |
- /** |
- * Check that the arguments to a call to Symbol() are correct. The [arguments] |
- * are the AST nodes of the arguments. The [argumentValues] are the values of |
- * the unnamed arguments. The [namedArgumentValues] are the values of the |
- * named arguments. Return `true` if the arguments are correct, `false` if |
- * there is an error. |
- */ |
- bool checkSymbolArguments(NodeList<Expression> arguments, |
- List<DartObjectImpl> argumentValues, |
- HashMap<String, DartObjectImpl> namedArgumentValues) { |
- if (arguments.length != 1) { |
- return false; |
- } |
- if (arguments[0] is NamedExpression) { |
- return false; |
- } |
- if (!identical(argumentValues[0].type, typeProvider.stringType)) { |
- return false; |
- } |
- String name = argumentValues[0].stringValue; |
- return isValidPublicSymbol(name); |
- } |
- |
- /** |
- * Compute the constant value associated with the given [constant]. |
- */ |
- void computeConstantValue(ConstantEvaluationTarget constant) { |
- validator.beforeComputeValue(constant); |
- if (constant is ParameterElement) { |
- if (constant.initializer != null) { |
- Expression defaultValue = |
- (constant as PotentiallyConstVariableElement).constantInitializer; |
- if (defaultValue != null) { |
- RecordingErrorListener errorListener = new RecordingErrorListener(); |
- ErrorReporter errorReporter = |
- new ErrorReporter(errorListener, constant.source); |
- DartObjectImpl dartObject = |
- defaultValue.accept(new ConstantVisitor(this, errorReporter)); |
- (constant as ParameterElementImpl).evaluationResult = |
- new EvaluationResultImpl(dartObject, errorListener.errors); |
- } |
- } |
- } else if (constant is VariableElement) { |
- Expression constantInitializer = |
- (constant as PotentiallyConstVariableElement).constantInitializer; |
- if (constantInitializer != null) { |
- RecordingErrorListener errorListener = new RecordingErrorListener(); |
- ErrorReporter errorReporter = |
- new ErrorReporter(errorListener, constant.source); |
- DartObjectImpl dartObject = constantInitializer |
- .accept(new ConstantVisitor(this, errorReporter)); |
- // Only check the type for truly const declarations (don't check final |
- // fields with initializers, since their types may be generic. The type |
- // of the final field will be checked later, when the constructor is |
- // invoked). |
- if (dartObject != null && constant.isConst) { |
- if (!runtimeTypeMatch(dartObject, constant.type)) { |
- errorReporter.reportErrorForElement( |
- CheckedModeCompileTimeErrorCode.VARIABLE_TYPE_MISMATCH, |
- constant, [dartObject.type, constant.type]); |
- } |
- } |
- (constant as VariableElementImpl).evaluationResult = |
- new EvaluationResultImpl(dartObject, errorListener.errors); |
- } |
- } else if (constant is ConstructorElement) { |
- if (constant.isConst) { |
- // No evaluation needs to be done; constructor declarations are only in |
- // the dependency graph to ensure that any constants referred to in |
- // initializer lists and parameter defaults are evaluated before |
- // invocations of the constructor. However we do need to annotate the |
- // element as being free of constant evaluation cycles so that later |
- // code will know that it is safe to evaluate. |
- (constant as ConstructorElementImpl).isCycleFree = true; |
- } |
- } else if (constant is ConstantEvaluationTarget_Annotation) { |
- Annotation constNode = constant.annotation; |
- ElementAnnotationImpl elementAnnotation = constNode.elementAnnotation; |
- // elementAnnotation is null if the annotation couldn't be resolved, in |
- // which case we skip it. |
- if (elementAnnotation != null) { |
- Element element = elementAnnotation.element; |
- if (element is PropertyAccessorElement && |
- element.variable is VariableElementImpl) { |
- // The annotation is a reference to a compile-time constant variable. |
- // Just copy the evaluation result. |
- VariableElementImpl variableElement = |
- element.variable as VariableElementImpl; |
- if (variableElement.evaluationResult != null) { |
- elementAnnotation.evaluationResult = |
- variableElement.evaluationResult; |
- } else { |
- // This could happen in the event that the annotation refers to a |
- // non-constant. The error is detected elsewhere, so just silently |
- // ignore it here. |
- elementAnnotation.evaluationResult = new EvaluationResultImpl(null); |
- } |
- } else if (element is ConstructorElementImpl && |
- element.isConst && |
- constNode.arguments != null) { |
- RecordingErrorListener errorListener = new RecordingErrorListener(); |
- CompilationUnit sourceCompilationUnit = |
- constNode.getAncestor((node) => node is CompilationUnit); |
- ErrorReporter errorReporter = new ErrorReporter( |
- errorListener, sourceCompilationUnit.element.source); |
- ConstantVisitor constantVisitor = |
- new ConstantVisitor(this, errorReporter); |
- DartObjectImpl result = evaluateConstructorCall(constNode, |
- constNode.arguments.arguments, element, constantVisitor, |
- errorReporter); |
- elementAnnotation.evaluationResult = |
- new EvaluationResultImpl(result, errorListener.errors); |
- } else { |
- // This may happen for invalid code (e.g. failing to pass arguments |
- // to an annotation which references a const constructor). The error |
- // is detected elsewhere, so just silently ignore it here. |
- elementAnnotation.evaluationResult = new EvaluationResultImpl(null); |
- } |
- } |
- } else { |
- // Should not happen. |
- assert(false); |
- AnalysisEngine.instance.logger.logError( |
- "Constant value computer trying to compute the value of a node of type ${constant.runtimeType}"); |
- return; |
- } |
- } |
- |
- /** |
- * Determine which constant elements need to have their values computed |
- * prior to computing the value of [constant], and report them using |
- * [callback]. |
- * |
- * Note that it's possible (in erroneous code) for a constant to depend on a |
- * non-constant. When this happens, we report the dependency anyhow so that |
- * if the non-constant changes to a constant, we will know to recompute the |
- * thing that depends on it. [computeDependencies] and |
- * [computeConstantValue] are responsible for ignoring the request if they |
- * are asked to act on a non-constant target. |
- */ |
- void computeDependencies( |
- ConstantEvaluationTarget constant, ReferenceFinderCallback callback) { |
- ReferenceFinder referenceFinder = new ReferenceFinder(callback); |
- if (constant is ParameterElement) { |
- if (constant.initializer != null) { |
- Expression defaultValue = |
- (constant as ConstVariableElement).constantInitializer; |
- if (defaultValue != null) { |
- defaultValue.accept(referenceFinder); |
- } |
- } |
- } else if (constant is PotentiallyConstVariableElement) { |
- Expression initializer = constant.constantInitializer; |
- if (initializer != null) { |
- initializer.accept(referenceFinder); |
- } |
- } else if (constant is ConstructorElementImpl) { |
- if (constant.isConst) { |
- constant.isCycleFree = false; |
- ConstructorElement redirectedConstructor = |
- getConstRedirectedConstructor(constant); |
- if (redirectedConstructor != null) { |
- ConstructorElement redirectedConstructorBase = |
- ConstantEvaluationEngine |
- ._getConstructorBase(redirectedConstructor); |
- callback(redirectedConstructorBase); |
- return; |
- } else if (constant.isFactory) { |
- // Factory constructor, but getConstRedirectedConstructor returned |
- // null. This can happen if we're visiting one of the special external |
- // const factory constructors in the SDK, or if the code contains |
- // errors (such as delegating to a non-const constructor, or delegating |
- // to a constructor that can't be resolved). In any of these cases, |
- // we'll evaluate calls to this constructor without having to refer to |
- // any other constants. So we don't need to report any dependencies. |
- return; |
- } |
- bool superInvocationFound = false; |
- List<ConstructorInitializer> initializers = |
- constant.constantInitializers; |
- for (ConstructorInitializer initializer in initializers) { |
- if (initializer is SuperConstructorInvocation) { |
- superInvocationFound = true; |
- } |
- initializer.accept(referenceFinder); |
- } |
- if (!superInvocationFound) { |
- // No explicit superconstructor invocation found, so we need to |
- // manually insert a reference to the implicit superconstructor. |
- InterfaceType superclass = |
- (constant.returnType as InterfaceType).superclass; |
- if (superclass != null && !superclass.isObject) { |
- ConstructorElement unnamedConstructor = ConstantEvaluationEngine |
- ._getConstructorBase(superclass.element.unnamedConstructor); |
- if (unnamedConstructor != null) { |
- callback(unnamedConstructor); |
- } |
- } |
- } |
- for (FieldElement field in constant.enclosingElement.fields) { |
- // Note: non-static const isn't allowed but we handle it anyway so |
- // that we won't be confused by incorrect code. |
- if ((field.isFinal || field.isConst) && |
- !field.isStatic && |
- field.initializer != null) { |
- callback(field); |
- } |
- } |
- for (ParameterElement parameterElement in constant.parameters) { |
- callback(parameterElement); |
- } |
- } |
- } else if (constant is ConstantEvaluationTarget_Annotation) { |
- Annotation constNode = constant.annotation; |
- ElementAnnotationImpl elementAnnotation = constNode.elementAnnotation; |
- // elementAnnotation is null if the annotation couldn't be resolved, in |
- // which case we skip it. |
- if (elementAnnotation != null) { |
- Element element = elementAnnotation.element; |
- if (element is PropertyAccessorElement && |
- element.variable is VariableElementImpl) { |
- // The annotation is a reference to a compile-time constant variable, |
- // so it depends on the variable. |
- callback(element.variable); |
- } else if (element is ConstructorElementImpl) { |
- // The annotation is a constructor invocation, so it depends on the |
- // constructor. |
- callback(element); |
- } else { |
- // This could happen in the event of invalid code. The error will be |
- // reported at constant evaluation time. |
- } |
- } |
- if (constNode.arguments != null) { |
- constNode.arguments.accept(referenceFinder); |
- } |
- } else { |
- // Should not happen. |
- assert(false); |
- AnalysisEngine.instance.logger.logError( |
- "Constant value computer trying to compute the value of a node of type ${constant.runtimeType}"); |
- } |
- } |
- |
- /** |
- * Evaluate a call to fromEnvironment() on the bool, int, or String class. The |
- * [environmentValue] is the value fetched from the environment. The |
- * [builtInDefaultValue] is the value that should be used as the default if no |
- * "defaultValue" argument appears in [namedArgumentValues]. The |
- * [namedArgumentValues] are the values of the named parameters passed to |
- * fromEnvironment(). Return a [DartObjectImpl] object corresponding to the |
- * evaluated result. |
- */ |
- DartObjectImpl computeValueFromEnvironment(DartObject environmentValue, |
- DartObjectImpl builtInDefaultValue, |
- HashMap<String, DartObjectImpl> namedArgumentValues) { |
- DartObjectImpl value = environmentValue as DartObjectImpl; |
- if (value.isUnknown || value.isNull) { |
- // The name either doesn't exist in the environment or we couldn't parse |
- // the corresponding value. |
- // If the code supplied an explicit default, use it. |
- if (namedArgumentValues.containsKey(_DEFAULT_VALUE_PARAM)) { |
- value = namedArgumentValues[_DEFAULT_VALUE_PARAM]; |
- } else if (value.isNull) { |
- // The code didn't supply an explicit default. |
- // The name exists in the environment but we couldn't parse the |
- // corresponding value. |
- // So use the built-in default value, because this is what the VM does. |
- value = builtInDefaultValue; |
- } else { |
- // The code didn't supply an explicit default. |
- // The name doesn't exist in the environment. |
- // The VM would use the built-in default value, but we don't want to do |
- // that for analysis because it's likely to lead to cascading errors. |
- // So just leave [value] in the unknown state. |
- } |
- } |
- return value; |
- } |
- |
- DartObjectImpl evaluateConstructorCall(AstNode node, |
- NodeList<Expression> arguments, ConstructorElement constructor, |
- ConstantVisitor constantVisitor, ErrorReporter errorReporter) { |
- if (!_getConstructorBase(constructor).isCycleFree) { |
- // It's not safe to evaluate this constructor, so bail out. |
- // TODO(paulberry): ensure that a reasonable error message is produced |
- // in this case, as well as other cases involving constant expression |
- // circularities (e.g. "compile-time constant expression depends on |
- // itself") |
- return new DartObjectImpl.validWithUnknownValue(constructor.returnType); |
- } |
- int argumentCount = arguments.length; |
- List<DartObjectImpl> argumentValues = |
- new List<DartObjectImpl>(argumentCount); |
- List<Expression> argumentNodes = new List<Expression>(argumentCount); |
- HashMap<String, DartObjectImpl> namedArgumentValues = |
- new HashMap<String, DartObjectImpl>(); |
- HashMap<String, NamedExpression> namedArgumentNodes = |
- new HashMap<String, NamedExpression>(); |
- for (int i = 0; i < argumentCount; i++) { |
- Expression argument = arguments[i]; |
- if (argument is NamedExpression) { |
- String name = argument.name.label.name; |
- namedArgumentValues[name] = |
- constantVisitor._valueOf(argument.expression); |
- namedArgumentNodes[name] = argument; |
- argumentValues[i] = typeProvider.nullObject; |
- } else { |
- argumentValues[i] = constantVisitor._valueOf(argument); |
- argumentNodes[i] = argument; |
- } |
- } |
- constructor = followConstantRedirectionChain(constructor); |
- InterfaceType definingClass = constructor.returnType as InterfaceType; |
- if (constructor.isFactory) { |
- // We couldn't find a non-factory constructor. |
- // See if it's because we reached an external const factory constructor |
- // that we can emulate. |
- if (constructor.name == "fromEnvironment") { |
- if (!checkFromEnvironmentArguments( |
- arguments, argumentValues, namedArgumentValues, definingClass)) { |
- errorReporter.reportErrorForNode( |
- CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION, node); |
- return null; |
- } |
- String variableName = |
- argumentCount < 1 ? null : argumentValues[0].stringValue; |
- if (identical(definingClass, typeProvider.boolType)) { |
- DartObject valueFromEnvironment; |
- valueFromEnvironment = |
- _declaredVariables.getBool(typeProvider, variableName); |
- return computeValueFromEnvironment(valueFromEnvironment, |
- new DartObjectImpl(typeProvider.boolType, BoolState.FALSE_STATE), |
- namedArgumentValues); |
- } else if (identical(definingClass, typeProvider.intType)) { |
- DartObject valueFromEnvironment; |
- valueFromEnvironment = |
- _declaredVariables.getInt(typeProvider, variableName); |
- return computeValueFromEnvironment(valueFromEnvironment, |
- new DartObjectImpl(typeProvider.nullType, NullState.NULL_STATE), |
- namedArgumentValues); |
- } else if (identical(definingClass, typeProvider.stringType)) { |
- DartObject valueFromEnvironment; |
- valueFromEnvironment = |
- _declaredVariables.getString(typeProvider, variableName); |
- return computeValueFromEnvironment(valueFromEnvironment, |
- new DartObjectImpl(typeProvider.nullType, NullState.NULL_STATE), |
- namedArgumentValues); |
- } |
- } else if (constructor.name == "" && |
- identical(definingClass, typeProvider.symbolType) && |
- argumentCount == 1) { |
- if (!checkSymbolArguments( |
- arguments, argumentValues, namedArgumentValues)) { |
- errorReporter.reportErrorForNode( |
- CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION, node); |
- return null; |
- } |
- String argumentValue = argumentValues[0].stringValue; |
- return new DartObjectImpl( |
- definingClass, new SymbolState(argumentValue)); |
- } |
- // Either it's an external const factory constructor that we can't |
- // emulate, or an error occurred (a cycle, or a const constructor trying |
- // to delegate to a non-const constructor). |
- // In the former case, the best we can do is consider it an unknown value. |
- // In the latter case, the error has already been reported, so considering |
- // it an unknown value will suppress further errors. |
- return new DartObjectImpl.validWithUnknownValue(definingClass); |
- } |
- ConstructorElementImpl constructorBase = _getConstructorBase(constructor); |
- validator.beforeGetConstantInitializers(constructorBase); |
- List<ConstructorInitializer> initializers = |
- constructorBase.constantInitializers; |
- if (initializers == null) { |
- // This can happen in some cases where there are compile errors in the |
- // code being analyzed (for example if the code is trying to create a |
- // const instance using a non-const constructor, or the node we're |
- // visiting is involved in a cycle). The error has already been reported, |
- // so consider it an unknown value to suppress further errors. |
- return new DartObjectImpl.validWithUnknownValue(definingClass); |
- } |
- HashMap<String, DartObjectImpl> fieldMap = |
- new HashMap<String, DartObjectImpl>(); |
- // Start with final fields that are initialized at their declaration site. |
- for (FieldElement field in constructor.enclosingElement.fields) { |
- if ((field.isFinal || field.isConst) && |
- !field.isStatic && |
- field is ConstFieldElementImpl) { |
- validator.beforeGetFieldEvaluationResult(field); |
- EvaluationResultImpl evaluationResult = field.evaluationResult; |
- DartType fieldType = |
- FieldMember.from(field, constructor.returnType).type; |
- DartObjectImpl fieldValue = evaluationResult.value; |
- if (fieldValue != null && !runtimeTypeMatch(fieldValue, fieldType)) { |
- errorReporter.reportErrorForNode( |
- CheckedModeCompileTimeErrorCode.CONST_CONSTRUCTOR_FIELD_TYPE_MISMATCH, |
- node, [fieldValue.type, field.name, fieldType]); |
- } |
- fieldMap[field.name] = evaluationResult.value; |
- } |
- } |
- // Now evaluate the constructor declaration. |
- HashMap<String, DartObjectImpl> parameterMap = |
- new HashMap<String, DartObjectImpl>(); |
- List<ParameterElement> parameters = constructor.parameters; |
- int parameterCount = parameters.length; |
- for (int i = 0; i < parameterCount; i++) { |
- ParameterElement parameter = parameters[i]; |
- ParameterElement baseParameter = parameter; |
- while (baseParameter is ParameterMember) { |
- baseParameter = (baseParameter as ParameterMember).baseElement; |
- } |
- DartObjectImpl argumentValue = null; |
- AstNode errorTarget = null; |
- if (baseParameter.parameterKind == ParameterKind.NAMED) { |
- argumentValue = namedArgumentValues[baseParameter.name]; |
- errorTarget = namedArgumentNodes[baseParameter.name]; |
- } else if (i < argumentCount) { |
- argumentValue = argumentValues[i]; |
- errorTarget = argumentNodes[i]; |
- } |
- if (errorTarget == null) { |
- // No argument node that we can direct error messages to, because we |
- // are handling an optional parameter that wasn't specified. So just |
- // direct error messages to the constructor call. |
- errorTarget = node; |
- } |
- if (argumentValue == null && baseParameter is ParameterElementImpl) { |
- // The parameter is an optional positional parameter for which no value |
- // was provided, so use the default value. |
- validator.beforeGetParameterDefault(baseParameter); |
- EvaluationResultImpl evaluationResult = baseParameter.evaluationResult; |
- if (evaluationResult == null) { |
- // No default was provided, so the default value is null. |
- argumentValue = typeProvider.nullObject; |
- } else if (evaluationResult.value != null) { |
- argumentValue = evaluationResult.value; |
- } |
- } |
- if (argumentValue != null) { |
- if (!runtimeTypeMatch(argumentValue, parameter.type)) { |
- errorReporter.reportErrorForNode( |
- CheckedModeCompileTimeErrorCode.CONST_CONSTRUCTOR_PARAM_TYPE_MISMATCH, |
- errorTarget, [argumentValue.type, parameter.type]); |
- } |
- if (baseParameter.isInitializingFormal) { |
- FieldElement field = (parameter as FieldFormalParameterElement).field; |
- if (field != null) { |
- DartType fieldType = field.type; |
- if (fieldType != parameter.type) { |
- // We've already checked that the argument can be assigned to the |
- // parameter; we also need to check that it can be assigned to |
- // the field. |
- if (!runtimeTypeMatch(argumentValue, fieldType)) { |
- errorReporter.reportErrorForNode( |
- CheckedModeCompileTimeErrorCode.CONST_CONSTRUCTOR_PARAM_TYPE_MISMATCH, |
- errorTarget, [argumentValue.type, fieldType]); |
- } |
- } |
- String fieldName = field.name; |
- if (fieldMap.containsKey(fieldName)) { |
- errorReporter.reportErrorForNode( |
- CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION, node); |
- } |
- fieldMap[fieldName] = argumentValue; |
- } |
- } else { |
- String name = baseParameter.name; |
- parameterMap[name] = argumentValue; |
- } |
- } |
- } |
- ConstantVisitor initializerVisitor = new ConstantVisitor( |
- this, errorReporter, lexicalEnvironment: parameterMap); |
- String superName = null; |
- NodeList<Expression> superArguments = null; |
- for (ConstructorInitializer initializer in initializers) { |
- if (initializer is ConstructorFieldInitializer) { |
- ConstructorFieldInitializer constructorFieldInitializer = initializer; |
- Expression initializerExpression = |
- constructorFieldInitializer.expression; |
- DartObjectImpl evaluationResult = |
- initializerExpression.accept(initializerVisitor); |
- if (evaluationResult != null) { |
- String fieldName = constructorFieldInitializer.fieldName.name; |
- if (fieldMap.containsKey(fieldName)) { |
- errorReporter.reportErrorForNode( |
- CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION, node); |
- } |
- fieldMap[fieldName] = evaluationResult; |
- PropertyAccessorElement getter = definingClass.getGetter(fieldName); |
- if (getter != null) { |
- PropertyInducingElement field = getter.variable; |
- if (!runtimeTypeMatch(evaluationResult, field.type)) { |
- errorReporter.reportErrorForNode( |
- CheckedModeCompileTimeErrorCode.CONST_CONSTRUCTOR_FIELD_TYPE_MISMATCH, |
- node, [evaluationResult.type, fieldName, field.type]); |
- } |
- } |
- } |
- } else if (initializer is SuperConstructorInvocation) { |
- SuperConstructorInvocation superConstructorInvocation = initializer; |
- SimpleIdentifier name = superConstructorInvocation.constructorName; |
- if (name != null) { |
- superName = name.name; |
- } |
- superArguments = superConstructorInvocation.argumentList.arguments; |
- } else if (initializer is RedirectingConstructorInvocation) { |
- // This is a redirecting constructor, so just evaluate the constructor |
- // it redirects to. |
- ConstructorElement constructor = initializer.staticElement; |
- if (constructor != null && constructor.isConst) { |
- return evaluateConstructorCall(node, |
- initializer.argumentList.arguments, constructor, |
- initializerVisitor, errorReporter); |
- } |
- } |
- } |
- // Evaluate explicit or implicit call to super(). |
- InterfaceType superclass = definingClass.superclass; |
- if (superclass != null && !superclass.isObject) { |
- ConstructorElement superConstructor = |
- superclass.lookUpConstructor(superName, constructor.library); |
- if (superConstructor != null) { |
- if (superArguments == null) { |
- superArguments = new NodeList<Expression>(null); |
- } |
- evaluateSuperConstructorCall(node, fieldMap, superConstructor, |
- superArguments, initializerVisitor, errorReporter); |
- } |
- } |
- return new DartObjectImpl(definingClass, new GenericState(fieldMap)); |
- } |
- |
- void evaluateSuperConstructorCall(AstNode node, |
- HashMap<String, DartObjectImpl> fieldMap, |
- ConstructorElement superConstructor, NodeList<Expression> superArguments, |
- ConstantVisitor initializerVisitor, ErrorReporter errorReporter) { |
- if (superConstructor != null && superConstructor.isConst) { |
- DartObjectImpl evaluationResult = evaluateConstructorCall(node, |
- superArguments, superConstructor, initializerVisitor, errorReporter); |
- if (evaluationResult != null) { |
- fieldMap[GenericState.SUPERCLASS_FIELD] = evaluationResult; |
- } |
- } |
- } |
- |
- /** |
- * Attempt to follow the chain of factory redirections until a constructor is |
- * reached which is not a const factory constructor. Return the constant |
- * constructor which terminates the chain of factory redirections, if the |
- * chain terminates. If there is a problem (e.g. a redirection can't be found, |
- * or a cycle is encountered), the chain will be followed as far as possible |
- * and then a const factory constructor will be returned. |
- */ |
- ConstructorElement followConstantRedirectionChain( |
- ConstructorElement constructor) { |
- HashSet<ConstructorElement> constructorsVisited = |
- new HashSet<ConstructorElement>(); |
- while (true) { |
- ConstructorElement redirectedConstructor = |
- getConstRedirectedConstructor(constructor); |
- if (redirectedConstructor == null) { |
- break; |
- } else { |
- ConstructorElement constructorBase = _getConstructorBase(constructor); |
- constructorsVisited.add(constructorBase); |
- ConstructorElement redirectedConstructorBase = |
- _getConstructorBase(redirectedConstructor); |
- if (constructorsVisited.contains(redirectedConstructorBase)) { |
- // Cycle in redirecting factory constructors--this is not allowed |
- // and is checked elsewhere--see |
- // [ErrorVerifier.checkForRecursiveFactoryRedirect()]). |
- break; |
- } |
- } |
- constructor = redirectedConstructor; |
- } |
- return constructor; |
- } |
- |
- /** |
- * Generate an error indicating that the given [constant] is not a valid |
- * compile-time constant because it references at least one of the constants |
- * in the given [cycle], each of which directly or indirectly references the |
- * constant. |
- */ |
- void generateCycleError(Iterable<ConstantEvaluationTarget> cycle, |
- ConstantEvaluationTarget constant) { |
- if (constant is VariableElement) { |
- RecordingErrorListener errorListener = new RecordingErrorListener(); |
- ErrorReporter errorReporter = |
- new ErrorReporter(errorListener, constant.source); |
- // TODO(paulberry): It would be really nice if we could extract enough |
- // information from the 'cycle' argument to provide the user with a |
- // description of the cycle. |
- errorReporter.reportErrorForElement( |
- CompileTimeErrorCode.RECURSIVE_COMPILE_TIME_CONSTANT, constant, []); |
- (constant as VariableElementImpl).evaluationResult = |
- new EvaluationResultImpl(null, errorListener.errors); |
- } else if (constant is ConstructorElement) { |
- // We don't report cycle errors on constructor declarations since there |
- // is nowhere to put the error information. |
- } else { |
- // Should not happen. Formal parameter defaults and annotations should |
- // never appear as part of a cycle because they can't be referred to. |
- assert(false); |
- AnalysisEngine.instance.logger.logError( |
- "Constant value computer trying to report a cycle error for a node of type ${constant.runtimeType}"); |
- } |
- } |
- |
- /** |
- * If [constructor] redirects to another const constructor, return the |
- * const constructor it redirects to. Otherwise return `null`. |
- */ |
- ConstructorElement getConstRedirectedConstructor( |
- ConstructorElement constructor) { |
- if (!constructor.isFactory) { |
- return null; |
- } |
- if (identical(constructor.enclosingElement.type, typeProvider.symbolType)) { |
- // The dart:core.Symbol has a const factory constructor that redirects |
- // to dart:_internal.Symbol. That in turn redirects to an external |
- // const constructor, which we won't be able to evaluate. |
- // So stop following the chain of redirections at dart:core.Symbol, and |
- // let [evaluateInstanceCreationExpression] handle it specially. |
- return null; |
- } |
- ConstructorElement redirectedConstructor = |
- constructor.redirectedConstructor; |
- if (redirectedConstructor == null) { |
- // This can happen if constructor is an external factory constructor. |
- return null; |
- } |
- if (!redirectedConstructor.isConst) { |
- // Delegating to a non-const constructor--this is not allowed (and |
- // is checked elsewhere--see |
- // [ErrorVerifier.checkForRedirectToNonConstConstructor()]). |
- return null; |
- } |
- return redirectedConstructor; |
- } |
- |
- /** |
- * Check if the object [obj] matches the type [type] according to runtime type |
- * checking rules. |
- */ |
- bool runtimeTypeMatch(DartObjectImpl obj, DartType type) { |
- if (obj.isNull) { |
- return true; |
- } |
- if (type.isUndefined) { |
- return false; |
- } |
- return obj.type.isSubtypeOf(type); |
- } |
- |
- /** |
- * Determine whether the given string is a valid name for a public symbol |
- * (i.e. whether it is allowed for a call to the Symbol constructor). |
- */ |
- static bool isValidPublicSymbol(String name) => name.isEmpty || |
- name == "void" || |
- new JavaPatternMatcher(_PUBLIC_SYMBOL_PATTERN, name).matches(); |
- |
- static ConstructorElementImpl _getConstructorBase( |
- ConstructorElement constructor) { |
- while (constructor is ConstructorMember) { |
- constructor = (constructor as ConstructorMember).baseElement; |
- } |
- return constructor; |
- } |
-} |
- |
-/** |
- * Wrapper around an [Annotation] which can be used as a |
- * [ConstantEvaluationTarget]. |
- */ |
-class ConstantEvaluationTarget_Annotation implements ConstantEvaluationTarget { |
- final AnalysisContext context; |
- final Source source; |
- final Source librarySource; |
- final Annotation annotation; |
- |
- ConstantEvaluationTarget_Annotation( |
- this.context, this.source, this.librarySource, this.annotation); |
- |
- @override |
- int get hashCode => JenkinsSmiHash.hash3( |
- source.hashCode, librarySource.hashCode, annotation.hashCode); |
- |
- @override |
- bool operator ==(other) { |
- if (other is ConstantEvaluationTarget_Annotation) { |
- return this.context == other.context && |
- this.source == other.source && |
- this.librarySource == other.librarySource && |
- this.annotation == other.annotation; |
- } else { |
- return false; |
- } |
- } |
-} |
- |
-/** |
- * Interface used by unit tests to verify correct dependency analysis during |
- * constant evaluation. |
- */ |
-abstract class ConstantEvaluationValidator { |
- /** |
- * This method is called just before computing the constant value associated |
- * with [constant]. Unit tests will override this method to introduce |
- * additional error checking. |
- */ |
- void beforeComputeValue(ConstantEvaluationTarget constant); |
- |
- /** |
- * This method is called just before getting the constant initializers |
- * associated with the [constructor]. Unit tests will override this method to |
- * introduce additional error checking. |
- */ |
- void beforeGetConstantInitializers(ConstructorElement constructor); |
- |
- /** |
- * This method is called just before retrieving an evaluation result from an |
- * element. Unit tests will override it to introduce additional error |
- * checking. |
- */ |
- void beforeGetEvaluationResult(ConstantEvaluationTarget constant); |
- |
- /** |
- * This method is called just before getting the constant value of a field |
- * with an initializer. Unit tests will override this method to introduce |
- * additional error checking. |
- */ |
- void beforeGetFieldEvaluationResult(FieldElementImpl field); |
- |
- /** |
- * This method is called just before getting a parameter's default value. Unit |
- * tests will override this method to introduce additional error checking. |
- */ |
- void beforeGetParameterDefault(ParameterElement parameter); |
-} |
- |
-/** |
- * Implementation of [ConstantEvaluationValidator] used in production; does no |
- * validation. |
- */ |
-class ConstantEvaluationValidator_ForProduction |
- implements ConstantEvaluationValidator { |
- @override |
- void beforeComputeValue(ConstantEvaluationTarget constant) {} |
- |
- @override |
- void beforeGetConstantInitializers(ConstructorElement constructor) {} |
- |
- @override |
- void beforeGetEvaluationResult(ConstantEvaluationTarget constant) {} |
- |
- @override |
- void beforeGetFieldEvaluationResult(FieldElementImpl field) {} |
- |
- @override |
- void beforeGetParameterDefault(ParameterElement parameter) {} |
-} |
- |
-/** |
- * 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: |
- * * A literal number. |
- * * A literal boolean. |
- * * A literal string where any interpolated expression is a compile-time |
- * constant that evaluates to a numeric, string or boolean value or to |
- * <b>null</b>. |
- * * A literal symbol. |
- * * <b>null</b>. |
- * * A qualified reference to a static constant variable. |
- * * An identifier expression that denotes a constant variable, class or type |
- * alias. |
- * * A constant constructor invocation. |
- * * A constant list literal. |
- * * A constant map literal. |
- * * A simple or qualified identifier denoting a top-level function or a static |
- * method. |
- * * A parenthesized expression <i>(e)</i> where <i>e</i> is a constant |
- * expression. |
- * * An expression of the form <i>identical(e<sub>1</sub>, e<sub>2</sub>)</i> |
- * where <i>e<sub>1</sub></i> and <i>e<sub>2</sub></i> are constant |
- * expressions and <i>identical()</i> is statically bound to the predefined |
- * dart function <i>identical()</i> discussed above. |
- * * An expression of one of the forms <i>e<sub>1</sub> == e<sub>2</sub></i> or |
- * <i>e<sub>1</sub> != e<sub>2</sub></i> where <i>e<sub>1</sub></i> and |
- * <i>e<sub>2</sub></i> are constant expressions that evaluate to a numeric, |
- * string or boolean value. |
- * * An expression of one of the forms <i>!e</i>, <i>e<sub>1</sub> && |
- * e<sub>2</sub></i> or <i>e<sub>1</sub> || e<sub>2</sub></i>, where <i>e</i>, |
- * <i>e1</sub></i> and <i>e2</sub></i> are constant expressions that evaluate |
- * to a boolean value. |
- * * An expression of one of the forms <i>~e</i>, <i>e<sub>1</sub> ^ |
- * e<sub>2</sub></i>, <i>e<sub>1</sub> & e<sub>2</sub></i>, |
- * <i>e<sub>1</sub> | e<sub>2</sub></i>, <i>e<sub>1</sub> >> |
- * e<sub>2</sub></i> or <i>e<sub>1</sub> << e<sub>2</sub></i>, where |
- * <i>e</i>, <i>e<sub>1</sub></i> and <i>e<sub>2</sub></i> are constant |
- * expressions that evaluate to an integer value or to <b>null</b>. |
- * * An expression of one of the forms <i>-e</i>, <i>e<sub>1</sub> + |
- * e<sub>2</sub></i>, <i>e<sub>1</sub> -e<sub>2</sub></i>, <i>e<sub>1</sub> * |
- * e<sub>2</sub></i>, <i>e<sub>1</sub> / e<sub>2</sub></i>, <i>e<sub>1</sub> |
- * ~/ e<sub>2</sub></i>, <i>e<sub>1</sub> > e<sub>2</sub></i>, |
- * <i>e<sub>1</sub> < e<sub>2</sub></i>, <i>e<sub>1</sub> >= |
- * e<sub>2</sub></i>, <i>e<sub>1</sub> <= e<sub>2</sub></i> or |
- * <i>e<sub>1</sub> % e<sub>2</sub></i>, where <i>e</i>, <i>e<sub>1</sub></i> |
- * and <i>e<sub>2</sub></i> are constant expressions that evaluate to a |
- * numeric value or to <b>null</b>. |
- * * An expression of the form <i>e<sub>1</sub> ? e<sub>2</sub> : |
- * e<sub>3</sub></i> where <i>e<sub>1</sub></i>, <i>e<sub>2</sub></i> and |
- * <i>e<sub>3</sub></i> are constant expressions, and <i>e<sub>1</sub></i> |
- * evaluates to a boolean value. |
- * </blockquote> |
- */ |
-class ConstantEvaluator { |
- /** |
- * The source containing the expression(s) that will be evaluated. |
- */ |
- final Source _source; |
- |
- /** |
- * The type provider used to access the known types. |
- */ |
- final TypeProvider _typeProvider; |
- |
- /** |
- * Initialize a newly created evaluator to evaluate expressions in the given |
- * [source]. The [typeProvider] is the type provider used to access known |
- * types. |
- */ |
- ConstantEvaluator(this._source, this._typeProvider); |
- |
- EvaluationResult evaluate(Expression expression) { |
- RecordingErrorListener errorListener = new RecordingErrorListener(); |
- ErrorReporter errorReporter = new ErrorReporter(errorListener, _source); |
- DartObjectImpl result = expression.accept(new ConstantVisitor( |
- new ConstantEvaluationEngine(_typeProvider, new DeclaredVariables()), |
- errorReporter)); |
- if (result != null) { |
- return EvaluationResult.forValue(result); |
- } |
- return EvaluationResult.forErrors(errorListener.errors); |
- } |
-} |
- |
-/** |
- * A visitor used to traverse the AST structures of all of the compilation units |
- * being resolved and build tables of the constant variables, constant |
- * constructors, constant constructor invocations, and annotations found in |
- * those compilation units. |
- */ |
-class ConstantFinder extends RecursiveAstVisitor<Object> { |
- final AnalysisContext context; |
- final Source source; |
- final Source librarySource; |
- |
- /** |
- * The elements and AST nodes whose constant values need to be computed. |
- */ |
- HashSet<ConstantEvaluationTarget> constantsToCompute = |
- new HashSet<ConstantEvaluationTarget>(); |
- |
- /** |
- * True if instance variables marked as "final" should be treated as "const". |
- */ |
- bool treatFinalInstanceVarAsConst = false; |
- |
- ConstantFinder(this.context, this.source, this.librarySource); |
- |
- @override |
- Object visitAnnotation(Annotation node) { |
- super.visitAnnotation(node); |
- constantsToCompute.add(new ConstantEvaluationTarget_Annotation( |
- context, source, librarySource, node)); |
- return null; |
- } |
- |
- @override |
- Object visitClassDeclaration(ClassDeclaration node) { |
- bool prevTreatFinalInstanceVarAsConst = treatFinalInstanceVarAsConst; |
- if (node.element.constructors.any((ConstructorElement e) => e.isConst)) { |
- // Instance vars marked "final" need to be included in the dependency |
- // graph, since constant constructors implicitly use the values in their |
- // initializers. |
- treatFinalInstanceVarAsConst = true; |
- } |
- try { |
- return super.visitClassDeclaration(node); |
- } finally { |
- treatFinalInstanceVarAsConst = prevTreatFinalInstanceVarAsConst; |
- } |
- } |
- |
- @override |
- Object visitConstructorDeclaration(ConstructorDeclaration node) { |
- super.visitConstructorDeclaration(node); |
- if (node.constKeyword != null) { |
- ConstructorElement element = node.element; |
- if (element != null) { |
- constantsToCompute.add(element); |
- constantsToCompute.addAll(element.parameters); |
- } |
- } |
- return null; |
- } |
- |
- @override |
- Object visitVariableDeclaration(VariableDeclaration node) { |
- super.visitVariableDeclaration(node); |
- Expression initializer = node.initializer; |
- VariableElement element = node.element; |
- if (initializer != null && |
- (node.isConst || |
- treatFinalInstanceVarAsConst && |
- element is FieldElement && |
- node.isFinal && |
- !element.isStatic)) { |
- if (node.element != null) { |
- constantsToCompute.add(node.element); |
- } |
- } |
- return null; |
- } |
-} |
- |
-/** |
- * An object used to compute the values of constant variables and constant |
- * constructor invocations 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 { |
- /** |
- * Source of RegExp matching declarable operator names. |
- * From sdk/lib/internal/symbol.dart. |
- */ |
- static String _OPERATOR_RE = |
- "(?:[\\-+*/%&|^]|\\[\\]=?|==|~/?|<[<=]?|>[>=]?|unary-)"; |
- |
- /** |
- * Source of RegExp matching Dart reserved words. |
- * From sdk/lib/internal/symbol.dart. |
- */ |
- static String _RESERVED_WORD_RE = |
- "(?:assert|break|c(?:a(?:se|tch)|lass|on(?:st|tinue))|d(?:efault|o)|e(?:lse|num|xtends)|f(?:alse|inal(?:ly)?|or)|i[fns]|n(?:ew|ull)|ret(?:hrow|urn)|s(?:uper|witch)|t(?:h(?:is|row)|r(?:ue|y))|v(?:ar|oid)|w(?:hile|ith))"; |
- |
- /** |
- * A graph in which the nodes are the constants, and the edges are from each |
- * constant to the other constants that are referenced by it. |
- */ |
- DirectedGraph<ConstantEvaluationTarget> referenceGraph = |
- new DirectedGraph<ConstantEvaluationTarget>(); |
- |
- /** |
- * The elements whose constant values need to be computed. Any elements |
- * which appear in [referenceGraph] but not in this set either belong to a |
- * different library cycle (and hence don't need to be recomputed) or were |
- * computed during a previous stage of resolution stage (e.g. constants |
- * associated with enums). |
- */ |
- HashSet<ConstantEvaluationTarget> _constantsToCompute = |
- new HashSet<ConstantEvaluationTarget>(); |
- |
- /** |
- * The evaluation engine that does the work of evaluating instance creation |
- * expressions. |
- */ |
- final ConstantEvaluationEngine evaluationEngine; |
- |
- final AnalysisContext _context; |
- |
- /** |
- * Initialize a newly created constant value computer. The [typeProvider] is |
- * the type provider used to access known types. The [declaredVariables] is |
- * the set of variables declared on the command line using '-D'. |
- */ |
- ConstantValueComputer(this._context, TypeProvider typeProvider, |
- DeclaredVariables declaredVariables, |
- [ConstantEvaluationValidator validator]) |
- : evaluationEngine = new ConstantEvaluationEngine( |
- typeProvider, declaredVariables, validator: validator); |
- |
- /** |
- * Add the constants in the given compilation [unit] to the list of constants |
- * whose value needs to be computed. |
- */ |
- void add(CompilationUnit unit, Source source, Source librarySource) { |
- ConstantFinder constantFinder = |
- new ConstantFinder(_context, source, librarySource); |
- unit.accept(constantFinder); |
- _constantsToCompute.addAll(constantFinder.constantsToCompute); |
- } |
- |
- /** |
- * Compute values for all of the constants in the compilation units that were |
- * added. |
- */ |
- void computeValues() { |
- for (ConstantEvaluationTarget constant in _constantsToCompute) { |
- referenceGraph.addNode(constant); |
- evaluationEngine.computeDependencies(constant, |
- (ConstantEvaluationTarget dependency) { |
- referenceGraph.addEdge(constant, dependency); |
- }); |
- } |
- List<List<ConstantEvaluationTarget>> topologicalSort = |
- referenceGraph.computeTopologicalSort(); |
- for (List<ConstantEvaluationTarget> constantsInCycle in topologicalSort) { |
- if (constantsInCycle.length == 1) { |
- ConstantEvaluationTarget constant = constantsInCycle[0]; |
- if (!referenceGraph.getTails(constant).contains(constant)) { |
- _computeValueFor(constant); |
- continue; |
- } |
- } |
- for (ConstantEvaluationTarget constant in constantsInCycle) { |
- evaluationEngine.generateCycleError(constantsInCycle, constant); |
- } |
- } |
- } |
- |
- /** |
- * Compute a value for the given [constant]. |
- */ |
- void _computeValueFor(ConstantEvaluationTarget constant) { |
- if (!_constantsToCompute.contains(constant)) { |
- // Element is in the dependency graph but should have been computed by |
- // a previous stage of analysis. |
- // TODO(paulberry): once we have moved over to the new task model, this |
- // should only occur for constants associated with enum members. Once |
- // that happens we should add an assertion to verify that it doesn't |
- // occur in any other cases. |
- return; |
- } |
- evaluationEngine.computeConstantValue(constant); |
- } |
-} |
- |
-/** |
- * A visitor used to evaluate constant expressions to produce their compile-time |
- * value. According to the Dart Language Specification: <blockquote> A constant |
- * expression is one of the following: |
- * |
- * * A literal number. |
- * * A literal boolean. |
- * * A literal string where any interpolated expression is a compile-time |
- * constant that evaluates to a numeric, string or boolean value or to |
- * <b>null</b>. |
- * * A literal symbol. |
- * * <b>null</b>. |
- * * A qualified reference to a static constant variable. |
- * * An identifier expression that denotes a constant variable, class or type |
- * alias. |
- * * A constant constructor invocation. |
- * * A constant list literal. |
- * * A constant map literal. |
- * * A simple or qualified identifier denoting a top-level function or a static |
- * method. |
- * * A parenthesized expression <i>(e)</i> where <i>e</i> is a constant |
- * expression. |
- * * An expression of the form <i>identical(e<sub>1</sub>, e<sub>2</sub>)</i> |
- * where <i>e<sub>1</sub></i> and <i>e<sub>2</sub></i> are constant |
- * expressions and <i>identical()</i> is statically bound to the predefined |
- * dart function <i>identical()</i> discussed above. |
- * * An expression of one of the forms <i>e<sub>1</sub> == e<sub>2</sub></i> or |
- * <i>e<sub>1</sub> != e<sub>2</sub></i> where <i>e<sub>1</sub></i> and |
- * <i>e<sub>2</sub></i> are constant expressions that evaluate to a numeric, |
- * string or boolean value. |
- * * An expression of one of the forms <i>!e</i>, <i>e<sub>1</sub> && |
- * e<sub>2</sub></i> or <i>e<sub>1</sub> || e<sub>2</sub></i>, where <i>e</i>, |
- * <i>e1</sub></i> and <i>e2</sub></i> are constant expressions that evaluate |
- * to a boolean value. |
- * * An expression of one of the forms <i>~e</i>, <i>e<sub>1</sub> ^ |
- * e<sub>2</sub></i>, <i>e<sub>1</sub> & e<sub>2</sub></i>, |
- * <i>e<sub>1</sub> | e<sub>2</sub></i>, <i>e<sub>1</sub> >> |
- * e<sub>2</sub></i> or <i>e<sub>1</sub> << e<sub>2</sub></i>, where |
- * <i>e</i>, <i>e<sub>1</sub></i> and <i>e<sub>2</sub></i> are constant |
- * expressions that evaluate to an integer value or to <b>null</b>. |
- * * An expression of one of the forms <i>-e</i>, <i>e<sub>1</sub> + |
- * e<sub>2</sub></i>, <i>e<sub>1</sub> - e<sub>2</sub></i>, <i>e<sub>1</sub> * |
- * e<sub>2</sub></i>, <i>e<sub>1</sub> / e<sub>2</sub></i>, <i>e<sub>1</sub> |
- * ~/ e<sub>2</sub></i>, <i>e<sub>1</sub> > e<sub>2</sub></i>, |
- * <i>e<sub>1</sub> < e<sub>2</sub></i>, <i>e<sub>1</sub> >= |
- * e<sub>2</sub></i>, <i>e<sub>1</sub> <= e<sub>2</sub></i> or |
- * <i>e<sub>1</sub> % e<sub>2</sub></i>, where <i>e</i>, <i>e<sub>1</sub></i> |
- * and <i>e<sub>2</sub></i> are constant expressions that evaluate to a |
- * numeric value or to <b>null</b>. |
- * * An expression of the form <i>e<sub>1</sub> ? e<sub>2</sub> : |
- * e<sub>3</sub></i> where <i>e<sub>1</sub></i>, <i>e<sub>2</sub></i> and |
- * <i>e<sub>3</sub></i> are constant expressions, and <i>e<sub>1</sub></i> |
- * evaluates to a boolean value. |
- * </blockquote> |
- */ |
-class ConstantVisitor extends UnifyingAstVisitor<DartObjectImpl> { |
- /** |
- * The type provider used to access the known types. |
- */ |
- final ConstantEvaluationEngine evaluationEngine; |
- |
- final HashMap<String, DartObjectImpl> _lexicalEnvironment; |
- |
- /** |
- * Error reporter that we use to report errors accumulated while computing the |
- * constant. |
- */ |
- final ErrorReporter _errorReporter; |
- |
- /** |
- * Helper class used to compute constant values. |
- */ |
- DartObjectComputer _dartObjectComputer; |
- |
- /** |
- * Initialize a newly created constant visitor. The [evaluationEngine] is |
- * used to evaluate instance creation expressions. The [lexicalEnvironment] |
- * is a map containing values which should override identifiers, or `null` if |
- * no overriding is necessary. The [_errorReporter] is used to report errors |
- * found during evaluation. The [validator] is used by unit tests to verify |
- * correct dependency analysis. |
- */ |
- ConstantVisitor(this.evaluationEngine, this._errorReporter, |
- {HashMap<String, DartObjectImpl> lexicalEnvironment}) |
- : _lexicalEnvironment = lexicalEnvironment { |
- this._dartObjectComputer = |
- new DartObjectComputer(_errorReporter, evaluationEngine.typeProvider); |
- } |
- |
- /** |
- * Convenience getter to gain access to the [evalationEngine]'s type |
- * provider. |
- */ |
- TypeProvider get _typeProvider => evaluationEngine.typeProvider; |
- |
- /** |
- * Convenience getter to gain access to the [evaluationEngine]'s type system. |
- */ |
- TypeSystem get _typeSystem => evaluationEngine.typeSystem; |
- |
- @override |
- DartObjectImpl visitAdjacentStrings(AdjacentStrings node) { |
- DartObjectImpl result = null; |
- for (StringLiteral string in node.strings) { |
- if (result == null) { |
- result = string.accept(this); |
- } else { |
- result = |
- _dartObjectComputer.concatenate(node, result, string.accept(this)); |
- } |
- } |
- return result; |
- } |
- |
- @override |
- DartObjectImpl visitBinaryExpression(BinaryExpression node) { |
- DartObjectImpl leftResult = node.leftOperand.accept(this); |
- DartObjectImpl rightResult = node.rightOperand.accept(this); |
- TokenType operatorType = node.operator.type; |
- // 'null' is almost never good operand |
- if (operatorType != TokenType.BANG_EQ && operatorType != TokenType.EQ_EQ) { |
- if (leftResult != null && leftResult.isNull || |
- rightResult != null && rightResult.isNull) { |
- _error(node, CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION); |
- return null; |
- } |
- } |
- // evaluate operator |
- while (true) { |
- if (operatorType == TokenType.AMPERSAND) { |
- return _dartObjectComputer.bitAnd(node, leftResult, rightResult); |
- } else if (operatorType == TokenType.AMPERSAND_AMPERSAND) { |
- return _dartObjectComputer.logicalAnd(node, leftResult, rightResult); |
- } else if (operatorType == TokenType.BANG_EQ) { |
- return _dartObjectComputer.notEqual(node, leftResult, rightResult); |
- } else if (operatorType == TokenType.BAR) { |
- return _dartObjectComputer.bitOr(node, leftResult, rightResult); |
- } else if (operatorType == TokenType.BAR_BAR) { |
- return _dartObjectComputer.logicalOr(node, leftResult, rightResult); |
- } else if (operatorType == TokenType.CARET) { |
- return _dartObjectComputer.bitXor(node, leftResult, rightResult); |
- } else if (operatorType == TokenType.EQ_EQ) { |
- return _dartObjectComputer.equalEqual(node, leftResult, rightResult); |
- } else if (operatorType == TokenType.GT) { |
- return _dartObjectComputer.greaterThan(node, leftResult, rightResult); |
- } else if (operatorType == TokenType.GT_EQ) { |
- return _dartObjectComputer.greaterThanOrEqual( |
- node, leftResult, rightResult); |
- } else if (operatorType == TokenType.GT_GT) { |
- return _dartObjectComputer.shiftRight(node, leftResult, rightResult); |
- } else if (operatorType == TokenType.LT) { |
- return _dartObjectComputer.lessThan(node, leftResult, rightResult); |
- } else if (operatorType == TokenType.LT_EQ) { |
- return _dartObjectComputer.lessThanOrEqual( |
- node, leftResult, rightResult); |
- } else if (operatorType == TokenType.LT_LT) { |
- return _dartObjectComputer.shiftLeft(node, leftResult, rightResult); |
- } else if (operatorType == TokenType.MINUS) { |
- return _dartObjectComputer.minus(node, leftResult, rightResult); |
- } else if (operatorType == TokenType.PERCENT) { |
- return _dartObjectComputer.remainder(node, leftResult, rightResult); |
- } else if (operatorType == TokenType.PLUS) { |
- return _dartObjectComputer.add(node, leftResult, rightResult); |
- } else if (operatorType == TokenType.STAR) { |
- return _dartObjectComputer.times(node, leftResult, rightResult); |
- } else if (operatorType == TokenType.SLASH) { |
- return _dartObjectComputer.divide(node, leftResult, rightResult); |
- } else if (operatorType == TokenType.TILDE_SLASH) { |
- return _dartObjectComputer.integerDivide(node, leftResult, rightResult); |
- } else { |
- // TODO(brianwilkerson) Figure out which error to report. |
- _error(node, null); |
- return null; |
- } |
- break; |
- } |
- } |
- |
- @override |
- DartObjectImpl visitBooleanLiteral(BooleanLiteral node) => |
- new DartObjectImpl(_typeProvider.boolType, BoolState.from(node.value)); |
- |
- @override |
- DartObjectImpl visitConditionalExpression(ConditionalExpression node) { |
- Expression condition = node.condition; |
- DartObjectImpl conditionResult = condition.accept(this); |
- DartObjectImpl thenResult = node.thenExpression.accept(this); |
- DartObjectImpl elseResult = node.elseExpression.accept(this); |
- if (conditionResult == null) { |
- return conditionResult; |
- } else if (!conditionResult.isBool) { |
- _errorReporter.reportErrorForNode( |
- CompileTimeErrorCode.CONST_EVAL_TYPE_BOOL, condition); |
- return null; |
- } else if (thenResult == null) { |
- return thenResult; |
- } else if (elseResult == null) { |
- return elseResult; |
- } |
- conditionResult = |
- _dartObjectComputer.applyBooleanConversion(condition, conditionResult); |
- if (conditionResult == null) { |
- return conditionResult; |
- } |
- if (conditionResult.isTrue) { |
- return thenResult; |
- } else if (conditionResult.isFalse) { |
- return elseResult; |
- } |
- ParameterizedType thenType = thenResult.type; |
- ParameterizedType elseType = elseResult.type; |
- return new DartObjectImpl.validWithUnknownValue( |
- _typeSystem.getLeastUpperBound(thenType, elseType) as InterfaceType); |
- } |
- |
- @override |
- DartObjectImpl visitDoubleLiteral(DoubleLiteral node) => |
- new DartObjectImpl(_typeProvider.doubleType, new DoubleState(node.value)); |
- |
- @override |
- DartObjectImpl visitInstanceCreationExpression( |
- InstanceCreationExpression node) { |
- if (!node.isConst) { |
- // TODO(brianwilkerson) Figure out which error to report. |
- _error(node, null); |
- return null; |
- } |
- ConstructorElement constructor = node.staticElement; |
- if (constructor == null) { |
- // Couldn't resolve the constructor so we can't compute a value. No |
- // problem - the error has already been reported. |
- return null; |
- } |
- return evaluationEngine.evaluateConstructorCall( |
- node, node.argumentList.arguments, constructor, this, _errorReporter); |
- } |
- |
- @override |
- DartObjectImpl visitIntegerLiteral(IntegerLiteral node) => |
- new DartObjectImpl(_typeProvider.intType, new IntState(node.value)); |
- |
- @override |
- DartObjectImpl visitInterpolationExpression(InterpolationExpression node) { |
- DartObjectImpl result = node.expression.accept(this); |
- if (result != null && !result.isBoolNumStringOrNull) { |
- _error(node, CompileTimeErrorCode.CONST_EVAL_TYPE_BOOL_NUM_STRING); |
- return null; |
- } |
- return _dartObjectComputer.performToString(node, result); |
- } |
- |
- @override |
- DartObjectImpl visitInterpolationString(InterpolationString node) => |
- new DartObjectImpl(_typeProvider.stringType, new StringState(node.value)); |
- |
- @override |
- DartObjectImpl visitListLiteral(ListLiteral node) { |
- if (node.constKeyword == null) { |
- _errorReporter.reportErrorForNode( |
- CompileTimeErrorCode.MISSING_CONST_IN_LIST_LITERAL, node); |
- return null; |
- } |
- bool errorOccurred = false; |
- List<DartObjectImpl> elements = new List<DartObjectImpl>(); |
- for (Expression element in node.elements) { |
- DartObjectImpl elementResult = element.accept(this); |
- if (elementResult == null) { |
- errorOccurred = true; |
- } else { |
- elements.add(elementResult); |
- } |
- } |
- if (errorOccurred) { |
- return null; |
- } |
- DartType elementType = _typeProvider.dynamicType; |
- if (node.typeArguments != null && |
- node.typeArguments.arguments.length == 1) { |
- DartType type = node.typeArguments.arguments[0].type; |
- if (type != null) { |
- elementType = type; |
- } |
- } |
- InterfaceType listType = _typeProvider.listType.substitute4([elementType]); |
- return new DartObjectImpl(listType, new ListState(elements)); |
- } |
- |
- @override |
- DartObjectImpl visitMapLiteral(MapLiteral node) { |
- if (node.constKeyword == null) { |
- _errorReporter.reportErrorForNode( |
- CompileTimeErrorCode.MISSING_CONST_IN_MAP_LITERAL, node); |
- return null; |
- } |
- bool errorOccurred = false; |
- HashMap<DartObjectImpl, DartObjectImpl> map = |
- new HashMap<DartObjectImpl, DartObjectImpl>(); |
- for (MapLiteralEntry entry in node.entries) { |
- DartObjectImpl keyResult = entry.key.accept(this); |
- DartObjectImpl valueResult = entry.value.accept(this); |
- if (keyResult == null || valueResult == null) { |
- errorOccurred = true; |
- } else { |
- map[keyResult] = valueResult; |
- } |
- } |
- if (errorOccurred) { |
- return null; |
- } |
- DartType keyType = _typeProvider.dynamicType; |
- DartType valueType = _typeProvider.dynamicType; |
- if (node.typeArguments != null && |
- node.typeArguments.arguments.length == 2) { |
- DartType keyTypeCandidate = node.typeArguments.arguments[0].type; |
- if (keyTypeCandidate != null) { |
- keyType = keyTypeCandidate; |
- } |
- DartType valueTypeCandidate = node.typeArguments.arguments[1].type; |
- if (valueTypeCandidate != null) { |
- valueType = valueTypeCandidate; |
- } |
- } |
- InterfaceType mapType = |
- _typeProvider.mapType.substitute4([keyType, valueType]); |
- return new DartObjectImpl(mapType, new MapState(map)); |
- } |
- |
- @override |
- DartObjectImpl visitMethodInvocation(MethodInvocation node) { |
- Element element = node.methodName.staticElement; |
- if (element is FunctionElement) { |
- FunctionElement function = element; |
- if (function.name == "identical") { |
- NodeList<Expression> arguments = node.argumentList.arguments; |
- if (arguments.length == 2) { |
- Element enclosingElement = function.enclosingElement; |
- if (enclosingElement is CompilationUnitElement) { |
- LibraryElement library = enclosingElement.library; |
- if (library.isDartCore) { |
- DartObjectImpl leftArgument = arguments[0].accept(this); |
- DartObjectImpl rightArgument = arguments[1].accept(this); |
- return _dartObjectComputer.isIdentical( |
- node, leftArgument, rightArgument); |
- } |
- } |
- } |
- } |
- } |
- // TODO(brianwilkerson) Figure out which error to report. |
- _error(node, null); |
- return null; |
- } |
- |
- @override |
- DartObjectImpl visitNamedExpression(NamedExpression node) => |
- node.expression.accept(this); |
- |
- @override |
- DartObjectImpl visitNode(AstNode node) { |
- // TODO(brianwilkerson) Figure out which error to report. |
- _error(node, null); |
- return null; |
- } |
- |
- @override |
- DartObjectImpl visitNullLiteral(NullLiteral node) => _typeProvider.nullObject; |
- |
- @override |
- DartObjectImpl visitParenthesizedExpression(ParenthesizedExpression node) => |
- node.expression.accept(this); |
- |
- @override |
- DartObjectImpl visitPrefixedIdentifier(PrefixedIdentifier node) { |
- SimpleIdentifier prefixNode = node.prefix; |
- Element prefixElement = prefixNode.staticElement; |
- // String.length |
- if (prefixElement is! PrefixElement && prefixElement is! ClassElement) { |
- DartObjectImpl prefixResult = node.prefix.accept(this); |
- if (_isStringLength(prefixResult, node.identifier)) { |
- return prefixResult.stringLength(_typeProvider); |
- } |
- } |
- // importPrefix.CONST |
- if (prefixElement is! PrefixElement) { |
- DartObjectImpl prefixResult = prefixNode.accept(this); |
- if (prefixResult == null) { |
- // The error has already been reported. |
- return null; |
- } |
- } |
- // validate prefixed identifier |
- return _getConstantValue(node, node.staticElement); |
- } |
- |
- @override |
- DartObjectImpl visitPrefixExpression(PrefixExpression node) { |
- DartObjectImpl operand = node.operand.accept(this); |
- if (operand != null && operand.isNull) { |
- _error(node, CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION); |
- return null; |
- } |
- while (true) { |
- if (node.operator.type == TokenType.BANG) { |
- return _dartObjectComputer.logicalNot(node, operand); |
- } else if (node.operator.type == TokenType.TILDE) { |
- return _dartObjectComputer.bitNot(node, operand); |
- } else if (node.operator.type == TokenType.MINUS) { |
- return _dartObjectComputer.negated(node, operand); |
- } else { |
- // TODO(brianwilkerson) Figure out which error to report. |
- _error(node, null); |
- return null; |
- } |
- break; |
- } |
- } |
- |
- @override |
- DartObjectImpl visitPropertyAccess(PropertyAccess node) { |
- if (node.target != null) { |
- DartObjectImpl prefixResult = node.target.accept(this); |
- if (_isStringLength(prefixResult, node.propertyName)) { |
- return prefixResult.stringLength(_typeProvider); |
- } |
- } |
- return _getConstantValue(node, node.propertyName.staticElement); |
- } |
- |
- @override |
- DartObjectImpl visitSimpleIdentifier(SimpleIdentifier node) { |
- if (_lexicalEnvironment != null && |
- _lexicalEnvironment.containsKey(node.name)) { |
- return _lexicalEnvironment[node.name]; |
- } |
- return _getConstantValue(node, node.staticElement); |
- } |
- |
- @override |
- DartObjectImpl visitSimpleStringLiteral(SimpleStringLiteral node) => |
- new DartObjectImpl(_typeProvider.stringType, new StringState(node.value)); |
- |
- @override |
- DartObjectImpl visitStringInterpolation(StringInterpolation node) { |
- DartObjectImpl result = null; |
- bool first = true; |
- for (InterpolationElement element in node.elements) { |
- if (first) { |
- result = element.accept(this); |
- first = false; |
- } else { |
- result = |
- _dartObjectComputer.concatenate(node, result, element.accept(this)); |
- } |
- } |
- return result; |
- } |
- |
- @override |
- DartObjectImpl visitSymbolLiteral(SymbolLiteral node) { |
- StringBuffer buffer = new StringBuffer(); |
- List<Token> components = node.components; |
- for (int i = 0; i < components.length; i++) { |
- if (i > 0) { |
- buffer.writeCharCode(0x2E); |
- } |
- buffer.write(components[i].lexeme); |
- } |
- return new DartObjectImpl( |
- _typeProvider.symbolType, new SymbolState(buffer.toString())); |
- } |
- |
- /** |
- * Create an error associated with the given [node]. The error will have the |
- * given error [code]. |
- */ |
- void _error(AstNode node, ErrorCode code) { |
- _errorReporter.reportErrorForNode( |
- code == null ? CompileTimeErrorCode.INVALID_CONSTANT : code, node); |
- } |
- |
- /** |
- * Return the constant value of the static constant represented by the given |
- * [element]. The [node] is the node to be used if an error needs to be |
- * reported. |
- */ |
- DartObjectImpl _getConstantValue(AstNode node, Element element) { |
- if (element is PropertyAccessorElement) { |
- element = (element as PropertyAccessorElement).variable; |
- } |
- if (element is VariableElementImpl) { |
- VariableElementImpl variableElementImpl = element; |
- evaluationEngine.validator.beforeGetEvaluationResult(element); |
- EvaluationResultImpl value = variableElementImpl.evaluationResult; |
- if (variableElementImpl.isConst && value != null) { |
- return value.value; |
- } |
- } else if (element is ExecutableElement) { |
- ExecutableElement function = element; |
- if (function.isStatic) { |
- ParameterizedType functionType = function.type; |
- if (functionType == null) { |
- functionType = _typeProvider.functionType; |
- } |
- return new DartObjectImpl(functionType, new FunctionState(function)); |
- } |
- } else if (element is ClassElement || |
- element is FunctionTypeAliasElement || |
- element is DynamicElementImpl) { |
- return new DartObjectImpl(_typeProvider.typeType, new TypeState(element)); |
- } |
- // TODO(brianwilkerson) Figure out which error to report. |
- _error(node, null); |
- return null; |
- } |
- |
- /** |
- * Return `true` if the given [targetResult] represents a string and the |
- * [identifier] is "length". |
- */ |
- bool _isStringLength( |
- DartObjectImpl targetResult, SimpleIdentifier identifier) { |
- if (targetResult == null || targetResult.type != _typeProvider.stringType) { |
- return false; |
- } |
- return identifier.name == 'length'; |
- } |
- |
- /** |
- * Return the value of the given [expression], or a representation of 'null' |
- * if the expression cannot be evaluated. |
- */ |
- DartObjectImpl _valueOf(Expression expression) { |
- DartObjectImpl expressionValue = expression.accept(this); |
- if (expressionValue != null) { |
- return expressionValue; |
- } |
- return _typeProvider.nullObject; |
- } |
-} |
- |
-/** |
- * The state of a Dart object. |
- */ |
-abstract class DartObject { |
- /** |
- * 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'. |
- */ |
- bool get boolValue; |
- |
- /** |
- * 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'. |
- */ |
- double get doubleValue; |
- |
- /** |
- * Return `true` if this object's value can be represented exactly. |
- */ |
- bool get hasExactValue; |
- |
- /** |
- * 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'. |
- */ |
- int get intValue; |
- |
- /** |
- * Return `true` if this object represents the value 'false'. |
- */ |
- bool get isFalse; |
- |
- /** |
- * Return `true` if this object represents the value 'null'. |
- */ |
- bool get isNull; |
- |
- /** |
- * Return `true` if this object represents the value 'true'. |
- */ |
- bool get isTrue; |
- |
- /** |
- * 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'. |
- */ |
- String get stringValue; |
- |
- /** |
- * Return the run-time type of this object. |
- */ |
- ParameterizedType get type; |
- |
- /** |
- * 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. |
- */ |
- Object get value; |
-} |
- |
-/** |
- * A utility class that contains methods for manipulating instances of a Dart |
- * class and for collecting errors during evaluation. |
- */ |
-class DartObjectComputer { |
- /** |
- * The error reporter that we are using to collect errors. |
- */ |
- final ErrorReporter _errorReporter; |
- |
- /** |
- * The type provider used to create objects of the appropriate types, and to |
- * identify when an object is of a built-in type. |
- */ |
- final TypeProvider _typeProvider; |
- |
- DartObjectComputer(this._errorReporter, this._typeProvider); |
- |
- DartObjectImpl add(BinaryExpression node, DartObjectImpl leftOperand, |
- DartObjectImpl rightOperand) { |
- if (leftOperand != null && rightOperand != null) { |
- try { |
- return leftOperand.add(_typeProvider, rightOperand); |
- } on EvaluationException catch (exception) { |
- _errorReporter.reportErrorForNode(exception.errorCode, node); |
- return null; |
- } |
- } |
- return null; |
- } |
- |
- /** |
- * Return the result of applying boolean conversion to the [evaluationResult]. |
- * The [node] is the node against which errors should be reported. |
- */ |
- DartObjectImpl applyBooleanConversion( |
- AstNode node, DartObjectImpl evaluationResult) { |
- if (evaluationResult != null) { |
- try { |
- return evaluationResult.convertToBool(_typeProvider); |
- } on EvaluationException catch (exception) { |
- _errorReporter.reportErrorForNode(exception.errorCode, node); |
- } |
- } |
- return null; |
- } |
- |
- DartObjectImpl bitAnd(BinaryExpression node, DartObjectImpl leftOperand, |
- DartObjectImpl rightOperand) { |
- if (leftOperand != null && rightOperand != null) { |
- try { |
- return leftOperand.bitAnd(_typeProvider, rightOperand); |
- } on EvaluationException catch (exception) { |
- _errorReporter.reportErrorForNode(exception.errorCode, node); |
- } |
- } |
- return null; |
- } |
- |
- DartObjectImpl bitNot(Expression node, DartObjectImpl evaluationResult) { |
- if (evaluationResult != null) { |
- try { |
- return evaluationResult.bitNot(_typeProvider); |
- } on EvaluationException catch (exception) { |
- _errorReporter.reportErrorForNode(exception.errorCode, node); |
- } |
- } |
- return null; |
- } |
- |
- DartObjectImpl bitOr(BinaryExpression node, DartObjectImpl leftOperand, |
- DartObjectImpl rightOperand) { |
- if (leftOperand != null && rightOperand != null) { |
- try { |
- return leftOperand.bitOr(_typeProvider, rightOperand); |
- } on EvaluationException catch (exception) { |
- _errorReporter.reportErrorForNode(exception.errorCode, node); |
- } |
- } |
- return null; |
- } |
- |
- DartObjectImpl bitXor(BinaryExpression node, DartObjectImpl leftOperand, |
- DartObjectImpl rightOperand) { |
- if (leftOperand != null && rightOperand != null) { |
- try { |
- return leftOperand.bitXor(_typeProvider, rightOperand); |
- } on EvaluationException catch (exception) { |
- _errorReporter.reportErrorForNode(exception.errorCode, node); |
- } |
- } |
- return null; |
- } |
- |
- DartObjectImpl concatenate(Expression node, DartObjectImpl leftOperand, |
- DartObjectImpl rightOperand) { |
- if (leftOperand != null && rightOperand != null) { |
- try { |
- return leftOperand.concatenate(_typeProvider, rightOperand); |
- } on EvaluationException catch (exception) { |
- _errorReporter.reportErrorForNode(exception.errorCode, node); |
- } |
- } |
- return null; |
- } |
- |
- DartObjectImpl divide(BinaryExpression node, DartObjectImpl leftOperand, |
- DartObjectImpl rightOperand) { |
- if (leftOperand != null && rightOperand != null) { |
- try { |
- return leftOperand.divide(_typeProvider, rightOperand); |
- } on EvaluationException catch (exception) { |
- _errorReporter.reportErrorForNode(exception.errorCode, node); |
- } |
- } |
- return null; |
- } |
- |
- DartObjectImpl equalEqual(Expression node, DartObjectImpl leftOperand, |
- DartObjectImpl rightOperand) { |
- if (leftOperand != null && rightOperand != null) { |
- try { |
- return leftOperand.equalEqual(_typeProvider, rightOperand); |
- } on EvaluationException catch (exception) { |
- _errorReporter.reportErrorForNode(exception.errorCode, node); |
- } |
- } |
- return null; |
- } |
- |
- DartObjectImpl greaterThan(BinaryExpression node, DartObjectImpl leftOperand, |
- DartObjectImpl rightOperand) { |
- if (leftOperand != null && rightOperand != null) { |
- try { |
- return leftOperand.greaterThan(_typeProvider, rightOperand); |
- } on EvaluationException catch (exception) { |
- _errorReporter.reportErrorForNode(exception.errorCode, node); |
- } |
- } |
- return null; |
- } |
- |
- DartObjectImpl greaterThanOrEqual(BinaryExpression node, |
- DartObjectImpl leftOperand, DartObjectImpl rightOperand) { |
- if (leftOperand != null && rightOperand != null) { |
- try { |
- return leftOperand.greaterThanOrEqual(_typeProvider, rightOperand); |
- } on EvaluationException catch (exception) { |
- _errorReporter.reportErrorForNode(exception.errorCode, node); |
- } |
- } |
- return null; |
- } |
- |
- DartObjectImpl integerDivide(BinaryExpression node, |
- DartObjectImpl leftOperand, DartObjectImpl rightOperand) { |
- if (leftOperand != null && rightOperand != null) { |
- try { |
- return leftOperand.integerDivide(_typeProvider, rightOperand); |
- } on EvaluationException catch (exception) { |
- _errorReporter.reportErrorForNode(exception.errorCode, node); |
- } |
- } |
- return null; |
- } |
- |
- DartObjectImpl isIdentical(Expression node, DartObjectImpl leftOperand, |
- DartObjectImpl rightOperand) { |
- if (leftOperand != null && rightOperand != null) { |
- try { |
- return leftOperand.isIdentical(_typeProvider, rightOperand); |
- } on EvaluationException catch (exception) { |
- _errorReporter.reportErrorForNode(exception.errorCode, node); |
- } |
- } |
- return null; |
- } |
- |
- DartObjectImpl lessThan(BinaryExpression node, DartObjectImpl leftOperand, |
- DartObjectImpl rightOperand) { |
- if (leftOperand != null && rightOperand != null) { |
- try { |
- return leftOperand.lessThan(_typeProvider, rightOperand); |
- } on EvaluationException catch (exception) { |
- _errorReporter.reportErrorForNode(exception.errorCode, node); |
- } |
- } |
- return null; |
- } |
- |
- DartObjectImpl lessThanOrEqual(BinaryExpression node, |
- DartObjectImpl leftOperand, DartObjectImpl rightOperand) { |
- if (leftOperand != null && rightOperand != null) { |
- try { |
- return leftOperand.lessThanOrEqual(_typeProvider, rightOperand); |
- } on EvaluationException catch (exception) { |
- _errorReporter.reportErrorForNode(exception.errorCode, node); |
- } |
- } |
- return null; |
- } |
- |
- DartObjectImpl logicalAnd(BinaryExpression node, DartObjectImpl leftOperand, |
- DartObjectImpl rightOperand) { |
- if (leftOperand != null && rightOperand != null) { |
- try { |
- return leftOperand.logicalAnd(_typeProvider, rightOperand); |
- } on EvaluationException catch (exception) { |
- _errorReporter.reportErrorForNode(exception.errorCode, node); |
- } |
- } |
- return null; |
- } |
- |
- DartObjectImpl logicalNot(Expression node, DartObjectImpl evaluationResult) { |
- if (evaluationResult != null) { |
- try { |
- return evaluationResult.logicalNot(_typeProvider); |
- } on EvaluationException catch (exception) { |
- _errorReporter.reportErrorForNode(exception.errorCode, node); |
- } |
- } |
- return null; |
- } |
- |
- DartObjectImpl logicalOr(BinaryExpression node, DartObjectImpl leftOperand, |
- DartObjectImpl rightOperand) { |
- if (leftOperand != null && rightOperand != null) { |
- try { |
- return leftOperand.logicalOr(_typeProvider, rightOperand); |
- } on EvaluationException catch (exception) { |
- _errorReporter.reportErrorForNode(exception.errorCode, node); |
- } |
- } |
- return null; |
- } |
- |
- DartObjectImpl minus(BinaryExpression node, DartObjectImpl leftOperand, |
- DartObjectImpl rightOperand) { |
- if (leftOperand != null && rightOperand != null) { |
- try { |
- return leftOperand.minus(_typeProvider, rightOperand); |
- } on EvaluationException catch (exception) { |
- _errorReporter.reportErrorForNode(exception.errorCode, node); |
- } |
- } |
- return null; |
- } |
- |
- DartObjectImpl negated(Expression node, DartObjectImpl evaluationResult) { |
- if (evaluationResult != null) { |
- try { |
- return evaluationResult.negated(_typeProvider); |
- } on EvaluationException catch (exception) { |
- _errorReporter.reportErrorForNode(exception.errorCode, node); |
- } |
- } |
- return null; |
- } |
- |
- DartObjectImpl notEqual(BinaryExpression node, DartObjectImpl leftOperand, |
- DartObjectImpl rightOperand) { |
- if (leftOperand != null && rightOperand != null) { |
- try { |
- return leftOperand.notEqual(_typeProvider, rightOperand); |
- } on EvaluationException catch (exception) { |
- _errorReporter.reportErrorForNode(exception.errorCode, node); |
- } |
- } |
- return null; |
- } |
- |
- DartObjectImpl performToString( |
- AstNode node, DartObjectImpl evaluationResult) { |
- if (evaluationResult != null) { |
- try { |
- return evaluationResult.performToString(_typeProvider); |
- } on EvaluationException catch (exception) { |
- _errorReporter.reportErrorForNode(exception.errorCode, node); |
- } |
- } |
- return null; |
- } |
- |
- DartObjectImpl remainder(BinaryExpression node, DartObjectImpl leftOperand, |
- DartObjectImpl rightOperand) { |
- if (leftOperand != null && rightOperand != null) { |
- try { |
- return leftOperand.remainder(_typeProvider, rightOperand); |
- } on EvaluationException catch (exception) { |
- _errorReporter.reportErrorForNode(exception.errorCode, node); |
- } |
- } |
- return null; |
- } |
- |
- DartObjectImpl shiftLeft(BinaryExpression node, DartObjectImpl leftOperand, |
- DartObjectImpl rightOperand) { |
- if (leftOperand != null && rightOperand != null) { |
- try { |
- return leftOperand.shiftLeft(_typeProvider, rightOperand); |
- } on EvaluationException catch (exception) { |
- _errorReporter.reportErrorForNode(exception.errorCode, node); |
- } |
- } |
- return null; |
- } |
- |
- DartObjectImpl shiftRight(BinaryExpression node, DartObjectImpl leftOperand, |
- DartObjectImpl rightOperand) { |
- if (leftOperand != null && rightOperand != null) { |
- try { |
- return leftOperand.shiftRight(_typeProvider, rightOperand); |
- } on EvaluationException catch (exception) { |
- _errorReporter.reportErrorForNode(exception.errorCode, node); |
- } |
- } |
- return null; |
- } |
- |
- /** |
- * Return the result of invoking the 'length' getter on the |
- * [evaluationResult]. The [node] is the node against which errors should be |
- * reported. |
- */ |
- EvaluationResultImpl stringLength( |
- Expression node, EvaluationResultImpl evaluationResult) { |
- if (evaluationResult.value != null) { |
- try { |
- return new EvaluationResultImpl( |
- evaluationResult.value.stringLength(_typeProvider)); |
- } on EvaluationException catch (exception) { |
- _errorReporter.reportErrorForNode(exception.errorCode, node); |
- } |
- } |
- return new EvaluationResultImpl(null); |
- } |
- |
- DartObjectImpl times(BinaryExpression node, DartObjectImpl leftOperand, |
- DartObjectImpl rightOperand) { |
- if (leftOperand != null && rightOperand != null) { |
- try { |
- return leftOperand.times(_typeProvider, rightOperand); |
- } on EvaluationException catch (exception) { |
- _errorReporter.reportErrorForNode(exception.errorCode, node); |
- } |
- } |
- return null; |
- } |
-} |
- |
-/** |
- * An instance of a Dart class. |
- */ |
-class DartObjectImpl implements DartObject { |
- /** |
- * An empty list of objects. |
- */ |
- static const List<DartObjectImpl> EMPTY_LIST = const <DartObjectImpl>[]; |
- |
- /** |
- * The run-time type of this object. |
- */ |
- final ParameterizedType type; |
- |
- /** |
- * The state of the object. |
- */ |
- final InstanceState _state; |
- |
- /** |
- * Initialize a newly created object to have the given [type] and [_state]. |
- */ |
- DartObjectImpl(this.type, this._state); |
- |
- /** |
- * Create an object to represent an unknown value. |
- */ |
- factory DartObjectImpl.validWithUnknownValue(InterfaceType type) { |
- if (type.element.library.isDartCore) { |
- String typeName = type.name; |
- if (typeName == "bool") { |
- return new DartObjectImpl(type, BoolState.UNKNOWN_VALUE); |
- } else if (typeName == "double") { |
- return new DartObjectImpl(type, DoubleState.UNKNOWN_VALUE); |
- } else if (typeName == "int") { |
- return new DartObjectImpl(type, IntState.UNKNOWN_VALUE); |
- } else if (typeName == "String") { |
- return new DartObjectImpl(type, StringState.UNKNOWN_VALUE); |
- } |
- } |
- return new DartObjectImpl(type, GenericState.UNKNOWN_VALUE); |
- } |
- |
- @override |
- bool get boolValue { |
- if (_state is BoolState) { |
- return (_state as BoolState).value; |
- } |
- return null; |
- } |
- |
- @override |
- double get doubleValue { |
- if (_state is DoubleState) { |
- return (_state as DoubleState).value; |
- } |
- return null; |
- } |
- |
- HashMap<String, DartObjectImpl> get fields => _state.fields; |
- |
- @override |
- bool get hasExactValue => _state.hasExactValue; |
- |
- @override |
- int get hashCode => JenkinsSmiHash.hash2(type.hashCode, _state.hashCode); |
- |
- @override |
- int get intValue { |
- if (_state is IntState) { |
- return (_state as IntState).value; |
- } |
- return null; |
- } |
- |
- /** |
- * Return `true` if this object represents an object whose type is 'bool'. |
- */ |
- bool get isBool => _state.isBool; |
- |
- /** |
- * Return `true` if this object represents an object whose type is either |
- * 'bool', 'num', 'String', or 'Null'. |
- */ |
- bool get isBoolNumStringOrNull => _state.isBoolNumStringOrNull; |
- |
- @override |
- bool get isFalse => |
- _state is BoolState && identical((_state as BoolState).value, false); |
- |
- @override |
- bool get isNull => _state is NullState; |
- |
- @override |
- bool get isTrue => |
- _state is BoolState && identical((_state as BoolState).value, true); |
- |
- /** |
- * Return `true` if this object represents an unknown value. |
- */ |
- bool get isUnknown => _state.isUnknown; |
- |
- /** |
- * Return `true` if this object represents an instance of a user-defined |
- * class. |
- */ |
- bool get isUserDefinedObject => _state is GenericState; |
- |
- @override |
- String get stringValue { |
- if (_state is StringState) { |
- return (_state as StringState).value; |
- } |
- return null; |
- } |
- |
- @override |
- Object get value => _state.value; |
- |
- @override |
- bool operator ==(Object object) { |
- if (object is! DartObjectImpl) { |
- return false; |
- } |
- DartObjectImpl dartObject = object as DartObjectImpl; |
- return type == dartObject.type && _state == dartObject._state; |
- } |
- |
- /** |
- * Return the result of invoking the '+' operator on this object with the |
- * given [rightOperand]. The [typeProvider] is the type provider used to find |
- * known types. |
- * |
- * Throws an [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); |
- } else if (result is StringState) { |
- return new DartObjectImpl(typeProvider.stringType, result); |
- } |
- // We should never get here. |
- throw new IllegalStateException("add returned a ${result.runtimeType}"); |
- } |
- |
- /** |
- * Return the result of invoking the '&' operator on this object with the |
- * [rightOperand]. The [typeProvider] is the type provider used to find known |
- * types. |
- * |
- * Throws an [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)); |
- |
- /** |
- * Return the result of invoking the '~' operator on this object. The |
- * [typeProvider] is the type provider used to find known types. |
- * |
- * Throws an [EvaluationException] if the operator is not appropriate for an |
- * object of this kind. |
- */ |
- DartObjectImpl bitNot(TypeProvider typeProvider) => |
- new DartObjectImpl(typeProvider.intType, _state.bitNot()); |
- |
- /** |
- * Return the result of invoking the '|' operator on this object with the |
- * [rightOperand]. The [typeProvider] is the type provider used to find known |
- * types. |
- * |
- * Throws an [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)); |
- |
- /** |
- * Return the result of invoking the '^' operator on this object with the |
- * [rightOperand]. The [typeProvider] is the type provider used to find known |
- * types. |
- * |
- * Throws an [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)); |
- |
- /** |
- * Return the result of invoking the ' ' operator on this object with the |
- * [rightOperand]. The [typeProvider] is the type provider used to find known |
- * types. |
- * |
- * Throws an [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)); |
- |
- /** |
- * Return the result of applying boolean conversion to this object. The |
- * [typeProvider] is the type provider used to find known types. |
- * |
- * Throws an [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()); |
- } |
- |
- /** |
- * Return the result of invoking the '/' operator on this object with the |
- * [rightOperand]. The [typeProvider] is the type provider used to find known |
- * types. |
- * |
- * Throws an [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}"); |
- } |
- |
- /** |
- * Return the result of invoking the '==' operator on this object with the |
- * [rightOperand]. The [typeProvider] is the type provider used to find known |
- * types. |
- * |
- * Throws an [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)); |
- } |
- |
- /** |
- * Return the result of invoking the '>' operator on this object with the |
- * [rightOperand]. The [typeProvider] is the type provider used to find known |
- * types. |
- * |
- * Throws an [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)); |
- |
- /** |
- * Return the result of invoking the '>=' operator on this object with the |
- * [rightOperand]. The [typeProvider] is the type provider used to find known |
- * types. |
- * |
- * Throws an [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)); |
- |
- /** |
- * Return the result of invoking the '~/' operator on this object with the |
- * [rightOperand]. The [typeProvider] is the type provider used to find known |
- * types. |
- * |
- * Throws an [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)); |
- |
- /** |
- * Return the result of invoking the identical function on this object with |
- * the [rightOperand]. The [typeProvider] is the type provider used to find |
- * known types. |
- */ |
- DartObjectImpl isIdentical( |
- TypeProvider typeProvider, DartObjectImpl rightOperand) { |
- return new DartObjectImpl( |
- typeProvider.boolType, _state.isIdentical(rightOperand._state)); |
- } |
- |
- /** |
- * Return the result of invoking the '<' operator on this object with the |
- * [rightOperand]. The [typeProvider] is the type provider used to find known |
- * types. |
- * |
- * Throws an [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)); |
- |
- /** |
- * Return the result of invoking the '<=' operator on this object with the |
- * [rightOperand]. The [typeProvider] is the type provider used to find known |
- * types. |
- * |
- * Throws an [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)); |
- |
- /** |
- * Return the result of invoking the '&&' operator on this object with the |
- * [rightOperand]. The [typeProvider] is the type provider used to find known |
- * types. |
- * |
- * Throws an [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)); |
- |
- /** |
- * Return the result of invoking the '!' operator on this object. The |
- * [typeProvider] is the type provider used to find known types. |
- * |
- * Throws an [EvaluationException] if the operator is not appropriate for an |
- * object of this kind. |
- */ |
- DartObjectImpl logicalNot(TypeProvider typeProvider) => |
- new DartObjectImpl(typeProvider.boolType, _state.logicalNot()); |
- |
- /** |
- * Return the result of invoking the '||' operator on this object with the |
- * [rightOperand]. The [typeProvider] is the type provider used to find known |
- * types. |
- * |
- * Throws an [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)); |
- |
- /** |
- * Return the result of invoking the '-' operator on this object with the |
- * [rightOperand]. The [typeProvider] is the type provider used to find known |
- * types. |
- * |
- * Throws an [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}"); |
- } |
- |
- /** |
- * Return the result of invoking the '-' operator on this object. The |
- * [typeProvider] is the type provider used to find known types. |
- * |
- * Throws an [EvaluationException] if the operator is not appropriate for an |
- * object of this kind. |
- */ |
- 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}"); |
- } |
- |
- /** |
- * Return the result of invoking the '!=' operator on this object with the |
- * [rightOperand]. The [typeProvider] is the type provider used to find known |
- * types. |
- * |
- * Throws an [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()); |
- } |
- |
- /** |
- * Return the result of converting this object to a 'String'. The |
- * [typeProvider] is the type provider used to find known types. |
- * |
- * Throws an [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()); |
- } |
- |
- /** |
- * Return the result of invoking the '%' operator on this object with the |
- * [rightOperand]. The [typeProvider] is the type provider used to find known |
- * types. |
- * |
- * Throws an [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}"); |
- } |
- |
- /** |
- * Return the result of invoking the '<<' operator on this object with |
- * the [rightOperand]. The [typeProvider] is the type provider used to find |
- * known types. |
- * |
- * Throws an [EvaluationException] if the operator is not appropriate for an |
- * object of this kind. |
- */ |
- DartObjectImpl shiftLeft( |
- TypeProvider typeProvider, DartObjectImpl rightOperand) => |
- new DartObjectImpl( |
- typeProvider.intType, _state.shiftLeft(rightOperand._state)); |
- |
- /** |
- * Return the result of invoking the '>>' operator on this object with |
- * the [rightOperand]. The [typeProvider] is the type provider used to find |
- * known types. |
- * |
- * Throws an [EvaluationException] if the operator is not appropriate for an |
- * object of this kind. |
- */ |
- DartObjectImpl shiftRight( |
- TypeProvider typeProvider, DartObjectImpl rightOperand) => |
- new DartObjectImpl( |
- typeProvider.intType, _state.shiftRight(rightOperand._state)); |
- |
- /** |
- * Return the result of invoking the 'length' getter on this object. The |
- * [typeProvider] is the type provider used to find known types. |
- * |
- * Throws an [EvaluationException] if the operator is not appropriate for an |
- * object of this kind. |
- */ |
- DartObjectImpl stringLength(TypeProvider typeProvider) => |
- new DartObjectImpl(typeProvider.intType, _state.stringLength()); |
- |
- /** |
- * Return the result of invoking the '*' operator on this object with the |
- * [rightOperand]. The [typeProvider] is the type provider used to find known |
- * types. |
- * |
- * Throws an [EvaluationException] if the operator is not appropriate for an |
- * object of this kind. |
- */ |
- 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}"); |
- } |
- |
- @override |
- String toString() => "${type.displayName} ($_state)"; |
-} |
- |
-/** |
- * An object used to provide access to the values of variables that have been |
- * defined on the command line using the `-D` option. |
- */ |
-class DeclaredVariables { |
- /** |
- * A table mapping the names of declared variables to their values. |
- */ |
- HashMap<String, String> _declaredVariables = new HashMap<String, String>(); |
- |
- /** |
- * Define a variable with the given [name] to have the given [value]. |
- */ |
- void define(String name, String value) { |
- _declaredVariables[name] = value; |
- } |
- |
- /** |
- * Return the value of the variable with the given [name] interpreted as a |
- * 'boolean' value. If the variable is not defined (or [name] is `null`), a |
- * DartObject representing "unknown" is returned. If the value cannot be |
- * parsed as a boolean, a DartObject representing 'null' is returned. The |
- * [typeProvider] is the type provider used to find the type 'bool'. |
- */ |
- DartObject getBool(TypeProvider typeProvider, String name) { |
- String value = _declaredVariables[name]; |
- if (value == null) { |
- return new DartObjectImpl(typeProvider.boolType, BoolState.UNKNOWN_VALUE); |
- } |
- if (value == "true") { |
- return new DartObjectImpl(typeProvider.boolType, BoolState.TRUE_STATE); |
- } else if (value == "false") { |
- return new DartObjectImpl(typeProvider.boolType, BoolState.FALSE_STATE); |
- } |
- return new DartObjectImpl(typeProvider.nullType, NullState.NULL_STATE); |
- } |
- |
- /** |
- * Return the value of the variable with the given [name] interpreted as an |
- * integer value. If the variable is not defined (or [name] is `null`), a |
- * DartObject representing "unknown" is returned. If the value cannot be |
- * parsed as an integer, a DartObject representing 'null' is returned. |
- */ |
- DartObject getInt(TypeProvider typeProvider, String name) { |
- String value = _declaredVariables[name]; |
- if (value == null) { |
- return new DartObjectImpl(typeProvider.intType, IntState.UNKNOWN_VALUE); |
- } |
- int bigInteger; |
- try { |
- bigInteger = int.parse(value); |
- } on FormatException { |
- return new DartObjectImpl(typeProvider.nullType, NullState.NULL_STATE); |
- } |
- return new DartObjectImpl(typeProvider.intType, new IntState(bigInteger)); |
- } |
- |
- /** |
- * Return the value of the variable with the given [name] interpreted as a |
- * String value, or `null` if the variable is not defined. Return the value of |
- * the variable with the given name interpreted as a String value. If the |
- * variable is not defined (or [name] is `null`), a DartObject representing |
- * "unknown" is returned. The [typeProvider] is the type provider used to find |
- * the type 'String'. |
- */ |
- DartObject getString(TypeProvider typeProvider, String name) { |
- String value = _declaredVariables[name]; |
- if (value == null) { |
- return new DartObjectImpl( |
- typeProvider.stringType, StringState.UNKNOWN_VALUE); |
- } |
- return new DartObjectImpl(typeProvider.stringType, new StringState(value)); |
- } |
-} |
- |
-/** |
- * The state of an object representing a double. |
- */ |
-class DoubleState extends NumState { |
- /** |
- * A state that can be used to represent a double whose value is not known. |
- */ |
- static DoubleState UNKNOWN_VALUE = new DoubleState(null); |
- |
- /** |
- * The value of this instance. |
- */ |
- final double value; |
- |
- /** |
- * Initialize a newly created state to represent a double with the given |
- * [value]. |
- */ |
- DoubleState(this.value); |
- |
- @override |
- bool get hasExactValue => true; |
- |
- @override |
- int get hashCode => value == null ? 0 : value.hashCode; |
- |
- @override |
- bool get isBoolNumStringOrNull => true; |
- |
- @override |
- bool get isUnknown => value == null; |
- |
- @override |
- String get typeName => "double"; |
- |
- @override |
- bool operator ==(Object object) => |
- object is DoubleState && (value == object.value); |
- |
- @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); |
- } |
- |
- @override |
- StringState convertToString() { |
- if (value == null) { |
- return StringState.UNKNOWN_VALUE; |
- } |
- return new StringState(value.toString()); |
- } |
- |
- @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); |
- } |
- |
- @override |
- BoolState equalEqual(InstanceState rightOperand) { |
- assertBoolNumStringOrNull(rightOperand); |
- return isIdentical(rightOperand); |
- } |
- |
- @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); |
- } |
- |
- @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); |
- } |
- |
- @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); |
- } |
- |
- @override |
- BoolState isIdentical(InstanceState 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 |
- 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); |
- } |
- |
- @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); |
- } |
- |
- @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); |
- } |
- |
- @override |
- NumState negated() { |
- if (value == null) { |
- return UNKNOWN_VALUE; |
- } |
- return new DoubleState(-(value)); |
- } |
- |
- @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); |
- } |
- |
- @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); |
- } |
- |
- @override |
- String toString() => value == null ? "-unknown-" : value.toString(); |
-} |
- |
-/** |
- * 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 |
- bool get isBool => true; |
- |
- @override |
- bool get isBoolNumStringOrNull => true; |
- |
- @override |
- String get typeName => "dynamic"; |
- |
- @override |
- NumState add(InstanceState rightOperand) { |
- assertNumOrNull(rightOperand); |
- return _unknownNum(rightOperand); |
- } |
- |
- @override |
- IntState bitAnd(InstanceState rightOperand) { |
- assertIntOrNull(rightOperand); |
- return IntState.UNKNOWN_VALUE; |
- } |
- |
- @override |
- IntState bitNot() => IntState.UNKNOWN_VALUE; |
- |
- @override |
- IntState bitOr(InstanceState rightOperand) { |
- assertIntOrNull(rightOperand); |
- return IntState.UNKNOWN_VALUE; |
- } |
- |
- @override |
- IntState bitXor(InstanceState rightOperand) { |
- assertIntOrNull(rightOperand); |
- return IntState.UNKNOWN_VALUE; |
- } |
- |
- @override |
- StringState concatenate(InstanceState rightOperand) { |
- assertString(rightOperand); |
- return StringState.UNKNOWN_VALUE; |
- } |
- |
- @override |
- BoolState convertToBool() => BoolState.UNKNOWN_VALUE; |
- |
- @override |
- StringState convertToString() => StringState.UNKNOWN_VALUE; |
- |
- @override |
- NumState divide(InstanceState rightOperand) { |
- assertNumOrNull(rightOperand); |
- return _unknownNum(rightOperand); |
- } |
- |
- @override |
- BoolState equalEqual(InstanceState rightOperand) { |
- assertBoolNumStringOrNull(rightOperand); |
- return BoolState.UNKNOWN_VALUE; |
- } |
- |
- @override |
- BoolState greaterThan(InstanceState rightOperand) { |
- assertNumOrNull(rightOperand); |
- return BoolState.UNKNOWN_VALUE; |
- } |
- |
- @override |
- BoolState greaterThanOrEqual(InstanceState rightOperand) { |
- assertNumOrNull(rightOperand); |
- return BoolState.UNKNOWN_VALUE; |
- } |
- |
- @override |
- IntState integerDivide(InstanceState rightOperand) { |
- assertNumOrNull(rightOperand); |
- return IntState.UNKNOWN_VALUE; |
- } |
- |
- @override |
- BoolState isIdentical(InstanceState rightOperand) { |
- return BoolState.UNKNOWN_VALUE; |
- } |
- |
- @override |
- BoolState lessThan(InstanceState rightOperand) { |
- assertNumOrNull(rightOperand); |
- return BoolState.UNKNOWN_VALUE; |
- } |
- |
- @override |
- BoolState lessThanOrEqual(InstanceState rightOperand) { |
- assertNumOrNull(rightOperand); |
- return BoolState.UNKNOWN_VALUE; |
- } |
- |
- @override |
- BoolState logicalAnd(InstanceState rightOperand) { |
- assertBool(rightOperand); |
- return BoolState.UNKNOWN_VALUE; |
- } |
- |
- @override |
- BoolState logicalNot() => BoolState.UNKNOWN_VALUE; |
- |
- @override |
- BoolState logicalOr(InstanceState rightOperand) { |
- assertBool(rightOperand); |
- return rightOperand.convertToBool(); |
- } |
- |
- @override |
- NumState minus(InstanceState rightOperand) { |
- assertNumOrNull(rightOperand); |
- return _unknownNum(rightOperand); |
- } |
- |
- @override |
- NumState negated() => NumState.UNKNOWN_VALUE; |
- |
- @override |
- NumState remainder(InstanceState rightOperand) { |
- assertNumOrNull(rightOperand); |
- return _unknownNum(rightOperand); |
- } |
- |
- @override |
- IntState shiftLeft(InstanceState rightOperand) { |
- assertIntOrNull(rightOperand); |
- return IntState.UNKNOWN_VALUE; |
- } |
- |
- @override |
- IntState shiftRight(InstanceState rightOperand) { |
- assertIntOrNull(rightOperand); |
- return IntState.UNKNOWN_VALUE; |
- } |
- |
- @override |
- NumState times(InstanceState rightOperand) { |
- assertNumOrNull(rightOperand); |
- return _unknownNum(rightOperand); |
- } |
- |
- /** |
- * Return an object representing an unknown numeric value whose type is based |
- * on the type of the [rightOperand]. |
- */ |
- 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; |
- } |
-} |
- |
-/** |
- * 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. |
- */ |
- final ErrorCode errorCode; |
- |
- /** |
- * Initialize a newly created exception to have the given [errorCode]. |
- */ |
- EvaluationException(this.errorCode); |
-} |
- |
-/** |
- * The result of attempting to evaluate an expression. |
- */ |
-class EvaluationResult { |
- /** |
- * 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 [value] and set of |
- * [_errors]. Clients should use one of the factory methods: [forErrors] and |
- * [forValue]. |
- */ |
- EvaluationResult(this.value, this._errors); |
- |
- /** |
- * Return a list containing the errors that should be reported for the |
- * expression(s) that were evaluated. If there are no such errors, the list |
- * will be empty. The list 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. |
- */ |
- bool get isValid => _errors == null; |
- |
- /** |
- * Return an evaluation result representing the result of evaluating an |
- * expression that is not a compile-time constant because of the given |
- * [errors]. |
- */ |
- 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]. |
- */ |
- static EvaluationResult forValue(DartObject value) => |
- new EvaluationResult(value, null); |
-} |
- |
-/** |
- * The result of attempting to evaluate a expression. |
- */ |
-class EvaluationResultImpl { |
- /** |
- * The errors encountered while trying to evaluate the compile time constant. |
- * These errors may or may not have prevented the expression from being a |
- * valid compile time constant. |
- */ |
- List<AnalysisError> _errors; |
- |
- /** |
- * The value of the expression, or `null` if the value couldn't be computed |
- * due to errors. |
- */ |
- final DartObjectImpl value; |
- |
- EvaluationResultImpl(this.value, [List<AnalysisError> errors]) { |
- this._errors = errors == null ? <AnalysisError>[] : errors; |
- } |
- |
- @deprecated // Use new EvaluationResultImpl(value) |
- EvaluationResultImpl.con1(this.value) { |
- this._errors = new List<AnalysisError>(0); |
- } |
- |
- @deprecated // Use new EvaluationResultImpl(value, errors) |
- EvaluationResultImpl.con2(this.value, List<AnalysisError> errors) { |
- this._errors = errors; |
- } |
- |
- List<AnalysisError> get errors => _errors; |
- |
- bool equalValues(TypeProvider typeProvider, EvaluationResultImpl result) { |
- if (this.value != null) { |
- if (result.value == null) { |
- return false; |
- } |
- return value == result.value; |
- } else { |
- return false; |
- } |
- } |
- |
- @override |
- String toString() { |
- if (value == null) { |
- return "error"; |
- } |
- return value.toString(); |
- } |
-} |
- |
-/** |
- * The state of an object representing a function. |
- */ |
-class FunctionState extends InstanceState { |
- /** |
- * The element representing the function being modeled. |
- */ |
- final ExecutableElement _element; |
- |
- /** |
- * Initialize a newly created state to represent the function with the given |
- * [element]. |
- */ |
- FunctionState(this._element); |
- |
- @override |
- int get hashCode => _element == null ? 0 : _element.hashCode; |
- |
- @override |
- String get typeName => "Function"; |
- |
- @override |
- bool operator ==(Object object) => |
- object is FunctionState && (_element == object._element); |
- |
- @override |
- StringState convertToString() { |
- if (_element == null) { |
- return StringState.UNKNOWN_VALUE; |
- } |
- return new StringState(_element.name); |
- } |
- |
- @override |
- BoolState equalEqual(InstanceState rightOperand) { |
- return isIdentical(rightOperand); |
- } |
- |
- @override |
- BoolState isIdentical(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; |
- } |
- |
- @override |
- String toString() => _element == null ? "-unknown-" : _element.name; |
-} |
- |
-/** |
- * The state of an object representing a Dart object for which there is no more |
- * specific state. |
- */ |
-class GenericState extends InstanceState { |
- /** |
- * Pseudo-field that we use to represent fields in the superclass. |
- */ |
- static String SUPERCLASS_FIELD = "(super)"; |
- |
- /** |
- * A state that can be used to represent an object whose state is not known. |
- */ |
- static GenericState UNKNOWN_VALUE = |
- new GenericState(new HashMap<String, DartObjectImpl>()); |
- |
- /** |
- * The values of the fields of this instance. |
- */ |
- final HashMap<String, DartObjectImpl> _fieldMap; |
- |
- /** |
- * Initialize a newly created state to represent a newly created object. The |
- * [fieldMap] contains the values of the fields of the instance. |
- */ |
- GenericState(this._fieldMap); |
- |
- @override |
- HashMap<String, DartObjectImpl> get fields => _fieldMap; |
- |
- @override |
- int get hashCode { |
- int hashCode = 0; |
- for (DartObjectImpl value in _fieldMap.values) { |
- hashCode += value.hashCode; |
- } |
- return hashCode; |
- } |
- |
- @override |
- bool get isUnknown => identical(this, UNKNOWN_VALUE); |
- |
- @override |
- String get typeName => "user defined type"; |
- |
- @override |
- bool operator ==(Object object) { |
- if (object is! GenericState) { |
- return false; |
- } |
- GenericState state = object as GenericState; |
- HashSet<String> otherFields = |
- new HashSet<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 |
- StringState convertToString() => StringState.UNKNOWN_VALUE; |
- |
- @override |
- BoolState equalEqual(InstanceState rightOperand) { |
- assertBoolNumStringOrNull(rightOperand); |
- return isIdentical(rightOperand); |
- } |
- |
- @override |
- BoolState isIdentical(InstanceState rightOperand) { |
- if (rightOperand is DynamicState) { |
- return BoolState.UNKNOWN_VALUE; |
- } |
- return BoolState.from(this == rightOperand); |
- } |
- |
- @override |
- String toString() { |
- StringBuffer buffer = new StringBuffer(); |
- List<String> fieldNames = _fieldMap.keys.toList(); |
- fieldNames.sort(); |
- bool first = true; |
- for (String fieldName in fieldNames) { |
- if (first) { |
- first = false; |
- } else { |
- buffer.write('; '); |
- } |
- buffer.write(fieldName); |
- buffer.write(' = '); |
- buffer.write(_fieldMap[fieldName]); |
- } |
- return buffer.toString(); |
- } |
-} |
- |
-/** |
- * The state of an object representing a Dart object. |
- */ |
-abstract class InstanceState { |
- /** |
- * If this represents a generic dart object, return a map from its field names |
- * to their values. Otherwise return null. |
- */ |
- HashMap<String, DartObjectImpl> get fields => null; |
- |
- /** |
- * Return `true` if this object's value can be represented exactly. |
- */ |
- bool get hasExactValue => false; |
- |
- /** |
- * Return `true` if this object represents an object whose type is 'bool'. |
- */ |
- bool get isBool => false; |
- |
- /** |
- * Return `true` if this object represents an object whose type is either |
- * 'bool', 'num', 'String', or 'Null'. |
- */ |
- bool get isBoolNumStringOrNull => false; |
- |
- /** |
- * Return `true` if this object represents an unknown value. |
- */ |
- bool get isUnknown => false; |
- |
- /** |
- * Return the name of the type of this value. |
- */ |
- String get typeName; |
- |
- /** |
- * 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. |
- */ |
- Object get value => null; |
- |
- /** |
- * Return the result of invoking the '+' operator on this object with the |
- * [rightOperand]. |
- * |
- * Throws an [EvaluationException] if the operator is not appropriate for an |
- * object of this kind. |
- */ |
- InstanceState add(InstanceState rightOperand) { |
- if (this is StringState && rightOperand is StringState) { |
- return concatenate(rightOperand); |
- } |
- assertNumOrNull(this); |
- assertNumOrNull(rightOperand); |
- throw new EvaluationException(CompileTimeErrorCode.INVALID_CONSTANT); |
- } |
- |
- /** |
- * Throw an exception if the given [state] does not represent a boolean value. |
- */ |
- void assertBool(InstanceState state) { |
- if (!(state is BoolState || state is DynamicState)) { |
- throw new EvaluationException(CompileTimeErrorCode.CONST_EVAL_TYPE_BOOL); |
- } |
- } |
- |
- /** |
- * Throw an exception if the given [state] does not represent a boolean, |
- * numeric, string or null value. |
- */ |
- 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); |
- } |
- } |
- |
- /** |
- * Throw an exception 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); |
- } |
- } |
- |
- /** |
- * Throw an exception 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); |
- } |
- } |
- |
- /** |
- * Throw an exception 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); |
- } |
- } |
- |
- /** |
- * Return the result of invoking the '&' operator on this object with the |
- * [rightOperand]. |
- * |
- * Throws an [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); |
- } |
- |
- /** |
- * Return the result of invoking the '~' operator on this object. |
- * |
- * Throws an [EvaluationException] if the operator is not appropriate for an |
- * object of this kind. |
- */ |
- IntState bitNot() { |
- assertIntOrNull(this); |
- throw new EvaluationException(CompileTimeErrorCode.INVALID_CONSTANT); |
- } |
- |
- /** |
- * Return the result of invoking the '|' operator on this object with the |
- * [rightOperand]. |
- * |
- * Throws an [EvaluationException] if the operator is not appropriate for an |
- * object of this kind. |
- */ |
- IntState bitOr(InstanceState rightOperand) { |
- assertIntOrNull(this); |
- assertIntOrNull(rightOperand); |
- throw new EvaluationException(CompileTimeErrorCode.INVALID_CONSTANT); |
- } |
- |
- /** |
- * Return the result of invoking the '^' operator on this object with the |
- * [rightOperand]. |
- * |
- * Throws an [EvaluationException] if the operator is not appropriate for an |
- * object of this kind. |
- */ |
- IntState bitXor(InstanceState rightOperand) { |
- assertIntOrNull(this); |
- assertIntOrNull(rightOperand); |
- throw new EvaluationException(CompileTimeErrorCode.INVALID_CONSTANT); |
- } |
- |
- /** |
- * Return the result of invoking the ' ' operator on this object with the |
- * [rightOperand]. |
- * |
- * Throws an [EvaluationException] if the operator is not appropriate for an |
- * object of this kind. |
- */ |
- StringState concatenate(InstanceState rightOperand) { |
- assertString(rightOperand); |
- throw new EvaluationException(CompileTimeErrorCode.INVALID_CONSTANT); |
- } |
- |
- /** |
- * Return the result of applying boolean conversion to this object. |
- * |
- * Throws an [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. |
- * |
- * Throws an [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 |
- * [rightOperand]. |
- * |
- * Throws an [EvaluationException] if the operator is not appropriate for an |
- * object of this kind. |
- */ |
- NumState divide(InstanceState rightOperand) { |
- assertNumOrNull(this); |
- assertNumOrNull(rightOperand); |
- throw new EvaluationException(CompileTimeErrorCode.INVALID_CONSTANT); |
- } |
- |
- /** |
- * Return the result of invoking the '==' operator on this object with the |
- * [rightOperand]. |
- * |
- * Throws an [EvaluationException] if the operator is not appropriate for an |
- * object of this kind. |
- */ |
- BoolState equalEqual(InstanceState rightOperand); |
- |
- /** |
- * Return the result of invoking the '>' operator on this object with the |
- * [rightOperand]. |
- * |
- * Throws an [EvaluationException] if the operator is not appropriate for an |
- * object of this kind. |
- */ |
- BoolState greaterThan(InstanceState rightOperand) { |
- assertNumOrNull(this); |
- assertNumOrNull(rightOperand); |
- throw new EvaluationException(CompileTimeErrorCode.INVALID_CONSTANT); |
- } |
- |
- /** |
- * Return the result of invoking the '>=' operator on this object with the |
- * [rightOperand]. |
- * |
- * Throws an [EvaluationException] if the operator is not appropriate for an |
- * object of this kind. |
- */ |
- BoolState greaterThanOrEqual(InstanceState rightOperand) { |
- assertNumOrNull(this); |
- assertNumOrNull(rightOperand); |
- throw new EvaluationException(CompileTimeErrorCode.INVALID_CONSTANT); |
- } |
- |
- /** |
- * Return the result of invoking the '~/' operator on this object with the |
- * [rightOperand]. |
- * |
- * Throws an [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); |
- } |
- |
- /** |
- * Return the result of invoking the identical function on this object with |
- * the [rightOperand]. |
- */ |
- BoolState isIdentical(InstanceState rightOperand); |
- |
- /** |
- * Return the result of invoking the '<' operator on this object with the |
- * [rightOperand]. |
- * |
- * Throws an [EvaluationException] if the operator is not appropriate for an |
- * object of this kind. |
- */ |
- BoolState lessThan(InstanceState rightOperand) { |
- assertNumOrNull(this); |
- assertNumOrNull(rightOperand); |
- throw new EvaluationException(CompileTimeErrorCode.INVALID_CONSTANT); |
- } |
- |
- /** |
- * Return the result of invoking the '<=' operator on this object with the |
- * [rightOperand]. |
- * |
- * Throws an [EvaluationException] if the operator is not appropriate for an |
- * object of this kind. |
- */ |
- 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 |
- * [rightOperand]. |
- * |
- * Throws an [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. |
- * |
- * Throws an [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 |
- * [rightOperand]. |
- * |
- * Throws an [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 |
- * [rightOperand]. |
- * |
- * Throws an [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); |
- } |
- |
- /** |
- * Return the result of invoking the '-' operator on this object. |
- * |
- * Throws an [EvaluationException] if the operator is not appropriate for an |
- * object of this kind. |
- */ |
- NumState negated() { |
- assertNumOrNull(this); |
- throw new EvaluationException(CompileTimeErrorCode.INVALID_CONSTANT); |
- } |
- |
- /** |
- * Return the result of invoking the '%' operator on this object with the |
- * [rightOperand]. |
- * |
- * Throws an [EvaluationException] if the operator is not appropriate for an |
- * object of this kind. |
- */ |
- 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 [rightOperand]. |
- * |
- * Throws an [EvaluationException] if the operator is not appropriate for an |
- * object of this kind. |
- */ |
- IntState shiftLeft(InstanceState rightOperand) { |
- assertIntOrNull(this); |
- assertIntOrNull(rightOperand); |
- throw new EvaluationException(CompileTimeErrorCode.INVALID_CONSTANT); |
- } |
- |
- /** |
- * Return the result of invoking the '>>' operator on this object with |
- * the [rightOperand]. |
- * |
- * Throws an [EvaluationException] if the operator is not appropriate for an |
- * object of this kind. |
- */ |
- IntState shiftRight(InstanceState rightOperand) { |
- assertIntOrNull(this); |
- assertIntOrNull(rightOperand); |
- throw new EvaluationException(CompileTimeErrorCode.INVALID_CONSTANT); |
- } |
- |
- /** |
- * Return the result of invoking the 'length' getter on this object. |
- * |
- * Throws an [EvaluationException] if the operator is not appropriate for an |
- * object of this kind. |
- */ |
- IntState stringLength() { |
- assertString(this); |
- throw new EvaluationException(CompileTimeErrorCode.INVALID_CONSTANT); |
- } |
- |
- /** |
- * Return the result of invoking the '*' operator on this object with the |
- * [rightOperand]. |
- * |
- * Throws an [EvaluationException] if the operator is not appropriate for an |
- * object of this kind. |
- */ |
- NumState times(InstanceState rightOperand) { |
- assertNumOrNull(this); |
- assertNumOrNull(rightOperand); |
- throw new EvaluationException(CompileTimeErrorCode.INVALID_CONSTANT); |
- } |
-} |
- |
-/** |
- * The state of an object representing an int. |
- */ |
-class IntState extends NumState { |
- /** |
- * A state that can be used to represent an int whose value is not known. |
- */ |
- static IntState UNKNOWN_VALUE = new IntState(null); |
- |
- /** |
- * The value of this instance. |
- */ |
- final int value; |
- |
- /** |
- * Initialize a newly created state to represent an int with the given |
- * [value]. |
- */ |
- IntState(this.value); |
- |
- @override |
- bool get hasExactValue => true; |
- |
- @override |
- int get hashCode => value == null ? 0 : value.hashCode; |
- |
- @override |
- bool get isBoolNumStringOrNull => true; |
- |
- @override |
- bool get isUnknown => value == null; |
- |
- @override |
- String get typeName => "int"; |
- |
- @override |
- bool operator ==(Object object) => |
- object is IntState && (value == object.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(rightOperand); |
- if (value == null) { |
- return DoubleState.UNKNOWN_VALUE; |
- } |
- if (rightOperand is IntState) { |
- int rightValue = rightOperand.value; |
- if (rightValue == null) { |
- return DoubleState.UNKNOWN_VALUE; |
- } else { |
- return new DoubleState(value.toDouble() / rightValue.toDouble()); |
- } |
- } 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 DoubleState.UNKNOWN_VALUE; |
- } |
- throw new EvaluationException( |
- CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION); |
- } |
- |
- @override |
- BoolState equalEqual(InstanceState rightOperand) { |
- assertBoolNumStringOrNull(rightOperand); |
- return isIdentical(rightOperand); |
- } |
- |
- @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); |
- } |
- |
- @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); |
- } |
- |
- @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; |
- } 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); |
- } |
- |
- @override |
- BoolState isIdentical(InstanceState 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; |
- } |
- |
- @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); |
- } |
- |
- @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); |
- } |
- |
- @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); |
- } |
- |
- @override |
- NumState negated() { |
- if (value == null) { |
- return UNKNOWN_VALUE; |
- } |
- return new IntState(-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); |
- } |
- |
- @override |
- IntState shiftLeft(InstanceState rightOperand) { |
- assertIntOrNull(rightOperand); |
- 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); |
- } |
- |
- @override |
- IntState shiftRight(InstanceState rightOperand) { |
- assertIntOrNull(rightOperand); |
- 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); |
- } |
- |
- @override |
- NumState times(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 |
- String toString() => value == null ? "-unknown-" : value.toString(); |
-} |
- |
-/** |
- * The state of an object representing a list. |
- */ |
-class ListState extends InstanceState { |
- /** |
- * The elements of the list. |
- */ |
- final List<DartObjectImpl> _elements; |
- |
- /** |
- * Initialize a newly created state to represent a list with the given |
- * [elements]. |
- */ |
- ListState(this._elements); |
- |
- @override |
- bool get hasExactValue { |
- int count = _elements.length; |
- for (int i = 0; i < count; i++) { |
- if (!_elements[i].hasExactValue) { |
- return false; |
- } |
- } |
- return 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; |
- } |
- |
- @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 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; |
- } |
- |
- @override |
- StringState convertToString() => StringState.UNKNOWN_VALUE; |
- |
- @override |
- BoolState equalEqual(InstanceState rightOperand) { |
- assertBoolNumStringOrNull(rightOperand); |
- return isIdentical(rightOperand); |
- } |
- |
- @override |
- BoolState isIdentical(InstanceState rightOperand) { |
- if (rightOperand is DynamicState) { |
- return BoolState.UNKNOWN_VALUE; |
- } |
- return BoolState.from(this == rightOperand); |
- } |
- |
- @override |
- String toString() { |
- StringBuffer buffer = new StringBuffer(); |
- buffer.write('['); |
- bool first = true; |
- _elements.forEach((DartObjectImpl element) { |
- if (first) { |
- first = false; |
- } else { |
- buffer.write(', '); |
- } |
- buffer.write(element); |
- }); |
- buffer.write(']'); |
- return buffer.toString(); |
- } |
-} |
- |
-/** |
- * The state of an object representing a map. |
- */ |
-class MapState extends InstanceState { |
- /** |
- * The entries in the map. |
- */ |
- final HashMap<DartObjectImpl, DartObjectImpl> _entries; |
- |
- /** |
- * Initialize a newly created state to represent a map with the given |
- * [entries]. |
- */ |
- MapState(this._entries); |
- |
- @override |
- bool get hasExactValue { |
- for (DartObjectImpl key in _entries.keys) { |
- if (!key.hasExactValue || !_entries[key].hasExactValue) { |
- return false; |
- } |
- } |
- return true; |
- } |
- |
- @override |
- int get hashCode { |
- int value = 0; |
- for (DartObjectImpl key in _entries.keys.toSet()) { |
- value = (value << 3) ^ key.hashCode; |
- } |
- return value; |
- } |
- |
- @override |
- String get typeName => "Map"; |
- |
- @override |
- Map<Object, Object> get value { |
- HashMap<Object, Object> result = new HashMap<Object, Object>(); |
- for (DartObjectImpl key in _entries.keys) { |
- DartObjectImpl value = _entries[key]; |
- if (!key.hasExactValue || !value.hasExactValue) { |
- return null; |
- } |
- result[key.value] = value.value; |
- } |
- return result; |
- } |
- |
- @override |
- bool operator ==(Object object) { |
- if (object is! MapState) { |
- return false; |
- } |
- HashMap<DartObjectImpl, DartObjectImpl> otherElements = |
- (object as MapState)._entries; |
- int count = _entries.length; |
- if (otherElements.length != count) { |
- return false; |
- } else if (count == 0) { |
- return true; |
- } |
- for (DartObjectImpl key in _entries.keys) { |
- DartObjectImpl value = _entries[key]; |
- DartObjectImpl otherValue = otherElements[key]; |
- if (value != otherValue) { |
- return false; |
- } |
- } |
- return true; |
- } |
- |
- @override |
- StringState convertToString() => StringState.UNKNOWN_VALUE; |
- |
- @override |
- BoolState equalEqual(InstanceState rightOperand) { |
- assertBoolNumStringOrNull(rightOperand); |
- return isIdentical(rightOperand); |
- } |
- |
- @override |
- BoolState isIdentical(InstanceState rightOperand) { |
- if (rightOperand is DynamicState) { |
- return BoolState.UNKNOWN_VALUE; |
- } |
- return BoolState.from(this == rightOperand); |
- } |
- |
- @override |
- String toString() { |
- StringBuffer buffer = new StringBuffer(); |
- buffer.write('{'); |
- bool first = true; |
- _entries.forEach((DartObjectImpl key, DartObjectImpl value) { |
- if (first) { |
- first = false; |
- } else { |
- buffer.write(', '); |
- } |
- buffer.write(key); |
- buffer.write(' = '); |
- buffer.write(value); |
- }); |
- buffer.write('}'); |
- return buffer.toString(); |
- } |
-} |
- |
-/** |
- * The state of an object representing the value 'null'. |
- */ |
-class NullState extends InstanceState { |
- /** |
- * An instance representing the boolean value 'null'. |
- */ |
- static NullState NULL_STATE = new NullState(); |
- |
- @override |
- bool get hasExactValue => true; |
- |
- @override |
- int get hashCode => 0; |
- |
- @override |
- bool get isBoolNumStringOrNull => true; |
- |
- @override |
- String get typeName => "Null"; |
- |
- @override |
- bool operator ==(Object object) => object is NullState; |
- |
- @override |
- BoolState convertToBool() { |
- throw new EvaluationException( |
- CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION); |
- } |
- |
- @override |
- StringState convertToString() => new StringState("null"); |
- |
- @override |
- BoolState equalEqual(InstanceState rightOperand) { |
- assertBoolNumStringOrNull(rightOperand); |
- return isIdentical(rightOperand); |
- } |
- |
- @override |
- BoolState isIdentical(InstanceState rightOperand) { |
- if (rightOperand is DynamicState) { |
- return BoolState.UNKNOWN_VALUE; |
- } |
- return BoolState.from(rightOperand is NullState); |
- } |
- |
- @override |
- BoolState logicalNot() { |
- throw new EvaluationException( |
- CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION); |
- } |
- |
- @override |
- String toString() => "null"; |
-} |
- |
-/** |
- * 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 |
- int get hashCode => 7; |
- |
- @override |
- bool get isBoolNumStringOrNull => true; |
- |
- @override |
- bool get isUnknown => identical(this, UNKNOWN_VALUE); |
- |
- @override |
- String get typeName => "num"; |
- |
- @override |
- bool operator ==(Object object) => object is NumState; |
- |
- @override |
- NumState add(InstanceState rightOperand) { |
- assertNumOrNull(rightOperand); |
- return UNKNOWN_VALUE; |
- } |
- |
- @override |
- StringState convertToString() => StringState.UNKNOWN_VALUE; |
- |
- @override |
- NumState divide(InstanceState rightOperand) { |
- assertNumOrNull(rightOperand); |
- return DoubleState.UNKNOWN_VALUE; |
- } |
- |
- @override |
- BoolState equalEqual(InstanceState rightOperand) { |
- assertBoolNumStringOrNull(rightOperand); |
- return BoolState.UNKNOWN_VALUE; |
- } |
- |
- @override |
- BoolState greaterThan(InstanceState rightOperand) { |
- assertNumOrNull(rightOperand); |
- return BoolState.UNKNOWN_VALUE; |
- } |
- |
- @override |
- BoolState greaterThanOrEqual(InstanceState rightOperand) { |
- assertNumOrNull(rightOperand); |
- return BoolState.UNKNOWN_VALUE; |
- } |
- |
- @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; |
- } |
- return IntState.UNKNOWN_VALUE; |
- } |
- |
- @override |
- BoolState isIdentical(InstanceState rightOperand) { |
- return BoolState.UNKNOWN_VALUE; |
- } |
- |
- @override |
- BoolState lessThan(InstanceState rightOperand) { |
- assertNumOrNull(rightOperand); |
- return BoolState.UNKNOWN_VALUE; |
- } |
- |
- @override |
- BoolState lessThanOrEqual(InstanceState rightOperand) { |
- assertNumOrNull(rightOperand); |
- return BoolState.UNKNOWN_VALUE; |
- } |
- |
- @override |
- NumState minus(InstanceState rightOperand) { |
- assertNumOrNull(rightOperand); |
- return UNKNOWN_VALUE; |
- } |
- |
- @override |
- NumState negated() => UNKNOWN_VALUE; |
- |
- @override |
- NumState remainder(InstanceState rightOperand) { |
- assertNumOrNull(rightOperand); |
- return UNKNOWN_VALUE; |
- } |
- |
- @override |
- NumState times(InstanceState rightOperand) { |
- assertNumOrNull(rightOperand); |
- return UNKNOWN_VALUE; |
- } |
- |
- @override |
- String toString() => "-unknown-"; |
-} |
- |
-/** |
- * An object used to 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 callback which should be used to report any dependencies that were |
- * found. |
- */ |
- final ReferenceFinderCallback _callback; |
- |
- /** |
- * Initialize a newly created reference finder to find references from a given |
- * variable to other variables and to add those references to the given graph. |
- * The [_callback] will be invoked for every dependency found. |
- */ |
- ReferenceFinder(this._callback); |
- |
- @override |
- Object visitInstanceCreationExpression(InstanceCreationExpression node) { |
- if (node.isConst) { |
- ConstructorElement constructor = |
- ConstantEvaluationEngine._getConstructorBase(node.staticElement); |
- if (constructor != null) { |
- _callback(constructor); |
- } |
- } |
- return super.visitInstanceCreationExpression(node); |
- } |
- |
- @override |
- Object visitLabel(Label node) { |
- // We are visiting the "label" part of a named expression in a function |
- // call (presumably a constructor call), e.g. "const C(label: ...)". We |
- // don't want to visit the SimpleIdentifier for the label because that's a |
- // reference to a function parameter that needs to be filled in; it's not a |
- // constant whose value we depend on. |
- return null; |
- } |
- |
- @override |
- Object visitRedirectingConstructorInvocation( |
- RedirectingConstructorInvocation node) { |
- super.visitRedirectingConstructorInvocation(node); |
- ConstructorElement target = |
- ConstantEvaluationEngine._getConstructorBase(node.staticElement); |
- if (target != null) { |
- _callback(target); |
- } |
- return null; |
- } |
- |
- @override |
- Object visitSimpleIdentifier(SimpleIdentifier node) { |
- Element element = node.staticElement; |
- if (element is PropertyAccessorElement) { |
- element = (element as PropertyAccessorElement).variable; |
- } |
- if (element is VariableElement) { |
- _callback(element); |
- } |
- return null; |
- } |
- |
- @override |
- Object visitSuperConstructorInvocation(SuperConstructorInvocation node) { |
- super.visitSuperConstructorInvocation(node); |
- ConstructorElement constructor = |
- ConstantEvaluationEngine._getConstructorBase(node.staticElement); |
- if (constructor != null) { |
- _callback(constructor); |
- } |
- return null; |
- } |
-} |
- |
-/** |
- * The state of an object representing a string. |
- */ |
-class StringState extends InstanceState { |
- /** |
- * A state that can be used to represent a double whose value is not known. |
- */ |
- static StringState UNKNOWN_VALUE = new StringState(null); |
- |
- /** |
- * The value of this instance. |
- */ |
- final String value; |
- |
- /** |
- * Initialize a newly created state to represent the given [value]. |
- */ |
- StringState(this.value); |
- |
- @override |
- bool get hasExactValue => true; |
- |
- @override |
- int get hashCode => value == null ? 0 : value.hashCode; |
- |
- @override |
- bool get isBoolNumStringOrNull => true; |
- |
- @override |
- bool get isUnknown => value == null; |
- |
- @override |
- String get typeName => "String"; |
- |
- @override |
- bool operator ==(Object object) => |
- object is StringState && (value == object.value); |
- |
- @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; |
- } |
- return super.concatenate(rightOperand); |
- } |
- |
- @override |
- StringState convertToString() => this; |
- |
- @override |
- BoolState equalEqual(InstanceState rightOperand) { |
- assertBoolNumStringOrNull(rightOperand); |
- return isIdentical(rightOperand); |
- } |
- |
- @override |
- BoolState isIdentical(InstanceState rightOperand) { |
- if (value == null) { |
- return BoolState.UNKNOWN_VALUE; |
- } |
- 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; |
- } |
- return BoolState.FALSE_STATE; |
- } |
- |
- @override |
- IntState stringLength() { |
- if (value == null) { |
- return IntState.UNKNOWN_VALUE; |
- } |
- return new IntState(value.length); |
- } |
- |
- @override |
- String toString() => value == null ? "-unknown-" : "'$value'"; |
-} |
- |
-/** |
- * The state of an object representing a symbol. |
- */ |
-class SymbolState extends InstanceState { |
- /** |
- * The value of this instance. |
- */ |
- final String value; |
- |
- /** |
- * Initialize a newly created state to represent the given [value]. |
- */ |
- SymbolState(this.value); |
- |
- @override |
- bool get hasExactValue => true; |
- |
- @override |
- int get hashCode => value == null ? 0 : value.hashCode; |
- |
- @override |
- String get typeName => "Symbol"; |
- |
- @override |
- bool operator ==(Object object) => |
- object is SymbolState && (value == object.value); |
- |
- @override |
- StringState convertToString() { |
- if (value == null) { |
- return StringState.UNKNOWN_VALUE; |
- } |
- return new StringState(value); |
- } |
- |
- @override |
- BoolState equalEqual(InstanceState rightOperand) { |
- assertBoolNumStringOrNull(rightOperand); |
- return isIdentical(rightOperand); |
- } |
- |
- @override |
- BoolState isIdentical(InstanceState 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; |
- } |
- return BoolState.FALSE_STATE; |
- } |
- |
- @override |
- String toString() => value == null ? "-unknown-" : "#$value"; |
-} |
- |
-/** |
- * The state of an object representing a type. |
- */ |
-class TypeState extends InstanceState { |
- /** |
- * The element representing the type being modeled. |
- */ |
- final Element _element; |
- |
- /** |
- * Initialize a newly created state to represent the given [value]. |
- */ |
- TypeState(this._element); |
- |
- @override |
- int get hashCode => _element == null ? 0 : _element.hashCode; |
- |
- @override |
- String get typeName => "Type"; |
- |
- @override |
- Element get value => _element; |
- |
- @override |
- bool operator ==(Object object) => |
- object is TypeState && (_element == object._element); |
- |
- @override |
- StringState convertToString() { |
- if (_element == null) { |
- return StringState.UNKNOWN_VALUE; |
- } |
- return new StringState(_element.name); |
- } |
- |
- @override |
- BoolState equalEqual(InstanceState rightOperand) { |
- assertBoolNumStringOrNull(rightOperand); |
- return isIdentical(rightOperand); |
- } |
- |
- @override |
- BoolState isIdentical(InstanceState rightOperand) { |
- if (_element == null) { |
- return BoolState.UNKNOWN_VALUE; |
- } |
- 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 BoolState.FALSE_STATE; |
- } |
- |
- @override |
- String toString() => _element == null ? "-unknown-" : _element.name; |
-} |