Rewrite skeletons for new patterns
This commit is contained in:
parent
d4442438fa
commit
231928f243
|
@ -5,8 +5,6 @@ import std/[hashes, lists, options, sets, tables]
|
|||
import preserves
|
||||
import ./actors, ./bags, ./patterns
|
||||
|
||||
template trace(args: varargs[untyped]) = stderr.writeLine(args)
|
||||
|
||||
type
|
||||
Value = Preserve[Ref]
|
||||
Path = seq[Value]
|
||||
|
@ -19,10 +17,10 @@ proc projectPath(v: Value; path: Path): Value =
|
|||
proc projectPaths(v: Value; paths: seq[Path]): seq[Value] =
|
||||
result.setLen(paths.len)
|
||||
for i, path in paths: result[i] = projectPath(v, path)
|
||||
trace "projected ", v, " by paths ", paths, " to ", result
|
||||
|
||||
type Class = distinct string
|
||||
|
||||
proc `$`(cls: Class): string {.borrow.}
|
||||
proc hash(cls: Class): Hash {.borrow.}
|
||||
proc `==`(x, y: Class): bool {.borrow.}
|
||||
|
||||
|
@ -45,9 +43,7 @@ proc classOf*(p: Pattern): Class =
|
|||
result = Class "{}"
|
||||
|
||||
proc step(value, index: Value): Value =
|
||||
try: result = value[index]
|
||||
except KeyError, ValueError:
|
||||
trace "step failed, ", index, " not in ", value
|
||||
result = value[index]
|
||||
|
||||
type
|
||||
EventKind = enum addedEvent, removedEvent, messageEvent
|
||||
|
@ -72,102 +68,107 @@ type
|
|||
edges: Table[Selector, TableRef[Class, Node]]
|
||||
continuation: Continuation
|
||||
|
||||
using
|
||||
continuation: Continuation
|
||||
leaf: Leaf
|
||||
node: Node
|
||||
from strutils import toHex
|
||||
proc `$`(node: Node): string =
|
||||
toHex(cast[ByteAddress](unsafeAddr node[]), 5)
|
||||
|
||||
proc isEmpty(leaf): bool =
|
||||
func isEmpty(leaf: Leaf): bool =
|
||||
leaf.cachedAssertions.len == 0 and leaf.observerGroups.len == 0
|
||||
|
||||
type
|
||||
ContinuationProc = proc (c: Continuation; v: Value) {.gcsafe.}
|
||||
LeafProc = proc (l: Leaf; v: Value) {.gcsafe.}
|
||||
ObserverProc = proc (turn: var Turn; h: ObserverGroup; vs: seq[Value]) {.gcsafe.}
|
||||
ContinuationProc = proc (c: Continuation; v: Value)
|
||||
LeafProc = proc (l: Leaf; v: Value)
|
||||
ObserverProc = proc (turn: var Turn; group: ObserverGroup; vs: seq[Value])
|
||||
|
||||
proc modify(node; turn: var Turn; operation: EventKind; outerValue: Value;
|
||||
mCont: ContinuationProc; mLeaf: LeafProc; mObserverGroup: ObserverProc) =
|
||||
trace "modify node with outerValue ", outerValue
|
||||
type TermStack = SinglyLinkedList[Value]
|
||||
|
||||
proc walkNode(turn: var Turn; node; termStack: SinglyLinkedList[Value]) =
|
||||
mCont(node.continuation, outerValue)
|
||||
if node.continuation.leafMap.len == 0:
|
||||
trace "node.continuation leafMap is empty"
|
||||
for (constPaths, constValMap) in node.continuation.leafMap.pairs:
|
||||
trace "got entry in node.continuation.leafMap for ", constPaths
|
||||
let constValues = projectPaths(outerValue, constPaths)
|
||||
var leaf = constValMap.getOrDefault(constValues)
|
||||
if leaf.isNil and operation == addedEvent:
|
||||
proc push(stack: TermStack; val: Value): Termstack =
|
||||
result = stack
|
||||
prepend(result, val)
|
||||
|
||||
proc pop(stack: TermStack; n: int): TermStack =
|
||||
result = stack
|
||||
var n = n
|
||||
while n > 0:
|
||||
result.remove(result.head)
|
||||
assert not stack.head.isNil, "popped too far"
|
||||
dec n
|
||||
|
||||
proc top(stack: TermStack): Value =
|
||||
assert not stack.head.isNil, "stack is empty"
|
||||
stack.head.value
|
||||
|
||||
|
||||
proc modify(node: Node; turn: var Turn; outerValue: Value; event: EventKind;
|
||||
modCont: ContinuationProc; modLeaf: LeafProc; modObs: ObserverProc) =
|
||||
|
||||
proc walk(turn: var Turn; cont: Continuation; outerValue: Value; event: EventKind) =
|
||||
modCont(cont, outerValue)
|
||||
for constPaths, constValMap in cont.leafMap.pairs:
|
||||
let constVals = projectPaths(outerValue, constPaths)
|
||||
var leaf = constValMap.getOrDefault(constVals)
|
||||
if leaf.isNil: # and event == addedEvent:
|
||||
new leaf
|
||||
constValMap[constValues] = leaf
|
||||
constValMap[constVals] = leaf
|
||||
if not leaf.isNil:
|
||||
mLeaf(leaf, outerValue)
|
||||
for (capturePaths, observerGroup) in leaf.observerGroups.pairs:
|
||||
mObserverGroup(turn, observerGroup, projectPaths(outerValue, capturePaths))
|
||||
if operation == removedEvent and leaf.isEmpty:
|
||||
constValMap.del(constValues)
|
||||
if constValues.len == 0:
|
||||
node.continuation.leafMap.del(constPaths)
|
||||
for (selector, table) in node.edges.pairs:
|
||||
var nextStack = termStack
|
||||
for _ in 1..selector.popCount:
|
||||
nextStack.head = nextStack.head.next
|
||||
trace "step ", nextStack.head.value, " with ", selector.index
|
||||
modLeaf(leaf, outerValue)
|
||||
for capturePaths, observerGroup in leaf.observerGroups.pairs:
|
||||
modObs(turn, observerGroup, projectPaths(outerValue, capturePaths))
|
||||
# TODO: cleanup dead leaves
|
||||
|
||||
proc walk(node: Node; turn: var Turn; outerValue: Value; event: EventKind; termStack: TermStack) =
|
||||
walk(turn, node.continuation, outerValue, event)
|
||||
for selector, table in node.edges:
|
||||
let
|
||||
nextValue = step(nextStack.head.value, selector.index)
|
||||
nextStack = pop(termStack, selector.popCount)
|
||||
nextValue = step(nextStack.top, selector.index)
|
||||
nextClass = classOf nextValue
|
||||
if nextClass != Class"":
|
||||
let nextNode = table.getOrDefault(nextClass)
|
||||
if not nextNode.isNil:
|
||||
nextStack.prepend(nextValue)
|
||||
walkNode(turn, nextNode, nextStack)
|
||||
walk(nextNode, turn, outerValue, event, push(nextStack, nextValue))
|
||||
|
||||
var stack: SinglyLinkedList[Value]
|
||||
stack.prepend(outerValue)
|
||||
walkNode(turn, node, stack)
|
||||
var stack: TermStack
|
||||
walk(node, turn, outerValue, event, push(stack, @[outerValue].toPreserve(Ref)))
|
||||
|
||||
proc extend(node: Node; pat: Pattern): Continuation =
|
||||
trace "extend node with ", pat
|
||||
proc extend(node: Node; popCount: Natural; stepIndex: Value; pat: Pattern; path: var Path): tuple[popCount: Natural, nextNode: Node] =
|
||||
case pat.orKind
|
||||
of PatternKind.DDiscard, PatternKind.DLit: result = (popCount, node)
|
||||
of PatternKind.DBind: result = extend(node, popCount, stepIndex, pat.dbind.pattern, path)
|
||||
of PatternKind.DCompound:
|
||||
let selector: Selector = (popCount, stepIndex,)
|
||||
var table = node.edges.getOrDefault(selector)
|
||||
if table.isNil:
|
||||
table = newTable[Class, Node]()
|
||||
node.edges[selector] = table
|
||||
let class = classOf pat
|
||||
result.nextNode = table.getOrDefault(class)
|
||||
if result.nextNode.isNil:
|
||||
new result.nextNode
|
||||
new result.nextNode.continuation
|
||||
table[class] = result.nextNode
|
||||
for a in node.continuation.cachedAssertions:
|
||||
if class == classOf projectPath(a, path):
|
||||
result.nextNode.continuation.cachedAssertions.incl a
|
||||
result.popCount = 0
|
||||
template walkKey(pat: Pattern; stepIndex: Value) =
|
||||
path.add(stepIndex)
|
||||
result = extend(result.nextNode, popCount, stepIndex, pat, path)
|
||||
discard path.pop()
|
||||
case pat.dcompound.orKind
|
||||
of DCompoundKind.rec:
|
||||
for k, e in pat.dcompound.rec.fields: walkKey(e, k.toPreserve(Ref))
|
||||
of DCompoundKind.arr:
|
||||
for k, e in pat.dcompound.arr.items: walkKey(e, k.toPreserve(Ref))
|
||||
of DCompoundKind.dict:
|
||||
for k, e in pat.dcompound.dict.entries: walkKey(e, k)
|
||||
result.popCount.inc
|
||||
when not defined(release):
|
||||
assert not node.edges[selector][classOf pat].isNil
|
||||
|
||||
proc extend(node: var Node; pat: Pattern): Continuation =
|
||||
var path: Path
|
||||
proc walkNode(node: Node; popCount: Natural; stepIndex: Value; pat: Pattern): tuple[popCount: Natural, nextNode: Node] =
|
||||
trace "walkNode step ", stepIndex, " of ", pat
|
||||
case pat.orKind
|
||||
of PatternKind.DDiscard, PatternKind.DLit: result = (popCount, node)
|
||||
of PatternKind.DBind: result = walkNode(node, popCount, stepIndex, pat.dbind.pattern)
|
||||
of PatternKind.DCompound:
|
||||
let selector = (popCount, stepIndex,)
|
||||
var table = node.edges.getOrDefault(selector)
|
||||
if table.isNil:
|
||||
trace "allocate new table for selector ", selector, " for ", pat
|
||||
table = newTable[Class, Node]()
|
||||
node.edges[selector] = table
|
||||
else:
|
||||
trace "got a table for ", pat, " with selector ", selector
|
||||
let class = classOf pat
|
||||
result.nextNode = table.getOrDefault(class)
|
||||
if result.nextNode.isNil:
|
||||
trace "allocate result.nextNode for ", string class
|
||||
new result.nextNode
|
||||
table[class] = result.nextNode
|
||||
new result.nextNode.continuation
|
||||
for a in node.continuation.cachedAssertions:
|
||||
if class == classOf projectPath(a, path):
|
||||
result.nextNode.continuation.cachedAssertions.incl a
|
||||
result.popCount = 0
|
||||
template walkKey(pat: Pattern; stepIndex: Value) =
|
||||
trace "walkKey ", pat, " with step ", stepIndex
|
||||
path.add(stepIndex)
|
||||
result = walkNode(result.nextNode, popCount, stepIndex, pat)
|
||||
discard path.pop()
|
||||
case pat.dcompound.orKind
|
||||
of DCompoundKind.rec:
|
||||
for k, e in pat.dcompound.rec.fields: walkKey(e, k.toPreserve(Ref))
|
||||
of DCompoundKind.arr:
|
||||
for k, e in pat.dcompound.arr.items: walkKey(e, k.toPreserve(Ref))
|
||||
of DCompoundKind.dict:
|
||||
for k, e in pat.dcompound.dict.entries: walkKey(e, k)
|
||||
result.popCount.inc
|
||||
walkNode(node, 0, toPreserve(0, Ref), pat).nextNode.continuation
|
||||
extend(node, 0, toPreserve(0, Ref), pat, path).nextNode.continuation
|
||||
|
||||
type
|
||||
Index* = object
|
||||
|
@ -178,13 +179,11 @@ proc initIndex*(): Index =
|
|||
Index(root: Node(continuation: Continuation()))
|
||||
|
||||
proc add*(index: var Index; turn: var Turn; pattern: Pattern; observer: Ref) =
|
||||
trace "add pattern ", pattern, " for ", observer
|
||||
let
|
||||
analysis = analyse pattern
|
||||
continuation = index.root.extend pattern
|
||||
var constValMap = continuation.leafMap.getOrDefault(analysis.constPaths)
|
||||
if constValMap.isNil:
|
||||
trace "allocate constValMap in leafMap for ", analysis.constPaths
|
||||
new constValMap
|
||||
for a in continuation.cachedAssertions:
|
||||
let key = projectPaths(a, analysis.constPaths)
|
||||
|
@ -193,16 +192,13 @@ proc add*(index: var Index; turn: var Turn; pattern: Pattern; observer: Ref) =
|
|||
new leaf
|
||||
constValMap[key] = leaf
|
||||
leaf.cachedAssertions.incl(a)
|
||||
trace "update leafMap for ", analysis.constPaths
|
||||
continuation.leafMap[analysis.constPaths] = constValMap
|
||||
var leaf = constValMap.getOrDefault(analysis.constValues)
|
||||
if leaf.isNil:
|
||||
new leaf
|
||||
constValMap[analysis.constValues] = leaf
|
||||
trace "get observerGroup for ", analysis.capturePaths
|
||||
var observerGroup = leaf.observerGroups.getOrDefault(analysis.capturePaths)
|
||||
if observerGroup.isNil:
|
||||
trace "allocate observerGroup for ", analysis.capturePaths
|
||||
new observerGroup
|
||||
for a in leaf.cachedAssertions:
|
||||
discard observerGroup.cachedCaptures.change(projectPaths(a, analysis.capturePaths), +1)
|
||||
|
@ -237,32 +233,29 @@ proc adjustAssertion*(index: var Index; turn: var Turn; outerValue: Value; delta
|
|||
case index.allAssertions.change(outerValue, delta)
|
||||
of cdAbsentToPresent:
|
||||
result = true
|
||||
index.root.modify(
|
||||
turn,
|
||||
addedEvent,
|
||||
outerValue,
|
||||
(proc (c: Continuation; v: Value) = c.cachedAssertions.incl(v)),
|
||||
(proc (l: Leaf; v: Value) = l.cachedAssertions.incl(v)),
|
||||
(proc (turn: var Turn; group: ObserverGroup; vs: seq[Value]) =
|
||||
if group.cachedCaptures.change(vs, +1) == cdAbsentToPresent:
|
||||
for (observer, captureMap) in group.observers.pairs:
|
||||
let a = vs.toPreserve(Ref)
|
||||
trace "publish to dataspace observer ", observer, " ", a
|
||||
captureMap[vs] = publish(turn, observer, a)))
|
||||
# TODO: this handle is coming from the facet?
|
||||
proc modContinuation(c: Continuation; v: Value) =
|
||||
c.cachedAssertions.incl(v)
|
||||
proc modLeaf(l: Leaf; v: Value) =
|
||||
l.cachedAssertions.incl(v)
|
||||
proc modObserver(turn: var Turn; group: ObserverGroup; vs: seq[Value]) =
|
||||
if group.cachedCaptures.change(vs, +1) == cdAbsentToPresent:
|
||||
for (observer, captureMap) in group.observers.pairs:
|
||||
let a = vs.toPreserve(Ref)
|
||||
captureMap[vs] = publish(turn, observer, a)
|
||||
# TODO: this handle is coming from the facet?
|
||||
modify(index.root, turn, outerValue, addedEvent, modContinuation, modLeaf, modObserver)
|
||||
of cdPresentToAbsent:
|
||||
result = true
|
||||
index.root.modify(
|
||||
turn,
|
||||
removedEvent,
|
||||
outerValue,
|
||||
(proc (c: Continuation; v: Value) = c.cachedAssertions.excl(v)),
|
||||
(proc (l: Leaf; v: Value) = l.cachedAssertions.excl(v)),
|
||||
(proc (turn: var Turn; group: ObserverGroup; vs: seq[Value]) =
|
||||
if group.cachedCaptures.change(vs, -1) == cdPresentToAbsent:
|
||||
for (observer, captureMap) in group.observers.pairs:
|
||||
retract(observer.target, turn, captureMap[vs])
|
||||
captureMap.del(vs)))
|
||||
proc modContinuation(c: Continuation; v: Value) =
|
||||
c.cachedAssertions.excl(v)
|
||||
proc modLeaf(l: Leaf; v: Value) =
|
||||
l.cachedAssertions.excl(v)
|
||||
proc modObserver(turn: var Turn; group: ObserverGroup; vs: seq[Value]) =
|
||||
if group.cachedCaptures.change(vs, -1) == cdPresentToAbsent:
|
||||
for (observer, captureMap) in group.observers.pairs:
|
||||
retract(observer.target, turn, captureMap[vs])
|
||||
captureMap.del(vs)
|
||||
modify(index.root, turn, outerValue, removedEvent, modContinuation, modLeaf, modObserver)
|
||||
else: discard
|
||||
|
||||
proc continuationNoop(c: Continuation; v: Value) = discard
|
||||
|
@ -273,7 +266,7 @@ proc add*(index: var Index; turn: var Turn; v: Assertion): bool =
|
|||
proc remove*(index: var Index; turn: var Turn; v: Assertion): bool =
|
||||
adjustAssertion(index, turn, v, -1)
|
||||
|
||||
proc deliverMessage*(index: Index; turn: var Turn; v: Value) =
|
||||
proc deliverMessage*(index: var Index; turn: var Turn; v: Value) =
|
||||
proc observersCb(turn: var Turn; group: ObserverGroup; vs: seq[Value]) =
|
||||
for observer in group.observers.keys: message(turn, observer, vs)
|
||||
index.root.modify(turn, messageEvent, v, continuationNoop, leafNoop, observersCb)
|
||||
index.root.modify(turn, v, messageEvent, continuationNoop, leafNoop, observersCb)
|
||||
|
|
Loading…
Reference in New Issue