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 }