mirror of
https://github.com/irmen/prog8.git
synced 2025-02-05 09:33:46 +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
|
package prog8.parser
|
||||||
|
|
||||||
import org.antlr.v4.runtime.*
|
|
||||||
import prog8.ast.IStringEncoding
|
import prog8.ast.IStringEncoding
|
||||||
import prog8.ast.Module
|
import prog8.ast.Module
|
||||||
import prog8.ast.Program
|
import prog8.ast.Program
|
||||||
@ -8,18 +7,14 @@ import prog8.ast.base.Position
|
|||||||
import prog8.ast.base.SyntaxError
|
import prog8.ast.base.SyntaxError
|
||||||
import prog8.ast.statements.Directive
|
import prog8.ast.statements.Directive
|
||||||
import prog8.ast.statements.DirectiveArg
|
import prog8.ast.statements.DirectiveArg
|
||||||
|
import java.io.File
|
||||||
import kotlin.io.FileSystemException
|
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.Path // TODO: use kotlin.io.paths.Path instead
|
||||||
import java.nio.file.Paths // 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('.')
|
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,
|
class ModuleImporter(private val program: Program,
|
||||||
private val encoder: IStringEncoding,
|
private val encoder: IStringEncoding,
|
||||||
@ -28,7 +23,7 @@ class ModuleImporter(private val program: Program,
|
|||||||
|
|
||||||
fun importModule(filePath: Path): Module {
|
fun importModule(filePath: Path): Module {
|
||||||
print("importing '${moduleName(filePath.fileName)}'")
|
print("importing '${moduleName(filePath.fileName)}'")
|
||||||
if(filePath.parent!=null) {
|
if (filePath.parent != null) { // TODO: use Path.relativize
|
||||||
var importloc = filePath.toString()
|
var importloc = filePath.toString()
|
||||||
val curdir = Paths.get("").toAbsolutePath().toString()
|
val curdir = Paths.get("").toAbsolutePath().toString()
|
||||||
if(importloc.startsWith(curdir))
|
if(importloc.startsWith(curdir))
|
||||||
@ -49,7 +44,7 @@ class ModuleImporter(private val program: Program,
|
|||||||
lines.asSequence()
|
lines.asSequence()
|
||||||
.mapIndexed { i, it -> i to it }
|
.mapIndexed { i, it -> i to it }
|
||||||
.filter { (it.second as? Directive)?.directive == "%import" }
|
.filter { (it.second as? Directive)?.directive == "%import" }
|
||||||
.forEach { executeImportDirective(it.second as Directive, filePath) }
|
.forEach { executeImportDirective(it.second as Directive, module) }
|
||||||
|
|
||||||
module.statements = lines
|
module.statements = lines
|
||||||
return module
|
return module
|
||||||
@ -59,13 +54,12 @@ class ModuleImporter(private val program: Program,
|
|||||||
val import = Directive("%import", listOf(
|
val import = Directive("%import", listOf(
|
||||||
DirectiveArg("", name, 42, position = Position("<<<implicit-import>>>", 0, 0, 0))
|
DirectiveArg("", name, 42, position = Position("<<<implicit-import>>>", 0, 0, 0))
|
||||||
), 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 {
|
//private fun importModule(stream: CharStream, modulePath: Path, isLibrary: Boolean): Module {
|
||||||
val parser = Prog8Parser
|
private fun importModule(src: SourceCode) : Module {
|
||||||
val sourceText = stream.toString()
|
val moduleAst = Prog8Parser.parseModule(src)
|
||||||
val moduleAst = parser.parseModule(SourceCode.of(sourceText))
|
|
||||||
moduleAst.program = program
|
moduleAst.program = program
|
||||||
moduleAst.linkParents(program.namespace)
|
moduleAst.linkParents(program.namespace)
|
||||||
program.modules.add(moduleAst)
|
program.modules.add(moduleAst)
|
||||||
@ -75,13 +69,13 @@ class ModuleImporter(private val program: Program,
|
|||||||
lines.asSequence()
|
lines.asSequence()
|
||||||
.mapIndexed { i, it -> i to it }
|
.mapIndexed { i, it -> i to it }
|
||||||
.filter { (it.second as? Directive)?.directive == "%import" }
|
.filter { (it.second as? Directive)?.directive == "%import" }
|
||||||
.forEach { executeImportDirective(it.second as Directive, modulePath) }
|
.forEach { executeImportDirective(it.second as Directive, moduleAst) }
|
||||||
|
|
||||||
moduleAst.statements = lines
|
moduleAst.statements = lines
|
||||||
return moduleAst
|
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)
|
if(import.directive!="%import" || import.args.size!=1 || import.args[0].name==null)
|
||||||
throw SyntaxError("invalid import directive", import.position)
|
throw SyntaxError("invalid import directive", import.position)
|
||||||
val moduleName = import.args[0].name!!
|
val moduleName = import.args[0].name!!
|
||||||
@ -90,19 +84,19 @@ class ModuleImporter(private val program: Program,
|
|||||||
|
|
||||||
val existing = program.modules.singleOrNull { it.name == moduleName }
|
val existing = program.modules.singleOrNull { it.name == moduleName }
|
||||||
if(existing!=null)
|
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 =
|
val importedModule =
|
||||||
if (srcCode != null) { // found in resources
|
if (srcCode != null) {
|
||||||
// load the module from the embedded resource
|
|
||||||
println("importing '$moduleName' (library): ${srcCode.origin}")
|
println("importing '$moduleName' (library): ${srcCode.origin}")
|
||||||
val path = Path.of(URL(srcCode.origin).file)
|
importModule(srcCode)
|
||||||
importModule(srcCode.getCharStream(), path)
|
} else {
|
||||||
} else {
|
srcCode = tryGetModuleFromFile(moduleName, importingModule)
|
||||||
val modulePath = tryGetModuleFromFile(moduleName, source, import.position)
|
if (srcCode == null)
|
||||||
importModule(modulePath)
|
throw NoSuchFileException(File("$moduleName.p8"))
|
||||||
}
|
importModule(srcCode)
|
||||||
|
}
|
||||||
|
|
||||||
removeDirectivesFromImportedModule(importedModule)
|
removeDirectivesFromImportedModule(importedModule)
|
||||||
return importedModule
|
return importedModule
|
||||||
@ -130,18 +124,27 @@ class ModuleImporter(private val program: Program,
|
|||||||
return null
|
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 fileName = "$name.p8"
|
||||||
val libpaths = libdirs.map {Path.of(it)}
|
val libpaths = libdirs.map { Path.of(it) }
|
||||||
val locations =
|
val locations =
|
||||||
(if(source.toString().isEmpty()) libpaths else libpaths.drop(1) + listOf(source.parent ?: Path.of("."))) +
|
if (importingModule == null) { // <=> imported from library module
|
||||||
listOf(Paths.get(Paths.get("").toAbsolutePath().toString(), "prog8lib"))
|
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 {
|
locations.forEach {
|
||||||
val file = pathFrom(it.toString(), fileName)
|
try {
|
||||||
if (Files.isReadable(file)) return file
|
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.Module
|
||||||
import prog8.ast.antlr.toAst
|
import prog8.ast.antlr.toAst
|
||||||
import prog8.ast.base.Position
|
import prog8.ast.base.Position
|
||||||
import java.nio.file.Path
|
import kotlin.io.path.Path
|
||||||
|
|
||||||
|
|
||||||
open class ParsingFailedError(override var message: String) : Exception(message)
|
open class ParsingFailedError(override var message: String) : Exception(message)
|
||||||
@ -41,7 +41,7 @@ object Prog8Parser {
|
|||||||
val parseTree = parser.module()
|
val parseTree = parser.module()
|
||||||
val moduleName = "anonymous"
|
val moduleName = "anonymous"
|
||||||
|
|
||||||
val module = parseTree.toAst(moduleName, pathFrom(""), PetsciiEncoding)
|
val module = parseTree.toAst(moduleName, Path(""), PetsciiEncoding)
|
||||||
// TODO: use Module ctor directly
|
// TODO: use Module ctor directly
|
||||||
|
|
||||||
for (statement in module.statements) {
|
for (statement in module.statements) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user