mirror of
https://github.com/irmen/prog8.git
synced 2025-08-15 14:27:37 +00:00
defer is now done *after* calculating a return value
This commit is contained in:
@@ -1,9 +1,9 @@
|
|||||||
package prog8.compiler.astprocessing
|
package prog8.compiler.astprocessing
|
||||||
|
|
||||||
|
import prog8.ast.base.FatalAstException
|
||||||
import prog8.code.SymbolTable
|
import prog8.code.SymbolTable
|
||||||
import prog8.code.ast.*
|
import prog8.code.ast.*
|
||||||
import prog8.code.core.DataType
|
import prog8.code.core.*
|
||||||
import prog8.code.core.IErrorReporter
|
|
||||||
|
|
||||||
internal fun postprocessIntermediateAst(program: PtProgram, st: SymbolTable, errors: IErrorReporter) {
|
internal fun postprocessIntermediateAst(program: PtProgram, st: SymbolTable, errors: IErrorReporter) {
|
||||||
coalesceDefers(program)
|
coalesceDefers(program)
|
||||||
@@ -39,7 +39,8 @@ private fun coalesceDefers(program: PtProgram) {
|
|||||||
|
|
||||||
|
|
||||||
private fun integrateDefers(program: PtProgram, st: SymbolTable) {
|
private fun integrateDefers(program: PtProgram, st: SymbolTable) {
|
||||||
val exitsToAugment = mutableListOf<PtNode>()
|
val jumpsToAugment = mutableListOf<PtJump>()
|
||||||
|
val returnsToAugment = mutableListOf<PtReturn>()
|
||||||
val subEndsToAugment = mutableListOf<PtSub>()
|
val subEndsToAugment = mutableListOf<PtSub>()
|
||||||
|
|
||||||
walkAst(program) { node, _ ->
|
walkAst(program) { node, _ ->
|
||||||
@@ -49,10 +50,10 @@ private fun integrateDefers(program: PtProgram, st: SymbolTable) {
|
|||||||
val stNode = st.lookup(node.identifier!!.name)!!
|
val stNode = st.lookup(node.identifier!!.name)!!
|
||||||
val targetSub = stNode.astNode.definingSub()
|
val targetSub = stNode.astNode.definingSub()
|
||||||
if(targetSub!=node.definingSub())
|
if(targetSub!=node.definingSub())
|
||||||
exitsToAugment.add(node)
|
jumpsToAugment.add(node)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
is PtReturn -> exitsToAugment.add(node)
|
is PtReturn -> returnsToAugment.add(node)
|
||||||
is PtSub -> {
|
is PtSub -> {
|
||||||
val lastStmt = node.children.lastOrNull { it !is PtDefer }
|
val lastStmt = node.children.lastOrNull { it !is PtDefer }
|
||||||
if(lastStmt != null && lastStmt !is PtReturn && lastStmt !is PtJump)
|
if(lastStmt != null && lastStmt !is PtReturn && lastStmt !is PtJump)
|
||||||
@@ -62,12 +63,66 @@ private fun integrateDefers(program: PtProgram, st: SymbolTable) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for(exit in exitsToAugment) {
|
fun invokedeferbefore(node: PtNode) {
|
||||||
val defer = exit.definingSub()!!.children.singleOrNull { it is PtDefer }
|
val defer = node.definingSub()!!.children.singleOrNull { it is PtDefer }
|
||||||
if(defer != null) {
|
if (defer != null) {
|
||||||
val idx = exit.parent.children.indexOf(exit)
|
val idx = node.parent.children.indexOf(node)
|
||||||
val invokedefer = PtBuiltinFunctionCall("invoke_defer", true, false, DataType.UNDEFINED, exit.position)
|
val invokedefer = PtBuiltinFunctionCall("invoke_defer", true, false, DataType.UNDEFINED, node.position)
|
||||||
exit.parent.add(idx, invokedefer)
|
node.parent.add(idx, invokedefer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for(exit in jumpsToAugment) {
|
||||||
|
invokedeferbefore(exit)
|
||||||
|
}
|
||||||
|
|
||||||
|
for(ret in returnsToAugment) {
|
||||||
|
val defer = ret.definingSub()!!.children.singleOrNull { it is PtDefer }
|
||||||
|
if(defer == null)
|
||||||
|
continue
|
||||||
|
if(ret.children.size>1)
|
||||||
|
TODO("support defer on multi return values")
|
||||||
|
if(!ret.hasValue || ret.value!!.isSimple()) {
|
||||||
|
invokedeferbefore(ret)
|
||||||
|
} else {
|
||||||
|
val value = ret.value!!
|
||||||
|
var typecast: DataType? = null
|
||||||
|
var pushWord = false
|
||||||
|
var pushFloat = false
|
||||||
|
|
||||||
|
when(value.type) {
|
||||||
|
DataType.BOOL -> typecast = DataType.BOOL
|
||||||
|
DataType.BYTE -> typecast = DataType.BYTE
|
||||||
|
DataType.WORD -> {
|
||||||
|
pushWord = true
|
||||||
|
typecast = DataType.WORD
|
||||||
|
}
|
||||||
|
DataType.UBYTE -> {}
|
||||||
|
DataType.UWORD, in PassByReferenceDatatypes -> pushWord = true
|
||||||
|
DataType.FLOAT -> pushFloat = true
|
||||||
|
else -> throw FatalAstException("unsupported return value type ${value.type} with defer")
|
||||||
|
}
|
||||||
|
|
||||||
|
val pushFunc = if(pushFloat) "floats.push" else if(pushWord) "sys.pushw" else "sys.push"
|
||||||
|
val popFunc = if(pushFloat) "floats.pop" else if(pushWord) "sys.popw" else "sys.pop"
|
||||||
|
val pushCall = PtFunctionCall(pushFunc, true, value.type, value.position)
|
||||||
|
pushCall.add(value)
|
||||||
|
val popCall = if(typecast!=null) {
|
||||||
|
PtTypeCast(typecast, value.position).also {
|
||||||
|
it.add(PtFunctionCall(popFunc, false, value.type, value.position))
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
PtFunctionCall(popFunc, false, value.type, value.position)
|
||||||
|
|
||||||
|
val newRet = PtReturn(ret.position)
|
||||||
|
newRet.add(popCall)
|
||||||
|
val group = PtNodeGroup()
|
||||||
|
group.add(pushCall)
|
||||||
|
group.add(PtBuiltinFunctionCall("invoke_defer", true, false, DataType.UNDEFINED, ret.position))
|
||||||
|
group.add(newRet)
|
||||||
|
group.parent = ret.parent
|
||||||
|
val idx = ret.parent.children.indexOf(ret)
|
||||||
|
ret.parent.children[idx] = group
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,7 +1,8 @@
|
|||||||
TODO
|
TODO
|
||||||
====
|
====
|
||||||
|
|
||||||
- fix defer that a return <expression> is evaluated first (and saved), then the defer is called, then a simple return <value> is done
|
- check defer stmt/block to not contain a return or jump statement!
|
||||||
|
- run defer also before sys.exit/exit2/exit3
|
||||||
- unit test for defer
|
- unit test for defer
|
||||||
- describe defer in the manual
|
- describe defer in the manual
|
||||||
|
|
||||||
|
@@ -1,4 +1,5 @@
|
|||||||
%import textio
|
%import textio
|
||||||
|
%import floats
|
||||||
%option no_sysinit
|
%option no_sysinit
|
||||||
%zeropage basicsafe
|
%zeropage basicsafe
|
||||||
|
|
||||||
@@ -8,6 +9,25 @@ main {
|
|||||||
txt.print("result from call=")
|
txt.print("result from call=")
|
||||||
txt.print_ub(x)
|
txt.print_ub(x)
|
||||||
txt.nl()
|
txt.nl()
|
||||||
|
float f = testdeferf()
|
||||||
|
txt.print("result from fcall=")
|
||||||
|
floats.print(f)
|
||||||
|
txt.nl()
|
||||||
|
|
||||||
|
floats.push(f)
|
||||||
|
txt.print("pushed f")
|
||||||
|
f = floats.pop()
|
||||||
|
floats.print(f)
|
||||||
|
txt.nl()
|
||||||
|
}
|
||||||
|
|
||||||
|
sub testdeferf() -> float {
|
||||||
|
defer {
|
||||||
|
txt.print("defer in floats\n")
|
||||||
|
}
|
||||||
|
float @shared zz = 111.111
|
||||||
|
cx16.r0++
|
||||||
|
return 123.456 + zz
|
||||||
}
|
}
|
||||||
|
|
||||||
sub testdefer() -> ubyte {
|
sub testdefer() -> ubyte {
|
||||||
@@ -22,7 +42,7 @@ main {
|
|||||||
|
|
||||||
if var==22 {
|
if var==22 {
|
||||||
var = 88
|
var = 88
|
||||||
return var
|
return var + other()
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
var++
|
var++
|
||||||
@@ -35,7 +55,8 @@ main {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sub other() {
|
sub other() -> ubyte {
|
||||||
cx16.r0++
|
txt.print("other()\n")
|
||||||
|
return 11
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user