6502-opcodes/firepower-core/src/main/scala/com/htmlism/firepower/core/AsmBlock.scala

121 lines
3.2 KiB
Scala
Raw Normal View History

2022-12-05 22:19:50 +00:00
package com.htmlism.firepower.core
2022-12-04 21:49:05 +00:00
sealed trait AsmBlock
2022-12-05 22:19:50 +00:00
object AsmBlock:
case class CommentBlock(xs: List[String]) extends AsmBlock
2022-12-04 21:49:05 +00:00
2022-12-05 22:19:50 +00:00
object CommentBlock:
def fromMultiline(s: String): CommentBlock =
CommentBlock(s.split("\\n").toList)
2022-12-04 21:56:03 +00:00
case class DefinesBlock(xs: List[(String, Int)]) extends AsmBlock
2022-12-06 20:38:39 +00:00
2022-12-05 22:19:50 +00:00
case class NamedCodeBlock(name: String, comment: Option[String], intents: List[AsmBlock.Intent]) extends AsmBlock
case class AnonymousCodeBlock(intents: List[AsmBlock.Intent]) extends AsmBlock
2022-12-04 21:56:03 +00:00
def interFlatMap[A, B](xs: List[A])(x: List[B], f: A => List[B]): List[B] =
xs match
case head :: tail =>
f(head) ::: tail.flatMap(a => x ::: f(a))
case Nil =>
Nil
2022-12-04 22:23:42 +00:00
def toComment(s: String): String =
"; " + s
def withIndent(s: String): String =
" " + s
2022-12-06 21:53:40 +00:00
def toHex(n: Int): String =
val hex =
if (n < 16 * 16)
String.format("%1$02x", n)
else if (n < 16 * 16 * 16)
String.format("%1$03x", n)
else
String.format("%1$04x", n)
"$" + hex.toUpperCase
def toLines(xs: AsmBlock): List[String] =
2022-12-04 21:49:05 +00:00
xs match
case CommentBlock(ys) =>
ys.map(toComment)
2022-12-04 21:49:05 +00:00
2022-12-06 20:38:39 +00:00
case DefinesBlock(kvs) =>
2022-12-06 20:47:00 +00:00
val maximumLength =
kvs
.map(_._1.length)
.max
2022-12-06 20:38:39 +00:00
kvs
.map { case (k, v) =>
2022-12-06 21:53:40 +00:00
String.format(s"define %-${maximumLength}s ${toHex(v)}", k)
2022-12-06 20:38:39 +00:00
}
2022-12-04 22:30:36 +00:00
case NamedCodeBlock(label, oComment, intents) =>
2022-12-04 22:23:42 +00:00
val headerParagraph =
List(label + ":") ++ oComment.map(toComment).map(withIndent).toList
2022-12-04 22:23:42 +00:00
val intentParagraphs =
2022-12-04 23:26:53 +00:00
intents.map(Intent.toLines)
2022-12-04 22:23:42 +00:00
2022-12-04 23:26:53 +00:00
interFlatMap(headerParagraph :: intentParagraphs)(List(""), identity)
2022-12-04 21:56:03 +00:00
2022-12-04 22:30:36 +00:00
case AnonymousCodeBlock(intents) =>
interFlatMap(intents)(List(""), Intent.toLines)
2022-12-04 22:15:29 +00:00
case class Intent(label: Option[String], instructions: List[Intent.Instruction])
object Intent:
2022-12-06 22:55:51 +00:00
sealed trait Instruction:
def length: Int
object Instruction:
case class One(code: String, operand: String, comment: Option[String]) extends Instruction:
def length: Int =
operand.length + 4
case class Zero(code: String, comment: Option[String]) extends Instruction:
def length: Int =
0
2022-12-04 22:15:29 +00:00
def toLines(x: Intent): List[String] =
2022-12-06 22:20:30 +00:00
val comment =
x.label.map(toComment).map(withIndent).toList
val maximumLength =
x
.instructions
2022-12-06 22:55:51 +00:00
.map(_.length)
2022-12-06 22:20:30 +00:00
.max
val instructions =
x
.instructions
2022-12-06 22:55:51 +00:00
.map {
case Instruction.Zero(code, oComment) =>
oComment match
case Some(c) =>
String.format(s"%-${maximumLength}s", code) + " " + toComment(c)
case None =>
code
case Instruction.One(code, operand, oComment) =>
val leftSlug =
code + " " + operand
oComment match
case Some(c) =>
String.format(s"%-${maximumLength}s", leftSlug) + " " + toComment(c)
2022-12-06 22:20:30 +00:00
2022-12-06 22:55:51 +00:00
case None =>
leftSlug
2022-12-06 22:20:30 +00:00
}
.map(withIndent)
comment ++ instructions