Attempt to introduce scopes for 'on ...' and 'during', so that pattern variables are bound.
This commit is contained in:
parent
ecf80bdb7d
commit
fa2ee1915d
|
@ -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
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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"),
|
||||
|
|
Loading…
Reference in New Issue