Parameterize Preserve type

This commit is contained in:
Emery Hemingway 2021-09-01 13:44:28 +02:00
parent cfd863fbf9
commit a5830a4a07
9 changed files with 72 additions and 51 deletions

View File

@ -1,14 +1,11 @@
# SPDX-License-Identifier: ISC
# SPDX-FileCopyrightText: ☭ 2021 Emery Hemingway
# SPDX-License-Identifier: Unlicense
import std/[asyncdispatch, macros, options]
import preserves, preserves/records
import syndicate/[assertions, dataspaces, events, skeletons]
export preserves.`%`
export preserves.fromPreserve
export records.init
export assertions.`?_`
export assertions.`?*`
export assertions.Observe
export dataspaces.Facet
export dataspaces.FieldId
@ -128,7 +125,7 @@ proc onEvent(event: EventKind, pattern, handler: NimNode): NimNode =
proc getCurrentFacet(): Facet {.inject, used.} = facet
`handler`
let a = `pattern`
result.assertion = Observe.init(a)
result.assertion = observe(a)
result.analysis = some(analyzeAssertion(a))
result.callback = wrap(facet, EventKind(`event`), `handlerSym`)
@ -197,13 +194,13 @@ template withFacet*(f: Facet; body: untyped): untyped =
## Execute a Syndicate ``body`` using the ``Facet`` at ``f``.
runnableExamples:
import preserves, preserves/records
type Foo = ref object
type Foo {.record: "foo".} = ref object
facet: Facet
i: int
proc incAndAssert(foo: Foo) =
inc(foo.i)
withFacet foo.facet:
react: assert: initRecord("Foo", %foo.i)
react: assert: foo
proc getCurrentFacet(): Facet {.inject, used.} = f
body
@ -219,3 +216,13 @@ type BootProc* = proc (facet: Facet) {.gcsafe.}
template boot*(module: BootProc) =
mixin getCurrentFacet
module(getCurrentFacet())
macro `?`*(x: untyped): untyped =
## Sugar for generating Syndicate patterns.
## `?_` is a pattern that matches but discards arbitrary
## values and `?` combined with any other identifier is
## a match and capture.
if eqIdent(x, "_"):
quote: toPreserve(Discard())
else:
quote: toPreserve(Capture())

View File

@ -1,21 +1,29 @@
# SPDX-License-Identifier: ISC
# SPDX-FileCopyrightText: ☭ 2021 Emery Hemingway
# SPDX-License-Identifier: Unlicense
import preserves, preserves/records
import std/options
import preserves
const
Discard* = RecordClass(label: symbol"discard", arity: 0)
Capture* = RecordClass(label: symbol"capture", arity: 1)
Observe* = RecordClass(label: symbol"observe", arity: 1)
#Inbound* = RecordClass(label: symbol"inbound", arity: 1)
#Outbound* = RecordClass(label: symbol"outbound", arity: 1)
#Instance* = RecordClass(label: symbol"instance", arity: 1)
type
Discard* {.record: "discard", pure.} = object
discard
`?_`* = initRecord("discard")
`?*`* = Capture % `?_`
Capture* {.record: "capture", pure.} = object
_: Discard
Observe* {.record: "observe", pure.} = object
pattern: Preserve
proc observe*[T](x: T): Preserve =
Observe(pattern: x.toPreserve).toPreserve
proc captureCount*(pattern: Preserve): int =
if Capture.isClassOf pattern:
if pattern.preserveTo(Capture).isSome:
result = 1
else:
for e in pattern.items:
result.inc captureCount(e)
when isMainModule:
let a = observe(`?*`)
assert($toPreserve(a) == "<capture <discard>>")

View File

@ -1,4 +1,5 @@
# SPDX-License-Identifier: ISC
# SPDX-FileCopyrightText: ☭ 2021 Emery Hemingway
# SPDX-License-Identifier: Unlicense
import ./bags, ./dataflow, ./events, ./skeletons
import preserves
@ -70,7 +71,7 @@ type
Field* = object of RootObj
id*: FieldId
Fields* = seq[Preserve]
Fields* = seq[Value]
# TODO: compile-time tuples
Turn = object
@ -403,7 +404,7 @@ proc initActivationAction(script: ActivationScript; name: string): Action =
ds.activations.add(script)
proc boot(root: Facet) =
root.addStartScript(script)
ds.addActor(name, boot, Preserve(kind: pkSet), actor)
ds.addActor(name, boot, Value(kind: pkSet), actor)
Action(impl: impl, kind: activationAction)
proc activate(facet; name: string; script: ActivationScript) =
@ -547,15 +548,15 @@ template declareField*(facet: Facet; F: untyped; T: typedesc; initial: T): untyp
let fieldOff = facet.fields.high
proc set(f: DistinctField; x: T) {.used.} =
facet.actor.dataspace.dataflow.recordDamage(f.id)
facet.fields[fieldOff] = toPreserve[T](x)
proc set(f: DistinctField; x: Preserve) {.used.} =
facet.fields[fieldOff] = toPreserve(x)
proc set(f: DistinctField; x: Value) {.used.} =
facet.actor.dataspace.dataflow.recordDamage(f.id)
facet.fields[fieldOff] = x
proc get(f: DistinctField): T {.used.} =
facet.actor.dataspace.dataflow.recordObservation(f.id)
if not fromPreserve[T](result, facet.fields[fieldOff]):
if not fromPreserve(result, facet.fields[fieldOff]):
raise newException(ValueError, "cannot convert field " & $F & " to " & $T)
proc getPreserve(f: DistinctField): Preserve {.used.} =
proc getPreserve(f: DistinctField): Value {.used.} =
facet.actor.dataspace.dataflow.recordObservation(f.id)
facet.fields[fieldOff]

