Compute `retracted` pattern just once during `during`. Avoids mutation-related bug.
This commit is contained in:
parent
7e144ab33b
commit
0b964bb1bb
|
@ -152,7 +152,7 @@ var modifiedSourceActions = {
|
|||
},
|
||||
|
||||
FacetSituation_assert: function(_assert, expr, whenClause, _sc) {
|
||||
return '\n.addAssertion(' + buildSubscription([expr], 'assert', 'pattern', whenClause) + ')';
|
||||
return '\n.addAssertion(' + buildSubscription([expr], 'assert', 'pattern', whenClause, null) + ')';
|
||||
},
|
||||
FacetSituation_event: function(_on, eventPattern, block) {
|
||||
return buildOnEvent(false,
|
||||
|
@ -166,18 +166,20 @@ var modifiedSourceActions = {
|
|||
return '\n.addOnEventHandler((function(' + id.asES5 + ') ' + block.asES5 + '))';
|
||||
},
|
||||
FacetSituation_during: function(_during, pattern, facetBlock) {
|
||||
var cachedAssertionVar = gensym('cachedAssertion');
|
||||
return buildOnEvent(false,
|
||||
'asserted',
|
||||
pattern.subscription,
|
||||
pattern.projection,
|
||||
pattern.bindings,
|
||||
'{ ' + facetBlock.facetVarDecls +
|
||||
'\nvar '+cachedAssertionVar+' = '+pattern.instantiatedAssertion+';'+
|
||||
'\nSyndicate.Actor.createFacet()' +
|
||||
facetBlock.asES5 +
|
||||
buildOnEvent(true,
|
||||
'retracted',
|
||||
pattern.instantiatedSubscription,
|
||||
pattern.instantiatedProjection,
|
||||
pattern.instantiatedSubscription(cachedAssertionVar),
|
||||
pattern.instantiatedProjection(cachedAssertionVar),
|
||||
[],
|
||||
'{}') +
|
||||
'.completeBuild(); }');
|
||||
|
@ -221,7 +223,7 @@ semantics.addAttribute('eventType', {
|
|||
FacetTransitionEventPattern_risingEdge: function (_lp, expr, _rp) { return 'risingEdge'; }
|
||||
});
|
||||
|
||||
function buildSubscription(children, patchMethod, mode, whenClause) {
|
||||
function buildSubscription(children, patchMethod, mode, whenClause, cachedAssertionVar) {
|
||||
var fragments = [];
|
||||
var hasWhenClause = (whenClause && (whenClause.numChildren === 1));
|
||||
fragments.push('(function() { var _ = Syndicate.__; return ');
|
||||
|
@ -233,7 +235,11 @@ function buildSubscription(children, patchMethod, mode, whenClause) {
|
|||
} else {
|
||||
fragments.push('{ assertion: ');
|
||||
}
|
||||
children.forEach(function (c) { c.buildSubscription(fragments, mode); });
|
||||
if (cachedAssertionVar) {
|
||||
fragments.push(cachedAssertionVar);
|
||||
} else {
|
||||
children.forEach(function (c) { c.buildSubscription(fragments, mode); });
|
||||
}
|
||||
if (patchMethod) {
|
||||
fragments.push(', ');
|
||||
} else {
|
||||
|
@ -254,25 +260,35 @@ function buildSubscription(children, patchMethod, mode, whenClause) {
|
|||
|
||||
semantics.addAttribute('subscription', {
|
||||
_default: function(children) {
|
||||
return buildSubscription(children, 'sub', 'pattern', null);
|
||||
return buildSubscription(children, 'sub', 'pattern', null, null);
|
||||
}
|
||||
});
|
||||
|
||||
semantics.addAttribute('instantiatedSubscription', {
|
||||
semantics.addAttribute('instantiatedAssertion', {
|
||||
_default: function(children) {
|
||||
return buildSubscription(children, 'sub', 'instantiated', null);
|
||||
var fragments = [];
|
||||
fragments.push('(function() { var _ = Syndicate.__; return ');
|
||||
children.forEach(function (c) { c.buildSubscription(fragments, 'instantiated'); });
|
||||
fragments.push('; })()');
|
||||
return fragments.join('');
|
||||
}
|
||||
});
|
||||
|
||||
semantics.addAttribute('instantiatedProjection', {
|
||||
semantics.addOperation('instantiatedSubscription(cachedAssertionVar)', {
|
||||
_default: function(children) {
|
||||
return buildSubscription(children, null, 'instantiated', null);
|
||||
return buildSubscription(children, 'sub', 'instantiated', null, this.args.cachedAssertionVar);
|
||||
}
|
||||
});
|
||||
|
||||
semantics.addOperation('instantiatedProjection(cachedAssertionVar)', {
|
||||
_default: function(children) {
|
||||
return buildSubscription(children, null, 'instantiated', null, this.args.cachedAssertionVar);
|
||||
}
|
||||
});
|
||||
|
||||
semantics.addAttribute('projection', {
|
||||
_default: function(children) {
|
||||
return buildSubscription(children, null, 'projection', null);
|
||||
return buildSubscription(children, null, 'projection', null, null);
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
// Illustrates a (now fixed) bug where mutation altering a
|
||||
// subscription caused the `retracted` half of a during instance to be
|
||||
// lost.
|
||||
//
|
||||
// Symptomatic output:
|
||||
// x= 123 v= 999
|
||||
// x= 124 v= 999
|
||||
//
|
||||
// Correct output:
|
||||
// x= 123 v= 999
|
||||
// finally for x= 124 v= 999
|
||||
// x= 124 v= 999
|
||||
//
|
||||
// Should eventually be turned into some kind of test case.
|
||||
|
||||
var Syndicate = require('./src/main.js');
|
||||
var Dataspace = Syndicate.Dataspace;
|
||||
|
||||
assertion type foo(x, y);
|
||||
|
||||
ground dataspace {
|
||||
actor {
|
||||
var x = 123;
|
||||
react {
|
||||
assert foo(x, 999);
|
||||
|
||||
during foo(x, $v) {
|
||||
do {
|
||||
console.log('x=', x, 'v=', v);
|
||||
if (x === 123) {
|
||||
x = 124;
|
||||
}
|
||||
}
|
||||
finally {
|
||||
console.log('finally for x=', x, 'v=', v);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -624,7 +624,7 @@
|
|||
(define (analyze-during! index P-stx O-stxs)
|
||||
(define E-stx #`(asserted #,P-stx))
|
||||
(define-values (_proj _pat _bindings instantiated) (analyze-pattern E-stx P-stx))
|
||||
(define I-stx #`(until (retracted #,instantiated) #,@O-stxs))
|
||||
(define I-stx #`(let ((p #,instantiated)) (until (retracted p) #,@O-stxs)))
|
||||
(analyze-event! index E-stx #`(#,I-stx)))
|
||||
|
||||
(define (analyze-assertion! index Pred-stx outer-expr-stx P-stx L-stx)
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
#lang syndicate
|
||||
;; Illustrates a (now fixed) bug where mutation altering a
|
||||
;; subscription caused the `retracted` half of a during instance to be
|
||||
;; lost.
|
||||
;;
|
||||
;; Symptomatic output:
|
||||
;; x=123 v=999
|
||||
;; x=124 v=999
|
||||
;;
|
||||
;; Correct output:
|
||||
;; x=123 v=999
|
||||
;; finally for x=124 v=999
|
||||
;; x=124 v=999
|
||||
;;
|
||||
;; Should eventually be turned into some kind of test case.
|
||||
|
||||
(require syndicate/actor)
|
||||
|
||||
(struct foo (x y) #:prefab)
|
||||
|
||||
(actor (define x 123)
|
||||
(forever
|
||||
(assert (foo x 999))
|
||||
(during (foo x $v)
|
||||
#:init [(log-info "x=~a v=~a" x v)
|
||||
(when (= x 123) (set! x 124))]
|
||||
#:done [(log-info "finally for x=~a v=~a" x v)])))
|
Loading…
Reference in New Issue