~ehmry/syndicate-nim

cfd863fbf998931f2f6734d5231e72e9d0a06699 — Emery Hemingway a month ago 6fd02e7
Test schema code generator
M src/syndicate/drivers/timers.nim => src/syndicate/drivers/timers.nim +8 -4
@@ 4,7 4,11 @@ import std/[asyncdispatch, monotimes, times]
import preserves, preserves/records
import syndicate

const TimeLaterThan* = RecordClass(label: symbol"TimeLaterThan", arity: 1)
type TimeLaterThan* {.record: "TimeLaterThan".} = object
    `deadline`*: Monotime

proc prsTimeLaterThan*(deadline: Preserve | Monotime): Preserve =
  initRecord(symbol("TimeLaterThan"), deadline)

proc toPreserveHook*(time: Monotime): Preserve =
  time.ticks.toPreserve


@@ 17,15 21,15 @@ proc fromPreserveHook*(mt: var Monotime; p: Preserve): bool =
syndicate timerDriver:

  spawn "timer":
    during(Observe % (TimeLaterThan % `?*`)) do (deadline: MonoTime):
    during(Observe % (prsTimeLaterThan(`?*`))) do (deadline: MonoTime):
      let
        now = getMonoTime()
        period = inMilliseconds(deadline - now)
      if period > 0:
        getCurrentFacet().beginExternalTask()
        addTimer(period.int, oneshot = true) do (fd: AsyncFD) -> bool:
          react: asserting(TimeLaterThan % deadline)
          react: asserting: prsTimeLaterThan(deadline)
          getCurrentFacet().endExternalTask()
          true
      else:
        react: asserting(TimeLaterThan % deadline)
        react: asserting: prsTimeLaterThan(deadline)

A tests/box_and_client.nim => tests/box_and_client.nim +17 -0
@@ 0,0 1,17 @@

## Date of generation: 2021-08-28 10:14
import
  std/typetraits, preserves

type
  BoxState* {.record: "box-state".} = object ## ``<box-state @value int>``
    `value`*: BiggestInt

  SetBox* {.record: "set-box".} = object ## ``<set-box @value int>``
    `value`*: BiggestInt

proc prsBoxState*(value: Preserve | BiggestInt): Preserve =
  initRecord(symbol("box-state"), value)

proc prsSetBox*(value: Preserve | BiggestInt): Preserve =
  initRecord(symbol("set-box"), value)

A tests/box_and_client.prs => tests/box_and_client.prs +5 -0
@@ 0,0 1,5 @@
version 1.

BoxState = <box-state @value int> .

SetBox = <set-box @value int> .

M tests/test_box_and_client.nim => tests/test_box_and_client.nim +10 -11
@@ 4,14 4,13 @@ import syndicate/assertions, syndicate/dataspaces, syndicate/events, syndicate/s
import preserves, preserves/records
import asyncdispatch, tables, options

import ./box_and_client

const N = 100000

const
  `?_` = init(Discard)
  `?$` = init(Capture, `?_`)
  BoxState = RecordClass(label: symbol"BoxState", arity: 1)
  SetBox = RecordClass(label: symbol"SetBox", arity: 1)


proc boot(facet: Facet) =



@@ 20,7 19,7 @@ proc boot(facet: Facet) =

    facet.addEndpoint do (facet: Facet) -> EndpointSpec:
      # echo "recomputing published BoxState ", facet.fields.value
      result.assertion = BoxState.init(value.getPreserve)
      result.assertion = prsBoxState(value.getPreserve)

    facet.addDataflow do (facet: Facet):
      # echo "box dataflow saw new value ", facet.fields.value


