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:
Irmen de Jong 2024-10-18 21:22:32 +02:00
parent 272a1001a8
commit fcdd9414d9
3 changed files with 76 additions and 42 deletions

View File

@ -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)

View File

@ -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) {
}
}

View File

@ -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++