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 ./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)