cleanup SourceCode class

This commit is contained in:
Irmen de Jong 2021-10-13 18:55:56 +02:00
parent 975594703d
commit 6070afa6b6
14 changed files with 170 additions and 160 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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])
* * `<String@44c56085>` 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])
* * `<String@44c56085>` 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 `<String@44c56085>`.
*/
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)
}
}
}
/**
* Turn a plain String into a [SourceCode] object.
* [origin] will be something like `<String@44c56085>`.
*/
class Text(val text: String): SourceCode() {
override val isFromResources = false
override val origin = "<String@${System.identityHashCode(text).toString(16)}>"
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]: `<library:/x/y/z.p8>` 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]: `<library:/x/y/z.p8>` 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])
*/
}
}

View File

@ -31,7 +31,7 @@ class TestAstToSourceCode {
private fun roundTrip(module: Module): Pair<String, Module> {
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'
}

View File

@ -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 <EOL> at '<EOF>'"
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<ParseError> { parseModule(SourceCode.of(srcBad)) }
val module = parseModule(SourceCode.of(srcGood))
assertFailsWith<ParseError> { 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<ParseError>{ parseModule(SourceCode.of("""
assertFailsWith<ParseError>{ parseModule(SourceCode.Text("""
blockA {
} blockB {
}
""")) }
// block and directive
assertFailsWith<ParseError>{ parseModule(SourceCode.of("""
assertFailsWith<ParseError>{ parseModule(SourceCode.Text("""
blockB {
} %import textio
""")) }
@ -89,12 +89,12 @@ class TestProg8Parser {
// Leaving them in anyways.
// dir and block
assertFailsWith<ParseError>{ parseModule(SourceCode.of("""
assertFailsWith<ParseError>{ parseModule(SourceCode.Text("""
%import textio blockB {
}
""")) }
assertFailsWith<ParseError>{ parseModule(SourceCode.of("""
assertFailsWith<ParseError>{ 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<ParseError> { parseModule(SourceCode.of(srcText)) }
assertFailsWith<ParseError> { parseModule(SourceCode.Text(srcText)) }
try {
parseModule(SourceCode.of(srcText))
parseModule(SourceCode.Text(srcText))
} catch (e: ParseError) {
assertPosition(e.position, Regex("^<String@[0-9a-f]+>$"), 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<ParseError> { parseModule(SourceCode.fromPath(path)) }
assertFailsWith<ParseError> { 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("^<String@[0-9a-f]+>$"), 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<Directive>()[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

View File

@ -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("^<String@[0-9a-f]+>$"))
@ -33,26 +33,26 @@ class TestSourceCode {
fun testFromPathWithNonExistingPath() {
val filename = "i_do_not_exist.p8"
val path = assumeNotExists(fixturesDir, filename)
assertFailsWith<NoSuchFileException> { SourceCode.fromPath(path) }
assertFailsWith<NoSuchFileException> { SourceCode.File(path) }
}
@Test
fun testFromPathWithMissingExtension_p8() {
val pathWithoutExt = assumeNotExists(fixturesDir,"simple_main")
assumeReadableFile(fixturesDir,"simple_main.p8")
assertFailsWith<NoSuchFileException> { SourceCode.fromPath(pathWithoutExt) }
assertFailsWith<NoSuchFileException> { SourceCode.File(pathWithoutExt) }
}
@Test
fun testFromPathWithDirectory() {
assertFailsWith<AccessDeniedException> { SourceCode.fromPath(fixturesDir) }
assertFailsWith<AccessDeniedException> { 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<NoSuchFileException> { SourceCode.fromResources(pathString) }
assertFailsWith<NoSuchFileException> { SourceCode.Resource(pathString) }
}
@Test
fun testFromResourcesWithNonExistingFile_withoutLeadingSlash() {
val pathString = "prog8lib/i_do_not_exist"
assumeNotExists(resourcesDir, pathString)
assertFailsWith<NoSuchFileException> { SourceCode.fromResources(pathString) }
assertFailsWith<NoSuchFileException> { SourceCode.Resource(pathString) }
}
@Test
@ -144,7 +144,7 @@ class TestSourceCode {
fun testFromResourcesWithDirectory() {
val pathString = "/prog8lib"
assumeDirectory(resourcesDir, pathString.substring(1))
assertFailsWith<AccessDeniedException> { SourceCode.fromResources(pathString) }
assertFailsWith<AccessDeniedException> { SourceCode.Resource(pathString) }
}
}

View File

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

View File

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

View File

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