Syntax support for initial assertions on spawn

This commit is contained in:
Tony Garnock-Jones 2018-11-04 19:54:10 +00:00
parent 2688c09639
commit a1d57e61f1
4 changed files with 71 additions and 14 deletions

View File

@ -20,13 +20,19 @@ import * as t from "@babel/types";
export function SpawnStatement(node) { export function SpawnStatement(node) {
this.word("spawn"); this.word("spawn");
this.space();
if (node.name) { if (node.name) {
this.space();
this.word("named"); this.word("named");
this.space(); this.space();
this.print(node.name, node); this.print(node.name, node);
this.space();
} }
for (let a of node.initialAssertions) {
this.space();
this.token(":asserting");
this.space();
this.print(a, node);
}
this.space();
this.printBlock(node); this.printBlock(node);
} }

View File

@ -199,6 +199,12 @@ export default class SyndicateParser extends _original_Parser {
this.next(); this.next();
node.name = this.parseExpression(); node.name = this.parseExpression();
} }
node.initialAssertions = [];
while (this.match(tt.colon)) {
this.next();
this.expectContextual("asserting");
node.initialAssertions.push(this.parseExpression());
}
node.body = this.parseStatement(); node.body = this.parseStatement();
return this.finishNode(node, "SpawnStatement"); return this.finishNode(node, "SpawnStatement");
} }

View File

@ -63,7 +63,7 @@ function discardAst(state) {
return _discardAst({ SYNDICATE: state.SyndicateID }); return _discardAst({ SYNDICATE: state.SyndicateID });
} }
const _listAst = template.expression(`IMMUTABLE.List(VS)`); const _listAst = template.expression(`IMMUTABLE.fromJS(VS)`);
function listAst(state, vs) { function listAst(state, vs) {
return _listAst({ IMMUTABLE: state.ImmutableID, VS: vs }); return _listAst({ IMMUTABLE: state.ImmutableID, VS: vs });
} }
@ -149,6 +149,25 @@ function compilePattern(state, patternPath) {
return [t.nullLiteral(), pattern]; return [t.nullLiteral(), pattern];
} }
case 'ArrayExpression': {
if (hasCapturesOrDiscards(patternPath)) {
let arity = pattern.elements.length;
let skel = [t.numericLiteral(arity)];
let assn = [];
for (let i = 0; i < arity; i++) {
syndicatePath.push(i);
let [s, a] = walk(patternPath.get('elements.' + i));
skel.push(s);
assn.push(a);
syndicatePath.pop();
}
return [t.arrayExpression(skel), t.arrayExpression(assn)];
} else {
pushConstant(pattern);
return [t.nullLiteral(), pattern];
}
}
default: default:
if (!isLiteral(pattern)) { if (!isLiteral(pattern)) {
console.error('Unsupported pattern node type', pattern); console.error('Unsupported pattern node type', pattern);
@ -286,10 +305,15 @@ export default declare((api, options) => {
SpawnStatement(path, state) { SpawnStatement(path, state) {
const { node } = path; const { node } = path;
path.replaceWith(template(`DATASPACE.spawn(NAME, function () { BODY })`)({ path.replaceWith(template(`DATASPACE.spawn(NAME, function () { BODY }, ASSERTIONS)`)({
DATASPACE: state.DataspaceID, DATASPACE: state.DataspaceID,
NAME: node.name || t.nullLiteral(), NAME: node.name || t.nullLiteral(),
BODY: node.body BODY: node.body,
ASSERTIONS: node.initialAssertions.length === 0 ? null :
template.expression(`IMMUTABLE.Set(SEQ)`)({
IMMUTABLE: state.ImmutableID,
SEQ: t.arrayExpression(node.initialAssertions)
}),
})); }));
}, },
@ -410,6 +434,26 @@ export default declare((api, options) => {
if (node.body.type === "SpawnStatement") { if (node.body.type === "SpawnStatement") {
let idId = path.scope.generateUidIdentifier("id"); let idId = path.scope.generateUidIdentifier("id");
let instId = path.scope.generateUidIdentifier("inst"); let instId = path.scope.generateUidIdentifier("inst");
let bodyPath = path.get('body');
bodyPath.unshiftContainer('initialAssertions', [
template.expression(`I`)({
I: instId
}),
template.expression(`S.Observe(S.Observe(I))`)({
S: state.SyndicateID,
I: instId
}),
]);
bodyPath.get('body').replaceWithMultiple([
syndicateTemplate(`assert I;`)({
I: instId
}),
syndicateTemplate(`stop on retracted S.Observe(I);`)({
S: state.SyndicateID,
I: instId
}),
node.body.body,
]);
path.replaceWith(syndicateTemplate( path.replaceWith(syndicateTemplate(
`on asserted PATTERN1 { `on asserted PATTERN1 {
let IDID = SYNDICATE.genUuid(); let IDID = SYNDICATE.genUuid();
@ -423,16 +467,11 @@ export default declare((api, options) => {
stop on asserted INSTID; stop on asserted INSTID;
} }
} }
spawn named NAME { BODY
assert INSTID;
stop on retracted SYNDICATE.Observe(INSTID);
BODY
}
}`)({ }`)({
PATTERN1: node.pattern, PATTERN1: node.pattern,
PATTERN2: instantiatePatternToPattern(state, path.get('pattern')), PATTERN2: instantiatePatternToPattern(state, path.get('pattern')),
NAME: node.body.name || t.nullLiteral(), BODY: node.body,
BODY: node.body.body, // the body of the SPAWN, which is itself the body of `node`
SYNDICATE: state.SyndicateID, SYNDICATE: state.SyndicateID,
IDID: idId, IDID: idId,
INSTID: instId, INSTID: instId,

View File

@ -25,14 +25,20 @@ import defineType, {
} from "@babel/types/lib/definitions/utils"; } from "@babel/types/lib/definitions/utils";
defineType("SpawnStatement", { defineType("SpawnStatement", {
builder: ["name", "body"], builder: ["name", "initialAssertions", "body"],
visitor: ["name", "body"], visitor: ["name", "initialAssertions", "body"],
aliases: ["Statement"], aliases: ["Statement"],
fields: { fields: {
name: { name: {
validate: assertNodeType("Expression"), validate: assertNodeType("Expression"),
optional: true, optional: true,
}, },
initialAssertions: {
validate: chain(
assertValueType("array"),
assertEach(assertNodeType("Expression")),
),
},
body: { body: {
validate: assertNodeType("Statement"), validate: assertNodeType("Statement"),
}, },