* refactor ModuleImporter: throw the proper NoSuchFileException if import isn't found, return SourceCode? from both, tryGetModuleFromResource and tryGetModuleFromFile

This commit is contained in:
meisl 2021-06-21 13:16:32 +02:00
parent af209ad50e
commit fa5ecd6495
2 changed files with 37 additions and 34 deletions

View File

@ -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("<<<implicit-import>>>", 0, 0, 0))
), Position("<<<implicit-import>>>", 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
}
}

View File

@ -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) {