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.JsBlock;
022: import com.google.gwt.dev.js.ast.JsBooleanLiteral;
023: import com.google.gwt.dev.js.ast.JsBreak;
024: import com.google.gwt.dev.js.ast.JsCase;
025: import com.google.gwt.dev.js.ast.JsCatch;
026: import com.google.gwt.dev.js.ast.JsConditional;
027: import com.google.gwt.dev.js.ast.JsContext;
028: import com.google.gwt.dev.js.ast.JsContinue;
029: import com.google.gwt.dev.js.ast.JsDebugger;
030: import com.google.gwt.dev.js.ast.JsDecimalLiteral;
031: import com.google.gwt.dev.js.ast.JsDefault;
032: import com.google.gwt.dev.js.ast.JsDoWhile;
033: import com.google.gwt.dev.js.ast.JsEmpty;
034: import com.google.gwt.dev.js.ast.JsExprStmt;
035: import com.google.gwt.dev.js.ast.JsExpression;
036: import com.google.gwt.dev.js.ast.JsFor;
037: import com.google.gwt.dev.js.ast.JsForIn;
038: import com.google.gwt.dev.js.ast.JsFunction;
039: import com.google.gwt.dev.js.ast.JsIf;
040: import com.google.gwt.dev.js.ast.JsIntegralLiteral;
041: import com.google.gwt.dev.js.ast.JsInvocation;
042: import com.google.gwt.dev.js.ast.JsLabel;
043: import com.google.gwt.dev.js.ast.JsNameRef;
044: import com.google.gwt.dev.js.ast.JsNew;
045: import com.google.gwt.dev.js.ast.JsNullLiteral;
046: import com.google.gwt.dev.js.ast.JsObjectLiteral;
047: import com.google.gwt.dev.js.ast.JsParameter;
048: import com.google.gwt.dev.js.ast.JsPostfixOperation;
049: import com.google.gwt.dev.js.ast.JsPrefixOperation;
050: import com.google.gwt.dev.js.ast.JsProgram;
051: import com.google.gwt.dev.js.ast.JsPropertyInitializer;
052: import com.google.gwt.dev.js.ast.JsRegExp;
053: import com.google.gwt.dev.js.ast.JsReturn;
054: import com.google.gwt.dev.js.ast.JsStatement;
055: import com.google.gwt.dev.js.ast.JsStringLiteral;
056: import com.google.gwt.dev.js.ast.JsSwitch;
057: import com.google.gwt.dev.js.ast.JsSwitchMember;
058: import com.google.gwt.dev.js.ast.JsThisRef;
059: import com.google.gwt.dev.js.ast.JsThrow;
060: import com.google.gwt.dev.js.ast.JsTry;
061: import com.google.gwt.dev.js.ast.JsVars;
062: import com.google.gwt.dev.js.ast.JsVisitor;
063: import com.google.gwt.dev.js.ast.JsWhile;
064: import com.google.gwt.dev.js.ast.JsVars.JsVar;
065:
066: /**
067: * Precedence indices from "JavaScript - The Definitive Guide" 4th Edition (page
068: * 57)
069: *
070: * Precedence 17 is for indivisible primaries that either don't have children,
071: * or provide their own delimiters.
072: *
073: * Precedence 16 is for really important things that have their own AST classes.
074: *
075: * Precedence 15 is for the new construct.
076: *
077: * Precedence 14 is for unary operators.
078: *
079: * Precedences 12 through 4 are for non-assigning binary operators.
080: *
081: * Precedence 3 is for the tertiary conditional.
082: *
083: * Precedence 2 is for assignments.
084: *
085: * Precedence 1 is for comma operations.
086: */
087: class JsPrecedenceVisitor extends JsVisitor {
088:
089: public static int exec(JsExpression expression) {
090: JsPrecedenceVisitor visitor = new JsPrecedenceVisitor();
091: visitor.accept(expression);
092: if (visitor.answer < 0) {
093: throw new RuntimeException("Precedence must be >= 0!");
094: }
095: return visitor.answer;
096: }
097:
098: private int answer = -1;
099:
100: private JsPrecedenceVisitor() {
101: }
102:
103: @Override
104: public boolean visit(JsArrayAccess x, JsContext<JsExpression> ctx) {
105: answer = 16;
106: return false;
107: }
108:
109: @Override
110: public boolean visit(JsArrayLiteral x, JsContext<JsExpression> ctx) {
111: answer = 17; // primary
112: return false;
113: }
114:
115: @Override
116: public boolean visit(JsBinaryOperation x,
117: JsContext<JsExpression> ctx) {
118: answer = x.getOperator().getPrecedence();
119: return false;
120: }
121:
122: @Override
123: public boolean visit(JsBlock x, JsContext<JsStatement> ctx) {
124: throw new RuntimeException("Only expressions have precedence.");
125: }
126:
127: @Override
128: public boolean visit(JsBooleanLiteral x, JsContext<JsExpression> ctx) {
129: answer = 17; // primary
130: return false;
131: }
132:
133: @Override
134: public boolean visit(JsBreak x, JsContext<JsStatement> ctx) {
135: throw new RuntimeException("Only expressions have precedence.");
136: }
137:
138: @Override
139: public boolean visit(JsCase x, JsContext<JsSwitchMember> ctx) {
140: throw new RuntimeException("Only expressions have precedence.");
141: }
142:
143: @Override
144: public boolean visit(JsCatch x, JsContext<JsCatch> ctx) {
145: throw new RuntimeException("Only expressions have precedence.");
146: }
147:
148: @Override
149: public boolean visit(JsConditional x, JsContext<JsExpression> ctx) {
150: answer = 3;
151: return false;
152: }
153:
154: @Override
155: public boolean visit(JsContinue x, JsContext<JsStatement> ctx) {
156: throw new RuntimeException("Only expressions have precedence.");
157: }
158:
159: @Override
160: public boolean visit(JsDebugger x, JsContext<JsStatement> ctx) {
161: throw new RuntimeException("Only expressions have precedence.");
162: }
163:
164: @Override
165: public boolean visit(JsDecimalLiteral x, JsContext<JsExpression> ctx) {
166: answer = 17; // primary
167: return false;
168: }
169:
170: @Override
171: public boolean visit(JsDefault x, JsContext<JsSwitchMember> ctx) {
172: throw new RuntimeException("Only expressions have precedence.");
173: }
174:
175: @Override
176: public boolean visit(JsDoWhile x, JsContext<JsStatement> ctx) {
177: throw new RuntimeException("Only expressions have precedence.");
178: }
179:
180: @Override
181: public boolean visit(JsEmpty x, JsContext<JsStatement> ctx) {
182: throw new RuntimeException("Only expressions have precedence.");
183: }
184:
185: @Override
186: public boolean visit(JsExprStmt x, JsContext<JsStatement> ctx) {
187: throw new RuntimeException("Only expressions have precedence.");
188: }
189:
190: @Override
191: public boolean visit(JsFor x, JsContext<JsStatement> ctx) {
192: throw new RuntimeException("Only expressions have precedence.");
193: }
194:
195: @Override
196: public boolean visit(JsForIn x, JsContext<JsStatement> ctx) {
197: throw new RuntimeException("Only expressions have precedence.");
198: }
199:
200: @Override
201: public boolean visit(JsFunction x, JsContext<JsExpression> ctx) {
202: answer = 17; // primary
203: return false;
204: }
205:
206: @Override
207: public boolean visit(JsIf x, JsContext<JsStatement> ctx) {
208: throw new RuntimeException("Only expressions have precedence.");
209: }
210:
211: @Override
212: public boolean visit(JsIntegralLiteral x,
213: JsContext<JsExpression> ctx) {
214: answer = 17; // primary
215: return false;
216: }
217:
218: @Override
219: public boolean visit(JsInvocation x, JsContext<JsExpression> ctx) {
220: answer = 16;
221: return false;
222: }
223:
224: @Override
225: public boolean visit(JsLabel x, JsContext<JsStatement> ctx) {
226: throw new RuntimeException("Only expressions have precedence.");
227: }
228:
229: @Override
230: public boolean visit(JsNameRef x, JsContext<JsExpression> ctx) {
231: if (x.isLeaf()) {
232: answer = 17; // primary
233: } else {
234: answer = 16; // property access
235: }
236: return false;
237: }
238:
239: @Override
240: public boolean visit(JsNew x, JsContext<JsExpression> ctx) {
241: answer = 15;
242: return false;
243: }
244:
245: @Override
246: public boolean visit(JsNullLiteral x, JsContext<JsExpression> ctx) {
247: answer = 17; // primary
248: return false;
249: }
250:
251: @Override
252: public boolean visit(JsObjectLiteral x, JsContext<JsExpression> ctx) {
253: answer = 17; // primary
254: return false;
255: }
256:
257: @Override
258: public boolean visit(JsParameter x, JsContext<JsParameter> ctx) {
259: throw new RuntimeException("Only expressions have precedence.");
260: }
261:
262: @Override
263: public boolean visit(JsPostfixOperation x,
264: JsContext<JsExpression> ctx) {
265: answer = x.getOperator().getPrecedence();
266: return false;
267: }
268:
269: @Override
270: public boolean visit(JsPrefixOperation x,
271: JsContext<JsExpression> ctx) {
272: answer = x.getOperator().getPrecedence();
273: return false;
274: }
275:
276: @Override
277: public boolean visit(JsProgram x, JsContext<JsProgram> ctx) {
278: throw new RuntimeException("Only expressions have precedence.");
279: }
280:
281: @Override
282: public boolean visit(JsPropertyInitializer x,
283: JsContext<JsPropertyInitializer> ctx) {
284: answer = 17; // primary
285: return false;
286: }
287:
288: @Override
289: public boolean visit(JsRegExp x, JsContext<JsExpression> ctx) {
290: answer = 17; // primary
291: return false;
292: }
293:
294: @Override
295: public boolean visit(JsReturn x, JsContext<JsStatement> ctx) {
296: throw new RuntimeException("Only expressions have precedence.");
297: }
298:
299: @Override
300: public boolean visit(JsStringLiteral x, JsContext<JsExpression> ctx) {
301: answer = 17; // primary
302: return false;
303: }
304:
305: @Override
306: public boolean visit(JsSwitch x, JsContext<JsStatement> ctx) {
307: throw new RuntimeException("Only expressions have precedence.");
308: }
309:
310: @Override
311: public boolean visit(JsThisRef x, JsContext<JsExpression> ctx) {
312: answer = 17; // primary
313: return false;
314: }
315:
316: @Override
317: public boolean visit(JsThrow x, JsContext<JsStatement> ctx) {
318: throw new RuntimeException("Only expressions have precedence.");
319: }
320:
321: @Override
322: public boolean visit(JsTry x, JsContext<JsStatement> ctx) {
323: throw new RuntimeException("Only expressions have precedence.");
324: }
325:
326: @Override
327: public boolean visit(JsVar x, JsContext<JsVar> ctx) {
328: throw new RuntimeException("Only expressions have precedence.");
329: }
330:
331: @Override
332: public boolean visit(JsVars x, JsContext<JsStatement> ctx) {
333: throw new RuntimeException("Only expressions have precedence.");
334: }
335:
336: @Override
337: public boolean visit(JsWhile x, JsContext<JsStatement> ctx) {
338: throw new RuntimeException("Only expressions have precedence.");
339: }
340:
341: }
|