Attempt to introduce scopes for 'on ...' and 'during', so that pattern variables are bound.

This commit is contained in:
Tony Garnock-Jones 2018-11-05 13:57:31 +00:00
parent ecf80bdb7d
commit fa2ee1915d
4 changed files with 52 additions and 10 deletions

View File

@ -21,7 +21,7 @@
// syntactic extensions to JS.
//---------------------------------------------------------------------------
// (0) Replace the `isStatement` and `isExpression` functions with
// (0) Replace `isStatement`, `isExpression`, etc. functions with
// non-hard-coded versions that check the contents of
// FLIPPED_ALIAS_KEYS at the time of each call.
//
@ -42,6 +42,7 @@ function _isX(X, previous) {
Validators.isStatement = _isX("Statement", Validators.isStatement);
Validators.isExpression = _isX("Expression", Validators.isExpression);
Validators.isScopable = _isX("Scopable", Validators.isScopable);
//---------------------------------------------------------------------------
// (1) Load the core parser in modifiable form.
@ -64,7 +65,9 @@ require.cache[require.resolve("@babel/parser")] = require.cache[require.resolve(
//
// We do this by loading and populating the core TYPES array, and then
// loading our extensions, followed by RESETTING the TYPES array to
// include the new extensions as well as the original definitions.
// include the new extensions as well as the original definitions. We
// also update various properties and mappings to include the new
// types.
//
const Types = require("@babel/types");
require("./types");
@ -80,6 +83,12 @@ Types.TYPES.splice(0);
Array.prototype.push.apply(Types.TYPES, Object.keys(Types.VISITOR_KEYS));
Array.prototype.push.apply(Types.TYPES, Object.keys(Types.FLIPPED_ALIAS_KEYS));
Array.prototype.push.apply(Types.TYPES, Object.keys(Types.DEPRECATED_KEYS));
//
// Update the means by which scopes discover binding identifiers from
// a node.
//
Types.getBindingIdentifiers.keys.EventHandlerEndpoint = ["captureIds"];
Types.getBindingIdentifiers.keys.DuringStatement = ["captureIds"];
//---------------------------------------------------------------------------
// (3) Install our modified parser in place of the core parser.
@ -98,12 +107,16 @@ BabelParser.__setParser(require("./parser").default);
// This is mostly optional, unless for some reason we want only the
// syntax extension but not the transform (e.g. if the plugin omitted
// its `visitor`).
const Generator = require("@babel/generator"); // needed for _load override, below
const Generators = require("@babel/generator/lib/generators");
const SyndicateGenerators = require("./generators");
Object.keys(SyndicateGenerators).forEach((f) => {
Generators[f] = SyndicateGenerators[f];
});
//
// Load this after updating Generators[...], because it copies the
// keys of Generators onto the Printer class.
//
const Generator = require("@babel/generator"); // needed for _load override, below
//---------------------------------------------------------------------------
// (5) Ensure that, no matter where we are when some module `require`s

View File

@ -130,6 +130,7 @@ export default class SyndicateParser extends _original_Parser {
} else {
node.body = this.parseStatement();
}
node.captureIds = 'UNINITIALIZED';
return this.finishNode(node, "DuringStatement");
}
@ -220,6 +221,7 @@ export default class SyndicateParser extends _original_Parser {
node.isDynamic = true;
node.pattern = this.parseExpression();
node.body = this.parseStatement();
node.captureIds = 'UNINITIALIZED';
return this.finishNode(node, "EventHandlerEndpoint");
}
@ -248,6 +250,7 @@ export default class SyndicateParser extends _original_Parser {
node.terminal = terminal;
node.pattern = this.parseExpression();
node.body = this.parseStatement();
node.captureIds = 'UNINITIALIZED';
return this.finishNode(node, "EventHandlerEndpoint");
default:

View File

@ -90,12 +90,12 @@ function compilePattern(state, patternPath) {
let constPaths = [];
let constVals = [];
let capturePaths = [];
let captureNames = [];
let captureIds = [];
let syndicatePath = [];
function pushCapture(idNode) {
capturePaths.push(syndicatePath.slice());
captureNames.push(idNode.name.slice(1));
captureIds.push(t.identifier(idNode.name.slice(1)));
}
function pushConstant(node) {
@ -186,7 +186,7 @@ function compilePattern(state, patternPath) {
constPathsAst: astifySyndicatePath(state, constPaths),
constValsAst: listAst(state, t.arrayExpression(constVals)),
capturePathsAst: astifySyndicatePath(state, capturePaths),
captureNames: captureNames,
captureIds: captureIds,
assertionAst: template.expression(`SYNDICATE.Observe(ASSERTION)`)({
SYNDICATE: state.SyndicateID,
ASSERTION: assertion
@ -213,11 +213,35 @@ function instantiatePatternToPattern(state, patternPath) {
return patternPath.node;
}
const bindingRegistrationVisitor = {
EventHandlerEndpoint(path, state) {
switch (path.node.triggerType) {
case "dataflow":
break;
case "asserted":
case "retracted":
case "message": {
let info = compilePattern(state, path.get('pattern'));
path.node.captureIds = info.captureIds;
path.scope.registerBinding('let', path);
break;
}
}
},
DuringStatement(path, state) {
let info = compilePattern(state, path.get('pattern'));
path.node.captureIds = info.captureIds;
path.scope.registerBinding('let', path);
},
};
function translateEndpoint(state, path, expectedEvt) {
const { node } = path;
let info = compilePattern(state, path.get('pattern'));
let _evt = path.scope.generateUidIdentifier("evt");
let _vs = path.scope.generateUidIdentifier("vs");
path.replaceWith(template(
`DATASPACE._currentFacet.addEndpoint(function () {
let HANDLER = {
@ -245,8 +269,8 @@ function translateEndpoint(state, path, expectedEvt) {
EVT: _evt,
EXPECTED: expectedEvt,
VS: _vs,
INITS: info.captureNames.map((n, i) => template(`let N = VS.get(I);`)({
N: t.identifier(n),
INITS: info.captureIds.map((n, i) => template(`let N = VS.get(I);`)({
N: n,
VS: _vs,
I: t.numericLiteral(i),
})),
@ -303,6 +327,8 @@ export default declare((api, options) => {
SYNDICATE: state.SyndicateID,
SAVEDGLOBALFACET: savedGlobalFacetUid,
}));
path.traverse(bindingRegistrationVisitor, state);
},
SpawnStatement(path, state) {

View File

@ -92,7 +92,7 @@ defineType("DataflowStatement", {
defineType("EventHandlerEndpoint", {
builder: ["terminal", "triggerType", "isDynamic", "pattern", "body"],
visitor: ["terminal", "triggerType", "isDynamic", "pattern", "body"],
aliases: ["Statement"],
aliases: ["Statement", "Scopable"],
fields: {
terminal: {
validate: assertOneOf(true, false),
@ -175,7 +175,7 @@ defineType("ActivationExpression", {
defineType("DuringStatement", {
builder: ["pattern", "body"],
visitor: ["pattern", "body"],
aliases: ["Statement"],
aliases: ["Statement", "Scopable"],
fields: {
pattern: {
validate: assertNodeType("Expression"),