@@ 29,36 28,36 @@ proc boot(facet: Facet) =
          echo "terminated box root facet"

    facet.addEndpoint do (facet: Facet) -> EndpointSpec:
      const a = SetBox.init(`?$`)
      const a = prsSetBox(`?$`)
      result.analysis = some analyzeAssertion(a)
      proc cb(facet: Facet; vs: seq[Value]) =
        facet.scheduleScript do (facet: Facet):
          value.set(vs[0])
          # echo "box updated value ", vs[0]
      result.callback = facet.wrap(messageEvent, cb)
      result.assertion = Observe.init(SetBox.init(`?$`))
      result.assertion = Observe.init(prsSetBox(`?$`))

  facet.spawn("client") do (facet: Facet):

    facet.addEndpoint do (facet: Facet) -> EndpointSpec:
      const a = BoxState.init(`?$`)
      const a = prsBoxState(`?$`)
      result.analysis = some analyzeAssertion(a)
      proc cb(facet: Facet; vs: seq[Value]) =
        facet.scheduleScript do (facet: Facet):
          let v = SetBox.init(vs[0].int.succ.toPreserve)
          let v = prsSetBox(vs[0].int.succ.toPreserve)
          # echo "client sending ", v
          facet.send(v)
      result.callback = facet.wrap(addedEvent, cb)
      result.assertion = Observe.init(BoxState.init(`?$`))
      result.assertion = Observe.init(prsBoxState(`?$`))

    facet.addEndpoint do (facet: Facet) -> EndpointSpec:
      const a = BoxState.init(`?_`)
      const a = prsBoxState(`?_`)
      result.analysis = some analyzeAssertion(a)
      proc cb(facet: Facet; vs: seq[Value]) =
        facet.scheduleScript do (facet: Facet):
          echo "box gone"
      result.callback = facet.wrap(removedEvent, cb)
      result.assertion = Observe.init(BoxState.init(`?_`))
      result.assertion = Observe.init(prsBoxState(`?_`))

  facet.actor.dataspace.ground.addStopHandler do (_: Dataspace):
    echo "stopping box-and-client"

M tests/test_dsl.nim => tests/test_dsl.nim +7 -9
@@ 4,18 4,16 @@ import asyncdispatch
import preserves, preserves/records
import syndicate

const
  BoxState = RecordClass(label: symbol"box-state", arity: 1)
  SetBox = RecordClass(label: symbol"set-box", arity: 1)
import ./box_and_client

syndicate testDsl:

  spawn "box":
    field(currentValue, int, 0)
    asserting(BoxState.init currentValue.get)
    field(currentValue, BiggestInt, 0)
    asserting prsBoxState(currentValue.get)
    stopIf currentValue.get == 10:
      echo "box: terminating"
    onMessage(SetBox % `?*`) do (newValue: int):
    onMessage(prsSetBox(`?*`)) do (newValue: int):
      # The SetBox message is unpacked to `newValue: int`
      echo "box: taking on new value ", newValue
      currentValue.set(newValue)


@@ 23,10 21,10 @@ syndicate testDsl:
  spawn "client":
    #stopIf retracted(observe(SetBox, _)):
    #  echo "client: box has gone"
    onAsserted(BoxState % `?*`) do (v: int):
    onAsserted(prsBoxState(`?*`)) do (v: BiggestInt):
      echo "client: learned that box's value is now ", v
      send(SetBox % v.succ)
    onRetracted(BoxState % `?_`) do (_):
      send(prsSetBox(v.succ))
    onRetracted(prsBoxState(`?_`)) do (_):
      echo "client: box state disappeared"
    onStop:
      quit(0) # Quit explicitly rather than let the dispatcher run empty.

M tests/test_timer.nim => tests/test_timer.nim +1 -1
@@ 13,7 13,7 @@ syndicate plainTimerDemo:
    field(deadline, MonoTime, getMonoTime())
    field(count, int, 0)

    onAsserted(TimeLaterThan % deadline.get) do ():
    onAsserted(prsTimeLaterThan(deadline.get)) do ():
      echo "TimeLaterThan ticked for deadline ", deadline.get
      count.set(count.get.succ)
      if count.get < 5: