mirror of
https://github.com/GayPizzaSpecifications/pork.git
synced 2025-08-03 21:21:33 +00:00
IR WIP
This commit is contained in:
7
bir/build.gradle.kts
Normal file
7
bir/build.gradle.kts
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
plugins {
|
||||||
|
id("gay.pizza.pork.module")
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
implementation(project(":common"))
|
||||||
|
}
|
7
bir/src/main/kotlin/gay/pizza/pork/bir/IrAccess.kt
Normal file
7
bir/src/main/kotlin/gay/pizza/pork/bir/IrAccess.kt
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
package gay.pizza.pork.bir
|
||||||
|
|
||||||
|
data class IrAccess(override val target: IrSymbol) : IrCodeElement, IrSymbolUser {
|
||||||
|
override fun crawl(block: (IrElement) -> Unit) {
|
||||||
|
block(target)
|
||||||
|
}
|
||||||
|
}
|
7
bir/src/main/kotlin/gay/pizza/pork/bir/IrBreak.kt
Normal file
7
bir/src/main/kotlin/gay/pizza/pork/bir/IrBreak.kt
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
package gay.pizza.pork.bir
|
||||||
|
|
||||||
|
data class IrBreak(val target: IrSymbol) : IrCodeElement {
|
||||||
|
override fun crawl(block: (IrElement) -> Unit) {
|
||||||
|
block(target)
|
||||||
|
}
|
||||||
|
}
|
13
bir/src/main/kotlin/gay/pizza/pork/bir/IrCall.kt
Normal file
13
bir/src/main/kotlin/gay/pizza/pork/bir/IrCall.kt
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
package gay.pizza.pork.bir
|
||||||
|
|
||||||
|
data class IrCall(
|
||||||
|
override val target: IrSymbol,
|
||||||
|
val arguments: List<IrCodeElement>,
|
||||||
|
val variableArguments: List<IrCodeElement>?
|
||||||
|
) : IrCodeElement, IrSymbolUser {
|
||||||
|
override fun crawl(block: (IrElement) -> Unit) {
|
||||||
|
block(target)
|
||||||
|
arguments.forEach(block)
|
||||||
|
variableArguments?.forEach(block)
|
||||||
|
}
|
||||||
|
}
|
7
bir/src/main/kotlin/gay/pizza/pork/bir/IrCodeBlock.kt
Normal file
7
bir/src/main/kotlin/gay/pizza/pork/bir/IrCodeBlock.kt
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
package gay.pizza.pork.bir
|
||||||
|
|
||||||
|
data class IrCodeBlock(val items: List<IrCodeElement>) : IrCodeElement {
|
||||||
|
override fun crawl(block: (IrElement) -> Unit) {
|
||||||
|
items.forEach(block)
|
||||||
|
}
|
||||||
|
}
|
3
bir/src/main/kotlin/gay/pizza/pork/bir/IrCodeElement.kt
Normal file
3
bir/src/main/kotlin/gay/pizza/pork/bir/IrCodeElement.kt
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
package gay.pizza.pork.bir
|
||||||
|
|
||||||
|
sealed interface IrCodeElement : IrElement
|
13
bir/src/main/kotlin/gay/pizza/pork/bir/IrConditional.kt
Normal file
13
bir/src/main/kotlin/gay/pizza/pork/bir/IrConditional.kt
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
package gay.pizza.pork.bir
|
||||||
|
|
||||||
|
data class IrConditional(
|
||||||
|
val conditional: IrCodeElement,
|
||||||
|
val ifTrue: IrCodeElement,
|
||||||
|
val ifFalse: IrCodeElement
|
||||||
|
) : IrCodeElement {
|
||||||
|
override fun crawl(block: (IrElement) -> Unit) {
|
||||||
|
block(conditional)
|
||||||
|
block(ifTrue)
|
||||||
|
block(ifFalse)
|
||||||
|
}
|
||||||
|
}
|
12
bir/src/main/kotlin/gay/pizza/pork/bir/IrConstant.kt
Normal file
12
bir/src/main/kotlin/gay/pizza/pork/bir/IrConstant.kt
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
package gay.pizza.pork.bir
|
||||||
|
|
||||||
|
sealed interface IrConstant : IrCodeElement {
|
||||||
|
override fun crawl(block: (IrElement) -> Unit) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
data class IrIntegerConstant(val value: Int) : IrConstant
|
||||||
|
data class IrLongConstant(val value: Long) : IrConstant
|
||||||
|
data class IrDoubleConstant(val value: Double) : IrConstant
|
||||||
|
data class IrStringConstant(val value: String) : IrConstant
|
||||||
|
data class IrBooleanConstant(val value: Boolean) : IrConstant
|
||||||
|
data object IrNoneConstant : IrConstant
|
7
bir/src/main/kotlin/gay/pizza/pork/bir/IrContinue.kt
Normal file
7
bir/src/main/kotlin/gay/pizza/pork/bir/IrContinue.kt
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
package gay.pizza.pork.bir
|
||||||
|
|
||||||
|
data class IrContinue(override val target: IrSymbol) : IrCodeElement, IrSymbolUser {
|
||||||
|
override fun crawl(block: (IrElement) -> Unit) {
|
||||||
|
block(target)
|
||||||
|
}
|
||||||
|
}
|
12
bir/src/main/kotlin/gay/pizza/pork/bir/IrDefinition.kt
Normal file
12
bir/src/main/kotlin/gay/pizza/pork/bir/IrDefinition.kt
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
package gay.pizza.pork.bir
|
||||||
|
|
||||||
|
data class IrDefinition(
|
||||||
|
override val symbol: IrSymbol,
|
||||||
|
val type: IrDefinitionType,
|
||||||
|
val code: IrCodeBlock
|
||||||
|
) : IrElement, IrSymbolOwner {
|
||||||
|
override fun crawl(block: (IrElement) -> Unit) {
|
||||||
|
block(symbol)
|
||||||
|
block(code)
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,6 @@
|
|||||||
|
package gay.pizza.pork.bir
|
||||||
|
|
||||||
|
enum class IrDefinitionType {
|
||||||
|
Variable,
|
||||||
|
Function
|
||||||
|
}
|
5
bir/src/main/kotlin/gay/pizza/pork/bir/IrElement.kt
Normal file
5
bir/src/main/kotlin/gay/pizza/pork/bir/IrElement.kt
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
package gay.pizza.pork.bir
|
||||||
|
|
||||||
|
sealed interface IrElement {
|
||||||
|
fun crawl(block: (IrElement) -> Unit)
|
||||||
|
}
|
8
bir/src/main/kotlin/gay/pizza/pork/bir/IrInfix.kt
Normal file
8
bir/src/main/kotlin/gay/pizza/pork/bir/IrInfix.kt
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
package gay.pizza.pork.bir
|
||||||
|
|
||||||
|
data class IrInfix(val op: IrInfixOp, val left: IrCodeElement, val right: IrCodeElement) : IrCodeElement {
|
||||||
|
override fun crawl(block: (IrElement) -> Unit) {
|
||||||
|
block(left)
|
||||||
|
block(right)
|
||||||
|
}
|
||||||
|
}
|
21
bir/src/main/kotlin/gay/pizza/pork/bir/IrInfixOp.kt
Normal file
21
bir/src/main/kotlin/gay/pizza/pork/bir/IrInfixOp.kt
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
package gay.pizza.pork.bir
|
||||||
|
|
||||||
|
enum class IrInfixOp {
|
||||||
|
Add,
|
||||||
|
Subtract,
|
||||||
|
Multiply,
|
||||||
|
Divide,
|
||||||
|
Equals,
|
||||||
|
NotEquals,
|
||||||
|
EuclideanModulo,
|
||||||
|
Remainder,
|
||||||
|
Lesser,
|
||||||
|
Greater,
|
||||||
|
LesserEqual,
|
||||||
|
GreaterEqual,
|
||||||
|
BooleanAnd,
|
||||||
|
BooleanOr,
|
||||||
|
BinaryAnd,
|
||||||
|
BinaryOr,
|
||||||
|
BinaryExclusiveOr
|
||||||
|
}
|
7
bir/src/main/kotlin/gay/pizza/pork/bir/IrList.kt
Normal file
7
bir/src/main/kotlin/gay/pizza/pork/bir/IrList.kt
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
package gay.pizza.pork.bir
|
||||||
|
|
||||||
|
data class IrList(val items: List<IrCodeElement>) : IrCodeElement {
|
||||||
|
override fun crawl(block: (IrElement) -> Unit) {
|
||||||
|
items.forEach(block)
|
||||||
|
}
|
||||||
|
}
|
7
bir/src/main/kotlin/gay/pizza/pork/bir/IrLoad.kt
Normal file
7
bir/src/main/kotlin/gay/pizza/pork/bir/IrLoad.kt
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
package gay.pizza.pork.bir
|
||||||
|
|
||||||
|
data class IrLoad(val symbol: IrSymbol) : IrCodeElement {
|
||||||
|
override fun crawl(block: (IrElement) -> Unit) {
|
||||||
|
block(symbol)
|
||||||
|
}
|
||||||
|
}
|
13
bir/src/main/kotlin/gay/pizza/pork/bir/IrLoop.kt
Normal file
13
bir/src/main/kotlin/gay/pizza/pork/bir/IrLoop.kt
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
package gay.pizza.pork.bir
|
||||||
|
|
||||||
|
data class IrLoop(
|
||||||
|
override val symbol: IrSymbol,
|
||||||
|
val condition: IrCodeElement,
|
||||||
|
val inner: IrCodeElement
|
||||||
|
) : IrCodeElement, IrSymbolOwner {
|
||||||
|
override fun crawl(block: (IrElement) -> Unit) {
|
||||||
|
block(symbol)
|
||||||
|
block(condition)
|
||||||
|
block(inner)
|
||||||
|
}
|
||||||
|
}
|
7
bir/src/main/kotlin/gay/pizza/pork/bir/IrPrefix.kt
Normal file
7
bir/src/main/kotlin/gay/pizza/pork/bir/IrPrefix.kt
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
package gay.pizza.pork.bir
|
||||||
|
|
||||||
|
data class IrPrefix(val op: IrPrefixOp, val value: IrCodeElement) : IrCodeElement {
|
||||||
|
override fun crawl(block: (IrElement) -> Unit) {
|
||||||
|
block(value)
|
||||||
|
}
|
||||||
|
}
|
8
bir/src/main/kotlin/gay/pizza/pork/bir/IrPrefixOp.kt
Normal file
8
bir/src/main/kotlin/gay/pizza/pork/bir/IrPrefixOp.kt
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
package gay.pizza.pork.bir
|
||||||
|
|
||||||
|
enum class IrPrefixOp {
|
||||||
|
BooleanNot,
|
||||||
|
UnaryPlus,
|
||||||
|
UnaryMinus,
|
||||||
|
BinaryNot
|
||||||
|
}
|
8
bir/src/main/kotlin/gay/pizza/pork/bir/IrReturn.kt
Normal file
8
bir/src/main/kotlin/gay/pizza/pork/bir/IrReturn.kt
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
package gay.pizza.pork.bir
|
||||||
|
|
||||||
|
data class IrReturn(val from: IrSymbol, val value: IrCodeElement) : IrCodeElement {
|
||||||
|
override fun crawl(block: (IrElement) -> Unit) {
|
||||||
|
block(from)
|
||||||
|
block(value)
|
||||||
|
}
|
||||||
|
}
|
11
bir/src/main/kotlin/gay/pizza/pork/bir/IrSlab.kt
Normal file
11
bir/src/main/kotlin/gay/pizza/pork/bir/IrSlab.kt
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
package gay.pizza.pork.bir
|
||||||
|
|
||||||
|
data class IrSlab(
|
||||||
|
val location: IrSlabLocation,
|
||||||
|
val definitions: List<IrDefinition>
|
||||||
|
) : IrElement {
|
||||||
|
override fun crawl(block: (IrElement) -> Unit) {
|
||||||
|
block(location)
|
||||||
|
definitions.forEach(block)
|
||||||
|
}
|
||||||
|
}
|
8
bir/src/main/kotlin/gay/pizza/pork/bir/IrSlabLocation.kt
Normal file
8
bir/src/main/kotlin/gay/pizza/pork/bir/IrSlabLocation.kt
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
package gay.pizza.pork.bir
|
||||||
|
|
||||||
|
data class IrSlabLocation(
|
||||||
|
val form: String,
|
||||||
|
val path: String
|
||||||
|
) : IrElement {
|
||||||
|
override fun crawl(block: (IrElement) -> Unit) {}
|
||||||
|
}
|
7
bir/src/main/kotlin/gay/pizza/pork/bir/IrStore.kt
Normal file
7
bir/src/main/kotlin/gay/pizza/pork/bir/IrStore.kt
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
package gay.pizza.pork.bir
|
||||||
|
|
||||||
|
data class IrStore(val symbol: IrSymbol, val value: IrCodeElement) : IrCodeElement {
|
||||||
|
override fun crawl(block: (IrElement) -> Unit) {
|
||||||
|
value.crawl(block)
|
||||||
|
}
|
||||||
|
}
|
7
bir/src/main/kotlin/gay/pizza/pork/bir/IrSuffix.kt
Normal file
7
bir/src/main/kotlin/gay/pizza/pork/bir/IrSuffix.kt
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
package gay.pizza.pork.bir
|
||||||
|
|
||||||
|
data class IrSuffix(val op: IrSuffixOp, override val target: IrSymbol) : IrCodeElement, IrSymbolUser {
|
||||||
|
override fun crawl(block: (IrElement) -> Unit) {
|
||||||
|
block(target)
|
||||||
|
}
|
||||||
|
}
|
6
bir/src/main/kotlin/gay/pizza/pork/bir/IrSuffixOp.kt
Normal file
6
bir/src/main/kotlin/gay/pizza/pork/bir/IrSuffixOp.kt
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
package gay.pizza.pork.bir
|
||||||
|
|
||||||
|
enum class IrSuffixOp {
|
||||||
|
Increment,
|
||||||
|
Decrement
|
||||||
|
}
|
5
bir/src/main/kotlin/gay/pizza/pork/bir/IrSymbol.kt
Normal file
5
bir/src/main/kotlin/gay/pizza/pork/bir/IrSymbol.kt
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
package gay.pizza.pork.bir
|
||||||
|
|
||||||
|
data class IrSymbol(val id: UInt, val tag: IrSymbolTag) : IrElement {
|
||||||
|
override fun crawl(block: (IrElement) -> Unit) {}
|
||||||
|
}
|
@ -0,0 +1,8 @@
|
|||||||
|
package gay.pizza.pork.bir
|
||||||
|
|
||||||
|
class IrSymbolAssignment {
|
||||||
|
private var index = 0u
|
||||||
|
|
||||||
|
private fun nextSymbolId(): UInt = index++
|
||||||
|
fun next(tag: IrSymbolTag): IrSymbol = IrSymbol(nextSymbolId(), tag)
|
||||||
|
}
|
40
bir/src/main/kotlin/gay/pizza/pork/bir/IrSymbolGraph.kt
Normal file
40
bir/src/main/kotlin/gay/pizza/pork/bir/IrSymbolGraph.kt
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
package gay.pizza.pork.bir
|
||||||
|
|
||||||
|
class IrSymbolGraph {
|
||||||
|
private val edges = mutableSetOf<Pair<IrSymbolUser, IrSymbolOwner>>()
|
||||||
|
|
||||||
|
private fun crawlForKnown(known: MutableMap<IrSymbol, IrSymbolOwner>, root: IrElement) {
|
||||||
|
if (root is IrSymbolOwner) {
|
||||||
|
known[root.symbol] = root
|
||||||
|
}
|
||||||
|
|
||||||
|
root.crawl { item ->
|
||||||
|
crawlForKnown(known, item)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun crawlForAssociations(known: Map<IrSymbol, IrSymbolOwner>, root: IrElement) {
|
||||||
|
if (root is IrSymbolUser) {
|
||||||
|
val what = known[root.target]
|
||||||
|
if (what != null) {
|
||||||
|
edges.add(root to what)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
root.crawl { item ->
|
||||||
|
crawlForAssociations(known, item)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun crawl(root: IrElement) {
|
||||||
|
val known = mutableMapOf<IrSymbol, IrSymbolOwner>()
|
||||||
|
crawlForKnown(known, root)
|
||||||
|
crawlForAssociations(known, root)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun forEachEdge(block: (IrSymbolUser, IrSymbolOwner) -> Unit) {
|
||||||
|
for ((from, to) in edges) {
|
||||||
|
block(from, to)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
5
bir/src/main/kotlin/gay/pizza/pork/bir/IrSymbolOwner.kt
Normal file
5
bir/src/main/kotlin/gay/pizza/pork/bir/IrSymbolOwner.kt
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
package gay.pizza.pork.bir
|
||||||
|
|
||||||
|
sealed interface IrSymbolOwner : IrElement {
|
||||||
|
val symbol: IrSymbol
|
||||||
|
}
|
8
bir/src/main/kotlin/gay/pizza/pork/bir/IrSymbolTag.kt
Normal file
8
bir/src/main/kotlin/gay/pizza/pork/bir/IrSymbolTag.kt
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
package gay.pizza.pork.bir
|
||||||
|
|
||||||
|
enum class IrSymbolTag {
|
||||||
|
Function,
|
||||||
|
Variable,
|
||||||
|
Local,
|
||||||
|
Loop
|
||||||
|
}
|
5
bir/src/main/kotlin/gay/pizza/pork/bir/IrSymbolUser.kt
Normal file
5
bir/src/main/kotlin/gay/pizza/pork/bir/IrSymbolUser.kt
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
package gay.pizza.pork.bir
|
||||||
|
|
||||||
|
sealed interface IrSymbolUser : IrElement {
|
||||||
|
val target: IrSymbol
|
||||||
|
}
|
7
bir/src/main/kotlin/gay/pizza/pork/bir/IrWorld.kt
Normal file
7
bir/src/main/kotlin/gay/pizza/pork/bir/IrWorld.kt
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
package gay.pizza.pork.bir
|
||||||
|
|
||||||
|
data class IrWorld(val slabs: List<IrSlab>) : IrElement {
|
||||||
|
override fun crawl(block: (IrElement) -> Unit) {
|
||||||
|
slabs.forEach(block)
|
||||||
|
}
|
||||||
|
}
|
@ -4,6 +4,7 @@ plugins {
|
|||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
api(project(":ast"))
|
api(project(":ast"))
|
||||||
|
api(project(":bir"))
|
||||||
api(project(":bytecode"))
|
api(project(":bytecode"))
|
||||||
api(project(":parser"))
|
api(project(":parser"))
|
||||||
api(project(":frontend"))
|
api(project(":frontend"))
|
||||||
|
@ -1,9 +1,14 @@
|
|||||||
package gay.pizza.pork.compiler
|
package gay.pizza.pork.compiler
|
||||||
|
|
||||||
import gay.pizza.pork.ast.gen.Symbol
|
import gay.pizza.pork.ast.gen.Symbol
|
||||||
|
import gay.pizza.pork.bir.IrDefinition
|
||||||
|
import gay.pizza.pork.bir.IrSlab
|
||||||
|
import gay.pizza.pork.bir.IrSlabLocation
|
||||||
import gay.pizza.pork.frontend.Slab
|
import gay.pizza.pork.frontend.Slab
|
||||||
|
|
||||||
class CompilableSlab(val compiler: Compiler, val slab: Slab) {
|
class CompilableSlab(val compiler: Compiler, val slab: Slab) {
|
||||||
|
val compiledIrSlab: IrSlab by lazy { compileIrSlab() }
|
||||||
|
|
||||||
val compilableSymbols: List<CompilableSymbol> by lazy {
|
val compilableSymbols: List<CompilableSymbol> by lazy {
|
||||||
slab.scope.internalSymbols.map { symbol ->
|
slab.scope.internalSymbols.map { symbol ->
|
||||||
CompilableSymbol(this, symbol)
|
CompilableSymbol(this, symbol)
|
||||||
@ -18,4 +23,13 @@ class CompilableSlab(val compiler: Compiler, val slab: Slab) {
|
|||||||
val scopeSymbol = slab.scope.resolve(symbol) ?: return null
|
val scopeSymbol = slab.scope.resolve(symbol) ?: return null
|
||||||
return compiler.resolveOrNull(scopeSymbol)
|
return compiler.resolveOrNull(scopeSymbol)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun compileIrSlab(): IrSlab {
|
||||||
|
val definitions = mutableListOf<IrDefinition>()
|
||||||
|
for (compilableSymbol in compilableSymbols) {
|
||||||
|
definitions.add(compilableSymbol.compiledIrDefinition)
|
||||||
|
}
|
||||||
|
val irSlabLocation = IrSlabLocation(slab.location.form, slab.location.filePath)
|
||||||
|
return IrSlab(irSlabLocation, definitions)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,9 +3,14 @@ package gay.pizza.pork.compiler
|
|||||||
import gay.pizza.pork.ast.gen.FunctionDefinition
|
import gay.pizza.pork.ast.gen.FunctionDefinition
|
||||||
import gay.pizza.pork.ast.gen.LetDefinition
|
import gay.pizza.pork.ast.gen.LetDefinition
|
||||||
import gay.pizza.pork.ast.gen.visit
|
import gay.pizza.pork.ast.gen.visit
|
||||||
|
import gay.pizza.pork.bir.IrCodeBlock
|
||||||
|
import gay.pizza.pork.bir.IrDefinition
|
||||||
|
import gay.pizza.pork.bir.IrDefinitionType
|
||||||
|
import gay.pizza.pork.bir.IrSymbolTag
|
||||||
import gay.pizza.pork.frontend.scope.ScopeSymbol
|
import gay.pizza.pork.frontend.scope.ScopeSymbol
|
||||||
|
|
||||||
class CompilableSymbol(val compilableSlab: CompilableSlab, val scopeSymbol: ScopeSymbol) {
|
class CompilableSymbol(val compilableSlab: CompilableSlab, val scopeSymbol: ScopeSymbol) {
|
||||||
|
val compiledIrDefinition: IrDefinition by lazy { compileIrDefinition() }
|
||||||
val compiledStubOps: CompiledSymbolResult by lazy { compile() }
|
val compiledStubOps: CompiledSymbolResult by lazy { compile() }
|
||||||
|
|
||||||
val usedSymbols: List<ScopeSymbol>
|
val usedSymbols: List<ScopeSymbol>
|
||||||
@ -27,6 +32,29 @@ class CompilableSymbol(val compilableSlab: CompilableSlab, val scopeSymbol: Scop
|
|||||||
return emitter.code.build()
|
return emitter.code.build()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun compileIrDefinition(): IrDefinition {
|
||||||
|
val compiler = compilableSlab.compiler
|
||||||
|
val functionSymbol = compiler.irSymbolWorld.lookup(scopeSymbol, IrSymbolTag.Function)
|
||||||
|
val irCodeEmitter = IrCodeEmitter(
|
||||||
|
self = functionSymbol,
|
||||||
|
irSymbolWorld = compiler.irSymbolWorld,
|
||||||
|
irSymbolAssignment = compiler.irSymbolAssignment,
|
||||||
|
scope = compilableSlab.slab.scope
|
||||||
|
)
|
||||||
|
val what = if (scopeSymbol.definition is FunctionDefinition) {
|
||||||
|
val functionDefinition = scopeSymbol.definition as FunctionDefinition
|
||||||
|
functionDefinition.block ?: functionDefinition.nativeFunctionDescriptor!!
|
||||||
|
} else {
|
||||||
|
val letDefinition = scopeSymbol.definition as LetDefinition
|
||||||
|
letDefinition.value
|
||||||
|
}
|
||||||
|
val irCodeElement = irCodeEmitter.visit(what)
|
||||||
|
val irCodeBlock = if (irCodeElement is IrCodeBlock) {
|
||||||
|
irCodeElement
|
||||||
|
} else IrCodeBlock(listOf(irCodeElement))
|
||||||
|
return IrDefinition(functionSymbol, IrDefinitionType.Function, irCodeBlock)
|
||||||
|
}
|
||||||
|
|
||||||
val id: String
|
val id: String
|
||||||
get() = "${compilableSlab.slab.location.commonLocationIdentity} ${scopeSymbol.symbol.id}"
|
get() = "${compilableSlab.slab.location.commonLocationIdentity} ${scopeSymbol.symbol.id}"
|
||||||
|
|
||||||
|
@ -0,0 +1,5 @@
|
|||||||
|
package gay.pizza.pork.compiler
|
||||||
|
|
||||||
|
import gay.pizza.pork.ast.gen.Node
|
||||||
|
|
||||||
|
class CompileError(message: String, val node: Node? = null) : RuntimeException(message)
|
@ -1,5 +1,6 @@
|
|||||||
package gay.pizza.pork.compiler
|
package gay.pizza.pork.compiler
|
||||||
|
|
||||||
|
import gay.pizza.pork.bir.IrSymbolAssignment
|
||||||
import gay.pizza.pork.bytecode.CompiledWorld
|
import gay.pizza.pork.bytecode.CompiledWorld
|
||||||
import gay.pizza.pork.bytecode.MutableConstantPool
|
import gay.pizza.pork.bytecode.MutableConstantPool
|
||||||
import gay.pizza.pork.frontend.Slab
|
import gay.pizza.pork.frontend.Slab
|
||||||
@ -11,6 +12,9 @@ class Compiler {
|
|||||||
CompilableSlab(this, slab)
|
CompilableSlab(this, slab)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val irSymbolAssignment: IrSymbolAssignment = IrSymbolAssignment()
|
||||||
|
val irSymbolWorld: IrSymbolWorld = IrSymbolWorld(irSymbolAssignment)
|
||||||
|
|
||||||
fun resolveOrNull(scopeSymbol: ScopeSymbol): CompilableSymbol? {
|
fun resolveOrNull(scopeSymbol: ScopeSymbol): CompilableSymbol? {
|
||||||
val compiledSlab = compilableSlabs.of(scopeSymbol.slabScope.slab)
|
val compiledSlab = compilableSlabs.of(scopeSymbol.slabScope.slab)
|
||||||
return compiledSlab.resolve(scopeSymbol.symbol)
|
return compiledSlab.resolve(scopeSymbol.symbol)
|
||||||
|
@ -0,0 +1,268 @@
|
|||||||
|
package gay.pizza.pork.compiler
|
||||||
|
|
||||||
|
import gay.pizza.pork.ast.FunctionLevelVisitor
|
||||||
|
import gay.pizza.pork.ast.gen.*
|
||||||
|
import gay.pizza.pork.bir.*
|
||||||
|
import gay.pizza.pork.frontend.scope.ScopeSymbol
|
||||||
|
import gay.pizza.pork.frontend.scope.SlabScope
|
||||||
|
|
||||||
|
class IrCodeEmitter(
|
||||||
|
val self: IrSymbol,
|
||||||
|
val irSymbolWorld: IrSymbolWorld,
|
||||||
|
val irSymbolAssignment: IrSymbolAssignment,
|
||||||
|
val scope: SlabScope
|
||||||
|
) : FunctionLevelVisitor<IrCodeElement>() {
|
||||||
|
private val loopSymbols = mutableListOf<IrSymbol>()
|
||||||
|
private val localVariables = mutableListOf<MutableList<LocalVariable>>()
|
||||||
|
|
||||||
|
private fun startLoop(): IrSymbol {
|
||||||
|
val symbol = irSymbolAssignment.next(IrSymbolTag.Loop)
|
||||||
|
loopSymbols.add(symbol)
|
||||||
|
return symbol
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun endLoop() {
|
||||||
|
loopSymbols.removeLast()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun <T> loop(block: (IrSymbol) -> T): T {
|
||||||
|
val symbol = startLoop()
|
||||||
|
return try {
|
||||||
|
block(symbol)
|
||||||
|
} finally {
|
||||||
|
endLoop()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun enterBlockScope() {
|
||||||
|
val locals = mutableListOf<LocalVariable>()
|
||||||
|
localVariables.add(locals)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun exitBlockScope() {
|
||||||
|
localVariables.removeLast()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createLocalVariable(name: Symbol): IrSymbol {
|
||||||
|
val symbol = irSymbolAssignment.next(IrSymbolTag.Local)
|
||||||
|
val variable = LocalVariable(symbol, name)
|
||||||
|
localVariables.last().add(variable)
|
||||||
|
return symbol
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun scopeSymbolToTag(scopeSymbol: ScopeSymbol): IrSymbolTag =
|
||||||
|
if (scopeSymbol.definition is FunctionDefinition) {
|
||||||
|
IrSymbolTag.Function
|
||||||
|
} else {
|
||||||
|
IrSymbolTag.Variable
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun lookupLocalVariable(name: Symbol): IrSymbol? {
|
||||||
|
for (i in 0..localVariables.size) {
|
||||||
|
val b = localVariables.size - i - 1
|
||||||
|
val scope = localVariables[b]
|
||||||
|
val found = scope.firstOrNull { it.name == name }
|
||||||
|
if (found != null) {
|
||||||
|
return found.symbol
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun lookup(name: Symbol): IrSymbol? {
|
||||||
|
val local = lookupLocalVariable(name)
|
||||||
|
if (local != null) {
|
||||||
|
return local
|
||||||
|
}
|
||||||
|
val scoped = scope.resolve(name)
|
||||||
|
if (scoped != null) {
|
||||||
|
return irSymbolWorld.lookup(scoped, scopeSymbolToTag(scoped))
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun lookupFunction(name: Symbol): Pair<ScopeSymbol, IrSymbol>? {
|
||||||
|
val scoped = scope.resolve(name) ?: return null
|
||||||
|
return scoped to irSymbolWorld.lookup(scoped, scopeSymbolToTag(scoped))
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitBlock(node: Block): IrCodeBlock {
|
||||||
|
enterBlockScope()
|
||||||
|
val block = IrCodeBlock(node.expressions.map { it.visit(this) })
|
||||||
|
exitBlockScope()
|
||||||
|
return block
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitBooleanLiteral(node: BooleanLiteral): IrCodeElement =
|
||||||
|
IrBooleanConstant(node.value)
|
||||||
|
|
||||||
|
override fun visitBreak(node: Break): IrCodeElement {
|
||||||
|
val currentLoopSymbol = loopSymbols.lastOrNull() ?:
|
||||||
|
throw CompileError("break does not have a target loop", node)
|
||||||
|
return IrBreak(currentLoopSymbol)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitContinue(node: Continue): IrCodeElement {
|
||||||
|
val currentLoopSymbol = loopSymbols.lastOrNull() ?:
|
||||||
|
throw CompileError("continue does not have a target loop", node)
|
||||||
|
return IrBreak(currentLoopSymbol)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitDoubleLiteral(node: DoubleLiteral): IrCodeElement =
|
||||||
|
IrDoubleConstant(node.value)
|
||||||
|
|
||||||
|
override fun visitForIn(node: ForIn): IrCodeElement {
|
||||||
|
return IrNoneConstant
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitFunctionCall(node: FunctionCall): IrCodeElement {
|
||||||
|
val (scopeSymbol, symbol) = lookupFunction(node.symbol) ?:
|
||||||
|
throw CompileError("Failed to resolve function call target '${node.symbol.id}'", node)
|
||||||
|
if (symbol.tag != IrSymbolTag.Function) {
|
||||||
|
throw CompileError("Failed to resolve function call target '${node.symbol.id}', it is not a function", node)
|
||||||
|
}
|
||||||
|
|
||||||
|
val functionDefinition = scopeSymbol.definition as FunctionDefinition
|
||||||
|
val arguments = mutableListOf<IrCodeElement>()
|
||||||
|
var variableArguments: List<IrCodeElement>? = null
|
||||||
|
|
||||||
|
val inputs = node.arguments
|
||||||
|
|
||||||
|
for ((index, spec) in functionDefinition.arguments.withIndex()) {
|
||||||
|
if (variableArguments != null) {
|
||||||
|
throw CompileError(
|
||||||
|
"Failed to build function call, '${node.symbol.id}', illegal function definition",
|
||||||
|
node
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (spec.multiple) {
|
||||||
|
variableArguments = inputs.drop(index).map { it.visit(this) }
|
||||||
|
} else {
|
||||||
|
if (index > inputs.size - 1) {
|
||||||
|
throw CompileError(
|
||||||
|
"Failed to build function call, '${node.symbol.id}', no matching argument for '${spec.symbol.id}'",
|
||||||
|
node
|
||||||
|
)
|
||||||
|
}
|
||||||
|
arguments.add(inputs[index].visit(this))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (functionDefinition.arguments.any { it.multiple }) {
|
||||||
|
variableArguments = mutableListOf()
|
||||||
|
}
|
||||||
|
|
||||||
|
return IrCall(symbol, arguments, variableArguments)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitIf(node: If): IrCodeElement =
|
||||||
|
IrConditional(
|
||||||
|
node.condition.visit(this),
|
||||||
|
node.thenBlock.visit(this),
|
||||||
|
node.elseBlock?.visit(this) ?: IrNoneConstant
|
||||||
|
)
|
||||||
|
|
||||||
|
override fun visitIndexedBy(node: IndexedBy): IrCodeElement {
|
||||||
|
TODO("Not yet implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitInfixOperation(node: InfixOperation): IrCodeElement {
|
||||||
|
val op = when (node.op) {
|
||||||
|
InfixOperator.Plus -> IrInfixOp.Add
|
||||||
|
InfixOperator.Minus -> IrInfixOp.Subtract
|
||||||
|
InfixOperator.Multiply -> IrInfixOp.Multiply
|
||||||
|
InfixOperator.Divide -> IrInfixOp.Divide
|
||||||
|
InfixOperator.Equals -> IrInfixOp.Equals
|
||||||
|
InfixOperator.NotEquals -> IrInfixOp.NotEquals
|
||||||
|
InfixOperator.EuclideanModulo -> IrInfixOp.EuclideanModulo
|
||||||
|
InfixOperator.Remainder -> IrInfixOp.Remainder
|
||||||
|
InfixOperator.Lesser -> IrInfixOp.Lesser
|
||||||
|
InfixOperator.Greater -> IrInfixOp.Greater
|
||||||
|
InfixOperator.GreaterEqual -> IrInfixOp.GreaterEqual
|
||||||
|
InfixOperator.LesserEqual -> IrInfixOp.LesserEqual
|
||||||
|
InfixOperator.BooleanAnd -> IrInfixOp.BooleanAnd
|
||||||
|
InfixOperator.BooleanOr -> IrInfixOp.BooleanOr
|
||||||
|
InfixOperator.BinaryAnd -> IrInfixOp.BinaryAnd
|
||||||
|
InfixOperator.BinaryOr -> IrInfixOp.BinaryOr
|
||||||
|
InfixOperator.BinaryExclusiveOr -> IrInfixOp.BinaryExclusiveOr
|
||||||
|
}
|
||||||
|
|
||||||
|
return IrInfix(op, node.left.visit(this), node.right.visit(this))
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitIntegerLiteral(node: IntegerLiteral): IrCodeElement =
|
||||||
|
IrIntegerConstant(node.value)
|
||||||
|
|
||||||
|
override fun visitLetAssignment(node: LetAssignment): IrCodeElement {
|
||||||
|
val symbol = createLocalVariable(node.symbol)
|
||||||
|
return IrStore(symbol, node.value.visit(this))
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitListLiteral(node: ListLiteral): IrCodeElement =
|
||||||
|
IrList(node.items.map { it.visit(this) })
|
||||||
|
|
||||||
|
override fun visitLongLiteral(node: LongLiteral): IrCodeElement =
|
||||||
|
IrLongConstant(node.value)
|
||||||
|
|
||||||
|
override fun visitNoneLiteral(node: NoneLiteral): IrCodeElement =
|
||||||
|
IrNoneConstant
|
||||||
|
|
||||||
|
override fun visitParentheses(node: Parentheses): IrCodeElement =
|
||||||
|
node.expression.visit(this)
|
||||||
|
|
||||||
|
override fun visitPrefixOperation(node: PrefixOperation): IrCodeElement {
|
||||||
|
val op = when (node.op) {
|
||||||
|
PrefixOperator.BooleanNot -> IrPrefixOp.BooleanNot
|
||||||
|
PrefixOperator.UnaryPlus -> IrPrefixOp.UnaryPlus
|
||||||
|
PrefixOperator.UnaryMinus -> IrPrefixOp.UnaryMinus
|
||||||
|
PrefixOperator.BinaryNot -> IrPrefixOp.BinaryNot
|
||||||
|
}
|
||||||
|
return IrPrefix(op, node.expression.visit(this))
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitReturn(node: Return): IrCodeElement =
|
||||||
|
IrReturn(from = self, value = node.value.visit(this))
|
||||||
|
|
||||||
|
override fun visitSetAssignment(node: SetAssignment): IrCodeElement {
|
||||||
|
val symbol = lookupLocalVariable(node.symbol) ?:
|
||||||
|
throw CompileError("Unable to find local variable target '${node.symbol.id}'", node)
|
||||||
|
return IrStore(symbol, node.value.visit(this))
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitStringLiteral(node: StringLiteral): IrCodeElement =
|
||||||
|
IrStringConstant(node.text)
|
||||||
|
|
||||||
|
override fun visitSuffixOperation(node: SuffixOperation): IrCodeElement {
|
||||||
|
val op = when (node.op) {
|
||||||
|
SuffixOperator.Increment -> IrSuffixOp.Increment
|
||||||
|
SuffixOperator.Decrement -> IrSuffixOp.Decrement
|
||||||
|
}
|
||||||
|
val symbol = lookup(node.reference.symbol) ?: throw CompileError(
|
||||||
|
"Unable to find symbol for suffix operation '${node.reference.symbol.id}'", node)
|
||||||
|
return IrSuffix(op, symbol)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitSymbolReference(node: SymbolReference): IrCodeElement {
|
||||||
|
val symbol = lookup(node.symbol) ?:
|
||||||
|
throw CompileError("Unable to resolve symbol reference '${node.symbol.id}'", node)
|
||||||
|
return IrLoad(symbol)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitVarAssignment(node: VarAssignment): IrCodeElement {
|
||||||
|
val local = createLocalVariable(node.symbol)
|
||||||
|
return IrStore(local, node.value.visit(this))
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitWhile(node: While): IrCodeElement = loop { symbol ->
|
||||||
|
IrLoop(
|
||||||
|
symbol = symbol,
|
||||||
|
condition = node.condition.visit(this),
|
||||||
|
inner = node.block.visit(this)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitNativeFunctionDescriptor(node: NativeFunctionDescriptor): IrCodeElement {
|
||||||
|
return IrNoneConstant
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,13 @@
|
|||||||
|
package gay.pizza.pork.compiler
|
||||||
|
|
||||||
|
import gay.pizza.pork.bir.IrSymbol
|
||||||
|
import gay.pizza.pork.bir.IrSymbolAssignment
|
||||||
|
import gay.pizza.pork.bir.IrSymbolTag
|
||||||
|
|
||||||
|
class IrSymbolWorld(val irSymbolAssignment: IrSymbolAssignment) {
|
||||||
|
private val symbols = mutableMapOf<Any, IrSymbol>()
|
||||||
|
|
||||||
|
fun lookup(value: Any, tag: IrSymbolTag): IrSymbol = symbols.getOrPut(value) {
|
||||||
|
irSymbolAssignment.next(tag)
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,6 @@
|
|||||||
|
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)
|
@ -6,4 +6,16 @@ import gay.pizza.pork.ast.gen.Symbol
|
|||||||
class ScopeSymbol(val slabScope: SlabScope, val definition: Definition) {
|
class ScopeSymbol(val slabScope: SlabScope, val definition: Definition) {
|
||||||
val symbol: Symbol = definition.symbol
|
val symbol: Symbol = definition.symbol
|
||||||
val scope: DefinitionScope by lazy { DefinitionScope(slabScope, definition) }
|
val scope: DefinitionScope by lazy { DefinitionScope(slabScope, definition) }
|
||||||
|
|
||||||
|
override fun equals(other: Any?): Boolean {
|
||||||
|
if (other !is ScopeSymbol) return false
|
||||||
|
return other.slabScope.slab == slabScope.slab && other.symbol == symbol
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun hashCode(): Int {
|
||||||
|
var result = slabScope.hashCode()
|
||||||
|
result = 31 * result + definition.hashCode()
|
||||||
|
result = 31 * result + symbol.hashCode()
|
||||||
|
return result
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,6 @@
|
|||||||
|
package gay.pizza.pork.frontend.scope
|
||||||
|
|
||||||
|
enum class SymbolType {
|
||||||
|
Variable,
|
||||||
|
Function
|
||||||
|
}
|
@ -6,6 +6,7 @@ include(
|
|||||||
":common",
|
":common",
|
||||||
":tokenizer",
|
":tokenizer",
|
||||||
":ast",
|
":ast",
|
||||||
|
":bir",
|
||||||
":bytecode",
|
":bytecode",
|
||||||
":parser",
|
":parser",
|
||||||
":frontend",
|
":frontend",
|
||||||
|
@ -4,6 +4,9 @@ import com.github.ajalt.clikt.core.CliktCommand
|
|||||||
import com.github.ajalt.clikt.parameters.arguments.argument
|
import com.github.ajalt.clikt.parameters.arguments.argument
|
||||||
import gay.pizza.dough.fs.PlatformFsProvider
|
import gay.pizza.dough.fs.PlatformFsProvider
|
||||||
import gay.pizza.pork.ast.gen.Symbol
|
import gay.pizza.pork.ast.gen.Symbol
|
||||||
|
import gay.pizza.pork.bir.IrSlab
|
||||||
|
import gay.pizza.pork.bir.IrSymbolGraph
|
||||||
|
import gay.pizza.pork.bir.IrWorld
|
||||||
import gay.pizza.pork.compiler.Compiler
|
import gay.pizza.pork.compiler.Compiler
|
||||||
import gay.pizza.pork.minimal.FileTool
|
import gay.pizza.pork.minimal.FileTool
|
||||||
|
|
||||||
@ -31,5 +34,18 @@ class CompileCommand : CliktCommand(help = "Compile Pork to Bytecode", name = "c
|
|||||||
println(" ${symbol.offset + index.toUInt()} ${op}${annotation}")
|
println(" ${symbol.offset + index.toUInt()} ${op}${annotation}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val compiledIrSlabs = mutableListOf<IrSlab>()
|
||||||
|
for (symbol in compiledMain.usedSymbols) {
|
||||||
|
val what = compiler.resolve(symbol)
|
||||||
|
compiledIrSlabs.add(what.compilableSlab.compiledIrSlab)
|
||||||
|
}
|
||||||
|
compiledIrSlabs.add(compiledMain.compilableSlab.compiledIrSlab)
|
||||||
|
val irWorld = IrWorld(compiledIrSlabs.toList())
|
||||||
|
val graph = IrSymbolGraph()
|
||||||
|
graph.crawl(irWorld)
|
||||||
|
graph.forEachEdge { user, owner ->
|
||||||
|
println("$user -> $owner")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user