mirror of
https://github.com/irmen/prog8.git
synced 2024-09-07 19:54:26 +00:00
fix: correctly insert return statement if needed to prevent 'fall through' into following subroutine
this wasn't working correctly anymore when the last statement before the subroutine was a jump/goto
This commit is contained in:
parent
547b1d3720
commit
dcf487bdc1
@ -31,6 +31,14 @@ internal class BeforeAsmGenerationAstChanger(val program: Program, private val o
|
||||
varsList.add(decl.name to decl)
|
||||
}
|
||||
|
||||
override fun before(block: Block, parent: Node): Iterable<IAstModification> {
|
||||
// move all subroutines to the bottom of the block
|
||||
val subs = block.statements.filterIsInstance<Subroutine>()
|
||||
block.statements.removeAll(subs)
|
||||
block.statements.addAll(subs)
|
||||
return noModifications
|
||||
}
|
||||
|
||||
override fun after(decl: VarDecl, parent: Node): Iterable<IAstModification> {
|
||||
if(decl.type==VarDeclType.VAR && decl.value != null && decl.datatype in NumericDatatypes)
|
||||
throw FatalAstException("vardecls for variables, with initial numerical value, should have been rewritten as plain vardecl + assignment $decl")
|
||||
@ -116,12 +124,14 @@ internal class BeforeAsmGenerationAstChanger(val program: Program, private val o
|
||||
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)
|
||||
if (subroutineStmtIdx > 0) {
|
||||
val prevStmt = outerStatements[subroutineStmtIdx-1]
|
||||
if(outerScope !is Block
|
||||
&& (prevStmt !is Jump || prevStmt.isGosub)
|
||||
&& prevStmt !is Subroutine
|
||||
&& prevStmt !is Return) {
|
||||
mods += IAstModification.InsertAfter(outerStatements[subroutineStmtIdx - 1], returnStmt, outerScope)
|
||||
}
|
||||
}
|
||||
return mods
|
||||
}
|
||||
|
@ -325,4 +325,24 @@ class TestSubroutines: FunSpec({
|
||||
errors.errors[0] shouldContain "cannot use arguments"
|
||||
errors.errors[1] shouldContain "invalid number of arguments"
|
||||
}
|
||||
|
||||
test("fallthrough prevented") {
|
||||
val text = """
|
||||
main {
|
||||
sub start() {
|
||||
func(1)
|
||||
|
||||
sub func(ubyte a) {
|
||||
a++
|
||||
}
|
||||
}
|
||||
}
|
||||
"""
|
||||
val result = compileText(C64Target, false, text, writeAssembly = true).assertSuccess()
|
||||
val stmts = result.program.entrypoint.statements
|
||||
|
||||
stmts.last() shouldBe instanceOf<Subroutine>()
|
||||
stmts.dropLast(1).last() shouldBe instanceOf<Return>() // this prevents the fallthrough
|
||||
stmts.dropLast(2).last() shouldBe instanceOf<Jump>()
|
||||
}
|
||||
})
|
||||
|
@ -1,30 +1,8 @@
|
||||
%import textio
|
||||
%zeropage basicsafe
|
||||
%option no_sysinit
|
||||
|
||||
main {
|
||||
sub start() {
|
||||
ubyte @shared bb
|
||||
|
||||
if bb + sin8u(bb) > 100-bb {
|
||||
bb++
|
||||
}
|
||||
|
||||
while bb + sin8u(bb) > 100-bb {
|
||||
bb++
|
||||
}
|
||||
|
||||
do {
|
||||
bb++
|
||||
} until bb + sin8u(bb) > 100-bb
|
||||
|
||||
const ubyte EN_TYPE=2
|
||||
uword eRef = $c000
|
||||
ubyte chance = rnd() % 100
|
||||
|
||||
if eRef[EN_TYPE] and chance < (eRef[EN_TYPE] << 1) {
|
||||
bb++
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user