From aa13c97dac536bd1c4bf2f4e5c6ee505a487c634 Mon Sep 17 00:00:00 2001 From: Michael Williamson Date: Sun, 26 Nov 2023 16:45:51 +0000 Subject: Support Patio exceptions in Patio Wasm backend --- .../compiler/backends/wasm/WasmPatioCodeGen.java | 109 ++++++++++++++++++++- 1 file changed, 106 insertions(+), 3 deletions(-) (limited to 'src/main/java') diff --git a/src/main/java/org/shedlang/compiler/backends/wasm/WasmPatioCodeGen.java b/src/main/java/org/shedlang/compiler/backends/wasm/WasmPatioCodeGen.java index 1447ee14..585de4e6 100644 --- a/src/main/java/org/shedlang/compiler/backends/wasm/WasmPatioCodeGen.java +++ b/src/main/java/org/shedlang/compiler/backends/wasm/WasmPatioCodeGen.java @@ -337,18 +337,36 @@ public class WasmPatioCodeGen { yield context; } - case PatioThrow throw_ -> - throw new UnsupportedOperationException("TODO"); + case PatioThrow throw_ -> { + context = generateOperand(throw_.value(), context); + + context = context.addInstruction(new WasmThrow(new WasmTagName(throw_.exceptionTypeName()))); + + yield context; + } case PatioTry try_ -> { + context = context.enterTryInstruction( + new WasmBlockType(List.of(WasmValueType.I32)) + ); + context = generateBlockBody(try_.body(), context); + for (var catchClause : try_.catchClauses()) { + context = context.enterCatch(new WasmTagName(catchClause.exceptionTypeName())); + + // TODO: pop into local for catch + context = context.addInstruction(new WasmDrop()); + context = generateBlockBody(catchClause.body(), context); + } + + context = context.exitTryInstruction(); + context = popIntoPatioLocals(try_.targets(), context); yield context; } - case PatioUnreachable patioUnreachable -> context.addInstruction(new WasmUnreachable()); @@ -732,6 +750,33 @@ public class WasmPatioCodeGen { return exitStructuredInstruction(); } + public Context enterTryInstruction(WasmBlockType blockType) { + return new Context( + this.module, + P.vector(), + this.instructionsStack.plus(this.instructions), + this.patioLocalNameToWasmLocalIndex, + new WasmTryInstructionBuilder(blockType), + this.structuredInstructionBuilderStack.plus(this.structuredInstructionBuilder) + ); + } + + public Context enterCatch(WasmTagName tagName) { + return new Context( + this.module, + P.vector(), + this.instructionsStack, + this.patioLocalNameToWasmLocalIndex, + this.structuredInstructionBuilder.enterCatch(tagName, this.instructions), + this.structuredInstructionBuilderStack + ); + } + + public Context exitTryInstruction() { + // TODO: verify matching enter/exit? + return exitStructuredInstruction(); + } + public Context exitStructuredInstruction() { var context = new Context( this.module, @@ -775,6 +820,13 @@ public class WasmPatioCodeGen { default WasmStructuredInstructionBuilder enterElse(PVector instructions) { throw new UnsupportedOperationException(); } + + default WasmStructuredInstructionBuilder enterCatch( + WasmTagName tagName, + PVector instructions + ) { + throw new UnsupportedOperationException(); + } } private static class NullStructuredInstructionBuilder implements WasmStructuredInstructionBuilder { @@ -821,4 +873,55 @@ public class WasmPatioCodeGen { return new WasmIf(blockType, ifTrue, instructions); } } + + private record WasmTryInstructionBuilder( + WasmBlockType blockType + ) implements WasmStructuredInstructionBuilder { + @Override + public WasmInstruction exit(PVector instructions) { + return new WasmTry(blockType, List.of(), instructions); + } + + @Override + public WasmStructuredInstructionBuilder enterCatch( + WasmTagName tagName, + PVector instructions + ) { + return new WasmTryCatchInstructionBuilder( + blockType, + instructions, + tagName, + P.vector() + ); + } + } + + private record WasmTryCatchInstructionBuilder( + WasmBlockType blockType, + List tryBodyInstructions, + WasmTagName tagName, + PVector catchBlocks + ) implements WasmStructuredInstructionBuilder { + @Override + public WasmInstruction exit(PVector instructions) { + return new WasmTry( + this.blockType, + this.catchBlocks.plus(new WasmCatchBlock(this.tagName, instructions)), + this.tryBodyInstructions + ); + } + + @Override + public WasmStructuredInstructionBuilder enterCatch( + WasmTagName tagName, + PVector instructions + ) { + return new WasmTryCatchInstructionBuilder( + this.blockType, + this.tryBodyInstructions, + tagName, + this.catchBlocks.plus(new WasmCatchBlock(this.tagName, instructions)) + ); + } + } } -- cgit v1.2.3