View File

@ -2,7 +2,7 @@
import std/[asyncdispatch, monotimes, times]
import preserves, preserves/records
import syndicate
import syndicate, syndicate/assertions
type TimeLaterThan* {.record: "TimeLaterThan".} = object
`deadline`*: Monotime
@ -21,7 +21,7 @@ proc fromPreserveHook*(mt: var Monotime; p: Preserve): bool =
syndicate timerDriver:
spawn "timer":
during(Observe % (prsTimeLaterThan(`?*`))) do (deadline: MonoTime):
during(observe(prsTimeLaterThan(?deadline))) do (deadline: MonoTime):
let
now = getMonoTime()
period = inMilliseconds(deadline - now)

View File

@ -1,4 +1,5 @@
# SPDX-License-Identifier: ISC
# SPDX-FileCopyrightText: ☭ 2021 Emery Hemingway
# SPDX-License-Identifier: Unlicense
import ./assertions, ./bags, ./events
import preserves, preserves/records
@ -36,9 +37,9 @@ proc projectPaths(v: Value; paths: seq[Path]): seq[Value] =
proc analyzeAssertion*(a: Value): Analysis =
var path: Path
proc walk(analysis: var Analysis; a: Value): Skeleton[Shape] =
if Discard.isClassOf a:
if a.preserveTo(Discard).isSome:
discard
elif Capture.isClassOf a:
elif a.preserveTo(Capture).isSome:
analysis.capturePaths.add(path)
result = walk(analysis, a.fields[0])
else:

View File

@ -9,4 +9,4 @@ srcDir = "src"
# Dependencies
requires "nim >= 1.4.8", "preserves >= 0.3.0"
requires "nim >= 1.4.8", "preserves >= 1.0.0"

View File

@ -1,9 +1,10 @@
## Date of generation: 2021-08-28 10:14
## Date of generation: 2021-09-01 13:32
import
std/typetraits, preserves
type
EmbeddedType = void
BoxState* {.record: "box-state".} = object ## ``<box-state @value int>``
`value`*: BiggestInt
@ -11,7 +12,9 @@ type
`value`*: BiggestInt
proc prsBoxState*(value: Preserve | BiggestInt): Preserve =
initRecord(symbol("box-state"), value)
initRecord[EmbeddedType](symbol("box-state", EmbeddedType),
toPreserve(value, EmbeddedType))
proc prsSetBox*(value: Preserve | BiggestInt): Preserve =
initRecord(symbol("set-box"), value)
initRecord[EmbeddedType](symbol("set-box", EmbeddedType),
toPreserve(value, EmbeddedType))

View File

@ -8,9 +8,9 @@ import ./box_and_client
const N = 100000
const
`?_` = init(Discard)
`?$` = init(Capture, `?_`)
let
`?_` = Discard().toPreserve
`?$` = Capture().toPreserve
proc boot(facet: Facet) =
@ -28,19 +28,19 @@ proc boot(facet: Facet) =
echo "terminated box root facet"
facet.addEndpoint do (facet: Facet) -> EndpointSpec:
const a = prsSetBox(`?$`)
let 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(prsSetBox(`?$`))
result.assertion = observe(prsSetBox(`?$`))
facet.spawn("client") do (facet: Facet):
facet.addEndpoint do (facet: Facet) -> EndpointSpec:
const a = prsBoxState(`?$`)
let a = prsBoxState(`?$`)
result.analysis = some analyzeAssertion(a)
proc cb(facet: Facet; vs: seq[Value]) =
facet.scheduleScript do (facet: Facet):
@ -48,16 +48,16 @@ proc boot(facet: Facet) =
# echo "client sending ", v
facet.send(v)
result.callback = facet.wrap(addedEvent, cb)
result.assertion = Observe.init(prsBoxState(`?$`))
result.assertion = observe(prsBoxState(`?$`))
facet.addEndpoint do (facet: Facet) -> EndpointSpec:
const a = prsBoxState(`?_`)
let 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(prsBoxState(`?_`))
result.assertion = observe(prsBoxState(`?_`))
facet.actor.dataspace.ground.addStopHandler do (_: Dataspace):
echo "stopping box-and-client"

View File

@ -1,7 +1,8 @@
# SPDX-License-Identifier: ISC
# SPDX-FileCopyrightText: ☭ 2021 Emery Hemingway
# SPDX-License-Identifier: Unlicense
import asyncdispatch
import preserves, preserves/records
import std/asyncdispatch
import preserves
import syndicate
import ./box_and_client
@ -13,7 +14,7 @@ syndicate testDsl:
asserting prsBoxState(currentValue.get)
stopIf currentValue.get == 10:
echo "box: terminating"
onMessage(prsSetBox(`?*`)) do (newValue: int):
onMessage(prsSetBox(?newValue)) do (newValue: int):
# The SetBox message is unpacked to `newValue: int`
echo "box: taking on new value ", newValue
currentValue.set(newValue)
@ -21,10 +22,10 @@ syndicate testDsl:
spawn "client":
#stopIf retracted(observe(SetBox, _)):
# echo "client: box has gone"
onAsserted(prsBoxState(`?*`)) do (v: BiggestInt):
onAsserted(prsBoxState(?v)) do (v: BiggestInt):
echo "client: learned that box's value is now ", v
send(prsSetBox(v.succ))
onRetracted(prsBoxState(`?_`)) do (_):
onRetracted(prsBoxState(?_)) do (_):
echo "client: box state disappeared"
onStop:
quit(0) # Quit explicitly rather than let the dispatcher run empty.