diff --git a/build.sbt b/build.sbt index d0af1f2..cb786a1 100644 --- a/build.sbt +++ b/build.sbt @@ -7,5 +7,4 @@ lazy val root = ) .withCats .withTesting - .withTestingBeta .withOrganizeImports diff --git a/project/ProjectPlugin.scala b/project/ProjectPlugin.scala index c656fec..a0c8409 100644 --- a/project/ProjectPlugin.scala +++ b/project/ProjectPlugin.scala @@ -15,12 +15,6 @@ object ProjectPlugin extends AutoPlugin { def withTesting: Project = p.settings(libraryDependencies += "org.scalatest" %% "scalatest" % "3.2.1" % "test") - - def withTestingBeta: Project = - p.settings( - libraryDependencies += "com.disneystreaming" %% "weaver-framework" % "0.4.2" % Test, - testFrameworks += new TestFramework("weaver.framework.TestFramework") - ) } } } diff --git a/src/main/scala/com/htmlism/mos6502/dsl/AsmDocumentContext.scala b/src/main/scala/com/htmlism/mos6502/dsl/AsmDocumentContext.scala index e6565f0..f47d17e 100644 --- a/src/main/scala/com/htmlism/mos6502/dsl/AsmDocumentContext.scala +++ b/src/main/scala/com/htmlism/mos6502/dsl/AsmDocumentContext.scala @@ -32,7 +32,7 @@ class DefinitionGroupContext { DefinitionGroup(s, xs.toList) } -case class Definition[A : Operand](name: String, x: A) +case class Definition[A: Operand](name: String, x: A) class AsmBlockContext { private val xs: ListBuffer[Statement] = @@ -40,4 +40,4 @@ class AsmBlockContext { def push(x: Statement): Unit = xs.append(x) -} \ No newline at end of file +} diff --git a/src/main/scala/com/htmlism/mos6502/dsl/BitField.scala b/src/main/scala/com/htmlism/mos6502/dsl/BitField.scala new file mode 100644 index 0000000..65ec0f4 --- /dev/null +++ b/src/main/scala/com/htmlism/mos6502/dsl/BitField.scala @@ -0,0 +1,9 @@ +package com.htmlism.mos6502.dsl + +import cats.data.NonEmptyList + +trait BitField[A] { + def comment: String + + def labels: NonEmptyList[String] +} diff --git a/src/main/scala/com/htmlism/mos6502/dsl/EnumAsm.scala b/src/main/scala/com/htmlism/mos6502/dsl/EnumAsm.scala new file mode 100644 index 0000000..54a9f89 --- /dev/null +++ b/src/main/scala/com/htmlism/mos6502/dsl/EnumAsm.scala @@ -0,0 +1,9 @@ +package com.htmlism.mos6502.dsl + +import cats.data.NonEmptyList + +trait EnumAsm[A] { + def comment: String + + def labels: NonEmptyList[String] +} diff --git a/src/main/scala/com/htmlism/mos6502/dsl/package.scala b/src/main/scala/com/htmlism/mos6502/dsl/package.scala index f1bdcfd..e150f2c 100644 --- a/src/main/scala/com/htmlism/mos6502/dsl/package.scala +++ b/src/main/scala/com/htmlism/mos6502/dsl/package.scala @@ -7,8 +7,7 @@ package object dsl { f(ctx) - ctx - .toDoc + ctx.toDoc } def group[A](s: String)(f: DefinitionGroupContext => A)(implicit ctx: AsmDocumentContext): A = { @@ -24,7 +23,51 @@ package object dsl { ret } - def define[A <: Address : Operand](name: String, x: A)(implicit ctx: DefinitionGroupContext): Definition[A] = { + def enum[A](implicit ctx: AsmDocumentContext, ev: EnumAsm[A]): Unit = { + val (_, xs) = + ev.labels + .foldLeft(0 -> List.empty[(String, Int)]) { + case ((next, acc), s) => + (next + 1) -> (acc :+ (s -> next)) + } + + val grp = + DefinitionGroup( + ev.comment, + xs + .map { + case (s, n) => + Definition(s, n) + } + ) + + ctx + .push(grp) + } + + def bitField[A](implicit ctx: AsmDocumentContext, ev: BitField[A]): Unit = { + val (_, xs) = + ev.labels + .foldLeft(1 -> List.empty[(String, Int)]) { + case ((next, acc), s) => + (next << 1) -> (acc :+ (s -> next)) + } + + val grp = + DefinitionGroup( + ev.comment, + xs + .map { + case (s, n) => + Definition(s, n) + } + ) + + ctx + .push(grp) + } + + def define[A <: Address: Operand](name: String, x: A)(implicit ctx: DefinitionGroupContext): Definition[A] = { val definition = Definition(name, x) diff --git a/src/test/scala/com/htmlism/mos6502/dsl/DslSpec.scala b/src/test/scala/com/htmlism/mos6502/dsl/DslSpec.scala index a41c81d..7a5bc4f 100644 --- a/src/test/scala/com/htmlism/mos6502/dsl/DslSpec.scala +++ b/src/test/scala/com/htmlism/mos6502/dsl/DslSpec.scala @@ -1,5 +1,6 @@ package com.htmlism.mos6502.dsl +import cats.data.NonEmptyList import org.scalatest.flatspec._ import org.scalatest.matchers._ @@ -9,54 +10,122 @@ class DslSpec extends AnyFlatSpec with should.Matchers { val doc = asmDoc { implicit ctx => group("snake things") { implicit g => - (define("snakeBodyStart", 0x12.z), - define("snakeDirection", 0x02.z), - define("snakeLength", 0x03.z)) + (define("snakeBodyStart", 0x12.z), define("snakeDirection", 0x02.z), define("snakeLength", 0x03.z)) } group("ASCII values of keys controlling the snake") { implicit g => - (define("ASCII_w", 0x77.z), - define("ASCII_a", 0x61.z), - define("ASCII_s", 0x73.z), - define("ASCII_d", 0x64.z)) + (define("ASCII_w", 0x77.z), define("ASCII_a", 0x61.z), define("ASCII_s", 0x73.z), define("ASCII_d", 0x64.z)) } group("System variables") { implicit g => - (define("sysRandom", 0xfe.z), - define("sysLastKey", 0xff.z)) + (define("sysRandom", 0xfe.z), define("sysLastKey", 0xff.z)) } group("constants test") { implicit g => - (constant("margin", 16), - constant("secret", 42)) + (constant("margin", 16), constant("secret", 42)) } () } - doc shouldEqual AsmDocument(List( - DefinitionGroup("snake things", List( - Definition("snakeBodyStart", 0x12.z), - Definition("snakeDirection", 0x02.z), - Definition("snakeLength", 0x03.z) - )), + doc shouldEqual AsmDocument( + List( + DefinitionGroup( + "snake things", + List( + Definition("snakeBodyStart", 0x12.z), + Definition("snakeDirection", 0x02.z), + Definition("snakeLength", 0x03.z) + ) + ), + DefinitionGroup( + "ASCII values of keys controlling the snake", + List( + Definition("ASCII_w", 0x77.z), + Definition("ASCII_a", 0x61.z), + Definition("ASCII_s", 0x73.z), + Definition("ASCII_d", 0x64.z) + ) + ), + DefinitionGroup( + "System variables", + List( + Definition("sysRandom", 0xfe.z), + Definition("sysLastKey", 0xff.z) + ) + ), + DefinitionGroup( + "constants test", + List( + Definition("margin", 16), + Definition("secret", 42) + ) + ) + ) + ) + } - DefinitionGroup("ASCII values of keys controlling the snake", List( - Definition("ASCII_w", 0x77.z), - Definition("ASCII_a", 0x61.z), - Definition("ASCII_s", 0x73.z), - Definition("ASCII_d", 0x64.z) - )), + "enum" should "compile" in { + val doc = + asmDoc { implicit ctx => + enum[Foo] + } - DefinitionGroup("System variables", List( - Definition("sysRandom", 0xfe.z), - Definition("sysLastKey", 0xff.z) - )), + doc shouldEqual AsmDocument( + List( + DefinitionGroup( + "foo as enum", + List( + Definition("courage", 0), + Definition("wisdom", 1), + Definition("power", 2) + ) + ) + ) + ) + } - DefinitionGroup("constants test", List( - Definition("margin", 16), - Definition("secret", 42) - )) - )) + "bit field" should "compile" in { + val doc = + asmDoc { implicit ctx => + bitField[Foo] + } + + doc shouldEqual AsmDocument( + List( + DefinitionGroup( + "foo as bit field", + List( + Definition("up", 0x01), + Definition("down", 0x02), + Definition("left", 0x04), + Definition("right", 0x08) + ) + ) + ) + ) } } + +class Foo + +object Foo { + implicit val enumFoo: EnumAsm[Foo] = + new EnumAsm[Foo] { + def comment: String = + "foo as enum" + + def labels: NonEmptyList[String] = + NonEmptyList.of("courage", "wisdom", "power") + } + + implicit val bitFieldFoo: BitField[Foo] = + new BitField[Foo] { + def comment: String = + "foo as bit field" + + def labels: NonEmptyList[String] = + NonEmptyList.of("up", "down", "left", "right") + + } +} diff --git a/src/test/scala/com/htmlism/mos6502/dsl/MySuite.scala b/src/test/scala/com/htmlism/mos6502/dsl/MySuite.scala deleted file mode 100644 index ded4a91..0000000 --- a/src/test/scala/com/htmlism/mos6502/dsl/MySuite.scala +++ /dev/null @@ -1,34 +0,0 @@ -package com.htmlism.mos6502.dsl - -import weaver.SimpleIOSuite -import cats.effect._ - -// Suites must be "objects" for them to be picked by the framework -object MySuite extends SimpleIOSuite { - - // A test for non-effectful (pure) functions - pureTest("hello pure") { - expect("hello".size == 6) - } - - val random = IO(java.util.UUID.randomUUID()) - - // A test for side-effecting functions - simpleTest("hello side-effects") { - for { - x <- random - y <- random - } yield expect(x != y) - } - - // A test with logs - loggedTest("hello logs") { log => - for { - x <- random - _ <- log.info(s"x : $x") - y <- random - _ <- log.info(s"y : $y") - } yield expect(x != y) - } - -}