actor{react{...}} ==> actor{...} for JS

This commit is contained in:
Tony Garnock-Jones 2016-08-25 13:12:32 +01:00
parent c61ed644ce
commit 138bab9ba6
19 changed files with 678 additions and 810 deletions

View File

@ -42,28 +42,29 @@ var forEachChild = (function () {
return forEachChild;
})();
function buildActor(nameExpOpt, block) {
function buildActor(nameExpOpt, block, withReact) {
var nameExpStr;
if (nameExpOpt.numChildren === 1) {
nameExpStr = ', ' + nameExpOpt.asES5;
} else {
nameExpStr = '';
}
return 'Syndicate.Actor.spawnActor(function() ' + block.asES5 + nameExpStr + ');';
return 'Syndicate.Actor.spawnActor(function() ' +
(withReact ? reactWrap(block.asES5) : block.asES5) +
nameExpStr + ');';
}
function buildFacet(facetBlock, transitionBlock) {
return '(function () { ' + (facetBlock ? facetBlock.facetVarDecls : '') +
'\nSyndicate.Actor.createFacet()' +
(facetBlock ? facetBlock.asES5 : '') +
(transitionBlock ? transitionBlock.asES5 : '') +
'.completeBuild(); }).call(this);';
function reactWrap(blockCode) {
return '{ Syndicate.Actor.Facet.build((function () { ' +
blockCode +
' }).bind(this)); }';
}
function buildOnEvent(isTerminal, eventType, subscription, projection, bindings, body) {
return '\n.onEvent(Syndicate.Actor.PRIORITY_NORMAL, ' + isTerminal + ', ' + JSON.stringify(eventType) + ', ' +
return 'Syndicate.Actor.Facet.current.onEvent(Syndicate.Actor.PRIORITY_NORMAL, ' + isTerminal + ', ' +
JSON.stringify(eventType) + ', ' +
subscription + ', ' + projection +
', (function(' + bindings.join(', ') + ') ' + body + '))';
', (function(' + bindings.join(', ') + ') ' + body + '));';
}
function buildCaseEvent(eventPattern, body) {
@ -85,8 +86,11 @@ function buildCaseEvent(eventPattern, body) {
}
var modifiedSourceActions = {
ActorStatement: function(_actor, _namedOpt, nameExpOpt, block) {
return buildActor(nameExpOpt, block);
ActorStatement_noReact: function(_actorStar, _namedOpt, nameExpOpt, block) {
return buildActor(nameExpOpt, block, false);
},
ActorStatement_withReact: function(_actor, _namedOpt, nameExpOpt, block) {
return buildActor(nameExpOpt, block, true);
},
DataspaceStatement_ground: function(_ground, _dataspace, maybeId, block) {
@ -101,14 +105,8 @@ var modifiedSourceActions = {
return 'Syndicate.Dataspace.spawn(new Dataspace(function () ' + block.asES5 + '));';
},
ActorFacetStatement_state: function(_state, facetBlock, _until, transitionBlock) {
return buildFacet(facetBlock, transitionBlock);
},
ActorFacetStatement_until: function(_react, _until, transitionBlock) {
return buildFacet(null, transitionBlock);
},
ActorFacetStatement_forever: function(_forever, facetBlock) {
return buildFacet(facetBlock, null);
ActorFacetStatement: function(_react, block) {
return '(function () ' + reactWrap(block.asES5) + ').call(this);';
},
AssertionTypeDeclarationStatement: function(_assertion,
@ -151,24 +149,17 @@ var modifiedSourceActions = {
return 'Syndicate.Dataspace.send(' + expr.asES5 + ')' + sc.interval.contents;
},
FacetBlock: function(_leftParen, _varStmts, init, situations, done, _rightParen) {
return (init ? init.asES5 : '') + situations.asES5.join('') + (done ? done.asES5 : '');
ActorEndpointStatement_start: function (_on, _start, block) {
return 'Syndicate.Actor.Facet.current.addInitBlock((function() ' + block.asES5 + '));';
},
FacetStateTransitionBlock: function(_leftParen, transitions, _rightParen) {
return transitions.asES5.join('');
ActorEndpointStatement_stop: function (_on, _stop, block) {
return 'Syndicate.Actor.Facet.current.addDoneBlock((function() ' + block.asES5 + '));';
},
FacetInitBlock: function(_init, block) {
return '\n.addInitBlock((function() ' + block.asES5 + '))';
ActorEndpointStatement_assert: function(_assert, expr, whenClause, _sc) {
return 'Syndicate.Actor.Facet.current.addAssertion(' +
buildSubscription([expr], 'assert', 'pattern', whenClause, null) + ');';
},
FacetDoneBlock: function(_done, block) {
return '\n.addDoneBlock((function() ' + block.asES5 + '))';
},
FacetSituation_assert: function(_assert, expr, whenClause, _sc) {
return '\n.addAssertion(' + buildSubscription([expr], 'assert', 'pattern', whenClause, null) + ')';
},
FacetSituation_event: function(_on, eventPattern, block) {
ActorEndpointStatement_event: function(_on, eventPattern, block) {
return buildOnEvent(false,
eventPattern.eventType,
eventPattern.subscription,
@ -176,63 +167,59 @@ var modifiedSourceActions = {
eventPattern.bindings,
block.asES5);
},
FacetSituation_onEvent: function (_on, _event, id, block) {
return '\n.addOnEventHandler((function(' + id.asES5 + ') ' + block.asES5 + '))';
ActorEndpointStatement_onEvent: function (_on, _event, id, block) {
return 'Syndicate.Actor.Facet.current.addOnEventHandler((function(' + id.asES5 + ') ' +
block.asES5 + '));';
},
FacetSituation_dataflow: function (_dataflow, block) {
return '\n.addDataflow((function () ' + block.asES5 + '))';
ActorEndpointStatement_stopOnWithCont: function(_stop, _on, eventPattern, block) {
return buildCaseEvent(eventPattern, block.asES5);
},
FacetSituation_during: function(_during, pattern, facetBlock) {
ActorEndpointStatement_stopOnNoCont: function(_stop, _on, eventPattern, _sc) {
return buildCaseEvent(eventPattern, '{}');
},
ActorEndpointStatement_dataflow: function (_dataflow, block) {
return 'Syndicate.Actor.Facet.current.addDataflow((function () ' + block.asES5 + '));';
},
ActorEndpointStatement_during: function(_during, pattern, block) {
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 +
'{\n' +
'var '+cachedAssertionVar+' = '+pattern.instantiatedAssertion+';\n'+
reactWrap(block.asES5 + '\n' +
buildOnEvent(true,
'retracted',
pattern.instantiatedSubscription(cachedAssertionVar),
pattern.instantiatedProjection(cachedAssertionVar),
[],
'{}') +
'.completeBuild(); }');
'{}')) + '}');
},
FacetSituation_duringActor: function(_during, pattern, _actor, _named, nameExpOpt, facetBlock) {
ActorEndpointStatement_duringActor: function(_during, pattern, _actor, _named, nameExpOpt, block)
{
var cachedAssertionVar = gensym('cachedAssertion');
var actorBlock = {
asES5: '{ ' + facetBlock.facetVarDecls +
'\nSyndicate.Actor.createFacet()' +
facetBlock.asES5 +
asES5: reactWrap(block.asES5 + '\n' +
buildOnEvent(true,
'retracted',
pattern.instantiatedSubscription(cachedAssertionVar),
pattern.instantiatedProjection(cachedAssertionVar),
[],
'{}') +
'.completeBuild(); }'
'{}'))
};
return buildOnEvent(false,
'asserted',
pattern.subscription,
pattern.projection,
pattern.bindings,
'{ var '+cachedAssertionVar+' = '+pattern.instantiatedAssertion+';'+
'\n' + buildActor(nameExpOpt, actorBlock) + ' }');
'{ var '+cachedAssertionVar+' = '+pattern.instantiatedAssertion+';\n'+
buildActor(nameExpOpt, actorBlock, true) + ' }');
},
AssertWhenClause: function(_when, _lparen, expr, _rparen) {
return expr.asES5;
},
FacetStateTransition_withContinuation: function(_case, eventPattern, block) {
return buildCaseEvent(eventPattern, block.asES5);
},
FacetStateTransition_noContinuation: function(_case, eventPattern, _sc) {
return buildCaseEvent(eventPattern, '{}');
}
};
@ -256,11 +243,7 @@ semantics.addAttribute('memberPropExpr', {
}
});
semantics.addAttribute('facetVarDecls', {
FacetBlock: function (_leftParen, varDecls, _init, _situations, _done, _rightParen) {
return varDecls.asES5.join(' ');
}
});
///////////////////////////////////////////////////////////////////////////
semantics.addAttribute('asSyndicateStructureArguments', {
FormalParameterList: function(formals) {

View File

@ -8,8 +8,6 @@ message type deposit(amount);
ground dataspace {
actor {
field this.balance = 0;
react {
assert account(this.balance);
dataflow {
console.log("Balance inside account is", this.balance);
@ -18,29 +16,21 @@ ground dataspace {
this.balance += amount;
}
}
}
actor {
react {
on asserted account($balance) {
console.log("Balance is now", balance);
}
}
}
actor {
react {
do {
on start {
console.log("Waiting for account.");
}
finally {
stop on asserted Syndicate.observe(deposit(_)) {
console.log("Account became ready.");
}
} until {
case asserted Syndicate.observe(deposit(_)) {
:: deposit(+100);
:: deposit(-30);
}
}
}
}

View File

@ -21,20 +21,19 @@ assertion type foo(x, y);
ground dataspace {
actor {
field this.x = 123;
react {
assert foo(this.x, 999);
during foo(this.x, $v) {
do {
on start {
console.log('x=', this.x, 'v=', v);
if (this.x === 123) {
this.x = 124;
}
}
finally {
on stop {
console.log('finally for x=', this.x, 'v=', v);
}
}
}
}
}

View File

@ -24,13 +24,12 @@ ground dataspace {
actor {
this.files = {};
react {
during Syndicate.observe(file($name, _)) {
do {
on start {
console.log("At least one reader exists for:", name);
}
assert file(name, field this.files[name]);
finally {
on stop {
console.log("No remaining readers exist for:", name);
}
}
@ -41,32 +40,29 @@ ground dataspace {
delete field this.files[name];
}
}
}
///////////////////////////////////////////////////////////////////////////
// A simple demo client of the file system
actor {
react {
on asserted file("hello.txt", $content) {
console.log("hello.txt has content", JSON.stringify(content));
}
} until {
case asserted file("hello.txt", "quit demo") {
stop on asserted file("hello.txt", "quit demo") {
console.log("The hello.txt file contained 'quit demo', so we will quit");
}
}
react until {
case asserted Syndicate.observe(saveFile(_, _)) {
actor {
stop on asserted Syndicate.observe(saveFile(_, _)) {
:: saveFile("hello.txt", "a");
:: deleteFile("hello.txt");
:: saveFile("hello.txt", "c");
:: saveFile("hello.txt", "quit demo");
:: saveFile("hello.txt", "final contents");
actor {
react until {
case asserted file("hello.txt", $content) {
stop on asserted file("hello.txt", $content) {
console.log("second observer sees that hello.txt content is",
JSON.stringify(content));
}
@ -74,5 +70,3 @@ ground dataspace {
}
}
}
}
}

View File

@ -60,33 +60,28 @@ assertion type view(str);
ground dataspace {
actor {
react {
field this.title = "first";
assert todo(this.title);
on message 3 {
this.title = "second";
}
}
}
actor {
react {
assert show();
}
}
actor {
react {
field this.editing = false;
during todo($title) {
do { console.log('OUTER++', title); }
on start { console.log('OUTER++', title); }
during show() {
do { console.log('++', title); }
on start { console.log('++', title); }
assert view((this.editing ? 'EDIT ' : 'VIEW ') + title);
finally { console.log('--', title); }
on stop { console.log('--', title); }
}
finally { console.log('OUTER--', title); }
on stop { console.log('OUTER--', title); }
}
on message 1 {
@ -99,20 +94,15 @@ ground dataspace {
this.editing = false;
}
}
}
actor {
react {
do { :: 0; }
} until {
case message 0 {
on start { :: 0; }
stop on message 0 {
:: 1;
}
}
}
actor {
react {
field this.count = 0;
on retracted view($x) { console.log('VIEW--', x); }
on asserted view($x) {
@ -127,4 +117,3 @@ ground dataspace {
}
}
}
}

View File

@ -15,33 +15,28 @@ assertion type entry(key, val);
ground dataspace {
actor named 'listener' {
react {
assert ready('listener');
on asserted entry($key, _) {
console.log('key asserted', key);
react {
on asserted entry(key, $value) { console.log('binding', key, '--->', value); }
on retracted entry(key, $value) { console.log('binding', key, '-/->', value); }
} until {
case retracted entry(key, _) {
stop on retracted entry(key, _) {
console.log('key retracted', key);
}
}
}
}
}
actor named 'other-listener' {
react {
assert ready('other-listener');
during entry($key, _) {
do { console.log('(other-listener) key asserted', key); }
on start { console.log('(other-listener) key asserted', key); }
during entry(key, $value) {
do { console.log('(other-listener) binding', key, '--->', value); }
finally { console.log('(other-listener) binding', key, '-/->', value); }
}
finally { console.log('(other-listener) key retracted', key); }
on start { console.log('(other-listener) binding', key, '--->', value); }
on stop { console.log('(other-listener) binding', key, '-/->', value); }
}
on stop { console.log('(other-listener) key retracted', key); }
}
}
@ -49,18 +44,16 @@ ground dataspace {
console.log('pause');
react {
assert ready('pause');
} until {
case asserted ready('pause') {
on asserted ready('pause') {
return k();
}
}
}
actor named 'driver' {
react until {
case asserted ready('listener') {
react until {
case asserted ready('other-listener') {
stop on asserted ready('listener') {
react {
stop on asserted ready('other-listener') {
Dataspace.stateChange(Patch.assert(entry('a', 1)));
Dataspace.stateChange(Patch.assert(entry('a', 2)));
Dataspace.stateChange(Patch.assert(entry('b', 3)));
@ -83,4 +76,3 @@ ground dataspace {
}
}
}
}

View File

@ -10,6 +10,7 @@ Syndicate <: ES5 {
+= ActorStatement
| DataspaceStatement
| ActorFacetStatement
| ActorEndpointStatement
| AssertionTypeDeclarationStatement
| FieldDeclarationStatement
| SendMessageStatement
@ -17,16 +18,29 @@ Syndicate <: ES5 {
FunctionBodyBlock = "{" FunctionBody "}" // odd that this isn't in es5.ohm somewhere
ActorStatement
= actor (named Expression<withIn>)? FunctionBodyBlock
= actorStar (named Expression<withIn>)? FunctionBodyBlock -- noReact
| actor (named Expression<withIn>)? FunctionBodyBlock -- withReact
DataspaceStatement
= ground dataspace identifier? FunctionBodyBlock -- ground
| dataspace FunctionBodyBlock -- normal
ActorFacetStatement
= react FacetBlock until FacetStateTransitionBlock -- state
| react until FacetStateTransitionBlock -- until
| react FacetBlock -- forever
= react FunctionBodyBlock
ActorEndpointStatement
= on start FunctionBodyBlock -- start
| on stop FunctionBodyBlock -- stop
| assert FacetPattern AssertWhenClause? #(sc) -- assert
| on FacetEventPattern FunctionBodyBlock -- event
| on event identifier FunctionBodyBlock -- onEvent
| stop on FacetTransitionEventPattern FunctionBodyBlock -- stopOnWithCont
| stop on FacetTransitionEventPattern #(sc) -- stopOnNoCont
| dataflow FunctionBodyBlock -- dataflow
| during FacetPattern FunctionBodyBlock -- during
| during FacetPattern actor (named Expression<withIn>)? FunctionBodyBlock -- duringActor
AssertWhenClause = when "(" Expression<withIn> ")"
AssertionTypeDeclarationStatement
= (assertion | message) type identifier "(" FormalParameterList ")" ("=" stringLiteral)? #(sc)
@ -37,30 +51,6 @@ Syndicate <: ES5 {
SendMessageStatement = "::" Expression<withIn> #(sc)
//---------------------------------------------------------------------------
// Ongoing event handlers.
FacetBlock = "{"
(VariableStatement | FieldDeclarationStatement | FunctionDeclaration)*
FacetInitBlock?
FacetSituation*
FacetDoneBlock?
"}"
FacetStateTransitionBlock = "{" FacetStateTransition* "}"
FacetInitBlock = do FunctionBodyBlock
FacetDoneBlock = finally FunctionBodyBlock
FacetSituation
= assert FacetPattern AssertWhenClause? #(sc) -- assert
| on FacetEventPattern FunctionBodyBlock -- event
| on event identifier FunctionBodyBlock -- onEvent
| dataflow FunctionBodyBlock -- dataflow
| during FacetPattern FacetBlock -- during
| during FacetPattern actor (named Expression<withIn>)? FacetBlock -- duringActor
AssertWhenClause = when "(" Expression<withIn> ")"
FacetEventPattern
= message FacetPattern -- messageEvent
| asserted FacetPattern -- assertedEvent
@ -70,10 +60,6 @@ Syndicate <: ES5 {
= FacetEventPattern -- facetEvent
| "(" Expression<withIn> ")" -- risingEdge
FacetStateTransition
= case FacetTransitionEventPattern FunctionBodyBlock -- withContinuation
| case FacetTransitionEventPattern #(sc) -- noContinuation
FacetPattern
= LeftHandSideExpression metalevel decimalIntegerLiteral -- withMetalevel
| LeftHandSideExpression -- noMetalevel
@ -83,7 +69,8 @@ Syndicate <: ES5 {
// we don't want to make them unavailable to programs as
// identifiers.
actor = "actor" ~identifierPart
actorStar = "actor*" ~identifierPart
actor = "actor" ~("*" | identifierPart)
assert = "assert" ~identifierPart
asserted = "asserted" ~identifierPart
assertion = "assertion" ~identifierPart
@ -99,7 +86,8 @@ Syndicate <: ES5 {
on = "on" ~identifierPart
react = "react" ~identifierPart
retracted = "retracted" ~identifierPart
start = "start" ~identifierPart
stop = "stop" ~identifierPart
type = "type" ~identifierPart
until = "until" ~identifierPart
when = "when" ~identifierPart
}

View File

@ -2,13 +2,11 @@ ground dataspace {
Syndicate.UI.spawnUIDriver();
actor {
field this.counter = 0;
var ui = new Syndicate.UI.Anchor();
react {
field this.counter = 0;
assert ui.html('#button-label', '' + this.counter);
on message Syndicate.UI.globalEvent('#counter', 'click', _) {
this.counter++;
}
}
}
}

View File

@ -19,7 +19,7 @@ function spawnChatApp() {
var ui = new Syndicate.UI.Anchor();
field this.nym;
field this.status;
react {
on asserted inputValue('#nym', $v) { this.nym = v; }
on asserted inputValue('#status', $v) { this.status = v; }
@ -53,7 +53,6 @@ function spawnChatApp() {
}
}
}
}
///////////////////////////////////////////////////////////////////////////
// Adding items to the transcript panel (plain Javascript/jQuery)
@ -84,7 +83,6 @@ assertion type inputValue(selector, value);
function spawnInputChangeMonitor() {
actor {
react {
during Syndicate.observe(inputValue($selector, _)) actor {
field this.value = $(selector).val();
assert inputValue(selector, this.value);
@ -94,7 +92,6 @@ function spawnInputChangeMonitor() {
}
}
}
}
///////////////////////////////////////////////////////////////////////////
// Main

View File

@ -11,27 +11,23 @@ assertion type componentPresent(name);
function spawnTV() {
actor {
var ui = new Syndicate.UI.Anchor();
react {
during tvAlert($text) {
assert ui.context(text).html('#tv', Mustache.render($('#alert_template').html(), { text: text }));
}
}
}
}
///////////////////////////////////////////////////////////////////////////
// Remote control and listener
function spawnRemoteControl() {
actor {
react {
assert componentPresent('remote control');
on message Syndicate.UI.globalEvent('#remote-control', 'click', _) {
:: remoteClick();
}
}
}
}
function spawnRemoteListener() {
actor {
@ -41,7 +37,6 @@ function spawnRemoteListener() {
// state, if we've been clicked, turn it off. We don't do this
// here, for simplicity.
react {
on asserted powerDraw($watts) {
this.stoveIsOn = watts > 0;
}
@ -53,7 +48,6 @@ function spawnRemoteListener() {
}
}
}
}
///////////////////////////////////////////////////////////////////////////
// Stove switch and power draw monitor
@ -62,7 +56,7 @@ function spawnStoveSwitch() {
actor {
field this.powerOn = false;
this.ui = new Syndicate.UI.Anchor();
react {
assert componentPresent('stove switch');
assert switchState(this.powerOn);
@ -77,9 +71,8 @@ function spawnStoveSwitch() {
on message switchAction($newState) {
this.powerOn = newState;
}
} until {
case message Syndicate.UI.globalEvent('#kill-stove-switch', 'click', _);
}
stop on message Syndicate.UI.globalEvent('#kill-stove-switch', 'click', _);
}
}
@ -87,7 +80,7 @@ function spawnPowerDrawMonitor() {
actor {
field this.watts = 0;
this.ui = new Syndicate.UI.Anchor();
react {
assert componentPresent('power draw monitor');
assert powerDraw(this.watts);
@ -97,9 +90,8 @@ function spawnPowerDrawMonitor() {
on asserted switchState($on) {
this.watts = on ? 1500 : 0;
}
} until {
case message Syndicate.UI.globalEvent('#kill-power-draw-monitor', 'click', _);
}
stop on message Syndicate.UI.globalEvent('#kill-power-draw-monitor', 'click', _);
}
}
@ -108,9 +100,8 @@ function spawnPowerDrawMonitor() {
function spawnTimeoutListener() {
actor {
react {
during powerDraw($watts) {
do {
on start {
if (watts > 0) {
var powerOnTime = Date.now();
react {
@ -126,11 +117,9 @@ function spawnTimeoutListener() {
}
}
}
}
// function spawnTimeoutListener() {
// actor {
// react {
// on asserted powerDraw($watts) {
// if (watts > 0) {
// var powerOnTime = Date.now();
@ -138,9 +127,7 @@ function spawnTimeoutListener() {
// on asserted Syndicate.Timer.timeLaterThan(powerOnTime + 3000) {
// react { assert tvAlert('Stove on too long?'); }
// }
// } until {
// case asserted powerDraw(0); // alt: on retracted powerDraw(watts);
// }
// stop on asserted powerDraw(0); // alt: on retracted powerDraw(watts);
// }
// }
// }
@ -151,7 +138,6 @@ function spawnTimeoutListener() {
// actor {
// this.mostRecentTime = 0;
// this.powerOnTime = null;
// react {
// on asserted powerDraw($watts) {
// this.powerOnTime = (watts > 0) ? this.mostRecentTime : null;
// }
@ -162,20 +148,16 @@ function spawnTimeoutListener() {
// when (this.powerOnTime !== null && this.mostRecentTime - this.powerOnTime > 3000);
// }
// }
// }
///////////////////////////////////////////////////////////////////////////
// Failure monitor
function spawnFailureMonitor() {
actor {
react {
on retracted componentPresent($who) {
react {
assert tvAlert('FAILURE: ' + who);
} until {
case asserted componentPresent(who);
}
stop on asserted componentPresent(who);
}
}
}
@ -185,7 +167,7 @@ function spawnFailureMonitor() {
// Chaos Monkey
function spawnChaosMonkey() {
actor {
actor* {
monitorComponent('power draw monitor',
'#spawn-power-draw-monitor',
'#kill-power-draw-monitor',
@ -201,11 +183,11 @@ function spawnChaosMonkey() {
var jKillButtons = $(killButtonSelector);
react {
during componentPresent(name) {
do {
on start {
jSpawnButtons.prop('disabled', true);
jKillButtons.prop('disabled', false);
}
finally {
on stop {
jSpawnButtons.prop('disabled', false);
jKillButtons.prop('disabled', true);
}

View File

@ -61,7 +61,6 @@ ground dataspace G {
timeout: 15000
}));
react {
field this.currentLocation = null;
var selectedMarker = null;
@ -117,7 +116,7 @@ ground dataspace G {
});
}
}
do {
on start {
marker.addListener('click', Syndicate.Dataspace.wrap(function () {
selectMarker();
}));
@ -138,11 +137,10 @@ ground dataspace G {
marker.setTitle(email + ' ' + latestTimestamp.toTimeString());
updateInfoWindow();
}
finally {
on stop {
marker.setMap(null);
if (selectedMarker === marker) selectedMarker = null;
}
}
}
}
}

View File

@ -23,7 +23,7 @@ ground dataspace G {
}
var wsurl = 'wss://demo-broker.syndicate-lang.org:8443/';
react {
assert brokerConnection(wsurl);
assert Syndicate.UI.uiAttribute('rect#my_color', 'fill', color);
@ -51,7 +51,6 @@ ground dataspace G {
}
}
}
}
// G.dataspace.setOnStateChange(function (mux, patch) {
// document.getElementById("ds-state").innerText = Syndicate.prettyTrie(mux.routingTable);

View File

@ -4,28 +4,23 @@ ground dataspace {
console.log('starting ground boot');
actor {
react until {
case asserted Syndicate.observe(beep(_)) {
stop on asserted Syndicate.observe(beep(_)) {
field this.counter = 0;
react {
do {
on start {
:: beep(this.counter++);
}
on message beep(_) {
:: beep(this.counter++);
}
} until {
case (this.counter > 10);
}
stop on (this.counter > 10);
}
}
}
actor {
react {
on message beep($counter) {
console.log("beep!", counter);
}
}
}
}

View File

@ -8,7 +8,6 @@ ground dataspace G {
field this.handX;
field this.handY;
react {
assert ui.html('#clock',
'<svg width="300px" viewBox="0 0 100 100">'+
'<circle fill="#0B79CE" r=45 cx=50 cy=50 />'+
@ -23,4 +22,3 @@ ground dataspace G {
}
}
}
}

View File

@ -3,11 +3,9 @@ message type setSortColumn(number);
function newRow(id, firstName, lastName, address, age) {
actor named ('model' + id) {
react {
assert person(id, firstName, lastName, address, age);
}
}
}
function spawnModel() {
newRow(1, 'Keith', 'Example', '94 Main St.', 44);
@ -27,7 +25,6 @@ function spawnView() {
return '<td>' + text + '</td>';
}
react {
on message setSortColumn($c) { this.orderColumn = c; }
during person($id, $firstName, $lastName, $address, $age) {
@ -38,17 +35,14 @@ function spawnView() {
}
}
}
}
function spawnController() {
actor named 'controller' {
react {
on message Syndicate.UI.globalEvent('table#the-table th', 'click', $e) {
:: setSortColumn(JSON.parse(e.target.dataset.column));
}
}
}
}
ground dataspace G {
Syndicate.UI.spawnUIDriver();

View File

@ -26,7 +26,6 @@ function piece(text, pos, lo, hi, cls) {
function spawnGui() {
actor {
react {
field this.text = '';
field this.pos = 0;
field this.highlightState = false;
@ -74,14 +73,12 @@ function spawnGui() {
}
}
}
}
///////////////////////////////////////////////////////////////////////////
// Textfield Model
function spawnModel() {
actor {
react {
field this.fieldValue = "initial";
field this.cursorPos = this.fieldValue.length; /* positions address gaps between characters */
@ -117,14 +114,12 @@ function spawnModel() {
}
}
}
}
///////////////////////////////////////////////////////////////////////////
// Search engine
function spawnSearch() {
actor {
react {
field this.searchtext = document.getElementById("searchBox").value;
field this.fieldValue = "";
field this.highlight = false;
@ -149,7 +144,6 @@ function spawnSearch() {
}
}
}
}
///////////////////////////////////////////////////////////////////////////
// Main

View File

@ -25,11 +25,12 @@ assertion type show(completed);
function todoListItemModel(initialId, initialTitle, initialCompleted) {
actor {
react {
field this.id = initialId;
field this.title = initialTitle;
field this.completed = initialCompleted;
stop on message deleteTodo(this.id);
assert todo(this.id, this.title, this.completed);
on message setCompleted(this.id, $v) { this.completed = v; }
@ -40,9 +41,6 @@ function todoListItemModel(initialId, initialTitle, initialCompleted) {
on message clearCompletedTodos() {
if (this.completed) :: deleteTodo(this.id);
}
} until {
case message deleteTodo(this.id);
}
}
}
@ -57,8 +55,9 @@ function getTemplate(id) {
function todoListItemView(id) {
actor {
stop on retracted todo(id, _, _);
this.ui = new Syndicate.UI.Anchor();
react {
field this.editing = false;
during todo(id, $title, $completed) {
@ -102,9 +101,6 @@ function todoListItemView(id) {
:: (newTitle ? setTitle(id, newTitle) : deleteTodo(id));
this.editing = false;
}
} until {
case retracted todo(id, _, _);
}
}
}
@ -114,19 +110,16 @@ ground dataspace G {
Syndicate.UI.spawnUIDriver();
actor {
react {
on message Syndicate.UI.globalEvent('.new-todo', 'change', $e) {
var newTitle = e.target.value.trim();
if (newTitle) :: createTodo(newTitle);
e.target.value = "";
}
}
}
actor {
this.ui = new Syndicate.UI.Anchor();
react {
during activeTodoCount($count) {
assert this.ui.context('count').html('.todo-count strong', '' + count);
assert this.ui.context('plural').html('.todo-count span.s', 's') when (count !== 1);
@ -145,8 +138,8 @@ ground dataspace G {
}
during allCompleted() {
do { :: Syndicate.UI.setProperty('.toggle-all', 'checked', true); }
finally { :: Syndicate.UI.setProperty('.toggle-all', 'checked', false); }
on start { :: Syndicate.UI.setProperty('.toggle-all', 'checked', true); }
on stop { :: Syndicate.UI.setProperty('.toggle-all', 'checked', false); }
}
on message Syndicate.UI.globalEvent('.toggle-all', 'change', $e) {
:: setAllCompleted(e.target.checked);
@ -156,10 +149,8 @@ ground dataspace G {
todoListItemView(id);
}
}
}
actor {
react {
field this.completedCount = 0;
field this.activeCount = 0;
on asserted todo($id, _, $c) { if (c) this.completedCount++; else this.activeCount++; }
@ -169,10 +160,8 @@ ground dataspace G {
assert totalTodoCount(this.activeCount + this.completedCount);
assert allCompleted() when (this.completedCount > 0 && this.activeCount === 0);
}
}
actor {
react {
during Syndicate.UI.locationHash($hash) {
assert Syndicate.UI.uiAttribute('ul.filters > li > a[href="#'+hash+'"]',
'class', 'selected');
@ -189,7 +178,6 @@ ground dataspace G {
assert show(true);
}
}
}
actor {
var db;
@ -202,32 +190,32 @@ ground dataspace G {
}
} else {
db = {nextId: 0, todos: {}};
react until {
case asserted Syndicate.observe(createTodo(_)) {
on start {
react {
stop on asserted Syndicate.observe(createTodo(_)) {
:: createTodo('Buy milk');
:: createTodo('Buy bread');
:: createTodo('Finish PhD');
}
}
}
}
react {
on message createTodo($title) {
todoListItemModel(db.nextId++, title, false);
}
during todo($id, _, _) {
during todo(id, $title, $completed) {
do {
on start {
db.todos[id] = {id: id, title: title, completed: completed};
localStorage['todos-syndicate'] = JSON.stringify(db);
}
}
finally {
on stop {
delete db.todos[id];
localStorage['todos-syndicate'] = JSON.stringify(db);
}
}
}
}
}

View File

@ -76,10 +76,9 @@ assertion type splitProposal(title, price, contribution, accepted);
/// core library.
///
function whileRelevantAssert(P) {
react {
actor {
assert P;
} until {
case retracted Syndicate.observe(P);
stop on retracted Syndicate.observe(P);
}
}
@ -117,15 +116,12 @@ function seller() {
/// The seller responds to interest in bookQuotes by asserting a
/// responsive record, if one exists.
react {
during Syndicate.observe(bookQuote($title, _)) {
assert bookQuote(title, this.priceOf(title));
}
}
/// It also responds to order requests.
react {
on asserted
Syndicate.observe(order($title, $offerPrice, _, _)) {
@ -144,20 +140,17 @@ function seller() {
var orderId = this.nextOrderId++;
delete field this.books[title];
actor {
whileRelevantAssert(
order(title, offerPrice, orderId, "March 9th"));
}
}
}
}
}
}
/// ### Implementation: SPLIT-PROPOSER and book-quote-requestor
function buyerA() {
actor {
actor* {
var self = this;
/// Our actor remembers which books remain on its shopping list, and
@ -184,8 +177,8 @@ function buyerA() {
/// First, retrieve a quote for the title, and analyze the result.
react until {
case asserted bookQuote(title, $price) {
react {
stop on asserted bookQuote(title, $price) {
if (price === false) {
console.log("A learns that "+title+" is out-of-stock.");
buyBooks();
@ -220,15 +213,15 @@ function buyerA() {
/// Make our proposal, and wait for a response.
react until {
case asserted
react {
stop on asserted
splitProposal(title, price, contribution, true) {
console.log("A learns that the split-proposal for "+
title+" was accepted");
buyBooks();
}
case asserted
stop on asserted
splitProposal(title, price, contribution, false) {
console.log("A learns that the split-proposal for "+
title+" was rejected");
@ -255,7 +248,6 @@ function buyerB() {
/// It spends its time waiting for a SPLIT-PROPOSER to offer a
/// `splitProposal`.
react {
on asserted
Syndicate.observe(splitProposal($title,
$price,
@ -285,7 +277,6 @@ function buyerB() {
this.funds = remainingFunds;
actor {
react {
/// While waiting for order confirmation, take the opportunity to
/// signal to our SPLIT-PROPOSER that we accepted their proposal.
@ -297,8 +288,7 @@ function buyerB() {
/// When order confirmation arrives, this purchase is completed.
} until {
case asserted order(title, price, $id, $date) {
stop on asserted order(title, price, $id, $date) {
console.log("The order for "+title+" has id "+id+
", and will be delivered on "+date);
}
@ -307,8 +297,6 @@ function buyerB() {
}
}
}
}
}
/// ### Starting Configuration

View File

@ -122,10 +122,6 @@ Actor.prototype.checkForTermination = function() {
//---------------------------------------------------------------------------
function createFacet() {
return new Facet(Dataspace.activeBehavior());
}
function Facet(actor) {
this.actor = actor;
this.endpoints = Immutable.Map();
@ -141,6 +137,12 @@ function Facet(actor) {
Facet.nextFid = 0;
Facet.current = null;
Facet.build = function(f) {
var facet = new Facet(Dataspace.activeBehavior());
withCurrentFacet(facet, f);
facet.completeBuild();
};
function withCurrentFacet(facet, f) {
var previousFacet = Facet.current;
Facet.current = facet;
@ -373,7 +375,7 @@ function deleteField(obj, prop) {
//---------------------------------------------------------------------------
module.exports.spawnActor = spawnActor;
module.exports.createFacet = createFacet;
module.exports.Facet = Facet;
module.exports.referenceField = referenceField;
module.exports.declareField = declareField;
module.exports.deleteField = deleteField;