diff --git a/compiler/src/prog8/compiler/Compiler.kt b/compiler/src/prog8/compiler/Compiler.kt index c256f4850..5cb3cc0e8 100644 --- a/compiler/src/prog8/compiler/Compiler.kt +++ b/compiler/src/prog8/compiler/Compiler.kt @@ -22,6 +22,7 @@ import prog8.parser.moduleName import java.io.File import java.io.InputStream import java.nio.file.Path +import kotlin.io.path.Path import kotlin.system.measureTimeMillis @@ -183,7 +184,10 @@ private fun parseImports(filepath: Path, importer.importModule(filepath) errors.report() - val importedFiles = programAst.modules.filter { !it.source.startsWith("@embedded@") }.map { it.source } + val importedFiles = programAst.modules + .mapNotNull { it.source } + .filter { !it.isFromResources } // TODO: parseImports/importedFiles - maybe rather `source.isFromFilesystem`? + .map { Path(it.pathString()) } val compilerOptions = determineCompilationOptions(programAst, compTarget) if (compilerOptions.launcher == LauncherType.BASIC && compilerOptions.output != OutputType.PRG) throw ParsingFailedError("${programAst.modules.first().position} BASIC launcher requires output type PRG.") @@ -357,14 +361,14 @@ fun printAst(programAst: Program) { println() } -fun loadAsmIncludeFile(filename: String, source: Path): String { - return if (filename.startsWith("library:")) { +fun loadAsmIncludeFile(filename: String, sourcePath: Path): String { + return if (filename.startsWith("library:")) { // FIXME: is the prefix "library:" or is it "@embedded@"? val resource = tryGetEmbeddedResource(filename.substring(8)) ?: throw IllegalArgumentException("library file '$filename' not found") resource.bufferedReader().use { it.readText() } } else { // first try in the isSameAs folder as where the containing file was imported from - val sib = source.resolveSibling(filename) + val sib = sourcePath.resolveSibling(filename) if (sib.toFile().isFile) sib.toFile().readText() else @@ -372,6 +376,9 @@ fun loadAsmIncludeFile(filename: String, source: Path): String { } } +/** + * Handle via SourceCode + */ internal fun tryGetEmbeddedResource(name: String): InputStream? { return object{}.javaClass.getResourceAsStream("/prog8lib/$name") } diff --git a/compiler/src/prog8/compiler/astprocessing/AstChecker.kt b/compiler/src/prog8/compiler/astprocessing/AstChecker.kt index ea184b71f..20c9a830f 100644 --- a/compiler/src/prog8/compiler/astprocessing/AstChecker.kt +++ b/compiler/src/prog8/compiler/astprocessing/AstChecker.kt @@ -17,6 +17,7 @@ import prog8.compiler.target.Cx16Target import prog8.compiler.target.ICompilationTarget import java.io.CharConversionException import java.io.File +import kotlin.io.path.* import java.util.* internal class AstChecker(private val program: Program, @@ -728,11 +729,23 @@ internal class AstChecker(private val program: Program, } private fun checkFileExists(directive: Directive, filename: String) { - var definingModule = directive.parent + if (File(filename).isFile) + return + + var definingModule = directive.parent // TODO: why not just use directive.definingModule() here? while (definingModule !is Module) definingModule = definingModule.parent - if (!(filename.startsWith("library:") || definingModule.source.resolveSibling(filename).toFile().isFile || File(filename).isFile)) - errors.err("included file not found: $filename", directive.position) + if (definingModule.isLibrary()) + return + + val s = definingModule.source?.pathString() + if (s != null) { + val sourceFileCandidate = Path(s).resolveSibling(filename).toFile() + if (sourceFileCandidate.isFile) + return + } + + errors.err("included file not found: $filename", directive.position) } override fun visit(array: ArrayLiteralValue) { diff --git a/compiler/src/prog8/compiler/target/cpu6502/codegen/AsmGen.kt b/compiler/src/prog8/compiler/target/cpu6502/codegen/AsmGen.kt index 212911571..cc55baed0 100644 --- a/compiler/src/prog8/compiler/target/cpu6502/codegen/AsmGen.kt +++ b/compiler/src/prog8/compiler/target/cpu6502/codegen/AsmGen.kt @@ -1311,13 +1311,17 @@ $repeatLabel lda $counterVar private fun translate(stmt: Directive) { when(stmt.directive) { "%asminclude" -> { - val sourcecode = loadAsmIncludeFile(stmt.args[0].str!!, stmt.definingModule().source) + // TODO: handle %asminclude with SourceCode + val sourcePath = Path.of(stmt.definingModule().source!!.pathString()) // FIXME: %asminclude inside non-library, non-filesystem module + val sourcecode = loadAsmIncludeFile(stmt.args[0].str!!, sourcePath) assemblyLines.add(sourcecode.trimEnd().trimStart('\n')) } "%asmbinary" -> { val offset = if(stmt.args.size>1) ", ${stmt.args[1].int}" else "" val length = if(stmt.args.size>2) ", ${stmt.args[2].int}" else "" - val includedSourcePath = stmt.definingModule().source.resolveSibling(stmt.args[0].str) + // TODO: handle %asmbinary with SourceCode + val sourcePath = Path.of(stmt.definingModule().source!!.pathString()) // FIXME: %asmbinary inside non-library, non-filesystem module + val includedSourcePath = sourcePath.resolveSibling(stmt.args[0].str) val relPath = Paths.get("").relativize(includedSourcePath) out(" .binary \"$relPath\" $offset $length") } diff --git a/compiler/test/AsmgenTests.kt b/compiler/test/AsmgenTests.kt index 8deeae874..20a77c71d 100644 --- a/compiler/test/AsmgenTests.kt +++ b/compiler/test/AsmgenTests.kt @@ -74,7 +74,7 @@ locallabel: val varInBlock = VarDecl(VarDeclType.VAR, DataType.UWORD, ZeropageWish.DONTCARE, null, "var_outside", null, false, false, false, Position.DUMMY) val block = Block("main", null, mutableListOf(labelInBlock, varInBlock, subroutine), false, Position.DUMMY) - val module = Module("test", mutableListOf(block), Position.DUMMY, Path.of("")) + val module = Module("test", mutableListOf(block), Position.DUMMY, null) module.linkParents(ParentSentinel) val program = Program("test", mutableListOf(module), DummyFunctions(), DummyMemsizer()) module.program = program diff --git a/compiler/test/TestMemory.kt b/compiler/test/TestMemory.kt index b9ca856d5..d0e926aa6 100644 --- a/compiler/test/TestMemory.kt +++ b/compiler/test/TestMemory.kt @@ -98,7 +98,7 @@ class TestMemory { val target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), Position.DUMMY) val assignment = Assignment(target, NumericLiteralValue.optimalInteger(0, Position.DUMMY), Position.DUMMY) val subroutine = Subroutine("test", emptyList(), emptyList(), emptyList(), emptyList(), emptySet(), null, false, false, mutableListOf(decl, assignment), Position.DUMMY) - val module = Module("test", mutableListOf(subroutine), Position.DUMMY, Path.of("")) + val module = Module("test", mutableListOf(subroutine), Position.DUMMY, null) module.linkParents(ParentSentinel) return target } @@ -117,7 +117,7 @@ class TestMemory { val target = AssignTarget(IdentifierReference(listOf("address"), Position.DUMMY), null, null, Position.DUMMY) val assignment = Assignment(target, NumericLiteralValue.optimalInteger(0, Position.DUMMY), Position.DUMMY) val subroutine = Subroutine("test", emptyList(), emptyList(), emptyList(), emptyList(), emptySet(), null, false, false, mutableListOf(decl, assignment), Position.DUMMY) - val module = Module("test", mutableListOf(subroutine), Position.DUMMY, Path.of("")) + val module = Module("test", mutableListOf(subroutine), Position.DUMMY, null) val program = Program("test", mutableListOf(module), DummyFunctions(), DummyMemsizer()) module.linkParents(ParentSentinel) assertTrue(C64Target.isInRegularRAM(target, program)) @@ -130,7 +130,7 @@ class TestMemory { val target = AssignTarget(IdentifierReference(listOf("address"), Position.DUMMY), null, null, Position.DUMMY) val assignment = Assignment(target, NumericLiteralValue.optimalInteger(0, Position.DUMMY), Position.DUMMY) val subroutine = Subroutine("test", emptyList(), emptyList(), emptyList(), emptyList(), emptySet(), null, false, false, mutableListOf(decl, assignment), Position.DUMMY) - val module = Module("test", mutableListOf(subroutine), Position.DUMMY, Path.of("")) + val module = Module("test", mutableListOf(subroutine), Position.DUMMY, null) val program = Program("test", mutableListOf(module), DummyFunctions(), DummyMemsizer()) module.linkParents(ParentSentinel) assertTrue(C64Target.isInRegularRAM(target, program)) @@ -143,7 +143,7 @@ class TestMemory { val target = AssignTarget(IdentifierReference(listOf("address"), Position.DUMMY), null, null, Position.DUMMY) val assignment = Assignment(target, NumericLiteralValue.optimalInteger(0, Position.DUMMY), Position.DUMMY) val subroutine = Subroutine("test", emptyList(), emptyList(), emptyList(), emptyList(), emptySet(), null, false, false, mutableListOf(decl, assignment), Position.DUMMY) - val module = Module("test", mutableListOf(subroutine), Position.DUMMY, Path.of("")) + val module = Module("test", mutableListOf(subroutine), Position.DUMMY, null) val program = Program("test", mutableListOf(module), DummyFunctions(), DummyMemsizer()) module.linkParents(ParentSentinel) assertFalse(C64Target.isInRegularRAM(target, program)) @@ -156,7 +156,7 @@ class TestMemory { val target = AssignTarget(null, arrayindexed, null, Position.DUMMY) val assignment = Assignment(target, NumericLiteralValue.optimalInteger(0, Position.DUMMY), Position.DUMMY) val subroutine = Subroutine("test", emptyList(), emptyList(), emptyList(), emptyList(), emptySet(), null, false, false, mutableListOf(decl, assignment), Position.DUMMY) - val module = Module("test", mutableListOf(subroutine), Position.DUMMY, Path.of("")) + val module = Module("test", mutableListOf(subroutine), Position.DUMMY, null) val program = Program("test", mutableListOf(module), DummyFunctions(), DummyMemsizer()) module.linkParents(ParentSentinel) assertTrue(C64Target.isInRegularRAM(target, program)) @@ -170,7 +170,7 @@ class TestMemory { val target = AssignTarget(null, arrayindexed, null, Position.DUMMY) val assignment = Assignment(target, NumericLiteralValue.optimalInteger(0, Position.DUMMY), Position.DUMMY) val subroutine = Subroutine("test", emptyList(), emptyList(), emptyList(), emptyList(), emptySet(), null, false, false, mutableListOf(decl, assignment), Position.DUMMY) - val module = Module("test", mutableListOf(subroutine), Position.DUMMY, Path.of("")) + val module = Module("test", mutableListOf(subroutine), Position.DUMMY, null) val program = Program("test", mutableListOf(module), DummyFunctions(), DummyMemsizer()) module.linkParents(ParentSentinel) assertTrue(C64Target.isInRegularRAM(target, program)) @@ -184,7 +184,7 @@ class TestMemory { val target = AssignTarget(null, arrayindexed, null, Position.DUMMY) val assignment = Assignment(target, NumericLiteralValue.optimalInteger(0, Position.DUMMY), Position.DUMMY) val subroutine = Subroutine("test", emptyList(), emptyList(), emptyList(), emptyList(), emptySet(), null, false, false, mutableListOf(decl, assignment), Position.DUMMY) - val module = Module("test", mutableListOf(subroutine), Position.DUMMY, Path.of("")) + val module = Module("test", mutableListOf(subroutine), Position.DUMMY, null) val program = Program("test", mutableListOf(module), DummyFunctions(), DummyMemsizer()) module.linkParents(ParentSentinel) assertFalse(C64Target.isInRegularRAM(target, program)) diff --git a/compilerAst/src/prog8/ast/AstToplevel.kt b/compilerAst/src/prog8/ast/AstToplevel.kt index 1d57f8508..81436cdac 100644 --- a/compilerAst/src/prog8/ast/AstToplevel.kt +++ b/compilerAst/src/prog8/ast/AstToplevel.kt @@ -5,6 +5,7 @@ import prog8.ast.expressions.* import prog8.ast.statements.* import prog8.ast.walk.AstWalker import prog8.ast.walk.IAstVisitor +import prog8.parser.SourceCode import java.nio.file.Path import java.nio.file.Paths import kotlin.io.path.name @@ -265,7 +266,7 @@ class Program(val name: String, init { // insert a container module for all interned strings later if(modules.firstOrNull()?.name != internedStringsModuleName) { - val internedStringsModule = Module(internedStringsModuleName, mutableListOf(), Position.DUMMY, Path.of("")) + val internedStringsModule = Module(internedStringsModuleName, mutableListOf(), Position.DUMMY, null) modules.add(0, internedStringsModule) val block = Block(internedStringsModuleName, null, mutableListOf(), true, Position.DUMMY) internedStringsModule.statements.add(block) @@ -342,7 +343,7 @@ class Program(val name: String, open class Module(override val name: String, override var statements: MutableList, override val position: Position, - val source: Path) : Node, INameScope { + val source: SourceCode?) : Node, INameScope { override lateinit var parent: Node lateinit var program: Program @@ -370,15 +371,7 @@ open class Module(override val name: String, fun accept(visitor: IAstVisitor) = visitor.visit(this) fun accept(visitor: AstWalker, parent: Node) = visitor.visit(this, parent) - companion object { - fun pathForResource(resourcePath: String): Path { - return Paths.get("@embedded@/$resourcePath") - } - - fun isLibrary(source: Path) = source.name=="" || source.startsWith("@embedded@/") - } - - fun isLibrary() = isLibrary(source) + fun isLibrary() = (source == null) || source.isFromResources } diff --git a/compilerAst/src/prog8/ast/antlr/Antlr2Kotlin.kt b/compilerAst/src/prog8/ast/antlr/Antlr2Kotlin.kt index d7abc240d..1792215b2 100644 --- a/compilerAst/src/prog8/ast/antlr/Antlr2Kotlin.kt +++ b/compilerAst/src/prog8/ast/antlr/Antlr2Kotlin.kt @@ -9,6 +9,7 @@ import prog8.ast.base.* import prog8.ast.expressions.* import prog8.ast.statements.* import prog8.parser.Prog8ANTLRParser +import prog8.parser.SourceCode import java.io.CharConversionException import java.io.File import java.nio.file.Path @@ -18,10 +19,10 @@ import java.nio.file.Path private data class NumericLiteral(val number: Number, val datatype: DataType) -internal fun Prog8ANTLRParser.ModuleContext.toAst(name: String, source: Path, encoding: IStringEncoding) : Module { +internal fun Prog8ANTLRParser.ModuleContext.toAst(name: String, source: SourceCode, encoding: IStringEncoding) : Module { val nameWithoutSuffix = if(name.endsWith(".p8")) name.substringBeforeLast('.') else name val directives = this.directive().map { it.toAst() } - val blocks = this.block().map { it.toAst(Module.isLibrary(source), encoding) } + val blocks = this.block().map { it.toAst(isInLibrary = source.isFromResources, encoding) } return Module(nameWithoutSuffix, (directives + blocks).toMutableList(), toPosition(), source) } diff --git a/compilerAst/src/prog8/parser/Prog8Parser.kt b/compilerAst/src/prog8/parser/Prog8Parser.kt index 0cde17230..4d080a8ea 100644 --- a/compilerAst/src/prog8/parser/Prog8Parser.kt +++ b/compilerAst/src/prog8/parser/Prog8Parser.kt @@ -6,7 +6,6 @@ import prog8.ast.antlr.toAst import prog8.ast.base.Position import prog8.ast.statements.Block import prog8.ast.statements.Directive -import kotlin.io.path.Path open class ParsingFailedError(override var message: String) : Exception(message) @@ -43,19 +42,18 @@ object Prog8Parser { return module } - private class ParsedModule(src: SourceCode) : Module( + private class ParsedModule(source: SourceCode) : Module( // FIXME: hacking together a name for the module: - name = src.pathString() + name = source.pathString() .substringBeforeLast(".") // must also work with an origin = "" .substringAfterLast("/") .substringAfterLast("\\") .replace("String@", "anonymous_"), - // FIXME: hacking together a path - source = Path(src.pathString()), statements = mutableListOf(), - position = Position(src.origin, 1, 0, 0) + position = Position(source.origin, 1, 0, 0), + source ) { - val provenance = Pair(src, Triple(1, 0, 0)) + val provenance = Pair(source, Triple(1, 0, 0)) /** * Adds a [Directive] to [statements] and diff --git a/compilerAst/src/prog8/parser/SourceCode.kt b/compilerAst/src/prog8/parser/SourceCode.kt index 005d90fbf..44f4fdb25 100644 --- a/compilerAst/src/prog8/parser/SourceCode.kt +++ b/compilerAst/src/prog8/parser/SourceCode.kt @@ -18,6 +18,12 @@ abstract class SourceCode { */ internal abstract fun getCharStream(): CharStream + /** + * Whether this [SourceCode] instance was created by + * factory method [fromResources] + */ + abstract val isFromResources: Boolean + /** * Where this [SourceCode] instance came from. * This can be one of the following: @@ -58,6 +64,7 @@ abstract class SourceCode { */ fun of(text: String): SourceCode { return object : SourceCode() { + override val isFromResources = false override val origin = "" override fun getCharStream(): CharStream { return CharStreams.fromString(text) @@ -86,6 +93,7 @@ abstract class SourceCode { throw AccessDeniedException(path.toFile(), reason = "Is not readable") val normalized = path.normalize() return object : SourceCode() { + override val isFromResources = false override val origin = normalized.absolutePathString() override fun getCharStream(): CharStream { return CharStreams.fromPath(normalized) @@ -108,6 +116,7 @@ abstract class SourceCode { reason = "looked in resources rooted at $rscRoot") } return object : SourceCode() { + override val isFromResources = true override val origin = "@embedded@$normalized" override fun getCharStream(): CharStream { val inpStr = object{}.javaClass.getResourceAsStream(normalized)