| // 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 'java_core.dart'; |
| import 'source.dart' show Source; |
| import 'error.dart' show AnalysisError, ErrorCode, CompileTimeErrorCode; |
| import 'scanner.dart' show TokenType; |
| import 'ast.dart'; |
| import 'element.dart'; |
| import 'engine.dart' show AnalysisEngine; |
| |
| /** |
| * Instances of the class {@code ConstantEvaluator} evaluate constant expressions to produce their |
| * compile-time value. According to the Dart Language Specification: <blockquote> A constant |
| * expression is one of the following: |
| * <ul> |
| * <li>A literal number.</li> |
| * <li>A literal boolean.</li> |
| * <li>A literal string where any interpolated expression is a compile-time constant that evaluates |
| * to a numeric, string or boolean value or to {@code null}.</li> |
| * <li>{@code null}.</li> |
| * <li>A reference to a static constant variable.</li> |
| * <li>An identifier expression that denotes a constant variable, a class or a type variable.</li> |
| * <li>A constant constructor invocation.</li> |
| * <li>A constant list literal.</li> |
| * <li>A constant map literal.</li> |
| * <li>A simple or qualified identifier denoting a top-level function or a static method.</li> |
| * <li>A parenthesized expression {@code (e)} where {@code e} is a constant expression.</li> |
| * <li>An expression of one of the forms {@code identical(e1, e2)}, {@code e1 == e2},{@code e1 != e2} where {@code e1} and {@code e2} are constant expressions that evaluate to a |
| * numeric, string or boolean value or to {@code null}.</li> |
| * <li>An expression of one of the forms {@code !e}, {@code e1 && e2} or {@code e1 || e2}, where{@code e}, {@code e1} and {@code e2} are constant expressions that evaluate to a boolean value or |
| * to {@code null}.</li> |
| * <li>An expression of one of the forms {@code ~e}, {@code e1 ^ e2}, {@code e1 & e2},{@code e1 | e2}, {@code e1 >> e2} or {@code e1 << e2}, where {@code e}, {@code e1} and {@code e2}are constant expressions that evaluate to an integer value or to {@code null}.</li> |
| * <li>An expression of one of the forms {@code -e}, {@code e1 + e2}, {@code e1 - e2},{@code e1 * e2}, {@code e1 / e2}, {@code e1 ~/ e2}, {@code e1 > e2}, {@code e1 < e2},{@code e1 >= e2}, {@code e1 <= e2} or {@code e1 % e2}, where {@code e}, {@code e1} and {@code e2}are constant expressions that evaluate to a numeric value or to {@code null}.</li> |
| * </ul> |
| * </blockquote> The values returned by instances of this class are therefore {@code null} and |
| * instances of the classes {@code Boolean}, {@code BigInteger}, {@code Double}, {@code String}, and{@code DartObject}. |
| * <p> |
| * In addition, this class defines several values that can be returned to indicate various |
| * conditions encountered during evaluation. These are documented with the static field that define |
| * those values. |
| */ |
| class ConstantEvaluator { |
| /** |
| * The source containing the expression(s) that will be evaluated. |
| */ |
| Source _source; |
| /** |
| * Initialize a newly created evaluator to evaluate expressions in the given source. |
| * @param source the source containing the expression(s) that will be evaluated |
| */ |
| ConstantEvaluator(Source source) { |
| this._source = source; |
| } |
| EvaluationResult evaluate(Expression expression) { |
| EvaluationResultImpl result = expression.accept(new ConstantVisitor()); |
| if (result is ValidResult) { |
| return EvaluationResult.forValue(((result as ValidResult)).value); |
| } |
| List<AnalysisError> errors = new List<AnalysisError>(); |
| for (ErrorResult_ErrorData data in ((result as ErrorResult)).errorData) { |
| ASTNode node2 = data.node; |
| errors.add(new AnalysisError.con2(_source, node2.offset, node2.length, data.errorCode, [])); |
| } |
| return EvaluationResult.forErrors(new List.from(errors)); |
| } |
| } |
| /** |
| * Instances of the class {@code EvaluationResult} represent the result of attempting to evaluate an |
| * expression. |
| */ |
| class EvaluationResult { |
| /** |
| * Return an evaluation result representing the result of evaluating an expression that is not a |
| * compile-time constant because of the given errors. |
| * @param errors the errors that should be reported for the expression(s) that were evaluated |
| * @return the result of evaluating an expression that is not a compile-time constant |
| */ |
| static EvaluationResult forErrors(List<AnalysisError> errors) => new EvaluationResult(null, errors); |
| /** |
| * Return an evaluation result representing the result of evaluating an expression that is a |
| * compile-time constant that evaluates to the given value. |
| * @param value the value of the expression |
| * @return the result of evaluating an expression that is a compile-time constant |
| */ |
| static EvaluationResult forValue(Object value) => new EvaluationResult(value, null); |
| /** |
| * The value of the expression. |
| */ |
| Object _value; |
| /** |
| * The errors that should be reported for the expression(s) that were evaluated. |
| */ |
| List<AnalysisError> _errors; |
| /** |
| * Initialize a newly created result object with the given state. Clients should use one of the |
| * factory methods: {@link #forErrors(AnalysisError\[\])} and {@link #forValue(Object)}. |
| * @param value the value of the expression |
| * @param errors the errors that should be reported for the expression(s) that were evaluated |
| */ |
| EvaluationResult(Object value, List<AnalysisError> errors) { |
| this._value = value; |
| this._errors = errors; |
| } |
| /** |
| * Return an array containing the errors that should be reported for the expression(s) that were |
| * evaluated. If there are no such errors, the array will be empty. The array can be empty even if |
| * 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 the value of the expression, or {@code null} if the expression evaluated to {@code null}or if the expression could not be evaluated, either because it was not a compile-time constant |
| * expression or because it would throw an exception when evaluated. |
| * @return the value of the expression |
| */ |
| Object get value => _value; |
| /** |
| * Return {@code true} if the expression is a compile-time constant expression that would not |
| * throw an exception when evaluated. |
| * @return {@code true} if the expression is a valid compile-time constant expression |
| */ |
| bool isValid() => _errors == null; |
| } |
| /** |
| * Instances of the class {@code ConstantFinder} are used to traverse the AST structures of all of |
| * the compilation units being resolved and build a table mapping constant variable elements to the |
| * declarations of those variables. |
| */ |
| class ConstantFinder extends RecursiveASTVisitor<Object> { |
| /** |
| * A table mapping constant variable elements to the declarations of those variables. |
| */ |
| Map<VariableElement, VariableDeclaration> _variableMap = new Map<VariableElement, VariableDeclaration>(); |
| /** |
| * Initialize a newly created constant finder. |
| */ |
| ConstantFinder() : super() { |
| } |
| /** |
| * Return a table mapping constant variable elements to the declarations of those variables. |
| * @return a table mapping constant variable elements to the declarations of those variables |
| */ |
| Map<VariableElement, VariableDeclaration> get variableMap => _variableMap; |
| Object visitVariableDeclaration(VariableDeclaration node) { |
| super.visitVariableDeclaration(node); |
| Expression initializer2 = node.initializer; |
| if (initializer2 != null && node.isConst()) { |
| VariableElement element2 = node.element; |
| if (element2 != null) { |
| _variableMap[element2] = node; |
| } |
| } |
| return null; |
| } |
| } |
| /** |
| * Instances of the class {@code ConstantValueComputer} compute the values of constant variables in |
| * one or more compilation units. The expected usage pattern is for the compilation units to be |
| * added to this computer using the method {@link #add(CompilationUnit)} and then for the method{@link #computeValues()} to invoked exactly once. Any use of an instance after invoking the |
| * method {@link #computeValues()} will result in unpredictable behavior. |
| */ |
| class ConstantValueComputer { |
| /** |
| * The object used to find constant variables in the compilation units that were added. |
| */ |
| ConstantFinder _constantFinder = new ConstantFinder(); |
| /** |
| * A graph in which the nodes are the constant variables and the edges are from each variable to |
| * the other constant variables that are referenced in the head's initializer. |
| */ |
| DirectedGraph<VariableElement> _referenceGraph = new DirectedGraph<VariableElement>(); |
| /** |
| * A table mapping constant variables to the declarations of those variables. |
| */ |
| Map<VariableElement, VariableDeclaration> _declarationMap; |
| /** |
| * Initialize a newly created constant value computer. |
| */ |
| ConstantValueComputer() : super() { |
| } |
| /** |
| * Add the constant variables in the given compilation unit to the list of constant variables |
| * whose value needs to be computed. |
| * @param unit the compilation unit defining the constant variables to be added |
| */ |
| void add(CompilationUnit unit) { |
| unit.accept(_constantFinder); |
| } |
| /** |
| * Compute values for all of the constant variables in the compilation units that were added. |
| */ |
| void computeValues() { |
| _declarationMap = _constantFinder.variableMap; |
| for (MapEntry<VariableElement, VariableDeclaration> entry in getMapEntrySet(_declarationMap)) { |
| VariableElement element = entry.getKey(); |
| ReferenceFinder referenceFinder = new ReferenceFinder(element, _referenceGraph); |
| _referenceGraph.addNode(element); |
| entry.getValue().initializer.accept(referenceFinder); |
| } |
| while (!_referenceGraph.isEmpty()) { |
| VariableElement element = _referenceGraph.removeSink(); |
| while (element != null) { |
| computeValueFor(element); |
| element = _referenceGraph.removeSink(); |
| } |
| if (!_referenceGraph.isEmpty()) { |
| List<VariableElement> variablesInCycle = _referenceGraph.findCycle(); |
| if (variablesInCycle == null) { |
| AnalysisEngine.instance.logger.logError("Exiting constant value computer with ${_referenceGraph.nodeCount} variables that are neither sinks no in a cycle"); |
| return; |
| } |
| for (VariableElement variable in variablesInCycle) { |
| generateCycleError(variablesInCycle, variable); |
| } |
| _referenceGraph.removeAllNodes(variablesInCycle); |
| } |
| } |
| } |
| /** |
| * Compute a value for the given variable. |
| * @param variable the variable for which a value is to be computed |
| */ |
| void computeValueFor(VariableElement variable) { |
| VariableDeclaration declaration = _declarationMap[variable]; |
| if (declaration == null) { |
| return; |
| } |
| EvaluationResultImpl result = declaration.initializer.accept(new ConstantVisitor()); |
| ((variable as VariableElementImpl)).evaluationResult = result; |
| if (result is ErrorResult) { |
| List<AnalysisError> errors = new List<AnalysisError>(); |
| for (ErrorResult_ErrorData data in ((result as ErrorResult)).errorData) { |
| ASTNode node2 = data.node; |
| Source source2 = variable.getAncestor(CompilationUnitElement).source; |
| errors.add(new AnalysisError.con2(source2, node2.offset, node2.length, data.errorCode, [])); |
| } |
| } |
| } |
| /** |
| * Generate an error indicating that the given variable is not a valid compile-time constant |
| * because it references at least one of the variables in the given cycle, each of which directly |
| * or indirectly references the variable. |
| * @param variablesInCycle the variables in the cycle that includes the given variable |
| * @param variable the variable that is not a valid compile-time constant |
| */ |
| void generateCycleError(List<VariableElement> variablesInCycle, VariableElement variable) { |
| } |
| } |
| /** |
| * Instances of the class {@code ConstantVisitor} evaluate constant expressions to produce their |
| * compile-time value. According to the Dart Language Specification: <blockquote> A constant |
| * expression is one of the following: |
| * <ul> |
| * <li>A literal number.</li> |
| * <li>A literal boolean.</li> |
| * <li>A literal string where any interpolated expression is a compile-time constant that evaluates |
| * to a numeric, string or boolean value or to {@code null}.</li> |
| * <li>{@code null}.</li> |
| * <li>A reference to a static constant variable.</li> |
| * <li>An identifier expression that denotes a constant variable, a class or a type variable.</li> |
| * <li>A constant constructor invocation.</li> |
| * <li>A constant list literal.</li> |
| * <li>A constant map literal.</li> |
| * <li>A simple or qualified identifier denoting a top-level function or a static method.</li> |
| * <li>A parenthesized expression {@code (e)} where {@code e} is a constant expression.</li> |
| * <li>An expression of one of the forms {@code identical(e1, e2)}, {@code e1 == e2},{@code e1 != e2} where {@code e1} and {@code e2} are constant expressions that evaluate to a |
| * numeric, string or boolean value or to {@code null}.</li> |
| * <li>An expression of one of the forms {@code !e}, {@code e1 && e2} or {@code e1 || e2}, where{@code e}, {@code e1} and {@code e2} are constant expressions that evaluate to a boolean value or |
| * to {@code null}.</li> |
| * <li>An expression of one of the forms {@code ~e}, {@code e1 ^ e2}, {@code e1 & e2},{@code e1 | e2}, {@code e1 >> e2} or {@code e1 << e2}, where {@code e}, {@code e1} and {@code e2}are constant expressions that evaluate to an integer value or to {@code null}.</li> |
| * <li>An expression of one of the forms {@code -e}, {@code e1 + e2}, {@code e1 - e2},{@code e1 * e2}, {@code e1 / e2}, {@code e1 ~/ e2}, {@code e1 > e2}, {@code e1 < e2},{@code e1 >= e2}, {@code e1 <= e2} or {@code e1 % e2}, where {@code e}, {@code e1} and {@code e2}are constant expressions that evaluate to a numeric value or to {@code null}.</li> |
| * </ul> |
| * </blockquote> |
| */ |
| class ConstantVisitor extends GeneralizingASTVisitor<EvaluationResultImpl> { |
| /** |
| * Initialize a newly created constant visitor. |
| */ |
| ConstantVisitor() : super() { |
| } |
| EvaluationResultImpl visitAdjacentStrings(AdjacentStrings node) { |
| EvaluationResultImpl result = null; |
| for (StringLiteral string in node.strings) { |
| if (result == null) { |
| result = string.accept(this); |
| } else { |
| result = result.concatenate(node, string.accept(this)); |
| } |
| } |
| return result; |
| } |
| EvaluationResultImpl visitBinaryExpression(BinaryExpression node) { |
| EvaluationResultImpl leftResult = node.leftOperand.accept(this); |
| EvaluationResultImpl rightResult = node.rightOperand.accept(this); |
| while (true) { |
| if (node.operator.type == TokenType.AMPERSAND) { |
| return leftResult.bitAnd(node, rightResult); |
| } else if (node.operator.type == TokenType.AMPERSAND_AMPERSAND) { |
| return leftResult.logicalAnd(node, rightResult); |
| } else if (node.operator.type == TokenType.BANG_EQ) { |
| return leftResult.notEqual(node, rightResult); |
| } else if (node.operator.type == TokenType.BAR) { |
| return leftResult.bitOr(node, rightResult); |
| } else if (node.operator.type == TokenType.BAR_BAR) { |
| return leftResult.logicalOr(node, rightResult); |
| } else if (node.operator.type == TokenType.CARET) { |
| return leftResult.bitXor(node, rightResult); |
| } else if (node.operator.type == TokenType.EQ_EQ) { |
| return leftResult.equalEqual(node, rightResult); |
| } else if (node.operator.type == TokenType.GT) { |
| return leftResult.greaterThan(node, rightResult); |
| } else if (node.operator.type == TokenType.GT_EQ) { |
| return leftResult.greaterThanOrEqual(node, rightResult); |
| } else if (node.operator.type == TokenType.GT_GT) { |
| return leftResult.shiftRight(node, rightResult); |
| } else if (node.operator.type == TokenType.LT) { |
| return leftResult.lessThan(node, rightResult); |
| } else if (node.operator.type == TokenType.LT_EQ) { |
| return leftResult.lessThanOrEqual(node, rightResult); |
| } else if (node.operator.type == TokenType.LT_LT) { |
| return leftResult.shiftLeft(node, rightResult); |
| } else if (node.operator.type == TokenType.MINUS) { |
| return leftResult.minus(node, rightResult); |
| } else if (node.operator.type == TokenType.PERCENT) { |
| return leftResult.remainder(node, rightResult); |
| } else if (node.operator.type == TokenType.PLUS) { |
| return leftResult.add(node, rightResult); |
| } else if (node.operator.type == TokenType.STAR) { |
| return leftResult.times(node, rightResult); |
| } else if (node.operator.type == TokenType.SLASH) { |
| return leftResult.divide(node, rightResult); |
| } else if (node.operator.type == TokenType.TILDE_SLASH) { |
| return leftResult.integerDivide(node, rightResult); |
| } |
| break; |
| } |
| return error(node, null); |
| } |
| EvaluationResultImpl visitBooleanLiteral(BooleanLiteral node) => node.value ? ValidResult.RESULT_TRUE : ValidResult.RESULT_FALSE; |
| EvaluationResultImpl visitDoubleLiteral(DoubleLiteral node) => new ValidResult(node.value); |
| EvaluationResultImpl visitInstanceCreationExpression(InstanceCreationExpression node) { |
| ConstructorElement constructor = node.element; |
| if (constructor != null && constructor.isConst()) { |
| node.argumentList.accept(this); |
| return ValidResult.RESULT_OBJECT; |
| } |
| return error(node, null); |
| } |
| EvaluationResultImpl visitIntegerLiteral(IntegerLiteral node) => new ValidResult(node.value); |
| EvaluationResultImpl visitInterpolationExpression(InterpolationExpression node) { |
| EvaluationResultImpl result = node.expression.accept(this); |
| return result.performToString(node); |
| } |
| EvaluationResultImpl visitInterpolationString(InterpolationString node) => new ValidResult(node.value); |
| EvaluationResultImpl visitListLiteral(ListLiteral node) { |
| ErrorResult result = null; |
| for (Expression element in node.elements) { |
| result = union(result, element.accept(this)); |
| } |
| if (result != null) { |
| return result; |
| } |
| return ValidResult.RESULT_OBJECT; |
| } |
| EvaluationResultImpl visitMapLiteral(MapLiteral node) { |
| ErrorResult result = null; |
| for (MapLiteralEntry entry in node.entries) { |
| result = union(result, entry.key.accept(this)); |
| result = union(result, entry.value.accept(this)); |
| } |
| if (result != null) { |
| return result; |
| } |
| return ValidResult.RESULT_OBJECT; |
| } |
| EvaluationResultImpl visitMethodInvocation(MethodInvocation node) { |
| Element element2 = node.methodName.element; |
| if (element2 is FunctionElement) { |
| FunctionElement function = element2 as FunctionElement; |
| if (function.name == "identical") { |
| NodeList<Expression> arguments2 = node.argumentList.arguments; |
| if (arguments2.length == 2) { |
| Element enclosingElement2 = function.enclosingElement; |
| if (enclosingElement2 is CompilationUnitElement) { |
| LibraryElement library2 = ((enclosingElement2 as CompilationUnitElement)).library; |
| if (library2.isDartCore()) { |
| EvaluationResultImpl leftArgument = arguments2[0].accept(this); |
| EvaluationResultImpl rightArgument = arguments2[1].accept(this); |
| return leftArgument.equalEqual(node, rightArgument); |
| } |
| } |
| } |
| } |
| } |
| return error(node, null); |
| } |
| EvaluationResultImpl visitNode(ASTNode node) => error(node, null); |
| EvaluationResultImpl visitNullLiteral(NullLiteral node) => new ValidResult(null); |
| EvaluationResultImpl visitParenthesizedExpression(ParenthesizedExpression node) => node.expression.accept(this); |
| EvaluationResultImpl visitPrefixedIdentifier(PrefixedIdentifier node) => getConstantValue(node, node.element); |
| EvaluationResultImpl visitPrefixExpression(PrefixExpression node) { |
| EvaluationResultImpl operand2 = node.operand.accept(this); |
| while (true) { |
| if (node.operator.type == TokenType.BANG) { |
| return operand2.logicalNot(node); |
| } else if (node.operator.type == TokenType.TILDE) { |
| return operand2.bitNot(node); |
| } else if (node.operator.type == TokenType.MINUS) { |
| return operand2.negated(node); |
| } |
| break; |
| } |
| return error(node, null); |
| } |
| EvaluationResultImpl visitPropertyAccess(PropertyAccess node) => getConstantValue(node, node.propertyName.element); |
| EvaluationResultImpl visitSimpleIdentifier(SimpleIdentifier node) => getConstantValue(node, node.element); |
| EvaluationResultImpl visitSimpleStringLiteral(SimpleStringLiteral node) => new ValidResult(node.value); |
| EvaluationResultImpl visitStringInterpolation(StringInterpolation node) { |
| EvaluationResultImpl result = null; |
| for (InterpolationElement element in node.elements) { |
| if (result == null) { |
| result = element.accept(this); |
| } else { |
| result = result.concatenate(node, element.accept(this)); |
| } |
| } |
| return result; |
| } |
| /** |
| * Return a result object representing an error associated with the given node. |
| * @param node the AST node associated with the error |
| * @param code the error code indicating the nature of the error |
| * @return a result object representing an error associated with the given node |
| */ |
| ErrorResult error(ASTNode node, ErrorCode code) => new ErrorResult.con1(node, code == null ? CompileTimeErrorCode.INVALID_CONSTANT : code); |
| /** |
| * Return the constant value of the static constant represented by the given element. |
| * @param node the node to be used if an error needs to be reported |
| * @param element the element whose value is to be returned |
| * @return the constant value of the static constant |
| */ |
| EvaluationResultImpl getConstantValue(ASTNode node, Element element) { |
| if (element is PropertyAccessorElement) { |
| element = ((element as PropertyAccessorElement)).variable; |
| } |
| if (element is VariableElementImpl) { |
| EvaluationResultImpl value = ((element as VariableElementImpl)).evaluationResult; |
| if (value != null) { |
| return value; |
| } |
| } else if (element is ExecutableElement) { |
| return new ValidResult(element); |
| } |
| return error(node, null); |
| } |
| /** |
| * Return the union of the errors encoded in the given results. |
| * @param leftResult the first set of errors, or {@code null} if there was no previous collection |
| * of errors |
| * @param rightResult the errors to be added to the collection, or a valid result if there are no |
| * errors to be added |
| * @return the union of the errors encoded in the given results |
| */ |
| ErrorResult union(ErrorResult leftResult, EvaluationResultImpl rightResult) { |
| if (rightResult is ErrorResult) { |
| if (leftResult != null) { |
| return new ErrorResult.con2(leftResult, (rightResult as ErrorResult)); |
| } else { |
| return rightResult as ErrorResult; |
| } |
| } |
| return leftResult; |
| } |
| } |
| /** |
| * Instances of the class {@code DirectedGraph} implement a directed graph in which the nodes are |
| * arbitrary (client provided) objects and edges are represented implicitly. The graph will allow an |
| * edge from any node to any other node, including itself, but will not represent multiple edges |
| * between the same pair of nodes. |
| * @param N the type of the nodes in the graph |
| */ |
| class DirectedGraph<N> { |
| /** |
| * The table encoding the edges in the graph. An edge is represented by an entry mapping the head |
| * to a set of tails. Nodes that are not the head of any edge are represented by an entry mapping |
| * the node to an empty set of tails. |
| */ |
| Map<N, Set<N>> _edges = new Map<N, Set<N>>(); |
| /** |
| * Initialize a newly create directed graph to be empty. |
| */ |
| DirectedGraph() : super() { |
| } |
| /** |
| * Add an edge from the given head node to the given tail node. Both nodes will be a part of the |
| * graph after this method is invoked, whether or not they were before. |
| * @param head the node at the head of the edge |
| * @param tail the node at the tail of the edge |
| */ |
| void addEdge(N head, N tail) { |
| Set<N> tails = _edges[tail]; |
| if (tails == null) { |
| _edges[tail] = new Set<N>(); |
| } |
| tails = _edges[head]; |
| if (tails == null) { |
| tails = new Set<N>(); |
| _edges[head] = tails; |
| } |
| javaSetAdd(tails, tail); |
| } |
| /** |
| * Add the given node to the set of nodes in the graph. |
| * @param node the node to be added |
| */ |
| void addNode(N node) { |
| Set<N> tails = _edges[node]; |
| if (tails == null) { |
| _edges[node] = new Set<N>(); |
| } |
| } |
| /** |
| * Return a list of nodes that form a cycle, or {@code null} if there are no cycles in this graph. |
| * @return a list of nodes that form a cycle |
| */ |
| List<N> findCycle() => null; |
| /** |
| * Return the number of nodes in this graph. |
| * @return the number of nodes in this graph |
| */ |
| int get nodeCount => _edges.length; |
| /** |
| * Return a set containing the tails of edges that have the given node as their head. The set will |
| * be empty if there are no such edges or if the node is not part of the graph. Clients must not |
| * modify the returned set. |
| * @param head the node at the head of all of the edges whose tails are to be returned |
| * @return a set containing the tails of edges that have the given node as their head |
| */ |
| Set<N> getTails(N head) { |
| Set<N> tails = _edges[head]; |
| if (tails == null) { |
| return new Set<N>(); |
| } |
| return tails; |
| } |
| /** |
| * Return {@code true} if this graph is empty. |
| * @return {@code true} if this graph is empty |
| */ |
| bool isEmpty() => _edges.isEmpty; |
| /** |
| * Remove all of the given nodes from this graph. As a consequence, any edges for which those |
| * nodes were either a head or a tail will also be removed. |
| * @param nodes the nodes to be removed |
| */ |
| void removeAllNodes(List<N> nodes) { |
| for (N node in nodes) { |
| removeNode(node); |
| } |
| } |
| /** |
| * Remove the edge from the given head node to the given tail node. If there was no such edge then |
| * the graph will be unmodified: the number of edges will be the same and the set of nodes will be |
| * the same (neither node will either be added or removed). |
| * @param head the node at the head of the edge |
| * @param tail the node at the tail of the edge |
| * @return {@code true} if the graph was modified as a result of this operation |
| */ |
| void removeEdge(N head, N tail) { |
| Set<N> tails = _edges[head]; |
| if (tails != null) { |
| tails.remove(tail); |
| } |
| } |
| /** |
| * Remove the given node from this graph. As a consequence, any edges for which that node was |
| * either a head or a tail will also be removed. |
| * @param node the node to be removed |
| */ |
| void removeNode(N node) { |
| _edges.remove(node); |
| for (Set<N> tails in _edges.values) { |
| tails.remove(node); |
| } |
| } |
| /** |
| * Find one node (referred to as a sink node) that has no outgoing edges (that is, for which there |
| * are no edges that have that node as the head of the edge) and remove it from this graph. Return |
| * the node that was removed, or {@code null} if there are no such nodes either because the graph |
| * is empty or because every node in the graph has at least one outgoing edge. As a consequence of |
| * removing the node from the graph any edges for which that node was a tail will also be removed. |
| * @return the sink node that was removed |
| */ |
| N removeSink() { |
| N sink = findSink(); |
| if (sink == null) { |
| return null; |
| } |
| removeNode(sink); |
| return sink; |
| } |
| /** |
| * Return one node that has no outgoing edges (that is, for which there are no edges that have |
| * that node as the head of the edge), or {@code null} if there are no such nodes. |
| * @return a sink node |
| */ |
| N findSink() { |
| for (MapEntry<N, Set<N>> entry in getMapEntrySet(_edges)) { |
| if (entry.getValue().isEmpty) { |
| return entry.getKey(); |
| } |
| } |
| return null; |
| } |
| } |
| /** |
| * Instances of the class {@code ErrorResult} represent the result of evaluating an expression that |
| * is not a valid compile time constant. |
| */ |
| class ErrorResult extends EvaluationResultImpl { |
| /** |
| * The errors that prevent the expression from being a valid compile time constant. |
| */ |
| List<ErrorResult_ErrorData> _errors = new List<ErrorResult_ErrorData>(); |
| /** |
| * Initialize a newly created result representing the error with the given code reported against |
| * the given node. |
| * @param node the node against which the error should be reported |
| * @param errorCode the error code for the error to be generated |
| */ |
| ErrorResult.con1(ASTNode node, ErrorCode errorCode) { |
| _jtd_constructor_168_impl(node, errorCode); |
| } |
| _jtd_constructor_168_impl(ASTNode node, ErrorCode errorCode) { |
| _errors.add(new ErrorResult_ErrorData(node, errorCode)); |
| } |
| /** |
| * Initialize a newly created result to represent the union of the errors in the given result |
| * objects. |
| * @param firstResult the first set of results being merged |
| * @param secondResult the second set of results being merged |
| */ |
| ErrorResult.con2(ErrorResult firstResult, ErrorResult secondResult) { |
| _jtd_constructor_169_impl(firstResult, secondResult); |
| } |
| _jtd_constructor_169_impl(ErrorResult firstResult, ErrorResult secondResult) { |
| _errors.addAll(firstResult._errors); |
| _errors.addAll(secondResult._errors); |
| } |
| EvaluationResultImpl add(BinaryExpression node, EvaluationResultImpl rightOperand) => rightOperand.addToError(node, this); |
| EvaluationResultImpl bitAnd(BinaryExpression node, EvaluationResultImpl rightOperand) => rightOperand.bitAndError(node, this); |
| EvaluationResultImpl bitNot(Expression node) => this; |
| EvaluationResultImpl bitOr(BinaryExpression node, EvaluationResultImpl rightOperand) => rightOperand.bitOrError(node, this); |
| EvaluationResultImpl bitXor(BinaryExpression node, EvaluationResultImpl rightOperand) => rightOperand.bitXorError(node, this); |
| EvaluationResultImpl concatenate(Expression node, EvaluationResultImpl rightOperand) => rightOperand.concatenateError(node, this); |
| EvaluationResultImpl divide(BinaryExpression node, EvaluationResultImpl rightOperand) => rightOperand.divideError(node, this); |
| EvaluationResultImpl equalEqual(Expression node, EvaluationResultImpl rightOperand) => rightOperand.equalEqualError(node, this); |
| List<ErrorResult_ErrorData> get errorData => _errors; |
| EvaluationResultImpl greaterThan(BinaryExpression node, EvaluationResultImpl rightOperand) => rightOperand.greaterThanError(node, this); |
| EvaluationResultImpl greaterThanOrEqual(BinaryExpression node, EvaluationResultImpl rightOperand) => rightOperand.greaterThanOrEqualError(node, this); |
| EvaluationResultImpl integerDivide(BinaryExpression node, EvaluationResultImpl rightOperand) => rightOperand.integerDivideError(node, this); |
| EvaluationResultImpl integerDivideValid(BinaryExpression node, ValidResult leftOperand) => this; |
| EvaluationResultImpl lessThan(BinaryExpression node, EvaluationResultImpl rightOperand) => rightOperand.lessThanError(node, this); |
| EvaluationResultImpl lessThanOrEqual(BinaryExpression node, EvaluationResultImpl rightOperand) => rightOperand.lessThanOrEqualError(node, this); |
| EvaluationResultImpl logicalAnd(BinaryExpression node, EvaluationResultImpl rightOperand) => rightOperand.logicalAndError(node, this); |
| EvaluationResultImpl logicalNot(Expression node) => this; |
| EvaluationResultImpl logicalOr(BinaryExpression node, EvaluationResultImpl rightOperand) => rightOperand.logicalOrError(node, this); |
| EvaluationResultImpl minus(BinaryExpression node, EvaluationResultImpl rightOperand) => rightOperand.minusError(node, this); |
| EvaluationResultImpl negated(Expression node) => this; |
| EvaluationResultImpl notEqual(BinaryExpression node, EvaluationResultImpl rightOperand) => rightOperand.notEqualError(node, this); |
| EvaluationResultImpl performToString(ASTNode node) => this; |
| EvaluationResultImpl remainder(BinaryExpression node, EvaluationResultImpl rightOperand) => rightOperand.remainderError(node, this); |
| EvaluationResultImpl shiftLeft(BinaryExpression node, EvaluationResultImpl rightOperand) => rightOperand.shiftLeftError(node, this); |
| EvaluationResultImpl shiftRight(BinaryExpression node, EvaluationResultImpl rightOperand) => rightOperand.shiftRightError(node, this); |
| EvaluationResultImpl times(BinaryExpression node, EvaluationResultImpl rightOperand) => rightOperand.timesError(node, this); |
| EvaluationResultImpl addToError(BinaryExpression node, ErrorResult leftOperand) => new ErrorResult.con2(this, leftOperand); |
| EvaluationResultImpl addToValid(BinaryExpression node, ValidResult leftOperand) => this; |
| EvaluationResultImpl bitAndError(BinaryExpression node, ErrorResult leftOperand) => new ErrorResult.con2(this, leftOperand); |
| EvaluationResultImpl bitAndValid(BinaryExpression node, ValidResult leftOperand) => this; |
| EvaluationResultImpl bitOrError(BinaryExpression node, ErrorResult leftOperand) => new ErrorResult.con2(this, leftOperand); |
| EvaluationResultImpl bitOrValid(BinaryExpression node, ValidResult leftOperand) => this; |
| EvaluationResultImpl bitXorError(BinaryExpression node, ErrorResult leftOperand) => new ErrorResult.con2(this, leftOperand); |
| EvaluationResultImpl bitXorValid(BinaryExpression node, ValidResult leftOperand) => this; |
| EvaluationResultImpl concatenateError(Expression node, ErrorResult leftOperand) => new ErrorResult.con2(this, leftOperand); |
| EvaluationResultImpl concatenateValid(Expression node, ValidResult leftOperand) => this; |
| EvaluationResultImpl divideError(BinaryExpression node, ErrorResult leftOperand) => new ErrorResult.con2(this, leftOperand); |
| EvaluationResultImpl divideValid(BinaryExpression node, ValidResult leftOperand) => this; |
| EvaluationResultImpl equalEqualError(Expression node, ErrorResult leftOperand) => new ErrorResult.con2(this, leftOperand); |
| EvaluationResultImpl equalEqualValid(Expression node, ValidResult leftOperand) => this; |
| EvaluationResultImpl greaterThanError(BinaryExpression node, ErrorResult leftOperand) => new ErrorResult.con2(this, leftOperand); |
| EvaluationResultImpl greaterThanOrEqualError(BinaryExpression node, ErrorResult leftOperand) => new ErrorResult.con2(this, leftOperand); |
| EvaluationResultImpl greaterThanOrEqualValid(BinaryExpression node, ValidResult leftOperand) => this; |
| EvaluationResultImpl greaterThanValid(BinaryExpression node, ValidResult leftOperand) => this; |
| EvaluationResultImpl integerDivideError(BinaryExpression node, ErrorResult leftOperand) => new ErrorResult.con2(this, leftOperand); |
| EvaluationResultImpl lessThanError(BinaryExpression node, ErrorResult leftOperand) => new ErrorResult.con2(this, leftOperand); |
| EvaluationResultImpl lessThanOrEqualError(BinaryExpression node, ErrorResult leftOperand) => new ErrorResult.con2(this, leftOperand); |
| EvaluationResultImpl lessThanOrEqualValid(BinaryExpression node, ValidResult leftOperand) => this; |
| EvaluationResultImpl lessThanValid(BinaryExpression node, ValidResult leftOperand) => this; |
| EvaluationResultImpl logicalAndError(BinaryExpression node, ErrorResult leftOperand) => new ErrorResult.con2(this, leftOperand); |
| EvaluationResultImpl logicalAndValid(BinaryExpression node, ValidResult leftOperand) => this; |
| EvaluationResultImpl logicalOrError(BinaryExpression node, ErrorResult leftOperand) => new ErrorResult.con2(this, leftOperand); |
| EvaluationResultImpl logicalOrValid(BinaryExpression node, ValidResult leftOperand) => this; |
| EvaluationResultImpl minusError(BinaryExpression node, ErrorResult leftOperand) => new ErrorResult.con2(this, leftOperand); |
| EvaluationResultImpl minusValid(BinaryExpression node, ValidResult leftOperand) => this; |
| EvaluationResultImpl notEqualError(BinaryExpression node, ErrorResult leftOperand) => new ErrorResult.con2(this, leftOperand); |
| EvaluationResultImpl notEqualValid(BinaryExpression node, ValidResult leftOperand) => this; |
| EvaluationResultImpl remainderError(BinaryExpression node, ErrorResult leftOperand) => new ErrorResult.con2(this, leftOperand); |
| EvaluationResultImpl remainderValid(BinaryExpression node, ValidResult leftOperand) => this; |
| EvaluationResultImpl shiftLeftError(BinaryExpression node, ErrorResult leftOperand) => new ErrorResult.con2(this, leftOperand); |
| EvaluationResultImpl shiftLeftValid(BinaryExpression node, ValidResult leftOperand) => this; |
| EvaluationResultImpl shiftRightError(BinaryExpression node, ErrorResult leftOperand) => new ErrorResult.con2(this, leftOperand); |
| EvaluationResultImpl shiftRightValid(BinaryExpression node, ValidResult leftOperand) => this; |
| EvaluationResultImpl timesError(BinaryExpression node, ErrorResult leftOperand) => new ErrorResult.con2(this, leftOperand); |
| EvaluationResultImpl timesValid(BinaryExpression node, ValidResult leftOperand) => this; |
| } |
| class ErrorResult_ErrorData { |
| /** |
| * The node against which the error should be reported. |
| */ |
| ASTNode _node; |
| /** |
| * The error code for the error to be generated. |
| */ |
| ErrorCode _errorCode; |
| /** |
| * Initialize a newly created data holder to represent the error with the given code reported |
| * against the given node. |
| * @param node the node against which the error should be reported |
| * @param errorCode the error code for the error to be generated |
| */ |
| ErrorResult_ErrorData(ASTNode node, ErrorCode errorCode) { |
| this._node = node; |
| this._errorCode = errorCode; |
| } |
| /** |
| * Return the error code for the error to be generated. |
| * @return the error code for the error to be generated |
| */ |
| ErrorCode get errorCode => _errorCode; |
| /** |
| * Return the node against which the error should be reported. |
| * @return the node against which the error should be reported |
| */ |
| ASTNode get node => _node; |
| } |
| /** |
| * Instances of the class {@code InternalResult} represent the result of attempting to evaluate a |
| * expression. |
| */ |
| abstract class EvaluationResultImpl { |
| EvaluationResultImpl add(BinaryExpression node, EvaluationResultImpl rightOperand); |
| EvaluationResultImpl bitAnd(BinaryExpression node, EvaluationResultImpl rightOperand); |
| EvaluationResultImpl bitNot(Expression node); |
| EvaluationResultImpl bitOr(BinaryExpression node, EvaluationResultImpl rightOperand); |
| EvaluationResultImpl bitXor(BinaryExpression node, EvaluationResultImpl rightOperand); |
| EvaluationResultImpl concatenate(Expression node, EvaluationResultImpl rightOperand); |
| EvaluationResultImpl divide(BinaryExpression node, EvaluationResultImpl rightOperand); |
| EvaluationResultImpl equalEqual(Expression node, EvaluationResultImpl rightOperand); |
| EvaluationResultImpl greaterThan(BinaryExpression node, EvaluationResultImpl rightOperand); |
| EvaluationResultImpl greaterThanOrEqual(BinaryExpression node, EvaluationResultImpl rightOperand); |
| EvaluationResultImpl integerDivide(BinaryExpression node, EvaluationResultImpl rightOperand); |
| EvaluationResultImpl lessThan(BinaryExpression node, EvaluationResultImpl rightOperand); |
| EvaluationResultImpl lessThanOrEqual(BinaryExpression node, EvaluationResultImpl rightOperand); |
| EvaluationResultImpl logicalAnd(BinaryExpression node, EvaluationResultImpl rightOperand); |
| EvaluationResultImpl logicalNot(Expression node); |
| EvaluationResultImpl logicalOr(BinaryExpression node, EvaluationResultImpl rightOperand); |
| EvaluationResultImpl minus(BinaryExpression node, EvaluationResultImpl rightOperand); |
| EvaluationResultImpl negated(Expression node); |
| EvaluationResultImpl notEqual(BinaryExpression node, EvaluationResultImpl rightOperand); |
| EvaluationResultImpl performToString(ASTNode node); |
| EvaluationResultImpl remainder(BinaryExpression node, EvaluationResultImpl rightOperand); |
| EvaluationResultImpl shiftLeft(BinaryExpression node, EvaluationResultImpl rightOperand); |
| EvaluationResultImpl shiftRight(BinaryExpression node, EvaluationResultImpl rightOperand); |
| EvaluationResultImpl times(BinaryExpression node, EvaluationResultImpl rightOperand); |
| EvaluationResultImpl addToError(BinaryExpression node, ErrorResult leftOperand); |
| EvaluationResultImpl addToValid(BinaryExpression node, ValidResult leftOperand); |
| EvaluationResultImpl bitAndError(BinaryExpression node, ErrorResult leftOperand); |
| EvaluationResultImpl bitAndValid(BinaryExpression node, ValidResult leftOperand); |
| EvaluationResultImpl bitOrError(BinaryExpression node, ErrorResult leftOperand); |
| EvaluationResultImpl bitOrValid(BinaryExpression node, ValidResult leftOperand); |
| EvaluationResultImpl bitXorError(BinaryExpression node, ErrorResult leftOperand); |
| EvaluationResultImpl bitXorValid(BinaryExpression node, ValidResult leftOperand); |
| EvaluationResultImpl concatenateError(Expression node, ErrorResult leftOperand); |
| EvaluationResultImpl concatenateValid(Expression node, ValidResult leftOperand); |
| EvaluationResultImpl divideError(BinaryExpression node, ErrorResult leftOperand); |
| EvaluationResultImpl divideValid(BinaryExpression node, ValidResult leftOperand); |
| EvaluationResultImpl equalEqualError(Expression node, ErrorResult leftOperand); |
| EvaluationResultImpl equalEqualValid(Expression node, ValidResult leftOperand); |
| EvaluationResultImpl greaterThanError(BinaryExpression node, ErrorResult leftOperand); |
| EvaluationResultImpl greaterThanOrEqualError(BinaryExpression node, ErrorResult leftOperand); |
| EvaluationResultImpl greaterThanOrEqualValid(BinaryExpression node, ValidResult leftOperand); |
| EvaluationResultImpl greaterThanValid(BinaryExpression node, ValidResult leftOperand); |
| EvaluationResultImpl integerDivideError(BinaryExpression node, ErrorResult leftOperand); |
| EvaluationResultImpl integerDivideValid(BinaryExpression node, ValidResult leftOperand); |
| EvaluationResultImpl lessThanError(BinaryExpression node, ErrorResult leftOperand); |
| EvaluationResultImpl lessThanOrEqualError(BinaryExpression node, ErrorResult leftOperand); |
| EvaluationResultImpl lessThanOrEqualValid(BinaryExpression node, ValidResult leftOperand); |
| EvaluationResultImpl lessThanValid(BinaryExpression node, ValidResult leftOperand); |
| EvaluationResultImpl logicalAndError(BinaryExpression node, ErrorResult leftOperand); |
| EvaluationResultImpl logicalAndValid(BinaryExpression node, ValidResult leftOperand); |
| EvaluationResultImpl logicalOrError(BinaryExpression node, ErrorResult leftOperand); |
| EvaluationResultImpl logicalOrValid(BinaryExpression node, ValidResult leftOperand); |
| EvaluationResultImpl minusError(BinaryExpression node, ErrorResult leftOperand); |
| EvaluationResultImpl minusValid(BinaryExpression node, ValidResult leftOperand); |
| EvaluationResultImpl notEqualError(BinaryExpression node, ErrorResult leftOperand); |
| EvaluationResultImpl notEqualValid(BinaryExpression node, ValidResult leftOperand); |
| EvaluationResultImpl remainderError(BinaryExpression node, ErrorResult leftOperand); |
| EvaluationResultImpl remainderValid(BinaryExpression node, ValidResult leftOperand); |
| EvaluationResultImpl shiftLeftError(BinaryExpression node, ErrorResult leftOperand); |
| EvaluationResultImpl shiftLeftValid(BinaryExpression node, ValidResult leftOperand); |
| EvaluationResultImpl shiftRightError(BinaryExpression node, ErrorResult leftOperand); |
| EvaluationResultImpl shiftRightValid(BinaryExpression node, ValidResult leftOperand); |
| EvaluationResultImpl timesError(BinaryExpression node, ErrorResult leftOperand); |
| EvaluationResultImpl timesValid(BinaryExpression node, ValidResult leftOperand); |
| } |
| /** |
| * Instances of the class {@code ReferenceFinder} add reference information for a given variable to |
| * the bi-directional mapping used to order the evaluation of constants. |
| */ |
| class ReferenceFinder extends RecursiveASTVisitor<Object> { |
| /** |
| * The element representing the variable whose initializer will be visited. |
| */ |
| VariableElement _source; |
| /** |
| * A graph in which the nodes are the constant variables and the edges are from each variable to |
| * the other constant variables that are referenced in the head's initializer. |
| */ |
| DirectedGraph<VariableElement> _referenceGraph; |
| /** |
| * Initialize a newly created reference finder to find references from the given variable to other |
| * variables and to add those references to the given graph. |
| * @param source the element representing the variable whose initializer will be visited |
| * @param referenceGraph a graph recording which variables (heads) reference which other variables |
| * (tails) in their initializers |
| */ |
| ReferenceFinder(VariableElement source, DirectedGraph<VariableElement> referenceGraph) { |
| this._source = source; |
| this._referenceGraph = referenceGraph; |
| } |
| Object visitSimpleIdentifier(SimpleIdentifier node) { |
| Element element2 = node.element; |
| if (element2 is PropertyAccessorElement) { |
| element2 = ((element2 as PropertyAccessorElement)).variable; |
| } |
| if (element2 is VariableElement) { |
| VariableElement variable = element2 as VariableElement; |
| if (variable.isConst()) { |
| _referenceGraph.addEdge(_source, variable); |
| } |
| } |
| return null; |
| } |
| } |
| /** |
| * Instances of the class {@code ValidResult} represent the result of attempting to evaluate a valid |
| * compile time constant expression. |
| */ |
| class ValidResult extends EvaluationResultImpl { |
| /** |
| * A result object representing the value 'false'. |
| */ |
| static ValidResult RESULT_FALSE = new ValidResult(false); |
| /** |
| * A result object representing the an arbitrary object on which no further operations can be |
| * performed. |
| */ |
| static ValidResult RESULT_OBJECT = new ValidResult(new Object()); |
| /** |
| * A result object representing the value 'true'. |
| */ |
| static ValidResult RESULT_TRUE = new ValidResult(true); |
| /** |
| * The value of the expression. |
| */ |
| Object _value; |
| /** |
| * Initialize a newly created result to represent the given value. |
| * @param value the value of the expression |
| */ |
| ValidResult(Object value) { |
| this._value = value; |
| } |
| EvaluationResultImpl add(BinaryExpression node, EvaluationResultImpl rightOperand) => rightOperand.addToValid(node, this); |
| EvaluationResultImpl bitAnd(BinaryExpression node, EvaluationResultImpl rightOperand) => rightOperand.bitAndValid(node, this); |
| EvaluationResultImpl bitNot(Expression node) { |
| if (_value == null) { |
| return error(node); |
| } else if (_value is int) { |
| return valueOf(~((_value as int))); |
| } |
| return error(node); |
| } |
| EvaluationResultImpl bitOr(BinaryExpression node, EvaluationResultImpl rightOperand) => rightOperand.bitOrValid(node, this); |
| EvaluationResultImpl bitXor(BinaryExpression node, EvaluationResultImpl rightOperand) => rightOperand.bitXorValid(node, this); |
| EvaluationResultImpl concatenate(Expression node, EvaluationResultImpl rightOperand) => rightOperand.concatenateValid(node, this); |
| EvaluationResultImpl divide(BinaryExpression node, EvaluationResultImpl rightOperand) => rightOperand.divideValid(node, this); |
| EvaluationResultImpl equalEqual(Expression node, EvaluationResultImpl rightOperand) => rightOperand.equalEqualValid(node, this); |
| Object get value => _value; |
| EvaluationResultImpl greaterThan(BinaryExpression node, EvaluationResultImpl rightOperand) => rightOperand.greaterThanValid(node, this); |
| EvaluationResultImpl greaterThanOrEqual(BinaryExpression node, EvaluationResultImpl rightOperand) => rightOperand.greaterThanOrEqualValid(node, this); |
| EvaluationResultImpl integerDivide(BinaryExpression node, EvaluationResultImpl rightOperand) => rightOperand.integerDivideValid(node, this); |
| EvaluationResultImpl lessThan(BinaryExpression node, EvaluationResultImpl rightOperand) => rightOperand.lessThanValid(node, this); |
| EvaluationResultImpl lessThanOrEqual(BinaryExpression node, EvaluationResultImpl rightOperand) => rightOperand.lessThanOrEqualValid(node, this); |
| EvaluationResultImpl logicalAnd(BinaryExpression node, EvaluationResultImpl rightOperand) => rightOperand.logicalAndValid(node, this); |
| EvaluationResultImpl logicalNot(Expression node) { |
| if (_value == null) { |
| return RESULT_TRUE; |
| } else if (_value is bool) { |
| return ((_value as bool)) ? RESULT_FALSE : RESULT_TRUE; |
| } |
| return error(node); |
| } |
| EvaluationResultImpl logicalOr(BinaryExpression node, EvaluationResultImpl rightOperand) => rightOperand.logicalOrValid(node, this); |
| EvaluationResultImpl minus(BinaryExpression node, EvaluationResultImpl rightOperand) => rightOperand.minusValid(node, this); |
| EvaluationResultImpl negated(Expression node) { |
| if (_value == null) { |
| return error(node); |
| } else if (_value is int) { |
| return valueOf(-((_value as int))); |
| } else if (_value is double) { |
| return valueOf3(-((_value as double))); |
| } |
| return error(node); |
| } |
| EvaluationResultImpl notEqual(BinaryExpression node, EvaluationResultImpl rightOperand) => rightOperand.notEqualValid(node, this); |
| EvaluationResultImpl performToString(ASTNode node) { |
| if (_value == null) { |
| return valueOf4("null"); |
| } else if (_value is bool) { |
| return valueOf4(((_value as bool)).toString()); |
| } else if (_value is int) { |
| return valueOf4(((_value as int)).toString()); |
| } else if (_value is double) { |
| return valueOf4(((_value as double)).toString()); |
| } else if (_value is String) { |
| return this; |
| } |
| return error(node); |
| } |
| EvaluationResultImpl remainder(BinaryExpression node, EvaluationResultImpl rightOperand) => rightOperand.remainderValid(node, this); |
| EvaluationResultImpl shiftLeft(BinaryExpression node, EvaluationResultImpl rightOperand) => rightOperand.shiftLeftValid(node, this); |
| EvaluationResultImpl shiftRight(BinaryExpression node, EvaluationResultImpl rightOperand) => rightOperand.shiftRightValid(node, this); |
| EvaluationResultImpl times(BinaryExpression node, EvaluationResultImpl rightOperand) => rightOperand.timesValid(node, this); |
| String toString() { |
| if (_value == null) { |
| return "null"; |
| } |
| return _value.toString(); |
| } |
| EvaluationResultImpl addToError(BinaryExpression node, ErrorResult leftOperand) => leftOperand; |
| EvaluationResultImpl addToValid(BinaryExpression node, ValidResult leftOperand2) { |
| Object leftValue = leftOperand2.value; |
| if (leftValue == null) { |
| return error(node.leftOperand); |
| } else if (_value == null) { |
| return error(node.rightOperand); |
| } else if (leftValue is int) { |
| if (_value is int) { |
| return valueOf(((leftValue as int)) + (_value as int)); |
| } else if (_value is double) { |
| return valueOf3(((leftValue as int)).toDouble() + ((_value as double))); |
| } |
| } else if (leftValue is double) { |
| if (_value is int) { |
| return valueOf3(((leftValue as double)) + ((_value as int)).toDouble()); |
| } else if (_value is double) { |
| return valueOf3(((leftValue as double)) + ((_value as double))); |
| } |
| } else if (leftValue is String) { |
| if (_value is String) { |
| return valueOf4("${((leftValue as String))}${((_value as String))}"); |
| } |
| } |
| return error(node); |
| } |
| EvaluationResultImpl bitAndError(BinaryExpression node, ErrorResult leftOperand) => leftOperand; |
| EvaluationResultImpl bitAndValid(BinaryExpression node, ValidResult leftOperand2) { |
| Object leftValue = leftOperand2.value; |
| if (leftValue == null) { |
| return error(node.leftOperand); |
| } else if (_value == null) { |
| return error(node.rightOperand); |
| } else if (leftValue is int) { |
| if (_value is int) { |
| return valueOf(((leftValue as int)) & (_value as int)); |
| } |
| return error(node.leftOperand); |
| } |
| if (_value is int) { |
| return error(node.rightOperand); |
| } |
| return union(error(node.leftOperand), error(node.rightOperand)); |
| } |
| EvaluationResultImpl bitOrError(BinaryExpression node, ErrorResult leftOperand) => leftOperand; |
| EvaluationResultImpl bitOrValid(BinaryExpression node, ValidResult leftOperand2) { |
| Object leftValue = leftOperand2.value; |
| if (leftValue == null) { |
| return error(node.leftOperand); |
| } else if (_value == null) { |
| return error(node.rightOperand); |
| } else if (leftValue is int) { |
| if (_value is int) { |
| return valueOf(((leftValue as int)) | (_value as int)); |
| } |
| return error(node.leftOperand); |
| } |
| if (_value is int) { |
| return error(node.rightOperand); |
| } |
| return union(error(node.leftOperand), error(node.rightOperand)); |
| } |
| EvaluationResultImpl bitXorError(BinaryExpression node, ErrorResult leftOperand) => leftOperand; |
| EvaluationResultImpl bitXorValid(BinaryExpression node, ValidResult leftOperand2) { |
| Object leftValue = leftOperand2.value; |
| if (leftValue == null) { |
| return error(node.leftOperand); |
| } else if (_value == null) { |
| return error(node.rightOperand); |
| } else if (leftValue is int) { |
| if (_value is int) { |
| return valueOf(((leftValue as int)) ^ (_value as int)); |
| } |
| return error(node.leftOperand); |
| } |
| if (_value is int) { |
| return error(node.rightOperand); |
| } |
| return union(error(node.leftOperand), error(node.rightOperand)); |
| } |
| EvaluationResultImpl concatenateError(Expression node, ErrorResult leftOperand) => leftOperand; |
| EvaluationResultImpl concatenateValid(Expression node, ValidResult leftOperand) { |
| Object leftValue = leftOperand.value; |
| if (leftValue is String && _value is String) { |
| return valueOf4("${((leftValue as String))}${((_value as String))}"); |
| } |
| return error(node); |
| } |
| EvaluationResultImpl divideError(BinaryExpression node, ErrorResult leftOperand) => leftOperand; |
| EvaluationResultImpl divideValid(BinaryExpression node, ValidResult leftOperand2) { |
| Object leftValue = leftOperand2.value; |
| if (leftValue == null) { |
| return error(node.leftOperand); |
| } else if (_value == null) { |
| return error(node.rightOperand); |
| } else if (leftValue is int) { |
| if (_value is int) { |
| if (((_value as int)) == 0) { |
| return valueOf3(((leftValue as int)).toDouble() / ((_value as int)).toDouble()); |
| } |
| return valueOf(((leftValue as int)) ~/ (_value as int)); |
| } else if (_value is double) { |
| return valueOf3(((leftValue as int)).toDouble() / ((_value as double))); |
| } |
| } else if (leftValue is double) { |
| if (_value is int) { |
| return valueOf3(((leftValue as double)) / ((_value as int)).toDouble()); |
| } else if (_value is double) { |
| return valueOf3(((leftValue as double)) / ((_value as double))); |
| } |
| } |
| return error(node); |
| } |
| EvaluationResultImpl equalEqualError(Expression node, ErrorResult leftOperand) => leftOperand; |
| EvaluationResultImpl equalEqualValid(Expression node, ValidResult leftOperand) { |
| Object leftValue = leftOperand.value; |
| if (leftValue == null) { |
| return valueOf2(_value == null); |
| } else if (leftValue is bool) { |
| if (_value is bool) { |
| return valueOf2(identical(((leftValue as bool)), ((_value as bool)))); |
| } |
| return RESULT_FALSE; |
| } else if (leftValue is int) { |
| if (_value is int) { |
| return valueOf2(((leftValue as int)) == _value); |
| } else if (_value is double) { |
| return valueOf2(toDouble((leftValue as int)) == _value); |
| } |
| return RESULT_FALSE; |
| } else if (leftValue is double) { |
| if (_value is int) { |
| return valueOf2(((leftValue as double)) == toDouble((_value as int))); |
| } else if (_value is double) { |
| return valueOf2(((leftValue as double)) == _value); |
| } |
| return RESULT_FALSE; |
| } else if (leftValue is String) { |
| if (_value is String) { |
| return valueOf2(((leftValue as String)) == _value); |
| } |
| return RESULT_FALSE; |
| } |
| return RESULT_FALSE; |
| } |
| EvaluationResultImpl greaterThanError(BinaryExpression node, ErrorResult leftOperand) => leftOperand; |
| EvaluationResultImpl greaterThanOrEqualError(BinaryExpression node, ErrorResult leftOperand) => leftOperand; |
| EvaluationResultImpl greaterThanOrEqualValid(BinaryExpression node, ValidResult leftOperand2) { |
| Object leftValue = leftOperand2.value; |
| if (leftValue == null) { |
| return error(node.leftOperand); |
| } else if (_value == null) { |
| return error(node.rightOperand); |
| } else if (leftValue is int) { |
| if (_value is int) { |
| return valueOf2(((leftValue as int)).compareTo((_value as int)) >= 0); |
| } else if (_value is double) { |
| return valueOf2(((leftValue as int)).toDouble() >= ((_value as double))); |
| } |
| } else if (leftValue is double) { |
| if (_value is int) { |
| return valueOf2(((leftValue as double)) >= ((_value as int)).toDouble()); |
| } else if (_value is double) { |
| return valueOf2(((leftValue as double)) >= ((_value as double))); |
| } |
| } |
| return error(node); |
| } |
| EvaluationResultImpl greaterThanValid(BinaryExpression node, ValidResult leftOperand2) { |
| Object leftValue = leftOperand2.value; |
| if (leftValue == null) { |
| return error(node.leftOperand); |
| } else if (_value == null) { |
| return error(node.rightOperand); |
| } else if (leftValue is int) { |
| if (_value is int) { |
| return valueOf2(((leftValue as int)).compareTo((_value as int)) > 0); |
| } else if (_value is double) { |
| return valueOf2(((leftValue as int)).toDouble() > ((_value as double))); |
| } |
| } else if (leftValue is double) { |
| if (_value is int) { |
| return valueOf2(((leftValue as double)) > ((_value as int)).toDouble()); |
| } else if (_value is double) { |
| return valueOf2(((leftValue as double)) > ((_value as double))); |
| } |
| } |
| return error(node); |
| } |
| EvaluationResultImpl integerDivideError(BinaryExpression node, ErrorResult leftOperand) => leftOperand; |
| EvaluationResultImpl integerDivideValid(BinaryExpression node, ValidResult leftOperand2) { |
| Object leftValue = leftOperand2.value; |
| if (leftValue == null) { |
| return error(node.leftOperand); |
| } else if (_value == null) { |
| return error(node.rightOperand); |
| } else if (leftValue is int) { |
| if (_value is int) { |
| if (((_value as int)) == 0) { |
| return valueOf3(((leftValue as int)).toDouble() / ((_value as int)).toDouble()); |
| } |
| return valueOf(((leftValue as int)) ~/ (_value as int)); |
| } else if (_value is double) { |
| double result = ((leftValue as int)).toDouble() / ((_value as double)); |
| return valueOf((result as int)); |
| } |
| } else if (leftValue is double) { |
| if (_value is int) { |
| double result = ((leftValue as double)) / ((_value as int)).toDouble(); |
| return valueOf((result as int)); |
| } else if (_value is double) { |
| double result = ((leftValue as double)) / ((_value as double)); |
| return valueOf((result as int)); |
| } |
| } |
| return error(node); |
| } |
| EvaluationResultImpl lessThanError(BinaryExpression node, ErrorResult leftOperand) => leftOperand; |
| EvaluationResultImpl lessThanOrEqualError(BinaryExpression node, ErrorResult leftOperand) => leftOperand; |
| EvaluationResultImpl lessThanOrEqualValid(BinaryExpression node, ValidResult leftOperand2) { |
| Object leftValue = leftOperand2.value; |
| if (leftValue == null) { |
| return error(node.leftOperand); |
| } else if (_value == null) { |
| return error(node.rightOperand); |
| } else if (leftValue is int) { |
| if (_value is int) { |
| return valueOf2(((leftValue as int)).compareTo((_value as int)) <= 0); |
| } else if (_value is double) { |
| return valueOf2(((leftValue as int)).toDouble() <= ((_value as double))); |
| } |
| } else if (leftValue is double) { |
| if (_value is int) { |
| return valueOf2(((leftValue as double)) <= ((_value as int)).toDouble()); |
| } else if (_value is double) { |
| return valueOf2(((leftValue as double)) <= ((_value as double))); |
| } |
| } |
| return error(node); |
| } |
| EvaluationResultImpl lessThanValid(BinaryExpression node, ValidResult leftOperand2) { |
| Object leftValue = leftOperand2.value; |
| if (leftValue == null) { |
| return error(node.leftOperand); |
| } else if (_value == null) { |
| return error(node.rightOperand); |
| } else if (leftValue is int) { |
| if (_value is int) { |
| return valueOf2(((leftValue as int)).compareTo((_value as int)) < 0); |
| } else if (_value is double) { |
| return valueOf2(((leftValue as int)).toDouble() < ((_value as double))); |
| } |
| } else if (leftValue is double) { |
| if (_value is int) { |
| return valueOf2(((leftValue as double)) < ((_value as int)).toDouble()); |
| } else if (_value is double) { |
| return valueOf2(((leftValue as double)) < ((_value as double))); |
| } |
| } |
| return error(node); |
| } |
| EvaluationResultImpl logicalAndError(BinaryExpression node, ErrorResult leftOperand) => leftOperand; |
| EvaluationResultImpl logicalAndValid(BinaryExpression node, ValidResult leftOperand) { |
| Object leftValue = leftOperand.value; |
| if (leftValue is bool && ((leftValue as bool))) { |
| return booleanConversion(node.rightOperand, _value); |
| } |
| return RESULT_FALSE; |
| } |
| EvaluationResultImpl logicalOrError(BinaryExpression node, ErrorResult leftOperand) => leftOperand; |
| EvaluationResultImpl logicalOrValid(BinaryExpression node, ValidResult leftOperand) { |
| Object leftValue = leftOperand.value; |
| if (leftValue is bool && ((leftValue as bool))) { |
| return RESULT_TRUE; |
| } |
| return booleanConversion(node.rightOperand, _value); |
| } |
| EvaluationResultImpl minusError(BinaryExpression node, ErrorResult leftOperand) => leftOperand; |
| EvaluationResultImpl minusValid(BinaryExpression node, ValidResult leftOperand2) { |
| Object leftValue = leftOperand2.value; |
| if (leftValue == null) { |
| return error(node.leftOperand); |
| } else if (_value == null) { |
| return error(node.rightOperand); |
| } else if (leftValue is int) { |
| if (_value is int) { |
| return valueOf(((leftValue as int)) - (_value as int)); |
| } else if (_value is double) { |
| return valueOf3(((leftValue as int)).toDouble() - ((_value as double))); |
| } |
| } else if (leftValue is double) { |
| if (_value is int) { |
| return valueOf3(((leftValue as double)) - ((_value as int)).toDouble()); |
| } else if (_value is double) { |
| return valueOf3(((leftValue as double)) - ((_value as double))); |
| } |
| } |
| return error(node); |
| } |
| EvaluationResultImpl notEqualError(BinaryExpression node, ErrorResult leftOperand) => leftOperand; |
| EvaluationResultImpl notEqualValid(BinaryExpression node, ValidResult leftOperand) { |
| Object leftValue = leftOperand.value; |
| if (leftValue == null) { |
| return valueOf2(_value != null); |
| } else if (leftValue is bool) { |
| if (_value is bool) { |
| return valueOf2(((leftValue as bool)) != ((_value as bool))); |
| } |
| return RESULT_TRUE; |
| } else if (leftValue is int) { |
| if (_value is int) { |
| return valueOf2(((leftValue as int)) != _value); |
| } else if (_value is double) { |
| return valueOf2(toDouble((leftValue as int)) != _value); |
| } |
| return RESULT_TRUE; |
| } else if (leftValue is double) { |
| if (_value is int) { |
| return valueOf2(((leftValue as double)) != toDouble((_value as int))); |
| } else if (_value is double) { |
| return valueOf2(((leftValue as double)) != _value); |
| } |
| return RESULT_TRUE; |
| } else if (leftValue is String) { |
| if (_value is String) { |
| return valueOf2(((leftValue as String)) != _value); |
| } |
| return RESULT_TRUE; |
| } |
| return RESULT_TRUE; |
| } |
| EvaluationResultImpl remainderError(BinaryExpression node, ErrorResult leftOperand) => leftOperand; |
| EvaluationResultImpl remainderValid(BinaryExpression node, ValidResult leftOperand2) { |
| Object leftValue = leftOperand2.value; |
| if (leftValue == null) { |
| return error(node.leftOperand); |
| } else if (_value == null) { |
| return error(node.rightOperand); |
| } else if (leftValue is int) { |
| if (_value is int) { |
| if (((_value as int)) == 0) { |
| return valueOf3(((leftValue as int)).toDouble() % ((_value as int)).toDouble()); |
| } |
| return valueOf(((leftValue as int)).remainder((_value as int))); |
| } else if (_value is double) { |
| return valueOf3(((leftValue as int)).toDouble() % ((_value as double))); |
| } |
| } else if (leftValue is double) { |
| if (_value is int) { |
| return valueOf3(((leftValue as double)) % ((_value as int)).toDouble()); |
| } else if (_value is double) { |
| return valueOf3(((leftValue as double)) % ((_value as double))); |
| } |
| } |
| return error(node); |
| } |
| EvaluationResultImpl shiftLeftError(BinaryExpression node, ErrorResult leftOperand) => leftOperand; |
| EvaluationResultImpl shiftLeftValid(BinaryExpression node, ValidResult leftOperand2) { |
| Object leftValue = leftOperand2.value; |
| if (leftValue == null) { |
| return error(node.leftOperand); |
| } else if (_value == null) { |
| return error(node.rightOperand); |
| } else if (leftValue is int) { |
| if (_value is int) { |
| return valueOf(((leftValue as int)) << ((_value as int))); |
| } |
| return error(node.rightOperand); |
| } |
| if (_value is int) { |
| return error(node.leftOperand); |
| } |
| return union(error(node.leftOperand), error(node.rightOperand)); |
| } |
| EvaluationResultImpl shiftRightError(BinaryExpression node, ErrorResult leftOperand) => leftOperand; |
| EvaluationResultImpl shiftRightValid(BinaryExpression node, ValidResult leftOperand2) { |
| Object leftValue = leftOperand2.value; |
| if (leftValue == null) { |
| return error(node.leftOperand); |
| } else if (_value == null) { |
| return error(node.rightOperand); |
| } else if (leftValue is int) { |
| if (_value is int) { |
| return valueOf(((leftValue as int)) >> ((_value as int))); |
| } |
| return error(node.rightOperand); |
| } |
| if (_value is int) { |
| return error(node.leftOperand); |
| } |
| return union(error(node.leftOperand), error(node.rightOperand)); |
| } |
| EvaluationResultImpl timesError(BinaryExpression node, ErrorResult leftOperand) => leftOperand; |
| EvaluationResultImpl timesValid(BinaryExpression node, ValidResult leftOperand2) { |
| Object leftValue = leftOperand2.value; |
| if (leftValue == null) { |
| return error(node.leftOperand); |
| } else if (_value == null) { |
| return error(node.rightOperand); |
| } else if (leftValue is int) { |
| if (_value is int) { |
| return valueOf(((leftValue as int)) * (_value as int)); |
| } else if (_value is double) { |
| return valueOf3(((leftValue as int)).toDouble() * ((_value as double))); |
| } |
| } else if (leftValue is double) { |
| if (_value is int) { |
| return valueOf3(((leftValue as double)) * ((_value as int)).toDouble()); |
| } else if (_value is double) { |
| return valueOf3(((leftValue as double)) * ((_value as double))); |
| } |
| } |
| return error(node); |
| } |
| /** |
| * Return the result of applying boolean conversion to the given value. |
| * @param node the node against which errors should be reported |
| * @param value the value to be converted to a boolean |
| * @return the result of applying boolean conversion to the given value |
| */ |
| EvaluationResultImpl booleanConversion(ASTNode node, Object value) { |
| if (value == null) { |
| return error(node); |
| } else if (value is bool && ((value as bool))) { |
| return RESULT_TRUE; |
| } |
| return RESULT_FALSE; |
| } |
| ErrorResult error(ASTNode node) => error2(node, CompileTimeErrorCode.INVALID_CONSTANT); |
| /** |
| * Return a result object representing an error associated with the given node. |
| * @param node the AST node associated with the error |
| * @param code the error code indicating the nature of the error |
| * @return a result object representing an error associated with the given node |
| */ |
| ErrorResult error2(ASTNode node, ErrorCode code) => new ErrorResult.con1(node, code); |
| double toDouble(int value) => value.toDouble(); |
| /** |
| * Return an error result that is the union of the two given error results. |
| * @param firstError the first error to be combined |
| * @param secondError the second error to be combined |
| * @return an error result that is the union of the two given error results |
| */ |
| ErrorResult union(ErrorResult firstError, ErrorResult secondError) => new ErrorResult.con2(firstError, secondError); |
| /** |
| * Return a result object representing the given value. |
| * @param value the value to be represented as a result object |
| * @return a result object representing the given value |
| */ |
| ValidResult valueOf(int value) => new ValidResult(value); |
| /** |
| * Return a result object representing the given value. |
| * @param value the value to be represented as a result object |
| * @return a result object representing the given value |
| */ |
| ValidResult valueOf2(bool value) => value ? RESULT_TRUE : RESULT_FALSE; |
| /** |
| * Return a result object representing the given value. |
| * @param value the value to be represented as a result object |
| * @return a result object representing the given value |
| */ |
| ValidResult valueOf3(double value) => new ValidResult(value); |
| /** |
| * Return a result object representing the given value. |
| * @param value the value to be represented as a result object |
| * @return a result object representing the given value |
| */ |
| ValidResult valueOf4(String value) => new ValidResult(value); |
| } |