KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > google > gwt > dev > js > JsToStringGenerationVisitor


1 /*
2  * Copyright 2007 Google Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5  * use this file except in compliance with the License. You may obtain a copy of
6  * the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13  * License for the specific language governing permissions and limitations under
14  * the License.
15  */

16 package com.google.gwt.dev.js;
17
18 import com.google.gwt.dev.js.ast.HasName;
19 import com.google.gwt.dev.js.ast.JsArrayAccess;
20 import com.google.gwt.dev.js.ast.JsArrayLiteral;
21 import com.google.gwt.dev.js.ast.JsBinaryOperation;
22 import com.google.gwt.dev.js.ast.JsBinaryOperator;
23 import com.google.gwt.dev.js.ast.JsBlock;
24 import com.google.gwt.dev.js.ast.JsBooleanLiteral;
25 import com.google.gwt.dev.js.ast.JsBreak;
26 import com.google.gwt.dev.js.ast.JsCase;
27 import com.google.gwt.dev.js.ast.JsCatch;
28 import com.google.gwt.dev.js.ast.JsConditional;
29 import com.google.gwt.dev.js.ast.JsContext;
30 import com.google.gwt.dev.js.ast.JsContinue;
31 import com.google.gwt.dev.js.ast.JsDebugger;
32 import com.google.gwt.dev.js.ast.JsDecimalLiteral;
33 import com.google.gwt.dev.js.ast.JsDefault;
34 import com.google.gwt.dev.js.ast.JsDoWhile;
35 import com.google.gwt.dev.js.ast.JsEmpty;
36 import com.google.gwt.dev.js.ast.JsExprStmt;
37 import com.google.gwt.dev.js.ast.JsExpression;
38 import com.google.gwt.dev.js.ast.JsFor;
39 import com.google.gwt.dev.js.ast.JsForIn;
40 import com.google.gwt.dev.js.ast.JsFunction;
41 import com.google.gwt.dev.js.ast.JsIf;
42 import com.google.gwt.dev.js.ast.JsIntegralLiteral;
43 import com.google.gwt.dev.js.ast.JsInvocation;
44 import com.google.gwt.dev.js.ast.JsLabel;
45 import com.google.gwt.dev.js.ast.JsName;
46 import com.google.gwt.dev.js.ast.JsNameRef;
47 import com.google.gwt.dev.js.ast.JsNew;
48 import com.google.gwt.dev.js.ast.JsNullLiteral;
49 import com.google.gwt.dev.js.ast.JsObjectLiteral;
50 import com.google.gwt.dev.js.ast.JsParameter;
51 import com.google.gwt.dev.js.ast.JsPostfixOperation;
52 import com.google.gwt.dev.js.ast.JsPrefixOperation;
53 import com.google.gwt.dev.js.ast.JsProgram;
54 import com.google.gwt.dev.js.ast.JsPropertyInitializer;
55 import com.google.gwt.dev.js.ast.JsRegExp;
56 import com.google.gwt.dev.js.ast.JsReturn;
57 import com.google.gwt.dev.js.ast.JsStatement;
58 import com.google.gwt.dev.js.ast.JsStringLiteral;
59 import com.google.gwt.dev.js.ast.JsSwitch;
60 import com.google.gwt.dev.js.ast.JsThisRef;
61 import com.google.gwt.dev.js.ast.JsThrow;
62 import com.google.gwt.dev.js.ast.JsTry;
63 import com.google.gwt.dev.js.ast.JsUnaryOperator;
64 import com.google.gwt.dev.js.ast.JsVars;
65 import com.google.gwt.dev.js.ast.JsVisitor;
66 import com.google.gwt.dev.js.ast.JsWhile;
67 import com.google.gwt.dev.js.ast.JsVars.JsVar;
68 import com.google.gwt.dev.util.TextOutput;
69
70 import java.util.Iterator JavaDoc;
71
72 /**
73  * Produces text output from a JavaScript AST.
74  */

