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) {
this.word("spawn");
this.space();
if (node.name) {
this.space();
this.word("named");
this.space();
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);
}

View File

@ -199,6 +199,12 @@ export default class SyndicateParser extends _original_Parser {
this.next();
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();
return this.finishNode(node, "SpawnStatement");
}

View File

@ -63,7 +63,7 @@ function discardAst(state) {
return _discardAst({ SYNDICATE: state.SyndicateID });
}
const _listAst = template.expression(`IMMUTABLE.List(VS)`);
const _listAst = template.expression(`IMMUTABLE.fromJS(VS)`);
function listAst(state, vs) {
return _listAst({ IMMUTABLE: state.ImmutableID, VS: vs });
}
@ -149,6 +149,25 @@ function compilePattern(state, patternPath) {
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:
if (!isLiteral(pattern)) {
console.error('Unsupported pattern node type', pattern);
@ -286,10 +305,15 @@ export default declare((api, options) => {
SpawnStatement(path, state) {
const { node } = path;
path.replaceWith(template(`DATASPACE.spawn(NAME, function () { BODY })`)({
path.replaceWith(template(`DATASPACE.spawn(NAME, function () { BODY }, ASSERTIONS)`)({
DATASPACE: state.DataspaceID,
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") {
let idId = path.scope.generateUidIdentifier("id");
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(
`on asserted PATTERN1 {
let IDID = SYNDICATE.genUuid();
@ -423,16 +467,11 @@ export default declare((api, options) => {
stop on asserted INSTID;
}
}
spawn named NAME {
assert INSTID;
stop on retracted SYNDICATE.Observe(INSTID);
BODY
}
BODY
}`)({
PATTERN1: node.pattern,
PATTERN2: instantiatePatternToPattern(state, path.get('pattern')),
NAME: node.body.name || t.nullLiteral(),
BODY: node.body.body, // the body of the SPAWN, which is itself the body of `node`
BODY: node.body,
SYNDICATE: state.SyndicateID,
IDID: idId,
INSTID: instId,

View File

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