From fa5ecd6495222272f9d85064c8fb8e5550de87a2 Mon Sep 17 00:00:00 2001 From: meisl Date: Mon, 21 Jun 2021 13:16:32 +0200 Subject: [PATCH] * refactor ModuleImporter: throw the proper NoSuchFileException if import isn't found, return SourceCode? from both, tryGetModuleFromResource and tryGetModuleFromFile --- compilerAst/src/prog8/parser/ModuleParsing.kt | 67 ++++++++++--------- compilerAst/src/prog8/parser/Prog8Parser.kt | 4 +- 2 files changed, 37 insertions(+), 34 deletions(-) diff --git a/compilerAst/src/prog8/parser/ModuleParsing.kt b/compilerAst/src/prog8/parser/ModuleParsing.kt index 69dd07820..d54bc6925 100644 --- a/compilerAst/src/prog8/parser/ModuleParsing.kt +++ b/compilerAst/src/prog8/parser/ModuleParsing.kt @@ -1,6 +1,5 @@ package prog8.parser -import org.antlr.v4.runtime.* import prog8.ast.IStringEncoding import prog8.ast.Module import prog8.ast.Program @@ -8,18 +7,14 @@ import prog8.ast.base.Position import prog8.ast.base.SyntaxError import prog8.ast.statements.Directive import prog8.ast.statements.DirectiveArg +import java.io.File import kotlin.io.FileSystemException -import java.net.URL -import java.nio.file.FileSystems -import java.nio.file.Files import java.nio.file.Path // TODO: use kotlin.io.paths.Path instead import java.nio.file.Paths // TODO: use kotlin.io.paths.Path instead fun moduleName(fileName: Path) = fileName.toString().substringBeforeLast('.') -internal fun pathFrom(stringPath: String, vararg rest: String): Path = FileSystems.getDefault().getPath(stringPath, *rest) - class ModuleImporter(private val program: Program, private val encoder: IStringEncoding, @@ -28,7 +23,7 @@ class ModuleImporter(private val program: Program, fun importModule(filePath: Path): Module { print("importing '${moduleName(filePath.fileName)}'") - if(filePath.parent!=null) { + if (filePath.parent != null) { // TODO: use Path.relativize var importloc = filePath.toString() val curdir = Paths.get("").toAbsolutePath().toString() if(importloc.startsWith(curdir)) @@ -49,7 +44,7 @@ class ModuleImporter(private val program: Program, lines.asSequence() .mapIndexed { i, it -> i to it } .filter { (it.second as? Directive)?.directive == "%import" } - .forEach { executeImportDirective(it.second as Directive, filePath) } + .forEach { executeImportDirective(it.second as Directive, module) } module.statements = lines return module @@ -59,13 +54,12 @@ class ModuleImporter(private val program: Program, val import = Directive("%import", listOf( DirectiveArg("", name, 42, position = Position("<<>>", 0, 0, 0)) ), Position("<<>>", 0, 0, 0)) - return executeImportDirective(import, Paths.get("")) + return executeImportDirective(import, null) } - private fun importModule(stream: CharStream, modulePath: Path): Module { - val parser = Prog8Parser - val sourceText = stream.toString() - val moduleAst = parser.parseModule(SourceCode.of(sourceText)) + //private fun importModule(stream: CharStream, modulePath: Path, isLibrary: Boolean): Module { + private fun importModule(src: SourceCode) : Module { + val moduleAst = Prog8Parser.parseModule(src) moduleAst.program = program moduleAst.linkParents(program.namespace) program.modules.add(moduleAst) @@ -75,13 +69,13 @@ class ModuleImporter(private val program: Program, lines.asSequence() .mapIndexed { i, it -> i to it } .filter { (it.second as? Directive)?.directive == "%import" } - .forEach { executeImportDirective(it.second as Directive, modulePath) } + .forEach { executeImportDirective(it.second as Directive, moduleAst) } moduleAst.statements = lines return moduleAst } - private fun executeImportDirective(import: Directive, source: Path): Module? { + private fun executeImportDirective(import: Directive, importingModule: Module?): Module? { if(import.directive!="%import" || import.args.size!=1 || import.args[0].name==null) throw SyntaxError("invalid import directive", import.position) val moduleName = import.args[0].name!! @@ -90,19 +84,19 @@ class ModuleImporter(private val program: Program, val existing = program.modules.singleOrNull { it.name == moduleName } if(existing!=null) - return null + return null // TODO: why return null instead of Module instance? - val srcCode = tryGetModuleFromResource("$moduleName.p8", compilationTargetName) + var srcCode = tryGetModuleFromResource("$moduleName.p8", compilationTargetName) val importedModule = - if (srcCode != null) { // found in resources - // load the module from the embedded resource + if (srcCode != null) { println("importing '$moduleName' (library): ${srcCode.origin}") - val path = Path.of(URL(srcCode.origin).file) - importModule(srcCode.getCharStream(), path) - } else { - val modulePath = tryGetModuleFromFile(moduleName, source, import.position) - importModule(modulePath) - } + importModule(srcCode) + } else { + srcCode = tryGetModuleFromFile(moduleName, importingModule) + if (srcCode == null) + throw NoSuchFileException(File("$moduleName.p8")) + importModule(srcCode) + } removeDirectivesFromImportedModule(importedModule) return importedModule @@ -130,18 +124,27 @@ class ModuleImporter(private val program: Program, return null } - private fun tryGetModuleFromFile(name: String, source: Path, position: Position?): Path { + private fun tryGetModuleFromFile(name: String, importingModule: Module?): SourceCode? { val fileName = "$name.p8" - val libpaths = libdirs.map {Path.of(it)} + val libpaths = libdirs.map { Path.of(it) } val locations = - (if(source.toString().isEmpty()) libpaths else libpaths.drop(1) + listOf(source.parent ?: Path.of("."))) + - listOf(Paths.get(Paths.get("").toAbsolutePath().toString(), "prog8lib")) + if (importingModule == null) { // <=> imported from library module + libpaths + } else { + libpaths.drop(1) + // TODO: why drop the first? + // FIXME: won't work until Prog8Parser is fixed s.t. it fully initialzes the modules it returns + listOf(Path.of(importingModule.position.file).parent ?: Path.of(".")) + + listOf(Path.of(".", "prog8lib")) + } locations.forEach { - val file = pathFrom(it.toString(), fileName) - if (Files.isReadable(file)) return file + try { + return SourceCode.fromPath(it.resolve(fileName)) + } catch (e: NoSuchFileException) { + } } - throw ParsingFailedError("$position Import: no module source file '$fileName' found (I've looked in: embedded libs and $locations)") + //throw ParsingFailedError("$position Import: no module source file '$fileName' found (I've looked in: embedded libs and $locations)") + return null } } diff --git a/compilerAst/src/prog8/parser/Prog8Parser.kt b/compilerAst/src/prog8/parser/Prog8Parser.kt index 45c684d60..96e341abe 100644 --- a/compilerAst/src/prog8/parser/Prog8Parser.kt +++ b/compilerAst/src/prog8/parser/Prog8Parser.kt @@ -4,7 +4,7 @@ import org.antlr.v4.runtime.* import prog8.ast.Module import prog8.ast.antlr.toAst import prog8.ast.base.Position -import java.nio.file.Path +import kotlin.io.path.Path open class ParsingFailedError(override var message: String) : Exception(message) @@ -41,7 +41,7 @@ object Prog8Parser { val parseTree = parser.module() val moduleName = "anonymous" - val module = parseTree.toAst(moduleName, pathFrom(""), PetsciiEncoding) + val module = parseTree.toAst(moduleName, Path(""), PetsciiEncoding) // TODO: use Module ctor directly for (statement in module.statements) {