From 231928f2430e4aad87033bb78a4f1425c9094f5a Mon Sep 17 00:00:00 2001 From: Emery Hemingway Date: Fri, 11 Mar 2022 14:29:46 -0600 Subject: [PATCH] Rewrite skeletons for new patterns --- src/syndicate/skeletons.nim | 227 +++++++++++++++++------------------- 1 file changed, 110 insertions(+), 117 deletions(-) diff --git a/src/syndicate/skeletons.nim b/src/syndicate/skeletons.nim index a5cf9f3..cd98b0f 100644 --- a/src/syndicate/skeletons.nim +++ b/src/syndicate/skeletons.nim @@ -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)