UNPKG

cst

Version:

JavaScript CST Implementation

296 lines (267 loc) 11.9 kB
'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })(); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } 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 Scope = (function () { function Scope(_ref) { var node = _ref.node; var parentScope = _ref.parentScope; var isProgramScope = _ref.isProgramScope; var isFunctionScope = _ref.isFunctionScope; var isClassScope = _ref.isClassScope; var isArrowFunctionScope = _ref.isArrowFunctionScope; return (function () { _classCallCheck(this, Scope); 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 Map(); this._references = new Map(); this._isProgramScope = Boolean(isProgramScope); this._isFunctionScope = Boolean(isFunctionScope); this._isClassScope = Boolean(isClassScope); this._isArrowFunctionScope = Boolean(isArrowFunctionScope); }).apply(this, arguments); } _createClass(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; var name = definitionInfo.name; var 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 = undefined; var _iteratorNormalCompletion = true; var _didIteratorError = false; var _iteratorError = undefined; try { for (var _iterator = variables[Symbol.iterator](), _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); } variable._addDefinition(new _Definition2['default']({ node: node, type: type, scope: this })); } }, { 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 = references[Symbol.iterator](), _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 = this._childScopes[Symbol.iterator](), _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'](_extends({ scope: this }, referenceInfo)); this._assignReference(reference, name); var references = this._references.get(name); if (references) { references.push(reference); } else { this._references.set(name, [reference]); } } }, { key: '_assignReference', value: function _assignReference(reference, name) { var currentScope = this; do { var variables = currentScope._variables.get(name); if (variables) { variables[0]._addReference(reference); break; } if (!currentScope._parentScope) { var globalVariable = new _Variable2['default']({ name: name, type: _Definition.types.ImplicitGlobal, scope: currentScope }); globalVariable._addReference(reference); currentScope._addVariable(globalVariable); break; } 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); break; } currentScope = currentScope._parentScope; } } while (true); } }, { 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); } } } }, { key: 'node', get: function get() { return this._node; } }, { key: 'parentScope', get: function get() { return this._parentScope; } }, { key: 'variables', get: function get() { return [].concat.apply([], Array.from(this._variables.values())); } }, { key: 'references', get: function get() { return [].concat.apply([], Array.from(this._references.values())); } }, { key: 'childScopes', get: function get() { return this._childScopes; } }]); 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); } } } } module.exports = exports['default'];