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 com.google.dart.compiler.backend.js.ast.JsExpressionStatement; 009 010 /** 011 * Determines if an expression statement needs to be surrounded by parentheses. 012 * <p/> 013 * The statement or the left-most expression needs to be surrounded by 014 * parentheses if the left-most expression is an object literal or a function 015 * object. Function declarations do not need parentheses. 016 * <p/> 017 * For example the following require parentheses:<br> 018 * <ul> 019 * <li>{ key : 'value'}</li> 020 * <li>{ key : 'value'}.key</li> 021 * <li>function () {return 1;}()</li> 022 * <li>function () {return 1;}.prototype</li> 023 * </ul> 024 * <p/> 025 * The following do not require parentheses:<br> 026 * <ul> 027 * <li>var x = { key : 'value'}</li> 028 * <li>"string" + { key : 'value'}.key</li> 029 * <li>function func() {}</li> 030 * <li>function() {}</li> 031 * </ul> 032 */ 033 public class JsFirstExpressionVisitor extends RecursiveJsVisitor { 034 public static boolean exec(JsExpressionStatement statement) { 035 JsExpression expression = statement.getExpression(); 036 // Pure function declarations do not need parentheses 037 if (expression instanceof JsFunction) { 038 return false; 039 } 040 041 JsFirstExpressionVisitor visitor = new JsFirstExpressionVisitor(); 042 visitor.accept(statement.getExpression()); 043 return visitor.needsParentheses; 044 } 045 046 private boolean needsParentheses = false; 047 048 private JsFirstExpressionVisitor() { 049 } 050 051 @Override 052 public void visitArrayAccess(JsArrayAccess x) { 053 accept(x.getArrayExpression()); 054 } 055 056 @Override 057 public void visitArray(JsArrayLiteral x) { 058 } 059 060 @Override 061 public void visitBinaryExpression(JsBinaryOperation x) { 062 accept(x.getArg1()); 063 } 064 065 @Override 066 public void visitConditional(JsConditional x) { 067 accept(x.getTestExpression()); 068 } 069 070 @Override 071 public void visitFunction(JsFunction x) { 072 needsParentheses = true; 073 } 074 075 @Override 076 public void visitInvocation(JsInvocation invocation) { 077 accept(invocation.getQualifier()); 078 } 079 080 @Override 081 public void visitNameRef(JsNameRef nameRef) { 082 if (!nameRef.isLeaf()) { 083 accept(nameRef.getQualifier()); 084 } 085 } 086 087 @Override 088 public void visitNew(JsNew x) { 089 } 090 091 @Override 092 public void visitObjectLiteral(JsObjectLiteral x) { 093 needsParentheses = true; 094 } 095 096 @Override 097 public void visitPostfixOperation(JsPostfixOperation x) { 098 accept(x.getArg()); 099 } 100 101 @Override 102 public void visitPrefixOperation(JsPrefixOperation x) { 103 } 104 }