From bed3635d310d243a7946566e4eea0ed5e4833a49 Mon Sep 17 00:00:00 2001 From: Michael Williamson Date: Wed, 20 Dec 2023 17:11:37 +0000 Subject: Move ShidToPatio code to separate package --- .../compiler/backends/PatioTextBackend.java | 4 +- .../compiler/backends/llvm/LlvmBackend.java | 4 +- .../compiler/backends/wasm/WasmBackend.java | 4 +- .../compiler/patio/PatioCodeGenClosures.java | 315 ------ .../org/shedlang/compiler/patio/ShidToPatio.java | 1013 -------------------- .../ShidToPatioCompilationUnitElementSpace.java | 19 - .../compiler/patio/ShidToPatioContext.java | 867 ----------------- .../compiler/patio/ShidToPatioEffects.java | 505 ---------- .../compiler/patio/ShidToPatioFunctions.java | 54 -- .../org/shedlang/compiler/patio/ShidToPatioGc.java | 208 ---- .../shedlang/compiler/patio/ShidToPatioInts.java | 156 --- .../compiler/patio/ShidToPatioLocalSpace.java | 48 - .../compiler/patio/ShidToPatioNamespaces.java | 310 ------ .../shedlang/compiler/patio/ShidToPatioResult.java | 4 - .../compiler/patio/ShidToPatioStrings.java | 84 -- .../compiler/patio/ShidToPatioStructs.java | 200 ---- .../shedlang/compiler/patio/ShidToPatioTuples.java | 132 --- .../shedlang/compiler/patio/ShidToPatioTypes.java | 11 - .../shedlang/compiler/patio/ShidToPatioVars.java | 80 -- .../DuplicateCompilationUnitElementName.java | 17 - .../shedlang/compiler/shidtopatio/ShidToPatio.java | 1013 ++++++++++++++++++++ .../compiler/shidtopatio/ShidToPatioClosures.java | 315 ++++++ .../ShidToPatioCompilationUnitElementSpace.java | 19 + .../compiler/shidtopatio/ShidToPatioContext.java | 867 +++++++++++++++++ .../compiler/shidtopatio/ShidToPatioEffects.java | 505 ++++++++++ .../compiler/shidtopatio/ShidToPatioFunctions.java | 54 ++ .../compiler/shidtopatio/ShidToPatioGc.java | 208 ++++ .../compiler/shidtopatio/ShidToPatioInts.java | 156 +++ .../shidtopatio/ShidToPatioLocalSpace.java | 48 + .../shidtopatio/ShidToPatioNamespaces.java | 310 ++++++ .../compiler/shidtopatio/ShidToPatioResult.java | 4 + .../compiler/shidtopatio/ShidToPatioStrings.java | 84 ++ .../compiler/shidtopatio/ShidToPatioStructs.java | 200 ++++ .../compiler/shidtopatio/ShidToPatioTuples.java | 132 +++ .../compiler/shidtopatio/ShidToPatioTypes.java | 11 + .../compiler/shidtopatio/ShidToPatioVars.java | 80 ++ .../DuplicateCompilationUnitElementName.java | 17 + 37 files changed, 4029 insertions(+), 4029 deletions(-) delete mode 100644 src/main/java/org/shedlang/compiler/patio/PatioCodeGenClosures.java delete mode 100644 src/main/java/org/shedlang/compiler/patio/ShidToPatio.java delete mode 100644 src/main/java/org/shedlang/compiler/patio/ShidToPatioCompilationUnitElementSpace.java delete mode 100644 src/main/java/org/shedlang/compiler/patio/ShidToPatioContext.java delete mode 100644 src/main/java/org/shedlang/compiler/patio/ShidToPatioEffects.java delete mode 100644 src/main/java/org/shedlang/compiler/patio/ShidToPatioFunctions.java delete mode 100644 src/main/java/org/shedlang/compiler/patio/ShidToPatioGc.java delete mode 100644 src/main/java/org/shedlang/compiler/patio/ShidToPatioInts.java delete mode 100644 src/main/java/org/shedlang/compiler/patio/ShidToPatioLocalSpace.java delete mode 100644 src/main/java/org/shedlang/compiler/patio/ShidToPatioNamespaces.java delete mode 100644 src/main/java/org/shedlang/compiler/patio/ShidToPatioResult.java delete mode 100644 src/main/java/org/shedlang/compiler/patio/ShidToPatioStrings.java delete mode 100644 src/main/java/org/shedlang/compiler/patio/ShidToPatioStructs.java delete mode 100644 src/main/java/org/shedlang/compiler/patio/ShidToPatioTuples.java delete mode 100644 src/main/java/org/shedlang/compiler/patio/ShidToPatioTypes.java delete mode 100644 src/main/java/org/shedlang/compiler/patio/ShidToPatioVars.java delete mode 100644 src/main/java/org/shedlang/compiler/patio/errors/DuplicateCompilationUnitElementName.java create mode 100644 src/main/java/org/shedlang/compiler/shidtopatio/ShidToPatio.java create mode 100644 src/main/java/org/shedlang/compiler/shidtopatio/ShidToPatioClosures.java create mode 100644 src/main/java/org/shedlang/compiler/shidtopatio/ShidToPatioCompilationUnitElementSpace.java create mode 100644 src/main/java/org/shedlang/compiler/shidtopatio/ShidToPatioContext.java create mode 100644 src/main/java/org/shedlang/compiler/shidtopatio/ShidToPatioEffects.java create mode 100644 src/main/java/org/shedlang/compiler/shidtopatio/ShidToPatioFunctions.java create mode 100644 src/main/java/org/shedlang/compiler/shidtopatio/ShidToPatioGc.java create mode 100644 src/main/java/org/shedlang/compiler/shidtopatio/ShidToPatioInts.java create mode 100644 src/main/java/org/shedlang/compiler/shidtopatio/ShidToPatioLocalSpace.java create mode 100644 src/main/java/org/shedlang/compiler/shidtopatio/ShidToPatioNamespaces.java create mode 100644 src/main/java/org/shedlang/compiler/shidtopatio/ShidToPatioResult.java create mode 100644 src/main/java/org/shedlang/compiler/shidtopatio/ShidToPatioStrings.java create mode 100644 src/main/java/org/shedlang/compiler/shidtopatio/ShidToPatioStructs.java create mode 100644 src/main/java/org/shedlang/compiler/shidtopatio/ShidToPatioTuples.java create mode 100644 src/main/java/org/shedlang/compiler/shidtopatio/ShidToPatioTypes.java create mode 100644 src/main/java/org/shedlang/compiler/shidtopatio/ShidToPatioVars.java create mode 100644 src/main/java/org/shedlang/compiler/shidtopatio/errors/DuplicateCompilationUnitElementName.java (limited to 'src/main/java') diff --git a/src/main/java/org/shedlang/compiler/backends/PatioTextBackend.java b/src/main/java/org/shedlang/compiler/backends/PatioTextBackend.java index bff63368..d5ebb923 100644 --- a/src/main/java/org/shedlang/compiler/backends/PatioTextBackend.java +++ b/src/main/java/org/shedlang/compiler/backends/PatioTextBackend.java @@ -2,8 +2,8 @@ package org.shedlang.compiler.backends; import org.shedlang.compiler.backends.paths.TargetDir; import org.shedlang.compiler.config.ProjectConfig; -import org.shedlang.compiler.patio.ShidToPatio; -import org.shedlang.compiler.patio.ShidToPatioContext; +import org.shedlang.compiler.shidtopatio.ShidToPatio; +import org.shedlang.compiler.shidtopatio.ShidToPatioContext; import org.shedlang.compiler.patio.ast.PatioSerializer; import org.shedlang.compiler.shid.ShidNamespace; import org.shedlang.compiler.typechecker.TypeInfos; diff --git a/src/main/java/org/shedlang/compiler/backends/llvm/LlvmBackend.java b/src/main/java/org/shedlang/compiler/backends/llvm/LlvmBackend.java index 4d628d75..350ef267 100644 --- a/src/main/java/org/shedlang/compiler/backends/llvm/LlvmBackend.java +++ b/src/main/java/org/shedlang/compiler/backends/llvm/LlvmBackend.java @@ -15,8 +15,8 @@ import org.shedlang.compiler.backends.llvm.ir.ast.types.LlvmTypes; import org.shedlang.compiler.backends.paths.TargetDir; import org.shedlang.compiler.config.ProjectConfig; import org.shedlang.compiler.filesystem.ShedCompilerFiles; -import org.shedlang.compiler.patio.ShidToPatio; -import org.shedlang.compiler.patio.ShidToPatioContext; +import org.shedlang.compiler.shidtopatio.ShidToPatio; +import org.shedlang.compiler.shidtopatio.ShidToPatioContext; import org.shedlang.compiler.shid.ShidNamespace; import org.shedlang.compiler.sources.Sources; import org.shedlang.compiler.typechecker.TypeInfos; diff --git a/src/main/java/org/shedlang/compiler/backends/wasm/WasmBackend.java b/src/main/java/org/shedlang/compiler/backends/wasm/WasmBackend.java index a3e376c3..77eeee70 100644 --- a/src/main/java/org/shedlang/compiler/backends/wasm/WasmBackend.java +++ b/src/main/java/org/shedlang/compiler/backends/wasm/WasmBackend.java @@ -12,8 +12,8 @@ import org.shedlang.compiler.backends.wasm.structure.ast.modules.WasmFunction; import org.shedlang.compiler.backends.wasm.structure.ast.modules.WasmModule; import org.shedlang.compiler.config.ProjectConfig; import org.shedlang.compiler.filesystem.ShedCompilerFiles; -import org.shedlang.compiler.patio.ShidToPatio; -import org.shedlang.compiler.patio.ShidToPatioContext; +import org.shedlang.compiler.shidtopatio.ShidToPatio; +import org.shedlang.compiler.shidtopatio.ShidToPatioContext; import org.shedlang.compiler.shid.ShidNamespace; import org.shedlang.compiler.sources.Sources; import org.shedlang.compiler.typechecker.TypeInfos; diff --git a/src/main/java/org/shedlang/compiler/patio/PatioCodeGenClosures.java b/src/main/java/org/shedlang/compiler/patio/PatioCodeGenClosures.java deleted file mode 100644 index 3171e750..00000000 --- a/src/main/java/org/shedlang/compiler/patio/PatioCodeGenClosures.java +++ /dev/null @@ -1,315 +0,0 @@ -package org.shedlang.compiler.patio; - -import org.shedlang.compiler.ast.typed.FreeVariable; -import org.shedlang.compiler.ast.typed.FreeVariables; -import org.shedlang.compiler.patio.ast.PatioVisibility; -import org.shedlang.compiler.patio.ast.instructions.*; -import org.shedlang.compiler.patio.ast.operands.PatioFunctionPtr; -import org.shedlang.compiler.patio.ast.operands.PatioLocalRef; -import org.shedlang.compiler.patio.ast.operands.PatioOperand; -import org.shedlang.compiler.patio.ast.types.PatioDataLayout; -import org.shedlang.compiler.patio.ast.types.PatioDataLayouts; -import org.shedlang.compiler.patio.ast.types.PatioType; -import org.shedlang.compiler.patio.ast.types.PatioTypes; -import org.shedlang.compiler.shid.instructions.ShidDefineFunction; -import org.shedlang.compiler.sources.Source; -import org.shedlang.compiler.util.P; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.function.BiFunction; -import java.util.stream.Stream; - -import static org.shedlang.compiler.util.Iterables.sortedBy; - -class ShidToPatioClosures { - public static final PatioType CLOSURE_POINTER_TYPE = PatioTypes.DATA_POINTER; - public static final PatioType CLOSURE_TYPE = ShidToPatioTypes.VALUE_TYPE; - - private ShidToPatioClosures() {} - - private static PatioDataLayout closureDataLayoutForCall() { - return ShidToPatioGc.gcObjectDataLayout(PatioDataLayouts.struct(List.of( - PatioDataLayouts.FUNCTION_POINTER - ))); - } - - static PatioDataLayout closureDataLayout( - PatioDataLayout additional, - FreeVariables freeVariables, - ShidToPatioContext context - ) { - return ShidToPatioGc.gcObjectDataLayout(PatioDataLayouts.struct(List.of( - PatioDataLayouts.FUNCTION_POINTER, - additional, - PatioDataLayouts.struct( - freeVariables.stream() - .map(freeVariable -> PatioDataLayouts.fromType( - context.shidLocalType(freeVariable.name()) - )) - .toList() - ) - ))); - } - - static final List FUNCTION_POINTER_OFFSET - = ShidToPatioGc.gcObjectOffset(List.of(0)); - - static List additionalOffset(List offset) { - return ShidToPatioGc.gcObjectOffset(P.vector(1).plusAll(offset)); - } - - private static List freeVariableOffset( - FreeVariable freeVariable - ) { - return ShidToPatioGc.gcObjectOffset(List.of(2, freeVariable.index())); - } - - private static final List GC_CHILDREN_OFFSET = - ShidToPatioGc.gcObjectOffset(List.of(2)); - - static ShidToPatioContext defineParams( - List positionalParams, - List namedParams, - ShidToPatioContext bodyContext - ) { - var orderedNamedParams = sortedBy(namedParams, param -> param.name()); - var shidParams = Stream.concat(positionalParams.stream(), orderedNamedParams.stream()).toList(); - - for (var shidParam : shidParams) { - bodyContext = bodyContext.defineShidParam(shidParam.name()); - } - - return bodyContext; - } - - static ShidToPatioContext create( - PatioLocalRef target, - ShidToPatioCompilationUnitElementSpace functionElementSpace, - String name, - List positionalParams, - List namedParams, - PatioDataLayout layout, - BiFunction storeAdditional, - FreeVariables freeVariables, - BiFunction generateBody, - Source source, - ShidToPatioContext context - ) { - var fullNameResult = context.allocateCompilationUnitElementName( - functionElementSpace, - name - ); - var fullName = fullNameResult.value(); - context = fullNameResult.context(); - - var bodyContextParent = context; - context = context.createFunction(fullName, PatioVisibility.PRIVATE, ShidToPatioTypes.VALUE_TYPE, source, bodyContext -> { - var closurePointerResult = bodyContext.allocateParam( - ShidToPatioLocalSpace.CLOSURE_POINTER, - ShidToPatioClosures.CLOSURE_POINTER_TYPE - ); - var closurePointer = closurePointerResult.value(); - bodyContext = closurePointerResult.context(); - - bodyContext = defineParams(positionalParams, namedParams, bodyContext); - - bodyContext = loadFreeVariables( - freeVariables, - closurePointer, - layout, - source, - bodyContext, - bodyContextParent - ); - - bodyContext = ShidToPatioGc.saveGcRootStack(source, bodyContext); - - bodyContext = generateBody.apply(closurePointer, bodyContext); - - return bodyContext; - }); - - context = ShidToPatioClosures.alloc( - target, - name, - fullName, - layout, - storeAdditional, - freeVariables, - source, - context - ); - - return context; - } - - static ShidToPatioContext alloc( - PatioLocalRef target, - String name, - String functionName, - PatioDataLayout layout, - BiFunction storeAdditional, - FreeVariables freeVariables, - Source source, - ShidToPatioContext context - ) { - var closurePointerResult = context.allocateVal( - ShidToPatioLocalSpace.CLOSURE_POINTER, - name, - PatioTypes.DATA_POINTER - ); - var closurePointer = closurePointerResult.value(); - context = closurePointerResult.context(); - - context = ShidToPatioGc.alloc( - closurePointer, - layout, - GC_CHILDREN_OFFSET, - freeVariables.size(), - source, - context - ); - - context = context.addInstruction(new PatioMemoryStore( - closurePointer, - layout, - FUNCTION_POINTER_OFFSET, - new PatioFunctionPtr(functionName), - source - )); - - context = storeAdditional.apply(closurePointer, context); - - context = storeFreeVariables( - freeVariables, - closurePointer, - layout, - source, - context - ); - - context = context.addInstruction(new PatioDataPtrToInt( - target, - closurePointer, - source - )); - - return context; - } - - static ShidToPatioContext storeFreeVariables( - FreeVariables freeVariables, - PatioLocalRef closurePointer, - PatioDataLayout closureLayout, - Source source, - ShidToPatioContext context - ) { - for (var freeVariable : freeVariables) { - context = context.onceShidLocalDefined( - freeVariable.name(), - c -> c.addInstruction(new PatioMemoryStore( - closurePointer, - closureLayout, - freeVariableOffset(freeVariable), - c.shidLocalNameToLocal(freeVariable.name()), - source - )) - ); - } - return context; - } - - static ShidToPatioContext loadFreeVariables( - FreeVariables freeVariables, - PatioLocalRef closurePointer, - PatioDataLayout closureLayout, - Source source, - ShidToPatioContext bodyContext, - ShidToPatioContext bodyContextParent - ) { - for (var freeVariable : freeVariables) { - var freeVariableLocalResult = bodyContext.declareShidVal( - freeVariable.name(), - bodyContextParent.shidLocalType(freeVariable.name()) - ); - var freeVariableLocal = freeVariableLocalResult.value(); - bodyContext = freeVariableLocalResult.context(); - - bodyContext = bodyContext.addInstruction(new PatioMemoryLoad( - freeVariableLocal, - closurePointer, - closureLayout, - freeVariableOffset(freeVariable), - source - )); - - bodyContext = bodyContext.initShidLocal(freeVariable.name()); - } - return bodyContext; - } - - static ShidToPatioContext beforeExit( - List escapees, - Source source, - ShidToPatioContext context - ) { - return ShidToPatioGc.restoreGcRootStack(escapees, source, context); - } - - static ShidToPatioContext call( - PatioLocalRef target, - PatioLocalRef closure, - List positionalArgs, - List> namedArgsByName, - Source source, - ShidToPatioContext context - ) { - var closurePointerResult = context.allocateVal( - ShidToPatioLocalSpace.CLOSURE_POINTER, - CLOSURE_POINTER_TYPE - ); - var closurePointer = closurePointerResult.value(); - context = closurePointerResult.context(); - - context = context.addInstruction(new PatioIntToDataPtr( - closurePointer, - closure, - source - )); - - var functionPointerResult = context.allocateVal( - ShidToPatioLocalSpace.CALL_FUNCTION_POINTER, - PatioTypes.FUNCTION_POINTER - ); - var functionPointer = functionPointerResult.value(); - context = functionPointerResult.context(); - - context = context.addInstruction(new PatioMemoryLoad( - functionPointer, - closurePointer, - closureDataLayoutForCall(), - FUNCTION_POINTER_OFFSET, - source - )); - - var args = new ArrayList(); - - args.add(closurePointer); - - args.addAll(positionalArgs); - - for (var namedArg : sortedBy(namedArgsByName, x -> x.getKey())) { - args.add(namedArg.getValue()); - } - - return context - .addInstruction(new PatioCallPointer( - target, - functionPointer, - args, - source - )); - } -} diff --git a/src/main/java/org/shedlang/compiler/patio/ShidToPatio.java b/src/main/java/org/shedlang/compiler/patio/ShidToPatio.java deleted file mode 100644 index 49fd0e03..00000000 --- a/src/main/java/org/shedlang/compiler/patio/ShidToPatio.java +++ /dev/null @@ -1,1013 +0,0 @@ -package org.shedlang.compiler.patio; - -import org.shedlang.compiler.patio.ast.PatioCompilationUnit; -import org.shedlang.compiler.patio.ast.PatioVisibility; -import org.shedlang.compiler.patio.ast.instructions.*; -import org.shedlang.compiler.patio.ast.operands.PatioInt; -import org.shedlang.compiler.patio.ast.operands.PatioLocalRef; -import org.shedlang.compiler.patio.ast.operands.PatioOperand; -import org.shedlang.compiler.patio.ast.types.PatioTypes; -import org.shedlang.compiler.shid.ShidNamespace; -import org.shedlang.compiler.shid.instructions.*; -import org.shedlang.compiler.sources.Source; -import org.shedlang.compiler.sources.Sources; -import org.shedlang.compiler.types.NamespaceName; - -import java.util.*; -import java.util.function.Function; - -import static org.shedlang.compiler.config.MainFunction.MAIN_FUNCTION_NAME; - -public class ShidToPatio { - private ShidToPatio() {} - - /** - * Generate a main function by importing the given namespace and calling the - * {@code main} field with no arguments. Callers are responsible for - * ensuring that such a field exists. - */ - public static ShidToPatioResult generateMain( - NamespaceName main, - Source source, - ShidToPatioContext context - ) { - var mainFunctionNameResult = context.allocateCompilationUnitElementName( - ShidToPatioCompilationUnitElementSpace.MAIN - ); - var mainFunctionName = mainFunctionNameResult.value(); - context = mainFunctionNameResult.context(); - - context = context.createFunction( - mainFunctionName, - PatioVisibility.PRIVATE, - PatioTypes.INT, - source, - mainContext -> { - var namespaceValueResult = mainContext.allocateVal( - ShidToPatioLocalSpace.NAMESPACE_VALUE, - ShidToPatioTypes.VALUE_TYPE - ); - var namespaceValue = namespaceValueResult.value(); - mainContext = namespaceValueResult.context(); - - mainContext = ShidToPatioNamespaces.importValue( - namespaceValue, - main, - source, - mainContext - ); - - var mainFieldResult = mainContext.allocateVal( - ShidToPatioLocalSpace.MAIN, - ShidToPatioTypes.VALUE_TYPE - ); - var mainField = mainFieldResult.value(); - mainContext = mainFieldResult.context(); - - mainContext = ShidToPatioNamespaces.fieldLoad( - mainField, - namespaceValue, - main, - MAIN_FUNCTION_NAME, - source, - mainContext - ); - - var exitCodeResult = mainContext.allocateVal( - ShidToPatioLocalSpace.MAIN, - ShidToPatioTypes.VALUE_TYPE - ); - var exitCode = exitCodeResult.value(); - mainContext = exitCodeResult.context(); - - mainContext = ShidToPatioClosures.call( - exitCode, - mainField, - List.of(), - List.of(), - source, - mainContext - ); - - mainContext = mainContext.addInstruction( - new PatioReturn(exitCode, source) - ); - - return mainContext; - } - ); - - return context.toResult(mainFunctionName); - } - - public static PatioCompilationUnit generateNamespace( - ShidNamespace shidNamespace, - ShidToPatioContext context - ) { - context = ShidToPatioNamespaces.define( - shidNamespace.namespaceName(), - initContext -> - generateBlockNoResults(shidNamespace.body(), initContext), - context - ); - - // TODO: set more appropriate source - return context.toCompilationUnit(Sources.NULL); - } - - public static ShidToPatioContext generateInstructions( - List shidInstructions, - ShidToPatioContext context - ) { - for (var shidInstruction : shidInstructions) { - context = generateInstruction(shidInstruction, context); - } - - return context; - } - - public static ShidToPatioContext generateInstruction( - ShidInstruction shidInstruction, - ShidToPatioContext context - ) { - return switch (shidInstruction) { - case ShidBlock shidBlock -> { - var patioBlockResult = generateBlock(shidBlock, context); - var patioBlock = patioBlockResult.value(); - context = patioBlockResult.context(); - - for (var instruction : patioBlock.body()) { - context = context.addInstruction(instruction); - } - - for (var result : patioBlock.results()) { - context = context.temporaryPush(result); - } - - yield context; - } - - case ShidCall call -> { - var namedArgsByName = new ArrayList>(); - for (var argName : call.namedArgNames().reversed()) { - var argResult = context.allocateVal( - ShidToPatioLocalSpace.CALL_ARG_NAMED, - argName, - ShidToPatioTypes.VALUE_TYPE - ); - var arg = argResult.value(); - context = argResult.context(); - - context = context.temporaryPopIntoLocal( - arg, - shidInstruction.source() - ); - - namedArgsByName.add(Map.entry(argName, arg)); - } - - var positionalArgs = new ArrayList(); - for (var i = 0; i < call.positionalArgCount(); i++) { - var argResult = context.allocateVal( - ShidToPatioLocalSpace.CALL_ARG_POSITIONAL, - Integer.toString(call.positionalArgCount() - i - 1), - ShidToPatioTypes.VALUE_TYPE - ); - var arg = argResult.value(); - context = argResult.context(); - - context = context.temporaryPopIntoLocal( - arg, - shidInstruction.source() - ); - - positionalArgs.add(arg); - } - Collections.reverse(positionalArgs); - - var receiverResult = context.allocateVal( - ShidToPatioLocalSpace.RECEIVER, - ShidToPatioTypes.VALUE_TYPE - ); - var receiver = receiverResult.value(); - context = receiverResult.context(); - - context = context.temporaryPopIntoLocal( - receiver, - shidInstruction.source() - ); - - var targetResult = context.allocateVal( - ShidToPatioLocalSpace.TEMPORARY, - ShidToPatioTypes.VALUE_TYPE - ); - var target = targetResult.value(); - context = targetResult.context(); - - yield ShidToPatioClosures.call( - target, - receiver, - positionalArgs, - namedArgsByName, - shidInstruction.source(), - context - ).temporaryPush(target); - } - - case ShidDefineEffect defineEffect -> { - var targetResult = context.allocateVal( - ShidToPatioLocalSpace.USER_DEFINED_EFFECT, - defineEffect.effect().name(), - ShidToPatioTypes.VALUE_TYPE - ); - var target = targetResult.value(); - context = targetResult.context(); - - context = ShidToPatioEffects.createUserDefinedEffect( - target, - defineEffect.effect(), - defineEffect.source(), - context - ); - - context = context.temporaryPush(target); - - yield context; - } - - case ShidDefineFunction defineFunction -> { - var targetResult = context.allocateVal( - ShidToPatioLocalSpace.CLOSURE, - defineFunction.name(), - ShidToPatioTypes.VALUE_TYPE - ); - var target = targetResult.value(); - context = targetResult.context(); - - Function generateBody = functionContext -> { - return generateBlockNoResults(defineFunction.body(), functionContext); - }; - - context = switch (defineFunction.variant()) { - case EFFECT_HANDLER_METHOD -> ShidToPatioEffects.createEffectHandlerMethod( - target, - defineFunction.name(), - defineFunction.positionalParams(), - defineFunction.namedParams(), - defineFunction.freeVariables(), - generateBody, - defineFunction.source(), - context - ); - case FUNCTION -> ShidToPatioFunctions.create( - target, - defineFunction.name(), - defineFunction.positionalParams(), - defineFunction.namedParams(), - defineFunction.freeVariables(), - generateBody, - defineFunction.source(), - context - ); - }; - - context = context.temporaryPush(target); - - yield context; - } - - case ShidDefineStruct defineStruct -> { - var targetResult = context.allocateVal( - ShidToPatioLocalSpace.STRUCT_TYPE, - defineStruct.type().name(), - ShidToPatioTypes.VALUE_TYPE - ); - var target = targetResult.value(); - context = targetResult.context(); - - context = ShidToPatioStructs.createType( - target, - defineStruct.type(), - defineStruct.fields(), - defineStruct.source(), - context - ); - - context = context.temporaryPush(target); - - yield context; - } - - case ShidDiscard discard -> - context.temporaryPop().context(); - - case ShidDuplicate duplicate -> { - var valueResult = context.temporaryPop(); - var value = valueResult.value(); - context = valueResult.context(); - - yield context.temporaryPush(value).temporaryPush(value); - } - - case ShidEffectHandlerBreak effectHandlerBreak -> { - var valueResult = context.temporaryPop(); - var value = valueResult.value(); - context = valueResult.context(); - - context = ShidToPatioEffects.break_( - effectHandlerBreak.effect(), - value, - effectHandlerBreak.source(), - context - ); - - yield context; - } - - case ShidFieldLoad fieldLoad -> { - var receiverResult = context.temporaryPop(); - var receiver = receiverResult.value(); - context = receiverResult.context(); - - var targetResult = context.allocateVal( - ShidToPatioLocalSpace.TEMPORARY, - fieldLoad.fieldName(), - ShidToPatioTypes.VALUE_TYPE - ); - var target = targetResult.value(); - context = targetResult.context(); - - switch (fieldLoad.receiver()) { - case ShidFieldLoad.Receiver.Effect receiverEffect -> { - context = ShidToPatioEffects.fieldLoad( - target, - receiver, - receiverEffect.effect(), - fieldLoad.fieldName(), - fieldLoad.source(), - context - ); - } - - case ShidFieldLoad.Receiver.Namespace receiverNamespace -> { - context = ShidToPatioNamespaces.fieldLoad( - target, - receiver, - receiverNamespace.name(), - fieldLoad.fieldName(), - fieldLoad.source(), - context - ); - } - - case ShidFieldLoad.Receiver.Struct receiverStruct -> { - context = ShidToPatioStructs.fieldLoad( - target, - receiver, - receiverStruct.type(), - fieldLoad.fieldName(), - fieldLoad.source(), - context - ); - } - } - - context = context.temporaryPush(target); - - yield context; - } - - case ShidIf if_ -> { - var conditionBoolResult = generateCondition(if_.source(), context); - var conditionBool = conditionBoolResult.value(); - context = conditionBoolResult.context(); - - var targets = new ArrayList(); - - for (var i = 0; i < if_.resultCount(); i++) { - var targetResult = context.allocateVal( - ShidToPatioLocalSpace.TEMPORARY, - ShidToPatioTypes.VALUE_TYPE - ); - var target = targetResult.value(); - context = targetResult.context(); - - targets.add(target); - } - - var trueBodyResult = generateBlock(if_.trueBody(), context); - var trueBody = trueBodyResult.value(); - context = trueBodyResult.context(); - - var falseBodyResult = generateBlock(if_.falseBody(), context); - var falseBody = falseBodyResult.value(); - context = falseBodyResult.context(); - - context = context.addInstruction(new PatioIf( - targets, - conditionBool, - trueBody, - falseBody, - if_.source() - )); - - for (var target : targets) { - context = context.temporaryPush(target); - } - - yield context; - } - - case ShidIntAdd intAdd -> - generateBinaryOperation( - (target, left, right, operationContext) -> - ShidToPatioInts.add( - target, - left, - right, - intAdd.source(), - operationContext - ), - context - ); - - case ShidIntEquals intEquals -> - generateComparison( - (target, left, right, operationContext) -> - ShidToPatioInts.equals( - target, - left, - right, - intEquals.source(), - operationContext - ), - intEquals.source(), - context - ); - - case ShidIntNotEqual intNotEqual -> - generateComparison( - (target, left, right, operationContext) -> - ShidToPatioInts.notEqual( - target, - left, - right, - intNotEqual.source(), - operationContext - ), - intNotEqual.source(), - context - ); - - case ShidIntSub intSub -> - generateBinaryOperation( - (target, left, right, operationContext) -> - ShidToPatioInts.sub( - target, - left, - right, - intSub.source(), - operationContext - ), - context - ); - - case ShidLocalDrop localDrop -> { - yield context; - } - - case ShidLocalLoad localLoad -> { - var local = context.shidLocalNameToLocal(localLoad.name()); - - yield context.temporaryPush(local); - } - - case ShidLocalStore localStore -> { - context = context.temporaryPopIntoLocal( - context.shidLocalNameToLocal(localStore.name()), - localStore.source() - ); - - context = context.initShidLocal(localStore.name()); - - yield context; - } - - case ShidLoopBreak loopBreak -> - context.addInstruction(new PatioLoopBreak(loopBreak.source())); - - case ShidLoopContinue loopContinue -> - context.addInstruction(new PatioLoopContinue(loopContinue.source())); - - case ShidLoop loop -> { - context = context.enterBlock(); - context = generateBlockNoResults(loop.body(), context); - - var bodyInstructionsResult = context.exitBlock(); - var bodyInstructions = bodyInstructionsResult.value(); - context = bodyInstructionsResult.context(); - - context = context.addInstruction(new PatioLoop(bodyInstructions, loop.source())); - - yield context; - } - - case ShidNamespaceFieldStore namespaceFieldStore -> { - var fieldValueResult = context.temporaryPop(); - var fieldValue = fieldValueResult.value(); - context = fieldValueResult.context(); - - context = ShidToPatioNamespaces.fieldStore( - namespaceFieldStore.namespaceName(), - namespaceFieldStore.fieldName(), - fieldValue, - namespaceFieldStore.source(), - context - ); - - yield context; - } - - case ShidNamespaceImport namespaceImport -> { - var namespaceValueResult = context.allocateVal( - ShidToPatioLocalSpace.NAMESPACE_VALUE, - ShidToPatioNamespaces.NAMESPACE_VALUE_TYPE - ); - var namespaceValue = namespaceValueResult.value(); - context = namespaceValueResult.context(); - - context = ShidToPatioNamespaces.importValue( - namespaceValue, - namespaceImport.namespaceName(), - namespaceImport.source(), - context - ); - - context = context.temporaryPush(namespaceValue); - - yield context; - } - - case ShidPushBool pushBool -> - pushValue(pushBool.value() ? 1 : 0, pushBool.source(), context); - - case ShidPushInt pushInt -> { - var targetResult = context.allocateVal( - ShidToPatioLocalSpace.INT, - ShidToPatioInts.INT_TYPE - ); - var target = targetResult.value(); - context = targetResult.context(); - - context = ShidToPatioInts.storeConst( - target, - pushInt.value(), - pushInt.source(), - context - ); - - context = context.temporaryPush(target); - - yield context; - } - - - case ShidPushString pushString -> { - var stringPtrOperandResult = ShidToPatioStrings.define( - pushString.value(), - pushString.source(), - context - ); - var stringPtrOperand = stringPtrOperandResult.value(); - context = stringPtrOperandResult.context(); - - var stringPtrResult = context.allocateVal( - ShidToPatioLocalSpace.STRING, - ShidToPatioTypes.VALUE_TYPE - ); - var stringPtr = stringPtrResult.value(); - context = stringPtrResult.context(); - - context = context.addInstruction(new PatioDataPtrToInt( - stringPtr, - stringPtrOperand, - pushString.source() - )); - - context = context.temporaryPush(stringPtr); - - yield context; - } - - case ShidPushUnit pushUnit -> - pushValue(0, pushUnit.source(), context); - - case ShidResume resume -> { - var valueResult = context.temporaryPop(); - var value = valueResult.value(); - context = valueResult.context(); - - context = ShidToPatioClosures.beforeExit( - List.of(value), - resume.source(), - context - ); - - yield ShidToPatioEffects.resume(value, resume.source(), context); - } - - case ShidReturn return_ -> { - var valueResult = context.temporaryPop(); - var value = valueResult.value(); - context = valueResult.context(); - - for (var onReturnInstruction : context.onReturn()) { - context = context.addInstruction(onReturnInstruction); - } - - - context = ShidToPatioClosures.beforeExit( - List.of(value), - return_.source(), - context - ); - - yield context.addInstruction(new PatioReturn(value, return_.source())); - } - - case ShidStringAdd stringAdd -> - generateBinaryOperation( - (target, left, right, operationContext) -> - ShidToPatioStrings.add( - target, - left, - right, - stringAdd.source(), - operationContext - ), - context - ); - - case ShidSwitch switch_ -> { - var targetResult = context.allocateVal( - ShidToPatioLocalSpace.TEMPORARY, - ShidToPatioTypes.VALUE_TYPE - ); - var target = targetResult.value(); - context = targetResult.context(); - - var valueResult = context.temporaryPop(); - var value = valueResult.value(); - context = valueResult.context(); - - var tagResult = context.allocateVal( - ShidToPatioLocalSpace.SWITCH_TAG, - ShidToPatioTypes.TAG_TYPE - ); - var tag = tagResult.value(); - context = tagResult.context(); - - context = ShidToPatioStructs.tagLoad( - tag, - value, - switch_.source(), - context - ); - - var cases = new ArrayList(); - - for (var shidCase : switch_.cases()) { - var bodyResult = generateBlock( - shidCase.body(), - context - ); - var body = bodyResult.value(); - context = bodyResult.context(); - - cases.add(new PatioSwitch.Case( - context.structTag(shidCase.caseType()), - body, - shidCase.source() - )); - } - - context = context.addInstruction(new PatioSwitch( - List.of(target), - tag, - cases, - new PatioBlock( - List.of( - new PatioUnreachable(switch_.source()) - ), - List.of(), - switch_.source() - ), - switch_.source() - )); - - context = context.temporaryPush(target); - - yield context; - } - - case ShidTry try_ -> { - var handlerMethodsByName = new HashMap(); - - for (var handlerMethodName : try_.handlerMethodNames().reversed()) { - var handlerMethodResult = context.temporaryPop(); - var handlerMethod = handlerMethodResult.value(); - context = handlerMethodResult.context(); - - handlerMethodsByName.put(handlerMethodName, handlerMethod); - } - - var targetResult = context.allocateVal( - ShidToPatioLocalSpace.TEMPORARY, - ShidToPatioTypes.VALUE_TYPE - ); - var target = targetResult.value(); - context = targetResult.context(); - - context = ShidToPatioEffects.try_( - target, - try_.handledEffect(), - handlerMethodsByName, - bodyContext -> - generateBlock(try_.body(), bodyContext), - try_.source(), - context - ); - - context = context.temporaryPush(target); - - yield context; - } - - case ShidTupleCreate tupleCreate -> { - var elements = new ArrayList(); - - for (var elementIndex = tupleCreate.elementCount(); elementIndex --> 0;) { - var tupleElementResult = context.allocateVal( - ShidToPatioLocalSpace.TUPLE_ELEMENT, - Integer.toString(elementIndex), - ShidToPatioTypes.VALUE_TYPE - ); - var tupleElement = tupleElementResult.value(); - context = tupleElementResult.context(); - - context = context.temporaryPopIntoLocal(tupleElement, tupleCreate.source()); - - elements.add(tupleElement); - } - - Collections.reverse(elements); - - var tupleResult = ShidToPatioTuples.create(elements, tupleCreate.source(), context); - var tuple = tupleResult.value(); - context = tupleResult.context(); - - yield context.temporaryPush(tuple); - } - - case ShidTupleGet tupleGet -> { - var tupleResult = context.temporaryPop(); - var tuple = tupleResult.value(); - context = tupleResult.context(); - - var targetResult = ShidToPatioTuples.get( - tuple, - tupleGet.elementIndex(), - tupleGet.elementCount(), - tupleGet.source(), - context - ); - var target = targetResult.value(); - context = targetResult.context(); - - yield context.temporaryPush(target); - } - - case ShidVarLoad varLoad -> { - var varValueResult = context.allocateVal( - ShidToPatioLocalSpace.VAR_VALUE, - varLoad.name(), - ShidToPatioTypes.VALUE_TYPE - ); - var varValue = varValueResult.value(); - context = varValueResult.context(); - - context = ShidToPatioVars.load( - varValue, - varLoad.name(), - varLoad.source(), - context - ); - - context = context.temporaryPush(varValue); - - yield context; - } - - case ShidVarStore varStore -> { - var valueResult = context.temporaryPop(); - var value = valueResult.value(); - context = valueResult.context(); - - context = ShidToPatioVars.store( - varStore.name(), - value, - varStore.source(), - context - ); - - yield context; - } - }; - } - - interface BinaryOperationCodeGen { - ShidToPatioContext generate( - PatioLocalRef target, - PatioOperand left, - PatioOperand right, - ShidToPatioContext context - ); - } - - private static ShidToPatioContext generateComparison( - BinaryOperationCodeGen binaryOperationCodeGen, - Source source, - ShidToPatioContext context - ) { - return generateBinaryOperation( - (target, left, right, operationContext) -> { - var targetBoolResult = operationContext.allocateVal( - ShidToPatioLocalSpace.TEMPORARY, - PatioTypes.INT - ); - var targetBool = targetBoolResult.value(); - operationContext = targetBoolResult.context(); - - operationContext = binaryOperationCodeGen.generate( - targetBool, - left, - right, - operationContext - ); - - operationContext = operationContext.addInstruction(new PatioBoolToInt( - target, - targetBool, - source - )); - - return operationContext; - }, - context - ); - } - - private static ShidToPatioContext generateBinaryOperation( - BinaryOperationCodeGen binaryOperationCodeGen, - ShidToPatioContext context - ) { - var rightResult = context.temporaryPop(); - var right = rightResult.value(); - context = rightResult.context(); - - var leftResult = context.temporaryPop(); - var left = leftResult.value(); - context = leftResult.context(); - - var targetResult = context.allocateVal( - ShidToPatioLocalSpace.BINARY_OP_RESULT, - ShidToPatioTypes.VALUE_TYPE - ); - var target = targetResult.value(); - context = targetResult.context(); - - return binaryOperationCodeGen.generate( - target, - left, - right, - context - ).temporaryPush(target); - } - - private static ShidToPatioContext generateBlockNoResults( - ShidBlock shidBlock, - ShidToPatioContext context - ) { - // TODO: just use a block in Patio instructions even where there are no targets? - var blockResult = generateBlock(shidBlock, context); - var block = blockResult.value(); - context = blockResult.context(); - - if (!block.results().isEmpty()) { - // TODO: better error - throw new RuntimeException("block has results"); - } - - for (var instruction : block.body()) { - context = context.addInstruction(instruction); - } - - return context; - } - - private static ShidToPatioResult generateBlock( - ShidBlock shidBlock, - ShidToPatioContext context - ) { - context = context.enterBlock(); - - context = declareShidVariables(shidBlock, context); - - for (var shidInstruction : shidBlock.instructions()) { - context = generateInstruction(shidInstruction, context); - } - - var targetsResult = context.temporaryPopAll(); - var targets = targetsResult.value().reversed(); - context = targetsResult.context(); - - var instructionsResult = context.exitBlock(); - var instructions = instructionsResult.value(); - context = instructionsResult.context(); - - return context.toResult(new PatioBlock( - instructions, - targets, - shidBlock.source() - )); - } - - private static ShidToPatioResult generateCondition( - Source source, - ShidToPatioContext context - ) { - var conditionIntResult = context.allocateVal( - ShidToPatioLocalSpace.TEMPORARY, - "conditionInt", - PatioTypes.INT - ); - var conditionInt = conditionIntResult.value(); - context = conditionIntResult.context(); - - context = context.temporaryPopIntoLocal(conditionInt, source); - - var conditionBoolResult = context.allocateVal( - ShidToPatioLocalSpace.TEMPORARY, - "conditionBool", - PatioTypes.BOOL - ); - var conditionBool = conditionBoolResult.value(); - context = conditionBoolResult.context(); - - context = context.addInstruction(new PatioIntToBool( - conditionBool, - conditionInt, - source - )); - - return context.toResult(conditionBool); - } - - private static ShidToPatioContext declareShidVariables( - ShidBlock body, - ShidToPatioContext context - ) { - for (var boundVariable : body.boundVariables()) { - switch (boundVariable.variant()) { - case PARAM -> { - // Params should be defined by the containing function. - } - case VAL -> { - context = context.declareShidVal( - boundVariable.name(), - ShidToPatioTypes.VALUE_TYPE - ).context(); - } - case VAR -> { - context = ShidToPatioVars.alloc( - boundVariable.name(), - // TODO: proper source (probably by storing variables on the function/namespace) - Sources.NULL, - context - ); - } - } - } - return context; - } - - private static ShidToPatioContext pushValue(int value, Source source, ShidToPatioContext context) { - var localResult = context.allocateVal(ShidToPatioLocalSpace.TEMPORARY, ShidToPatioTypes.VALUE_TYPE); - var local = localResult.value(); - context = localResult.context(); - - return context - .addInstruction(new PatioLocalStore(local, new PatioInt(value), source)) - .temporaryPush(local); - } -} diff --git a/src/main/java/org/shedlang/compiler/patio/ShidToPatioCompilationUnitElementSpace.java b/src/main/java/org/shedlang/compiler/patio/ShidToPatioCompilationUnitElementSpace.java deleted file mode 100644 index 3b95e99a..00000000 --- a/src/main/java/org/shedlang/compiler/patio/ShidToPatioCompilationUnitElementSpace.java +++ /dev/null @@ -1,19 +0,0 @@ -package org.shedlang.compiler.patio; - -public enum ShidToPatioCompilationUnitElementSpace { - EFFECT_HANDLER_METHOD("effectHandlerMethod"), - FUNCTION("function"), - MAIN("main"), - STRING("string"); - - private final String name; - - ShidToPatioCompilationUnitElementSpace(String name) { - this.name = name; - } - - @Override - public String toString() { - return name; - } -} diff --git a/src/main/java/org/shedlang/compiler/patio/ShidToPatioContext.java b/src/main/java/org/shedlang/compiler/patio/ShidToPatioContext.java deleted file mode 100644 index dfbcaf77..00000000 --- a/src/main/java/org/shedlang/compiler/patio/ShidToPatioContext.java +++ /dev/null @@ -1,867 +0,0 @@ -package org.shedlang.compiler.patio; - -import org.pcollections.OrderedPMap; -import org.pcollections.PMap; -import org.pcollections.PStack; -import org.pcollections.PVector; -import org.shedlang.compiler.backends.NameAllocator; -import org.shedlang.compiler.patio.ast.*; -import org.shedlang.compiler.patio.ast.instructions.PatioInstruction; -import org.shedlang.compiler.patio.ast.instructions.PatioLocalStore; -import org.shedlang.compiler.patio.ast.operands.PatioLocalRef; -import org.shedlang.compiler.patio.ast.operands.PatioOperand; -import org.shedlang.compiler.patio.ast.types.PatioDataValue; -import org.shedlang.compiler.patio.ast.types.PatioType; -import org.shedlang.compiler.patio.errors.DuplicateCompilationUnitElementName; -import org.shedlang.compiler.sources.Source; -import org.shedlang.compiler.typechecker.TypeInfos; -import org.shedlang.compiler.types.*; -import org.shedlang.compiler.util.CheckReturnValue; -import org.shedlang.compiler.util.P; - -import java.util.ArrayList; -import java.util.List; -import java.util.Optional; -import java.util.function.Function; - -public record ShidToPatioContext( - GlobalContext globalContext, - CompilationUnitContext compilationUnitContext, - PStack blockStack, - FunctionContext functionContext -) { - public record GlobalContext( - TypeInfos typeInfos, - PMap structTags, - PMap effectTags - ) { - public static final GlobalContext EMPTY = forTypeInfos(TypeInfos.EMPTY); - - @CheckReturnValue - public static GlobalContext forTypeInfos(TypeInfos typeInfos) { - var structTags = generateStructTags(typeInfos); - var effectTags = generateEffectTags(typeInfos); - - return new GlobalContext( - typeInfos, - structTags, - effectTags - ); - } - - @CheckReturnValue - private static PMap generateStructTags(TypeInfos typeInfos) { - var tags = P.map(); - var nextTag = 0; - for (var structType : typeInfos.structTypes()) { - tags = tags.plus(structType, nextTag); - nextTag++; - } - return tags; - } - - @CheckReturnValue - private static PMap generateEffectTags(TypeInfos typeInfos) { - var tags = P.map(); - var nextTag = 0; - for (var effect : typeInfos.userDefinedEffects()) { - tags = tags.plus(effect, nextTag); - nextTag++; - } - return tags; - } - - @CheckReturnValue - public NamespaceTypeInfo namespaceTypeInfo(NamespaceName namespaceName) { - return typeInfos.namespaceTypeInfo(namespaceName) - // TODO: throw better error - .orElseThrow(() -> new RuntimeException("No type info for: " + namespaceName)); - } - - @CheckReturnValue - public StructTypeInfo structTypeInfo(StructType type) { - return typeInfos.structTypeInfo(type) - // TODO: throw better error - .orElseThrow(() -> new RuntimeException("No type info for: " + type)); - } - - @CheckReturnValue - public int structTag(StructType type) { - var tag = this.structTags.get(type); - if (tag == null) { - // TODO: throw better error - throw new RuntimeException("No tag for: " + type); - } else { - return tag; - } - } - - @CheckReturnValue - public UserDefinedEffectInfo userDefinedEffectInfo(UserDefinedEffect effect) { - return typeInfos.userDefinedEffectInfo(effect) - // TODO: throw better error - .orElseThrow(() -> new RuntimeException("No effect info for: " + effect)); - } - - @CheckReturnValue - public int effectTag(UserDefinedEffect effect) { - var tag = this.effectTags.get(effect); - if (tag == null) { - // TODO: throw better error - throw new RuntimeException("No tag for: " + effect); - } else { - return tag; - } - } - } - - public record CompilationUnitContext( - OrderedPMap elementsByName - ) { - public static CompilationUnitContext EMPTY = new CompilationUnitContext(OrderedPMap.empty()); - - @CheckReturnValue - public CompilationUnitContext addElement(PatioCompilationUnitElement element) { - // TODO: handle existing element with name. - return new CompilationUnitContext( - this.elementsByName.plus(element.name(), element) - ); - } - - @CheckReturnValue - private Result toResult(T value) { - return new Result<>(value, this); - } - - @CheckReturnValue - public Result allocateCompilationUnitName( - ShidToPatioCompilationUnitElementSpace space, - Optional name - ) { - var fullName = NameAllocator.allocateName( - elementsByName::containsKey, - "shed__" + space, - name - ); - - return toResult(fullName); - } - - @CheckReturnValue - public CompilationUnitContext addCompilationUnitElement( - PatioCompilationUnitElement element - ) { - if (this.elementsByName.containsKey(element.name())) { - throw new DuplicateCompilationUnitElementName(element.name(), element.source()); - } - - return new CompilationUnitContext( - this.elementsByName.plus(element.name(), element) - ); - } - - @CheckReturnValue - public CompilationUnitContext ensureCompilationUnitElement( - PatioCompilationUnitElement element - ) { - var existingElement = this.elementsByName.get(element.name()); - - if (existingElement == null) { - return new CompilationUnitContext( - this.elementsByName.plus(element.name(), element) - ); - } else if (existingElement.equals(element)) { - return this; - } else { - throw new DuplicateCompilationUnitElementName(element.name(), element.source()); - } - - } - - public record Result(T value, CompilationUnitContext context) {} - } - - public record FunctionContext( - PStack temporaryStack, - PVector instructions, - OrderedPMap localsByName, - PMap shidNameToLocal, - PMap>> waitingForShidLocal, - Optional stashedEffectHandler, - Optional stashedGcRootStackIndex, - PStack onReturn - ) { - public static final FunctionContext EMPTY = new FunctionContext( - P.stack(), - P.vector(), - OrderedPMap.empty(), - P.map(), - P.map(), - Optional.empty(), - Optional.empty(), - P.stack() - ); - - @CheckReturnValue - public Result temporaryPop() { - return new FunctionContext( - this.temporaryStack.minus(0), - this.instructions, - this.localsByName, - this.shidNameToLocal, - this.waitingForShidLocal, - this.stashedEffectHandler, - this.stashedGcRootStackIndex, - this.onReturn - ).toResult(this.temporaryStack.get(0)); - } - - @CheckReturnValue - public Result> temporaryPopAll() { - return new FunctionContext( - P.stack(), - this.instructions, - this.localsByName, - this.shidNameToLocal, - this.waitingForShidLocal, - this.stashedEffectHandler, - this.stashedGcRootStackIndex, - this.onReturn - ).toResult(this.temporaryStack); - } - - @CheckReturnValue - public FunctionContext temporaryPush(PatioOperand value) { - return new FunctionContext( - this.temporaryStack.plus(value), - this.instructions, - this.localsByName, - this.shidNameToLocal, - this.waitingForShidLocal, - this.stashedEffectHandler, - this.stashedGcRootStackIndex, - this.onReturn - ); - } - - @CheckReturnValue - public FunctionContext addInstruction(PatioInstruction instruction) { - return new FunctionContext( - this.temporaryStack, - this.instructions.plus(instruction), - this.localsByName, - this.shidNameToLocal, - this.waitingForShidLocal, - this.stashedEffectHandler, - this.stashedGcRootStackIndex, - this.onReturn - ); - } - - @CheckReturnValue - public Result allocateLocal( - ShidToPatioLocalSpace space, - Optional name, - Function createLocal - ) { - var fullName = NameAllocator.allocateName( - this.localsByName::containsKey, - space, - name - ); - - return new FunctionContext( - this.temporaryStack, - this.instructions, - this.localsByName.plus(fullName, createLocal.apply(fullName)), - this.shidNameToLocal, - this.waitingForShidLocal, - this.stashedEffectHandler, - this.stashedGcRootStackIndex, - this.onReturn - ).toResult(new PatioLocalRef(fullName)); - } - - @CheckReturnValue - public FunctionContext.Result declareShidLocal( - String name, - PatioType type, - PatioLocalType localType - ) { - var context = this; - - if (this.shidNameToLocal.containsKey(name)) { - // TODO: better error - throw new RuntimeException("Shid local already exists: " + name); - } - - var fullName = NameAllocator.allocateFixedName( - this.localsByName::containsKey, - ShidToPatioLocalSpace.LOCAL, - name - ); - - var localRef = new PatioLocalRef(fullName); - - context = new FunctionContext( - this.temporaryStack, - this.instructions, - this.localsByName.plus( - fullName, - new PatioLocal(fullName, type, localType) - ), - // TODO: the mapping is redundant given we fix the mapping - this.shidNameToLocal.plus(name, localRef), - this.waitingForShidLocal.plus(name, P.vector()), - this.stashedEffectHandler, - this.stashedGcRootStackIndex, - this.onReturn - ); - - return context.toResult(localRef); - } - - @CheckReturnValue - public FunctionContext.Result>> initShidLocal(String name) { - var context = new FunctionContext( - this.temporaryStack, - this.instructions, - this.localsByName, - this.shidNameToLocal, - this.waitingForShidLocal.minus(name), - this.stashedEffectHandler, - this.stashedGcRootStackIndex, - this.onReturn - ); - - return context.toResult(this.waitingForShidLocal.getOrDefault(name, P.vector())); - } - - @CheckReturnValue - public PatioLocalRef shidLocalNameToLocal(String name) { - var local = this.shidNameToLocal.get(name); - - if (local == null) { - // TODO: better error - throw new RuntimeException("Unknown Shid local: " + name); - } - - return local; - } - - @CheckReturnValue - public Optional shidLocalNameToLocalOrNone(String name) { - var local = this.shidNameToLocal.get(name); - - return Optional.ofNullable(local); - } - - @CheckReturnValue - public boolean isShidLocalDefined(String name) { - return !this.waitingForShidLocal.containsKey(name); - } - - @CheckReturnValue - public PatioType localType(PatioLocalRef local){ - // TODO: handle missing key. - return this.localsByName.get(local.name()).type(); - } - - @CheckReturnValue - public FunctionContext addWaitingForShidLocal( - String name, - Function func - ) { - return new FunctionContext( - this.temporaryStack, - this.instructions, - this.localsByName, - this.shidNameToLocal, - this.waitingForShidLocal.plus( - name, - this.waitingForShidLocal.getOrDefault(name, P.vector()).plus(func) - ), - this.stashedEffectHandler, - this.stashedGcRootStackIndex, - this.onReturn - ); - } - - @CheckReturnValue - public FunctionContext stashEffectHandler(PatioOperand effectHandler) { - return new FunctionContext( - this.temporaryStack, - this.instructions, - this.localsByName, - this.shidNameToLocal, - this.waitingForShidLocal, - // TODO: check current value is empty - Optional.of(effectHandler), - this.stashedGcRootStackIndex, - this.onReturn - ); - } - - @CheckReturnValue - public PatioOperand stashedEffectHandlerOrThrow() { - // TODO: better error - return this.stashedEffectHandler - .orElseThrow(() -> new RuntimeException("No stashed effect handler")); - } - - @CheckReturnValue - public FunctionContext stashGcRootStackIndex(PatioOperand gcRootStackIndex) { - return new FunctionContext( - this.temporaryStack, - this.instructions, - this.localsByName, - this.shidNameToLocal, - this.waitingForShidLocal, - this.stashedEffectHandler, - // TODO: check current value is empty - Optional.of(gcRootStackIndex), - this.onReturn - ); - } - - @CheckReturnValue - public PatioOperand stashedGcRootStackIndexOrThrow() { - // TODO: better error - return this.stashedGcRootStackIndex - .orElseThrow(() -> new RuntimeException("No stashed GC root stack index")); - } - - public FunctionContext pushOnReturn(PatioInstruction onReturn) { - return new FunctionContext( - this.temporaryStack, - this.instructions, - this.localsByName, - this.shidNameToLocal, - this.waitingForShidLocal, - this.stashedEffectHandler, - this.stashedGcRootStackIndex, - this.onReturn.plus(onReturn) - ); - } - - public FunctionContext popOnReturn() { - return new FunctionContext( - this.temporaryStack, - this.instructions, - this.localsByName, - this.shidNameToLocal, - this.waitingForShidLocal, - this.stashedEffectHandler, - this.stashedGcRootStackIndex, - this.onReturn.minus(0) - ); - } - - private Result toResult(T value) { - return new Result<>(value, this); - } - - public record Result(T value, FunctionContext context) {} - } - - public static final ShidToPatioContext EMPTY = new ShidToPatioContext( - GlobalContext.EMPTY, - CompilationUnitContext.EMPTY, - P.stack(), - FunctionContext.EMPTY - ); - - @CheckReturnValue - public static ShidToPatioContext forTypeInfos(TypeInfos typeInfos) { - return new ShidToPatioContext( - GlobalContext.forTypeInfos(typeInfos), - CompilationUnitContext.EMPTY, - P.stack(), - FunctionContext.EMPTY - ); - } - - @CheckReturnValue - public NamespaceTypeInfo namespaceTypeInfo(NamespaceName namespaceName) { - return this.globalContext.namespaceTypeInfo(namespaceName); - } - - @CheckReturnValue - public StructTypeInfo structTypeInfo(StructType type) { - return this.globalContext.structTypeInfo(type); - } - - @CheckReturnValue - public int structTag(StructType type) { - return globalContext.structTag(type); - } - - @CheckReturnValue - public UserDefinedEffectInfo userDefinedEffectInfo(UserDefinedEffect effect) { - return this.globalContext.userDefinedEffectInfo(effect); - } - - @CheckReturnValue - public int effectTag(UserDefinedEffect effect) { - return globalContext.effectTag(effect); - } - - @CheckReturnValue - public ShidToPatioResult allocateCompilationUnitElementName( - ShidToPatioCompilationUnitElementSpace space, - String name - ) { - return withCompilationUnitContextResult( - this.compilationUnitContext.allocateCompilationUnitName( - space, - Optional.of(name) - ) - ); - } - - @CheckReturnValue - public ShidToPatioResult allocateCompilationUnitElementName( - ShidToPatioCompilationUnitElementSpace space - ) { - return withCompilationUnitContextResult( - this.compilationUnitContext.allocateCompilationUnitName( - space, - Optional.empty() - ) - ); - } - - @CheckReturnValue - public ShidToPatioContext addDataElementMutable(String name, PatioDataValue initialValue, Source source) { - var dataElement = new PatioDataElementMutable(name, initialValue, source); - return addCompilationUnitElement(dataElement); - } - - @CheckReturnValue - public ShidToPatioContext addCompilationUnitElement( - PatioCompilationUnitElement element - ) { - return withCompilationUnitContext( - this.compilationUnitContext.addCompilationUnitElement(element) - ); - } - - @CheckReturnValue - public ShidToPatioContext ensureCompilationUnitElement( - PatioCompilationUnitElement element - ) { - return withCompilationUnitContext( - this.compilationUnitContext.ensureCompilationUnitElement(element) - ); - } - - @CheckReturnValue - public ShidToPatioResult temporaryPop() { - var result = this.functionContext.temporaryPop(); - - return withFunctionContextResult(result); - } - - @CheckReturnValue - public ShidToPatioContext temporaryPopIntoLocal(PatioLocalRef target, Source source) { - var result = this.functionContext.temporaryPop(); - - return new ShidToPatioContext(this.globalContext, this.compilationUnitContext, this.blockStack, result.context) - .addInstruction(new PatioLocalStore(target, result.value, source)); - } - - @CheckReturnValue - public ShidToPatioResult> temporaryPopAll() { - var result = this.functionContext.temporaryPopAll(); - - return withFunctionContextResult(result); - } - - @CheckReturnValue - public ShidToPatioContext temporaryPush(PatioOperand value) { - var result = this.functionContext.temporaryPush(value); - - return withFunctionContext(result); - } - - @CheckReturnValue - public ShidToPatioContext addInstruction(PatioInstruction instruction) { - return withFunctionContext(this.functionContext.addInstruction(instruction)); - } - - @CheckReturnValue - public ShidToPatioResult allocateParam( - ShidToPatioLocalSpace space, - PatioType type - ) { - var result = this.functionContext.allocateLocal( - space, - Optional.empty(), - (patioName) -> new PatioLocal(patioName, type, PatioLocalType.PARAM) - ); - - return withFunctionContextResult(result); - } - - @CheckReturnValue - public ShidToPatioResult allocateVal( - ShidToPatioLocalSpace space, - PatioType type - ) { - var result = this.functionContext.allocateLocal( - space, - Optional.empty(), - (patioName) -> new PatioLocal(patioName, type, PatioLocalType.VAL) - ); - - return withFunctionContextResult(result); - } - - @CheckReturnValue - public ShidToPatioResult allocateVal( - ShidToPatioLocalSpace space, - String name, - PatioType type - ) { - var result = this.functionContext.allocateLocal( - space, - Optional.of(name), - (patioName) -> new PatioLocal(patioName, type, PatioLocalType.VAL) - ); - - return withFunctionContextResult(result); - } - - @CheckReturnValue - public ShidToPatioContext defineShidParam(String name) { - return declareShidParam(name).initShidLocal(name); - } - - @CheckReturnValue - private ShidToPatioContext declareShidParam(String name) { - return declareShidLocal( - name, - ShidToPatioTypes.VALUE_TYPE, - PatioLocalType.PARAM - ).context(); - } - - @CheckReturnValue - public ShidToPatioResult declareShidVal(String name, PatioType type) { - return declareShidLocal( - name, - type, - PatioLocalType.VAL - ); - } - - @CheckReturnValue - public ShidToPatioResult declareShidLocal( - String name, - PatioType type, - PatioLocalType patioLocalType - ) { - return withFunctionContextResult(this.functionContext.declareShidLocal( - name, - type, - patioLocalType - )); - } - - @CheckReturnValue - public ShidToPatioContext initShidLocal(String name) { - var result = this.functionContext.initShidLocal(name); - var context = withFunctionContext(result.context); - - for (var func : result.value) { - context = func.apply(context); - } - - return context; - } - - @CheckReturnValue - public ShidToPatioContext onceShidLocalDefined( - String name, - Function func - ) { - var local = this.functionContext.shidLocalNameToLocalOrNone(name); - - if (local.isEmpty()) { - // TODO: better error - throw new RuntimeException("Unknown Shid local: " + name); - } else if (!this.functionContext.isShidLocalDefined(name)) { - return withFunctionContext( - this.functionContext.addWaitingForShidLocal(name, func) - ); - } else { - return func.apply(this); - } - } - - @CheckReturnValue - public PatioLocalRef shidLocalNameToLocal(String name) { - return this.functionContext.shidLocalNameToLocal(name); - } - - @CheckReturnValue - public PatioType localType(PatioLocalRef local) { - return this.functionContext.localType(local); - } - - @CheckReturnValue - public PatioType shidLocalType(String name) { - var local = shidLocalNameToLocal(name); - return localType(local); - } - - @CheckReturnValue - public ShidToPatioContext createFunction( - String name, - PatioVisibility visibility, - PatioType returnType, - Source source, - Function createBody - ) { - var bodyContext = new ShidToPatioContext( - this.globalContext, - this.compilationUnitContext, - P.stack(), - FunctionContext.EMPTY - ); - - bodyContext = createBody.apply(bodyContext); - - var locals = bodyContext.functionContext.localsByName.values().stream().toList(); - - return new ShidToPatioContext( - this.globalContext, - bodyContext.compilationUnitContext.addElement(new PatioFunctionDefinition( - name, - visibility, - locals, - returnType, - bodyContext.functionContext.instructions, - source - )), - this.blockStack, - this.functionContext - ); - } - - @CheckReturnValue - public ShidToPatioContext enterBlock() { - return new ShidToPatioContext( - this.globalContext, - this.compilationUnitContext, - this.blockStack.plus(this.functionContext), - new FunctionContext( - P.stack(), - P.vector(), - this.functionContext.localsByName, - this.functionContext.shidNameToLocal, - this.functionContext.waitingForShidLocal, - this.functionContext.stashedEffectHandler, - this.functionContext.stashedGcRootStackIndex, - this.functionContext.onReturn - ) - ); - } - - @CheckReturnValue - public ShidToPatioResult> exitBlock() { - if (!this.functionContext.temporaryStack.isEmpty()) { - throw new RuntimeException("temporary stack must be empty at the end of a block"); - } - - return new ShidToPatioContext( - this.globalContext, - this.compilationUnitContext, - this.blockStack.minus(0), - new FunctionContext( - this.blockStack.get(0).temporaryStack, - this.blockStack.get(0).instructions, - this.functionContext.localsByName, - this.functionContext.shidNameToLocal, - this.functionContext.waitingForShidLocal, - this.blockStack.get(0).stashedEffectHandler, - this.blockStack.get(0).stashedGcRootStackIndex, - this.blockStack.get(0).onReturn - ) - ).toResult(this.functionContext.instructions); - } - - @CheckReturnValue - public ShidToPatioContext stashEffectHandler(PatioOperand effectHandler) { - return withFunctionContext(this.functionContext.stashEffectHandler(effectHandler)); - } - - @CheckReturnValue - public PatioOperand stashedEffectHandler() { - return this.functionContext.stashedEffectHandlerOrThrow(); - } - - @CheckReturnValue - public String exceptionTypeName(UserDefinedEffect effect) { - // TODO: Allocate properly - return "shed__effect__exception__" + String.join("_", effect.namespaceName().parts()) + "__" + effect.name(); - } - - @CheckReturnValue - public ShidToPatioContext stashGcRootStackIndex(PatioOperand gcRootStackIndex) { - return withFunctionContext(this.functionContext.stashGcRootStackIndex(gcRootStackIndex)); - } - - @CheckReturnValue - public PatioOperand stashedGcRootStackIndex() { - return this.functionContext.stashedGcRootStackIndexOrThrow(); - } - - @CheckReturnValue - public ShidToPatioContext pushOnReturn(PatioInstruction onReturn) { - return withFunctionContext(this.functionContext.pushOnReturn(onReturn)); - } - - @CheckReturnValue - public ShidToPatioContext popOnReturn() { - return withFunctionContext(this.functionContext.popOnReturn()); - } - - @CheckReturnValue - public List onReturn() { - return this.functionContext.onReturn(); - } - - @CheckReturnValue - private ShidToPatioContext withCompilationUnitContext(CompilationUnitContext compilationUnitContext) { - return new ShidToPatioContext(this.globalContext, compilationUnitContext, this.blockStack, this.functionContext); - } - - @CheckReturnValue - private ShidToPatioResult withCompilationUnitContextResult(CompilationUnitContext.Result result) { - return withCompilationUnitContext(result.context).toResult(result.value); - } - - @CheckReturnValue - private ShidToPatioContext withFunctionContext(FunctionContext functionContext) { - return new ShidToPatioContext(this.globalContext, this.compilationUnitContext, this.blockStack, functionContext); - } - - @CheckReturnValue - private ShidToPatioResult withFunctionContextResult(FunctionContext.Result result) { - return withFunctionContext(result.context).toResult(result.value); - } - - @CheckReturnValue - public ShidToPatioResult toResult(T value) { - return new ShidToPatioResult<>(value, this); - } - - @CheckReturnValue - public PatioCompilationUnit toCompilationUnit(Source source) { - return new PatioCompilationUnit( - new ArrayList<>(this.compilationUnitContext.elementsByName.values()), - source - ); - } -} diff --git a/src/main/java/org/shedlang/compiler/patio/ShidToPatioEffects.java b/src/main/java/org/shedlang/compiler/patio/ShidToPatioEffects.java deleted file mode 100644 index 6ea11694..00000000 --- a/src/main/java/org/shedlang/compiler/patio/ShidToPatioEffects.java +++ /dev/null @@ -1,505 +0,0 @@ -package org.shedlang.compiler.patio; - -import org.shedlang.compiler.ast.typed.FreeVariables; -import org.shedlang.compiler.patio.ast.PatioExceptionTypeDefinition; -import org.shedlang.compiler.patio.ast.PatioFunctionDeclaration; -import org.shedlang.compiler.patio.ast.PatioLocal; -import org.shedlang.compiler.patio.ast.instructions.*; -import org.shedlang.compiler.patio.ast.operands.PatioInt; -import org.shedlang.compiler.patio.ast.operands.PatioLocalRef; -import org.shedlang.compiler.patio.ast.operands.PatioOperand; -import org.shedlang.compiler.patio.ast.types.PatioDataLayout; -import org.shedlang.compiler.patio.ast.types.PatioDataLayouts; -import org.shedlang.compiler.patio.ast.types.PatioType; -import org.shedlang.compiler.patio.ast.types.PatioTypes; -import org.shedlang.compiler.shid.instructions.ShidDefineFunction; -import org.shedlang.compiler.sources.Source; -import org.shedlang.compiler.sources.Sources; -import org.shedlang.compiler.types.UserDefinedEffect; -import org.shedlang.compiler.util.Lists; - -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.function.Function; -import java.util.stream.IntStream; - -public class ShidToPatioEffects { - private static final PatioType EFFECT_TAG_TYPE = PatioTypes.INT; - private static final PatioType EFFECT_METHOD_INDEX_TYPE = PatioTypes.INT; - private static final PatioType EFFECT_HANDLER_TYPE = PatioTypes.DATA_POINTER; - private static final PatioType EFFECT_HANDLER_METHOD_POINTER_TYPE = PatioTypes.DATA_POINTER; - private static final PatioType EFFECT_HANDLER_METHOD_TYPE = ShidToPatioTypes.VALUE_TYPE; - - private static PatioDataLayout effectHandlerMethodDataLayout( - FreeVariables freeVariables, - ShidToPatioContext context - ) { - return ShidToPatioClosures.closureDataLayout( - PatioDataLayouts.struct(List.of(PatioDataLayouts.DATA_POINTER)), - freeVariables, - context - ); - } - - private static final List CLOSURE_EFFECT_HANDLER_OFFSET - = ShidToPatioClosures.additionalOffset(List.of(0)); - - private static PatioDataLayout userDefinedEffectLayout( - UserDefinedEffect effect, - ShidToPatioContext context - ) { - var effectInfo = context.userDefinedEffectInfo(effect); - return ShidToPatioGc.gcObjectDataLayout(PatioDataLayouts.struct(Lists.repeat( - PatioDataLayouts.fromType(ShidToPatioClosures.CLOSURE_TYPE), - effectInfo.methodCount() - ))); - } - - private static List userDefinedEffectMethodOffset(int methodIndex) { - return ShidToPatioGc.gcObjectOffset(List.of(methodIndex)); - } - - private static final List USER_DEFINED_EFFECT_GC_CHILDREN_OFFSET = - ShidToPatioGc.gcObjectOffset(List.of()); - - private static final PatioFunctionDeclaration FIND_HANDLER_METHOD_DECLARATION = new PatioFunctionDeclaration( - "shed__runtime__effects_find_handler_method", - List.of( - PatioLocal.param("effectTag", EFFECT_TAG_TYPE), - PatioLocal.param("methodIndex", EFFECT_METHOD_INDEX_TYPE) - ), - EFFECT_HANDLER_METHOD_TYPE, - Sources.RUNTIME - ); - - private static final PatioFunctionDeclaration GET_HANDLER_DECLARATION = new PatioFunctionDeclaration( - "shed__runtime__effects_get_handler", - List.of(), - EFFECT_HANDLER_TYPE, - Sources.RUNTIME - ); - - private static final PatioFunctionDeclaration SET_HANDLER_DECLARATION = new PatioFunctionDeclaration( - "shed__runtime__effects_set_handler", - List.of(PatioLocal.param("effectHandler", EFFECT_HANDLER_TYPE)), - PatioTypes.VOID, - Sources.RUNTIME - ); - - private static final PatioFunctionDeclaration PUSH_HANDLER_DECLARATION = new PatioFunctionDeclaration( - "shed__runtime__effects_push_handler", - List.of( - PatioLocal.param("effectTag", EFFECT_TAG_TYPE), - PatioLocal.param("methodCount", PatioTypes.INT) - ), - EFFECT_HANDLER_TYPE, - Sources.RUNTIME - ); - - private static final PatioFunctionDeclaration SET_HANDLER_METHOD_DECLARATION = new PatioFunctionDeclaration( - "shed__runtime__effects_set_handler_method", - List.of( - PatioLocal.param("handler", EFFECT_HANDLER_TYPE), - PatioLocal.param("methodIndex", EFFECT_METHOD_INDEX_TYPE), - PatioLocal.param("handlerMethod", EFFECT_HANDLER_METHOD_TYPE) - ), - PatioTypes.VOID, - Sources.RUNTIME - ); - - private static final PatioFunctionDeclaration POP_HANDLER_DECLARATION = new PatioFunctionDeclaration( - "shed__runtime__effects_pop_handler", - List.of(), - PatioTypes.VOID, - Sources.RUNTIME - ); - - private ShidToPatioEffects() { - } - - public static ShidToPatioContext createUserDefinedEffect( - PatioLocalRef target, - UserDefinedEffect effect, - Source source, - ShidToPatioContext context - ) { - context = context.addCompilationUnitElement(new PatioExceptionTypeDefinition( - context.exceptionTypeName(effect), - ShidToPatioTypes.VALUE_TYPE, - source - )); - - var effectPointerResult = context.allocateVal( - ShidToPatioLocalSpace.USER_DEFINED_EFFECT_POINTER, - effect.name(), - PatioTypes.DATA_POINTER - ); - var effectPointer = effectPointerResult.value(); - context = effectPointerResult.context(); - - var effectLayout = userDefinedEffectLayout(effect, context); - - var effectInfo = context.userDefinedEffectInfo(effect); - - context = ShidToPatioGc.alloc( - effectPointer, - effectLayout, - USER_DEFINED_EFFECT_GC_CHILDREN_OFFSET, - effectInfo.methodCount(), - source, - context - ); - - for (var method : effectInfo.methods()) { - var effectMethodResult = context.allocateVal( - ShidToPatioLocalSpace.USER_DEFINED_EFFECT_METHOD, - method.name(), - ShidToPatioClosures.CLOSURE_TYPE - ); - var effectMethod = effectMethodResult.value(); - context = effectMethodResult.context(); - - var positionalParams = IntStream.range(0, method.type().positionalParams().size()) - // TODO: ensure names of positional params doesn't clash with named params - .mapToObj(paramIndex -> new ShidDefineFunction.Param("arg" + paramIndex, source)) - .toList(); - - context = ShidToPatioFunctions.create( - effectMethod, - method.name(), - positionalParams, - method.type().namedParams().stream() - .map(namedParam -> new ShidDefineFunction.Param(namedParam.name(), source)) - .toList(), - FreeVariables.empty(), - bodyContext -> { - bodyContext = bodyContext.ensureCompilationUnitElement(FIND_HANDLER_METHOD_DECLARATION); - - var handlerMethodResult = bodyContext.allocateVal( - ShidToPatioLocalSpace.EFFECT_HANDLER_METHOD, - EFFECT_HANDLER_METHOD_TYPE - ); - var handlerMethod = handlerMethodResult.value(); - bodyContext = handlerMethodResult.context(); - - bodyContext = bodyContext.addInstruction(new PatioCall( - Optional.of(handlerMethod), - FIND_HANDLER_METHOD_DECLARATION.name(), - List.of( - new PatioInt(bodyContext.effectTag(effect)), - new PatioInt(method.fieldIndex()) - ), - source - )); - - var returnValueResult = bodyContext.allocateVal( - ShidToPatioLocalSpace.TEMPORARY, - ShidToPatioTypes.VALUE_TYPE - ); - var returnValue = returnValueResult.value(); - bodyContext = returnValueResult.context(); - - var bodyContextArgs = bodyContext; - bodyContext = ShidToPatioClosures.call( - returnValue, - handlerMethod, - positionalParams.stream() - .map(param -> bodyContextArgs.shidLocalNameToLocal(param.name())) - .toList(), - method.type().namedParams().stream() - .map(param -> Map.entry( - param.name(), - bodyContextArgs.shidLocalNameToLocal(param.name()) - )) - .toList(), - source, - bodyContext - ); - - bodyContext = bodyContext.addInstruction(new PatioReturn(returnValue, source)); - - return bodyContext; - }, - source, - context - ); - - context = context - .addInstruction(new PatioMemoryStore( - effectPointer, - effectLayout, - userDefinedEffectMethodOffset(method.fieldIndex()), - effectMethod, - source - )); - } - - context = context.addInstruction(new PatioDataPtrToInt( - target, - effectPointer, - source - )); - - return context; - } - - public static ShidToPatioContext fieldLoad( - PatioLocalRef target, - PatioOperand receiver, - UserDefinedEffect effect, - String fieldName, - Source source, - ShidToPatioContext context - ) { - var effectPointerResult = context.allocateVal( - ShidToPatioLocalSpace.USER_DEFINED_EFFECT_POINTER, - PatioTypes.DATA_POINTER - ); - var effectPointer = effectPointerResult.value(); - context = effectPointerResult.context(); - - context = context.addInstruction(new PatioIntToDataPtr( - effectPointer, - receiver, - source - )); - - var effectDataLayout = userDefinedEffectLayout(effect, context); - - var effectInfo = context.userDefinedEffectInfo(effect); - var methodIndex = effectInfo.methodIndex(fieldName); - - context = context.addInstruction(new PatioMemoryLoad( - target, - effectPointer, - effectDataLayout, - userDefinedEffectMethodOffset(methodIndex), - source - )); - - return context; - } - - public static ShidToPatioContext try_( - PatioLocalRef target, - UserDefinedEffect effect, - Map handlerMethodsByName, - Function> generateBody, - Source source, - ShidToPatioContext context - ) { - var effectInfo = context.userDefinedEffectInfo(effect); - - context = context - .ensureCompilationUnitElement(PUSH_HANDLER_DECLARATION) - .ensureCompilationUnitElement(SET_HANDLER_METHOD_DECLARATION) - .ensureCompilationUnitElement(POP_HANDLER_DECLARATION); - - var effectHandlerResult = context.allocateVal( - ShidToPatioLocalSpace.EFFECT_HANDLER, - EFFECT_HANDLER_TYPE - ); - var effectHandler = effectHandlerResult.value(); - context = effectHandlerResult.context(); - - context = context.addInstruction(new PatioCall( - Optional.of(effectHandler), - PUSH_HANDLER_DECLARATION.name(), - List.of( - new PatioInt(context.effectTag(effect)), - new PatioInt(effectInfo.methodCount()) - ), - source - )); - - for (var handlerMethodInfo : effectInfo.methods()) { - context = context.addInstruction(new PatioCall( - Optional.empty(), - SET_HANDLER_METHOD_DECLARATION.name(), - List.of( - effectHandler, - new PatioInt(handlerMethodInfo.fieldIndex()), - handlerMethodsByName.get(handlerMethodInfo.name()) - ), - source - )); - } - - var popHandler = new PatioCall( - Optional.empty(), - POP_HANDLER_DECLARATION.name(), - List.of(), - source - ); - - context = context.pushOnReturn(popHandler); - - var bodyResult = generateBody.apply(context); - var body = bodyResult.value(); - context = bodyResult.context(); - - context = context.popOnReturn(); - - var exceptionValueResult = context.allocateVal( - ShidToPatioLocalSpace.TEMPORARY, - ShidToPatioTypes.VALUE_TYPE - ); - var exceptionValue = exceptionValueResult.value(); - context = exceptionValueResult.context(); - - context = context.addInstruction(new PatioTry( - List.of(target), - List.of( - new PatioCatchClause( - context.exceptionTypeName(effect), - exceptionValue, - new PatioBlock( - List.of(), - List.of(exceptionValue), - source - ), - source - ) - ), - body.addInstruction(popHandler), - source - )); - - return context; - } - - public static ShidToPatioContext createEffectHandlerMethod( - PatioLocalRef target, - String name, - List positionalParams, - List namedParams, - FreeVariables freeVariables, - Function generateBody, - Source source, - ShidToPatioContext context - ) { - context = context - .ensureCompilationUnitElement(GET_HANDLER_DECLARATION) - .ensureCompilationUnitElement(SET_HANDLER_DECLARATION); - - var layout = effectHandlerMethodDataLayout(freeVariables, context); - - return ShidToPatioClosures.create( - target, - ShidToPatioCompilationUnitElementSpace.EFFECT_HANDLER_METHOD, - name, - positionalParams, - namedParams, - layout, - (closurePointer, allocContext) -> { - var effectHandlerResult = allocContext.allocateVal( - ShidToPatioLocalSpace.EFFECT_HANDLER_CURRENT, - EFFECT_HANDLER_TYPE - ); - var effectHandler = effectHandlerResult.value(); - allocContext = effectHandlerResult.context(); - - allocContext = getCurrentEffectHandler(effectHandler, source, allocContext); - - allocContext = allocContext.addInstruction(new PatioMemoryStore( - closurePointer, - layout, - CLOSURE_EFFECT_HANDLER_OFFSET, - effectHandler, - source - )); - - return allocContext; - }, - freeVariables, - (closurePointer, bodyContext) -> { - var previousEffectHandlerResult = bodyContext.allocateVal( - ShidToPatioLocalSpace.EFFECT_HANDLER, - EFFECT_HANDLER_METHOD_POINTER_TYPE - ); - var previousEffectHandler = previousEffectHandlerResult.value(); - bodyContext = previousEffectHandlerResult.context(); - - bodyContext = getCurrentEffectHandler(previousEffectHandler, source, bodyContext); - - bodyContext = bodyContext.stashEffectHandler(previousEffectHandler); - - var effectHandlerResult = bodyContext.allocateVal( - ShidToPatioLocalSpace.EFFECT_HANDLER, - EFFECT_HANDLER_METHOD_POINTER_TYPE - ); - var effectHandler = effectHandlerResult.value(); - bodyContext = effectHandlerResult.context(); - - bodyContext = bodyContext.addInstruction(new PatioMemoryLoad( - effectHandler, - closurePointer, - layout, - CLOSURE_EFFECT_HANDLER_OFFSET, - source - )); - - bodyContext = bodyContext.addInstruction(new PatioCall( - Optional.empty(), - SET_HANDLER_DECLARATION.name(), - List.of(effectHandler), - source - )); - - bodyContext = generateBody.apply(bodyContext); - - return bodyContext; - }, - source, - context - ); - } - - public static ShidToPatioContext resume( - PatioOperand value, - Source source, - ShidToPatioContext context - ) { - context = context.addInstruction(new PatioCall( - Optional.empty(), - SET_HANDLER_DECLARATION.name(), - List.of(context.stashedEffectHandler()), - source - )); - - context = context.addInstruction(new PatioResume(value, source)); - - return context; - } - - public static ShidToPatioContext break_( - UserDefinedEffect effect, - PatioOperand value, - Source source, - ShidToPatioContext context - ) { - var exceptionTypeName = context.exceptionTypeName(effect); - - context = context.addInstruction(new PatioThrow( - exceptionTypeName, - value, - source - )); - - return context; - } - - private static ShidToPatioContext getCurrentEffectHandler( - PatioLocalRef target, - Source source, - ShidToPatioContext context - ) { - return context.addInstruction(new PatioCall( - Optional.of(target), - GET_HANDLER_DECLARATION.name(), - List.of(), - source - )); - } -} diff --git a/src/main/java/org/shedlang/compiler/patio/ShidToPatioFunctions.java b/src/main/java/org/shedlang/compiler/patio/ShidToPatioFunctions.java deleted file mode 100644 index 77da6a10..00000000 --- a/src/main/java/org/shedlang/compiler/patio/ShidToPatioFunctions.java +++ /dev/null @@ -1,54 +0,0 @@ -package org.shedlang.compiler.patio; - -import org.shedlang.compiler.ast.typed.FreeVariables; -import org.shedlang.compiler.patio.ast.operands.PatioLocalRef; -import org.shedlang.compiler.patio.ast.types.PatioDataLayout; -import org.shedlang.compiler.patio.ast.types.PatioDataLayouts; -import org.shedlang.compiler.shid.instructions.ShidDefineFunction; -import org.shedlang.compiler.sources.Source; - -import java.util.List; -import java.util.function.Function; - -public class ShidToPatioFunctions { - private ShidToPatioFunctions() { - } - - private static PatioDataLayout functionDataLayout( - FreeVariables freeVariables, - ShidToPatioContext context - ) { - return ShidToPatioClosures.closureDataLayout( - PatioDataLayouts.struct(List.of()), - freeVariables, - context - ); - } - - public static ShidToPatioContext create( - PatioLocalRef target, - String name, - List positionalParams, - List namedParams, - FreeVariables freeVariables, - Function generateBody, - Source source, - ShidToPatioContext context - ) { - var layout = functionDataLayout(freeVariables, context); - - return ShidToPatioClosures.create( - target, - ShidToPatioCompilationUnitElementSpace.FUNCTION, - name, - positionalParams, - namedParams, - layout, - (closurePointer, storeContext) -> storeContext, - freeVariables, - (closurePointer, bodyContext) -> generateBody.apply(bodyContext), - source, - context - ); - } -} diff --git a/src/main/java/org/shedlang/compiler/patio/ShidToPatioGc.java b/src/main/java/org/shedlang/compiler/patio/ShidToPatioGc.java deleted file mode 100644 index 809d9076..00000000 --- a/src/main/java/org/shedlang/compiler/patio/ShidToPatioGc.java +++ /dev/null @@ -1,208 +0,0 @@ -package org.shedlang.compiler.patio; - -import org.shedlang.compiler.patio.ast.PatioFunctionDeclaration; -import org.shedlang.compiler.patio.ast.PatioLocal; -import org.shedlang.compiler.patio.ast.instructions.PatioAllocHeap; -import org.shedlang.compiler.patio.ast.instructions.PatioCall; -import org.shedlang.compiler.patio.ast.operands.PatioLocalRef; -import org.shedlang.compiler.patio.ast.operands.PatioOperand; -import org.shedlang.compiler.patio.ast.types.*; -import org.shedlang.compiler.sources.Source; -import org.shedlang.compiler.sources.Sources; -import org.shedlang.compiler.util.Lists; - -import java.util.List; -import java.util.Optional; - -public class ShidToPatioGc { - // TODO: garbage collect after throws, and the end of blocks (especially for loops) - private ShidToPatioGc() { - } - - public static PatioDataLayout gcObjectDataLayout(PatioDataLayout valueLayout) { - return PatioDataLayouts.struct(List.of( - PatioDataLayouts.struct(List.of( - PatioDataLayouts.DATA_POINTER, // next - PatioDataLayouts.INT, // mark - PatioDataLayouts.INT, // children offset - PatioDataLayouts.INT // children count - )), - valueLayout - )); - } - - public static List gcObjectOffset(List valueOffset) { - return Lists.concat(List.of(1), valueOffset); - } - - /** - * Creates a data value for GC objects with no GC children that should never - * be garbage collected. Such a value does not need to be added to the set - * of GC roots. - */ - public static PatioDataValue gcObjectStaticDataValue(PatioDataValue value) { - return PatioDataValues.struct(List.of( - PatioDataValues.struct(List.of( - PatioDataValues.int_(0), - // Static values are always marked: see gc.c - PatioDataValues.int_(0b110), - PatioDataValues.int_(0), - PatioDataValues.int_(0) - )), - value - )); - } - - // == Roots == - - public static final PatioType GC_ROOT_STACK_INDEX_TYPE = PatioTypes.INT; - - private static final PatioFunctionDeclaration GET_GC_ROOT_STACK_INDEX = new PatioFunctionDeclaration( - "shed__runtime__gc_get_root_stack_index", - List.of(), - GC_ROOT_STACK_INDEX_TYPE, - Sources.RUNTIME - ); - - public static ShidToPatioContext getGcRootStackIndex( - PatioLocalRef target, - Source source, - ShidToPatioContext context - ) { - return context - .ensureCompilationUnitElement(GET_GC_ROOT_STACK_INDEX) - .addInstruction(new PatioCall( - Optional.of(target), - GET_GC_ROOT_STACK_INDEX.name(), - List.of(), - source - )); - } - - private static final PatioFunctionDeclaration SET_GC_ROOT_STACK_INDEX = new PatioFunctionDeclaration( - "shed__runtime__gc_set_root_stack_index", - List.of(PatioLocal.param("gc_root_stack_index", GC_ROOT_STACK_INDEX_TYPE)), - PatioTypes.VOID, - Sources.RUNTIME - ); - - public static ShidToPatioContext setGcRootStackIndex( - PatioOperand gcRootIndex, - Source source, - ShidToPatioContext context - ) { - return context - .ensureCompilationUnitElement(SET_GC_ROOT_STACK_INDEX) - .addInstruction(new PatioCall( - Optional.empty(), - SET_GC_ROOT_STACK_INDEX.name(), - List.of(gcRootIndex), - source - )); - } - - private static final PatioFunctionDeclaration PUSH_GC_ROOT = new PatioFunctionDeclaration( - "shed__runtime__gc_push_root", - List.of(PatioLocal.param("gc_root", ShidToPatioTypes.VALUE_TYPE)), - PatioTypes.VOID, - Sources.RUNTIME - ); - - public static ShidToPatioContext pushGcRoot( - PatioOperand escapee, - Source source, - ShidToPatioContext context - ) { - return context - .ensureCompilationUnitElement(PUSH_GC_ROOT) - .addInstruction(new PatioCall( - Optional.empty(), - PUSH_GC_ROOT.name(), - List.of(escapee), - source - )); - } - - // == Allocation == - - public static ShidToPatioContext alloc( - PatioLocalRef target, - PatioDataLayout layout, - List childrenOffset, - int childrenCount, - Source source, - ShidToPatioContext context - ) { - return context.addInstruction(new PatioAllocHeap( - target, - layout, - childrenOffset, - childrenCount, - source - )); - } - - // == Collection == - - private static final PatioFunctionDeclaration COLLECT = new PatioFunctionDeclaration( - "shed__runtime__gc_collect", - List.of(), - PatioTypes.VOID, - Sources.RUNTIME - ); - - public static ShidToPatioContext collect( - Source source, - ShidToPatioContext context - ) { - return context - .ensureCompilationUnitElement(COLLECT) - .addInstruction(new PatioCall( - Optional.empty(), - COLLECT.name(), - List.of(), - source - )); - } - - // == Save/Restore == - - static ShidToPatioContext saveGcRootStack(Source source, ShidToPatioContext context) { - var gcRootStackIndexResult = context.allocateVal( - ShidToPatioLocalSpace.GC_ROOT_STACK_INDEX, - ShidToPatioGc.GC_ROOT_STACK_INDEX_TYPE - ); - var gcRootStackIndex = gcRootStackIndexResult.value(); - context = gcRootStackIndexResult.context(); - - context = ShidToPatioGc.getGcRootStackIndex( - gcRootStackIndex, - source, - context - ); - - context = context.stashGcRootStackIndex(gcRootStackIndex); - - return context; - } - - static ShidToPatioContext restoreGcRootStack( - List escapees, - Source source, - ShidToPatioContext context - ) { - context = ShidToPatioGc.setGcRootStackIndex( - context.stashedGcRootStackIndex(), - source, - context - ); - - for (var escapee : escapees) { - context = ShidToPatioGc.pushGcRoot(escapee, source, context); - } - - context = ShidToPatioGc.collect(source, context); - - return context; - } -} diff --git a/src/main/java/org/shedlang/compiler/patio/ShidToPatioInts.java b/src/main/java/org/shedlang/compiler/patio/ShidToPatioInts.java deleted file mode 100644 index 378a2cc5..00000000 --- a/src/main/java/org/shedlang/compiler/patio/ShidToPatioInts.java +++ /dev/null @@ -1,156 +0,0 @@ -package org.shedlang.compiler.patio; - -import org.shedlang.compiler.patio.ast.PatioFunctionDeclaration; -import org.shedlang.compiler.patio.ast.PatioLocal; -import org.shedlang.compiler.patio.ast.instructions.PatioCall; -import org.shedlang.compiler.patio.ast.operands.PatioInt; -import org.shedlang.compiler.patio.ast.operands.PatioLocalRef; -import org.shedlang.compiler.patio.ast.operands.PatioOperand; -import org.shedlang.compiler.patio.ast.types.PatioType; -import org.shedlang.compiler.patio.ast.types.PatioTypes; -import org.shedlang.compiler.sources.Source; -import org.shedlang.compiler.sources.Sources; - -import java.math.BigInteger; -import java.util.List; -import java.util.Optional; - -public class ShidToPatioInts { - public static final PatioFunctionDeclaration INT_CREATE_DECLARATION = new PatioFunctionDeclaration( - "shed__runtime__int_create", - List.of( - PatioLocal.param("value", PatioTypes.INT) - ), - ShidToPatioTypes.VALUE_TYPE, - Sources.RUNTIME - ); - - public static final PatioFunctionDeclaration INT_ADD_DECLARATION = new PatioFunctionDeclaration( - "shed__runtime__int_add", - List.of( - PatioLocal.param("left", ShidToPatioTypes.VALUE_TYPE), - PatioLocal.param("right", ShidToPatioTypes.VALUE_TYPE) - ), - ShidToPatioTypes.VALUE_TYPE, - Sources.RUNTIME - ); - - public static final PatioFunctionDeclaration INT_SUB_DECLARATION = new PatioFunctionDeclaration( - "shed__runtime__int_sub", - List.of( - PatioLocal.param("left", ShidToPatioTypes.VALUE_TYPE), - PatioLocal.param("right", ShidToPatioTypes.VALUE_TYPE) - ), - ShidToPatioTypes.VALUE_TYPE, - Sources.RUNTIME - ); - - public static final PatioFunctionDeclaration INT_EQUALS_DECLARATION = new PatioFunctionDeclaration( - "shed__runtime__int_equals", - List.of( - PatioLocal.param("left", ShidToPatioTypes.VALUE_TYPE), - PatioLocal.param("right", ShidToPatioTypes.VALUE_TYPE) - ), - PatioTypes.BOOL, - Sources.RUNTIME - ); - - public static final PatioFunctionDeclaration INT_NOT_EQUAL_DECLARATION = new PatioFunctionDeclaration( - "shed__runtime__int_not_equal", - List.of( - PatioLocal.param("left", ShidToPatioTypes.VALUE_TYPE), - PatioLocal.param("right", ShidToPatioTypes.VALUE_TYPE) - ), - PatioTypes.BOOL, - Sources.RUNTIME - ); - - public static final PatioType INT_TYPE = ShidToPatioTypes.VALUE_TYPE; - - private ShidToPatioInts() { - } - - public static ShidToPatioContext storeConst( - PatioLocalRef target, - BigInteger value, - Source source, - ShidToPatioContext context - ) { - return context - .ensureCompilationUnitElement(INT_CREATE_DECLARATION) - .addInstruction(new PatioCall( - Optional.of(target), - INT_CREATE_DECLARATION.name(), - List.of(new PatioInt(value.intValueExact())), - source - )); - } - - public static ShidToPatioContext add( - PatioLocalRef target, - PatioOperand left, - PatioOperand right, - Source source, - ShidToPatioContext context - ) { - return context - .ensureCompilationUnitElement(INT_ADD_DECLARATION) - .addInstruction(new PatioCall( - Optional.of(target), - INT_ADD_DECLARATION.name(), - List.of(left, right), - source - )); - } - - public static ShidToPatioContext sub( - PatioLocalRef target, - PatioOperand left, - PatioOperand right, - Source source, - ShidToPatioContext context - ) { - return context - .ensureCompilationUnitElement(INT_SUB_DECLARATION) - .addInstruction(new PatioCall( - Optional.of(target), - INT_SUB_DECLARATION.name(), - List.of(left, right), - source - )); - } - - public static ShidToPatioContext equals( - PatioLocalRef target, - PatioOperand left, - PatioOperand right, - Source source, - ShidToPatioContext context - ) { - return context - .ensureCompilationUnitElement(INT_EQUALS_DECLARATION) - .addInstruction(new PatioCall( - Optional.of(target), - INT_EQUALS_DECLARATION.name(), - List.of(left, right), - source - )); - } - - public static ShidToPatioContext notEqual( - PatioLocalRef target, - PatioOperand left, - PatioOperand right, - Source source, - ShidToPatioContext context - ) { - return context - .ensureCompilationUnitElement(INT_NOT_EQUAL_DECLARATION) - .addInstruction(new PatioCall( - Optional.of(target), - INT_NOT_EQUAL_DECLARATION.name(), - List.of(left, right), - source - )); - } -} diff --git a/src/main/java/org/shedlang/compiler/patio/ShidToPatioLocalSpace.java b/src/main/java/org/shedlang/compiler/patio/ShidToPatioLocalSpace.java deleted file mode 100644 index 48a6a9c6..00000000 --- a/src/main/java/org/shedlang/compiler/patio/ShidToPatioLocalSpace.java +++ /dev/null @@ -1,48 +0,0 @@ -package org.shedlang.compiler.patio; - -public enum ShidToPatioLocalSpace { - BINARY_OP_RESULT("binaryOpResult"), - CALL_ARG_POSITIONAL("callArgPositional"), - CALL_ARG_NAMED("callArgNamed"), - CALL_FUNCTION_POINTER("callFunctionPointer"), - CLOSURE("closure"), - CLOSURE_POINTER("closurePointer"), - CLOSURE_FUNCTION_POINTER("closureFunctionPointer"), - EFFECT_HANDLER("effectHandler"), - EFFECT_HANDLER_CURRENT("effectHandlerCurrent"), - EFFECT_HANDLER_METHOD("effectHandlerMethod"), - EFFECT_HANDLER_METHOD_POINTER("effectHandlerMethodPointer"), - GC_ROOT_STACK_INDEX("gcRootStackIndex"), - INT("int"), - MAIN("main"), - NAMESPACE_IS_INITED_POINTER("namespaceIsInitedPointer"), - NAMESPACE_POINTER("namespacePointer"), - NAMESPACE_VALUE("namespaceValue"), - LOCAL("local"), - RECEIVER("receiver"), - STRING("string"), - STRUCT_TAG_POINTER("structTagPointer"), - STRUCT_TYPE("structType"), - STRUCT_VALUE("structValue"), - STRUCT_VALUE_POINTER("structValuePointer"), - SWITCH_TAG("switchTag"), - TEMPORARY("tmp"), - TUPLE("tuple"), - TUPLE_ELEMENT("tupleElement"), - TUPLE_POINTER("tuplePointer"), - USER_DEFINED_EFFECT("userDefinedEffect"), - USER_DEFINED_EFFECT_METHOD("userDefinedMethod"), - USER_DEFINED_EFFECT_POINTER("userDefinedEffectPointer"), - VAR_VALUE("varValue"); - - private final String name; - - ShidToPatioLocalSpace(String name) { - this.name = name; - } - - @Override - public String toString() { - return name; - } -} diff --git a/src/main/java/org/shedlang/compiler/patio/ShidToPatioNamespaces.java b/src/main/java/org/shedlang/compiler/patio/ShidToPatioNamespaces.java deleted file mode 100644 index e04b58af..00000000 --- a/src/main/java/org/shedlang/compiler/patio/ShidToPatioNamespaces.java +++ /dev/null @@ -1,310 +0,0 @@ -package org.shedlang.compiler.patio; - -import org.shedlang.compiler.patio.ast.PatioFunctionDeclaration; -import org.shedlang.compiler.patio.ast.PatioVisibility; -import org.shedlang.compiler.patio.ast.instructions.*; -import org.shedlang.compiler.patio.ast.operands.PatioBool; -import org.shedlang.compiler.patio.ast.operands.PatioDataPtr; -import org.shedlang.compiler.patio.ast.operands.PatioLocalRef; -import org.shedlang.compiler.patio.ast.operands.PatioOperand; -import org.shedlang.compiler.patio.ast.types.*; -import org.shedlang.compiler.sources.Source; -import org.shedlang.compiler.sources.Sources; -import org.shedlang.compiler.types.NamespaceName; -import org.shedlang.compiler.types.NamespaceTypeInfo; -import org.shedlang.compiler.util.Lists; - -import java.util.List; -import java.util.Optional; -import java.util.function.Function; - -public class ShidToPatioNamespaces { - public static final PatioType NAMESPACE_VALUE_TYPE = ShidToPatioTypes.VALUE_TYPE; - - private ShidToPatioNamespaces() {} - - public static ShidToPatioContext define( - NamespaceName namespaceName, - Function generateInitBody, - ShidToPatioContext context - ) { - // TODO: proper source. Probably wrap up stack namespace in a data structure with a source? - var source = Sources.NULL; - - var namespaceTypeInfo = context.namespaceTypeInfo(namespaceName); - var layout = namespaceDataLayout(namespaceTypeInfo); - - context = context.addDataElementMutable( - globalNameNamespaceValue(namespaceName), - PatioDataValues.dataPointerNull(), - source - ); - - context = context.addDataElementMutable( - globalNameNamespaceIsInited(namespaceName), - PatioDataValues.bool(false), - source - ); - - context = context.createFunction( - globalNameNamespaceInit(namespaceName), - PatioVisibility.PRIVATE, - PatioTypes.VOID, - source, - initContext -> { - var namespaceValueResult = initContext.allocateVal( - ShidToPatioLocalSpace.NAMESPACE_VALUE, - PatioTypes.DATA_POINTER - ); - var namespaceValue = namespaceValueResult.value(); - initContext = namespaceValueResult.context(); - - initContext = ShidToPatioGc.alloc( - namespaceValue, - layout, - GC_CHILDREN_OFFSET, - namespaceTypeInfo.fieldCount(), - source, - initContext - ); - - initContext = initContext.addInstruction(new PatioMemoryStore( - new PatioDataPtr(globalNameNamespaceValue(namespaceName)), - PatioDataLayouts.DATA_POINTER, - List.of(), - namespaceValue, - source - )); - - initContext = generateInitBody.apply(initContext); - - initContext = initContext.addInstruction(new PatioMemoryStore( - new PatioDataPtr(globalNameNamespaceIsInited(namespaceName)), - PatioDataLayouts.BOOL, - List.of(), - new PatioBool(true), - source - )); - - initContext = initContext.addInstruction(new PatioReturnVoid(source)); - - return initContext; - } - ); - - context = context.createFunction( - globalNameNamespaceImport(namespaceName), - PatioVisibility.PUBLIC, - NAMESPACE_VALUE_TYPE, - source, - importContext -> { - var isInitedResult = importContext.allocateVal( - ShidToPatioLocalSpace.TEMPORARY, - PatioTypes.BOOL - ); - var isInited = isInitedResult.value(); - importContext = isInitedResult.context(); - - importContext = importContext.addInstruction(new PatioMemoryLoad( - isInited, - new PatioDataPtr(globalNameNamespaceIsInited(namespaceName)), - PatioDataLayouts.BOOL, - List.of(), - source - )); - - importContext = importContext.addInstruction(new PatioIf( - List.of(), - isInited, - new PatioBlock( - List.of(), - List.of(), - source - ), - new PatioBlock( - List.of( - new PatioCall( - Optional.empty(), - globalNameNamespaceInit(namespaceName), - List.of(), - source - ) - ), - List.of(), - source - ), - source - )); - - var namespaceValuePointerResult = importContext.allocateVal( - ShidToPatioLocalSpace.NAMESPACE_POINTER, - NAMESPACE_VALUE_TYPE - ); - var namespaceValuePointer = namespaceValuePointerResult.value(); - importContext = namespaceValuePointerResult.context(); - - importContext = importContext.addInstruction(new PatioMemoryLoad( - namespaceValuePointer, - new PatioDataPtr(globalNameNamespaceValue(namespaceName)), - PatioDataLayouts.DATA_POINTER, - List.of(), - source - )); - - var namespaceValueResult = importContext.allocateVal( - ShidToPatioLocalSpace.NAMESPACE_VALUE, - NAMESPACE_VALUE_TYPE - ); - var namespaceValue = namespaceValueResult.value(); - importContext = namespaceValueResult.context(); - - importContext = importContext.addInstruction(new PatioDataPtrToInt( - namespaceValue, - namespaceValuePointer, - source - )); - - importContext = importContext.addInstruction(new PatioReturn( - namespaceValue, - source - )); - - return importContext; - } - ); - - return context; - } - - public static ShidToPatioContext importValue( - PatioLocalRef target, - NamespaceName namespaceName, - Source source, - ShidToPatioContext context - ) { - context = context.addCompilationUnitElement(new PatioFunctionDeclaration( - globalNameNamespaceImport(namespaceName), - List.of(), - NAMESPACE_VALUE_TYPE, - source - )); - - context = context.addInstruction(new PatioCall( - Optional.of(target), - globalNameNamespaceImport(namespaceName), - List.of(), - source - )); - - return context; - } - - public static ShidToPatioContext fieldLoad( - PatioLocalRef target, - PatioOperand receiver, - NamespaceName namespaceName, - String fieldName, - Source source, - ShidToPatioContext context - ) { - var namespaceTypeInfo = context.namespaceTypeInfo(namespaceName); - var layout = namespaceDataLayout(namespaceTypeInfo); - - var namespacePointerResult = context.allocateVal( - ShidToPatioLocalSpace.NAMESPACE_POINTER, - namespaceNameToPatioIdentifier(namespaceName), - PatioTypes.DATA_POINTER - ); - var namespacePointer = namespacePointerResult.value(); - context = namespacePointerResult.context(); - - context = context.addInstruction(new PatioIntToDataPtr( - namespacePointer, - receiver, - source - )); - - context = context.addInstruction(new PatioMemoryLoad( - target, - namespacePointer, - layout, - fieldOffset(namespaceTypeInfo.fieldIndex(fieldName)), - source - )); - - return context; - } - - public static ShidToPatioContext fieldStore( - NamespaceName namespaceName, - String fieldName, - PatioOperand fieldValue, - Source source, - ShidToPatioContext context - ) { - var namespaceTypeInfo = context.namespaceTypeInfo(namespaceName); - var layout = namespaceDataLayout(namespaceTypeInfo); - - var namespaceValueResult = context.allocateVal( - ShidToPatioLocalSpace.NAMESPACE_VALUE, - PatioTypes.DATA_POINTER - ); - var namespaceValue = namespaceValueResult.value(); - context = namespaceValueResult.context(); - - context = context.addInstruction(new PatioMemoryLoad( - namespaceValue, - new PatioDataPtr(globalNameNamespaceValue(namespaceName)), - PatioDataLayouts.DATA_POINTER, - List.of(), - source - )); - - context = context.addInstruction(new PatioMemoryStore( - namespaceValue, - layout, - fieldOffset(namespaceTypeInfo.fieldIndex(fieldName)), - fieldValue, - source - )); - - return context; - } - - private static PatioDataLayout namespaceDataLayout(NamespaceTypeInfo namespaceTypeInfo) { - return ShidToPatioGc.gcObjectDataLayout(PatioDataLayouts.struct( - Lists.repeat( - PatioDataLayouts.INT, - namespaceTypeInfo.fieldCount() - ) - )); - } - - private static List fieldOffset(int fieldIndex) { - return ShidToPatioGc.gcObjectOffset(List.of(fieldIndex)); - } - - private static final List GC_CHILDREN_OFFSET = - ShidToPatioGc.gcObjectOffset(List.of()); - - // TODO: allocate names through context - private static String globalNameNamespaceValue(NamespaceName namespaceName) { - return "shed__namespace__" + namespaceNameToPatioIdentifier(namespaceName); - } - - private static String globalNameNamespaceInit(NamespaceName namespaceName) { - return "shed__namespaceInit__" + namespaceNameToPatioIdentifier(namespaceName); - } - - private static String globalNameNamespaceIsInited(NamespaceName namespaceName) { - return "shed__namespaceIsInited__" + namespaceNameToPatioIdentifier(namespaceName); - } - - private static String globalNameNamespaceImport(NamespaceName namespaceName) { - return "shed__namespaceImport__" + namespaceNameToPatioIdentifier(namespaceName); - } - - public static String namespaceNameToPatioIdentifier(NamespaceName namespaceName) { - return String.join("_", namespaceName.parts()); - } -} diff --git a/src/main/java/org/shedlang/compiler/patio/ShidToPatioResult.java b/src/main/java/org/shedlang/compiler/patio/ShidToPatioResult.java deleted file mode 100644 index ed5abcdd..00000000 --- a/src/main/java/org/shedlang/compiler/patio/ShidToPatioResult.java +++ /dev/null @@ -1,4 +0,0 @@ -package org.shedlang.compiler.patio; - -public record ShidToPatioResult(T value, ShidToPatioContext context) { -} diff --git a/src/main/java/org/shedlang/compiler/patio/ShidToPatioStrings.java b/src/main/java/org/shedlang/compiler/patio/ShidToPatioStrings.java deleted file mode 100644 index 8294e699..00000000 --- a/src/main/java/org/shedlang/compiler/patio/ShidToPatioStrings.java +++ /dev/null @@ -1,84 +0,0 @@ -package org.shedlang.compiler.patio; - -import org.shedlang.compiler.patio.ast.PatioDataElementImmutable; -import org.shedlang.compiler.patio.ast.PatioFunctionDeclaration; -import org.shedlang.compiler.patio.ast.PatioLocal; -import org.shedlang.compiler.patio.ast.instructions.PatioCall; -import org.shedlang.compiler.patio.ast.operands.PatioDataPtr; -import org.shedlang.compiler.patio.ast.operands.PatioLocalRef; -import org.shedlang.compiler.patio.ast.operands.PatioOperand; -import org.shedlang.compiler.patio.ast.types.PatioDataLayouts; -import org.shedlang.compiler.patio.ast.types.PatioDataValue; -import org.shedlang.compiler.patio.ast.types.PatioDataValues; -import org.shedlang.compiler.sources.Source; -import org.shedlang.compiler.sources.Sources; - -import java.nio.charset.StandardCharsets; -import java.util.ArrayList; -import java.util.List; -import java.util.Optional; - -public class ShidToPatioStrings { - public static final PatioFunctionDeclaration STRING_ADD_DECLARATION = new PatioFunctionDeclaration( - "shed__runtime__string_add", - List.of( - PatioLocal.param("left", ShidToPatioTypes.VALUE_TYPE), - PatioLocal.param("right", ShidToPatioTypes.VALUE_TYPE) - ), - ShidToPatioTypes.VALUE_TYPE, - Sources.RUNTIME - ); - - private ShidToPatioStrings() {} - - public static ShidToPatioResult define( - String value, - Source source, - ShidToPatioContext context - ) { - var codeUnits = value.getBytes(StandardCharsets.UTF_8); - - var codeUnitsDataValues = new ArrayList(); - for (var codeUnit : codeUnits) { - codeUnitsDataValues.add(PatioDataValues.byte_(codeUnit)); - } - - var dataValue = ShidToPatioGc.gcObjectStaticDataValue(PatioDataValues.struct(List.of( - PatioDataValues.int_(codeUnits.length), - PatioDataValues.array(PatioDataLayouts.BYTE, codeUnitsDataValues) - ))); - - var elementNameResult = context.allocateCompilationUnitElementName( - ShidToPatioCompilationUnitElementSpace.STRING - ); - var elementName = elementNameResult.value(); - context = elementNameResult.context(); - - context = context.addCompilationUnitElement(new PatioDataElementImmutable( - elementName, - dataValue, - source - )); - - return context.toResult(new PatioDataPtr(elementName)); - } - - public static ShidToPatioContext add( - PatioLocalRef target, - PatioOperand left, - PatioOperand right, - Source source, - ShidToPatioContext context - ) { - context = context.ensureCompilationUnitElement(STRING_ADD_DECLARATION); - - context = context.addInstruction(new PatioCall( - Optional.of(target), - STRING_ADD_DECLARATION.name(), - List.of(left, right), - source - )); - - return context; - } -} diff --git a/src/main/java/org/shedlang/compiler/patio/ShidToPatioStructs.java b/src/main/java/org/shedlang/compiler/patio/ShidToPatioStructs.java deleted file mode 100644 index cc1e79f0..00000000 --- a/src/main/java/org/shedlang/compiler/patio/ShidToPatioStructs.java +++ /dev/null @@ -1,200 +0,0 @@ -package org.shedlang.compiler.patio; - -import org.shedlang.compiler.ast.typed.FreeVariables; -import org.shedlang.compiler.patio.ast.instructions.*; -import org.shedlang.compiler.patio.ast.operands.PatioInt; -import org.shedlang.compiler.patio.ast.operands.PatioLocalRef; -import org.shedlang.compiler.patio.ast.operands.PatioOperand; -import org.shedlang.compiler.patio.ast.types.PatioDataLayout; -import org.shedlang.compiler.patio.ast.types.PatioDataLayouts; -import org.shedlang.compiler.patio.ast.types.PatioTypes; -import org.shedlang.compiler.sources.Source; -import org.shedlang.compiler.shid.instructions.ShidDefineFunction; -import org.shedlang.compiler.shid.instructions.ShidDefineStruct; -import org.shedlang.compiler.types.StructType; -import org.shedlang.compiler.util.Lists; - -import java.util.List; - -public class ShidToPatioStructs { - private ShidToPatioStructs() { - } - - public static ShidToPatioContext createType( - PatioLocalRef target, - StructType type, - List fields, - Source source, - ShidToPatioContext context - ) { - return ShidToPatioFunctions.create( - target, - type.name(), - List.of(), - fields.stream() - .map(field -> new ShidDefineFunction.Param(field.name(), field.source())) - .toList(), - FreeVariables.empty(), - bodyContext -> { - var valuePointerResult = bodyContext.allocateVal( - ShidToPatioLocalSpace.STRUCT_VALUE_POINTER, - PatioTypes.DATA_POINTER - ); - var valuePointer = valuePointerResult.value(); - bodyContext = valuePointerResult.context(); - - var structDataLayout = structDataLayout(type, context); - - bodyContext = ShidToPatioGc.alloc( - valuePointer, - structDataLayout, - GC_CHILDREN_OFFSET, - fields.size(), - source, - bodyContext - ); - - bodyContext = bodyContext - .addInstruction(new PatioMemoryStore( - valuePointer, - structDataLayout, - TAG_OFFSET, - new PatioInt(context.structTag(type)), - source - )); - - for (var fieldIndex = 0; fieldIndex < fields.size(); fieldIndex++) { - var field = fields.get(fieldIndex); - - bodyContext = bodyContext - .addInstruction(new PatioMemoryStore( - valuePointer, - structDataLayout, - fieldOffset(fieldIndex), - bodyContext.shidLocalNameToLocal(field.name()), - source - )); - } - - var valueResult = bodyContext.allocateVal( - ShidToPatioLocalSpace.STRUCT_VALUE, - ShidToPatioTypes.VALUE_TYPE - ); - var value = valueResult.value(); - bodyContext = valueResult.context(); - - bodyContext = bodyContext.addInstruction(new PatioDataPtrToInt( - value, - valuePointer, - source - )); - - bodyContext = bodyContext.addInstruction(new PatioReturn(value, source)); - - return bodyContext; - }, - source, - context - ); - } - - public static ShidToPatioContext fieldLoad( - PatioLocalRef target, - PatioOperand receiver, - StructType type, - String fieldName, - Source source, - ShidToPatioContext context - ) { - var valuePointerResult = context.allocateVal( - ShidToPatioLocalSpace.STRUCT_VALUE_POINTER, - PatioTypes.DATA_POINTER - ); - var valuePointer = valuePointerResult.value(); - context = valuePointerResult.context(); - - context = context.addInstruction(new PatioIntToDataPtr( - valuePointer, - receiver, - source - )); - - var structDataLayout = structDataLayout(type, context); - - var structTypeInfo = context.structTypeInfo(type); - var fieldIndex = structTypeInfo.fieldIndex(fieldName); - - context = context.addInstruction(new PatioMemoryLoad( - target, - valuePointer, - structDataLayout, - fieldOffset(fieldIndex), - source - )); - - return context; - } - - public static ShidToPatioContext tagLoad( - PatioLocalRef target, - PatioOperand receiver, - Source source, - ShidToPatioContext context - ) { - var valuePointerResult = context.allocateVal( - ShidToPatioLocalSpace.STRUCT_VALUE_POINTER, - PatioTypes.DATA_POINTER - ); - var valuePointer = valuePointerResult.value(); - context = valuePointerResult.context(); - - context = context.addInstruction(new PatioIntToDataPtr( - valuePointer, - receiver, - source - )); - - var structDataLayout = unknownStructDataLayout(); - - context = context.addInstruction(new PatioMemoryLoad( - target, - valuePointer, - structDataLayout, - TAG_OFFSET, - source - )); - - return context; - } - - private static PatioDataLayout unknownStructDataLayout() { - return ShidToPatioGc.gcObjectDataLayout(PatioDataLayouts.struct(List.of( - PatioDataLayouts.INT - ))); - } - - private static PatioDataLayout structDataLayout( - StructType type, - ShidToPatioContext context - ) { - var structTypeInfo = context.structTypeInfo(type); - - return ShidToPatioGc.gcObjectDataLayout(PatioDataLayouts.struct(List.of( - PatioDataLayouts.INT, - PatioDataLayouts.struct(Lists.repeat( - PatioDataLayouts.INT, - structTypeInfo.fieldCount() - )) - ))); - } - - private static final List TAG_OFFSET - = ShidToPatioGc.gcObjectOffset(List.of(0)); - - private static List fieldOffset(int fieldIndex) { - return ShidToPatioGc.gcObjectOffset(List.of(1, fieldIndex)); - } - - private static final List GC_CHILDREN_OFFSET = - ShidToPatioGc.gcObjectOffset(List.of(1)); -} diff --git a/src/main/java/org/shedlang/compiler/patio/ShidToPatioTuples.java b/src/main/java/org/shedlang/compiler/patio/ShidToPatioTuples.java deleted file mode 100644 index 7bfbaeb8..00000000 --- a/src/main/java/org/shedlang/compiler/patio/ShidToPatioTuples.java +++ /dev/null @@ -1,132 +0,0 @@ -package org.shedlang.compiler.patio; - -import org.shedlang.compiler.patio.ast.instructions.*; -import org.shedlang.compiler.patio.ast.operands.PatioInt; -import org.shedlang.compiler.patio.ast.operands.PatioLocalRef; -import org.shedlang.compiler.patio.ast.operands.PatioOperand; -import org.shedlang.compiler.patio.ast.types.PatioDataLayout; -import org.shedlang.compiler.patio.ast.types.PatioDataLayouts; -import org.shedlang.compiler.patio.ast.types.PatioTypes; -import org.shedlang.compiler.sources.Source; -import org.shedlang.compiler.util.Lists; - -import java.util.List; - -public class ShidToPatioTuples { - private ShidToPatioTuples() { - } - - public static ShidToPatioResult create( - List elements, - Source source, - ShidToPatioContext context - ) { - var tupleResult = context.allocateVal( - ShidToPatioLocalSpace.TUPLE, - ShidToPatioTypes.VALUE_TYPE - ); - var tuple = tupleResult.value(); - context = tupleResult.context(); - - if (elements.size() == 0) { - context = context.addInstruction(new PatioLocalStore( - tuple, - new PatioInt(0), - source - )); - - return context.toResult(tuple); - } - - var tuplePointerResult = context.allocateVal( - ShidToPatioLocalSpace.TUPLE_POINTER, - PatioTypes.DATA_POINTER - ); - var tuplePointer = tuplePointerResult.value(); - context = tuplePointerResult.context(); - - var tupleLayout = tupleDataLayout(elements.size()); - - context = ShidToPatioGc.alloc( - tuplePointer, - tupleLayout, - GC_CHILDREN_OFFSET, - elements.size(), - source, - context - ); - - for (var elementIndex = 0; elementIndex < elements.size(); elementIndex++) { - var element = elements.get(elementIndex); - - context = context.addInstruction(new PatioMemoryStore( - tuplePointer, - tupleLayout, - elementOffset(elementIndex), - element, - source - )); - } - - context = context.addInstruction(new PatioDataPtrToInt( - tuple, - tuplePointer, - source - )); - - return context.toResult(tuple); - } - - public static ShidToPatioResult get( - PatioOperand tuple, - int elementIndex, - int elementCount, - Source source, - ShidToPatioContext context - ) { - var tuplePointerResult = context.allocateVal( - ShidToPatioLocalSpace.TUPLE, - PatioTypes.DATA_POINTER - ); - var tuplePointer = tuplePointerResult.value(); - context = tuplePointerResult.context(); - - context = context.addInstruction(new PatioIntToDataPtr( - tuplePointer, - tuple, - source - )); - - var targetResult = context.allocateVal( - ShidToPatioLocalSpace.TUPLE_ELEMENT, - Integer.toString(elementIndex), - ShidToPatioTypes.VALUE_TYPE - ); - var target = targetResult.value(); - context = targetResult.context(); - - context = context.addInstruction(new PatioMemoryLoad( - target, - tuplePointer, - tupleDataLayout(elementCount), - elementOffset(elementIndex), - source - )); - - return context.toResult(target); - } - - private static PatioDataLayout tupleDataLayout(int elementCount) { - return ShidToPatioGc.gcObjectDataLayout(PatioDataLayouts.struct(Lists.repeat( - PatioDataLayouts.INT, - elementCount - ))); - } - - private static List elementOffset(int elementIndex) { - return ShidToPatioGc.gcObjectOffset(List.of(elementIndex)); - } - - private static final List GC_CHILDREN_OFFSET = - ShidToPatioGc.gcObjectOffset(List.of()); -} diff --git a/src/main/java/org/shedlang/compiler/patio/ShidToPatioTypes.java b/src/main/java/org/shedlang/compiler/patio/ShidToPatioTypes.java deleted file mode 100644 index 0035d210..00000000 --- a/src/main/java/org/shedlang/compiler/patio/ShidToPatioTypes.java +++ /dev/null @@ -1,11 +0,0 @@ -package org.shedlang.compiler.patio; - -import org.shedlang.compiler.patio.ast.types.PatioType; -import org.shedlang.compiler.patio.ast.types.PatioTypes; - -public class ShidToPatioTypes { - private ShidToPatioTypes() {} - - public static final PatioType TAG_TYPE = PatioTypes.INT; - public static final PatioType VALUE_TYPE = PatioTypes.INT; -} diff --git a/src/main/java/org/shedlang/compiler/patio/ShidToPatioVars.java b/src/main/java/org/shedlang/compiler/patio/ShidToPatioVars.java deleted file mode 100644 index 18854fd0..00000000 --- a/src/main/java/org/shedlang/compiler/patio/ShidToPatioVars.java +++ /dev/null @@ -1,80 +0,0 @@ -package org.shedlang.compiler.patio; - -import org.shedlang.compiler.patio.ast.instructions.PatioMemoryLoad; -import org.shedlang.compiler.patio.ast.instructions.PatioMemoryStore; -import org.shedlang.compiler.patio.ast.operands.PatioLocalRef; -import org.shedlang.compiler.patio.ast.operands.PatioOperand; -import org.shedlang.compiler.patio.ast.types.PatioDataLayout; -import org.shedlang.compiler.patio.ast.types.PatioDataLayouts; -import org.shedlang.compiler.patio.ast.types.PatioTypes; -import org.shedlang.compiler.sources.Source; - -import java.util.List; - -public class ShidToPatioVars { - private ShidToPatioVars() { - } - - private static final PatioDataLayout VAR_DATA_LAYOUT = - ShidToPatioGc.gcObjectDataLayout(PatioDataLayouts.fromType(ShidToPatioTypes.VALUE_TYPE)); - - private static final List VALUE_OFFSET = ShidToPatioGc.gcObjectOffset(List.of()); - private static final List GC_CHILDREN_OFFSET = ShidToPatioGc.gcObjectOffset(List.of()); - private static final int GC_CHILDREN_COUNT = 1; - - public static ShidToPatioContext alloc( - String shidName, - Source source, - ShidToPatioContext context - ) { - var patioLocalResult = context.declareShidVal( - shidName, - PatioTypes.DATA_POINTER - ); - var patioLocal = patioLocalResult.value(); - context = patioLocalResult.context(); - - context = ShidToPatioGc.alloc( - patioLocal, - VAR_DATA_LAYOUT, - GC_CHILDREN_OFFSET, - GC_CHILDREN_COUNT, - source, - context - ); - - context = context.initShidLocal(shidName); - - return context; - } - - public static ShidToPatioContext store( - String shidName, - PatioOperand value, - Source source, - ShidToPatioContext context - ) { - return context.addInstruction(new PatioMemoryStore( - context.shidLocalNameToLocal(shidName), - VAR_DATA_LAYOUT, - VALUE_OFFSET, - value, - source - )); - } - - public static ShidToPatioContext load( - PatioLocalRef target, - String shidName, - Source source, - ShidToPatioContext context - ) { - return context.addInstruction(new PatioMemoryLoad( - target, - context.shidLocalNameToLocal(shidName), - VAR_DATA_LAYOUT, - VALUE_OFFSET, - source - )); - } -} diff --git a/src/main/java/org/shedlang/compiler/patio/errors/DuplicateCompilationUnitElementName.java b/src/main/java/org/shedlang/compiler/patio/errors/DuplicateCompilationUnitElementName.java deleted file mode 100644 index 264d7da8..00000000 --- a/src/main/java/org/shedlang/compiler/patio/errors/DuplicateCompilationUnitElementName.java +++ /dev/null @@ -1,17 +0,0 @@ -package org.shedlang.compiler.patio.errors; - -import org.shedlang.compiler.errors.InternalCompilerError; -import org.shedlang.compiler.sources.Source; - -public class DuplicateCompilationUnitElementName extends InternalCompilerError { - private final String elementName; - - public DuplicateCompilationUnitElementName(String elementName, Source source) { - super("Duplicate compilation unit element name: " + elementName, source); - this.elementName = elementName; - } - - public String elementName() { - return elementName; - } -} diff --git a/src/main/java/org/shedlang/compiler/shidtopatio/ShidToPatio.java b/src/main/java/org/shedlang/compiler/shidtopatio/ShidToPatio.java new file mode 100644 index 00000000..62d374a3 --- /dev/null +++ b/src/main/java/org/shedlang/compiler/shidtopatio/ShidToPatio.java @@ -0,0 +1,1013 @@ +package org.shedlang.compiler.shidtopatio; + +import org.shedlang.compiler.patio.ast.PatioCompilationUnit; +import org.shedlang.compiler.patio.ast.PatioVisibility; +import org.shedlang.compiler.patio.ast.instructions.*; +import org.shedlang.compiler.patio.ast.operands.PatioInt; +import org.shedlang.compiler.patio.ast.operands.PatioLocalRef; +import org.shedlang.compiler.patio.ast.operands.PatioOperand; +import org.shedlang.compiler.patio.ast.types.PatioTypes; +import org.shedlang.compiler.shid.ShidNamespace; +import org.shedlang.compiler.shid.instructions.*; +import org.shedlang.compiler.sources.Source; +import org.shedlang.compiler.sources.Sources; +import org.shedlang.compiler.types.NamespaceName; + +import java.util.*; +import java.util.function.Function; + +import static org.shedlang.compiler.config.MainFunction.MAIN_FUNCTION_NAME; + +public class ShidToPatio { + private ShidToPatio() {} + + /** + * Generate a main function by importing the given namespace and calling the + * {@code main} field with no arguments. Callers are responsible for + * ensuring that such a field exists. + */ + public static ShidToPatioResult generateMain( + NamespaceName main, + Source source, + ShidToPatioContext context + ) { + var mainFunctionNameResult = context.allocateCompilationUnitElementName( + ShidToPatioCompilationUnitElementSpace.MAIN + ); + var mainFunctionName = mainFunctionNameResult.value(); + context = mainFunctionNameResult.context(); + + context = context.createFunction( + mainFunctionName, + PatioVisibility.PRIVATE, + PatioTypes.INT, + source, + mainContext -> { + var namespaceValueResult = mainContext.allocateVal( + ShidToPatioLocalSpace.NAMESPACE_VALUE, + ShidToPatioTypes.VALUE_TYPE + ); + var namespaceValue = namespaceValueResult.value(); + mainContext = namespaceValueResult.context(); + + mainContext = ShidToPatioNamespaces.importValue( + namespaceValue, + main, + source, + mainContext + ); + + var mainFieldResult = mainContext.allocateVal( + ShidToPatioLocalSpace.MAIN, + ShidToPatioTypes.VALUE_TYPE + ); + var mainField = mainFieldResult.value(); + mainContext = mainFieldResult.context(); + + mainContext = ShidToPatioNamespaces.fieldLoad( + mainField, + namespaceValue, + main, + MAIN_FUNCTION_NAME, + source, + mainContext + ); + + var exitCodeResult = mainContext.allocateVal( + ShidToPatioLocalSpace.MAIN, + ShidToPatioTypes.VALUE_TYPE + ); + var exitCode = exitCodeResult.value(); + mainContext = exitCodeResult.context(); + + mainContext = ShidToPatioClosures.call( + exitCode, + mainField, + List.of(), + List.of(), + source, + mainContext + ); + + mainContext = mainContext.addInstruction( + new PatioReturn(exitCode, source) + ); + + return mainContext; + } + ); + + return context.toResult(mainFunctionName); + } + + public static PatioCompilationUnit generateNamespace( + ShidNamespace shidNamespace, + ShidToPatioContext context + ) { + context = ShidToPatioNamespaces.define( + shidNamespace.namespaceName(), + initContext -> + generateBlockNoResults(shidNamespace.body(), initContext), + context + ); + + // TODO: set more appropriate source + return context.toCompilationUnit(Sources.NULL); + } + + public static ShidToPatioContext generateInstructions( + List shidInstructions, + ShidToPatioContext context + ) { + for (var shidInstruction : shidInstructions) { + context = generateInstruction(shidInstruction, context); + } + + return context; + } + + public static ShidToPatioContext generateInstruction( + ShidInstruction shidInstruction, + ShidToPatioContext context + ) { + return switch (shidInstruction) { + case ShidBlock shidBlock -> { + var patioBlockResult = generateBlock(shidBlock, context); + var patioBlock = patioBlockResult.value(); + context = patioBlockResult.context(); + + for (var instruction : patioBlock.body()) { + context = context.addInstruction(instruction); + } + + for (var result : patioBlock.results()) { + context = context.temporaryPush(result); + } + + yield context; + } + + case ShidCall call -> { + var namedArgsByName = new ArrayList>(); + for (var argName : call.namedArgNames().reversed()) { + var argResult = context.allocateVal( + ShidToPatioLocalSpace.CALL_ARG_NAMED, + argName, + ShidToPatioTypes.VALUE_TYPE + ); + var arg = argResult.value(); + context = argResult.context(); + + context = context.temporaryPopIntoLocal( + arg, + shidInstruction.source() + ); + + namedArgsByName.add(Map.entry(argName, arg)); + } + + var positionalArgs = new ArrayList(); + for (var i = 0; i < call.positionalArgCount(); i++) { + var argResult = context.allocateVal( + ShidToPatioLocalSpace.CALL_ARG_POSITIONAL, + Integer.toString(call.positionalArgCount() - i - 1), + ShidToPatioTypes.VALUE_TYPE + ); + var arg = argResult.value(); + context = argResult.context(); + + context = context.temporaryPopIntoLocal( + arg, + shidInstruction.source() + ); + + positionalArgs.add(arg); + } + Collections.reverse(positionalArgs); + + var receiverResult = context.allocateVal( + ShidToPatioLocalSpace.RECEIVER, + ShidToPatioTypes.VALUE_TYPE + ); + var receiver = receiverResult.value(); + context = receiverResult.context(); + + context = context.temporaryPopIntoLocal( + receiver, + shidInstruction.source() + ); + + var targetResult = context.allocateVal( + ShidToPatioLocalSpace.TEMPORARY, + ShidToPatioTypes.VALUE_TYPE + ); + var target = targetResult.value(); + context = targetResult.context(); + + yield ShidToPatioClosures.call( + target, + receiver, + positionalArgs, + namedArgsByName, + shidInstruction.source(), + context + ).temporaryPush(target); + } + + case ShidDefineEffect defineEffect -> { + var targetResult = context.allocateVal( + ShidToPatioLocalSpace.USER_DEFINED_EFFECT, + defineEffect.effect().name(), + ShidToPatioTypes.VALUE_TYPE + ); + var target = targetResult.value(); + context = targetResult.context(); + + context = ShidToPatioEffects.createUserDefinedEffect( + target, + defineEffect.effect(), + defineEffect.source(), + context + ); + + context = context.temporaryPush(target); + + yield context; + } + + case ShidDefineFunction defineFunction -> { + var targetResult = context.allocateVal( + ShidToPatioLocalSpace.CLOSURE, + defineFunction.name(), + ShidToPatioTypes.VALUE_TYPE + ); + var target = targetResult.value(); + context = targetResult.context(); + + Function generateBody = functionContext -> { + return generateBlockNoResults(defineFunction.body(), functionContext); + }; + + context = switch (defineFunction.variant()) { + case EFFECT_HANDLER_METHOD -> ShidToPatioEffects.createEffectHandlerMethod( + target, + defineFunction.name(), + defineFunction.positionalParams(), + defineFunction.namedParams(), + defineFunction.freeVariables(), + generateBody, + defineFunction.source(), + context + ); + case FUNCTION -> ShidToPatioFunctions.create( + target, + defineFunction.name(), + defineFunction.positionalParams(), + defineFunction.namedParams(), + defineFunction.freeVariables(), + generateBody, + defineFunction.source(), + context + ); + }; + + context = context.temporaryPush(target); + + yield context; + } + + case ShidDefineStruct defineStruct -> { + var targetResult = context.allocateVal( + ShidToPatioLocalSpace.STRUCT_TYPE, + defineStruct.type().name(), + ShidToPatioTypes.VALUE_TYPE + ); + var target = targetResult.value(); + context = targetResult.context(); + + context = ShidToPatioStructs.createType( + target, + defineStruct.type(), + defineStruct.fields(), + defineStruct.source(), + context + ); + + context = context.temporaryPush(target); + + yield context; + } + + case ShidDiscard discard -> + context.temporaryPop().context(); + + case ShidDuplicate duplicate -> { + var valueResult = context.temporaryPop(); + var value = valueResult.value(); + context = valueResult.context(); + + yield context.temporaryPush(value).temporaryPush(value); + } + + case ShidEffectHandlerBreak effectHandlerBreak -> { + var valueResult = context.temporaryPop(); + var value = valueResult.value(); + context = valueResult.context(); + + context = ShidToPatioEffects.break_( + effectHandlerBreak.effect(), + value, + effectHandlerBreak.source(), + context + ); + + yield context; + } + + case ShidFieldLoad fieldLoad -> { + var receiverResult = context.temporaryPop(); + var receiver = receiverResult.value(); + context = receiverResult.context(); + + var targetResult = context.allocateVal( + ShidToPatioLocalSpace.TEMPORARY, + fieldLoad.fieldName(), + ShidToPatioTypes.VALUE_TYPE + ); + var target = targetResult.value(); + context = targetResult.context(); + + switch (fieldLoad.receiver()) { + case ShidFieldLoad.Receiver.Effect receiverEffect -> { + context = ShidToPatioEffects.fieldLoad( + target, + receiver, + receiverEffect.effect(), + fieldLoad.fieldName(), + fieldLoad.source(), + context + ); + } + + case ShidFieldLoad.Receiver.Namespace receiverNamespace -> { + context = ShidToPatioNamespaces.fieldLoad( + target, + receiver, + receiverNamespace.name(), + fieldLoad.fieldName(), + fieldLoad.source(), + context + ); + } + + case ShidFieldLoad.Receiver.Struct receiverStruct -> { + context = ShidToPatioStructs.fieldLoad( + target, + receiver, + receiverStruct.type(), + fieldLoad.fieldName(), + fieldLoad.source(), + context + ); + } + } + + context = context.temporaryPush(target); + + yield context; + } + + case ShidIf if_ -> { + var conditionBoolResult = generateCondition(if_.source(), context); + var conditionBool = conditionBoolResult.value(); + context = conditionBoolResult.context(); + + var targets = new ArrayList(); + + for (var i = 0; i < if_.resultCount(); i++) { + var targetResult = context.allocateVal( + ShidToPatioLocalSpace.TEMPORARY, + ShidToPatioTypes.VALUE_TYPE + ); + var target = targetResult.value(); + context = targetResult.context(); + + targets.add(target); + } + + var trueBodyResult = generateBlock(if_.trueBody(), context); + var trueBody = trueBodyResult.value(); + context = trueBodyResult.context(); + + var falseBodyResult = generateBlock(if_.falseBody(), context); + var falseBody = falseBodyResult.value(); + context = falseBodyResult.context(); + + context = context.addInstruction(new PatioIf( + targets, + conditionBool, + trueBody, + falseBody, + if_.source() + )); + + for (var target : targets) { + context = context.temporaryPush(target); + } + + yield context; + } + + case ShidIntAdd intAdd -> + generateBinaryOperation( + (target, left, right, operationContext) -> + ShidToPatioInts.add( + target, + left, + right, + intAdd.source(), + operationContext + ), + context + ); + + case ShidIntEquals intEquals -> + generateComparison( + (target, left, right, operationContext) -> + ShidToPatioInts.equals( + target, + left, + right, + intEquals.source(), + operationContext + ), + intEquals.source(), + context + ); + + case ShidIntNotEqual intNotEqual -> + generateComparison( + (target, left, right, operationContext) -> + ShidToPatioInts.notEqual( + target, + left, + right, + intNotEqual.source(), + operationContext + ), + intNotEqual.source(), + context + ); + + case ShidIntSub intSub -> + generateBinaryOperation( + (target, left, right, operationContext) -> + ShidToPatioInts.sub( + target, + left, + right, + intSub.source(), + operationContext + ), + context + ); + + case ShidLocalDrop localDrop -> { + yield context; + } + + case ShidLocalLoad localLoad -> { + var local = context.shidLocalNameToLocal(localLoad.name()); + + yield context.temporaryPush(local); + } + + case ShidLocalStore localStore -> { + context = context.temporaryPopIntoLocal( + context.shidLocalNameToLocal(localStore.name()), + localStore.source() + ); + + context = context.initShidLocal(localStore.name()); + + yield context; + } + + case ShidLoopBreak loopBreak -> + context.addInstruction(new PatioLoopBreak(loopBreak.source())); + + case ShidLoopContinue loopContinue -> + context.addInstruction(new PatioLoopContinue(loopContinue.source())); + + case ShidLoop loop -> { + context = context.enterBlock(); + context = generateBlockNoResults(loop.body(), context); + + var bodyInstructionsResult = context.exitBlock(); + var bodyInstructions = bodyInstructionsResult.value(); + context = bodyInstructionsResult.context(); + + context = context.addInstruction(new PatioLoop(bodyInstructions, loop.source())); + + yield context; + } + + case ShidNamespaceFieldStore namespaceFieldStore -> { + var fieldValueResult = context.temporaryPop(); + var fieldValue = fieldValueResult.value(); + context = fieldValueResult.context(); + + context = ShidToPatioNamespaces.fieldStore( + namespaceFieldStore.namespaceName(), + namespaceFieldStore.fieldName(), + fieldValue, + namespaceFieldStore.source(), + context + ); + + yield context; + } + + case ShidNamespaceImport namespaceImport -> { + var namespaceValueResult = context.allocateVal( + ShidToPatioLocalSpace.NAMESPACE_VALUE, + ShidToPatioNamespaces.NAMESPACE_VALUE_TYPE + ); + var namespaceValue = namespaceValueResult.value(); + context = namespaceValueResult.context(); + + context = ShidToPatioNamespaces.importValue( + namespaceValue, + namespaceImport.namespaceName(), + namespaceImport.source(), + context + ); + + context = context.temporaryPush(namespaceValue); + + yield context; + } + + case ShidPushBool pushBool -> + pushValue(pushBool.value() ? 1 : 0, pushBool.source(), context); + + case ShidPushInt pushInt -> { + var targetResult = context.allocateVal( + ShidToPatioLocalSpace.INT, + ShidToPatioInts.INT_TYPE + ); + var target = targetResult.value(); + context = targetResult.context(); + + context = ShidToPatioInts.storeConst( + target, + pushInt.value(), + pushInt.source(), + context + ); + + context = context.temporaryPush(target); + + yield context; + } + + + case ShidPushString pushString -> { + var stringPtrOperandResult = ShidToPatioStrings.define( + pushString.value(), + pushString.source(), + context + ); + var stringPtrOperand = stringPtrOperandResult.value(); + context = stringPtrOperandResult.context(); + + var stringPtrResult = context.allocateVal( + ShidToPatioLocalSpace.STRING, + ShidToPatioTypes.VALUE_TYPE + ); + var stringPtr = stringPtrResult.value(); + context = stringPtrResult.context(); + + context = context.addInstruction(new PatioDataPtrToInt( + stringPtr, + stringPtrOperand, + pushString.source() + )); + + context = context.temporaryPush(stringPtr); + + yield context; + } + + case ShidPushUnit pushUnit -> + pushValue(0, pushUnit.source(), context); + + case ShidResume resume -> { + var valueResult = context.temporaryPop(); + var value = valueResult.value(); + context = valueResult.context(); + + context = ShidToPatioClosures.beforeExit( + List.of(value), + resume.source(), + context + ); + + yield ShidToPatioEffects.resume(value, resume.source(), context); + } + + case ShidReturn return_ -> { + var valueResult = context.temporaryPop(); + var value = valueResult.value(); + context = valueResult.context(); + + for (var onReturnInstruction : context.onReturn()) { + context = context.addInstruction(onReturnInstruction); + } + + + context = ShidToPatioClosures.beforeExit( + List.of(value), + return_.source(), + context + ); + + yield context.addInstruction(new PatioReturn(value, return_.source())); + } + + case ShidStringAdd stringAdd -> + generateBinaryOperation( + (target, left, right, operationContext) -> + ShidToPatioStrings.add( + target, + left, + right, + stringAdd.source(), + operationContext + ), + context + ); + + case ShidSwitch switch_ -> { + var targetResult = context.allocateVal( + ShidToPatioLocalSpace.TEMPORARY, + ShidToPatioTypes.VALUE_TYPE + ); + var target = targetResult.value(); + context = targetResult.context(); + + var valueResult = context.temporaryPop(); + var value = valueResult.value(); + context = valueResult.context(); + + var tagResult = context.allocateVal( + ShidToPatioLocalSpace.SWITCH_TAG, + ShidToPatioTypes.TAG_TYPE + ); + var tag = tagResult.value(); + context = tagResult.context(); + + context = ShidToPatioStructs.tagLoad( + tag, + value, + switch_.source(), + context + ); + + var cases = new ArrayList(); + + for (var shidCase : switch_.cases()) { + var bodyResult = generateBlock( + shidCase.body(), + context + ); + var body = bodyResult.value(); + context = bodyResult.context(); + + cases.add(new PatioSwitch.Case( + context.structTag(shidCase.caseType()), + body, + shidCase.source() + )); + } + + context = context.addInstruction(new PatioSwitch( + List.of(target), + tag, + cases, + new PatioBlock( + List.of( + new PatioUnreachable(switch_.source()) + ), + List.of(), + switch_.source() + ), + switch_.source() + )); + + context = context.temporaryPush(target); + + yield context; + } + + case ShidTry try_ -> { + var handlerMethodsByName = new HashMap(); + + for (var handlerMethodName : try_.handlerMethodNames().reversed()) { + var handlerMethodResult = context.temporaryPop(); + var handlerMethod = handlerMethodResult.value(); + context = handlerMethodResult.context(); + + handlerMethodsByName.put(handlerMethodName, handlerMethod); + } + + var targetResult = context.allocateVal( + ShidToPatioLocalSpace.TEMPORARY, + ShidToPatioTypes.VALUE_TYPE + ); + var target = targetResult.value(); + context = targetResult.context(); + + context = ShidToPatioEffects.try_( + target, + try_.handledEffect(), + handlerMethodsByName, + bodyContext -> + generateBlock(try_.body(), bodyContext), + try_.source(), + context + ); + + context = context.temporaryPush(target); + + yield context; + } + + case ShidTupleCreate tupleCreate -> { + var elements = new ArrayList(); + + for (var elementIndex = tupleCreate.elementCount(); elementIndex --> 0;) { + var tupleElementResult = context.allocateVal( + ShidToPatioLocalSpace.TUPLE_ELEMENT, + Integer.toString(elementIndex), + ShidToPatioTypes.VALUE_TYPE + ); + var tupleElement = tupleElementResult.value(); + context = tupleElementResult.context(); + + context = context.temporaryPopIntoLocal(tupleElement, tupleCreate.source()); + + elements.add(tupleElement); + } + + Collections.reverse(elements); + + var tupleResult = ShidToPatioTuples.create(elements, tupleCreate.source(), context); + var tuple = tupleResult.value(); + context = tupleResult.context(); + + yield context.temporaryPush(tuple); + } + + case ShidTupleGet tupleGet -> { + var tupleResult = context.temporaryPop(); + var tuple = tupleResult.value(); + context = tupleResult.context(); + + var targetResult = ShidToPatioTuples.get( + tuple, + tupleGet.elementIndex(), + tupleGet.elementCount(), + tupleGet.source(), + context + ); + var target = targetResult.value(); + context = targetResult.context(); + + yield context.temporaryPush(target); + } + + case ShidVarLoad varLoad -> { + var varValueResult = context.allocateVal( + ShidToPatioLocalSpace.VAR_VALUE, + varLoad.name(), + ShidToPatioTypes.VALUE_TYPE + ); + var varValue = varValueResult.value(); + context = varValueResult.context(); + + context = ShidToPatioVars.load( + varValue, + varLoad.name(), + varLoad.source(), + context + ); + + context = context.temporaryPush(varValue); + + yield context; + } + + case ShidVarStore varStore -> { + var valueResult = context.temporaryPop(); + var value = valueResult.value(); + context = valueResult.context(); + + context = ShidToPatioVars.store( + varStore.name(), + value, + varStore.source(), + context + ); + + yield context; + } + }; + } + + interface BinaryOperationCodeGen { + ShidToPatioContext generate( + PatioLocalRef target, + PatioOperand left, + PatioOperand right, + ShidToPatioContext context + ); + } + + private static ShidToPatioContext generateComparison( + BinaryOperationCodeGen binaryOperationCodeGen, + Source source, + ShidToPatioContext context + ) { + return generateBinaryOperation( + (target, left, right, operationContext) -> { + var targetBoolResult = operationContext.allocateVal( + ShidToPatioLocalSpace.TEMPORARY, + PatioTypes.INT + ); + var targetBool = targetBoolResult.value(); + operationContext = targetBoolResult.context(); + + operationContext = binaryOperationCodeGen.generate( + targetBool, + left, + right, + operationContext + ); + + operationContext = operationContext.addInstruction(new PatioBoolToInt( + target, + targetBool, + source + )); + + return operationContext; + }, + context + ); + } + + private static ShidToPatioContext generateBinaryOperation( + BinaryOperationCodeGen binaryOperationCodeGen, + ShidToPatioContext context + ) { + var rightResult = context.temporaryPop(); + var right = rightResult.value(); + context = rightResult.context(); + + var leftResult = context.temporaryPop(); + var left = leftResult.value(); + context = leftResult.context(); + + var targetResult = context.allocateVal( + ShidToPatioLocalSpace.BINARY_OP_RESULT, + ShidToPatioTypes.VALUE_TYPE + ); + var target = targetResult.value(); + context = targetResult.context(); + + return binaryOperationCodeGen.generate( + target, + left, + right, + context + ).temporaryPush(target); + } + + private static ShidToPatioContext generateBlockNoResults( + ShidBlock shidBlock, + ShidToPatioContext context + ) { + // TODO: just use a block in Patio instructions even where there are no targets? + var blockResult = generateBlock(shidBlock, context); + var block = blockResult.value(); + context = blockResult.context(); + + if (!block.results().isEmpty()) { + // TODO: better error + throw new RuntimeException("block has results"); + } + + for (var instruction : block.body()) { + context = context.addInstruction(instruction); + } + + return context; + } + + private static ShidToPatioResult generateBlock( + ShidBlock shidBlock, + ShidToPatioContext context + ) { + context = context.enterBlock(); + + context = declareShidVariables(shidBlock, context); + + for (var shidInstruction : shidBlock.instructions()) { + context = generateInstruction(shidInstruction, context); + } + + var targetsResult = context.temporaryPopAll(); + var targets = targetsResult.value().reversed(); + context = targetsResult.context(); + + var instructionsResult = context.exitBlock(); + var instructions = instructionsResult.value(); + context = instructionsResult.context(); + + return context.toResult(new PatioBlock( + instructions, + targets, + shidBlock.source() + )); + } + + private static ShidToPatioResult generateCondition( + Source source, + ShidToPatioContext context + ) { + var conditionIntResult = context.allocateVal( + ShidToPatioLocalSpace.TEMPORARY, + "conditionInt", + PatioTypes.INT + ); + var conditionInt = conditionIntResult.value(); + context = conditionIntResult.context(); + + context = context.temporaryPopIntoLocal(conditionInt, source); + + var conditionBoolResult = context.allocateVal( + ShidToPatioLocalSpace.TEMPORARY, + "conditionBool", + PatioTypes.BOOL + ); + var conditionBool = conditionBoolResult.value(); + context = conditionBoolResult.context(); + + context = context.addInstruction(new PatioIntToBool( + conditionBool, + conditionInt, + source + )); + + return context.toResult(conditionBool); + } + + private static ShidToPatioContext declareShidVariables( + ShidBlock body, + ShidToPatioContext context + ) { + for (var boundVariable : body.boundVariables()) { + switch (boundVariable.variant()) { + case PARAM -> { + // Params should be defined by the containing function. + } + case VAL -> { + context = context.declareShidVal( + boundVariable.name(), + ShidToPatioTypes.VALUE_TYPE + ).context(); + } + case VAR -> { + context = ShidToPatioVars.alloc( + boundVariable.name(), + // TODO: proper source (probably by storing variables on the function/namespace) + Sources.NULL, + context + ); + } + } + } + return context; + } + + private static ShidToPatioContext pushValue(int value, Source source, ShidToPatioContext context) { + var localResult = context.allocateVal(ShidToPatioLocalSpace.TEMPORARY, ShidToPatioTypes.VALUE_TYPE); + var local = localResult.value(); + context = localResult.context(); + + return context + .addInstruction(new PatioLocalStore(local, new PatioInt(value), source)) + .temporaryPush(local); + } +} diff --git a/src/main/java/org/shedlang/compiler/shidtopatio/ShidToPatioClosures.java b/src/main/java/org/shedlang/compiler/shidtopatio/ShidToPatioClosures.java new file mode 100644 index 00000000..5bc55bc3 --- /dev/null +++ b/src/main/java/org/shedlang/compiler/shidtopatio/ShidToPatioClosures.java @@ -0,0 +1,315 @@ +package org.shedlang.compiler.shidtopatio; + +import org.shedlang.compiler.ast.typed.FreeVariable; +import org.shedlang.compiler.ast.typed.FreeVariables; +import org.shedlang.compiler.patio.ast.PatioVisibility; +import org.shedlang.compiler.patio.ast.instructions.*; +import org.shedlang.compiler.patio.ast.operands.PatioFunctionPtr; +import org.shedlang.compiler.patio.ast.operands.PatioLocalRef; +import org.shedlang.compiler.patio.ast.operands.PatioOperand; +import org.shedlang.compiler.patio.ast.types.PatioDataLayout; +import org.shedlang.compiler.patio.ast.types.PatioDataLayouts; +import org.shedlang.compiler.patio.ast.types.PatioType; +import org.shedlang.compiler.patio.ast.types.PatioTypes; +import org.shedlang.compiler.shid.instructions.ShidDefineFunction; +import org.shedlang.compiler.sources.Source; +import org.shedlang.compiler.util.P; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.function.BiFunction; +import java.util.stream.Stream; + +import static org.shedlang.compiler.util.Iterables.sortedBy; + +class ShidToPatioClosures { + public static final PatioType CLOSURE_POINTER_TYPE = PatioTypes.DATA_POINTER; + public static final PatioType CLOSURE_TYPE = ShidToPatioTypes.VALUE_TYPE; + + private ShidToPatioClosures() {} + + private static PatioDataLayout closureDataLayoutForCall() { + return ShidToPatioGc.gcObjectDataLayout(PatioDataLayouts.struct(List.of( + PatioDataLayouts.FUNCTION_POINTER + ))); + } + + static PatioDataLayout closureDataLayout( + PatioDataLayout additional, + FreeVariables freeVariables, + ShidToPatioContext context + ) { + return ShidToPatioGc.gcObjectDataLayout(PatioDataLayouts.struct(List.of( + PatioDataLayouts.FUNCTION_POINTER, + additional, + PatioDataLayouts.struct( + freeVariables.stream() + .map(freeVariable -> PatioDataLayouts.fromType( + context.shidLocalType(freeVariable.name()) + )) + .toList() + ) + ))); + } + + static final List FUNCTION_POINTER_OFFSET + = ShidToPatioGc.gcObjectOffset(List.of(0)); + + static List additionalOffset(List offset) { + return ShidToPatioGc.gcObjectOffset(P.vector(1).plusAll(offset)); + } + + private static List freeVariableOffset( + FreeVariable freeVariable + ) { + return ShidToPatioGc.gcObjectOffset(List.of(2, freeVariable.index())); + } + + private static final List GC_CHILDREN_OFFSET = + ShidToPatioGc.gcObjectOffset(List.of(2)); + + static ShidToPatioContext defineParams( + List positionalParams, + List namedParams, + ShidToPatioContext bodyContext + ) { + var orderedNamedParams = sortedBy(namedParams, param -> param.name()); + var shidParams = Stream.concat(positionalParams.stream(), orderedNamedParams.stream()).toList(); + + for (var shidParam : shidParams) { + bodyContext = bodyContext.defineShidParam(shidParam.name()); + } + + return bodyContext; + } + + static ShidToPatioContext create( + PatioLocalRef target, + ShidToPatioCompilationUnitElementSpace functionElementSpace, + String name, + List positionalParams, + List namedParams, + PatioDataLayout layout, + BiFunction storeAdditional, + FreeVariables freeVariables, + BiFunction generateBody, + Source source, + ShidToPatioContext context + ) { + var fullNameResult = context.allocateCompilationUnitElementName( + functionElementSpace, + name + ); + var fullName = fullNameResult.value(); + context = fullNameResult.context(); + + var bodyContextParent = context; + context = context.createFunction(fullName, PatioVisibility.PRIVATE, ShidToPatioTypes.VALUE_TYPE, source, bodyContext -> { + var closurePointerResult = bodyContext.allocateParam( + ShidToPatioLocalSpace.CLOSURE_POINTER, + ShidToPatioClosures.CLOSURE_POINTER_TYPE + ); + var closurePointer = closurePointerResult.value(); + bodyContext = closurePointerResult.context(); + + bodyContext = defineParams(positionalParams, namedParams, bodyContext); + + bodyContext = loadFreeVariables( + freeVariables, + closurePointer, + layout, + source, + bodyContext, + bodyContextParent + ); + + bodyContext = ShidToPatioGc.saveGcRootStack(source, bodyContext); + + bodyContext = generateBody.apply(closurePointer, bodyContext); + + return bodyContext; + }); + + context = ShidToPatioClosures.alloc( + target, + name, + fullName, + layout, + storeAdditional, + freeVariables, + source, + context + ); + + return context; + } + + static ShidToPatioContext alloc( + PatioLocalRef target, + String name, + String functionName, + PatioDataLayout layout, + BiFunction storeAdditional, + FreeVariables freeVariables, + Source source, + ShidToPatioContext context + ) { + var closurePointerResult = context.allocateVal( + ShidToPatioLocalSpace.CLOSURE_POINTER, + name, + PatioTypes.DATA_POINTER + ); + var closurePointer = closurePointerResult.value(); + context = closurePointerResult.context(); + + context = ShidToPatioGc.alloc( + closurePointer, + layout, + GC_CHILDREN_OFFSET, + freeVariables.size(), + source, + context + ); + + context = context.addInstruction(new PatioMemoryStore( + closurePointer, + layout, + FUNCTION_POINTER_OFFSET, + new PatioFunctionPtr(functionName), + source + )); + + context = storeAdditional.apply(closurePointer, context); + + context = storeFreeVariables( + freeVariables, + closurePointer, + layout, + source, + context + ); + + context = context.addInstruction(new PatioDataPtrToInt( + target, + closurePointer, + source + )); + + return context; + } + + static ShidToPatioContext storeFreeVariables( + FreeVariables freeVariables, + PatioLocalRef closurePointer, + PatioDataLayout closureLayout, + Source source, + ShidToPatioContext context + ) { + for (var freeVariable : freeVariables) { + context = context.onceShidLocalDefined( + freeVariable.name(), + c -> c.addInstruction(new PatioMemoryStore( + closurePointer, + closureLayout, + freeVariableOffset(freeVariable), + c.shidLocalNameToLocal(freeVariable.name()), + source + )) + ); + } + return context; + } + + static ShidToPatioContext loadFreeVariables( + FreeVariables freeVariables, + PatioLocalRef closurePointer, + PatioDataLayout closureLayout, + Source source, + ShidToPatioContext bodyContext, + ShidToPatioContext bodyContextParent + ) { + for (var freeVariable : freeVariables) { + var freeVariableLocalResult = bodyContext.declareShidVal( + freeVariable.name(), + bodyContextParent.shidLocalType(freeVariable.name()) + ); + var freeVariableLocal = freeVariableLocalResult.value(); + bodyContext = freeVariableLocalResult.context(); + + bodyContext = bodyContext.addInstruction(new PatioMemoryLoad( + freeVariableLocal, + closurePointer, + closureLayout, + freeVariableOffset(freeVariable), + source + )); + + bodyContext = bodyContext.initShidLocal(freeVariable.name()); + } + return bodyContext; + } + + static ShidToPatioContext beforeExit( + List escapees, + Source source, + ShidToPatioContext context + ) { + return ShidToPatioGc.restoreGcRootStack(escapees, source, context); + } + + static ShidToPatioContext call( + PatioLocalRef target, + PatioLocalRef closure, + List positionalArgs, + List> namedArgsByName, + Source source, + ShidToPatioContext context + ) { + var closurePointerResult = context.allocateVal( + ShidToPatioLocalSpace.CLOSURE_POINTER, + CLOSURE_POINTER_TYPE + ); + var closurePointer = closurePointerResult.value(); + context = closurePointerResult.context(); + + context = context.addInstruction(new PatioIntToDataPtr( + closurePointer, + closure, + source + )); + + var functionPointerResult = context.allocateVal( + ShidToPatioLocalSpace.CALL_FUNCTION_POINTER, + PatioTypes.FUNCTION_POINTER + ); + var functionPointer = functionPointerResult.value(); + context = functionPointerResult.context(); + + context = context.addInstruction(new PatioMemoryLoad( + functionPointer, + closurePointer, + closureDataLayoutForCall(), + FUNCTION_POINTER_OFFSET, + source + )); + + var args = new ArrayList(); + + args.add(closurePointer); + + args.addAll(positionalArgs); + + for (var namedArg : sortedBy(namedArgsByName, x -> x.getKey())) { + args.add(namedArg.getValue()); + } + + return context + .addInstruction(new PatioCallPointer( + target, + functionPointer, + args, + source + )); + } +} diff --git a/src/main/java/org/shedlang/compiler/shidtopatio/ShidToPatioCompilationUnitElementSpace.java b/src/main/java/org/shedlang/compiler/shidtopatio/ShidToPatioCompilationUnitElementSpace.java new file mode 100644 index 00000000..babda049 --- /dev/null +++ b/src/main/java/org/shedlang/compiler/shidtopatio/ShidToPatioCompilationUnitElementSpace.java @@ -0,0 +1,19 @@ +package org.shedlang.compiler.shidtopatio; + +public enum ShidToPatioCompilationUnitElementSpace { + EFFECT_HANDLER_METHOD("effectHandlerMethod"), + FUNCTION("function"), + MAIN("main"), + STRING("string"); + + private final String name; + + ShidToPatioCompilationUnitElementSpace(String name) { + this.name = name; + } + + @Override + public String toString() { + return name; + } +} diff --git a/src/main/java/org/shedlang/compiler/shidtopatio/ShidToPatioContext.java b/src/main/java/org/shedlang/compiler/shidtopatio/ShidToPatioContext.java new file mode 100644 index 00000000..8870bc17 --- /dev/null +++ b/src/main/java/org/shedlang/compiler/shidtopatio/ShidToPatioContext.java @@ -0,0 +1,867 @@ +package org.shedlang.compiler.shidtopatio; + +import org.pcollections.OrderedPMap; +import org.pcollections.PMap; +import org.pcollections.PStack; +import org.pcollections.PVector; +import org.shedlang.compiler.backends.NameAllocator; +import org.shedlang.compiler.patio.ast.*; +import org.shedlang.compiler.patio.ast.instructions.PatioInstruction; +import org.shedlang.compiler.patio.ast.instructions.PatioLocalStore; +import org.shedlang.compiler.patio.ast.operands.PatioLocalRef; +import org.shedlang.compiler.patio.ast.operands.PatioOperand; +import org.shedlang.compiler.patio.ast.types.PatioDataValue; +import org.shedlang.compiler.patio.ast.types.PatioType; +import org.shedlang.compiler.shidtopatio.errors.DuplicateCompilationUnitElementName; +import org.shedlang.compiler.sources.Source; +import org.shedlang.compiler.typechecker.TypeInfos; +import org.shedlang.compiler.types.*; +import org.shedlang.compiler.util.CheckReturnValue; +import org.shedlang.compiler.util.P; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import java.util.function.Function; + +public record ShidToPatioContext( + GlobalContext globalContext, + CompilationUnitContext compilationUnitContext, + PStack blockStack, + FunctionContext functionContext +) { + public record GlobalContext( + TypeInfos typeInfos, + PMap structTags, + PMap effectTags + ) { + public static final GlobalContext EMPTY = forTypeInfos(TypeInfos.EMPTY); + + @CheckReturnValue + public static GlobalContext forTypeInfos(TypeInfos typeInfos) { + var structTags = generateStructTags(typeInfos); + var effectTags = generateEffectTags(typeInfos); + + return new GlobalContext( + typeInfos, + structTags, + effectTags + ); + } + + @CheckReturnValue + private static PMap generateStructTags(TypeInfos typeInfos) { + var tags = P.map(); + var nextTag = 0; + for (var structType : typeInfos.structTypes()) { + tags = tags.plus(structType, nextTag); + nextTag++; + } + return tags; + } + + @CheckReturnValue + private static PMap generateEffectTags(TypeInfos typeInfos) { + var tags = P.map(); + var nextTag = 0; + for (var effect : typeInfos.userDefinedEffects()) { + tags = tags.plus(effect, nextTag); + nextTag++; + } + return tags; + } + + @CheckReturnValue + public NamespaceTypeInfo namespaceTypeInfo(NamespaceName namespaceName) { + return typeInfos.namespaceTypeInfo(namespaceName) + // TODO: throw better error + .orElseThrow(() -> new RuntimeException("No type info for: " + namespaceName)); + } + + @CheckReturnValue + public StructTypeInfo structTypeInfo(StructType type) { + return typeInfos.structTypeInfo(type) + // TODO: throw better error + .orElseThrow(() -> new RuntimeException("No type info for: " + type)); + } + + @CheckReturnValue + public int structTag(StructType type) { + var tag = this.structTags.get(type); + if (tag == null) { + // TODO: throw better error + throw new RuntimeException("No tag for: " + type); + } else { + return tag; + } + } + + @CheckReturnValue + public UserDefinedEffectInfo userDefinedEffectInfo(UserDefinedEffect effect) { + return typeInfos.userDefinedEffectInfo(effect) + // TODO: throw better error + .orElseThrow(() -> new RuntimeException("No effect info for: " + effect)); + } + + @CheckReturnValue + public int effectTag(UserDefinedEffect effect) { + var tag = this.effectTags.get(effect); + if (tag == null) { + // TODO: throw better error + throw new RuntimeException("No tag for: " + effect); + } else { + return tag; + } + } + } + + public record CompilationUnitContext( + OrderedPMap elementsByName + ) { + public static CompilationUnitContext EMPTY = new CompilationUnitContext(OrderedPMap.empty()); + + @CheckReturnValue + public CompilationUnitContext addElement(PatioCompilationUnitElement element) { + // TODO: handle existing element with name. + return new CompilationUnitContext( + this.elementsByName.plus(element.name(), element) + ); + } + + @CheckReturnValue + private Result toResult(T value) { + return new Result<>(value, this); + } + + @CheckReturnValue + public Result allocateCompilationUnitName( + ShidToPatioCompilationUnitElementSpace space, + Optional name + ) { + var fullName = NameAllocator.allocateName( + elementsByName::containsKey, + "shed__" + space, + name + ); + + return toResult(fullName); + } + + @CheckReturnValue + public CompilationUnitContext addCompilationUnitElement( + PatioCompilationUnitElement element + ) { + if (this.elementsByName.containsKey(element.name())) { + throw new DuplicateCompilationUnitElementName(element.name(), element.source()); + } + + return new CompilationUnitContext( + this.elementsByName.plus(element.name(), element) + ); + } + + @CheckReturnValue + public CompilationUnitContext ensureCompilationUnitElement( + PatioCompilationUnitElement element + ) { + var existingElement = this.elementsByName.get(element.name()); + + if (existingElement == null) { + return new CompilationUnitContext( + this.elementsByName.plus(element.name(), element) + ); + } else if (existingElement.equals(element)) { + return this; + } else { + throw new DuplicateCompilationUnitElementName(element.name(), element.source()); + } + + } + + public record Result(T value, CompilationUnitContext context) {} + } + + public record FunctionContext( + PStack temporaryStack, + PVector instructions, + OrderedPMap localsByName, + PMap shidNameToLocal, + PMap>> waitingForShidLocal, + Optional stashedEffectHandler, + Optional stashedGcRootStackIndex, + PStack onReturn + ) { + public static final FunctionContext EMPTY = new FunctionContext( + P.stack(), + P.vector(), + OrderedPMap.empty(), + P.map(), + P.map(), + Optional.empty(), + Optional.empty(), + P.stack() + ); + + @CheckReturnValue + public Result temporaryPop() { + return new FunctionContext( + this.temporaryStack.minus(0), + this.instructions, + this.localsByName, + this.shidNameToLocal, + this.waitingForShidLocal, + this.stashedEffectHandler, + this.stashedGcRootStackIndex, + this.onReturn + ).toResult(this.temporaryStack.get(0)); + } + + @CheckReturnValue + public Result> temporaryPopAll() { + return new FunctionContext( + P.stack(), + this.instructions, + this.localsByName, + this.shidNameToLocal, + this.waitingForShidLocal, + this.stashedEffectHandler, + this.stashedGcRootStackIndex, + this.onReturn + ).toResult(this.temporaryStack); + } + + @CheckReturnValue + public FunctionContext temporaryPush(PatioOperand value) { + return new FunctionContext( + this.temporaryStack.plus(value), + this.instructions, + this.localsByName, + this.shidNameToLocal, + this.waitingForShidLocal, + this.stashedEffectHandler, + this.stashedGcRootStackIndex, + this.onReturn + ); + } + + @CheckReturnValue + public FunctionContext addInstruction(PatioInstruction instruction) { + return new FunctionContext( + this.temporaryStack, + this.instructions.plus(instruction), + this.localsByName, + this.shidNameToLocal, + this.waitingForShidLocal, + this.stashedEffectHandler, + this.stashedGcRootStackIndex, + this.onReturn + ); + } + + @CheckReturnValue + public Result allocateLocal( + ShidToPatioLocalSpace space, + Optional name, + Function createLocal + ) { + var fullName = NameAllocator.allocateName( + this.localsByName::containsKey, + space, + name + ); + + return new FunctionContext( + this.temporaryStack, + this.instructions, + this.localsByName.plus(fullName, createLocal.apply(fullName)), + this.shidNameToLocal, + this.waitingForShidLocal, + this.stashedEffectHandler, + this.stashedGcRootStackIndex, + this.onReturn + ).toResult(new PatioLocalRef(fullName)); + } + + @CheckReturnValue + public FunctionContext.Result declareShidLocal( + String name, + PatioType type, + PatioLocalType localType + ) { + var context = this; + + if (this.shidNameToLocal.containsKey(name)) { + // TODO: better error + throw new RuntimeException("Shid local already exists: " + name); + } + + var fullName = NameAllocator.allocateFixedName( + this.localsByName::containsKey, + ShidToPatioLocalSpace.LOCAL, + name + ); + + var localRef = new PatioLocalRef(fullName); + + context = new FunctionContext( + this.temporaryStack, + this.instructions, + this.localsByName.plus( + fullName, + new PatioLocal(fullName, type, localType) + ), + // TODO: the mapping is redundant given we fix the mapping + this.shidNameToLocal.plus(name, localRef), + this.waitingForShidLocal.plus(name, P.vector()), + this.stashedEffectHandler, + this.stashedGcRootStackIndex, + this.onReturn + ); + + return context.toResult(localRef); + } + + @CheckReturnValue + public FunctionContext.Result>> initShidLocal(String name) { + var context = new FunctionContext( + this.temporaryStack, + this.instructions, + this.localsByName, + this.shidNameToLocal, + this.waitingForShidLocal.minus(name), + this.stashedEffectHandler, + this.stashedGcRootStackIndex, + this.onReturn + ); + + return context.toResult(this.waitingForShidLocal.getOrDefault(name, P.vector())); + } + + @CheckReturnValue + public PatioLocalRef shidLocalNameToLocal(String name) { + var local = this.shidNameToLocal.get(name); + + if (local == null) { + // TODO: better error + throw new RuntimeException("Unknown Shid local: " + name); + } + + return local; + } + + @CheckReturnValue + public Optional shidLocalNameToLocalOrNone(String name) { + var local = this.shidNameToLocal.get(name); + + return Optional.ofNullable(local); + } + + @CheckReturnValue + public boolean isShidLocalDefined(String name) { + return !this.waitingForShidLocal.containsKey(name); + } + + @CheckReturnValue + public PatioType localType(PatioLocalRef local){ + // TODO: handle missing key. + return this.localsByName.get(local.name()).type(); + } + + @CheckReturnValue + public FunctionContext addWaitingForShidLocal( + String name, + Function func + ) { + return new FunctionContext( + this.temporaryStack, + this.instructions, + this.localsByName, + this.shidNameToLocal, + this.waitingForShidLocal.plus( + name, + this.waitingForShidLocal.getOrDefault(name, P.vector()).plus(func) + ), + this.stashedEffectHandler, + this.stashedGcRootStackIndex, + this.onReturn + ); + } + + @CheckReturnValue + public FunctionContext stashEffectHandler(PatioOperand effectHandler) { + return new FunctionContext( + this.temporaryStack, + this.instructions, + this.localsByName, + this.shidNameToLocal, + this.waitingForShidLocal, + // TODO: check current value is empty + Optional.of(effectHandler), + this.stashedGcRootStackIndex, + this.onReturn + ); + } + + @CheckReturnValue + public PatioOperand stashedEffectHandlerOrThrow() { + // TODO: better error + return this.stashedEffectHandler + .orElseThrow(() -> new RuntimeException("No stashed effect handler")); + } + + @CheckReturnValue + public FunctionContext stashGcRootStackIndex(PatioOperand gcRootStackIndex) { + return new FunctionContext( + this.temporaryStack, + this.instructions, + this.localsByName, + this.shidNameToLocal, + this.waitingForShidLocal, + this.stashedEffectHandler, + // TODO: check current value is empty + Optional.of(gcRootStackIndex), + this.onReturn + ); + } + + @CheckReturnValue + public PatioOperand stashedGcRootStackIndexOrThrow() { + // TODO: better error + return this.stashedGcRootStackIndex + .orElseThrow(() -> new RuntimeException("No stashed GC root stack index")); + } + + public FunctionContext pushOnReturn(PatioInstruction onReturn) { + return new FunctionContext( + this.temporaryStack, + this.instructions, + this.localsByName, + this.shidNameToLocal, + this.waitingForShidLocal, + this.stashedEffectHandler, + this.stashedGcRootStackIndex, + this.onReturn.plus(onReturn) + ); + } + + public FunctionContext popOnReturn() { + return new FunctionContext( + this.temporaryStack, + this.instructions, + this.localsByName, + this.shidNameToLocal, + this.waitingForShidLocal, + this.stashedEffectHandler, + this.stashedGcRootStackIndex, + this.onReturn.minus(0) + ); + } + + private Result toResult(T value) { + return new Result<>(value, this); + } + + public record Result(T value, FunctionContext context) {} + } + + public static final ShidToPatioContext EMPTY = new ShidToPatioContext( + GlobalContext.EMPTY, + CompilationUnitContext.EMPTY, + P.stack(), + FunctionContext.EMPTY + ); + + @CheckReturnValue + public static ShidToPatioContext forTypeInfos(TypeInfos typeInfos) { + return new ShidToPatioContext( + GlobalContext.forTypeInfos(typeInfos), + CompilationUnitContext.EMPTY, + P.stack(), + FunctionContext.EMPTY + ); + } + + @CheckReturnValue + public NamespaceTypeInfo namespaceTypeInfo(NamespaceName namespaceName) { + return this.globalContext.namespaceTypeInfo(namespaceName); + } + + @CheckReturnValue + public StructTypeInfo structTypeInfo(StructType type) { + return this.globalContext.structTypeInfo(type); + } + + @CheckReturnValue + public int structTag(StructType type) { + return globalContext.structTag(type); + } + + @CheckReturnValue + public UserDefinedEffectInfo userDefinedEffectInfo(UserDefinedEffect effect) { + return this.globalContext.userDefinedEffectInfo(effect); + } + + @CheckReturnValue + public int effectTag(UserDefinedEffect effect) { + return globalContext.effectTag(effect); + } + + @CheckReturnValue + public ShidToPatioResult allocateCompilationUnitElementName( + ShidToPatioCompilationUnitElementSpace space, + String name + ) { + return withCompilationUnitContextResult( + this.compilationUnitContext.allocateCompilationUnitName( + space, + Optional.of(name) + ) + ); + } + + @CheckReturnValue + public ShidToPatioResult allocateCompilationUnitElementName( + ShidToPatioCompilationUnitElementSpace space + ) { + return withCompilationUnitContextResult( + this.compilationUnitContext.allocateCompilationUnitName( + space, + Optional.empty() + ) + ); + } + + @CheckReturnValue + public ShidToPatioContext addDataElementMutable(String name, PatioDataValue initialValue, Source source) { + var dataElement = new PatioDataElementMutable(name, initialValue, source); + return addCompilationUnitElement(dataElement); + } + + @CheckReturnValue + public ShidToPatioContext addCompilationUnitElement( + PatioCompilationUnitElement element + ) { + return withCompilationUnitContext( + this.compilationUnitContext.addCompilationUnitElement(element) + ); + } + + @CheckReturnValue + public ShidToPatioContext ensureCompilationUnitElement( + PatioCompilationUnitElement element + ) { + return withCompilationUnitContext( + this.compilationUnitContext.ensureCompilationUnitElement(element) + ); + } + + @CheckReturnValue + public ShidToPatioResult temporaryPop() { + var result = this.functionContext.temporaryPop(); + + return withFunctionContextResult(result); + } + + @CheckReturnValue + public ShidToPatioContext temporaryPopIntoLocal(PatioLocalRef target, Source source) { + var result = this.functionContext.temporaryPop(); + + return new ShidToPatioContext(this.globalContext, this.compilationUnitContext, this.blockStack, result.context) + .addInstruction(new PatioLocalStore(target, result.value, source)); + } + + @CheckReturnValue + public ShidToPatioResult> temporaryPopAll() { + var result = this.functionContext.temporaryPopAll(); + + return withFunctionContextResult(result); + } + + @CheckReturnValue + public ShidToPatioContext temporaryPush(PatioOperand value) { + var result = this.functionContext.temporaryPush(value); + + return withFunctionContext(result); + } + + @CheckReturnValue + public ShidToPatioContext addInstruction(PatioInstruction instruction) { + return withFunctionContext(this.functionContext.addInstruction(instruction)); + } + + @CheckReturnValue + public ShidToPatioResult allocateParam( + ShidToPatioLocalSpace space, + PatioType type + ) { + var result = this.functionContext.allocateLocal( + space, + Optional.empty(), + (patioName) -> new PatioLocal(patioName, type, PatioLocalType.PARAM) + ); + + return withFunctionContextResult(result); + } + + @CheckReturnValue + public ShidToPatioResult allocateVal( + ShidToPatioLocalSpace space, + PatioType type + ) { + var result = this.functionContext.allocateLocal( + space, + Optional.empty(), + (patioName) -> new PatioLocal(patioName, type, PatioLocalType.VAL) + ); + + return withFunctionContextResult(result); + } + + @CheckReturnValue + public ShidToPatioResult allocateVal( + ShidToPatioLocalSpace space, + String name, + PatioType type + ) { + var result = this.functionContext.allocateLocal( + space, + Optional.of(name), + (patioName) -> new PatioLocal(patioName, type, PatioLocalType.VAL) + ); + + return withFunctionContextResult(result); + } + + @CheckReturnValue + public ShidToPatioContext defineShidParam(String name) { + return declareShidParam(name).initShidLocal(name); + } + + @CheckReturnValue + private ShidToPatioContext declareShidParam(String name) { + return declareShidLocal( + name, + ShidToPatioTypes.VALUE_TYPE, + PatioLocalType.PARAM + ).context(); + } + + @CheckReturnValue + public ShidToPatioResult declareShidVal(String name, PatioType type) { + return declareShidLocal( + name, + type, + PatioLocalType.VAL + ); + } + + @CheckReturnValue + public ShidToPatioResult declareShidLocal( + String name, + PatioType type, + PatioLocalType patioLocalType + ) { + return withFunctionContextResult(this.functionContext.declareShidLocal( + name, + type, + patioLocalType + )); + } + + @CheckReturnValue + public ShidToPatioContext initShidLocal(String name) { + var result = this.functionContext.initShidLocal(name); + var context = withFunctionContext(result.context); + + for (var func : result.value) { + context = func.apply(context); + } + + return context; + } + + @CheckReturnValue + public ShidToPatioContext onceShidLocalDefined( + String name, + Function func + ) { + var local = this.functionContext.shidLocalNameToLocalOrNone(name); + + if (local.isEmpty()) { + // TODO: better error + throw new RuntimeException("Unknown Shid local: " + name); + } else if (!this.functionContext.isShidLocalDefined(name)) { + return withFunctionContext( + this.functionContext.addWaitingForShidLocal(name, func) + ); + } else { + return func.apply(this); + } + } + + @CheckReturnValue + public PatioLocalRef shidLocalNameToLocal(String name) { + return this.functionContext.shidLocalNameToLocal(name); + } + + @CheckReturnValue + public PatioType localType(PatioLocalRef local) { + return this.functionContext.localType(local); + } + + @CheckReturnValue + public PatioType shidLocalType(String name) { + var local = shidLocalNameToLocal(name); + return localType(local); + } + + @CheckReturnValue + public ShidToPatioContext createFunction( + String name, + PatioVisibility visibility, + PatioType returnType, + Source source, + Function createBody + ) { + var bodyContext = new ShidToPatioContext( + this.globalContext, + this.compilationUnitContext, + P.stack(), + FunctionContext.EMPTY + ); + + bodyContext = createBody.apply(bodyContext); + + var locals = bodyContext.functionContext.localsByName.values().stream().toList(); + + return new ShidToPatioContext( + this.globalContext, + bodyContext.compilationUnitContext.addElement(new PatioFunctionDefinition( + name, + visibility, + locals, + returnType, + bodyContext.functionContext.instructions, + source + )), + this.blockStack, + this.functionContext + ); + } + + @CheckReturnValue + public ShidToPatioContext enterBlock() { + return new ShidToPatioContext( + this.globalContext, + this.compilationUnitContext, + this.blockStack.plus(this.functionContext), + new FunctionContext( + P.stack(), + P.vector(), + this.functionContext.localsByName, + this.functionContext.shidNameToLocal, + this.functionContext.waitingForShidLocal, + this.functionContext.stashedEffectHandler, + this.functionContext.stashedGcRootStackIndex, + this.functionContext.onReturn + ) + ); + } + + @CheckReturnValue + public ShidToPatioResult> exitBlock() { + if (!this.functionContext.temporaryStack.isEmpty()) { + throw new RuntimeException("temporary stack must be empty at the end of a block"); + } + + return new ShidToPatioContext( + this.globalContext, + this.compilationUnitContext, + this.blockStack.minus(0), + new FunctionContext( + this.blockStack.get(0).temporaryStack, + this.blockStack.get(0).instructions, + this.functionContext.localsByName, + this.functionContext.shidNameToLocal, + this.functionContext.waitingForShidLocal, + this.blockStack.get(0).stashedEffectHandler, + this.blockStack.get(0).stashedGcRootStackIndex, + this.blockStack.get(0).onReturn + ) + ).toResult(this.functionContext.instructions); + } + + @CheckReturnValue + public ShidToPatioContext stashEffectHandler(PatioOperand effectHandler) { + return withFunctionContext(this.functionContext.stashEffectHandler(effectHandler)); + } + + @CheckReturnValue + public PatioOperand stashedEffectHandler() { + return this.functionContext.stashedEffectHandlerOrThrow(); + } + + @CheckReturnValue + public String exceptionTypeName(UserDefinedEffect effect) { + // TODO: Allocate properly + return "shed__effect__exception__" + String.join("_", effect.namespaceName().parts()) + "__" + effect.name(); + } + + @CheckReturnValue + public ShidToPatioContext stashGcRootStackIndex(PatioOperand gcRootStackIndex) { + return withFunctionContext(this.functionContext.stashGcRootStackIndex(gcRootStackIndex)); + } + + @CheckReturnValue + public PatioOperand stashedGcRootStackIndex() { + return this.functionContext.stashedGcRootStackIndexOrThrow(); + } + + @CheckReturnValue + public ShidToPatioContext pushOnReturn(PatioInstruction onReturn) { + return withFunctionContext(this.functionContext.pushOnReturn(onReturn)); + } + + @CheckReturnValue + public ShidToPatioContext popOnReturn() { + return withFunctionContext(this.functionContext.popOnReturn()); + } + + @CheckReturnValue + public List onReturn() { + return this.functionContext.onReturn(); + } + + @CheckReturnValue + private ShidToPatioContext withCompilationUnitContext(CompilationUnitContext compilationUnitContext) { + return new ShidToPatioContext(this.globalContext, compilationUnitContext, this.blockStack, this.functionContext); + } + + @CheckReturnValue + private ShidToPatioResult withCompilationUnitContextResult(CompilationUnitContext.Result result) { + return withCompilationUnitContext(result.context).toResult(result.value); + } + + @CheckReturnValue + private ShidToPatioContext withFunctionContext(FunctionContext functionContext) { + return new ShidToPatioContext(this.globalContext, this.compilationUnitContext, this.blockStack, functionContext); + } + + @CheckReturnValue + private ShidToPatioResult withFunctionContextResult(FunctionContext.Result result) { + return withFunctionContext(result.context).toResult(result.value); + } + + @CheckReturnValue + public ShidToPatioResult toResult(T value) { + return new ShidToPatioResult<>(value, this); + } + + @CheckReturnValue + public PatioCompilationUnit toCompilationUnit(Source source) { + return new PatioCompilationUnit( + new ArrayList<>(this.compilationUnitContext.elementsByName.values()), + source + ); + } +} diff --git a/src/main/java/org/shedlang/compiler/shidtopatio/ShidToPatioEffects.java b/src/main/java/org/shedlang/compiler/shidtopatio/ShidToPatioEffects.java new file mode 100644 index 00000000..cbb321d6 --- /dev/null +++ b/src/main/java/org/shedlang/compiler/shidtopatio/ShidToPatioEffects.java @@ -0,0 +1,505 @@ +package org.shedlang.compiler.shidtopatio; + +import org.shedlang.compiler.ast.typed.FreeVariables; +import org.shedlang.compiler.patio.ast.PatioExceptionTypeDefinition; +import org.shedlang.compiler.patio.ast.PatioFunctionDeclaration; +import org.shedlang.compiler.patio.ast.PatioLocal; +import org.shedlang.compiler.patio.ast.instructions.*; +import org.shedlang.compiler.patio.ast.operands.PatioInt; +import org.shedlang.compiler.patio.ast.operands.PatioLocalRef; +import org.shedlang.compiler.patio.ast.operands.PatioOperand; +import org.shedlang.compiler.patio.ast.types.PatioDataLayout; +import org.shedlang.compiler.patio.ast.types.PatioDataLayouts; +import org.shedlang.compiler.patio.ast.types.PatioType; +import org.shedlang.compiler.patio.ast.types.PatioTypes; +import org.shedlang.compiler.shid.instructions.ShidDefineFunction; +import org.shedlang.compiler.sources.Source; +import org.shedlang.compiler.sources.Sources; +import org.shedlang.compiler.types.UserDefinedEffect; +import org.shedlang.compiler.util.Lists; + +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.function.Function; +import java.util.stream.IntStream; + +public class ShidToPatioEffects { + private static final PatioType EFFECT_TAG_TYPE = PatioTypes.INT; + private static final PatioType EFFECT_METHOD_INDEX_TYPE = PatioTypes.INT; + private static final PatioType EFFECT_HANDLER_TYPE = PatioTypes.DATA_POINTER; + private static final PatioType EFFECT_HANDLER_METHOD_POINTER_TYPE = PatioTypes.DATA_POINTER; + private static final PatioType EFFECT_HANDLER_METHOD_TYPE = ShidToPatioTypes.VALUE_TYPE; + + private static PatioDataLayout effectHandlerMethodDataLayout( + FreeVariables freeVariables, + ShidToPatioContext context + ) { + return ShidToPatioClosures.closureDataLayout( + PatioDataLayouts.struct(List.of(PatioDataLayouts.DATA_POINTER)), + freeVariables, + context + ); + } + + private static final List CLOSURE_EFFECT_HANDLER_OFFSET + = ShidToPatioClosures.additionalOffset(List.of(0)); + + private static PatioDataLayout userDefinedEffectLayout( + UserDefinedEffect effect, + ShidToPatioContext context + ) { + var effectInfo = context.userDefinedEffectInfo(effect); + return ShidToPatioGc.gcObjectDataLayout(PatioDataLayouts.struct(Lists.repeat( + PatioDataLayouts.fromType(ShidToPatioClosures.CLOSURE_TYPE), + effectInfo.methodCount() + ))); + } + + private static List userDefinedEffectMethodOffset(int methodIndex) { + return ShidToPatioGc.gcObjectOffset(List.of(methodIndex)); + } + + private static final List USER_DEFINED_EFFECT_GC_CHILDREN_OFFSET = + ShidToPatioGc.gcObjectOffset(List.of()); + + private static final PatioFunctionDeclaration FIND_HANDLER_METHOD_DECLARATION = new PatioFunctionDeclaration( + "shed__runtime__effects_find_handler_method", + List.of( + PatioLocal.param("effectTag", EFFECT_TAG_TYPE), + PatioLocal.param("methodIndex", EFFECT_METHOD_INDEX_TYPE) + ), + EFFECT_HANDLER_METHOD_TYPE, + Sources.RUNTIME + ); + + private static final PatioFunctionDeclaration GET_HANDLER_DECLARATION = new PatioFunctionDeclaration( + "shed__runtime__effects_get_handler", + List.of(), + EFFECT_HANDLER_TYPE, + Sources.RUNTIME + ); + + private static final PatioFunctionDeclaration SET_HANDLER_DECLARATION = new PatioFunctionDeclaration( + "shed__runtime__effects_set_handler", + List.of(PatioLocal.param("effectHandler", EFFECT_HANDLER_TYPE)), + PatioTypes.VOID, + Sources.RUNTIME + ); + + private static final PatioFunctionDeclaration PUSH_HANDLER_DECLARATION = new PatioFunctionDeclaration( + "shed__runtime__effects_push_handler", + List.of( + PatioLocal.param("effectTag", EFFECT_TAG_TYPE), + PatioLocal.param("methodCount", PatioTypes.INT) + ), + EFFECT_HANDLER_TYPE, + Sources.RUNTIME + ); + + private static final PatioFunctionDeclaration SET_HANDLER_METHOD_DECLARATION = new PatioFunctionDeclaration( + "shed__runtime__effects_set_handler_method", + List.of( + PatioLocal.param("handler", EFFECT_HANDLER_TYPE), + PatioLocal.param("methodIndex", EFFECT_METHOD_INDEX_TYPE), + PatioLocal.param("handlerMethod", EFFECT_HANDLER_METHOD_TYPE) + ), + PatioTypes.VOID, + Sources.RUNTIME + ); + + private static final PatioFunctionDeclaration POP_HANDLER_DECLARATION = new PatioFunctionDeclaration( + "shed__runtime__effects_pop_handler", + List.of(), + PatioTypes.VOID, + Sources.RUNTIME + ); + + private ShidToPatioEffects() { + } + + public static ShidToPatioContext createUserDefinedEffect( + PatioLocalRef target, + UserDefinedEffect effect, + Source source, + ShidToPatioContext context + ) { + context = context.addCompilationUnitElement(new PatioExceptionTypeDefinition( + context.exceptionTypeName(effect), + ShidToPatioTypes.VALUE_TYPE, + source + )); + + var effectPointerResult = context.allocateVal( + ShidToPatioLocalSpace.USER_DEFINED_EFFECT_POINTER, + effect.name(), + PatioTypes.DATA_POINTER + ); + var effectPointer = effectPointerResult.value(); + context = effectPointerResult.context(); + + var effectLayout = userDefinedEffectLayout(effect, context); + + var effectInfo = context.userDefinedEffectInfo(effect); + + context = ShidToPatioGc.alloc( + effectPointer, + effectLayout, + USER_DEFINED_EFFECT_GC_CHILDREN_OFFSET, + effectInfo.methodCount(), + source, + context + ); + + for (var method : effectInfo.methods()) { + var effectMethodResult = context.allocateVal( + ShidToPatioLocalSpace.USER_DEFINED_EFFECT_METHOD, + method.name(), + ShidToPatioClosures.CLOSURE_TYPE + ); + var effectMethod = effectMethodResult.value(); + context = effectMethodResult.context(); + + var positionalParams = IntStream.range(0, method.type().positionalParams().size()) + // TODO: ensure names of positional params doesn't clash with named params + .mapToObj(paramIndex -> new ShidDefineFunction.Param("arg" + paramIndex, source)) + .toList(); + + context = ShidToPatioFunctions.create( + effectMethod, + method.name(), + positionalParams, + method.type().namedParams().stream() + .map(namedParam -> new ShidDefineFunction.Param(namedParam.name(), source)) + .toList(), + FreeVariables.empty(), + bodyContext -> { + bodyContext = bodyContext.ensureCompilationUnitElement(FIND_HANDLER_METHOD_DECLARATION); + + var handlerMethodResult = bodyContext.allocateVal( + ShidToPatioLocalSpace.EFFECT_HANDLER_METHOD, + EFFECT_HANDLER_METHOD_TYPE + ); + var handlerMethod = handlerMethodResult.value(); + bodyContext = handlerMethodResult.context(); + + bodyContext = bodyContext.addInstruction(new PatioCall( + Optional.of(handlerMethod), + FIND_HANDLER_METHOD_DECLARATION.name(), + List.of( + new PatioInt(bodyContext.effectTag(effect)), + new PatioInt(method.fieldIndex()) + ), + source + )); + + var returnValueResult = bodyContext.allocateVal( + ShidToPatioLocalSpace.TEMPORARY, + ShidToPatioTypes.VALUE_TYPE + ); + var returnValue = returnValueResult.value(); + bodyContext = returnValueResult.context(); + + var bodyContextArgs = bodyContext; + bodyContext = ShidToPatioClosures.call( + returnValue, + handlerMethod, + positionalParams.stream() + .map(param -> bodyContextArgs.shidLocalNameToLocal(param.name())) + .toList(), + method.type().namedParams().stream() + .map(param -> Map.entry( + param.name(), + bodyContextArgs.shidLocalNameToLocal(param.name()) + )) + .toList(), + source, + bodyContext + ); + + bodyContext = bodyContext.addInstruction(new PatioReturn(returnValue, source)); + + return bodyContext; + }, + source, + context + ); + + context = context + .addInstruction(new PatioMemoryStore( + effectPointer, + effectLayout, + userDefinedEffectMethodOffset(method.fieldIndex()), + effectMethod, + source + )); + } + + context = context.addInstruction(new PatioDataPtrToInt( + target, + effectPointer, + source + )); + + return context; + } + + public static ShidToPatioContext fieldLoad( + PatioLocalRef target, + PatioOperand receiver, + UserDefinedEffect effect, + String fieldName, + Source source, + ShidToPatioContext context + ) { + var effectPointerResult = context.allocateVal( + ShidToPatioLocalSpace.USER_DEFINED_EFFECT_POINTER, + PatioTypes.DATA_POINTER + ); + var effectPointer = effectPointerResult.value(); + context = effectPointerResult.context(); + + context = context.addInstruction(new PatioIntToDataPtr( + effectPointer, + receiver, + source + )); + + var effectDataLayout = userDefinedEffectLayout(effect, context); + + var effectInfo = context.userDefinedEffectInfo(effect); + var methodIndex = effectInfo.methodIndex(fieldName); + + context = context.addInstruction(new PatioMemoryLoad( + target, + effectPointer, + effectDataLayout, + userDefinedEffectMethodOffset(methodIndex), + source + )); + + return context; + } + + public static ShidToPatioContext try_( + PatioLocalRef target, + UserDefinedEffect effect, + Map handlerMethodsByName, + Function> generateBody, + Source source, + ShidToPatioContext context + ) { + var effectInfo = context.userDefinedEffectInfo(effect); + + context = context + .ensureCompilationUnitElement(PUSH_HANDLER_DECLARATION) + .ensureCompilationUnitElement(SET_HANDLER_METHOD_DECLARATION) + .ensureCompilationUnitElement(POP_HANDLER_DECLARATION); + + var effectHandlerResult = context.allocateVal( + ShidToPatioLocalSpace.EFFECT_HANDLER, + EFFECT_HANDLER_TYPE + ); + var effectHandler = effectHandlerResult.value(); + context = effectHandlerResult.context(); + + context = context.addInstruction(new PatioCall( + Optional.of(effectHandler), + PUSH_HANDLER_DECLARATION.name(), + List.of( + new PatioInt(context.effectTag(effect)), + new PatioInt(effectInfo.methodCount()) + ), + source + )); + + for (var handlerMethodInfo : effectInfo.methods()) { + context = context.addInstruction(new PatioCall( + Optional.empty(), + SET_HANDLER_METHOD_DECLARATION.name(), + List.of( + effectHandler, + new PatioInt(handlerMethodInfo.fieldIndex()), + handlerMethodsByName.get(handlerMethodInfo.name()) + ), + source + )); + } + + var popHandler = new PatioCall( + Optional.empty(), + POP_HANDLER_DECLARATION.name(), + List.of(), + source + ); + + context = context.pushOnReturn(popHandler); + + var bodyResult = generateBody.apply(context); + var body = bodyResult.value(); + context = bodyResult.context(); + + context = context.popOnReturn(); + + var exceptionValueResult = context.allocateVal( + ShidToPatioLocalSpace.TEMPORARY, + ShidToPatioTypes.VALUE_TYPE + ); + var exceptionValue = exceptionValueResult.value(); + context = exceptionValueResult.context(); + + context = context.addInstruction(new PatioTry( + List.of(target), + List.of( + new PatioCatchClause( + context.exceptionTypeName(effect), + exceptionValue, + new PatioBlock( + List.of(), + List.of(exceptionValue), + source + ), + source + ) + ), + body.addInstruction(popHandler), + source + )); + + return context; + } + + public static ShidToPatioContext createEffectHandlerMethod( + PatioLocalRef target, + String name, + List positionalParams, + List namedParams, + FreeVariables freeVariables, + Function generateBody, + Source source, + ShidToPatioContext context + ) { + context = context + .ensureCompilationUnitElement(GET_HANDLER_DECLARATION) + .ensureCompilationUnitElement(SET_HANDLER_DECLARATION); + + var layout = effectHandlerMethodDataLayout(freeVariables, context); + + return ShidToPatioClosures.create( + target, + ShidToPatioCompilationUnitElementSpace.EFFECT_HANDLER_METHOD, + name, + positionalParams, + namedParams, + layout, + (closurePointer, allocContext) -> { + var effectHandlerResult = allocContext.allocateVal( + ShidToPatioLocalSpace.EFFECT_HANDLER_CURRENT, + EFFECT_HANDLER_TYPE + ); + var effectHandler = effectHandlerResult.value(); + allocContext = effectHandlerResult.context(); + + allocContext = getCurrentEffectHandler(effectHandler, source, allocContext); + + allocContext = allocContext.addInstruction(new PatioMemoryStore( + closurePointer, + layout, + CLOSURE_EFFECT_HANDLER_OFFSET, + effectHandler, + source + )); + + return allocContext; + }, + freeVariables, + (closurePointer, bodyContext) -> { + var previousEffectHandlerResult = bodyContext.allocateVal( + ShidToPatioLocalSpace.EFFECT_HANDLER, + EFFECT_HANDLER_METHOD_POINTER_TYPE + ); + var previousEffectHandler = previousEffectHandlerResult.value(); + bodyContext = previousEffectHandlerResult.context(); + + bodyContext = getCurrentEffectHandler(previousEffectHandler, source, bodyContext); + + bodyContext = bodyContext.stashEffectHandler(previousEffectHandler); + + var effectHandlerResult = bodyContext.allocateVal( + ShidToPatioLocalSpace.EFFECT_HANDLER, + EFFECT_HANDLER_METHOD_POINTER_TYPE + ); + var effectHandler = effectHandlerResult.value(); + bodyContext = effectHandlerResult.context(); + + bodyContext = bodyContext.addInstruction(new PatioMemoryLoad( + effectHandler, + closurePointer, + layout, + CLOSURE_EFFECT_HANDLER_OFFSET, + source + )); + + bodyContext = bodyContext.addInstruction(new PatioCall( + Optional.empty(), + SET_HANDLER_DECLARATION.name(), + List.of(effectHandler), + source + )); + + bodyContext = generateBody.apply(bodyContext); + + return bodyContext; + }, + source, + context + ); + } + + public static ShidToPatioContext resume( + PatioOperand value, + Source source, + ShidToPatioContext context + ) { + context = context.addInstruction(new PatioCall( + Optional.empty(), + SET_HANDLER_DECLARATION.name(), + List.of(context.stashedEffectHandler()), + source + )); + + context = context.addInstruction(new PatioResume(value, source)); + + return context; + } + + public static ShidToPatioContext break_( + UserDefinedEffect effect, + PatioOperand value, + Source source, + ShidToPatioContext context + ) { + var exceptionTypeName = context.exceptionTypeName(effect); + + context = context.addInstruction(new PatioThrow( + exceptionTypeName, + value, + source + )); + + return context; + } + + private static ShidToPatioContext getCurrentEffectHandler( + PatioLocalRef target, + Source source, + ShidToPatioContext context + ) { + return context.addInstruction(new PatioCall( + Optional.of(target), + GET_HANDLER_DECLARATION.name(), + List.of(), + source + )); + } +} diff --git a/src/main/java/org/shedlang/compiler/shidtopatio/ShidToPatioFunctions.java b/src/main/java/org/shedlang/compiler/shidtopatio/ShidToPatioFunctions.java new file mode 100644 index 00000000..e6e7259a --- /dev/null +++ b/src/main/java/org/shedlang/compiler/shidtopatio/ShidToPatioFunctions.java @@ -0,0 +1,54 @@ +package org.shedlang.compiler.shidtopatio; + +import org.shedlang.compiler.ast.typed.FreeVariables; +import org.shedlang.compiler.patio.ast.operands.PatioLocalRef; +import org.shedlang.compiler.patio.ast.types.PatioDataLayout; +import org.shedlang.compiler.patio.ast.types.PatioDataLayouts; +import org.shedlang.compiler.shid.instructions.ShidDefineFunction; +import org.shedlang.compiler.sources.Source; + +import java.util.List; +import java.util.function.Function; + +public class ShidToPatioFunctions { + private ShidToPatioFunctions() { + } + + private static PatioDataLayout functionDataLayout( + FreeVariables freeVariables, + ShidToPatioContext context + ) { + return ShidToPatioClosures.closureDataLayout( + PatioDataLayouts.struct(List.of()), + freeVariables, + context + ); + } + + public static ShidToPatioContext create( + PatioLocalRef target, + String name, + List positionalParams, + List namedParams, + FreeVariables freeVariables, + Function generateBody, + Source source, + ShidToPatioContext context + ) { + var layout = functionDataLayout(freeVariables, context); + + return ShidToPatioClosures.create( + target, + ShidToPatioCompilationUnitElementSpace.FUNCTION, + name, + positionalParams, + namedParams, + layout, + (closurePointer, storeContext) -> storeContext, + freeVariables, + (closurePointer, bodyContext) -> generateBody.apply(bodyContext), + source, + context + ); + } +} diff --git a/src/main/java/org/shedlang/compiler/shidtopatio/ShidToPatioGc.java b/src/main/java/org/shedlang/compiler/shidtopatio/ShidToPatioGc.java new file mode 100644 index 00000000..7a55f67e --- /dev/null +++ b/src/main/java/org/shedlang/compiler/shidtopatio/ShidToPatioGc.java @@ -0,0 +1,208 @@ +package org.shedlang.compiler.shidtopatio; + +import org.shedlang.compiler.patio.ast.PatioFunctionDeclaration; +import org.shedlang.compiler.patio.ast.PatioLocal; +import org.shedlang.compiler.patio.ast.instructions.PatioAllocHeap; +import org.shedlang.compiler.patio.ast.instructions.PatioCall; +import org.shedlang.compiler.patio.ast.operands.PatioLocalRef; +import org.shedlang.compiler.patio.ast.operands.PatioOperand; +import org.shedlang.compiler.patio.ast.types.*; +import org.shedlang.compiler.sources.Source; +import org.shedlang.compiler.sources.Sources; +import org.shedlang.compiler.util.Lists; + +import java.util.List; +import java.util.Optional; + +public class ShidToPatioGc { + // TODO: garbage collect after throws, and the end of blocks (especially for loops) + private ShidToPatioGc() { + } + + public static PatioDataLayout gcObjectDataLayout(PatioDataLayout valueLayout) { + return PatioDataLayouts.struct(List.of( + PatioDataLayouts.struct(List.of( + PatioDataLayouts.DATA_POINTER, // next + PatioDataLayouts.INT, // mark + PatioDataLayouts.INT, // children offset + PatioDataLayouts.INT // children count + )), + valueLayout + )); + } + + public static List gcObjectOffset(List valueOffset) { + return Lists.concat(List.of(1), valueOffset); + } + + /** + * Creates a data value for GC objects with no GC children that should never + * be garbage collected. Such a value does not need to be added to the set + * of GC roots. + */ + public static PatioDataValue gcObjectStaticDataValue(PatioDataValue value) { + return PatioDataValues.struct(List.of( + PatioDataValues.struct(List.of( + PatioDataValues.int_(0), + // Static values are always marked: see gc.c + PatioDataValues.int_(0b110), + PatioDataValues.int_(0), + PatioDataValues.int_(0) + )), + value + )); + } + + // == Roots == + + public static final PatioType GC_ROOT_STACK_INDEX_TYPE = PatioTypes.INT; + + private static final PatioFunctionDeclaration GET_GC_ROOT_STACK_INDEX = new PatioFunctionDeclaration( + "shed__runtime__gc_get_root_stack_index", + List.of(), + GC_ROOT_STACK_INDEX_TYPE, + Sources.RUNTIME + ); + + public static ShidToPatioContext getGcRootStackIndex( + PatioLocalRef target, + Source source, + ShidToPatioContext context + ) { + return context + .ensureCompilationUnitElement(GET_GC_ROOT_STACK_INDEX) + .addInstruction(new PatioCall( + Optional.of(target), + GET_GC_ROOT_STACK_INDEX.name(), + List.of(), + source + )); + } + + private static final PatioFunctionDeclaration SET_GC_ROOT_STACK_INDEX = new PatioFunctionDeclaration( + "shed__runtime__gc_set_root_stack_index", + List.of(PatioLocal.param("gc_root_stack_index", GC_ROOT_STACK_INDEX_TYPE)), + PatioTypes.VOID, + Sources.RUNTIME + ); + + public static ShidToPatioContext setGcRootStackIndex( + PatioOperand gcRootIndex, + Source source, + ShidToPatioContext context + ) { + return context + .ensureCompilationUnitElement(SET_GC_ROOT_STACK_INDEX) + .addInstruction(new PatioCall( + Optional.empty(), + SET_GC_ROOT_STACK_INDEX.name(), + List.of(gcRootIndex), + source + )); + } + + private static final PatioFunctionDeclaration PUSH_GC_ROOT = new PatioFunctionDeclaration( + "shed__runtime__gc_push_root", + List.of(PatioLocal.param("gc_root", ShidToPatioTypes.VALUE_TYPE)), + PatioTypes.VOID, + Sources.RUNTIME + ); + + public static ShidToPatioContext pushGcRoot( + PatioOperand escapee, + Source source, + ShidToPatioContext context + ) { + return context + .ensureCompilationUnitElement(PUSH_GC_ROOT) + .addInstruction(new PatioCall( + Optional.empty(), + PUSH_GC_ROOT.name(), + List.of(escapee), + source + )); + } + + // == Allocation == + + public static ShidToPatioContext alloc( + PatioLocalRef target, + PatioDataLayout layout, + List childrenOffset, + int childrenCount, + Source source, + ShidToPatioContext context + ) { + return context.addInstruction(new PatioAllocHeap( + target, + layout, + childrenOffset, + childrenCount, + source + )); + } + + // == Collection == + + private static final PatioFunctionDeclaration COLLECT = new PatioFunctionDeclaration( + "shed__runtime__gc_collect", + List.of(), + PatioTypes.VOID, + Sources.RUNTIME + ); + + public static ShidToPatioContext collect( + Source source, + ShidToPatioContext context + ) { + return context + .ensureCompilationUnitElement(COLLECT) + .addInstruction(new PatioCall( + Optional.empty(), + COLLECT.name(), + List.of(), + source + )); + } + + // == Save/Restore == + + static ShidToPatioContext saveGcRootStack(Source source, ShidToPatioContext context) { + var gcRootStackIndexResult = context.allocateVal( + ShidToPatioLocalSpace.GC_ROOT_STACK_INDEX, + ShidToPatioGc.GC_ROOT_STACK_INDEX_TYPE + ); + var gcRootStackIndex = gcRootStackIndexResult.value(); + context = gcRootStackIndexResult.context(); + + context = ShidToPatioGc.getGcRootStackIndex( + gcRootStackIndex, + source, + context + ); + + context = context.stashGcRootStackIndex(gcRootStackIndex); + + return context; + } + + static ShidToPatioContext restoreGcRootStack( + List escapees, + Source source, + ShidToPatioContext context + ) { + context = ShidToPatioGc.setGcRootStackIndex( + context.stashedGcRootStackIndex(), + source, + context + ); + + for (var escapee : escapees) { + context = ShidToPatioGc.pushGcRoot(escapee, source, context); + } + + context = ShidToPatioGc.collect(source, context); + + return context; + } +} diff --git a/src/main/java/org/shedlang/compiler/shidtopatio/ShidToPatioInts.java b/src/main/java/org/shedlang/compiler/shidtopatio/ShidToPatioInts.java new file mode 100644 index 00000000..98dfea10 --- /dev/null +++ b/src/main/java/org/shedlang/compiler/shidtopatio/ShidToPatioInts.java @@ -0,0 +1,156 @@ +package org.shedlang.compiler.shidtopatio; + +import org.shedlang.compiler.patio.ast.PatioFunctionDeclaration; +import org.shedlang.compiler.patio.ast.PatioLocal; +import org.shedlang.compiler.patio.ast.instructions.PatioCall; +import org.shedlang.compiler.patio.ast.operands.PatioInt; +import org.shedlang.compiler.patio.ast.operands.PatioLocalRef; +import org.shedlang.compiler.patio.ast.operands.PatioOperand; +import org.shedlang.compiler.patio.ast.types.PatioType; +import org.shedlang.compiler.patio.ast.types.PatioTypes; +import org.shedlang.compiler.sources.Source; +import org.shedlang.compiler.sources.Sources; + +import java.math.BigInteger; +import java.util.List; +import java.util.Optional; + +public class ShidToPatioInts { + public static final PatioFunctionDeclaration INT_CREATE_DECLARATION = new PatioFunctionDeclaration( + "shed__runtime__int_create", + List.of( + PatioLocal.param("value", PatioTypes.INT) + ), + ShidToPatioTypes.VALUE_TYPE, + Sources.RUNTIME + ); + + public static final PatioFunctionDeclaration INT_ADD_DECLARATION = new PatioFunctionDeclaration( + "shed__runtime__int_add", + List.of( + PatioLocal.param("left", ShidToPatioTypes.VALUE_TYPE), + PatioLocal.param("right", ShidToPatioTypes.VALUE_TYPE) + ), + ShidToPatioTypes.VALUE_TYPE, + Sources.RUNTIME + ); + + public static final PatioFunctionDeclaration INT_SUB_DECLARATION = new PatioFunctionDeclaration( + "shed__runtime__int_sub", + List.of( + PatioLocal.param("left", ShidToPatioTypes.VALUE_TYPE), + PatioLocal.param("right", ShidToPatioTypes.VALUE_TYPE) + ), + ShidToPatioTypes.VALUE_TYPE, + Sources.RUNTIME + ); + + public static final PatioFunctionDeclaration INT_EQUALS_DECLARATION = new PatioFunctionDeclaration( + "shed__runtime__int_equals", + List.of( + PatioLocal.param("left", ShidToPatioTypes.VALUE_TYPE), + PatioLocal.param("right", ShidToPatioTypes.VALUE_TYPE) + ), + PatioTypes.BOOL, + Sources.RUNTIME + ); + + public static final PatioFunctionDeclaration INT_NOT_EQUAL_DECLARATION = new PatioFunctionDeclaration( + "shed__runtime__int_not_equal", + List.of( + PatioLocal.param("left", ShidToPatioTypes.VALUE_TYPE), + PatioLocal.param("right", ShidToPatioTypes.VALUE_TYPE) + ), + PatioTypes.BOOL, + Sources.RUNTIME + ); + + public static final PatioType INT_TYPE = ShidToPatioTypes.VALUE_TYPE; + + private ShidToPatioInts() { + } + + public static ShidToPatioContext storeConst( + PatioLocalRef target, + BigInteger value, + Source source, + ShidToPatioContext context + ) { + return context + .ensureCompilationUnitElement(INT_CREATE_DECLARATION) + .addInstruction(new PatioCall( + Optional.of(target), + INT_CREATE_DECLARATION.name(), + List.of(new PatioInt(value.intValueExact())), + source + )); + } + + public static ShidToPatioContext add( + PatioLocalRef target, + PatioOperand left, + PatioOperand right, + Source source, + ShidToPatioContext context + ) { + return context + .ensureCompilationUnitElement(INT_ADD_DECLARATION) + .addInstruction(new PatioCall( + Optional.of(target), + INT_ADD_DECLARATION.name(), + List.of(left, right), + source + )); + } + + public static ShidToPatioContext sub( + PatioLocalRef target, + PatioOperand left, + PatioOperand right, + Source source, + ShidToPatioContext context + ) { + return context + .ensureCompilationUnitElement(INT_SUB_DECLARATION) + .addInstruction(new PatioCall( + Optional.of(target), + INT_SUB_DECLARATION.name(), + List.of(left, right), + source + )); + } + + public static ShidToPatioContext equals( + PatioLocalRef target, + PatioOperand left, + PatioOperand right, + Source source, + ShidToPatioContext context + ) { + return context + .ensureCompilationUnitElement(INT_EQUALS_DECLARATION) + .addInstruction(new PatioCall( + Optional.of(target), + INT_EQUALS_DECLARATION.name(), + List.of(left, right), + source + )); + } + + public static ShidToPatioContext notEqual( + PatioLocalRef target, + PatioOperand left, + PatioOperand right, + Source source, + ShidToPatioContext context + ) { + return context + .ensureCompilationUnitElement(INT_NOT_EQUAL_DECLARATION) + .addInstruction(new PatioCall( + Optional.of(target), + INT_NOT_EQUAL_DECLARATION.name(), + List.of(left, right), + source + )); + } +} diff --git a/src/main/java/org/shedlang/compiler/shidtopatio/ShidToPatioLocalSpace.java b/src/main/java/org/shedlang/compiler/shidtopatio/ShidToPatioLocalSpace.java new file mode 100644 index 00000000..d5d592ef --- /dev/null +++ b/src/main/java/org/shedlang/compiler/shidtopatio/ShidToPatioLocalSpace.java @@ -0,0 +1,48 @@ +package org.shedlang.compiler.shidtopatio; + +public enum ShidToPatioLocalSpace { + BINARY_OP_RESULT("binaryOpResult"), + CALL_ARG_POSITIONAL("callArgPositional"), + CALL_ARG_NAMED("callArgNamed"), + CALL_FUNCTION_POINTER("callFunctionPointer"), + CLOSURE("closure"), + CLOSURE_POINTER("closurePointer"), + CLOSURE_FUNCTION_POINTER("closureFunctionPointer"), + EFFECT_HANDLER("effectHandler"), + EFFECT_HANDLER_CURRENT("effectHandlerCurrent"), + EFFECT_HANDLER_METHOD("effectHandlerMethod"), + EFFECT_HANDLER_METHOD_POINTER("effectHandlerMethodPointer"), + GC_ROOT_STACK_INDEX("gcRootStackIndex"), + INT("int"), + MAIN("main"), + NAMESPACE_IS_INITED_POINTER("namespaceIsInitedPointer"), + NAMESPACE_POINTER("namespacePointer"), + NAMESPACE_VALUE("namespaceValue"), + LOCAL("local"), + RECEIVER("receiver"), + STRING("string"), + STRUCT_TAG_POINTER("structTagPointer"), + STRUCT_TYPE("structType"), + STRUCT_VALUE("structValue"), + STRUCT_VALUE_POINTER("structValuePointer"), + SWITCH_TAG("switchTag"), + TEMPORARY("tmp"), + TUPLE("tuple"), + TUPLE_ELEMENT("tupleElement"), + TUPLE_POINTER("tuplePointer"), + USER_DEFINED_EFFECT("userDefinedEffect"), + USER_DEFINED_EFFECT_METHOD("userDefinedMethod"), + USER_DEFINED_EFFECT_POINTER("userDefinedEffectPointer"), + VAR_VALUE("varValue"); + + private final String name; + + ShidToPatioLocalSpace(String name) { + this.name = name; + } + + @Override + public String toString() { + return name; + } +} diff --git a/src/main/java/org/shedlang/compiler/shidtopatio/ShidToPatioNamespaces.java b/src/main/java/org/shedlang/compiler/shidtopatio/ShidToPatioNamespaces.java new file mode 100644 index 00000000..68d55634 --- /dev/null +++ b/src/main/java/org/shedlang/compiler/shidtopatio/ShidToPatioNamespaces.java @@ -0,0 +1,310 @@ +package org.shedlang.compiler.shidtopatio; + +import org.shedlang.compiler.patio.ast.PatioFunctionDeclaration; +import org.shedlang.compiler.patio.ast.PatioVisibility; +import org.shedlang.compiler.patio.ast.instructions.*; +import org.shedlang.compiler.patio.ast.operands.PatioBool; +import org.shedlang.compiler.patio.ast.operands.PatioDataPtr; +import org.shedlang.compiler.patio.ast.operands.PatioLocalRef; +import org.shedlang.compiler.patio.ast.operands.PatioOperand; +import org.shedlang.compiler.patio.ast.types.*; +import org.shedlang.compiler.sources.Source; +import org.shedlang.compiler.sources.Sources; +import org.shedlang.compiler.types.NamespaceName; +import org.shedlang.compiler.types.NamespaceTypeInfo; +import org.shedlang.compiler.util.Lists; + +import java.util.List; +import java.util.Optional; +import java.util.function.Function; + +public class ShidToPatioNamespaces { + public static final PatioType NAMESPACE_VALUE_TYPE = ShidToPatioTypes.VALUE_TYPE; + + private ShidToPatioNamespaces() {} + + public static ShidToPatioContext define( + NamespaceName namespaceName, + Function generateInitBody, + ShidToPatioContext context + ) { + // TODO: proper source. Probably wrap up stack namespace in a data structure with a source? + var source = Sources.NULL; + + var namespaceTypeInfo = context.namespaceTypeInfo(namespaceName); + var layout = namespaceDataLayout(namespaceTypeInfo); + + context = context.addDataElementMutable( + globalNameNamespaceValue(namespaceName), + PatioDataValues.dataPointerNull(), + source + ); + + context = context.addDataElementMutable( + globalNameNamespaceIsInited(namespaceName), + PatioDataValues.bool(false), + source + ); + + context = context.createFunction( + globalNameNamespaceInit(namespaceName), + PatioVisibility.PRIVATE, + PatioTypes.VOID, + source, + initContext -> { + var namespaceValueResult = initContext.allocateVal( + ShidToPatioLocalSpace.NAMESPACE_VALUE, + PatioTypes.DATA_POINTER + ); + var namespaceValue = namespaceValueResult.value(); + initContext = namespaceValueResult.context(); + + initContext = ShidToPatioGc.alloc( + namespaceValue, + layout, + GC_CHILDREN_OFFSET, + namespaceTypeInfo.fieldCount(), + source, + initContext + ); + + initContext = initContext.addInstruction(new PatioMemoryStore( + new PatioDataPtr(globalNameNamespaceValue(namespaceName)), + PatioDataLayouts.DATA_POINTER, + List.of(), + namespaceValue, + source + )); + + initContext = generateInitBody.apply(initContext); + + initContext = initContext.addInstruction(new PatioMemoryStore( + new PatioDataPtr(globalNameNamespaceIsInited(namespaceName)), + PatioDataLayouts.BOOL, + List.of(), + new PatioBool(true), + source + )); + + initContext = initContext.addInstruction(new PatioReturnVoid(source)); + + return initContext; + } + ); + + context = context.createFunction( + globalNameNamespaceImport(namespaceName), + PatioVisibility.PUBLIC, + NAMESPACE_VALUE_TYPE, + source, + importContext -> { + var isInitedResult = importContext.allocateVal( + ShidToPatioLocalSpace.TEMPORARY, + PatioTypes.BOOL + ); + var isInited = isInitedResult.value(); + importContext = isInitedResult.context(); + + importContext = importContext.addInstruction(new PatioMemoryLoad( + isInited, + new PatioDataPtr(globalNameNamespaceIsInited(namespaceName)), + PatioDataLayouts.BOOL, + List.of(), + source + )); + + importContext = importContext.addInstruction(new PatioIf( + List.of(), + isInited, + new PatioBlock( + List.of(), + List.of(), + source + ), + new PatioBlock( + List.of( + new PatioCall( + Optional.empty(), + globalNameNamespaceInit(namespaceName), + List.of(), + source + ) + ), + List.of(), + source + ), + source + )); + + var namespaceValuePointerResult = importContext.allocateVal( + ShidToPatioLocalSpace.NAMESPACE_POINTER, + NAMESPACE_VALUE_TYPE + ); + var namespaceValuePointer = namespaceValuePointerResult.value(); + importContext = namespaceValuePointerResult.context(); + + importContext = importContext.addInstruction(new PatioMemoryLoad( + namespaceValuePointer, + new PatioDataPtr(globalNameNamespaceValue(namespaceName)), + PatioDataLayouts.DATA_POINTER, + List.of(), + source + )); + + var namespaceValueResult = importContext.allocateVal( + ShidToPatioLocalSpace.NAMESPACE_VALUE, + NAMESPACE_VALUE_TYPE + ); + var namespaceValue = namespaceValueResult.value(); + importContext = namespaceValueResult.context(); + + importContext = importContext.addInstruction(new PatioDataPtrToInt( + namespaceValue, + namespaceValuePointer, + source + )); + + importContext = importContext.addInstruction(new PatioReturn( + namespaceValue, + source + )); + + return importContext; + } + ); + + return context; + } + + public static ShidToPatioContext importValue( + PatioLocalRef target, + NamespaceName namespaceName, + Source source, + ShidToPatioContext context + ) { + context = context.addCompilationUnitElement(new PatioFunctionDeclaration( + globalNameNamespaceImport(namespaceName), + List.of(), + NAMESPACE_VALUE_TYPE, + source + )); + + context = context.addInstruction(new PatioCall( + Optional.of(target), + globalNameNamespaceImport(namespaceName), + List.of(), + source + )); + + return context; + } + + public static ShidToPatioContext fieldLoad( + PatioLocalRef target, + PatioOperand receiver, + NamespaceName namespaceName, + String fieldName, + Source source, + ShidToPatioContext context + ) { + var namespaceTypeInfo = context.namespaceTypeInfo(namespaceName); + var layout = namespaceDataLayout(namespaceTypeInfo); + + var namespacePointerResult = context.allocateVal( + ShidToPatioLocalSpace.NAMESPACE_POINTER, + namespaceNameToPatioIdentifier(namespaceName), + PatioTypes.DATA_POINTER + ); + var namespacePointer = namespacePointerResult.value(); + context = namespacePointerResult.context(); + + context = context.addInstruction(new PatioIntToDataPtr( + namespacePointer, + receiver, + source + )); + + context = context.addInstruction(new PatioMemoryLoad( + target, + namespacePointer, + layout, + fieldOffset(namespaceTypeInfo.fieldIndex(fieldName)), + source + )); + + return context; + } + + public static ShidToPatioContext fieldStore( + NamespaceName namespaceName, + String fieldName, + PatioOperand fieldValue, + Source source, + ShidToPatioContext context + ) { + var namespaceTypeInfo = context.namespaceTypeInfo(namespaceName); + var layout = namespaceDataLayout(namespaceTypeInfo); + + var namespaceValueResult = context.allocateVal( + ShidToPatioLocalSpace.NAMESPACE_VALUE, + PatioTypes.DATA_POINTER + ); + var namespaceValue = namespaceValueResult.value(); + context = namespaceValueResult.context(); + + context = context.addInstruction(new PatioMemoryLoad( + namespaceValue, + new PatioDataPtr(globalNameNamespaceValue(namespaceName)), + PatioDataLayouts.DATA_POINTER, + List.of(), + source + )); + + context = context.addInstruction(new PatioMemoryStore( + namespaceValue, + layout, + fieldOffset(namespaceTypeInfo.fieldIndex(fieldName)), + fieldValue, + source + )); + + return context; + } + + private static PatioDataLayout namespaceDataLayout(NamespaceTypeInfo namespaceTypeInfo) { + return ShidToPatioGc.gcObjectDataLayout(PatioDataLayouts.struct( + Lists.repeat( + PatioDataLayouts.INT, + namespaceTypeInfo.fieldCount() + ) + )); + } + + private static List fieldOffset(int fieldIndex) { + return ShidToPatioGc.gcObjectOffset(List.of(fieldIndex)); + } + + private static final List GC_CHILDREN_OFFSET = + ShidToPatioGc.gcObjectOffset(List.of()); + + // TODO: allocate names through context + private static String globalNameNamespaceValue(NamespaceName namespaceName) { + return "shed__namespace__" + namespaceNameToPatioIdentifier(namespaceName); + } + + private static String globalNameNamespaceInit(NamespaceName namespaceName) { + return "shed__namespaceInit__" + namespaceNameToPatioIdentifier(namespaceName); + } + + private static String globalNameNamespaceIsInited(NamespaceName namespaceName) { + return "shed__namespaceIsInited__" + namespaceNameToPatioIdentifier(namespaceName); + } + + private static String globalNameNamespaceImport(NamespaceName namespaceName) { + return "shed__namespaceImport__" + namespaceNameToPatioIdentifier(namespaceName); + } + + public static String namespaceNameToPatioIdentifier(NamespaceName namespaceName) { + return String.join("_", namespaceName.parts()); + } +} diff --git a/src/main/java/org/shedlang/compiler/shidtopatio/ShidToPatioResult.java b/src/main/java/org/shedlang/compiler/shidtopatio/ShidToPatioResult.java new file mode 100644 index 00000000..537b8f6f --- /dev/null +++ b/src/main/java/org/shedlang/compiler/shidtopatio/ShidToPatioResult.java @@ -0,0 +1,4 @@ +package org.shedlang.compiler.shidtopatio; + +public record ShidToPatioResult(T value, ShidToPatioContext context) { +} diff --git a/src/main/java/org/shedlang/compiler/shidtopatio/ShidToPatioStrings.java b/src/main/java/org/shedlang/compiler/shidtopatio/ShidToPatioStrings.java new file mode 100644 index 00000000..06cb5855 --- /dev/null +++ b/src/main/java/org/shedlang/compiler/shidtopatio/ShidToPatioStrings.java @@ -0,0 +1,84 @@ +package org.shedlang.compiler.shidtopatio; + +import org.shedlang.compiler.patio.ast.PatioDataElementImmutable; +import org.shedlang.compiler.patio.ast.PatioFunctionDeclaration; +import org.shedlang.compiler.patio.ast.PatioLocal; +import org.shedlang.compiler.patio.ast.instructions.PatioCall; +import org.shedlang.compiler.patio.ast.operands.PatioDataPtr; +import org.shedlang.compiler.patio.ast.operands.PatioLocalRef; +import org.shedlang.compiler.patio.ast.operands.PatioOperand; +import org.shedlang.compiler.patio.ast.types.PatioDataLayouts; +import org.shedlang.compiler.patio.ast.types.PatioDataValue; +import org.shedlang.compiler.patio.ast.types.PatioDataValues; +import org.shedlang.compiler.sources.Source; +import org.shedlang.compiler.sources.Sources; + +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + +public class ShidToPatioStrings { + public static final PatioFunctionDeclaration STRING_ADD_DECLARATION = new PatioFunctionDeclaration( + "shed__runtime__string_add", + List.of( + PatioLocal.param("left", ShidToPatioTypes.VALUE_TYPE), + PatioLocal.param("right", ShidToPatioTypes.VALUE_TYPE) + ), + ShidToPatioTypes.VALUE_TYPE, + Sources.RUNTIME + ); + + private ShidToPatioStrings() {} + + public static ShidToPatioResult define( + String value, + Source source, + ShidToPatioContext context + ) { + var codeUnits = value.getBytes(StandardCharsets.UTF_8); + + var codeUnitsDataValues = new ArrayList(); + for (var codeUnit : codeUnits) { + codeUnitsDataValues.add(PatioDataValues.byte_(codeUnit)); + } + + var dataValue = ShidToPatioGc.gcObjectStaticDataValue(PatioDataValues.struct(List.of( + PatioDataValues.int_(codeUnits.length), + PatioDataValues.array(PatioDataLayouts.BYTE, codeUnitsDataValues) + ))); + + var elementNameResult = context.allocateCompilationUnitElementName( + ShidToPatioCompilationUnitElementSpace.STRING + ); + var elementName = elementNameResult.value(); + context = elementNameResult.context(); + + context = context.addCompilationUnitElement(new PatioDataElementImmutable( + elementName, + dataValue, + source + )); + + return context.toResult(new PatioDataPtr(elementName)); + } + + public static ShidToPatioContext add( + PatioLocalRef target, + PatioOperand left, + PatioOperand right, + Source source, + ShidToPatioContext context + ) { + context = context.ensureCompilationUnitElement(STRING_ADD_DECLARATION); + + context = context.addInstruction(new PatioCall( + Optional.of(target), + STRING_ADD_DECLARATION.name(), + List.of(left, right), + source + )); + + return context; + } +} diff --git a/src/main/java/org/shedlang/compiler/shidtopatio/ShidToPatioStructs.java b/src/main/java/org/shedlang/compiler/shidtopatio/ShidToPatioStructs.java new file mode 100644 index 00000000..7e8159d2 --- /dev/null +++ b/src/main/java/org/shedlang/compiler/shidtopatio/ShidToPatioStructs.java @@ -0,0 +1,200 @@ +package org.shedlang.compiler.shidtopatio; + +import org.shedlang.compiler.ast.typed.FreeVariables; +import org.shedlang.compiler.patio.ast.instructions.*; +import org.shedlang.compiler.patio.ast.operands.PatioInt; +import org.shedlang.compiler.patio.ast.operands.PatioLocalRef; +import org.shedlang.compiler.patio.ast.operands.PatioOperand; +import org.shedlang.compiler.patio.ast.types.PatioDataLayout; +import org.shedlang.compiler.patio.ast.types.PatioDataLayouts; +import org.shedlang.compiler.patio.ast.types.PatioTypes; +import org.shedlang.compiler.sources.Source; +import org.shedlang.compiler.shid.instructions.ShidDefineFunction; +import org.shedlang.compiler.shid.instructions.ShidDefineStruct; +import org.shedlang.compiler.types.StructType; +import org.shedlang.compiler.util.Lists; + +import java.util.List; + +public class ShidToPatioStructs { + private ShidToPatioStructs() { + } + + public static ShidToPatioContext createType( + PatioLocalRef target, + StructType type, + List fields, + Source source, + ShidToPatioContext context + ) { + return ShidToPatioFunctions.create( + target, + type.name(), + List.of(), + fields.stream() + .map(field -> new ShidDefineFunction.Param(field.name(), field.source())) + .toList(), + FreeVariables.empty(), + bodyContext -> { + var valuePointerResult = bodyContext.allocateVal( + ShidToPatioLocalSpace.STRUCT_VALUE_POINTER, + PatioTypes.DATA_POINTER + ); + var valuePointer = valuePointerResult.value(); + bodyContext = valuePointerResult.context(); + + var structDataLayout = structDataLayout(type, context); + + bodyContext = ShidToPatioGc.alloc( + valuePointer, + structDataLayout, + GC_CHILDREN_OFFSET, + fields.size(), + source, + bodyContext + ); + + bodyContext = bodyContext + .addInstruction(new PatioMemoryStore( + valuePointer, + structDataLayout, + TAG_OFFSET, + new PatioInt(context.structTag(type)), + source + )); + + for (var fieldIndex = 0; fieldIndex < fields.size(); fieldIndex++) { + var field = fields.get(fieldIndex); + + bodyContext = bodyContext + .addInstruction(new PatioMemoryStore( + valuePointer, + structDataLayout, + fieldOffset(fieldIndex), + bodyContext.shidLocalNameToLocal(field.name()), + source + )); + } + + var valueResult = bodyContext.allocateVal( + ShidToPatioLocalSpace.STRUCT_VALUE, + ShidToPatioTypes.VALUE_TYPE + ); + var value = valueResult.value(); + bodyContext = valueResult.context(); + + bodyContext = bodyContext.addInstruction(new PatioDataPtrToInt( + value, + valuePointer, + source + )); + + bodyContext = bodyContext.addInstruction(new PatioReturn(value, source)); + + return bodyContext; + }, + source, + context + ); + } + + public static ShidToPatioContext fieldLoad( + PatioLocalRef target, + PatioOperand receiver, + StructType type, + String fieldName, + Source source, + ShidToPatioContext context + ) { + var valuePointerResult = context.allocateVal( + ShidToPatioLocalSpace.STRUCT_VALUE_POINTER, + PatioTypes.DATA_POINTER + ); + var valuePointer = valuePointerResult.value(); + context = valuePointerResult.context(); + + context = context.addInstruction(new PatioIntToDataPtr( + valuePointer, + receiver, + source + )); + + var structDataLayout = structDataLayout(type, context); + + var structTypeInfo = context.structTypeInfo(type); + var fieldIndex = structTypeInfo.fieldIndex(fieldName); + + context = context.addInstruction(new PatioMemoryLoad( + target, + valuePointer, + structDataLayout, + fieldOffset(fieldIndex), + source + )); + + return context; + } + + public static ShidToPatioContext tagLoad( + PatioLocalRef target, + PatioOperand receiver, + Source source, + ShidToPatioContext context + ) { + var valuePointerResult = context.allocateVal( + ShidToPatioLocalSpace.STRUCT_VALUE_POINTER, + PatioTypes.DATA_POINTER + ); + var valuePointer = valuePointerResult.value(); + context = valuePointerResult.context(); + + context = context.addInstruction(new PatioIntToDataPtr( + valuePointer, + receiver, + source + )); + + var structDataLayout = unknownStructDataLayout(); + + context = context.addInstruction(new PatioMemoryLoad( + target, + valuePointer, + structDataLayout, + TAG_OFFSET, + source + )); + + return context; + } + + private static PatioDataLayout unknownStructDataLayout() { + return ShidToPatioGc.gcObjectDataLayout(PatioDataLayouts.struct(List.of( + PatioDataLayouts.INT + ))); + } + + private static PatioDataLayout structDataLayout( + StructType type, + ShidToPatioContext context + ) { + var structTypeInfo = context.structTypeInfo(type); + + return ShidToPatioGc.gcObjectDataLayout(PatioDataLayouts.struct(List.of( + PatioDataLayouts.INT, + PatioDataLayouts.struct(Lists.repeat( + PatioDataLayouts.INT, + structTypeInfo.fieldCount() + )) + ))); + } + + private static final List TAG_OFFSET + = ShidToPatioGc.gcObjectOffset(List.of(0)); + + private static List fieldOffset(int fieldIndex) { + return ShidToPatioGc.gcObjectOffset(List.of(1, fieldIndex)); + } + + private static final List GC_CHILDREN_OFFSET = + ShidToPatioGc.gcObjectOffset(List.of(1)); +} diff --git a/src/main/java/org/shedlang/compiler/shidtopatio/ShidToPatioTuples.java b/src/main/java/org/shedlang/compiler/shidtopatio/ShidToPatioTuples.java new file mode 100644 index 00000000..75815fcb --- /dev/null +++ b/src/main/java/org/shedlang/compiler/shidtopatio/ShidToPatioTuples.java @@ -0,0 +1,132 @@ +package org.shedlang.compiler.shidtopatio; + +import org.shedlang.compiler.patio.ast.instructions.*; +import org.shedlang.compiler.patio.ast.operands.PatioInt; +import org.shedlang.compiler.patio.ast.operands.PatioLocalRef; +import org.shedlang.compiler.patio.ast.operands.PatioOperand; +import org.shedlang.compiler.patio.ast.types.PatioDataLayout; +import org.shedlang.compiler.patio.ast.types.PatioDataLayouts; +import org.shedlang.compiler.patio.ast.types.PatioTypes; +import org.shedlang.compiler.sources.Source; +import org.shedlang.compiler.util.Lists; + +import java.util.List; + +public class ShidToPatioTuples { + private ShidToPatioTuples() { + } + + public static ShidToPatioResult create( + List elements, + Source source, + ShidToPatioContext context + ) { + var tupleResult = context.allocateVal( + ShidToPatioLocalSpace.TUPLE, + ShidToPatioTypes.VALUE_TYPE + ); + var tuple = tupleResult.value(); + context = tupleResult.context(); + + if (elements.size() == 0) { + context = context.addInstruction(new PatioLocalStore( + tuple, + new PatioInt(0), + source + )); + + return context.toResult(tuple); + } + + var tuplePointerResult = context.allocateVal( + ShidToPatioLocalSpace.TUPLE_POINTER, + PatioTypes.DATA_POINTER + ); + var tuplePointer = tuplePointerResult.value(); + context = tuplePointerResult.context(); + + var tupleLayout = tupleDataLayout(elements.size()); + + context = ShidToPatioGc.alloc( + tuplePointer, + tupleLayout, + GC_CHILDREN_OFFSET, + elements.size(), + source, + context + ); + + for (var elementIndex = 0; elementIndex < elements.size(); elementIndex++) { + var element = elements.get(elementIndex); + + context = context.addInstruction(new PatioMemoryStore( + tuplePointer, + tupleLayout, + elementOffset(elementIndex), + element, + source + )); + } + + context = context.addInstruction(new PatioDataPtrToInt( + tuple, + tuplePointer, + source + )); + + return context.toResult(tuple); + } + + public static ShidToPatioResult get( + PatioOperand tuple, + int elementIndex, + int elementCount, + Source source, + ShidToPatioContext context + ) { + var tuplePointerResult = context.allocateVal( + ShidToPatioLocalSpace.TUPLE, + PatioTypes.DATA_POINTER + ); + var tuplePointer = tuplePointerResult.value(); + context = tuplePointerResult.context(); + + context = context.addInstruction(new PatioIntToDataPtr( + tuplePointer, + tuple, + source + )); + + var targetResult = context.allocateVal( + ShidToPatioLocalSpace.TUPLE_ELEMENT, + Integer.toString(elementIndex), + ShidToPatioTypes.VALUE_TYPE + ); + var target = targetResult.value(); + context = targetResult.context(); + + context = context.addInstruction(new PatioMemoryLoad( + target, + tuplePointer, + tupleDataLayout(elementCount), + elementOffset(elementIndex), + source + )); + + return context.toResult(target); + } + + private static PatioDataLayout tupleDataLayout(int elementCount) { + return ShidToPatioGc.gcObjectDataLayout(PatioDataLayouts.struct(Lists.repeat( + PatioDataLayouts.INT, + elementCount + ))); + } + + private static List elementOffset(int elementIndex) { + return ShidToPatioGc.gcObjectOffset(List.of(elementIndex)); + } + + private static final List GC_CHILDREN_OFFSET = + ShidToPatioGc.gcObjectOffset(List.of()); +} diff --git a/src/main/java/org/shedlang/compiler/shidtopatio/ShidToPatioTypes.java b/src/main/java/org/shedlang/compiler/shidtopatio/ShidToPatioTypes.java new file mode 100644 index 00000000..1d6a6567 --- /dev/null +++ b/src/main/java/org/shedlang/compiler/shidtopatio/ShidToPatioTypes.java @@ -0,0 +1,11 @@ +package org.shedlang.compiler.shidtopatio; + +import org.shedlang.compiler.patio.ast.types.PatioType; +import org.shedlang.compiler.patio.ast.types.PatioTypes; + +public class ShidToPatioTypes { + private ShidToPatioTypes() {} + + public static final PatioType TAG_TYPE = PatioTypes.INT; + public static final PatioType VALUE_TYPE = PatioTypes.INT; +} diff --git a/src/main/java/org/shedlang/compiler/shidtopatio/ShidToPatioVars.java b/src/main/java/org/shedlang/compiler/shidtopatio/ShidToPatioVars.java new file mode 100644 index 00000000..1aca893f --- /dev/null +++ b/src/main/java/org/shedlang/compiler/shidtopatio/ShidToPatioVars.java @@ -0,0 +1,80 @@ +package org.shedlang.compiler.shidtopatio; + +import org.shedlang.compiler.patio.ast.instructions.PatioMemoryLoad; +import org.shedlang.compiler.patio.ast.instructions.PatioMemoryStore; +import org.shedlang.compiler.patio.ast.operands.PatioLocalRef; +import org.shedlang.compiler.patio.ast.operands.PatioOperand; +import org.shedlang.compiler.patio.ast.types.PatioDataLayout; +import org.shedlang.compiler.patio.ast.types.PatioDataLayouts; +import org.shedlang.compiler.patio.ast.types.PatioTypes; +import org.shedlang.compiler.sources.Source; + +import java.util.List; + +public class ShidToPatioVars { + private ShidToPatioVars() { + } + + private static final PatioDataLayout VAR_DATA_LAYOUT = + ShidToPatioGc.gcObjectDataLayout(PatioDataLayouts.fromType(ShidToPatioTypes.VALUE_TYPE)); + + private static final List VALUE_OFFSET = ShidToPatioGc.gcObjectOffset(List.of()); + private static final List GC_CHILDREN_OFFSET = ShidToPatioGc.gcObjectOffset(List.of()); + private static final int GC_CHILDREN_COUNT = 1; + + public static ShidToPatioContext alloc( + String shidName, + Source source, + ShidToPatioContext context + ) { + var patioLocalResult = context.declareShidVal( + shidName, + PatioTypes.DATA_POINTER + ); + var patioLocal = patioLocalResult.value(); + context = patioLocalResult.context(); + + context = ShidToPatioGc.alloc( + patioLocal, + VAR_DATA_LAYOUT, + GC_CHILDREN_OFFSET, + GC_CHILDREN_COUNT, + source, + context + ); + + context = context.initShidLocal(shidName); + + return context; + } + + public static ShidToPatioContext store( + String shidName, + PatioOperand value, + Source source, + ShidToPatioContext context + ) { + return context.addInstruction(new PatioMemoryStore( + context.shidLocalNameToLocal(shidName), + VAR_DATA_LAYOUT, + VALUE_OFFSET, + value, + source + )); + } + + public static ShidToPatioContext load( + PatioLocalRef target, + String shidName, + Source source, + ShidToPatioContext context + ) { + return context.addInstruction(new PatioMemoryLoad( + target, + context.shidLocalNameToLocal(shidName), + VAR_DATA_LAYOUT, + VALUE_OFFSET, + source + )); + } +} diff --git a/src/main/java/org/shedlang/compiler/shidtopatio/errors/DuplicateCompilationUnitElementName.java b/src/main/java/org/shedlang/compiler/shidtopatio/errors/DuplicateCompilationUnitElementName.java new file mode 100644 index 00000000..3ef1b361 --- /dev/null +++ b/src/main/java/org/shedlang/compiler/shidtopatio/errors/DuplicateCompilationUnitElementName.java @@ -0,0 +1,17 @@ +package org.shedlang.compiler.shidtopatio.errors; + +import org.shedlang.compiler.errors.InternalCompilerError; +import org.shedlang.compiler.sources.Source; + +public class DuplicateCompilationUnitElementName extends InternalCompilerError { + private final String elementName; + + public DuplicateCompilationUnitElementName(String elementName, Source source) { + super("Duplicate compilation unit element name: " + elementName, source); + this.elementName = elementName; + } + + public String elementName() { + return elementName; + } +} -- cgit v1.2.3