75 public class JsToStringGenerationVisitor extends JsVisitor {
76
77   private static final char[] CHARS_BREAK = "break".toCharArray();
78   private static final char[] CHARS_CASE = "case".toCharArray();
79   private static final char[] CHARS_CATCH = "catch".toCharArray();
80   private static final char[] CHARS_CONTINUE = "continue".toCharArray();
81   private static final char[] CHARS_DEBUGGER = "debugger".toCharArray();
82   private static final char[] CHARS_DEFAULT = "default".toCharArray();
83   private static final char[] CHARS_DELETE = "delete".toCharArray();
84   private static final char[] CHARS_DO = "do".toCharArray();
85   private static final char[] CHARS_ELSE = "else".toCharArray();
86   private static final char[] CHARS_FALSE = "false".toCharArray();
87   private static final char[] CHARS_FINALLY = "finally".toCharArray();
88   private static final char[] CHARS_FOR = "for".toCharArray();
89   private static final char[] CHARS_FUNCTION = "function".toCharArray();
90   private static final char[] CHARS_IF = "if".toCharArray();
91   private static final char[] CHARS_IN = "in".toCharArray();
92   private static final char[] CHARS_NEW = "new".toCharArray();
93   private static final char[] CHARS_NULL = "null".toCharArray();
94   private static final char[] CHARS_RETURN = "return".toCharArray();
95   private static final char[] CHARS_SWITCH = "switch".toCharArray();
96   private static final char[] CHARS_THIS = "this".toCharArray();
97   private static final char[] CHARS_THROW = "throw".toCharArray();
98   private static final char[] CHARS_TRUE = "true".toCharArray();
99   private static final char[] CHARS_TRY = "try".toCharArray();
100   private static final char[] CHARS_VAR = "var".toCharArray();
101   private static final char[] CHARS_WHILE = "while".toCharArray();
102   private static final char[] HEX_DIGITS = {
103       '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D',
104       'E', 'F'};
105
106   /**
107    * How many lines of code to print inside of a JsBlock when printing terse.
108    */

109   private static final int JSBLOCK_LINES_TO_PRINT = 3;
110
111   protected boolean needSemi = true;
112   private final TextOutput p;
113
114   public JsToStringGenerationVisitor(TextOutput out) {
115     this.p = out;
116   }
117
118   public boolean visit(JsArrayAccess x, JsContext ctx) {
119     JsExpression arrayExpr = x.getArrayExpr();
120     _parenPush(x, arrayExpr, false);
121     accept(arrayExpr);
122     _parenPop(x, arrayExpr, false);
123     _lsquare();
124     accept(x.getIndexExpr());
125     _rsquare();
126     return false;
127   }
128
129   public boolean visit(JsArrayLiteral x, JsContext ctx) {
130     _lsquare();
131     boolean sep = false;
132     for (Iterator JavaDoc iter = x.getExpressions().iterator(); iter.hasNext();) {
133       JsExpression arg = (JsExpression) iter.next();
134       sep = _sepCommaOptSpace(sep);
135       _parenPushIfCommaExpr(arg);
136       accept(arg);
137       _parenPopIfCommaExpr(arg);
138     }
139     _rsquare();
140     return false;
141   }
142
143   public boolean visit(JsBinaryOperation x, JsContext ctx) {
144     JsBinaryOperator op = x.getOperator();
145     JsExpression arg1 = x.getArg1();
146     _parenPush(x, arg1, !op.isLeftAssociative());
147     accept(arg1);
148     boolean needSpace = op.isKeyword() || arg1 instanceof JsPostfixOperation;
149     if (needSpace) {
150       _parenPopOrSpace(x, arg1, !op.isLeftAssociative());
151     } else {
152       _parenPop(x, arg1, !op.isLeftAssociative());
153       _spaceOpt();
154     }
155     p.print(op.getSymbol());
156     JsExpression arg2 = x.getArg2();
157     needSpace = op.isKeyword() || arg2 instanceof JsPrefixOperation;
158     if (needSpace) {
159       _parenPushOrSpace(x, arg2, op.isLeftAssociative());
160     } else {
161       _spaceOpt();
162       _parenPush(x, arg2, op.isLeftAssociative());
163     }
164     accept(arg2);
165     _parenPop(x, arg2, op.isLeftAssociative());
166     return false;
167   }
168
169   public boolean visit(JsBlock x, JsContext ctx) {
170     printJsBlockOptionalTruncate(x, true);
171     return false;
172   }
173
174   public boolean visit(JsBooleanLiteral x, JsContext ctx) {
175     if (x.getValue()) {
176       _true();
177     } else {
178       _false();
179     }
180     return false;
181   }
182
183   public boolean visit(JsBreak x, JsContext ctx) {
184     _break();
185
186     JsNameRef label = x.getLabel();
187     if (label != null) {
188       _space();
189       _nameRef(label);
190     }
191
192     return false;
193   }
194
195   public boolean visit(JsCase x, JsContext ctx) {
196     _case();
197     _space();
198     accept(x.getCaseExpr());
199     _colon();
200     _newlineOpt();
201
202     indent();
203     for (Iterator JavaDoc iter = x.getStmts().iterator(); iter.hasNext();) {
204       JsStatement stmt = (JsStatement) iter.next();
205       needSemi = true;
206       accept(stmt);
207       if (needSemi) {
208         _semi();
209       }
210       _newlineOpt();
211     }
212     outdent();
213     needSemi = false;
214     return false;
215   }
216
217   public boolean visit(JsCatch x, JsContext ctx) {
218     _spaceOpt();
219     _catch();
220     _spaceOpt();
221     _lparen();
222     _nameDef(x.getParameter().getName());
223
224     // Optional catch condition.
225
//
226
JsExpression catchCond = x.getCondition();
227     if (catchCond != null) {
228       _space();
229       _if();
230       _space();
231       accept(catchCond);
232     }
233
234     _rparen();
235     _spaceOpt();
236     accept(x.getBody());
237
238     return false;
239   }
240
241   public boolean visit(JsConditional x, JsContext ctx) {
242     // right associative
243
{
244       JsExpression testExpression = x.getTestExpression();
245       _parenPush(x, testExpression, true);
246       accept(testExpression);
247       _parenPop(x, testExpression, true);
248     }
249     _questionMark();
250     {
251       JsExpression thenExpression = x.getThenExpression();
252       _parenPush(x, thenExpression, true);
253       accept(thenExpression);
254       _parenPop(x, thenExpression, true);
255     }
256     _colon();
257     {
258       JsExpression elseExpression = x.getElseExpression();
259       _parenPush(x, elseExpression, false);
260       accept(elseExpression);
261       _parenPop(x, elseExpression, false);
262     }
263     return false;
264   }
265
266   public boolean visit(JsContinue x, JsContext ctx) {
267     _continue();
268
269     JsNameRef label = x.getLabel();
270     if (label != null) {
271       _space();
272       _nameRef(label);
273     }
274
275     return false;
276   }
277
278   public boolean visit(JsDebugger x, JsContext ctx) {
279     _debugger();
280     return false;
281   }
282
283   public boolean visit(JsDecimalLiteral x, JsContext ctx) {
284     String JavaDoc s = x.getValue();
285     // TODO: optimize this to only the cases that need it
286
if (s.startsWith("-")) {
287       _space();
288     }
289     p.print(s);
290     return false;
291   }
292
293   public boolean visit(JsDefault x, JsContext ctx) {
294     _default();
295     _colon();
296
297     indent();
298     for (Iterator JavaDoc iter = x.getStmts().iterator(); iter.hasNext();) {
299       JsStatement stmt = (JsStatement) iter.next();
300       needSemi = true;
301       accept(stmt);
302       if (needSemi) {
303         _semi();
304       }
305       _newlineOpt();
306     }
307     outdent();
308     needSemi = false;
309     return false;
310   }
311
312   public boolean visit(JsDoWhile x, JsContext ctx) {
313     _do();
314     _nestedPush(x.getBody(), true);
315     accept(x.getBody());
316     _nestedPop(x.getBody());
317     if (needSemi) {
318       _semi();
319       _newlineOpt();
320     } else {
321       _spaceOpt();
322       needSemi = true;
323     }
324     _while();
325     _spaceOpt();
326     _lparen();
327     accept(x.getCondition());
328     _rparen();
329     return false;
330   }
331
332   public boolean visit(JsEmpty x, JsContext ctx) {
333     return false;
334   }
335
336   public boolean visit(JsExprStmt x, JsContext ctx) {
337     final JsExpression expr = x.getExpression();
338     accept(expr);
339     return false;
340   }
341
342   public boolean visit(JsFor x, JsContext ctx) {
343     _for();
344     _spaceOpt();
345     _lparen();
346
347     // The init expressions or var decl.
348
//
349
if (x.getInitExpr() != null) {
350       accept(x.getInitExpr());
351     } else if (x.getInitVars() != null) {
352       accept(x.getInitVars());
353     }
354
355     _semi();
356
357     // The loop test.
358
//
359
if (x.getCondition() != null) {
360       _spaceOpt();
361       accept(x.getCondition());
362     }
363
364     _semi();
365
366     // The incr expression.
367
//
368
if (x.getIncrExpr() != null) {
369       _spaceOpt();
370       accept(x.getIncrExpr());
371     }
372
373     _rparen();
374     _nestedPush(x.getBody(), false);
375     accept(x.getBody());
376     _nestedPop(x.getBody());
377     return false;
378   }
379
380   public boolean visit(JsForIn x, JsContext ctx) {
381     _for();
382     _spaceOpt();
383     _lparen();
384
385     if (x.getIterVarName() != null) {
386       _var();
387       _space();
388       _nameDef(x.getIterVarName());
389
390       if (x.getIterExpr() != null) {
391         _spaceOpt();
392         _assignment();
393         _spaceOpt();
394         accept(x.getIterExpr());
395       }
396     } else {
397       // Just a name ref.
398
//
399
accept(x.getIterExpr());
400     }
401
402     _space();
403     _in();
404     _space();
405     accept(x.getObjExpr());
406
407     _rparen();
408     _nestedPush(x.getBody(), false);
409     accept(x.getBody());
410     _nestedPop(x.getBody());
411     return false;
412   }
413
414   // function foo(a, b) {
415
// stmts...
416
// }
417
//
418
public boolean visit(JsFunction x, JsContext ctx) {
419     _function();
420
421     // Functions can be anonymous.
422
//
423
if (x.getName() != null) {
424       _space();
425       _nameOf(x);
426     }
427
428     _lparen();
429     boolean sep = false;
430     for (Iterator JavaDoc iter = x.getParameters().iterator(); iter.hasNext();) {
431       JsParameter param = (JsParameter) iter.next();
432       sep = _sepCommaOptSpace(sep);
433       accept(param);
434     }
435     _rparen();
436
437     accept(x.getBody());
438     needSemi = true;
439     return false;
440   }
441
442   public boolean visit(JsIf x, JsContext ctx) {
443     _if();
444     _spaceOpt();
445     _lparen();
446     accept(x.getIfExpr());
447     _rparen();
448     JsStatement thenStmt = x.getThenStmt();
449     _nestedPush(thenStmt, false);
450     accept(thenStmt);
451     _nestedPop(thenStmt);
452     JsStatement elseStmt = x.getElseStmt();
453     if (elseStmt != null) {
454       if (needSemi) {
455         _semi();
456         _newlineOpt();
457       } else {
458         _spaceOpt();
459         needSemi = true;
460       }
461       _else();
462       boolean elseIf = elseStmt instanceof JsIf;
463       if (!elseIf) {
464         _nestedPush(elseStmt, true);
465       } else {
466         _space();
467       }
468       accept(elseStmt);
469       if (!elseIf) {
470         _nestedPop(elseStmt);
471       }
472     }
473     return false;
474   }
475
476   public boolean visit(JsIntegralLiteral x, JsContext ctx) {
477     String JavaDoc s = x.getValue().toString();
478     boolean needParens = s.startsWith("-");
479     if (needParens) {
480       _lparen();
481     }
482     p.print(s);
483     if (needParens) {
484       _rparen();
485     }
486     return false;
487   }
488
489   public boolean visit(JsInvocation x, JsContext ctx) {
490     accept(x.getQualifier());
491
492     _lparen();
493     boolean sep = false;
494     for (Iterator JavaDoc iter = x.getArguments().iterator(); iter.hasNext();) {
495       JsExpression arg = (JsExpression) iter.next();
496       sep = _sepCommaOptSpace(sep);
497       _parenPushIfCommaExpr(arg);
498       accept(arg);
499       _parenPopIfCommaExpr(arg);
500     }
501     _rparen();
502     return false;
503   }
504
505   public boolean visit(JsLabel x, JsContext ctx) {
506     _nameOf(x);
507     _colon();
508     _spaceOpt();
509     accept(x.getStmt());
510     return false;
511   }
512
513   public boolean visit(JsNameRef x, JsContext ctx) {
514     JsExpression q = x.getQualifier();
515     if (q != null) {
516       _parenPush(x, q, false);
517       accept(q);
518       _parenPop(x, q, false);
519       _dot();
520     }
521     _nameRef(x);
522     return false;
523   }
524
525   public boolean visit(JsNew x, JsContext ctx) {
526     _new();
527     _space();
528
529     JsExpression ctorExpr = x.getConstructorExpression();
530     _parenPush(x, ctorExpr, true);
531     accept(ctorExpr);
532     _parenPop(x, ctorExpr, true);
533
534     _lparen();
535     boolean sep = false;
536     for (Iterator JavaDoc iter = x.getArguments().iterator(); iter.hasNext();) {
537       JsExpression arg = (JsExpression) iter.next();
538       sep = _sepCommaOptSpace(sep);
539       _parenPushIfCommaExpr(arg);
540       accept(arg);
541       _parenPopIfCommaExpr(arg);
542     }
543     _rparen();
544
545     return false;
546   }
547
548   public boolean visit(JsNullLiteral x, JsContext ctx) {
549     _null();
550     return false;
551   }
552
553   public boolean visit(JsObjectLiteral x, JsContext ctx) {
554     _lbrace();
555     boolean sep = false;
556     for (Iterator JavaDoc iter = x.getPropertyInitializers().iterator(); iter.hasNext();) {
557       sep = _sepCommaOptSpace(sep);
558       JsPropertyInitializer propInit = (JsPropertyInitializer) iter.next();
559       JsExpression labelExpr = propInit.getLabelExpr();
560       _parenPushIfConditional(labelExpr);
561       accept(labelExpr);
562       _parenPopIfConditional(labelExpr);
563       _colon();
564       JsExpression valueExpr = propInit.getValueExpr();
565       _parenPushIfConditional(valueExpr);
566       accept(valueExpr);
567       _parenPopIfConditional(valueExpr);
568     }
569     _rbrace();
570     return false;
571   }
572
573   public boolean visit(JsParameter x, JsContext ctx) {
574     _nameOf(x);
575     return false;
576   }
577
578   public boolean visit(JsPostfixOperation x, JsContext ctx) {
579     JsUnaryOperator op = x.getOperator();
580     JsExpression arg = x.getArg();
581     // unary operators always associate correctly (I think)
582
_parenPush(x, arg, true);
583     accept(arg);
584     _parenPop(x, arg, true);
585     p.print(op.getSymbol());
586     return false;
587   }
588
589   public boolean visit(JsPrefixOperation x, JsContext ctx) {
590     JsUnaryOperator op = x.getOperator();
591     p.print(op.getSymbol());
592     if (op.isKeyword()) {
593       _space();
594     }
595     JsExpression arg = x.getArg();
596     // unary operators always associate correctly (I think)
597
_parenPush(x, arg, true);
598     accept(arg);
599     _parenPop(x, arg, true);
600     return false;
601   }
602
603   public boolean visit(JsProgram x, JsContext ctx) {
604     p.print("<JsProgram>");
605     return false;
606   }
607
608   public boolean visit(JsPropertyInitializer x, JsContext ctx) {
609     // Since there are separators, we actually print the property init
610
// in visit(JsObjectLiteral).
611
//
612
return false;
613   }
614
615   public boolean visit(JsRegExp x, JsContext ctx) {
616     _slash();
617     p.print(x.getPattern());
618     _slash();
619     String JavaDoc flags = x.getFlags();
620     if (flags != null) {
621       p.print(flags);
622     }
623     return false;
624   }
625
626   public boolean visit(JsReturn x, JsContext ctx) {
627     _return();
628     JsExpression expr = x.getExpr();
629     if (expr != null) {
630       _space();
631       accept(expr);
632     }
633     return false;
634   }
635
636   public boolean visit(JsStringLiteral x, JsContext ctx) {
637     printStringLiteral(x.getValue());
638     return false;
639   }
640
641   public boolean visit(JsSwitch x, JsContext ctx) {
642     _switch();
643     _spaceOpt();
644     _lparen();
645     accept(x.getExpr());
646     _rparen();
647     _spaceOpt();
648     _blockOpen();
649     accept(x.getCases());
650     _blockClose();
651     return false;
652   }
653
654   public boolean visit(JsThisRef x, JsContext ctx) {
655     _this();
656     return false;
657   }
658
659   public boolean visit(JsThrow x, JsContext ctx) {
660     _throw();
661     _space();
662     accept(x.getExpr());
663     return false;
664   }
665
666   public boolean visit(JsTry x, JsContext ctx) {
667     _try();
668     _spaceOpt();
669     accept(x.getTryBlock());
670
671     accept(x.getCatches());
672
673     JsBlock finallyBlock = x.getFinallyBlock();
674     if (finallyBlock != null) {
675       _spaceOpt();
676       _finally();
677       _spaceOpt();
678       accept(finallyBlock);
679     }
680
681     return false;
682   }
683
684   public boolean visit(JsVar x, JsContext ctx) {
685     _nameOf(x);
686     JsExpression initExpr = x.getInitExpr();
687     if (initExpr != null) {
688       _spaceOpt();
689       _assignment();
690       _spaceOpt();
691       _parenPushIfCommaExpr(initExpr);
692       accept(initExpr);
693       _parenPopIfCommaExpr(initExpr);
694     }
695     return false;
696   }
697
698   public boolean visit(JsVars x, JsContext ctx) {
699     _var();
700     _space();
701     boolean sep = false;
702     for (Iterator JavaDoc iter = x.iterator(); iter.hasNext();) {
703       sep = _sepCommaOptSpace(sep);
704       JsVars.JsVar var = (JsVars.JsVar) iter.next();
705       accept(var);
706     }
707     return false;
708   }
709
710   public boolean visit(JsWhile x, JsContext ctx) {
711     _while();
712     _spaceOpt();
713     _lparen();
714     accept(x.getCondition());
715     _rparen();
716     _nestedPush(x.getBody(), false);
717     accept(x.getBody());
718     _nestedPop(x.getBody());
719     return false;
720   }
721
722   // CHECKSTYLE_NAMING_OFF
723
protected void _newline() {
724     p.newline();
725   }
726
727   protected void _newlineOpt() {
728     p.newlineOpt();
729   }
730
731   protected void printJsBlockOptionalTruncate(JsBlock x, boolean truncate) {
732     boolean needBraces = !x.isGlobalBlock();
733
734     if (needBraces) {
735       // Open braces.
736
//
737
_blockOpen();
738     }
739
740     int count = 0;
741     for (Iterator JavaDoc iter = x.getStatements().iterator(); iter.hasNext(); ++count) {
742       if (truncate && count > JSBLOCK_LINES_TO_PRINT) {
743         p.print("[...]");
744         _newlineOpt();
745         break;
746       }
747       JsStatement stmt = (JsStatement) iter.next();
748       needSemi = true;
749       accept(stmt);
750       if (needSemi) {
751         /*
752          * Special treatment of function decls: function decls always set
753          * needSemi back to true. But if they are the only item in a statement
754          * (i.e. not part of an assignment operation), just give them a newline
755          * instead of a semi since it makes obfuscated code so much "nicer"
756          * (sic).
757          */

758         if (stmt instanceof JsExprStmt
759             && ((JsExprStmt) stmt).getExpression() instanceof JsFunction) {
760           _newline();
761         } else {
762           _semi();
763           _newlineOpt();
764         }
765       }
766     }
767
768     if (needBraces) {
769       // Close braces.
770
//
771
_blockClose();
772     }
773     needSemi = false;
774   }
775
776   private void _assignment() {
777     p.print('=');
778   }
779
780   private void _blockClose() {
781     p.indentOut();
782     p.print('}');
783     _newlineOpt();
784   }
785
786   private void _blockOpen() {
787     p.print('{');
788     p.indentIn();
789     _newlineOpt();
790   }
791
792   private void _break() {
793     p.print(CHARS_BREAK);
794   }
795
796   private void _case() {
797     p.print(CHARS_CASE);
798   }
799
800   private void _catch() {
801     p.print(CHARS_CATCH);
802   }
803
804   private void _colon() {
805     p.print(':');
806   }
807
808   private void _continue() {
809     p.print(CHARS_CONTINUE);
810   }
811
812   private void _debugger() {
813     p.print(CHARS_DEBUGGER);
814   }
815
816   private void _default() {
817     p.print(CHARS_DEFAULT);
818   }
819
820   private void _delete() {
821     p.print(CHARS_DELETE);
822   }
823
824   private void _do() {
825     p.print(CHARS_DO);
826   }
827
828   private void _dot() {
829     p.print('.');
830   }
831
832   private void _else() {
833     p.print(CHARS_ELSE);
834   }
835
836   private void _false() {
837     p.print(CHARS_FALSE);
838   }
839
840   private void _finally() {
841     p.print(CHARS_FINALLY);
842   }
843
844   private void _for() {
845     p.print(CHARS_FOR);
846   }
847
848   private void _function() {
849     p.print(CHARS_FUNCTION);
850   }
851
852   private void _if() {
853     p.print(CHARS_IF);
854   }
855
856   private void _in() {
857     p.print(CHARS_IN);
858   }
859
860   private void _lbrace() {
861     p.print('{');
862   }
863
864   private void _lparen() {
865     p.print('(');
866   }
867
868   private void _lsquare() {
869     p.print('[');
870   }
871
872   private void _nameDef(JsName name) {
873     p.print(name.getShortIdent());
874   }
875
876   private void _nameOf(HasName hasName) {
877     _nameDef(hasName.getName());
878   }
879
880   private void _nameRef(JsNameRef nameRef) {
881     p.print(nameRef.getShortIdent());
882   }
883
884   private boolean _nestedPop(JsStatement statement) {
885     boolean pop = !(statement instanceof JsBlock);
886     if (pop) {
887       p.indentOut();
888     }
889     return pop;
890   }
891
892   private boolean _nestedPush(JsStatement statement, boolean needSpace) {
893     boolean push = !(statement instanceof JsBlock);
894     if (push) {
895       if (needSpace) {
896         _space();
897       }
898       p.indentIn();
899       _newlineOpt();
900     } else {
901       _spaceOpt();
902     }
903     return push;
904   }
905
906   private void _new() {
907     p.print(CHARS_NEW);
908   }
909
910   private void _null() {
911     p.print(CHARS_NULL);
912   }
913
914   private boolean _parenCalc(JsExpression parent, JsExpression child,
915       boolean wrongAssoc) {
916     int parentPrec = JsPrecedenceVisitor.exec(parent);
917     int childPrec = JsPrecedenceVisitor.exec(child);
918     return (parentPrec > childPrec || (parentPrec == childPrec && wrongAssoc));
919   }
920
921   private boolean _parenPop(JsExpression parent, JsExpression child,
922       boolean wrongAssoc) {
923     boolean doPop = _parenCalc(parent, child, wrongAssoc);
924     if (doPop) {
925       _rparen();
926     }
927     return doPop;
928   }
929
930   private boolean _parenPopIfCommaExpr(JsExpression x) {
931     boolean doPop = x instanceof JsBinaryOperation
932         && ((JsBinaryOperation) x).getOperator() == JsBinaryOperator.COMMA;
933     if (doPop) {
934       _rparen();
935     }
936     return doPop;
937   }
938
939   private boolean _parenPopIfConditional(JsExpression x) {
940     boolean doPop = x instanceof JsConditional;
941     if (doPop) {
942       _rparen();
943     }
944     return doPop;
945   }
946
947   private boolean _parenPopOrSpace(JsExpression parent, JsExpression child,
948       boolean wrongAssoc) {
949     boolean doPop = _parenCalc(parent, child, wrongAssoc);
950     if (doPop) {
951       _rparen();
952     } else {
953       _space();
954     }
955     return doPop;
956   }
957
958   private boolean _parenPush(JsExpression parent, JsExpression child,
959       boolean wrongAssoc) {
960     boolean doPush = _parenCalc(parent, child, wrongAssoc);
961     if (doPush) {
962       _lparen();
963     }
964     return doPush;
965   }
966
967   private boolean _parenPushIfCommaExpr(JsExpression x) {
968     boolean doPush = x instanceof JsBinaryOperation
969         && ((JsBinaryOperation) x).getOperator() == JsBinaryOperator.COMMA;
970     if (doPush) {
971       _lparen();
972     }
973     return doPush;
974   }
975
976   private boolean _parenPushIfConditional(JsExpression x) {
977     boolean doPush = x instanceof JsConditional;
978     if (doPush) {
979       _lparen();
980     }
981     return doPush;
982   }
983
984   private boolean _parenPushOrSpace(JsExpression parent, JsExpression child,
985       boolean wrongAssoc) {
986     boolean doPush = _parenCalc(parent, child, wrongAssoc);
987     if (doPush) {
988       _lparen();
989     } else {
990       _space();
991     }
992     return doPush;
993   }
994
995   private void _questionMark() {
996     p.print('?');
997   }
998
999   private void _rbrace() {
1000    p.print('}');
1001  }
1002
1003  private void _return() {
1004    p.print(CHARS_RETURN);
1005  }
1006
1007  private void _rparen() {
1008    p.print(')');
1009  }
1010
1011  private void _rsquare() {
1012    p.print(']');
1013  }
1014
1015  private void _semi() {
1016    p.print(';');
1017  }
1018
1019  private boolean _sepCommaOptSpace(boolean sep) {
1020    if (sep) {
1021      p.print(',');
1022      _spaceOpt();
1023    }
1024    return true;
1025  }
1026
1027  private void _slash() {
1028    p.print('/');
1029  }
1030
1031  private void _space() {
1032    p.print(' ');
1033  }
1034
1035  private void _spaceOpt() {
1036    p.printOpt(' ');
1037  }
1038
1039  private void _switch() {
1040    p.print(CHARS_SWITCH);
1041  }
1042
1043  private void _this() {
1044    p.print(CHARS_THIS);
1045  }
1046
1047  private void _throw() {
1048    p.print(CHARS_THROW);
1049  }
1050
1051  private void _true() {
1052    p.print(CHARS_TRUE);
1053  }
1054
1055  private void _try() {
1056    p.print(CHARS_TRY);
1057  }
1058
1059  private void _var() {
1060    p.print(CHARS_VAR);
1061  }
1062
1063  private void _while() {
1064    p.print(CHARS_WHILE);
1065  }
1066
1067  // CHECKSTYLE_NAMING_ON
1068

1069  /**
1070   * Escapes any closing XML tags embedded in <code>str</code>, which could
1071   * potentially cause a parse failure in a browser, for example, embedding
1072   * a closing <code>&lt;script&gt;</code> tag.
1073   *
1074   * @param str an unescaped literal; May be null
1075   */

1076  private void escapeClosingTags(StringBuffer JavaDoc str) {
1077    if (str == null) {
1078      return;
1079    }
1080
1081    int index = 0;
1082
1083    while ((index = str.indexOf("</", index)) != -1) {
1084      str.insert(index + 1, '\\');
1085    }
1086  }
1087
1088  private void indent() {
1089    p.indentIn();
1090  }
1091
1092  private void outdent() {
1093    p.indentOut();
1094  }
1095
1096  /**
1097   * Adapted from
1098   * {@link com.google.gwt.dev.js.rhino.ScriptRuntime#escapeString(String)}.
1099   * The difference is that we quote with either &quot; or &apos; depending on
1100   * which one is used less inside the string.
1101   */

1102  private void printStringLiteral(String JavaDoc value) {
1103
1104    char[] chars = value.toCharArray();
1105    final int n = chars.length;
1106    int quoteCount = 0;
1107    int aposCount = 0;
1108    for (int i = 0; i < n; ++i) {
1109      switch (chars[i]) {
1110        case '"':
1111          ++quoteCount;
1112          break;
1113        case '\'':
1114          ++aposCount;
1115          break;
1116      }
1117    }
1118
1119    StringBuffer JavaDoc result = new StringBuffer JavaDoc(value.length() + 16);
1120
1121    char quoteChar = (quoteCount < aposCount) ? '"' : '\'';
1122    p.print(quoteChar);
1123
1124    for (int i = 0; i < n; ++i) {
1125      char c = chars[i];
1126
1127      if (' ' <= c && c <= '~' && c != quoteChar && c != '\\') {
1128        // an ordinary print character (like C isprint())
1129
result.append(c);
1130        continue;
1131      }
1132
1133      int escape = -1;
1134      switch (c) {
1135        case 0:
1136          escape = '0';
1137          break;
1138        case '\b':
1139          escape = 'b';
1140          break;
1141        case '\f':
1142          escape = 'f';
1143          break;
1144        case '\n':
1145          escape = 'n';
1146          break;
1147        case '\r':
1148          escape = 'r';
1149          break;
1150        case '\t':
1151          escape = 't';
1152          break;
1153        case '"':
1154          escape = '"';
1155          break; // only reach here if == quoteChar
1156
case '\'':
1157          escape = '\'';
1158          break; // only reach here if == quoteChar
1159
case '\\':
1160          escape = '\\';
1161          break;
1162      }
1163
1164      if (escape >= 0) {
1165        // an \escaped sort of character
1166
result.append('\\');
1167        result.append((char) escape);
1168      } else {
1169        int hexSize;
1170        if (c < 256) {
1171          // 2-digit hex
1172
result.append("\\x");
1173          hexSize = 2;
1174        } else {
1175          // Unicode.
1176
result.append("\\u");
1177          hexSize = 4;
1178        }
1179        // append hexadecimal form of ch left-padded with 0
1180
for (int shift = (hexSize - 1) * 4; shift >= 0; shift -= 4) {
1181          int digit = 0xf & (c >> shift);
1182          result.append(HEX_DIGITS[digit]);
1183        }
1184      }
1185    }
1186    result.append(quoteChar);
1187    escapeClosingTags(result);
1188    p.print(result.toString());
1189  }
1190}
1191
Popular Tags