reducing dependencies

This commit is contained in:
Irmen de Jong 2021-02-20 17:19:54 +01:00
parent d23c2eed86
commit f4cef3eaf2
16 changed files with 74 additions and 58 deletions

View File

@ -11,7 +11,7 @@ import prog8.ast.walk.IAstModification
import prog8.compiler.target.ICompilationTarget
internal class BeforeAsmGenerationAstChanger(val program: Program, val errors: ErrorReporter, private val compTarget: ICompilationTarget) : AstWalker() {
internal class BeforeAsmGenerationAstChanger(val program: Program, val errors: IErrorReporter, private val compTarget: ICompilationTarget) : AstWalker() {
private val noModifications = emptyList<IAstModification>()

View File

@ -165,7 +165,7 @@ private class BuiltinFunctionsFacade(functions: Map<String, FSignature>): IBuilt
builtinFunctionReturnType(name, args, program)
}
private fun parseImports(filepath: Path, errors: ErrorReporter, compTarget: ICompilationTarget): Triple<Program, CompilationOptions, List<Path>> {
private fun parseImports(filepath: Path, errors: IErrorReporter, compTarget: ICompilationTarget): Triple<Program, CompilationOptions, List<Path>> {
val compilationTargetName = compTarget.name
println("Compiler target: $compilationTargetName. Parsing...")
val importer = ModuleImporter()
@ -173,7 +173,7 @@ private fun parseImports(filepath: Path, errors: ErrorReporter, compTarget: ICom
val programAst = Program(moduleName(filepath.fileName), mutableListOf(), bf, compTarget)
bf.program = programAst
importer.importModule(programAst, filepath, compTarget, compilationTargetName)
errors.handle()
errors.report()
val importedFiles = programAst.modules.filter { !it.source.startsWith("@embedded@") }.map { it.source }
val compilerOptions = determineCompilationOptions(programAst, compTarget)
@ -187,7 +187,7 @@ private fun parseImports(filepath: Path, errors: ErrorReporter, compTarget: ICom
// always import prog8_lib and math
importer.importLibraryModule(programAst, "math", compTarget, compilationTargetName)
importer.importLibraryModule(programAst, "prog8_lib", compTarget, compilationTargetName)
errors.handle()
errors.report()
return Triple(programAst, compilerOptions, importedFiles)
}
@ -242,25 +242,25 @@ private fun determineCompilationOptions(program: Program, compTarget: ICompilati
)
}
private fun processAst(programAst: Program, errors: ErrorReporter, compilerOptions: CompilationOptions) {
private fun processAst(programAst: Program, errors: IErrorReporter, compilerOptions: CompilationOptions) {
// perform initial syntax checks and processings
println("Processing for target ${compilerOptions.compTarget.name}...")
programAst.checkIdentifiers(errors, compilerOptions.compTarget)
errors.handle()
errors.report()
programAst.constantFold(errors, compilerOptions.compTarget)
errors.handle()
errors.report()
programAst.reorderStatements(errors)
errors.handle()
errors.report()
programAst.addTypecasts(errors)
errors.handle()
errors.report()
programAst.variousCleanups()
programAst.checkValid(compilerOptions, errors, compilerOptions.compTarget)
errors.handle()
errors.report()
programAst.checkIdentifiers(errors, compilerOptions.compTarget)
errors.handle()
errors.report()
}
private fun optimizeAst(programAst: Program, errors: ErrorReporter, functions: IBuiltinFunctions, compTarget: ICompilationTarget) {
private fun optimizeAst(programAst: Program, errors: IErrorReporter, functions: IBuiltinFunctions, compTarget: ICompilationTarget) {
// optimize the parse tree
println("Optimizing...")
while (true) {
@ -269,7 +269,7 @@ private fun optimizeAst(programAst: Program, errors: ErrorReporter, functions: I
val optsDone2 = programAst.splitBinaryExpressions(compTarget)
val optsDone3 = programAst.optimizeStatements(errors, functions, compTarget)
programAst.constantFold(errors, compTarget) // because simplified statements and expressions can result in more constants that can be folded away
errors.handle()
errors.report()
if (optsDone1 + optsDone2 + optsDone3 == 0)
break
}
@ -277,29 +277,29 @@ private fun optimizeAst(programAst: Program, errors: ErrorReporter, functions: I
val remover = UnusedCodeRemover(programAst, errors, compTarget)
remover.visit(programAst)
remover.applyModifications()
errors.handle()
errors.report()
}
private fun postprocessAst(programAst: Program, errors: ErrorReporter, compilerOptions: CompilationOptions) {
private fun postprocessAst(programAst: Program, errors: IErrorReporter, compilerOptions: CompilationOptions) {
programAst.addTypecasts(errors)
errors.handle()
errors.report()
programAst.variousCleanups()
programAst.checkValid(compilerOptions, errors, compilerOptions.compTarget) // check if final tree is still valid
errors.handle()
errors.report()
val callGraph = CallGraph(programAst)
callGraph.checkRecursiveCalls(errors)
errors.handle()
errors.report()
programAst.verifyFunctionArgTypes()
programAst.moveMainAndStartToFirst()
}
private fun writeAssembly(programAst: Program,
errors: ErrorReporter,
errors: IErrorReporter,
outputDir: Path,
compilerOptions: CompilationOptions): String {
// asm generation directly from the Ast,
programAst.processAstBeforeAsmGeneration(errors, compilerOptions.compTarget)
errors.handle()
errors.report()
// printAst(programAst)
@ -311,7 +311,7 @@ private fun writeAssembly(programAst: Program,
compilerOptions,
outputDir).compileToAssembly()
assembly.assemble(compilerOptions)
errors.handle()
errors.report()
return assembly.name
}

View File

@ -3,7 +3,16 @@ package prog8.compiler
import prog8.ast.base.Position
import prog8.parser.ParsingFailedError
class ErrorReporter {
interface IErrorReporter {
fun err(msg: String, position: Position)
fun warn(msg: String, position: Position)
fun isEmpty(): Boolean
fun report()
}
internal class ErrorReporter: IErrorReporter {
private enum class MessageSeverity {
WARNING,
ERROR
@ -13,10 +22,14 @@ class ErrorReporter {
private val messages = mutableListOf<CompilerMessage>()
private val alreadyReportedMessages = mutableSetOf<String>()
fun err(msg: String, position: Position) = messages.add(CompilerMessage(MessageSeverity.ERROR, msg, position))
fun warn(msg: String, position: Position) = messages.add(CompilerMessage(MessageSeverity.WARNING, msg, position))
override fun err(msg: String, position: Position) {
messages.add(CompilerMessage(MessageSeverity.ERROR, msg, position))
}
override fun warn(msg: String, position: Position) {
messages.add(CompilerMessage(MessageSeverity.WARNING, msg, position))
}
fun handle() {
override fun report() {
var numErrors = 0
var numWarnings = 0
messages.forEach {
@ -40,5 +53,5 @@ class ErrorReporter {
throw ParsingFailedError("There are $numErrors errors and $numWarnings warnings.")
}
fun isEmpty() = messages.isEmpty()
override fun isEmpty() = messages.isEmpty()
}

View File

@ -21,7 +21,7 @@ abstract class Zeropage(protected val options: CompilationOptions) {
fun available() = if(options.zeropage==ZeropageType.DONTUSE) 0 else free.size
fun allocate(scopedname: String, datatype: DataType, position: Position?, errors: ErrorReporter): Int {
fun allocate(scopedname: String, datatype: DataType, position: Position?, errors: IErrorReporter): Int {
assert(scopedname.isEmpty() || !allocations.values.any { it.first==scopedname } ) {"scopedname can't be allocated twice"}
if(options.zeropage==ZeropageType.DONTUSE)

View File

@ -8,7 +8,7 @@ import prog8.ast.expressions.*
import prog8.ast.statements.*
import prog8.ast.walk.IAstVisitor
import prog8.compiler.CompilationOptions
import prog8.compiler.ErrorReporter
import prog8.compiler.IErrorReporter
import prog8.compiler.functions.BuiltinFunctions
import prog8.compiler.functions.builtinFunctionReturnType
import prog8.compiler.target.C64Target
@ -18,7 +18,7 @@ import java.io.File
internal class AstChecker(private val program: Program,
private val compilerOptions: CompilationOptions,
private val errors: ErrorReporter,
private val errors: IErrorReporter,
private val compTarget: ICompilationTarget
) : IAstVisitor {
@ -1416,7 +1416,10 @@ internal class AstChecker(private val program: Program,
}
false
}
else -> errors.err("cannot assign new value to variable of type $targetDatatype", position)
else -> {
errors.err("cannot assign new value to variable of type $targetDatatype", position)
false
}
}
if(result)

View File

@ -5,28 +5,28 @@ import prog8.ast.base.FatalAstException
import prog8.ast.statements.Directive
import prog8.compiler.BeforeAsmGenerationAstChanger
import prog8.compiler.CompilationOptions
import prog8.compiler.ErrorReporter
import prog8.compiler.IErrorReporter
import prog8.compiler.target.ICompilationTarget
internal fun Program.checkValid(compilerOptions: CompilationOptions, errors: ErrorReporter, compTarget: ICompilationTarget) {
internal fun Program.checkValid(compilerOptions: CompilationOptions, errors: IErrorReporter, compTarget: ICompilationTarget) {
val checker = AstChecker(this, compilerOptions, errors, compTarget)
checker.visit(this)
}
internal fun Program.processAstBeforeAsmGeneration(errors: ErrorReporter, compTarget: ICompilationTarget) {
internal fun Program.processAstBeforeAsmGeneration(errors: IErrorReporter, compTarget: ICompilationTarget) {
val fixer = BeforeAsmGenerationAstChanger(this, errors, compTarget)
fixer.visit(this)
fixer.applyModifications()
}
internal fun Program.reorderStatements(errors: ErrorReporter) {
internal fun Program.reorderStatements(errors: IErrorReporter) {
val reorder = StatementReorderer(this, errors)
reorder.visit(this)
reorder.applyModifications()
}
internal fun Program.addTypecasts(errors: ErrorReporter) {
internal fun Program.addTypecasts(errors: IErrorReporter) {
val caster = TypecastsAdder(this, errors)
caster.visit(this)
caster.applyModifications()
@ -37,7 +37,7 @@ internal fun Program.verifyFunctionArgTypes() {
fixer.visit(this)
}
internal fun Program.checkIdentifiers(errors: ErrorReporter, compTarget: ICompilationTarget) {
internal fun Program.checkIdentifiers(errors: IErrorReporter, compTarget: ICompilationTarget) {
val checker2 = AstIdentifiersChecker(this, errors, compTarget)
checker2.visit(this)

View File

@ -10,11 +10,11 @@ import prog8.ast.expressions.NumericLiteralValue
import prog8.ast.expressions.StringLiteralValue
import prog8.ast.statements.*
import prog8.ast.walk.IAstVisitor
import prog8.compiler.ErrorReporter
import prog8.compiler.IErrorReporter
import prog8.compiler.functions.BuiltinFunctions
import prog8.compiler.target.ICompilationTarget
internal class AstIdentifiersChecker(private val program: Program, private val errors: ErrorReporter, private val compTarget: ICompilationTarget) : IAstVisitor {
internal class AstIdentifiersChecker(private val program: Program, private val errors: IErrorReporter, private val compTarget: ICompilationTarget) : IAstVisitor {
private var blocks = mutableMapOf<String, Block>()
private fun nameError(name: String, position: Position, existing: Statement) {

View File

@ -6,11 +6,11 @@ import prog8.ast.expressions.*
import prog8.ast.statements.*
import prog8.ast.walk.AstWalker
import prog8.ast.walk.IAstModification
import prog8.compiler.ErrorReporter
import prog8.compiler.IErrorReporter
import prog8.compiler.functions.BuiltinFunctions
internal class StatementReorderer(val program: Program, val errors: ErrorReporter) : AstWalker() {
internal class StatementReorderer(val program: Program, val errors: IErrorReporter) : AstWalker() {
// Reorders the statements in a way the compiler needs.
// - 'main' block must be the very first statement UNLESS it has an address set.
// - library blocks are put last.

View File

@ -8,11 +8,11 @@ import prog8.ast.expressions.*
import prog8.ast.statements.*
import prog8.ast.walk.AstWalker
import prog8.ast.walk.IAstModification
import prog8.compiler.ErrorReporter
import prog8.compiler.IErrorReporter
import prog8.compiler.functions.BuiltinFunctions
class TypecastsAdder(val program: Program, val errors: ErrorReporter) : AstWalker() {
class TypecastsAdder(val program: Program, val errors: IErrorReporter) : AstWalker() {
/*
* Make sure any value assignments get the proper type casts if needed to cast them into the target variable's type.
* (this includes function call arguments)

View File

@ -8,7 +8,7 @@ import prog8.ast.expressions.IdentifierReference
import prog8.ast.expressions.NumericLiteralValue
import prog8.ast.statements.AssignTarget
import prog8.compiler.CompilationOptions
import prog8.compiler.ErrorReporter
import prog8.compiler.IErrorReporter
import prog8.compiler.Zeropage
import prog8.compiler.target.c64.C64MachineDefinition
import prog8.compiler.target.c64.Petscii
@ -108,7 +108,7 @@ internal object Cx16Target: ICompilationTarget {
internal fun asmGeneratorFor(
compTarget: ICompilationTarget,
program: Program,
errors: ErrorReporter,
errors: IErrorReporter,
zp: Zeropage,
options: CompilationOptions,
outputDir: Path

View File

@ -23,7 +23,7 @@ import kotlin.math.absoluteValue
internal class AsmGen(private val program: Program,
val errors: ErrorReporter,
val errors: IErrorReporter,
val zeropage: Zeropage,
val options: CompilationOptions,
private val compTarget: ICompilationTarget,
@ -263,7 +263,7 @@ internal class AsmGen(private val program: Program,
try {
val errors = ErrorReporter()
val address = zeropage.allocate(fullName, variable.datatype, null, errors)
errors.handle()
errors.report()
out("${variable.name} = $address\t; auto zp ${variable.datatype}")
// make sure we add the var to the set of zpvars for this block
allocatedZeropageVariables[fullName] = address to variable.datatype

View File

@ -11,7 +11,7 @@ import prog8.ast.expressions.FunctionCall
import prog8.ast.expressions.IdentifierReference
import prog8.ast.statements.*
import prog8.ast.walk.IAstVisitor
import prog8.compiler.ErrorReporter
import prog8.compiler.IErrorReporter
import prog8.compiler.loadAsmIncludeFile
private val alwaysKeepSubroutines = setOf(
@ -213,7 +213,7 @@ class CallGraph(private val program: Program) : IAstVisitor {
}
}
fun checkRecursiveCalls(errors: ErrorReporter) {
fun checkRecursiveCalls(errors: IErrorReporter) {
val cycles = recursionCycles()
if(cycles.any()) {
errors.warn("Program contains recursive subroutine calls. These only works in very specific limited scenarios!", Position.DUMMY)

View File

@ -10,11 +10,11 @@ import prog8.ast.statements.ForLoop
import prog8.ast.statements.VarDecl
import prog8.ast.walk.AstWalker
import prog8.ast.walk.IAstModification
import prog8.compiler.ErrorReporter
import prog8.compiler.IErrorReporter
import prog8.compiler.target.ICompilationTarget
// Fix up the literal value's type to match that of the vardecl
internal class VarConstantValueTypeAdjuster(private val program: Program, private val errors: ErrorReporter) : AstWalker() {
internal class VarConstantValueTypeAdjuster(private val program: Program, private val errors: IErrorReporter) : AstWalker() {
private val noModifications = emptyList<IAstModification>()
override fun after(decl: VarDecl, parent: Node): Iterable<IAstModification> {
@ -39,7 +39,7 @@ internal class VarConstantValueTypeAdjuster(private val program: Program, privat
// Replace all constant identifiers with their actual value,
// and the array var initializer values and sizes.
// This is needed because further constant optimizations depend on those.
internal class ConstantIdentifierReplacer(private val program: Program, private val errors: ErrorReporter, private val compTarget: ICompilationTarget) : AstWalker() {
internal class ConstantIdentifierReplacer(private val program: Program, private val errors: IErrorReporter, private val compTarget: ICompilationTarget) : AstWalker() {
private val noModifications = emptyList<IAstModification>()
override fun after(identifier: IdentifierReference, parent: Node): Iterable<IAstModification> {

View File

@ -2,11 +2,11 @@ package prog8.optimizer
import prog8.ast.IBuiltinFunctions
import prog8.ast.Program
import prog8.compiler.ErrorReporter
import prog8.compiler.IErrorReporter
import prog8.compiler.target.ICompilationTarget
internal fun Program.constantFold(errors: ErrorReporter, compTarget: ICompilationTarget) {
internal fun Program.constantFold(errors: IErrorReporter, compTarget: ICompilationTarget) {
val valuetypefixer = VarConstantValueTypeAdjuster(this, errors)
valuetypefixer.visit(this)
if(errors.isEmpty()) {
@ -40,7 +40,7 @@ internal fun Program.constantFold(errors: ErrorReporter, compTarget: ICompilatio
}
internal fun Program.optimizeStatements(errors: ErrorReporter, functions: IBuiltinFunctions, compTarget: ICompilationTarget): Int {
internal fun Program.optimizeStatements(errors: IErrorReporter, functions: IBuiltinFunctions, compTarget: ICompilationTarget): Int {
val optimizer = StatementOptimizer(this, errors, functions, compTarget)
optimizer.visit(this)
val optimizationCount = optimizer.applyModifications()

View File

@ -10,13 +10,13 @@ import prog8.ast.statements.*
import prog8.ast.walk.AstWalker
import prog8.ast.walk.IAstModification
import prog8.ast.walk.IAstVisitor
import prog8.compiler.ErrorReporter
import prog8.compiler.IErrorReporter
import prog8.compiler.target.ICompilationTarget
import kotlin.math.floor
internal class StatementOptimizer(private val program: Program,
private val errors: ErrorReporter,
private val errors: IErrorReporter,
private val functions: IBuiltinFunctions,
private val compTarget: ICompilationTarget
) : AstWalker() {

View File

@ -10,11 +10,11 @@ import prog8.ast.expressions.TypecastExpression
import prog8.ast.statements.*
import prog8.ast.walk.AstWalker
import prog8.ast.walk.IAstModification
import prog8.compiler.ErrorReporter
import prog8.compiler.IErrorReporter
import prog8.compiler.target.ICompilationTarget
internal class UnusedCodeRemover(private val program: Program, private val errors: ErrorReporter, private val compTarget: ICompilationTarget): AstWalker() {
internal class UnusedCodeRemover(private val program: Program, private val errors: IErrorReporter, private val compTarget: ICompilationTarget): AstWalker() {
override fun before(program: Program, parent: Node): Iterable<IAstModification> {
val callgraph = CallGraph(program)