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 }