1
0
mirror of https://github.com/KarolS/millfork.git synced 2025-01-17 07:30:04 +00:00

Compilation order should be decided by the import statements

This commit is contained in:
Karol Stasiak 2019-06-14 23:20:03 +02:00
parent ba16021426
commit f46466365b
4 changed files with 42 additions and 5 deletions

View File

@ -143,7 +143,18 @@ A function can be declared at the top level. For more details, see [Functions](.
## `import` statements ## `import` statements
TODO import <module>
Adds a module to the program.
The module is looked up first in the current working directory, and then in the include directories.
Usually, the imported module will undergo the first phase of compilation first.
This means that the constants in the imported module will be resolved first, allowing you to use them in the importing module.
The only exception to this rule is when the importing graph has a cycle, in which case the order of modules within the cycle is unspecified.
All starting modules are considered to be imported by all source files explicitly mentioned on the command line.
## Statements ## Statements

View File

@ -4,8 +4,7 @@ import java.nio.charset.StandardCharsets
import java.nio.file.{Files, Paths} import java.nio.file.{Files, Paths}
import fastparse.core.Parsed.{Failure, Success} import fastparse.core.Parsed.{Failure, Success}
import millfork.{CompilationFlag, CompilationOptions} import millfork.{CompilationFlag, CompilationOptions, Tarjan}
import millfork.error.ConsoleLogger
import millfork.node.{ImportStatement, Position, Program} import millfork.node.{ImportStatement, Position, Program}
import scala.collection.mutable import scala.collection.mutable
@ -16,12 +15,32 @@ abstract class AbstractSourceLoadingQueue[T](val initialFilenames: List[String],
val options: CompilationOptions) { val options: CompilationOptions) {
protected val parsedModules: mutable.Map[String, Program] = mutable.Map[String, Program]() protected val parsedModules: mutable.Map[String, Program] = mutable.Map[String, Program]()
protected val moduleDependecies: mutable.Set[(String, String)] = mutable.Set[(String, String)]()
protected val moduleQueue: mutable.Queue[() => Unit] = mutable.Queue[() => Unit]() protected val moduleQueue: mutable.Queue[() => Unit] = mutable.Queue[() => Unit]()
val extension: String = ".mfk" val extension: String = ".mfk"
def standardModules: IndexedSeq[String]
def enqueueStandardModules(): Unit def enqueueStandardModules(): Unit
def run(): Program = { def run(): Program = {
for {
initialFilename <- initialFilenames
startingModule <- options.platform.startingModules
} {
val initialModule = extractName(initialFilename)
moduleDependecies += initialModule -> startingModule
for (standardModule <- standardModules) {
moduleDependecies += initialModule -> standardModule
moduleDependecies += startingModule -> standardModule
}
}
for {
earlier <- standardModules.indices
later <- (earlier + 1) until standardModules.length
} {
moduleDependecies += standardModules(later) -> standardModules(earlier)
}
initialFilenames.foreach { i => initialFilenames.foreach { i =>
parseModule(extractName(i), includePath, Right(i)) parseModule(extractName(i), includePath, Right(i))
} }
@ -37,7 +56,9 @@ abstract class AbstractSourceLoadingQueue[T](val initialFilenames: List[String],
} }
} }
options.log.assertNoErrors("Parse failed") options.log.assertNoErrors("Parse failed")
parsedModules.values.reduce(_ + _).applyImportantAliases val compilationOrder = Tarjan.sort(parsedModules.keys, moduleDependecies)
options.log.debug("Compilation order: " + compilationOrder.mkString(", "))
compilationOrder.filter(parsedModules.contains).map(parsedModules).reduce(_ + _).applyImportantAliases
} }
def lookupModuleFile(includePath: List[String], moduleName: String, position: Option[Position]): String = { def lookupModuleFile(includePath: List[String], moduleName: String, position: Option[Position]): String = {
@ -75,6 +96,7 @@ abstract class AbstractSourceLoadingQueue[T](val initialFilenames: List[String],
parsedModules.put(moduleName, prog) parsedModules.put(moduleName, prog)
prog.declarations.foreach { prog.declarations.foreach {
case s@ImportStatement(m) => case s@ImportStatement(m) =>
moduleDependecies += moduleName -> m
if (!parsedModules.contains(m)) { if (!parsedModules.contains(m)) {
moduleQueue.enqueue(() => parseModule(m, parentDir :: includePath, Left(s.position))) moduleQueue.enqueue(() => parseModule(m, parentDir :: includePath, Left(s.position)))
} }
@ -94,6 +116,6 @@ abstract class AbstractSourceLoadingQueue[T](val initialFilenames: List[String],
def extractName(i: String): String = { def extractName(i: String): String = {
val noExt = i.stripSuffix(extension) val noExt = i.stripSuffix(extension)
val lastSlash = noExt.lastIndexOf('/') max noExt.lastIndexOf('\\') val lastSlash = noExt.lastIndexOf('/') max noExt.lastIndexOf('\\')
if (lastSlash >= 0) i.substring(lastSlash + 1) else i if (lastSlash >= 0) noExt.substring(lastSlash + 1) else noExt
} }
} }

View File

@ -13,6 +13,8 @@ class MosSourceLoadingQueue(initialFilenames: List[String],
override def createParser(filename: String, src: String, parentDir: String, featureConstants: Map[String, Long], pragmas: Set[String]): MfParser[AssemblyLine] = override def createParser(filename: String, src: String, parentDir: String, featureConstants: Map[String, Long], pragmas: Set[String]): MfParser[AssemblyLine] =
MosParser(filename, src, parentDir, options, featureConstants) MosParser(filename, src, parentDir, options, featureConstants)
override def standardModules: IndexedSeq[String] = IndexedSeq("zp_reg", "bcd_6502")
def enqueueStandardModules(): Unit = { def enqueueStandardModules(): Unit = {
if (options.zpRegisterSize > 0) { if (options.zpRegisterSize > 0) {
moduleQueue.enqueue(() => parseModule("zp_reg", includePath, Left(None))) moduleQueue.enqueue(() => parseModule("zp_reg", includePath, Left(None)))

View File

@ -19,6 +19,8 @@ class ZSourceLoadingQueue(initialFilenames: List[String],
Z80Parser(filename, src, parentDir, options, featureConstants, useIntelSyntax) Z80Parser(filename, src, parentDir, options, featureConstants, useIntelSyntax)
} }
override def standardModules: IndexedSeq[String] = IndexedSeq.empty
def enqueueStandardModules(): Unit = { def enqueueStandardModules(): Unit = {
// TODO // TODO
} }