diff --git a/bir/src/main/kotlin/gay/pizza/pork/bir/IrBreak.kt b/bir/src/main/kotlin/gay/pizza/pork/bir/IrBreak.kt index 9838e9f..d648c0f 100644 --- a/bir/src/main/kotlin/gay/pizza/pork/bir/IrBreak.kt +++ b/bir/src/main/kotlin/gay/pizza/pork/bir/IrBreak.kt @@ -1,5 +1,8 @@ package gay.pizza.pork.bir +import kotlinx.serialization.Serializable + +@Serializable data class IrBreak(val target: IrSymbol) : IrCodeElement { override fun crawl(block: (IrElement) -> Unit) { block(target) diff --git a/bir/src/main/kotlin/gay/pizza/pork/bir/IrCall.kt b/bir/src/main/kotlin/gay/pizza/pork/bir/IrCall.kt index f355022..b1e169d 100644 --- a/bir/src/main/kotlin/gay/pizza/pork/bir/IrCall.kt +++ b/bir/src/main/kotlin/gay/pizza/pork/bir/IrCall.kt @@ -1,5 +1,8 @@ package gay.pizza.pork.bir +import kotlinx.serialization.Serializable + +@Serializable data class IrCall( override val target: IrSymbol, val arguments: List, diff --git a/bir/src/main/kotlin/gay/pizza/pork/bir/IrCodeBlock.kt b/bir/src/main/kotlin/gay/pizza/pork/bir/IrCodeBlock.kt index a6f3bbf..01bf0fe 100644 --- a/bir/src/main/kotlin/gay/pizza/pork/bir/IrCodeBlock.kt +++ b/bir/src/main/kotlin/gay/pizza/pork/bir/IrCodeBlock.kt @@ -1,5 +1,8 @@ package gay.pizza.pork.bir +import kotlinx.serialization.Serializable + +@Serializable data class IrCodeBlock(val items: List) : IrCodeElement { override fun crawl(block: (IrElement) -> Unit) { items.forEach(block) diff --git a/bir/src/main/kotlin/gay/pizza/pork/bir/IrCodeElement.kt b/bir/src/main/kotlin/gay/pizza/pork/bir/IrCodeElement.kt index 3bdbef6..2885fcb 100644 --- a/bir/src/main/kotlin/gay/pizza/pork/bir/IrCodeElement.kt +++ b/bir/src/main/kotlin/gay/pizza/pork/bir/IrCodeElement.kt @@ -1,3 +1,6 @@ package gay.pizza.pork.bir +import kotlinx.serialization.Serializable + +@Serializable sealed interface IrCodeElement : IrElement diff --git a/compiler/src/main/kotlin/gay/pizza/pork/compiler/IrCodeVisitor.kt b/bir/src/main/kotlin/gay/pizza/pork/bir/IrCodeVisitor.kt similarity index 92% rename from compiler/src/main/kotlin/gay/pizza/pork/compiler/IrCodeVisitor.kt rename to bir/src/main/kotlin/gay/pizza/pork/bir/IrCodeVisitor.kt index 00eb1a8..c80d1ed 100644 --- a/compiler/src/main/kotlin/gay/pizza/pork/compiler/IrCodeVisitor.kt +++ b/bir/src/main/kotlin/gay/pizza/pork/bir/IrCodeVisitor.kt @@ -1,6 +1,4 @@ -package gay.pizza.pork.compiler - -import gay.pizza.pork.bir.* +package gay.pizza.pork.bir interface IrCodeVisitor : IrVisitor { override fun visitIrDefinition(ir: IrDefinition): T { diff --git a/bir/src/main/kotlin/gay/pizza/pork/bir/IrConditional.kt b/bir/src/main/kotlin/gay/pizza/pork/bir/IrConditional.kt index c81a816..ccca1a8 100644 --- a/bir/src/main/kotlin/gay/pizza/pork/bir/IrConditional.kt +++ b/bir/src/main/kotlin/gay/pizza/pork/bir/IrConditional.kt @@ -1,5 +1,8 @@ package gay.pizza.pork.bir +import kotlinx.serialization.Serializable + +@Serializable data class IrConditional( val conditional: IrCodeElement, val ifTrue: IrCodeElement, diff --git a/bir/src/main/kotlin/gay/pizza/pork/bir/IrConstant.kt b/bir/src/main/kotlin/gay/pizza/pork/bir/IrConstant.kt index 8ff6211..fc29f64 100644 --- a/bir/src/main/kotlin/gay/pizza/pork/bir/IrConstant.kt +++ b/bir/src/main/kotlin/gay/pizza/pork/bir/IrConstant.kt @@ -1,12 +1,26 @@ package gay.pizza.pork.bir +import kotlinx.serialization.Serializable + +@Serializable sealed interface IrConstant : IrCodeElement { override fun crawl(block: (IrElement) -> Unit) {} } +@Serializable data class IrIntegerConstant(val value: Int) : IrConstant + +@Serializable data class IrLongConstant(val value: Long) : IrConstant + +@Serializable data class IrDoubleConstant(val value: Double) : IrConstant + +@Serializable data class IrStringConstant(val value: String) : IrConstant + +@Serializable data class IrBooleanConstant(val value: Boolean) : IrConstant + +@Serializable data object IrNoneConstant : IrConstant diff --git a/bir/src/main/kotlin/gay/pizza/pork/bir/IrContinue.kt b/bir/src/main/kotlin/gay/pizza/pork/bir/IrContinue.kt index 113f3d2..444f304 100644 --- a/bir/src/main/kotlin/gay/pizza/pork/bir/IrContinue.kt +++ b/bir/src/main/kotlin/gay/pizza/pork/bir/IrContinue.kt @@ -1,5 +1,8 @@ package gay.pizza.pork.bir +import kotlinx.serialization.Serializable + +@Serializable data class IrContinue(override val target: IrSymbol) : IrCodeElement, IrSymbolUser { override fun crawl(block: (IrElement) -> Unit) { block(target) diff --git a/bir/src/main/kotlin/gay/pizza/pork/bir/IrDefinition.kt b/bir/src/main/kotlin/gay/pizza/pork/bir/IrDefinition.kt index af300a9..eefc1ab 100644 --- a/bir/src/main/kotlin/gay/pizza/pork/bir/IrDefinition.kt +++ b/bir/src/main/kotlin/gay/pizza/pork/bir/IrDefinition.kt @@ -1,5 +1,8 @@ package gay.pizza.pork.bir +import kotlinx.serialization.Serializable + +@Serializable data class IrDefinition( override val symbol: IrSymbol, val type: IrDefinitionType, diff --git a/bir/src/main/kotlin/gay/pizza/pork/bir/IrDefinitionType.kt b/bir/src/main/kotlin/gay/pizza/pork/bir/IrDefinitionType.kt index 34c3867..0185de3 100644 --- a/bir/src/main/kotlin/gay/pizza/pork/bir/IrDefinitionType.kt +++ b/bir/src/main/kotlin/gay/pizza/pork/bir/IrDefinitionType.kt @@ -1,5 +1,8 @@ package gay.pizza.pork.bir +import kotlinx.serialization.Serializable + +@Serializable enum class IrDefinitionType { Variable, CodeFunction, diff --git a/bir/src/main/kotlin/gay/pizza/pork/bir/IrElement.kt b/bir/src/main/kotlin/gay/pizza/pork/bir/IrElement.kt index 349a42a..86aea1d 100644 --- a/bir/src/main/kotlin/gay/pizza/pork/bir/IrElement.kt +++ b/bir/src/main/kotlin/gay/pizza/pork/bir/IrElement.kt @@ -1,5 +1,8 @@ package gay.pizza.pork.bir +import kotlinx.serialization.Serializable + +@Serializable sealed interface IrElement { fun crawl(block: (IrElement) -> Unit) } diff --git a/bir/src/main/kotlin/gay/pizza/pork/bir/IrFunctionArgument.kt b/bir/src/main/kotlin/gay/pizza/pork/bir/IrFunctionArgument.kt index e317109..7998456 100644 --- a/bir/src/main/kotlin/gay/pizza/pork/bir/IrFunctionArgument.kt +++ b/bir/src/main/kotlin/gay/pizza/pork/bir/IrFunctionArgument.kt @@ -1,5 +1,8 @@ package gay.pizza.pork.bir +import kotlinx.serialization.Serializable + +@Serializable data class IrFunctionArgument(override val symbol: IrSymbol) : IrSymbolOwner { override fun crawl(block: (IrElement) -> Unit) {} } diff --git a/bir/src/main/kotlin/gay/pizza/pork/bir/IrIndex.kt b/bir/src/main/kotlin/gay/pizza/pork/bir/IrIndex.kt new file mode 100644 index 0000000..b590283 --- /dev/null +++ b/bir/src/main/kotlin/gay/pizza/pork/bir/IrIndex.kt @@ -0,0 +1,11 @@ +package gay.pizza.pork.bir + +import kotlinx.serialization.Serializable + +@Serializable +data class IrIndex(val data: IrCodeElement, val index: IrCodeElement) : IrCodeElement { + override fun crawl(block: (IrElement) -> Unit) { + block(data) + block(index) + } +} diff --git a/bir/src/main/kotlin/gay/pizza/pork/bir/IrInfix.kt b/bir/src/main/kotlin/gay/pizza/pork/bir/IrInfix.kt index 91449a1..943ebb8 100644 --- a/bir/src/main/kotlin/gay/pizza/pork/bir/IrInfix.kt +++ b/bir/src/main/kotlin/gay/pizza/pork/bir/IrInfix.kt @@ -1,5 +1,8 @@ package gay.pizza.pork.bir +import kotlinx.serialization.Serializable + +@Serializable data class IrInfix(val op: IrInfixOp, val left: IrCodeElement, val right: IrCodeElement) : IrCodeElement { override fun crawl(block: (IrElement) -> Unit) { block(left) diff --git a/bir/src/main/kotlin/gay/pizza/pork/bir/IrInfixOp.kt b/bir/src/main/kotlin/gay/pizza/pork/bir/IrInfixOp.kt index e57a45e..c6243d7 100644 --- a/bir/src/main/kotlin/gay/pizza/pork/bir/IrInfixOp.kt +++ b/bir/src/main/kotlin/gay/pizza/pork/bir/IrInfixOp.kt @@ -1,5 +1,8 @@ package gay.pizza.pork.bir +import kotlinx.serialization.Serializable + +@Serializable enum class IrInfixOp { Add, Subtract, diff --git a/bir/src/main/kotlin/gay/pizza/pork/bir/IrList.kt b/bir/src/main/kotlin/gay/pizza/pork/bir/IrList.kt index 8780a9d..338d78f 100644 --- a/bir/src/main/kotlin/gay/pizza/pork/bir/IrList.kt +++ b/bir/src/main/kotlin/gay/pizza/pork/bir/IrList.kt @@ -1,5 +1,8 @@ package gay.pizza.pork.bir +import kotlinx.serialization.Serializable + +@Serializable data class IrList(val items: List) : IrCodeElement { override fun crawl(block: (IrElement) -> Unit) { items.forEach(block) diff --git a/bir/src/main/kotlin/gay/pizza/pork/bir/IrListSize.kt b/bir/src/main/kotlin/gay/pizza/pork/bir/IrListSize.kt new file mode 100644 index 0000000..585663c --- /dev/null +++ b/bir/src/main/kotlin/gay/pizza/pork/bir/IrListSize.kt @@ -0,0 +1,10 @@ +package gay.pizza.pork.bir + +import kotlinx.serialization.Serializable + +@Serializable +data class IrListSize(val list: IrCodeElement) : IrCodeElement { + override fun crawl(block: (IrElement) -> Unit) { + block(list) + } +} diff --git a/bir/src/main/kotlin/gay/pizza/pork/bir/IrLoad.kt b/bir/src/main/kotlin/gay/pizza/pork/bir/IrLoad.kt index 41c53fc..f2870ba 100644 --- a/bir/src/main/kotlin/gay/pizza/pork/bir/IrLoad.kt +++ b/bir/src/main/kotlin/gay/pizza/pork/bir/IrLoad.kt @@ -1,5 +1,8 @@ package gay.pizza.pork.bir +import kotlinx.serialization.Serializable + +@Serializable data class IrLoad(override val target: IrSymbol) : IrCodeElement, IrSymbolUser { override fun crawl(block: (IrElement) -> Unit) { block(target) diff --git a/bir/src/main/kotlin/gay/pizza/pork/bir/IrLoop.kt b/bir/src/main/kotlin/gay/pizza/pork/bir/IrLoop.kt index 2463931..61bbf6f 100644 --- a/bir/src/main/kotlin/gay/pizza/pork/bir/IrLoop.kt +++ b/bir/src/main/kotlin/gay/pizza/pork/bir/IrLoop.kt @@ -1,5 +1,8 @@ package gay.pizza.pork.bir +import kotlinx.serialization.Serializable + +@Serializable data class IrLoop( override val symbol: IrSymbol, val condition: IrCodeElement, diff --git a/bir/src/main/kotlin/gay/pizza/pork/bir/IrNativeDefinition.kt b/bir/src/main/kotlin/gay/pizza/pork/bir/IrNativeDefinition.kt index 45e91db..676f32c 100644 --- a/bir/src/main/kotlin/gay/pizza/pork/bir/IrNativeDefinition.kt +++ b/bir/src/main/kotlin/gay/pizza/pork/bir/IrNativeDefinition.kt @@ -1,5 +1,8 @@ package gay.pizza.pork.bir +import kotlinx.serialization.Serializable + +@Serializable data class IrNativeDefinition(val form: String, val definitions: List) : IrCodeElement { override fun crawl(block: (IrElement) -> Unit) {} } diff --git a/bir/src/main/kotlin/gay/pizza/pork/bir/IrPrefix.kt b/bir/src/main/kotlin/gay/pizza/pork/bir/IrPrefix.kt index c28e226..8f43627 100644 --- a/bir/src/main/kotlin/gay/pizza/pork/bir/IrPrefix.kt +++ b/bir/src/main/kotlin/gay/pizza/pork/bir/IrPrefix.kt @@ -1,5 +1,8 @@ package gay.pizza.pork.bir +import kotlinx.serialization.Serializable + +@Serializable data class IrPrefix(val op: IrPrefixOp, val value: IrCodeElement) : IrCodeElement { override fun crawl(block: (IrElement) -> Unit) { block(value) diff --git a/bir/src/main/kotlin/gay/pizza/pork/bir/IrPrefixOp.kt b/bir/src/main/kotlin/gay/pizza/pork/bir/IrPrefixOp.kt index 0b7052b..6d20a2e 100644 --- a/bir/src/main/kotlin/gay/pizza/pork/bir/IrPrefixOp.kt +++ b/bir/src/main/kotlin/gay/pizza/pork/bir/IrPrefixOp.kt @@ -1,5 +1,8 @@ package gay.pizza.pork.bir +import kotlinx.serialization.Serializable + +@Serializable enum class IrPrefixOp { BooleanNot, UnaryPlus, diff --git a/bir/src/main/kotlin/gay/pizza/pork/bir/IrReturn.kt b/bir/src/main/kotlin/gay/pizza/pork/bir/IrReturn.kt index dacee0b..05dfacb 100644 --- a/bir/src/main/kotlin/gay/pizza/pork/bir/IrReturn.kt +++ b/bir/src/main/kotlin/gay/pizza/pork/bir/IrReturn.kt @@ -1,5 +1,8 @@ package gay.pizza.pork.bir +import kotlinx.serialization.Serializable + +@Serializable data class IrReturn(val from: IrSymbol, val value: IrCodeElement) : IrCodeElement { override fun crawl(block: (IrElement) -> Unit) { block(from) diff --git a/bir/src/main/kotlin/gay/pizza/pork/bir/IrSlab.kt b/bir/src/main/kotlin/gay/pizza/pork/bir/IrSlab.kt index c1f4463..3b72be2 100644 --- a/bir/src/main/kotlin/gay/pizza/pork/bir/IrSlab.kt +++ b/bir/src/main/kotlin/gay/pizza/pork/bir/IrSlab.kt @@ -1,5 +1,8 @@ package gay.pizza.pork.bir +import kotlinx.serialization.Serializable + +@Serializable data class IrSlab( val location: IrSlabLocation, val definitions: List diff --git a/bir/src/main/kotlin/gay/pizza/pork/bir/IrSlabLocation.kt b/bir/src/main/kotlin/gay/pizza/pork/bir/IrSlabLocation.kt index 729989f..e99898b 100644 --- a/bir/src/main/kotlin/gay/pizza/pork/bir/IrSlabLocation.kt +++ b/bir/src/main/kotlin/gay/pizza/pork/bir/IrSlabLocation.kt @@ -1,5 +1,8 @@ package gay.pizza.pork.bir +import kotlinx.serialization.Serializable + +@Serializable data class IrSlabLocation( val form: String, val path: String diff --git a/bir/src/main/kotlin/gay/pizza/pork/bir/IrStore.kt b/bir/src/main/kotlin/gay/pizza/pork/bir/IrStore.kt index 51225fe..d802e23 100644 --- a/bir/src/main/kotlin/gay/pizza/pork/bir/IrStore.kt +++ b/bir/src/main/kotlin/gay/pizza/pork/bir/IrStore.kt @@ -1,5 +1,8 @@ package gay.pizza.pork.bir +import kotlinx.serialization.Serializable + +@Serializable data class IrStore(override val target: IrSymbol, val value: IrCodeElement) : IrCodeElement, IrSymbolUser { override fun crawl(block: (IrElement) -> Unit) { value.crawl(block) diff --git a/bir/src/main/kotlin/gay/pizza/pork/bir/IrSuffix.kt b/bir/src/main/kotlin/gay/pizza/pork/bir/IrSuffix.kt index abad0e1..9433be9 100644 --- a/bir/src/main/kotlin/gay/pizza/pork/bir/IrSuffix.kt +++ b/bir/src/main/kotlin/gay/pizza/pork/bir/IrSuffix.kt @@ -1,5 +1,8 @@ package gay.pizza.pork.bir +import kotlinx.serialization.Serializable + +@Serializable data class IrSuffix(val op: IrSuffixOp, override val target: IrSymbol) : IrCodeElement, IrSymbolUser { override fun crawl(block: (IrElement) -> Unit) { block(target) diff --git a/bir/src/main/kotlin/gay/pizza/pork/bir/IrSuffixOp.kt b/bir/src/main/kotlin/gay/pizza/pork/bir/IrSuffixOp.kt index 0d4d270..4bc3c36 100644 --- a/bir/src/main/kotlin/gay/pizza/pork/bir/IrSuffixOp.kt +++ b/bir/src/main/kotlin/gay/pizza/pork/bir/IrSuffixOp.kt @@ -1,5 +1,8 @@ package gay.pizza.pork.bir +import kotlinx.serialization.Serializable + +@Serializable enum class IrSuffixOp { Increment, Decrement diff --git a/bir/src/main/kotlin/gay/pizza/pork/bir/IrSymbol.kt b/bir/src/main/kotlin/gay/pizza/pork/bir/IrSymbol.kt index f473d5e..c3cfeaf 100644 --- a/bir/src/main/kotlin/gay/pizza/pork/bir/IrSymbol.kt +++ b/bir/src/main/kotlin/gay/pizza/pork/bir/IrSymbol.kt @@ -1,5 +1,24 @@ package gay.pizza.pork.bir -data class IrSymbol(val id: UInt, val tag: IrSymbolTag) : IrElement { +import kotlinx.serialization.Serializable + +@Serializable +data class IrSymbol(val id: UInt, val tag: IrSymbolTag, val name: String? = null) : IrElement { override fun crawl(block: (IrElement) -> Unit) {} + + override fun equals(other: Any?): Boolean { + if (other !is IrSymbol) return false + return other.id == id && other.tag == tag + } + + override fun hashCode(): Int { + var result = id.hashCode() + result = 31 * result + tag.hashCode() + return result + } + + val friendlyName: String + get() = if (name != null) { + "$id $tag $name" + } else "$id $tag" } diff --git a/bir/src/main/kotlin/gay/pizza/pork/bir/IrSymbolAssignment.kt b/bir/src/main/kotlin/gay/pizza/pork/bir/IrSymbolAssignment.kt index 8f3b63a..05da5a7 100644 --- a/bir/src/main/kotlin/gay/pizza/pork/bir/IrSymbolAssignment.kt +++ b/bir/src/main/kotlin/gay/pizza/pork/bir/IrSymbolAssignment.kt @@ -4,5 +4,6 @@ class IrSymbolAssignment { private var index = 0u private fun nextSymbolId(): UInt = index++ - fun next(tag: IrSymbolTag): IrSymbol = IrSymbol(nextSymbolId(), tag) + fun next(tag: IrSymbolTag, name: String? = null): IrSymbol = + IrSymbol(id = nextSymbolId(), tag = tag, name = name) } diff --git a/bir/src/main/kotlin/gay/pizza/pork/bir/IrSymbolOwner.kt b/bir/src/main/kotlin/gay/pizza/pork/bir/IrSymbolOwner.kt index f52ae66..8d307fb 100644 --- a/bir/src/main/kotlin/gay/pizza/pork/bir/IrSymbolOwner.kt +++ b/bir/src/main/kotlin/gay/pizza/pork/bir/IrSymbolOwner.kt @@ -1,5 +1,8 @@ package gay.pizza.pork.bir +import kotlinx.serialization.Serializable + +@Serializable sealed interface IrSymbolOwner : IrElement { val symbol: IrSymbol } diff --git a/bir/src/main/kotlin/gay/pizza/pork/bir/IrSymbolTag.kt b/bir/src/main/kotlin/gay/pizza/pork/bir/IrSymbolTag.kt index 565feb1..78e2e6c 100644 --- a/bir/src/main/kotlin/gay/pizza/pork/bir/IrSymbolTag.kt +++ b/bir/src/main/kotlin/gay/pizza/pork/bir/IrSymbolTag.kt @@ -1,5 +1,8 @@ package gay.pizza.pork.bir +import kotlinx.serialization.Serializable + +@Serializable enum class IrSymbolTag { Function, Variable, diff --git a/bir/src/main/kotlin/gay/pizza/pork/bir/IrSymbolUser.kt b/bir/src/main/kotlin/gay/pizza/pork/bir/IrSymbolUser.kt index c888ce1..98ede87 100644 --- a/bir/src/main/kotlin/gay/pizza/pork/bir/IrSymbolUser.kt +++ b/bir/src/main/kotlin/gay/pizza/pork/bir/IrSymbolUser.kt @@ -1,5 +1,8 @@ package gay.pizza.pork.bir +import kotlinx.serialization.Serializable + +@Serializable sealed interface IrSymbolUser : IrElement { val target: IrSymbol } diff --git a/bir/src/main/kotlin/gay/pizza/pork/bir/IrVisitor.kt b/bir/src/main/kotlin/gay/pizza/pork/bir/IrVisitor.kt index 2cfd3be..076e8c2 100644 --- a/bir/src/main/kotlin/gay/pizza/pork/bir/IrVisitor.kt +++ b/bir/src/main/kotlin/gay/pizza/pork/bir/IrVisitor.kt @@ -27,6 +27,8 @@ interface IrVisitor { fun visitIrWorld(ir: IrWorld): T fun visitIrNativeDefinition(ir: IrNativeDefinition): T fun visitIrFunctionArgument(ir: IrFunctionArgument): T + fun visitIrIndex(ir: IrIndex): T + fun visitIrListSize(ir: IrListSize): T fun visit(ir: IrElement): T = when (ir) { is IrBreak -> visitIrBeak(ir) @@ -55,5 +57,7 @@ interface IrVisitor { is IrWorld -> visitIrWorld(ir) is IrNativeDefinition -> visitIrNativeDefinition(ir) is IrFunctionArgument -> visitIrFunctionArgument(ir) + is IrIndex -> visitIrIndex(ir) + is IrListSize -> visitIrListSize(ir) } } diff --git a/bir/src/main/kotlin/gay/pizza/pork/bir/IrWorld.kt b/bir/src/main/kotlin/gay/pizza/pork/bir/IrWorld.kt index 32726df..0b860bc 100644 --- a/bir/src/main/kotlin/gay/pizza/pork/bir/IrWorld.kt +++ b/bir/src/main/kotlin/gay/pizza/pork/bir/IrWorld.kt @@ -1,5 +1,8 @@ package gay.pizza.pork.bir +import kotlinx.serialization.Serializable + +@Serializable data class IrWorld(val slabs: List) : IrElement { override fun crawl(block: (IrElement) -> Unit) { slabs.forEach(block) diff --git a/bytecode/src/main/kotlin/gay/pizza/pork/bytecode/Opcode.kt b/bytecode/src/main/kotlin/gay/pizza/pork/bytecode/Opcode.kt index c5e634b..ed68ad2 100644 --- a/bytecode/src/main/kotlin/gay/pizza/pork/bytecode/Opcode.kt +++ b/bytecode/src/main/kotlin/gay/pizza/pork/bytecode/Opcode.kt @@ -33,13 +33,14 @@ enum class Opcode(val id: UByte) { ListMake(31u), ListSize(32u), Integer(33u), - Double(34u), - Call(35u), - EuclideanModulo(36u), - Remainder(37u), - Index(38u), - ScopeIn(39u), - ScopeOut(40u), - ReturnAddress(41u), + Long(34u), + Double(35u), + Call(36u), + EuclideanModulo(37u), + Remainder(38u), + Index(39u), + ScopeIn(40u), + ScopeOut(41u), + ReturnAddress(42u), End(255u), } diff --git a/compiler/src/main/kotlin/gay/pizza/pork/compiler/CompilableSlab.kt b/compiler/src/main/kotlin/gay/pizza/pork/compiler/CompilableSlab.kt index fac74e7..36aade8 100644 --- a/compiler/src/main/kotlin/gay/pizza/pork/compiler/CompilableSlab.kt +++ b/compiler/src/main/kotlin/gay/pizza/pork/compiler/CompilableSlab.kt @@ -19,11 +19,6 @@ class CompilableSlab(val compiler: Compiler, val slab: Slab) { it.scopeSymbol.symbol == symbol } - fun resolveVisible(symbol: Symbol): CompilableSymbol? { - val scopeSymbol = slab.scope.resolve(symbol) ?: return null - return compiler.resolveOrNull(scopeSymbol) - } - private fun compileIrSlab(): IrSlab { val definitions = mutableListOf() for (compilableSymbol in compilableSymbols) { diff --git a/compiler/src/main/kotlin/gay/pizza/pork/compiler/CompilableSymbol.kt b/compiler/src/main/kotlin/gay/pizza/pork/compiler/CompilableSymbol.kt index 1089f39..797e17d 100644 --- a/compiler/src/main/kotlin/gay/pizza/pork/compiler/CompilableSymbol.kt +++ b/compiler/src/main/kotlin/gay/pizza/pork/compiler/CompilableSymbol.kt @@ -28,7 +28,7 @@ class CompilableSymbol(val compilableSlab: CompilableSlab, val scopeSymbol: Scop private fun compileIrDefinition(): IrDefinition { val compiler = compilableSlab.compiler - val functionSymbol = compiler.irSymbolWorld.create(scopeSymbol, IrSymbolTag.Function) + val functionSymbol = compiler.irSymbolWorld.create(scopeSymbol, IrSymbolTag.Function, scopeSymbol.symbol.id) val irCodeEmitter = IrCodeEmitter( self = functionSymbol, irSymbolWorld = compiler.irSymbolWorld, diff --git a/compiler/src/main/kotlin/gay/pizza/pork/compiler/CompiledWorldLayout.kt b/compiler/src/main/kotlin/gay/pizza/pork/compiler/CompiledWorldLayout.kt index fa996b2..265be98 100644 --- a/compiler/src/main/kotlin/gay/pizza/pork/compiler/CompiledWorldLayout.kt +++ b/compiler/src/main/kotlin/gay/pizza/pork/compiler/CompiledWorldLayout.kt @@ -13,7 +13,7 @@ class CompiledWorldLayout(val compiler: Compiler) : StubResolutionContext { val stubOps = result.ops symbolTable[symbol] = SymbolInfo( slab = symbol.compilableSlab.slab.location.commonLocationIdentity, - symbol = symbol.id, + symbol = symbol.scopeSymbol.symbol.id, offset = start.toUInt(), size = stubOps.size.toUInt() ) diff --git a/compiler/src/main/kotlin/gay/pizza/pork/compiler/Compiler.kt b/compiler/src/main/kotlin/gay/pizza/pork/compiler/Compiler.kt index 9c796e3..336cb27 100644 --- a/compiler/src/main/kotlin/gay/pizza/pork/compiler/Compiler.kt +++ b/compiler/src/main/kotlin/gay/pizza/pork/compiler/Compiler.kt @@ -1,12 +1,15 @@ package gay.pizza.pork.compiler +import gay.pizza.pork.bir.IrSlab import gay.pizza.pork.bir.IrSymbolAssignment +import gay.pizza.pork.bir.IrWorld import gay.pizza.pork.bytecode.CompiledWorld import gay.pizza.pork.bytecode.MutableConstantPool import gay.pizza.pork.frontend.Slab +import gay.pizza.pork.frontend.World import gay.pizza.pork.frontend.scope.ScopeSymbol -class Compiler { +class Compiler(val world: World) { val constantPool: MutableConstantPool = MutableConstantPool() val compilableSlabs: ComputableState = ComputableState { slab -> CompilableSlab(this, slab) @@ -39,6 +42,14 @@ class Compiler { } } + fun compileIrWorld(): IrWorld { + val slabs = mutableListOf() + for (slab in world.slabs) { + slabs.add(compilableSlabs.of(slab).compiledIrSlab) + } + return IrWorld(slabs) + } + fun compile(entryPointSymbol: CompilableSymbol): CompiledWorld { val usedSymbolSet = mutableSetOf() contributeCompiledSymbols(usedSymbolSet, entryPointSymbol.scopeSymbol, entryPointSymbol) diff --git a/compiler/src/main/kotlin/gay/pizza/pork/compiler/IrCodeEmitter.kt b/compiler/src/main/kotlin/gay/pizza/pork/compiler/IrCodeEmitter.kt index 2d9cd2b..9492eba 100644 --- a/compiler/src/main/kotlin/gay/pizza/pork/compiler/IrCodeEmitter.kt +++ b/compiler/src/main/kotlin/gay/pizza/pork/compiler/IrCodeEmitter.kt @@ -13,7 +13,7 @@ class IrCodeEmitter( val scope: SlabScope ) : FunctionLevelVisitor() { private val loopSymbols = mutableListOf() - private val localVariables = mutableListOf>() + private val localVariables = mutableListOf, LocalVariable>>() var functionArguments: List = emptyList() @@ -46,7 +46,7 @@ class IrCodeEmitter( } fun enterLocalScope() { - val locals = mutableMapOf() + val locals = mutableMapOf, LocalVariable>() localVariables.add(locals) } @@ -54,15 +54,16 @@ class IrCodeEmitter( localVariables.removeLast() } - private fun createLocalVariable(name: Symbol): IrSymbol { - val symbol = irSymbolAssignment.next(IrSymbolTag.Local) + private fun createLocalVariable(name: Symbol? = null): IrSymbol { + val symbol = irSymbolAssignment.next(tag = IrSymbolTag.Local, name = name?.id) val variable = LocalVariable(symbol, name) val variables = localVariables.last() - val existing = variables[name.id] + val identifier = name?.id to (if (name == null) symbol.id else null) + val existing = variables[identifier] if (existing != null) { - throw CompileError("Unable to define local variable '${name.id}' within this scope, it already exists", name) + throw CompileError("Unable to define local variable '${identifier.first}' within this scope, it already exists", name) } - variables[name.id] = variable + variables[identifier] = variable return symbol } @@ -74,10 +75,11 @@ class IrCodeEmitter( } private fun lookupLocalVariable(name: Symbol): IrSymbol? { + val identifier = name.id to null for (i in 1..localVariables.size) { val b = localVariables.size - i val scope = localVariables[b] - val found = scope[name.id] + val found = scope[identifier] if (found != null) { return found.symbol } @@ -99,7 +101,7 @@ class IrCodeEmitter( private fun lookupFunction(name: Symbol): Pair? { val scoped = scope.resolve(name) ?: return null - return scoped to irSymbolWorld.create(scoped, scopeSymbolToTag(scoped)) + return scoped to irSymbolWorld.create(value = scoped, tag = scopeSymbolToTag(scoped), name = scoped.symbol.id) } override fun visitBlock(node: Block): IrCodeBlock { @@ -128,7 +130,33 @@ class IrCodeEmitter( IrDoubleConstant(node.value) override fun visitForIn(node: ForIn): IrCodeElement { - return IrNoneConstant + val listLocal = createLocalVariable() + val indexLocal = createLocalVariable() + val sizeLocal = createLocalVariable() + val loopSymbol = irSymbolAssignment.next(IrSymbolTag.Loop) + + val items = mutableListOf( + IrStore(listLocal, visit(node.expression)), + IrStore(indexLocal, IrIntegerConstant(0)), + IrStore(sizeLocal, IrListSize(IrLoad(listLocal))) + ) + + enterLocalScope() + val loopValueLocal = createLocalVariable(node.item.symbol) + val subCodeBlock = visitBlock(node.block) + val innerCodeBlock = IrCodeBlock(listOf( + IrStore(loopValueLocal, IrIndex(IrLoad(listLocal), IrLoad(indexLocal))), + IrStore(indexLocal, IrInfix(IrInfixOp.Add, IrLoad(indexLocal), IrIntegerConstant(1))), + subCodeBlock + )) + exitLocalScope() + val loop = IrLoop( + symbol = loopSymbol, + condition = IrInfix(IrInfixOp.Lesser, IrLoad(indexLocal), IrLoad(sizeLocal)), + inner = innerCodeBlock + ) + items.add(loop) + return IrCodeBlock(items) } override fun visitFunctionCall(node: FunctionCall): IrCodeElement { @@ -169,19 +197,20 @@ class IrCodeEmitter( variableArguments = mutableListOf() } - return IrCall(symbol, arguments, variableArguments) + return IrCall(target = symbol, arguments = arguments, variableArguments = variableArguments) } override fun visitIf(node: If): IrCodeElement = IrConditional( - node.condition.visit(this), - node.thenBlock.visit(this), - node.elseBlock?.visit(this) ?: IrNoneConstant + conditional = node.condition.visit(this), + ifTrue = node.thenBlock.visit(this), + ifFalse = node.elseBlock?.visit(this) ?: IrNoneConstant ) - override fun visitIndexedBy(node: IndexedBy): IrCodeElement { - TODO("Not yet implemented") - } + override fun visitIndexedBy(node: IndexedBy): IrCodeElement = IrIndex( + data = visit(node.expression), + index = visit(node.index) + ) override fun visitInfixOperation(node: InfixOperation): IrCodeElement { val op = when (node.op) { diff --git a/compiler/src/main/kotlin/gay/pizza/pork/compiler/IrStubOpEmitter.kt b/compiler/src/main/kotlin/gay/pizza/pork/compiler/IrStubOpEmitter.kt index dbf91c9..94facde 100644 --- a/compiler/src/main/kotlin/gay/pizza/pork/compiler/IrStubOpEmitter.kt +++ b/compiler/src/main/kotlin/gay/pizza/pork/compiler/IrStubOpEmitter.kt @@ -74,10 +74,10 @@ class IrStubOpEmitter(val irDefinition: IrDefinition, val code: CodeBuilder) : I val endRel = MutableRel(0u) visit(ir.conditional) code.patch(Opcode.JumpIf, listOf(0u), 0, symbol, thenRel) - visit(ir.ifTrue) + visit(ir.ifFalse) code.patch(Opcode.Jump, listOf(0u), 0, symbol, endRel) thenRel.rel = code.nextOpInst() - visit(ir.ifFalse) + visit(ir.ifTrue) endRel.rel = code.nextOpInst() } @@ -90,11 +90,16 @@ class IrStubOpEmitter(val irDefinition: IrDefinition, val code: CodeBuilder) : I } override fun visitIrLongConstant(ir: IrLongConstant) { - code.emit(Opcode.Integer, listOf(ir.value.toUInt())) + val value1 = ir.value.toUInt() + val value2 = (ir.value shr 32).toUInt() + code.emit(Opcode.Long, listOf(value1, value2)) } override fun visitIrDoubleConstant(ir: IrDoubleConstant) { - code.emit(Opcode.Integer, listOf(ir.value.toUInt())) + val value = ir.value.toRawBits() + val value1 = value.toUInt() + val value2 = (value shr 32).toUInt() + code.emit(Opcode.Double, listOf(value1, value2)) } override fun visitIrStringConstant(ir: IrStringConstant) { @@ -219,4 +224,15 @@ class IrStubOpEmitter(val irDefinition: IrDefinition, val code: CodeBuilder) : I ) code.emit(Opcode.Native, listOf(formConstant, ir.definitions.size.toUInt(), functionArgumentCount.toUInt())) } + + override fun visitIrIndex(ir: IrIndex) { + visit(ir.index) + visit(ir.data) + code.emit(Opcode.Index) + } + + override fun visitIrListSize(ir: IrListSize) { + visit(ir.list) + code.emit(Opcode.ListSize) + } } diff --git a/compiler/src/main/kotlin/gay/pizza/pork/compiler/IrSymbolWorld.kt b/compiler/src/main/kotlin/gay/pizza/pork/compiler/IrSymbolWorld.kt index 00989f9..1eecd20 100644 --- a/compiler/src/main/kotlin/gay/pizza/pork/compiler/IrSymbolWorld.kt +++ b/compiler/src/main/kotlin/gay/pizza/pork/compiler/IrSymbolWorld.kt @@ -7,8 +7,8 @@ import gay.pizza.pork.bir.IrSymbolTag class IrSymbolWorld(val irSymbolAssignment: IrSymbolAssignment) { private val symbols = mutableMapOf() - fun create(value: T, tag: IrSymbolTag): IrSymbol = symbols.getOrPut(value) { - irSymbolAssignment.next(tag) + fun create(value: T, tag: IrSymbolTag, name: String? = null): IrSymbol = symbols.getOrPut(value) { + irSymbolAssignment.next(tag, name) } fun resolve(value: T): IrSymbol? = symbols[value] diff --git a/compiler/src/main/kotlin/gay/pizza/pork/compiler/LocalVariable.kt b/compiler/src/main/kotlin/gay/pizza/pork/compiler/LocalVariable.kt index c0b92cd..9e5113e 100644 --- a/compiler/src/main/kotlin/gay/pizza/pork/compiler/LocalVariable.kt +++ b/compiler/src/main/kotlin/gay/pizza/pork/compiler/LocalVariable.kt @@ -3,4 +3,4 @@ package gay.pizza.pork.compiler import gay.pizza.pork.ast.gen.Symbol import gay.pizza.pork.bir.IrSymbol -data class LocalVariable(val symbol: IrSymbol, val name: Symbol) +data class LocalVariable(val symbol: IrSymbol, val name: Symbol? = null) diff --git a/examples/fib.pork b/examples/fib.pork index f093f48..0655100 100644 --- a/examples/fib.pork +++ b/examples/fib.pork @@ -1,9 +1,9 @@ /* fibonacci sequence */ func fib(n) { - return if n < 2 { - n + if n < 2 { + return n } else { - fib(n - 1) + fib(n - 2) + return fib(n - 1) + fib(n - 2) } } diff --git a/examples/for.pork b/examples/for.pork index 7c5f333..ee0a9d2 100644 --- a/examples/for.pork +++ b/examples/for.pork @@ -1,6 +1,5 @@ -let items = ["Hello", "Goodbye"] - export func main() { + let items = ["Hello", "Goodbye"] for item in items { println(item) } diff --git a/examples/list.pork b/examples/list.pork new file mode 100644 index 0000000..bf7be56 --- /dev/null +++ b/examples/list.pork @@ -0,0 +1,6 @@ +export func main() { + let items = listInitWith(30, 0) + for item in items { + println(item) + } +} diff --git a/execution/src/main/kotlin/gay/pizza/pork/execution/NativeRegistry.kt b/execution/src/main/kotlin/gay/pizza/pork/execution/NativeRegistry.kt index 7d04bf3..0119aa6 100644 --- a/execution/src/main/kotlin/gay/pizza/pork/execution/NativeRegistry.kt +++ b/execution/src/main/kotlin/gay/pizza/pork/execution/NativeRegistry.kt @@ -14,5 +14,5 @@ class NativeRegistry { } fun of(form: String): NativeProvider = - providers[form] ?: throw RuntimeException("Unknown native form: ${form}") + providers[form] ?: throw RuntimeException("Unknown native form: $form") } diff --git a/tool/src/main/kotlin/gay/pizza/pork/tool/CompileCommand.kt b/tool/src/main/kotlin/gay/pizza/pork/tool/CompileCommand.kt index 4b4cf5f..4689698 100644 --- a/tool/src/main/kotlin/gay/pizza/pork/tool/CompileCommand.kt +++ b/tool/src/main/kotlin/gay/pizza/pork/tool/CompileCommand.kt @@ -4,21 +4,40 @@ import com.github.ajalt.clikt.core.CliktCommand import com.github.ajalt.clikt.parameters.arguments.argument import gay.pizza.dough.fs.PlatformFsProvider import gay.pizza.pork.ast.gen.Symbol +import gay.pizza.pork.bir.IrWorld +import gay.pizza.pork.bytecode.CompiledWorld import gay.pizza.pork.compiler.Compiler import gay.pizza.pork.minimal.FileTool +import kotlinx.serialization.ExperimentalSerializationApi +import kotlinx.serialization.json.Json +@OptIn(ExperimentalSerializationApi::class) class CompileCommand : CliktCommand(help = "Compile Pork to Bytecode", name = "compile") { val path by argument("file") override fun run() { val tool = FileTool(PlatformFsProvider.resolve(path)) val world = tool.buildWorld() - val compiler = Compiler() + val compiler = Compiler(world) val slab = world.load(tool.rootImportLocator) val compiledSlab = compiler.compilableSlabs.of(slab) val compiledMain = compiledSlab.resolve(Symbol("main")) ?: throw RuntimeException("'main' function not found.") val compiledWorld = compiler.compile(compiledMain) + val irWorld = compiler.compileIrWorld() + printCompiledIr(irWorld) + printCompiledWorld(compiledWorld) + } + + private fun printCompiledIr(irWorld: IrWorld) { + val json = Json { + prettyPrint = true + prettyPrintIndent = " " + } + println(json.encodeToString(IrWorld.serializer(), irWorld)) + } + + private fun printCompiledWorld(compiledWorld: CompiledWorld) { for (symbol in compiledWorld.symbolTable.symbols) { val code = compiledWorld.code.subList(symbol.offset.toInt(), (symbol.offset + symbol.size).toInt()) println(symbol.commonSymbolIdentity) diff --git a/vm/src/main/kotlin/gay/pizza/pork/vm/InternalMachine.kt b/vm/src/main/kotlin/gay/pizza/pork/vm/InternalMachine.kt index b0217a0..1bf37c0 100644 --- a/vm/src/main/kotlin/gay/pizza/pork/vm/InternalMachine.kt +++ b/vm/src/main/kotlin/gay/pizza/pork/vm/InternalMachine.kt @@ -47,11 +47,14 @@ class InternalMachine(val world: CompiledWorld, val nativeRegistry: NativeRegist } } - fun loadLocal(id: UInt) { + fun localAt(id: UInt): Any { val localSet = locals.last() - val local = localSet[id] - ?: throw VirtualMachineException("Attempted to load local $id but it was not stored.") - push(local) + return localSet[id] ?: + throw VirtualMachineException("Attempted to load local $id but it was not stored.") + } + + fun loadLocal(id: UInt) { + push(localAt(id)) } fun storeLocal(id: UInt) { @@ -108,4 +111,11 @@ class InternalMachine(val world: CompiledWorld, val nativeRegistry: NativeRegist exitFlag = false autoNextInst = true } + + fun frame(at: UInt = inst): StackFrame? { + val (symbolInfo, rel) = world.symbolTable.lookup(at) ?: (null to null) + return if (symbolInfo != null && rel != null) { + StackFrame(symbolInfo, rel) + } else null + } } diff --git a/vm/src/main/kotlin/gay/pizza/pork/vm/StackFrame.kt b/vm/src/main/kotlin/gay/pizza/pork/vm/StackFrame.kt new file mode 100644 index 0000000..e034269 --- /dev/null +++ b/vm/src/main/kotlin/gay/pizza/pork/vm/StackFrame.kt @@ -0,0 +1,19 @@ +package gay.pizza.pork.vm + +import gay.pizza.pork.bytecode.CompiledWorld +import gay.pizza.pork.bytecode.Op +import gay.pizza.pork.bytecode.SymbolInfo + +data class StackFrame(val symbolInfo: SymbolInfo, val rel: UInt) { + val worldCodeOffset: UInt + get() = symbolInfo.offset + rel + + fun opInWorld(world: CompiledWorld): Op = + world.code[worldCodeOffset.toInt()] + + fun describeInWorld(world: CompiledWorld): String = + "StackFrame(${worldCodeOffset}, ${symbolInfo.slab} ${symbolInfo.symbol} + ${rel}, ${opInWorld(world)})" + + override fun toString(): String = + "StackFrame(${worldCodeOffset}, ${symbolInfo.slab} ${symbolInfo.symbol} + ${rel})" +} diff --git a/vm/src/main/kotlin/gay/pizza/pork/vm/VirtualMachineProvider.kt b/vm/src/main/kotlin/gay/pizza/pork/vm/VirtualMachineProvider.kt index 9b39618..bd3b98e 100644 --- a/vm/src/main/kotlin/gay/pizza/pork/vm/VirtualMachineProvider.kt +++ b/vm/src/main/kotlin/gay/pizza/pork/vm/VirtualMachineProvider.kt @@ -10,7 +10,7 @@ import gay.pizza.pork.frontend.World class VirtualMachineProvider(val world: World) : ExecutionContextProvider { override fun prepare(importLocator: ImportLocator, entryPointSymbol: Symbol, nativeRegistry: NativeRegistry): ExecutionContext { - val compiler = Compiler() + val compiler = Compiler(world) val slab = world.load(importLocator) val compilableSlab = compiler.compilableSlabs.of(slab) val compilableSymbol = compilableSlab.resolve(entryPointSymbol) ?: diff --git a/vm/src/main/kotlin/gay/pizza/pork/vm/ops/AddOpHandler.kt b/vm/src/main/kotlin/gay/pizza/pork/vm/ops/AddOpHandler.kt index 3b7ad68..394aa39 100644 --- a/vm/src/main/kotlin/gay/pizza/pork/vm/ops/AddOpHandler.kt +++ b/vm/src/main/kotlin/gay/pizza/pork/vm/ops/AddOpHandler.kt @@ -7,8 +7,8 @@ import gay.pizza.pork.vm.OpHandler object AddOpHandler : OpHandler(Opcode.Add) { override fun handle(machine: InternalMachine, op: Op) { - val left = machine.pop() val right = machine.pop() + val left = machine.pop() machine.push(left + right) } } diff --git a/vm/src/main/kotlin/gay/pizza/pork/vm/ops/NativeOpHandler.kt b/vm/src/main/kotlin/gay/pizza/pork/vm/ops/NativeOpHandler.kt index 8cab8e1..b44207e 100644 --- a/vm/src/main/kotlin/gay/pizza/pork/vm/ops/NativeOpHandler.kt +++ b/vm/src/main/kotlin/gay/pizza/pork/vm/ops/NativeOpHandler.kt @@ -2,6 +2,7 @@ package gay.pizza.pork.vm.ops import gay.pizza.pork.bytecode.Op import gay.pizza.pork.bytecode.Opcode +import gay.pizza.pork.execution.None import gay.pizza.pork.vm.InternalMachine import gay.pizza.pork.vm.OpHandler @@ -9,9 +10,10 @@ object NativeOpHandler : OpHandler(Opcode.Native) { override fun handle(machine: InternalMachine, op: Op) { val argumentCount = op.args[2] val arguments = mutableListOf() - for (i in 0u until argumentCount) { - machine.loadLocal(i) - arguments.add(machine.popAnyValue()) + var x = argumentCount + while (x > 0u) { + x-- + arguments.add(machine.localAt(x)) } val formConstant = machine.world.constantPool.read(op.args[0]) val form = formConstant.readAsString() @@ -22,6 +24,7 @@ object NativeOpHandler : OpHandler(Opcode.Native) { defs.add(machine.pop()) } val function = provider.provideNativeFunction(defs) - function.invoke(arguments) + val result = function.invoke(arguments) + machine.push(if (result == Unit) None else result) } } diff --git a/vm/src/main/kotlin/gay/pizza/pork/vm/ops/SubtractOpHandler.kt b/vm/src/main/kotlin/gay/pizza/pork/vm/ops/SubtractOpHandler.kt index 15eccdb..a1e96bd 100644 --- a/vm/src/main/kotlin/gay/pizza/pork/vm/ops/SubtractOpHandler.kt +++ b/vm/src/main/kotlin/gay/pizza/pork/vm/ops/SubtractOpHandler.kt @@ -7,8 +7,8 @@ import gay.pizza.pork.vm.OpHandler object SubtractOpHandler : OpHandler(Opcode.Subtract) { override fun handle(machine: InternalMachine, op: Op) { - val left = machine.pop() val right = machine.pop() + val left = machine.pop() machine.push(left - right) } }