Rewrite skeletons for new patterns

This commit is contained in:
Emery Hemingway 2022-03-11 14:29:46 -06:00
parent d4442438fa
commit 231928f243
1 changed files with 110 additions and 117 deletions

View File

@ -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,102 +68,107 @@ 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 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 var path: Path
proc walkNode(node: Node; popCount: Natural; stepIndex: Value; pat: Pattern): tuple[popCount: Natural, nextNode: Node] = extend(node, 0, toPreserve(0, Ref), pat, path).nextNode.continuation
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
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)), if group.cachedCaptures.change(vs, +1) == cdAbsentToPresent:
(proc (turn: var Turn; group: ObserverGroup; vs: seq[Value]) = for (observer, captureMap) in group.observers.pairs:
if group.cachedCaptures.change(vs, +1) == cdAbsentToPresent: let a = vs.toPreserve(Ref)
for (observer, captureMap) in group.observers.pairs: captureMap[vs] = publish(turn, observer, a)
let a = vs.toPreserve(Ref) # TODO: this handle is coming from the facet?
trace "publish to dataspace observer ", observer, " ", a modify(index.root, turn, outerValue, addedEvent, modContinuation, modLeaf, modObserver)
captureMap[vs] = publish(turn, observer, a)))
# TODO: this handle is coming from the facet?
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)), if group.cachedCaptures.change(vs, -1) == cdPresentToAbsent:
(proc (turn: var Turn; group: ObserverGroup; vs: seq[Value]) = for (observer, captureMap) in group.observers.pairs:
if group.cachedCaptures.change(vs, -1) == cdPresentToAbsent: retract(observer.target, turn, captureMap[vs])
for (observer, captureMap) in group.observers.pairs: captureMap.del(vs)
retract(observer.target, turn, captureMap[vs]) modify(index.root, turn, outerValue, removedEvent, modContinuation, modLeaf, modObserver)
captureMap.del(vs)))
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)