mirror of
https://github.com/irmen/prog8.git
synced 2024-12-24 16:29:21 +00:00
* refactor ModuleImporter: throw the proper NoSuchFileException if import isn't found, return SourceCode? from both, tryGetModuleFromResource and tryGetModuleFromFile
This commit is contained in:
parent
af209ad50e
commit
fa5ecd6495
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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) {
|
||||
|
Loading…
Reference in New Issue
Block a user