1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 package org.millscript.millscript.expr;
22
23 import org.millscript.commons.util.IList;
24 import org.millscript.millscript.action.Action;
25 import org.millscript.millscript.action.ForAction;
26 import org.millscript.millscript.action.ForConditionAction;
27 import org.millscript.millscript.vm.CompilerState;
28
29 import java.util.Stack;
30
31 /**
32 * This class represents a For loop expression. A for loop expression may
33 * contain multiple condition/binding expressions, a single body expression and
34 * a single termination expression.
35 *
36 * @see org.millscript.millscript.syntax.ForSyntax
37 * @see ForAction
38 */
39 public final class ForExpr extends Expr< ForAction > {
40
41 /**
42 * This list holds the conditions and bindings that control this for loops
43 * iteration.
44 */
45 private final IList< ForConditionExpr > bindings;
46
47 /**
48 * The for loops body expression. This will be executed on each iteration of
49 * the for loop.
50 */
51 private final Expr< ? > body;
52
53 /**
54 * The for loops termination expression. This will be executed when the for
55 * loop terminates, unless one of the other conditions has an override.
56 */
57 private final Expr< ? > terminateExpr;
58
59 /**
60 * Construct a new For Expression with the supplied conditions/bindings,
61 * body and normal termination expression.
62 *
63 * @param a list of conditions and bindings
64 * @param b body Expr
65 * @param t normal termination Expr
66 */
67 public ForExpr( final IList< ForConditionExpr > a, final Expr< ? > b, final Expr< ? > t ) {
68 bindings = a;
69 body = b;
70 terminateExpr = t;
71 }
72
73 /**
74 * {@inheritDoc}
75 *
76 * <p>
77 * If the for loop body has an arity of zero, the for loops arity is zero,
78 * otherwise the for loop arity is unknown. The for loop arity would depend
79 * on the number of iterations, etc.
80 * </p>
81 */
82 @Override
83 public int arity() {
84 return body.arity() == 0 ? 0 : -1;
85 }
86
87 /**
88 * @see org.millscript.millscript.expr.Expr#compileIt()
89 */
90 @Override
91 public ForAction compileIt() {
92
93
94 final Action finalAct = terminateExpr.compile();
95
96
97
98 ForConditionAction[] fa = new ForConditionAction[ this.bindings.size() ];
99 for ( int i = 0; i < this.bindings.size(); i++ ) {
100 ForConditionExpr< ? > b = this.bindings.get0( i );
101 fa[ i ] = b.compile();
102 fa[ i ].setFinallyAction( finalAct );
103 }
104 return new ForAction( fa, body.compile() );
105 }
106
107 /**
108 * @see org.millscript.millscript.expr.Expr#resolve(org.millscript.millscript.vm.CompilerState)
109 *
110 * <p>
111 * In a for expression, the renaming process is slightly more compilcated
112 * than usual. The renaming uses the following sequence:
113 * <ol>
114 * <li>binding expressions children are pushed onto the stack</li>
115 * <li>binding expressions are renamed</li>
116 * <li>the termination expression is renamed</li>
117 * <li>a new scope is declared
118 * <ol>
119 * <li>any bound variables are pushed onto the stack</li>
120 * <li>remaining for conditions are renamed</li>
121 * <li>for loop body is renamed</li>
122 * </ol>
123 * </li>
124 * </ol>
125 * Which ensures that the relevant bindings are available within the
126 * condition and body expression.
127 * </p>
128 */
129 @Override
130 public void resolve( final CompilerState state ) {
131
132
133
134
135 for ( int i = 1; i <= this.bindings.size(); i++ ) {
136 ForConditionExpr e = this.bindings.get( i );
137 if ( e instanceof BindingExpr ) {
138 e.resolve( state );
139 }
140 }
141
142
143
144
145
146
147 terminateExpr.resolve( state );
148
149
150
151
152 Stack< Expr > scopes = state.getScopes();
153 int n = scopes.size();
154 for ( int i = 1; i <= this.bindings.size(); i++ ) {
155 ForConditionExpr< ? > e = this.bindings.get( i );
156 if ( e instanceof BindingExpr ) {
157 ((BindingExpr< ? >) e).pushNames( scopes );
158 }
159 }
160 state.declareLocalsFrom( n );
161
162
163
164
165 for ( int i = 1; i <= this.bindings.size(); i++ ) {
166 ForConditionExpr e = this.bindings.get( i );
167 if ( !( e instanceof BindingExpr ) ) {
168
169
170 e.resolve( state );
171 }
172 }
173
174
175 body.resolve( state );
176 scopes.setSize( n );
177 }
178
179 /**
180 * @see org.millscript.millscript.expr.Expr#showComponents(int)
181 */
182 @Override
183 void showComponents( final int n ) {
184 for ( int i = 1; i <= this.bindings.size(); i++ ) {
185 ForConditionExpr e = this.bindings.get( i );
186 e.show( n );
187 }
188 this.body.show( n );
189 this.terminateExpr.show( n );
190 }
191
192 }