diff --git a/compiler/build.gradle b/compiler/build.gradle index 129cbb240..45f67efa4 100644 --- a/compiler/build.gradle +++ b/compiler/build.gradle @@ -1,5 +1,5 @@ plugins { - id "org.jetbrains.kotlin.jvm" version "1.3.30" + id "org.jetbrains.kotlin.jvm" version "1.3.40" id 'application' } @@ -8,7 +8,7 @@ repositories { jcenter() } -def kotlinVersion = '1.3.30' +def kotlinVersion = '1.3.40' dependencies { implementation project(':parser') diff --git a/compiler/res/version.txt b/compiler/res/version.txt index d3bdbdf1f..625934097 100644 --- a/compiler/res/version.txt +++ b/compiler/res/version.txt @@ -1 +1 @@ -1.7 +1.8 diff --git a/compiler/src/prog8/CompilerMain.kt b/compiler/src/prog8/CompilerMain.kt index 09af5abad..8bf5a3959 100644 --- a/compiler/src/prog8/CompilerMain.kt +++ b/compiler/src/prog8/CompilerMain.kt @@ -8,6 +8,7 @@ import prog8.optimizing.constantFold import prog8.optimizing.optimizeStatements import prog8.optimizing.simplifyExpressions import prog8.parser.ParsingFailedError +import prog8.parser.importLibraryModule import prog8.parser.importModule import java.io.File import java.io.PrintStream @@ -71,60 +72,65 @@ private fun compileMain(args: Array) { try { val totalTime = measureTimeMillis { - // import main module and process additional imports + // import main module and everything it needs println("Parsing...") - val moduleAst = importModule(filepath) - moduleAst.linkParents() - var namespace = moduleAst.definingScope() - - // determine special compiler options - - val compilerOptions = determineCompilationOptions(moduleAst) + val programAst = Program(filepath.fileName.toString(), mutableListOf()) + importModule(programAst, filepath) + val compilerOptions = determineCompilationOptions(programAst) if (compilerOptions.launcher == LauncherType.BASIC && compilerOptions.output != OutputType.PRG) - throw ParsingFailedError("${moduleAst.position} BASIC launcher requires output type PRG.") + throw ParsingFailedError("${programAst.modules.first().position} BASIC launcher requires output type PRG.") + + // if we're producing a PRG or BASIC program, include the c64utils and c64lib libraries + if(compilerOptions.launcher==LauncherType.BASIC || compilerOptions.output==OutputType.PRG) { + importLibraryModule(programAst, "c64lib") + importLibraryModule(programAst, "c64utils") + } + + // always import prog8lib and math + importLibraryModule(programAst, "math") + importLibraryModule(programAst, "prog8lib") + // perform initial syntax checks and constant folding println("Syntax check...") - val heap = HeapValues() val time1= measureTimeMillis { - moduleAst.checkIdentifiers(namespace) + programAst.checkIdentifiers() } //println(" time1: $time1") val time2 = measureTimeMillis { - moduleAst.constantFold(namespace, heap) + programAst.constantFold() } //println(" time2: $time2") val time3 = measureTimeMillis { - moduleAst.reorderStatements(namespace,heap) // reorder statements to please the compiler later + programAst.reorderStatements() // reorder statements to please the compiler later } //println(" time3: $time3") val time4 = measureTimeMillis { - moduleAst.checkValid(namespace, compilerOptions, heap) // check if tree is valid + programAst.checkValid(compilerOptions) // check if tree is valid } //println(" time4: $time4") - moduleAst.checkIdentifiers(namespace) + programAst.checkIdentifiers() if(optimize) { // optimize the parse tree println("Optimizing...") while (true) { // keep optimizing expressions and statements until no more steps remain - val optsDone1 = moduleAst.simplifyExpressions(namespace, heap) - val optsDone2 = moduleAst.optimizeStatements(namespace, heap) + val optsDone1 = programAst.simplifyExpressions() + val optsDone2 = programAst.optimizeStatements() if (optsDone1 + optsDone2 == 0) break } } - namespace = moduleAst.definingScope() // create it again, it could have changed in the meantime - moduleAst.checkValid(namespace, compilerOptions, heap) // check if final tree is valid - moduleAst.checkRecursion(namespace) // check if there are recursive subroutine calls + programAst.checkValid(compilerOptions) // check if final tree is valid + programAst.checkRecursion() // check if there are recursive subroutine calls // namespace.debugPrint() // compile the syntax tree into stackvmProg form, and optimize that - val compiler = Compiler(moduleAst, namespace, heap) + val compiler = Compiler(programAst) val intermediate = compiler.compile(compilerOptions) if(optimize) intermediate.optimize() @@ -140,7 +146,7 @@ private fun compileMain(args: Array) { if(writeAssembly) { val zeropage = C64Zeropage(compilerOptions) intermediate.allocateZeropage(zeropage) - val assembly = AsmGen(compilerOptions, intermediate, heap, zeropage).compileToAssembly(optimize) + val assembly = AsmGen(compilerOptions, intermediate, programAst.heap, zeropage).compileToAssembly(optimize) assembly.assemble(compilerOptions) programname = assembly.name } @@ -180,7 +186,9 @@ private fun compileMain(args: Array) { } } -fun determineCompilationOptions(moduleAst: Module): CompilationOptions { + +fun determineCompilationOptions(program: Program): CompilationOptions { + val moduleAst = program.modules.first() val options = moduleAst.statements.filter { it is Directive && it.directive == "%option" }.flatMap { (it as Directive).args }.toSet() val outputType = (moduleAst.statements.singleOrNull { it is Directive && it.directive == "%output" } as? Directive)?.args?.single()?.name?.toUpperCase() diff --git a/compiler/src/prog8/ast/AST.kt b/compiler/src/prog8/ast/AST.kt index 58af745ad..796b6badb 100644 --- a/compiler/src/prog8/ast/AST.kt +++ b/compiler/src/prog8/ast/AST.kt @@ -130,6 +130,10 @@ data class Position(val file: String, val line: Int, val startCol: Int, val endC interface IAstProcessor { + fun process(program: Program) { + program.modules.forEach { process(it) } + } + fun process(module: Module) { module.statements = module.statements.asSequence().map { it.process(this) }.toMutableList() } @@ -301,6 +305,13 @@ interface Node { val position: Position var parent: Node // will be linked correctly later (late init) fun linkParents(parent: Node) + + fun definingModule(): Module { + if(this is Module) + return this + return findParentNode(this)!! + } + fun definingScope(): INameScope { val scope = findParentNode(this) if(scope!=null) { @@ -398,22 +409,27 @@ interface INameScope { fun allLabelsAndVariables(): Set = statements.filterIsInstance