compiler: full support for IR based compilation

This commit is contained in:
Alex Zenla 2023-11-23 21:48:10 -08:00
parent 2d88666f05
commit 8951c3cd60
Signed by: alex
GPG Key ID: C0780728420EBFE5
32 changed files with 554 additions and 400 deletions

View File

@ -1,10 +1,10 @@
package gay.pizza.pork.bir package gay.pizza.pork.bir
data class IrCall( data class IrCall(
val target: IrSymbol, override val target: IrSymbol,
val arguments: List<IrCodeElement>, val arguments: List<IrCodeElement>,
val variableArguments: List<IrCodeElement>? val variableArguments: List<IrCodeElement>?
) : IrCodeElement { ) : IrCodeElement, IrSymbolUser {
override fun crawl(block: (IrElement) -> Unit) { override fun crawl(block: (IrElement) -> Unit) {
block(target) block(target)
arguments.forEach(block) arguments.forEach(block)

View File

@ -1,3 +1,7 @@
package gay.pizza.pork.bir package gay.pizza.pork.bir
data class IrCodeBlock(val items: List<IrCodeElement>) : IrCodeElement data class IrCodeBlock(val items: List<IrCodeElement>) : IrCodeElement {
override fun crawl(block: (IrElement) -> Unit) {
items.forEach(block)
}
}

View File

@ -1,6 +1,6 @@
package gay.pizza.pork.bir package gay.pizza.pork.bir
data class IrContinue(val target: IrSymbol) : IrCodeElement { data class IrContinue(override val target: IrSymbol) : IrCodeElement, IrSymbolUser {
override fun crawl(block: (IrElement) -> Unit) { override fun crawl(block: (IrElement) -> Unit) {
block(target) block(target)
} }

View File

@ -1,12 +1,14 @@
package gay.pizza.pork.bir package gay.pizza.pork.bir
data class IrDefinition( data class IrDefinition(
val symbol: IrSymbol, override val symbol: IrSymbol,
val type: IrDefinitionType, val type: IrDefinitionType,
val arguments: List<IrFunctionArgument>,
val code: IrCodeBlock val code: IrCodeBlock
) : IrElement { ) : IrElement, IrSymbolOwner {
override fun crawl(block: (IrElement) -> Unit) { override fun crawl(block: (IrElement) -> Unit) {
block(symbol) block(symbol)
arguments.forEach(block)
block(code) block(code)
} }
} }

View File

@ -2,5 +2,6 @@ package gay.pizza.pork.bir
enum class IrDefinitionType { enum class IrDefinitionType {
Variable, Variable,
Function CodeFunction,
NativeFunction
} }

View File

@ -0,0 +1,5 @@
package gay.pizza.pork.bir
data class IrFunctionArgument(override val symbol: IrSymbol) : IrSymbolOwner {
override fun crawl(block: (IrElement) -> Unit) {}
}

View File

@ -1,7 +1,7 @@
package gay.pizza.pork.bir package gay.pizza.pork.bir
data class IrLoad(val symbol: IrSymbol) : IrCodeElement { data class IrLoad(override val target: IrSymbol) : IrCodeElement, IrSymbolUser {
override fun crawl(block: (IrElement) -> Unit) { override fun crawl(block: (IrElement) -> Unit) {
block(symbol) block(target)
} }
} }

View File

@ -1,6 +1,10 @@
package gay.pizza.pork.bir package gay.pizza.pork.bir
data class IrLoop(val symbol: IrSymbol, val condition: IrCodeElement, val inner: IrCodeElement) : IrCodeElement { data class IrLoop(
override val symbol: IrSymbol,
val condition: IrCodeElement,
val inner: IrCodeElement
) : IrCodeElement, IrSymbolOwner {
override fun crawl(block: (IrElement) -> Unit) { override fun crawl(block: (IrElement) -> Unit) {
block(symbol) block(symbol)
block(condition) block(condition)

View File

@ -0,0 +1,5 @@
package gay.pizza.pork.bir
data class IrNativeDefinition(val form: String, val definitions: List<String>) : IrCodeElement {
override fun crawl(block: (IrElement) -> Unit) {}
}

View File

@ -1,6 +1,6 @@
package gay.pizza.pork.bir package gay.pizza.pork.bir
data class IrStore(val symbol: IrSymbol, val value: IrCodeElement) : IrCodeElement { data class IrStore(override val target: IrSymbol, val value: IrCodeElement) : IrCodeElement, IrSymbolUser {
override fun crawl(block: (IrElement) -> Unit) { override fun crawl(block: (IrElement) -> Unit) {
value.crawl(block) value.crawl(block)
} }

View 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)
}
}

View File

@ -0,0 +1,6 @@
package gay.pizza.pork.bir
enum class IrSuffixOp {
Increment,
Decrement
}

View 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)
}
}
}

View File

@ -0,0 +1,5 @@
package gay.pizza.pork.bir
sealed interface IrSymbolOwner : IrElement {
val symbol: IrSymbol
}

View File

@ -0,0 +1,5 @@
package gay.pizza.pork.bir
sealed interface IrSymbolUser : IrElement {
val target: IrSymbol
}

View File

@ -0,0 +1,59 @@
package gay.pizza.pork.bir
interface IrVisitor<T> {
fun visitIrSlab(ir: IrSlab): T
fun visitIrSlabLocation(ir: IrSlabLocation): T
fun visitIrDefinition(ir: IrDefinition): T
fun visitIrSymbol(ir: IrSymbol): T
fun visitIrBeak(ir: IrBreak): T
fun visitIrCall(ir: IrCall): T
fun visitIrCodeBlock(ir: IrCodeBlock): T
fun visitIrConditional(ir: IrConditional): T
fun visitIrBooleanConstant(ir: IrBooleanConstant): T
fun visitIrIntegerConstant(ir: IrIntegerConstant): T
fun visitIrLongConstant(ir: IrLongConstant): T
fun visitIrDoubleConstant(ir: IrDoubleConstant): T
fun visitIrStringConstant(ir: IrStringConstant): T
fun visitIrNoneConstant(ir: IrNoneConstant): T
fun visitIrContinue(ir: IrContinue): T
fun visitIrInfix(ir: IrInfix): T
fun visitIrList(ir: IrList): T
fun visitIrLoad(ir: IrLoad): T
fun visitIrLoop(ir: IrLoop): T
fun visitIrPrefix(ir: IrPrefix): T
fun visitIrReturn(ir: IrReturn): T
fun visitIrStore(ir: IrStore): T
fun visitIrSuffix(ir: IrSuffix): T
fun visitIrWorld(ir: IrWorld): T
fun visitIrNativeDefinition(ir: IrNativeDefinition): T
fun visitIrFunctionArgument(ir: IrFunctionArgument): T
fun visit(ir: IrElement): T = when (ir) {
is IrBreak -> visitIrBeak(ir)
is IrCall -> visitIrCall(ir)
is IrCodeBlock -> visitIrCodeBlock(ir)
is IrConditional -> visitIrConditional(ir)
is IrBooleanConstant -> visitIrBooleanConstant(ir)
is IrDoubleConstant -> visitIrDoubleConstant(ir)
is IrIntegerConstant -> visitIrIntegerConstant(ir)
is IrLongConstant -> visitIrLongConstant(ir)
is IrNoneConstant -> visitIrNoneConstant(ir)
is IrStringConstant -> visitIrStringConstant(ir)
is IrContinue -> visitIrContinue(ir)
is IrInfix -> visitIrInfix(ir)
is IrList -> visitIrList(ir)
is IrLoad -> visitIrLoad(ir)
is IrLoop -> visitIrLoop(ir)
is IrPrefix -> visitIrPrefix(ir)
is IrReturn -> visitIrReturn(ir)
is IrStore -> visitIrStore(ir)
is IrSuffix -> visitIrSuffix(ir)
is IrDefinition -> visitIrDefinition(ir)
is IrSlab -> visitIrSlab(ir)
is IrSlabLocation -> visitIrSlabLocation(ir)
is IrSymbol -> visitIrSymbol(ir)
is IrWorld -> visitIrWorld(ir)
is IrNativeDefinition -> visitIrNativeDefinition(ir)
is IrFunctionArgument -> visitIrFunctionArgument(ir)
}
}

View File

@ -1,7 +1,7 @@
package gay.pizza.pork.bir package gay.pizza.pork.bir
data class IrAccess(val target: IrSymbol) : IrCodeElement { data class IrWorld(val slabs: List<IrSlab>) : IrElement {
override fun crawl(block: (IrElement) -> Unit) { override fun crawl(block: (IrElement) -> Unit) {
block(target) slabs.forEach(block)
} }
} }

View File

@ -1,3 +1,3 @@
package gay.pizza.pork.bytecode package gay.pizza.pork.bytecode
class MutableRel(var rel: UInt) data class MutableRel(var rel: UInt)

View File

@ -1,3 +0,0 @@
package gay.pizza.pork.bytecode
class Ops(val ops: List<Op>)

View File

@ -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)
}
} }

View File

@ -2,29 +2,62 @@ 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.NativeFunctionDescriptor
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>
get() = scopeSymbol.scope.usedSymbols get() = scopeSymbol.scope.usedSymbols
private fun compile(): CompiledSymbolResult { private fun compile(): CompiledSymbolResult {
val emitter = StubOpEmitter(compilableSlab.compiler, this) val code = CodeBuilder(this)
emitter.enter() val ir = compiledIrDefinition
val emitter = IrStubOpEmitter(ir, code)
emitter.visit(ir.code)
emitter.final()
return emitter.code.build()
}
private fun compileIrDefinition(): IrDefinition {
val compiler = compilableSlab.compiler
val functionSymbol = compiler.irSymbolWorld.create(scopeSymbol, IrSymbolTag.Function)
val irCodeEmitter = IrCodeEmitter(
self = functionSymbol,
irSymbolWorld = compiler.irSymbolWorld,
irSymbolAssignment = compiler.irSymbolAssignment,
scope = compilableSlab.slab.scope
)
irCodeEmitter.enterLocalScope()
val what = if (scopeSymbol.definition is FunctionDefinition) { val what = if (scopeSymbol.definition is FunctionDefinition) {
val functionDefinition = scopeSymbol.definition as FunctionDefinition val functionDefinition = scopeSymbol.definition as FunctionDefinition
emitter.allocateOuterScope(functionDefinition) irCodeEmitter.createFunctionArguments(functionDefinition)
functionDefinition.block ?: functionDefinition.nativeFunctionDescriptor!! functionDefinition.block ?: functionDefinition.nativeFunctionDescriptor!!
} else { } else {
val letDefinition = scopeSymbol.definition as LetDefinition val letDefinition = scopeSymbol.definition as LetDefinition
letDefinition.value letDefinition.value
} }
emitter.visit(what) val type = if (what is NativeFunctionDescriptor) {
emitter.exit() IrDefinitionType.NativeFunction
return emitter.code.build() } else IrDefinitionType.CodeFunction
val irCodeElement = irCodeEmitter.visit(what)
val irCodeBlock = if (irCodeElement is IrCodeBlock) {
irCodeElement
} else IrCodeBlock(listOf(irCodeElement))
irCodeEmitter.exitLocalScope()
return IrDefinition(
symbol = functionSymbol,
type = type,
arguments = irCodeEmitter.functionArguments,
code = irCodeBlock
)
} }
val id: String val id: String

View File

@ -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<Any> = 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)

