mirror of
https://github.com/GayPizzaSpecifications/pork.git
synced 2025-08-03 21:21:33 +00:00
language: implement proper virtual machine support
This commit is contained in:
@ -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<IrDefinition>()
|
||||
for (compilableSymbol in compilableSymbols) {
|
||||
|
@ -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,
|
||||
|
@ -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()
|
||||
)
|
||||
|
@ -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<Slab, CompilableSlab> = ComputableState { slab ->
|
||||
CompilableSlab(this, slab)
|
||||
@ -39,6 +42,14 @@ class Compiler {
|
||||
}
|
||||
}
|
||||
|
||||
fun compileIrWorld(): IrWorld {
|
||||
val slabs = mutableListOf<IrSlab>()
|
||||
for (slab in world.slabs) {
|
||||
slabs.add(compilableSlabs.of(slab).compiledIrSlab)
|
||||
}
|
||||
return IrWorld(slabs)
|
||||
}
|
||||
|
||||
fun compile(entryPointSymbol: CompilableSymbol): CompiledWorld {
|
||||
val usedSymbolSet = mutableSetOf<CompilableSymbol>()
|
||||
contributeCompiledSymbols(usedSymbolSet, entryPointSymbol.scopeSymbol, entryPointSymbol)
|
||||
|
@ -13,7 +13,7 @@ class IrCodeEmitter(
|
||||
val scope: SlabScope
|
||||
) : FunctionLevelVisitor<IrCodeElement>() {
|
||||
private val loopSymbols = mutableListOf<IrSymbol>()
|
||||
private val localVariables = mutableListOf<MutableMap<String, LocalVariable>>()
|
||||
private val localVariables = mutableListOf<MutableMap<Pair<String?, UInt?>, LocalVariable>>()
|
||||
|
||||
var functionArguments: List<IrFunctionArgument> = emptyList()
|
||||
|
||||
@ -46,7 +46,7 @@ class IrCodeEmitter(
|
||||
}
|
||||
|
||||
fun enterLocalScope() {
|
||||
val locals = mutableMapOf<String, LocalVariable>()
|
||||
val locals = mutableMapOf<Pair<String?, UInt?>, 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<ScopeSymbol, IrSymbol>? {
|
||||
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<IrCodeElement>(
|
||||
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) {
|
||||
|
@ -1,33 +0,0 @@
|
||||
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.")
|
||||
}
|
||||
}
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -7,8 +7,8 @@ import gay.pizza.pork.bir.IrSymbolTag
|
||||
class IrSymbolWorld<T>(val irSymbolAssignment: IrSymbolAssignment) {
|
||||
private val symbols = mutableMapOf<T, IrSymbol>()
|
||||
|
||||
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]
|
||||
|
@ -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)
|
||||
|
Reference in New Issue
Block a user