Skip to content

Commit f4989fd

Browse files
committed
Else blocks for while statements and breaking loops
1 parent 178e139 commit f4989fd

File tree

6 files changed

+119
-4
lines changed

6 files changed

+119
-4
lines changed

compiler/src/main/java/dev/ultreon/pythonc/JvmWriter.java

+13
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,19 @@ public Context getContext() {
2222
return context;
2323
}
2424

25+
public LoopContext getLoopContext() {
26+
for (int i = pc.contextStack.size() - 1; i >= 0; i--) {
27+
Context context = pc.contextStack.get(i);
28+
if (context instanceof FunctionContext) {
29+
throw new CompilerException("Not inside a loop or loop is outside of function.");
30+
}
31+
if (context instanceof LoopContext) {
32+
return (LoopContext) context;
33+
}
34+
}
35+
throw new RuntimeException("No loop context found");
36+
}
37+
2538
public JvmClass getClassSymbol(String className) {
2639
return pc.getClassSymbol(className);
2740
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package dev.ultreon.pythonc;
2+
3+
import org.objectweb.asm.Label;
4+
5+
public interface LoopContext extends Context {
6+
7+
Label getContinuationLabel();
8+
9+
Label getBreakLabel();
10+
}

compiler/src/main/java/dev/ultreon/pythonc/PythonCompiler.java

+56-2
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ public class PythonCompiler extends PythonParserBaseVisitor<Object> {
6262
private PyClass curPyClass = null;
6363
private final List<CompilerException> compileErrors = new ArrayList<>();
6464
private Label elifLabel;
65-
private final Stack<Context> contextStack = new Stack<>();
65+
final Stack<Context> contextStack = new Stack<>();
6666

6767
public final JvmWriter writer = new JvmWriter(this);
6868

@@ -318,19 +318,41 @@ public Object visitCompound_stmt(PythonParser.Compound_stmtContext ctx) {
318318
return visit(whileStmtContext);
319319
}
320320

321+
PythonParser.For_stmtContext forStmtContext = ctx.for_stmt();
322+
if (forStmtContext != null) {
323+
return visit(forStmtContext);
324+
}
325+
321326
throw new RuntimeException("No supported matching compound_stmt found for:\n" + ctx.getText());
322327
}
323328

329+
@Override
330+
public Object visitFor_stmt(PythonParser.For_stmtContext ctx) {
331+
// PythonParser.Named_expressionContext namedExpressionContext = ctx.named_expression();
332+
// if (namedExpressionContext != null) {
333+
// Object visit = visit(namedExpressionContext);
334+
// loadExpr(ctx, visit);
335+
// } else {
336+
// throw new RuntimeException("No supported matching named_expression found for:\n" + ctx.getText());
337+
// }
338+
339+
throw new RuntimeException("No supported matching for_stmt found for:\n" + ctx.getText());
340+
}
341+
324342
@Override
325343
public Object visitWhile_stmt(PythonParser.While_stmtContext ctx) {
326344
Label loopStart = new Label();
327345
Label loopEnd = new Label();
346+
Label elseBlock = null;
347+
if (ctx.else_block() != null) {
348+
elseBlock = new Label();
349+
}
328350

329351
// Loop start:
330352
mv.visitLabel(loopStart);
331353

332354
// region Comparison(named_expression)
333-
pushContext(new WhileConditionContext(loopEnd));
355+
pushContext(new WhileConditionContext(loopEnd, elseBlock));
334356
PythonParser.Named_expressionContext namedExpressionContext = ctx.named_expression();
335357
if (namedExpressionContext != null) {
336358
Object visit = visit(namedExpressionContext);
@@ -343,18 +365,35 @@ public Object visitWhile_stmt(PythonParser.While_stmtContext ctx) {
343365
// endregion Comparison
344366

345367
// region Loop(block)
368+
Context loopContext = new WhileLoopContext(loopStart, loopEnd);
369+
pushContext(loopContext);
346370
PythonParser.BlockContext block = ctx.block();
347371
if (block != null) {
348372
visit(block);
349373
}
350374
if (context.needsPop()) {
351375
throw new RuntimeException("Still values on stack for:\n" + ctx.getText());
352376
}
377+
popContext();
353378
// endregion Loop
354379

355380
// Jump to loop start
356381
mv.visitJumpInsn(GOTO, loopStart);
357382

383+
if (elseBlock != null) {
384+
mv.visitLabel(elseBlock);
385+
386+
// region Else(block)
387+
PythonParser.BlockContext elseBlockContext = ctx.else_block().block();
388+
if (elseBlockContext != null) {
389+
visit(elseBlockContext);
390+
}
391+
if (context.needsPop()) {
392+
throw new RuntimeException("Still values on stack for:\n" + ctx.getText());
393+
}
394+
// endregion Else
395+
}
396+
358397
// Loop end:
359398
mv.visitLabel(loopEnd);
360399

@@ -980,6 +1019,21 @@ public Object visitSimple_stmt(PythonParser.Simple_stmtContext ctx) {
9801019
writer.pop();
9811020
return visit;
9821021
}
1022+
1023+
TerminalNode aBreak = ctx.BREAK();
1024+
if (aBreak != null) {
1025+
Context context = writer.getLoopContext();
1026+
if (context instanceof WhileLoopContext whileConditionContext) {
1027+
mv.visitJumpInsn(GOTO, whileConditionContext.endLabel);
1028+
return Unit.Instance;
1029+
// } else if (writer.getContext() instanceof ForConditionContext) {
1030+
// ForConditionContext forConditionContext = (ForConditionContext) writer.getContext();
1031+
// mv.visitJumpInsn(GOTO, forConditionContext.loopEnd);
1032+
// return Unit.Instance;
1033+
} else {
1034+
throw new RuntimeException("Not in a loop:\n" + ctx.getText());
1035+
}
1036+
}
9831037
throw new RuntimeException("No supported matching simple_stmt found of type " + ctx.getClass().getSimpleName() + " for:\n" + ctx.getText());
9841038
}
9851039

compiler/src/main/java/dev/ultreon/pythonc/WhileConditionContext.java

+4-2
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,11 @@
55

66
public class WhileConditionContext extends AbstractContext implements ConditionContext {
77
public final Label loopEnd;
8+
public final Label elseBlock;
89

9-
public WhileConditionContext(Label loopEnd) {
10+
public WhileConditionContext(Label loopEnd, Label elseBlock) {
1011
this.loopEnd = loopEnd;
12+
this.elseBlock = elseBlock;
1113
}
1214

1315
@Override
@@ -17,6 +19,6 @@ public WhileConditionContext(Label loopEnd) {
1719

1820
@Override
1921
public @Nullable Label ifFalse() {
20-
return loopEnd;
22+
return elseBlock != null ? elseBlock : loopEnd;
2123
}
2224
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package dev.ultreon.pythonc;
2+
3+
import org.objectweb.asm.Label;
4+
5+
public class WhileLoopContext extends AbstractContext implements LoopContext {
6+
public final Label startLabel;
7+
public final Label endLabel;
8+
9+
public WhileLoopContext(Label startLabel, Label endLabel) {
10+
this.startLabel = startLabel;
11+
this.endLabel = endLabel;
12+
}
13+
14+
@Override
15+
public Label getContinuationLabel() {
16+
return startLabel;
17+
}
18+
19+
@Override
20+
public Label getBreakLabel() {
21+
return endLabel;
22+
}
23+
}

src/main/python/example/hello.py

+13
Original file line numberDiff line numberDiff line change
@@ -127,5 +127,18 @@ def init():
127127
print(i)
128128
print("Hello, world!")
129129
i = i + 1
130+
else:
131+
print("Done!")
132+
133+
i = 0
134+
while i < 10:
135+
print(i)
136+
print("Hello, world!")
137+
i = i + 1
138+
if i == 5:
139+
print("Break!")
140+
break
141+
else:
142+
print("Done!")
130143

131144

0 commit comments

Comments
 (0)