Page MenuHomec4science

Scope.js
No OneTemporary

File Metadata

Created
Sat, Feb 1, 06:51

Scope.js

import extractNames from './extractNames.js';
import reserved from '../utils/reserved.js';
export default function Scope(options) {
options = options || {};
this.parent = options.parent;
this.isBlockScope = !!options.block;
this.createDeclarationCallback = options.declare;
let scope = this;
while (scope.isBlockScope) scope = scope.parent;
this.functionScope = scope;
this.identifiers = [];
this.declarations = Object.create(null);
this.references = Object.create(null);
this.blockScopedDeclarations = this.isBlockScope ? null : Object.create(null);
this.aliases = Object.create(null);
}
Scope.prototype = {
addDeclaration(node, kind) {
for (const identifier of extractNames(node)) {
const name = identifier.name;
const declaration = { name, node: identifier, kind, instances: [] };
this.declarations[name] = declaration;
if (this.isBlockScope) {
if (!this.functionScope.blockScopedDeclarations[name])
this.functionScope.blockScopedDeclarations[name] = [];
this.functionScope.blockScopedDeclarations[name].push(declaration);
}
}
},
addReference(identifier) {
if (this.consolidated) {
this.consolidateReference(identifier);
} else {
this.identifiers.push(identifier);
}
},
consolidate() {
for (let i = 0; i < this.identifiers.length; i += 1) {
// we might push to the array during consolidation, so don't cache length
const identifier = this.identifiers[i];
this.consolidateReference(identifier);
}
this.consolidated = true; // TODO understand why this is necessary... seems bad
},
consolidateReference(identifier) {
const declaration = this.declarations[identifier.name];
if (declaration) {
declaration.instances.push(identifier);
} else {
this.references[identifier.name] = true;
if (this.parent) this.parent.addReference(identifier);
}
},
contains(name) {
return (
this.declarations[name] ||
(this.parent ? this.parent.contains(name) : false)
);
},
createIdentifier(base) {
if (typeof base === 'number') base = base.toString();
base = base
.replace(/\s/g, '')
.replace(/\[([^\]]+)\]/g, '_$1')
.replace(/[^a-zA-Z0-9_$]/g, '_')
.replace(/_{2,}/, '_');
let name = base;
let counter = 1;
while (
this.declarations[name] ||
this.references[name] ||
this.aliases[name] ||
name in reserved
) {
name = `${base}$${counter++}`;
}
this.aliases[name] = true;
return name;
},
createDeclaration(base) {
const id = this.createIdentifier(base);
this.createDeclarationCallback(id);
return id;
},
findDeclaration(name) {
return (
this.declarations[name] ||
(this.parent && this.parent.findDeclaration(name))
);
},
// Sometimes, block scope declarations change name during transpilation
resolveName(name) {
const declaration = this.findDeclaration(name);
return declaration ? declaration.name : name;
}
};

Event Timeline