View File

@ -8,12 +8,23 @@ import gay.pizza.pork.frontend.scope.SlabScope
class IrCodeEmitter( class IrCodeEmitter(
val self: IrSymbol, val self: IrSymbol,
val irSymbolWorld: IrSymbolWorld, val irSymbolWorld: IrSymbolWorld<Any>,
val irSymbolAssignment: IrSymbolAssignment, val irSymbolAssignment: IrSymbolAssignment,
val scope: SlabScope val scope: SlabScope
) : FunctionLevelVisitor<IrCodeElement>() { ) : FunctionLevelVisitor<IrCodeElement>() {
private val loopSymbols = mutableListOf<IrSymbol>() private val loopSymbols = mutableListOf<IrSymbol>()
private val localVariables = mutableListOf<MutableList<LocalVariable>>() private val localVariables = mutableListOf<MutableMap<String, LocalVariable>>()
var functionArguments: List<IrFunctionArgument> = emptyList()
fun createFunctionArguments(functionDefinition: FunctionDefinition) {
val functionSymbols = mutableListOf<IrFunctionArgument>()
for (arg in functionDefinition.arguments) {
val symbol = createLocalVariable(arg.symbol)
functionSymbols.add(IrFunctionArgument(symbol))
}
functionArguments = functionSymbols
}
private fun startLoop(): IrSymbol { private fun startLoop(): IrSymbol {
val symbol = irSymbolAssignment.next(IrSymbolTag.Loop) val symbol = irSymbolAssignment.next(IrSymbolTag.Loop)
@ -34,19 +45,24 @@ class IrCodeEmitter(
} }
} }
private fun enterBlockScope() { fun enterLocalScope() {
val locals = mutableListOf<LocalVariable>() val locals = mutableMapOf<String, LocalVariable>()
localVariables.add(locals) localVariables.add(locals)
} }
private fun exitBlockScope() { fun exitLocalScope() {
localVariables.removeLast() localVariables.removeLast()
} }
private fun createLocalVariable(name: Symbol): IrSymbol { private fun createLocalVariable(name: Symbol): IrSymbol {
val symbol = irSymbolAssignment.next(IrSymbolTag.Local) val symbol = irSymbolAssignment.next(IrSymbolTag.Local)
val variable = LocalVariable(symbol, name) val variable = LocalVariable(symbol, name)
localVariables.last().add(variable) val variables = localVariables.last()
val existing = variables[name.id]
if (existing != null) {
throw CompileError("Unable to define local variable '${name.id}' within this scope, it already exists", name)
}
variables[name.id] = variable
return symbol return symbol
} }
@ -58,10 +74,10 @@ class IrCodeEmitter(
} }
private fun lookupLocalVariable(name: Symbol): IrSymbol? { private fun lookupLocalVariable(name: Symbol): IrSymbol? {
for (i in 0..localVariables.size) { for (i in 1..localVariables.size) {
val b = localVariables.size - i - 1 val b = localVariables.size - i
val scope = localVariables[b] val scope = localVariables[b]
val found = scope.firstOrNull { it.name == name } val found = scope[name.id]
if (found != null) { if (found != null) {
return found.symbol return found.symbol
} }
@ -76,20 +92,20 @@ class IrCodeEmitter(
} }
val scoped = scope.resolve(name) val scoped = scope.resolve(name)
if (scoped != null) { if (scoped != null) {
return irSymbolWorld.lookup(scoped, scopeSymbolToTag(scoped)) return irSymbolWorld.create(scoped, scopeSymbolToTag(scoped))
} }
return null return null
} }
private fun lookupFunction(name: Symbol): Pair<ScopeSymbol, IrSymbol>? { private fun lookupFunction(name: Symbol): Pair<ScopeSymbol, IrSymbol>? {
val scoped = scope.resolve(name) ?: return null val scoped = scope.resolve(name) ?: return null
return scoped to irSymbolWorld.lookup(scoped, scopeSymbolToTag(scoped)) return scoped to irSymbolWorld.create(scoped, scopeSymbolToTag(scoped))
} }
override fun visitBlock(node: Block): IrCodeBlock { override fun visitBlock(node: Block): IrCodeBlock {
enterBlockScope() enterLocalScope()
val block = IrCodeBlock(node.expressions.map { it.visit(this) }) val block = IrCodeBlock(node.expressions.map { it.visit(this) })
exitBlockScope() exitLocalScope()
return block return block
} }
@ -149,7 +165,7 @@ class IrCodeEmitter(
} }
} }
if (functionDefinition.arguments.any { it.multiple }) { if (variableArguments == null && functionDefinition.arguments.any { it.multiple }) {
variableArguments = mutableListOf() variableArguments = mutableListOf()
} }
@ -234,7 +250,13 @@ class IrCodeEmitter(
IrStringConstant(node.text) IrStringConstant(node.text)
override fun visitSuffixOperation(node: SuffixOperation): IrCodeElement { override fun visitSuffixOperation(node: SuffixOperation): IrCodeElement {
TODO("Not yet implemented") 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 { override fun visitSymbolReference(node: SymbolReference): IrCodeElement {
@ -255,4 +277,9 @@ class IrCodeEmitter(
inner = node.block.visit(this) inner = node.block.visit(this)
) )
} }
override fun visitNativeFunctionDescriptor(node: NativeFunctionDescriptor): IrCodeElement = IrNativeDefinition(
form = node.form.id,
definitions = node.definitions.map { it.text }
)
} }

