2018-11-01 15:20:20 +00:00
|
|
|
"use strict";
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
// @syndicate-lang/syntax, a translator of Syndicate extensions to JS.
|
|
|
|
// Copyright (C) 2016-2018 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
|
|
|
|
//
|
|
|
|
// This program is free software: you can redistribute it and/or modify
|
|
|
|
// it under the terms of the GNU General Public License as published by
|
|
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
|
|
// (at your option) any later version.
|
|
|
|
//
|
|
|
|
// This program is distributed in the hope that it will be useful,
|
|
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
// GNU General Public License for more details.
|
|
|
|
//
|
|
|
|
// You should have received a copy of the GNU General Public License
|
|
|
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
|
|
// Monkeypatch Babel in an utterly horrible way to support Syndicate
|
|
|
|
// syntactic extensions to JS.
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
2018-11-05 13:57:31 +00:00
|
|
|
// (0) Replace `isStatement`, `isExpression`, etc. functions with
|
2018-11-01 23:35:11 +00:00
|
|
|
// non-hard-coded versions that check the contents of
|
|
|
|
// FLIPPED_ALIAS_KEYS at the time of each call.
|
2018-11-01 15:20:20 +00:00
|
|
|
//
|
|
|
|
// This allows our later extensions to be picked up correctly.
|
|
|
|
//
|
2018-11-03 15:54:15 +00:00
|
|
|
const Validators = require("@babel/types/lib/validators/generated");
|
|
|
|
const shallowEqual = require("@babel/types/lib/utils/shallowEqual");
|
2018-11-01 23:35:11 +00:00
|
|
|
|
|
|
|
function _isX(X, previous) {
|
|
|
|
return (node, opts) => {
|
|
|
|
if (node && Types.FLIPPED_ALIAS_KEYS[X].indexOf(node.type) !== -1) {
|
|
|
|
return typeof opts === "undefined" || shallowEqual.default(node, opts);
|
|
|
|
} else {
|
|
|
|
return previous(node, opts);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
Validators.isStatement = _isX("Statement", Validators.isStatement);
|
|
|
|
Validators.isExpression = _isX("Expression", Validators.isExpression);
|
2018-11-05 13:57:31 +00:00
|
|
|
Validators.isScopable = _isX("Scopable", Validators.isScopable);
|
2018-11-01 15:20:20 +00:00
|
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
// (1) Load the core parser in modifiable form.
|
|
|
|
//
|
|
|
|
// We do this by, in the build scripts, COPYING the parser COMPILED
|
|
|
|
// code, and MODIFYING it to add a couple of new exports. See
|
|
|
|
// `../babel_parser_suffix.js`.
|
|
|
|
//
|
|
|
|
// Here, then, we load the MODIFIED copy of the parser, and then
|
|
|
|
// PRE-POPULATE THE REQUIRE CACHE with it. Later requires of the
|
|
|
|
// ACTUAL module will then get our MODIFIED copy.
|
|
|
|
//
|
|
|
|
// Vile.
|
|
|
|
//
|
2018-11-03 15:54:15 +00:00
|
|
|
const BabelParser = require("./babel_parser");
|
2018-11-01 15:20:20 +00:00
|
|
|
require.cache[require.resolve("@babel/parser")] = require.cache[require.resolve("./babel_parser")];
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
// (2) Install the new AST node types required.
|
|
|
|
//
|
|
|
|
// We do this by loading and populating the core TYPES array, and then
|
|
|
|
// loading our extensions, followed by RESETTING the TYPES array to
|
2018-11-05 13:57:31 +00:00
|
|
|
// include the new extensions as well as the original definitions. We
|
|
|
|
// also update various properties and mappings to include the new
|
|
|
|
// types.
|
2018-11-01 15:20:20 +00:00
|
|
|
//
|
2018-11-03 15:54:15 +00:00
|
|
|
const Types = require("@babel/types");
|
2018-11-01 15:20:20 +00:00
|
|
|
require("./types");
|
|
|
|
//
|
|
|
|
// Now reset the TYPES array. This code is roughly equivalent to the
|
|
|
|
// declaration of TYPES in babel-types/src/definitions/index.js:
|
|
|
|
//
|
|
|
|
// const TYPES: Array<string> = Object.keys(VISITOR_KEYS)
|
|
|
|
// .concat(Object.keys(FLIPPED_ALIAS_KEYS))
|
|
|
|
// .concat(Object.keys(DEPRECATED_KEYS));
|
|
|
|
//
|
|
|
|
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));
|
2018-11-05 13:57:31 +00:00
|
|
|
//
|
|
|
|
// Update the means by which scopes discover binding identifiers from
|
|
|
|
// a node.
|
|
|
|
//
|
|
|
|
Types.getBindingIdentifiers.keys.EventHandlerEndpoint = ["captureIds"];
|
|
|
|
Types.getBindingIdentifiers.keys.DuringStatement = ["captureIds"];
|
2018-11-05 17:48:26 +00:00
|
|
|
Types.getBindingIdentifiers.keys.SpawnStatement = ["parentIds"];
|
2018-11-01 15:20:20 +00:00
|
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
// (3) Install our modified parser in place of the core parser.
|
|
|
|
//
|
|
|
|
// This makes use of the modification we installed from
|
|
|
|
// `../babel_parser_suffix.js` in step (1).
|
|
|
|
//
|
|
|
|
// It overrides the parser's notion of its root class -- effectively,
|
|
|
|
// the Syndicate parser becomes a mixin.
|
|
|
|
//
|
|
|
|
BabelParser.__setParser(require("./parser").default);
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
// (4) Install generators for the new AST node types.
|
|
|
|
//
|
|
|
|
// 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`).
|
2018-11-03 15:54:15 +00:00
|
|
|
const Generators = require("@babel/generator/lib/generators");
|
|
|
|
const SyndicateGenerators = require("./generators");
|
2018-11-01 15:20:20 +00:00
|
|
|
Object.keys(SyndicateGenerators).forEach((f) => {
|
|
|
|
Generators[f] = SyndicateGenerators[f];
|
|
|
|
});
|
2018-11-05 13:57:31 +00:00
|
|
|
//
|
|
|
|
// 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
|
2018-11-01 15:20:20 +00:00
|
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
2018-11-03 15:54:05 +00:00
|
|
|
// (5) Ensure that, no matter where we are when some module `require`s
|
|
|
|
// one of our patched modules, we give them the patched version. This
|
|
|
|
// is ultra disgusting.
|
|
|
|
|
|
|
|
(function () {
|
|
|
|
const Module = require('module');
|
|
|
|
const _oldLoad = Module._load;
|
|
|
|
Module._load = function (request, parent) {
|
|
|
|
if (!parent) return _oldLoad.apply(this, arguments);
|
|
|
|
switch (request) {
|
|
|
|
case "@babel/parser": return BabelParser;
|
|
|
|
case "@babel/types": return Types;
|
|
|
|
case "@babel/generator": return Generator;
|
|
|
|
default: return _oldLoad.apply(this, arguments);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
})();
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
// (6) At this point, we should (?) be able to load and use Babel
|
2018-11-01 15:20:20 +00:00
|
|
|
// somewhat normally.
|