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