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)
|
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> {
|
override fun after(decl: VarDecl, parent: Node): Iterable<IAstModification> {
|
||||||
if(decl.type==VarDeclType.VAR && decl.value != null && decl.datatype in NumericDatatypes)
|
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")
|
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 outerScope = subroutine.definingScope
|
||||||
val outerStatements = outerScope.statements
|
val outerStatements = outerScope.statements
|
||||||
val subroutineStmtIdx = outerStatements.indexOf(subroutine)
|
val subroutineStmtIdx = outerStatements.indexOf(subroutine)
|
||||||
if (subroutineStmtIdx > 0
|
if (subroutineStmtIdx > 0) {
|
||||||
&& outerStatements[subroutineStmtIdx - 1] !is Jump
|
val prevStmt = outerStatements[subroutineStmtIdx-1]
|
||||||
&& outerStatements[subroutineStmtIdx - 1] !is Subroutine
|
if(outerScope !is Block
|
||||||
&& outerStatements[subroutineStmtIdx - 1] !is Return
|
&& (prevStmt !is Jump || prevStmt.isGosub)
|
||||||
&& outerScope !is Block) {
|
&& prevStmt !is Subroutine
|
||||||
mods += IAstModification.InsertAfter(outerStatements[subroutineStmtIdx - 1], returnStmt, outerScope)
|
&& prevStmt !is Return) {
|
||||||
|
mods += IAstModification.InsertAfter(outerStatements[subroutineStmtIdx - 1], returnStmt, outerScope)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return mods
|
return mods
|
||||||
}
|
}
|
||||||
|
@ -325,4 +325,24 @@ class TestSubroutines: FunSpec({
|
|||||||
errors.errors[0] shouldContain "cannot use arguments"
|
errors.errors[0] shouldContain "cannot use arguments"
|
||||||
errors.errors[1] shouldContain "invalid number of 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
|
%import textio
|
||||||
%zeropage basicsafe
|
%zeropage basicsafe
|
||||||
%option no_sysinit
|
|
||||||
|
|
||||||
main {
|
main {
|
||||||
sub start() {
|
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