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 org.jetbrains.kotlin.js.backend.ast;
006    
007    import org.jetbrains.kotlin.js.util.AstUtil;
008    import org.jetbrains.annotations.NotNull;
009    
010    /**
011     * A <code>for</code> statement. If specified at all, the initializer part is
012     * either a declaration of one or more variables, in which case
013     * {@link #getInitVars()} is used, or an expression, in which case
014     * {@link #getInitExpression()} is used. In the latter case, the comma operator is
015     * often used to create a compound expression.
016     * <p/>
017     * <p/>
018     * Note that any of the parts of the <code>for</code> loop header can be
019     * <code>null</code>, although the body will never be null.
020     */
021    public class JsFor extends SourceInfoAwareJsNode implements JsStatement {
022        private JsStatement body;
023        private JsExpression condition;
024        private JsExpression incrementExpression;
025        private JsExpression initExpression;
026        private JsVars initVars;
027    
028        public JsFor(JsVars initVars, JsExpression condition, JsExpression incrementExpression) {
029            this(initVars, condition, incrementExpression, null);
030        }
031    
032        public JsFor(JsVars initVars, JsExpression condition, JsExpression incrementExpression, JsStatement body) {
033            this.initVars = initVars;
034            this.incrementExpression = incrementExpression;
035            this.condition = condition;
036            this.body = body;
037            initExpression = null;
038        }
039    
040        public JsFor(JsExpression initExpression, JsExpression condition, JsExpression incrementExpression) {
041            this(initExpression, condition, incrementExpression, null);
042        }
043    
044        public JsFor(JsExpression initExpression, JsExpression condition, JsExpression incrementExpression, JsStatement body) {
045            this.initExpression = initExpression;
046            this.incrementExpression = incrementExpression;
047            this.condition = condition;
048            this.body = body;
049            initVars = null;
050        }
051    
052        public JsStatement getBody() {
053            return body;
054        }
055    
056        public JsExpression getCondition() {
057            return condition;
058        }
059    
060        public JsExpression getIncrementExpression() {
061            return incrementExpression;
062        }
063    
064        public JsExpression getInitExpression() {
065            return initExpression;
066        }
067    
068        public JsVars getInitVars() {
069            return initVars;
070        }
071    
072        public void setBody(JsStatement body) {
073            this.body = body;
074        }
075    
076        @Override
077        public void accept(JsVisitor v) {
078            v.visitFor(this);
079        }
080    
081        @Override
082        public void acceptChildren(JsVisitor visitor) {
083            assert (!(initExpression != null && initVars != null));
084    
085            if (initExpression != null) {
086                visitor.accept(initExpression);
087            }
088            else if (initVars != null) {
089                visitor.accept(initVars);
090            }
091    
092            if (condition != null) {
093                visitor.accept(condition);
094            }
095    
096            if (incrementExpression != null) {
097                visitor.accept(incrementExpression);
098            }
099            visitor.accept(body);
100        }
101    
102        @Override
103        public void traverse(JsVisitorWithContext v, JsContext ctx) {
104            if (v.visit(this, ctx)) {
105                assert (!(initExpression != null && initVars != null));
106    
107                if (initExpression != null) {
108                    initExpression = v.accept(initExpression);
109                } else if (initVars != null) {
110                    JsStatement newInitVars = v.<JsStatement>acceptStatement(initVars);
111                    if (newInitVars instanceof JsVars) {
112                        initVars = (JsVars) newInitVars;
113                    }
114                    else {
115                        initVars = null;
116                        if (newInitVars instanceof JsExpressionStatement) {
117                            initExpression = ((JsExpressionStatement) newInitVars).getExpression();
118                        } else if (newInitVars != null) {
119                            ctx.addPrevious(newInitVars);
120                        }
121                    }
122                }
123    
124                if (condition != null) {
125                    condition = v.accept(condition);
126                }
127    
128                if (incrementExpression != null) {
129                    incrementExpression = v.accept(incrementExpression);
130                }
131                body = v.acceptStatement(body);
132            }
133            v.endVisit(this, ctx);
134        }
135    
136        @NotNull
137        @Override
138        public JsFor deepCopy() {
139            JsStatement bodyCopy = AstUtil.deepCopy(body);
140            JsExpression conditionCopy = AstUtil.deepCopy(condition);
141            JsExpression incrementalExprCopy = AstUtil.deepCopy(incrementExpression);
142    
143            JsFor result;
144            if (initVars != null) {
145                result = new JsFor(initVars.deepCopy(), conditionCopy, incrementalExprCopy, bodyCopy);
146            } else {
147                result = new JsFor(initExpression.deepCopy(), conditionCopy, incrementalExprCopy, bodyCopy);
148            }
149    
150            return result.withMetadataFrom(this);
151        }
152    }