UNPKG

cst

Version:

JavaScript CST Implementation

445 lines (386 loc) 17 kB
'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); var _toConsumableArray2 = require('babel-runtime/helpers/toConsumableArray'); var _toConsumableArray3 = _interopRequireDefault(_toConsumableArray2); var _extends2 = require('babel-runtime/helpers/extends'); var _extends3 = _interopRequireDefault(_extends2); var _getIterator2 = require('babel-runtime/core-js/get-iterator'); var _getIterator3 = _interopRequireDefault(_getIterator2); var _map = require('babel-runtime/core-js/map'); var _map2 = _interopRequireDefault(_map); var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck'); var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); var _createClass2 = require('babel-runtime/helpers/createClass'); var _createClass3 = _interopRequireDefault(_createClass2); var _Reference = require('./Reference'); var _Reference2 = _interopRequireDefault(_Reference); var _Variable = require('./Variable'); var _Variable2 = _interopRequireDefault(_Variable); var _Definition = require('./Definition'); var _Definition2 = _interopRequireDefault(_Definition); var _toArray = require('../../utils/toArray'); var _toArray2 = _interopRequireDefault(_toArray); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } var Scope = function () { function Scope(scopeInfo) { (0, _classCallCheck3.default)(this, Scope); var node = scopeInfo.node, parentScope = scopeInfo.parentScope, isProgramScope = scopeInfo.isProgramScope, isFunctionScope = scopeInfo.isFunctionScope, isClassScope = scopeInfo.isClassScope, isArrowFunctionScope = scopeInfo.isArrowFunctionScope; this.node = node; this.parentScope = parentScope; if (parentScope) { parentScope.childScopes.push(this); this._depth = parentScope._depth + 1; } else { this._depth = 0; } this.childScopes = []; this._variables = new _map2.default(); this._references = new _map2.default(); this._isProgramScope = Boolean(isProgramScope); this._isFunctionScope = Boolean(isFunctionScope); this._isClassScope = Boolean(isClassScope); this._isArrowFunctionScope = Boolean(isArrowFunctionScope); if (isProgramScope) { this._programReferences = new _map2.default(); this._programDefinitions = new _map2.default(); } } (0, _createClass3.default)(Scope, [{ key: '_addVariable', value: function _addVariable(variable) { var variables = this._variables.get(variable.name); if (variables) { variables.push(variable); variables.sort(function (variable1, variable2) { var typeOrder1 = _Definition.typeOrder[variable1.type]; var typeOrder2 = _Definition.typeOrder[variable2.type]; if (typeOrder1 > typeOrder2) { return 1; } if (typeOrder1 < typeOrder2) { return -1; } return 0; }); } else { this._variables.set(variable.name, [variable]); } } }, { key: '_addDefinition', value: function _addDefinition(definitionInfo) { var node = definitionInfo.node, name = definitionInfo.name, type = definitionInfo.type; if (type === _Definition.types.Variable) { if (!this._isFunctionScope && this.parentScope) { this.parentScope._addDefinition(definitionInfo); return; } } var variables = this._variables.get(name) || []; var variable = void 0; var _iteratorNormalCompletion = true; var _didIteratorError = false; var _iteratorError = undefined; try { for (var _iterator = (0, _getIterator3.default)(variables), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { var item = _step.value; if (item.type === type) { variable = item; break; } } } catch (err) { _didIteratorError = true; _iteratorError = err; } finally { try { if (!_iteratorNormalCompletion && _iterator.return) { _iterator.return(); } } finally { if (_didIteratorError) { throw _iteratorError; } } } if (!variable) { variable = new _Variable2.default({ name: name, type: type, scope: this }); this._adjustReferencesOnVariableAdd(variable); this._addVariable(variable); } var definition = new _Definition2.default({ node: node, type: type, scope: this }); variable._addDefinition(definition); var programScope = this._getProgramScope(); if (programScope) { programScope._programDefinitions.set(node, definition); } } }, { key: '_removeDefinition', value: function _removeDefinition(definition) { var variable = definition.variable; variable._removeDefinition(definition); if (variable._definitions.size === 0 && (variable.type === 'LetVariable' || variable.type === 'Constant' || variable.type === 'Variable' || variable.type === 'Parameter' || variable.type === 'SelfReference' || variable.type === 'CatchClauseError' || variable.type === 'ImportBinding')) { removeVariable(variable); } var programScope = this._getProgramScope(); if (programScope) { programScope._programDefinitions.delete(definition.node); } } }, { key: '_adjustReferencesOnVariableAdd', value: function _adjustReferencesOnVariableAdd(variable) { var depth = variable.scope._depth; var references = this._references.get(variable.name); if (references) { var _iteratorNormalCompletion2 = true; var _didIteratorError2 = false; var _iteratorError2 = undefined; try { for (var _iterator2 = (0, _getIterator3.default)(references), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) { var reference = _step2.value; var refVar = reference.variable; var varDepth = refVar.scope._depth; if (varDepth === depth) { if (_Definition.typeOrder[variable.type] < _Definition.typeOrder[refVar.type]) { refVar._transferReferences(variable); removeVariableIfRequired(refVar); } } else if (varDepth < depth) { refVar._references.delete(reference); variable._addReference(reference); reference.variable = variable; removeVariableIfRequired(refVar); } } } catch (err) { _didIteratorError2 = true; _iteratorError2 = err; } finally { try { if (!_iteratorNormalCompletion2 && _iterator2.return) { _iterator2.return(); } } finally { if (_didIteratorError2) { throw _iteratorError2; } } } } var _iteratorNormalCompletion3 = true; var _didIteratorError3 = false; var _iteratorError3 = undefined; try { for (var _iterator3 = (0, _getIterator3.default)(this.childScopes), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) { var childScope = _step3.value; childScope._adjustReferencesOnVariableAdd(variable); } } catch (err) { _didIteratorError3 = true; _iteratorError3 = err; } finally { try { if (!_iteratorNormalCompletion3 && _iterator3.return) { _iterator3.return(); } } finally { if (_didIteratorError3) { throw _iteratorError3; } } } } }, { key: '_addReference', value: function _addReference(referenceInfo) { var name = referenceInfo.name; var reference = new _Reference2.default((0, _extends3.default)({ scope: this }, referenceInfo)); this._assignReference(reference, name); var references = this._references.get(name); if (references) { references.push(reference); } else { this._references.set(name, [reference]); } var programScope = this._getProgramScope(); if (programScope) { programScope._programReferences.set(reference.node, reference); } } }, { key: '_assignReference', value: function _assignReference(reference, name) { var currentScope = this; do { var variables = currentScope._variables.get(name); if (variables) { if (reference.type) { var _iteratorNormalCompletion4 = true; var _didIteratorError4 = false; var _iteratorError4 = undefined; try { for (var _iterator4 = (0, _getIterator3.default)(variables), _step4; !(_iteratorNormalCompletion4 = (_step4 = _iterator4.next()).done); _iteratorNormalCompletion4 = true) { var variable = _step4.value; if (variable.type === reference.type) { variable._addReference(reference); return; } } } catch (err) { _didIteratorError4 = true; _iteratorError4 = err; } finally { try { if (!_iteratorNormalCompletion4 && _iterator4.return) { _iterator4.return(); } } finally { if (_didIteratorError4) { throw _iteratorError4; } } } } else { variables[0]._addReference(reference); return; } } if (!currentScope.parentScope) { var globalVariable = new _Variable2.default({ name: name, type: _Definition.types.ImplicitGlobal, scope: currentScope }); globalVariable._addReference(reference); currentScope._addVariable(globalVariable); return; } else { if ((name === 'arguments' || name === 'this') && currentScope._isFunctionScope && !currentScope._isArrowFunctionScope && !currentScope._isProgramScope || name === 'super' && currentScope._isClassScope) { var builtInVariable = new _Variable2.default({ name: name, type: _Definition.types.BuiltIn, scope: currentScope }); builtInVariable._addReference(reference); currentScope._addVariable(builtInVariable); return; } currentScope = currentScope.parentScope; } } while (true); } }, { key: '_removeReference', value: function _removeReference(reference) { var variable = reference.variable; var name = variable.name; var references = this._references.get(name); if (references) { var index = references.indexOf(reference); if (index !== -1) { references.splice(index, 1); } } variable._removeReference(reference); if (variable._references.size === 0 && (variable.type === 'ImplicitGlobal' || variable.type === 'BuiltIn')) { removeVariable(variable); } var programScope = this._getProgramScope(); if (programScope) { programScope._programReferences.delete(reference.node); } } }, { key: '_getProgramScope', value: function _getProgramScope() { var scope = this; while (scope && !scope._isProgramScope) { scope = scope.parentScope; } return scope; } }, { key: 'getVariables', value: function getVariables() { var _ref; return (_ref = []).concat.apply(_ref, (0, _toConsumableArray3.default)((0, _toArray2.default)(this._variables.values()))); } }, { key: 'getReferences', value: function getReferences() { var _ref2; return (_ref2 = []).concat.apply(_ref2, (0, _toConsumableArray3.default)((0, _toArray2.default)(this._references.values()))); } }, { key: 'destroy', value: function destroy() { var parentScope = this.parentScope; if (parentScope) { var scopeIndex = parentScope.childScopes.indexOf(this); if (scopeIndex !== -1) { parentScope.childScopes.splice(scopeIndex, 1); } } this.getReferences().forEach(this._removeReference, this); } }]); return Scope; }(); exports.default = Scope; function removeVariableIfRequired(variable) { if (variable._references.size === 0 && variable._definitions.size === 0) { var variables = variable.scope._variables.get(variable.name); if (variables) { var index = variables.indexOf(variable); if (index !== -1) { variables.splice(index, 1); } if (variables.length === 0) { variable.scope._variables.delete(variable.name); } } } } function removeVariable(variable) { var scope = variable.scope; var variables = scope._variables.get(variable.name); if (variables) { var index = variables.indexOf(variable); if (index !== -1) { variables.splice(index, 1); if (variables.length === 0) { scope._variables.delete(variable.name); } var _iteratorNormalCompletion5 = true; var _didIteratorError5 = false; var _iteratorError5 = undefined; try { for (var _iterator5 = (0, _getIterator3.default)(variable._references), _step5; !(_iteratorNormalCompletion5 = (_step5 = _iterator5.next()).done); _iteratorNormalCompletion5 = true) { var reference = _step5.value; reference.scope._assignReference(reference, variable.name); } } catch (err) { _didIteratorError5 = true; _iteratorError5 = err; } finally { try { if (!_iteratorNormalCompletion5 && _iterator5.return) { _iterator5.return(); } } finally { if (_didIteratorError5) { throw _iteratorError5; } } } } } } //# sourceMappingURL=Scope.js.map