cst
Version:
JavaScript CST Implementation
296 lines (267 loc) • 11.9 kB
JavaScript
'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'];