actor{react{...}} ==> actor{...} for JS
This commit is contained in:
parent
c61ed644ce
commit
138bab9ba6
|
@ -42,28 +42,29 @@ var forEachChild = (function () {
|
||||||
return forEachChild;
|
return forEachChild;
|
||||||
})();
|
})();
|
||||||
|
|
||||||
function buildActor(nameExpOpt, block) {
|
function buildActor(nameExpOpt, block, withReact) {
|
||||||
var nameExpStr;
|
var nameExpStr;
|
||||||
if (nameExpOpt.numChildren === 1) {
|
if (nameExpOpt.numChildren === 1) {
|
||||||
nameExpStr = ', ' + nameExpOpt.asES5;
|
nameExpStr = ', ' + nameExpOpt.asES5;
|
||||||
} else {
|
} else {
|
||||||
nameExpStr = '';
|
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) {
|
function reactWrap(blockCode) {
|
||||||
return '(function () { ' + (facetBlock ? facetBlock.facetVarDecls : '') +
|
return '{ Syndicate.Actor.Facet.build((function () { ' +
|
||||||
'\nSyndicate.Actor.createFacet()' +
|
blockCode +
|
||||||
(facetBlock ? facetBlock.asES5 : '') +
|
' }).bind(this)); }';
|
||||||
(transitionBlock ? transitionBlock.asES5 : '') +
|
|
||||||
'.completeBuild(); }).call(this);';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function buildOnEvent(isTerminal, eventType, subscription, projection, bindings, body) {
|
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 +
|
subscription + ', ' + projection +
|
||||||
', (function(' + bindings.join(', ') + ') ' + body + '))';
|
', (function(' + bindings.join(', ') + ') ' + body + '));';
|
||||||
}
|
}
|
||||||
|
|
||||||
function buildCaseEvent(eventPattern, body) {
|
function buildCaseEvent(eventPattern, body) {
|
||||||
|
@ -85,8 +86,11 @@ function buildCaseEvent(eventPattern, body) {
|
||||||
}
|
}
|
||||||
|
|
||||||
var modifiedSourceActions = {
|
var modifiedSourceActions = {
|
||||||
ActorStatement: function(_actor, _namedOpt, nameExpOpt, block) {
|
ActorStatement_noReact: function(_actorStar, _namedOpt, nameExpOpt, block) {
|
||||||
return buildActor(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) {
|
DataspaceStatement_ground: function(_ground, _dataspace, maybeId, block) {
|
||||||
|
@ -101,14 +105,8 @@ var modifiedSourceActions = {
|
||||||
return 'Syndicate.Dataspace.spawn(new Dataspace(function () ' + block.asES5 + '));';
|
return 'Syndicate.Dataspace.spawn(new Dataspace(function () ' + block.asES5 + '));';
|
||||||
},
|
},
|
||||||
|
|
||||||
ActorFacetStatement_state: function(_state, facetBlock, _until, transitionBlock) {
|
ActorFacetStatement: function(_react, block) {
|
||||||
return buildFacet(facetBlock, transitionBlock);
|
return '(function () ' + reactWrap(block.asES5) + ').call(this);';
|
||||||
},
|
|
||||||
ActorFacetStatement_until: function(_react, _until, transitionBlock) {
|
|
||||||
return buildFacet(null, transitionBlock);
|
|
||||||
},
|
|
||||||
ActorFacetStatement_forever: function(_forever, facetBlock) {
|
|
||||||
return buildFacet(facetBlock, null);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
AssertionTypeDeclarationStatement: function(_assertion,
|
AssertionTypeDeclarationStatement: function(_assertion,
|
||||||
|
@ -151,24 +149,17 @@ var modifiedSourceActions = {
|
||||||
return 'Syndicate.Dataspace.send(' + expr.asES5 + ')' + sc.interval.contents;
|
return 'Syndicate.Dataspace.send(' + expr.asES5 + ')' + sc.interval.contents;
|
||||||
},
|
},
|
||||||
|
|
||||||
FacetBlock: function(_leftParen, _varStmts, init, situations, done, _rightParen) {
|
ActorEndpointStatement_start: function (_on, _start, block) {
|
||||||
return (init ? init.asES5 : '') + situations.asES5.join('') + (done ? done.asES5 : '');
|
return 'Syndicate.Actor.Facet.current.addInitBlock((function() ' + block.asES5 + '));';
|
||||||
},
|
},
|
||||||
FacetStateTransitionBlock: function(_leftParen, transitions, _rightParen) {
|
ActorEndpointStatement_stop: function (_on, _stop, block) {
|
||||||
return transitions.asES5.join('');
|
return 'Syndicate.Actor.Facet.current.addDoneBlock((function() ' + block.asES5 + '));';
|
||||||
},
|
},
|
||||||
|
ActorEndpointStatement_assert: function(_assert, expr, whenClause, _sc) {
|
||||||
FacetInitBlock: function(_init, block) {
|
return 'Syndicate.Actor.Facet.current.addAssertion(' +
|
||||||
return '\n.addInitBlock((function() ' + block.asES5 + '))';
|
buildSubscription([expr], 'assert', 'pattern', whenClause, null) + ');';
|
||||||
},
|
},
|
||||||
FacetDoneBlock: function(_done, block) {
|
ActorEndpointStatement_event: function(_on, eventPattern, 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) {
|
|
||||||
return buildOnEvent(false,
|
return buildOnEvent(false,
|
||||||
eventPattern.eventType,
|
eventPattern.eventType,
|
||||||
eventPattern.subscription,
|
eventPattern.subscription,
|
||||||
|
@ -176,63 +167,59 @@ var modifiedSourceActions = {
|
||||||
eventPattern.bindings,
|
eventPattern.bindings,
|
||||||
block.asES5);
|
block.asES5);
|
||||||
},
|
},
|
||||||
FacetSituation_onEvent: function (_on, _event, id, block) {
|
ActorEndpointStatement_onEvent: function (_on, _event, id, block) {
|
||||||
return '\n.addOnEventHandler((function(' + id.asES5 + ') ' + block.asES5 + '))';
|
return 'Syndicate.Actor.Facet.current.addOnEventHandler((function(' + id.asES5 + ') ' +
|
||||||
|
block.asES5 + '));';
|
||||||
},
|
},
|
||||||
FacetSituation_dataflow: function (_dataflow, block) {
|
ActorEndpointStatement_stopOnWithCont: function(_stop, _on, eventPattern, block) {
|
||||||
return '\n.addDataflow((function () ' + block.asES5 + '))';
|
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');
|
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 +
|
'{\n' +
|
||||||
'\nvar '+cachedAssertionVar+' = '+pattern.instantiatedAssertion+';'+
|
'var '+cachedAssertionVar+' = '+pattern.instantiatedAssertion+';\n'+
|
||||||
'\nSyndicate.Actor.createFacet()' +
|
reactWrap(block.asES5 + '\n' +
|
||||||
facetBlock.asES5 +
|
buildOnEvent(true,
|
||||||
buildOnEvent(true,
|
'retracted',
|
||||||
'retracted',
|
pattern.instantiatedSubscription(cachedAssertionVar),
|
||||||
pattern.instantiatedSubscription(cachedAssertionVar),
|
pattern.instantiatedProjection(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 cachedAssertionVar = gensym('cachedAssertion');
|
||||||
var actorBlock = {
|
var actorBlock = {
|
||||||
asES5: '{ ' + facetBlock.facetVarDecls +
|
asES5: reactWrap(block.asES5 + '\n' +
|
||||||
'\nSyndicate.Actor.createFacet()' +
|
buildOnEvent(true,
|
||||||
facetBlock.asES5 +
|
'retracted',
|
||||||
buildOnEvent(true,
|
pattern.instantiatedSubscription(cachedAssertionVar),
|
||||||
'retracted',
|
pattern.instantiatedProjection(cachedAssertionVar),
|
||||||
pattern.instantiatedSubscription(cachedAssertionVar),
|
[],
|
||||||
pattern.instantiatedProjection(cachedAssertionVar),
|
'{}'))
|
||||||
[],
|
|
||||||
'{}') +
|
|
||||||
'.completeBuild(); }'
|
|
||||||
};
|
};
|
||||||
return buildOnEvent(false,
|
return buildOnEvent(false,
|
||||||
'asserted',
|
'asserted',
|
||||||
pattern.subscription,
|
pattern.subscription,
|
||||||
pattern.projection,
|
pattern.projection,
|
||||||
pattern.bindings,
|
pattern.bindings,
|
||||||
'{ var '+cachedAssertionVar+' = '+pattern.instantiatedAssertion+';'+
|
'{ var '+cachedAssertionVar+' = '+pattern.instantiatedAssertion+';\n'+
|
||||||
'\n' + buildActor(nameExpOpt, actorBlock) + ' }');
|
buildActor(nameExpOpt, actorBlock, true) + ' }');
|
||||||
},
|
},
|
||||||
|
|
||||||
AssertWhenClause: function(_when, _lparen, expr, _rparen) {
|
AssertWhenClause: function(_when, _lparen, expr, _rparen) {
|
||||||
return expr.asES5;
|
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', {
|
semantics.addAttribute('asSyndicateStructureArguments', {
|
||||||
FormalParameterList: function(formals) {
|
FormalParameterList: function(formals) {
|
||||||
|
|
|
@ -8,39 +8,29 @@ message type deposit(amount);
|
||||||
ground dataspace {
|
ground dataspace {
|
||||||
actor {
|
actor {
|
||||||
field this.balance = 0;
|
field this.balance = 0;
|
||||||
|
assert account(this.balance);
|
||||||
react {
|
dataflow {
|
||||||
assert account(this.balance);
|
console.log("Balance inside account is", this.balance);
|
||||||
dataflow {
|
}
|
||||||
console.log("Balance inside account is", this.balance);
|
on message deposit($amount) {
|
||||||
}
|
this.balance += amount;
|
||||||
on message deposit($amount) {
|
|
||||||
this.balance += amount;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
actor {
|
actor {
|
||||||
react {
|
on asserted account($balance) {
|
||||||
on asserted account($balance) {
|
console.log("Balance is now", balance);
|
||||||
console.log("Balance is now", balance);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
actor {
|
actor {
|
||||||
react {
|
on start {
|
||||||
do {
|
console.log("Waiting for account.");
|
||||||
console.log("Waiting for account.");
|
}
|
||||||
}
|
stop on asserted Syndicate.observe(deposit(_)) {
|
||||||
finally {
|
console.log("Account became ready.");
|
||||||
console.log("Account became ready.");
|
:: deposit(+100);
|
||||||
}
|
:: deposit(-30);
|
||||||
} until {
|
|
||||||
case asserted Syndicate.observe(deposit(_)) {
|
|
||||||
:: deposit(+100);
|
|
||||||
:: deposit(-30);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,20 +21,19 @@ assertion type foo(x, y);
|
||||||
ground dataspace {
|
ground dataspace {
|
||||||
actor {
|
actor {
|
||||||
field this.x = 123;
|
field this.x = 123;
|
||||||
react {
|
|
||||||
assert foo(this.x, 999);
|
|
||||||
|
|
||||||
during foo(this.x, $v) {
|
assert foo(this.x, 999);
|
||||||
do {
|
|
||||||
console.log('x=', this.x, 'v=', v);
|
during foo(this.x, $v) {
|
||||||
if (this.x === 123) {
|
on start {
|
||||||
this.x = 124;
|
console.log('x=', this.x, 'v=', v);
|
||||||
}
|
if (this.x === 123) {
|
||||||
}
|
this.x = 124;
|
||||||
finally {
|
|
||||||
console.log('finally for x=', this.x, 'v=', v);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
on stop {
|
||||||
|
console.log('finally for x=', this.x, 'v=', v);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,53 +24,47 @@ ground dataspace {
|
||||||
|
|
||||||
actor {
|
actor {
|
||||||
this.files = {};
|
this.files = {};
|
||||||
react {
|
during Syndicate.observe(file($name, _)) {
|
||||||
during Syndicate.observe(file($name, _)) {
|
on start {
|
||||||
do {
|
console.log("At least one reader exists for:", name);
|
||||||
console.log("At least one reader exists for:", name);
|
|
||||||
}
|
|
||||||
assert file(name, field this.files[name]);
|
|
||||||
finally {
|
|
||||||
console.log("No remaining readers exist for:", name);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
on message saveFile($name, $newcontent) {
|
assert file(name, field this.files[name]);
|
||||||
field this.files[name] = newcontent;
|
on stop {
|
||||||
}
|
console.log("No remaining readers exist for:", name);
|
||||||
on message deleteFile($name) {
|
|
||||||
delete field this.files[name];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
on message saveFile($name, $newcontent) {
|
||||||
|
field this.files[name] = newcontent;
|
||||||
|
}
|
||||||
|
on message deleteFile($name) {
|
||||||
|
delete field this.files[name];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
// A simple demo client of the file system
|
// A simple demo client of the file system
|
||||||
|
|
||||||
actor {
|
actor {
|
||||||
react {
|
on asserted file("hello.txt", $content) {
|
||||||
on asserted file("hello.txt", $content) {
|
console.log("hello.txt has content", JSON.stringify(content));
|
||||||
console.log("hello.txt has content", JSON.stringify(content));
|
|
||||||
}
|
|
||||||
} until {
|
|
||||||
case asserted file("hello.txt", "quit demo") {
|
|
||||||
console.log("The hello.txt file contained 'quit demo', so we will quit");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
react until {
|
stop on asserted file("hello.txt", "quit demo") {
|
||||||
case asserted Syndicate.observe(saveFile(_, _)) {
|
console.log("The hello.txt file contained 'quit demo', so we will quit");
|
||||||
:: saveFile("hello.txt", "a");
|
}
|
||||||
:: deleteFile("hello.txt");
|
}
|
||||||
:: saveFile("hello.txt", "c");
|
|
||||||
:: saveFile("hello.txt", "quit demo");
|
actor {
|
||||||
:: saveFile("hello.txt", "final contents");
|
stop on asserted Syndicate.observe(saveFile(_, _)) {
|
||||||
actor {
|
:: saveFile("hello.txt", "a");
|
||||||
react until {
|
:: deleteFile("hello.txt");
|
||||||
case asserted file("hello.txt", $content) {
|
:: saveFile("hello.txt", "c");
|
||||||
console.log("second observer sees that hello.txt content is",
|
:: saveFile("hello.txt", "quit demo");
|
||||||
JSON.stringify(content));
|
:: saveFile("hello.txt", "final contents");
|
||||||
}
|
actor {
|
||||||
}
|
stop on asserted file("hello.txt", $content) {
|
||||||
|
console.log("second observer sees that hello.txt content is",
|
||||||
|
JSON.stringify(content));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -60,69 +60,58 @@ assertion type view(str);
|
||||||
|
|
||||||
ground dataspace {
|
ground dataspace {
|
||||||
actor {
|
actor {
|
||||||
react {
|
field this.title = "first";
|
||||||
field this.title = "first";
|
assert todo(this.title);
|
||||||
assert todo(this.title);
|
on message 3 {
|
||||||
on message 3 {
|
this.title = "second";
|
||||||
this.title = "second";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
actor {
|
actor {
|
||||||
react {
|
assert show();
|
||||||
assert show();
|
}
|
||||||
|
|
||||||
|
actor {
|
||||||
|
field this.editing = false;
|
||||||
|
|
||||||
|
during todo($title) {
|
||||||
|
on start { console.log('OUTER++', title); }
|
||||||
|
during show() {
|
||||||
|
on start { console.log('++', title); }
|
||||||
|
assert view((this.editing ? 'EDIT ' : 'VIEW ') + title);
|
||||||
|
on stop { console.log('--', title); }
|
||||||
|
}
|
||||||
|
on stop { console.log('OUTER--', title); }
|
||||||
|
}
|
||||||
|
|
||||||
|
on message 1 {
|
||||||
|
this.editing = true;
|
||||||
|
:: 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
on message 2 {
|
||||||
|
:: 3;
|
||||||
|
this.editing = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
actor {
|
actor {
|
||||||
react {
|
on start { :: 0; }
|
||||||
field this.editing = false;
|
stop on message 0 {
|
||||||
|
:: 1;
|
||||||
during todo($title) {
|
|
||||||
do { console.log('OUTER++', title); }
|
|
||||||
during show() {
|
|
||||||
do { console.log('++', title); }
|
|
||||||
assert view((this.editing ? 'EDIT ' : 'VIEW ') + title);
|
|
||||||
finally { console.log('--', title); }
|
|
||||||
}
|
|
||||||
finally { console.log('OUTER--', title); }
|
|
||||||
}
|
|
||||||
|
|
||||||
on message 1 {
|
|
||||||
this.editing = true;
|
|
||||||
:: 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
on message 2 {
|
|
||||||
:: 3;
|
|
||||||
this.editing = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
actor {
|
actor {
|
||||||
react {
|
field this.count = 0;
|
||||||
do { :: 0; }
|
on retracted view($x) { console.log('VIEW--', x); }
|
||||||
} until {
|
on asserted view($x) {
|
||||||
case message 0 {
|
console.log('VIEW++', x);
|
||||||
:: 1;
|
if (x === 'VIEW second') {
|
||||||
}
|
this.count++;
|
||||||
}
|
if (this.count === 1) {
|
||||||
}
|
console.log("Kicking off second edit cycle");
|
||||||
|
:: 1;
|
||||||
actor {
|
|
||||||
react {
|
|
||||||
field this.count = 0;
|
|
||||||
on retracted view($x) { console.log('VIEW--', x); }
|
|
||||||
on asserted view($x) {
|
|
||||||
console.log('VIEW++', x);
|
|
||||||
if (x === 'VIEW second') {
|
|
||||||
this.count++;
|
|
||||||
if (this.count === 1) {
|
|
||||||
console.log("Kicking off second edit cycle");
|
|
||||||
:: 1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,33 +15,28 @@ assertion type entry(key, val);
|
||||||
|
|
||||||
ground dataspace {
|
ground dataspace {
|
||||||
actor named 'listener' {
|
actor named 'listener' {
|
||||||
react {
|
assert ready('listener');
|
||||||
assert ready('listener');
|
on asserted entry($key, _) {
|
||||||
on asserted entry($key, _) {
|
console.log('key asserted', key);
|
||||||
console.log('key asserted', key);
|
react {
|
||||||
react {
|
on asserted entry(key, $value) { console.log('binding', key, '--->', value); }
|
||||||
on asserted entry(key, $value) { console.log('binding', key, '--->', value); }
|
on retracted entry(key, $value) { console.log('binding', key, '-/->', value); }
|
||||||
on retracted entry(key, $value) { console.log('binding', key, '-/->', value); }
|
stop on retracted entry(key, _) {
|
||||||
} until {
|
console.log('key retracted', key);
|
||||||
case retracted entry(key, _) {
|
|
||||||
console.log('key retracted', key);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
actor named 'other-listener' {
|
actor named 'other-listener' {
|
||||||
react {
|
assert ready('other-listener');
|
||||||
assert ready('other-listener');
|
during entry($key, _) {
|
||||||
during entry($key, _) {
|
on start { console.log('(other-listener) key asserted', key); }
|
||||||
do { console.log('(other-listener) key asserted', key); }
|
during entry(key, $value) {
|
||||||
during entry(key, $value) {
|
on start { console.log('(other-listener) binding', key, '--->', value); }
|
||||||
do { console.log('(other-listener) binding', key, '--->', value); }
|
on stop { console.log('(other-listener) binding', key, '-/->', value); }
|
||||||
finally { console.log('(other-listener) binding', key, '-/->', value); }
|
|
||||||
}
|
|
||||||
finally { console.log('(other-listener) key retracted', key); }
|
|
||||||
}
|
}
|
||||||
|
on stop { console.log('(other-listener) key retracted', key); }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -49,36 +44,33 @@ ground dataspace {
|
||||||
console.log('pause');
|
console.log('pause');
|
||||||
react {
|
react {
|
||||||
assert ready('pause');
|
assert ready('pause');
|
||||||
} until {
|
on asserted ready('pause') {
|
||||||
case asserted ready('pause') {
|
|
||||||
return k();
|
return k();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
actor named 'driver' {
|
actor named 'driver' {
|
||||||
react until {
|
stop on asserted ready('listener') {
|
||||||
case asserted ready('listener') {
|
react {
|
||||||
react until {
|
stop on asserted ready('other-listener') {
|
||||||
case asserted ready('other-listener') {
|
Dataspace.stateChange(Patch.assert(entry('a', 1)));
|
||||||
Dataspace.stateChange(Patch.assert(entry('a', 1)));
|
Dataspace.stateChange(Patch.assert(entry('a', 2)));
|
||||||
Dataspace.stateChange(Patch.assert(entry('a', 2)));
|
Dataspace.stateChange(Patch.assert(entry('b', 3)));
|
||||||
Dataspace.stateChange(Patch.assert(entry('b', 3)));
|
Dataspace.stateChange(Patch.assert(entry('c', 33)));
|
||||||
Dataspace.stateChange(Patch.assert(entry('c', 33)));
|
Dataspace.stateChange(Patch.assert(entry('a', 4)));
|
||||||
Dataspace.stateChange(Patch.assert(entry('a', 4)));
|
Dataspace.stateChange(Patch.assert(entry('a', 5)));
|
||||||
Dataspace.stateChange(Patch.assert(entry('a', 5)));
|
pause(function () {
|
||||||
|
Dataspace.stateChange(Patch.retract(entry('a', 2)));
|
||||||
|
Dataspace.stateChange(Patch.retract(entry('c', 33)));
|
||||||
|
Dataspace.stateChange(Patch.assert(entry('a', 9)));
|
||||||
pause(function () {
|
pause(function () {
|
||||||
Dataspace.stateChange(Patch.retract(entry('a', 2)));
|
Dataspace.stateChange(Patch.retract(entry('a', __)));
|
||||||
Dataspace.stateChange(Patch.retract(entry('c', 33)));
|
|
||||||
Dataspace.stateChange(Patch.assert(entry('a', 9)));
|
|
||||||
pause(function () {
|
pause(function () {
|
||||||
Dataspace.stateChange(Patch.retract(entry('a', __)));
|
console.log('done');
|
||||||
pause(function () {
|
|
||||||
console.log('done');
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,7 @@ Syndicate <: ES5 {
|
||||||
+= ActorStatement
|
+= ActorStatement
|
||||||
| DataspaceStatement
|
| DataspaceStatement
|
||||||
| ActorFacetStatement
|
| ActorFacetStatement
|
||||||
|
| ActorEndpointStatement
|
||||||
| AssertionTypeDeclarationStatement
|
| AssertionTypeDeclarationStatement
|
||||||
| FieldDeclarationStatement
|
| FieldDeclarationStatement
|
||||||
| SendMessageStatement
|
| SendMessageStatement
|
||||||
|
@ -17,16 +18,29 @@ Syndicate <: ES5 {
|
||||||
FunctionBodyBlock = "{" FunctionBody "}" // odd that this isn't in es5.ohm somewhere
|
FunctionBodyBlock = "{" FunctionBody "}" // odd that this isn't in es5.ohm somewhere
|
||||||
|
|
||||||
ActorStatement
|
ActorStatement
|
||||||
= actor (named Expression<withIn>)? FunctionBodyBlock
|
= actorStar (named Expression<withIn>)? FunctionBodyBlock -- noReact
|
||||||
|
| actor (named Expression<withIn>)? FunctionBodyBlock -- withReact
|
||||||
|
|
||||||
DataspaceStatement
|
DataspaceStatement
|
||||||
= ground dataspace identifier? FunctionBodyBlock -- ground
|
= ground dataspace identifier? FunctionBodyBlock -- ground
|
||||||
| dataspace FunctionBodyBlock -- normal
|
| dataspace FunctionBodyBlock -- normal
|
||||||
|
|
||||||
ActorFacetStatement
|
ActorFacetStatement
|
||||||
= react FacetBlock until FacetStateTransitionBlock -- state
|
= react FunctionBodyBlock
|
||||||
| react until FacetStateTransitionBlock -- until
|
|
||||||
| react FacetBlock -- forever
|
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
|
AssertionTypeDeclarationStatement
|
||||||
= (assertion | message) type identifier "(" FormalParameterList ")" ("=" stringLiteral)? #(sc)
|
= (assertion | message) type identifier "(" FormalParameterList ")" ("=" stringLiteral)? #(sc)
|
||||||
|
@ -37,30 +51,6 @@ Syndicate <: ES5 {
|
||||||
|
|
||||||
SendMessageStatement = "::" Expression<withIn> #(sc)
|
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
|
FacetEventPattern
|
||||||
= message FacetPattern -- messageEvent
|
= message FacetPattern -- messageEvent
|
||||||
| asserted FacetPattern -- assertedEvent
|
| asserted FacetPattern -- assertedEvent
|
||||||
|
@ -70,10 +60,6 @@ Syndicate <: ES5 {
|
||||||
= FacetEventPattern -- facetEvent
|
= FacetEventPattern -- facetEvent
|
||||||
| "(" Expression<withIn> ")" -- risingEdge
|
| "(" Expression<withIn> ")" -- risingEdge
|
||||||
|
|
||||||
FacetStateTransition
|
|
||||||
= case FacetTransitionEventPattern FunctionBodyBlock -- withContinuation
|
|
||||||
| case FacetTransitionEventPattern #(sc) -- noContinuation
|
|
||||||
|
|
||||||
FacetPattern
|
FacetPattern
|
||||||
= LeftHandSideExpression metalevel decimalIntegerLiteral -- withMetalevel
|
= LeftHandSideExpression metalevel decimalIntegerLiteral -- withMetalevel
|
||||||
| LeftHandSideExpression -- noMetalevel
|
| LeftHandSideExpression -- noMetalevel
|
||||||
|
@ -83,7 +69,8 @@ Syndicate <: ES5 {
|
||||||
// we don't want to make them unavailable to programs as
|
// we don't want to make them unavailable to programs as
|
||||||
// identifiers.
|
// identifiers.
|
||||||
|
|
||||||
actor = "actor" ~identifierPart
|
actorStar = "actor*" ~identifierPart
|
||||||
|
actor = "actor" ~("*" | identifierPart)
|
||||||
assert = "assert" ~identifierPart
|
assert = "assert" ~identifierPart
|
||||||
asserted = "asserted" ~identifierPart
|
asserted = "asserted" ~identifierPart
|
||||||
assertion = "assertion" ~identifierPart
|
assertion = "assertion" ~identifierPart
|
||||||
|
@ -99,7 +86,8 @@ Syndicate <: ES5 {
|
||||||
on = "on" ~identifierPart
|
on = "on" ~identifierPart
|
||||||
react = "react" ~identifierPart
|
react = "react" ~identifierPart
|
||||||
retracted = "retracted" ~identifierPart
|
retracted = "retracted" ~identifierPart
|
||||||
|
start = "start" ~identifierPart
|
||||||
|
stop = "stop" ~identifierPart
|
||||||
type = "type" ~identifierPart
|
type = "type" ~identifierPart
|
||||||
until = "until" ~identifierPart
|
|
||||||
when = "when" ~identifierPart
|
when = "when" ~identifierPart
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,13 +2,11 @@ ground dataspace {
|
||||||
Syndicate.UI.spawnUIDriver();
|
Syndicate.UI.spawnUIDriver();
|
||||||
|
|
||||||
actor {
|
actor {
|
||||||
field this.counter = 0;
|
|
||||||
var ui = new Syndicate.UI.Anchor();
|
var ui = new Syndicate.UI.Anchor();
|
||||||
react {
|
field this.counter = 0;
|
||||||
assert ui.html('#button-label', '' + this.counter);
|
assert ui.html('#button-label', '' + this.counter);
|
||||||
on message Syndicate.UI.globalEvent('#counter', 'click', _) {
|
on message Syndicate.UI.globalEvent('#counter', 'click', _) {
|
||||||
this.counter++;
|
this.counter++;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,37 +19,36 @@ function spawnChatApp() {
|
||||||
var ui = new Syndicate.UI.Anchor();
|
var ui = new Syndicate.UI.Anchor();
|
||||||
field this.nym;
|
field this.nym;
|
||||||
field this.status;
|
field this.status;
|
||||||
react {
|
|
||||||
on asserted inputValue('#nym', $v) { this.nym = v; }
|
|
||||||
on asserted inputValue('#status', $v) { this.status = v; }
|
|
||||||
|
|
||||||
on asserted brokerConnected($url) { outputState('connected to ' + url); }
|
on asserted inputValue('#nym', $v) { this.nym = v; }
|
||||||
on retracted brokerConnected($url) { outputState('disconnected from ' + url); }
|
on asserted inputValue('#status', $v) { this.status = v; }
|
||||||
|
|
||||||
during inputValue('#wsurl', $url) {
|
on asserted brokerConnected($url) { outputState('connected to ' + url); }
|
||||||
assert brokerConnection(url);
|
on retracted brokerConnected($url) { outputState('disconnected from ' + url); }
|
||||||
|
|
||||||
on message Syndicate.WakeDetector.wakeEvent() {
|
during inputValue('#wsurl', $url) {
|
||||||
:: forceBrokerDisconnect(url);
|
assert brokerConnection(url);
|
||||||
}
|
|
||||||
|
|
||||||
assert toBroker(url, present(this.nym, this.status));
|
on message Syndicate.WakeDetector.wakeEvent() {
|
||||||
during fromBroker(url, present($who, $status)) {
|
:: forceBrokerDisconnect(url);
|
||||||
assert ui.context(who, status)
|
}
|
||||||
.html('#nymlist',
|
|
||||||
Mustache.render($('#nym_template').html(), { who: who, status: status }));
|
|
||||||
}
|
|
||||||
|
|
||||||
on message Syndicate.UI.globalEvent('#send_chat', 'click', _) {
|
assert toBroker(url, present(this.nym, this.status));
|
||||||
var inp = $("#chat_input");
|
during fromBroker(url, present($who, $status)) {
|
||||||
var utterance = inp.val();
|
assert ui.context(who, status)
|
||||||
inp.val("");
|
.html('#nymlist',
|
||||||
if (utterance) :: toBroker(url, says(this.nym, utterance));
|
Mustache.render($('#nym_template').html(), { who: who, status: status }));
|
||||||
}
|
}
|
||||||
|
|
||||||
on message fromBroker(url, says($who, $what)) {
|
on message Syndicate.UI.globalEvent('#send_chat', 'click', _) {
|
||||||
outputUtterance(who, what);
|
var inp = $("#chat_input");
|
||||||
}
|
var utterance = inp.val();
|
||||||
|
inp.val("");
|
||||||
|
if (utterance) :: toBroker(url, says(this.nym, utterance));
|
||||||
|
}
|
||||||
|
|
||||||
|
on message fromBroker(url, says($who, $what)) {
|
||||||
|
outputUtterance(who, what);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -84,13 +83,11 @@ assertion type inputValue(selector, value);
|
||||||
|
|
||||||
function spawnInputChangeMonitor() {
|
function spawnInputChangeMonitor() {
|
||||||
actor {
|
actor {
|
||||||
react {
|
during Syndicate.observe(inputValue($selector, _)) actor {
|
||||||
during Syndicate.observe(inputValue($selector, _)) actor {
|
field this.value = $(selector).val();
|
||||||
field this.value = $(selector).val();
|
assert inputValue(selector, this.value);
|
||||||
assert inputValue(selector, this.value);
|
on message Syndicate.UI.globalEvent(selector, 'change', $e) {
|
||||||
on message Syndicate.UI.globalEvent(selector, 'change', $e) {
|
this.value = e.target.value;
|
||||||
this.value = e.target.value;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,10 +11,8 @@ assertion type componentPresent(name);
|
||||||
function spawnTV() {
|
function spawnTV() {
|
||||||
actor {
|
actor {
|
||||||
var ui = new Syndicate.UI.Anchor();
|
var ui = new Syndicate.UI.Anchor();
|
||||||
react {
|
during tvAlert($text) {
|
||||||
during tvAlert($text) {
|
assert ui.context(text).html('#tv', Mustache.render($('#alert_template').html(), { text: text }));
|
||||||
assert ui.context(text).html('#tv', Mustache.render($('#alert_template').html(), { text: text }));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -24,11 +22,9 @@ function spawnTV() {
|
||||||
|
|
||||||
function spawnRemoteControl() {
|
function spawnRemoteControl() {
|
||||||
actor {
|
actor {
|
||||||
react {
|
assert componentPresent('remote control');
|
||||||
assert componentPresent('remote control');
|
on message Syndicate.UI.globalEvent('#remote-control', 'click', _) {
|
||||||
on message Syndicate.UI.globalEvent('#remote-control', 'click', _) {
|
:: remoteClick();
|
||||||
:: remoteClick();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -41,15 +37,13 @@ function spawnRemoteListener() {
|
||||||
// state, if we've been clicked, turn it off. We don't do this
|
// state, if we've been clicked, turn it off. We don't do this
|
||||||
// here, for simplicity.
|
// here, for simplicity.
|
||||||
|
|
||||||
react {
|
on asserted powerDraw($watts) {
|
||||||
on asserted powerDraw($watts) {
|
this.stoveIsOn = watts > 0;
|
||||||
this.stoveIsOn = watts > 0;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
on message remoteClick() {
|
on message remoteClick() {
|
||||||
if (this.stoveIsOn) {
|
if (this.stoveIsOn) {
|
||||||
:: switchAction(false);
|
:: switchAction(false);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -62,24 +56,23 @@ function spawnStoveSwitch() {
|
||||||
actor {
|
actor {
|
||||||
field this.powerOn = false;
|
field this.powerOn = false;
|
||||||
this.ui = new Syndicate.UI.Anchor();
|
this.ui = new Syndicate.UI.Anchor();
|
||||||
react {
|
|
||||||
assert componentPresent('stove switch');
|
|
||||||
assert switchState(this.powerOn);
|
|
||||||
|
|
||||||
assert this.ui.html('#stove-switch',
|
assert componentPresent('stove switch');
|
||||||
Mustache.render($('#stove_element_template').html(),
|
assert switchState(this.powerOn);
|
||||||
{ imgurl: ("img/stove-coil-element-" +
|
|
||||||
(this.powerOn ? "hot" : "cold") + ".jpg") }));
|
|
||||||
|
|
||||||
on message Syndicate.UI.globalEvent('#stove-switch-on', 'click', _) { this.powerOn = true; }
|
assert this.ui.html('#stove-switch',
|
||||||
on message Syndicate.UI.globalEvent('#stove-switch-off', 'click', _) { this.powerOn = false; }
|
Mustache.render($('#stove_element_template').html(),
|
||||||
|
{ imgurl: ("img/stove-coil-element-" +
|
||||||
|
(this.powerOn ? "hot" : "cold") + ".jpg") }));
|
||||||
|
|
||||||
on message switchAction($newState) {
|
on message Syndicate.UI.globalEvent('#stove-switch-on', 'click', _) { this.powerOn = true; }
|
||||||
this.powerOn = newState;
|
on message Syndicate.UI.globalEvent('#stove-switch-off', 'click', _) { this.powerOn = false; }
|
||||||
}
|
|
||||||
} until {
|
on message switchAction($newState) {
|
||||||
case message Syndicate.UI.globalEvent('#kill-stove-switch', 'click', _);
|
this.powerOn = newState;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
stop on message Syndicate.UI.globalEvent('#kill-stove-switch', 'click', _);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -87,19 +80,18 @@ function spawnPowerDrawMonitor() {
|
||||||
actor {
|
actor {
|
||||||
field this.watts = 0;
|
field this.watts = 0;
|
||||||
this.ui = new Syndicate.UI.Anchor();
|
this.ui = new Syndicate.UI.Anchor();
|
||||||
react {
|
|
||||||
assert componentPresent('power draw monitor');
|
|
||||||
assert powerDraw(this.watts);
|
|
||||||
|
|
||||||
assert this.ui.html('#power-draw-meter',
|
assert componentPresent('power draw monitor');
|
||||||
Mustache.render($('#power_draw_template').html(), { watts: this.watts }));
|
assert powerDraw(this.watts);
|
||||||
|
|
||||||
on asserted switchState($on) {
|
assert this.ui.html('#power-draw-meter',
|
||||||
this.watts = on ? 1500 : 0;
|
Mustache.render($('#power_draw_template').html(), { watts: this.watts }));
|
||||||
}
|
|
||||||
} until {
|
on asserted switchState($on) {
|
||||||
case message Syndicate.UI.globalEvent('#kill-power-draw-monitor', 'click', _);
|
this.watts = on ? 1500 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
stop on message Syndicate.UI.globalEvent('#kill-power-draw-monitor', 'click', _);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -108,18 +100,16 @@ function spawnPowerDrawMonitor() {
|
||||||
|
|
||||||
function spawnTimeoutListener() {
|
function spawnTimeoutListener() {
|
||||||
actor {
|
actor {
|
||||||
react {
|
during powerDraw($watts) {
|
||||||
during powerDraw($watts) {
|
on start {
|
||||||
do {
|
if (watts > 0) {
|
||||||
if (watts > 0) {
|
var powerOnTime = Date.now();
|
||||||
var powerOnTime = Date.now();
|
react {
|
||||||
react {
|
on asserted Syndicate.Timer.timeLaterThan(powerOnTime + 3000) {
|
||||||
on asserted Syndicate.Timer.timeLaterThan(powerOnTime + 3000) {
|
react { assert tvAlert('Stove on too long?'); }
|
||||||
react { assert tvAlert('Stove on too long?'); }
|
}
|
||||||
}
|
on asserted Syndicate.Timer.timeLaterThan(powerOnTime + 10000) {
|
||||||
on asserted Syndicate.Timer.timeLaterThan(powerOnTime + 10000) {
|
$("img.flames").show();
|
||||||
$("img.flames").show();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -130,17 +120,14 @@ function spawnTimeoutListener() {
|
||||||
|
|
||||||
// function spawnTimeoutListener() {
|
// function spawnTimeoutListener() {
|
||||||
// actor {
|
// actor {
|
||||||
// react {
|
// on asserted powerDraw($watts) {
|
||||||
// on asserted powerDraw($watts) {
|
// if (watts > 0) {
|
||||||
// if (watts > 0) {
|
// var powerOnTime = Date.now();
|
||||||
// var powerOnTime = Date.now();
|
// react {
|
||||||
// react {
|
// on asserted Syndicate.Timer.timeLaterThan(powerOnTime + 3000) {
|
||||||
// on asserted Syndicate.Timer.timeLaterThan(powerOnTime + 3000) {
|
// react { assert tvAlert('Stove on too long?'); }
|
||||||
// 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,16 +138,14 @@ function spawnTimeoutListener() {
|
||||||
// actor {
|
// actor {
|
||||||
// this.mostRecentTime = 0;
|
// this.mostRecentTime = 0;
|
||||||
// this.powerOnTime = null;
|
// this.powerOnTime = null;
|
||||||
// react {
|
// on asserted powerDraw($watts) {
|
||||||
// on asserted powerDraw($watts) {
|
// this.powerOnTime = (watts > 0) ? this.mostRecentTime : null;
|
||||||
// this.powerOnTime = (watts > 0) ? this.mostRecentTime : null;
|
|
||||||
// }
|
|
||||||
// on message Syndicate.Timer.periodicTick(200) {
|
|
||||||
// this.mostRecentTime = Date.now();
|
|
||||||
// }
|
|
||||||
// assert tvAlert('Stove on too long?')
|
|
||||||
// when (this.powerOnTime !== null && this.mostRecentTime - this.powerOnTime > 3000);
|
|
||||||
// }
|
// }
|
||||||
|
// on message Syndicate.Timer.periodicTick(200) {
|
||||||
|
// this.mostRecentTime = Date.now();
|
||||||
|
// }
|
||||||
|
// assert tvAlert('Stove on too long?')
|
||||||
|
// when (this.powerOnTime !== null && this.mostRecentTime - this.powerOnTime > 3000);
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
|
|
||||||
|
@ -169,13 +154,10 @@ function spawnTimeoutListener() {
|
||||||
|
|
||||||
function spawnFailureMonitor() {
|
function spawnFailureMonitor() {
|
||||||
actor {
|
actor {
|
||||||
react {
|
on retracted componentPresent($who) {
|
||||||
on retracted componentPresent($who) {
|
react {
|
||||||
react {
|
assert tvAlert('FAILURE: ' + who);
|
||||||
assert tvAlert('FAILURE: ' + who);
|
stop on asserted componentPresent(who);
|
||||||
} until {
|
|
||||||
case asserted componentPresent(who);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -185,7 +167,7 @@ function spawnFailureMonitor() {
|
||||||
// Chaos Monkey
|
// Chaos Monkey
|
||||||
|
|
||||||
function spawnChaosMonkey() {
|
function spawnChaosMonkey() {
|
||||||
actor {
|
actor* {
|
||||||
monitorComponent('power draw monitor',
|
monitorComponent('power draw monitor',
|
||||||
'#spawn-power-draw-monitor',
|
'#spawn-power-draw-monitor',
|
||||||
'#kill-power-draw-monitor',
|
'#kill-power-draw-monitor',
|
||||||
|
@ -201,11 +183,11 @@ function spawnChaosMonkey() {
|
||||||
var jKillButtons = $(killButtonSelector);
|
var jKillButtons = $(killButtonSelector);
|
||||||
react {
|
react {
|
||||||
during componentPresent(name) {
|
during componentPresent(name) {
|
||||||
do {
|
on start {
|
||||||
jSpawnButtons.prop('disabled', true);
|
jSpawnButtons.prop('disabled', true);
|
||||||
jKillButtons.prop('disabled', false);
|
jKillButtons.prop('disabled', false);
|
||||||
}
|
}
|
||||||
finally {
|
on stop {
|
||||||
jSpawnButtons.prop('disabled', false);
|
jSpawnButtons.prop('disabled', false);
|
||||||
jKillButtons.prop('disabled', true);
|
jKillButtons.prop('disabled', true);
|
||||||
}
|
}
|
||||||
|
|
|
@ -61,87 +61,85 @@ ground dataspace G {
|
||||||
timeout: 15000
|
timeout: 15000
|
||||||
}));
|
}));
|
||||||
|
|
||||||
react {
|
field this.currentLocation = null;
|
||||||
field this.currentLocation = null;
|
var selectedMarker = null;
|
||||||
var selectedMarker = null;
|
|
||||||
|
|
||||||
assert brokerConnection(this.wsurl);
|
assert brokerConnection(this.wsurl);
|
||||||
assert toBroker(this.wsurl, this.currentLocation) when (this.currentLocation);
|
assert toBroker(this.wsurl, this.currentLocation) when (this.currentLocation);
|
||||||
|
|
||||||
on message Syndicate.UI.globalEvent('#my_email', 'change', _) {
|
on message Syndicate.UI.globalEvent('#my_email', 'change', _) {
|
||||||
var v = email_element.value.trim();
|
var v = email_element.value.trim();
|
||||||
if (this.currentLocation) this.currentLocation = this.currentLocation.set(1, v);
|
if (this.currentLocation) this.currentLocation = this.currentLocation.set(1, v);
|
||||||
localStorage.my_email = v;
|
localStorage.my_email = v;
|
||||||
|
}
|
||||||
|
|
||||||
|
on message Syndicate.UI.globalEvent('#group', 'change', _) {
|
||||||
|
localStorage.group = group_element.value.trim();
|
||||||
|
this.wsurl = wsurl_base + group_element.value.trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
on message Syndicate.UI.globalEvent('#findMarker', 'click', $e) {
|
||||||
|
:: findMarker(document.getElementById('markerList').value);
|
||||||
|
}
|
||||||
|
on message Syndicate.UI.globalEvent('#markerList', 'change', $e) {
|
||||||
|
:: findMarker(document.getElementById('markerList').value);
|
||||||
|
}
|
||||||
|
|
||||||
|
on message ($loc = locationRecord(_, _, _, _, _)) {
|
||||||
|
this.currentLocation = loc;
|
||||||
|
}
|
||||||
|
|
||||||
|
during fromBroker(this.wsurl, locationRecord($id, $email, _, _, _)) {
|
||||||
|
var ui = new Syndicate.UI.Anchor();
|
||||||
|
var marker = new google.maps.Marker({
|
||||||
|
map: map,
|
||||||
|
clickable: true,
|
||||||
|
icon: 'https://www.gravatar.com/avatar/' + md5(email.trim().toLowerCase()) + '?s=32&d=retro'
|
||||||
|
});
|
||||||
|
var latestTimestamp = null;
|
||||||
|
var latestPosition = null;
|
||||||
|
function selectMarker() {
|
||||||
|
selectedMarker = marker;
|
||||||
|
updateInfoWindow();
|
||||||
|
infoWindow.open(map, marker);
|
||||||
}
|
}
|
||||||
|
function updateInfoWindow() {
|
||||||
on message Syndicate.UI.globalEvent('#group', 'change', _) {
|
if (selectedMarker === marker && latestPosition && latestTimestamp) {
|
||||||
localStorage.group = group_element.value.trim();
|
geocoder.geocode({'location': latestPosition}, function (results, status) {
|
||||||
this.wsurl = wsurl_base + group_element.value.trim();
|
if (status === google.maps.GeocoderStatus.OK && results[0]) {
|
||||||
}
|
infoWindow.setContent(Mustache.render(document.getElementById('info').innerHTML, {
|
||||||
|
email: email,
|
||||||
on message Syndicate.UI.globalEvent('#findMarker', 'click', $e) {
|
timestamp: latestTimestamp ? latestTimestamp.toString() : '',
|
||||||
:: findMarker(document.getElementById('markerList').value);
|
address: results[0].formatted_address
|
||||||
}
|
}));
|
||||||
on message Syndicate.UI.globalEvent('#markerList', 'change', $e) {
|
}
|
||||||
:: findMarker(document.getElementById('markerList').value);
|
});
|
||||||
}
|
|
||||||
|
|
||||||
on message ($loc = locationRecord(_, _, _, _, _)) {
|
|
||||||
this.currentLocation = loc;
|
|
||||||
}
|
|
||||||
|
|
||||||
during fromBroker(this.wsurl, locationRecord($id, $email, _, _, _)) {
|
|
||||||
var ui = new Syndicate.UI.Anchor();
|
|
||||||
var marker = new google.maps.Marker({
|
|
||||||
map: map,
|
|
||||||
clickable: true,
|
|
||||||
icon: 'https://www.gravatar.com/avatar/' + md5(email.trim().toLowerCase()) + '?s=32&d=retro'
|
|
||||||
});
|
|
||||||
var latestTimestamp = null;
|
|
||||||
var latestPosition = null;
|
|
||||||
function selectMarker() {
|
|
||||||
selectedMarker = marker;
|
|
||||||
updateInfoWindow();
|
|
||||||
infoWindow.open(map, marker);
|
|
||||||
}
|
}
|
||||||
function updateInfoWindow() {
|
}
|
||||||
if (selectedMarker === marker && latestPosition && latestTimestamp) {
|
on start {
|
||||||
geocoder.geocode({'location': latestPosition}, function (results, status) {
|
marker.addListener('click', Syndicate.Dataspace.wrap(function () {
|
||||||
if (status === google.maps.GeocoderStatus.OK && results[0]) {
|
|
||||||
infoWindow.setContent(Mustache.render(document.getElementById('info').innerHTML, {
|
|
||||||
email: email,
|
|
||||||
timestamp: latestTimestamp ? latestTimestamp.toString() : '',
|
|
||||||
address: results[0].formatted_address
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
do {
|
|
||||||
marker.addListener('click', Syndicate.Dataspace.wrap(function () {
|
|
||||||
selectMarker();
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
assert ui.html('#markerList',
|
|
||||||
Mustache.render(document.getElementById('markerList-option').innerHTML, {
|
|
||||||
id: id,
|
|
||||||
email: email
|
|
||||||
}));
|
|
||||||
on message findMarker(id) {
|
|
||||||
selectMarker();
|
selectMarker();
|
||||||
if (latestPosition) map.panTo(latestPosition);
|
}));
|
||||||
}
|
}
|
||||||
on asserted fromBroker(this.wsurl, locationRecord(id, email, $timestamp, $lat, $lng)) {
|
assert ui.html('#markerList',
|
||||||
latestTimestamp = new Date(timestamp);
|
Mustache.render(document.getElementById('markerList-option').innerHTML, {
|
||||||
latestPosition = {lat: lat, lng: lng};
|
id: id,
|
||||||
marker.setPosition(latestPosition);
|
email: email
|
||||||
marker.setTitle(email + ' ' + latestTimestamp.toTimeString());
|
}));
|
||||||
updateInfoWindow();
|
on message findMarker(id) {
|
||||||
}
|
selectMarker();
|
||||||
finally {
|
if (latestPosition) map.panTo(latestPosition);
|
||||||
marker.setMap(null);
|
}
|
||||||
if (selectedMarker === marker) selectedMarker = null;
|
on asserted fromBroker(this.wsurl, locationRecord(id, email, $timestamp, $lat, $lng)) {
|
||||||
}
|
latestTimestamp = new Date(timestamp);
|
||||||
|
latestPosition = {lat: lat, lng: lng};
|
||||||
|
marker.setPosition(latestPosition);
|
||||||
|
marker.setTitle(email + ' ' + latestTimestamp.toTimeString());
|
||||||
|
updateInfoWindow();
|
||||||
|
}
|
||||||
|
on stop {
|
||||||
|
marker.setMap(null);
|
||||||
|
if (selectedMarker === marker) selectedMarker = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,32 +23,31 @@ ground dataspace G {
|
||||||
}
|
}
|
||||||
|
|
||||||
var wsurl = 'wss://demo-broker.syndicate-lang.org:8443/';
|
var wsurl = 'wss://demo-broker.syndicate-lang.org:8443/';
|
||||||
react {
|
|
||||||
assert brokerConnection(wsurl);
|
|
||||||
|
|
||||||
assert Syndicate.UI.uiAttribute('rect#my_color', 'fill', color);
|
assert brokerConnection(wsurl);
|
||||||
|
|
||||||
assert toBroker(wsurl, point(color, this.publishedX, this.publishedY));
|
assert Syndicate.UI.uiAttribute('rect#my_color', 'fill', color);
|
||||||
on message Syndicate.Timer.periodicTick(100) {
|
|
||||||
this.publishedX = x;
|
|
||||||
this.publishedY = y;
|
|
||||||
}
|
|
||||||
|
|
||||||
on message Syndicate.UI.windowEvent('deviceorientation', $e) {
|
assert toBroker(wsurl, point(color, this.publishedX, this.publishedY));
|
||||||
var scale = 0.5;
|
on message Syndicate.Timer.periodicTick(100) {
|
||||||
x = clamp(e.gamma * scale);
|
this.publishedX = x;
|
||||||
y = clamp((e.beta - 40) * scale);
|
this.publishedY = y;
|
||||||
}
|
}
|
||||||
|
|
||||||
during fromBroker(wsurl, point($oc, $ox, $oy)) {
|
on message Syndicate.UI.windowEvent('deviceorientation', $e) {
|
||||||
assert ui.context(oc)
|
var scale = 0.5;
|
||||||
.html('#container',
|
x = clamp(e.gamma * scale);
|
||||||
Mustache.render(document.getElementById('circle-template').innerHTML, {
|
y = clamp((e.beta - 40) * scale);
|
||||||
color: oc,
|
}
|
||||||
x: ox,
|
|
||||||
y: oy
|
during fromBroker(wsurl, point($oc, $ox, $oy)) {
|
||||||
}));
|
assert ui.context(oc)
|
||||||
}
|
.html('#container',
|
||||||
|
Mustache.render(document.getElementById('circle-template').innerHTML, {
|
||||||
|
color: oc,
|
||||||
|
x: ox,
|
||||||
|
y: oy
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,28 +4,23 @@ ground dataspace {
|
||||||
console.log('starting ground boot');
|
console.log('starting ground boot');
|
||||||
|
|
||||||
actor {
|
actor {
|
||||||
react until {
|
stop on asserted Syndicate.observe(beep(_)) {
|
||||||
case asserted Syndicate.observe(beep(_)) {
|
field this.counter = 0;
|
||||||
field this.counter = 0;
|
react {
|
||||||
react {
|
on start {
|
||||||
do {
|
:: beep(this.counter++);
|
||||||
:: beep(this.counter++);
|
|
||||||
}
|
|
||||||
on message beep(_) {
|
|
||||||
:: beep(this.counter++);
|
|
||||||
}
|
|
||||||
} until {
|
|
||||||
case (this.counter > 10);
|
|
||||||
}
|
}
|
||||||
|
on message beep(_) {
|
||||||
|
:: beep(this.counter++);
|
||||||
|
}
|
||||||
|
stop on (this.counter > 10);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
actor {
|
actor {
|
||||||
react {
|
on message beep($counter) {
|
||||||
on message beep($counter) {
|
console.log("beep!", counter);
|
||||||
console.log("beep!", counter);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,19 +8,17 @@ ground dataspace G {
|
||||||
field this.handX;
|
field this.handX;
|
||||||
field this.handY;
|
field this.handY;
|
||||||
|
|
||||||
react {
|
assert ui.html('#clock',
|
||||||
assert ui.html('#clock',
|
'<svg width="300px" viewBox="0 0 100 100">'+
|
||||||
'<svg width="300px" viewBox="0 0 100 100">'+
|
'<circle fill="#0B79CE" r=45 cx=50 cy=50 />'+
|
||||||
'<circle fill="#0B79CE" r=45 cx=50 cy=50 />'+
|
'<line stroke="#023963" x1=50 y1=50 x2='+this.handX+' y2='+this.handY+' />'+
|
||||||
'<line stroke="#023963" x1=50 y1=50 x2='+this.handX+' y2='+this.handY+' />'+
|
'</svg>')
|
||||||
'</svg>')
|
|
||||||
when (typeof this.angle === 'number');
|
when (typeof this.angle === 'number');
|
||||||
|
|
||||||
on message Syndicate.Timer.periodicTick(1000) {
|
on message Syndicate.Timer.periodicTick(1000) {
|
||||||
this.angle = ((((Date.now() / 1000) % 60) / 60) - 0.25) * 2 * Math.PI;
|
this.angle = ((((Date.now() / 1000) % 60) / 60) - 0.25) * 2 * Math.PI;
|
||||||
this.handX = 50 + 40 * Math.cos(this.angle);
|
this.handX = 50 + 40 * Math.cos(this.angle);
|
||||||
this.handY = 50 + 40 * Math.sin(this.angle);
|
this.handY = 50 + 40 * Math.sin(this.angle);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,9 +3,7 @@ message type setSortColumn(number);
|
||||||
|
|
||||||
function newRow(id, firstName, lastName, address, age) {
|
function newRow(id, firstName, lastName, address, age) {
|
||||||
actor named ('model' + id) {
|
actor named ('model' + id) {
|
||||||
react {
|
assert person(id, firstName, lastName, address, age);
|
||||||
assert person(id, firstName, lastName, address, age);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,25 +25,21 @@ function spawnView() {
|
||||||
return '<td>' + text + '</td>';
|
return '<td>' + text + '</td>';
|
||||||
}
|
}
|
||||||
|
|
||||||
react {
|
on message setSortColumn($c) { this.orderColumn = c; }
|
||||||
on message setSortColumn($c) { this.orderColumn = c; }
|
|
||||||
|
|
||||||
during person($id, $firstName, $lastName, $address, $age) {
|
during person($id, $firstName, $lastName, $address, $age) {
|
||||||
assert ui.context(id)
|
assert ui.context(id)
|
||||||
.html('table#the-table tbody',
|
.html('table#the-table tbody',
|
||||||
'<tr>' + [id, firstName, lastName, address, age].map(cell).join('') + '</tr>',
|
'<tr>' + [id, firstName, lastName, address, age].map(cell).join('') + '</tr>',
|
||||||
[id, firstName, lastName, address, age][this.orderColumn]);
|
[id, firstName, lastName, address, age][this.orderColumn]);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function spawnController() {
|
function spawnController() {
|
||||||
actor named 'controller' {
|
actor named 'controller' {
|
||||||
react {
|
on message Syndicate.UI.globalEvent('table#the-table th', 'click', $e) {
|
||||||
on message Syndicate.UI.globalEvent('table#the-table th', 'click', $e) {
|
:: setSortColumn(JSON.parse(e.target.dataset.column));
|
||||||
:: setSortColumn(JSON.parse(e.target.dataset.column));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,52 +26,50 @@ function piece(text, pos, lo, hi, cls) {
|
||||||
|
|
||||||
function spawnGui() {
|
function spawnGui() {
|
||||||
actor {
|
actor {
|
||||||
react {
|
field this.text = '';
|
||||||
field this.text = '';
|
field this.pos = 0;
|
||||||
field this.pos = 0;
|
field this.highlightState = false;
|
||||||
field this.highlightState = false;
|
|
||||||
|
|
||||||
dataflow {
|
dataflow {
|
||||||
var text = this.text;
|
var text = this.text;
|
||||||
var pos = this.pos;
|
var pos = this.pos;
|
||||||
var highlight = this.highlightState;
|
var highlight = this.highlightState;
|
||||||
var hLeft = highlight ? highlight[0] : 0;
|
var hLeft = highlight ? highlight[0] : 0;
|
||||||
var hRight = highlight ? highlight[1] : 0;
|
var hRight = highlight ? highlight[1] : 0;
|
||||||
document.getElementById("fieldContents").innerHTML = highlight
|
document.getElementById("fieldContents").innerHTML = highlight
|
||||||
? piece(text, pos, 0, hLeft, "normal") +
|
? piece(text, pos, 0, hLeft, "normal") +
|
||||||
piece(text, pos, hLeft, hRight, "highlight") +
|
piece(text, pos, hLeft, hRight, "highlight") +
|
||||||
piece(text, pos, hRight, text.length + 1, "normal")
|
piece(text, pos, hRight, text.length + 1, "normal")
|
||||||
: piece(text, pos, 0, text.length + 1, "normal");
|
: piece(text, pos, 0, text.length + 1, "normal");
|
||||||
}
|
}
|
||||||
|
|
||||||
on message globalEvent("#inputRow", "+keydown", $event) {
|
on message globalEvent("#inputRow", "+keydown", $event) {
|
||||||
switch (event.keyCode) {
|
switch (event.keyCode) {
|
||||||
case 37 /* left */: :: fieldCommand("cursorLeft"); break;
|
case 37 /* left */: :: fieldCommand("cursorLeft"); break;
|
||||||
case 39 /* right */: :: fieldCommand("cursorRight"); break;
|
case 39 /* right */: :: fieldCommand("cursorRight"); break;
|
||||||
case 9 /* tab */: /* ignore */ break;
|
case 9 /* tab */: /* ignore */ break;
|
||||||
case 8 /* backspace */:
|
case 8 /* backspace */:
|
||||||
event.preventDefault(); // that this works here is a minor miracle
|
event.preventDefault(); // that this works here is a minor miracle
|
||||||
:: fieldCommand("backspace");
|
:: fieldCommand("backspace");
|
||||||
break;
|
break;
|
||||||
default: break;
|
default: break;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
on message globalEvent("#inputRow", "keypress", $event) {
|
on message globalEvent("#inputRow", "keypress", $event) {
|
||||||
var character = String.fromCharCode(event.charCode);
|
var character = String.fromCharCode(event.charCode);
|
||||||
if (event.charCode && character) {
|
if (event.charCode && character) {
|
||||||
:: fieldCommand(["insert", character]);
|
:: fieldCommand(["insert", character]);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
on asserted fieldContents($text, $pos) {
|
on asserted fieldContents($text, $pos) {
|
||||||
this.text = text;
|
this.text = text;
|
||||||
this.pos = pos;
|
this.pos = pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
on asserted highlight($state) {
|
on asserted highlight($state) {
|
||||||
this.highlightState = state;
|
this.highlightState = state;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -81,40 +79,38 @@ function spawnGui() {
|
||||||
|
|
||||||
function spawnModel() {
|
function spawnModel() {
|
||||||
actor {
|
actor {
|
||||||
react {
|
field this.fieldValue = "initial";
|
||||||
field this.fieldValue = "initial";
|
field this.cursorPos = this.fieldValue.length; /* positions address gaps between characters */
|
||||||
field this.cursorPos = this.fieldValue.length; /* positions address gaps between characters */
|
|
||||||
|
|
||||||
assert fieldContents(this.fieldValue, this.cursorPos);
|
assert fieldContents(this.fieldValue, this.cursorPos);
|
||||||
|
|
||||||
on message fieldCommand("cursorLeft") {
|
on message fieldCommand("cursorLeft") {
|
||||||
this.cursorPos--;
|
this.cursorPos--;
|
||||||
if (this.cursorPos < 0)
|
if (this.cursorPos < 0)
|
||||||
this.cursorPos = 0;
|
this.cursorPos = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
on message fieldCommand("cursorRight") {
|
||||||
|
this.cursorPos++;
|
||||||
|
if (this.cursorPos > this.fieldValue.length)
|
||||||
|
this.cursorPos = this.fieldValue.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
on message fieldCommand("backspace") {
|
||||||
|
if (this.cursorPos > 0) {
|
||||||
|
this.fieldValue =
|
||||||
|
this.fieldValue.substring(0, this.cursorPos - 1) +
|
||||||
|
this.fieldValue.substring(this.cursorPos);
|
||||||
|
this.cursorPos--;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
on message fieldCommand("cursorRight") {
|
on message fieldCommand(["insert", $newText]) {
|
||||||
this.cursorPos++;
|
this.fieldValue =
|
||||||
if (this.cursorPos > this.fieldValue.length)
|
this.fieldValue.substring(0, this.cursorPos) +
|
||||||
this.cursorPos = this.fieldValue.length;
|
newText +
|
||||||
}
|
this.fieldValue.substring(this.cursorPos);
|
||||||
|
this.cursorPos += newText.length;
|
||||||
on message fieldCommand("backspace") {
|
|
||||||
if (this.cursorPos > 0) {
|
|
||||||
this.fieldValue =
|
|
||||||
this.fieldValue.substring(0, this.cursorPos - 1) +
|
|
||||||
this.fieldValue.substring(this.cursorPos);
|
|
||||||
this.cursorPos--;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
on message fieldCommand(["insert", $newText]) {
|
|
||||||
this.fieldValue =
|
|
||||||
this.fieldValue.substring(0, this.cursorPos) +
|
|
||||||
newText +
|
|
||||||
this.fieldValue.substring(this.cursorPos);
|
|
||||||
this.cursorPos += newText.length;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -124,29 +120,27 @@ function spawnModel() {
|
||||||
|
|
||||||
function spawnSearch() {
|
function spawnSearch() {
|
||||||
actor {
|
actor {
|
||||||
react {
|
field this.searchtext = document.getElementById("searchBox").value;
|
||||||
field this.searchtext = document.getElementById("searchBox").value;
|
field this.fieldValue = "";
|
||||||
field this.fieldValue = "";
|
field this.highlight = false;
|
||||||
field this.highlight = false;
|
|
||||||
|
|
||||||
assert highlight(this.highlight);
|
assert highlight(this.highlight);
|
||||||
|
|
||||||
dataflow {
|
dataflow {
|
||||||
if (this.searchtext) {
|
if (this.searchtext) {
|
||||||
var pos = this.fieldValue.indexOf(this.searchtext);
|
var pos = this.fieldValue.indexOf(this.searchtext);
|
||||||
this.highlight = (pos !== -1) && [pos, pos + this.searchtext.length];
|
this.highlight = (pos !== -1) && [pos, pos + this.searchtext.length];
|
||||||
} else {
|
} else {
|
||||||
this.highlight = false;
|
this.highlight = false;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
on message globalEvent("#searchBox", "input", $event) {
|
on message globalEvent("#searchBox", "input", $event) {
|
||||||
this.searchtext = document.getElementById("searchBox").value;
|
this.searchtext = document.getElementById("searchBox").value;
|
||||||
}
|
}
|
||||||
|
|
||||||
on asserted fieldContents($text, _) {
|
on asserted fieldContents($text, _) {
|
||||||
this.fieldValue = text;
|
this.fieldValue = text;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,23 +25,21 @@ assertion type show(completed);
|
||||||
|
|
||||||
function todoListItemModel(initialId, initialTitle, initialCompleted) {
|
function todoListItemModel(initialId, initialTitle, initialCompleted) {
|
||||||
actor {
|
actor {
|
||||||
react {
|
field this.id = initialId;
|
||||||
field this.id = initialId;
|
field this.title = initialTitle;
|
||||||
field this.title = initialTitle;
|
field this.completed = initialCompleted;
|
||||||
field this.completed = initialCompleted;
|
|
||||||
|
|
||||||
assert todo(this.id, this.title, this.completed);
|
stop on message deleteTodo(this.id);
|
||||||
|
|
||||||
on message setCompleted(this.id, $v) { this.completed = v; }
|
assert todo(this.id, this.title, this.completed);
|
||||||
on message setAllCompleted($v) { this.completed = v; }
|
|
||||||
|
|
||||||
on message setTitle(this.id, $v) { this.title = v; }
|
on message setCompleted(this.id, $v) { this.completed = v; }
|
||||||
|
on message setAllCompleted($v) { this.completed = v; }
|
||||||
|
|
||||||
on message clearCompletedTodos() {
|
on message setTitle(this.id, $v) { this.title = v; }
|
||||||
if (this.completed) :: deleteTodo(this.id);
|
|
||||||
}
|
on message clearCompletedTodos() {
|
||||||
} until {
|
if (this.completed) :: deleteTodo(this.id);
|
||||||
case message deleteTodo(this.id);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -57,53 +55,51 @@ function getTemplate(id) {
|
||||||
|
|
||||||
function todoListItemView(id) {
|
function todoListItemView(id) {
|
||||||
actor {
|
actor {
|
||||||
|
stop on retracted todo(id, _, _);
|
||||||
|
|
||||||
this.ui = new Syndicate.UI.Anchor();
|
this.ui = new Syndicate.UI.Anchor();
|
||||||
react {
|
field this.editing = false;
|
||||||
field this.editing = false;
|
|
||||||
|
|
||||||
during todo(id, $title, $completed) {
|
during todo(id, $title, $completed) {
|
||||||
during show(completed) {
|
during show(completed) {
|
||||||
assert this.ui.html('.todo-list',
|
assert this.ui.html('.todo-list',
|
||||||
Mustache.render(getTemplate(this.editing
|
Mustache.render(getTemplate(this.editing
|
||||||
? 'todo-list-item-edit-template'
|
? 'todo-list-item-edit-template'
|
||||||
: 'todo-list-item-view-template'),
|
: 'todo-list-item-view-template'),
|
||||||
{
|
{
|
||||||
id: id,
|
id: id,
|
||||||
title: title,
|
title: title,
|
||||||
completed_class: completed ? "completed" : "",
|
completed_class: completed ? "completed" : "",
|
||||||
checked: completed ? "checked" : "",
|
checked: completed ? "checked" : "",
|
||||||
}),
|
}),
|
||||||
id);
|
id);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
on message this.ui.event('.toggle', 'change', $e) {
|
on message this.ui.event('.toggle', 'change', $e) {
|
||||||
:: setCompleted(id, e.target.checked);
|
:: setCompleted(id, e.target.checked);
|
||||||
}
|
}
|
||||||
|
|
||||||
on message this.ui.event('.destroy', 'click', _) {
|
on message this.ui.event('.destroy', 'click', _) {
|
||||||
:: deleteTodo(id);
|
:: deleteTodo(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
on message this.ui.event('label', 'dblclick', _) {
|
on message this.ui.event('label', 'dblclick', _) {
|
||||||
this.editing = true;
|
this.editing = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
on message this.ui.event('input.edit', 'keyup', $e) {
|
on message this.ui.event('input.edit', 'keyup', $e) {
|
||||||
if (e.keyCode === ESCAPE_KEY_CODE || e.keyCode === ENTER_KEY_CODE) {
|
if (e.keyCode === ESCAPE_KEY_CODE || e.keyCode === ENTER_KEY_CODE) {
|
||||||
this.editing = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
on message this.ui.event('input.edit', 'blur', $e) {
|
|
||||||
this.editing = false;
|
this.editing = false;
|
||||||
}
|
}
|
||||||
on message this.ui.event('input.edit', 'change', $e) {
|
}
|
||||||
var newTitle = e.target.value.trim();
|
on message this.ui.event('input.edit', 'blur', $e) {
|
||||||
:: (newTitle ? setTitle(id, newTitle) : deleteTodo(id));
|
this.editing = false;
|
||||||
this.editing = false;
|
}
|
||||||
}
|
on message this.ui.event('input.edit', 'change', $e) {
|
||||||
} until {
|
var newTitle = e.target.value.trim();
|
||||||
case retracted todo(id, _, _);
|
:: (newTitle ? setTitle(id, newTitle) : deleteTodo(id));
|
||||||
|
this.editing = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -114,80 +110,72 @@ ground dataspace G {
|
||||||
Syndicate.UI.spawnUIDriver();
|
Syndicate.UI.spawnUIDriver();
|
||||||
|
|
||||||
actor {
|
actor {
|
||||||
react {
|
on message Syndicate.UI.globalEvent('.new-todo', 'change', $e) {
|
||||||
on message Syndicate.UI.globalEvent('.new-todo', 'change', $e) {
|
var newTitle = e.target.value.trim();
|
||||||
var newTitle = e.target.value.trim();
|
if (newTitle) :: createTodo(newTitle);
|
||||||
if (newTitle) :: createTodo(newTitle);
|
e.target.value = "";
|
||||||
e.target.value = "";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
actor {
|
actor {
|
||||||
this.ui = new Syndicate.UI.Anchor();
|
this.ui = new Syndicate.UI.Anchor();
|
||||||
|
|
||||||
react {
|
during activeTodoCount($count) {
|
||||||
during activeTodoCount($count) {
|
assert this.ui.context('count').html('.todo-count strong', '' + 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);
|
||||||
assert this.ui.context('plural').html('.todo-count span.s', 's') when (count !== 1);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
during totalTodoCount(0) {
|
during totalTodoCount(0) {
|
||||||
assert Syndicate.UI.uiAttribute('section.main', 'class', 'hidden');
|
assert Syndicate.UI.uiAttribute('section.main', 'class', 'hidden');
|
||||||
assert Syndicate.UI.uiAttribute('footer.footer', 'class', 'hidden');
|
assert Syndicate.UI.uiAttribute('footer.footer', 'class', 'hidden');
|
||||||
}
|
}
|
||||||
|
|
||||||
during completedTodoCount(0) {
|
during completedTodoCount(0) {
|
||||||
assert Syndicate.UI.uiAttribute('button.clear-completed', 'class', 'hidden');
|
assert Syndicate.UI.uiAttribute('button.clear-completed', 'class', 'hidden');
|
||||||
}
|
}
|
||||||
on message Syndicate.UI.globalEvent('button.clear-completed', 'click', _) {
|
on message Syndicate.UI.globalEvent('button.clear-completed', 'click', _) {
|
||||||
:: clearCompletedTodos();
|
:: clearCompletedTodos();
|
||||||
}
|
}
|
||||||
|
|
||||||
during allCompleted() {
|
during allCompleted() {
|
||||||
do { :: Syndicate.UI.setProperty('.toggle-all', 'checked', true); }
|
on start { :: Syndicate.UI.setProperty('.toggle-all', 'checked', true); }
|
||||||
finally { :: Syndicate.UI.setProperty('.toggle-all', 'checked', false); }
|
on stop { :: Syndicate.UI.setProperty('.toggle-all', 'checked', false); }
|
||||||
}
|
}
|
||||||
on message Syndicate.UI.globalEvent('.toggle-all', 'change', $e) {
|
on message Syndicate.UI.globalEvent('.toggle-all', 'change', $e) {
|
||||||
:: setAllCompleted(e.target.checked);
|
:: setAllCompleted(e.target.checked);
|
||||||
}
|
}
|
||||||
|
|
||||||
on asserted todo($id, _, _) {
|
on asserted todo($id, _, _) {
|
||||||
todoListItemView(id);
|
todoListItemView(id);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
actor {
|
actor {
|
||||||
react {
|
field this.completedCount = 0;
|
||||||
field this.completedCount = 0;
|
field this.activeCount = 0;
|
||||||
field this.activeCount = 0;
|
on asserted todo($id, _, $c) { if (c) this.completedCount++; else this.activeCount++; }
|
||||||
on asserted todo($id, _, $c) { if (c) this.completedCount++; else this.activeCount++; }
|
on retracted todo($id, _, $c) { if (c) this.completedCount--; else this.activeCount--; }
|
||||||
on retracted todo($id, _, $c) { if (c) this.completedCount--; else this.activeCount--; }
|
assert activeTodoCount(this.activeCount);
|
||||||
assert activeTodoCount(this.activeCount);
|
assert completedTodoCount(this.completedCount);
|
||||||
assert completedTodoCount(this.completedCount);
|
assert totalTodoCount(this.activeCount + this.completedCount);
|
||||||
assert totalTodoCount(this.activeCount + this.completedCount);
|
assert allCompleted() when (this.completedCount > 0 && this.activeCount === 0);
|
||||||
assert allCompleted() when (this.completedCount > 0 && this.activeCount === 0);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
actor {
|
actor {
|
||||||
react {
|
during Syndicate.UI.locationHash($hash) {
|
||||||
during Syndicate.UI.locationHash($hash) {
|
assert Syndicate.UI.uiAttribute('ul.filters > li > a[href="#'+hash+'"]',
|
||||||
assert Syndicate.UI.uiAttribute('ul.filters > li > a[href="#'+hash+'"]',
|
'class', 'selected');
|
||||||
'class', 'selected');
|
}
|
||||||
}
|
|
||||||
|
|
||||||
during Syndicate.UI.locationHash('/') {
|
during Syndicate.UI.locationHash('/') {
|
||||||
assert show(true);
|
assert show(true);
|
||||||
assert show(false);
|
assert show(false);
|
||||||
}
|
}
|
||||||
during Syndicate.UI.locationHash('/active') {
|
during Syndicate.UI.locationHash('/active') {
|
||||||
assert show(false);
|
assert show(false);
|
||||||
}
|
}
|
||||||
during Syndicate.UI.locationHash('/completed') {
|
during Syndicate.UI.locationHash('/completed') {
|
||||||
assert show(true);
|
assert show(true);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -202,32 +190,32 @@ ground dataspace G {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
db = {nextId: 0, todos: {}};
|
db = {nextId: 0, todos: {}};
|
||||||
react until {
|
on start {
|
||||||
case asserted Syndicate.observe(createTodo(_)) {
|
react {
|
||||||
:: createTodo('Buy milk');
|
stop on asserted Syndicate.observe(createTodo(_)) {
|
||||||
:: createTodo('Buy bread');
|
:: createTodo('Buy milk');
|
||||||
:: createTodo('Finish PhD');
|
:: createTodo('Buy bread');
|
||||||
|
:: createTodo('Finish PhD');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
react {
|
on message createTodo($title) {
|
||||||
on message createTodo($title) {
|
todoListItemModel(db.nextId++, title, false);
|
||||||
todoListItemModel(db.nextId++, title, false);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
during todo($id, _, _) {
|
during todo($id, _, _) {
|
||||||
during todo(id, $title, $completed) {
|
during todo(id, $title, $completed) {
|
||||||
do {
|
on start {
|
||||||
db.todos[id] = {id: id, title: title, completed: completed};
|
db.todos[id] = {id: id, title: title, completed: completed};
|
||||||
localStorage['todos-syndicate'] = JSON.stringify(db);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
delete db.todos[id];
|
|
||||||
localStorage['todos-syndicate'] = JSON.stringify(db);
|
localStorage['todos-syndicate'] = JSON.stringify(db);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
on stop {
|
||||||
|
delete db.todos[id];
|
||||||
|
localStorage['todos-syndicate'] = JSON.stringify(db);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -76,10 +76,9 @@ assertion type splitProposal(title, price, contribution, accepted);
|
||||||
/// core library.
|
/// core library.
|
||||||
///
|
///
|
||||||
function whileRelevantAssert(P) {
|
function whileRelevantAssert(P) {
|
||||||
react {
|
actor {
|
||||||
assert P;
|
assert P;
|
||||||
} until {
|
stop on retracted Syndicate.observe(P);
|
||||||
case retracted Syndicate.observe(P);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -117,38 +116,32 @@ function seller() {
|
||||||
/// The seller responds to interest in bookQuotes by asserting a
|
/// The seller responds to interest in bookQuotes by asserting a
|
||||||
/// responsive record, if one exists.
|
/// responsive record, if one exists.
|
||||||
|
|
||||||
react {
|
during Syndicate.observe(bookQuote($title, _)) {
|
||||||
during Syndicate.observe(bookQuote($title, _)) {
|
assert bookQuote(title, this.priceOf(title));
|
||||||
assert bookQuote(title, this.priceOf(title));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// It also responds to order requests.
|
/// It also responds to order requests.
|
||||||
|
|
||||||
react {
|
on asserted
|
||||||
on asserted
|
Syndicate.observe(order($title, $offerPrice, _, _)) {
|
||||||
Syndicate.observe(order($title, $offerPrice, _, _)) {
|
|
||||||
|
|
||||||
/// We cannot sell a book we do not have, and we will not sell for
|
/// We cannot sell a book we do not have, and we will not sell for
|
||||||
/// less than our asking price.
|
/// less than our asking price.
|
||||||
|
|
||||||
var askingPrice = this.priceOf(title);
|
var askingPrice = this.priceOf(title);
|
||||||
if ((askingPrice === false) || (offerPrice < askingPrice)) {
|
if ((askingPrice === false) || (offerPrice < askingPrice)) {
|
||||||
whileRelevantAssert(
|
whileRelevantAssert(
|
||||||
order(title, offerPrice, false, false));
|
order(title, offerPrice, false, false));
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
/// But if we can sell it, we do so by allocating an order ID and
|
/// But if we can sell it, we do so by allocating an order ID and
|
||||||
/// replying to the orderer.
|
/// replying to the orderer.
|
||||||
|
|
||||||
var orderId = this.nextOrderId++;
|
var orderId = this.nextOrderId++;
|
||||||
delete field this.books[title];
|
delete field this.books[title];
|
||||||
|
|
||||||
actor {
|
whileRelevantAssert(
|
||||||
whileRelevantAssert(
|
order(title, offerPrice, orderId, "March 9th"));
|
||||||
order(title, offerPrice, orderId, "March 9th"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -157,7 +150,7 @@ function seller() {
|
||||||
/// ### Implementation: SPLIT-PROPOSER and book-quote-requestor
|
/// ### Implementation: SPLIT-PROPOSER and book-quote-requestor
|
||||||
|
|
||||||
function buyerA() {
|
function buyerA() {
|
||||||
actor {
|
actor* {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
/// Our actor remembers which books remain on its shopping list, and
|
/// 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.
|
/// First, retrieve a quote for the title, and analyze the result.
|
||||||
|
|
||||||
react until {
|
react {
|
||||||
case asserted bookQuote(title, $price) {
|
stop on asserted bookQuote(title, $price) {
|
||||||
if (price === false) {
|
if (price === false) {
|
||||||
console.log("A learns that "+title+" is out-of-stock.");
|
console.log("A learns that "+title+" is out-of-stock.");
|
||||||
buyBooks();
|
buyBooks();
|
||||||
|
@ -220,15 +213,15 @@ function buyerA() {
|
||||||
|
|
||||||
/// Make our proposal, and wait for a response.
|
/// Make our proposal, and wait for a response.
|
||||||
|
|
||||||
react until {
|
react {
|
||||||
case asserted
|
stop on asserted
|
||||||
splitProposal(title, price, contribution, true) {
|
splitProposal(title, price, contribution, true) {
|
||||||
console.log("A learns that the split-proposal for "+
|
console.log("A learns that the split-proposal for "+
|
||||||
title+" was accepted");
|
title+" was accepted");
|
||||||
buyBooks();
|
buyBooks();
|
||||||
}
|
}
|
||||||
|
|
||||||
case asserted
|
stop on asserted
|
||||||
splitProposal(title, price, contribution, false) {
|
splitProposal(title, price, contribution, false) {
|
||||||
console.log("A learns that the split-proposal for "+
|
console.log("A learns that the split-proposal for "+
|
||||||
title+" was rejected");
|
title+" was rejected");
|
||||||
|
@ -255,55 +248,50 @@ function buyerB() {
|
||||||
/// It spends its time waiting for a SPLIT-PROPOSER to offer a
|
/// It spends its time waiting for a SPLIT-PROPOSER to offer a
|
||||||
/// `splitProposal`.
|
/// `splitProposal`.
|
||||||
|
|
||||||
react {
|
on asserted
|
||||||
on asserted
|
Syndicate.observe(splitProposal($title,
|
||||||
Syndicate.observe(splitProposal($title,
|
$price,
|
||||||
$price,
|
$theirContribution,
|
||||||
$theirContribution,
|
_))
|
||||||
_))
|
{
|
||||||
{
|
var myContribution = price - theirContribution;
|
||||||
var myContribution = price - theirContribution;
|
console.log("B is being asked to contribute "+myContribution+
|
||||||
console.log("B is being asked to contribute "+myContribution+
|
" toward "+title+" at price "+price);
|
||||||
" toward "+title+" at price "+price);
|
|
||||||
|
|
||||||
/// We may not be able to afford contributing this much.
|
/// We may not be able to afford contributing this much.
|
||||||
|
|
||||||
if (myContribution > this.funds) {
|
if (myContribution > this.funds) {
|
||||||
console.log("B hasn't enough funds ("+this.funds+
|
console.log("B hasn't enough funds ("+this.funds+
|
||||||
" remaining)");
|
" remaining)");
|
||||||
whileRelevantAssert(
|
whileRelevantAssert(
|
||||||
splitProposal(title, price, theirContribution, false));
|
splitProposal(title, price, theirContribution, false));
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
/// But if we *can* afford it, update our remaining funds and spawn a
|
/// But if we *can* afford it, update our remaining funds and spawn a
|
||||||
/// small actor to handle the actual purchase now that we have agreed
|
/// small actor to handle the actual purchase now that we have agreed
|
||||||
/// on a split.
|
/// on a split.
|
||||||
|
|
||||||
var remainingFunds = this.funds - myContribution;
|
var remainingFunds = this.funds - myContribution;
|
||||||
console.log("B accepts the offer, leaving them with "+
|
console.log("B accepts the offer, leaving them with "+
|
||||||
remainingFunds+" remaining funds");
|
remainingFunds+" remaining funds");
|
||||||
this.funds = remainingFunds;
|
this.funds = remainingFunds;
|
||||||
|
|
||||||
actor {
|
actor {
|
||||||
react {
|
|
||||||
|
|
||||||
/// While waiting for order confirmation, take the opportunity to
|
/// While waiting for order confirmation, take the opportunity to
|
||||||
/// signal to our SPLIT-PROPOSER that we accepted their proposal.
|
/// signal to our SPLIT-PROPOSER that we accepted their proposal.
|
||||||
|
|
||||||
assert splitProposal(title,
|
assert splitProposal(title,
|
||||||
price,
|
price,
|
||||||
theirContribution,
|
theirContribution,
|
||||||
true);
|
true);
|
||||||
|
|
||||||
/// When order confirmation arrives, this purchase is completed.
|
/// When order confirmation arrives, this purchase is completed.
|
||||||
|
|
||||||
} until {
|
stop on asserted order(title, price, $id, $date) {
|
||||||
case asserted order(title, price, $id, $date) {
|
console.log("The order for "+title+" has id "+id+
|
||||||
console.log("The order for "+title+" has id "+id+
|
", and will be delivered on "+date);
|
||||||
", and will be delivered on "+date);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -122,10 +122,6 @@ Actor.prototype.checkForTermination = function() {
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
function createFacet() {
|
|
||||||
return new Facet(Dataspace.activeBehavior());
|
|
||||||
}
|
|
||||||
|
|
||||||
function Facet(actor) {
|
function Facet(actor) {
|
||||||
this.actor = actor;
|
this.actor = actor;
|
||||||
this.endpoints = Immutable.Map();
|
this.endpoints = Immutable.Map();
|
||||||
|
@ -141,6 +137,12 @@ function Facet(actor) {
|
||||||
Facet.nextFid = 0;
|
Facet.nextFid = 0;
|
||||||
Facet.current = null;
|
Facet.current = null;
|
||||||
|
|
||||||
|
Facet.build = function(f) {
|
||||||
|
var facet = new Facet(Dataspace.activeBehavior());
|
||||||
|
withCurrentFacet(facet, f);
|
||||||
|
facet.completeBuild();
|
||||||
|
};
|
||||||
|
|
||||||
function withCurrentFacet(facet, f) {
|
function withCurrentFacet(facet, f) {
|
||||||
var previousFacet = Facet.current;
|
var previousFacet = Facet.current;
|
||||||
Facet.current = facet;
|
Facet.current = facet;
|
||||||
|
@ -373,7 +375,7 @@ function deleteField(obj, prop) {
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
module.exports.spawnActor = spawnActor;
|
module.exports.spawnActor = spawnActor;
|
||||||
module.exports.createFacet = createFacet;
|
module.exports.Facet = Facet;
|
||||||
module.exports.referenceField = referenceField;
|
module.exports.referenceField = referenceField;
|
||||||
module.exports.declareField = declareField;
|
module.exports.declareField = declareField;
|
||||||
module.exports.deleteField = deleteField;
|
module.exports.deleteField = deleteField;
|
||||||
|
|
Loading…
Reference in New Issue