package millfork.node import millfork.assembly.Elidability import millfork.assembly.m6809.{MAddrMode, MOpcode} import millfork.assembly.mos.opt.SourceOfNZ import millfork.assembly.mos.{AddrMode, Opcode} import millfork.assembly.z80.{NoRegisters, OneRegister, ZOpcode, ZRegisters} import millfork.env.{Constant, EnumType, ParamPassingConvention, Type, VariableType} import millfork.output.MemoryAlignment case class Position(moduleName: String, line: Int, column: Int, cursor: Int) case class FieldDesc(typeName:String, fieldName: String, arraySize: Option[Expression]) case class ResolvedFieldDesc(typ:VariableType, fieldName: String, arrayIndexTypeAndSize: Option[(VariableType, Int)]) sealed trait Node { var position: Option[Position] = None } object Node { implicit class NodeOps[N<:Node](val node: N) extends AnyVal { def pos(position: Position): N = { node.position = Some(position) node } def pos(position: Option[Position]): N = { if (position.isDefined) { node.position = position } node } } } sealed trait Expression extends Node { def renameVariable(variable: String, newVariable: String): Expression def replaceVariable(variable: String, actualParam: Expression): Expression def replaceIndexedExpression(predicate: IndexedExpression => Boolean, replacement: IndexedExpression => Expression): Expression def containsVariable(variable: String): Boolean def getPointies: Seq[String] def isPure: Boolean def getAllIdentifiers: Set[String] def prettyPrint: String def #+#(smallInt: Int): Expression = if (smallInt == 0) this else (this #+# LiteralExpression(smallInt, 1).pos(this.position)).pos(this.position) def #+#(that: Expression): Expression = that match { case SumExpression(params, false) => SumExpression((false -> this) :: params, decimal = false) case _ => SumExpression(List(false -> this, false -> that), decimal = false) } def #*#(smallInt: Int): Expression = if (smallInt == 1) this else FunctionCallExpression("*", List(this, LiteralExpression(smallInt, 1).pos(this.position))).pos(this.position) def #-#(smallInt: Int): Expression = if (smallInt == 0) this else (this #-# LiteralExpression(smallInt, 1).pos(this.position)).pos(this.position) def #-#(that: Expression): Expression = SumExpression(List(false -> this, true -> that), decimal = false) @transient var typeCache: Type = _ @transient var constantValueCache: Option[Constant] = _ } case class ConstantArrayElementExpression(constant: Constant) extends Expression { override def renameVariable(variable: String, newVariable: String): Expression = this override def replaceVariable(variable: String, actualParam: Expression): Expression = this override def replaceIndexedExpression(predicate: IndexedExpression => Boolean, replacement: IndexedExpression => Expression): Expression = this override def containsVariable(variable: String): Boolean = false override def getPointies: Seq[String] = Seq.empty override def isPure: Boolean = true override def getAllIdentifiers: Set[String] = Set.empty override def prettyPrint: String = constant.toString } case class LiteralExpression(value: Long, requiredSize: Int) extends Expression { override def renameVariable(variable: String, newVariable: String): Expression = this override def replaceVariable(variable: String, actualParam: Expression): Expression = this override def replaceIndexedExpression(predicate: IndexedExpression => Boolean, replacement: IndexedExpression => Expression): Expression = this override def containsVariable(variable: String): Boolean = false override def getPointies: Seq[String] = Seq.empty override def isPure: Boolean = true override def getAllIdentifiers: Set[String] = Set.empty override def prettyPrint: String = "$" + value.toHexString } case class TextLiteralExpression(characters: List[Expression]) extends Expression { override def renameVariable(variable: String, newVariable: String): Expression = this override def replaceVariable(variable: String, actualParam: Expression): Expression = this override def replaceIndexedExpression(predicate: IndexedExpression => Boolean, replacement: IndexedExpression => Expression): Expression = this override def containsVariable(variable: String): Boolean = false override def getPointies: Seq[String] = Seq.empty override def isPure: Boolean = true override def getAllIdentifiers: Set[String] = Set.empty override def prettyPrint: String = characters.map(_.prettyPrint).mkString("[", ",", "]") } case class GeneratedConstantExpression(value: Constant, typ: Type) extends Expression { override def renameVariable(variable: String, newVariable: String): Expression = this override def replaceVariable(variable: String, actualParam: Expression): Expression = this override def replaceIndexedExpression(predicate: IndexedExpression => Boolean, replacement: IndexedExpression => Expression): Expression = this override def containsVariable(variable: String): Boolean = false override def getPointies: Seq[String] = Seq.empty override def isPure: Boolean = true override def getAllIdentifiers: Set[String] = Set.empty override def prettyPrint: String = value.toString } case class BooleanLiteralExpression(value: Boolean) extends Expression { override def renameVariable(variable: String, newVariable: String): Expression = this override def replaceVariable(variable: String, actualParam: Expression): Expression = this override def replaceIndexedExpression(predicate: IndexedExpression => Boolean, replacement: IndexedExpression => Expression): Expression = this override def containsVariable(variable: String): Boolean = false override def getPointies: Seq[String] = Seq.empty override def isPure: Boolean = true override def getAllIdentifiers: Set[String] = Set.empty override def prettyPrint: String = value.toString } sealed trait LhsExpression extends Expression case object BlackHoleExpression extends LhsExpression { override def renameVariable(variable: String, newVariable: String): Expression = this override def replaceVariable(variable: String, actualParam: Expression): LhsExpression = this override def replaceIndexedExpression(predicate: IndexedExpression => Boolean, replacement: IndexedExpression => Expression): Expression = this override def containsVariable(variable: String): Boolean = false override def getPointies: Seq[String] = Seq.empty override def isPure: Boolean = true override def getAllIdentifiers: Set[String] = Set.empty override def prettyPrint: String = "(_|_)" } case class SeparateBytesExpression(hi: Expression, lo: Expression) extends LhsExpression { override def renameVariable(variable: String, newVariable: String): Expression = SeparateBytesExpression( hi.renameVariable(variable, newVariable), lo.renameVariable(variable, newVariable)).pos(position) def replaceVariable(variable: String, actualParam: Expression): Expression = SeparateBytesExpression( hi.replaceVariable(variable, actualParam), lo.replaceVariable(variable, actualParam)).pos(position) override def replaceIndexedExpression(predicate: IndexedExpression => Boolean, replacement: IndexedExpression => Expression): Expression = SeparateBytesExpression( hi.replaceIndexedExpression(predicate, replacement), lo.replaceIndexedExpression(predicate, replacement)).pos(position) override def containsVariable(variable: String): Boolean = hi.containsVariable(variable) || lo.containsVariable(variable) override def getPointies: Seq[String] = hi.getPointies ++ lo.getPointies override def isPure: Boolean = hi.isPure && lo.isPure override def getAllIdentifiers: Set[String] = hi.getAllIdentifiers ++ lo.getAllIdentifiers override def prettyPrint: String = s"($hi:$lo)" } case class SumExpression(expressions: List[(Boolean, Expression)], decimal: Boolean) extends Expression { override def renameVariable(variable: String, newVariable: String): Expression = SumExpression(expressions.map { case (n, e) => n -> e.renameVariable(variable, newVariable) }, decimal).pos(position) override def replaceVariable(variable: String, actualParam: Expression): Expression = SumExpression(expressions.map { case (n, e) => n -> e.replaceVariable(variable, actualParam) }, decimal).pos(position) override def replaceIndexedExpression(predicate: IndexedExpression => Boolean, replacement: IndexedExpression => Expression): Expression = SumExpression(expressions.map { case (n, e) => n -> e.replaceIndexedExpression(predicate, replacement) }, decimal).pos(position) override def containsVariable(variable: String): Boolean = expressions.exists(_._2.containsVariable(variable)) override def getPointies: Seq[String] = expressions.flatMap(_._2.getPointies) override def isPure: Boolean = expressions.forall(_._2.isPure) override def getAllIdentifiers: Set[String] = expressions.map(_._2.getAllIdentifiers).fold(Set[String]())(_ ++ _) override def #+#(that: Expression): Expression = if (decimal) super.#+#(that) else that match { case SumExpression(params, false) => SumExpression(expressions ++ params, decimal = false) case _ => SumExpression(expressions :+ (false -> that), decimal = false) } override def #-#(that: Expression): Expression = if (decimal) super.#-#(that) else SumExpression(expressions :+ (true -> that), decimal = false) override def prettyPrint: String = '(' + expressions.map{case(neg, e) => (if (neg) "- " else "+ ") + e.prettyPrint}.mkString("", " ", ")").stripPrefix("+ ") } case class FunctionCallExpression(functionName: String, expressions: List[Expression]) extends Expression { override def renameVariable(variable: String, newVariable: String): Expression = FunctionCallExpression(functionName, expressions.map { _.renameVariable(variable, newVariable) }).pos(position) override def replaceVariable(variable: String, actualParam: Expression): Expression = FunctionCallExpression(functionName, expressions.map { _.replaceVariable(variable, actualParam) }).pos(position) override def replaceIndexedExpression(predicate: IndexedExpression => Boolean, replacement: IndexedExpression => Expression): Expression = FunctionCallExpression(functionName, expressions.map { _.replaceIndexedExpression(predicate, replacement) }).pos(position) override def containsVariable(variable: String): Boolean = expressions.exists(_.containsVariable(variable)) override def getPointies: Seq[String] = expressions.flatMap(_.getPointies) override def isPure: Boolean = false // TODO override def getAllIdentifiers: Set[String] = expressions.map(_.getAllIdentifiers).fold(Set[String]())(_ ++ _) + functionName override def prettyPrint: String = if (expressions.size != 2 || functionName.exists(Character.isAlphabetic(_))) functionName + expressions.map(_.prettyPrint).mkString("(", ", ", ")") else s"(${expressions.head.prettyPrint} $functionName ${expressions(1).prettyPrint}" } case class HalfWordExpression(expression: Expression, hiByte: Boolean) extends Expression { override def renameVariable(variable: String, newVariable: String): Expression = HalfWordExpression(expression.renameVariable(variable, newVariable), hiByte).pos(position) override def replaceVariable(variable: String, actualParam: Expression): Expression = HalfWordExpression(expression.replaceVariable(variable, actualParam), hiByte).pos(position) override def replaceIndexedExpression(predicate: IndexedExpression => Boolean, replacement: IndexedExpression => Expression): Expression = HalfWordExpression(expression.replaceIndexedExpression(predicate, replacement), hiByte).pos(position) override def containsVariable(variable: String): Boolean = expression.containsVariable(variable) override def getPointies: Seq[String] = expression.getPointies override def isPure: Boolean = expression.isPure override def getAllIdentifiers: Set[String] = expression.getAllIdentifiers override def prettyPrint: String = '(' + expression.prettyPrint + (if (hiByte) ").hi" else ").lo") } sealed class NiceFunctionProperty(override val toString: String) object NiceFunctionProperty { case object DoesntReadMemory extends NiceFunctionProperty("MR") case object DoesntWriteMemory extends NiceFunctionProperty("MW") case object Idempotent extends NiceFunctionProperty("Idem") case object IsLeaf extends NiceFunctionProperty("LEAF") } object MosNiceFunctionProperty { case object DoesntChangeA extends NiceFunctionProperty("A") case object DoesntChangeX extends NiceFunctionProperty("X") case object DoesntChangeY extends NiceFunctionProperty("Y") case object DoesntChangeIZ extends NiceFunctionProperty("Z") case object DoesntChangeAH extends NiceFunctionProperty("AH") case object DoesntChangeC extends NiceFunctionProperty("C") case object DoesntConcernD extends NiceFunctionProperty("D") case object DoesntChangeZpRegister extends NiceFunctionProperty("reg") case class SetsSourceOfNZ(sourceOfNZ: SourceOfNZ) extends NiceFunctionProperty(sourceOfNZ + "NZ") case class SetsXTo(value: Int) extends NiceFunctionProperty("Y=" + value) case class SetsYTo(value: Int) extends NiceFunctionProperty("Z=" + value) case class SetsATo(value: Int) extends NiceFunctionProperty("A=" + value) case class Bit0OfA(value: Boolean) extends NiceFunctionProperty("A0=" + value) case class Bit7OfA(value: Boolean) extends NiceFunctionProperty("A7=" + value) } object Z80NiceFunctionProperty { case object DoesntChangeA extends NiceFunctionProperty("A") case object DoesntChangeBC extends NiceFunctionProperty("BC") case object DoesntChangeDE extends NiceFunctionProperty("DE") case object DoesntChangeHL extends NiceFunctionProperty("HL") case object DoesntChangeCF extends NiceFunctionProperty("CF") case object DoesntChangeIY extends NiceFunctionProperty("IY") case class SetsATo(value: Int) extends NiceFunctionProperty("A=" + value) } object M6809NiceFunctionProperty { case object DoesntChangeA extends NiceFunctionProperty("A") case object DoesntChangeB extends NiceFunctionProperty("B") case object DoesntChangeX extends NiceFunctionProperty("X") case object DoesntChangeY extends NiceFunctionProperty("Y") case object DoesntChangeU extends NiceFunctionProperty("U") case object DoesntChangeDP extends NiceFunctionProperty("DP") case object DoesntChangeCF extends NiceFunctionProperty("C") case class SetsBTo(value: Int) extends NiceFunctionProperty("B=" + value) } object MosRegister extends Enumeration { val A, X, Y, AX, AY, YA, XA, XY, YX, AW = Value } object ZRegister extends Enumeration { val A, B, C, D, E, H, L, AF, BC, HL, DE, SP, IXH, IXL, IYH, IYL, IX, IY, R, I, MEM_HL, MEM_BC, MEM_DE, MEM_IX_D, MEM_IY_D, MEM_ABS_8, MEM_ABS_16, IMM_8, IMM_16 = Value def registerSize(reg: Value): Int = reg match { case AF | BC | DE | HL | IX | IY | IMM_16 => 2 case A | B | C | D | E | H | L | IXH | IXL | IYH | IYL | R | I | IMM_8 => 1 } def matchingImm(target: ZRegister.Value): ZRegister.Value = registerSize(target) match { case 1 => IMM_8 case 2 => IMM_16 } def matchingMemAbs(target: ZRegister.Value): ZRegister.Value = registerSize(target) match { case 1 => MEM_ABS_8 case 2 => MEM_ABS_16 } val main7Registers: Set[ZRegister.Value] = Set[ZRegister.Value](ZRegister.A, ZRegister.B, ZRegister.C, ZRegister.D, ZRegister.D, ZRegister.E, ZRegister.H, ZRegister.L) } object M6809Register extends Enumeration { val A, B, D, DP, X, Y, U, S, PC, CC = Value def registerSize(reg: Value): Int = reg match { case D | X | Y | U | S | PC => 2 case A | B | DP | CC => 1 } def registerPushMask(register: M6809Register.Value): Int = { register match { case CC => 1 case A => 2 case B => 4 case D => 6 case X => 0x10 case Y => 0x20 case U => 0x40 case S => 0x40 case PC => 0x80 case DP => 0 } } } //case class Indexing(child: Expression, register: Register.Value) extends Expression case class VariableExpression(name: String) extends LhsExpression { override def renameVariable(variable: String, newVariable: String): Expression = if (name == variable) VariableExpression(newVariable).pos(position) else if (name.startsWith(variable) && name(variable.length) == '.') VariableExpression(newVariable + name.stripPrefix(variable)).pos(position) else this override def replaceVariable(variable: String, actualParam: Expression): Expression = if (name == variable) actualParam else if (name.startsWith(variable) && name(variable.length) == '.') { actualParam match { case VariableExpression(newVariable) => this.renameVariable(variable, newVariable) case _ => name.stripPrefix(variable) match { case ".lo" => FunctionCallExpression("lo", List(this)).pos(position) case ".hi" => FunctionCallExpression("hi", List(this)).pos(position) case _ => ??? // TODO } } } else this override def replaceIndexedExpression(predicate: IndexedExpression => Boolean, replacement: IndexedExpression => Expression): Expression = this override def containsVariable(variable: String): Boolean = name == variable override def getPointies: Seq[String] = if (name.endsWith(".addr.lo")) Seq(name.stripSuffix(".addr.lo")) else Seq.empty override def isPure: Boolean = true override def getAllIdentifiers: Set[String] = Set(name) override def prettyPrint: String = name } case class IndexedExpression(name: String, index: Expression) extends LhsExpression { override def renameVariable(variable: String, newVariable: String): Expression = { val newIndex = index.renameVariable(variable, newVariable) if (name == variable) IndexedExpression(newVariable, newIndex).pos(position) else if (name.startsWith(variable) && name(variable.length) == '.') IndexedExpression(newVariable + name.stripPrefix(variable), newIndex).pos(position) else IndexedExpression(name, newIndex).pos(position) } override def replaceVariable(variable: String, actualParam: Expression): Expression = if (name == variable) { actualParam match { case VariableExpression(actualVariable) => IndexedExpression(actualVariable, index.replaceVariable(variable, actualParam)).pos(position) case _ => ??? // TODO } } else IndexedExpression(name, index.replaceVariable(variable, actualParam)).pos(position) override def replaceIndexedExpression(predicate: IndexedExpression => Boolean, replacement: IndexedExpression => Expression): Expression = if (predicate(this)) replacement(this).pos(position = position) else IndexedExpression(name, index.replaceIndexedExpression(predicate, replacement)) override def containsVariable(variable: String): Boolean = name == variable || index.containsVariable(variable) override def getPointies: Seq[String] = Seq(name) override def isPure: Boolean = index.isPure override def getAllIdentifiers: Set[String] = index.getAllIdentifiers + name override def prettyPrint: String = s"$name[${index.prettyPrint}]" } case class IndirectFieldExpression(root: Expression, firstIndices: Seq[Expression], fields: Seq[(Boolean, String, Seq[Expression])]) extends LhsExpression { override def renameVariable(variable: String, newVariable: String): Expression = IndirectFieldExpression( root.renameVariable(variable, newVariable), firstIndices.map(_.renameVariable(variable, newVariable)), fields.map{case (dot, f, i) => (dot, f, i.map(_.renameVariable(variable, newVariable)))}) override def replaceVariable(variable: String, actualParam: Expression): Expression = IndirectFieldExpression( root.replaceVariable(variable, actualParam), firstIndices.map(_.replaceVariable(variable, actualParam)), fields.map{case (dot, f, i) => (dot, f, i.map(_.replaceVariable(variable, actualParam)))}) override def replaceIndexedExpression(predicate: IndexedExpression => Boolean, replacement: IndexedExpression => Expression): Expression = IndirectFieldExpression( root.replaceIndexedExpression(predicate, replacement), firstIndices.map(_.replaceIndexedExpression(predicate, replacement)), fields.map{case (dot, f, i) => (dot, f, i.map(_.replaceIndexedExpression(predicate, replacement)))}) override def containsVariable(variable: String): Boolean = root.containsVariable(variable) || firstIndices.exists(_.containsVariable(variable)) || fields.exists(_._3.exists(_.containsVariable(variable))) override def getPointies: Seq[String] = (root match { case VariableExpression(v) => List(v) case _ => root.getPointies }) ++ firstIndices.flatMap(_.getPointies) ++ fields.flatMap(_._3.flatMap(_.getPointies)) override def isPure: Boolean = root.isPure && firstIndices.forall(_.isPure) && fields.forall(_._3.forall(_.isPure)) override def getAllIdentifiers: Set[String] = root.getAllIdentifiers ++ firstIndices.flatMap(_.getAllIdentifiers) ++ fields.flatMap(_._3.flatMap(_.getAllIdentifiers)) override def prettyPrint: String = root.prettyPrint + firstIndices.map(i => '[' + i.prettyPrint + ']').mkString("") + fields.map{case (dot, f, ixs) => (if (dot) "." else "->") + f + ixs.map(i => '[' + i.prettyPrint + ']').mkString("")} } case class DerefDebuggingExpression(inner: Expression, preferredSize: Int) extends LhsExpression { override def renameVariable(variable: String, newVariable: String): Expression = DerefDebuggingExpression(inner.renameVariable(variable, newVariable), preferredSize) override def replaceVariable(variable: String, actualParam: Expression): Expression = DerefDebuggingExpression(inner.replaceVariable(variable, actualParam), preferredSize) override def replaceIndexedExpression(predicate: IndexedExpression => Boolean, replacement: IndexedExpression => Expression): Expression = DerefDebuggingExpression(inner.replaceIndexedExpression(predicate, replacement), preferredSize) override def containsVariable(variable: String): Boolean = inner.containsVariable(variable) override def getPointies: Seq[String] = inner match { case VariableExpression(v) => List(v) case _ => inner.getPointies } override def isPure: Boolean = inner.isPure override def getAllIdentifiers: Set[String] = inner.getAllIdentifiers override def prettyPrint: String = s"¥deref(${inner.prettyPrint})" } case class DerefExpression(inner: Expression, offset: Int, targetType: Type) extends LhsExpression { override def renameVariable(variable: String, newVariable: String): Expression = DerefExpression(inner.renameVariable(variable, newVariable), offset, targetType) override def replaceVariable(variable: String, actualParam: Expression): Expression = DerefExpression(inner.replaceVariable(variable, actualParam), offset, targetType) override def replaceIndexedExpression(predicate: IndexedExpression => Boolean, replacement: IndexedExpression => Expression): Expression = DerefExpression(inner.replaceIndexedExpression(predicate, replacement), offset, targetType) override def containsVariable(variable: String): Boolean = inner.containsVariable(variable) override def getPointies: Seq[String] = inner match { case VariableExpression(v) => List(v) case _ => inner.getPointies } override def isPure: Boolean = inner.isPure override def getAllIdentifiers: Set[String] = inner.getAllIdentifiers override def prettyPrint: String = s"¥deref(${inner.prettyPrint})" } sealed trait Statement extends Node { def getAllExpressions: List[Expression] def getAllPointies: Seq[String] = getAllExpressions.flatMap(_.getPointies) } sealed trait DeclarationStatement extends Statement { def name: String } sealed trait BankedDeclarationStatement extends DeclarationStatement { def bank: Option[String] def name: String def optimizationHints: Set[String] def withChangedBank(bank: String): BankedDeclarationStatement } case class TypeDefinitionStatement(name: String, parent: String) extends DeclarationStatement { override def getAllExpressions: List[Expression] = Nil } case class VariableDeclarationStatement(name: String, typ: String, bank: Option[String], global: Boolean, stack: Boolean, constant: Boolean, volatile: Boolean, register: Boolean, initialValue: Option[Expression], address: Option[Expression], optimizationHints: Set[String], alignment: Option[MemoryAlignment]) extends BankedDeclarationStatement { override def getAllExpressions: List[Expression] = List(initialValue, address).flatten override def withChangedBank(bank: String): BankedDeclarationStatement = copy(bank = Some(bank)) } trait ArrayContents extends Node { def getAllExpressions(bigEndian: Boolean): List[Expression] def renameVariable(variableToRename: String, newVariable: String): ArrayContents def replaceVariable(variableToReplace: String, expression: Expression): ArrayContents } case class LiteralContents(contents: List[Expression]) extends ArrayContents { override def getAllExpressions(bigEndian: Boolean): List[Expression] = contents override def renameVariable(variableToRename: String, newVariable: String): ArrayContents = LiteralContents(contents.map(_.renameVariable(variableToRename, newVariable))) override def replaceVariable(variable: String, expression: Expression): ArrayContents = LiteralContents(contents.map(_.replaceVariable(variable, expression))) } case class ForLoopContents(variable: String, start: Expression, end: Expression, direction: ForDirection.Value, body: ArrayContents) extends ArrayContents { override def getAllExpressions(bigEndian: Boolean): List[Expression] = start :: end :: body.getAllExpressions(bigEndian).map(_.replaceVariable(variable, LiteralExpression(0, 1))) override def renameVariable(variableToRename: String, newVariable: String): ArrayContents = if (variableToRename == variable) this else ForLoopContents( variable, start.renameVariable(variableToRename, newVariable), end.renameVariable(variableToRename, newVariable), direction, body.renameVariable(variableToRename, newVariable)) override def replaceVariable(variableToReplace: String, expression: Expression): ArrayContents = if (variableToReplace == variable) this else ForLoopContents( variable, start.replaceVariable(variableToReplace, expression), end.replaceVariable(variableToReplace, expression), direction, body.replaceVariable(variableToReplace, expression)) } case class CombinedContents(contents: List[ArrayContents]) extends ArrayContents { override def getAllExpressions(bigEndian: Boolean): List[Expression] = contents.flatMap(_.getAllExpressions(bigEndian)) override def renameVariable(variableToRename: String, newVariable: String): ArrayContents = CombinedContents(contents.map(_.renameVariable(variableToRename, newVariable))) override def replaceVariable(variableToReplace: String, expression: Expression): ArrayContents = CombinedContents(contents.map(_.replaceVariable(variableToReplace, expression))) } case class ProcessedContents(processor: String, values: ArrayContents) extends ArrayContents { private def normalizeProcessor(bigEndian: Boolean): String = processor match { case "word" => if (bigEndian) "word_be" else "word_le" case "long" => if (bigEndian) "long_be" else "long_le" case x => x } override def getAllExpressions(bigEndian: Boolean): List[Expression] = normalizeProcessor(bigEndian) match { case "word_le" => values.getAllExpressions(bigEndian).flatMap(expr => List( FunctionCallExpression("lo", List(expr)).pos(expr.position), FunctionCallExpression("hi", List(expr)).pos(expr.position) )) case "word_be" => values.getAllExpressions(bigEndian).flatMap(expr => List( FunctionCallExpression("hi", List(expr)).pos(expr.position), FunctionCallExpression("lo", List(expr)).pos(expr.position) )) case "long_le" => values.getAllExpressions(bigEndian).flatMap(expr => List( FunctionCallExpression("lo", List(expr)).pos(expr.position), FunctionCallExpression("lo", List(FunctionCallExpression(">>", List(expr, LiteralExpression(8, 1))).pos(expr.position))).pos(expr.position), FunctionCallExpression("lo", List(FunctionCallExpression(">>", List(expr, LiteralExpression(16, 1))).pos(expr.position))).pos(expr.position), FunctionCallExpression("lo", List(FunctionCallExpression(">>", List(expr, LiteralExpression(24, 1))).pos(expr.position))).pos(expr.position) )) case "long_be" => values.getAllExpressions(bigEndian).flatMap(expr => List( FunctionCallExpression("lo", List(FunctionCallExpression(">>", List(expr, LiteralExpression(24, 1))).pos(expr.position))).pos(expr.position), FunctionCallExpression("lo", List(FunctionCallExpression(">>", List(expr, LiteralExpression(16, 1))).pos(expr.position))).pos(expr.position), FunctionCallExpression("lo", List(FunctionCallExpression(">>", List(expr, LiteralExpression(8, 1))).pos(expr.position))).pos(expr.position), FunctionCallExpression("lo", List(expr)).pos(expr.position) )) case "struct" => values.getAllExpressions(bigEndian) // not used for emitting actual arrays } override def renameVariable(variableToRename: String, newVariable: String): ArrayContents = ProcessedContents(processor, values.renameVariable(variableToRename, newVariable)) override def replaceVariable(variableToReplace: String, expression: Expression): ArrayContents = ProcessedContents(processor, values.replaceVariable(variableToReplace, expression)) } case class AliasDefinitionStatement(name: String, target: String, important: Boolean) extends DeclarationStatement { override def getAllExpressions: List[Expression] = Nil } case class EnumDefinitionStatement(name: String, variants: List[(String, Option[Expression])]) extends DeclarationStatement { override def getAllExpressions: List[Expression] = variants.flatMap(_._2) } case class StructDefinitionStatement(name: String, fields: List[FieldDesc], alignment: Option[MemoryAlignment]) extends DeclarationStatement { override def getAllExpressions: List[Expression] = Nil } case class UnionDefinitionStatement(name: String, fields: List[FieldDesc], alignment: Option[MemoryAlignment]) extends DeclarationStatement { override def getAllExpressions: List[Expression] = Nil } case class ArrayDeclarationStatement(name: String, bank: Option[String], length: Option[Expression], elementType: String, address: Option[Expression], const: Boolean, elements: Option[ArrayContents], optimizationHints: Set[String], alignment: Option[MemoryAlignment], bigEndian: Boolean) extends BankedDeclarationStatement { override def getAllExpressions: List[Expression] = List(length, address).flatten ++ elements.fold(List[Expression]())(_.getAllExpressions(bigEndian)) override def withChangedBank(bank: String): BankedDeclarationStatement = copy(bank = Some(bank)) } case class ParameterDeclaration(typ: String, assemblyParamPassingConvention: ParamPassingConvention) extends Node case class ImportStatement(filename: String, templateParams: List[String]) extends DeclarationStatement { override def getAllExpressions: List[Expression] = Nil override def name: String = "" } case class FunctionDeclarationStatement(name: String, resultType: String, params: List[ParameterDeclaration], bank: Option[String], address: Option[Expression], optimizationHints: Set[String], alignment: Option[MemoryAlignment], statements: Option[List[Statement]], isMacro: Boolean, inlinable: Option[Boolean], assembly: Boolean, interrupt: Boolean, kernalInterrupt: Boolean, constPure: Boolean, reentrant: Boolean) extends BankedDeclarationStatement { override def getAllExpressions: List[Expression] = address.toList ++ statements.getOrElse(Nil).flatMap(_.getAllExpressions) override def withChangedBank(bank: String): BankedDeclarationStatement = copy(bank = Some(bank)) override def getAllPointies: Seq[String] = statements match { case None => Seq.empty case Some(stmts) => val locals = stmts.flatMap{ case s:VariableDeclarationStatement => Some(s.name) case s:ArrayDeclarationStatement => Some(s.name) case _ => None }.toSet val pointies = stmts.flatMap(_.getAllPointies).toSet (pointies -- locals).toSeq } } sealed trait ExecutableStatement extends Statement { def isValidFunctionEnd: Boolean = false } case class RawBytesStatement(contents: ArrayContents, bigEndian: Boolean) extends ExecutableStatement { override def getAllExpressions: List[Expression] = contents.getAllExpressions(bigEndian) } sealed trait CompoundStatement extends ExecutableStatement { def getChildStatements: Seq[Statement] def flatMap(f: ExecutableStatement => Option[ExecutableStatement]): Option[ExecutableStatement] def loopVariable: String } case class ExpressionStatement(expression: Expression) extends ExecutableStatement { override def getAllExpressions: List[Expression] = List(expression) } case class ReturnStatement(value: Option[Expression]) extends ExecutableStatement { override def getAllExpressions: List[Expression] = value.toList override def isValidFunctionEnd: Boolean = true } case class GotoStatement(target: Expression) extends ExecutableStatement { override def getAllExpressions: List[Expression] = List(target) override def isValidFunctionEnd: Boolean = true } case class LabelStatement(name: String) extends ExecutableStatement { override def getAllExpressions: List[Expression] = Nil } case class EmptyStatement(toTypecheck: List[ExecutableStatement]) extends ExecutableStatement { override def getAllExpressions: List[Expression] = toTypecheck.flatMap(_.getAllExpressions) } trait ReturnDispatchLabel extends Node { def getAllExpressions: List[Expression] } case class DefaultReturnDispatchLabel(start: Option[Expression], end: Option[Expression]) extends ReturnDispatchLabel { def getAllExpressions: List[Expression] = List(start, end).flatten } case class StandardReturnDispatchLabel(labels:List[Expression]) extends ReturnDispatchLabel { def getAllExpressions: List[Expression] = labels } case class ReturnDispatchBranch(label: ReturnDispatchLabel, function: Expression, params: List[Expression]) extends Node { def getAllExpressions: List[Expression] = label.getAllExpressions ++ params } case class ReturnDispatchStatement(indexer: Expression, params: List[LhsExpression], branches: List[ReturnDispatchBranch]) extends ExecutableStatement { override def getAllExpressions: List[Expression] = indexer :: params ++ branches.flatMap(_.getAllExpressions) } case class Assignment(destination: LhsExpression, source: Expression) extends ExecutableStatement { override def getAllExpressions: List[Expression] = List(destination, source) } case class MosAssemblyStatement(opcode: Opcode.Value, addrMode: AddrMode.Value, expression: Expression, elidability: Elidability.Value) extends ExecutableStatement { override def getAllExpressions: List[Expression] = List(expression) override def getAllPointies: Seq[String] = addrMode match { case AddrMode.IndexedY | AddrMode.IndexedX | AddrMode.LongIndexedY | AddrMode.IndexedZ | AddrMode.LongIndexedZ | AddrMode.ZeroPage | AddrMode.ZeroPageX | AddrMode.ZeroPageY => expression.getAllIdentifiers.toSeq.map(_.takeWhile(_ != '.')) case AddrMode.Immediate => expression.getAllIdentifiers.toSeq.filter(i => !i.contains('.') || i.endsWith(".addr") || i.endsWith(".addr.lo")).map(_.takeWhile(_ != '.')) case _ => Seq.empty } override def isValidFunctionEnd: Boolean = opcode == Opcode.RTS || opcode == Opcode.RTI || opcode == Opcode.JMP || opcode == Opcode.BRA } case class Z80AssemblyStatement(opcode: ZOpcode.Value, registers: ZRegisters, offsetExpression: Option[Expression], expression: Expression, elidability: Elidability.Value) extends ExecutableStatement { override def getAllExpressions: List[Expression] = List(expression) override def isValidFunctionEnd: Boolean = registers match { case NoRegisters | OneRegister(_) => opcode == ZOpcode.RETN || opcode == ZOpcode.RETI || opcode == ZOpcode.JP case _ => false } } case class M6809AssemblyStatement(opcode: MOpcode.Value, addrMode: MAddrMode, expression: Expression, elidability: Elidability.Value) extends ExecutableStatement { override def getAllExpressions: List[Expression] = List(expression) override def isValidFunctionEnd: Boolean = opcode == MOpcode.RTS || opcode == MOpcode.JMP || opcode == MOpcode.BRA || opcode == MOpcode.RTI } case class IfStatement(condition: Expression, thenBranch: List[ExecutableStatement], elseBranch: List[ExecutableStatement]) extends CompoundStatement { override def getAllExpressions: List[Expression] = condition :: (thenBranch ++ elseBranch).flatMap(_.getAllExpressions) override def getChildStatements: Seq[Statement] = thenBranch ++ elseBranch override def flatMap(f: ExecutableStatement => Option[ExecutableStatement]): Option[ExecutableStatement] = { val t = thenBranch.map(f) val e = elseBranch.map(f) if (t.forall(_.isDefined) && e.forall(_.isDefined)) Some(IfStatement(condition, t.map(_.get), e.map(_.get)).pos(this.position)) else None } override def loopVariable: String = "-none-" override def isValidFunctionEnd: Boolean = thenBranch.lastOption.fold(false)(_.isValidFunctionEnd) && elseBranch.lastOption.fold(false)(_.isValidFunctionEnd) } case class WhileStatement(condition: Expression, body: List[ExecutableStatement], increment: List[ExecutableStatement], labels: Set[String] = Set("", "while")) extends CompoundStatement { override def getAllExpressions: List[Expression] = condition :: body.flatMap(_.getAllExpressions) override def getChildStatements: Seq[Statement] = body ++ increment override def flatMap(f: ExecutableStatement => Option[ExecutableStatement]): Option[ExecutableStatement] = { val b = body.map(f) val i = increment.map(f) if (b.forall(_.isDefined) && i.forall(_.isDefined)) Some(WhileStatement(condition, b.map(_.get), i.map(_.get), labels).pos(this.position)) else None } override def loopVariable: String = "-none-" } object ForDirection extends Enumeration { val To, Until, DownTo, ParallelTo, ParallelUntil = Value } case class ForStatement(variable: String, start: Expression, end: Expression, direction: ForDirection.Value, body: List[ExecutableStatement], extraIncrement: List[ExecutableStatement] = Nil) extends CompoundStatement { override def getAllExpressions: List[Expression] = VariableExpression(variable) :: start :: end :: (body.flatMap(_.getAllExpressions) ++ extraIncrement.flatMap(_.getAllExpressions)) override def getChildStatements: Seq[Statement] = body ++ extraIncrement override def flatMap(f: ExecutableStatement => Option[ExecutableStatement]): Option[ExecutableStatement] = { val b = body.map(f) val i = extraIncrement.map(f) if (b.forall(_.isDefined) && i.forall(_.isDefined)) Some(ForStatement(variable, start, end, direction, b.map(_.get), i.map(_.get)).pos(this.position)) else None } override def loopVariable: String = variable } case class MemsetStatement(start: Expression, size: Constant, value: Expression, direction: ForDirection.Value, original: Option[ForStatement]) extends CompoundStatement { if (original.isEmpty && direction != ForDirection.ParallelUntil) { throw new IllegalArgumentException } override def getAllExpressions: List[Expression] = List(start, value) ++ original.toList.flatMap(_.getAllExpressions) override def getChildStatements: Seq[Statement] = original.toList.flatMap(_.getChildStatements) override def flatMap(f: ExecutableStatement => Option[ExecutableStatement]): Option[ExecutableStatement] = // shouldn't ever yield None, as this is possible only in case of control-flow changing statements: Some(copy(original = original.flatMap(_.flatMap(f).asInstanceOf[Option[ForStatement]]))) override def loopVariable: String = original.fold("_none")(_.loopVariable) } case class ForEachStatement(variable: String, pointerVariable: Option[String], values: Either[Expression, List[Expression]], body: List[ExecutableStatement]) extends CompoundStatement { override def getAllExpressions: List[Expression] = VariableExpression(variable) :: (values.fold[List[Expression]](_ => Nil, identity) ++ body.flatMap(_.getAllExpressions)) override def getChildStatements: Seq[Statement] = body override def flatMap(f: ExecutableStatement => Option[ExecutableStatement]): Option[ExecutableStatement] = { val b = body.map(f) if (b.forall(_.isDefined)) Some(ForEachStatement(variable, pointerVariable, values, b.map(_.get)).pos(this.position)) else None } override def loopVariable: String = variable } case class DoWhileStatement(body: List[ExecutableStatement], increment: List[ExecutableStatement], condition: Expression, labels: Set[String] = Set("", "do")) extends CompoundStatement { override def getAllExpressions: List[Expression] = condition :: body.flatMap(_.getAllExpressions) override def getChildStatements: Seq[Statement] = body ++ increment override def flatMap(f: ExecutableStatement => Option[ExecutableStatement]): Option[ExecutableStatement] = { val b = body.map(f) val i = increment.map(f) if (b.forall(_.isDefined) && i.forall(_.isDefined)) Some(DoWhileStatement(b.map(_.get), i.map(_.get), condition, labels).pos(this.position)) else None } override def loopVariable: String = "-none-" } case class BreakStatement(label: String) extends ExecutableStatement { override def getAllExpressions: List[Expression] = Nil } case class ContinueStatement(label: String) extends ExecutableStatement { override def getAllExpressions: List[Expression] = Nil } object MosAssemblyStatement { def implied(opcode: Opcode.Value, elidability: Elidability.Value) = MosAssemblyStatement(opcode, AddrMode.Implied, LiteralExpression(0, 1), elidability) def nonexistent(opcode: Opcode.Value) = MosAssemblyStatement(opcode, AddrMode.DoesNotExist, LiteralExpression(0, 1), elidability = Elidability.Elidable) }