View File

@ -0,0 +1,33 @@
package gay.pizza.pork.compiler
import gay.pizza.pork.bir.*
interface IrCodeVisitor<T> : IrVisitor<T> {
override fun visitIrDefinition(ir: IrDefinition): T {
codeOnlyError("IrDefinition")
}
override fun visitIrSlab(ir: IrSlab): T {
codeOnlyError("IrSlab")
}
override fun visitIrSlabLocation(ir: IrSlabLocation): T {
codeOnlyError("IrSlabLocation")
}
override fun visitIrWorld(ir: IrWorld): T {
codeOnlyError("IrWorld")
}
override fun visitIrSymbol(ir: IrSymbol): T {
codeOnlyError("IrSymbol")
}
override fun visitIrFunctionArgument(ir: IrFunctionArgument): T {
codeOnlyError("IrFunctionArgument")
}
private fun codeOnlyError(type: String): Nothing {
throw RuntimeException("This visitor targets only code, and $type is not a code element.")
}
}

View File

@ -0,0 +1,222 @@
package gay.pizza.pork.compiler
import gay.pizza.pork.bir.*
import gay.pizza.pork.bytecode.ConstantTag
import gay.pizza.pork.bytecode.MutableRel
import gay.pizza.pork.bytecode.Opcode
class IrStubOpEmitter(val irDefinition: IrDefinition, val code: CodeBuilder) : IrCodeVisitor<Unit> {
private val symbol = code.symbol
private val functionArgumentCount = irDefinition.arguments.size
init {
for (argument in irDefinition.arguments.reversed()) {
val stubVar = code.localState.createOrFindLocal(argument.symbol)
code.emit(Opcode.StoreLocal, listOf(stubVar.index))
}
}
fun final() {
if (irDefinition.type == IrDefinitionType.CodeFunction) {
code.emit(Opcode.None)
}
code.emit(Opcode.Return)
code.emit(Opcode.End)
}
private fun resolve(symbol: IrSymbol): Loadable = code.localState.resolve(symbol)
private fun load(callOrStubVar: Loadable) {
if (callOrStubVar.stubVar != null) {
code.emit(Opcode.LoadLocal, listOf(callOrStubVar.stubVar.index))
} else {
code.emit(Opcode.Integer, listOf(code.nextOpInst() + 2u))
code.patch(Opcode.Call, listOf(0u), mapOf(0 to callOrStubVar.call!!))
}
}
private fun store(stubVar: StubVar) {
code.emit(Opcode.StoreLocal, listOf(stubVar.index))
}
override fun visitIrBeak(ir: IrBreak) {
val loop = code.localState.findLoopState(ir.target)
code.patch(Opcode.Jump, listOf(0u), 0, symbol, loop.exitJumpTarget)
}
override fun visitIrCall(ir: IrCall) {
val target = resolve(ir.target)
val targetSymbol = target.call!!
val retRel = MutableRel(0u)
for (argument in ir.arguments) {
visit(argument)
}
val variableArguments = ir.variableArguments
if (variableArguments != null) {
for (argument in variableArguments) {
visit(argument)
}
code.emit(Opcode.ListMake, listOf(variableArguments.size.toUInt()))
}
retRel.rel = code.nextOpInst() + 2u
code.patch(Opcode.ReturnAddress, listOf(0u), 0, symbol, retRel)
code.patch(Opcode.Call, listOf(0u), mapOf(0 to targetSymbol))
}
override fun visitIrCodeBlock(ir: IrCodeBlock) {
for (item in ir.items) {
visit(item)
}
}
override fun visitIrConditional(ir: IrConditional) {
val thenRel = MutableRel(0u)
val endRel = MutableRel(0u)
visit(ir.conditional)
code.patch(Opcode.JumpIf, listOf(0u), 0, symbol, thenRel)
visit(ir.ifTrue)
code.patch(Opcode.Jump, listOf(0u), 0, symbol, endRel)
thenRel.rel = code.nextOpInst()
visit(ir.ifFalse)
endRel.rel = code.nextOpInst()
}
override fun visitIrBooleanConstant(ir: IrBooleanConstant) {
code.emit(if (ir.value) Opcode.True else Opcode.False)
}
override fun visitIrIntegerConstant(ir: IrIntegerConstant) {
code.emit(Opcode.Integer, listOf(ir.value.toUInt()))
}
override fun visitIrLongConstant(ir: IrLongConstant) {
code.emit(Opcode.Integer, listOf(ir.value.toUInt()))
}
override fun visitIrDoubleConstant(ir: IrDoubleConstant) {
code.emit(Opcode.Integer, listOf(ir.value.toUInt()))
}
override fun visitIrStringConstant(ir: IrStringConstant) {
val bytes = ir.value.toByteArray()
val constant = symbol.compilableSlab.compiler.constantPool.assign(ConstantTag.String, bytes)
code.emit(Opcode.Constant, listOf(constant))
}
override fun visitIrNoneConstant(ir: IrNoneConstant) {
code.emit(Opcode.None)
}
override fun visitIrContinue(ir: IrContinue) {
val loop = code.localState.findLoopState(ir.target)
code.patch(Opcode.Jump, listOf(0u), 0, symbol, loop.exitJumpTarget)
}
override fun visitIrInfix(ir: IrInfix) {
visit(ir.left)
visit(ir.right)
when (ir.op) {
IrInfixOp.Add -> code.emit(Opcode.Add)
IrInfixOp.Subtract -> code.emit(Opcode.Subtract)
IrInfixOp.Multiply -> code.emit(Opcode.Multiply)
IrInfixOp.Divide -> code.emit(Opcode.Divide)
IrInfixOp.Equals -> code.emit(Opcode.CompareEqual)
IrInfixOp.NotEquals -> {
code.emit(Opcode.CompareEqual)
code.emit(Opcode.Not)
}
IrInfixOp.EuclideanModulo -> code.emit(Opcode.EuclideanModulo)
IrInfixOp.Remainder -> code.emit(Opcode.Remainder)
IrInfixOp.Lesser -> code.emit(Opcode.CompareLesser)
IrInfixOp.Greater -> code.emit(Opcode.CompareGreater)
IrInfixOp.GreaterEqual -> code.emit(Opcode.CompareGreaterEqual)
IrInfixOp.LesserEqual -> code.emit(Opcode.CompareLesserEqual)
IrInfixOp.BooleanAnd -> code.emit(Opcode.And)
IrInfixOp.BooleanOr -> code.emit(Opcode.Or)
IrInfixOp.BinaryAnd -> code.emit(Opcode.BinaryAnd)
IrInfixOp.BinaryOr -> code.emit(Opcode.BinaryOr)
IrInfixOp.BinaryExclusiveOr -> code.emit(Opcode.BinaryXor)
}
}
override fun visitIrList(ir: IrList) {
val count = ir.items.size
for (item in ir.items) {
visit(item)
}
code.emit(Opcode.ListMake, listOf(count.toUInt()))
}
override fun visitIrLoad(ir: IrLoad) {
val loadable = resolve(ir.target)
load(loadable)
}
override fun visitIrLoop(ir: IrLoop) {
val startOfBody = MutableRel(0u)
val startOfLoop = MutableRel(0u)
val endOfLoop = MutableRel(0u)
code.localState.startLoop(ir.symbol, code.nextOpInst(), endOfLoop)
startOfLoop.rel = code.nextOpInst()
visit(ir.condition)
code.patch(Opcode.JumpIf, listOf(0u), 0, symbol, startOfBody)
code.patch(Opcode.Jump, listOf(0u), 0, symbol, endOfLoop)
startOfBody.rel = code.nextOpInst()
visit(ir.inner)
code.patch(Opcode.Jump, listOf(0u), 0, symbol, startOfLoop)
endOfLoop.rel = code.nextOpInst()
code.localState.endLoop(ir.symbol)
}
override fun visitIrPrefix(ir: IrPrefix) {
visit(ir.value)
when (ir.op) {
IrPrefixOp.BooleanNot -> code.emit(Opcode.Not)
IrPrefixOp.UnaryPlus -> code.emit(Opcode.UnaryPlus)
IrPrefixOp.UnaryMinus -> code.emit(Opcode.UnaryMinus)
IrPrefixOp.BinaryNot -> code.emit(Opcode.BinaryNot)
}
}
override fun visitIrReturn(ir: IrReturn) {
visit(ir.value)
code.emit(Opcode.Return)
}
override fun visitIrStore(ir: IrStore) {
visit(ir.value)
val variable = code.localState.createOrFindLocal(ir.target)
store(variable)
}
override fun visitIrSuffix(ir: IrSuffix) {
val loadable = code.localState.resolve(ir.target)
load(loadable)
when (ir.op) {
IrSuffixOp.Increment -> {
code.emit(Opcode.Integer, listOf(1u))
code.emit(Opcode.Add, emptyList())
}
IrSuffixOp.Decrement-> {
code.emit(Opcode.Integer, listOf(1u))
code.emit(Opcode.Subtract, emptyList())
}
}
store(loadable.stubVar!!)
}
override fun visitIrNativeDefinition(ir: IrNativeDefinition) {
for (def in ir.definitions.reversed()) {
val defConstant = symbol.compilableSlab.compiler.constantPool.assign(
ConstantTag.String,
def.encodeToByteArray()
)
code.emit(Opcode.Constant, listOf(defConstant))
}
val formConstant = symbol.compilableSlab.compiler.constantPool.assign(
ConstantTag.String,
ir.form.encodeToByteArray()
)
code.emit(Opcode.Native, listOf(formConstant, ir.definitions.size.toUInt(), functionArgumentCount.toUInt()))
}
}

