mirror of
https://github.com/irmen/prog8.git
synced 2025-02-16 07:31:48 +00:00
allow multiple targets in AssignTarget
This commit is contained in:
parent
66e7c51064
commit
edc83305a4
@ -41,9 +41,18 @@ class PtSubroutineParameter(name: String, val type: DataType, position: Position
|
||||
sealed interface IPtAssignment {
|
||||
val children: MutableList<PtNode>
|
||||
val target: PtAssignTarget
|
||||
get() = children[0] as PtAssignTarget
|
||||
get() {
|
||||
if(children.size==2)
|
||||
return children[0] as PtAssignTarget
|
||||
else if(children.size<2)
|
||||
throw AssemblyError("incomplete node")
|
||||
else
|
||||
throw AssemblyError("no singular target")
|
||||
}
|
||||
val value: PtExpression
|
||||
get() = children[1] as PtExpression
|
||||
get() = children.last() as PtExpression
|
||||
val multiTarget: Boolean
|
||||
get() = children.size>2
|
||||
}
|
||||
|
||||
class PtAssignment(position: Position) : PtNode(position), IPtAssignment
|
||||
|
@ -1,5 +1,6 @@
|
||||
package prog8.codegen.intermediate
|
||||
|
||||
import prog8.code.StRomSub
|
||||
import prog8.code.ast.*
|
||||
import prog8.code.core.*
|
||||
import prog8.intermediate.*
|
||||
@ -8,15 +9,34 @@ import prog8.intermediate.*
|
||||
internal class AssignmentGen(private val codeGen: IRCodeGen, private val expressionEval: ExpressionGen) {
|
||||
|
||||
internal fun translate(assignment: PtAssignment): IRCodeChunks {
|
||||
if(assignment.target.children.single() is PtIrRegister)
|
||||
throw AssemblyError("assigning to a register should be done by just evaluating the expression into resultregister")
|
||||
if(assignment.multiTarget) {
|
||||
val values = assignment.value as? PtFunctionCall
|
||||
?: throw AssemblyError("only function calls can return multiple values in a multi-assign")
|
||||
|
||||
val chunks = translateRegularAssign(assignment)
|
||||
chunks.filterIsInstance<IRCodeChunk>().firstOrNull()?.appendSrcPosition(assignment.position)
|
||||
return chunks
|
||||
val sub = codeGen.symbolTable.lookup(values.name) as? StRomSub
|
||||
?: throw AssemblyError("only asmsubs can return multiple values")
|
||||
|
||||
val result = mutableListOf<IRCodeChunkBase>()
|
||||
sub.returns.zip(assignment.children).forEach { (returns, target) ->
|
||||
val singleAssign = PtAssignment(assignment.position)
|
||||
singleAssign.children.add(target)
|
||||
TODO("IR cannot store machine register results yet ${assignment.position}")
|
||||
// singleAssign.children.add(PtMachineRegister(4242, returns.type, assignment.position))
|
||||
// result += translateRegularAssign(singleAssign)
|
||||
}
|
||||
return result
|
||||
} else {
|
||||
if (assignment.target.children.single() is PtIrRegister)
|
||||
throw AssemblyError("assigning to a register should be done by just evaluating the expression into resultregister")
|
||||
|
||||
val chunks = translateRegularAssign(assignment)
|
||||
chunks.filterIsInstance<IRCodeChunk>().firstOrNull()?.appendSrcPosition(assignment.position)
|
||||
return chunks
|
||||
}
|
||||
}
|
||||
|
||||
internal fun translate(augAssign: PtAugmentedAssign): IRCodeChunks {
|
||||
// augmented assignment always has just a single target
|
||||
if(augAssign.target.children.single() is PtIrRegister)
|
||||
throw AssemblyError("assigning to a register should be done by just evaluating the expression into resultregister")
|
||||
|
||||
|
@ -309,7 +309,7 @@ internal class ConstantIdentifierReplacer(
|
||||
val add = BinaryExpression(NumericLiteral(cval.type, cval.number, identifier.position), "+", arrayIdx.indexer.indexExpr, identifier.position)
|
||||
return if(arrayIdx.parent is AssignTarget) {
|
||||
val memwrite = DirectMemoryWrite(add, identifier.position)
|
||||
val assignTarget = AssignTarget(null, null, memwrite, identifier.position)
|
||||
val assignTarget = AssignTarget(null, null, memwrite, null, identifier.position)
|
||||
listOf(IAstModification.ReplaceNode(arrayIdx.parent, assignTarget, arrayIdx.parent.parent))
|
||||
} else {
|
||||
val memread = DirectMemoryRead(add, identifier.position)
|
||||
|
@ -162,7 +162,7 @@ class StatementOptimizer(private val program: Program,
|
||||
// for loop over a (constant) range of just a single value-- optimize the loop away
|
||||
// loopvar/reg = range value , follow by block
|
||||
val scope = AnonymousScope(mutableListOf(), forLoop.position)
|
||||
scope.statements.add(Assignment(AssignTarget(forLoop.loopVar, null, null, forLoop.position), range.from, AssignmentOrigin.OPTIMIZER, forLoop.position))
|
||||
scope.statements.add(Assignment(AssignTarget(forLoop.loopVar, null, null, null, forLoop.position), range.from, AssignmentOrigin.OPTIMIZER, forLoop.position))
|
||||
scope.statements.addAll(forLoop.body.statements)
|
||||
return listOf(IAstModification.ReplaceNode(forLoop, scope, parent))
|
||||
}
|
||||
@ -177,7 +177,7 @@ class StatementOptimizer(private val program: Program,
|
||||
val character = options.compTarget.encodeString(sv.value, sv.encoding)[0]
|
||||
val byte = NumericLiteral(DataType.UBYTE, character.toDouble(), iterable.position)
|
||||
val scope = AnonymousScope(mutableListOf(), forLoop.position)
|
||||
scope.statements.add(Assignment(AssignTarget(forLoop.loopVar, null, null, forLoop.position), byte, AssignmentOrigin.OPTIMIZER, forLoop.position))
|
||||
scope.statements.add(Assignment(AssignTarget(forLoop.loopVar, null, null, null, forLoop.position), byte, AssignmentOrigin.OPTIMIZER, forLoop.position))
|
||||
scope.statements.addAll(forLoop.body.statements)
|
||||
return listOf(IAstModification.ReplaceNode(forLoop, scope, parent))
|
||||
}
|
||||
@ -190,7 +190,7 @@ class StatementOptimizer(private val program: Program,
|
||||
if(av!=null) {
|
||||
val scope = AnonymousScope(mutableListOf(), forLoop.position)
|
||||
scope.statements.add(Assignment(
|
||||
AssignTarget(forLoop.loopVar, null, null, forLoop.position), NumericLiteral.optimalInteger(av.toInt(), iterable.position),
|
||||
AssignTarget(forLoop.loopVar, null, null, null, forLoop.position), NumericLiteral.optimalInteger(av.toInt(), iterable.position),
|
||||
AssignmentOrigin.OPTIMIZER, forLoop.position))
|
||||
scope.statements.addAll(forLoop.body.statements)
|
||||
return listOf(IAstModification.ReplaceNode(forLoop, scope, parent))
|
||||
@ -206,7 +206,7 @@ class StatementOptimizer(private val program: Program,
|
||||
val pos = forLoop.position
|
||||
val loopVar = forLoop.loopVar
|
||||
val addSubOne = BinaryExpression(loopVar.copy(), if(inc) "+" else "-", NumericLiteral.optimalInteger(1, pos), pos, false)
|
||||
return Assignment(AssignTarget(loopVar.copy(), null, null, pos), addSubOne, AssignmentOrigin.USERCODE, pos)
|
||||
return Assignment(AssignTarget(loopVar.copy(), null, null, null, pos), addSubOne, AssignmentOrigin.USERCODE, pos)
|
||||
}
|
||||
|
||||
if (range != null && range.to.constValue(program)?.number == 0.0 && range.step.constValue(program)?.number==-1.0) {
|
||||
@ -219,7 +219,7 @@ class StatementOptimizer(private val program: Program,
|
||||
val decOne = incOrDec(false)
|
||||
forLoop.body.statements.add(decOne)
|
||||
val replacement = AnonymousScope(mutableListOf(
|
||||
Assignment(AssignTarget(forLoop.loopVar.copy(), null, null, pos),
|
||||
Assignment(AssignTarget(forLoop.loopVar.copy(), null, null, null, pos),
|
||||
fromExpr, AssignmentOrigin.OPTIMIZER, pos),
|
||||
UntilLoop(forLoop.body, condition, pos)
|
||||
), pos)
|
||||
|
@ -517,32 +517,78 @@ internal class AstChecker(private val program: Program,
|
||||
}
|
||||
|
||||
override fun visit(assignment: Assignment) {
|
||||
val targetDt = assignment.target.inferType(program)
|
||||
val valueDt = assignment.value.inferType(program)
|
||||
if(valueDt.isKnown && !(valueDt isAssignableTo targetDt)) {
|
||||
if(targetDt.isIterable)
|
||||
errors.err("cannot assign value to string or array", assignment.value.position)
|
||||
else if(!(valueDt istype DataType.STR && targetDt istype DataType.UWORD)) {
|
||||
if(targetDt.isUnknown) {
|
||||
if(assignment.target.identifier?.targetStatement(program)!=null)
|
||||
errors.err("target datatype is unknown", assignment.target.position)
|
||||
// otherwise, another error about missing symbol is already reported.
|
||||
fun checkType(target: AssignTarget, value: Expression, augmentable: Boolean) {
|
||||
val targetDt = target.inferType(program)
|
||||
val valueDt = value.inferType(program)
|
||||
if(valueDt.isKnown && !(valueDt isAssignableTo targetDt)) {
|
||||
if(targetDt.isIterable)
|
||||
errors.err("cannot assign value to string or array", value.position)
|
||||
else if(!(valueDt istype DataType.STR && targetDt istype DataType.UWORD)) {
|
||||
if(targetDt.isUnknown) {
|
||||
if(target.identifier?.targetStatement(program)!=null)
|
||||
errors.err("target datatype is unknown", target.position)
|
||||
// otherwise, another error about missing symbol is already reported.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(value is TypecastExpression) {
|
||||
if(augmentable && targetDt istype DataType.FLOAT)
|
||||
errors.err("typecasting a float value in-place makes no sense", value.position)
|
||||
}
|
||||
|
||||
val numvalue = value.constValue(program)
|
||||
if(numvalue!=null && targetDt.isKnown)
|
||||
checkValueTypeAndRange(targetDt.getOr(DataType.UNDEFINED), numvalue)
|
||||
}
|
||||
|
||||
if(assignment.target.multi==null) {
|
||||
checkType(assignment.target, assignment.value, assignment.isAugmentable)
|
||||
}
|
||||
|
||||
|
||||
// multi-assign: check the number of assign targets vs. the number of return values of the subroutine
|
||||
// also check the types of the variables vs the types of each return value
|
||||
val fcall = assignment.value as? IFunctionCall
|
||||
val fcallTarget = fcall?.target?.targetSubroutine(program)
|
||||
if(assignment.target.multi!=null) {
|
||||
val multi = assignment.target.multi!!
|
||||
if(fcall==null) {
|
||||
errors.err("expected a function call with multiple return values", assignment.value.position)
|
||||
} else {
|
||||
if(fcallTarget==null) {
|
||||
errors.err("expected a function call with multiple return values", assignment.value.position)
|
||||
} else {
|
||||
if(fcallTarget.returntypes.size!=multi.size) {
|
||||
errors.err("expected ${multi.size} return values, have ${fcallTarget.returntypes.size}", fcall.position)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(errors.noErrors()) {
|
||||
// check the types...
|
||||
fcallTarget!!.returntypes.zip(multi).withIndex().forEach { (index, p) ->
|
||||
val (returnType, target) = p
|
||||
val targetDt = target.inferType(program).getOr(DataType.UNDEFINED)
|
||||
if(!(returnType isAssignableTo targetDt))
|
||||
errors.err("can't assign returnvalue #${index+1} to corresponding target; ${returnType} vs $targetDt", target.position)
|
||||
}
|
||||
}
|
||||
|
||||
} else if(fcallTarget!=null) {
|
||||
if(fcallTarget.returntypes.size!=1) {
|
||||
// If there are 2 return values, one of them being a boolean in a status register, this is okay.
|
||||
// In that case the normal value is assigned and the status bit is dealth with separately for example with if_cs
|
||||
val (returnRegisters, _) = fcallTarget.asmReturnvaluesRegisters.partition { rr -> rr.registerOrPair != null }
|
||||
if(returnRegisters.size>1)
|
||||
errors.err("expected 1 return value, have ${fcallTarget.returntypes.size}", fcall.position)
|
||||
}
|
||||
}
|
||||
|
||||
if(assignment.value is TypecastExpression) {
|
||||
if(assignment.isAugmentable && targetDt istype DataType.FLOAT)
|
||||
errors.err("typecasting a float value in-place makes no sense", assignment.value.position)
|
||||
}
|
||||
|
||||
val numvalue = assignment.value.constValue(program)
|
||||
if(numvalue!=null && targetDt.isKnown)
|
||||
checkValueTypeAndRange(targetDt.getOr(DataType.UNDEFINED), numvalue)
|
||||
|
||||
super.visit(assignment)
|
||||
}
|
||||
|
||||
|
||||
override fun visit(assignTarget: AssignTarget) {
|
||||
super.visit(assignTarget)
|
||||
|
||||
@ -552,6 +598,9 @@ internal class AstChecker(private val program: Program,
|
||||
errors.err("address out of range", assignTarget.position)
|
||||
}
|
||||
|
||||
if(assignTarget.parent is AssignTarget)
|
||||
return // sub-target of a multi-assign is tested elsewhere
|
||||
|
||||
val assignment = assignTarget.parent as Statement
|
||||
val targetIdentifier = assignTarget.identifier
|
||||
if (targetIdentifier != null) {
|
||||
@ -1174,25 +1223,6 @@ internal class AstChecker(private val program: Program,
|
||||
if(error!=null)
|
||||
errors.err(error.first, error.second)
|
||||
|
||||
// check the functions that return multiple returnvalues.
|
||||
val stmt = functionCallExpr.target.targetStatement(program)
|
||||
if (stmt is Subroutine) {
|
||||
if (stmt.returntypes.size > 1) {
|
||||
// Currently, it's only possible to handle ONE (or zero) return values from a subroutine.
|
||||
// asmsub routines can have multiple return values, for instance in 2 different registers.
|
||||
// It's not (yet) possible to handle these multiple return values because assignments
|
||||
// are only to a single unique target at the same time.
|
||||
// EXCEPTION:
|
||||
// if the asmsub returns multiple values and one of them is via a status register bit (such as carry),
|
||||
// it *is* possible to handle them by just actually assigning the register value and
|
||||
// dealing with the status bit as just being that, the status bit after the call.
|
||||
val (returnRegisters, _) = stmt.asmReturnvaluesRegisters.partition { rr -> rr.registerOrPair != null }
|
||||
if (returnRegisters.size>1) {
|
||||
errors.err("It's not possible to store the multiple result values of this asmsub call; you should use a small block of custom inline assembly for this.", functionCallExpr.position)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// functions that don't return a value, can't be used in an expression or assignment
|
||||
if(targetStatement is Subroutine) {
|
||||
if(targetStatement.returntypes.isEmpty()) {
|
||||
|
@ -121,7 +121,7 @@ class AstPreprocessor(val program: Program,
|
||||
// we need to handle multi-decl here too, the desugarer maybe has not processed it here yet...
|
||||
if(decl.value!=null) {
|
||||
decl.names.forEach { name ->
|
||||
val target = AssignTarget(IdentifierReference(listOf(name), decl.position), null, null, decl.position)
|
||||
val target = AssignTarget(IdentifierReference(listOf(name), decl.position), null, null, null, decl.position)
|
||||
val assign = Assignment(target.copy(), decl.value!!.copy(), AssignmentOrigin.VARINIT, decl.position)
|
||||
replacements.add(IAstModification.InsertAfter(decl, assign, scope))
|
||||
}
|
||||
@ -137,7 +137,7 @@ class AstPreprocessor(val program: Program,
|
||||
} else {
|
||||
// handle declaration of a single variable
|
||||
if(decl.value!=null && (decl.datatype in NumericDatatypes || decl.datatype==DataType.BOOL)) {
|
||||
val target = AssignTarget(IdentifierReference(listOf(decl.name), decl.position), null, null, decl.position)
|
||||
val target = AssignTarget(IdentifierReference(listOf(decl.name), decl.position), null, null, null, decl.position)
|
||||
val assign = Assignment(target, decl.value!!, AssignmentOrigin.VARINIT, decl.position)
|
||||
replacements.add(IAstModification.ReplaceNode(decl, assign, scope))
|
||||
decl.value = null
|
||||
|
@ -183,7 +183,7 @@ _after:
|
||||
}
|
||||
if(functionCall.target.nameInSource==listOf("poke")) {
|
||||
// poke(a, v) is synonymous with @(a) = v
|
||||
val tgt = AssignTarget(null, null, DirectMemoryWrite(functionCall.args[0], position), position)
|
||||
val tgt = AssignTarget(null, null, DirectMemoryWrite(functionCall.args[0], position), null, position)
|
||||
val assign = Assignment(tgt, functionCall.args[1], AssignmentOrigin.OPTIMIZER, position)
|
||||
return listOf(IAstModification.ReplaceNode(functionCall as Node, assign, parent))
|
||||
}
|
||||
@ -222,7 +222,7 @@ _after:
|
||||
return if(parent is AssignTarget) {
|
||||
// assignment to array
|
||||
val memwrite = DirectMemoryWrite(address, arrayIndexedExpression.position)
|
||||
val newtarget = AssignTarget(null, null, memwrite, arrayIndexedExpression.position)
|
||||
val newtarget = AssignTarget(null, null, memwrite, null, arrayIndexedExpression.position)
|
||||
listOf(IAstModification.ReplaceNode(parent, newtarget, parent.parent))
|
||||
} else {
|
||||
// read from array
|
||||
|
@ -90,6 +90,7 @@ class IntermediateAstMaker(private val program: Program, private val errors: IEr
|
||||
|
||||
private fun transform(srcAssign: Assignment): PtNode {
|
||||
if(srcAssign.isAugmentable) {
|
||||
require(srcAssign.target.multi==null)
|
||||
val srcExpr = srcAssign.value
|
||||
val (operator: String, augmentedValue: Expression?) = when(srcExpr) {
|
||||
is BinaryExpression -> {
|
||||
@ -136,7 +137,12 @@ class IntermediateAstMaker(private val program: Program, private val errors: IEr
|
||||
}
|
||||
|
||||
val assign = PtAssignment(srcAssign.position)
|
||||
assign.add(transform(srcAssign.target))
|
||||
val multi = srcAssign.target.multi
|
||||
if(multi==null) {
|
||||
assign.add(transform(srcAssign.target))
|
||||
} else {
|
||||
multi.forEach { target -> assign.add(transform(target)) }
|
||||
}
|
||||
assign.add(transformExpression(srcAssign.value))
|
||||
return assign
|
||||
}
|
||||
@ -272,11 +278,8 @@ class IntermediateAstMaker(private val program: Program, private val errors: IEr
|
||||
|
||||
private fun transform(srcCall: FunctionCallExpression): PtFunctionCall {
|
||||
val (target, _) = srcCall.target.targetNameAndType(program)
|
||||
val type = srcCall.inferType(program).getOrElse {
|
||||
throw FatalAstException("unknown dt $srcCall")
|
||||
}
|
||||
val isVoid = type==DataType.UNDEFINED
|
||||
val call = PtFunctionCall(target, isVoid, type, srcCall.position)
|
||||
val iType = srcCall.inferType(program)
|
||||
val call = PtFunctionCall(target, iType.isUnknown, iType.getOrElse { DataType.UNDEFINED }, srcCall.position)
|
||||
for (arg in srcCall.args)
|
||||
call.add(transformExpression(arg))
|
||||
return call
|
||||
|
@ -60,7 +60,8 @@ internal class StatementReorderer(
|
||||
// Add assignment to initialize with zero
|
||||
// Note: for block-level vars, this will introduce assignments in the block scope. These have to be dealt with correctly later.
|
||||
val identifier = IdentifierReference(listOf(decl.name), decl.position)
|
||||
val assignzero = Assignment(AssignTarget(identifier, null, null, decl.position), decl.zeroElementValue(), AssignmentOrigin.VARINIT, decl.position)
|
||||
val assignzero = Assignment(AssignTarget(identifier, null, null, null, decl.position),
|
||||
decl.zeroElementValue(), AssignmentOrigin.VARINIT, decl.position)
|
||||
return listOf(IAstModification.InsertAfter(
|
||||
decl, assignzero, parent as IStatementContainer
|
||||
))
|
||||
@ -72,7 +73,8 @@ internal class StatementReorderer(
|
||||
// So basically consider 'ubyte xx=99' as a short form for 'ubyte xx; xx=99'
|
||||
val pos = decl.value!!.position
|
||||
val identifier = IdentifierReference(listOf(decl.name), pos)
|
||||
val assign = Assignment(AssignTarget(identifier, null, null, pos), decl.value!!, AssignmentOrigin.VARINIT, pos)
|
||||
val assign = Assignment(AssignTarget(identifier, null, null, null, pos),
|
||||
decl.value!!, AssignmentOrigin.VARINIT, pos)
|
||||
decl.value = null
|
||||
return listOf(IAstModification.InsertAfter(
|
||||
decl, assign, parent as IStatementContainer
|
||||
@ -90,7 +92,8 @@ internal class StatementReorderer(
|
||||
if(target!=null && target.isArray) {
|
||||
val pos = decl.value!!.position
|
||||
val identifier = IdentifierReference(listOf(decl.name), pos)
|
||||
val assign = Assignment(AssignTarget(identifier, null, null, pos), decl.value!!, AssignmentOrigin.VARINIT, pos)
|
||||
val assign = Assignment(AssignTarget(identifier, null, null, null, pos),
|
||||
decl.value!!, AssignmentOrigin.VARINIT, pos)
|
||||
decl.value = null
|
||||
return listOf(IAstModification.InsertAfter(
|
||||
decl, assign, parent as IStatementContainer
|
||||
|
@ -36,49 +36,49 @@ class TestMemory: FunSpec({
|
||||
test("assignment target not in mapped IO space C64") {
|
||||
|
||||
var memexpr = NumericLiteral.optimalInteger(0x0002, Position.DUMMY)
|
||||
var target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), Position.DUMMY)
|
||||
var target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), null, Position.DUMMY)
|
||||
var assign = Assignment(target, NumericLiteral.optimalInteger(0, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
|
||||
wrapWithProgram(listOf(assign))
|
||||
target.isIOAddress(c64target.machine) shouldBe false
|
||||
|
||||
memexpr = NumericLiteral.optimalInteger(0x1000, Position.DUMMY)
|
||||
target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), Position.DUMMY)
|
||||
target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), null, Position.DUMMY)
|
||||
assign = Assignment(target, NumericLiteral.optimalInteger(0, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
|
||||
wrapWithProgram(listOf(assign))
|
||||
target.isIOAddress(c64target.machine) shouldBe false
|
||||
|
||||
memexpr = NumericLiteral.optimalInteger(0x9fff, Position.DUMMY)
|
||||
target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), Position.DUMMY)
|
||||
target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), null, Position.DUMMY)
|
||||
assign = Assignment(target, NumericLiteral.optimalInteger(0, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
|
||||
wrapWithProgram(listOf(assign))
|
||||
target.isIOAddress(c64target.machine) shouldBe false
|
||||
|
||||
memexpr = NumericLiteral.optimalInteger(0xa000, Position.DUMMY)
|
||||
target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), Position.DUMMY)
|
||||
target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), null, Position.DUMMY)
|
||||
assign = Assignment(target, NumericLiteral.optimalInteger(0, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
|
||||
wrapWithProgram(listOf(assign))
|
||||
target.isIOAddress(c64target.machine) shouldBe false
|
||||
|
||||
memexpr = NumericLiteral.optimalInteger(0xc000, Position.DUMMY)
|
||||
target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), Position.DUMMY)
|
||||
target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), null, Position.DUMMY)
|
||||
assign = Assignment(target, NumericLiteral.optimalInteger(0, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
|
||||
wrapWithProgram(listOf(assign))
|
||||
target.isIOAddress(c64target.machine) shouldBe false
|
||||
|
||||
memexpr = NumericLiteral.optimalInteger(0xcfff, Position.DUMMY)
|
||||
target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), Position.DUMMY)
|
||||
target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), null, Position.DUMMY)
|
||||
assign = Assignment(target, NumericLiteral.optimalInteger(0, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
|
||||
wrapWithProgram(listOf(assign))
|
||||
target.isIOAddress(c64target.machine) shouldBe false
|
||||
|
||||
memexpr = NumericLiteral.optimalInteger(0xeeee, Position.DUMMY)
|
||||
target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), Position.DUMMY)
|
||||
target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), null, Position.DUMMY)
|
||||
assign = Assignment(target, NumericLiteral.optimalInteger(0, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
|
||||
wrapWithProgram(listOf(assign))
|
||||
target.isIOAddress(c64target.machine) shouldBe false
|
||||
|
||||
memexpr = NumericLiteral.optimalInteger(0xffff, Position.DUMMY)
|
||||
target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), Position.DUMMY)
|
||||
target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), null, Position.DUMMY)
|
||||
assign = Assignment(target, NumericLiteral.optimalInteger(0, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
|
||||
wrapWithProgram(listOf(assign))
|
||||
target.isIOAddress(c64target.machine) shouldBe false
|
||||
@ -87,25 +87,25 @@ class TestMemory: FunSpec({
|
||||
test("assign target in mapped IO space C64") {
|
||||
|
||||
var memexpr = NumericLiteral.optimalInteger(0x0000, Position.DUMMY)
|
||||
var target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), Position.DUMMY)
|
||||
var target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), null, Position.DUMMY)
|
||||
var assign = Assignment(target, NumericLiteral.optimalInteger(0, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
|
||||
wrapWithProgram(listOf(assign))
|
||||
target.isIOAddress(c64target.machine) shouldBe true
|
||||
|
||||
memexpr = NumericLiteral.optimalInteger(0x0001, Position.DUMMY)
|
||||
target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), Position.DUMMY)
|
||||
target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), null, Position.DUMMY)
|
||||
assign = Assignment(target, NumericLiteral.optimalInteger(0, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
|
||||
wrapWithProgram(listOf(assign))
|
||||
target.isIOAddress(c64target.machine) shouldBe true
|
||||
|
||||
memexpr = NumericLiteral.optimalInteger(0xd000, Position.DUMMY)
|
||||
target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), Position.DUMMY)
|
||||
target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), null, Position.DUMMY)
|
||||
assign = Assignment(target, NumericLiteral.optimalInteger(0, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
|
||||
wrapWithProgram(listOf(assign))
|
||||
target.isIOAddress(c64target.machine) shouldBe true
|
||||
|
||||
memexpr = NumericLiteral.optimalInteger(0xdfff, Position.DUMMY)
|
||||
target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), Position.DUMMY)
|
||||
target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), null, Position.DUMMY)
|
||||
assign = Assignment(target, NumericLiteral.optimalInteger(0, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
|
||||
wrapWithProgram(listOf(assign))
|
||||
target.isIOAddress(c64target.machine) shouldBe true
|
||||
@ -114,7 +114,7 @@ class TestMemory: FunSpec({
|
||||
fun createTestProgramForMemoryRefViaVar(address: UInt, vartype: VarDeclType): AssignTarget {
|
||||
val decl = VarDecl(vartype, VarDeclOrigin.USERCODE, DataType.BYTE, ZeropageWish.DONTCARE, null, "address", emptyList(), NumericLiteral.optimalInteger(address, Position.DUMMY), false, false, Position.DUMMY)
|
||||
val memexpr = IdentifierReference(listOf("address"), Position.DUMMY)
|
||||
val target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), Position.DUMMY)
|
||||
val target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), null, Position.DUMMY)
|
||||
val assignment = Assignment(target, NumericLiteral.optimalInteger(0, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
|
||||
wrapWithProgram(listOf(decl, assignment))
|
||||
return target
|
||||
@ -137,13 +137,13 @@ class TestMemory: FunSpec({
|
||||
|
||||
test("memory expression mapped to IO memory on C64") {
|
||||
var memexpr = PrefixExpression("+", NumericLiteral.optimalInteger(0x1000, Position.DUMMY), Position.DUMMY)
|
||||
var target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), Position.DUMMY)
|
||||
var target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), null, Position.DUMMY)
|
||||
var assign = Assignment(target, NumericLiteral.optimalInteger(0, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
|
||||
wrapWithProgram(listOf(assign))
|
||||
target.isIOAddress(c64target.machine) shouldBe false
|
||||
|
||||
memexpr = PrefixExpression("+", NumericLiteral.optimalInteger(0xd020, Position.DUMMY), Position.DUMMY)
|
||||
target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), Position.DUMMY)
|
||||
target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), null, Position.DUMMY)
|
||||
assign = Assignment(target, NumericLiteral.optimalInteger(0, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
|
||||
wrapWithProgram(listOf(assign))
|
||||
target.isIOAddress(c64target.machine) shouldBe true
|
||||
@ -151,7 +151,7 @@ class TestMemory: FunSpec({
|
||||
|
||||
test("regular variable not in mapped IO ram on C64") {
|
||||
val decl = VarDecl(VarDeclType.VAR, VarDeclOrigin.USERCODE, DataType.BYTE, ZeropageWish.DONTCARE, null, "address", emptyList(), null, false, false, Position.DUMMY)
|
||||
val target = AssignTarget(IdentifierReference(listOf("address"), Position.DUMMY), null, null, Position.DUMMY)
|
||||
val target = AssignTarget(IdentifierReference(listOf("address"), Position.DUMMY), null, null, null, Position.DUMMY)
|
||||
val assignment = Assignment(target, NumericLiteral.optimalInteger(0, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
|
||||
val subroutine = Subroutine("test", mutableListOf(), mutableListOf(), emptyList(), emptyList(), emptySet(), null, false, false, false, mutableListOf(decl, assignment), Position.DUMMY)
|
||||
val module = Module(mutableListOf(subroutine), Position.DUMMY, SourceCode.Generated("test"))
|
||||
@ -163,7 +163,7 @@ class TestMemory: FunSpec({
|
||||
test("memory mapped variable not in mapped IO ram on C64") {
|
||||
val address = 0x1000u
|
||||
val decl = VarDecl(VarDeclType.MEMORY, VarDeclOrigin.USERCODE, DataType.UBYTE, ZeropageWish.DONTCARE, null, "address", emptyList(), NumericLiteral.optimalInteger(address, Position.DUMMY), false, false, Position.DUMMY)
|
||||
val target = AssignTarget(IdentifierReference(listOf("address"), Position.DUMMY), null, null, Position.DUMMY)
|
||||
val target = AssignTarget(IdentifierReference(listOf("address"), Position.DUMMY), null, null, null, Position.DUMMY)
|
||||
val assignment = Assignment(target, NumericLiteral.optimalInteger(0, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
|
||||
val subroutine = Subroutine("test", mutableListOf(), mutableListOf(), emptyList(), emptyList(), emptySet(), null, false, false, false, mutableListOf(decl, assignment), Position.DUMMY)
|
||||
val module = Module(mutableListOf(subroutine), Position.DUMMY, SourceCode.Generated("test"))
|
||||
@ -175,7 +175,7 @@ class TestMemory: FunSpec({
|
||||
test("memory mapped variable in mapped IO ram on C64") {
|
||||
val address = 0xd020u
|
||||
val decl = VarDecl(VarDeclType.MEMORY, VarDeclOrigin.USERCODE, DataType.UBYTE, ZeropageWish.DONTCARE, null, "address", emptyList(), NumericLiteral.optimalInteger(address, Position.DUMMY), false, false, Position.DUMMY)
|
||||
val target = AssignTarget(IdentifierReference(listOf("address"), Position.DUMMY), null, null, Position.DUMMY)
|
||||
val target = AssignTarget(IdentifierReference(listOf("address"), Position.DUMMY), null, null, null, Position.DUMMY)
|
||||
val assignment = Assignment(target, NumericLiteral.optimalInteger(0, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
|
||||
val subroutine = Subroutine("test", mutableListOf(), mutableListOf(), emptyList(), emptyList(), emptySet(), null, false, false, false, mutableListOf(decl, assignment), Position.DUMMY)
|
||||
val module = Module(mutableListOf(subroutine), Position.DUMMY, SourceCode.Generated("test"))
|
||||
@ -187,7 +187,7 @@ class TestMemory: FunSpec({
|
||||
test("array not in mapped IO ram") {
|
||||
val decl = VarDecl(VarDeclType.VAR, VarDeclOrigin.USERCODE, DataType.ARRAY_UB, ZeropageWish.DONTCARE, null, "address", emptyList(), null, false, false, Position.DUMMY)
|
||||
val arrayindexed = ArrayIndexedExpression(IdentifierReference(listOf("address"), Position.DUMMY), ArrayIndex(NumericLiteral.optimalInteger(1, Position.DUMMY), Position.DUMMY), Position.DUMMY)
|
||||
val target = AssignTarget(null, arrayindexed, null, Position.DUMMY)
|
||||
val target = AssignTarget(null, arrayindexed, null, null, Position.DUMMY)
|
||||
val assignment = Assignment(target, NumericLiteral.optimalInteger(0, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
|
||||
val subroutine = Subroutine("test", mutableListOf(), mutableListOf(), emptyList(), emptyList(), emptySet(), null, false, false, false, mutableListOf(decl, assignment), Position.DUMMY)
|
||||
val module = Module(mutableListOf(subroutine), Position.DUMMY, SourceCode.Generated("test"))
|
||||
@ -200,7 +200,7 @@ class TestMemory: FunSpec({
|
||||
val address = 0x1000u
|
||||
val decl = VarDecl(VarDeclType.MEMORY, VarDeclOrigin.USERCODE, DataType.ARRAY_UB, ZeropageWish.DONTCARE, null, "address", emptyList(), NumericLiteral.optimalInteger(address, Position.DUMMY), false, false, Position.DUMMY)
|
||||
val arrayindexed = ArrayIndexedExpression(IdentifierReference(listOf("address"), Position.DUMMY), ArrayIndex(NumericLiteral.optimalInteger(1, Position.DUMMY), Position.DUMMY), Position.DUMMY)
|
||||
val target = AssignTarget(null, arrayindexed, null, Position.DUMMY)
|
||||
val target = AssignTarget(null, arrayindexed, null, null, Position.DUMMY)
|
||||
val assignment = Assignment(target, NumericLiteral.optimalInteger(0, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
|
||||
val subroutine = Subroutine("test", mutableListOf(), mutableListOf(), emptyList(), emptyList(), emptySet(), null, false, false, false, mutableListOf(decl, assignment), Position.DUMMY)
|
||||
val module = Module(mutableListOf(subroutine), Position.DUMMY, SourceCode.Generated("test"))
|
||||
@ -213,7 +213,7 @@ class TestMemory: FunSpec({
|
||||
val address = 0xd800u
|
||||
val decl = VarDecl(VarDeclType.MEMORY, VarDeclOrigin.USERCODE, DataType.ARRAY_UB, ZeropageWish.DONTCARE, null, "address", emptyList(), NumericLiteral.optimalInteger(address, Position.DUMMY), false, false, Position.DUMMY)
|
||||
val arrayindexed = ArrayIndexedExpression(IdentifierReference(listOf("address"), Position.DUMMY), ArrayIndex(NumericLiteral.optimalInteger(1, Position.DUMMY), Position.DUMMY), Position.DUMMY)
|
||||
val target = AssignTarget(null, arrayindexed, null, Position.DUMMY)
|
||||
val target = AssignTarget(null, arrayindexed, null, null, Position.DUMMY)
|
||||
val assignment = Assignment(target, NumericLiteral.optimalInteger(0, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
|
||||
val subroutine = Subroutine("test", mutableListOf(), mutableListOf(), emptyList(), emptyList(), emptySet(), null, false, false, false, mutableListOf(decl, assignment), Position.DUMMY)
|
||||
val module = Module(mutableListOf(subroutine), Position.DUMMY, SourceCode.Generated("test"))
|
||||
|
@ -50,7 +50,7 @@ class TestAsmGenSymbols: StringSpec({
|
||||
val var2InSub = VarDecl(VarDeclType.VAR, VarDeclOrigin.USERCODE, DataType.UWORD, ZeropageWish.DONTCARE, null, "tgt", emptyList(), null, false, false, Position.DUMMY)
|
||||
val labelInSub = Label("locallabel", Position.DUMMY)
|
||||
|
||||
val tgt = AssignTarget(IdentifierReference(listOf("tgt"), Position.DUMMY), null, null, Position.DUMMY)
|
||||
val tgt = AssignTarget(IdentifierReference(listOf("tgt"), Position.DUMMY), null, null, null, Position.DUMMY)
|
||||
val assign1 = Assignment(tgt, IdentifierReference(listOf("localvar"), Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
|
||||
val assign2 = Assignment(tgt, AddressOf(IdentifierReference(listOf("locallabel"), Position.DUMMY), null, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
|
||||
val assign3 = Assignment(tgt, AddressOf(IdentifierReference(listOf("var_outside"), Position.DUMMY), null, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
|
||||
|
@ -409,6 +409,14 @@ class AstToSourceTextConverter(val output: (text: String) -> Unit, val program:
|
||||
assignTarget.memoryAddress?.accept(this)
|
||||
assignTarget.identifier?.accept(this)
|
||||
assignTarget.arrayindexed?.accept(this)
|
||||
val multi = assignTarget.multi
|
||||
if(multi!=null) {
|
||||
multi.dropLast(1).forEach { target ->
|
||||
target.accept(this)
|
||||
output(", ")
|
||||
}
|
||||
multi.last().accept(this)
|
||||
}
|
||||
}
|
||||
|
||||
override fun visit(scope: AnonymousScope) {
|
||||
|
@ -322,20 +322,25 @@ private fun Sub_paramsContext.toAst(): List<SubroutineParameter> =
|
||||
private fun Assign_targetContext.toAst() : AssignTarget {
|
||||
return when(this) {
|
||||
is IdentifierTargetContext ->
|
||||
AssignTarget(scoped_identifier().toAst(), null, null, scoped_identifier().toPosition())
|
||||
AssignTarget(scoped_identifier().toAst(), null, null, null, scoped_identifier().toPosition())
|
||||
is MemoryTargetContext ->
|
||||
AssignTarget(null, null, DirectMemoryWrite(directmemory().expression().toAst(), directmemory().toPosition()), toPosition())
|
||||
AssignTarget(null, null, DirectMemoryWrite(directmemory().expression().toAst(), directmemory().toPosition()), null, toPosition())
|
||||
is ArrayindexedTargetContext -> {
|
||||
val ax = arrayindexed()
|
||||
val arrayvar = ax.scoped_identifier().toAst()
|
||||
val index = ax.arrayindex().toAst()
|
||||
val arrayindexed = ArrayIndexedExpression(arrayvar, index, ax.toPosition())
|
||||
AssignTarget(null, arrayindexed, null, toPosition())
|
||||
AssignTarget(null, arrayindexed, null, null, toPosition())
|
||||
}
|
||||
else -> throw FatalAstException("weird assign target node $this")
|
||||
}
|
||||
}
|
||||
|
||||
private fun Multi_assign_targetContext.toAst() : AssignTarget {
|
||||
val targets = this.assign_target().map { it.toAst() }
|
||||
return AssignTarget(null, null, null, targets, toPosition())
|
||||
}
|
||||
|
||||
private fun ClobberContext.toAst() : Set<CpuRegister> {
|
||||
val names = this.NAME().map { it.text }
|
||||
try {
|
||||
@ -346,6 +351,11 @@ private fun ClobberContext.toAst() : Set<CpuRegister> {
|
||||
}
|
||||
|
||||
private fun AssignmentContext.toAst(): Statement {
|
||||
val multiAssign = multi_assign_target()
|
||||
if(multiAssign!=null) {
|
||||
return Assignment(multiAssign.toAst(), expression().toAst(), AssignmentOrigin.USERCODE, toPosition())
|
||||
}
|
||||
|
||||
val nestedAssign = assignment()
|
||||
if(nestedAssign==null)
|
||||
return Assignment(assign_target().toAst(), expression().toAst(), AssignmentOrigin.USERCODE, toPosition())
|
||||
|
@ -493,6 +493,7 @@ class Assignment(var target: AssignTarget, var value: Expression, var origin: As
|
||||
data class AssignTarget(var identifier: IdentifierReference?,
|
||||
var arrayindexed: ArrayIndexedExpression?,
|
||||
val memoryAddress: DirectMemoryWrite?,
|
||||
val multi: List<AssignTarget>?,
|
||||
override val position: Position) : Node {
|
||||
override lateinit var parent: Node
|
||||
|
||||
@ -501,12 +502,14 @@ data class AssignTarget(var identifier: IdentifierReference?,
|
||||
identifier?.linkParents(this)
|
||||
arrayindexed?.linkParents(this)
|
||||
memoryAddress?.linkParents(this)
|
||||
multi?.forEach { it.linkParents(this) }
|
||||
}
|
||||
|
||||
override fun replaceChildNode(node: Node, replacement: Node) {
|
||||
when {
|
||||
node === identifier -> identifier = replacement as IdentifierReference
|
||||
node === arrayindexed -> arrayindexed = replacement as ArrayIndexedExpression
|
||||
node === multi -> throw FatalAstException("can't replace multi assign targets")
|
||||
else -> throw FatalAstException("invalid replace")
|
||||
}
|
||||
replacement.parent = this
|
||||
@ -514,11 +517,12 @@ data class AssignTarget(var identifier: IdentifierReference?,
|
||||
|
||||
fun accept(visitor: IAstVisitor) = visitor.visit(this)
|
||||
fun accept(visitor: AstWalker, parent: Node) = visitor.visit(this, parent)
|
||||
override fun copy() = AssignTarget(identifier?.copy(), arrayindexed?.copy(), memoryAddress?.copy(), position)
|
||||
override fun copy() = AssignTarget(identifier?.copy(), arrayindexed?.copy(), memoryAddress?.copy(), multi?.toList(), position)
|
||||
override fun referencesIdentifier(nameInSource: List<String>): Boolean =
|
||||
identifier?.referencesIdentifier(nameInSource)==true ||
|
||||
arrayindexed?.referencesIdentifier(nameInSource)==true ||
|
||||
memoryAddress?.referencesIdentifier(nameInSource)==true
|
||||
memoryAddress?.referencesIdentifier(nameInSource)==true ||
|
||||
multi?.any { it.referencesIdentifier(nameInSource)}==true
|
||||
|
||||
fun inferType(program: Program): InferredTypes.InferredType {
|
||||
if (identifier != null) {
|
||||
@ -533,6 +537,8 @@ data class AssignTarget(var identifier: IdentifierReference?,
|
||||
if (memoryAddress != null)
|
||||
return InferredTypes.knownFor(DataType.UBYTE)
|
||||
|
||||
// a multi-assign has no 1 type... TODO although it could perhaps be the type of the first target?
|
||||
|
||||
return InferredTypes.unknown()
|
||||
}
|
||||
|
||||
@ -542,7 +548,8 @@ data class AssignTarget(var identifier: IdentifierReference?,
|
||||
identifier != null -> identifier!!.copy()
|
||||
arrayindexed != null -> arrayindexed!!.copy()
|
||||
memoryAddress != null -> DirectMemoryRead(memoryAddress.addressExpression.copy(), memoryAddress.position)
|
||||
else -> throw FatalAstException("invalid assignmenttarget $this")
|
||||
multi != null -> throw FatalAstException("cannot turn a multi-assign into a single source expression")
|
||||
else -> throw FatalAstException("invalid assignmenttarget")
|
||||
}
|
||||
}
|
||||
|
||||
@ -562,6 +569,7 @@ data class AssignTarget(var identifier: IdentifierReference?,
|
||||
else
|
||||
false
|
||||
}
|
||||
multi != null -> false
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
@ -583,6 +591,9 @@ data class AssignTarget(var identifier: IdentifierReference?,
|
||||
return x1 != null && x2 != null && x1 == x2
|
||||
}
|
||||
}
|
||||
if(this.multi != null && other.multi != null)
|
||||
return this.multi == other.multi
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
@ -624,6 +635,9 @@ data class AssignTarget(var identifier: IdentifierReference?,
|
||||
else
|
||||
false
|
||||
}
|
||||
multi != null -> {
|
||||
return multi.any { it.isIOAddress(machine) }
|
||||
}
|
||||
else -> return false
|
||||
}
|
||||
}
|
||||
|
@ -432,6 +432,7 @@ abstract class AstWalker {
|
||||
assignTarget.arrayindexed?.accept(this, assignTarget)
|
||||
assignTarget.identifier?.accept(this, assignTarget)
|
||||
assignTarget.memoryAddress?.accept(this, assignTarget)
|
||||
assignTarget.multi?.forEach { it.accept(this, assignTarget) }
|
||||
track(after(assignTarget, parent), assignTarget, parent)
|
||||
}
|
||||
|
||||
|
@ -152,6 +152,7 @@ interface IAstVisitor {
|
||||
assignTarget.arrayindexed?.accept(this)
|
||||
assignTarget.identifier?.accept(this)
|
||||
assignTarget.memoryAddress?.accept(this)
|
||||
assignTarget.multi?.forEach { it.accept(this) }
|
||||
}
|
||||
|
||||
fun visit(scope: AnonymousScope) {
|
||||
|
@ -66,7 +66,6 @@ Optimizations:
|
||||
those checks should probably be removed, or be made permanent
|
||||
- optimizeCommonSubExpressions: currently only looks in expressions on a single line, could search across multiple expressions
|
||||
|
||||
|
||||
STRUCTS again?
|
||||
--------------
|
||||
|
||||
|
@ -150,7 +150,7 @@ datatype: 'ubyte' | 'byte' | 'uword' | 'word' | 'float' | 'str' | 'bool' ;
|
||||
|
||||
arrayindex: '[' expression ']' ;
|
||||
|
||||
assignment : (assign_target '=' expression) | (assign_target '=' assignment);
|
||||
assignment : (assign_target '=' expression) | (assign_target '=' assignment) | (multi_assign_target '=' expression);
|
||||
|
||||
augassignment :
|
||||
assign_target operator=('+=' | '-=' | '/=' | '*=' | '&=' | '|=' | '^=' | '%=' | '<<=' | '>>=' ) expression
|
||||
@ -162,6 +162,9 @@ assign_target:
|
||||
| directmemory #MemoryTarget
|
||||
;
|
||||
|
||||
multi_assign_target:
|
||||
assign_target (',' assign_target)+ ;
|
||||
|
||||
postincrdecr : assign_target operator = ('++' | '--') ;
|
||||
|
||||
expression :
|
||||
|
Loading…
x
Reference in New Issue
Block a user