diff --git a/compiler/res/version.txt b/compiler/res/version.txt index 4fedf1d20..b8854fde2 100644 --- a/compiler/res/version.txt +++ b/compiler/res/version.txt @@ -1 +1 @@ -7.0 +7.1-dev diff --git a/compiler/src/prog8/CompilerMain.kt b/compiler/src/prog8/CompilerMain.kt index 3483e04ca..de274233d 100644 --- a/compiler/src/prog8/CompilerMain.kt +++ b/compiler/src/prog8/CompilerMain.kt @@ -16,22 +16,20 @@ import kotlin.system.exitProcess fun main(args: Array) { - printSoftwareHeader("compiler") - - compileMain(args) -} - -internal fun printSoftwareHeader(what: String) { val buildVersion = object {}.javaClass.getResource("/version.txt").readText().trim() - println("\nProg8 $what v$buildVersion by Irmen de Jong (irmen@razorvine.net)") + println("\nProg8 compiler v$buildVersion by Irmen de Jong (irmen@razorvine.net)") println("This software is licensed under the GNU GPL 3.0, see https://www.gnu.org/licenses/gpl.html\n") + + val succes = compileMain(args) + if(!succes) + exitProcess(1) } fun pathFrom(stringPath: String, vararg rest: String): Path = FileSystems.getDefault().getPath(stringPath, *rest) -private fun compileMain(args: Array) { +private fun compileMain(args: Array): Boolean { val cli = ArgParser("prog8compiler", prefixStyle = ArgParser.OptionPrefixStyle.JVM) val startEmulator by cli.option(ArgType.Boolean, fullName = "emu", description = "auto-start emulator after successful compilation") val outputDir by cli.option(ArgType.String, fullName = "out", description = "directory for output files instead of current directory").default(".") @@ -47,19 +45,19 @@ private fun compileMain(args: Array) { cli.parse(args) } catch (e: IllegalStateException) { System.err.println(e.message) - exitProcess(1) + return false } val outputPath = pathFrom(outputDir) if(!outputPath.toFile().isDirectory) { System.err.println("Output path doesn't exist") - exitProcess(1) + return false } val faultyOption = moduleFiles.firstOrNull { it.startsWith('-') } if(faultyOption!=null) { System.err.println("Unknown command line option given: $faultyOption") - exitProcess(1) + return false } val libdirs = libDirs.toMutableList() @@ -114,11 +112,11 @@ private fun compileMain(args: Array) { try { compilationResult = compileProgram(filepath, dontOptimize!=true, dontWriteAssembly!=true, slowCodegenWarnings==true, compilationTarget, libdirs, outputPath) if(!compilationResult.success) - exitProcess(1) + return false } catch (x: ParsingFailedError) { - exitProcess(1) + return false } catch (x: AstException) { - exitProcess(1) + return false } if (startEmulator==true) { @@ -130,4 +128,6 @@ private fun compileMain(args: Array) { } } } + + return true } diff --git a/compiler/src/prog8/compiler/Compiler.kt b/compiler/src/prog8/compiler/Compiler.kt index cc80c2756..c256f4850 100644 --- a/compiler/src/prog8/compiler/Compiler.kt +++ b/compiler/src/prog8/compiler/Compiler.kt @@ -22,7 +22,6 @@ import prog8.parser.moduleName import java.io.File import java.io.InputStream import java.nio.file.Path -import kotlin.system.exitProcess import kotlin.system.measureTimeMillis @@ -81,10 +80,7 @@ fun compileProgram(filepath: Path, when(compilationTarget) { C64Target.name -> C64Target Cx16Target.name -> Cx16Target - else -> { - System.err.println("invalid compilation target") - exitProcess(1) - } + else -> throw IllegalArgumentException("invalid compilation target") } try { @@ -102,8 +98,15 @@ fun compileProgram(filepath: Path, // printAst(programAst) - if(writeAssembly) - programName = writeAssembly(programAst, errors, outputDir, compilationOptions) + 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) + } + } } System.out.flush() System.err.flush() @@ -198,10 +201,10 @@ private fun parseImports(filepath: Path, private fun determineCompilationOptions(program: Program, compTarget: ICompilationTarget): CompilationOptions { val mainModule = program.mainModule - val outputType = (mainModule.statements.singleOrNull { it is Directive && it.directive == "%output" } - as? Directive)?.args?.single()?.name?.uppercase() - val launcherType = (mainModule.statements.singleOrNull { it is Directive && it.directive == "%launcher" } - as? Directive)?.args?.single()?.name?.uppercase() + val outputDirective = (mainModule.statements.singleOrNull { it is Directive && it.directive == "%output" } as? Directive) + val launcherDirective = (mainModule.statements.singleOrNull { it is Directive && it.directive == "%launcher" } as? Directive) + val outputTypeStr = outputDirective?.args?.single()?.name?.uppercase() + val launcherTypeStr = launcherDirective?.args?.single()?.name?.uppercase() val zpoption: String? = (mainModule.statements.singleOrNull { it is Directive && it.directive == "%zeropage" } as? Directive)?.args?.single()?.name?.uppercase() val allOptions = program.modules.flatMap { it.statements }.filter { it is Directive && it.directive == "%option" } @@ -231,18 +234,26 @@ private fun determineCompilationOptions(program: Program, compTarget: ICompilati .map { it[0].int!!..it[1].int!! } .toList() - if (outputType != null && !OutputType.values().any { it.name == outputType }) { - System.err.println("invalid output type $outputType") - exitProcess(1) + val outputType = if (outputTypeStr == null) OutputType.PRG else { + try { + OutputType.valueOf(outputTypeStr) + } catch (x: IllegalArgumentException) { + // set default value; actual check and error handling of invalid option is handled in the AstChecker later + OutputType.PRG + } } - if (launcherType != null && !LauncherType.values().any { it.name == launcherType }) { - System.err.println("invalid launcher type $launcherType") - exitProcess(1) + val launcherType = if (launcherTypeStr == null) LauncherType.BASIC else { + try { + LauncherType.valueOf(launcherTypeStr) + } catch (x: IllegalArgumentException) { + // set default value; actual check and error handling of invalid option is handled in the AstChecker later + LauncherType.BASIC + } } return CompilationOptions( - if (outputType == null) OutputType.PRG else OutputType.valueOf(outputType), - if (launcherType == null) LauncherType.BASIC else LauncherType.valueOf(launcherType), + outputType, + launcherType, zpType, zpReserved, floatsEnabled, noSysInit, compTarget ) @@ -316,7 +327,7 @@ private fun postprocessAst(programAst: Program, errors: IErrorReporter, compiler private fun writeAssembly(programAst: Program, errors: IErrorReporter, outputDir: Path, - compilerOptions: CompilationOptions): String { + compilerOptions: CompilationOptions): Pair { // asm generation directly from the Ast programAst.processAstBeforeAsmGeneration(errors, compilerOptions.compTarget) errors.report() @@ -330,9 +341,13 @@ private fun writeAssembly(programAst: Program, compilerOptions.compTarget.machine.zeropage, compilerOptions, outputDir).compileToAssembly() - assembly.assemble(compilerOptions) - errors.report() - return assembly.name + val assemblerReturnStatus = assembly.assemble(compilerOptions) + return if(assemblerReturnStatus!=0) + Pair(false, "assembler step failed with return code $assemblerReturnStatus") + else { + errors.report() + Pair(true, assembly.name) + } } fun printAst(programAst: Program) { diff --git a/compiler/src/prog8/compiler/target/IAssemblyGenerator.kt b/compiler/src/prog8/compiler/target/IAssemblyGenerator.kt index 4dfb94f42..0b01f492a 100644 --- a/compiler/src/prog8/compiler/target/IAssemblyGenerator.kt +++ b/compiler/src/prog8/compiler/target/IAssemblyGenerator.kt @@ -12,5 +12,5 @@ internal const val subroutineFloatEvalResultVar2 = "_prog8_float_eval_result2" internal interface IAssemblyProgram { val name: String - fun assemble(options: CompilationOptions) + fun assemble(options: CompilationOptions): Int } diff --git a/compiler/src/prog8/compiler/target/cbm/AssemblyProgram.kt b/compiler/src/prog8/compiler/target/cbm/AssemblyProgram.kt index 202c02dd4..024bd565c 100644 --- a/compiler/src/prog8/compiler/target/cbm/AssemblyProgram.kt +++ b/compiler/src/prog8/compiler/target/cbm/AssemblyProgram.kt @@ -5,7 +5,6 @@ import prog8.compiler.OutputType import prog8.compiler.target.IAssemblyProgram import prog8.compiler.target.generatedLabelPrefix import java.nio.file.Path -import kotlin.system.exitProcess class AssemblyProgram(override val name: String, outputDir: Path, private val compTarget: String) : IAssemblyProgram { private val assemblyFile = outputDir.resolve("$name.asm") @@ -13,7 +12,7 @@ class AssemblyProgram(override val name: String, outputDir: Path, private val co private val binFile = outputDir.resolve("$name.bin") private val viceMonListFile = outputDir.resolve("$name.vice-mon-list") - override fun assemble(options: CompilationOptions) { + override fun assemble(options: CompilationOptions): Int { // add "-Wlong-branch" to see warnings about conversion of branch instructions to jumps (default = do this silently) val command = mutableListOf("64tass", "--ascii", "--case-sensitive", "--long-branch", "-Wall", "-Wno-strict-bool", "-Wno-shadow", // "-Werror", @@ -35,13 +34,11 @@ class AssemblyProgram(override val name: String, outputDir: Path, private val co val proc = ProcessBuilder(command).inheritIO().start() val result = proc.waitFor() - if (result != 0) { - System.err.println("assembler failed with returncode $result") - exitProcess(result) + if (result == 0) { + removeGeneratedLabelsFromMonlist() + generateBreakpointList() } - - removeGeneratedLabelsFromMonlist() - generateBreakpointList() + return result } private fun removeGeneratedLabelsFromMonlist() { diff --git a/compiler/test/AsmgenTests.kt b/compiler/test/AsmgenTests.kt index c087f1856..6cd6ac808 100644 --- a/compiler/test/AsmgenTests.kt +++ b/compiler/test/AsmgenTests.kt @@ -2,7 +2,6 @@ package prog8tests import org.hamcrest.MatcherAssert.assertThat import org.hamcrest.Matchers.equalTo -import org.junit.jupiter.api.Disabled import org.junit.jupiter.api.Test import org.junit.jupiter.api.TestInstance import prog8.ast.IBuiltinFunctions diff --git a/compiler/test/TestCompilerOnCharLit.kt b/compiler/test/TestCompilerOnCharLit.kt index 245f9fe39..03a5b2a7e 100644 --- a/compiler/test/TestCompilerOnCharLit.kt +++ b/compiler/test/TestCompilerOnCharLit.kt @@ -2,17 +2,19 @@ package prog8tests import org.junit.jupiter.api.Test import org.junit.jupiter.api.TestInstance -import kotlin.test.* -import kotlin.io.path.* - import prog8.ast.IFunctionCall import prog8.ast.base.DataType import prog8.ast.base.VarDeclType import prog8.ast.expressions.IdentifierReference import prog8.ast.expressions.NumericLiteralValue -import prog8.compiler.target.Cx16Target - import prog8.compiler.compileProgram +import prog8.compiler.target.Cx16Target +import kotlin.io.path.Path +import kotlin.io.path.absolute +import kotlin.io.path.isDirectory +import kotlin.test.assertEquals +import kotlin.test.assertIs +import kotlin.test.assertTrue /** @@ -135,4 +137,4 @@ class TestCompilerOnCharLit { } } -} \ No newline at end of file +} diff --git a/compiler/test/TestCompilerOnExamples.kt b/compiler/test/TestCompilerOnExamples.kt index 4b4107acb..effd4c23d 100644 --- a/compiler/test/TestCompilerOnExamples.kt +++ b/compiler/test/TestCompilerOnExamples.kt @@ -2,12 +2,14 @@ package prog8tests import org.junit.jupiter.api.Test import org.junit.jupiter.api.TestInstance -import kotlin.test.* -import kotlin.io.path.* - -import prog8.compiler.target.Cx16Target import prog8.compiler.compileProgram +import prog8.compiler.target.Cx16Target import prog8.compiler.target.ICompilationTarget +import kotlin.io.path.Path +import kotlin.io.path.absolute +import kotlin.io.path.isDirectory +import kotlin.test.assertEquals +import kotlin.test.assertTrue /** @@ -75,4 +77,4 @@ class TestCompilerOnExamples { testExample("animals", Cx16Target, true) } -} \ No newline at end of file +} diff --git a/examples/test.p8 b/examples/test.p8 index 043f30c2c..860fab040 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -5,7 +5,6 @@ main { label: sub start() { - sub2(&label) sub2(&label_local) sub2(&main.sub2.label_in_sub2)