View File

@ -4,10 +4,13 @@ import gay.pizza.pork.bir.IrSymbol
import gay.pizza.pork.bir.IrSymbolAssignment import gay.pizza.pork.bir.IrSymbolAssignment
import gay.pizza.pork.bir.IrSymbolTag import gay.pizza.pork.bir.IrSymbolTag
class IrSymbolWorld(val irSymbolAssignment: IrSymbolAssignment) { class IrSymbolWorld<T>(val irSymbolAssignment: IrSymbolAssignment) {
private val symbols = mutableMapOf<Any, IrSymbol>() private val symbols = mutableMapOf<T, IrSymbol>()
fun lookup(value: Any, tag: IrSymbolTag): IrSymbol = symbols.getOrPut(value) { fun create(value: T, tag: IrSymbolTag): IrSymbol = symbols.getOrPut(value) {
irSymbolAssignment.next(tag) irSymbolAssignment.next(tag)
} }
fun resolve(value: T): IrSymbol? = symbols[value]
fun resolve(symbol: IrSymbol): T? = symbols.entries.firstOrNull { it.value == symbol }?.key
} }

View File

@ -1,62 +1,55 @@
package gay.pizza.pork.compiler package gay.pizza.pork.compiler
import gay.pizza.pork.ast.gen.Symbol import gay.pizza.pork.bir.IrSymbol
import gay.pizza.pork.bytecode.MutableRel import gay.pizza.pork.bytecode.MutableRel
import gay.pizza.pork.frontend.scope.ScopeSymbol
class LocalState(val symbol: CompilableSymbol) { class LocalState(val symbol: CompilableSymbol) {
private var internalLoopState: LoopState? = null private var internalLoopState: LoopState? = null
val loopState: LoopState?
get() = internalLoopState
private var localVarIndex: UInt = 0u private var localVarIndex: UInt = 0u
private val variables = mutableListOf<MutableList<StubVar>>() private val stubVariables = mutableMapOf<IrSymbol, StubVar>()
private val loops = mutableMapOf<IrSymbol, LoopState>()
fun startLoop(startOfLoop: UInt, exitJumpTarget: MutableRel) { fun startLoop(symbol: IrSymbol, startOfLoop: UInt, exitJumpTarget: MutableRel) {
internalLoopState = LoopState( val existing = loops[symbol]
if (existing != null) {
throw CompileError("Starting loop that already is started")
}
val loopState = LoopState(
startOfLoop = startOfLoop, startOfLoop = startOfLoop,
exitJumpTarget = exitJumpTarget, exitJumpTarget = exitJumpTarget,
scopeDepth = (internalLoopState?.scopeDepth ?: 0u) + 1u, scopeDepth = (internalLoopState?.scopeDepth ?: 0u) + 1u
enclosing = internalLoopState
) )
loops[symbol] = loopState
} }
fun endLoop() { fun findLoopState(symbol: IrSymbol): LoopState =
internalLoopState = internalLoopState?.enclosing loops[symbol] ?: throw CompileError("Unable to find target loop")
fun endLoop(symbol: IrSymbol) {
loops.remove(symbol) ?: throw CompileError("End of loop target not found")
} }
fun createLocal(symbol: Symbol): StubVar { fun createOrFindLocal(symbol: IrSymbol): StubVar {
val scope = variables.last() val existing = stubVariables[symbol]
val variable = StubVar(localVarIndex++, symbol) if (existing != null) {
scope.add(variable) return existing
}
val variable = StubVar(localVarIndex++, symbol.id)
stubVariables[symbol] = variable
return variable return variable
} }
fun createAnonymousLocal(): StubVar { fun resolve(symbol: IrSymbol): Loadable {
val scope = variables.last() val localStubVar = stubVariables[symbol]
val variable = StubVar(localVarIndex++) if (localStubVar != null) {
scope.add(variable) return Loadable(stubVar = localStubVar)
return variable
}
fun pushScope() {
variables.add(mutableListOf())
}
fun popScope() {
variables.removeLast()
}
fun resolve(symbol: Symbol): Loadable {
for (scope in variables.reversed()) {
val found = scope.firstOrNull { it.symbol == symbol }
if (found != null) {
return Loadable(stubVar = found)
}
} }
val found = this.symbol.compilableSlab.resolveVisible(symbol) val value = this.symbol.compilableSlab.compiler.irSymbolWorld.resolve(symbol) ?:
if (found != null) { throw RuntimeException("Unable to resolve symbol: ${symbol.id} ${symbol.tag}")
return Loadable(call = found) val scopeSymbol = value as ScopeSymbol
} val call = this.symbol.compilableSlab.compiler.resolve(scopeSymbol)
throw RuntimeException("Unable to resolve symbol: ${symbol.id}") return Loadable(call = call)
} }
} }

