diff options
| author | Michael Williamson <mike@zwobble.org> | 2023-12-13 22:25:10 +0000 |
|---|---|---|
| committer | Michael Williamson <mike@zwobble.org> | 2023-12-13 22:25:10 +0000 |
| commit | 778f8d3a31286ab3cf8016289a35757f9aef808d (patch) | |
| tree | 6333168316b32d915fc069a4cba6c9ccd529977b /src/main/java | |
| parent | e67385e2086ae14c430865e4577986dacba72256 (diff) | |
Introduce ShidBlock
Diffstat (limited to 'src/main/java')
12 files changed, 134 insertions, 83 deletions
diff --git a/src/main/java/org/shedlang/compiler/backends/ShidTextBackend.java b/src/main/java/org/shedlang/compiler/backends/ShidTextBackend.java index ceda128b..bdc5e61d 100644 --- a/src/main/java/org/shedlang/compiler/backends/ShidTextBackend.java +++ b/src/main/java/org/shedlang/compiler/backends/ShidTextBackend.java @@ -23,10 +23,8 @@ public class ShidTextBackend implements Backend { TargetDir targetDir ) throws IOException { for (var namespace : namespaces) { - var instructions = namespace.instructions(); - var builder = new StringBuilder(); - ShidSerializer.serializeInstructions(instructions, builder); + ShidSerializer.serializeBlock(namespace.body(), builder); var instructionsString = builder.toString(); var path = targetDir.namespace(namespace.namespaceName()) diff --git a/src/main/java/org/shedlang/compiler/patio/PatioCodeGen.java b/src/main/java/org/shedlang/compiler/patio/PatioCodeGen.java index 582d3959..45a96ef5 100644 --- a/src/main/java/org/shedlang/compiler/patio/PatioCodeGen.java +++ b/src/main/java/org/shedlang/compiler/patio/PatioCodeGen.java @@ -108,12 +108,12 @@ public class PatioCodeGen { shidNamespace.namespaceName(), initContext -> { initContext = declareShidLocals( - shidNamespace.instructions(), + shidNamespace.body(), FreeVariables.empty(), initContext ); - return generateInstructions(shidNamespace.instructions(), initContext); + return generateInstructions(shidNamespace.body(), initContext); }, context ); @@ -123,6 +123,13 @@ public class PatioCodeGen { } public static PatioCodeGenContext generateInstructions( + ShidBlock block, + PatioCodeGenContext context + ) { + return generateInstructions(block.instructions(), context); + } + + public static PatioCodeGenContext generateInstructions( List<ShidInstruction> shidInstructions, PatioCodeGenContext context ) { @@ -138,6 +145,12 @@ public class PatioCodeGen { PatioCodeGenContext context ) { return switch (shidInstruction) { + case ShidBlock block -> { + context = generateInstructions(block, context); + + yield context; + } + case ShidCall call -> { var namedArgsByName = new ArrayList<Map.Entry<String, PatioLocalRef>>(); for (var argName : call.namedArgNames().reversed()) { @@ -860,12 +873,12 @@ public class PatioCodeGen { private static PatioCodeGenResult<PatioBlock> generateBlock( int resultCount, - List<ShidInstruction> shidInstructions, + ShidBlock shidBlock, Source source, PatioCodeGenContext context ) { context = context.enterBlock(); - context = generateInstructions(shidInstructions, context); + context = generateInstructions(shidBlock, context); var targets = new ArrayList<PatioOperand>(); for (var i = 0; i < resultCount; i++) { @@ -920,7 +933,7 @@ public class PatioCodeGen { } private static PatioCodeGenContext declareShidLocals( - List<ShidInstruction> body, + ShidBlock body, FreeVariables freeVariables, PatioCodeGenContext context ) { @@ -960,11 +973,14 @@ public class PatioCodeGen { } private static OrderedPSet<BoundVariable> findAssignedVariables( - List<ShidInstruction> body, + ShidBlock body, OrderedPSet<BoundVariable> boundVariables ) { - for (var bodyInstruction : body) { + for (var bodyInstruction : body.instructions()) { switch (bodyInstruction) { + case ShidBlock blockInstruction -> { + boundVariables = findAssignedVariables(blockInstruction, boundVariables); + } case ShidCall callInstruction -> { } case ShidDefineEffect defineEffectInstruction -> { diff --git a/src/main/java/org/shedlang/compiler/shid/ShidCodeGen.java b/src/main/java/org/shedlang/compiler/shid/ShidCodeGen.java index 2396f06b..e26dd39c 100644 --- a/src/main/java/org/shedlang/compiler/shid/ShidCodeGen.java +++ b/src/main/java/org/shedlang/compiler/shid/ShidCodeGen.java @@ -219,12 +219,12 @@ public class ShidCodeGen { private static Context compileFunction( String name, TypedParamsNode params, - TypedFunctionBodyNode body, + TypedFunctionBodyNode bodyNode, ShidDefineFunction.Variant variant, Source source, Context context ) { - context = context.enterBlock(body.boundVariables()); + context = context.enterBlock(bodyNode.boundVariables()); var c = context; @@ -242,31 +242,31 @@ public class ShidCodeGen { )) .toList(); - context = compileBlockWithYield(body.block(), context); + context = compileBlockWithYield(bodyNode.block(), context); - switch (body.behaviour()) { + switch (bodyNode.behaviour()) { case TypedFunctionStatementBehaviour.BlockReturn blockReturn -> { - context = context.addInstruction(new ShidReturn(body.source())); + context = context.addInstruction(new ShidReturn(bodyNode.source())); } case TypedFunctionStatementBehaviour.Continue continue_ -> { - context = context.addInstruction(new ShidReturn(body.source())); + context = context.addInstruction(new ShidReturn(bodyNode.source())); } case TypedFunctionStatementBehaviour.Terminate terminate -> { } } - var bodyInstructions = context.instructions; + var bodyResult = context.exitBlock(bodyNode.source()); + var body = bodyResult.value; + context = bodyResult.context; - context = context.exitBlock(); - - var freeVariables = generateFreeVariables(body.freeVariables(), context); + var freeVariables = generateFreeVariables(bodyNode.freeVariables(), context); var defineFunctionInstruction = new ShidDefineFunction( name, positionalParams, namedParams, freeVariables, - bodyInstructions, + body, variant, source ); @@ -375,19 +375,22 @@ public class ShidCodeGen { if (conditionalBranches.isEmpty()) { context = context.enterBlock(elseBody.boundVariables()); context = compileBlockWithYield(elseBody, context); - var elseInstructions = context.instructions; - context = context.exitBlock(); - for (var instruction : elseInstructions) { - context = context.addInstruction(instruction); - } + + var bodyResult = context.exitBlock(elseBody.source()); + var body = bodyResult.value; + context = bodyResult.context; + + context = context.addInstruction(body); } else { var conditionalBranch = conditionalBranches.get(0); context = compileExpression(conditionalBranch.condition(), context); context = context.enterBlock(conditionalBranch.body().boundVariables()); context = compileBlockWithYield(conditionalBranch.body(), context); - var ifTrueInstructions = context.instructions; - context = context.exitBlock(); + + var ifTrueResult = context.exitBlock(conditionalBranch.body().source()); + var ifTrue = ifTrueResult.value; + context = ifTrueResult.context; context = context.enterBlock(List.of()); context = compileIf( @@ -395,13 +398,15 @@ public class ShidCodeGen { elseBody, context ); - var ifFalseInstructions = context.instructions; - context = context.exitBlock(); + + var ifFalseResult = context.exitBlock(conditionalBranch.source()); + var ifFalse = ifFalseResult.value; + context = ifFalseResult.context; context = context.addInstruction(new ShidIf( 1, - ifTrueInstructions, - ifFalseInstructions, + ifTrue, + ifFalse, conditionalBranch.source() )); } @@ -414,7 +419,7 @@ public class ShidCodeGen { } public static ShidNamespace compileNamespace(TypedNamespaceNode node) { - var context = Context.EMPTY; + var context = Context.EMPTY.enterBlock(node.boundVariables()); context = context.addShedVal(ShedBuiltins.PRINT_NAME); var printLocalName = context.shedVariableToLocal(ShedBuiltins.PRINT_NAME); @@ -428,10 +433,6 @@ public class ShidCodeGen { )) .addInstruction(new ShidLocalStore(printLocalName, node.source())); - for (var boundVariable : node.boundVariables()) { - context = context.addShedVariable(boundVariable); - } - for (var importNode : node.imports()) { var localName = context.shedVariableToLocal(importNode.variableName()); context = context @@ -478,7 +479,11 @@ public class ShidCodeGen { )); } - return new ShidNamespace(node.namespaceName(), context.instructions); + var bodyResult = context.exitBlock(node.source()); + var body = bodyResult.value; + context = bodyResult.context; + + return new ShidNamespace(node.namespaceName(), body); } public static Context compileNamespaceStatement(TypedNamespaceStatementNode node, Context context) { @@ -639,15 +644,17 @@ public class ShidCodeGen { context = context.enterBlock(node.body().boundVariables()); context = compileBlockWithYield(node.body(), context); - var bodyInstructions = context.instructions; - context = context.exitBlock(); + + var bodyResult = context.exitBlock(node.body().source()); + var body = bodyResult.value; + context = bodyResult.context; var instruction = new ShidTry( node.handledEffect().value(), node.handlerMethods().stream() .map(methodNode -> methodNode.name()) .toList(), - bodyInstructions, + body, node.source() ); @@ -692,12 +699,14 @@ public class ShidCodeGen { for (var whenCase : node.cases()) { context = context.enterBlock(whenCase.body().boundVariables()); context = compileBlockWithYield(whenCase.body(), context); - var caseBodyInstructions = context.instructions; - context = context.exitBlock(); + + var caseBodyResult = context.exitBlock(whenCase.body().source()); + var caseBody = caseBodyResult.value; + context = caseBodyResult.context; var switchCase = new ShidSwitch.Case( whenCase.caseType().value(), - caseBodyInstructions, + caseBody, whenCase.source() ); switchCases.add(switchCase); @@ -714,29 +723,35 @@ public class ShidCodeGen { private static Context compileWhile(TypedWhileNode node, Context context) { context = context.enterBlock(node.body().boundVariables()); context = compileBlockWithoutYield(node.body(), context); - var ifTrueInstructions = context.instructions; - context = context.exitBlock(); + + var ifTrueResult = context.exitBlock(node.body().source()); + var ifTrue = ifTrueResult.value; + context = ifTrueResult.context; context = context.enterBlock(List.of()); context = compileExpression(node.condition(), context); context = context.addInstruction(new ShidIf( 0, - List.of(), - List.of( - new ShidLoopBreak(node.source()) + new ShidBlock(List.of(), node.source()), + new ShidBlock( + List.of( + new ShidLoopBreak(node.source()) + ), + node.source() ), node.source() )); - context = context.addInstructions(ifTrueInstructions); + context = context.addInstruction(ifTrue); context = context.addInstruction(new ShidLoopContinue(node.source())); - var bodyInstructions = context.instructions; - context = context.exitBlock(); + var bodyResult = context.exitBlock(node.source()); + var body = bodyResult.value; + context = bodyResult.context; - context = context.addInstruction(new ShidLoop(bodyInstructions, node.source())); + context = context.addInstruction(new ShidLoop(body, node.source())); return context; } @@ -786,14 +801,14 @@ public class ShidCodeGen { return context; } - public Context exitBlock() { + public Result<ShidBlock> exitBlock(Source source) { return new Context( this.instructionsStack.minus(0), this.instructionsStack.get(0), this.localNames, this.shedVariablesByNameStack.minus(0), this.shedVariablesByNameStack.get(0) - ); + ).toResult(new ShidBlock(this.instructions, source)); } private Context addInstruction(ShidInstruction instruction) { @@ -830,10 +845,12 @@ public class ShidCodeGen { return shedVariable; } + // TODO: make private / remove? Variables should be declared using enterBlock(). public Context addShedVal(String variableName) { return addShedVariable(BoundVariable.immutable(variableName)); } + // TODO: make private? Variables should be declared using enterBlock(). public Context addShedVariable(BoundVariable boundVariable) { var localName = generateLocalNameForVariable(boundVariable.name()); @@ -861,6 +878,12 @@ public class ShidCodeGen { public List<ShidInstruction> instructions() { return this.instructions; } + + public <T> Result<T> toResult(T value) { + return new Result<>(value, this); + } + + public record Result<T>(T value, Context context) {} } private record ShedVariable(String shidLocalName, boolean isVar) {} diff --git a/src/main/java/org/shedlang/compiler/shid/ShidNamespace.java b/src/main/java/org/shedlang/compiler/shid/ShidNamespace.java index 4c5f134f..d3fb4b0f 100644 --- a/src/main/java/org/shedlang/compiler/shid/ShidNamespace.java +++ b/src/main/java/org/shedlang/compiler/shid/ShidNamespace.java @@ -1,12 +1,10 @@ package org.shedlang.compiler.shid; -import org.shedlang.compiler.shid.instructions.ShidInstruction; +import org.shedlang.compiler.shid.instructions.ShidBlock; import org.shedlang.compiler.types.NamespaceName; -import java.util.List; - public record ShidNamespace( NamespaceName namespaceName, - List<ShidInstruction> instructions + ShidBlock body ) { } diff --git a/src/main/java/org/shedlang/compiler/shid/ShidSerializer.java b/src/main/java/org/shedlang/compiler/shid/ShidSerializer.java index bd6971fd..e764edca 100644 --- a/src/main/java/org/shedlang/compiler/shid/ShidSerializer.java +++ b/src/main/java/org/shedlang/compiler/shid/ShidSerializer.java @@ -14,8 +14,8 @@ public class ShidSerializer { private ShidSerializer() { } - public static void serializeInstructions(List<ShidInstruction> instructions, StringBuilder builder) { - var tree = instructionsToTree(instructions); + public static void serializeBlock(ShidBlock block, StringBuilder builder) { + var tree = blockToTree(block); serializeTree(tree, builder, 0); } @@ -24,6 +24,10 @@ public class ShidSerializer { serializeTree(tree, builder, 0); } + private static Tree blockToTree(ShidBlock block) { + return instructionsToTree(block.instructions()); + } + private static Tree instructionsToTree(List<? extends ShidInstruction> instructions) { return treeListIndented( instructions.stream() @@ -34,6 +38,12 @@ public class ShidSerializer { private static Tree instructionToTree(ShidInstruction instruction) { return switch (instruction) { + case ShidBlock blockInstruction -> + treeListIndented( + treeIdentifier("block"), + instructionsToTree(blockInstruction.instructions()) + ); + case ShidCall callInstruction -> treeList( treeIdentifier("call"), @@ -80,7 +90,7 @@ public class ShidSerializer { .map(freeVariable -> treeString(freeVariable.name())) .toList() )), - treeNamed("body", instructionsToTree(defineFunctionInstruction.body())) + treeNamed("body", blockToTree(defineFunctionInstruction.body())) ); case ShidDefineStruct defineStructInstruction -> @@ -139,8 +149,8 @@ public class ShidSerializer { treeListIndented( treeIdentifier("if"), treeNamed("result-count", treeInt(if_.resultCount())), - instructionsToTree(if_.trueBody()), - instructionsToTree(if_.falseBody()) + blockToTree(if_.trueBody()), + blockToTree(if_.falseBody()) ); case ShidIntAdd intAdd -> @@ -176,7 +186,7 @@ public class ShidSerializer { case ShidLoop loop -> treeListIndented( treeIdentifier("loop"), - instructionsToTree(loop.body()) + blockToTree(loop.body()) ); case ShidLoopBreak loopBreak -> @@ -241,7 +251,7 @@ public class ShidSerializer { switchInstruction.cases().stream() .map(switchCase -> treeListIndented( structTypeToTree(switchCase.caseType()), - instructionsToTree(switchCase.body()) + blockToTree(switchCase.body()) )) .toList() ) @@ -256,7 +266,7 @@ public class ShidSerializer { .map(name -> treeString(name)) .toList() ), - instructionsToTree(tryInstruction.body()) + blockToTree(tryInstruction.body()) ); case ShidTupleCreate tupleCreateInstruction -> diff --git a/src/main/java/org/shedlang/compiler/shid/instructions/ShidBlock.java b/src/main/java/org/shedlang/compiler/shid/instructions/ShidBlock.java new file mode 100644 index 00000000..427c2a88 --- /dev/null +++ b/src/main/java/org/shedlang/compiler/shid/instructions/ShidBlock.java @@ -0,0 +1,11 @@ +package org.shedlang.compiler.shid.instructions; + +import org.shedlang.compiler.sources.Source; + +import java.util.List; + +public record ShidBlock( + List<ShidInstruction> instructions, + Source source +) implements ShidInstruction { +} diff --git a/src/main/java/org/shedlang/compiler/shid/instructions/ShidDefineFunction.java b/src/main/java/org/shedlang/compiler/shid/instructions/ShidDefineFunction.java index f0a45844..9377a69b 100644 --- a/src/main/java/org/shedlang/compiler/shid/instructions/ShidDefineFunction.java +++ b/src/main/java/org/shedlang/compiler/shid/instructions/ShidDefineFunction.java @@ -17,7 +17,7 @@ public record ShidDefineFunction( List<Param> positionalParams, List<Param> namedParams, FreeVariables freeVariables, - List<ShidInstruction> body, + ShidBlock body, Variant variant, Source source ) implements ShidInstruction { @@ -55,7 +55,7 @@ public record ShidDefineFunction( positionalParams, namedParams, freeVariables.build(), - body, + new ShidBlock(body, Sources.NULL), variant, Sources.NULL ); diff --git a/src/main/java/org/shedlang/compiler/shid/instructions/ShidIf.java b/src/main/java/org/shedlang/compiler/shid/instructions/ShidIf.java index 408ccbef..d3a05919 100644 --- a/src/main/java/org/shedlang/compiler/shid/instructions/ShidIf.java +++ b/src/main/java/org/shedlang/compiler/shid/instructions/ShidIf.java @@ -3,20 +3,17 @@ package org.shedlang.compiler.shid.instructions; import org.shedlang.compiler.sources.Source; -import java.util.List; - /** * Pop a value from the temporary value stack, and assume it is a Bool. If it is - * true, execute the instructions in the "true" body, otherwise execute the - * instructions in the "false" body. + * true, execute the "true" body, otherwise execute the "false" body. * <p> * Each branch body should push <code>resultCount</code> values onto the * temporary value stack. */ public record ShidIf( int resultCount, - List<ShidInstruction> trueBody, - List<ShidInstruction> falseBody, + ShidBlock trueBody, + ShidBlock falseBody, Source source ) implements ShidInstruction { } diff --git a/src/main/java/org/shedlang/compiler/shid/instructions/ShidInstruction.java b/src/main/java/org/shedlang/compiler/shid/instructions/ShidInstruction.java index 1c1afc3c..7f5a33e2 100644 --- a/src/main/java/org/shedlang/compiler/shid/instructions/ShidInstruction.java +++ b/src/main/java/org/shedlang/compiler/shid/instructions/ShidInstruction.java @@ -3,7 +3,7 @@ package org.shedlang.compiler.shid.instructions; import org.shedlang.compiler.sources.Source; public sealed interface ShidInstruction - permits ShedEffectHandlerBreak, ShidCall, ShidDefineEffect, ShidDefineFunction, ShidDefineStruct, ShidDiscard, ShidDuplicate, ShidFieldLoad, ShidIf, ShidIntAdd, ShidIntEquals, ShidIntNotEqual, ShidIntSub, ShidLocalDrop, ShidLocalLoad, ShidLocalStore, ShidLoop, ShidLoopBreak, ShidLoopContinue, ShidNamespaceFieldStore, ShidNamespaceImport, ShidPushBool, ShidPushInt, ShidPushString, ShidPushUnit, ShidResume, ShidReturn, ShidStringAdd, ShidSwitch, ShidTry, ShidTupleCreate, ShidTupleGet, ShidVarLoad, ShidVarStore { + permits ShedEffectHandlerBreak, ShidBlock, ShidCall, ShidDefineEffect, ShidDefineFunction, ShidDefineStruct, ShidDiscard, ShidDuplicate, ShidFieldLoad, ShidIf, ShidIntAdd, ShidIntEquals, ShidIntNotEqual, ShidIntSub, ShidLocalDrop, ShidLocalLoad, ShidLocalStore, ShidLoop, ShidLoopBreak, ShidLoopContinue, ShidNamespaceFieldStore, ShidNamespaceImport, ShidPushBool, ShidPushInt, ShidPushString, ShidPushUnit, ShidResume, ShidReturn, ShidStringAdd, ShidSwitch, ShidTry, ShidTupleCreate, ShidTupleGet, ShidVarLoad, ShidVarStore { Source source(); } diff --git a/src/main/java/org/shedlang/compiler/shid/instructions/ShidLoop.java b/src/main/java/org/shedlang/compiler/shid/instructions/ShidLoop.java index bfa7a1fa..6ab81b47 100644 --- a/src/main/java/org/shedlang/compiler/shid/instructions/ShidLoop.java +++ b/src/main/java/org/shedlang/compiler/shid/instructions/ShidLoop.java @@ -3,15 +3,13 @@ package org.shedlang.compiler.shid.instructions; import org.shedlang.compiler.sources.Source; -import java.util.List; - /** * Execute the body. The <code>continue</code> instruction can jump back to the * start of the body. The <code>break</code> instruction can jump to the end of * the body. */ public record ShidLoop( - List<ShidInstruction> body, + ShidBlock body, Source source ) implements ShidInstruction { } diff --git a/src/main/java/org/shedlang/compiler/shid/instructions/ShidSwitch.java b/src/main/java/org/shedlang/compiler/shid/instructions/ShidSwitch.java index 00126f3c..c1596084 100644 --- a/src/main/java/org/shedlang/compiler/shid/instructions/ShidSwitch.java +++ b/src/main/java/org/shedlang/compiler/shid/instructions/ShidSwitch.java @@ -7,8 +7,8 @@ import java.util.List; /** * Pop a value from the temporary value stack, find the case corresponding to - * that value's type, and execute the instructions in the case's body. If there - * is no such case, the behaviour of this instruction is not defined. + * that value's type, and execute the case's body. If there is no such case, the + * behaviour of this instruction is not defined. * <p> * Each case body should push exactly one value onto the temporary value stack. */ @@ -16,6 +16,6 @@ public record ShidSwitch( List<Case> cases, Source source ) implements ShidInstruction { - public record Case(StructType caseType, List<ShidInstruction> body, Source source) { + public record Case(StructType caseType, ShidBlock body, Source source) { } } diff --git a/src/main/java/org/shedlang/compiler/shid/instructions/ShidTry.java b/src/main/java/org/shedlang/compiler/shid/instructions/ShidTry.java index ef763eda..ac9419f0 100644 --- a/src/main/java/org/shedlang/compiler/shid/instructions/ShidTry.java +++ b/src/main/java/org/shedlang/compiler/shid/instructions/ShidTry.java @@ -20,7 +20,7 @@ import java.util.List; public record ShidTry( UserDefinedEffect handledEffect, List<String> handlerMethodNames, - List<ShidInstruction> body, + ShidBlock body, Source source ) implements ShidInstruction { } |
