diff --git a/compiler/src/prog8/compiler/Compiler.kt b/compiler/src/prog8/compiler/Compiler.kt index 27472c2cc..d9d9f214c 100644 --- a/compiler/src/prog8/compiler/Compiler.kt +++ b/compiler/src/prog8/compiler/Compiler.kt @@ -18,6 +18,7 @@ import prog8.compiler.target.ICompilationTarget import prog8.compiler.target.asmGeneratorFor import prog8.optimizer.* import prog8.parser.ParsingFailedError +import prog8.parser.SourceCode import prog8.parser.SourceCode.Companion.libraryFilePrefix import java.io.File import java.nio.file.Path @@ -185,9 +186,8 @@ fun parseImports(filepath: Path, importedModuleResult.onFailure { throw it } errors.report() - val importedFiles = programAst.modules - .mapNotNull { it.source } - .filter { !it.isFromResources } // TODO: parseImports/importedFiles - maybe rather `source.isFromFilesystem`? + val importedFiles = programAst.modules.map { it.source } + .filter { it !is SourceCode.Generated && !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) diff --git a/compiler/src/prog8/compiler/ModuleImporter.kt b/compiler/src/prog8/compiler/ModuleImporter.kt index 2e5ec5fca..f8979f9fa 100644 --- a/compiler/src/prog8/compiler/ModuleImporter.kt +++ b/compiler/src/prog8/compiler/ModuleImporter.kt @@ -42,7 +42,7 @@ class ModuleImporter(private val program: Program, val logMsg = "importing '${filePath.nameWithoutExtension}' (from file $srcPath)" println(logMsg) - return Ok(importModule(SourceCode.fromPath(srcPath))) + return Ok(importModule(SourceCode.File(srcPath))) } fun importLibraryModule(name: String): Module? { @@ -110,11 +110,11 @@ class ModuleImporter(private val program: Program, private fun tryGetModuleFromResource(name: String, compilationTargetName: String): SourceCode? { // try target speficic first try { - return SourceCode.fromResources("/prog8lib/$compilationTargetName/$name") + return SourceCode.Resource("/prog8lib/$compilationTargetName/$name") } catch (e: FileSystemException) { } try { - return SourceCode.fromResources("/prog8lib/$name") + return SourceCode.Resource("/prog8lib/$name") } catch (e: FileSystemException) { } return null @@ -134,7 +134,7 @@ class ModuleImporter(private val program: Program, locations.forEach { try { - return SourceCode.fromPath(it.resolve(fileName)) + return SourceCode.File(it.resolve(fileName)) } catch (e: NoSuchFileException) { } } diff --git a/compiler/src/prog8/compiler/astprocessing/AstChecker.kt b/compiler/src/prog8/compiler/astprocessing/AstChecker.kt index cafce0d3c..511ba12a3 100644 --- a/compiler/src/prog8/compiler/astprocessing/AstChecker.kt +++ b/compiler/src/prog8/compiler/astprocessing/AstChecker.kt @@ -13,6 +13,7 @@ import prog8.compiler.ZeropageType import prog8.compiler.functions.BuiltinFunctions import prog8.compiler.functions.builtinFunctionReturnType import prog8.compiler.target.ICompilationTarget +import prog8.parser.SourceCode import java.io.CharConversionException import java.io.File import java.util.* @@ -726,20 +727,16 @@ internal class AstChecker(private val program: Program, 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 (definingModule.isLibrary) + val definingModule = directive.definingModule + if (definingModule.isLibrary || definingModule.source is SourceCode.Generated) 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) + val s = definingModule.source.pathString() + val sourceFileCandidate = Path(s).resolveSibling(filename).toFile() + if (sourceFileCandidate.isFile) + return + else + 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 3ff00f288..f383eb1be 100644 --- a/compiler/src/prog8/compiler/target/cpu6502/codegen/AsmGen.kt +++ b/compiler/src/prog8/compiler/target/cpu6502/codegen/AsmGen.kt @@ -1325,7 +1325,7 @@ $repeatLabel lda $counterVar "%asminclude" -> { // TODO: handle %asminclude with SourceCode val includedName = stmt.args[0].str!! - val sourcePath = Path(stmt.definingModule.source!!.pathString()) // FIXME: %asminclude inside non-library, non-filesystem module + val sourcePath = Path(stmt.definingModule.source.pathString()) // FIXME: %asminclude inside non-library, non-filesystem module loadAsmIncludeFile(includedName, sourcePath).fold( success = { assemblyLines.add(it.trimEnd().trimStart('\n')) }, failure = { errors.err(it.toString(), stmt.position) } @@ -1335,7 +1335,7 @@ $repeatLabel lda $counterVar val includedName = stmt.args[0].str!! 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 sourcePath = Path(stmt.definingModule.source!!.pathString()) // FIXME: %asmbinary inside non-library, non-filesystem module + val sourcePath = Path(stmt.definingModule.source.pathString()) // FIXME: %asmbinary inside non-library, non-filesystem module val includedPath = sourcePath.resolveSibling(includedName) val pathForAssembler = outputDir // #54: 64tass needs the path *relative to the .asm file* .absolute() // avoid IllegalArgumentExc due to non-absolute path .relativize(absolute path) diff --git a/compiler/test/AsmgenTests.kt b/compiler/test/AsmgenTests.kt index f1f385f37..c0440c54c 100644 --- a/compiler/test/AsmgenTests.kt +++ b/compiler/test/AsmgenTests.kt @@ -15,6 +15,7 @@ import prog8.compiler.* import prog8.compiler.target.C64Target import prog8.compiler.target.c64.C64MachineDefinition import prog8.compiler.target.cpu6502.codegen.AsmGen +import prog8.parser.SourceCode import prog8tests.helpers.DummyFunctions import prog8tests.helpers.DummyMemsizer import java.nio.file.Path @@ -67,7 +68,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, null) + val module = Module("test", mutableListOf(block), Position.DUMMY, SourceCode.Generated("test")) val program = Program("test", DummyFunctions, DummyMemsizer) .addModule(module) module.linkParents(program.namespace) diff --git a/compiler/test/TestMemory.kt b/compiler/test/TestMemory.kt index 6f6fef236..07982be04 100644 --- a/compiler/test/TestMemory.kt +++ b/compiler/test/TestMemory.kt @@ -14,6 +14,7 @@ import prog8.ast.expressions.NumericLiteralValue import prog8.ast.expressions.PrefixExpression import prog8.ast.statements.* import prog8.compiler.target.C64Target +import prog8.parser.SourceCode import prog8tests.helpers.DummyFunctions import prog8tests.helpers.DummyMemsizer import kotlin.test.assertFalse @@ -91,7 +92,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, null) + val module = Module("test", mutableListOf(subroutine), Position.DUMMY, SourceCode.Generated("test")) module.linkParents(program.namespace) return target } @@ -110,7 +111,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, null) + val module = Module("test", mutableListOf(subroutine), Position.DUMMY, SourceCode.Generated("test")) val program = Program("test", DummyFunctions, DummyMemsizer) .addModule(module) module.linkParents(program.namespace) @@ -124,7 +125,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, null) + val module = Module("test", mutableListOf(subroutine), Position.DUMMY, SourceCode.Generated("test")) val program = Program("test", DummyFunctions, DummyMemsizer) .addModule(module) module.linkParents(program.namespace) @@ -138,7 +139,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, null) + val module = Module("test", mutableListOf(subroutine), Position.DUMMY, SourceCode.Generated("test")) val program = Program("test", DummyFunctions, DummyMemsizer) .addModule(module) module.linkParents(program.namespace) @@ -152,7 +153,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, null) + val module = Module("test", mutableListOf(subroutine), Position.DUMMY, SourceCode.Generated("test")) val program = Program("test", DummyFunctions, DummyMemsizer) .addModule(module) module.linkParents(program.namespace) @@ -167,7 +168,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, null) + val module = Module("test", mutableListOf(subroutine), Position.DUMMY, SourceCode.Generated("test")) val program = Program("test", DummyFunctions, DummyMemsizer) .addModule(module) module.linkParents(program.namespace) @@ -182,7 +183,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, null) + val module = Module("test", mutableListOf(subroutine), Position.DUMMY, SourceCode.Generated("test")) val program = Program("test", DummyFunctions, DummyMemsizer) .addModule(module) module.linkParents(program.namespace) diff --git a/compilerAst/src/prog8/ast/AstToplevel.kt b/compilerAst/src/prog8/ast/AstToplevel.kt index dd8dd937f..3a28bc837 100644 --- a/compilerAst/src/prog8/ast/AstToplevel.kt +++ b/compilerAst/src/prog8/ast/AstToplevel.kt @@ -246,7 +246,8 @@ class Program(val name: String, init { // insert a container module for all interned strings later - val internedStringsModule = Module(internedStringsModuleName, mutableListOf(), Position.DUMMY, null) + val internedStringsModule = Module(internedStringsModuleName, mutableListOf(), + Position.DUMMY, SourceCode.Generated(internedStringsModuleName)) val block = Block(internedStringsModuleName, null, mutableListOf(), true, Position.DUMMY) internedStringsModule.statements.add(block) @@ -350,7 +351,7 @@ class Program(val name: String, open class Module(override val name: String, override var statements: MutableList, final override val position: Position, - val source: SourceCode?) : Node, INameScope { + val source: SourceCode) : Node, INameScope { override lateinit var parent: Node lateinit var program: Program @@ -380,7 +381,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) - val isLibrary get() = (source == null) || source.isFromResources + val isLibrary get() = source.isFromResources } diff --git a/compilerAst/src/prog8/parser/SourceCode.kt b/compilerAst/src/prog8/parser/SourceCode.kt index 44436b44a..df1975aef 100644 --- a/compilerAst/src/prog8/parser/SourceCode.kt +++ b/compilerAst/src/prog8/parser/SourceCode.kt @@ -3,6 +3,7 @@ package prog8.parser import org.antlr.v4.runtime.CharStream import org.antlr.v4.runtime.CharStreams import java.io.File +import java.io.IOException import java.nio.file.Path import kotlin.io.path.absolutePathString import kotlin.io.path.exists @@ -13,7 +14,7 @@ import kotlin.io.path.isReadable * Encapsulates - and ties together - actual source code (=text) * and its [origin]. */ -abstract class SourceCode { +sealed class SourceCode { /** * To be used *only* by the parser (as input to a TokenStream). @@ -23,16 +24,16 @@ abstract class SourceCode { /** * Whether this [SourceCode] instance was created by - * factory method [fromResources] + * factory method [Resource] */ abstract val isFromResources: Boolean /** * Where this [SourceCode] instance came from. * This can be one of the following: - * * a normal string representation of a [java.nio.file.Path], if it originates from a file (see [fromPath]) - * * `` if was created via [of] - * * `library:/x/y/z.ext` if it is a library file that was loaded from resources (see [fromResources]) + * * a normal string representation of a [java.nio.file.Path], if it originates from a file (see [File]) + * * `` if was created via [String] + * * `library:/x/y/z.ext` if it is a library file that was loaded from resources (see [Resource]) */ abstract val origin: String @@ -42,9 +43,7 @@ abstract class SourceCode { * This is really just [origin] with any stuff removed that would render it an invalid path name. * (Note: a *valid* path name does NOT mean that the denoted file or folder *exists*) */ - fun pathString() = - origin - .substringAfter("<").substringBeforeLast(">") // or from plain string? + fun pathString() = origin.substringAfter("<").substringBeforeLast(">") // or from plain string? /** * The source code as plain string. @@ -58,42 +57,39 @@ abstract class SourceCode { */ final override fun toString() = "${this.javaClass.name}[${this.origin}]" - // "static" factory methods companion object { /** * filename prefix to designate library files that will be retreived from internal resources rather than disk */ const val libraryFilePrefix = "library:" + } - /** - * Turn a plain String into a [SourceCode] object. - * [origin] will be something like ``. - */ - fun of(text: String): SourceCode { - return object : SourceCode() { - override val isFromResources = false - override val origin = "" - override fun getCharStream(): CharStream { - return CharStreams.fromString(text) - } - } - } + /** + * Turn a plain String into a [SourceCode] object. + * [origin] will be something like ``. + */ + class Text(val text: String): SourceCode() { + override val isFromResources = false + override val origin = "" + override fun getCharStream(): CharStream = CharStreams.fromString(text) + } - /** - * Get [SourceCode] from the file represented by the specified Path. - * This does not actually *access* the file, but it does check - * whether it - * * exists - * * is a regular file (ie: not a directory) - * * and is actually readable - * - * [origin] will be the given path in absolute and normalized form. - * @throws NoSuchFileException if the file does not exist - * @throws AccessDeniedException if the given path points to a directory or the file is non-readable for some other reason - */ - fun fromPath(path: Path): SourceCode { - val normalized = path.normalize() + /** + * Get [SourceCode] from the file represented by the specified Path. + * This does not actually *access* the file, but it does check + * whether it + * * exists + * * is a regular file (ie: not a directory) + * * and is actually readable + * + * [origin] will be the given path in absolute and normalized form. + * @throws NoSuchFileException if the file does not exist + * @throws AccessDeniedException if the given path points to a directory or the file is non-readable for some other reason + */ + class File(path: Path): SourceCode() { + private val normalized = path.normalize() + init { val file = normalized.toFile() if (!path.exists()) throw NoSuchFileException(file) @@ -101,40 +97,48 @@ abstract class SourceCode { throw AccessDeniedException(file, reason = "Not a file but a directory") if (!path.isReadable()) throw AccessDeniedException(file, reason = "Is not readable") - return object : SourceCode() { - override val isFromResources = false - override val origin = normalized.absolutePathString() - override fun getCharStream(): CharStream { - return CharStreams.fromPath(normalized) - } - } } - /** - * [origin]: `` for a given `pathString` of "x/y/z.p8" - */ - fun fromResources(pathString: String): SourceCode { - val path = Path.of(pathString).normalize() - val sep = "/" - val normalized = sep + path.toMutableList().joinToString(sep) - val rscURL = object{}.javaClass.getResource(normalized) + override val isFromResources = false + override val origin = normalized.absolutePathString() + override fun getCharStream(): CharStream = CharStreams.fromPath(normalized) + } + + /** + * [origin]: `` for a given `pathString` of "x/y/z.p8" + */ + class Resource(pathString: String): SourceCode() { + private val normalized = "/" + Path.of(pathString).normalize().toMutableList().joinToString("/") + + init { + val rscURL = object {}.javaClass.getResource(normalized) if (rscURL == null) { - val rscRoot = object{}.javaClass.getResource("/") + val rscRoot = object {}.javaClass.getResource("/") throw NoSuchFileException( File(normalized), - reason = "looked in resources rooted at $rscRoot") - } - return object : SourceCode() { - override val isFromResources = true - override val origin = "$libraryFilePrefix$normalized" - override fun getCharStream(): CharStream { - val inpStr = object {}.javaClass.getResourceAsStream(normalized) - return CharStreams.fromStream(inpStr) - } + reason = "looked in resources rooted at $rscRoot" + ) } } - // TODO: possibly more, like fromURL(..) + override val isFromResources = true + override val origin = "$libraryFilePrefix$normalized" + override fun getCharStream(): CharStream { + val inpStr = object {}.javaClass.getResourceAsStream(normalized) + return CharStreams.fromStream(inpStr) + } + } + + /** + * SourceCode for internally generated nodes (usually Modules) + */ + class Generated(name: String) : SourceCode() { + override fun getCharStream(): CharStream = throw IOException("generated code doesn't have a stream to read") + override val isFromResources: Boolean = false + override val origin: String = name + } + + // TODO: possibly more, like fromURL(..) /* // For `jar:..` URLs // see https://stackoverflow.com/questions/22605666/java-access-files-in-jar-causes-java-nio-file-filesystemnotfoundexception var url = URL("jar:file:/E:/x16/prog8(meisl)/compiler/build/libs/prog8compiler-7.0-BETA3-all.jar!/prog8lib/c64/textio.p8") @@ -143,5 +147,4 @@ abstract class SourceCode { val fs = FileSystems.newFileSystem(URI.create(parts[0]), mutableMapOf(Pair("", "")) ) val path = fs.getPath(parts[1]) */ - } } diff --git a/compilerAst/test/TestAstToSourceCode.kt b/compilerAst/test/TestAstToSourceCode.kt index bf1918101..82fa0384b 100644 --- a/compilerAst/test/TestAstToSourceCode.kt +++ b/compilerAst/test/TestAstToSourceCode.kt @@ -31,7 +31,7 @@ class TestAstToSourceCode { private fun roundTrip(module: Module): Pair { val generatedText = generateP8(module) try { - val parsedAgain = parseModule(SourceCode.of(generatedText)) + val parsedAgain = parseModule(SourceCode.Text(generatedText)) return Pair(generatedText, parsedAgain) } catch (e: ParseError) { assert(false) { "should produce valid Prog8 but threw $e" } @@ -41,7 +41,7 @@ class TestAstToSourceCode { @Test fun testMentionsInternedStringsModule() { - val orig = SourceCode.of("\n") + val orig = SourceCode.Text("\n") val (txt, _) = roundTrip(parseModule(orig)) // assertContains has *actual* first! assertContains(txt, Regex(";.*$internedStringsModuleName")) @@ -49,7 +49,7 @@ class TestAstToSourceCode { @Test fun testImportDirectiveWithLib() { - val orig = SourceCode.of("%import textio\n") + val orig = SourceCode.Text("%import textio\n") val (txt, _) = roundTrip(parseModule(orig)) // assertContains has *actual* first! assertContains(txt, Regex("%import +textio")) @@ -57,7 +57,7 @@ class TestAstToSourceCode { @Test fun testImportDirectiveWithUserModule() { - val orig = SourceCode.of("%import my_own_stuff\n") + val orig = SourceCode.Text("%import my_own_stuff\n") val (txt, _) = roundTrip(parseModule(orig)) // assertContains has *actual* first! assertContains(txt, Regex("%import +my_own_stuff")) @@ -66,7 +66,7 @@ class TestAstToSourceCode { @Test fun testStringLiteral_noAlt() { - val orig = SourceCode.of(""" + val orig = SourceCode.Text(""" main { str s = "fooBar\n" } @@ -78,7 +78,7 @@ class TestAstToSourceCode { @Test fun testStringLiteral_withAlt() { - val orig = SourceCode.of(""" + val orig = SourceCode.Text(""" main { str sAlt = @"fooBar\n" } @@ -90,7 +90,7 @@ class TestAstToSourceCode { @Test fun testCharLiteral_noAlt() { - val orig = SourceCode.of(""" + val orig = SourceCode.Text(""" main { ubyte c = 'x' } @@ -102,7 +102,7 @@ class TestAstToSourceCode { @Test fun testCharLiteral_withAlt() { - val orig = SourceCode.of(""" + val orig = SourceCode.Text(""" main { ubyte cAlt = @'x' } diff --git a/compilerAst/test/TestProg8Parser.kt b/compilerAst/test/TestProg8Parser.kt index 7e3c6d3fe..b5786b8a9 100644 --- a/compilerAst/test/TestProg8Parser.kt +++ b/compilerAst/test/TestProg8Parser.kt @@ -39,7 +39,7 @@ class TestProg8Parser { @Test fun `is not required - #40, fixed by #45`() { val nl = "\n" // say, Unix-style (different flavours tested elsewhere) - val src = SourceCode.of("foo {" + nl + "}") // source ends with '}' (= NO newline, issue #40) + val src = SourceCode.Text("foo {" + nl + "}") // source ends with '}' (= NO newline, issue #40) // #40: Prog8ANTLRParser would report (throw) "missing at ''" val module = parseModule(src) @@ -50,7 +50,7 @@ class TestProg8Parser { fun `is still accepted - #40, fixed by #45`() { val nl = "\n" // say, Unix-style (different flavours tested elsewhere) val srcText = "foo {" + nl + "}" + nl // source does end with a newline (issue #40) - val module = parseModule(SourceCode.of(srcText)) + val module = parseModule(SourceCode.Text(srcText)) assertEquals(1, module.statements.size) } } @@ -65,22 +65,22 @@ class TestProg8Parser { // GOOD: 2nd block `bar` does start on a new line; however, a nl at the very end ain't needed val srcGood = "foo {" + nl + "}" + nl + "bar {" + nl + "}" - assertFailsWith { parseModule(SourceCode.of(srcBad)) } - val module = parseModule(SourceCode.of(srcGood)) + assertFailsWith { parseModule(SourceCode.Text(srcBad)) } + val module = parseModule(SourceCode.Text(srcGood)) assertEquals(2, module.statements.size) } @Test fun `is required between two Blocks or Directives - #47`() { // block and block - assertFailsWith{ parseModule(SourceCode.of(""" + assertFailsWith{ parseModule(SourceCode.Text(""" blockA { } blockB { } """)) } // block and directive - assertFailsWith{ parseModule(SourceCode.of(""" + assertFailsWith{ parseModule(SourceCode.Text(""" blockB { } %import textio """)) } @@ -89,12 +89,12 @@ class TestProg8Parser { // Leaving them in anyways. // dir and block - assertFailsWith{ parseModule(SourceCode.of(""" + assertFailsWith{ parseModule(SourceCode.Text(""" %import textio blockB { } """)) } - assertFailsWith{ parseModule(SourceCode.of(""" + assertFailsWith{ parseModule(SourceCode.Text(""" %import textio %import syslib """)) } } @@ -123,7 +123,7 @@ class TestProg8Parser { "}" + nlUnix // end with newline (see testModuleSourceNeedNotEndWithNewline) - val module = parseModule(SourceCode.of(srcText)) + val module = parseModule(SourceCode.Text(srcText)) assertEquals(2, module.statements.size) } } @@ -142,7 +142,7 @@ class TestProg8Parser { blockA { } """ - val module = parseModule(SourceCode.of(srcText)) + val module = parseModule(SourceCode.Text(srcText)) assertEquals(1, module.statements.size) } @@ -159,7 +159,7 @@ class TestProg8Parser { blockB { } """ - val module = parseModule(SourceCode.of(srcText)) + val module = parseModule(SourceCode.Text(srcText)) assertEquals(2, module.statements.size) } @@ -174,7 +174,7 @@ class TestProg8Parser { ; comment """ - val module = parseModule(SourceCode.of(srcText)) + val module = parseModule(SourceCode.Text(srcText)) assertEquals(1, module.statements.size) } } @@ -187,7 +187,7 @@ class TestProg8Parser { val importedNoExt = assumeNotExists(fixturesDir, "i_do_not_exist") assumeNotExists(fixturesDir, "i_do_not_exist.p8") val text = "%import ${importedNoExt.name}" - val module = parseModule(SourceCode.of(text)) + val module = parseModule(SourceCode.Text(text)) assertEquals(1, module.statements.size) } @@ -198,14 +198,14 @@ class TestProg8Parser { inner class EmptySourcecode { @Test fun `from an empty string should result in empty Module`() { - val module = parseModule(SourceCode.of("")) + val module = parseModule(SourceCode.Text("")) assertEquals(0, module.statements.size) } @Test fun `from an empty file should result in empty Module`() { val path = assumeReadableFile(fixturesDir, "empty.p8") - val module = parseModule(SourceCode.fromPath(path)) + val module = parseModule(SourceCode.File(path)) assertEquals(0, module.statements.size) } } @@ -218,7 +218,7 @@ class TestProg8Parser { main { } """.trimIndent() - val module = parseModule(SourceCode.of(srcText)) + val module = parseModule(SourceCode.Text(srcText)) // Note: assertContains has *actual* as first param assertContains(module.name, Regex("^anonymous_[0-9a-f]+$")) @@ -227,7 +227,7 @@ class TestProg8Parser { @Test fun `parsed from a file`() { val path = assumeReadableFile(fixturesDir, "simple_main.p8") - val module = parseModule(SourceCode.fromPath(path)) + val module = parseModule(SourceCode.File(path)) assertEquals(path.nameWithoutExtension, module.name) } } @@ -287,9 +287,9 @@ class TestProg8Parser { fun `in ParseError from bad string source code`() { val srcText = "bad * { }\n" - assertFailsWith { parseModule(SourceCode.of(srcText)) } + assertFailsWith { parseModule(SourceCode.Text(srcText)) } try { - parseModule(SourceCode.of(srcText)) + parseModule(SourceCode.Text(srcText)) } catch (e: ParseError) { assertPosition(e.position, Regex("^$"), 1, 4, 4) } @@ -299,9 +299,9 @@ class TestProg8Parser { fun `in ParseError from bad file source code`() { val path = assumeReadableFile(fixturesDir, "file_with_syntax_error.p8") - assertFailsWith { parseModule(SourceCode.fromPath(path)) } + assertFailsWith { parseModule(SourceCode.File(path)) } try { - parseModule(SourceCode.fromPath(path)) + parseModule(SourceCode.File(path)) } catch (e: ParseError) { assertPosition(e.position, path.absolutePathString(), 2, 6) // TODO: endCol wrong } @@ -313,7 +313,7 @@ class TestProg8Parser { main { } """.trimIndent() - val module = parseModule(SourceCode.of(srcText)) + val module = parseModule(SourceCode.Text(srcText)) assertPositionOf(module, Regex("^$"), 1, 0) // TODO: endCol wrong } @@ -321,7 +321,7 @@ class TestProg8Parser { fun `of Module parsed from a file`() { val path = assumeReadableFile(fixturesDir, "simple_main.p8") - val module = parseModule(SourceCode.fromPath(path)) + val module = parseModule(SourceCode.File(path)) assertPositionOf(module, path.absolutePathString(), 1, 0) // TODO: endCol wrong } @@ -329,7 +329,7 @@ class TestProg8Parser { fun `of non-root Nodes parsed from file`() { val path = assumeReadableFile(fixturesDir, "simple_main.p8") - val module = parseModule(SourceCode.fromPath(path)) + val module = parseModule(SourceCode.File(path)) val mpf = module.position.file assertPositionOf(module, path.absolutePathString(), 1, 0) // TODO: endCol wrong @@ -360,7 +360,7 @@ class TestProg8Parser { } } """.trimIndent() - val module = parseModule(SourceCode.of(srcText)) + val module = parseModule(SourceCode.Text(srcText)) val mpf = module.position.file val targetDirective = module.statements.filterIsInstance()[0] @@ -388,7 +388,7 @@ class TestProg8Parser { @Test fun `in argument position, no altEnc`() { - val src = SourceCode.of(""" + val src = SourceCode.Text(""" main { sub start() { chrout('\n') @@ -409,7 +409,7 @@ class TestProg8Parser { @Test fun `on rhs of block-level var decl, no AltEnc`() { - val src = SourceCode.of(""" + val src = SourceCode.Text(""" main { ubyte c = 'x' } @@ -426,7 +426,7 @@ class TestProg8Parser { @Test fun `on rhs of block-level const decl, with AltEnc`() { - val src = SourceCode.of(""" + val src = SourceCode.Text(""" main { const ubyte c = @'x' } @@ -443,7 +443,7 @@ class TestProg8Parser { @Test fun `on rhs of subroutine-level var decl, no AltEnc`() { - val src = SourceCode.of(""" + val src = SourceCode.Text(""" main { sub start() { ubyte c = 'x' @@ -463,7 +463,7 @@ class TestProg8Parser { @Test fun `on rhs of subroutine-level const decl, with AltEnc`() { - val src = SourceCode.of(""" + val src = SourceCode.Text(""" main { sub start() { const ubyte c = @'x' @@ -487,7 +487,7 @@ class TestProg8Parser { @Test fun `in for-loops`() { - val module = parseModule(SourceCode.of(""" + val module = parseModule(SourceCode.Text(""" main { sub start() { ubyte ub diff --git a/compilerAst/test/TestSourceCode.kt b/compilerAst/test/TestSourceCode.kt index 1597b7ad7..c012e031a 100644 --- a/compilerAst/test/TestSourceCode.kt +++ b/compilerAst/test/TestSourceCode.kt @@ -22,7 +22,7 @@ class TestSourceCode { val text = """ main { } """.trimIndent() - val src = SourceCode.of(text) + val src = SourceCode.Text(text) val actualText = src.getCharStream().toString() assertContains(src.origin, Regex("^$")) @@ -33,26 +33,26 @@ class TestSourceCode { fun testFromPathWithNonExistingPath() { val filename = "i_do_not_exist.p8" val path = assumeNotExists(fixturesDir, filename) - assertFailsWith { SourceCode.fromPath(path) } + assertFailsWith { SourceCode.File(path) } } @Test fun testFromPathWithMissingExtension_p8() { val pathWithoutExt = assumeNotExists(fixturesDir,"simple_main") assumeReadableFile(fixturesDir,"simple_main.p8") - assertFailsWith { SourceCode.fromPath(pathWithoutExt) } + assertFailsWith { SourceCode.File(pathWithoutExt) } } @Test fun testFromPathWithDirectory() { - assertFailsWith { SourceCode.fromPath(fixturesDir) } + assertFailsWith { SourceCode.File(fixturesDir) } } @Test fun testFromPathWithExistingPath() { val filename = "simple_main.p8" val path = assumeReadableFile(fixturesDir, filename) - val src = SourceCode.fromPath(path) + val src = SourceCode.File(path) val expectedOrigin = path.normalize().absolutePathString() assertEquals(expectedOrigin, src.origin) @@ -64,7 +64,7 @@ class TestSourceCode { val filename = "simple_main.p8" val path = Path(".", "test", "..", "test", "fixtures", filename) val srcFile = assumeReadableFile(path).toFile() - val src = SourceCode.fromPath(path) + val src = SourceCode.File(path) val expectedOrigin = path.normalize().absolutePathString() assertEquals(expectedOrigin, src.origin) @@ -75,7 +75,7 @@ class TestSourceCode { fun testFromResourcesWithExistingP8File_withoutLeadingSlash() { val pathString = "prog8lib/math.p8" val srcFile = assumeReadableFile(resourcesDir, pathString).toFile() - val src = SourceCode.fromResources(pathString) + val src = SourceCode.Resource(pathString) assertEquals("$libraryFilePrefix/$pathString", src.origin) assertEquals(srcFile.readText(), src.asString()) @@ -85,7 +85,7 @@ class TestSourceCode { fun testFromResourcesWithExistingP8File_withLeadingSlash() { val pathString = "/prog8lib/math.p8" val srcFile = assumeReadableFile(resourcesDir, pathString.substring(1)).toFile() - val src = SourceCode.fromResources(pathString) + val src = SourceCode.Resource(pathString) assertEquals("$libraryFilePrefix$pathString", src.origin) assertEquals(srcFile.readText(), src.asString()) @@ -95,7 +95,7 @@ class TestSourceCode { fun testFromResourcesWithExistingAsmFile_withoutLeadingSlash() { val pathString = "prog8lib/math.asm" val srcFile = assumeReadableFile(resourcesDir, pathString).toFile() - val src = SourceCode.fromResources(pathString) + val src = SourceCode.Resource(pathString) assertEquals("$libraryFilePrefix/$pathString", src.origin) assertEquals(srcFile.readText(), src.asString()) @@ -106,7 +106,7 @@ class TestSourceCode { fun testFromResourcesWithExistingAsmFile_withLeadingSlash() { val pathString = "/prog8lib/math.asm" val srcFile = assumeReadableFile(resourcesDir, pathString.substring(1)).toFile() - val src = SourceCode.fromResources(pathString) + val src = SourceCode.Resource(pathString) assertEquals("$libraryFilePrefix$pathString", src.origin) assertEquals(srcFile.readText(), src.asString()) @@ -116,7 +116,7 @@ class TestSourceCode { fun testFromResourcesWithNonNormalizedPath() { val pathString = "/prog8lib/../prog8lib/math.p8" val srcFile = assumeReadableFile(resourcesDir, pathString.substring(1)).toFile() - val src = SourceCode.fromResources(pathString) + val src = SourceCode.Resource(pathString) assertEquals("$libraryFilePrefix/prog8lib/math.p8", src.origin) assertEquals(srcFile.readText(), src.asString()) @@ -129,14 +129,14 @@ class TestSourceCode { val pathString = "/prog8lib/i_do_not_exist" assumeNotExists(resourcesDir, pathString.substring(1)) - assertFailsWith { SourceCode.fromResources(pathString) } + assertFailsWith { SourceCode.Resource(pathString) } } @Test fun testFromResourcesWithNonExistingFile_withoutLeadingSlash() { val pathString = "prog8lib/i_do_not_exist" assumeNotExists(resourcesDir, pathString) - assertFailsWith { SourceCode.fromResources(pathString) } + assertFailsWith { SourceCode.Resource(pathString) } } @Test @@ -144,7 +144,7 @@ class TestSourceCode { fun testFromResourcesWithDirectory() { val pathString = "/prog8lib" assumeDirectory(resourcesDir, pathString.substring(1)) - assertFailsWith { SourceCode.fromResources(pathString) } + assertFailsWith { SourceCode.Resource(pathString) } } } diff --git a/compilerAst/test/ast/ProgramTests.kt b/compilerAst/test/ast/ProgramTests.kt index e01e44324..16059ee3d 100644 --- a/compilerAst/test/ast/ProgramTests.kt +++ b/compilerAst/test/ast/ProgramTests.kt @@ -11,6 +11,7 @@ import prog8.ast.Module import prog8.ast.Program import prog8.ast.base.Position import prog8.ast.internedStringsModuleName +import prog8.parser.SourceCode import prog8tests.helpers.DummyFunctions import prog8tests.helpers.DummyMemsizer import kotlin.test.assertContains @@ -39,7 +40,7 @@ class ProgramTests { @Test fun withEmptyModule() { val program = Program("foo", DummyFunctions, DummyMemsizer) - val m1 = Module("bar", mutableListOf(), Position.DUMMY, null) + val m1 = Module("bar", mutableListOf(), Position.DUMMY, SourceCode.Generated("bar")) val retVal = program.addModule(m1) @@ -73,15 +74,15 @@ class ProgramTests { @Test fun withForeignModule() { val program = Program("foo", DummyFunctions, DummyMemsizer) - val m = Module("bar", mutableListOf(), Position.DUMMY, null) + val m = Module("bar", mutableListOf(), Position.DUMMY, SourceCode.Generated("bar")) assertFailsWith { program.moveModuleToFront(m) } } @Test fun withFirstOfPreviouslyAddedModules() { val program = Program("foo", DummyFunctions, DummyMemsizer) - val m1 = Module("bar", mutableListOf(), Position.DUMMY, null) - val m2 = Module("qmbl", mutableListOf(), Position.DUMMY, null) + val m1 = Module("bar", mutableListOf(), Position.DUMMY, SourceCode.Generated("bar")) + val m2 = Module("qmbl", mutableListOf(), Position.DUMMY, SourceCode.Generated("qmbl")) program.addModule(m1) program.addModule(m2) @@ -92,8 +93,8 @@ class ProgramTests { @Test fun withSecondOfPreviouslyAddedModules() { val program = Program("foo", DummyFunctions, DummyMemsizer) - val m1 = Module("bar", mutableListOf(), Position.DUMMY, null) - val m2 = Module("qmbl", mutableListOf(), Position.DUMMY, null) + val m1 = Module("bar", mutableListOf(), Position.DUMMY, SourceCode.Generated("bar")) + val m2 = Module("qmbl", mutableListOf(), Position.DUMMY, SourceCode.Generated("qmbl")) program.addModule(m1) program.addModule(m2) diff --git a/docs/source/todo.rst b/docs/source/todo.rst index ca5aac3fe..f79ba3bd1 100644 --- a/docs/source/todo.rst +++ b/docs/source/todo.rst @@ -4,7 +4,6 @@ TODO For next compiler release ^^^^^^^^^^^^^^^^^^^^^^^^^ - can we derive module.name from module.source (taking just the filename base)? -- can Position.file be a Path- making the source variable for nodes unnecessary? Blocked by Commander-x16 v39 release diff --git a/examples/test.p8 b/examples/test.p8 index 665e629a0..e52d7a5c9 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -1,7 +1,14 @@ -%option enable_floats +%import textio + main { - sub start() { - float[] cs = 1 to 42 ; values are computed at compile time - cs[0] = 23 ; keep optimizer from removing it - } + str myBar = "main.bar" + +foo_bar: + %asminclude "compiler/test/fixtures/foo_bar.asm22" ; FIXME: should be accessible from inside start() but give assembler error + + sub start() { + txt.print(myBar) + txt.print(&foo_bar) + return + } }