* no more scattering magic "@embedded@" all over the place: add SourceCode.isFromResources, *change Module.source from type Path to type SourceCode*

This commit is contained in:
meisl 2021-07-09 17:32:33 +02:00
parent b0073ac933
commit 19bb56df47
9 changed files with 62 additions and 37 deletions

View File

@ -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")
}

View File

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

View File

@ -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")
}

View File

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

View File

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

View File

@ -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<Statement>,
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
}

View File

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

View File

@ -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 = "<String@123beef>"
.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

View File

@ -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 = "<String@${System.identityHashCode(text).toString(16)}>"
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)