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 }