View File

@ -5,6 +5,5 @@ import gay.pizza.pork.bytecode.MutableRel
class LoopState( class LoopState(
val startOfLoop: UInt, val startOfLoop: UInt,
val exitJumpTarget: MutableRel, val exitJumpTarget: MutableRel,
val scopeDepth: UInt, val scopeDepth: UInt
val enclosing: LoopState? = null
) )

View File

@ -1,301 +0,0 @@
package gay.pizza.pork.compiler
import gay.pizza.pork.ast.FunctionLevelVisitor
import gay.pizza.pork.ast.gen.*
import gay.pizza.pork.bytecode.ConstantTag
import gay.pizza.pork.bytecode.MutableRel
import gay.pizza.pork.bytecode.Opcode
class StubOpEmitter(val compiler: Compiler, val symbol: CompilableSymbol) : FunctionLevelVisitor<Unit>() {
val code: CodeBuilder = CodeBuilder(symbol)
fun allocateOuterScope(definition: FunctionDefinition) {
val allNormalArguments = definition.arguments.takeWhile { !it.multiple }
val varArgument = definition.arguments.firstOrNull { it.multiple }
for (arg in allNormalArguments.reversed()) {
val functionLocal = code.localState.createLocal(arg.symbol)
code.emit(Opcode.StoreLocal, listOf(functionLocal.index))
}
if (varArgument != null) {
val functionLocal = code.localState.createLocal(varArgument.symbol)
code.emit(Opcode.StoreLocal, listOf(functionLocal.index))
}
}
fun enter() {
code.localState.pushScope()
}
fun exit() {
code.localState.popScope()
code.emit(Opcode.None)
code.emit(Opcode.Return)
}
override fun visitBlock(node: Block) {
code.localState.pushScope()
node.visitChildren(this)
code.localState.popScope()
}
override fun visitBooleanLiteral(node: BooleanLiteral) {
code.emit(if (node.value) Opcode.True else Opcode.False)
}
override fun visitBreak(node: Break) {
code.patch(Opcode.Jump, listOf(0u), 0, symbol, code.localState.loopState!!.exitJumpTarget)
}
override fun visitContinue(node: Continue) {
code.patch(Opcode.Jump, listOf(0u), 0, symbol, code.localState.loopState!!.startOfLoop)
}
override fun visitDoubleLiteral(node: DoubleLiteral) {
code.emit(Opcode.Integer, listOf(node.value.toUInt()))
}
override fun visitForIn(node: ForIn) {
val listLocalVar = code.localState.createAnonymousLocal()
val sizeLocalVar = code.localState.createAnonymousLocal()
val currentIndexVar = code.localState.createAnonymousLocal()
val currentValueVar = code.localState.createLocal(node.item.symbol)
node.expression.visit(this)
code.emit(Opcode.StoreLocal, listOf(listLocalVar.index))
load(Loadable(stubVar = listLocalVar))
code.emit(Opcode.ListSize)
code.emit(Opcode.StoreLocal, listOf(sizeLocalVar.index))
code.emit(Opcode.Integer, listOf(0u))
code.emit(Opcode.StoreLocal, listOf(currentIndexVar.index))
val endOfLoop = MutableRel(0u)
val startOfLoop = code.nextOpInst()
code.localState.startLoop(startOfLoop, endOfLoop)
load(Loadable(stubVar = currentIndexVar))
load(Loadable(stubVar = sizeLocalVar))
code.emit(Opcode.CompareGreaterEqual)
code.patch(Opcode.JumpIf, listOf(0u), 0, symbol, endOfLoop)
load(Loadable(stubVar = currentIndexVar))
load(Loadable(stubVar = listLocalVar))
code.emit(Opcode.Index)
code.emit(Opcode.StoreLocal, listOf(currentValueVar.index))
node.block.visit(this)
code.emit(Opcode.LoadLocal, listOf(currentIndexVar.index))
code.emit(Opcode.Integer, listOf(1u))
code.emit(Opcode.Add)
code.emit(Opcode.StoreLocal, listOf(currentIndexVar.index))
code.patch(Opcode.Jump, listOf(0u), 0, symbol, startOfLoop)
endOfLoop.rel = code.nextOpInst()
}
override fun visitFunctionCall(node: FunctionCall) {
val targetScopeSymbol = symbol.scopeSymbol.scope.resolve(node.symbol) ?:
throw RuntimeException("Unable to resolve symbol: ${node.symbol.id}")
val targetSymbol = compiler.resolve(targetScopeSymbol)
val functionDefinition = targetSymbol.scopeSymbol.definition as FunctionDefinition
val retRel = MutableRel(0u)
val normalArguments = mutableListOf<Expression>()
var variableArguments: List<Expression>? = null
if (functionDefinition.arguments.any { it.multiple }) {
variableArguments = emptyList()
}
for ((index, item) in functionDefinition.arguments.zip(node.arguments).withIndex()) {
val (spec, value) = item
if (spec.multiple) {
val remaining = node.arguments.drop(index)
variableArguments = remaining
break
} else {
normalArguments.add(value)
}
}
if (variableArguments != null) {
for (item in variableArguments.reversed()) {
item.visit(this)
}
code.emit(Opcode.ListMake, listOf(variableArguments.size.toUInt()))
}
for (item in normalArguments.reversed()) {
visit(item)
}
retRel.rel = code.nextOpInst() + 2u
code.patch(Opcode.ReturnAddress, listOf(0u), 0, symbol, retRel)
code.patch(Opcode.Call, listOf(0u), mapOf(0 to targetSymbol))
}
override fun visitIf(node: If) {
val thenRel = MutableRel(0u)
val endRel = MutableRel(0u)
node.condition.visit(this)
code.patch(Opcode.JumpIf, listOf(0u), 0, symbol, thenRel)
node.elseBlock?.visit(this)
code.patch(Opcode.Jump, listOf(0u), 0, symbol, endRel)
thenRel.rel = code.nextOpInst()
node.thenBlock.visit(this)
endRel.rel = code.nextOpInst()
}
override fun visitIndexedBy(node: IndexedBy) {
node.expression.visit(this)
node.index.visit(this)
code.emit(Opcode.Index)
}
override fun visitInfixOperation(node: InfixOperation) {
node.left.visit(this)
node.right.visit(this)
when (node.op) {
InfixOperator.Plus -> code.emit(Opcode.Add)
InfixOperator.Minus -> code.emit(Opcode.Subtract)
InfixOperator.Multiply -> code.emit(Opcode.Multiply)
InfixOperator.Divide -> code.emit(Opcode.Divide)
InfixOperator.Equals -> code.emit(Opcode.CompareEqual)
InfixOperator.NotEquals -> {
code.emit(Opcode.CompareEqual)
code.emit(Opcode.Not)
}
InfixOperator.EuclideanModulo -> code.emit(Opcode.EuclideanModulo)
InfixOperator.Remainder -> code.emit(Opcode.Remainder)
InfixOperator.Lesser -> code.emit(Opcode.CompareLesser)
InfixOperator.Greater -> code.emit(Opcode.CompareGreater)
InfixOperator.GreaterEqual -> code.emit(Opcode.CompareGreaterEqual)
InfixOperator.LesserEqual -> code.emit(Opcode.CompareLesserEqual)
InfixOperator.BooleanAnd -> code.emit(Opcode.And)
InfixOperator.BooleanOr -> code.emit(Opcode.Or)
InfixOperator.BinaryAnd -> code.emit(Opcode.BinaryAnd)
InfixOperator.BinaryOr -> code.emit(Opcode.BinaryOr)
InfixOperator.BinaryExclusiveOr -> code.emit(Opcode.BinaryXor)
}
}
override fun visitIntegerLiteral(node: IntegerLiteral) {
code.emit(Opcode.Integer, listOf(node.value.toUInt()))
}
override fun visitLetAssignment(node: LetAssignment) {
val variable = code.localState.createLocal(node.symbol)
node.value.visit(this)
code.emit(Opcode.StoreLocal, listOf(variable.index))
}
override fun visitListLiteral(node: ListLiteral) {
val count = node.items.size
for (item in node.items) {
item.visit(this)
}
code.emit(Opcode.ListMake, listOf(count.toUInt()))
}
override fun visitLongLiteral(node: LongLiteral) {
code.emit(Opcode.Integer, listOf(node.value.toUInt()))
}
override fun visitNoneLiteral(node: NoneLiteral) {
code.emit(Opcode.None)
}
override fun visitParentheses(node: Parentheses) {
node.expression.visit(this)
}
override fun visitPrefixOperation(node: PrefixOperation) {
node.expression.visit(this)
when (node.op) {
PrefixOperator.BooleanNot -> code.emit(Opcode.Not)
PrefixOperator.UnaryPlus -> code.emit(Opcode.UnaryPlus)
PrefixOperator.UnaryMinus -> code.emit(Opcode.UnaryMinus)
PrefixOperator.BinaryNot -> code.emit(Opcode.BinaryNot)
}
}
override fun visitReturn(node: Return) {
node.value.visit(this)
code.emit(Opcode.Return)
}
override fun visitSetAssignment(node: SetAssignment) {
val stubVarOrCall = code.localState.resolve(node.symbol)
if (stubVarOrCall.stubVar == null) {
throw RuntimeException("Invalid set assignment.")
}
node.value.visit(this)
code.emit(Opcode.StoreLocal, listOf(stubVarOrCall.stubVar.index))
}
override fun visitStringLiteral(node: StringLiteral) {
val bytes = node.text.toByteArray()
val constant = compiler.constantPool.assign(ConstantTag.String, bytes)
code.emit(Opcode.Constant, listOf(constant))
}
override fun visitSuffixOperation(node: SuffixOperation) {
val stubVarOrCall = code.localState.resolve(node.reference.symbol)
if (stubVarOrCall.stubVar == null) {
throw RuntimeException("Invalid suffix operation.")
}
load(stubVarOrCall)
when (node.op) {
SuffixOperator.Increment -> {
code.emit(Opcode.Integer, listOf(1u))
code.emit(Opcode.Add, emptyList())
code.emit(Opcode.StoreLocal, listOf(stubVarOrCall.stubVar.index))
}
SuffixOperator.Decrement -> {
code.emit(Opcode.Integer, listOf(1u))
code.emit(Opcode.Subtract, emptyList())
code.emit(Opcode.StoreLocal, listOf(stubVarOrCall.stubVar.index))
}
}
}
override fun visitSymbolReference(node: SymbolReference) {
val variable = code.localState.resolve(node.symbol)
load(variable)
}
override fun visitVarAssignment(node: VarAssignment) {
val variable = code.localState.createLocal(node.symbol)
node.value.visit(this)
code.emit(Opcode.StoreLocal, listOf(variable.index))
}
override fun visitWhile(node: While) {
val startOfBody = MutableRel(0u)
val startOfLoop = MutableRel(0u)
val endOfLoop = MutableRel(0u)
code.localState.startLoop(code.nextOpInst(), endOfLoop)
startOfLoop.rel = code.nextOpInst()
node.condition.visit(this)
code.patch(Opcode.JumpIf, listOf(0u), 0, symbol, startOfBody)
code.patch(Opcode.Jump, listOf(0u), 0, symbol, endOfLoop)
startOfBody.rel = code.nextOpInst()
node.block.visit(this)
code.patch(Opcode.Jump, listOf(0u), 0, symbol, startOfLoop)
endOfLoop.rel = code.nextOpInst()
code.localState.endLoop()
}
override fun visitNativeFunctionDescriptor(node: NativeFunctionDescriptor) {
for (def in node.definitions) {
val defConstant = compiler.constantPool.assign(ConstantTag.String, def.text.toByteArray())
code.emit(Opcode.Constant, listOf(defConstant))
}
val formConstant = compiler.constantPool.assign(ConstantTag.String, node.form.id.toByteArray())
val functionDefinition = symbol.scopeSymbol.definition as FunctionDefinition
val functionArgumentCount = functionDefinition.arguments.size
code.emit(Opcode.Native, listOf(formConstant, node.definitions.size.toUInt(), functionArgumentCount.toUInt()))
}
private fun load(callOrStubVar: Loadable) {
if (callOrStubVar.stubVar != null) {
code.emit(Opcode.LoadLocal, listOf(callOrStubVar.stubVar.index))
} else {
code.emit(Opcode.Integer, listOf(code.nextOpInst() + 2u))
code.patch(Opcode.Call, listOf(0u), mapOf(0 to callOrStubVar.call!!))
}
}
}

