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) {
|
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) {
|
FacetSituation_event: function(_on, eventPattern, block) {
|
||||||
return buildOnEvent(false,
|
return buildOnEvent(false,
|
||||||
|
@ -166,18 +166,20 @@ var modifiedSourceActions = {
|
||||||
return '\n.addOnEventHandler((function(' + id.asES5 + ') ' + block.asES5 + '))';
|
return '\n.addOnEventHandler((function(' + id.asES5 + ') ' + block.asES5 + '))';
|
||||||
},
|
},
|
||||||
FacetSituation_during: function(_during, pattern, facetBlock) {
|
FacetSituation_during: function(_during, pattern, facetBlock) {
|
||||||
|
var cachedAssertionVar = gensym('cachedAssertion');
|
||||||
return buildOnEvent(false,
|
return buildOnEvent(false,
|
||||||
'asserted',
|
'asserted',
|
||||||
pattern.subscription,
|
pattern.subscription,
|
||||||
pattern.projection,
|
pattern.projection,
|
||||||
pattern.bindings,
|
pattern.bindings,
|
||||||
'{ ' + facetBlock.facetVarDecls +
|
'{ ' + facetBlock.facetVarDecls +
|
||||||
|
'\nvar '+cachedAssertionVar+' = '+pattern.instantiatedAssertion+';'+
|
||||||
'\nSyndicate.Actor.createFacet()' +
|
'\nSyndicate.Actor.createFacet()' +
|
||||||
facetBlock.asES5 +
|
facetBlock.asES5 +
|
||||||
buildOnEvent(true,
|
buildOnEvent(true,
|
||||||
'retracted',
|
'retracted',
|
||||||
pattern.instantiatedSubscription,
|
pattern.instantiatedSubscription(cachedAssertionVar),
|
||||||
pattern.instantiatedProjection,
|
pattern.instantiatedProjection(cachedAssertionVar),
|
||||||
[],
|
[],
|
||||||
'{}') +
|
'{}') +
|
||||||
'.completeBuild(); }');
|
'.completeBuild(); }');
|
||||||
|
@ -221,7 +223,7 @@ semantics.addAttribute('eventType', {
|
||||||
FacetTransitionEventPattern_risingEdge: function (_lp, expr, _rp) { return 'risingEdge'; }
|
FacetTransitionEventPattern_risingEdge: function (_lp, expr, _rp) { return 'risingEdge'; }
|
||||||
});
|
});
|
||||||
|
|
||||||
function buildSubscription(children, patchMethod, mode, whenClause) {
|
function buildSubscription(children, patchMethod, mode, whenClause, cachedAssertionVar) {
|
||||||
var fragments = [];
|
var fragments = [];
|
||||||
var hasWhenClause = (whenClause && (whenClause.numChildren === 1));
|
var hasWhenClause = (whenClause && (whenClause.numChildren === 1));
|
||||||
fragments.push('(function() { var _ = Syndicate.__; return ');
|
fragments.push('(function() { var _ = Syndicate.__; return ');
|
||||||
|
@ -233,7 +235,11 @@ function buildSubscription(children, patchMethod, mode, whenClause) {
|
||||||
} else {
|
} else {
|
||||||
fragments.push('{ assertion: ');
|
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) {
|
if (patchMethod) {
|
||||||
fragments.push(', ');
|
fragments.push(', ');
|
||||||
} else {
|
} else {
|
||||||
|
@ -254,25 +260,35 @@ function buildSubscription(children, patchMethod, mode, whenClause) {
|
||||||
|
|
||||||
semantics.addAttribute('subscription', {
|
semantics.addAttribute('subscription', {
|
||||||
_default: function(children) {
|
_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) {
|
_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) {
|
_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', {
|
semantics.addAttribute('projection', {
|
||||||
_default: function(children) {
|
_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 (analyze-during! index P-stx O-stxs)
|
||||||
(define E-stx #`(asserted #,P-stx))
|
(define E-stx #`(asserted #,P-stx))
|
||||||
(define-values (_proj _pat _bindings instantiated) (analyze-pattern E-stx 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)))
|
(analyze-event! index E-stx #`(#,I-stx)))
|
||||||
|
|
||||||
(define (analyze-assertion! index Pred-stx outer-expr-stx P-stx L-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