diff --git a/bir/src/main/kotlin/gay/pizza/pork/bir/IrNop.kt b/bir/src/main/kotlin/gay/pizza/pork/bir/IrNop.kt new file mode 100644 index 0000000..2ba2bf2 --- /dev/null +++ b/bir/src/main/kotlin/gay/pizza/pork/bir/IrNop.kt @@ -0,0 +1,5 @@ +package gay.pizza.pork.bir + +object IrNop : IrCodeElement() { + override fun crawl(block: (IrElement) -> Unit) {} +} diff --git a/bir/src/main/kotlin/gay/pizza/pork/bir/IrVisitor.kt b/bir/src/main/kotlin/gay/pizza/pork/bir/IrVisitor.kt index cc630eb..84323b6 100644 --- a/bir/src/main/kotlin/gay/pizza/pork/bir/IrVisitor.kt +++ b/bir/src/main/kotlin/gay/pizza/pork/bir/IrVisitor.kt @@ -30,6 +30,7 @@ interface IrVisitor { 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 { is IrIndex -> visitIrIndex(ir) is IrListSize -> visitIrListSize(ir) is IrDeclare -> visitIrDeclare(ir) + IrNop -> visitIrNop(ir as IrNop) } } diff --git a/compiler/src/main/kotlin/gay/pizza/pork/compiler/AstIrEmitter.kt b/compiler/src/main/kotlin/gay/pizza/pork/compiler/AstIrEmitter.kt index 406ddca..bf24a07 100644 --- a/compiler/src/main/kotlin/gay/pizza/pork/compiler/AstIrEmitter.kt +++ b/compiler/src/main/kotlin/gay/pizza/pork/compiler/AstIrEmitter.kt @@ -20,10 +20,26 @@ class AstIrEmitter( fun createFunctionArguments(functionDefinition: FunctionDefinition) { val functionSymbols = mutableListOf() 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)) } diff --git a/compiler/src/main/kotlin/gay/pizza/pork/compiler/CompilableSymbol.kt b/compiler/src/main/kotlin/gay/pizza/pork/compiler/CompilableSymbol.kt index cc9f03c..ebc43c2 100644 --- a/compiler/src/main/kotlin/gay/pizza/pork/compiler/CompilableSymbol.kt +++ b/compiler/src/main/kotlin/gay/pizza/pork/compiler/CompilableSymbol.kt @@ -52,6 +52,7 @@ class CompilableSymbol(val compilableSlab: CompilableSlab, val scopeSymbol: Scop else -> { val letDefinition = scopeSymbol.definition as LetDefinition + irCodeEmitter.checkLetDefinition(letDefinition) letDefinition.value } } diff --git a/compiler/src/main/kotlin/gay/pizza/pork/compiler/IrStubOpEmitter.kt b/compiler/src/main/kotlin/gay/pizza/pork/compiler/IrStubOpEmitter.kt index 3faba0b..00d8ac4 100644 --- a/compiler/src/main/kotlin/gay/pizza/pork/compiler/IrStubOpEmitter.kt +++ b/compiler/src/main/kotlin/gay/pizza/pork/compiler/IrStubOpEmitter.kt @@ -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) diff --git a/examples/ack.pork b/examples/ack.pork new file mode 100644 index 0000000..c36de84 --- /dev/null +++ b/examples/ack.pork @@ -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) +} diff --git a/examples/ffi.pork b/examples/ffi.pork index 4bcc244..401c069 100644 --- a/examples/ffi.pork +++ b/examples/ffi.pork @@ -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*)" diff --git a/examples/fib.pork b/examples/fib.pork index af5a33d..3fd24e5 100644 --- a/examples/fib.pork +++ b/examples/fib.pork @@ -8,6 +8,6 @@ func fib(n: int32): int32 { } export func main() { - let result: int32 = fib(28) + let result: int32 = fib(31) println(result) } diff --git a/frontend/src/main/kotlin/gay/pizza/pork/frontend/scope/ExternalSymbolUsageAnalyzer.kt b/frontend/src/main/kotlin/gay/pizza/pork/frontend/scope/ExternalSymbolUsageAnalyzer.kt index 90e05cd..5f01bc5 100644 --- a/frontend/src/main/kotlin/gay/pizza/pork/frontend/scope/ExternalSymbolUsageAnalyzer.kt +++ b/frontend/src/main/kotlin/gay/pizza/pork/frontend/scope/ExternalSymbolUsageAnalyzer.kt @@ -11,6 +11,14 @@ class ExternalSymbolUsageAnalyzer : FunctionLevelVisitor() { 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() diff --git a/stdlib/src/main/pork/lang/prelude.pork b/stdlib/src/main/pork/lang/prelude.pork index a83496f..8909bed 100644 --- a/stdlib/src/main/pork/lang/prelude.pork +++ b/stdlib/src/main/pork/lang/prelude.pork @@ -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) 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 dac3de2..d50c235 100644 --- a/tool/src/main/kotlin/gay/pizza/pork/tool/CompileCommand.kt +++ b/tool/src/main/kotlin/gay/pizza/pork/tool/CompileCommand.kt @@ -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() + "\""