mirror of
https://github.com/irmen/prog8.git
synced 2024-12-24 16:29:21 +00:00
tweaking multiple assignment targets
This commit is contained in:
parent
4ade45f51f
commit
23c1167d7f
@ -107,7 +107,9 @@ datatype: 'ubyte' | 'byte' | 'uword' | 'word' | 'float' | 'str' | 'str_p' | 'st
|
||||
|
||||
arrayspec: '[' expression ']' ;
|
||||
|
||||
assignment : assign_target '=' expression ;
|
||||
assignment : assign_targets '=' expression ;
|
||||
|
||||
assign_targets : assign_target (',' assign_target)* ;
|
||||
|
||||
augassignment :
|
||||
assign_target operator=('+=' | '-=' | '/=' | '//=' | '*=' | '**=' | '&=' | '|=' | '^=') expression
|
||||
|
@ -7,11 +7,13 @@
|
||||
|
||||
sub start() {
|
||||
|
||||
ubyte derp
|
||||
ubyte v1
|
||||
ubyte v2
|
||||
|
||||
|
||||
derp=foo()
|
||||
derp=c64.GETADR()
|
||||
v1=foo()
|
||||
v1 , v2 =c64.GETADR()
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -191,7 +191,7 @@ interface IAstProcessor {
|
||||
}
|
||||
|
||||
fun process(assignment: Assignment): IStatement {
|
||||
assignment.target = assignment.target.process(this)
|
||||
assignment.targets = assignment.targets.map { it.process(this) }
|
||||
assignment.value = assignment.value.process(this)
|
||||
return assignment
|
||||
}
|
||||
@ -641,26 +641,31 @@ class VarDecl(val type: VarDeclType,
|
||||
}
|
||||
|
||||
|
||||
open class Assignment(var target: AssignTarget, val aug_op : String?, var value: IExpression, override val position: Position) : IStatement {
|
||||
open class Assignment(var targets: List<AssignTarget>, val aug_op : String?, var value: IExpression, override val position: Position) : IStatement {
|
||||
override lateinit var parent: Node
|
||||
|
||||
override fun linkParents(parent: Node) {
|
||||
this.parent = parent
|
||||
target.linkParents(this)
|
||||
targets.forEach { it.linkParents(this) }
|
||||
value.linkParents(this)
|
||||
}
|
||||
|
||||
override fun process(processor: IAstProcessor) = processor.process(this)
|
||||
|
||||
override fun toString(): String {
|
||||
return("Assignment(augop: $aug_op, target: $target, value: $value, pos=$position)")
|
||||
return("Assignment(augop: $aug_op, targets: $targets, value: $value, pos=$position)")
|
||||
}
|
||||
|
||||
val singleTarget: AssignTarget?
|
||||
get() {
|
||||
return targets.singleOrNull() // common case
|
||||
}
|
||||
}
|
||||
|
||||
// This is a special class so the compiler can see if the assignments are for initializing the vars in the scope,
|
||||
// or just a regular assignment. It may optimize the initialization step from this.
|
||||
class VariableInitializationAssignment(target: AssignTarget, aug_op: String?, value: IExpression, position: Position)
|
||||
: Assignment(target, aug_op, value, position)
|
||||
: Assignment(listOf(target), aug_op, value, position)
|
||||
|
||||
|
||||
data class AssignTarget(val register: Register?,
|
||||
@ -1645,11 +1650,11 @@ private fun prog8Parser.StatementContext.toAst() : IStatement {
|
||||
}
|
||||
|
||||
assignment()?.let {
|
||||
return Assignment(it.assign_target().toAst(),null, it.expression().toAst(), it.toPosition())
|
||||
return Assignment(it.assign_targets().toAst(), null, it.expression().toAst(), it.toPosition())
|
||||
}
|
||||
|
||||
augassignment()?.let {
|
||||
return Assignment(it.assign_target().toAst(),
|
||||
return Assignment(listOf(it.assign_target().toAst()),
|
||||
it.operator.text,
|
||||
it.expression().toAst(),
|
||||
it.toPosition())
|
||||
@ -1707,6 +1712,8 @@ private fun prog8Parser.StatementContext.toAst() : IStatement {
|
||||
throw FatalAstException("unprocessed source text (are we missing ast conversion rules for parser elements?): $text")
|
||||
}
|
||||
|
||||
private fun prog8Parser.Assign_targetsContext.toAst(): List<AssignTarget> = assign_target().map { it.toAst() }
|
||||
|
||||
|
||||
private fun prog8Parser.AsmsubroutineContext.toAst(): IStatement {
|
||||
val name = identifier().text
|
||||
|
@ -303,22 +303,31 @@ class AstChecker(private val namespace: INameScope,
|
||||
* Also check data type compatibility
|
||||
*/
|
||||
override fun process(assignment: Assignment): IStatement {
|
||||
if(assignment.target.identifier!=null) {
|
||||
val targetName = assignment.target.identifier!!.nameInSource
|
||||
var resultingAssignment = assignment
|
||||
for (target in assignment.targets) {
|
||||
resultingAssignment = processAssignmentTarget(resultingAssignment, target)
|
||||
}
|
||||
return super.process(resultingAssignment)
|
||||
}
|
||||
|
||||
private fun processAssignmentTarget(assignment: Assignment, target: AssignTarget): Assignment {
|
||||
if(target.identifier!=null) {
|
||||
val targetName = target.identifier.nameInSource
|
||||
val targetSymbol = namespace.lookup(targetName, assignment)
|
||||
when {
|
||||
targetSymbol == null -> {
|
||||
checkResult.add(ExpressionError("undefined symbol: ${targetName.joinToString(".")}", assignment.position))
|
||||
return super.process(assignment)
|
||||
return assignment
|
||||
}
|
||||
targetSymbol !is VarDecl -> {
|
||||
checkResult.add(SyntaxError("assignment LHS must be register or variable", assignment.position))
|
||||
return super.process(assignment)
|
||||
return assignment
|
||||
}
|
||||
targetSymbol.type == VarDeclType.CONST -> {
|
||||
checkResult.add(ExpressionError("cannot assign new value to a constant", assignment.position))
|
||||
return super.process(assignment)
|
||||
return assignment
|
||||
}
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
|
||||
@ -329,27 +338,27 @@ class AstChecker(private val namespace: INameScope,
|
||||
if(assignment.aug_op!=null) {
|
||||
// check augmented assignment:
|
||||
// A /= 3 -> check as if it was A = A / 3
|
||||
val target: IExpression =
|
||||
val newTarget: IExpression =
|
||||
when {
|
||||
assignment.target.register!=null -> RegisterExpr(assignment.target.register!!, assignment.target.position)
|
||||
assignment.target.identifier!=null -> assignment.target.identifier!!
|
||||
assignment.target.arrayindexed!=null -> assignment.target.arrayindexed!!
|
||||
target.register!=null -> RegisterExpr(target.register, target.position)
|
||||
target.identifier!=null -> target.identifier
|
||||
target.arrayindexed!=null -> target.arrayindexed
|
||||
else -> throw FatalAstException("strange assignment")
|
||||
}
|
||||
|
||||
val expression = BinaryExpression(target, assignment.aug_op.substringBeforeLast('='), assignment.value, assignment.position)
|
||||
val expression = BinaryExpression(newTarget, assignment.aug_op.substringBeforeLast('='), assignment.value, assignment.position)
|
||||
expression.linkParents(assignment.parent)
|
||||
val assignment2 = Assignment(assignment.target, null, expression, assignment.position)
|
||||
val assignment2 = Assignment(listOf(target), null, expression, assignment.position)
|
||||
assignment2.linkParents(assignment.parent)
|
||||
return process(assignment2)
|
||||
return assignment2
|
||||
}
|
||||
|
||||
val targetDatatype = assignment.target.determineDatatype(namespace, heap, assignment)
|
||||
val targetDatatype = target.determineDatatype(namespace, heap, assignment)
|
||||
if(targetDatatype!=null) {
|
||||
val constVal = assignment.value.constValue(namespace, heap)
|
||||
if(constVal!=null) {
|
||||
val arrayspec = if(assignment.target.identifier!=null) {
|
||||
val targetVar = namespace.lookup(assignment.target.identifier!!.nameInSource, assignment) as? VarDecl
|
||||
val arrayspec = if(target.identifier!=null) {
|
||||
val targetVar = namespace.lookup(target.identifier.nameInSource, assignment) as? VarDecl
|
||||
targetVar?.arrayspec
|
||||
} else null
|
||||
checkValueTypeAndRange(targetDatatype,
|
||||
@ -375,8 +384,7 @@ class AstChecker(private val namespace: INameScope,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return super.process(assignment)
|
||||
return assignment
|
||||
}
|
||||
|
||||
|
||||
|
@ -1089,10 +1089,11 @@ 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}")
|
||||
prog.line(stmt.position)
|
||||
translate(stmt.value)
|
||||
val valueDt = stmt.value.resultingDatatype(namespace, heap)
|
||||
val targetDt = stmt.target.determineDatatype(namespace, heap, stmt)
|
||||
val targetDt = assignTarget.determineDatatype(namespace, heap, stmt)
|
||||
if(valueDt!=targetDt) {
|
||||
// convert value to target datatype if possible
|
||||
when(targetDt) {
|
||||
@ -1124,26 +1125,26 @@ private class StatementTranslator(private val prog: IntermediateProgram,
|
||||
if(stmt.aug_op!=null) {
|
||||
// augmented assignment
|
||||
when {
|
||||
stmt.target.identifier!=null -> {
|
||||
val target = stmt.target.identifier!!.targetStatement(namespace)!!
|
||||
assignTarget.identifier!=null -> {
|
||||
val target = assignTarget.identifier.targetStatement(namespace)!!
|
||||
when(target) {
|
||||
is VarDecl -> {
|
||||
val opcode = opcodePushvar(stmt.target.determineDatatype(namespace, heap, stmt)!!)
|
||||
val opcode = opcodePushvar(assignTarget.determineDatatype(namespace, heap, stmt)!!)
|
||||
prog.instr(opcode, callLabel = target.scopedname)
|
||||
}
|
||||
else -> throw CompilerException("invalid assignment target type ${target::class}")
|
||||
}
|
||||
}
|
||||
stmt.target.register!=null -> prog.instr(Opcode.PUSH_VAR_BYTE, callLabel = stmt.target.register.toString())
|
||||
stmt.target.arrayindexed!=null -> translate(stmt.target.arrayindexed!!, false)
|
||||
assignTarget.register!=null -> prog.instr(Opcode.PUSH_VAR_BYTE, callLabel = assignTarget.register.toString())
|
||||
assignTarget.arrayindexed!=null -> translate(assignTarget.arrayindexed, false)
|
||||
}
|
||||
|
||||
translateAugAssignOperator(stmt.aug_op, stmt.value.resultingDatatype(namespace, heap))
|
||||
}
|
||||
|
||||
// pop the result value back into the assignment target
|
||||
val datatype = stmt.target.determineDatatype(namespace, heap, stmt)!!
|
||||
popValueIntoTarget(stmt.target, datatype)
|
||||
val datatype = assignTarget.determineDatatype(namespace, heap, stmt)!!
|
||||
popValueIntoTarget(assignTarget, datatype)
|
||||
}
|
||||
|
||||
private fun popValueIntoTarget(assignTarget: AssignTarget, datatype: DataType) {
|
||||
@ -1394,7 +1395,7 @@ private class StatementTranslator(private val prog: IntermediateProgram,
|
||||
else
|
||||
AssignTarget(null, loop.loopVar!!.copy(), null, loop.position)
|
||||
val arrayspec = ArraySpec(RegisterExpr(Register.X, loop.position), loop.position)
|
||||
val assignLv = Assignment(assignTarget, null, ArrayIndexedExpression((loop.iterable as IdentifierReference).copy(), arrayspec, loop.position), loop.position)
|
||||
val assignLv = Assignment(listOf(assignTarget), null, ArrayIndexedExpression((loop.iterable as IdentifierReference).copy(), arrayspec, loop.position), loop.position)
|
||||
assignLv.linkParents(loop.body)
|
||||
translate(assignLv)
|
||||
translate(loop.body)
|
||||
@ -1519,7 +1520,7 @@ private class StatementTranslator(private val prog: IntermediateProgram,
|
||||
AssignTarget(register, null, null, range.position)
|
||||
}
|
||||
|
||||
val startAssignment = Assignment(makeAssignmentTarget(), null, range.from, range.position)
|
||||
val startAssignment = Assignment(listOf(makeAssignmentTarget()), null, range.from, range.position)
|
||||
startAssignment.linkParents(range.parent)
|
||||
translate(startAssignment)
|
||||
|
||||
|
@ -536,7 +536,7 @@ class ConstantFolding(private val namespace: INameScope, private val heap: HeapV
|
||||
super.process(assignment)
|
||||
val lv = assignment.value as? LiteralValue
|
||||
if(lv!=null) {
|
||||
val targetDt = assignment.target.determineDatatype(namespace, heap, assignment)
|
||||
val targetDt = assignment.singleTarget?.determineDatatype(namespace, heap, assignment)
|
||||
// see if we can promote/convert a literal value to the required datatype
|
||||
when(targetDt) {
|
||||
DataType.UWORD -> {
|
||||
|
@ -105,7 +105,7 @@ class StatementOptimizer(private val namespace: INameScope, private val heap: He
|
||||
if(range.size()==1) {
|
||||
// for loop over a (constant) range of just a single value-- optimize the loop away
|
||||
// loopvar/reg = range value , follow by block
|
||||
val assignment = Assignment(AssignTarget(forLoop.loopRegister, forLoop.loopVar, null, forLoop.position), null, range.from, forLoop.position)
|
||||
val assignment = Assignment(listOf(AssignTarget(forLoop.loopRegister, forLoop.loopVar, null, forLoop.position)), null, range.from, forLoop.position)
|
||||
forLoop.body.statements.add(0, assignment)
|
||||
optimizationsDone++
|
||||
return forLoop.body
|
||||
@ -174,4 +174,4 @@ class StatementOptimizer(private val namespace: INameScope, private val heap: He
|
||||
}
|
||||
return jump
|
||||
}
|
||||
}
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user