diff --git a/codeCore/src/prog8/code/Globals.kt b/codeCore/src/prog8/code/Globals.kt index 0240921ed..dcccc4a52 100644 --- a/codeCore/src/prog8/code/Globals.kt +++ b/codeCore/src/prog8/code/Globals.kt @@ -1,8 +1,31 @@ package prog8.code +import java.io.IOException +import java.nio.file.Path +import kotlin.io.path.absolute + // the automatically generated module where all string literals are interned to: const val INTERNED_STRINGS_MODULENAME = "prog8_interned_strings" // all automatically generated labels everywhere need to have the same label name prefix: const val GENERATED_LABEL_PREFIX = "p8_label_gen_" + + +/** + * Returns the absolute path of the given path, + * where links are replaced by the actual directories, + * and containing no redundant path elements. + * If the path doesn't refer to an existing directory or file on the file system, + * it is returned unchanged. + */ +fun Path.sanitize(): Path { + try { + return this.toRealPath().normalize() + } catch (_: java.nio.file.NoSuchFileException) { + return this.absolute().normalize() + //throw NoSuchFileException(this.toFile(), null, nx.reason).also { it.initCause(nx) } + } catch (iox: IOException) { + throw FileSystemException(this.toFile()).also { it.initCause(iox) } + } +} \ No newline at end of file diff --git a/codeCore/src/prog8/code/core/Position.kt b/codeCore/src/prog8/code/core/Position.kt index 7527de6a9..40928d50c 100644 --- a/codeCore/src/prog8/code/core/Position.kt +++ b/codeCore/src/prog8/code/core/Position.kt @@ -1,9 +1,9 @@ package prog8.code.core +import prog8.code.sanitize import prog8.code.source.SourceCode import java.nio.file.InvalidPathException import kotlin.io.path.Path -import kotlin.io.path.absolute data class Position(val file: String, val line: Int, val startCol: Int, val endCol: Int) { override fun toString(): String = "[$file: line $line col ${startCol+1}-${endCol+1}]" @@ -13,7 +13,7 @@ data class Position(val file: String, val line: Int, val startCol: Int, val endC if(SourceCode.isLibraryResource(file)) return "$file:$line:$startCol:" return try { - val path = Path(file).absolute().normalize().toString() + val path = Path(file).sanitize().toString() "file://$path:$line:$startCol:" } catch(_: InvalidPathException) { // this can occur on Windows when the source origin contains "invalid" characters such as ':' diff --git a/codeCore/src/prog8/code/source/ImportFileSystem.kt b/codeCore/src/prog8/code/source/ImportFileSystem.kt index 461f90c1a..d3cfc9d0c 100644 --- a/codeCore/src/prog8/code/source/ImportFileSystem.kt +++ b/codeCore/src/prog8/code/source/ImportFileSystem.kt @@ -1,10 +1,10 @@ package prog8.code.source import prog8.code.core.Position +import prog8.code.sanitize import java.nio.file.Path -import java.util.TreeMap +import java.util.* import kotlin.io.path.Path -import kotlin.io.path.absolute // Resource caching "filesystem". @@ -22,7 +22,7 @@ object ImportFileSystem { fun expandTilde(path: Path): Path = Path(expandTilde(path.toString())) fun getFile(path: Path, isLibrary: Boolean=false): SourceCode { - val normalized = path.absolute().normalize() + val normalized = path.sanitize() val cached = cache[normalized.toString()] if (cached != null) return cached @@ -48,7 +48,7 @@ object ImportFileSystem { val cached = cache[position.file] if(cached != null) return getLine(cached, position.line) - val path = Path(position.file).absolute().normalize() + val path = Path(position.file).sanitize() val cached2 = cache[path.toString()] if(cached2 != null) return getLine(cached2, position.line) diff --git a/codeCore/src/prog8/code/source/SourceCode.kt b/codeCore/src/prog8/code/source/SourceCode.kt index a950b1bbe..97998b563 100644 --- a/codeCore/src/prog8/code/source/SourceCode.kt +++ b/codeCore/src/prog8/code/source/SourceCode.kt @@ -1,5 +1,6 @@ package prog8.code.source +import prog8.code.sanitize import java.io.IOException import java.nio.file.Path import java.text.Normalizer @@ -59,7 +60,7 @@ sealed class SourceCode { private const val LIBRARYFILEPREFIX = "library:" private const val STRINGSOURCEPREFIX = "string:" val curdir: Path = Path(".").absolute() - fun relative(path: Path): Path = curdir.relativize(path.absolute()) + fun relative(path: Path): Path = curdir.relativize(path.sanitize()) fun isRegularFilesystemPath(pathString: String) = !isLibraryResource(pathString) && !isStringResource(pathString) fun isLibraryResource(path: String) = path.startsWith(LIBRARYFILEPREFIX) fun isStringResource(path: String) = path.startsWith(STRINGSOURCEPREFIX) diff --git a/codeCore/src/prog8/code/target/VMTarget.kt b/codeCore/src/prog8/code/target/VMTarget.kt index 3135f0713..1c4f234ef 100644 --- a/codeCore/src/prog8/code/target/VMTarget.kt +++ b/codeCore/src/prog8/code/target/VMTarget.kt @@ -75,7 +75,7 @@ class VMTarget: ICompilationTarget, IStringEncoding by Encoder, IMemSizer by Nor if(withExt.isReadable()) vm.runProgram(withExt.readText()) else - throw NoSuchFileException(withExt.toFile(), reason="not a .p8ir file") + throw java.nio.file.NoSuchFileException(withExt.name, null, "not a .p8ir file") } } diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/AsmGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/AsmGen.kt index bdc9cf4be..a94260b65 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/AsmGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/AsmGen.kt @@ -1,13 +1,7 @@ package prog8.codegen.cpu6502 import com.github.michaelbull.result.fold -import prog8.code.GENERATED_LABEL_PREFIX -import prog8.code.IAssemblyProgram -import prog8.code.ICodeGeneratorBackend -import prog8.code.StNode -import prog8.code.StNodeType -import prog8.code.SymbolTable -import prog8.code.SymbolTableMaker +import prog8.code.* import prog8.code.ast.* import prog8.code.core.* import prog8.code.source.ImportFileSystem @@ -15,7 +9,6 @@ import prog8.code.source.SourceCode import prog8.code.target.Cx16Target import prog8.codegen.cpu6502.assignment.* import kotlin.io.path.Path -import kotlin.io.path.absolute import kotlin.io.path.writeLines @@ -1144,8 +1137,8 @@ $repeatLabel""") val sourcePath = Path(incbin.definingBlock()!!.source.origin) val includedPath = sourcePath.resolveSibling(incbin.file) val pathForAssembler = options.outputDir // #54: 64tass needs the path *relative to the .asm file* - .absolute() - .relativize(includedPath.absolute()) + .sanitize() + .relativize(includedPath.sanitize()) .normalize() // avoid assembler warnings (-Wportable; only some, not all) .toString().replace('\\', '/') out(" .binary \"$pathForAssembler\" $offset $length") diff --git a/compiler/src/prog8/compiler/ModuleImporter.kt b/compiler/src/prog8/compiler/ModuleImporter.kt index f1302e976..f742300f4 100644 --- a/compiler/src/prog8/compiler/ModuleImporter.kt +++ b/compiler/src/prog8/compiler/ModuleImporter.kt @@ -8,6 +8,7 @@ import prog8.ast.statements.Directive import prog8.ast.statements.DirectiveArg import prog8.code.core.IErrorReporter import prog8.code.core.Position +import prog8.code.sanitize import prog8.code.source.ImportFileSystem import prog8.code.source.SourceCode import prog8.parser.Prog8Parser @@ -24,8 +25,8 @@ class ModuleImporter(private val program: Program, sourceDirs: List, libraryDirs: List) { - private val sourcePaths: List = sourceDirs.map { Path(it).absolute().normalize() }.toSortedSet().toList() - private val libraryPaths: List = libraryDirs.map { Path(it).absolute().normalize() }.toSortedSet().toList() + private val sourcePaths: List = sourceDirs.map { Path(it).sanitize() }.toSortedSet().toList() + private val libraryPaths: List = libraryDirs.map { Path(it).sanitize() }.toSortedSet().toList() fun importMainModule(filePath: Path): Result { val searchIn = (listOf(Path("").absolute()) + sourcePaths).toSortedSet() @@ -141,7 +142,7 @@ class ModuleImporter(private val program: Program, if (importingModule == null) { sourcePaths } else { - val pathFromImportingModule = (Path(importingModule.position.file).parent ?: Path("")).absolute().normalize() + val pathFromImportingModule = (Path(importingModule.position.file).parent ?: Path("")).sanitize() listOf(pathFromImportingModule) + sourcePaths } diff --git a/compiler/src/prog8/compiler/astprocessing/SimplifiedAstMaker.kt b/compiler/src/prog8/compiler/astprocessing/SimplifiedAstMaker.kt index 9437eb57b..abc89f566 100644 --- a/compiler/src/prog8/compiler/astprocessing/SimplifiedAstMaker.kt +++ b/compiler/src/prog8/compiler/astprocessing/SimplifiedAstMaker.kt @@ -10,12 +10,12 @@ import prog8.ast.expressions.* import prog8.ast.statements.* import prog8.code.ast.* import prog8.code.core.* +import prog8.code.sanitize import prog8.code.source.ImportFileSystem import prog8.code.source.SourceCode import prog8.compiler.builtinFunctionReturnType import java.io.File import kotlin.io.path.Path -import kotlin.io.path.absolute import kotlin.io.path.isRegularFile @@ -268,10 +268,10 @@ class SimplifiedAstMaker(private val program: Program, private val errors: IErro val offset: UInt? = if(directive.args.size>=2) directive.args[1].int!! else null val length: UInt? = if(directive.args.size>=3) directive.args[2].int!! else null val abspath = if(File(filename).isFile) { - Path(filename).absolute() + Path(filename).sanitize() } else { val sourcePath = Path(directive.definingModule.source.origin) - sourcePath.resolveSibling(filename).absolute() + sourcePath.resolveSibling(filename).sanitize() } if(abspath.toFile().isFile) PtIncludeBinary(abspath, offset, length, directive.position) diff --git a/compiler/test/TestCompilerOnImportsAndIncludes.kt b/compiler/test/TestCompilerOnImportsAndIncludes.kt index 36d8af3fb..c122dee1f 100644 --- a/compiler/test/TestCompilerOnImportsAndIncludes.kt +++ b/compiler/test/TestCompilerOnImportsAndIncludes.kt @@ -2,6 +2,7 @@ package prog8tests.compiler import io.kotest.assertions.withClue import io.kotest.core.spec.style.FunSpec +import io.kotest.datatest.withData import io.kotest.engine.spec.tempdir import io.kotest.matchers.shouldBe import io.kotest.matchers.shouldNotBe @@ -10,24 +11,18 @@ import prog8.ast.expressions.IdentifierReference import prog8.ast.expressions.StringLiteral import prog8.ast.statements.FunctionCallStatement import prog8.ast.statements.Label +import prog8.code.sanitize import prog8.code.target.Cx16Target import prog8tests.helpers.* -import kotlin.io.path.absolute import kotlin.io.path.name - -/** - * 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. - */ class TestCompilerOnImportsAndIncludes: FunSpec({ - val outputDir = tempdir().toPath() context("Import") { test("testImportFromSameFolder") { + val outputDir = tempdir().toPath() val filepath = assumeReadableFile(fixturesDir, "importFromSameFolder.p8") assumeReadableFile(fixturesDir, "foo_bar.p8") @@ -49,7 +44,7 @@ class TestCompilerOnImportsAndIncludes: FunSpec({ } context("AsmInclude") { - test("testAsmIncludeFromSameFolder") { + test("AsmIncludeFromSameFolder") { val filepath = assumeReadableFile(fixturesDir, "asmIncludeFromSameFolder.p8") assumeReadableFile(fixturesDir, "foo_bar.asm") @@ -89,26 +84,22 @@ class TestCompilerOnImportsAndIncludes: FunSpec({ } val tests = listOf( - Triple("same ", "asmBinaryFromSameFolder.p8", "do_nothing1.bin"), - Triple("sub", "asmBinaryFromSubFolder.p8", "subFolder/do_nothing2.bin"), + "same" to "asmBinaryFromSameFolder.p8", + "sub" to "asmBinaryFromSubFolder.p8" ) - tests.forEach { - val (where, p8Str, _) = it - test("%asmbinary from ${where}folder") { - val p8Path = assumeReadableFile(fixturesDir, p8Str) - // val binPath = assumeReadableFile(fixturesDir, binStr) + withData>({"%asmbinary from ${it.first} folder"}, tests) { (_, p8Str) -> + val p8Path = assumeReadableFile(fixturesDir, p8Str) - // the bug we're testing for (#54) was hidden if outputDir == workingDir - withClue("sanity check: workingDir and outputDir should not be the same folder") { - outputDir.absolute().normalize() shouldNotBe workingDir.absolute().normalize() - } + // the bug we're testing for (#54) was hidden if outputDir == workingDir + withClue("sanity check: workingDir and outputDir should not be the same folder") { + outputDir.sanitize() shouldNotBe workingDir.sanitize() + } - withClue("argument to assembler directive .binary " + - "should be relative to the generated .asm file (in output dir), " + - "NOT relative to .p8 neither current working dir") { - compileFile(Cx16Target(), false, p8Path.parent, p8Path.name, outputDir) shouldNotBe null - } + withClue("argument to assembler directive .binary " + + "should be relative to the generated .asm file (in output dir), " + + "NOT relative to .p8 neither current working dir") { + compileFile(Cx16Target(), false, p8Path.parent, p8Path.name, outputDir) shouldNotBe null } } } diff --git a/compiler/test/TestCompilerOptionLibdirs.kt b/compiler/test/TestCompilerOptionLibdirs.kt index d987cb431..89b7f136f 100644 --- a/compiler/test/TestCompilerOptionLibdirs.kt +++ b/compiler/test/TestCompilerOptionLibdirs.kt @@ -3,6 +3,7 @@ package prog8tests.compiler import io.kotest.core.spec.style.FunSpec import io.kotest.engine.spec.tempdir import io.kotest.matchers.shouldNotBe +import prog8.code.sanitize import prog8.code.target.Cx16Target import prog8.compiler.CompilationResult import prog8.compiler.CompilerArguments @@ -11,7 +12,6 @@ import prog8tests.helpers.assumeReadableFile import prog8tests.helpers.fixturesDir import prog8tests.helpers.workingDir import java.nio.file.Path -import kotlin.io.path.absolute /** * ATTENTION: this is just kludge! @@ -51,7 +51,7 @@ class TestCompilerOptionSourcedirs: FunSpec({ test("testAbsoluteFilePathOutsideWorkingDir") { val filepath = assumeReadableFile(fixturesDir, "ast_simple_main.p8") - compileFile(filepath.absolute(), listOf()) shouldNotBe null + compileFile(filepath.sanitize(), listOf()) shouldNotBe null } test("testFilePathOutsideWorkingDirRelativeToWorkingDir") { diff --git a/syntax-files/IDEA/Prog8.xml b/syntax-files/IDEA/Prog8.xml index 62defe5d8..e335436c6 100644 --- a/syntax-files/IDEA/Prog8.xml +++ b/syntax-files/IDEA/Prog8.xml @@ -14,10 +14,10 @@ - + - + - \ No newline at end of file + diff --git a/virtualmachine/src/prog8/vm/SysCalls.kt b/virtualmachine/src/prog8/vm/SysCalls.kt index fc11a0aa0..47a2700ec 100644 --- a/virtualmachine/src/prog8/vm/SysCalls.kt +++ b/virtualmachine/src/prog8/vm/SysCalls.kt @@ -555,7 +555,7 @@ object SysCalls { Syscall.DIRECTORY -> { // no arguments val directory = Path("") - println("Directory listing for ${directory.absolute().normalize()}") + println("Directory listing for ${directory}") directory.listDirectoryEntries().sorted().forEach { println("${it.toFile().length()}\t${it.normalize()}") }