mirror of
https://github.com/irmen/prog8.git
synced 2024-11-27 03:50:27 +00:00
cleaned up the way return statements are added to avoid code falling through in/out of subroutines
This commit is contained in:
parent
f2bb238e9b
commit
8805693ed2
@ -1058,12 +1058,12 @@ internal class AstChecker(private val program: Program,
|
||||
&& stmt.target.nameInSource.last()=="exit"
|
||||
&& 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)
|
||||
errors.warn("unreachable code, preceding exit call will never return", 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)
|
||||
errors.warn("unreachable code, preceding return statement", statements[index + 1].position)
|
||||
}
|
||||
|
||||
stmt.accept(this)
|
||||
|
@ -30,10 +30,21 @@ interface IAstModification {
|
||||
}
|
||||
}
|
||||
|
||||
class Insert(val after: Statement?, val stmt: Statement, val parent: Node) : IAstModification {
|
||||
class InsertFirst(val stmt: Statement, val parent: Node) : IAstModification {
|
||||
override fun perform() {
|
||||
if(parent is INameScope) {
|
||||
val idx = if(after==null) 0 else parent.statements.indexOf(after)
|
||||
parent.statements.add(0, stmt)
|
||||
stmt.linkParents(parent)
|
||||
} else {
|
||||
throw FatalAstException("parent of an insert modification is not an INameScope")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class InsertAfter(val after: Statement, val stmt: Statement, val parent: Node) : IAstModification {
|
||||
override fun perform() {
|
||||
if(parent is INameScope) {
|
||||
val idx = parent.statements.indexOf(after)+1
|
||||
parent.statements.add(idx, stmt)
|
||||
stmt.linkParents(parent)
|
||||
} else {
|
||||
|
@ -41,17 +41,40 @@ class AsmVariableAndReturnsPreparer(val program: Program, val errors: ErrorRepor
|
||||
it.value = null // make sure no value init assignment for this vardecl will be created later (would be superfluous)
|
||||
val target = AssignTarget(null, IdentifierReference(listOf(it.name), it.position), null, null, it.position)
|
||||
val assign = Assignment(target, null, initValue, it.position)
|
||||
IAstModification.Insert(null, assign, scope)
|
||||
IAstModification.InsertFirst(assign, scope)
|
||||
} +
|
||||
decls.map { IAstModification.ReplaceNode(it, NopStatement(it.position), scope) } +
|
||||
decls.map { IAstModification.Insert(null, it, sub) } // move it up to the subroutine
|
||||
decls.map { IAstModification.InsertFirst(it, sub) } // move it up to the subroutine
|
||||
}
|
||||
}
|
||||
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()
|
||||
// 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, and some other situations.
|
||||
val mods = mutableListOf<IAstModification>()
|
||||
val returnStmt = Return(null, subroutine.position)
|
||||
if(subroutine.asmAddress==null
|
||||
&& subroutine.statements.isNotEmpty()
|
||||
&& subroutine.amountOfRtsInAsm()==0
|
||||
&& subroutine.statements.lastOrNull {it !is VarDecl } !is Return
|
||||
&& subroutine.statements.last() !is Subroutine) {
|
||||
mods += IAstModification.InsertAfter(subroutine.statements.last(), returnStmt, subroutine)
|
||||
}
|
||||
|
||||
// precede a subroutine with a return to avoid falling through into the subroutine from code above it
|
||||
val outerScope = subroutine.definingScope()
|
||||
val outerStatements = outerScope.statements
|
||||
val subroutineStmtIdx = outerStatements.indexOf(subroutine)
|
||||
if(subroutineStmtIdx>0
|
||||
&& outerStatements[subroutineStmtIdx-1] !is Jump
|
||||
&& outerStatements[subroutineStmtIdx-1] !is Subroutine
|
||||
&& outerStatements[subroutineStmtIdx-1] !is Return
|
||||
&& outerScope !is Block) {
|
||||
mods += IAstModification.InsertAfter(outerStatements[subroutineStmtIdx-1], returnStmt, outerScope as Node)
|
||||
}
|
||||
|
||||
return mods
|
||||
}
|
||||
}
|
||||
|
@ -14,12 +14,30 @@ main {
|
||||
v1 = 100
|
||||
v2 = 127
|
||||
A=5
|
||||
return
|
||||
|
||||
sub bla () {
|
||||
A=99
|
||||
A=99
|
||||
bla2()
|
||||
|
||||
|
||||
sub bla2 () {
|
||||
A=100
|
||||
foo.ding()
|
||||
foo.ding2()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
foo {
|
||||
ubyte derp=99
|
||||
sub ding() {
|
||||
A=derp
|
||||
}
|
||||
sub ding2() {
|
||||
A=derp
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user