package org.shedlang.compiler.shidtopatio; import org.shedlang.compiler.patio.PatioCompilationUnit; import org.shedlang.compiler.patio.PatioDataElementImmutableDefinition; import org.shedlang.compiler.patio.PatioVisibility; import org.shedlang.compiler.patio.instructions.*; import org.shedlang.compiler.patio.operands.PatioIntConst; import org.shedlang.compiler.patio.operands.PatioLocalRef; import org.shedlang.compiler.patio.operands.PatioOperand; import org.shedlang.compiler.patio.types.PatioDataLayouts; import org.shedlang.compiler.patio.types.PatioDataValues; import org.shedlang.compiler.patio.types.PatioTypes; import org.shedlang.compiler.patio.values.PatioIntValueByteOffsetOf; 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, List.of(PatioTypes.INT), source, mainContext -> { mainContext = ShidToPatioGc.init(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 ); // TODO: main returns unit, not an exit code // TODO: (do we enforce this anywhere?) var exitCode = exitCodeResult.value(); mainContext = exitCodeResult.context(); mainContext = ShidToPatioClosures.call( exitCode, mainField, List.of(), List.of(), source, mainContext ); mainContext = ShidToPatioGc.collect(source, mainContext); mainContext = ShidToPatioGc.clear(source, mainContext); mainContext = mainContext.addInstruction( new PatioReturn(List.of(exitCode), source) ); return mainContext; } ); return context.toResult(mainFunctionName); } public static ShidToPatioContext.GlobalContext.Result generateNamespace( ShidNamespace shidNamespace, ShidToPatioContext context ) { context = ShidToPatioNamespaces.define( shidNamespace.namespaceName(), initContext -> generateBlockNoResults(shidNamespace.body(), initContext), shidNamespace.source(), 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 destinationResult = context.allocateVal( ShidToPatioLocalSpace.TEMPORARY, ShidToPatioTypes.VALUE_TYPE ); var destination = destinationResult.value(); context = destinationResult.context(); yield ShidToPatioClosures.call( destination, receiver, positionalArgs, namedArgsByName, shidInstruction.source(), context ).temporaryPush(destination); } case ShidDeclareNativeType declareNativeType -> { yield pushValue(0, declareNativeType.source(), context); } case ShidDefineEffect defineEffect -> { var destinationResult = context.allocateVal( ShidToPatioLocalSpace.USER_DEFINED_EFFECT, defineEffect.effect().name(), ShidToPatioTypes.VALUE_TYPE ); var destination = destinationResult.value(); context = destinationResult.context(); context = ShidToPatioEffects.createUserDefinedEffect( destination, defineEffect.effect(), defineEffect.source(), context ); context = context.temporaryPush(destination); yield context; } case ShidDeclareNativeFunction declareNativeFunction -> { var destinationResult = context.allocateVal( ShidToPatioLocalSpace.CLOSURE, declareNativeFunction.name(), ShidToPatioTypes.VALUE_TYPE ); var destination = destinationResult.value(); context = destinationResult.context(); context = ShidToPatioFunctions.createNative( destination, declareNativeFunction.namespaceName(), declareNativeFunction.name(), declareNativeFunction.positionalParams(), declareNativeFunction.namedParams(), declareNativeFunction.source(), context ); context = context.temporaryPush(destination); yield context; } case ShidDefineFunction defineFunction -> { var destinationResult = context.allocateVal( ShidToPatioLocalSpace.CLOSURE, defineFunction.name(), ShidToPatioTypes.VALUE_TYPE ); var destination = destinationResult.value(); context = destinationResult.context(); Function generateBody = functionContext -> { return generateBlockNoResults(defineFunction.body(), functionContext); }; context = switch (defineFunction.variant()) { case EFFECT_HANDLER_METHOD -> ShidToPatioEffects.createEffectHandlerMethod( destination, defineFunction.name(), defineFunction.positionalParams(), defineFunction.namedParams(), defineFunction.freeVariables(), generateBody, defineFunction.source(), context ); case FUNCTION -> ShidToPatioFunctions.create( destination, defineFunction.name(), defineFunction.positionalParams(), defineFunction.namedParams(), defineFunction.freeVariables(), generateBody, defineFunction.source(), context ); }; context = context.temporaryPush(destination); yield context; } case ShidDefineStruct defineStruct -> { var destinationResult = context.allocateVal( ShidToPatioLocalSpace.STRUCT_TYPE, defineStruct.type().name(), ShidToPatioTypes.VALUE_TYPE ); var destination = destinationResult.value(); context = destinationResult.context(); context = ShidToPatioStructs.createType( destination, defineStruct.type(), defineStruct.fields(), defineStruct.source(), context ); context = context.temporaryPush(destination); 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 destinationResult = context.allocateVal( ShidToPatioLocalSpace.TEMPORARY, fieldLoad.fieldName(), ShidToPatioTypes.VALUE_TYPE ); var destination = destinationResult.value(); context = destinationResult.context(); switch (fieldLoad.receiver()) { case ShidFieldLoad.Receiver.Effect receiverEffect -> { context = ShidToPatioEffects.fieldLoad( destination, receiver, receiverEffect.effect(), fieldLoad.fieldName(), fieldLoad.source(), context ); } case ShidFieldLoad.Receiver.Namespace receiverNamespace -> { context = ShidToPatioNamespaces.fieldLoad( destination, receiver, receiverNamespace.name(), fieldLoad.fieldName(), fieldLoad.source(), context ); } case ShidFieldLoad.Receiver.Struct receiverStruct -> { context = ShidToPatioStructs.fieldLoad( destination, receiver, receiverStruct.type(), fieldLoad.fieldName(), fieldLoad.source(), context ); } } context = context.temporaryPush(destination); yield context; } case ShidIf if_ -> { var conditionBoolResult = generateCondition(if_.source(), context); var conditionBool = conditionBoolResult.value(); context = conditionBoolResult.context(); var destinations = new ArrayList(); for (var i = 0; i < if_.resultCount(); i++) { var destinationResult = context.allocateVal( ShidToPatioLocalSpace.TEMPORARY, ShidToPatioTypes.VALUE_TYPE ); var destination = destinationResult.value(); context = destinationResult.context(); destinations.add(destination); } 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( destinations, conditionBool, trueBody, falseBody, if_.source() )); for (var destination : destinations) { context = context.temporaryPush(destination); } yield context; } case ShidIntAdd intAdd -> generateBinaryOperation( (destination, left, right, operationContext) -> ShidToPatioInts.add( destination, left, right, intAdd.source(), operationContext ), context ); case ShidIntEquals intEquals -> generateComparison( (destination, left, right, operationContext) -> ShidToPatioInts.equals( destination, left, right, intEquals.source(), operationContext ), intEquals.source(), context ); case ShidIntGreaterThan intGreaterThan -> generateComparison( (destination, left, right, operationContext) -> ShidToPatioInts.greaterThan( destination, left, right, intGreaterThan.source(), operationContext ), intGreaterThan.source(), context ); case ShidIntGreaterThanOrEqual intGreaterThanOrEqual -> generateComparison( (destination, left, right, operationContext) -> ShidToPatioInts.greaterThanOrEqual( destination, left, right, intGreaterThanOrEqual.source(), operationContext ), intGreaterThanOrEqual.source(), context ); case ShidIntLessThan intLessThan -> generateComparison( (destination, left, right, operationContext) -> ShidToPatioInts.lessThan( destination, left, right, intLessThan.source(), operationContext ), intLessThan.source(), context ); case ShidIntLessThanOrEqual intLessThanOrEqual -> generateComparison( (destination, left, right, operationContext) -> ShidToPatioInts.lessThanOrEqual( destination, left, right, intLessThanOrEqual.source(), operationContext ), intLessThanOrEqual.source(), context ); case ShidIntMultiply intMultiply -> generateBinaryOperation( (destination, left, right, operationContext) -> ShidToPatioInts.multiply( destination, left, right, intMultiply.source(), operationContext ), context ); case ShidIntNotEqual intNotEqual -> generateComparison( (destination, left, right, operationContext) -> ShidToPatioInts.notEqual( destination, left, right, intNotEqual.source(), operationContext ), intNotEqual.source(), context ); case ShidIntSub intSub -> generateBinaryOperation( (destination, left, right, operationContext) -> ShidToPatioInts.sub( destination, 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 ShidMethodLoad methodLoad -> { var destinationResult = context.allocateVal( ShidToPatioLocalSpace.TEMPORARY, methodLoad.methodName(), ShidToPatioTypes.VALUE_TYPE ); var destination = destinationResult.value(); context = destinationResult.context(); context = ShidToPatioMethods.methodLoad( destination, methodLoad.type(), methodLoad.methodName(), methodLoad.source(), context ); context = context.temporaryPush(destination); yield context; } case ShidMethodStore methodStore -> { var methodValueResult = context.temporaryPop(); var methodValue = methodValueResult.value(); context = methodValueResult.context(); context = ShidToPatioMethods.methodStore( methodStore.type(), methodStore.methodName(), methodValue, methodStore.source(), context ); 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 destinationResult = context.allocateVal( ShidToPatioLocalSpace.INT, ShidToPatioInts.INT_TYPE ); var destination = destinationResult.value(); context = destinationResult.context(); context = ShidToPatioInts.storeConst( destination, pushInt.value(), pushInt.source(), context ); context = context.temporaryPush(destination); 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(List.of(value), return_.source())); } case ShidStringAdd stringAdd -> generateBinaryOperation( (destination, left, right, operationContext) -> ShidToPatioStrings.add( destination, left, right, stringAdd.source(), operationContext ), context ); case ShidSwitch switch_ -> { var destinationResult = context.allocateVal( ShidToPatioLocalSpace.TEMPORARY, ShidToPatioTypes.VALUE_TYPE ); var destination = destinationResult.value(); context = destinationResult.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 PatioSwitchCase( context.structTag(shidCase.caseType()), body, shidCase.source() )); } context = context.addInstruction(new PatioSwitch( List.of(destination), tag, cases, new PatioBlock( List.of( new PatioUnreachable(switch_.source()) ), List.of(), switch_.source() ), switch_.source() )); context = context.temporaryPush(destination); 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 destinationResult = context.allocateVal( ShidToPatioLocalSpace.TEMPORARY, ShidToPatioTypes.VALUE_TYPE ); var destination = destinationResult.value(); context = destinationResult.context(); context = ShidToPatioEffects.try_( destination, try_.handledEffect(), handlerMethodsByName, bodyContext -> generateBlock(try_.body(), bodyContext), try_.source(), context ); context = context.temporaryPush(destination); 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 destinationResult = ShidToPatioTuples.get( tuple, tupleGet.elementIndex(), tupleGet.elementCount(), tupleGet.source(), context ); var destination = destinationResult.value(); context = destinationResult.context(); yield context.temporaryPush(destination); } 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 destination, PatioOperand left, PatioOperand right, ShidToPatioContext context ); } private static ShidToPatioContext generateComparison( BinaryOperationCodeGen binaryOperationCodeGen, Source source, ShidToPatioContext context ) { return generateBinaryOperation( (destination, left, right, operationContext) -> { var destinationBoolResult = operationContext.allocateVal( ShidToPatioLocalSpace.TEMPORARY, PatioTypes.BOOL ); var destinationBool = destinationBoolResult.value(); operationContext = destinationBoolResult.context(); operationContext = binaryOperationCodeGen.generate( destinationBool, left, right, operationContext ); operationContext = operationContext.addInstruction(new PatioBoolToInt( destination, destinationBool, 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 destinationResult = context.allocateVal( ShidToPatioLocalSpace.BINARY_OP_RESULT, ShidToPatioTypes.VALUE_TYPE ); var destination = destinationResult.value(); context = destinationResult.context(); return binaryOperationCodeGen.generate( destination, left, right, context ).temporaryPush(destination); } private static ShidToPatioContext generateBlockNoResults( ShidBlock shidBlock, ShidToPatioContext context ) { // TODO: just use a block in Patio instructions even where there are no destinations? 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 destinationsResult = context.temporaryPopAll(); var destinations = destinationsResult.value().reversed(); context = destinationsResult.context(); var instructionsResult = context.exitBlock(); var instructions = instructionsResult.value(); context = instructionsResult.context(); return context.toResult(new PatioBlock( instructions, destinations, 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, PatioIntConst.of(value), source)) .temporaryPush(local); } public static ShidToPatioContext generateRtti( Source source, ShidToPatioContext context ) { var runtimeTypes = context.runtimeTypes(); context = context.addCompilationUnitElement(new PatioDataElementImmutableDefinition( "shed__rtti", PatioVisibility.PUBLIC, PatioDataValues.array( PatioDataLayouts.struct(List.of( PatioDataLayouts.INT32, PatioDataLayouts.INT32 )), runtimeTypes.stream() .map(runtimeType -> PatioDataValues.struct(List.of( PatioDataValues.int32(new PatioIntValueByteOffsetOf( runtimeType.layout(), runtimeType.gcChildrenOffset() )), PatioDataValues.int32(runtimeType.gcChildrenCount()) ))) .toList() ), source )); return context; } }