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     * Determines if a statement at the end of a block requires a semicolon.
011     * <p/>
012     * For example, the following statements require semicolons:<br>
013     * <ul>
014     * <li>if (cond);</li>
015     * <li>while (cond);</li>
016     * </ul>
017     * <p/>
018     * The following do not require semicolons:<br>
019     * <ul>
020     * <li>return 1</li>
021     * <li>do {} while(true)</li>
022     * </ul>
023     */
024    public class JsRequiresSemiVisitor extends JsVisitor {
025        private boolean needsSemicolon;
026    
027        private JsRequiresSemiVisitor() {
028        }
029    
030        public static boolean exec(JsStatement lastStatement) {
031            JsRequiresSemiVisitor visitor = new JsRequiresSemiVisitor();
032            visitor.accept(lastStatement);
033            return visitor.needsSemicolon;
034        }
035    
036        @Override
037        public void visitFor(JsFor x) {
038            if (x.getBody() instanceof JsEmpty) {
039                needsSemicolon = true;
040            }
041        }
042    
043        @Override
044        public void visitForIn(JsForIn x) {
045            if (x.getBody() instanceof JsEmpty) {
046                needsSemicolon = true;
047            }
048        }
049    
050        @Override
051        public void visitIf(JsIf x) {
052            JsStatement thenStmt = x.getThenStatement();
053            JsStatement elseStmt = x.getElseStatement();
054            JsStatement toCheck = thenStmt;
055            if (elseStmt != null) {
056                toCheck = elseStmt;
057            }
058            if (toCheck instanceof JsEmpty) {
059                needsSemicolon = true;
060            }
061            else {
062                // Must recurse to determine last statement (possible if-else chain).
063                accept(toCheck);
064            }
065        }
066    
067        @Override
068        public void visitLabel(JsLabel x) {
069            if (x.getStatement() instanceof JsEmpty) {
070                needsSemicolon = true;
071            }
072        }
073    
074        @Override
075        public void visitWhile(JsWhile x) {
076            if (x.getBody() instanceof JsEmpty) {
077                needsSemicolon = true;
078            }
079        }
080    }