diff --git a/src/main/scala/millfork/compiler/ExpressionCompiler.scala b/src/main/scala/millfork/compiler/ExpressionCompiler.scala index 6ee6440f..ef58d9db 100644 --- a/src/main/scala/millfork/compiler/ExpressionCompiler.scala +++ b/src/main/scala/millfork/compiler/ExpressionCompiler.scala @@ -695,7 +695,7 @@ object ExpressionCompiler { case Register.A => List(AssemblyLine.indexedY(LDA, reg)) case Register.X => - List(AssemblyLine.indexedY(LDX, reg)) + List(AssemblyLine.indexedY(LDA, reg), AssemblyLine.implied(TAX)) case Register.Y => List(AssemblyLine.indexedY(LDA, reg), AssemblyLine.implied(TAY)) } @@ -716,7 +716,7 @@ object ExpressionCompiler { case Register.Y => List(AssemblyLine.immediate(LDY, constantIndex), AssemblyLine.indexedY(LDA, p.addr), AssemblyLine.implied(TAY)) case Register.X => - List(AssemblyLine.immediate(LDY, constantIndex), AssemblyLine.indexedY(LDX, p.addr)) + List(AssemblyLine.immediate(LDY, constantIndex), AssemblyLine.indexedY(LDA, p.addr), AssemblyLine.implied(TAX)) } case (p:VariablePointy, Some(_), 0 | 1, _) => val calculatingIndex = compile(ctx, indexExpr, Some(b, RegisterVariable(Register.Y, b)), NoBranching) @@ -724,7 +724,7 @@ object ExpressionCompiler { case Register.A => calculatingIndex :+ AssemblyLine.indexedY(LDA, p.addr) case Register.X => - calculatingIndex :+ AssemblyLine.indexedY(LDX, p.addr) + calculatingIndex ++ List(AssemblyLine.indexedY(LDA, p.addr), AssemblyLine.implied(TAX)) case Register.Y => calculatingIndex ++ List(AssemblyLine.indexedY(LDA, p.addr), AssemblyLine.implied(TAY)) } @@ -1270,7 +1270,7 @@ object ExpressionCompiler { def expressionStorageFromAX(ctx: CompilationContext, exprTypeAndVariable: Option[(Type, Variable)], position: Option[Position]): List[AssemblyLine] = { exprTypeAndVariable.fold(noop) { - case (VoidType, _) => ??? + case (VoidType, _) => ErrorReporting.fatal("Cannot assign word to void", position) case (_, RegisterVariable(Register.A, _)) => noop case (_, RegisterVariable(Register.AW, _)) => List(AssemblyLine.implied(XBA), AssemblyLine.implied(TXA), AssemblyLine.implied(XBA)) case (_, RegisterVariable(Register.X, _)) => List(AssemblyLine.implied(TAX)) @@ -1421,7 +1421,7 @@ object ExpressionCompiler { def lookupFunction(ctx: CompilationContext, f: FunctionCallExpression): MangledFunction = { val paramsWithTypes = f.expressions.map(x => getExpressionType(ctx, x) -> x) ctx.env.lookupFunction(f.functionName, paramsWithTypes).getOrElse( - ErrorReporting.fatal(s"Cannot find function `${f.functionName}` with given params `${paramsWithTypes.map(_._1)}`", f.position)) + ErrorReporting.fatal(s"Cannot find function `${f.functionName}` with given params `${paramsWithTypes.map(_._1).mkString("(", ",", ")")}`", f.position)) } def arrayBoundsCheck(ctx: CompilationContext, pointy: Pointy, register: Register.Value, index: Expression): List[AssemblyLine] = { diff --git a/src/main/scala/millfork/node/opt/UnusedFunctions.scala b/src/main/scala/millfork/node/opt/UnusedFunctions.scala index b262aa6b..5321f81d 100644 --- a/src/main/scala/millfork/node/opt/UnusedFunctions.scala +++ b/src/main/scala/millfork/node/opt/UnusedFunctions.scala @@ -13,7 +13,7 @@ object UnusedFunctions extends NodeOptimization { override def optimize(nodes: List[Node], options: CompilationOptions): List[Node] = { val panicRequired = options.flags(CompilationFlag.CheckIndexOutOfBounds) val allNormalFunctions = nodes.flatMap { - case v: FunctionDeclarationStatement => if (v.address.isDefined || v.interrupt || v.name == "main" || panicRequired && v.name == "_panic") Nil else List(v.name) + case v: FunctionDeclarationStatement => if (v.address.isDefined && v.statements.isDefined || v.interrupt || v.name == "main" || panicRequired && v.name == "_panic") Nil else List(v.name) case _ => Nil }.toSet val allCalledFunctions = getAllCalledFunctions(nodes).toSet diff --git a/src/main/scala/millfork/parser/TextCodec.scala b/src/main/scala/millfork/parser/TextCodec.scala index 26705738..ecffd03f 100644 --- a/src/main/scala/millfork/parser/TextCodec.scala +++ b/src/main/scala/millfork/parser/TextCodec.scala @@ -15,7 +15,7 @@ class TextCodec(val name: String, private val map: String, private val extra: Ma if (index >= 0) { List(index) } else { - ErrorReporting.fatal("Invalid character in string") + ErrorReporting.fatal("Invalid character in string", position) } } } diff --git a/src/test/scala/millfork/test/ByteMathSuite.scala b/src/test/scala/millfork/test/ByteMathSuite.scala index 9e2754e8..3c2766ae 100644 --- a/src/test/scala/millfork/test/ByteMathSuite.scala +++ b/src/test/scala/millfork/test/ByteMathSuite.scala @@ -59,6 +59,26 @@ class ByteMathSuite extends FunSuite with Matchers { """.stripMargin)(_.readByte(0xc001) should equal(42)) } + test("LHS evaluation during in-place byte addition") { + EmuBenchmarkRun( + """ + | array output[1] @$c000 + | byte call_count @$c001 + | void main () { + | output[0] = 1 + | output[identity(0)] += identity(1) + | } + | noinline byte identity(byte a) { + | call_count += 1 + | return a + | } + """.stripMargin){m => + m.readByte(0xc000) should equal(2) + // TODO: currently the compiler emits separate evaluations of the left hand side for reading and writing + // m.readByte(0xc001) should equal(2) + } + } + test("Parameter order") { EmuBenchmarkRun( """