From ee115b33372298983131b8eb128593bb27f26b70 Mon Sep 17 00:00:00 2001 From: meisl Date: Sat, 17 Jul 2021 10:37:58 +0200 Subject: [PATCH 1/4] + expose #54, %asmbinary when outputDir != workingDir; also: refactor compiler tests on examples and add test helpers --- compiler/test/Helpers.kt | 156 +++++++++++++++++ compiler/test/TestCompilerOnExamples.kt | 157 ++++++++++++------ .../test/TestCompilerOnImportsAndIncludes.kt | 135 +++++++++++++++ .../test/fixtures/asmBinaryFromSameFolder.p8 | 10 ++ .../test/fixtures/asmBinaryFromSubFolder.p8 | 10 ++ .../test/fixtures/asmBinaryNonExisting.p8 | 10 ++ .../test/fixtures/asmBinaryNonReadable.p8 | 10 ++ .../test/fixtures/asmIncludeFromSameFolder.p8 | 13 ++ compiler/test/fixtures/do_nothing.asm | 7 + compiler/test/fixtures/do_nothing1.bin | 1 + compiler/test/fixtures/foo_bar.asm | 2 + compiler/test/fixtures/foo_bar.p8 | 3 + .../test/fixtures/importFromSameFolder.p8 | 9 + .../test/fixtures/subFolder/do_nothing2.bin | 1 + 14 files changed, 469 insertions(+), 55 deletions(-) create mode 100644 compiler/test/Helpers.kt create mode 100644 compiler/test/TestCompilerOnImportsAndIncludes.kt create mode 100644 compiler/test/fixtures/asmBinaryFromSameFolder.p8 create mode 100644 compiler/test/fixtures/asmBinaryFromSubFolder.p8 create mode 100644 compiler/test/fixtures/asmBinaryNonExisting.p8 create mode 100644 compiler/test/fixtures/asmBinaryNonReadable.p8 create mode 100644 compiler/test/fixtures/asmIncludeFromSameFolder.p8 create mode 100644 compiler/test/fixtures/do_nothing.asm create mode 100644 compiler/test/fixtures/do_nothing1.bin create mode 100644 compiler/test/fixtures/foo_bar.asm create mode 100644 compiler/test/fixtures/foo_bar.p8 create mode 100644 compiler/test/fixtures/importFromSameFolder.p8 create mode 100644 compiler/test/fixtures/subFolder/do_nothing2.bin diff --git a/compiler/test/Helpers.kt b/compiler/test/Helpers.kt new file mode 100644 index 000000000..0ea41bf05 --- /dev/null +++ b/compiler/test/Helpers.kt @@ -0,0 +1,156 @@ +package prog8tests.helpers + +import kotlin.test.* +import kotlin.io.path.* +import java.nio.file.Path + +import prog8.ast.IBuiltinFunctions +import prog8.ast.IMemSizer +import prog8.ast.IStringEncoding +import prog8.ast.base.DataType +import prog8.ast.base.Position +import prog8.ast.expressions.Expression +import prog8.ast.expressions.InferredTypes +import prog8.ast.expressions.NumericLiteralValue +import prog8.compiler.CompilationResult +import prog8.compiler.compileProgram +import prog8.compiler.target.ICompilationTarget + +// TODO: find a way to share with compilerAst/test/Helpers.kt, while still being able to amend it (-> compileFile(..)) + +internal fun CompilationResult.assertSuccess(description: String = ""): CompilationResult { + assertTrue(success, "expected successful compilation but failed $description") + return this +} + +internal fun CompilationResult.assertFailure(description: String = ""): CompilationResult { + assertFalse(success, "expected failure to compile but succeeded $description") + return this +} + +/** + * @see CompilationResult.assertSuccess + * @see CompilationResult.assertFailure + */ +internal fun compileFile( + platform: ICompilationTarget, + optimize: Boolean, + fileDir: Path, + fileName: String, + outputDir: Path = prog8tests.helpers.outputDir +) : CompilationResult { + val filepath = fileDir.resolve(fileName) + assumeReadableFile(filepath) + return compileProgram( + filepath, + optimize, + writeAssembly = true, + slowCodegenWarnings = false, + platform.name, + libdirs = listOf(), + outputDir + ) +} + +/** + * Takes a [sourceText] as a String, writes it to a temporary + * file and then runs the compiler on that. + * @see compileFile + */ +internal fun compileText( + platform: ICompilationTarget, + optimize: Boolean, + sourceText: String +) : 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) +} + + + +val workingDir : Path = Path("").absolute() // Note: Path(".") does NOT work..! +val fixturesDir : Path = workingDir.resolve("test/fixtures") +val resourcesDir : Path = workingDir.resolve("res") +val outputDir : Path = workingDir.resolve("build/tmp/test") + +fun assumeReadable(path: Path) { + assertTrue(path.isReadable(), "sanity check: should be readable: ${path.absolute()}") +} + +fun assumeReadableFile(path: Path) { + assumeReadable(path) + assertTrue(path.isRegularFile(), "sanity check: should be normal file: ${path.absolute()}") +} + +fun assumeDirectory(path: Path) { + assertTrue(path.isDirectory(), "sanity check; should be directory: $path") +} + +fun assumeNotExists(path: Path) { + assertFalse(path.exists(), "sanity check: should not exist: ${path.absolute()}") +} + +fun sanityCheckDirectories(workingDirName: String? = null) { + if (workingDirName != null) + assertEquals(workingDirName, workingDir.fileName.toString(), "name of current working dir") + assumeDirectory(workingDir) + assumeDirectory(fixturesDir) + assumeDirectory(resourcesDir) + assumeDirectory(outputDir) +} + + +fun mapCombinations(dim1: Iterable, dim2: Iterable, combine2: (A, B) -> R) = + sequence { + for (a in dim1) + for (b in dim2) + yield(combine2(a, b)) + }.toList() + +fun mapCombinations(dim1: Iterable, dim2: Iterable, dim3: Iterable, combine3: (A, B, C) -> R) = + sequence { + for (a in dim1) + for (b in dim2) + for (c in dim3) + yield(combine3(a, b, c)) + }.toList() + +fun mapCombinations(dim1: Iterable, dim2: Iterable, dim3: Iterable, dim4: Iterable, combine4: (A, B, C, D) -> R) = + sequence { + for (a in dim1) + for (b in dim2) + for (c in dim3) + for (d in dim4) + yield(combine4(a, b, c, d)) + }.toList() + + +val DummyEncoding = object : IStringEncoding { + override fun encodeString(str: String, altEncoding: Boolean): List { + throw Exception("just a dummy - should not be called") + } + + override fun decodeString(bytes: List, altEncoding: Boolean): String { + throw Exception("just a dummy - should not be called") + } +} + +val DummyFunctions = object : IBuiltinFunctions { + override val names: Set = emptySet() + override val purefunctionNames: Set = emptySet() + override fun constValue( + name: String, + args: List, + position: Position, + memsizer: IMemSizer + ): NumericLiteralValue? = null + + override fun returnType(name: String, args: MutableList) = InferredTypes.InferredType.unknown() +} + +val DummyMemsizer = object : IMemSizer { + override fun memorySize(dt: DataType): Int = 0 +} + diff --git a/compiler/test/TestCompilerOnExamples.kt b/compiler/test/TestCompilerOnExamples.kt index effd4c23d..361d5f174 100644 --- a/compiler/test/TestCompilerOnExamples.kt +++ b/compiler/test/TestCompilerOnExamples.kt @@ -1,80 +1,127 @@ package prog8tests -import org.junit.jupiter.api.Test import org.junit.jupiter.api.TestInstance +import org.junit.jupiter.api.TestFactory +import org.junit.jupiter.api.Disabled +import org.junit.jupiter.api.BeforeAll +import org.junit.jupiter.api.DynamicTest +import org.junit.jupiter.api.DynamicTest.dynamicTest +import prog8tests.helpers.* +import kotlin.io.path.* + import prog8.compiler.compileProgram +import prog8.compiler.target.C64Target 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 /** * ATTENTION: this is just kludge! * They are not really unit tests, but rather tests of the whole process, * from source file loading all the way through to running 64tass. - * What's more: in case of failure (to compile and assemble) - which is when tests should help you - - * these tests will actually be ignored (ie. NOT fail), - * because in the code there are calls to Process.exit, making it essentially untestable. */ +//@Disabled("to save some time") @TestInstance(TestInstance.Lifecycle.PER_CLASS) class TestCompilerOnExamples { - val workingDir = Path("").absolute() // Note: Path(".") does NOT work..! - val examplesDir = workingDir.resolve("../examples") - val outputDir = workingDir.resolve("build/tmp/test") + private val examplesDir = workingDir.resolve("../examples") - @Test - fun testDirectoriesSanityCheck() { - assertEquals("compiler", workingDir.fileName.toString()) - assertTrue(examplesDir.isDirectory(), "sanity check; should be directory: $examplesDir") - assertTrue(outputDir.isDirectory(), "sanity check; should be directory: $outputDir") + @BeforeAll + fun setUp() { + sanityCheckDirectories("compiler") + assumeDirectory(examplesDir) } // TODO: make assembly stage testable - in case of failure (eg of 64tass) it Process.exit s - fun testExample(nameWithoutExt: String, platform: ICompilationTarget, optimize: Boolean) { - val filepath = examplesDir.resolve("$nameWithoutExt.p8") - val result = compileProgram( - filepath, - optimize, - writeAssembly = true, - slowCodegenWarnings = false, - compilationTarget = platform.name, - libdirs = listOf(), - outputDir - ) - assertTrue(result.success, "${platform.name}, optimize=$optimize: \"$filepath\"") + private fun makeDynamicCompilerTest(name: String, platform: ICompilationTarget, optimize: Boolean) : DynamicTest { + val searchIn = mutableListOf(examplesDir) + if (platform == Cx16Target) { + searchIn.add(0, examplesDir.resolve("cx16")) + } + val filepath = searchIn.map { it.resolve("$name.p8") }.first { it.exists() } + val displayName = "${examplesDir.relativize(filepath)}: ${platform.name}, optimize=$optimize" + return dynamicTest(displayName) { + compileProgram( + filepath, + optimize, + writeAssembly = true, + slowCodegenWarnings = false, + compilationTarget = platform.name, + libdirs = listOf(), + outputDir + ).assertSuccess("; $displayName") + } } + @TestFactory + @Disabled + fun bothCx16AndC64() = mapCombinations( + dim1 = listOf( + "animals", + "balls", + "cube3d", + "cube3d-float", + "cube3d-gfx", + "cxlogo", + "dirlist", + "fibonacci", + "line-circle-gfx", + "line-circle-txt", + "mandelbrot", + "mandelbrot-gfx", + "numbergame", + "primes", + "rasterbars", + "screencodes", + "sorting", + "swirl", + "swirl-float", + "tehtriz", + "test", + "textelite", + ), + dim2 = listOf(Cx16Target, C64Target), + dim3 = listOf(false, true), + combine3 = ::makeDynamicCompilerTest + ) - @Test - fun test_cxLogo_noopt() { - testExample("cxlogo", Cx16Target, false) - } - @Test - fun test_cxLogo_opt() { - testExample("cxlogo", Cx16Target, true) - } - - @Test - fun test_swirl_noopt() { - testExample("swirl", Cx16Target, false) - } - @Test - fun test_swirl_opt() { - testExample("swirl", Cx16Target, true) - } - - @Test - fun test_animals_noopt() { - testExample("animals", Cx16Target, false) - } - @Test - fun test_animals_opt() { - testExample("animals", Cx16Target, true) - } + @TestFactory +// @Disabled + fun onlyC64() = mapCombinations( + dim1 = listOf( + "balloonflight", + "bdmusic", + "bdmusic-irq", + "charset", + "cube3d-sprites", + "plasma", + "sprites", + "turtle-gfx", + "wizzine", + ), + dim2 = listOf(C64Target), + dim3 = listOf(false, true), + combine3 = ::makeDynamicCompilerTest + ) + @TestFactory +// @Disabled + fun onlyCx16() = mapCombinations( + dim1 = listOf( + "vtui/testvtui", + "amiga", + "bobs", + "cobramk3-gfx", + "colorbars", + "datetime", + "highresbitmap", + "kefrenbars", + "mandelbrot-gfx-colors", + "multipalette", + "testgfx2", + ), + dim2 = listOf(Cx16Target), + dim3 = listOf(false, true), + combine3 = ::makeDynamicCompilerTest + ) } diff --git a/compiler/test/TestCompilerOnImportsAndIncludes.kt b/compiler/test/TestCompilerOnImportsAndIncludes.kt new file mode 100644 index 000000000..e67600783 --- /dev/null +++ b/compiler/test/TestCompilerOnImportsAndIncludes.kt @@ -0,0 +1,135 @@ +package prog8tests + +import org.junit.jupiter.api.TestInstance +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.BeforeAll +import org.junit.jupiter.api.TestFactory +import org.junit.jupiter.api.DynamicTest +import org.junit.jupiter.api.DynamicTest.dynamicTest +import kotlin.test.* +import kotlin.io.path.* +import prog8tests.helpers.* + +import prog8.ast.expressions.AddressOf +import prog8.ast.expressions.IdentifierReference +import prog8.ast.expressions.StringLiteralValue +import prog8.ast.statements.FunctionCallStatement +import prog8.ast.statements.Label +import prog8.compiler.target.Cx16Target + + +/** + * ATTENTION: this is just kludge! + * They are not really unit tests, but rather tests of the whole process, + * from source file loading all the way through to running 64tass. + */ +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +class TestCompilerOnImportsAndIncludes { + + @BeforeAll + fun setUp() { + sanityCheckDirectories("compiler") + } + + @Test + fun testImportFromSameFolder() { + val filepath = fixturesDir.resolve("importFromSameFolder.p8") + val imported = fixturesDir.resolve("foo_bar.p8") + assumeReadableFile(filepath) + assumeReadableFile(imported) + + val platform = Cx16Target + val result = compileFile(platform, false, fixturesDir, filepath.name) + .assertSuccess() + + val program = result.programAst + val startSub = program.entrypoint() + val strLits = startSub.statements + .filterIsInstance() + .map { it.args[0] as IdentifierReference } + .map { it.targetVarDecl(program)!!.value as StringLiteralValue } + + assertEquals("main.bar", strLits[0].value) + assertEquals("foo.bar", strLits[1].value) + assertEquals("main", strLits[0].definingScope().name) + assertEquals("foo", strLits[1].definingScope().name) + } + + @Test + fun testAsmIncludeFromSameFolder() { + val filepath = fixturesDir.resolve("asmIncludeFromSameFolder.p8") + val included = fixturesDir.resolve("foo_bar.asm") + assumeReadableFile(filepath) + assumeReadableFile(included) + + val platform = Cx16Target + val result = compileFile(platform, false, fixturesDir, filepath.name) + .assertSuccess() + + val program = result.programAst + val startSub = program.entrypoint() + val args = startSub.statements + .filterIsInstance() + .map { it.args[0] } + + val str0 = (args[0] as IdentifierReference).targetVarDecl(program)!!.value as StringLiteralValue + assertEquals("main.bar", str0.value) + assertEquals("main", str0.definingScope().name) + + val id1 = (args[1] as AddressOf).identifier + val lbl1 = id1.targetStatement(program) as Label + assertEquals("foo_bar", lbl1.name) + assertEquals("start", lbl1.definingScope().name) + } + + @Test + fun testAsmbinaryDirectiveWithNonExistingFile() { + val p8Path = fixturesDir.resolve("asmbinaryNonExisting.p8") + val binPath = fixturesDir.resolve("i_do_not_exist.bin") + assumeReadableFile(p8Path) + assumeNotExists(binPath) + + compileFile(Cx16Target, false, p8Path.parent, p8Path.name, outputDir) + .assertFailure() + } + + @Test + fun testAsmbinaryDirectiveWithNonReadableFile() { + val p8Path = fixturesDir.resolve("asmbinaryNonReadable.p8") + val binPath = fixturesDir.resolve("subFolder") + assumeReadableFile(p8Path) + assumeDirectory(binPath) + + compileFile(Cx16Target, false, p8Path.parent, p8Path.name, outputDir) + .assertFailure() + } + + @TestFactory + fun asmbinaryDirectiveWithExistingBinFile(): Iterable = + listOf( + Triple("same ", "asmBinaryFromSameFolder.p8", "do_nothing1.bin"), + Triple("sub", "asmBinaryFromSubFolder.p8", "subFolder/do_nothing2.bin"), + ).map { + val (where, p8Str, binStr) = it + val p8Path = fixturesDir.resolve(p8Str) + val binPath = fixturesDir.resolve(binStr) + val displayName = "%asmbinary from ${where}folder" + dynamicTest(displayName) { + assumeReadableFile(p8Path) + assumeReadableFile(binPath) + assertNotEquals( // the bug we're testing for (#??) was hidden if outputDir == workinDir + workingDir.normalize().toAbsolutePath(), + outputDir.normalize().toAbsolutePath(), + "sanity check: workingDir and outputDir should not be the same folder") + + compileFile(Cx16Target, false, p8Path.parent, p8Path.name, outputDir) + .assertSuccess( + "argument to assembler directive .binary " + + "should be relative to the generated .asm file (in output dir), " + + "NOT relative to .p8 neither current working dir" + ) + } + } + + } + diff --git a/compiler/test/fixtures/asmBinaryFromSameFolder.p8 b/compiler/test/fixtures/asmBinaryFromSameFolder.p8 new file mode 100644 index 000000000..d48a8c6b0 --- /dev/null +++ b/compiler/test/fixtures/asmBinaryFromSameFolder.p8 @@ -0,0 +1,10 @@ +main { + sub start() { + stuff.do_nothing() + } +} + +stuff $1000 { + romsub $1000 = do_nothing() + %asmbinary "do_nothing1.bin", 0 +} \ No newline at end of file diff --git a/compiler/test/fixtures/asmBinaryFromSubFolder.p8 b/compiler/test/fixtures/asmBinaryFromSubFolder.p8 new file mode 100644 index 000000000..5b48b7892 --- /dev/null +++ b/compiler/test/fixtures/asmBinaryFromSubFolder.p8 @@ -0,0 +1,10 @@ +main { + sub start() { + stuff.do_nothing() + } +} + +stuff $1000 { + romsub $1000 = do_nothing() + %asmbinary "subFolder/do_nothing2.bin", 0 +} \ No newline at end of file diff --git a/compiler/test/fixtures/asmBinaryNonExisting.p8 b/compiler/test/fixtures/asmBinaryNonExisting.p8 new file mode 100644 index 000000000..2ff4e2f46 --- /dev/null +++ b/compiler/test/fixtures/asmBinaryNonExisting.p8 @@ -0,0 +1,10 @@ +main { + sub start() { + stuff.do_nothing() + } +} + +stuff $1000 { + romsub $1000 = do_nothing() + %asmbinary "i_do_not_exist.bin", 0 +} \ No newline at end of file diff --git a/compiler/test/fixtures/asmBinaryNonReadable.p8 b/compiler/test/fixtures/asmBinaryNonReadable.p8 new file mode 100644 index 000000000..3b7f63bfc --- /dev/null +++ b/compiler/test/fixtures/asmBinaryNonReadable.p8 @@ -0,0 +1,10 @@ +main { + sub start() { + stuff.do_nothing() + } +} + +stuff $1000 { + romsub $1000 = do_nothing() + %asmbinary "subFolder", 0 +} \ No newline at end of file diff --git a/compiler/test/fixtures/asmIncludeFromSameFolder.p8 b/compiler/test/fixtures/asmIncludeFromSameFolder.p8 new file mode 100644 index 000000000..df25f6e78 --- /dev/null +++ b/compiler/test/fixtures/asmIncludeFromSameFolder.p8 @@ -0,0 +1,13 @@ +%import textio +main { + str myBar = "main.bar" +;foo_bar: +; %asminclude "foo_bar.asm" ; FIXME: should be accessible from inside start() but give assembler error + sub start() { + txt.print(myBar) + txt.print(&foo_bar) + return +foo_bar: + %asminclude "foo_bar.asm" + } +} diff --git a/compiler/test/fixtures/do_nothing.asm b/compiler/test/fixtures/do_nothing.asm new file mode 100644 index 000000000..6bfed22b6 --- /dev/null +++ b/compiler/test/fixtures/do_nothing.asm @@ -0,0 +1,7 @@ +; this is the source code for do_nothing1.bin and subFolder/do_nothing2.bin +; command lines: +; 64tass --ascii --nostart do_nothing.asm --output do_nothing1.bin +; 64tass --ascii --nostart do_nothing.asm --output subFolder/do_nothing2.bin +*=0 + rts + diff --git a/compiler/test/fixtures/do_nothing1.bin b/compiler/test/fixtures/do_nothing1.bin new file mode 100644 index 000000000..64845fb76 --- /dev/null +++ b/compiler/test/fixtures/do_nothing1.bin @@ -0,0 +1 @@ +` \ No newline at end of file diff --git a/compiler/test/fixtures/foo_bar.asm b/compiler/test/fixtures/foo_bar.asm new file mode 100644 index 000000000..d415b6923 --- /dev/null +++ b/compiler/test/fixtures/foo_bar.asm @@ -0,0 +1,2 @@ +bar .text "foo.bar",0 + diff --git a/compiler/test/fixtures/foo_bar.p8 b/compiler/test/fixtures/foo_bar.p8 new file mode 100644 index 000000000..e60fa8199 --- /dev/null +++ b/compiler/test/fixtures/foo_bar.p8 @@ -0,0 +1,3 @@ +foo { + str bar = "foo.bar" +} diff --git a/compiler/test/fixtures/importFromSameFolder.p8 b/compiler/test/fixtures/importFromSameFolder.p8 new file mode 100644 index 000000000..3f233b10d --- /dev/null +++ b/compiler/test/fixtures/importFromSameFolder.p8 @@ -0,0 +1,9 @@ +%import textio +%import foo_bar +main { + str myBar = "main.bar" + sub start() { + txt.print(myBar) + txt.print(foo.bar) + } +} diff --git a/compiler/test/fixtures/subFolder/do_nothing2.bin b/compiler/test/fixtures/subFolder/do_nothing2.bin new file mode 100644 index 000000000..64845fb76 --- /dev/null +++ b/compiler/test/fixtures/subFolder/do_nothing2.bin @@ -0,0 +1 @@ +` \ No newline at end of file From 23c99002c01df8bf174d200bc1663da8198eaa44 Mon Sep 17 00:00:00 2001 From: meisl Date: Sat, 17 Jul 2021 12:04:49 +0200 Subject: [PATCH 2/4] * fix #54 / step 1: relativize threw IllegalArgumentException if called on non-absolute path with absolute path as argument ("different type of path") --- .../prog8/compiler/target/cpu6502/codegen/AsmGen.kt | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/compiler/src/prog8/compiler/target/cpu6502/codegen/AsmGen.kt b/compiler/src/prog8/compiler/target/cpu6502/codegen/AsmGen.kt index 212911571..6513f0deb 100644 --- a/compiler/src/prog8/compiler/target/cpu6502/codegen/AsmGen.kt +++ b/compiler/src/prog8/compiler/target/cpu6502/codegen/AsmGen.kt @@ -18,6 +18,7 @@ import java.nio.file.Paths import java.time.LocalDate import java.time.LocalDateTime import java.util.* +import kotlin.io.path.absolute import kotlin.math.absoluteValue @@ -1315,11 +1316,14 @@ $repeatLabel lda $counterVar assemblyLines.add(sourcecode.trimEnd().trimStart('\n')) } "%asmbinary" -> { + val includedName = stmt.args[0].str!! val offset = if(stmt.args.size>1) ", ${stmt.args[1].int}" else "" val length = if(stmt.args.size>2) ", ${stmt.args[2].int}" else "" - val includedSourcePath = stmt.definingModule().source.resolveSibling(stmt.args[0].str) - val relPath = Paths.get("").relativize(includedSourcePath) - out(" .binary \"$relPath\" $offset $length") + val includedPath = stmt.definingModule().source.resolveSibling(includedName) + val pathForAssembler = Paths.get("") + .absolute() // avoid IllegalArgumentExc in case non-absolute path .relativize(absolute path) + .relativize(includedPath) + out(" .binary \"$pathForAssembler\" $offset $length") } "%breakpoint" -> { val label = "_prog8_breakpoint_${breakpointLabels.size+1}" From 402884b5ce6b6d13222c5d1eb50cbce79325c1ff Mon Sep 17 00:00:00 2001 From: meisl Date: Sat, 17 Jul 2021 12:17:31 +0200 Subject: [PATCH 3/4] * fix #54 / step 2: the path stated with assembler directive .binary must be *relative to the .asm file*, not the working directory --- .../compiler/target/cpu6502/codegen/AsmGen.kt | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/compiler/src/prog8/compiler/target/cpu6502/codegen/AsmGen.kt b/compiler/src/prog8/compiler/target/cpu6502/codegen/AsmGen.kt index 6513f0deb..2a4b30b58 100644 --- a/compiler/src/prog8/compiler/target/cpu6502/codegen/AsmGen.kt +++ b/compiler/src/prog8/compiler/target/cpu6502/codegen/AsmGen.kt @@ -1309,19 +1309,26 @@ $repeatLabel lda $counterVar } } + /** + * TODO: %asminclude and %asmbinary should be done earlier than code gen (-> put content into AST) + */ private fun translate(stmt: Directive) { when(stmt.directive) { "%asminclude" -> { - val sourcecode = loadAsmIncludeFile(stmt.args[0].str!!, stmt.definingModule().source) + val includedName = stmt.args[0].str!! + val sourcePath = stmt.definingModule().source // FIXME: %asminclude inside non-library, non-filesystem module + val sourcecode = loadAsmIncludeFile(includedName, sourcePath) assemblyLines.add(sourcecode.trimEnd().trimStart('\n')) } "%asmbinary" -> { val includedName = stmt.args[0].str!! val offset = if(stmt.args.size>1) ", ${stmt.args[1].int}" else "" val length = if(stmt.args.size>2) ", ${stmt.args[2].int}" else "" - val includedPath = stmt.definingModule().source.resolveSibling(includedName) - val pathForAssembler = Paths.get("") - .absolute() // avoid IllegalArgumentExc in case non-absolute path .relativize(absolute path) + val sourcePath = stmt.definingModule().source // FIXME: %asmbinary inside non-library, non-filesystem module + val includedPath = sourcePath.resolveSibling(includedName) + + val pathForAssembler = outputDir // 64tass needs the path *relative to the .asm file* + .absolute() // avoid IllegalArgumentExc due to non-absolute path .relativize(absolute path) .relativize(includedPath) out(" .binary \"$pathForAssembler\" $offset $length") } From b2c6274f7453ccdef7895bc41459b5af216beace Mon Sep 17 00:00:00 2001 From: meisl Date: Sat, 17 Jul 2021 12:40:50 +0200 Subject: [PATCH 4/4] * fix #54 / step 3: avoid some (= not all) complaints re the .binary filename 64tass still had/has. Actually, I don't quite understand why it still says "not the real name of the file". The 64tass docs say: > -Wno-portable > Don't warn about source portability problems. > These cross platform development annoyances are checked for: > * Case insensitive use of file names or use of short names. > * Use of backslashes for path separation instead of forward slashes. > * Use of reserved characters in file names. > * Absolute paths --- compiler/src/prog8/compiler/target/cpu6502/codegen/AsmGen.kt | 4 +++- compiler/test/TestCompilerOnImportsAndIncludes.kt | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/compiler/src/prog8/compiler/target/cpu6502/codegen/AsmGen.kt b/compiler/src/prog8/compiler/target/cpu6502/codegen/AsmGen.kt index 2a4b30b58..27ca32e1a 100644 --- a/compiler/src/prog8/compiler/target/cpu6502/codegen/AsmGen.kt +++ b/compiler/src/prog8/compiler/target/cpu6502/codegen/AsmGen.kt @@ -1327,9 +1327,11 @@ $repeatLabel lda $counterVar val sourcePath = stmt.definingModule().source // FIXME: %asmbinary inside non-library, non-filesystem module val includedPath = sourcePath.resolveSibling(includedName) - val pathForAssembler = outputDir // 64tass needs the path *relative to the .asm file* + val pathForAssembler = outputDir // #54: 64tass needs the path *relative to the .asm file* .absolute() // avoid IllegalArgumentExc due to non-absolute path .relativize(absolute path) .relativize(includedPath) + .normalize() // avoid assembler warnings (-Wportable; only some, not all) + .toString().replace('\\', '/') out(" .binary \"$pathForAssembler\" $offset $length") } "%breakpoint" -> { diff --git a/compiler/test/TestCompilerOnImportsAndIncludes.kt b/compiler/test/TestCompilerOnImportsAndIncludes.kt index e67600783..d166f92d3 100644 --- a/compiler/test/TestCompilerOnImportsAndIncludes.kt +++ b/compiler/test/TestCompilerOnImportsAndIncludes.kt @@ -117,7 +117,7 @@ class TestCompilerOnImportsAndIncludes { dynamicTest(displayName) { assumeReadableFile(p8Path) assumeReadableFile(binPath) - assertNotEquals( // the bug we're testing for (#??) was hidden if outputDir == workinDir + assertNotEquals( // the bug we're testing for (#54) was hidden if outputDir == workinDir workingDir.normalize().toAbsolutePath(), outputDir.normalize().toAbsolutePath(), "sanity check: workingDir and outputDir should not be the same folder")