mirror of
https://github.com/irmen/prog8.git
synced 2025-02-04 02:30:19 +00:00
fix defer interfering with return value, fix prefix expression error when operand is functioncall that doesn't return a value.
This commit is contained in:
parent
272a1001a8
commit
fcdd9414d9
@ -1054,6 +1054,14 @@ internal class AstChecker(private val program: Program,
|
||||
}
|
||||
|
||||
override fun visit(expr: PrefixExpression) {
|
||||
|
||||
if(expr.expression is IFunctionCall) {
|
||||
val targetStatement = (expr.expression as IFunctionCall).target.targetSubroutine(program)
|
||||
if(targetStatement?.returntypes?.isEmpty()==true) {
|
||||
errors.err("subroutine doesn't return a value", expr.expression.position)
|
||||
}
|
||||
}
|
||||
|
||||
checkLongType(expr)
|
||||
val dt = expr.expression.inferType(program).getOr(DataType.UNDEFINED)
|
||||
if(dt==DataType.UNDEFINED)
|
||||
|
@ -71,61 +71,85 @@ private fun integrateDefers(program: PtProgram, st: SymbolTable) {
|
||||
node.parent.add(idx, invokedefer)
|
||||
}
|
||||
}
|
||||
fun notComplex(value: PtExpression): Boolean = when(value) {
|
||||
is PtAddressOf -> value.arrayIndexExpr == null || notComplex(value.arrayIndexExpr!!)
|
||||
is PtBuiltinFunctionCall -> {
|
||||
when (value.name) {
|
||||
in arrayOf("msb", "lsb", "mkword", "set_carry", "set_irqd", "clear_carry", "clear_irqd") -> value.args.all { notComplex(it) }
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
is PtMemoryByte -> value.address is PtNumber
|
||||
is PtPrefix -> notComplex(value.value)
|
||||
is PtTypeCast -> notComplex(value.value)
|
||||
is PtArray,
|
||||
is PtIrRegister,
|
||||
is PtBool,
|
||||
is PtNumber,
|
||||
is PtRange,
|
||||
is PtString -> true
|
||||
else -> false
|
||||
}
|
||||
|
||||
// jump exits
|
||||
for(exit in jumpsToAugment) {
|
||||
invokedeferbefore(exit)
|
||||
}
|
||||
|
||||
// return exits
|
||||
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()) {
|
||||
val value = ret.value
|
||||
if(value==null || notComplex(value)) {
|
||||
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
|
||||
continue
|
||||
}
|
||||
|
||||
// complex return value, need to store it before calling the defer block
|
||||
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
|
||||
}
|
||||
|
||||
// subroutine ends
|
||||
for(sub in subEndsToAugment) {
|
||||
val defer = sub.children.singleOrNull { it is PtDefer }
|
||||
if(defer != null) {
|
||||
@ -138,3 +162,4 @@ private fun integrateDefers(program: PtProgram, st: SymbolTable) {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@ -31,18 +31,19 @@ main {
|
||||
}
|
||||
|
||||
sub testdefer() -> ubyte {
|
||||
ubyte var = 22
|
||||
ubyte @shared var = 22
|
||||
|
||||
defer txt.print("defer1\n")
|
||||
defer {
|
||||
txt.print("defer2, var=")
|
||||
txt.print_ub(var)
|
||||
txt.nl()
|
||||
var=33
|
||||
}
|
||||
|
||||
if var==22 {
|
||||
var = 88
|
||||
return var + other()
|
||||
return var ; + other()
|
||||
}
|
||||
else {
|
||||
var++
|
||||
|
Loading…
x
Reference in New Issue
Block a user