diff --git a/nescant/src/main/scala/com/htmlism/nescant/GlobalAddress.scala b/nescant/src/main/scala/com/htmlism/nescant/GlobalAddress.scala
index d083ed1..5c8c05c 100644
--- a/nescant/src/main/scala/com/htmlism/nescant/GlobalAddress.scala
+++ b/nescant/src/main/scala/com/htmlism/nescant/GlobalAddress.scala
@@ -1,5 +1,11 @@
package com.htmlism.nescant
-object GlobalAddress {}
+object GlobalAddress {
+ implicit val sourceForGlobalAddress: Source[GlobalAddress] =
+ new Source[GlobalAddress] {}
+
+ implicit val sinkForGlobalAddress: Sink[GlobalAddress] =
+ new Sink[GlobalAddress] {}
+}
case class GlobalAddress(n: Int)
diff --git a/nescant/src/main/scala/com/htmlism/nescant/Operand.scala b/nescant/src/main/scala/com/htmlism/nescant/Operand.scala
index 9684c45..0042902 100644
--- a/nescant/src/main/scala/com/htmlism/nescant/Operand.scala
+++ b/nescant/src/main/scala/com/htmlism/nescant/Operand.scala
@@ -1,7 +1,10 @@
package com.htmlism.nescant
-sealed trait Operand
+trait Operand[A] {
+ def encode(x: A): String
+}
-case class LiteralOperand(value: String) extends Operand
-
-case class NamedOperand(name: String, value: String) extends Operand
+object Operand {
+ implicit val operandForInt: Operand[Int] =
+ _.toString
+}
diff --git a/nescant/src/main/scala/com/htmlism/nescant/ReadWriteLocation.scala b/nescant/src/main/scala/com/htmlism/nescant/ReadWriteLocation.scala
new file mode 100644
index 0000000..4e1aee3
--- /dev/null
+++ b/nescant/src/main/scala/com/htmlism/nescant/ReadWriteLocation.scala
@@ -0,0 +1,21 @@
+package com.htmlism.nescant
+
+/**
+ * @param name A name for this location, used to alias its address
+ *
+ * @tparam A The input type of the write and the output type of the read
+ */
+case class ReadWriteLocation[A](name: String, address: ZeroPageAddress)
+
+object ReadWriteLocation {
+ implicit def sourceForReadWriteLocation[A: Operand]: Source[ReadWriteLocation[A]] =
+ new Source[ReadWriteLocation[A]] {}
+
+ implicit def sinkForReadWriteLocation[A: Operand]: Sink[ReadWriteLocation[A]] =
+ new Sink[ReadWriteLocation[A]] {}
+
+ implicit def operandForReadWriteLocation[A: Operand]: Operand[ReadWriteLocation[A]] =
+ new Operand[ReadWriteLocation[A]] {
+ def encode(x: ReadWriteLocation[A]): String = ""
+ }
+}
diff --git a/nescant/src/main/scala/com/htmlism/nescant/Source.scala b/nescant/src/main/scala/com/htmlism/nescant/Source.scala
index 8592c88..2cf3ed5 100644
--- a/nescant/src/main/scala/com/htmlism/nescant/Source.scala
+++ b/nescant/src/main/scala/com/htmlism/nescant/Source.scala
@@ -3,6 +3,6 @@ package com.htmlism.nescant
trait Source[A]
object Source {
- // TODO int can be a source
- // TODO a volitile device can be a source
+ implicit val sourceForInt: Source[Int] =
+ new Source[Int] {}
}
diff --git a/nescant/src/main/scala/com/htmlism/nescant/VolatileDevice.scala b/nescant/src/main/scala/com/htmlism/nescant/VolatileDevice.scala
new file mode 100644
index 0000000..8822d0d
--- /dev/null
+++ b/nescant/src/main/scala/com/htmlism/nescant/VolatileDevice.scala
@@ -0,0 +1,22 @@
+package com.htmlism.nescant
+
+//import com.htmlism.mos6502.model._
+
+/**
+ * For a memory-mapped device that may return different values across multiple reads (e.g. a random number generator)
+ *
+ * @param name A name for this device, used to alias its address
+ *
+ * @tparam A The output type of the read
+ */
+case class VolatileDevice[A](name: String, address: ZeroPageAddress)
+
+object VolatileDevice {
+ implicit def sourceForVolatileDevice[A: Operand]: Source[VolatileDevice[A]] =
+ new Source[VolatileDevice[A]] {}
+
+ implicit def operandForVolatileDevice[A: Operand]: Operand[VolatileDevice[A]] =
+ new Operand[VolatileDevice[A]] {
+ def encode(x: VolatileDevice[A]): String = ""
+ }
+}
diff --git a/nescant/src/main/scala/com/htmlism/nescant/ZeroPageAddress.scala b/nescant/src/main/scala/com/htmlism/nescant/ZeroPageAddress.scala
index 9a4bf0d..79b1f62 100644
--- a/nescant/src/main/scala/com/htmlism/nescant/ZeroPageAddress.scala
+++ b/nescant/src/main/scala/com/htmlism/nescant/ZeroPageAddress.scala
@@ -1,5 +1,11 @@
package com.htmlism.nescant
-object ZeroPageAddress {}
+object ZeroPageAddress {
+ implicit val sourceForZeroPageAddress: Source[ZeroPageAddress] =
+ new Source[ZeroPageAddress] {}
+
+ implicit val sinkForZeroPageAddress: Sink[ZeroPageAddress] =
+ new Sink[ZeroPageAddress] {}
+}
case class ZeroPageAddress(n: Int)
diff --git a/nescant/src/main/scala/com/htmlism/nescant/dsl/package.scala b/nescant/src/main/scala/com/htmlism/nescant/dsl/package.scala
index 3ae5fa5..b61731e 100644
--- a/nescant/src/main/scala/com/htmlism/nescant/dsl/package.scala
+++ b/nescant/src/main/scala/com/htmlism/nescant/dsl/package.scala
@@ -8,4 +8,10 @@ package object dsl {
def g: GlobalAddress =
GlobalAddress(n)
}
+
+ implicit class SinkOps[A: Sink](x: A) {
+ def write[B: Source](src: B): Unit = {
+ val _ = src
+ }
+ }
}
diff --git a/nescant/src/test/scala/com/htmlism/nescant/dsl/SinkSpec.scala b/nescant/src/test/scala/com/htmlism/nescant/dsl/SinkSpec.scala
new file mode 100644
index 0000000..6bb1afc
--- /dev/null
+++ b/nescant/src/test/scala/com/htmlism/nescant/dsl/SinkSpec.scala
@@ -0,0 +1,21 @@
+package com.htmlism.nescant
+package dsl
+
+import org.scalatest.flatspec._
+import org.scalatest.matchers._
+
+class SinkSpec extends AnyFlatSpec with should.Matchers {
+ "A zero page address" should "be a sink" in {
+ 123.z.write(456)
+ }
+
+ "A global address" should "be a sink" in {
+ 123.g.write(456)
+ }
+
+ "A read write location" should "be a sink" in {
+ val sink = ReadWriteLocation[Int]("", 0.z)
+
+ sink.write(456)
+ }
+}
diff --git a/nescant/src/test/scala/com/htmlism/nescant/dsl/SourceSpec.scala b/nescant/src/test/scala/com/htmlism/nescant/dsl/SourceSpec.scala
new file mode 100644
index 0000000..c5ca46c
--- /dev/null
+++ b/nescant/src/test/scala/com/htmlism/nescant/dsl/SourceSpec.scala
@@ -0,0 +1,31 @@
+package com.htmlism.nescant
+package dsl
+
+import org.scalatest.flatspec._
+import org.scalatest.matchers._
+
+class SourceSpec extends AnyFlatSpec with should.Matchers {
+ "A number" should "be a source" in {
+ 123.z.write(456)
+ }
+
+ "A zero page address" should "be a source" in {
+ 123.z.write(456.z)
+ }
+
+ "A global address" should "be a source" in {
+ 123.z.write(456.g)
+ }
+
+ "A volatile device" should "be a source" in {
+ val src = VolatileDevice[Int]("", 0.z)
+
+ 123.z.write(src)
+ }
+
+ "A read write location" should "be a source" in {
+ val src = ReadWriteLocation[Int]("", 0.z)
+
+ 123.z.write(src)
+ }
+}