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