mirror of
https://github.com/GayPizzaSpecifications/pork.git
synced 2025-08-03 05:10:55 +00:00
compiler: first attempt at restructuring
This commit is contained in:
parent
041848c14e
commit
4c50d48e1e
@ -0,0 +1,43 @@
|
|||||||
|
package gay.pizza.pork.compiler
|
||||||
|
|
||||||
|
import gay.pizza.pork.bytecode.MutableRel
|
||||||
|
import gay.pizza.pork.bytecode.Op
|
||||||
|
import gay.pizza.pork.bytecode.Opcode
|
||||||
|
|
||||||
|
class CodeBuilder(val symbol: CompilableSymbol) {
|
||||||
|
private val ops = mutableListOf<StubOp>()
|
||||||
|
|
||||||
|
val localState: LocalState = LocalState(symbol)
|
||||||
|
|
||||||
|
fun nextOpInst(): UInt = ops.size.toUInt()
|
||||||
|
|
||||||
|
fun emit(op: StubOp) {
|
||||||
|
ops.add(op)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun emit(op: Op) {
|
||||||
|
ops.add(StaticOp(op))
|
||||||
|
}
|
||||||
|
|
||||||
|
fun emit(code: Opcode, arguments: List<UInt>) {
|
||||||
|
emit(Op(code, arguments))
|
||||||
|
}
|
||||||
|
|
||||||
|
fun emit(code: Opcode) {
|
||||||
|
emit(code, emptyList())
|
||||||
|
}
|
||||||
|
|
||||||
|
fun patch(code: Opcode, arguments: List<UInt>, index: Int, symbol: CompilableSymbol, rel: MutableRel) {
|
||||||
|
emit(PatchRelOp(Op(code, arguments), index, symbol, rel))
|
||||||
|
}
|
||||||
|
|
||||||
|
fun patch(code: Opcode, arguments: List<UInt>, index: Int, symbol: CompilableSymbol, rel: UInt) {
|
||||||
|
emit(PatchRelOp(Op(code, arguments), index, symbol, MutableRel(rel)))
|
||||||
|
}
|
||||||
|
|
||||||
|
fun patch(code: Opcode, arguments: List<UInt>, patches: Map<Int, CompilableSymbol>) {
|
||||||
|
ops.add(PatchSymOp(Op(code, arguments), patches))
|
||||||
|
}
|
||||||
|
|
||||||
|
fun build(): List<StubOp> = ops.toList()
|
||||||
|
}
|
@ -10,7 +10,7 @@ class CompilableSlab(val compiler: Compiler, val slab: Slab) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun compilableSymbolOf(symbol: Symbol): CompilableSymbol? = compilableSymbols.firstOrNull {
|
fun resolve(symbol: Symbol): CompilableSymbol? = compilableSymbols.firstOrNull {
|
||||||
it.scopeSymbol.symbol == symbol
|
it.scopeSymbol.symbol == symbol
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -24,7 +24,7 @@ class CompilableSymbol(val compilableSlab: CompilableSlab, val scopeSymbol: Scop
|
|||||||
}
|
}
|
||||||
emitter.visit(what)
|
emitter.visit(what)
|
||||||
emitter.exit()
|
emitter.exit()
|
||||||
return emitter.ops()
|
return emitter.code.build()
|
||||||
}
|
}
|
||||||
|
|
||||||
val id: String
|
val id: String
|
||||||
|
@ -13,7 +13,7 @@ class Compiler {
|
|||||||
|
|
||||||
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.compilableSymbolOf(scopeSymbol.symbol)
|
return compiledSlab.resolve(scopeSymbol.symbol)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun resolve(scopeSymbol: ScopeSymbol): CompilableSymbol = resolveOrNull(scopeSymbol) ?:
|
fun resolve(scopeSymbol: ScopeSymbol): CompilableSymbol = resolveOrNull(scopeSymbol) ?:
|
||||||
|
@ -0,0 +1,6 @@
|
|||||||
|
package gay.pizza.pork.compiler
|
||||||
|
|
||||||
|
class Loadable(
|
||||||
|
val call: CompilableSymbol? = null,
|
||||||
|
val stubVar: StubVar? = null
|
||||||
|
)
|
@ -0,0 +1,55 @@
|
|||||||
|
package gay.pizza.pork.compiler
|
||||||
|
|
||||||
|
import gay.pizza.pork.ast.gen.Symbol
|
||||||
|
import gay.pizza.pork.bytecode.MutableRel
|
||||||
|
|
||||||
|
class LocalState(val symbol: CompilableSymbol) {
|
||||||
|
private var internalLoopState: LoopState? = null
|
||||||
|
val loopState: LoopState?
|
||||||
|
get() = internalLoopState
|
||||||
|
|
||||||
|
private var localVarIndex: UInt = 0u
|
||||||
|
private val variables = mutableListOf<MutableList<StubVar>>()
|
||||||
|
|
||||||
|
fun startLoop(startOfLoop: UInt, exitJumpTarget: MutableRel) {
|
||||||
|
internalLoopState = LoopState(
|
||||||
|
startOfLoop = startOfLoop,
|
||||||
|
exitJumpTarget = exitJumpTarget,
|
||||||
|
scopeDepth = (internalLoopState?.scopeDepth ?: 0u) + 1u,
|
||||||
|
enclosing = internalLoopState
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun endLoop() {
|
||||||
|
internalLoopState = internalLoopState?.enclosing
|
||||||
|
}
|
||||||
|
|
||||||
|
fun createLocal(symbol: Symbol): StubVar {
|
||||||
|
val scope = variables.last()
|
||||||
|
val variable = StubVar(localVarIndex++, symbol)
|
||||||
|
scope.add(variable)
|
||||||
|
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.resolve(symbol)
|
||||||
|
if (found != null) {
|
||||||
|
return Loadable(call = found)
|
||||||
|
}
|
||||||
|
throw RuntimeException("Unable to resolve symbol: ${symbol.id}")
|
||||||
|
}
|
||||||
|
}
|
@ -5,7 +5,6 @@ import gay.pizza.pork.bytecode.MutableRel
|
|||||||
class LoopState(
|
class LoopState(
|
||||||
val startOfLoop: UInt,
|
val startOfLoop: UInt,
|
||||||
val exitJumpTarget: MutableRel,
|
val exitJumpTarget: MutableRel,
|
||||||
val body: MutableRel,
|
val scopeDepth: UInt,
|
||||||
val scopeDepth: Int,
|
|
||||||
val enclosing: LoopState? = null
|
val enclosing: LoopState? = null
|
||||||
)
|
)
|
||||||
|
@ -3,99 +3,55 @@ package gay.pizza.pork.compiler
|
|||||||
import gay.pizza.pork.ast.FunctionLevelVisitor
|
import gay.pizza.pork.ast.FunctionLevelVisitor
|
||||||
import gay.pizza.pork.ast.gen.*
|
import gay.pizza.pork.ast.gen.*
|
||||||
import gay.pizza.pork.bytecode.MutableRel
|
import gay.pizza.pork.bytecode.MutableRel
|
||||||
import gay.pizza.pork.bytecode.Op
|
|
||||||
import gay.pizza.pork.bytecode.Opcode
|
import gay.pizza.pork.bytecode.Opcode
|
||||||
|
|
||||||
class StubOpEmitter(val compiler: Compiler, val symbol: CompilableSymbol) : FunctionLevelVisitor<Unit>() {
|
class StubOpEmitter(val compiler: Compiler, val symbol: CompilableSymbol) : FunctionLevelVisitor<Unit>() {
|
||||||
private val ops = mutableListOf<StubOp>()
|
val code = CodeBuilder(symbol)
|
||||||
|
|
||||||
private var loopState: LoopState? = null
|
|
||||||
private val localVariables = mutableListOf<MutableList<StubVar>>()
|
|
||||||
private var localVarIndex = 0u
|
|
||||||
|
|
||||||
private val requiredLoopState: LoopState
|
|
||||||
get() {
|
|
||||||
if (loopState != null) {
|
|
||||||
return loopState!!
|
|
||||||
}
|
|
||||||
throw RuntimeException("loopState expected but was not found.")
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun allocateLocalVariable(symbol: Symbol): StubVar {
|
|
||||||
val scope = localVariables.last()
|
|
||||||
val variable = StubVar(localVarIndex++, symbol)
|
|
||||||
scope.add(variable)
|
|
||||||
return variable
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun resolveSymbol(symbol: Symbol): CallOrStubVar {
|
|
||||||
for (scope in localVariables.reversed()) {
|
|
||||||
val found = scope.firstOrNull { it.symbol == symbol }
|
|
||||||
if (found != null) {
|
|
||||||
return CallOrStubVar(stubVar = found)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
val found = this.symbol.compilableSlab.compilableSymbolOf(symbol)
|
|
||||||
if (found != null) {
|
|
||||||
return CallOrStubVar(call = found)
|
|
||||||
}
|
|
||||||
throw RuntimeException("Unable to resolve symbol: ${symbol.id}")
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun pushScope() {
|
|
||||||
emit(Opcode.ScopeIn)
|
|
||||||
localVariables.add(mutableListOf())
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun popScope() {
|
|
||||||
emit(Opcode.ScopeOut)
|
|
||||||
localVariables.removeLast()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun enter() {
|
|
||||||
pushScope()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun allocateOuterScope(definition: FunctionDefinition) {
|
fun allocateOuterScope(definition: FunctionDefinition) {
|
||||||
val allNormalArguments = definition.arguments.takeWhile { !it.multiple }
|
val allNormalArguments = definition.arguments.takeWhile { !it.multiple }
|
||||||
val varArgument = definition.arguments.firstOrNull { it.multiple }
|
val varArgument = definition.arguments.firstOrNull { it.multiple }
|
||||||
|
|
||||||
for (arg in allNormalArguments.reversed()) {
|
for (arg in allNormalArguments.reversed()) {
|
||||||
val functionLocal = allocateLocalVariable(arg.symbol)
|
val functionLocal = code.localState.createLocal(arg.symbol)
|
||||||
emit(Opcode.StoreLocal, listOf(functionLocal.index))
|
code.emit(Opcode.StoreLocal, listOf(functionLocal.index))
|
||||||
}
|
}
|
||||||
|
|
||||||
if (varArgument != null) {
|
if (varArgument != null) {
|
||||||
val functionLocal = allocateLocalVariable(varArgument.symbol)
|
val functionLocal = code.localState.createLocal(varArgument.symbol)
|
||||||
emit(Opcode.StoreLocal, listOf(functionLocal.index))
|
code.emit(Opcode.StoreLocal, listOf(functionLocal.index))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun enter() {
|
||||||
|
code.localState.pushScope()
|
||||||
|
}
|
||||||
|
|
||||||
fun exit() {
|
fun exit() {
|
||||||
popScope()
|
code.localState.popScope()
|
||||||
emit(Opcode.Return)
|
code.emit(Opcode.Return)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitBlock(node: Block) {
|
override fun visitBlock(node: Block) {
|
||||||
pushScope()
|
code.localState.pushScope()
|
||||||
node.visitChildren(this)
|
node.visitChildren(this)
|
||||||
popScope()
|
code.localState.popScope()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitBooleanLiteral(node: BooleanLiteral) {
|
override fun visitBooleanLiteral(node: BooleanLiteral) {
|
||||||
emit(if (node.value) Opcode.True else Opcode.False)
|
code.emit(if (node.value) Opcode.True else Opcode.False)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitBreak(node: Break) {
|
override fun visitBreak(node: Break) {
|
||||||
patch(Opcode.Jump, listOf(0u), 0, symbol, requiredLoopState.exitJumpTarget)
|
code.patch(Opcode.Jump, listOf(0u), 0, symbol, code.localState.loopState!!.exitJumpTarget)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitContinue(node: Continue) {
|
override fun visitContinue(node: Continue) {
|
||||||
patch(Opcode.Jump, listOf(0u), 0, symbol, requiredLoopState.startOfLoop)
|
code.patch(Opcode.Jump, listOf(0u), 0, symbol, code.localState.loopState!!.startOfLoop)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitDoubleLiteral(node: DoubleLiteral) {
|
override fun visitDoubleLiteral(node: DoubleLiteral) {
|
||||||
emit(Opcode.Integer, listOf(node.value.toUInt()))
|
code.emit(Opcode.Integer, listOf(node.value.toUInt()))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitForIn(node: ForIn) {
|
override fun visitForIn(node: ForIn) {
|
||||||
@ -108,7 +64,7 @@ class StubOpEmitter(val compiler: Compiler, val symbol: CompilableSymbol) : Func
|
|||||||
val targetSymbol = compiler.resolve(targetScopeSymbol)
|
val targetSymbol = compiler.resolve(targetScopeSymbol)
|
||||||
val functionDefinition = targetSymbol.scopeSymbol.definition as FunctionDefinition
|
val functionDefinition = targetSymbol.scopeSymbol.definition as FunctionDefinition
|
||||||
val retRel = MutableRel(0u)
|
val retRel = MutableRel(0u)
|
||||||
patch(Opcode.Integer, listOf(0u), 0, symbol, retRel)
|
code.patch(Opcode.Integer, listOf(0u), 0, symbol, retRel)
|
||||||
|
|
||||||
val normalArguments = mutableListOf<Expression>()
|
val normalArguments = mutableListOf<Expression>()
|
||||||
var variableArguments: List<Expression>? = null
|
var variableArguments: List<Expression>? = null
|
||||||
@ -127,70 +83,70 @@ class StubOpEmitter(val compiler: Compiler, val symbol: CompilableSymbol) : Func
|
|||||||
for (item in variableArguments.reversed()) {
|
for (item in variableArguments.reversed()) {
|
||||||
item.visit(this)
|
item.visit(this)
|
||||||
}
|
}
|
||||||
emit(Opcode.List, listOf(variableArguments.size.toUInt()))
|
code.emit(Opcode.List, listOf(variableArguments.size.toUInt()))
|
||||||
}
|
}
|
||||||
|
|
||||||
for (item in normalArguments.reversed()) {
|
for (item in normalArguments.reversed()) {
|
||||||
visit(item)
|
visit(item)
|
||||||
}
|
}
|
||||||
|
|
||||||
retRel.rel = (ops.size + 1).toUInt()
|
retRel.rel = code.nextOpInst() + 1u
|
||||||
patch(Opcode.Call, listOf(0u), mapOf(0 to targetSymbol))
|
code.patch(Opcode.Call, listOf(0u), mapOf(0 to targetSymbol))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitIf(node: If) {
|
override fun visitIf(node: If) {
|
||||||
val thenRel = MutableRel(0u)
|
val thenRel = MutableRel(0u)
|
||||||
val endRel = MutableRel(0u)
|
val endRel = MutableRel(0u)
|
||||||
node.condition.visit(this)
|
node.condition.visit(this)
|
||||||
patch(Opcode.JumpIf, listOf(0u), 0, symbol, thenRel)
|
code.patch(Opcode.JumpIf, listOf(0u), 0, symbol, thenRel)
|
||||||
node.elseBlock?.visit(this)
|
node.elseBlock?.visit(this)
|
||||||
patch(Opcode.Jump, listOf(0u), 0, symbol, endRel)
|
code.patch(Opcode.Jump, listOf(0u), 0, symbol, endRel)
|
||||||
thenRel.rel = ops.size.toUInt()
|
thenRel.rel = code.nextOpInst()
|
||||||
node.thenBlock.visit(this)
|
node.thenBlock.visit(this)
|
||||||
endRel.rel = ops.size.toUInt()
|
endRel.rel = code.nextOpInst()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitIndexedBy(node: IndexedBy) {
|
override fun visitIndexedBy(node: IndexedBy) {
|
||||||
node.expression.visit(this)
|
node.expression.visit(this)
|
||||||
node.index.visit(this)
|
node.index.visit(this)
|
||||||
emit(Opcode.Index)
|
code.emit(Opcode.Index)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitInfixOperation(node: InfixOperation) {
|
override fun visitInfixOperation(node: InfixOperation) {
|
||||||
node.left.visit(this)
|
node.left.visit(this)
|
||||||
node.right.visit(this)
|
node.right.visit(this)
|
||||||
when (node.op) {
|
when (node.op) {
|
||||||
InfixOperator.Plus -> emit(Opcode.Add)
|
InfixOperator.Plus -> code.emit(Opcode.Add)
|
||||||
InfixOperator.Minus -> emit(Opcode.Subtract)
|
InfixOperator.Minus -> code.emit(Opcode.Subtract)
|
||||||
InfixOperator.Multiply -> emit(Opcode.Multiply)
|
InfixOperator.Multiply -> code.emit(Opcode.Multiply)
|
||||||
InfixOperator.Divide -> emit(Opcode.Divide)
|
InfixOperator.Divide -> code.emit(Opcode.Divide)
|
||||||
InfixOperator.Equals -> emit(Opcode.CompareEqual)
|
InfixOperator.Equals -> code.emit(Opcode.CompareEqual)
|
||||||
InfixOperator.NotEquals -> {
|
InfixOperator.NotEquals -> {
|
||||||
emit(Opcode.CompareEqual)
|
code.emit(Opcode.CompareEqual)
|
||||||
emit(Opcode.Not)
|
code.emit(Opcode.Not)
|
||||||
}
|
}
|
||||||
InfixOperator.EuclideanModulo -> emit(Opcode.EuclideanModulo)
|
InfixOperator.EuclideanModulo -> code.emit(Opcode.EuclideanModulo)
|
||||||
InfixOperator.Remainder -> emit(Opcode.Remainder)
|
InfixOperator.Remainder -> code.emit(Opcode.Remainder)
|
||||||
InfixOperator.Lesser -> emit(Opcode.CompareLesser)
|
InfixOperator.Lesser -> code.emit(Opcode.CompareLesser)
|
||||||
InfixOperator.Greater -> emit(Opcode.CompareGreater)
|
InfixOperator.Greater -> code.emit(Opcode.CompareGreater)
|
||||||
InfixOperator.GreaterEqual -> emit(Opcode.CompareGreaterEqual)
|
InfixOperator.GreaterEqual -> code.emit(Opcode.CompareGreaterEqual)
|
||||||
InfixOperator.LesserEqual -> emit(Opcode.CompareLesserEqual)
|
InfixOperator.LesserEqual -> code.emit(Opcode.CompareLesserEqual)
|
||||||
InfixOperator.BooleanAnd -> emit(Opcode.And)
|
InfixOperator.BooleanAnd -> code.emit(Opcode.And)
|
||||||
InfixOperator.BooleanOr -> emit(Opcode.Or)
|
InfixOperator.BooleanOr -> code.emit(Opcode.Or)
|
||||||
InfixOperator.BinaryAnd -> emit(Opcode.BinaryAnd)
|
InfixOperator.BinaryAnd -> code.emit(Opcode.BinaryAnd)
|
||||||
InfixOperator.BinaryOr -> emit(Opcode.BinaryOr)
|
InfixOperator.BinaryOr -> code.emit(Opcode.BinaryOr)
|
||||||
InfixOperator.BinaryExclusiveOr -> emit(Opcode.BinaryXor)
|
InfixOperator.BinaryExclusiveOr -> code.emit(Opcode.BinaryXor)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitIntegerLiteral(node: IntegerLiteral) {
|
override fun visitIntegerLiteral(node: IntegerLiteral) {
|
||||||
emit(Opcode.Integer, listOf(node.value.toUInt()))
|
code.emit(Opcode.Integer, listOf(node.value.toUInt()))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitLetAssignment(node: LetAssignment) {
|
override fun visitLetAssignment(node: LetAssignment) {
|
||||||
val variable = allocateLocalVariable(node.symbol)
|
val variable = code.localState.createLocal(node.symbol)
|
||||||
node.value.visit(this)
|
node.value.visit(this)
|
||||||
emit(Opcode.StoreLocal, listOf(variable.index))
|
code.emit(Opcode.StoreLocal, listOf(variable.index))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitListLiteral(node: ListLiteral) {
|
override fun visitListLiteral(node: ListLiteral) {
|
||||||
@ -198,15 +154,15 @@ class StubOpEmitter(val compiler: Compiler, val symbol: CompilableSymbol) : Func
|
|||||||
for (item in node.items) {
|
for (item in node.items) {
|
||||||
item.visit(this)
|
item.visit(this)
|
||||||
}
|
}
|
||||||
emit(Opcode.List, listOf(count.toUInt()))
|
code.emit(Opcode.List, listOf(count.toUInt()))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitLongLiteral(node: LongLiteral) {
|
override fun visitLongLiteral(node: LongLiteral) {
|
||||||
emit(Opcode.Integer, listOf(node.value.toUInt()))
|
code.emit(Opcode.Integer, listOf(node.value.toUInt()))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitNoneLiteral(node: NoneLiteral) {
|
override fun visitNoneLiteral(node: NoneLiteral) {
|
||||||
emit(Opcode.None)
|
code.emit(Opcode.None)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitParentheses(node: Parentheses) {
|
override fun visitParentheses(node: Parentheses) {
|
||||||
@ -216,121 +172,90 @@ class StubOpEmitter(val compiler: Compiler, val symbol: CompilableSymbol) : Func
|
|||||||
override fun visitPrefixOperation(node: PrefixOperation) {
|
override fun visitPrefixOperation(node: PrefixOperation) {
|
||||||
node.expression.visit(this)
|
node.expression.visit(this)
|
||||||
when (node.op) {
|
when (node.op) {
|
||||||
PrefixOperator.BooleanNot -> emit(Opcode.Not)
|
PrefixOperator.BooleanNot -> code.emit(Opcode.Not)
|
||||||
PrefixOperator.UnaryPlus -> emit(Opcode.UnaryPlus)
|
PrefixOperator.UnaryPlus -> code.emit(Opcode.UnaryPlus)
|
||||||
PrefixOperator.UnaryMinus -> emit(Opcode.UnaryMinus)
|
PrefixOperator.UnaryMinus -> code.emit(Opcode.UnaryMinus)
|
||||||
PrefixOperator.BinaryNot -> emit(Opcode.BinaryNot)
|
PrefixOperator.BinaryNot -> code.emit(Opcode.BinaryNot)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitSetAssignment(node: SetAssignment) {
|
override fun visitSetAssignment(node: SetAssignment) {
|
||||||
val stubVarOrCall = resolveSymbol(node.symbol)
|
val stubVarOrCall = code.localState.resolve(node.symbol)
|
||||||
if (stubVarOrCall.stubVar == null) {
|
if (stubVarOrCall.stubVar == null) {
|
||||||
throw RuntimeException("Invalid set assignment.")
|
throw RuntimeException("Invalid set assignment.")
|
||||||
}
|
}
|
||||||
node.value.visit(this)
|
node.value.visit(this)
|
||||||
emit(Opcode.StoreLocal, listOf(stubVarOrCall.stubVar.index))
|
code.emit(Opcode.StoreLocal, listOf(stubVarOrCall.stubVar.index))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitStringLiteral(node: StringLiteral) {
|
override fun visitStringLiteral(node: StringLiteral) {
|
||||||
val bytes = node.text.toByteArray()
|
val bytes = node.text.toByteArray()
|
||||||
val constant = compiler.constantPool.assign(bytes)
|
val constant = compiler.constantPool.assign(bytes)
|
||||||
emit(Opcode.Constant, listOf(constant))
|
code.emit(Opcode.Constant, listOf(constant))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitSuffixOperation(node: SuffixOperation) {
|
override fun visitSuffixOperation(node: SuffixOperation) {
|
||||||
val stubVarOrCall = resolveSymbol(node.reference.symbol)
|
val stubVarOrCall = code.localState.resolve(node.reference.symbol)
|
||||||
if (stubVarOrCall.stubVar == null) {
|
if (stubVarOrCall.stubVar == null) {
|
||||||
throw RuntimeException("Invalid suffix operation.")
|
throw RuntimeException("Invalid suffix operation.")
|
||||||
}
|
}
|
||||||
load(stubVarOrCall)
|
load(stubVarOrCall)
|
||||||
when (node.op) {
|
when (node.op) {
|
||||||
SuffixOperator.Increment -> {
|
SuffixOperator.Increment -> {
|
||||||
emit(Opcode.Integer, listOf(1u))
|
code.emit(Opcode.Integer, listOf(1u))
|
||||||
emit(Opcode.Add, emptyList())
|
code.emit(Opcode.Add, emptyList())
|
||||||
emit(Opcode.StoreLocal, listOf(stubVarOrCall.stubVar.index))
|
code.emit(Opcode.StoreLocal, listOf(stubVarOrCall.stubVar.index))
|
||||||
}
|
}
|
||||||
SuffixOperator.Decrement -> {
|
SuffixOperator.Decrement -> {
|
||||||
emit(Opcode.Integer, listOf(1u))
|
code.emit(Opcode.Integer, listOf(1u))
|
||||||
emit(Opcode.Subtract, emptyList())
|
code.emit(Opcode.Subtract, emptyList())
|
||||||
emit(Opcode.StoreLocal, listOf(stubVarOrCall.stubVar.index))
|
code.emit(Opcode.StoreLocal, listOf(stubVarOrCall.stubVar.index))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitSymbolReference(node: SymbolReference) {
|
override fun visitSymbolReference(node: SymbolReference) {
|
||||||
val variable = resolveSymbol(node.symbol)
|
val variable = code.localState.resolve(node.symbol)
|
||||||
load(variable)
|
load(variable)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitVarAssignment(node: VarAssignment) {
|
override fun visitVarAssignment(node: VarAssignment) {
|
||||||
val variable = allocateLocalVariable(node.symbol)
|
val variable = code.localState.createLocal(node.symbol)
|
||||||
node.value.visit(this)
|
node.value.visit(this)
|
||||||
emit(Opcode.StoreLocal, listOf(variable.index))
|
code.emit(Opcode.StoreLocal, listOf(variable.index))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitWhile(node: While) {
|
override fun visitWhile(node: While) {
|
||||||
val startOfBody = MutableRel(0u)
|
val startOfBody = MutableRel(0u)
|
||||||
|
val startOfLoop = MutableRel(0u)
|
||||||
val endOfLoop = MutableRel(0u)
|
val endOfLoop = MutableRel(0u)
|
||||||
val currentLoopState = LoopState(
|
code.localState.startLoop(code.nextOpInst(), endOfLoop)
|
||||||
startOfLoop = ops.size.toUInt(),
|
startOfLoop.rel = code.nextOpInst()
|
||||||
exitJumpTarget = endOfLoop,
|
|
||||||
body = startOfBody,
|
|
||||||
scopeDepth = (loopState?.scopeDepth ?: 0) + 1,
|
|
||||||
enclosing = loopState
|
|
||||||
)
|
|
||||||
loopState = currentLoopState
|
|
||||||
node.condition.visit(this)
|
node.condition.visit(this)
|
||||||
patch(Opcode.JumpIf, listOf(0u), 0, symbol, startOfBody)
|
code.patch(Opcode.JumpIf, listOf(0u), 0, symbol, startOfBody)
|
||||||
patch(Opcode.Jump, listOf(0u), 0, symbol, endOfLoop)
|
code.patch(Opcode.Jump, listOf(0u), 0, symbol, endOfLoop)
|
||||||
startOfBody.rel = ops.size.toUInt()
|
startOfBody.rel = code.nextOpInst()
|
||||||
node.block.visit(this)
|
node.block.visit(this)
|
||||||
patch(Opcode.Jump, listOf(0u), 0, symbol, currentLoopState.startOfLoop)
|
code.patch(Opcode.Jump, listOf(0u), 0, symbol, startOfLoop)
|
||||||
endOfLoop.rel = ops.size.toUInt()
|
endOfLoop.rel = code.nextOpInst()
|
||||||
|
code.localState.endLoop()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitNativeFunctionDescriptor(node: NativeFunctionDescriptor) {
|
override fun visitNativeFunctionDescriptor(node: NativeFunctionDescriptor) {
|
||||||
for (def in node.definitions) {
|
for (def in node.definitions) {
|
||||||
val defConstant = compiler.constantPool.assign(def.text.toByteArray())
|
val defConstant = compiler.constantPool.assign(def.text.toByteArray())
|
||||||
emit(Opcode.Constant, listOf(defConstant))
|
code.emit(Opcode.Constant, listOf(defConstant))
|
||||||
}
|
}
|
||||||
val formConstant = compiler.constantPool.assign(node.form.id.toByteArray())
|
val formConstant = compiler.constantPool.assign(node.form.id.toByteArray())
|
||||||
emit(Opcode.Native, listOf(formConstant, node.definitions.size.toUInt()))
|
code.emit(Opcode.Native, listOf(formConstant, node.definitions.size.toUInt()))
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun emit(code: Opcode) {
|
private fun load(callOrStubVar: Loadable) {
|
||||||
emit(code, emptyList())
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun emit(code: Opcode, arguments: List<UInt>) {
|
|
||||||
ops.add(StaticOp(Op(code, arguments)))
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun patch(code: Opcode, arguments: List<UInt>, index: Int, symbol: CompilableSymbol, rel: MutableRel) {
|
|
||||||
ops.add(PatchRelOp(Op(code, arguments), index, symbol, rel))
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun patch(code: Opcode, arguments: List<UInt>, index: Int, symbol: CompilableSymbol, rel: UInt) {
|
|
||||||
ops.add(PatchRelOp(Op(code, arguments), index, symbol, MutableRel(rel)))
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun patch(code: Opcode, arguments: List<UInt>, patches: Map<Int, CompilableSymbol>) {
|
|
||||||
ops.add(PatchSymOp(Op(code, arguments), patches))
|
|
||||||
}
|
|
||||||
|
|
||||||
fun ops(): List<StubOp> = ops
|
|
||||||
|
|
||||||
private fun load(callOrStubVar: CallOrStubVar) {
|
|
||||||
if (callOrStubVar.stubVar != null) {
|
if (callOrStubVar.stubVar != null) {
|
||||||
emit(Opcode.LoadLocal, listOf(callOrStubVar.stubVar.index))
|
code.emit(Opcode.LoadLocal, listOf(callOrStubVar.stubVar.index))
|
||||||
} else {
|
} else {
|
||||||
emit(Opcode.Integer, listOf(ops.size.toUInt() + 2u))
|
code.emit(Opcode.Integer, listOf(code.nextOpInst() + 2u))
|
||||||
patch(Opcode.Call, listOf(0u), mapOf(0 to callOrStubVar.call!!))
|
code.patch(Opcode.Call, listOf(0u), mapOf(0 to callOrStubVar.call!!))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class CallOrStubVar(
|
|
||||||
val call: CompilableSymbol? = null,
|
|
||||||
val stubVar: StubVar? = null
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,7 @@ class CompileCommand : CliktCommand(help = "Compile Pork to Bytecode", name = "c
|
|||||||
val compiler = Compiler()
|
val compiler = Compiler()
|
||||||
val slab = world.load(tool.rootImportLocator)
|
val slab = world.load(tool.rootImportLocator)
|
||||||
val compiledSlab = compiler.compilableSlabs.of(slab)
|
val compiledSlab = compiler.compilableSlabs.of(slab)
|
||||||
val compiledMain = compiledSlab.compilableSymbolOf(Symbol("main"))
|
val compiledMain = compiledSlab.resolve(Symbol("main"))
|
||||||
?: throw RuntimeException("'main' function not found.")
|
?: throw RuntimeException("'main' function not found.")
|
||||||
val compiledWorld = compiler.compile(compiledMain)
|
val compiledWorld = compiler.compile(compiledMain)
|
||||||
for (symbol in compiledWorld.symbolTable.symbols) {
|
for (symbol in compiledWorld.symbolTable.symbols) {
|
||||||
|
@ -12,7 +12,7 @@ class VirtualMachineProvider(val world: World) : ExecutionContextProvider {
|
|||||||
val compiler = Compiler()
|
val compiler = Compiler()
|
||||||
val slab = world.load(importLocator)
|
val slab = world.load(importLocator)
|
||||||
val compilableSlab = compiler.compilableSlabs.of(slab)
|
val compilableSlab = compiler.compilableSlabs.of(slab)
|
||||||
val compilableSymbol = compilableSlab.compilableSymbolOf(entryPointSymbol) ?:
|
val compilableSymbol = compilableSlab.resolve(entryPointSymbol) ?:
|
||||||
throw RuntimeException("Unable to find compilable symbol for entry point '${entryPointSymbol.id}'")
|
throw RuntimeException("Unable to find compilable symbol for entry point '${entryPointSymbol.id}'")
|
||||||
val compiledWorld = compiler.compile(compilableSymbol)
|
val compiledWorld = compiler.compile(compilableSymbol)
|
||||||
return VirtualMachine(compiledWorld)
|
return VirtualMachine(compiledWorld)
|
||||||
|
Loading…
Reference in New Issue
Block a user