mirror of
https://github.com/irmen/prog8.git
synced 2024-12-02 07:49: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"
|
&& stmt.target.nameInSource.last()=="exit"
|
||||||
&& index < statements.lastIndex) {
|
&& index < statements.lastIndex) {
|
||||||
println("STMT AFTER EXIT ${statements[index+1]}") // TODO fix message if next stmt is not a regular stmt
|
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) {
|
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
|
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)
|
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() {
|
override fun perform() {
|
||||||
if(parent is INameScope) {
|
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)
|
parent.statements.add(idx, stmt)
|
||||||
stmt.linkParents(parent)
|
stmt.linkParents(parent)
|
||||||
} else {
|
} 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)
|
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 target = AssignTarget(null, IdentifierReference(listOf(it.name), it.position), null, null, it.position)
|
||||||
val assign = Assignment(target, null, initValue, 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.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()
|
return emptyList()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun after(subroutine: Subroutine, parent: Node): Iterable<IAstModification> {
|
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")
|
// add the implicit return statement at the end (if it's not there yet), but only if it's not a kernel routine.
|
||||||
return emptyList()
|
// 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
|
v1 = 100
|
||||||
v2 = 127
|
v2 = 127
|
||||||
A=5
|
A=5
|
||||||
return
|
|
||||||
|
|
||||||
sub bla () {
|
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