From d87118f686330813f2702a35c22cb1a26be27c92 Mon Sep 17 00:00:00 2001 From: Tony Garnock-Jones Date: Sat, 19 Mar 2016 13:48:49 -0400 Subject: [PATCH] Support risingEdge transition events --- js/compiler/compiler.js | 43 ++++++++++++++++++++--------- js/compiler/syndicate.ohm | 8 ++++-- js/src/actor.js | 58 ++++++++++++++++++++++++--------------- 3 files changed, 72 insertions(+), 37 deletions(-) diff --git a/js/compiler/compiler.js b/js/compiler/compiler.js index 72f873c..e1d2ff5 100644 --- a/js/compiler/compiler.js +++ b/js/compiler/compiler.js @@ -60,6 +60,24 @@ function buildOnEvent(isTerminal, eventType, subscription, projection, bindings, ', (function(' + bindings.join(', ') + ') ' + body + '))'; } +function buildCaseEvent(eventPattern, body) { + if (eventPattern.eventType === 'risingEdge') { + return buildOnEvent(true, + eventPattern.eventType, + 'function() { return (' + eventPattern.asES5 + '); }', + 'null', + [], + body); + } else { + return buildOnEvent(true, + eventPattern.eventType, + eventPattern.subscription, + eventPattern.projection, + eventPattern.bindings, + body); + } +} + var modifiedSourceActions = { ActorStatement_noConstructor: function(_actor, block) { return buildActor('Object()', block); @@ -166,20 +184,10 @@ var modifiedSourceActions = { }, FacetStateTransition_withContinuation: function(_case, eventPattern, block) { - return buildOnEvent(true, - eventPattern.eventType, - eventPattern.subscription, - eventPattern.projection, - eventPattern.bindings, - block.asES5); + return buildCaseEvent(eventPattern, block.asES5); }, FacetStateTransition_noContinuation: function(_case, eventPattern, _sc) { - return buildOnEvent(true, - eventPattern.eventType, - eventPattern.subscription, - eventPattern.projection, - eventPattern.bindings, - ''); + return buildCaseEvent(eventPattern, ''); } }; @@ -197,7 +205,10 @@ semantics.addAttribute('asSyndicateStructureArguments', { semantics.addAttribute('eventType', { FacetEventPattern_messageEvent: function(_kw, _pattern) { return 'message'; }, FacetEventPattern_assertedEvent: function(_kw, _pattern) { return 'asserted'; }, - FacetEventPattern_retractedEvent: function(_kw, _pattern) { return 'retracted'; } + FacetEventPattern_retractedEvent: function(_kw, _pattern) { return 'retracted'; }, + + FacetTransitionEventPattern_facetEvent: function (pattern) { return pattern.eventType; }, + FacetTransitionEventPattern_risingEdge: function (expr) { return 'risingEdge'; } }); function buildSubscription(children, patchMethod, mode) { @@ -247,6 +258,8 @@ semantics.addAttribute('metalevel', { FacetEventPattern_assertedEvent: function(_kw, p) { return p.metalevel; }, FacetEventPattern_retractedEvent: function(_kw, p) { return p.metalevel; }, + FacetTransitionEventPattern_facetEvent: function (pattern) { return pattern.metalevel; }, + FacetPattern_withMetalevel: function(_expr, _kw, metalevel) { return metalevel.interval.contents; }, @@ -266,6 +279,10 @@ semantics.addOperation('buildSubscription(acc,mode)', { pattern.buildSubscription(this.args.acc, this.args.mode); }, + FacetTransitionEventPattern_facetEvent: function (pattern) { + pattern.buildSubscription(this.args.acc, this.args.mode); + }, + FacetPattern: function (v) { v.children[0].buildSubscription(this.args.acc, this.args.mode); // both branches! }, diff --git a/js/compiler/syndicate.ohm b/js/compiler/syndicate.ohm index a7d3886..98a236b 100644 --- a/js/compiler/syndicate.ohm +++ b/js/compiler/syndicate.ohm @@ -50,9 +50,13 @@ Syndicate <: ES5 { | asserted FacetPattern -- assertedEvent | retracted FacetPattern -- retractedEvent + FacetTransitionEventPattern + = FacetEventPattern -- facetEvent + | Expression -- risingEdge + FacetStateTransition - = case FacetEventPattern Block -- withContinuation - | case FacetEventPattern #(sc) -- noContinuation + = case FacetTransitionEventPattern Block -- withContinuation + | case FacetTransitionEventPattern #(sc) -- noContinuation FacetPattern = LeftHandSideExpression metalevel decimalIntegerLiteral -- withMetalevel diff --git a/js/src/actor.js b/js/src/actor.js index 5cb9dde..e11d480 100644 --- a/js/src/actor.js +++ b/js/src/actor.js @@ -67,13 +67,13 @@ Facet.prototype.addAssertion = function(assertionFn) { Facet.prototype.onEvent = function(isTerminal, eventType, subscriptionFn, projectionFn, handlerFn) { var facet = this; - return this.addEndpoint(new Endpoint(subscriptionFn, function(e) { - var proj = projectionFn.call(facet.actor.state); - var spec = Patch.prependAtMeta(proj.assertion, proj.metalevel); + switch (eventType) { - switch (e.type) { - case 'message': - if (eventType === 'message') { + case 'message': + return this.addEndpoint(new Endpoint(subscriptionFn, function(e) { + if (e.type === 'message') { + var proj = projectionFn.call(facet.actor.state); + var spec = Patch.prependAtMeta(proj.assertion, proj.metalevel); var match = Route.matchPattern(e.message, spec); // console.log(match); if (match) { @@ -81,29 +81,43 @@ Facet.prototype.onEvent = function(isTerminal, eventType, subscriptionFn, projec Util.kwApply(handlerFn, facet.actor.state, match); } } - break; - case 'stateChange': - { - var objects; - switch (eventType) { - case 'asserted': - objects = Route.projectObjects(e.patch.added, Route.compileProjection(spec)); - break; - case 'retracted': - objects = Route.projectObjects(e.patch.removed, Route.compileProjection(spec)); - break; - default: - break; - } + })); + + case 'asserted': /* fall through */ + case 'retracted': + return this.addEndpoint(new Endpoint(subscriptionFn, function(e) { + if (e.type === 'stateChange') { + var proj = projectionFn.call(facet.actor.state); + var spec = Patch.prependAtMeta(proj.assertion, proj.metalevel); + var compiledSpec = Route.compileProjection(spec); + var objects = Route.projectObjects(eventType === 'asserted' + ? e.patch.added + : e.patch.removed, + compiledSpec); if (objects) { if (isTerminal) { facet.terminate(); } // console.log(objects.toArray()); objects.forEach(function (o) { Util.kwApply(handlerFn, facet.actor.state, o); }); } } - } + })); - })); + case 'risingEdge': + var endpoint = new Endpoint(function() { return Patch.emptyPatch; }, + function(e) { + var newValue = subscriptionFn.call(facet.actor.state); + if (newValue && !this.currentValue) { + if (isTerminal) { facet.terminate(); } + handlerFn.call(facet.actor.state); + } + this.currentValue = newValue; + }); + endpoint.currentValue = false; + return this.addEndpoint(endpoint); + + default: + throw new Error("Unsupported Facet eventType: " + eventType); + } }; Facet.prototype.addEndpoint = function(endpoint) {