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