tweaking multiple assignment targets

This commit is contained in:
Irmen de Jong 2018-11-15 00:49:06 +01:00
parent 23c1167d7f
commit a2a8a772ec
4 changed files with 70 additions and 3 deletions

View File

@ -9,10 +9,18 @@ sub start() {
ubyte v1
ubyte v2
float f2
uword address
v1=foo()
v1 , v2 =c64.GETADR()
X, Y =c64.GETADR()
v1, v2 =c64.GETADR()
address =c64.MEMBOT(1, 0.w)
address =c64.IOBASE()
A = c64.CHRIN()
X = c64.CHRIN()
v1 = c64.CHRIN()
return
}

View File

@ -709,6 +709,16 @@ data class AssignTarget(val register: Register?,
}
return null
}
fun shortString(): String {
if(register!=null)
return register.toString()
if(identifier!=null)
return identifier.nameInSource.last()
if(arrayindexed!=null)
return arrayindexed.identifier!!.nameInSource.last()
return "???"
}
}

View File

@ -371,7 +371,17 @@ class AstChecker(private val namespace: INameScope,
// a functioncall COULD return multiple values (from an asm subroutine), treat that differently
val stmt = (assignment.value as FunctionCall).target.targetStatement(namespace)
if(stmt is Subroutine && stmt.returntypes.size>1) {
checkResult.add(ExpressionError("subroutine returning multiple values", assignment.value.position)) // TODO check this
if(stmt.isAsmSubroutine) {
if(stmt.returntypes.size != assignment.targets.size)
checkResult.add(ExpressionError("number of return values doesn't match number of assignment targets", assignment.value.position))
else {
for(thing in stmt.returntypes.zip(assignment.targets)) {
if(thing.second.determineDatatype(namespace, heap, assignment)!=thing.first)
checkResult.add(ExpressionError("return type mismatch for target ${thing.second.shortString()}", assignment.value.position))
}
}
} else
checkResult.add(ExpressionError("only asmsub subroutines can return multiple values", assignment.value.position))
}
else
checkResult.add(ExpressionError("function call doesn't return a suitable value to use in assignment", assignment.value.position))

View File

@ -1089,7 +1089,46 @@ private class StatementTranslator(private val prog: IntermediateProgram,
}
private fun translate(stmt: Assignment) {
val assignTarget= stmt.singleTarget ?: throw CompilerException("cannot use assignment to multiple assignment targets ${stmt.position}")
val assignTarget= stmt.singleTarget
if(assignTarget==null) {
// we're dealing with multiple return values
val targetStmt = (stmt.value as? FunctionCall)?.target?.targetStatement(namespace)
if(targetStmt is Subroutine && targetStmt.isAsmSubroutine) {
// we're dealing with the one case where multiple assignment targets are allowed: a call to an asmsub with multiple return values
// for now, we only support multiple return values as long as they're returned in registers as well.
if(targetStmt.asmReturnvaluesRegisters.isEmpty())
throw CompilerException("we only support multiple return values / assignment when the asmsub returns values in registers")
// if the result registers are not assigned in the exact same registers, or in variables, we need some code
if(stmt.targets.all{it.register!=null}) {
val resultRegisters = mutableListOf<Register>()
for(x in targetStmt.asmReturnvaluesRegisters) {
when(x.registerOrPair) {
RegisterOrPair.A -> resultRegisters.add(Register.A)
RegisterOrPair.X -> resultRegisters.add(Register.X)
RegisterOrPair.Y -> resultRegisters.add(Register.Y)
RegisterOrPair.AX -> {
resultRegisters.add(Register.A)
resultRegisters.add(Register.X)
}
RegisterOrPair.AY -> {
resultRegisters.add(Register.A)
resultRegisters.add(Register.Y)
}
RegisterOrPair.XY -> {
resultRegisters.add(Register.X)
resultRegisters.add(Register.Y)
}
}
}
TODO("$resultRegisters")
} else {
TODO("store results from registers ${targetStmt.asmReturnvaluesRegisters}")
}
} else throw CompilerException("can only use multiple assignment targets on an asmsub call")
return
}
prog.line(stmt.position)
translate(stmt.value)
val valueDt = stmt.value.resultingDatatype(namespace, heap)