From 4f7465ba44303c2c08667b3e0f44fafac4786b71 Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Tue, 12 Oct 2021 21:59:19 +0200 Subject: [PATCH] better return types --- compiler/src/prog8/compiler/Compiler.kt | 26 ++++++++++++------- .../cpu6502/codegen/FunctionCallAsmGen.kt | 7 ++--- compilerAst/src/prog8/Either.kt | 15 +++++++++++ .../src/prog8/ast/statements/AstStatements.kt | 9 ++++--- 4 files changed, 39 insertions(+), 18 deletions(-) create mode 100644 compilerAst/src/prog8/Either.kt diff --git a/compiler/src/prog8/compiler/Compiler.kt b/compiler/src/prog8/compiler/Compiler.kt index c9237ec73..5015f9fc2 100644 --- a/compiler/src/prog8/compiler/Compiler.kt +++ b/compiler/src/prog8/compiler/Compiler.kt @@ -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 { + 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") } } diff --git a/compiler/src/prog8/compiler/target/cpu6502/codegen/FunctionCallAsmGen.kt b/compiler/src/prog8/compiler/target/cpu6502/codegen/FunctionCallAsmGen.kt index a40bf54e8..5e1774035 100644 --- a/compiler/src/prog8/compiler/target/cpu6502/codegen/FunctionCallAsmGen.kt +++ b/compiler/src/prog8/compiler/target/cpu6502/codegen/FunctionCallAsmGen.kt @@ -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) } diff --git a/compilerAst/src/prog8/Either.kt b/compilerAst/src/prog8/Either.kt new file mode 100644 index 000000000..72dfab043 --- /dev/null +++ b/compilerAst/src/prog8/Either.kt @@ -0,0 +1,15 @@ +package prog8 + +sealed class Either { + + data class Left(val value: L) : Either() + + data class Right(val value: R) : Either() + + fun isRight() = this is Right + + fun isLeft() = this is Left +} + +fun left(a: L) = Either.Left(a) +fun right(b: R) = Either.Right(b) diff --git a/compilerAst/src/prog8/ast/statements/AstStatements.kt b/compilerAst/src/prog8/ast/statements/AstStatements.kt index 8f5486214..452b92fd4 100644 --- a/compilerAst/src/prog8/ast/statements/AstStatements.kt +++ b/compilerAst/src/prog8/ast/statements/AstStatements.kt @@ -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 { + + 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