diff --git a/bir/build.gradle.kts b/bir/build.gradle.kts new file mode 100644 index 0000000..55f1ba8 --- /dev/null +++ b/bir/build.gradle.kts @@ -0,0 +1,7 @@ +plugins { + id("gay.pizza.pork.module") +} + +dependencies { + implementation(project(":common")) +} diff --git a/bir/src/main/kotlin/gay/pizza/pork/bir/IrAccess.kt b/bir/src/main/kotlin/gay/pizza/pork/bir/IrAccess.kt new file mode 100644 index 0000000..9787b4b --- /dev/null +++ b/bir/src/main/kotlin/gay/pizza/pork/bir/IrAccess.kt @@ -0,0 +1,7 @@ +package gay.pizza.pork.bir + +data class IrAccess(val target: IrSymbol) : IrCodeElement { + override fun crawl(block: (IrElement) -> Unit) { + block(target) + } +} diff --git a/bir/src/main/kotlin/gay/pizza/pork/bir/IrBreak.kt b/bir/src/main/kotlin/gay/pizza/pork/bir/IrBreak.kt new file mode 100644 index 0000000..9838e9f --- /dev/null +++ b/bir/src/main/kotlin/gay/pizza/pork/bir/IrBreak.kt @@ -0,0 +1,7 @@ +package gay.pizza.pork.bir + +data class IrBreak(val target: IrSymbol) : IrCodeElement { + override fun crawl(block: (IrElement) -> Unit) { + block(target) + } +} diff --git a/bir/src/main/kotlin/gay/pizza/pork/bir/IrCall.kt b/bir/src/main/kotlin/gay/pizza/pork/bir/IrCall.kt new file mode 100644 index 0000000..8f3b23b --- /dev/null +++ b/bir/src/main/kotlin/gay/pizza/pork/bir/IrCall.kt @@ -0,0 +1,13 @@ +package gay.pizza.pork.bir + +data class IrCall( + val target: IrSymbol, + val arguments: List, + val variableArguments: List? +) : IrCodeElement { + override fun crawl(block: (IrElement) -> Unit) { + block(target) + arguments.forEach(block) + variableArguments?.forEach(block) + } +} diff --git a/bir/src/main/kotlin/gay/pizza/pork/bir/IrCodeBlock.kt b/bir/src/main/kotlin/gay/pizza/pork/bir/IrCodeBlock.kt new file mode 100644 index 0000000..6d98c25 --- /dev/null +++ b/bir/src/main/kotlin/gay/pizza/pork/bir/IrCodeBlock.kt @@ -0,0 +1,3 @@ +package gay.pizza.pork.bir + +data class IrCodeBlock(val items: List) : IrCodeElement diff --git a/bir/src/main/kotlin/gay/pizza/pork/bir/IrCodeElement.kt b/bir/src/main/kotlin/gay/pizza/pork/bir/IrCodeElement.kt new file mode 100644 index 0000000..3bdbef6 --- /dev/null +++ b/bir/src/main/kotlin/gay/pizza/pork/bir/IrCodeElement.kt @@ -0,0 +1,3 @@ +package gay.pizza.pork.bir + +sealed interface IrCodeElement : IrElement diff --git a/bir/src/main/kotlin/gay/pizza/pork/bir/IrConditional.kt b/bir/src/main/kotlin/gay/pizza/pork/bir/IrConditional.kt new file mode 100644 index 0000000..c81a816 --- /dev/null +++ b/bir/src/main/kotlin/gay/pizza/pork/bir/IrConditional.kt @@ -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) + } +} diff --git a/bir/src/main/kotlin/gay/pizza/pork/bir/IrConstant.kt b/bir/src/main/kotlin/gay/pizza/pork/bir/IrConstant.kt new file mode 100644 index 0000000..8ff6211 --- /dev/null +++ b/bir/src/main/kotlin/gay/pizza/pork/bir/IrConstant.kt @@ -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 diff --git a/bir/src/main/kotlin/gay/pizza/pork/bir/IrContinue.kt b/bir/src/main/kotlin/gay/pizza/pork/bir/IrContinue.kt new file mode 100644 index 0000000..f9fdd6a --- /dev/null +++ b/bir/src/main/kotlin/gay/pizza/pork/bir/IrContinue.kt @@ -0,0 +1,7 @@ +package gay.pizza.pork.bir + +data class IrContinue(val target: IrSymbol) : IrCodeElement { + override fun crawl(block: (IrElement) -> Unit) { + block(target) + } +} diff --git a/bir/src/main/kotlin/gay/pizza/pork/bir/IrDefinition.kt b/bir/src/main/kotlin/gay/pizza/pork/bir/IrDefinition.kt new file mode 100644 index 0000000..d6d62bb --- /dev/null +++ b/bir/src/main/kotlin/gay/pizza/pork/bir/IrDefinition.kt @@ -0,0 +1,12 @@ +package gay.pizza.pork.bir + +data class IrDefinition( + val symbol: IrSymbol, + val type: IrDefinitionType, + val code: IrCodeBlock +) : IrElement { + override fun crawl(block: (IrElement) -> Unit) { + block(symbol) + block(code) + } +} diff --git a/bir/src/main/kotlin/gay/pizza/pork/bir/IrDefinitionType.kt b/bir/src/main/kotlin/gay/pizza/pork/bir/IrDefinitionType.kt new file mode 100644 index 0000000..46acaf7 --- /dev/null +++ b/bir/src/main/kotlin/gay/pizza/pork/bir/IrDefinitionType.kt @@ -0,0 +1,6 @@ +package gay.pizza.pork.bir + +enum class IrDefinitionType { + Variable, + Function +} diff --git a/bir/src/main/kotlin/gay/pizza/pork/bir/IrElement.kt b/bir/src/main/kotlin/gay/pizza/pork/bir/IrElement.kt new file mode 100644 index 0000000..349a42a --- /dev/null +++ b/bir/src/main/kotlin/gay/pizza/pork/bir/IrElement.kt @@ -0,0 +1,5 @@ +package gay.pizza.pork.bir + +sealed interface IrElement { + fun crawl(block: (IrElement) -> Unit) +} diff --git a/bir/src/main/kotlin/gay/pizza/pork/bir/IrInfix.kt b/bir/src/main/kotlin/gay/pizza/pork/bir/IrInfix.kt new file mode 100644 index 0000000..91449a1 --- /dev/null +++ b/bir/src/main/kotlin/gay/pizza/pork/bir/IrInfix.kt @@ -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) + } +} diff --git a/bir/src/main/kotlin/gay/pizza/pork/bir/IrInfixOp.kt b/bir/src/main/kotlin/gay/pizza/pork/bir/IrInfixOp.kt new file mode 100644 index 0000000..e57a45e --- /dev/null +++ b/bir/src/main/kotlin/gay/pizza/pork/bir/IrInfixOp.kt @@ -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 +} diff --git a/bir/src/main/kotlin/gay/pizza/pork/bir/IrList.kt b/bir/src/main/kotlin/gay/pizza/pork/bir/IrList.kt new file mode 100644 index 0000000..8780a9d --- /dev/null +++ b/bir/src/main/kotlin/gay/pizza/pork/bir/IrList.kt @@ -0,0 +1,7 @@ +package gay.pizza.pork.bir + +data class IrList(val items: List) : IrCodeElement { + override fun crawl(block: (IrElement) -> Unit) { + items.forEach(block) + } +} diff --git a/bir/src/main/kotlin/gay/pizza/pork/bir/IrLoad.kt b/bir/src/main/kotlin/gay/pizza/pork/bir/IrLoad.kt new file mode 100644 index 0000000..59361a6 --- /dev/null +++ b/bir/src/main/kotlin/gay/pizza/pork/bir/IrLoad.kt @@ -0,0 +1,7 @@ +package gay.pizza.pork.bir + +data class IrLoad(val symbol: IrSymbol) : IrCodeElement { + override fun crawl(block: (IrElement) -> Unit) { + block(symbol) + } +} diff --git a/bir/src/main/kotlin/gay/pizza/pork/bir/IrLoop.kt b/bir/src/main/kotlin/gay/pizza/pork/bir/IrLoop.kt new file mode 100644 index 0000000..8d43193 --- /dev/null +++ b/bir/src/main/kotlin/gay/pizza/pork/bir/IrLoop.kt @@ -0,0 +1,9 @@ +package gay.pizza.pork.bir + +data class IrLoop(val symbol: IrSymbol, val condition: IrCodeElement, val inner: IrCodeElement) : IrCodeElement { + override fun crawl(block: (IrElement) -> Unit) { + block(symbol) + block(condition) + block(inner) + } +} diff --git a/bir/src/main/kotlin/gay/pizza/pork/bir/IrPrefix.kt b/bir/src/main/kotlin/gay/pizza/pork/bir/IrPrefix.kt new file mode 100644 index 0000000..c28e226 --- /dev/null +++ b/bir/src/main/kotlin/gay/pizza/pork/bir/IrPrefix.kt @@ -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) + } +} diff --git a/bir/src/main/kotlin/gay/pizza/pork/bir/IrPrefixOp.kt b/bir/src/main/kotlin/gay/pizza/pork/bir/IrPrefixOp.kt new file mode 100644 index 0000000..0b7052b --- /dev/null +++ b/bir/src/main/kotlin/gay/pizza/pork/bir/IrPrefixOp.kt @@ -0,0 +1,8 @@ +package gay.pizza.pork.bir + +enum class IrPrefixOp { + BooleanNot, + UnaryPlus, + UnaryMinus, + BinaryNot +} diff --git a/bir/src/main/kotlin/gay/pizza/pork/bir/IrReturn.kt b/bir/src/main/kotlin/gay/pizza/pork/bir/IrReturn.kt new file mode 100644 index 0000000..dacee0b --- /dev/null +++ b/bir/src/main/kotlin/gay/pizza/pork/bir/IrReturn.kt @@ -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) + } +} diff --git a/bir/src/main/kotlin/gay/pizza/pork/bir/IrSlab.kt b/bir/src/main/kotlin/gay/pizza/pork/bir/IrSlab.kt new file mode 100644 index 0000000..c1f4463 --- /dev/null +++ b/bir/src/main/kotlin/gay/pizza/pork/bir/IrSlab.kt @@ -0,0 +1,11 @@ +package gay.pizza.pork.bir + +data class IrSlab( + val location: IrSlabLocation, + val definitions: List +) : IrElement { + override fun crawl(block: (IrElement) -> Unit) { + block(location) + definitions.forEach(block) + } +} diff --git a/bir/src/main/kotlin/gay/pizza/pork/bir/IrSlabLocation.kt b/bir/src/main/kotlin/gay/pizza/pork/bir/IrSlabLocation.kt new file mode 100644 index 0000000..729989f --- /dev/null +++ b/bir/src/main/kotlin/gay/pizza/pork/bir/IrSlabLocation.kt @@ -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) {} +} diff --git a/bir/src/main/kotlin/gay/pizza/pork/bir/IrStore.kt b/bir/src/main/kotlin/gay/pizza/pork/bir/IrStore.kt new file mode 100644 index 0000000..acc7f9f --- /dev/null +++ b/bir/src/main/kotlin/gay/pizza/pork/bir/IrStore.kt @@ -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) + } +} diff --git a/bir/src/main/kotlin/gay/pizza/pork/bir/IrSymbol.kt b/bir/src/main/kotlin/gay/pizza/pork/bir/IrSymbol.kt new file mode 100644 index 0000000..f473d5e --- /dev/null +++ b/bir/src/main/kotlin/gay/pizza/pork/bir/IrSymbol.kt @@ -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) {} +} diff --git a/bir/src/main/kotlin/gay/pizza/pork/bir/IrSymbolAssignment.kt b/bir/src/main/kotlin/gay/pizza/pork/bir/IrSymbolAssignment.kt new file mode 100644 index 0000000..8f3b63a --- /dev/null +++ b/bir/src/main/kotlin/gay/pizza/pork/bir/IrSymbolAssignment.kt @@ -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) +} diff --git a/bir/src/main/kotlin/gay/pizza/pork/bir/IrSymbolTag.kt b/bir/src/main/kotlin/gay/pizza/pork/bir/IrSymbolTag.kt new file mode 100644 index 0000000..565feb1 --- /dev/null +++ b/bir/src/main/kotlin/gay/pizza/pork/bir/IrSymbolTag.kt @@ -0,0 +1,8 @@ +package gay.pizza.pork.bir + +enum class IrSymbolTag { + Function, + Variable, + Local, + Loop +} diff --git a/compiler/build.gradle.kts b/compiler/build.gradle.kts index fbb65c8..e93d6ea 100644 --- a/compiler/build.gradle.kts +++ b/compiler/build.gradle.kts @@ -4,6 +4,7 @@ plugins { dependencies { api(project(":ast")) + api(project(":bir")) api(project(":bytecode")) api(project(":parser")) api(project(":frontend")) diff --git a/compiler/src/main/kotlin/gay/pizza/pork/compiler/CompileError.kt b/compiler/src/main/kotlin/gay/pizza/pork/compiler/CompileError.kt new file mode 100644 index 0000000..2ceb2a7 --- /dev/null +++ b/compiler/src/main/kotlin/gay/pizza/pork/compiler/CompileError.kt @@ -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) diff --git a/compiler/src/main/kotlin/gay/pizza/pork/compiler/IrCodeEmitter.kt b/compiler/src/main/kotlin/gay/pizza/pork/compiler/IrCodeEmitter.kt new file mode 100644 index 0000000..1bc88ea --- /dev/null +++ b/compiler/src/main/kotlin/gay/pizza/pork/compiler/IrCodeEmitter.kt @@ -0,0 +1,258 @@ +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() { + private val loopSymbols = mutableListOf() + private val localVariables = mutableListOf>() + + private fun startLoop(): IrSymbol { + val symbol = irSymbolAssignment.next(IrSymbolTag.Loop) + loopSymbols.add(symbol) + return symbol + } + + private fun endLoop() { + loopSymbols.removeLast() + } + + private fun loop(block: (IrSymbol) -> T): T { + val symbol = startLoop() + return try { + block(symbol) + } finally { + endLoop() + } + } + + private fun enterBlockScope() { + val locals = mutableListOf() + 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? { + 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() + var variableArguments: List? = 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 { + TODO("Not yet implemented") + } + + 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) + ) + } +} diff --git a/compiler/src/main/kotlin/gay/pizza/pork/compiler/IrSymbolWorld.kt b/compiler/src/main/kotlin/gay/pizza/pork/compiler/IrSymbolWorld.kt new file mode 100644 index 0000000..5e5170a --- /dev/null +++ b/compiler/src/main/kotlin/gay/pizza/pork/compiler/IrSymbolWorld.kt @@ -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() + + fun lookup(value: Any, tag: IrSymbolTag): IrSymbol = symbols.getOrPut(value) { + irSymbolAssignment.next(tag) + } +} diff --git a/compiler/src/main/kotlin/gay/pizza/pork/compiler/LocalVariable.kt b/compiler/src/main/kotlin/gay/pizza/pork/compiler/LocalVariable.kt new file mode 100644 index 0000000..c0b92cd --- /dev/null +++ b/compiler/src/main/kotlin/gay/pizza/pork/compiler/LocalVariable.kt @@ -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) diff --git a/frontend/src/main/kotlin/gay/pizza/pork/frontend/scope/ScopeSymbol.kt b/frontend/src/main/kotlin/gay/pizza/pork/frontend/scope/ScopeSymbol.kt index c386069..049c194 100644 --- a/frontend/src/main/kotlin/gay/pizza/pork/frontend/scope/ScopeSymbol.kt +++ b/frontend/src/main/kotlin/gay/pizza/pork/frontend/scope/ScopeSymbol.kt @@ -6,4 +6,16 @@ import gay.pizza.pork.ast.gen.Symbol class ScopeSymbol(val slabScope: SlabScope, val definition: Definition) { val symbol: Symbol = definition.symbol 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 + } } diff --git a/frontend/src/main/kotlin/gay/pizza/pork/frontend/scope/SymbolType.kt b/frontend/src/main/kotlin/gay/pizza/pork/frontend/scope/SymbolType.kt new file mode 100644 index 0000000..3fd4267 --- /dev/null +++ b/frontend/src/main/kotlin/gay/pizza/pork/frontend/scope/SymbolType.kt @@ -0,0 +1,6 @@ +package gay.pizza.pork.frontend.scope + +enum class SymbolType { + Variable, + Function +} diff --git a/settings.gradle.kts b/settings.gradle.kts index d9ccc87..8d07785 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -6,6 +6,7 @@ include( ":common", ":tokenizer", ":ast", + ":bir", ":bytecode", ":parser", ":frontend", diff --git a/tool/src/main/kotlin/gay/pizza/pork/tool/CompileCommand.kt b/tool/src/main/kotlin/gay/pizza/pork/tool/CompileCommand.kt index 4b4cf5f..ac46313 100644 --- a/tool/src/main/kotlin/gay/pizza/pork/tool/CompileCommand.kt +++ b/tool/src/main/kotlin/gay/pizza/pork/tool/CompileCommand.kt @@ -3,8 +3,14 @@ package gay.pizza.pork.tool import com.github.ajalt.clikt.core.CliktCommand import com.github.ajalt.clikt.parameters.arguments.argument import gay.pizza.dough.fs.PlatformFsProvider +import gay.pizza.pork.ast.gen.FunctionDefinition 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.IrCodeEmitter +import gay.pizza.pork.compiler.IrSymbolWorld import gay.pizza.pork.minimal.FileTool class CompileCommand : CliktCommand(help = "Compile Pork to Bytecode", name = "compile") { @@ -31,5 +37,12 @@ class CompileCommand : CliktCommand(help = "Compile Pork to Bytecode", name = "c 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) } }