@@ -14,6 +14,7 @@ struct Effect {
1414}
1515
1616struct Word {
17+ bool manual;
1718 Effect effect;
1819 bool unsafe;
1920}
@@ -126,7 +127,9 @@ class StackChecker {
126127 }
127128
128129 void EvaluateFuncDef (FuncDefNode node) {
129- words[node.name] = Word(Effect(node.returnTypes.length, node.params.length));
130+ words[node.name] = Word(
131+ node.manual, Effect (node.returnTypes.length, node.params.length)
132+ );
130133
131134 if (node.unsafe) return ;
132135
@@ -154,47 +157,83 @@ class StackChecker {
154157 }
155158
156159 void EvaluateIf (IfNode node) {
157- size_t blockStack;
158-
159- if (node.hasElse) {
160+ bool setExpect = false ;
161+ size_t expectSize;
162+ string note;
163+ bool allowCondPop = false ;
164+
165+ if (! node.hasElse && (node.condition.length == 1 )) {
166+ allowCondPop = true ;
167+ note = " Single if condition must have no stack effect" ;
168+ }
169+ else if (node.hasElse) {
160170 auto oldStack = stack.dup ;
171+
161172 Evaluate(node.doElse);
162- blockStack = stack.length;
173+ expectSize = stack.length;
163174 stack = oldStack;
175+ setExpect = true ;
176+ note = " Single if condition must have same stack effect as else block" ;
177+
178+ if (node.condition.length == 1 ) {
179+ allowCondPop = true ;
180+ setExpect = false ;
181+ }
182+ }
183+ else {
184+ note = " Inconsistent stack effect in if statement" ;
164185 }
165186
166187 foreach (i, ref cond ; node.condition) {
167- auto oldStack = stack.dup ;
188+ if (cond.empty()) {
189+ Error(node.error, " Empty condition in if statement" );
190+ }
168191
169- Node conditionNode = node.condition.empty()? node : cond[$ - 1 ] ;
192+ StackCell[] oldStack ;
170193
171- Evaluate(cond);
172- Pop(conditionNode, 1 );
173- Evaluate(node.doIf[i]);
194+ if (allowCondPop) {
195+ Evaluate(cond);
196+ Pop(node, 1 );
197+ oldStack = stack.dup ;
174198
175- if ((i == 0 ) && ! node.hasElse) {
176- blockStack = stack.length;
199+ if (! setExpect) {
200+ expectSize = stack.length;
201+ }
177202 }
178- else if (stack.length != blockStack) {
179- Node errorNode = node.doIf[i].empty()?
180- node : node.doIf[i][$ - 1 ];
203+ else {
204+ oldStack = stack.dup ;
205+ Evaluate(cond);
206+ Pop(node, 1 );
207+ }
208+
209+ Evaluate(node.doIf[i]);
181210
182- Note(errorNode.error, " Expected stack length '%d', got '%d'" , blockStack, stack.length);
183- Error(errorNode.error, " If statement has inconsistent stack effects" );
211+ Node errorNode = node.doIf[i].empty()? node : node.doIf[i][$ - 1 ];
184212
185- if (stack.length > blockStack) {
186- StackOverflow(errorNode, blockStack);
187- }
213+ if (! setExpect) {
214+ expectSize = stack.length;
215+ setExpect = true ;
216+ }
217+
218+ if (stack.length > expectSize) {
219+ Note(errorNode.error, note);
220+ Note(errorNode.error, " Expected stack size %d, got %d" , expectSize, stack.length);
221+ StackOverflow(errorNode, expectSize);
222+ }
223+ else if (stack.length < expectSize) {
224+ Note(errorNode.error, note);
225+ Note(errorNode.error, " Expected stack size %d, got %d" , expectSize, stack.length);
226+ Error(errorNode.error, " Stack underflow" );
188227 }
189228
190229 stack = oldStack;
191230 }
192231
193- if (stack.length > blockStack ) {
194- Pop (node, stack.length - blockStack );
232+ if (expectSize > stack.length ) {
233+ Push (node, expectSize - stack.length );
195234 }
196- else if (stack.length < blockStack ) {
197- Push (node, blockStack - stack.length);
235+ else if (expectSize < stack.length ) {
236+ Pop (node, stack.length - expectSize );
198237 }
199238 }
200239
@@ -256,11 +295,11 @@ class StackChecker {
256295
257296 if (node.externType == ExternType.C) {
258297 words[name] = Word(
259- Effect(node.retType == " void" ? 0 : 1 , node.types.length)
298+ false , Effect (node.retType == " void" ? 0 : 1 , node.types.length)
260299 );
261300 }
262301 else {
263- words[name] = Word(Effect.init, false );
302+ words[name] = Word(false , Effect.init, false );
264303 }
265304 }
266305
@@ -283,7 +322,6 @@ class StackChecker {
283322 Error(node.error, " Unknown function '%s'" , node.func);
284323 }
285324
286-
287325 auto word = words[node.func];
288326
289327 assert (! word.unsafe);
@@ -379,10 +417,14 @@ class StackChecker {
379417 void DumpFunctions () {
380418 size_t spaces = words.keys ().fold! ((a, e) => e.length > a.length? e : a).length;
381419
382- foreach (key, value ; words) {
420+ auto keys = words.keys ().sort();
421+
422+ foreach (key ; keys ) {
423+ auto value = words[key];
424+
383425 writefln(
384- " %s %s= %d -> %d" , key, replicate([' ' ], spaces - key.length),
385- value.effect.pop, value.effect.push
426+ " %s %s= %d %s -> %d" , key, replicate([' ' ], spaces - key.length),
427+ value.effect.pop, value.manual? " m " : " " , value. effect.push
386428 );
387429 }
388430 }
0 commit comments