Skip to content

Commit 1046439

Browse files
committed
oh no
1 parent 4ae82a8 commit 1046439

File tree

1 file changed

+72
-30
lines changed

1 file changed

+72
-30
lines changed

source/stackCheck.d

Lines changed: 72 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ struct Effect {
1414
}
1515

1616
struct 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

Comments
 (0)