Treat synthetic patches differently wrt previousKnowledge

This commit is contained in:
Tony Garnock-Jones 2016-08-07 19:44:57 -04:00
parent cd754be396
commit eaade6e4fd
3 changed files with 66 additions and 22 deletions

View File

@ -70,7 +70,7 @@ Actor.prototype.handleEvent = function(e) {
throw new Error('Syndicate: pendingActions must not be nonempty at start of handleEvent');
}
this.facets.forEach(function (f) {
withCurrentFacet(actor, f, function () { f.handleEvent(e); });
withCurrentFacet(actor, f, function () { f.handleEvent(e, false); });
});
this.quiesce();
};
@ -160,10 +160,10 @@ function withCurrentFacet(actor, facet, f) {
return result;
}
Facet.prototype.handleEvent = function(e) {
Facet.prototype.handleEvent = function(e, isSynthetic) {
var facet = this;
facet.endpoints.forEach(function(endpoint) {
endpoint.handlerFn.call(facet.fields, e);
endpoint.handlerFn.call(facet.fields, e, isSynthetic);
});
};
@ -218,7 +218,7 @@ Facet.prototype.onEvent = function(priority,
case 'asserted': /* fall through */
case 'retracted':
return this.addEndpoint(new Endpoint(subscriptionFn, function(e) {
return this.addEndpoint(new Endpoint(subscriptionFn, function(e, isSynthetic) {
if (e.type === 'stateChange') {
var proj = projectionFn.call(facet.fields);
var spec = Patch.prependAtMeta(proj.assertion, proj.metalevel);
@ -230,7 +230,7 @@ Facet.prototype.onEvent = function(priority,
var shouldTerminate = isTerminal;
objects.forEach(function (o) {
var instantiated = Trie.instantiateProjection(spec, o);
if (facet.interestWas(eventType, instantiated)) {
if (facet.interestWas(eventType, instantiated, isSynthetic)) {
if (shouldTerminate) {
shouldTerminate = false;
facet.terminate();
@ -264,9 +264,10 @@ Facet.prototype.onEvent = function(priority,
}
};
Facet.prototype.interestWas = function(assertedOrRetracted, pat) {
Facet.prototype.interestWas = function(assertedOrRetracted, pat, isSyntheticEvent) {
function orStar(a, b) { return (a || b); }
var oldExists = Trie.matchValue(this.actor.previousKnowledge, pat, false, orStar);
var previousKnowledge = isSyntheticEvent ? Trie.emptyTrie : this.actor.previousKnowledge;
var oldExists = Trie.matchValue(previousKnowledge, pat, false, orStar);
var newExists = Trie.matchValue(this.actor.knowledge, pat, false, orStar);
switch (assertedOrRetracted) {
case 'asserted':
@ -310,7 +311,7 @@ Facet.prototype.completeBuild = function() {
facet.initBlocks.forEach(function(b) { b.call(facet.fields); });
});
var initialEvent = _Dataspace.stateChange(new Patch.Patch(facet.actor.knowledge, Trie.emptyTrie));
withCurrentFacet(this.actor, facet, function () { facet.handleEvent(initialEvent); });
withCurrentFacet(this.actor, facet, function () { facet.handleEvent(initialEvent, true); });
};
Facet.prototype.terminate = function() {

View File

@ -397,7 +397,7 @@
(define (on-event* where proc #:priority [priority *normal-priority*])
(add-endpoint! where
(lambda () patch-empty)
(lambda (e)
(lambda (e _synthetic?)
(schedule-script! #:priority priority #f (lambda () (proc e))))))
(define-syntax (on stx)
@ -620,19 +620,20 @@
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Syntax-time support
(define (interests-pre-and-post-patch pat)
(define (interests-pre-and-post-patch pat synthetic?)
(define (or* x y) (or x y))
(define a (current-actor-state))
(define old (trie-lookup (actor-state-previous-knowledge a) pat #f #:wildcard-union or*))
(define previous-knowledge (if synthetic? trie-empty (actor-state-previous-knowledge a)))
(define old (trie-lookup previous-knowledge pat #f #:wildcard-union or*))
(define new (trie-lookup (actor-state-knowledge a) pat #f #:wildcard-union or*))
(values old new))
(define (interest-just-appeared-matching? pat)
(define-values (old new) (interests-pre-and-post-patch pat))
(define (interest-just-appeared-matching? pat synthetic?)
(define-values (old new) (interests-pre-and-post-patch pat synthetic?))
(and (not old) new))
(define (interest-just-disappeared-matching? pat)
(define-values (old new) (interests-pre-and-post-patch pat))
(define (interest-just-disappeared-matching? pat synthetic?)
(define-values (old new) (interests-pre-and-post-patch pat synthetic?))
(and old (not new)))
(define-for-syntax (analyze-asserted/retracted outer-expr-stx
@ -654,7 +655,7 @@
(lambda () (if #,when-pred-stx
(core:sub #,pat)
patch-empty))
(lambda (e)
(lambda (e synthetic?)
(core:match-event e
[(? #,event-predicate-stx p)
(define proj #,proj-stx)
@ -670,7 +671,7 @@
#,(let ((entry-handler-stx
(quasisyntax/loc script-stx
(let ((instantiated (instantiate-projection proj entry)))
(and (#,change-detector-stx instantiated)
(and (#,change-detector-stx instantiated synthetic?)
(schedule-script!
#:priority #,priority-stx
#,(if terminal? #'#t #'#f)
@ -722,7 +723,7 @@
(lambda () (if #,when-pred-stx
(core:sub #,pat)
patch-empty))
(lambda (e)
(lambda (e _synthetic?)
(core:match-event e
[(core:message body)
(define capture-vals
@ -933,7 +934,8 @@
[field-descriptors (current-field-descriptors)])))))
(facet-handle-event! fid
(lookup-facet fid)
(patch (actor-state-knowledge (current-actor-state)) trie-empty))
(patch (actor-state-knowledge (current-actor-state)) trie-empty)
#t)
(when (and (facet-live? fid) parent-fid (not (facet-live? parent-fid)))
(terminate-facet! fid)))
@ -1067,13 +1069,13 @@
(current-pending-actions '())
(current-pending-scripts (make-empty-pending-scripts))]
(for [((fid f) (in-hash (actor-state-facets a)))]
(facet-handle-event! fid f e))
(facet-handle-event! fid f e #f))
(run-scripts!))))
(define (facet-handle-event! fid f e)
(define (facet-handle-event! fid f e synthetic?)
(with-current-facet fid (facet-field-descriptors f) #f
(for [(ep (in-hash-values (facet-endpoints f)))]
((endpoint-handler-fn ep) e))))
((endpoint-handler-fn ep) e synthetic?))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Script suspend-and-resume.

View File

@ -0,0 +1,41 @@
#lang syndicate/actor
;; Illustrates a (now fixed) bug where creating a facet interested in something
;; already known didn't properly trigger the assertion-handler.
;;
;; Symptomatic output:
;;
;; +outer "first"
;; +show
;; -show
;; -outer "first"
;; +outer "second"
;;
;; Correct output:
;;
;; +outer "first"
;; +show
;; -show
;; -outer "first"
;; +outer "second"
;; +show
;;
;; Should eventually be turned into some kind of test case.
(struct outer (v) #:prefab)
(struct show () #:prefab)
(actor (react (field [v "first"])
(assert (outer (v)))
(assert (show))
(on (message 2)
(v "second"))))
(actor (react (on-start (send! 1))
(during (outer $v)
(on-start (log-info "+outer ~v" v))
(on-stop (log-info "-outer ~v" v))
(during (show)
(on-start (log-info "+show"))
(on-stop (log-info "-show"))))
(on (message 1)
(send! 2))))