| // Copyright (c) 2011, 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. |
| |
| part of dart2js; |
| |
| class TreeValidatorTask extends CompilerTask { |
| TreeValidatorTask(Compiler compiler) : super(compiler); |
| |
| void validate(Node tree) { |
| assert(check(tree)); |
| } |
| |
| bool check(Node tree) { |
| List<InvalidNodeError> errors = []; |
| void report(node, message) { |
| final error = new InvalidNodeError(node, message); |
| errors.add(error); |
| compiler.reportWarning(node, message); |
| }; |
| final validator = new ValidatorVisitor(report); |
| tree.accept(new TraversingVisitor(validator)); |
| |
| return errors.isEmpty; |
| } |
| } |
| |
| class ValidatorVisitor extends Visitor { |
| final Function reportInvalidNode; |
| |
| ValidatorVisitor(Function this.reportInvalidNode); |
| |
| expect(Node node, bool test, [message]) { |
| if (!test) reportInvalidNode(node, message); |
| } |
| |
| visitNode(Node node) {} |
| |
| visitSendSet(SendSet node) { |
| final selector = node.selector; |
| final name = node.assignmentOperator.source.stringValue; |
| final arguments = node.arguments; |
| |
| expect(node, arguments != null); |
| expect(node, |
| selector is Identifier || selector is FunctionExpression, |
| 'selector is not assignable'); |
| if (identical(name, '++') || identical(name, '--')) { |
| expect(node, node.assignmentOperator is Operator); |
| if (node.isIndex) { |
| expect(node.arguments.tail.head, node.arguments.tail.isEmpty); |
| } else { |
| expect(node.arguments.head, node.arguments.isEmpty); |
| } |
| } else { |
| expect(node, !node.arguments.isEmpty); |
| } |
| } |
| |
| visitReturn(Return node) { |
| if (!node.isRedirectingFactoryBody && node.hasExpression) { |
| // We allow non-expression expressions in Return nodes, but only when |
| // using them to hold redirecting factory constructors. |
| expect(node, node.expression.asExpression() != null); |
| } |
| } |
| } |
| |
| class InvalidNodeError { |
| final Node node; |
| final String message; |
| InvalidNodeError(this.node, [this.message]); |
| |
| toString() { |
| String nodeString = node.toDebugString(); |
| String result = 'invalid node: $nodeString'; |
| if (message != null) result = '$result ($message)'; |
| return result; |
| } |
| } |