001 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
002 // for details. All rights reserved. Use of this source code is governed by a
003 // BSD-style license that can be found in the LICENSE file.
004
005 package com.google.dart.compiler.backend.js;
006
007 import com.google.dart.compiler.backend.js.ast.*;
008
009 /**
010 * Searches for method invocations in constructor expressions that would not
011 * normally be surrounded by parentheses.
012 */
013 public class JsConstructExpressionVisitor extends RecursiveJsVisitor {
014 public static boolean exec(JsExpression expression) {
015 if (JsPrecedenceVisitor.exec(expression) < JsPrecedenceVisitor.PRECEDENCE_NEW) {
016 return true;
017 }
018 JsConstructExpressionVisitor visitor = new JsConstructExpressionVisitor();
019 visitor.accept(expression);
020 return visitor.containsInvocation;
021 }
022
023 private boolean containsInvocation;
024
025 private JsConstructExpressionVisitor() {
026 }
027
028 /**
029 * We only look at the array expression since the index has its own scope.
030 */
031 @Override
032 public void visitArrayAccess(JsArrayAccess x) {
033 accept(x.getArrayExpression());
034 }
035
036 /**
037 * Array literals have their own scoping.
038 */
039 @Override
040 public void visitArray(JsArrayLiteral x) {
041 }
042
043 /**
044 * Functions have their own scoping.
045 */
046 @Override
047 public void visitFunction(JsFunction x) {
048 }
049
050 @Override
051 public void visitInvocation(JsInvocation invocation) {
052 containsInvocation = true;
053 }
054
055 @Override
056 public void visitNameRef(JsNameRef nameRef) {
057 if (!nameRef.isLeaf()) {
058 accept(nameRef.getQualifier());
059 }
060 }
061
062 /**
063 * New constructs bind to the nearest set of parentheses.
064 */
065 @Override
066 public void visitNew(JsNew x) {
067 }
068
069 /**
070 * Object literals have their own scope.
071 */
072 @Override
073 public void visitObjectLiteral(JsObjectLiteral x) {
074 }
075
076 /**
077 * We only look at nodes that would not normally be surrounded by parentheses.
078 */
079 @Override
080 public <T extends JsNode> void accept(T node) {
081 // Assign to Object to prevent 'inconvertible types' compile errors due
082 // to http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6548436
083 // reproducible in jdk1.6.0_02.
084 if (node instanceof JsExpression) {
085 JsExpression expression = (JsExpression) node;
086 int precedence = JsPrecedenceVisitor.exec(expression);
087 // Only visit expressions that won't automatically be surrounded by
088 // parentheses
089 if (precedence < JsPrecedenceVisitor.PRECEDENCE_NEW) {
090 return;
091 }
092 }
093 super.accept(node);
094 }
095 }