diff --git a/compiler/src/prog8/ast/processing/AstChecker.kt b/compiler/src/prog8/ast/processing/AstChecker.kt index 75bbdf31d..74d06db42 100644 --- a/compiler/src/prog8/ast/processing/AstChecker.kt +++ b/compiler/src/prog8/ast/processing/AstChecker.kt @@ -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) diff --git a/compiler/src/prog8/ast/processing/AstWalker.kt b/compiler/src/prog8/ast/processing/AstWalker.kt index 41c07e486..b476ade9a 100644 --- a/compiler/src/prog8/ast/processing/AstWalker.kt +++ b/compiler/src/prog8/ast/processing/AstWalker.kt @@ -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 { diff --git a/compiler/src/prog8/compiler/target/AsmVariableAndReturnsPreparer.kt b/compiler/src/prog8/compiler/target/AsmVariableAndReturnsPreparer.kt index adaaed6fe..814ce88e2 100644 --- a/compiler/src/prog8/compiler/target/AsmVariableAndReturnsPreparer.kt +++ b/compiler/src/prog8/compiler/target/AsmVariableAndReturnsPreparer.kt @@ -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 { - 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() + 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 } } diff --git a/examples/test.p8 b/examples/test.p8 index 632f52c43..5d39fe345 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -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 + } +}