001: /*
002: * Copyright 2007 Google Inc.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License"); you may not
005: * use this file except in compliance with the License. You may obtain a copy of
006: * the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
012: * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
013: * License for the specific language governing permissions and limitations under
014: * the License.
015: */
016: package com.google.gwt.dev.js;
017:
018: import com.google.gwt.dev.js.ast.JsArrayAccess;
019: import com.google.gwt.dev.js.ast.JsArrayLiteral;
020: import com.google.gwt.dev.js.ast.JsBinaryOperation;
021: import com.google.gwt.dev.js.ast.JsConditional;
022: import com.google.gwt.dev.js.ast.JsContext;
023: import com.google.gwt.dev.js.ast.JsExprStmt;
024: import com.google.gwt.dev.js.ast.JsExpression;
025: import com.google.gwt.dev.js.ast.JsFunction;
026: import com.google.gwt.dev.js.ast.JsInvocation;
027: import com.google.gwt.dev.js.ast.JsNameRef;
028: import com.google.gwt.dev.js.ast.JsNew;
029: import com.google.gwt.dev.js.ast.JsObjectLiteral;
030: import com.google.gwt.dev.js.ast.JsPostfixOperation;
031: import com.google.gwt.dev.js.ast.JsPrefixOperation;
032: import com.google.gwt.dev.js.ast.JsRegExp;
033: import com.google.gwt.dev.js.ast.JsVisitor;
034:
035: /**
036: * Determines if an expression statement needs to be surrounded by parentheses.
037: *
038: * The statement or the left-most expression needs to be surrounded by
039: * parentheses if the left-most expression is an object literal or a function
040: * object. Function declarations do not need parentheses.
041: *
042: * For example the following require parentheses:<br>
043: * <ul>
044: * <li>{ key : 'value'}</li>
045: * <li>{ key : 'value'}.key</li>
046: * <li>function () {return 1;}()</li>
047: * <li>function () {return 1;}.prototype</li>
048: * </ul>
049: *
050: * The following do not require parentheses:<br>
051: * <ul>
052: * <li>var x = { key : 'value'}</li>
053: * <li>"string" + { key : 'value'}.key</li>
054: * <li>function func() {}</li>
055: * <li>function() {}</li>
056: * </ul>
057: */
058: public class JsFirstExpressionVisitor extends JsVisitor {
059:
060: public static boolean exec(JsExprStmt statement) {
061: JsFirstExpressionVisitor visitor = new JsFirstExpressionVisitor();
062: JsExpression expression = statement.getExpression();
063: // Pure function declarations do not need parentheses
064: if (expression instanceof JsFunction) {
065: return false;
066: }
067: visitor.accept(statement.getExpression());
068: return visitor.needsParentheses;
069: }
070:
071: private boolean needsParentheses = false;
072:
073: private JsFirstExpressionVisitor() {
074: }
075:
076: public boolean visit(JsArrayAccess x, JsContext<JsExpression> ctx) {
077: accept(x.getArrayExpr());
078: return false;
079: }
080:
081: public boolean visit(JsArrayLiteral x, JsContext<JsExpression> ctx) {
082: return false;
083: }
084:
085: public boolean visit(JsBinaryOperation x,
086: JsContext<JsExpression> ctx) {
087: accept(x.getArg1());
088: return false;
089: }
090:
091: public boolean visit(JsConditional x, JsContext<JsExpression> ctx) {
092: accept(x.getTestExpression());
093: return false;
094: }
095:
096: public boolean visit(JsFunction x, JsContext<JsExpression> ctx) {
097: needsParentheses = true;
098: return false;
099: }
100:
101: public boolean visit(JsInvocation x, JsContext<JsExpression> ctx) {
102: accept(x.getQualifier());
103: return false;
104: }
105:
106: public boolean visit(JsNameRef x, JsContext<JsExpression> ctx) {
107: if (!x.isLeaf()) {
108: accept(x.getQualifier());
109: }
110: return false;
111: }
112:
113: public boolean visit(JsNew x, JsContext<JsExpression> ctx) {
114: return false;
115: }
116:
117: public boolean visit(JsObjectLiteral x, JsContext<JsExpression> ctx) {
118: needsParentheses = true;
119: return false;
120: }
121:
122: public boolean visit(JsPostfixOperation x,
123: JsContext<JsExpression> ctx) {
124: accept(x.getArg());
125: return false;
126: }
127:
128: public boolean visit(JsPrefixOperation x,
129: JsContext<JsExpression> ctx) {
130: return false;
131: }
132:
133: public boolean visit(JsRegExp x, JsContext<JsExpression> ctx) {
134: return false;
135: }
136:
137: }
|