Parameterize Preserve type
This commit is contained in:
parent
cfd863fbf9
commit
a5830a4a07
|
@ -1,14 +1,11 @@
|
||||||
# SPDX-License-Identifier: ISC
|
# SPDX-FileCopyrightText: ☭ 2021 Emery Hemingway
|
||||||
|
# SPDX-License-Identifier: Unlicense
|
||||||
|
|
||||||
import std/[asyncdispatch, macros, options]
|
import std/[asyncdispatch, macros, options]
|
||||||
import preserves, preserves/records
|
import preserves, preserves/records
|
||||||
import syndicate/[assertions, dataspaces, events, skeletons]
|
import syndicate/[assertions, dataspaces, events, skeletons]
|
||||||
|
|
||||||
export preserves.`%`
|
|
||||||
export preserves.fromPreserve
|
export preserves.fromPreserve
|
||||||
export records.init
|
|
||||||
export assertions.`?_`
|
|
||||||
export assertions.`?*`
|
|
||||||
export assertions.Observe
|
export assertions.Observe
|
||||||
export dataspaces.Facet
|
export dataspaces.Facet
|
||||||
export dataspaces.FieldId
|
export dataspaces.FieldId
|
||||||
|
@ -128,7 +125,7 @@ proc onEvent(event: EventKind, pattern, handler: NimNode): NimNode =
|
||||||
proc getCurrentFacet(): Facet {.inject, used.} = facet
|
proc getCurrentFacet(): Facet {.inject, used.} = facet
|
||||||
`handler`
|
`handler`
|
||||||
let a = `pattern`
|
let a = `pattern`
|
||||||
result.assertion = Observe.init(a)
|
result.assertion = observe(a)
|
||||||
result.analysis = some(analyzeAssertion(a))
|
result.analysis = some(analyzeAssertion(a))
|
||||||
result.callback = wrap(facet, EventKind(`event`), `handlerSym`)
|
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``.
|
## Execute a Syndicate ``body`` using the ``Facet`` at ``f``.
|
||||||
runnableExamples:
|
runnableExamples:
|
||||||
import preserves, preserves/records
|
import preserves, preserves/records
|
||||||
type Foo = ref object
|
type Foo {.record: "foo".} = ref object
|
||||||
facet: Facet
|
facet: Facet
|
||||||
i: int
|
i: int
|
||||||
proc incAndAssert(foo: Foo) =
|
proc incAndAssert(foo: Foo) =
|
||||||
inc(foo.i)
|
inc(foo.i)
|
||||||
withFacet foo.facet:
|
withFacet foo.facet:
|
||||||
react: assert: initRecord("Foo", %foo.i)
|
react: assert: foo
|
||||||
proc getCurrentFacet(): Facet {.inject, used.} = f
|
proc getCurrentFacet(): Facet {.inject, used.} = f
|
||||||
body
|
body
|
||||||
|
|
||||||
|
@ -219,3 +216,13 @@ type BootProc* = proc (facet: Facet) {.gcsafe.}
|
||||||
template boot*(module: BootProc) =
|
template boot*(module: BootProc) =
|
||||||
mixin getCurrentFacet
|
mixin getCurrentFacet
|
||||||
module(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())
|
||||||
|
|
|
@ -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
|
type
|
||||||
Discard* = RecordClass(label: symbol"discard", arity: 0)
|
Discard* {.record: "discard", pure.} = object
|
||||||
Capture* = RecordClass(label: symbol"capture", arity: 1)
|
discard
|
||||||
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)
|
|
||||||
|
|
||||||
`?_`* = initRecord("discard")
|
Capture* {.record: "capture", pure.} = object
|
||||||
`?*`* = Capture % `?_`
|
_: Discard
|
||||||
|
|
||||||
|
Observe* {.record: "observe", pure.} = object
|
||||||
|
pattern: Preserve
|
||||||
|
|
||||||
|
proc observe*[T](x: T): Preserve =
|
||||||
|
Observe(pattern: x.toPreserve).toPreserve
|
||||||
|
|
||||||
proc captureCount*(pattern: Preserve): int =
|
proc captureCount*(pattern: Preserve): int =
|
||||||
if Capture.isClassOf pattern:
|
if pattern.preserveTo(Capture).isSome:
|
||||||
result = 1
|
result = 1
|
||||||
else:
|
else:
|
||||||
for e in pattern.items:
|
for e in pattern.items:
|
||||||
result.inc captureCount(e)
|
result.inc captureCount(e)
|
||||||
|
|
||||||
|
when isMainModule:
|
||||||
|
let a = observe(`?*`)
|
||||||
|
assert($toPreserve(a) == "<capture <discard>>")
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
# SPDX-License-Identifier: ISC
|
# SPDX-FileCopyrightText: ☭ 2021 Emery Hemingway
|
||||||
|
# SPDX-License-Identifier: Unlicense
|
||||||
|
|
||||||
import ./bags, ./dataflow, ./events, ./skeletons
|
import ./bags, ./dataflow, ./events, ./skeletons
|
||||||
import preserves
|
import preserves
|
||||||
|
@ -70,7 +71,7 @@ type
|
||||||
|
|
||||||
Field* = object of RootObj
|
Field* = object of RootObj
|
||||||
id*: FieldId
|
id*: FieldId
|
||||||
Fields* = seq[Preserve]
|
Fields* = seq[Value]
|
||||||
# TODO: compile-time tuples
|
# TODO: compile-time tuples
|
||||||
|
|
||||||
Turn = object
|
Turn = object
|
||||||
|
@ -403,7 +404,7 @@ proc initActivationAction(script: ActivationScript; name: string): Action =
|
||||||
ds.activations.add(script)
|
ds.activations.add(script)
|
||||||
proc boot(root: Facet) =
|
proc boot(root: Facet) =
|
||||||
root.addStartScript(script)
|
root.addStartScript(script)
|
||||||
ds.addActor(name, boot, Preserve(kind: pkSet), actor)
|
ds.addActor(name, boot, Value(kind: pkSet), actor)
|
||||||
Action(impl: impl, kind: activationAction)
|
Action(impl: impl, kind: activationAction)
|
||||||
|
|
||||||
proc activate(facet; name: string; script: ActivationScript) =
|
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
|
let fieldOff = facet.fields.high
|
||||||
proc set(f: DistinctField; x: T) {.used.} =
|
proc set(f: DistinctField; x: T) {.used.} =
|
||||||
facet.actor.dataspace.dataflow.recordDamage(f.id)
|
facet.actor.dataspace.dataflow.recordDamage(f.id)
|
||||||
facet.fields[fieldOff] = toPreserve[T](x)
|
facet.fields[fieldOff] = toPreserve(x)
|
||||||
proc set(f: DistinctField; x: Preserve) {.used.} =
|
proc set(f: DistinctField; x: Value) {.used.} =
|
||||||
facet.actor.dataspace.dataflow.recordDamage(f.id)
|
facet.actor.dataspace.dataflow.recordDamage(f.id)
|
||||||
facet.fields[fieldOff] = x
|
facet.fields[fieldOff] = x
|
||||||
proc get(f: DistinctField): T {.used.} =
|
proc get(f: DistinctField): T {.used.} =
|
||||||
facet.actor.dataspace.dataflow.recordObservation(f.id)
|
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)
|
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.actor.dataspace.dataflow.recordObservation(f.id)
|
||||||
facet.fields[fieldOff]
|
facet.fields[fieldOff]
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
import std/[asyncdispatch, monotimes, times]
|
import std/[asyncdispatch, monotimes, times]
|
||||||
import preserves, preserves/records
|
import preserves, preserves/records
|
||||||
import syndicate
|
import syndicate, syndicate/assertions
|
||||||
|
|
||||||
type TimeLaterThan* {.record: "TimeLaterThan".} = object
|
type TimeLaterThan* {.record: "TimeLaterThan".} = object
|
||||||
`deadline`*: Monotime
|
`deadline`*: Monotime
|
||||||
|
@ -21,7 +21,7 @@ proc fromPreserveHook*(mt: var Monotime; p: Preserve): bool =
|
||||||
syndicate timerDriver:
|
syndicate timerDriver:
|
||||||
|
|
||||||
spawn "timer":
|
spawn "timer":
|
||||||
during(Observe % (prsTimeLaterThan(`?*`))) do (deadline: MonoTime):
|
during(observe(prsTimeLaterThan(?deadline))) do (deadline: MonoTime):
|
||||||
let
|
let
|
||||||
now = getMonoTime()
|
now = getMonoTime()
|
||||||
period = inMilliseconds(deadline - now)
|
period = inMilliseconds(deadline - now)
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
# SPDX-License-Identifier: ISC
|
# SPDX-FileCopyrightText: ☭ 2021 Emery Hemingway
|
||||||
|
# SPDX-License-Identifier: Unlicense
|
||||||
|
|
||||||
import ./assertions, ./bags, ./events
|
import ./assertions, ./bags, ./events
|
||||||
import preserves, preserves/records
|
import preserves, preserves/records
|
||||||
|
@ -36,9 +37,9 @@ proc projectPaths(v: Value; paths: seq[Path]): seq[Value] =
|
||||||
proc analyzeAssertion*(a: Value): Analysis =
|
proc analyzeAssertion*(a: Value): Analysis =
|
||||||
var path: Path
|
var path: Path
|
||||||
proc walk(analysis: var Analysis; a: Value): Skeleton[Shape] =
|
proc walk(analysis: var Analysis; a: Value): Skeleton[Shape] =
|
||||||
if Discard.isClassOf a:
|
if a.preserveTo(Discard).isSome:
|
||||||
discard
|
discard
|
||||||
elif Capture.isClassOf a:
|
elif a.preserveTo(Capture).isSome:
|
||||||
analysis.capturePaths.add(path)
|
analysis.capturePaths.add(path)
|
||||||
result = walk(analysis, a.fields[0])
|
result = walk(analysis, a.fields[0])
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -9,4 +9,4 @@ srcDir = "src"
|
||||||
|
|
||||||
# Dependencies
|
# Dependencies
|
||||||
|
|
||||||
requires "nim >= 1.4.8", "preserves >= 0.3.0"
|
requires "nim >= 1.4.8", "preserves >= 1.0.0"
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
|
|
||||||
## Date of generation: 2021-08-28 10:14
|
## Date of generation: 2021-09-01 13:32
|
||||||
import
|
import
|
||||||
std/typetraits, preserves
|
std/typetraits, preserves
|
||||||
|
|
||||||
type
|
type
|
||||||
|
EmbeddedType = void
|
||||||
BoxState* {.record: "box-state".} = object ## ``<box-state @value int>``
|
BoxState* {.record: "box-state".} = object ## ``<box-state @value int>``
|
||||||
`value`*: BiggestInt
|
`value`*: BiggestInt
|
||||||
|
|
||||||
|
@ -11,7 +12,9 @@ type
|
||||||
`value`*: BiggestInt
|
`value`*: BiggestInt
|
||||||
|
|
||||||
proc prsBoxState*(value: Preserve | BiggestInt): Preserve =
|
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 =
|
proc prsSetBox*(value: Preserve | BiggestInt): Preserve =
|
||||||
initRecord(symbol("set-box"), value)
|
initRecord[EmbeddedType](symbol("set-box", EmbeddedType),
|
||||||
|
toPreserve(value, EmbeddedType))
|
||||||
|
|
|
@ -8,9 +8,9 @@ import ./box_and_client
|
||||||
|
|
||||||
const N = 100000
|
const N = 100000
|
||||||
|
|
||||||
const
|
let
|
||||||
`?_` = init(Discard)
|
`?_` = Discard().toPreserve
|
||||||
`?$` = init(Capture, `?_`)
|
`?$` = Capture().toPreserve
|
||||||
|
|
||||||
proc boot(facet: Facet) =
|
proc boot(facet: Facet) =
|
||||||
|
|
||||||
|
@ -28,19 +28,19 @@ proc boot(facet: Facet) =
|
||||||
echo "terminated box root facet"
|
echo "terminated box root facet"
|
||||||
|
|
||||||
facet.addEndpoint do (facet: Facet) -> EndpointSpec:
|
facet.addEndpoint do (facet: Facet) -> EndpointSpec:
|
||||||
const a = prsSetBox(`?$`)
|
let a = prsSetBox(`?$`)
|
||||||
result.analysis = some analyzeAssertion(a)
|
result.analysis = some analyzeAssertion(a)
|
||||||
proc cb(facet: Facet; vs: seq[Value]) =
|
proc cb(facet: Facet; vs: seq[Value]) =
|
||||||
facet.scheduleScript do (facet: Facet):
|
facet.scheduleScript do (facet: Facet):
|
||||||
value.set(vs[0])
|
value.set(vs[0])
|
||||||
# echo "box updated value ", vs[0]
|
# echo "box updated value ", vs[0]
|
||||||
result.callback = facet.wrap(messageEvent, cb)
|
result.callback = facet.wrap(messageEvent, cb)
|
||||||
result.assertion = Observe.init(prsSetBox(`?$`))
|
result.assertion = observe(prsSetBox(`?$`))
|
||||||
|
|
||||||
facet.spawn("client") do (facet: Facet):
|
facet.spawn("client") do (facet: Facet):
|
||||||
|
|
||||||
facet.addEndpoint do (facet: Facet) -> EndpointSpec:
|
facet.addEndpoint do (facet: Facet) -> EndpointSpec:
|
||||||
const a = prsBoxState(`?$`)
|
let a = prsBoxState(`?$`)
|
||||||
result.analysis = some analyzeAssertion(a)
|
result.analysis = some analyzeAssertion(a)
|
||||||
proc cb(facet: Facet; vs: seq[Value]) =
|
proc cb(facet: Facet; vs: seq[Value]) =
|
||||||
facet.scheduleScript do (facet: Facet):
|
facet.scheduleScript do (facet: Facet):
|
||||||
|
@ -48,16 +48,16 @@ proc boot(facet: Facet) =
|
||||||
# echo "client sending ", v
|
# echo "client sending ", v
|
||||||
facet.send(v)
|
facet.send(v)
|
||||||
result.callback = facet.wrap(addedEvent, cb)
|
result.callback = facet.wrap(addedEvent, cb)
|
||||||
result.assertion = Observe.init(prsBoxState(`?$`))
|
result.assertion = observe(prsBoxState(`?$`))
|
||||||
|
|
||||||
facet.addEndpoint do (facet: Facet) -> EndpointSpec:
|
facet.addEndpoint do (facet: Facet) -> EndpointSpec:
|
||||||
const a = prsBoxState(`?_`)
|
let a = prsBoxState(`?_`)
|
||||||
result.analysis = some analyzeAssertion(a)
|
result.analysis = some analyzeAssertion(a)
|
||||||
proc cb(facet: Facet; vs: seq[Value]) =
|
proc cb(facet: Facet; vs: seq[Value]) =
|
||||||
facet.scheduleScript do (facet: Facet):
|
facet.scheduleScript do (facet: Facet):
|
||||||
echo "box gone"
|
echo "box gone"
|
||||||
result.callback = facet.wrap(removedEvent, cb)
|
result.callback = facet.wrap(removedEvent, cb)
|
||||||
result.assertion = Observe.init(prsBoxState(`?_`))
|
result.assertion = observe(prsBoxState(`?_`))
|
||||||
|
|
||||||
facet.actor.dataspace.ground.addStopHandler do (_: Dataspace):
|
facet.actor.dataspace.ground.addStopHandler do (_: Dataspace):
|
||||||
echo "stopping box-and-client"
|
echo "stopping box-and-client"
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
# SPDX-License-Identifier: ISC
|
# SPDX-FileCopyrightText: ☭ 2021 Emery Hemingway
|
||||||
|
# SPDX-License-Identifier: Unlicense
|
||||||
|
|
||||||
import asyncdispatch
|
import std/asyncdispatch
|
||||||
import preserves, preserves/records
|
import preserves
|
||||||
import syndicate
|
import syndicate
|
||||||
|
|
||||||
import ./box_and_client
|
import ./box_and_client
|
||||||
|
@ -13,7 +14,7 @@ syndicate testDsl:
|
||||||
asserting prsBoxState(currentValue.get)
|
asserting prsBoxState(currentValue.get)
|
||||||
stopIf currentValue.get == 10:
|
stopIf currentValue.get == 10:
|
||||||
echo "box: terminating"
|
echo "box: terminating"
|
||||||
onMessage(prsSetBox(`?*`)) do (newValue: int):
|
onMessage(prsSetBox(?newValue)) do (newValue: int):
|
||||||
# The SetBox message is unpacked to `newValue: int`
|
# The SetBox message is unpacked to `newValue: int`
|
||||||
echo "box: taking on new value ", newValue
|
echo "box: taking on new value ", newValue
|
||||||
currentValue.set(newValue)
|
currentValue.set(newValue)
|
||||||
|
@ -21,10 +22,10 @@ syndicate testDsl:
|
||||||
spawn "client":
|
spawn "client":
|
||||||
#stopIf retracted(observe(SetBox, _)):
|
#stopIf retracted(observe(SetBox, _)):
|
||||||
# echo "client: box has gone"
|
# 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
|
echo "client: learned that box's value is now ", v
|
||||||
send(prsSetBox(v.succ))
|
send(prsSetBox(v.succ))
|
||||||
onRetracted(prsBoxState(`?_`)) do (_):
|
onRetracted(prsBoxState(?_)) do (_):
|
||||||
echo "client: box state disappeared"
|
echo "client: box state disappeared"
|
||||||
onStop:
|
onStop:
|
||||||
quit(0) # Quit explicitly rather than let the dispatcher run empty.
|
quit(0) # Quit explicitly rather than let the dispatcher run empty.
|
||||||
|
|
Loading…
Reference in New Issue