mirror of
https://github.com/irmen/prog8.git
synced 2025-01-12 04:30:03 +00:00
better return types
This commit is contained in:
parent
f891fc698c
commit
4f7465ba44
@ -100,12 +100,13 @@ fun compileProgram(filepath: Path,
|
||||
// printAst(programAst)
|
||||
|
||||
if(writeAssembly) {
|
||||
val (success, message) = writeAssembly(programAst, errors, outputDir, compilationOptions)
|
||||
if(success)
|
||||
programName = message
|
||||
else {
|
||||
System.err.println(message)
|
||||
return CompilationResult(false, programAst, programName, compTarget, importedFiles)
|
||||
val result = writeAssembly(programAst, errors, outputDir, compilationOptions)
|
||||
when(result) {
|
||||
is WriteAssemblyResult.Ok -> programName = result.filename
|
||||
is WriteAssemblyResult.Fail -> {
|
||||
System.err.println(result.error)
|
||||
return CompilationResult(false, programAst, programName, compTarget, importedFiles)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -319,10 +320,15 @@ private fun postprocessAst(programAst: Program, errors: IErrorReporter, compiler
|
||||
programAst.moveMainAndStartToFirst()
|
||||
}
|
||||
|
||||
private sealed class WriteAssemblyResult {
|
||||
class Ok(val filename: String): WriteAssemblyResult()
|
||||
class Fail(val error: String): WriteAssemblyResult()
|
||||
}
|
||||
|
||||
private fun writeAssembly(programAst: Program,
|
||||
errors: IErrorReporter,
|
||||
outputDir: Path,
|
||||
compilerOptions: CompilationOptions): Pair<Boolean, String> {
|
||||
compilerOptions: CompilationOptions): WriteAssemblyResult {
|
||||
// asm generation directly from the Ast
|
||||
programAst.processAstBeforeAsmGeneration(errors, compilerOptions.compTarget)
|
||||
errors.report()
|
||||
@ -340,14 +346,14 @@ private fun writeAssembly(programAst: Program,
|
||||
return if(assembly.valid && errors.noErrors()) {
|
||||
val assemblerReturnStatus = assembly.assemble(compilerOptions)
|
||||
if(assemblerReturnStatus!=0)
|
||||
Pair(false, "assembler step failed with return code $assemblerReturnStatus")
|
||||
WriteAssemblyResult.Fail("assembler step failed with return code $assemblerReturnStatus")
|
||||
else {
|
||||
errors.report()
|
||||
Pair(true, assembly.name)
|
||||
WriteAssemblyResult.Ok(assembly.name)
|
||||
}
|
||||
} else {
|
||||
errors.report()
|
||||
Pair(false, "compiler failed with errors")
|
||||
WriteAssemblyResult.Fail("compiler failed with errors")
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -30,9 +30,8 @@ internal class FunctionCallAsmGen(private val program: Program, private val asmg
|
||||
val sub = stmt.target.targetSubroutine(program) ?: throw AssemblyError("undefined subroutine ${stmt.target}")
|
||||
if(sub.shouldSaveX()) {
|
||||
val regSaveOnStack = sub.asmAddress==null // rom-routines don't require registers to be saved on stack, normal subroutines do because they can contain nested calls
|
||||
val (keepAonEntry: Boolean, keepAonReturn: Boolean) = sub.shouldKeepA()
|
||||
if(regSaveOnStack)
|
||||
asmgen.saveRegisterStack(CpuRegister.X, keepAonEntry)
|
||||
asmgen.saveRegisterStack(CpuRegister.X, sub.shouldKeepA().saveOnEntry)
|
||||
else
|
||||
asmgen.saveRegisterLocal(CpuRegister.X, (stmt as Node).definingSubroutine!!)
|
||||
}
|
||||
@ -42,10 +41,8 @@ internal class FunctionCallAsmGen(private val program: Program, private val asmg
|
||||
val sub = stmt.target.targetSubroutine(program) ?: throw AssemblyError("undefined subroutine ${stmt.target}")
|
||||
if(sub.shouldSaveX()) {
|
||||
val regSaveOnStack = sub.asmAddress==null // rom-routines don't require registers to be saved on stack, normal subroutines do because they can contain nested calls
|
||||
val (keepAonEntry: Boolean, keepAonReturn: Boolean) = sub.shouldKeepA()
|
||||
|
||||
if(regSaveOnStack)
|
||||
asmgen.restoreRegisterStack(CpuRegister.X, keepAonReturn)
|
||||
asmgen.restoreRegisterStack(CpuRegister.X, sub.shouldKeepA().saveOnReturn)
|
||||
else
|
||||
asmgen.restoreRegisterLocal(CpuRegister.X)
|
||||
}
|
||||
|
15
compilerAst/src/prog8/Either.kt
Normal file
15
compilerAst/src/prog8/Either.kt
Normal file
@ -0,0 +1,15 @@
|
||||
package prog8
|
||||
|
||||
sealed class Either<out L, out R> {
|
||||
|
||||
data class Left<out L>(val value: L) : Either<L, Nothing>()
|
||||
|
||||
data class Right<out R>(val value: R) : Either<Nothing, R>()
|
||||
|
||||
fun isRight() = this is Right<R>
|
||||
|
||||
fun isLeft() = this is Left<L>
|
||||
}
|
||||
|
||||
fun <L> left(a: L) = Either.Left(a)
|
||||
fun <R> right(b: R) = Either.Right(b)
|
@ -651,15 +651,18 @@ class Subroutine(override val name: String,
|
||||
fun regXasResult() = asmReturnvaluesRegisters.any { it.registerOrPair in setOf(RegisterOrPair.X, RegisterOrPair.AX, RegisterOrPair.XY) }
|
||||
fun regXasParam() = asmParameterRegisters.any { it.registerOrPair in setOf(RegisterOrPair.X, RegisterOrPair.AX, RegisterOrPair.XY) }
|
||||
fun shouldSaveX() = CpuRegister.X in asmClobbers || regXasResult() || regXasParam()
|
||||
fun shouldKeepA(): Pair<Boolean, Boolean> {
|
||||
|
||||
class KeepAresult(val saveOnEntry: Boolean, val saveOnReturn: Boolean)
|
||||
|
||||
fun shouldKeepA(): KeepAresult {
|
||||
// determine if A's value should be kept when preparing for calling the subroutine, and when returning from it
|
||||
if(!isAsmSubroutine)
|
||||
return Pair(false, false)
|
||||
return KeepAresult(saveOnEntry = false, saveOnReturn = false)
|
||||
|
||||
// it seems that we never have to save A when calling? will be loaded correctly after setup.
|
||||
// but on return it depends on wether the routine returns something in A.
|
||||
val saveAonReturn = asmReturnvaluesRegisters.any { it.registerOrPair==RegisterOrPair.A || it.registerOrPair==RegisterOrPair.AY || it.registerOrPair==RegisterOrPair.AX }
|
||||
return Pair(false, saveAonReturn)
|
||||
return KeepAresult(false, saveAonReturn)
|
||||
}
|
||||
|
||||
fun amountOfRtsInAsm(): Int = statements
|
||||
|
Loading…
x
Reference in New Issue
Block a user