introduce ir nop to fix loop bugs

This commit is contained in:
Alex Zenla 2025-07-24 22:30:18 -07:00
parent 837e0c1b38
commit 69230deefc
No known key found for this signature in database
GPG Key ID: 067B238899B51269
11 changed files with 65 additions and 12 deletions

View File

@ -0,0 +1,5 @@
package gay.pizza.pork.bir
object IrNop : IrCodeElement() {
override fun crawl(block: (IrElement) -> Unit) {}
}

View File

@ -30,6 +30,7 @@ interface IrVisitor<T> {
fun visitIrIndex(ir: IrIndex): T
fun visitIrListSize(ir: IrListSize): T
fun visitIrDeclare(ir: IrDeclare): T
fun visitIrNop(ir: IrNop): T
fun visit(ir: IrElement): T = when (ir) {
is IrBreak -> visitIrBeak(ir)
@ -61,5 +62,6 @@ interface IrVisitor<T> {
is IrIndex -> visitIrIndex(ir)
is IrListSize -> visitIrListSize(ir)
is IrDeclare -> visitIrDeclare(ir)
IrNop -> visitIrNop(ir as IrNop)
}
}

View File

@ -20,10 +20,26 @@ class AstIrEmitter(
fun createFunctionArguments(functionDefinition: FunctionDefinition) {
val functionSymbols = mutableListOf<IrFunctionArgument>()
for (arg in functionDefinition.arguments) {
if (arg.typeSpec != null) {
validateTypeSpec(arg.typeSpec!!)
}
val symbol = createLocalVariable(arg.symbol)
functionSymbols.add(IrFunctionArgument(symbol))
}
functionArguments = functionSymbols
if (functionDefinition.returnType != null) {
validateTypeSpec(functionDefinition.returnType!!)
}
}
fun checkLetDefinition(letDefinition: LetDefinition) {
if (letDefinition.typeSpec != null) {
validateTypeSpec(letDefinition.typeSpec!!)
}
}
private fun validateTypeSpec(typeSpec: TypeSpec) {
lookup(typeSpec.symbol) ?: throw CompileError("Unresolved type: ${typeSpec.symbol.id}")
}
private fun startLoop(): IrSymbol {
@ -204,7 +220,7 @@ class AstIrEmitter(
IrConditional(
conditional = node.condition.visit(this),
ifTrue = node.thenBlock.visit(this),
ifFalse = node.elseBlock?.visit(this) ?: IrNoneConstant
ifFalse = node.elseBlock?.visit(this) ?: IrNop
)
override fun visitIndexedBy(node: IndexedBy): IrCodeElement = IrIndex(
@ -240,6 +256,9 @@ class AstIrEmitter(
IrIntegerConstant(node.value)
override fun visitLetAssignment(node: LetAssignment): IrCodeElement {
if (node.typeSpec != null) {
validateTypeSpec(node.typeSpec!!)
}
val symbol = createLocalVariable(node.symbol)
return IrDeclare(symbol, node.value.visit(this))
}
@ -295,6 +314,9 @@ class AstIrEmitter(
}
override fun visitVarAssignment(node: VarAssignment): IrCodeElement {
if (node.typeSpec != null) {
validateTypeSpec(node.typeSpec!!)
}
val local = createLocalVariable(node.symbol)
return IrDeclare(local, node.value.visit(this))
}

View File

@ -52,6 +52,7 @@ class CompilableSymbol(val compilableSlab: CompilableSlab, val scopeSymbol: Scop
else -> {
val letDefinition = scopeSymbol.definition as LetDefinition
irCodeEmitter.checkLetDefinition(letDefinition)
letDefinition.value
}
}

View File

@ -194,6 +194,8 @@ class IrStubOpEmitter(val irDefinition: IrDefinition, val code: CodeBuilder) : I
store(variable)
}
override fun visitIrNop(ir: IrNop) {}
override fun visitIrStore(ir: IrStore) {
visit(ir.value)
val variable = code.localState.createOrFindLocal(ir.target)

17
examples/ack.pork Normal file
View File

@ -0,0 +1,17 @@
/* ackermann function */
func ack(m: int32, n: int32): int32 {
if m == 0 {
return n + 1
}
if n == 0 {
return ack(m - 1, 1)
}
return ack(m - 1, ack(m, n - 1))
}
export func main() {
let result: int32 = ack(3, 1)
println(result)
}

View File

@ -1,14 +1,7 @@
import std ffi.struct
export let timeval = ffiStructDefine(
"long", "seconds",
"unsigned int", "microseconds"
)
export let timezone = ffiStructDefine(
"int", "minutes_greenwich",
"int", "dst_time"
)
export type timeval = native ffi "long" "seconds" "unsigned int" "microseconds"
export type timezone = native ffi "int" "minutes_greenwich" "int" "dst_time"
func gettimeofday(value, tz)
native ffi "c" "int gettimeofday(struct timeval*, struct timezone*)"

View File

@ -8,6 +8,6 @@ func fib(n: int32): int32 {
}
export func main() {
let result: int32 = fib(28)
let result: int32 = fib(31)
println(result)
}

View File

@ -11,6 +11,14 @@ class ExternalSymbolUsageAnalyzer : FunctionLevelVisitor<Unit>() {
get() = symbols
override fun visitFunctionDefinition(node: FunctionDefinition) {
for (argument in node.arguments) {
visit(argument.typeSpec!!)
}
if (node.returnType != null) {
visit(node.returnType!!)
}
internalSymbols.add(node.arguments.map { it.symbol }.toMutableSet())
node.block?.visit(this)
internalSymbols.removeLast()

View File

@ -1,7 +1,10 @@
export type int32 = native internal "int32"
export type int64 = native internal "int64"
export type float32 = native internal "float32"
export type float64 = native internal "float64"
export type string = native internal "string"
export type list = native internal "list"
export type bool = native internal "bool"
export type any = native internal "any"
export func print(values...: string)

View File

@ -69,7 +69,7 @@ class CompileCommand : CliktCommand("compile") {
annotation = " ; ${annotations.joinToString(", ") { it.text }}"
}
print(" ${symbol.offset + index.toUInt()} ${op}${annotation}")
if (op.code == Opcode.Constant || op.code == Opcode.NativeFunction) {
if (op.code == Opcode.Constant || op.code == Opcode.NativeFunction || op.code == Opcode.NativeType) {
val constant = compiledWorld.constantPool.constants[op.args[0].toInt()]
val constantString = when (constant.tag) {
ConstantTag.String -> "string = \"" + constant.readAsString() + "\""