diff --git a/src/main/scala/com/htmlism/mos6502/dsl/AsmDocumentContext.scala b/src/main/scala/com/htmlism/mos6502/dsl/AsmDocumentContext.scala new file mode 100644 index 0000000..648b71c --- /dev/null +++ b/src/main/scala/com/htmlism/mos6502/dsl/AsmDocumentContext.scala @@ -0,0 +1,43 @@ +package com.htmlism.mos6502.dsl + +import scala.collection.mutable.ListBuffer + +case class AsmDocument(xs: List[TopLevelAsmDocumentFragment]) + +class AsmDocumentContext { + private val xs: ListBuffer[TopLevelAsmDocumentFragment] = + ListBuffer() + + def push(x: TopLevelAsmDocumentFragment): Unit = + xs.append(x) + + def toDoc: AsmDocument = + AsmDocument(xs.toList) +} + +sealed trait TopLevelAsmDocumentFragment + +sealed trait AsmBlockFragment extends TopLevelAsmDocumentFragment + +case class DefineGroup(xs: List[Definition[_]]) extends TopLevelAsmDocumentFragment + +class DefineGroupContext { + private val xs: ListBuffer[Definition[_]] = + ListBuffer() + + def push(x: Definition[_]): Unit = + xs.append(x) + + def toGroup: DefineGroup = + DefineGroup(xs.toList) +} + +case class Definition[A : Operand](name: String, x: A) + +class AsmBlockContext { + private val xs: ListBuffer[Statement] = + ListBuffer() + + def push(x: Statement): Unit = + xs.append(x) +} \ No newline at end of file diff --git a/src/main/scala/com/htmlism/mos6502/dsl/DslDemo.scala b/src/main/scala/com/htmlism/mos6502/dsl/DslDemo.scala index 58a3b8f..fc4c684 100644 --- a/src/main/scala/com/htmlism/mos6502/dsl/DslDemo.scala +++ b/src/main/scala/com/htmlism/mos6502/dsl/DslDemo.scala @@ -49,14 +49,6 @@ object DslDemo extends App { println() println() } - - implicit class AddressOps(n: Int) { - def z: ZeroAddress = - ZeroAddress(n) - - def addr: GlobalAddress = - GlobalAddress(n) - } } object registers { diff --git a/src/main/scala/com/htmlism/mos6502/dsl/package.scala b/src/main/scala/com/htmlism/mos6502/dsl/package.scala new file mode 100644 index 0000000..ae118d9 --- /dev/null +++ b/src/main/scala/com/htmlism/mos6502/dsl/package.scala @@ -0,0 +1,35 @@ +package com.htmlism.mos6502 + +package object dsl { + def asmDoc(f: AsmDocumentContext => Unit): AsmDocument = { + val ctx: AsmDocumentContext = + new AsmDocumentContext + + f(ctx) + + ctx + .toDoc + } + + def group(f: DefineGroupContext => Unit)(implicit ctx: AsmDocumentContext): Unit = { + val g: DefineGroupContext = + new DefineGroupContext + + f(g) + + ctx + .push(g.toGroup) + } + + def define[A : Operand](name: String, x: A)(implicit ctx: DefineGroupContext): Unit = + ctx + .push(Definition(name, x)) + + implicit class AddressOps(n: Int) { + def z: ZeroAddress = + ZeroAddress(n) + + def addr: GlobalAddress = + GlobalAddress(n) + } +} diff --git a/src/test/scala/com/htmlism/mos6502/dsl/DslSpec.scala b/src/test/scala/com/htmlism/mos6502/dsl/DslSpec.scala new file mode 100644 index 0000000..2555e9d --- /dev/null +++ b/src/test/scala/com/htmlism/mos6502/dsl/DslSpec.scala @@ -0,0 +1,39 @@ +package com.htmlism.mos6502.dsl + +import org.scalatest.flatspec._ +import org.scalatest.matchers._ + +class DslSpec extends AnyFlatSpec with should.Matchers { + + "the dsl" should "compile" in { + val doc = + asmDoc { implicit ctx => + group { implicit g => + define("snakeBodyStart", 0x12.z) + define("snakeDirection", 0x02.z) + define("snakeLength", 0x03.z) + } + + group { implicit g => + define("ASCII_w", 0x77) + define("ASCII_a", 0x61) + define("ASCII_s", 0x73) + define("ASCII_d", 0x64) + } + } + + doc shouldEqual AsmDocument(List( + DefineGroup(List( + Definition("snakeBodyStart", 0x12.z), + Definition("snakeDirection", 0x02.z), + Definition("snakeLength", 0x03.z) + )), + DefineGroup(List( + Definition("ASCII_w", 0x77), + Definition("ASCII_a", 0x61), + Definition("ASCII_s", 0x73), + Definition("ASCII_d", 0x64) + )) + )) + } +} diff --git a/src/test/scala/com/htmlism/mos6502/dsl/MySuite.scala b/src/test/scala/com/htmlism/mos6502/dsl/MySuite.scala new file mode 100644 index 0000000..ded4a91 --- /dev/null +++ b/src/test/scala/com/htmlism/mos6502/dsl/MySuite.scala @@ -0,0 +1,34 @@ +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) + } + +}