From a2a8a772ecc727b8acf040e0c536cd1a81cbe22d Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Thu, 15 Nov 2018 00:49:06 +0100 Subject: [PATCH] tweaking multiple assignment targets --- compiler/examples/test.p8 | 10 +++++- compiler/src/prog8/ast/AST.kt | 10 ++++++ compiler/src/prog8/ast/AstChecker.kt | 12 +++++++- compiler/src/prog8/compiler/Compiler.kt | 41 ++++++++++++++++++++++++- 4 files changed, 70 insertions(+), 3 deletions(-) diff --git a/compiler/examples/test.p8 b/compiler/examples/test.p8 index efaa51226..008329291 100644 --- a/compiler/examples/test.p8 +++ b/compiler/examples/test.p8 @@ -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 } diff --git a/compiler/src/prog8/ast/AST.kt b/compiler/src/prog8/ast/AST.kt index 0687fc3c5..c85b38ef1 100644 --- a/compiler/src/prog8/ast/AST.kt +++ b/compiler/src/prog8/ast/AST.kt @@ -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 "???" + } } diff --git a/compiler/src/prog8/ast/AstChecker.kt b/compiler/src/prog8/ast/AstChecker.kt index 815b3e242..7c1e56a22 100644 --- a/compiler/src/prog8/ast/AstChecker.kt +++ b/compiler/src/prog8/ast/AstChecker.kt @@ -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)) diff --git a/compiler/src/prog8/compiler/Compiler.kt b/compiler/src/prog8/compiler/Compiler.kt index f9195e50a..3d812b2eb 100644 --- a/compiler/src/prog8/compiler/Compiler.kt +++ b/compiler/src/prog8/compiler/Compiler.kt @@ -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() + 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)