mirror of
https://github.com/irmen/prog8.git
synced 2025-08-14 22:27:48 +00:00
allow 'void' as dummy assign target in multi-assignment statements
This commit is contained in:
@@ -60,7 +60,7 @@ class PtAssignment(position: Position) : PtNode(position), IPtAssignment
|
|||||||
class PtAugmentedAssign(val operator: String, position: Position) : PtNode(position), IPtAssignment
|
class PtAugmentedAssign(val operator: String, position: Position) : PtNode(position), IPtAssignment
|
||||||
|
|
||||||
|
|
||||||
class PtAssignTarget(position: Position) : PtNode(position) {
|
class PtAssignTarget(val void: Boolean, position: Position) : PtNode(position) {
|
||||||
val identifier: PtIdentifier?
|
val identifier: PtIdentifier?
|
||||||
get() = children.single() as? PtIdentifier
|
get() = children.single() as? PtIdentifier
|
||||||
val array: PtArrayIndexer?
|
val array: PtArrayIndexer?
|
||||||
@@ -78,7 +78,7 @@ class PtAssignTarget(position: Position) : PtNode(position) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
infix fun isSameAs(expression: PtExpression): Boolean = expression.isSameAs(this)
|
infix fun isSameAs(expression: PtExpression): Boolean = !void && expression.isSameAs(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@@ -89,7 +89,7 @@ private fun optimizeCommonSubExpressions(program: PtProgram, errors: IErrorRepor
|
|||||||
singleReplacement2.parent = occurrence2.parent
|
singleReplacement2.parent = occurrence2.parent
|
||||||
|
|
||||||
val tempassign = PtAssignment(binexpr.position).also { assign ->
|
val tempassign = PtAssignment(binexpr.position).also { assign ->
|
||||||
assign.add(PtAssignTarget(binexpr.position).also { tgt->
|
assign.add(PtAssignTarget(false, binexpr.position).also { tgt->
|
||||||
tgt.add(PtIdentifier("$containerScopedName.$tempvarName", datatype, binexpr.position))
|
tgt.add(PtIdentifier("$containerScopedName.$tempvarName", datatype, binexpr.position))
|
||||||
})
|
})
|
||||||
assign.add(occurrence1)
|
assign.add(occurrence1)
|
||||||
|
@@ -35,7 +35,6 @@ internal class AssignmentAsmGen(private val program: PtProgram,
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun translateMultiAssign(assignment: PtAssignment) {
|
fun translateMultiAssign(assignment: PtAssignment) {
|
||||||
// TODO("translate multi-value assignment ${assignment.position}")
|
|
||||||
val values = assignment.value as? PtFunctionCall
|
val values = assignment.value as? PtFunctionCall
|
||||||
?: throw AssemblyError("only function calls can return multiple values in a multi-assign")
|
?: throw AssemblyError("only function calls can return multiple values in a multi-assign")
|
||||||
|
|
||||||
@@ -66,35 +65,48 @@ internal class AssignmentAsmGen(private val program: PtProgram,
|
|||||||
|
|
||||||
fun assignRegisterResults(registersResults: List<Pair<StRomSubParameter, PtNode>>) {
|
fun assignRegisterResults(registersResults: List<Pair<StRomSubParameter, PtNode>>) {
|
||||||
registersResults.forEach { (returns, target) ->
|
registersResults.forEach { (returns, target) ->
|
||||||
val targetIdent = (target as PtAssignTarget).identifier
|
target as PtAssignTarget
|
||||||
val targetMem = target.memory
|
if(!target.void) {
|
||||||
if(targetIdent!=null || targetMem!=null) {
|
val targetIdent = target.identifier
|
||||||
val tgt = AsmAssignTarget.fromAstAssignment(target, target.definingISub(), asmgen)
|
val targetMem = target.memory
|
||||||
when(returns.type) {
|
if(targetIdent!=null || targetMem!=null) {
|
||||||
in ByteDatatypesWithBoolean -> {
|
val tgt = AsmAssignTarget.fromAstAssignment(target, target.definingISub(), asmgen)
|
||||||
assignRegisterByte(tgt, returns.register.registerOrPair!!.asCpuRegister(), false, false)
|
when(returns.type) {
|
||||||
|
in ByteDatatypesWithBoolean -> {
|
||||||
|
assignRegisterByte(tgt, returns.register.registerOrPair!!.asCpuRegister(), false, false)
|
||||||
|
}
|
||||||
|
in WordDatatypes -> {
|
||||||
|
assignRegisterpairWord(tgt, returns.register.registerOrPair!!)
|
||||||
|
}
|
||||||
|
else -> throw AssemblyError("weird dt")
|
||||||
}
|
}
|
||||||
in WordDatatypes -> {
|
|
||||||
assignRegisterpairWord(tgt, returns.register.registerOrPair!!)
|
|
||||||
}
|
|
||||||
else -> throw AssemblyError("weird dt")
|
|
||||||
}
|
}
|
||||||
|
else TODO("array target for multi-value assignment") // Not done yet due to result register clobbering complexity
|
||||||
}
|
}
|
||||||
else TODO("array target for multi-value assignment") // Not done yet due to result register clobbering complexity
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val assignmentTargets = assignment.children.dropLast(1)
|
val assignmentTargets = assignment.children.dropLast(1)
|
||||||
if(sub.returns.size==assignmentTargets.size) {
|
if(sub.returns.size==assignmentTargets.size) {
|
||||||
// because we can only handle integer results right now we can just zip() it all up
|
// because we can only handle integer results right now we can just zip() it all up
|
||||||
val (statusFlagResult, registersResults) = sub.returns.zip(assignmentTargets).partition { it.first.register.statusflag!=null }
|
val (statusFlagResults, registersResults) = sub.returns.zip(assignmentTargets).partition { it.first.register.statusflag!=null }
|
||||||
if(statusFlagResult.isNotEmpty()) {
|
if(statusFlagResults.isNotEmpty()) {
|
||||||
val (returns, target) = statusFlagResult.single()
|
if(statusFlagResults.size>1)
|
||||||
|
TODO("handle multiple status flag results")
|
||||||
|
val (returns, target) = statusFlagResults.single()
|
||||||
if(returns.register.statusflag!=Statusflag.Pc)
|
if(returns.register.statusflag!=Statusflag.Pc)
|
||||||
TODO("other status flag for return value")
|
TODO("other status flag for return value")
|
||||||
|
|
||||||
target as PtAssignTarget
|
target as PtAssignTarget
|
||||||
if(registersResults.all { (it.second as PtAssignTarget).identifier!=null}) {
|
if(target.void) {
|
||||||
|
// forget about the Carry status flag, only assign the normal return values
|
||||||
|
assignRegisterResults(registersResults)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if(registersResults.all {
|
||||||
|
val tgt = it.second as PtAssignTarget
|
||||||
|
tgt.void || tgt.identifier!=null})
|
||||||
|
{
|
||||||
// all other results are just stored into identifiers directly so first handle those
|
// all other results are just stored into identifiers directly so first handle those
|
||||||
// (simple store instructions that don't modify the carry flag)
|
// (simple store instructions that don't modify the carry flag)
|
||||||
assignRegisterResults(registersResults)
|
assignRegisterResults(registersResults)
|
||||||
@@ -104,16 +116,6 @@ internal class AssignmentAsmGen(private val program: PtProgram,
|
|||||||
assignCarryResult(target, needsToSaveA(registersResults))
|
assignCarryResult(target, needsToSaveA(registersResults))
|
||||||
}
|
}
|
||||||
assignRegisterResults(registersResults)
|
assignRegisterResults(registersResults)
|
||||||
} else if (sub.returns.size>assignmentTargets.size) {
|
|
||||||
// Targets and values don't match. Skip status flag results, assign only the normal value results.
|
|
||||||
val targets = assignmentTargets.iterator()
|
|
||||||
sub.returns.forEach {
|
|
||||||
if(it.register.registerOrPair!=null) {
|
|
||||||
val target = targets.next() as PtAssignTarget
|
|
||||||
assignRegisterResults(listOf(it to target))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
require(!targets.hasNext())
|
|
||||||
} else {
|
} else {
|
||||||
throw AssemblyError("number of values and targets don't match")
|
throw AssemblyError("number of values and targets don't match")
|
||||||
}
|
}
|
||||||
@@ -706,7 +708,7 @@ internal class AssignmentAsmGen(private val program: PtProgram,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
TargetStorageKind.MEMORY -> {
|
TargetStorageKind.MEMORY -> {
|
||||||
val tgt = PtAssignTarget(assign.target.position)
|
val tgt = PtAssignTarget(false, assign.target.position)
|
||||||
val targetmem = assign.target.memory!!
|
val targetmem = assign.target.memory!!
|
||||||
val mem = PtMemoryByte(targetmem.position)
|
val mem = PtMemoryByte(targetmem.position)
|
||||||
mem.add(targetmem.address)
|
mem.add(targetmem.address)
|
||||||
@@ -716,7 +718,7 @@ internal class AssignmentAsmGen(private val program: PtProgram,
|
|||||||
assignTrue.add(PtNumber.fromBoolean(true, assign.position))
|
assignTrue.add(PtNumber.fromBoolean(true, assign.position))
|
||||||
}
|
}
|
||||||
TargetStorageKind.ARRAY -> {
|
TargetStorageKind.ARRAY -> {
|
||||||
val tgt = PtAssignTarget(assign.target.position)
|
val tgt = PtAssignTarget(false, assign.target.position)
|
||||||
val targetarray = assign.target.array!!
|
val targetarray = assign.target.array!!
|
||||||
val array = PtArrayIndexer(assign.target.datatype, targetarray.position)
|
val array = PtArrayIndexer(assign.target.datatype, targetarray.position)
|
||||||
array.add(targetarray.variable)
|
array.add(targetarray.variable)
|
||||||
|
@@ -53,7 +53,7 @@ class TestCodegen: FunSpec({
|
|||||||
sub.add(PtVariable("xx", DataType.WORD, ZeropageWish.DONTCARE, PtNumber(DataType.WORD, 1.0, Position.DUMMY), null, Position.DUMMY))
|
sub.add(PtVariable("xx", DataType.WORD, ZeropageWish.DONTCARE, PtNumber(DataType.WORD, 1.0, Position.DUMMY), null, Position.DUMMY))
|
||||||
|
|
||||||
val assign = PtAugmentedAssign("+=", Position.DUMMY)
|
val assign = PtAugmentedAssign("+=", Position.DUMMY)
|
||||||
val target = PtAssignTarget(Position.DUMMY).also {
|
val target = PtAssignTarget(false, Position.DUMMY).also {
|
||||||
val targetIdx = PtArrayIndexer(DataType.UBYTE, Position.DUMMY).also { idx ->
|
val targetIdx = PtArrayIndexer(DataType.UBYTE, Position.DUMMY).also { idx ->
|
||||||
idx.add(PtIdentifier("main.start.particleX", DataType.ARRAY_UB, Position.DUMMY))
|
idx.add(PtIdentifier("main.start.particleX", DataType.ARRAY_UB, Position.DUMMY))
|
||||||
idx.add(PtNumber(DataType.UBYTE, 2.0, Position.DUMMY))
|
idx.add(PtNumber(DataType.UBYTE, 2.0, Position.DUMMY))
|
||||||
@@ -68,7 +68,7 @@ class TestCodegen: FunSpec({
|
|||||||
sub.add(assign)
|
sub.add(assign)
|
||||||
|
|
||||||
val prefixAssign = PtAugmentedAssign("-", Position.DUMMY)
|
val prefixAssign = PtAugmentedAssign("-", Position.DUMMY)
|
||||||
val prefixTarget = PtAssignTarget(Position.DUMMY).also {
|
val prefixTarget = PtAssignTarget(false, Position.DUMMY).also {
|
||||||
it.add(PtIdentifier("main.start.xx", DataType.WORD, Position.DUMMY))
|
it.add(PtIdentifier("main.start.xx", DataType.WORD, Position.DUMMY))
|
||||||
}
|
}
|
||||||
prefixAssign.add(prefixTarget)
|
prefixAssign.add(prefixTarget)
|
||||||
@@ -76,7 +76,7 @@ class TestCodegen: FunSpec({
|
|||||||
sub.add(prefixAssign)
|
sub.add(prefixAssign)
|
||||||
|
|
||||||
val numberAssign = PtAugmentedAssign("-=", Position.DUMMY)
|
val numberAssign = PtAugmentedAssign("-=", Position.DUMMY)
|
||||||
val numberAssignTarget = PtAssignTarget(Position.DUMMY).also {
|
val numberAssignTarget = PtAssignTarget(false, Position.DUMMY).also {
|
||||||
it.add(PtIdentifier("main.start.xx", DataType.WORD, Position.DUMMY))
|
it.add(PtIdentifier("main.start.xx", DataType.WORD, Position.DUMMY))
|
||||||
}
|
}
|
||||||
numberAssign.add(numberAssignTarget)
|
numberAssign.add(numberAssignTarget)
|
||||||
@@ -84,7 +84,7 @@ class TestCodegen: FunSpec({
|
|||||||
sub.add(numberAssign)
|
sub.add(numberAssign)
|
||||||
|
|
||||||
val cxregAssign = PtAugmentedAssign("+=", Position.DUMMY)
|
val cxregAssign = PtAugmentedAssign("+=", Position.DUMMY)
|
||||||
val cxregAssignTarget = PtAssignTarget(Position.DUMMY).also {
|
val cxregAssignTarget = PtAssignTarget(false, Position.DUMMY).also {
|
||||||
it.add(PtIdentifier("main.start.xx", DataType.WORD, Position.DUMMY))
|
it.add(PtIdentifier("main.start.xx", DataType.WORD, Position.DUMMY))
|
||||||
}
|
}
|
||||||
cxregAssign.add(cxregAssignTarget)
|
cxregAssign.add(cxregAssignTarget)
|
||||||
|
@@ -25,25 +25,15 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express
|
|||||||
val assignmentTargets = assignment.children.dropLast(1)
|
val assignmentTargets = assignment.children.dropLast(1)
|
||||||
addToResult(result, funcCall, funcCall.resultReg, funcCall.resultFpReg)
|
addToResult(result, funcCall, funcCall.resultReg, funcCall.resultFpReg)
|
||||||
if(sub.returns.size==assignmentTargets.size) {
|
if(sub.returns.size==assignmentTargets.size) {
|
||||||
// Targets and values match. Assign all the things.
|
// Targets and values match. Assign all the things. Skip 'void' targets.
|
||||||
sub.returns.zip(assignmentTargets).zip(funcCall.multipleResultRegs).forEach {
|
sub.returns.zip(assignmentTargets).zip(funcCall.multipleResultRegs).forEach {
|
||||||
val regNumber = it.second
|
|
||||||
val returns = it.first.first
|
|
||||||
val target = it.first.second as PtAssignTarget
|
val target = it.first.second as PtAssignTarget
|
||||||
result += assignCpuRegister(returns, regNumber, target)
|
if(!target.void) {
|
||||||
}
|
|
||||||
} else if (sub.returns.size>assignmentTargets.size) {
|
|
||||||
// Targets and values don't match. Skip status flag results, assign only the normal value results.
|
|
||||||
val targets = assignmentTargets.iterator()
|
|
||||||
sub.returns.zip(funcCall.multipleResultRegs).forEach {
|
|
||||||
val returns = it.first
|
|
||||||
if(returns.register.registerOrPair!=null) {
|
|
||||||
val target = targets.next() as PtAssignTarget
|
|
||||||
val regNumber = it.second
|
val regNumber = it.second
|
||||||
|
val returns = it.first.first
|
||||||
result += assignCpuRegister(returns, regNumber, target)
|
result += assignCpuRegister(returns, regNumber, target)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
require(!targets.hasNext())
|
|
||||||
} else {
|
} else {
|
||||||
throw AssemblyError("number of values and targets don't match")
|
throw AssemblyError("number of values and targets don't match")
|
||||||
}
|
}
|
||||||
|
@@ -854,7 +854,7 @@ internal class BuiltinFuncGen(private val codeGen: IRCodeGen, private val exprGe
|
|||||||
|
|
||||||
private fun assignRegisterTo(target: PtExpression, register: Int): IRCodeChunks {
|
private fun assignRegisterTo(target: PtExpression, register: Int): IRCodeChunks {
|
||||||
val assignment = PtAssignment(target.position)
|
val assignment = PtAssignment(target.position)
|
||||||
val assignTarget = PtAssignTarget(target.position)
|
val assignTarget = PtAssignTarget(false, target.position)
|
||||||
assignTarget.children.add(target)
|
assignTarget.children.add(target)
|
||||||
assignment.children.add(assignTarget)
|
assignment.children.add(assignTarget)
|
||||||
assignment.children.add(PtIrRegister(register, target.type, target.position))
|
assignment.children.add(PtIrRegister(register, target.type, target.position))
|
||||||
|
@@ -50,7 +50,7 @@ class TestVmCodeGen: FunSpec({
|
|||||||
sub.add(PtVariable("xx", DataType.WORD, ZeropageWish.DONTCARE, PtNumber(DataType.WORD, 1.0, Position.DUMMY), null, Position.DUMMY))
|
sub.add(PtVariable("xx", DataType.WORD, ZeropageWish.DONTCARE, PtNumber(DataType.WORD, 1.0, Position.DUMMY), null, Position.DUMMY))
|
||||||
|
|
||||||
val assign = PtAugmentedAssign("+=", Position.DUMMY)
|
val assign = PtAugmentedAssign("+=", Position.DUMMY)
|
||||||
val target = PtAssignTarget(Position.DUMMY).also {
|
val target = PtAssignTarget(false, Position.DUMMY).also {
|
||||||
val targetIdx = PtArrayIndexer(DataType.UBYTE, Position.DUMMY).also { idx ->
|
val targetIdx = PtArrayIndexer(DataType.UBYTE, Position.DUMMY).also { idx ->
|
||||||
idx.add(PtIdentifier("main.start.particleX", DataType.ARRAY_UB, Position.DUMMY))
|
idx.add(PtIdentifier("main.start.particleX", DataType.ARRAY_UB, Position.DUMMY))
|
||||||
idx.add(PtNumber(DataType.UBYTE, 2.0, Position.DUMMY))
|
idx.add(PtNumber(DataType.UBYTE, 2.0, Position.DUMMY))
|
||||||
@@ -65,7 +65,7 @@ class TestVmCodeGen: FunSpec({
|
|||||||
sub.add(assign)
|
sub.add(assign)
|
||||||
|
|
||||||
val prefixAssign = PtAugmentedAssign("-", Position.DUMMY)
|
val prefixAssign = PtAugmentedAssign("-", Position.DUMMY)
|
||||||
val prefixTarget = PtAssignTarget(Position.DUMMY).also {
|
val prefixTarget = PtAssignTarget(false, Position.DUMMY).also {
|
||||||
it.add(PtIdentifier("main.start.xx", DataType.WORD, Position.DUMMY))
|
it.add(PtIdentifier("main.start.xx", DataType.WORD, Position.DUMMY))
|
||||||
}
|
}
|
||||||
prefixAssign.add(prefixTarget)
|
prefixAssign.add(prefixTarget)
|
||||||
@@ -73,7 +73,7 @@ class TestVmCodeGen: FunSpec({
|
|||||||
sub.add(prefixAssign)
|
sub.add(prefixAssign)
|
||||||
|
|
||||||
val numberAssign = PtAugmentedAssign("+=", Position.DUMMY)
|
val numberAssign = PtAugmentedAssign("+=", Position.DUMMY)
|
||||||
val numberAssignTarget = PtAssignTarget(Position.DUMMY).also {
|
val numberAssignTarget = PtAssignTarget(false, Position.DUMMY).also {
|
||||||
it.add(PtIdentifier("main.start.xx", DataType.WORD, Position.DUMMY))
|
it.add(PtIdentifier("main.start.xx", DataType.WORD, Position.DUMMY))
|
||||||
}
|
}
|
||||||
numberAssign.add(numberAssignTarget)
|
numberAssign.add(numberAssignTarget)
|
||||||
@@ -81,7 +81,7 @@ class TestVmCodeGen: FunSpec({
|
|||||||
sub.add(numberAssign)
|
sub.add(numberAssign)
|
||||||
|
|
||||||
val cxregAssign = PtAugmentedAssign("+=", Position.DUMMY)
|
val cxregAssign = PtAugmentedAssign("+=", Position.DUMMY)
|
||||||
val cxregAssignTarget = PtAssignTarget(Position.DUMMY).also {
|
val cxregAssignTarget = PtAssignTarget(false, Position.DUMMY).also {
|
||||||
it.add(PtIdentifier("main.start.xx", DataType.WORD, Position.DUMMY))
|
it.add(PtIdentifier("main.start.xx", DataType.WORD, Position.DUMMY))
|
||||||
}
|
}
|
||||||
cxregAssign.add(cxregAssignTarget)
|
cxregAssign.add(cxregAssignTarget)
|
||||||
|
@@ -309,7 +309,7 @@ internal class ConstantIdentifierReplacer(
|
|||||||
val add = BinaryExpression(NumericLiteral(cval.type, cval.number, identifier.position), "+", arrayIdx.indexer.indexExpr, identifier.position)
|
val add = BinaryExpression(NumericLiteral(cval.type, cval.number, identifier.position), "+", arrayIdx.indexer.indexExpr, identifier.position)
|
||||||
return if(arrayIdx.parent is AssignTarget) {
|
return if(arrayIdx.parent is AssignTarget) {
|
||||||
val memwrite = DirectMemoryWrite(add, identifier.position)
|
val memwrite = DirectMemoryWrite(add, identifier.position)
|
||||||
val assignTarget = AssignTarget(null, null, memwrite, null, identifier.position)
|
val assignTarget = AssignTarget(null, null, memwrite, null, false, identifier.position)
|
||||||
listOf(IAstModification.ReplaceNode(arrayIdx.parent, assignTarget, arrayIdx.parent.parent))
|
listOf(IAstModification.ReplaceNode(arrayIdx.parent, assignTarget, arrayIdx.parent.parent))
|
||||||
} else {
|
} else {
|
||||||
val memread = DirectMemoryRead(add, identifier.position)
|
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
|
// for loop over a (constant) range of just a single value-- optimize the loop away
|
||||||
// loopvar/reg = range value , follow by block
|
// loopvar/reg = range value , follow by block
|
||||||
val scope = AnonymousScope(mutableListOf(), forLoop.position)
|
val scope = AnonymousScope(mutableListOf(), forLoop.position)
|
||||||
scope.statements.add(Assignment(AssignTarget(forLoop.loopVar, null, null, null, forLoop.position), range.from, AssignmentOrigin.OPTIMIZER, forLoop.position))
|
scope.statements.add(Assignment(AssignTarget(forLoop.loopVar, null, null, null, false, forLoop.position), range.from, AssignmentOrigin.OPTIMIZER, forLoop.position))
|
||||||
scope.statements.addAll(forLoop.body.statements)
|
scope.statements.addAll(forLoop.body.statements)
|
||||||
return listOf(IAstModification.ReplaceNode(forLoop, scope, parent))
|
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 character = options.compTarget.encodeString(sv.value, sv.encoding)[0]
|
||||||
val byte = NumericLiteral(DataType.UBYTE, character.toDouble(), iterable.position)
|
val byte = NumericLiteral(DataType.UBYTE, character.toDouble(), iterable.position)
|
||||||
val scope = AnonymousScope(mutableListOf(), forLoop.position)
|
val scope = AnonymousScope(mutableListOf(), forLoop.position)
|
||||||
scope.statements.add(Assignment(AssignTarget(forLoop.loopVar, null, null, null, forLoop.position), byte, AssignmentOrigin.OPTIMIZER, forLoop.position))
|
scope.statements.add(Assignment(AssignTarget(forLoop.loopVar, null, null, null, false, forLoop.position), byte, AssignmentOrigin.OPTIMIZER, forLoop.position))
|
||||||
scope.statements.addAll(forLoop.body.statements)
|
scope.statements.addAll(forLoop.body.statements)
|
||||||
return listOf(IAstModification.ReplaceNode(forLoop, scope, parent))
|
return listOf(IAstModification.ReplaceNode(forLoop, scope, parent))
|
||||||
}
|
}
|
||||||
@@ -190,7 +190,7 @@ class StatementOptimizer(private val program: Program,
|
|||||||
if(av!=null) {
|
if(av!=null) {
|
||||||
val scope = AnonymousScope(mutableListOf(), forLoop.position)
|
val scope = AnonymousScope(mutableListOf(), forLoop.position)
|
||||||
scope.statements.add(Assignment(
|
scope.statements.add(Assignment(
|
||||||
AssignTarget(forLoop.loopVar, null, null, null, forLoop.position), NumericLiteral.optimalInteger(av.toInt(), iterable.position),
|
AssignTarget(forLoop.loopVar, null, null, null, false, forLoop.position), NumericLiteral.optimalInteger(av.toInt(), iterable.position),
|
||||||
AssignmentOrigin.OPTIMIZER, forLoop.position))
|
AssignmentOrigin.OPTIMIZER, forLoop.position))
|
||||||
scope.statements.addAll(forLoop.body.statements)
|
scope.statements.addAll(forLoop.body.statements)
|
||||||
return listOf(IAstModification.ReplaceNode(forLoop, scope, parent))
|
return listOf(IAstModification.ReplaceNode(forLoop, scope, parent))
|
||||||
@@ -206,7 +206,7 @@ class StatementOptimizer(private val program: Program,
|
|||||||
val pos = forLoop.position
|
val pos = forLoop.position
|
||||||
val loopVar = forLoop.loopVar
|
val loopVar = forLoop.loopVar
|
||||||
val addSubOne = BinaryExpression(loopVar.copy(), if(inc) "+" else "-", NumericLiteral.optimalInteger(1, pos), pos, false)
|
val addSubOne = BinaryExpression(loopVar.copy(), if(inc) "+" else "-", NumericLiteral.optimalInteger(1, pos), pos, false)
|
||||||
return Assignment(AssignTarget(loopVar.copy(), null, null, null, pos), addSubOne, AssignmentOrigin.USERCODE, pos)
|
return Assignment(AssignTarget(loopVar.copy(), null, null, null, false, pos), addSubOne, AssignmentOrigin.USERCODE, pos)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (range != null && range.to.constValue(program)?.number == 0.0 && range.step.constValue(program)?.number==-1.0) {
|
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)
|
val decOne = incOrDec(false)
|
||||||
forLoop.body.statements.add(decOne)
|
forLoop.body.statements.add(decOne)
|
||||||
val replacement = AnonymousScope(mutableListOf(
|
val replacement = AnonymousScope(mutableListOf(
|
||||||
Assignment(AssignTarget(forLoop.loopVar.copy(), null, null, null, pos),
|
Assignment(AssignTarget(forLoop.loopVar.copy(), null, null, null, false, pos),
|
||||||
fromExpr, AssignmentOrigin.OPTIMIZER, pos),
|
fromExpr, AssignmentOrigin.OPTIMIZER, pos),
|
||||||
UntilLoop(forLoop.body, condition, pos)
|
UntilLoop(forLoop.body, condition, pos)
|
||||||
), pos)
|
), pos)
|
||||||
@@ -454,12 +454,6 @@ class StatementOptimizer(private val program: Program,
|
|||||||
|
|
||||||
override fun after(whenStmt: When, parent: Node): Iterable<IAstModification> {
|
override fun after(whenStmt: When, parent: Node): Iterable<IAstModification> {
|
||||||
|
|
||||||
fun replaceWithIf(condition: Expression, trueBlock: AnonymousScope, elseBlock: AnonymousScope?): List<IAstModification> {
|
|
||||||
val ifStmt = IfElse(condition, trueBlock, elseBlock ?: AnonymousScope(mutableListOf(), whenStmt.position), whenStmt.position)
|
|
||||||
errors.info("for boolean condition a normal if statement is preferred", whenStmt.position)
|
|
||||||
return listOf(IAstModification.ReplaceNode(whenStmt, ifStmt, parent))
|
|
||||||
}
|
|
||||||
|
|
||||||
val constantValue = whenStmt.condition.constValue(program)?.number
|
val constantValue = whenStmt.condition.constValue(program)?.number
|
||||||
if(constantValue!=null) {
|
if(constantValue!=null) {
|
||||||
// when condition is a constant
|
// when condition is a constant
|
||||||
|
@@ -53,7 +53,7 @@ internal class AstChecker(private val program: Program,
|
|||||||
override fun visit(module: Module) {
|
override fun visit(module: Module) {
|
||||||
super.visit(module)
|
super.visit(module)
|
||||||
if(module.name.startsWith('_'))
|
if(module.name.startsWith('_'))
|
||||||
errors.err("module names cannot start with an underscore", module.position)
|
errors.err("identifiers cannot start with an underscore", module.position)
|
||||||
val directives = module.statements.filterIsInstance<Directive>().groupBy { it.directive }
|
val directives = module.statements.filterIsInstance<Directive>().groupBy { it.directive }
|
||||||
directives.filter { it.value.size > 1 }.forEach{ entry ->
|
directives.filter { it.value.size > 1 }.forEach{ entry ->
|
||||||
when(entry.key) {
|
when(entry.key) {
|
||||||
@@ -67,6 +67,14 @@ internal class AstChecker(private val program: Program,
|
|||||||
if(identifier.nameInSource.any { it.startsWith('_') }) {
|
if(identifier.nameInSource.any { it.startsWith('_') }) {
|
||||||
errors.err("identifiers cannot start with an underscore", identifier.position)
|
errors.err("identifiers cannot start with an underscore", identifier.position)
|
||||||
}
|
}
|
||||||
|
if(identifier.nameInSource.any { it=="void" }) {
|
||||||
|
// 'void' as "identifier" is only allowed as part of a multi-assignment expression
|
||||||
|
if (!(identifier.nameInSource == listOf("void") && (identifier.parent as? AssignTarget)?.multi?.isNotEmpty() == true
|
||||||
|
|| identifier.parent is AssignTarget && (identifier.parent.parent as? AssignTarget)?.multi?.isNotEmpty() == true)
|
||||||
|
) {
|
||||||
|
errors.err("identifiers cannot contain the 'void' keyword", identifier.position)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
checkLongType(identifier)
|
checkLongType(identifier)
|
||||||
val stmt = identifier.targetStatement(program)
|
val stmt = identifier.targetStatement(program)
|
||||||
@@ -273,7 +281,7 @@ internal class AstChecker(private val program: Program,
|
|||||||
|
|
||||||
override fun visit(block: Block) {
|
override fun visit(block: Block) {
|
||||||
if(block.name.startsWith('_'))
|
if(block.name.startsWith('_'))
|
||||||
errors.err("block names cannot start with an underscore", block.position)
|
errors.err("identifiers cannot start with an underscore", block.position)
|
||||||
|
|
||||||
val addr = block.address
|
val addr = block.address
|
||||||
if(addr!=null && addr>65535u) {
|
if(addr!=null && addr>65535u) {
|
||||||
@@ -305,7 +313,7 @@ internal class AstChecker(private val program: Program,
|
|||||||
|
|
||||||
override fun visit(label: Label) {
|
override fun visit(label: Label) {
|
||||||
if(label.name.startsWith('_'))
|
if(label.name.startsWith('_'))
|
||||||
errors.err("labels cannot start with an underscore", label.position)
|
errors.err("identifiers cannot start with an underscore", label.position)
|
||||||
|
|
||||||
// scope check
|
// scope check
|
||||||
if(label.parent !is Block && label.parent !is Subroutine && label.parent !is AnonymousScope) {
|
if(label.parent !is Block && label.parent !is Subroutine && label.parent !is AnonymousScope) {
|
||||||
@@ -349,7 +357,7 @@ internal class AstChecker(private val program: Program,
|
|||||||
fun err(msg: String) = errors.err(msg, subroutine.position)
|
fun err(msg: String) = errors.err(msg, subroutine.position)
|
||||||
|
|
||||||
if(subroutine.name.startsWith('_'))
|
if(subroutine.name.startsWith('_'))
|
||||||
errors.err("subroutine names cannot start with an underscore", subroutine.position)
|
errors.err("identifiers cannot start with an underscore", subroutine.position)
|
||||||
|
|
||||||
if(subroutine.name in BuiltinFunctions)
|
if(subroutine.name in BuiltinFunctions)
|
||||||
err("cannot redefine a built-in function")
|
err("cannot redefine a built-in function")
|
||||||
@@ -490,7 +498,7 @@ internal class AstChecker(private val program: Program,
|
|||||||
// Instead, their reference (address) should be passed (as an UWORD).
|
// Instead, their reference (address) should be passed (as an UWORD).
|
||||||
for(p in subroutine.parameters) {
|
for(p in subroutine.parameters) {
|
||||||
if(p.name.startsWith('_'))
|
if(p.name.startsWith('_'))
|
||||||
errors.err("parameter names cannot start with an underscore", p.position)
|
errors.err("identifiers cannot start with an underscore", p.position)
|
||||||
|
|
||||||
if(p.type in PassByReferenceDatatypes && p.type !in listOf(DataType.STR, DataType.ARRAY_UB)) {
|
if(p.type in PassByReferenceDatatypes && p.type !in listOf(DataType.STR, DataType.ARRAY_UB)) {
|
||||||
errors.err("this pass-by-reference type can't be used as a parameter type. Instead, use an uword to receive the address, or access the variable from the outer scope directly.", p.position)
|
errors.err("this pass-by-reference type can't be used as a parameter type. Instead, use an uword to receive the address, or access the variable from the outer scope directly.", p.position)
|
||||||
@@ -591,38 +599,15 @@ internal class AstChecker(private val program: Program,
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
val targets = assignment.target.multi!!
|
val targets = assignment.target.multi!!
|
||||||
if(fcallTarget.returntypes.size<targets.size) {
|
if(fcallTarget.returntypes.size!=targets.size) {
|
||||||
errors.err("too many assignment targets, ${targets.size} targets for ${fcallTarget.returntypes.size} return values", fcall.position)
|
errors.err("number of assignment targets doesn't match number of return values", fcall.position)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if(fcallTarget.returntypes.size>targets.size) {
|
fcallTarget.returntypes.zip(targets).withIndex().forEach { (index, p) ->
|
||||||
// You can have LESS assign targets than the number of result values,
|
val (returnType, target) = p
|
||||||
// as long as the result values contain booleans that are returned in cpu status flags (like Carry).
|
val targetDt = target.inferType(program).getOr(DataType.UNDEFINED)
|
||||||
// These may be ignored in the assignment - only "true" values NEED to have a target.
|
if (!target.void && !(returnType isAssignableTo targetDt))
|
||||||
val numberOfNormalValues = fcallTarget.asmReturnvaluesRegisters.count { it.registerOrPair!=null }
|
errors.err("can't assign returnvalue #${index + 1} to corresponding target; $returnType vs $targetDt", target.position)
|
||||||
if(numberOfNormalValues != targets.size) {
|
|
||||||
errors.err("multiple return values and too few assignment targets, need at least $numberOfNormalValues", fcall.position)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
// check the types of the 'normal' values that are being assigned
|
|
||||||
val returnTypesAndRegisters = fcallTarget.returntypes.zip(fcallTarget.asmReturnvaluesRegisters)
|
|
||||||
returnTypesAndRegisters.zip(targets).withIndex().forEach { (index, p) ->
|
|
||||||
val (returnType, register) = p.first
|
|
||||||
if(register.registerOrPair!=null) {
|
|
||||||
val target = p.second
|
|
||||||
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 {
|
|
||||||
// check all the assigment target types
|
|
||||||
fcallTarget.returntypes.zip(targets).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)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -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...
|
// we need to handle multi-decl here too, the desugarer maybe has not processed it here yet...
|
||||||
if(decl.value!=null) {
|
if(decl.value!=null) {
|
||||||
decl.names.forEach { name ->
|
decl.names.forEach { name ->
|
||||||
val target = AssignTarget(IdentifierReference(listOf(name), decl.position), null, null, null, decl.position)
|
val target = AssignTarget(IdentifierReference(listOf(name), decl.position), null, null, null, false, decl.position)
|
||||||
val assign = Assignment(target.copy(), decl.value!!.copy(), AssignmentOrigin.VARINIT, decl.position)
|
val assign = Assignment(target.copy(), decl.value!!.copy(), AssignmentOrigin.VARINIT, decl.position)
|
||||||
replacements.add(IAstModification.InsertAfter(decl, assign, scope))
|
replacements.add(IAstModification.InsertAfter(decl, assign, scope))
|
||||||
}
|
}
|
||||||
@@ -137,7 +137,7 @@ class AstPreprocessor(val program: Program,
|
|||||||
} else {
|
} else {
|
||||||
// handle declaration of a single variable
|
// handle declaration of a single variable
|
||||||
if(decl.value!=null && (decl.datatype in NumericDatatypes || decl.datatype==DataType.BOOL)) {
|
if(decl.value!=null && (decl.datatype in NumericDatatypes || decl.datatype==DataType.BOOL)) {
|
||||||
val target = AssignTarget(IdentifierReference(listOf(decl.name), decl.position), null, null, null, decl.position)
|
val target = AssignTarget(IdentifierReference(listOf(decl.name), decl.position), null, null, null, false, decl.position)
|
||||||
val assign = Assignment(target, decl.value!!, AssignmentOrigin.VARINIT, decl.position)
|
val assign = Assignment(target, decl.value!!, AssignmentOrigin.VARINIT, decl.position)
|
||||||
replacements.add(IAstModification.ReplaceNode(decl, assign, scope))
|
replacements.add(IAstModification.ReplaceNode(decl, assign, scope))
|
||||||
decl.value = null
|
decl.value = null
|
||||||
|
@@ -183,7 +183,7 @@ _after:
|
|||||||
}
|
}
|
||||||
if(functionCall.target.nameInSource==listOf("poke")) {
|
if(functionCall.target.nameInSource==listOf("poke")) {
|
||||||
// poke(a, v) is synonymous with @(a) = v
|
// poke(a, v) is synonymous with @(a) = v
|
||||||
val tgt = AssignTarget(null, null, DirectMemoryWrite(functionCall.args[0], position), null, position)
|
val tgt = AssignTarget(null, null, DirectMemoryWrite(functionCall.args[0], position), null, false, position)
|
||||||
val assign = Assignment(tgt, functionCall.args[1], AssignmentOrigin.OPTIMIZER, position)
|
val assign = Assignment(tgt, functionCall.args[1], AssignmentOrigin.OPTIMIZER, position)
|
||||||
return listOf(IAstModification.ReplaceNode(functionCall as Node, assign, parent))
|
return listOf(IAstModification.ReplaceNode(functionCall as Node, assign, parent))
|
||||||
}
|
}
|
||||||
@@ -222,7 +222,7 @@ _after:
|
|||||||
return if(parent is AssignTarget) {
|
return if(parent is AssignTarget) {
|
||||||
// assignment to array
|
// assignment to array
|
||||||
val memwrite = DirectMemoryWrite(address, arrayIndexedExpression.position)
|
val memwrite = DirectMemoryWrite(address, arrayIndexedExpression.position)
|
||||||
val newtarget = AssignTarget(null, null, memwrite, null, arrayIndexedExpression.position)
|
val newtarget = AssignTarget(null, null, memwrite, null, false, arrayIndexedExpression.position)
|
||||||
listOf(IAstModification.ReplaceNode(parent, newtarget, parent.parent))
|
listOf(IAstModification.ReplaceNode(parent, newtarget, parent.parent))
|
||||||
} else {
|
} else {
|
||||||
// read from array
|
// read from array
|
||||||
|
@@ -148,14 +148,14 @@ class IntermediateAstMaker(private val program: Program, private val errors: IEr
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun transform(srcTarget: AssignTarget): PtAssignTarget {
|
private fun transform(srcTarget: AssignTarget): PtAssignTarget {
|
||||||
val target = PtAssignTarget(srcTarget.position)
|
val target = PtAssignTarget(srcTarget.void, srcTarget.position)
|
||||||
if(srcTarget.identifier!=null)
|
if(srcTarget.identifier!=null)
|
||||||
target.add(transform(srcTarget.identifier!!))
|
target.add(transform(srcTarget.identifier!!))
|
||||||
else if(srcTarget.arrayindexed!=null)
|
else if(srcTarget.arrayindexed!=null)
|
||||||
target.add(transform(srcTarget.arrayindexed!!))
|
target.add(transform(srcTarget.arrayindexed!!))
|
||||||
else if(srcTarget.memoryAddress!=null)
|
else if(srcTarget.memoryAddress!=null)
|
||||||
target.add(transform(srcTarget.memoryAddress!!))
|
target.add(transform(srcTarget.memoryAddress!!))
|
||||||
else
|
else if(!srcTarget.void)
|
||||||
throw FatalAstException("invalid AssignTarget")
|
throw FatalAstException("invalid AssignTarget")
|
||||||
return target
|
return target
|
||||||
}
|
}
|
||||||
|
@@ -60,7 +60,7 @@ internal class StatementReorderer(
|
|||||||
// Add assignment to initialize with zero
|
// 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.
|
// 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 identifier = IdentifierReference(listOf(decl.name), decl.position)
|
||||||
val assignzero = Assignment(AssignTarget(identifier, null, null, null, decl.position),
|
val assignzero = Assignment(AssignTarget(identifier, null, null, null, false, decl.position),
|
||||||
decl.zeroElementValue(), AssignmentOrigin.VARINIT, decl.position)
|
decl.zeroElementValue(), AssignmentOrigin.VARINIT, decl.position)
|
||||||
return listOf(IAstModification.InsertAfter(
|
return listOf(IAstModification.InsertAfter(
|
||||||
decl, assignzero, parent as IStatementContainer
|
decl, assignzero, parent as IStatementContainer
|
||||||
@@ -73,7 +73,7 @@ internal class StatementReorderer(
|
|||||||
// So basically consider 'ubyte xx=99' as a short form for 'ubyte xx; xx=99'
|
// So basically consider 'ubyte xx=99' as a short form for 'ubyte xx; xx=99'
|
||||||
val pos = decl.value!!.position
|
val pos = decl.value!!.position
|
||||||
val identifier = IdentifierReference(listOf(decl.name), pos)
|
val identifier = IdentifierReference(listOf(decl.name), pos)
|
||||||
val assign = Assignment(AssignTarget(identifier, null, null, null, pos),
|
val assign = Assignment(AssignTarget(identifier, null, null, null, false, pos),
|
||||||
decl.value!!, AssignmentOrigin.VARINIT, pos)
|
decl.value!!, AssignmentOrigin.VARINIT, pos)
|
||||||
decl.value = null
|
decl.value = null
|
||||||
return listOf(IAstModification.InsertAfter(
|
return listOf(IAstModification.InsertAfter(
|
||||||
@@ -92,7 +92,7 @@ internal class StatementReorderer(
|
|||||||
if(target!=null && target.isArray) {
|
if(target!=null && target.isArray) {
|
||||||
val pos = decl.value!!.position
|
val pos = decl.value!!.position
|
||||||
val identifier = IdentifierReference(listOf(decl.name), pos)
|
val identifier = IdentifierReference(listOf(decl.name), pos)
|
||||||
val assign = Assignment(AssignTarget(identifier, null, null, null, pos),
|
val assign = Assignment(AssignTarget(identifier, null, null, null, false, pos),
|
||||||
decl.value!!, AssignmentOrigin.VARINIT, pos)
|
decl.value!!, AssignmentOrigin.VARINIT, pos)
|
||||||
decl.value = null
|
decl.value = null
|
||||||
return listOf(IAstModification.InsertAfter(
|
return listOf(IAstModification.InsertAfter(
|
||||||
|
@@ -36,49 +36,49 @@ class TestMemory: FunSpec({
|
|||||||
test("assignment target not in mapped IO space C64") {
|
test("assignment target not in mapped IO space C64") {
|
||||||
|
|
||||||
var memexpr = NumericLiteral.optimalInteger(0x0002, Position.DUMMY)
|
var memexpr = NumericLiteral.optimalInteger(0x0002, Position.DUMMY)
|
||||||
var target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), null, Position.DUMMY)
|
var target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), null, false, Position.DUMMY)
|
||||||
var assign = Assignment(target, NumericLiteral.optimalInteger(0, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
|
var assign = Assignment(target, NumericLiteral.optimalInteger(0, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
|
||||||
wrapWithProgram(listOf(assign))
|
wrapWithProgram(listOf(assign))
|
||||||
target.isIOAddress(c64target.machine) shouldBe false
|
target.isIOAddress(c64target.machine) shouldBe false
|
||||||
|
|
||||||
memexpr = NumericLiteral.optimalInteger(0x1000, Position.DUMMY)
|
memexpr = NumericLiteral.optimalInteger(0x1000, Position.DUMMY)
|
||||||
target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), null, Position.DUMMY)
|
target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), null, false, Position.DUMMY)
|
||||||
assign = Assignment(target, NumericLiteral.optimalInteger(0, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
|
assign = Assignment(target, NumericLiteral.optimalInteger(0, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
|
||||||
wrapWithProgram(listOf(assign))
|
wrapWithProgram(listOf(assign))
|
||||||
target.isIOAddress(c64target.machine) shouldBe false
|
target.isIOAddress(c64target.machine) shouldBe false
|
||||||
|
|
||||||
memexpr = NumericLiteral.optimalInteger(0x9fff, Position.DUMMY)
|
memexpr = NumericLiteral.optimalInteger(0x9fff, Position.DUMMY)
|
||||||
target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), null, Position.DUMMY)
|
target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), null, false, Position.DUMMY)
|
||||||
assign = Assignment(target, NumericLiteral.optimalInteger(0, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
|
assign = Assignment(target, NumericLiteral.optimalInteger(0, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
|
||||||
wrapWithProgram(listOf(assign))
|
wrapWithProgram(listOf(assign))
|
||||||
target.isIOAddress(c64target.machine) shouldBe false
|
target.isIOAddress(c64target.machine) shouldBe false
|
||||||
|
|
||||||
memexpr = NumericLiteral.optimalInteger(0xa000, Position.DUMMY)
|
memexpr = NumericLiteral.optimalInteger(0xa000, Position.DUMMY)
|
||||||
target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), null, Position.DUMMY)
|
target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), null, false, Position.DUMMY)
|
||||||
assign = Assignment(target, NumericLiteral.optimalInteger(0, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
|
assign = Assignment(target, NumericLiteral.optimalInteger(0, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
|
||||||
wrapWithProgram(listOf(assign))
|
wrapWithProgram(listOf(assign))
|
||||||
target.isIOAddress(c64target.machine) shouldBe false
|
target.isIOAddress(c64target.machine) shouldBe false
|
||||||
|
|
||||||
memexpr = NumericLiteral.optimalInteger(0xc000, Position.DUMMY)
|
memexpr = NumericLiteral.optimalInteger(0xc000, Position.DUMMY)
|
||||||
target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), null, Position.DUMMY)
|
target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), null, false, Position.DUMMY)
|
||||||
assign = Assignment(target, NumericLiteral.optimalInteger(0, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
|
assign = Assignment(target, NumericLiteral.optimalInteger(0, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
|
||||||
wrapWithProgram(listOf(assign))
|
wrapWithProgram(listOf(assign))
|
||||||
target.isIOAddress(c64target.machine) shouldBe false
|
target.isIOAddress(c64target.machine) shouldBe false
|
||||||
|
|
||||||
memexpr = NumericLiteral.optimalInteger(0xcfff, Position.DUMMY)
|
memexpr = NumericLiteral.optimalInteger(0xcfff, Position.DUMMY)
|
||||||
target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), null, Position.DUMMY)
|
target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), null, false, Position.DUMMY)
|
||||||
assign = Assignment(target, NumericLiteral.optimalInteger(0, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
|
assign = Assignment(target, NumericLiteral.optimalInteger(0, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
|
||||||
wrapWithProgram(listOf(assign))
|
wrapWithProgram(listOf(assign))
|
||||||
target.isIOAddress(c64target.machine) shouldBe false
|
target.isIOAddress(c64target.machine) shouldBe false
|
||||||
|
|
||||||
memexpr = NumericLiteral.optimalInteger(0xeeee, Position.DUMMY)
|
memexpr = NumericLiteral.optimalInteger(0xeeee, Position.DUMMY)
|
||||||
target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), null, Position.DUMMY)
|
target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), null, false, Position.DUMMY)
|
||||||
assign = Assignment(target, NumericLiteral.optimalInteger(0, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
|
assign = Assignment(target, NumericLiteral.optimalInteger(0, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
|
||||||
wrapWithProgram(listOf(assign))
|
wrapWithProgram(listOf(assign))
|
||||||
target.isIOAddress(c64target.machine) shouldBe false
|
target.isIOAddress(c64target.machine) shouldBe false
|
||||||
|
|
||||||
memexpr = NumericLiteral.optimalInteger(0xffff, Position.DUMMY)
|
memexpr = NumericLiteral.optimalInteger(0xffff, Position.DUMMY)
|
||||||
target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), null, Position.DUMMY)
|
target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), null, false, Position.DUMMY)
|
||||||
assign = Assignment(target, NumericLiteral.optimalInteger(0, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
|
assign = Assignment(target, NumericLiteral.optimalInteger(0, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
|
||||||
wrapWithProgram(listOf(assign))
|
wrapWithProgram(listOf(assign))
|
||||||
target.isIOAddress(c64target.machine) shouldBe false
|
target.isIOAddress(c64target.machine) shouldBe false
|
||||||
@@ -87,25 +87,25 @@ class TestMemory: FunSpec({
|
|||||||
test("assign target in mapped IO space C64") {
|
test("assign target in mapped IO space C64") {
|
||||||
|
|
||||||
var memexpr = NumericLiteral.optimalInteger(0x0000, Position.DUMMY)
|
var memexpr = NumericLiteral.optimalInteger(0x0000, Position.DUMMY)
|
||||||
var target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), null, Position.DUMMY)
|
var target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), null, false, Position.DUMMY)
|
||||||
var assign = Assignment(target, NumericLiteral.optimalInteger(0, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
|
var assign = Assignment(target, NumericLiteral.optimalInteger(0, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
|
||||||
wrapWithProgram(listOf(assign))
|
wrapWithProgram(listOf(assign))
|
||||||
target.isIOAddress(c64target.machine) shouldBe true
|
target.isIOAddress(c64target.machine) shouldBe true
|
||||||
|
|
||||||
memexpr = NumericLiteral.optimalInteger(0x0001, Position.DUMMY)
|
memexpr = NumericLiteral.optimalInteger(0x0001, Position.DUMMY)
|
||||||
target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), null, Position.DUMMY)
|
target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), null, false, Position.DUMMY)
|
||||||
assign = Assignment(target, NumericLiteral.optimalInteger(0, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
|
assign = Assignment(target, NumericLiteral.optimalInteger(0, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
|
||||||
wrapWithProgram(listOf(assign))
|
wrapWithProgram(listOf(assign))
|
||||||
target.isIOAddress(c64target.machine) shouldBe true
|
target.isIOAddress(c64target.machine) shouldBe true
|
||||||
|
|
||||||
memexpr = NumericLiteral.optimalInteger(0xd000, Position.DUMMY)
|
memexpr = NumericLiteral.optimalInteger(0xd000, Position.DUMMY)
|
||||||
target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), null, Position.DUMMY)
|
target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), null, false, Position.DUMMY)
|
||||||
assign = Assignment(target, NumericLiteral.optimalInteger(0, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
|
assign = Assignment(target, NumericLiteral.optimalInteger(0, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
|
||||||
wrapWithProgram(listOf(assign))
|
wrapWithProgram(listOf(assign))
|
||||||
target.isIOAddress(c64target.machine) shouldBe true
|
target.isIOAddress(c64target.machine) shouldBe true
|
||||||
|
|
||||||
memexpr = NumericLiteral.optimalInteger(0xdfff, Position.DUMMY)
|
memexpr = NumericLiteral.optimalInteger(0xdfff, Position.DUMMY)
|
||||||
target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), null, Position.DUMMY)
|
target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), null, false, Position.DUMMY)
|
||||||
assign = Assignment(target, NumericLiteral.optimalInteger(0, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
|
assign = Assignment(target, NumericLiteral.optimalInteger(0, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
|
||||||
wrapWithProgram(listOf(assign))
|
wrapWithProgram(listOf(assign))
|
||||||
target.isIOAddress(c64target.machine) shouldBe true
|
target.isIOAddress(c64target.machine) shouldBe true
|
||||||
@@ -114,7 +114,7 @@ class TestMemory: FunSpec({
|
|||||||
fun createTestProgramForMemoryRefViaVar(address: UInt, vartype: VarDeclType): AssignTarget {
|
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 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 memexpr = IdentifierReference(listOf("address"), Position.DUMMY)
|
||||||
val target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), null, Position.DUMMY)
|
val target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), null, false, Position.DUMMY)
|
||||||
val assignment = Assignment(target, NumericLiteral.optimalInteger(0, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
|
val assignment = Assignment(target, NumericLiteral.optimalInteger(0, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
|
||||||
wrapWithProgram(listOf(decl, assignment))
|
wrapWithProgram(listOf(decl, assignment))
|
||||||
return target
|
return target
|
||||||
@@ -137,13 +137,13 @@ class TestMemory: FunSpec({
|
|||||||
|
|
||||||
test("memory expression mapped to IO memory on C64") {
|
test("memory expression mapped to IO memory on C64") {
|
||||||
var memexpr = PrefixExpression("+", NumericLiteral.optimalInteger(0x1000, Position.DUMMY), Position.DUMMY)
|
var memexpr = PrefixExpression("+", NumericLiteral.optimalInteger(0x1000, Position.DUMMY), Position.DUMMY)
|
||||||
var target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), null, Position.DUMMY)
|
var target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), null, false, Position.DUMMY)
|
||||||
var assign = Assignment(target, NumericLiteral.optimalInteger(0, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
|
var assign = Assignment(target, NumericLiteral.optimalInteger(0, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
|
||||||
wrapWithProgram(listOf(assign))
|
wrapWithProgram(listOf(assign))
|
||||||
target.isIOAddress(c64target.machine) shouldBe false
|
target.isIOAddress(c64target.machine) shouldBe false
|
||||||
|
|
||||||
memexpr = PrefixExpression("+", NumericLiteral.optimalInteger(0xd020, Position.DUMMY), Position.DUMMY)
|
memexpr = PrefixExpression("+", NumericLiteral.optimalInteger(0xd020, Position.DUMMY), Position.DUMMY)
|
||||||
target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), null, Position.DUMMY)
|
target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), null, false, Position.DUMMY)
|
||||||
assign = Assignment(target, NumericLiteral.optimalInteger(0, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
|
assign = Assignment(target, NumericLiteral.optimalInteger(0, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
|
||||||
wrapWithProgram(listOf(assign))
|
wrapWithProgram(listOf(assign))
|
||||||
target.isIOAddress(c64target.machine) shouldBe true
|
target.isIOAddress(c64target.machine) shouldBe true
|
||||||
@@ -151,7 +151,7 @@ class TestMemory: FunSpec({
|
|||||||
|
|
||||||
test("regular variable not in mapped IO ram on C64") {
|
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 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, null, Position.DUMMY)
|
val target = AssignTarget(IdentifierReference(listOf("address"), Position.DUMMY), null, null, null, false, Position.DUMMY)
|
||||||
val assignment = Assignment(target, NumericLiteral.optimalInteger(0, Position.DUMMY), AssignmentOrigin.USERCODE, 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 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"))
|
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") {
|
test("memory mapped variable not in mapped IO ram on C64") {
|
||||||
val address = 0x1000u
|
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 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, null, Position.DUMMY)
|
val target = AssignTarget(IdentifierReference(listOf("address"), Position.DUMMY), null, null, null, false, Position.DUMMY)
|
||||||
val assignment = Assignment(target, NumericLiteral.optimalInteger(0, Position.DUMMY), AssignmentOrigin.USERCODE, 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 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"))
|
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") {
|
test("memory mapped variable in mapped IO ram on C64") {
|
||||||
val address = 0xd020u
|
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 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, null, Position.DUMMY)
|
val target = AssignTarget(IdentifierReference(listOf("address"), Position.DUMMY), null, null, null, false, Position.DUMMY)
|
||||||
val assignment = Assignment(target, NumericLiteral.optimalInteger(0, Position.DUMMY), AssignmentOrigin.USERCODE, 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 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"))
|
val module = Module(mutableListOf(subroutine), Position.DUMMY, SourceCode.Generated("test"))
|
||||||
@@ -187,7 +187,7 @@ class TestMemory: FunSpec({
|
|||||||
test("array not in mapped IO ram") {
|
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 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 arrayindexed = ArrayIndexedExpression(IdentifierReference(listOf("address"), Position.DUMMY), ArrayIndex(NumericLiteral.optimalInteger(1, Position.DUMMY), Position.DUMMY), Position.DUMMY)
|
||||||
val target = AssignTarget(null, arrayindexed, null, null, Position.DUMMY)
|
val target = AssignTarget(null, arrayindexed, null, null, false, Position.DUMMY)
|
||||||
val assignment = Assignment(target, NumericLiteral.optimalInteger(0, Position.DUMMY), AssignmentOrigin.USERCODE, 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 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"))
|
val module = Module(mutableListOf(subroutine), Position.DUMMY, SourceCode.Generated("test"))
|
||||||
@@ -200,7 +200,7 @@ class TestMemory: FunSpec({
|
|||||||
val address = 0x1000u
|
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 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 arrayindexed = ArrayIndexedExpression(IdentifierReference(listOf("address"), Position.DUMMY), ArrayIndex(NumericLiteral.optimalInteger(1, Position.DUMMY), Position.DUMMY), Position.DUMMY)
|
||||||
val target = AssignTarget(null, arrayindexed, null, null, Position.DUMMY)
|
val target = AssignTarget(null, arrayindexed, null, null, false, Position.DUMMY)
|
||||||
val assignment = Assignment(target, NumericLiteral.optimalInteger(0, Position.DUMMY), AssignmentOrigin.USERCODE, 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 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"))
|
val module = Module(mutableListOf(subroutine), Position.DUMMY, SourceCode.Generated("test"))
|
||||||
@@ -213,7 +213,7 @@ class TestMemory: FunSpec({
|
|||||||
val address = 0xd800u
|
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 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 arrayindexed = ArrayIndexedExpression(IdentifierReference(listOf("address"), Position.DUMMY), ArrayIndex(NumericLiteral.optimalInteger(1, Position.DUMMY), Position.DUMMY), Position.DUMMY)
|
||||||
val target = AssignTarget(null, arrayindexed, null, null, Position.DUMMY)
|
val target = AssignTarget(null, arrayindexed, null, null, false, Position.DUMMY)
|
||||||
val assignment = Assignment(target, NumericLiteral.optimalInteger(0, Position.DUMMY), AssignmentOrigin.USERCODE, 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 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"))
|
val module = Module(mutableListOf(subroutine), Position.DUMMY, SourceCode.Generated("test"))
|
||||||
|
@@ -115,7 +115,8 @@ main {
|
|||||||
|
|
||||||
cx16.r0L, flag = test2(12345, 5566, flag, -42)
|
cx16.r0L, flag = test2(12345, 5566, flag, -42)
|
||||||
cx16.r1, flag, bytevar = test3()
|
cx16.r1, flag, bytevar = test3()
|
||||||
cx16.r1, bytevar = test3() ; omitting the status flag result should also work
|
cx16.r1, void, bytevar = test3()
|
||||||
|
void, void, void = test3()
|
||||||
}
|
}
|
||||||
|
|
||||||
asmsub test2(uword arg @AY, uword arg2 @R1, bool flag @Pc, byte value @X) -> ubyte @A, bool @Pc {
|
asmsub test2(uword arg @AY, uword arg2 @R1, bool flag @Pc, byte value @X) -> ubyte @A, bool @Pc {
|
||||||
@@ -140,23 +141,30 @@ main {
|
|||||||
val result = compileText(Cx16Target(), false, src, errors, true)!!
|
val result = compileText(Cx16Target(), false, src, errors, true)!!
|
||||||
errors.errors.size shouldBe 0
|
errors.errors.size shouldBe 0
|
||||||
val start = result.codegenAst!!.entrypoint()!!
|
val start = result.codegenAst!!.entrypoint()!!
|
||||||
start.children.size shouldBe 8
|
start.children.size shouldBe 9
|
||||||
val a1_1 = start.children[4] as PtAssignment
|
val a1_1 = start.children[4] as PtAssignment
|
||||||
val a1_2 = start.children[5] as PtAssignment
|
val a1_2 = start.children[5] as PtAssignment
|
||||||
val a1_3 = start.children[6] as PtAssignment
|
val a1_3 = start.children[6] as PtAssignment
|
||||||
|
val a1_4 = start.children[7] as PtAssignment
|
||||||
a1_1.multiTarget shouldBe true
|
a1_1.multiTarget shouldBe true
|
||||||
a1_2.multiTarget shouldBe true
|
a1_2.multiTarget shouldBe true
|
||||||
a1_3.multiTarget shouldBe true
|
a1_3.multiTarget shouldBe true
|
||||||
|
a1_4.multiTarget shouldBe true
|
||||||
a1_1.children.size shouldBe 3
|
a1_1.children.size shouldBe 3
|
||||||
a1_2.children.size shouldBe 4
|
a1_2.children.size shouldBe 4
|
||||||
a1_3.children.size shouldBe 3
|
a1_3.children.size shouldBe 4
|
||||||
|
a1_4.children.size shouldBe 4
|
||||||
(a1_1.children[0] as PtAssignTarget).identifier!!.name shouldBe("cx16.r0L")
|
(a1_1.children[0] as PtAssignTarget).identifier!!.name shouldBe("cx16.r0L")
|
||||||
(a1_1.children[1] as PtAssignTarget).identifier!!.name shouldBe("p8b_main.p8s_start.p8v_flag")
|
(a1_1.children[1] as PtAssignTarget).identifier!!.name shouldBe("p8b_main.p8s_start.p8v_flag")
|
||||||
(a1_2.children[0] as PtAssignTarget).identifier!!.name shouldBe("cx16.r1")
|
(a1_2.children[0] as PtAssignTarget).identifier!!.name shouldBe("cx16.r1")
|
||||||
(a1_2.children[1] as PtAssignTarget).identifier!!.name shouldBe("p8b_main.p8s_start.p8v_flag")
|
(a1_2.children[1] as PtAssignTarget).identifier!!.name shouldBe("p8b_main.p8s_start.p8v_flag")
|
||||||
(a1_2.children[2] as PtAssignTarget).identifier!!.name shouldBe("p8b_main.p8s_start.p8v_bytevar")
|
(a1_2.children[2] as PtAssignTarget).identifier!!.name shouldBe("p8b_main.p8s_start.p8v_bytevar")
|
||||||
(a1_3.children[0] as PtAssignTarget).identifier!!.name shouldBe("cx16.r1")
|
(a1_3.children[0] as PtAssignTarget).identifier!!.name shouldBe("cx16.r1")
|
||||||
(a1_3.children[1] as PtAssignTarget).identifier!!.name shouldBe("p8b_main.p8s_start.p8v_bytevar")
|
(a1_3.children[1] as PtAssignTarget).void shouldBe true
|
||||||
|
(a1_3.children[2] as PtAssignTarget).identifier!!.name shouldBe("p8b_main.p8s_start.p8v_bytevar")
|
||||||
|
(a1_4.children[0] as PtAssignTarget).void shouldBe true
|
||||||
|
(a1_4.children[1] as PtAssignTarget).void shouldBe true
|
||||||
|
(a1_4.children[2] as PtAssignTarget).void shouldBe true
|
||||||
}
|
}
|
||||||
|
|
||||||
test("multi-assign from romsub") {
|
test("multi-assign from romsub") {
|
||||||
@@ -169,7 +177,8 @@ main {
|
|||||||
flag = test(42)
|
flag = test(42)
|
||||||
cx16.r0L, flag = test2(12345, 5566, flag, -42)
|
cx16.r0L, flag = test2(12345, 5566, flag, -42)
|
||||||
cx16.r1, flag, bytevar = test3()
|
cx16.r1, flag, bytevar = test3()
|
||||||
cx16.r1, bytevar = test3() ; omitting the status flag result should also work
|
cx16.r1, void, bytevar = test3()
|
||||||
|
void, void, void = test3()
|
||||||
}
|
}
|
||||||
|
|
||||||
romsub ${'$'}8000 = test(ubyte arg @A) -> bool @Pc
|
romsub ${'$'}8000 = test(ubyte arg @A) -> bool @Pc
|
||||||
@@ -182,22 +191,29 @@ main {
|
|||||||
val result = compileText(Cx16Target(), false, src, errors, true)!!
|
val result = compileText(Cx16Target(), false, src, errors, true)!!
|
||||||
errors.errors.size shouldBe 0
|
errors.errors.size shouldBe 0
|
||||||
val start = result.codegenAst!!.entrypoint()!!
|
val start = result.codegenAst!!.entrypoint()!!
|
||||||
start.children.size shouldBe 9
|
start.children.size shouldBe 10
|
||||||
val a1_1 = start.children[5] as PtAssignment
|
val a1_1 = start.children[5] as PtAssignment
|
||||||
val a1_2 = start.children[6] as PtAssignment
|
val a1_2 = start.children[6] as PtAssignment
|
||||||
val a1_3 = start.children[7] as PtAssignment
|
val a1_3 = start.children[7] as PtAssignment
|
||||||
|
val a1_4 = start.children[8] as PtAssignment
|
||||||
a1_1.multiTarget shouldBe true
|
a1_1.multiTarget shouldBe true
|
||||||
a1_2.multiTarget shouldBe true
|
a1_2.multiTarget shouldBe true
|
||||||
a1_3.multiTarget shouldBe true
|
a1_3.multiTarget shouldBe true
|
||||||
|
a1_4.multiTarget shouldBe true
|
||||||
a1_1.children.size shouldBe 3
|
a1_1.children.size shouldBe 3
|
||||||
a1_2.children.size shouldBe 4
|
a1_2.children.size shouldBe 4
|
||||||
a1_3.children.size shouldBe 3
|
a1_3.children.size shouldBe 4
|
||||||
|
a1_4.children.size shouldBe 4
|
||||||
(a1_1.children[0] as PtAssignTarget).identifier!!.name shouldBe("cx16.r0L")
|
(a1_1.children[0] as PtAssignTarget).identifier!!.name shouldBe("cx16.r0L")
|
||||||
(a1_1.children[1] as PtAssignTarget).identifier!!.name shouldBe("p8b_main.p8s_start.p8v_flag")
|
(a1_1.children[1] as PtAssignTarget).identifier!!.name shouldBe("p8b_main.p8s_start.p8v_flag")
|
||||||
(a1_2.children[0] as PtAssignTarget).identifier!!.name shouldBe("cx16.r1")
|
(a1_2.children[0] as PtAssignTarget).identifier!!.name shouldBe("cx16.r1")
|
||||||
(a1_2.children[1] as PtAssignTarget).identifier!!.name shouldBe("p8b_main.p8s_start.p8v_flag")
|
(a1_2.children[1] as PtAssignTarget).identifier!!.name shouldBe("p8b_main.p8s_start.p8v_flag")
|
||||||
(a1_2.children[2] as PtAssignTarget).identifier!!.name shouldBe("p8b_main.p8s_start.p8v_bytevar")
|
(a1_2.children[2] as PtAssignTarget).identifier!!.name shouldBe("p8b_main.p8s_start.p8v_bytevar")
|
||||||
(a1_3.children[0] as PtAssignTarget).identifier!!.name shouldBe("cx16.r1")
|
(a1_3.children[0] as PtAssignTarget).identifier!!.name shouldBe("cx16.r1")
|
||||||
(a1_3.children[1] as PtAssignTarget).identifier!!.name shouldBe("p8b_main.p8s_start.p8v_bytevar")
|
(a1_3.children[1] as PtAssignTarget).void shouldBe true
|
||||||
|
(a1_3.children[2] as PtAssignTarget).identifier!!.name shouldBe("p8b_main.p8s_start.p8v_bytevar")
|
||||||
|
(a1_4.children[0] as PtAssignTarget).void shouldBe true
|
||||||
|
(a1_4.children[1] as PtAssignTarget).void shouldBe true
|
||||||
|
(a1_4.children[2] as PtAssignTarget).void shouldBe true
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@@ -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 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 labelInSub = Label("locallabel", Position.DUMMY)
|
||||||
|
|
||||||
val tgt = AssignTarget(IdentifierReference(listOf("tgt"), Position.DUMMY), null, null, null, Position.DUMMY)
|
val tgt = AssignTarget(IdentifierReference(listOf("tgt"), Position.DUMMY), null, null, null, false, Position.DUMMY)
|
||||||
val assign1 = Assignment(tgt, IdentifierReference(listOf("localvar"), Position.DUMMY), AssignmentOrigin.USERCODE, 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 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)
|
val assign3 = Assignment(tgt, AddressOf(IdentifierReference(listOf("var_outside"), Position.DUMMY), null, Position.DUMMY), AssignmentOrigin.USERCODE, Position.DUMMY)
|
||||||
|
@@ -406,16 +406,20 @@ class AstToSourceTextConverter(val output: (text: String) -> Unit, val program:
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun visit(assignTarget: AssignTarget) {
|
override fun visit(assignTarget: AssignTarget) {
|
||||||
assignTarget.memoryAddress?.accept(this)
|
if(assignTarget.void)
|
||||||
assignTarget.identifier?.accept(this)
|
output("void")
|
||||||
assignTarget.arrayindexed?.accept(this)
|
else {
|
||||||
val multi = assignTarget.multi
|
assignTarget.memoryAddress?.accept(this)
|
||||||
if(multi!=null) {
|
assignTarget.identifier?.accept(this)
|
||||||
multi.dropLast(1).forEach { target ->
|
assignTarget.arrayindexed?.accept(this)
|
||||||
target.accept(this)
|
val multi = assignTarget.multi
|
||||||
output(", ")
|
if (multi != null) {
|
||||||
|
multi.dropLast(1).forEach { target ->
|
||||||
|
target.accept(this)
|
||||||
|
output(", ")
|
||||||
|
}
|
||||||
|
multi.last().accept(this)
|
||||||
}
|
}
|
||||||
multi.last().accept(this)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -246,7 +246,7 @@ private fun Asmsub_paramsContext.toAst(): List<AsmSubroutineParameter>
|
|||||||
val identifiers = vardecl.identifier()
|
val identifiers = vardecl.identifier()
|
||||||
if(identifiers.size>1)
|
if(identifiers.size>1)
|
||||||
throw SyntaxError("parameter name must be singular", identifiers[0].toPosition())
|
throw SyntaxError("parameter name must be singular", identifiers[0].toPosition())
|
||||||
val identifiername = identifiers[0].NAME() ?: identifiers[0].UNDERSCORENAME() ?: identifiers[0].UNDERSCOREPLACEHOLDER()
|
val identifiername = identifiers[0].NAME() ?: identifiers[0].UNDERSCORENAME() ?: identifiers[0].VOID()
|
||||||
AsmSubroutineParameter(identifiername.text, datatype, registerorpair, statusregister, toPosition())
|
AsmSubroutineParameter(identifiername.text, datatype, registerorpair, statusregister, toPosition())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -317,22 +317,27 @@ private fun Sub_paramsContext.toAst(): List<SubroutineParameter> =
|
|||||||
val identifiers = it.identifier()
|
val identifiers = it.identifier()
|
||||||
if(identifiers.size>1)
|
if(identifiers.size>1)
|
||||||
throw SyntaxError("parameter name must be singular", identifiers[0].toPosition())
|
throw SyntaxError("parameter name must be singular", identifiers[0].toPosition())
|
||||||
val identifiername = identifiers[0].NAME() ?: identifiers[0].UNDERSCORENAME() ?: identifiers[0].UNDERSCOREPLACEHOLDER()
|
val identifiername = identifiers[0].NAME() ?: identifiers[0].UNDERSCORENAME() ?: identifiers[0].VOID()
|
||||||
SubroutineParameter(identifiername.text, datatype, it.toPosition())
|
SubroutineParameter(identifiername.text, datatype, it.toPosition())
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun Assign_targetContext.toAst() : AssignTarget {
|
private fun Assign_targetContext.toAst() : AssignTarget {
|
||||||
return when(this) {
|
return when(this) {
|
||||||
is IdentifierTargetContext ->
|
is IdentifierTargetContext -> {
|
||||||
AssignTarget(scoped_identifier().toAst(), null, null, null, scoped_identifier().toPosition())
|
val identifier = scoped_identifier().toAst()
|
||||||
|
if(identifier.nameInSource==listOf("void"))
|
||||||
|
AssignTarget(null, null, null, null, true, scoped_identifier().toPosition())
|
||||||
|
else
|
||||||
|
AssignTarget(identifier, null, null, null, false, scoped_identifier().toPosition())
|
||||||
|
}
|
||||||
is MemoryTargetContext ->
|
is MemoryTargetContext ->
|
||||||
AssignTarget(null, null, DirectMemoryWrite(directmemory().expression().toAst(), directmemory().toPosition()), null, toPosition())
|
AssignTarget(null, null, DirectMemoryWrite(directmemory().expression().toAst(), directmemory().toPosition()), null, false, toPosition())
|
||||||
is ArrayindexedTargetContext -> {
|
is ArrayindexedTargetContext -> {
|
||||||
val ax = arrayindexed()
|
val ax = arrayindexed()
|
||||||
val arrayvar = ax.scoped_identifier().toAst()
|
val arrayvar = ax.scoped_identifier().toAst()
|
||||||
val index = ax.arrayindex().toAst()
|
val index = ax.arrayindex().toAst()
|
||||||
val arrayindexed = ArrayIndexedExpression(arrayvar, index, ax.toPosition())
|
val arrayindexed = ArrayIndexedExpression(arrayvar, index, ax.toPosition())
|
||||||
AssignTarget(null, arrayindexed, null, null, toPosition())
|
AssignTarget(null, arrayindexed, null, null, false, toPosition())
|
||||||
}
|
}
|
||||||
else -> throw FatalAstException("weird assign target node $this")
|
else -> throw FatalAstException("weird assign target node $this")
|
||||||
}
|
}
|
||||||
@@ -340,7 +345,7 @@ private fun Assign_targetContext.toAst() : AssignTarget {
|
|||||||
|
|
||||||
private fun Multi_assign_targetContext.toAst() : AssignTarget {
|
private fun Multi_assign_targetContext.toAst() : AssignTarget {
|
||||||
val targets = this.assign_target().map { it.toAst() }
|
val targets = this.assign_target().map { it.toAst() }
|
||||||
return AssignTarget(null, null, null, targets, toPosition())
|
return AssignTarget(null, null, null, targets, false, toPosition())
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun ClobberContext.toAst() : Set<CpuRegister> {
|
private fun ClobberContext.toAst() : Set<CpuRegister> {
|
||||||
@@ -672,7 +677,7 @@ private fun VardeclContext.toAst(type: VarDeclType, value: Expression?): VarDecl
|
|||||||
else -> ZeropageWish.DONTCARE
|
else -> ZeropageWish.DONTCARE
|
||||||
}
|
}
|
||||||
val identifiers = identifier()
|
val identifiers = identifier()
|
||||||
val identifiername = identifiers[0].NAME() ?: identifiers[0].UNDERSCORENAME() ?: identifiers[0].UNDERSCOREPLACEHOLDER()
|
val identifiername = identifiers[0].NAME() ?: identifiers[0].UNDERSCORENAME() ?: identifiers[0].VOID()
|
||||||
val name = if(identifiers.size==1) identifiername.text else "<multiple>"
|
val name = if(identifiers.size==1) identifiername.text else "<multiple>"
|
||||||
val isArray = ARRAYSIG() != null || arrayindex() != null
|
val isArray = ARRAYSIG() != null || arrayindex() != null
|
||||||
val split = options.SPLIT().isNotEmpty()
|
val split = options.SPLIT().isNotEmpty()
|
||||||
@@ -695,7 +700,7 @@ private fun VardeclContext.toAst(type: VarDeclType, value: Expression?): VarDecl
|
|||||||
arrayindex()?.toAst(),
|
arrayindex()?.toAst(),
|
||||||
name,
|
name,
|
||||||
if(identifiers.size==1) emptyList() else identifiers.map {
|
if(identifiers.size==1) emptyList() else identifiers.map {
|
||||||
val idname = it.NAME() ?: it.UNDERSCORENAME() ?: it.UNDERSCOREPLACEHOLDER()
|
val idname = it.NAME() ?: it.UNDERSCORENAME() ?: it.VOID()
|
||||||
idname.text
|
idname.text
|
||||||
},
|
},
|
||||||
value,
|
value,
|
||||||
|
@@ -494,6 +494,7 @@ data class AssignTarget(var identifier: IdentifierReference?,
|
|||||||
var arrayindexed: ArrayIndexedExpression?,
|
var arrayindexed: ArrayIndexedExpression?,
|
||||||
val memoryAddress: DirectMemoryWrite?,
|
val memoryAddress: DirectMemoryWrite?,
|
||||||
val multi: List<AssignTarget>?,
|
val multi: List<AssignTarget>?,
|
||||||
|
val void: Boolean,
|
||||||
override val position: Position) : Node {
|
override val position: Position) : Node {
|
||||||
override lateinit var parent: Node
|
override lateinit var parent: Node
|
||||||
|
|
||||||
@@ -517,7 +518,7 @@ data class AssignTarget(var identifier: IdentifierReference?,
|
|||||||
|
|
||||||
fun accept(visitor: IAstVisitor) = visitor.visit(this)
|
fun accept(visitor: IAstVisitor) = visitor.visit(this)
|
||||||
fun accept(visitor: AstWalker, parent: Node) = visitor.visit(this, parent)
|
fun accept(visitor: AstWalker, parent: Node) = visitor.visit(this, parent)
|
||||||
override fun copy() = AssignTarget(identifier?.copy(), arrayindexed?.copy(), memoryAddress?.copy(), multi?.toList(), position)
|
override fun copy() = AssignTarget(identifier?.copy(), arrayindexed?.copy(), memoryAddress?.copy(), multi?.toList(), void, position)
|
||||||
override fun referencesIdentifier(nameInSource: List<String>): Boolean =
|
override fun referencesIdentifier(nameInSource: List<String>): Boolean =
|
||||||
identifier?.referencesIdentifier(nameInSource)==true ||
|
identifier?.referencesIdentifier(nameInSource)==true ||
|
||||||
arrayindexed?.referencesIdentifier(nameInSource)==true ||
|
arrayindexed?.referencesIdentifier(nameInSource)==true ||
|
||||||
@@ -577,6 +578,8 @@ data class AssignTarget(var identifier: IdentifierReference?,
|
|||||||
fun isSameAs(other: AssignTarget, program: Program): Boolean {
|
fun isSameAs(other: AssignTarget, program: Program): Boolean {
|
||||||
if (this === other)
|
if (this === other)
|
||||||
return true
|
return true
|
||||||
|
if(void && other.void)
|
||||||
|
return true
|
||||||
if (this.identifier != null && other.identifier != null)
|
if (this.identifier != null && other.identifier != null)
|
||||||
return this.identifier!!.nameInSource == other.identifier!!.nameInSource
|
return this.identifier!!.nameInSource == other.identifier!!.nameInSource
|
||||||
if (this.memoryAddress != null && other.memoryAddress != null) {
|
if (this.memoryAddress != null && other.memoryAddress != null) {
|
||||||
|
@@ -684,13 +684,13 @@ are all assigned to individual assignment targets. You simply write them as a co
|
|||||||
|
|
||||||
asmsub multisub() -> uword @AY, bool @Pc, ubyte @X { ... }
|
asmsub multisub() -> uword @AY, bool @Pc, ubyte @X { ... }
|
||||||
|
|
||||||
**There is also a special rule:** you are allowed to omit assignments of the boolean values returned in status registers such as the carry flag.
|
**Skipping values:** you are allowed to omit assignments of one or more values by putting ``void`` as the assignment target.
|
||||||
So in the case of multisub() above, you could also write `wordvar, bytevar = multisub()` and leave out the carry flag.
|
One of the cases where this is useful is with boolean values returned in status flags such as the carry flag.
|
||||||
The compiler will try to assign the normal numeric values and leave the status flags untouched, which then allows you to
|
Storing that flag as a boolean in a variable first, and then possibly adding an ``if flag...`` statement afterwards, is a lot less
|
||||||
use a conditional branch such as `if_cs` to do something with it. This is always more efficient
|
efficient than just keeping the flag as-is and using a conditional branch such as ``if_cs`` to do something with it.
|
||||||
than storing it in a variable and then adding an `if flag...` statement afterwards.
|
So in the case above that could be::
|
||||||
It can sometimes be tricky to keep the status flags that are returned from the subroutine intact though,
|
|
||||||
if the assign targets are not simple variables. In such cases, make sure you check the generated assembly code to see if it all works out.
|
wordvar, void, bytevar = multisub()
|
||||||
|
|
||||||
|
|
||||||
Subroutine definitions
|
Subroutine definitions
|
||||||
|
@@ -1,12 +1,6 @@
|
|||||||
TODO
|
TODO
|
||||||
====
|
====
|
||||||
|
|
||||||
try to replace the variable number of assignment targets by allowing placeholder '_' target
|
|
||||||
or try to do this with 'void' instead, is more prog8-like?
|
|
||||||
|
|
||||||
|
|
||||||
check souce code of examples and library, for void calls that could now be turned into multi-assign calls.
|
|
||||||
|
|
||||||
...
|
...
|
||||||
|
|
||||||
|
|
||||||
|
@@ -6,8 +6,9 @@ main {
|
|||||||
sub start() {
|
sub start() {
|
||||||
ubyte @shared bytevar
|
ubyte @shared bytevar
|
||||||
uword @shared wordvar
|
uword @shared wordvar
|
||||||
|
bool flag
|
||||||
|
|
||||||
wordvar, bytevar = test4()
|
wordvar, bytevar, void = test4()
|
||||||
if_cs
|
if_cs
|
||||||
txt.print("true! ")
|
txt.print("true! ")
|
||||||
else
|
else
|
||||||
|
@@ -26,7 +26,6 @@ WS : [ \t] -> skip ;
|
|||||||
VOID: 'void';
|
VOID: 'void';
|
||||||
NAME : [\p{Letter}][\p{Letter}\p{Mark}\p{Digit}_]* ; // match unicode properties
|
NAME : [\p{Letter}][\p{Letter}\p{Mark}\p{Digit}_]* ; // match unicode properties
|
||||||
UNDERSCORENAME : '_' NAME ; // match unicode properties
|
UNDERSCORENAME : '_' NAME ; // match unicode properties
|
||||||
UNDERSCOREPLACEHOLDER: '_' ;
|
|
||||||
DEC_INTEGER : DEC_DIGIT (DEC_DIGIT | '_')* ;
|
DEC_INTEGER : DEC_DIGIT (DEC_DIGIT | '_')* ;
|
||||||
HEX_INTEGER : '$' HEX_DIGIT (HEX_DIGIT | '_')* ;
|
HEX_INTEGER : '$' HEX_DIGIT (HEX_DIGIT | '_')* ;
|
||||||
BIN_INTEGER : '%' BIN_DIGIT (BIN_DIGIT | '_')* ;
|
BIN_INTEGER : '%' BIN_DIGIT (BIN_DIGIT | '_')* ;
|
||||||
@@ -222,7 +221,7 @@ breakstmt : 'break';
|
|||||||
|
|
||||||
continuestmt: 'continue';
|
continuestmt: 'continue';
|
||||||
|
|
||||||
identifier : NAME | UNDERSCORENAME | UNDERSCOREPLACEHOLDER;
|
identifier : NAME | UNDERSCORENAME | VOID;
|
||||||
|
|
||||||
scoped_identifier : identifier ('.' identifier)* ;
|
scoped_identifier : identifier ('.' identifier)* ;
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user