during, during/spawn and react; not quite working yet

This commit is contained in:
Tony Garnock-Jones 2018-11-02 17:08:48 +00:00
parent 95f8e881d2
commit 8f7907fa3e
6 changed files with 186 additions and 21 deletions

View File

@ -27,3 +27,4 @@ module.exports.Observe = Struct.makeConstructor('Observe', ['specification']);
module.exports.Seal = Seal;
module.exports.Inbound = Struct.makeConstructor('Inbound', ['assertion']);
module.exports.Outbound = Struct.makeConstructor('Outbound', ['assertion']);
module.exports.Instance = Struct.makeConstructor('Instance', ['uniqueId']);

View File

@ -41,5 +41,10 @@ module.exports.Observe = Assertions.Observe;
module.exports.Seal = Assertions.Seal;
module.exports.Inbound = Assertions.Inbound;
module.exports.Outbound = Assertions.Outbound;
module.exports.Instance = Assertions.Instance;
module.exports.bootModule = Ground.bootModule;
module.exports.genUuid = function () {
return Symbol('@syndicate-lang/core');
};

View File

@ -78,6 +78,10 @@ export function EventHandlerEndpoint(node) {
} else {
this.word(node.triggerType);
this.space();
if (!node.isDynamic) {
this.word(":snapshot");
this.space();
}
this.print(node.pattern, node);
}
this.space();
@ -122,3 +126,17 @@ export function ActivationExpression(node) {
this.space();
this.print(node.moduleExpr, node);
}
export function DuringStatement(node) {
this.word("during");
this.space();
this.print(node.pattern, node);
this.space();
this.print(node.body, node);
}
export function SyndicateReactStatement(node) {
this.word("react");
this.space();
this.print(node.body, node);
}

View File