View File

@ -1,8 +1,6 @@
package gay.pizza.pork.compiler package gay.pizza.pork.compiler
import gay.pizza.pork.ast.gen.Symbol
class StubVar( class StubVar(
val index: UInt, val index: UInt,
val symbol: Symbol? = null val id: UInt
) )

View File

@ -18,4 +18,6 @@ class ScopeSymbol(val slabScope: SlabScope, val definition: Definition) {
result = 31 * result + symbol.hashCode() result = 31 * result + symbol.hashCode()
return result return result
} }
override fun toString(): String = "ScopeSymbol(${symbol.id})"
} }

View File

@ -3,14 +3,8 @@ package gay.pizza.pork.tool
import com.github.ajalt.clikt.core.CliktCommand 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.FunctionDefinition
import gay.pizza.pork.ast.gen.Symbol import gay.pizza.pork.ast.gen.Symbol
import gay.pizza.pork.ast.gen.visit
import gay.pizza.pork.bir.IrSymbolAssignment
import gay.pizza.pork.bir.IrSymbolTag
import gay.pizza.pork.compiler.Compiler import gay.pizza.pork.compiler.Compiler
import gay.pizza.pork.compiler.IrCodeEmitter
import gay.pizza.pork.compiler.IrSymbolWorld
import gay.pizza.pork.minimal.FileTool import gay.pizza.pork.minimal.FileTool
class CompileCommand : CliktCommand(help = "Compile Pork to Bytecode", name = "compile") { class CompileCommand : CliktCommand(help = "Compile Pork to Bytecode", name = "compile") {
@ -37,12 +31,5 @@ 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 irSymbolAssignment = IrSymbolAssignment()
val irSymbolWorld = IrSymbolWorld(irSymbolAssignment)
val self = irSymbolAssignment.next(IrSymbolTag.Function)
val irCodeEmitter = IrCodeEmitter(self, irSymbolWorld, irSymbolAssignment, compiledSlab.slab.scope)
val ir = irCodeEmitter.visit((compiledMain.scopeSymbol.definition as FunctionDefinition).block!!)
println(ir)
} }
} }