WiP! Value transition
This commit is contained in:
parent
a0355637d8
commit
1e107131d8
|
@ -1,2 +1,3 @@
|
|||
/nim.cfg
|
||||
/tests/*.run
|
||||
*.check
|
||||
*.run
|
||||
|
|
|
@ -13,6 +13,8 @@ import ./syndicate/protocols/dataspace
|
|||
|
||||
export actors, dataspaces, patterns
|
||||
|
||||
type Assertion* {.deprecated: "Assertion and Preserve[void] replaced by Value".} = Value
|
||||
|
||||
proc `!`*(typ: static typedesc): Pattern {.inline.} =
|
||||
patterns.dropType(typ)
|
||||
|
||||
|
@ -33,9 +35,9 @@ proc `??`*(pat: Pattern; bindings: openArray[(int, Pattern)]): Pattern {.inline.
|
|||
|
||||
type
|
||||
Observe* = dataspace.Observe
|
||||
PublishProc = proc (turn: var Turn; v: Assertion; h: Handle) {.closure, gcsafe.}
|
||||
PublishProc = proc (turn: var Turn; v: Value; h: Handle) {.closure, gcsafe.}
|
||||
RetractProc = proc (turn: var Turn; h: Handle) {.closure, gcsafe.}
|
||||
MessageProc = proc (turn: var Turn; v: Assertion) {.closure, gcsafe.}
|
||||
MessageProc = proc (turn: var Turn; v: Value) {.closure, gcsafe.}
|
||||
ClosureEntity = ref object of Entity
|
||||
publishImpl: PublishProc
|
||||
retractImpl: RetractProc
|
||||
|
@ -92,7 +94,7 @@ proc wrapPublishHandler(turn, handler: NimNode): NimNode =
|
|||
handlerSym = genSym(nskProc, "publish")
|
||||
bindingsSym = ident"bindings"
|
||||
quote do:
|
||||
proc `handlerSym`(`turn`: var Turn; `bindingsSym`: Assertion; `handleSym`: Handle) =
|
||||
proc `handlerSym`(`turn`: var Turn; `bindingsSym`: Value; `handleSym`: Handle) =
|
||||
`varSection`
|
||||
if fromPreserves(`valuesSym`, bindings):
|
||||
`publishBody`
|
||||
|
@ -104,7 +106,7 @@ proc wrapMessageHandler(turn, handler: NimNode): NimNode =
|
|||
handlerSym = genSym(nskProc, "message")
|
||||
bindingsSym = ident"bindings"
|
||||
quote do:
|
||||
proc `handlerSym`(`turn`: var Turn; `bindingsSym`: Assertion) =
|
||||
proc `handlerSym`(`turn`: var Turn; `bindingsSym`: Value) =
|
||||
`varSection`
|
||||
if fromPreserves(`valuesSym`, bindings):
|
||||
`body`
|
||||
|
@ -118,13 +120,13 @@ proc wrapDuringHandler(turn, entryBody, exitBody: NimNode): NimNode =
|
|||
duringSym = genSym(nskProc, "during")
|
||||
if exitBody.isNil:
|
||||
quote do:
|
||||
proc `duringSym`(`turn`: var Turn; `bindingsSym`: Assertion; `handleSym`: Handle): TurnAction =
|
||||
proc `duringSym`(`turn`: var Turn; `bindingsSym`: Value; `handleSym`: Handle): TurnAction =
|
||||
`varSection`
|
||||
if fromPreserves(`valuesSym`, `bindingsSym`):
|
||||
`publishBody`
|
||||
else:
|
||||
quote do:
|
||||
proc `duringSym`(`turn`: var Turn; `bindingsSym`: Assertion; `handleSym`: Handle): TurnAction =
|
||||
proc `duringSym`(`turn`: var Turn; `bindingsSym`: Value; `handleSym`: Handle): TurnAction =
|
||||
`varSection`
|
||||
if fromPreserves(`valuesSym`, `bindingsSym`):
|
||||
`publishBody`
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
# SPDX-FileCopyrightText: ☭ Emery Hemingway
|
||||
# SPDX-License-Identifier: Unlicense
|
||||
|
||||
import std/[asyncfutures, deques, hashes, monotimes, options, sets, tables, times]
|
||||
import std/[asyncfutures, hashes, monotimes, options, sets, tables, times]
|
||||
import preserves
|
||||
import ../syndicate/protocols/[protocol, sturdy]
|
||||
|
||||
|
@ -27,7 +27,6 @@ generateIdType(TurnId)
|
|||
|
||||
type
|
||||
Oid = sturdy.Oid
|
||||
Assertion* = Value
|
||||
Caveat = sturdy.Caveat
|
||||
Attenuation = seq[Caveat]
|
||||
Rewrite = sturdy.Rewrite
|
||||
|
@ -40,7 +39,7 @@ type
|
|||
Entity* = ref object of RootObj
|
||||
oid*: Oid # oid is how Entities are identified over the wire
|
||||
|
||||
Cap* {.unpreservable.} = ref object
|
||||
Cap* {.final.} = ref object of EmbeddedObj
|
||||
relay*: Facet
|
||||
target*: Entity
|
||||
attenuation*: Attenuation
|
||||
|
@ -166,7 +165,7 @@ proc enqueue(turn: var Turn; target: Facet; action: TurnAction) =
|
|||
|
||||
type Bindings = Table[Value, Value]
|
||||
|
||||
proc match(bindings: var Bindings; p: Pattern; v: Assertion): bool =
|
||||
proc match(bindings: var Bindings; p: Pattern; v: Value): bool =
|
||||
case p.orKind
|
||||
of PatternKind.Pdiscard: result = true
|
||||
of PatternKind.Patom:
|
||||
|
@ -220,18 +219,19 @@ proc match(bindings: var Bindings; p: Pattern; v: Assertion): bool =
|
|||
result = true
|
||||
break
|
||||
|
||||
proc match(p: Pattern; v: Assertion): Option[Bindings] =
|
||||
proc match(p: Pattern; v: Value): Option[Bindings] =
|
||||
var b: Bindings
|
||||
if match(b, p, v):
|
||||
result = some b
|
||||
|
||||
proc instantiate(t: Template; bindings: Bindings): Assertion =
|
||||
proc instantiate(t: Template; bindings: Bindings): Value =
|
||||
case t.orKind
|
||||
of TemplateKind.Tattenuate:
|
||||
let v = instantiate(t.tattenuate.template, bindings)
|
||||
if not v.isEmbedded:
|
||||
let cap = v.unembed(Cap)
|
||||
if cap.isNone:
|
||||
raise newException(ValueError, "Attempt to attenuate non-capability")
|
||||
result = embed(attenuate(v.embed, t.tattenuate.attenuation))
|
||||
result = attenuate(get cap, t.tattenuate.attenuation).embed
|
||||
of TemplateKind.TRef:
|
||||
let n = $t.tref.binding.int
|
||||
try: result = bindings[n.toPreserves]
|
||||
|
@ -254,12 +254,12 @@ proc instantiate(t: Template; bindings: Bindings): Assertion =
|
|||
for key, tt in t.tcompound.dict.entries:
|
||||
result[key] = instantiate(tt, bindings)
|
||||
|
||||
proc rewrite(r: Rewrite; v: Assertion): Assertion =
|
||||
proc rewrite(r: Rewrite; v: Value): Value =
|
||||
let bindings = match(r.pattern, v)
|
||||
if bindings.isSome:
|
||||
result = instantiate(r.template, get bindings)
|
||||
|
||||
proc examineAlternatives(cav: Caveat; v: Assertion): Assertion =
|
||||
proc examineAlternatives(cav: Caveat; v: Value): Value =
|
||||
case cav.orKind
|
||||
of CaveatKind.Rewrite:
|
||||
result = rewrite(cav.rewrite, v)
|
||||
|
@ -270,13 +270,13 @@ proc examineAlternatives(cav: Caveat; v: Assertion): Assertion =
|
|||
of CaveatKind.Reject: discard
|
||||
of CaveatKind.unknown: discard
|
||||
|
||||
proc runRewrites*(a: Attenuation; v: Assertion): Assertion =
|
||||
proc runRewrites*(a: Attenuation; v: Value): Value =
|
||||
result = v
|
||||
for stage in a:
|
||||
result = examineAlternatives(stage, result)
|
||||
if result.isFalse: break
|
||||
|
||||
proc publish(turn: var Turn; r: Cap; v: Assertion; h: Handle) =
|
||||
proc publish(turn: var Turn; r: Cap; v: Value; h: Handle) =
|
||||
var a = runRewrites(r.attenuation, v)
|
||||
if not a.isFalse:
|
||||
let e = OutboundAssertion(
|
||||
|
@ -298,7 +298,7 @@ proc publish(turn: var Turn; r: Cap; v: Assertion; h: Handle) =
|
|||
turn.desc.actions.add act
|
||||
|
||||
|
||||
proc publish*(turn: var Turn; r: Cap; a: Assertion): Handle =
|
||||
proc publish*(turn: var Turn; r: Cap; a: Value): Handle =
|
||||
result = turn.facet.nextHandle()
|
||||
publish(turn, r, a, result)
|
||||
|
||||
|
@ -316,7 +316,7 @@ proc retract*(turn: var Turn; h: Handle) =
|
|||
if turn.facet.outbound.pop(h, e):
|
||||
turn.retract(e)
|
||||
|
||||
proc message*(turn: var Turn; r: Cap; v: Assertion) =
|
||||
proc message*(turn: var Turn; r: Cap; v: Value) =
|
||||
var a = runRewrites(r.attenuation, v)
|
||||
if not a.isFalse:
|
||||
enqueue(turn, r.relay) do (turn: var Turn):
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
# SPDX-FileCopyrightText: ☭ 2022 Emery Hemingway
|
||||
# SPDX-License-Identifier: Unlicense
|
||||
|
||||
import std/[hashes, tables]
|
||||
import std/[hashes, options, tables]
|
||||
import preserves
|
||||
import ./actors, ./protocols/dataspace, ./skeletons
|
||||
|
||||
|
@ -18,18 +18,21 @@ type
|
|||
|
||||
method publish(ds: Dataspace; turn: var Turn; a: AssertionRef; h: Handle) {.gcsafe.} =
|
||||
if add(ds.index, turn, a.value):
|
||||
var obs: Observe
|
||||
if obs.fromPreserves(a.value):
|
||||
ds.index.add(turn, obs.pattern, obs.observer)
|
||||
var obs = a.value.preservesTo(Observe)
|
||||
if obs.isSome:
|
||||
var cap = obs.get.observer.unembed(Cap)
|
||||
if cap.isSome:
|
||||
ds.index.add(turn, obs.get.pattern, cap.get)
|
||||
ds.handleMap[h] = a.value
|
||||
|
||||
method retract(ds: Dataspace; turn: var Turn; h: Handle) {.gcsafe.} =
|
||||
let v = ds.handleMap[h]
|
||||
if remove(ds.index, turn, v):
|
||||
ds.handleMap.del h
|
||||
var obs: Observe
|
||||
if obs.fromPreserves v:
|
||||
ds.index.remove(turn, obs.pattern, obs.observer)
|
||||
var obs = v.preservesTo(Observe)
|
||||
if obs.isSome:
|
||||
var cap = obs.get.observer.unembed(Cap)
|
||||
ds.index.remove(turn, obs.get.pattern, cap.get)
|
||||
|
||||
method message(ds: Dataspace; turn: var Turn; a: AssertionRef) {.gcsafe.} =
|
||||
ds.index.deliverMessage(turn, a.value)
|
||||
|
|
|
@ -12,7 +12,7 @@ type
|
|||
Turn = actors.Turn
|
||||
|
||||
type
|
||||
DuringProc* = proc (turn: var Turn; a: Assertion; h: Handle): TurnAction {.gcsafe.}
|
||||
DuringProc* = proc (turn: var Turn; a: Value; h: Handle): TurnAction {.gcsafe.}
|
||||
DuringActionKind = enum null, dead, act
|
||||
DuringAction = object
|
||||
case kind: DuringActionKind
|
||||
|
@ -51,4 +51,4 @@ method retract(de: DuringEntity; turn: var Turn; h: Handle) =
|
|||
proc during*(cb: DuringProc): DuringEntity = DuringEntity(cb: cb)
|
||||
|
||||
proc observe*(turn: var Turn; ds: Cap; pat: Pattern; e: Entity): Handle =
|
||||
publish(turn, ds, Observe(pattern: pat, observer: newCap(turn, e)))
|
||||
publish(turn, ds, Observe(pattern: pat, observer: newCap(turn, e).embed))
|
||||
|
|
|
@ -57,7 +57,7 @@ proc drop*(): Pattern {.inline.} = Pattern(orKind: PatternKind.DDiscard)
|
|||
proc grab*(): Pattern {.inline.} = DBind(pattern: drop()).toPattern
|
||||
## Create a pattern to capture any value.
|
||||
|
||||
proc grab*[T](pr: Value): Pattern =
|
||||
proc grab*(pr: Value): Pattern =
|
||||
## Convert a `Preserve` value to a `Pattern`.
|
||||
runnableExamples:
|
||||
from std/unittest import check
|
||||
|
@ -66,42 +66,43 @@ proc grab*[T](pr: Value): Pattern =
|
|||
$(grab parsePreserves"""<foo "bar" #"00" [0 1 2.0] {maybe: #t} <_>>""") ==
|
||||
"""<rec foo [<lit "bar"> <lit #"00"> <arr [<lit 0> <lit 1> <lit 2.0>]> <dict {maybe: <lit #t>}> <_>]>"""
|
||||
|
||||
assert not pr.embedded
|
||||
case pr.kind
|
||||
of pkBoolean:
|
||||
AnyAtom(orKind: AnyAtomKind.`bool`, bool: pr.bool).toPattern
|
||||
of pkFloat:
|
||||
AnyAtom(orKind: AnyAtomKind.`float`, float: pr.float).toPattern
|
||||
of pkDouble:
|
||||
AnyAtom(orKind: AnyAtomKind.`double`, double: pr.double).toPattern
|
||||
of pkRegister:
|
||||
AnyAtom(orKind: AnyAtomKind.`int`, int: pr.register).toPattern
|
||||
of pkString:
|
||||
AnyAtom(orKind: AnyAtomKind.`string`, string: pr.string).toPattern
|
||||
of pkByteString:
|
||||
AnyAtom(orKind: AnyAtomKind.`bytes`, bytes: pr.bytes).toPattern
|
||||
of pkSymbol:
|
||||
AnyAtom(orKind: AnyAtomKind.`symbol`, symbol: pr.symbol).toPattern
|
||||
of pkRecord:
|
||||
if (pr.isRecord("_") and pr.arity == 0) or (pr.isRecord("bind") and pr.arity == 1):
|
||||
if pr.embedded: drop()
|
||||
else:
|
||||
case pr.kind
|
||||
of pkBoolean:
|
||||
AnyAtom(orKind: AnyAtomKind.`bool`, bool: pr.bool).toPattern
|
||||
of pkFloat:
|
||||
AnyAtom(orKind: AnyAtomKind.`float`, float: pr.float).toPattern
|
||||
of pkDouble:
|
||||
AnyAtom(orKind: AnyAtomKind.`double`, double: pr.double).toPattern
|
||||
of pkRegister:
|
||||
AnyAtom(orKind: AnyAtomKind.`int`, int: pr.register).toPattern
|
||||
of pkString:
|
||||
AnyAtom(orKind: AnyAtomKind.`string`, string: pr.string).toPattern
|
||||
of pkByteString:
|
||||
AnyAtom(orKind: AnyAtomKind.`bytes`, bytes: pr.bytes).toPattern
|
||||
of pkSymbol:
|
||||
AnyAtom(orKind: AnyAtomKind.`symbol`, symbol: pr.symbol).toPattern
|
||||
of pkRecord:
|
||||
if (pr.isRecord("_") and pr.arity == 0) or (pr.isRecord("bind") and pr.arity == 1):
|
||||
drop()
|
||||
else:
|
||||
DCompoundRec(
|
||||
label: pr.label,
|
||||
fields: map[Value, Pattern](pr.fields, grab)).toPattern
|
||||
of pkSequence:
|
||||
DCompoundArr(items: map(pr.sequence, grab)).toPattern
|
||||
of pkSet:
|
||||
raiseAssert "cannot construct a pattern over a set literal"
|
||||
of pkDictionary:
|
||||
var dict = DCompoundDict()
|
||||
for key, val in pr.pairs: dict.entries[key] = grab val
|
||||
dict.toPattern
|
||||
of pkEmbedded:
|
||||
# TODO: can patterns be constructed over embedded literals?
|
||||
drop()
|
||||
else:
|
||||
DCompoundRec(
|
||||
label: pr.label,
|
||||
fields: map[Value, Pattern](pr.fields, grab)).toPattern
|
||||
of pkSequence:
|
||||
DCompoundArr(items: map(pr.sequence, grab)).toPattern
|
||||
of pkSet:
|
||||
raiseAssert "cannot construct a pattern over a set literal"
|
||||
of pkDictionary:
|
||||
var dict = DCompoundDict()
|
||||
for key, val in pr.pairs: dict.entries[key] = grab val
|
||||
dict.toPattern
|
||||
of pkEmbedded:
|
||||
# TODO: can patterns be constructed over embedded literals?
|
||||
drop()
|
||||
else:
|
||||
raise newException(ValueError, "cannot generate a pattern for unhandled Value type")
|
||||
raise newException(ValueError, "cannot generate a pattern for unhandled Value type")
|
||||
|
||||
proc grab*[T](x: T): Pattern =
|
||||
## Construct a `Pattern` from value of type `T`.
|
||||
|
@ -382,12 +383,12 @@ func projectPaths*(v: Value; paths: Paths): Option[Captures] =
|
|||
else: return
|
||||
some res
|
||||
|
||||
func matches*(pat: Pattern; pr: Value): bool =
|
||||
proc matches*(pat: Pattern; pr: Value): bool =
|
||||
let analysis = analyse(pat)
|
||||
assert analysis.constPaths.len == analysis.constValues.len
|
||||
for i, path in analysis.constPaths:
|
||||
let v = step(pr, path)
|
||||
if v.isNone : return false
|
||||
if v.isNone: return false
|
||||
if analysis.constValues[i] != v.get: return false
|
||||
for path in analysis.capturePaths:
|
||||
if isNone step(pr, path): return false
|
||||
|
|
|
@ -5,7 +5,7 @@ import
|
|||
type
|
||||
Observe* {.preservesRecord: "Observe".} = object
|
||||
`pattern`*: dataspacePatterns.Pattern
|
||||
`observer`*: Value
|
||||
`observer`* {.preservesEmbedded.}: Value
|
||||
|
||||
proc `$`*(x: Observe): string =
|
||||
`$`(toPreserves(x))
|
||||
|
|
|
@ -5,7 +5,7 @@ import
|
|||
type
|
||||
Bind* {.preservesRecord: "bind".} = object
|
||||
`description`*: Description
|
||||
`target`*: Value
|
||||
`target`* {.preservesEmbedded.}: Value
|
||||
`observer`*: BindObserver
|
||||
|
||||
Route* {.preservesRecord: "route".} = object
|
||||
|
@ -26,12 +26,12 @@ type
|
|||
|
||||
TransportConnection* {.preservesRecord: "connect-transport".} = object
|
||||
`addr`*: Value
|
||||
`control`*: TransportControl
|
||||
`control`* {.preservesEmbedded.}: TransportControl
|
||||
`resolved`*: Resolved
|
||||
|
||||
Step* = Value
|
||||
ResolvedPathStep* {.preservesRecord: "path-step".} = object
|
||||
`origin`*: Resolve
|
||||
`origin`* {.preservesEmbedded.}: Resolve
|
||||
`pathStep`*: PathStep
|
||||
`resolved`*: Resolved
|
||||
|
||||
|
@ -57,12 +57,12 @@ type
|
|||
|
||||
Resolve* {.preservesRecord: "resolve".} = object
|
||||
`step`*: Step
|
||||
`observer`*: Resolved
|
||||
`observer`* {.preservesEmbedded.}: Resolved
|
||||
|
||||
ResolvedKind* {.pure.} = enum
|
||||
`accepted`, `Rejected`
|
||||
ResolvedAccepted* {.preservesRecord: "accepted".} = object
|
||||
`responderSession`*: Value
|
||||
`responderSession`* {.preservesEmbedded.}: Value
|
||||
|
||||
`Resolved`* {.preservesOr.} = object
|
||||
case orKind*: ResolvedKind
|
||||
|
@ -77,7 +77,7 @@ type
|
|||
ResolvePath* {.preservesRecord: "resolve-path".} = object
|
||||
`route`*: Route
|
||||
`addr`*: Value
|
||||
`control`*: TransportControl
|
||||
`control`* {.preservesEmbedded.}: TransportControl
|
||||
`resolved`*: Resolved
|
||||
|
||||
PathStep* = Value
|
||||
|
|
|
@ -23,8 +23,8 @@ type
|
|||
`message`*: string
|
||||
|
||||
StreamConnection* {.preservesRecord: "stream-connection".} = object
|
||||
`source`*: Source
|
||||
`sink`*: Sink
|
||||
`source`* {.preservesEmbedded.}: Source
|
||||
`sink`* {.preservesEmbedded.}: Sink
|
||||
`spec`*: Value
|
||||
|
||||
`LineMode`* {.preservesOr, pure.} = enum
|
||||
|
@ -32,7 +32,7 @@ type
|
|||
SourceKind* {.pure.} = enum
|
||||
`sink`, `StreamError`, `credit`
|
||||
SourceSink* {.preservesRecord: "sink".} = object
|
||||
`controller`*: Sink
|
||||
`controller`* {.preservesEmbedded.}: Sink
|
||||
|
||||
SourceCredit* {.preservesRecord: "credit".} = object
|
||||
`amount`*: CreditAmount
|
||||
|
@ -53,7 +53,7 @@ type
|
|||
SinkKind* {.pure.} = enum
|
||||
`source`, `StreamError`, `data`, `eof`
|
||||
SinkSource* {.preservesRecord: "source".} = object
|
||||
`controller`*: Source
|
||||
`controller`* {.preservesEmbedded.}: Source
|
||||
|
||||
SinkData* {.preservesRecord: "data".} = object
|
||||
`payload`*: Value
|
||||
|
|
|
@ -8,7 +8,7 @@ type
|
|||
`port`*: BiggestInt
|
||||
|
||||
TcpPeerInfo* {.preservesRecord: "tcp-peer".} = object
|
||||
`handle`*: Value
|
||||
`handle`* {.preservesEmbedded.}: Value
|
||||
`local`*: TcpLocal
|
||||
`remote`*: TcpRemote
|
||||
|
||||
|
|
|
@ -39,20 +39,6 @@ proc classOf(p: Pattern): Class =
|
|||
else:
|
||||
Class(kind: classNone)
|
||||
|
||||
proc `$`(class: Class): string =
|
||||
case class.kind
|
||||
of classNone: result = "null"
|
||||
of classRecord:
|
||||
result.add($class.label)
|
||||
result.add(':')
|
||||
result.add($class.arity)
|
||||
of classSequence:
|
||||
result.add('[')
|
||||
result.add($class.arity)
|
||||
result.add(']')
|
||||
of classDictionary:
|
||||
result = "{…:…}"
|
||||
|
||||
type
|
||||
EventKind = enum addedEvent, removedEvent, messageEvent
|
||||
|
||||
|
@ -78,9 +64,6 @@ func isEmpty(leaf: Leaf): bool =
|
|||
func isEmpty(cont: Continuation): bool =
|
||||
cont.cache.len == 0 and cont.leafMap.len == 0
|
||||
|
||||
proc `$`(x: Leaf|Continuation): string =
|
||||
cast[uint](x[].unsafeAddr).toHex
|
||||
|
||||
type
|
||||
ContinuationProc = proc (c: Continuation; v: Value) {.gcsafe.}
|
||||
LeafProc = proc (l: Leaf; v: Value) {.gcsafe.}
|
||||
|
@ -117,9 +100,6 @@ type
|
|||
func isEmpty(node: Node): bool =
|
||||
node.continuation.isEmpty and node.edges.len == 0
|
||||
|
||||
proc `$`(node: Node): string =
|
||||
$(cast[uint](unsafeAddr node[]) and 0xffffff)
|
||||
|
||||
type TermStack = seq[Value]
|
||||
|
||||
proc push(stack: TermStack; val: Value): Termstack =
|
||||
|
@ -288,7 +268,7 @@ proc adjustAssertion(index: var Index; turn: var Turn; outerValue: Value; delta:
|
|||
c.cache.incl(v)
|
||||
proc modLeaf(l: Leaf; v: Value) =
|
||||
l.cache.incl(v)
|
||||
proc modObserver(turn: var Turn; group: ObserverGroup; vs: seq[Value]) =
|
||||
proc modObserver(turn: var Turn; group: ObserverGroup; vs: seq[Value]) {.gcsafe.} =
|
||||
let change = group.cachedCaptures.change(vs, +1)
|
||||
if change == cdAbsentToPresent:
|
||||
for (observer, captureMap) in group.observers.pairs:
|
||||
|
@ -301,20 +281,21 @@ proc adjustAssertion(index: var Index; turn: var Turn; outerValue: Value; delta:
|
|||
c.cache.excl(v)
|
||||
proc modLeaf(l: Leaf; v: Value) =
|
||||
l.cache.excl(v)
|
||||
proc modObserver(turn: var Turn; group: ObserverGroup; vs: seq[Value]) =
|
||||
proc modObserver(turn: var Turn; group: ObserverGroup; vs: seq[Value]) {.gcsafe.} =
|
||||
if group.cachedCaptures.change(vs, -1) == cdPresentToAbsent:
|
||||
for (observer, captureMap) in group.observers.pairs:
|
||||
retract(observer.target, turn, captureMap[vs])
|
||||
captureMap.del(vs)
|
||||
var h: Handle
|
||||
if captureMap.take(vs, h):
|
||||
retract(observer.target, turn, h)
|
||||
modify(index.root, turn, outerValue, removedEvent, modContinuation, modLeaf, modObserver)
|
||||
else: discard
|
||||
|
||||
proc continuationNoop(c: Continuation; v: Value) = discard
|
||||
proc leafNoop(l: Leaf; v: Value) = discard
|
||||
|
||||
proc add*(index: var Index; turn: var Turn; v: Assertion): bool =
|
||||
proc add*(index: var Index; turn: var Turn; v: Value): bool =
|
||||
adjustAssertion(index, turn, v, +1)
|
||||
proc remove*(index: var Index; turn: var Turn; v: Assertion): bool =
|
||||
proc remove*(index: var Index; turn: var Turn; v: Value): bool =
|
||||
adjustAssertion(index, turn, v, -1)
|
||||
|
||||
proc deliverMessage*(index: var Index; turn: var Turn; v: Value) =
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
# Package
|
||||
|
||||
version = "20231231"
|
||||
version = "20240101"
|
||||
author = "Emery Hemingway"
|
||||
description = "Syndicated actors for conversational concurrency"
|
||||
license = "Unlicense"
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
# SPDX-FileCopyrightText: ☭ Emery Hemingway
|
||||
# SPDX-License-Identifier: Unlicense
|
||||
|
||||
import std/[tables, unittest]
|
||||
import std/[options, tables, unittest]
|
||||
|
||||
import preserves, syndicate
|
||||
|
||||
|
@ -9,14 +9,14 @@ import ./test_schema
|
|||
|
||||
test "patterns":
|
||||
let
|
||||
observerPat = ?Observe(pattern: !Foo) ?? {0: grab()}
|
||||
pat = ?Observe(pattern: !Foo) ?? {0: grab()}
|
||||
text = """<rec Observe [<rec rec [<lit foo> <arr [<bind <_>> <_> <_>]>]> <_>]>"""
|
||||
check($observerPat == text)
|
||||
check($pat == text)
|
||||
|
||||
let
|
||||
worte = @["alles", "in", "ordnung"]
|
||||
observer = Observe(pattern: inject(?:Foo, { 0: ?worte })).toPreserves
|
||||
have = capture(observerPat, observer).toPreserves.unpackLiterals
|
||||
have = capture(pat, observer).toPreserves.unpackLiterals
|
||||
want = [worte.toPreserves].toPreserves
|
||||
check(have == want)
|
||||
|
||||
|
@ -52,7 +52,40 @@ type
|
|||
|
||||
test "literals":
|
||||
const txt = """<rec request [<lit 3> <dict {artists: <lit "kyyyyym"> date: <lit "2023-10-14"> notes: <lit "Lots of stuff"> title: <lit "Domes show">}> <dict {front-cover: <dict {name: <lit "ADULT_TIME_Glielmi.jpg"> path: <lit "/tmp/652adad1b3d2b666dcc8d857.jpg"> size: <lit 255614> type: <lit "image/jpeg">}>}>]>"""
|
||||
var pr = parsePreserves(txt, Cap)
|
||||
var pr = parsePreserves(txt)
|
||||
|
||||
var capture: Literal[Request]
|
||||
check capture.fromPreserves(pr)
|
||||
|
||||
suite "captures":
|
||||
for txt in [
|
||||
"#f",
|
||||
"#t",
|
||||
"0",
|
||||
"-1",
|
||||
"foo",
|
||||
"<foo>",
|
||||
"[0, 1, 2]",
|
||||
]:
|
||||
test txt:
|
||||
let
|
||||
pr = parsePreserves txt
|
||||
pat = grab pr
|
||||
checkpoint $pat
|
||||
check pat.matches pr
|
||||
|
||||
suite "later-than":
|
||||
let
|
||||
obsA = parsePreserves"""<Observe <rec later-than [<lit 1704113731.419243>]> #!#f>"""
|
||||
obsB = parsePreserves"""<Observe <rec Observe [<rec rec [<lit later-than> <arr [<rec lit [<bind <_>>]>]>]> <_>]> #!#f>"""
|
||||
patA = """<rec later-than [<lit 1704113731.419243>]>""".parsePreserves.preservesTo(Pattern).get
|
||||
patB = """<rec Observe [<rec rec [<lit later-than> <arr [<rec lit [<bind <_>>]>]>]> <_>]>""".parsePreserves.preservesTo(Pattern).get
|
||||
|
||||
patC = grab obsA
|
||||
|
||||
test $patC:
|
||||
check patC.matches obsA
|
||||
|
||||
test $patB:
|
||||
checkpoint $obsA
|
||||
check patB.matches obsA
|
||||
|
|
Loading…
Reference in New Issue