mirror of
https://github.com/irmen/prog8.git
synced 2024-11-27 03:50:27 +00:00
cleaned up various ast checks/mutations
This commit is contained in:
parent
131fe670a4
commit
f2bb238e9b
@ -4,7 +4,7 @@ import prog8.ast.Module
|
||||
import prog8.ast.Program
|
||||
import prog8.ast.processing.*
|
||||
import prog8.compiler.CompilationOptions
|
||||
import prog8.compiler.target.AsmVariablePreparer
|
||||
import prog8.compiler.target.AsmVariableAndReturnsPreparer
|
||||
import prog8.optimizer.FlattenAnonymousScopesAndNopRemover
|
||||
|
||||
|
||||
@ -13,10 +13,10 @@ internal fun Program.checkValid(compilerOptions: CompilationOptions, errors: Err
|
||||
checker.visit(this)
|
||||
}
|
||||
|
||||
internal fun Program.prepareAsmVariables(errors: ErrorReporter) {
|
||||
val mover = AsmVariablePreparer(this, errors)
|
||||
mover.visit(this)
|
||||
mover.applyModifications()
|
||||
internal fun Program.prepareAsmVariablesAndReturns(errors: ErrorReporter) {
|
||||
val fixer = AsmVariableAndReturnsPreparer(this, errors)
|
||||
fixer.visit(this)
|
||||
fixer.applyModifications()
|
||||
}
|
||||
|
||||
internal fun Program.reorderStatements() {
|
||||
|
@ -413,9 +413,11 @@ internal class AstChecker(private val program: Program,
|
||||
}
|
||||
}
|
||||
}
|
||||
val targetDt = assignTarget.inferType(program, assignment).typeOrElse(DataType.STR)
|
||||
if(targetDt in IterableDatatypes)
|
||||
errors.err("cannot assign to a string or array type", assignTarget.position)
|
||||
|
||||
// target type check is already done at the Assignment:
|
||||
// val targetDt = assignTarget.inferType(program, assignment).typeOrElse(DataType.STR)
|
||||
// if(targetDt in IterableDatatypes)
|
||||
// errors.err("cannot assign to a string or array type", assignTarget.position)
|
||||
|
||||
if (assignment is Assignment) {
|
||||
|
||||
@ -1054,11 +1056,15 @@ internal class AstChecker(private val program: Program,
|
||||
for((index, stmt) in statements.withIndex()) {
|
||||
if(stmt is FunctionCallStatement
|
||||
&& stmt.target.nameInSource.last()=="exit"
|
||||
&& index < statements.lastIndex)
|
||||
errors.warn("unreachable code, exit call above never returns", statements[index+1].position)
|
||||
&& index < statements.lastIndex) {
|
||||
println("STMT AFTER EXIT ${statements[index+1]}") // TODO fix message if next stmt is not a regular stmt
|
||||
errors.warn("unreachable code, exit call above never returns", statements[index + 1].position)
|
||||
}
|
||||
|
||||
if(stmt is Return && index < statements.lastIndex)
|
||||
errors.warn("unreachable code, return statement above", statements[index+1].position)
|
||||
if(stmt is Return && index < statements.lastIndex) {
|
||||
println("STMT AFTER RETURN ${statements[index+1]}") // TODO fix message if next stmt is not a regular stmt
|
||||
errors.warn("unreachable code, return statement above", statements[index + 1].position)
|
||||
}
|
||||
|
||||
stmt.accept(this)
|
||||
}
|
||||
|
@ -25,11 +25,9 @@ internal class StatementReorderer(private val program: Program): IAstModifyingVi
|
||||
|
||||
private val directivesToMove = setOf("%output", "%launcher", "%zeropage", "%zpreserved", "%address", "%option")
|
||||
|
||||
private val addReturns = mutableListOf<Pair<INameScope, Int>>()
|
||||
private val addVardecls = mutableMapOf<INameScope, MutableList<VarDecl>>()
|
||||
|
||||
override fun visit(module: Module) {
|
||||
addReturns.clear()
|
||||
addVardecls.clear()
|
||||
super.visit(module)
|
||||
|
||||
@ -59,13 +57,6 @@ internal class StatementReorderer(private val program: Program): IAstModifyingVi
|
||||
module.statements.removeAll(directives)
|
||||
module.statements.addAll(0, directives)
|
||||
|
||||
// add new statements
|
||||
for(pos in addReturns) {
|
||||
val returnStmt = Return(null, pos.first.position)
|
||||
returnStmt.linkParents(pos.first as Node)
|
||||
pos.first.statements.add(pos.second, returnStmt)
|
||||
}
|
||||
|
||||
for((where, decls) in addVardecls) {
|
||||
where.statements.addAll(0, decls)
|
||||
decls.forEach { it.linkParents(where as Node) }
|
||||
@ -93,23 +84,6 @@ internal class StatementReorderer(private val program: Program): IAstModifyingVi
|
||||
}
|
||||
}
|
||||
|
||||
// make sure there is a 'return' in front of the first subroutine
|
||||
// (if it isn't the first statement in the block itself, and isn't the program's entrypoint)
|
||||
if(numSubroutinesAtEnd>0 && block.statements.size > (numSubroutinesAtEnd+1)) {
|
||||
val firstSub = block.statements[block.statements.size - numSubroutinesAtEnd] as Subroutine
|
||||
if(firstSub.name != "start" && block.name != "main") {
|
||||
val stmtBeforeFirstSub = block.statements[block.statements.size - numSubroutinesAtEnd - 1]
|
||||
if (stmtBeforeFirstSub !is Return
|
||||
&& stmtBeforeFirstSub !is Jump
|
||||
&& stmtBeforeFirstSub !is Subroutine
|
||||
&& stmtBeforeFirstSub !is BuiltinFunctionStatementPlaceholder) {
|
||||
val ret = Return(null, stmtBeforeFirstSub.position)
|
||||
ret.linkParents(block)
|
||||
block.statements.add(block.statements.size - numSubroutinesAtEnd, ret)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val varDecls = block.statements.filterIsInstance<VarDecl>()
|
||||
block.statements.removeAll(varDecls)
|
||||
block.statements.addAll(0, varDecls)
|
||||
@ -124,19 +98,6 @@ internal class StatementReorderer(private val program: Program): IAstModifyingVi
|
||||
override fun visit(subroutine: Subroutine): Statement {
|
||||
super.visit(subroutine)
|
||||
|
||||
val scope = subroutine.definingScope()
|
||||
if(scope is Subroutine) {
|
||||
for(stmt in scope.statements.withIndex()) {
|
||||
if(stmt.index>0 && stmt.value===subroutine) {
|
||||
val precedingStmt = scope.statements[stmt.index-1]
|
||||
if(precedingStmt !is Jump && precedingStmt !is Subroutine) {
|
||||
// insert a return statement before a nested subroutine, to avoid falling trough inside the subroutine
|
||||
addReturns.add(Pair(scope, stmt.index))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val varDecls = subroutine.statements.filterIsInstance<VarDecl>()
|
||||
subroutine.statements.removeAll(varDecls)
|
||||
subroutine.statements.addAll(0, varDecls)
|
||||
@ -144,18 +105,6 @@ internal class StatementReorderer(private val program: Program): IAstModifyingVi
|
||||
subroutine.statements.removeAll(directives)
|
||||
subroutine.statements.addAll(0, directives)
|
||||
|
||||
if(subroutine.returntypes.isEmpty()) {
|
||||
// add the implicit return statement at the end (if it's not there yet), but only if it's not a kernel routine.
|
||||
// and if an assembly block doesn't contain a rts/rti
|
||||
if(subroutine.asmAddress==null && subroutine.amountOfRtsInAsm()==0) {
|
||||
if (subroutine.statements.lastOrNull {it !is VarDecl } !is Return) {
|
||||
val returnStmt = Return(null, subroutine.position)
|
||||
returnStmt.linkParents(subroutine)
|
||||
subroutine.statements.add(returnStmt)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return subroutine
|
||||
}
|
||||
|
||||
|
@ -45,11 +45,10 @@ class TypecastsAdder(val program: Program, val errors: ErrorReporter) : AstWalke
|
||||
val targettype = targetItype.typeOrElse(DataType.STRUCT)
|
||||
val valuetype = valueItype.typeOrElse(DataType.STRUCT)
|
||||
if (valuetype != targettype) {
|
||||
if (valuetype isAssignableTo targettype)
|
||||
return listOf(IAstModification.ReplaceNode(
|
||||
assignment.value,
|
||||
TypecastExpression(assignment.value, targettype, true, assignment.value.position),
|
||||
assignment))
|
||||
return listOf(IAstModification.ReplaceNode(
|
||||
assignment.value,
|
||||
TypecastExpression(assignment.value, targettype, true, assignment.value.position),
|
||||
assignment))
|
||||
}
|
||||
}
|
||||
return emptyList()
|
||||
|
@ -40,7 +40,7 @@ fun compileProgram(filepath: Path,
|
||||
if (optimize)
|
||||
optimizeAst(programAst, errors)
|
||||
postprocessAst(programAst, errors, compilationOptions)
|
||||
// printAst(programAst)
|
||||
printAst(programAst) // TODO
|
||||
if(writeAssembly)
|
||||
programName = writeAssembly(programAst, errors, outputDir, optimize, compilationOptions)
|
||||
}
|
||||
@ -179,7 +179,7 @@ private fun writeAssembly(programAst: Program, errors: ErrorReporter, outputDir:
|
||||
optimize: Boolean, compilerOptions: CompilationOptions): String {
|
||||
// asm generation directly from the Ast,
|
||||
val zeropage = CompilationTarget.machine.getZeropage(compilerOptions)
|
||||
programAst.prepareAsmVariables(errors)
|
||||
programAst.prepareAsmVariablesAndReturns(errors)
|
||||
errors.handle()
|
||||
val assembly = CompilationTarget.asmGenerator(
|
||||
programAst,
|
||||
|
@ -11,7 +11,7 @@ import prog8.ast.processing.IAstModification
|
||||
import prog8.ast.statements.*
|
||||
|
||||
|
||||
class AsmVariablePreparer(val program: Program, val errors: ErrorReporter): AstWalker() {
|
||||
class AsmVariableAndReturnsPreparer(val program: Program, val errors: ErrorReporter): AstWalker() {
|
||||
|
||||
override fun after(decl: VarDecl, parent: Node): Iterable<IAstModification> {
|
||||
if(decl.value==null && decl.type==VarDeclType.VAR && decl.datatype in NumericDatatypes) {
|
||||
@ -49,4 +49,9 @@ class AsmVariablePreparer(val program: Program, val errors: ErrorReporter): AstW
|
||||
}
|
||||
return emptyList()
|
||||
}
|
||||
|
||||
override fun after(subroutine: Subroutine, parent: Node): Iterable<IAstModification> {
|
||||
TODO("insert Return statements at the required places such as at the end of a subroutine if they're missing")
|
||||
return emptyList()
|
||||
}
|
||||
}
|
@ -199,7 +199,6 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge
|
||||
when(expr.operator) {
|
||||
">>" -> {
|
||||
// bit-shifts are always by a constant number (for now)
|
||||
// TODO for everything except UBYTE, if shifting > 2 bits, use a subroutine
|
||||
translateExpression(expr.left)
|
||||
val amount = expr.right.constValue(program)!!.number.toInt()
|
||||
when (leftDt) {
|
||||
@ -239,7 +238,6 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge
|
||||
}
|
||||
"<<" -> {
|
||||
// bit-shifts are always by a constant number (for now)
|
||||
// TODO for the word types, if shifting > 3 bits, use a subroutine
|
||||
translateExpression(expr.left)
|
||||
val amount = expr.right.constValue(program)!!.number.toInt()
|
||||
if (leftDt in ByteDatatypes) {
|
||||
|
@ -8,7 +8,6 @@ import prog8.ast.processing.IAstModifyingVisitor
|
||||
import prog8.ast.statements.*
|
||||
import prog8.compiler.target.CompilationTarget
|
||||
import prog8.functions.BuiltinFunctions
|
||||
import kotlin.math.floor
|
||||
|
||||
|
||||
internal class ConstantFoldingOptimizer(private val program: Program, private val errors: ErrorReporter) : IAstModifyingVisitor {
|
||||
@ -620,74 +619,4 @@ internal class ConstantFoldingOptimizer(private val program: Program, private va
|
||||
}
|
||||
return array
|
||||
}
|
||||
|
||||
|
||||
// TODO: type casts are already done elsewhere, remove all this?:
|
||||
override fun visit(assignment: Assignment): Statement {
|
||||
super.visit(assignment)
|
||||
val lv = assignment.value as? NumericLiteralValue
|
||||
if(lv!=null) {
|
||||
// see if we can promote/convert a literal value to the required datatype
|
||||
val idt = assignment.target.inferType(program, assignment)
|
||||
if(!idt.isKnown)
|
||||
return assignment
|
||||
when(idt.typeOrElse(DataType.STRUCT)) {
|
||||
DataType.UWORD -> {
|
||||
// we can convert to UWORD: any UBYTE, BYTE/WORD that are >=0, FLOAT that's an integer 0..65535,
|
||||
if(lv.type== DataType.UBYTE)
|
||||
assignment.value = NumericLiteralValue(DataType.UWORD, lv.number.toInt(), lv.position)
|
||||
else if(lv.type== DataType.BYTE && lv.number.toInt()>=0)
|
||||
assignment.value = NumericLiteralValue(DataType.UWORD, lv.number.toInt(), lv.position)
|
||||
else if(lv.type== DataType.WORD && lv.number.toInt()>=0)
|
||||
assignment.value = NumericLiteralValue(DataType.UWORD, lv.number.toInt(), lv.position)
|
||||
else if(lv.type== DataType.FLOAT) {
|
||||
val d = lv.number.toDouble()
|
||||
if(floor(d)==d && d>=0 && d<=65535)
|
||||
assignment.value = NumericLiteralValue(DataType.UWORD, floor(d).toInt(), lv.position)
|
||||
}
|
||||
}
|
||||
DataType.UBYTE -> {
|
||||
// we can convert to UBYTE: UWORD <=255, BYTE >=0, FLOAT that's an integer 0..255,
|
||||
if(lv.type== DataType.UWORD && lv.number.toInt() <= 255)
|
||||
assignment.value = NumericLiteralValue(DataType.UBYTE, lv.number.toShort(), lv.position)
|
||||
else if(lv.type== DataType.BYTE && lv.number.toInt() >=0)
|
||||
assignment.value = NumericLiteralValue(DataType.UBYTE, lv.number.toShort(), lv.position)
|
||||
else if(lv.type== DataType.FLOAT) {
|
||||
val d = lv.number.toDouble()
|
||||
if(floor(d)==d && d >=0 && d<=255)
|
||||
assignment.value = NumericLiteralValue(DataType.UBYTE, floor(d).toShort(), lv.position)
|
||||
}
|
||||
}
|
||||
DataType.BYTE -> {
|
||||
// we can convert to BYTE: UWORD/UBYTE <= 127, FLOAT that's an integer 0..127
|
||||
if(lv.type== DataType.UWORD && lv.number.toInt() <= 127)
|
||||
assignment.value = NumericLiteralValue(DataType.BYTE, lv.number.toShort(), lv.position)
|
||||
else if(lv.type== DataType.UBYTE && lv.number.toInt() <= 127)
|
||||
assignment.value = NumericLiteralValue(DataType.BYTE, lv.number.toShort(), lv.position)
|
||||
else if(lv.type== DataType.FLOAT) {
|
||||
val d = lv.number.toDouble()
|
||||
if(floor(d)==d && d>=0 && d<=127)
|
||||
assignment.value = NumericLiteralValue(DataType.BYTE, floor(d).toShort(), lv.position)
|
||||
}
|
||||
}
|
||||
DataType.WORD -> {
|
||||
// we can convert to WORD: any UBYTE/BYTE, UWORD <= 32767, FLOAT that's an integer -32768..32767,
|
||||
if(lv.type== DataType.UBYTE || lv.type== DataType.BYTE)
|
||||
assignment.value = NumericLiteralValue(DataType.WORD, lv.number.toInt(), lv.position)
|
||||
else if(lv.type== DataType.UWORD && lv.number.toInt() <= 32767)
|
||||
assignment.value = NumericLiteralValue(DataType.WORD, lv.number.toInt(), lv.position)
|
||||
else if(lv.type== DataType.FLOAT) {
|
||||
val d = lv.number.toDouble()
|
||||
if(floor(d)==d && d>=-32768 && d<=32767)
|
||||
assignment.value = NumericLiteralValue(DataType.BYTE, floor(d).toShort(), lv.position)
|
||||
}
|
||||
}
|
||||
DataType.FLOAT -> {
|
||||
assignment.value = NumericLiteralValue(DataType.FLOAT, lv.number.toDouble(), lv.position)
|
||||
}
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
return assignment
|
||||
}
|
||||
}
|
||||
|
@ -115,7 +115,6 @@ internal class StatementOptimizer(private val program: Program,
|
||||
return NopStatement.insteadOf(subroutine)
|
||||
}
|
||||
|
||||
visitStatements(subroutine.statements)
|
||||
return subroutine
|
||||
}
|
||||
|
||||
@ -548,7 +547,6 @@ internal class StatementOptimizer(private val program: Program,
|
||||
if(linesToRemove.isNotEmpty()) {
|
||||
linesToRemove.reversed().forEach{scope.statements.removeAt(it)}
|
||||
}
|
||||
visitStatements(scope.statements)
|
||||
return super.visit(scope)
|
||||
}
|
||||
|
||||
@ -561,21 +559,6 @@ internal class StatementOptimizer(private val program: Program,
|
||||
|
||||
return super.visit(label)
|
||||
}
|
||||
|
||||
|
||||
private fun visitStatements(statements: MutableList<Statement>) {
|
||||
// TODO remove all unreachable code statements after call to exit() or a return
|
||||
// this is not yet correct because we still have nested subroutines
|
||||
// val exitCallIndex = statements.indexOfFirst { it is FunctionCallStatement && it.target.nameInSource.last()=="exit" }
|
||||
// if(exitCallIndex>=0) {
|
||||
// while(exitCallIndex < statements.lastIndex) {
|
||||
// val stmt = statements[exitCallIndex+1]
|
||||
// println("after exit() removing: $stmt")
|
||||
// statements.removeAt(exitCallIndex+1)
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -26,9 +26,6 @@ Memory Block Operations integrated in language?
|
||||
|
||||
array/string memory block operations?
|
||||
|
||||
- vector inc/dec/add/sub/mul/div...? (on array or string):
|
||||
``arrayvar++ / arrayvar-- / arrayvar += 2 / arrayvar -= 2 / arrayvar *= 3 / arrayvar /= 3``
|
||||
|
||||
- array operations
|
||||
copy (from another array with the same length), shift-N(left,right), rotate-N(left,right)
|
||||
clear (set whole array to the given value, default 0)
|
||||
|
@ -6,6 +6,20 @@
|
||||
main {
|
||||
|
||||
sub start() {
|
||||
c64scr.print("ubyte shift left\n")
|
||||
byte v1
|
||||
byte v2
|
||||
|
||||
bla()
|
||||
exit(4)
|
||||
v1 = 100
|
||||
v2 = 127
|
||||
A=5
|
||||
return
|
||||
|
||||
sub bla () {
|
||||
A=99
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user