diff --git a/compiler/src/prog8/compiler/Compiler.kt b/compiler/src/prog8/compiler/Compiler.kt index e464a59f0..95eee168a 100644 --- a/compiler/src/prog8/compiler/Compiler.kt +++ b/compiler/src/prog8/compiler/Compiler.kt @@ -73,11 +73,11 @@ fun compileProgram(filepath: Path, slowCodegenWarnings: Boolean, compilationTarget: String, sourceDirs: List, - outputDir: Path): CompilationResult { + outputDir: Path, + errors: IErrorReporter = ErrorReporter()): CompilationResult { var programName = "" lateinit var programAst: Program lateinit var importedFiles: List - val errors = ErrorReporter() val compTarget = when(compilationTarget) { diff --git a/compiler/src/prog8/compiler/ErrorReporting.kt b/compiler/src/prog8/compiler/ErrorReporting.kt index 5f56d29a4..2efd8e31a 100644 --- a/compiler/src/prog8/compiler/ErrorReporting.kt +++ b/compiler/src/prog8/compiler/ErrorReporting.kt @@ -9,6 +9,10 @@ interface IErrorReporter { fun warn(msg: String, position: Position) fun noErrors(): Boolean fun report() + fun finalizeNumErrors(numErrors: Int, numWarnings: Int) { + if(numErrors>0) + throw ParsingFailedError("There are $numErrors errors and $numWarnings warnings.") + } } @@ -49,8 +53,7 @@ internal class ErrorReporter: IErrorReporter { System.err.print("\u001b[0m") // reset color } messages.clear() - if(numErrors>0) - throw ParsingFailedError("There are $numErrors errors and $numWarnings warnings.") + finalizeNumErrors(numErrors, numWarnings) } override fun noErrors() = messages.none { it.severity==MessageSeverity.ERROR } diff --git a/compiler/test/ModuleImporterTests.kt b/compiler/test/ModuleImporterTests.kt index ecc335f68..d5dd6474e 100644 --- a/compiler/test/ModuleImporterTests.kt +++ b/compiler/test/ModuleImporterTests.kt @@ -36,7 +36,7 @@ class TestModuleImporter { } private fun makeImporter(errors: IErrorReporter? = null, searchIn: Iterable) = - ModuleImporter(program, "blah", errors ?: ErrorReporterForTests(), searchIn.toList()) + ModuleImporter(program, "blah", errors ?: ErrorReporterForTests(false), searchIn.toList()) @Nested inner class Constructor { @@ -243,7 +243,7 @@ class TestModuleImporter { @Test fun testWithNonExistingName() { val searchIn = assumeDirectory("./", workingDir.relativize(fixturesDir)) - val errors = ErrorReporterForTests() + val errors = ErrorReporterForTests(false) val importer = makeImporter(errors, searchIn.invariantSeparatorsPathString) val filenameNoExt = assumeNotExists(fixturesDir, "i_do_not_exist").name val filenameWithExt = assumeNotExists(fixturesDir, "i_do_not_exist.p8").name diff --git a/compiler/test/TestCompilerOnRanges.kt b/compiler/test/TestCompilerOnRanges.kt index 51f0b4128..56f60561f 100644 --- a/compiler/test/TestCompilerOnRanges.kt +++ b/compiler/test/TestCompilerOnRanges.kt @@ -13,10 +13,10 @@ import prog8.compiler.astprocessing.size import prog8.compiler.astprocessing.toConstantIntegerRange import prog8.compiler.target.C64Target import prog8.compiler.target.Cx16Target +import prog8tests.helpers.* import prog8tests.helpers.assertFailure import prog8tests.helpers.assertSuccess import prog8tests.helpers.compileText -import prog8tests.helpers.mapCombinations import kotlin.test.assertEquals @@ -224,6 +224,7 @@ class TestCompilerOnRanges { @Test fun testForLoopWithRange_str_downto_str() { + val errors = ErrorReporterForTests() compileText(Cx16Target, true, """ main { sub start() { @@ -233,8 +234,10 @@ class TestCompilerOnRanges { } } } - """).assertFailure() - //TODO("test exact compile error(s)") + """, errors, false).assertFailure() + assertEquals(2, errors.errors.size) + assertEquals("range expression from value must be integer", errors.errors[0]) + assertEquals("range expression to value must be integer", errors.errors[1]) } @Test diff --git a/compiler/test/TestSubroutines.kt b/compiler/test/TestSubroutines.kt index f3848ef17..84fb70136 100644 --- a/compiler/test/TestSubroutines.kt +++ b/compiler/test/TestSubroutines.kt @@ -7,6 +7,7 @@ import prog8.ast.base.DataType import prog8.ast.statements.Block import prog8.ast.statements.Subroutine import prog8.compiler.target.C64Target +import prog8tests.helpers.ErrorReporterForTests import prog8tests.helpers.assertFailure import prog8tests.helpers.assertSuccess import prog8tests.helpers.compileText @@ -32,8 +33,11 @@ class TestSubroutines { } } """ - val result = compileText(C64Target, false, text).assertFailure("currently str type in signature is invalid") // TODO should not be invalid - // TODO: check for specific error message(s) + val errors = ErrorReporterForTests() + compileText(C64Target, false, text, errors, false).assertFailure("currently str type in signature is invalid") // TODO should not be invalid + assertEquals(0, errors.warnings.size) + // TODO fix extra error "string var must be initialized with a string literal" + assertTrue(errors.errors.single().startsWith("Pass-by-reference types (str, array) cannot occur as a parameter type directly.")) } @Test @@ -53,8 +57,10 @@ class TestSubroutines { } """ - val result = compileText(C64Target, false, text).assertFailure("currently array dt in signature is invalid") // TODO should not be invalid? - // TODO: check for specific error message(s) + val errors = ErrorReporterForTests() + compileText(C64Target, false, text, errors, false).assertFailure("currently array dt in signature is invalid") // TODO should not be invalid? + assertEquals(0, errors.warnings.size) + assertTrue(errors.errors.single().startsWith("Pass-by-reference types (str, array) cannot occur as a parameter type directly.")) } @Test @@ -82,7 +88,7 @@ class TestSubroutines { } } """ - val result = compileText(C64Target, false, text).assertSuccess() + val result = compileText(C64Target, false, text, writeAssembly = false).assertSuccess() val module = result.programAst.toplevelModule val mainBlock = module.statements.single() as Block val asmfunc = mainBlock.statements.filterIsInstance().single { it.name=="asmfunc"} @@ -121,7 +127,7 @@ class TestSubroutines { } """ - val result = compileText(C64Target, false, text).assertSuccess() + val result = compileText(C64Target, false, text, writeAssembly = false).assertSuccess() val module = result.programAst.toplevelModule val mainBlock = module.statements.single() as Block val asmfunc = mainBlock.statements.filterIsInstance().single { it.name=="asmfunc"} diff --git a/compiler/test/helpers/ErrorReporterForTests.kt b/compiler/test/helpers/ErrorReporterForTests.kt index 0d77cc766..c76070d50 100644 --- a/compiler/test/helpers/ErrorReporterForTests.kt +++ b/compiler/test/helpers/ErrorReporterForTests.kt @@ -3,7 +3,7 @@ package prog8tests.helpers import prog8.ast.base.Position import prog8.compiler.IErrorReporter -class ErrorReporterForTests: IErrorReporter { +class ErrorReporterForTests(private val throwExceptionAtReportIfErrors: Boolean=true): IErrorReporter { val errors = mutableListOf() @@ -20,6 +20,8 @@ class ErrorReporterForTests: IErrorReporter { override fun noErrors(): Boolean = errors.isEmpty() override fun report() { + if(throwExceptionAtReportIfErrors) + finalizeNumErrors(errors.size, warnings.size) errors.clear() warnings.clear() } diff --git a/compiler/test/helpers/compileXyz.kt b/compiler/test/helpers/compileXyz.kt index 4e59e499c..aafc1fe8e 100644 --- a/compiler/test/helpers/compileXyz.kt +++ b/compiler/test/helpers/compileXyz.kt @@ -1,6 +1,8 @@ package prog8tests.helpers import prog8.compiler.CompilationResult +import prog8.compiler.ErrorReporter +import prog8.compiler.IErrorReporter import prog8.compiler.compileProgram import prog8.compiler.target.ICompilationTarget import java.nio.file.Path @@ -28,18 +30,21 @@ internal fun compileFile( optimize: Boolean, fileDir: Path, fileName: String, - outputDir: Path = prog8tests.helpers.outputDir + outputDir: Path = prog8tests.helpers.outputDir, + errors: IErrorReporter? = null, + writeAssembly: Boolean = true ) : CompilationResult { val filepath = fileDir.resolve(fileName) assumeReadableFile(filepath) return compileProgram( filepath, optimize, - writeAssembly = true, + writeAssembly = writeAssembly, slowCodegenWarnings = false, platform.name, sourceDirs = listOf(), - outputDir + outputDir, + errors = errors ?: ErrorReporter() ) } @@ -51,10 +56,12 @@ internal fun compileFile( internal fun compileText( platform: ICompilationTarget, optimize: Boolean, - sourceText: String + sourceText: String, + errors: IErrorReporter? = null, + writeAssembly: Boolean = true ) : CompilationResult { val filePath = outputDir.resolve("on_the_fly_test_" + sourceText.hashCode().toUInt().toString(16) + ".p8") // we don't assumeNotExists(filePath) - should be ok to just overwrite it filePath.toFile().writeText(sourceText) - return compileFile(platform, optimize, filePath.parent, filePath.name) + return compileFile(platform, optimize, filePath.parent, filePath.name, errors=errors, writeAssembly=writeAssembly) }