@ -88,14 +88,7 @@ export default class SyndicateParser extends _original_Parser {
}
if (this.isContextual("spawn")) {
this.next();
const node = this.startNode();
if (this.isContextual("named")) {
this.next();
node.name = this.parseExpression();
}
node.body = this.parseStatement();
return this.finishNode(node, "SpawnStatement");
return this.parseSpawnStatement();
}
if (this.isContextual("assert")) {
@ -127,6 +120,25 @@ export default class SyndicateParser extends _original_Parser {
return this.parseEventHandlerEndpoint(false, true);
}
if (this.isContextual("during")) {
this.next();
const node = this.startNode();
node.pattern = this.parseExpression();
if (this.isContextual("spawn")) {
node.body = this.parseSpawnStatement();
} else {
node.body = this.parseStatement();
}
return this.finishNode(node, "DuringStatement");
}
if (this.isContextual("react")) {
this.next();
const node = this.startNode();
node.body = this.parseStatement();
return this.finishNode(node, "SyndicateReactStatement");
}
if (this.isContextual("assertion") || this.isContextual("message")) {
const node = this.startNode();
node.expectedUse = this.state.value;
@ -180,6 +192,17 @@ export default class SyndicateParser extends _original_Parser {
}
}
parseSpawnStatement() {
this.next();
const node = this.startNode();
if (this.isContextual("named")) {
this.next();
node.name = this.parseExpression();
}
node.body = this.parseStatement();
return this.finishNode(node, "SpawnStatement");
}
parseEventHandlerEndpoint(terminal, pseudoEventsAllowed) {
this.expectContextual("on");
const node = this.startNode();
@ -187,6 +210,7 @@ export default class SyndicateParser extends _original_Parser {
if (this.match(tt.parenL)) {
node.terminal = terminal;
node.triggerType = "dataflow";
node.isDynamic = true;
node.pattern = this.parseExpression();
node.body = this.parseStatement();
return this.finishNode(node, "EventHandlerEndpoint");
@ -213,6 +237,7 @@ export default class SyndicateParser extends _original_Parser {
case "message":
node.triggerType = this.state.value;
this.next();
node.isDynamic = this.parseMaybeSnapshot();
node.terminal = terminal;
node.pattern = this.parseExpression();
node.body = this.parseStatement();
@ -222,4 +247,14 @@ export default class SyndicateParser extends _original_Parser {
this.unexpected(null, "Unknown event handler trigger type");
}
}
parseMaybeSnapshot() {
if (this.match(tt.colon)) {
this.next();
this.expectContextual("snapshot");
return false;
} else {
return true;
}
}
}

View File

@ -18,9 +18,14 @@
import { declare } from "@babel/helper-plugin-utils";
import { types as t } from "@babel/core";
import { cloneDeep } from "@babel/types";
import { cloneDeep, isLiteral } from "@babel/types";
import template from "@babel/template";
import traverse from "@babel/traverse";
import builder from "@babel/types/lib/builders/builder";
function syndicateTemplate(str) {
return template(str, { plugins: [ "syndicate" ] });
}
function maybeTerminalWrap(state, terminal, ast) {
if (terminal) {
@ -125,7 +130,7 @@ function compilePattern(state, patternPath) {
assn.push(a);
syndicatePath.pop();
}
return [t.arrayExpression(skel), t.callExpression(pattern.callee, assn)];
return [t.arrayExpression(skel), t.callExpression(cloneDeep(pattern.callee), assn)];
} else {
pushConstant(pattern);
return [t.nullLiteral(), pattern];
@ -145,7 +150,9 @@ function compilePattern(state, patternPath) {
}
default:
console.error('Unsupported pattern node type', pattern);
if (!isLiteral(pattern)) {
console.error('Unsupported pattern node type', pattern);
}
pushConstant(pattern);
return [t.nullLiteral(), pattern];
}
@ -166,6 +173,25 @@ function compilePattern(state, patternPath) {
};
}
function instantiatePatternToPattern(state, patternPath) {
patternPath.node = cloneDeep(patternPath.node);
patternPath.traverse({
CallExpression(path) {
if (isCaptureIdentifier(path.node.callee)) {
path.replaceWith(t.identifier(path.node.callee.name.slice(1)));
path.skip();
}
},
Identifier(path) {
if (isCaptureIdentifier(path.node)) {
path.replaceWith(t.identifier(path.node.name.slice(1)));
path.skip();
}
},
});
return patternPath.node;
}
function translateEndpoint(state, path, expectedEvt) {
const { node } = path;
let info = compilePattern(state, path.get('pattern'));
@ -188,7 +214,7 @@ function translateEndpoint(state, path, expectedEvt) {
})
};
return [ASSERTION, HANDLER];
});`)({
}, ISDYNAMIC);`)({
DATASPACE: state.DataspaceID,
HANDLER: path.scope.generateUidIdentifier("handler"),
SKELETON: info.skeletonAst,
@ -205,6 +231,7 @@ function translateEndpoint(state, path, expectedEvt) {
})),
BODY: maybeTerminalWrap(state, node.terminal, node.body),
ASSERTION: info.assertionAst,
ISDYNAMIC: t.booleanLiteral(node.isDynamic),
}));
}
@ -311,13 +338,10 @@ export default declare((api, options) => {
const { node } = path;
switch (node.triggerType) {
case "dataflow":
path.replaceWith(template(`DATASPACE._currentFacet.addDataflow(function () {
if (PATTERN) { BODY }
});`)({
DATASPACE: state.DataspaceID,
PATTERN: node.pattern,
BODY: maybeTerminalWrap(state, node.terminal, node.body),
}));
path.replaceWith(syndicateTemplate(`dataflow { if (PATTERN) { BODY } }`)({
PATTERN: node.pattern,
BODY: maybeTerminalWrap(state, node.terminal, node.body),
}));
break;
case "asserted":
@ -380,6 +404,60 @@ export default declare((api, options) => {
MODULE: node.moduleExpr,
}));
},
DuringStatement(path, state) {
const { node } = path;
if (node.body.type === "SpawnStatement") {
let idId = path.scope.generateUidIdentifier("id");
let instId = path.scope.generateUidIdentifier("inst");
path.replaceWith(syndicateTemplate(
`on asserted PATTERN1 {
let IDID = SYNDICATE.genUuid();
let INSTID = SYNDICATE.Instance(IDID);
react {
stop on asserted INSTID react {
stop on retracted INSTID;
stop on retracted :snapshot PATTERN2;
}
stop on retracted :snapshot PATTERN2 react {
stop on asserted INSTID;
}
}
spawn {
assert INSTID;
stop on retracted SYNDICATE.Observe(INSTID);
BODY
}
}`)({
PATTERN1: node.pattern,
PATTERN2: instantiatePatternToPattern(state, path.get('pattern')),
BODY: node.body,
SYNDICATE: state.SyndicateID,
IDID: idId,
INSTID: instId,
}));
} else {
// during
path.replaceWith(syndicateTemplate(
`on asserted PATTERN1 react on retracted :snapshot PATTERN2 BODY`)({
PATTERN1: node.pattern,
PATTERN2: instantiatePatternToPattern(state, path.get('pattern')),
BODY: node.body,
}));
}
},
SyndicateReactStatement(path, state) {
const { node } = path;
path.replaceWith(template(
`DATASPACE._currentFacet.actor.addFacet(
DATASPACE._currentFacet,
function () { BODY },
true);`)({
DATASPACE: state.DataspaceID,
BODY: node.body,
}));
},
},
};
});

View File

@ -81,8 +81,8 @@ defineType("DataflowStatement", {
});
defineType("EventHandlerEndpoint", {
builder: ["terminal", "triggerType", "pattern", "body"],
visitor: ["terminal", "triggerType", "pattern", "body"],
builder: ["terminal", "triggerType", "isDynamic", "pattern", "body"],
visitor: ["terminal", "triggerType", "isDynamic", "pattern", "body"],
aliases: ["Statement"],
fields: {
terminal: {
@ -91,6 +91,9 @@ defineType("EventHandlerEndpoint", {
triggerType: {
validate: assertOneOf("asserted", "retracted", "message", "dataflow"),
},
isDynamic: {
validate: assertOneOf(true, false),
},
pattern: {
validate: assertNodeType("Expression"),
},
@ -159,3 +162,28 @@ defineType("ActivationExpression", {
},
},
});
defineType("DuringStatement", {
builder: ["pattern", "body"],
visitor: ["pattern", "body"],
aliases: ["Statement"],
fields: {
pattern: {
validate: assertNodeType("Expression"),
},
body: {
validate: assertNodeType("Statement"),
},
},
});
defineType("SyndicateReactStatement", {
builder: ["body"],
visitor: ["body"],
aliases: ["Statement"],
fields: {
body: {
validate: assertNodeType("Statement"),
},
},
});