switch scope tracking to a path based system

This commit is contained in:
Sebastian McKenzie 2015-03-12 14:35:55 +11:00
parent 3cd110a7c9
commit 9cff51915d
4 changed files with 44 additions and 29 deletions

View File

@ -1,6 +1,7 @@
import convertSourceMap from "convert-source-map";
import shebangRegex from "shebang-regex";
import isFunction from "lodash/lang/isFunction";
import TraversalPath from "../traversal/path";
import sourceMap from "source-map";
import transform from "./index";
import generate from "../generation";
@ -375,7 +376,7 @@ export default class File {
this.usedHelpers[name] = true;
var generator = this.get("helperGenerator");
var runtime = this.get("helpersNamespace");
var runtime = this.get("helpersNamespace");
if (generator) {
return generator(name);
} else if (runtime) {
@ -425,9 +426,11 @@ export default class File {
transform(ast) {
this.log.debug();
this.ast = ast;
this.path = TraversalPath.get(null, null, ast, ast, "program", this);
this.scope = this.path.scope;
this.ast = ast;
this.lastStatements = t.getLastStatements(ast.program);
this.scope = new Scope(ast.program, ast, null, this);
var modFormatter = this.moduleFormatter = this.getModuleFormatter(this.opts.modules);
if (modFormatter.init && this.transformers["es6.modules"].canRun()) {
@ -481,14 +484,14 @@ export default class File {
if (inputMap) {
map.sources[0] = inputMap.file;
var inputMapConsumer = new sourceMap.SourceMapConsumer(inputMap);
var outputMapConsumer = new sourceMap.SourceMapConsumer(map);
var inputMapConsumer = new sourceMap.SourceMapConsumer(inputMap);
var outputMapConsumer = new sourceMap.SourceMapConsumer(map);
var outputMapGenerator = sourceMap.SourceMapGenerator.fromSourceMap(outputMapConsumer);
outputMapGenerator.applySourceMap(inputMapConsumer);
var mergedMap = outputMapGenerator.toJSON();
mergedMap.sources = inputMap.sources
mergedMap.file = inputMap.file;
mergedMap.file = inputMap.file;
return mergedMap;
}

View File

@ -29,9 +29,6 @@ export function ForOfStatement(node, parent, scope, file) {
t.inherits(loop, node);
// todo: find out why this is necessary? #538
loop._scopeInfo = node._scopeInfo;
if (build.replaceParent) {
this.parentPath.node = build.node;
} else {

View File

@ -10,7 +10,7 @@ export default class TraversalPath {
this.data = {};
}
static get(parentPath, context, parent, container, key) {
static get(parentPath: TraversalPath, context?: TraversalContext, parent, container, key, file?: File) {
var targetNode = container[key];
var paths = container._paths ||= [];
var path;
@ -28,17 +28,17 @@ export default class TraversalPath {
paths.push(path);
}
path.setContext(parentPath, context, key);
path.setContext(parentPath, context, key, file);
return path;
}
static getScope(node, parent, scope) {
static getScope(path: TraversalPath, scope: Scope, file?: File) {
var ourScope = scope;
// we're entering a new scope so let's construct it!
if (t.isScope(node, parent)) {
ourScope = new Scope(node, parent, scope);
if (path.isScope()) {
ourScope = new Scope(path, scope, file);
}
return ourScope;
@ -60,21 +60,24 @@ export default class TraversalPath {
return this.data[key];
}
setScope() {
this.scope = TraversalPath.getScope(this.node, this.parent, this.context.scope);
setScope(file?) {
this.scope = TraversalPath.getScope(this, this.context && this.context.scope, file);
}
setContext(parentPath, context, key) {
setContext(parentPath, context, key, file?) {
this.shouldSkip = false;
this.shouldStop = false;
this.parentPath = parentPath || this.parentPath;
this.context = context;
this.state = context.state;
this.opts = context.opts;
this.key = key;
this.setScope();
if (context) {
this.context = context;
this.state = context.state;
this.opts = context.opts;
}
this.setScope(file);
}
remove() {
@ -200,6 +203,10 @@ export default class TraversalPath {
return TraversalPath.get(this, this.context, this.node, this.node, key);
}
isScope() {
return t.isScope(this.node, this.parent);
}
isReferencedIdentifier(opts) {
return t.isReferencedIdentifier(this.node, this.parent, opts);
}

View File

@ -65,12 +65,20 @@ export default class Scope {
* within.
*/
constructor(block: Object, parentBlock: Object, parent?: Scope, file?: File) {
constructor(path: TraversalPath, parent?: Scope, file?: File) {
var cached = path.getData("scope");
if (cached) {
return cached;
} else {
path.setData("scope", this);
}
this.parent = parent;
this.file = parent ? parent.file : file;
this.parentBlock = parentBlock;
this.block = block;
this.parentBlock = path.parent;
this.block = path.node;
this.path = path;
this.crawl();
}
@ -472,7 +480,7 @@ export default class Scope {
*/
recrawl() {
this.block._scopeInfo = null;
this.path.setData("scopeInfo", null);
this.crawl();
}
@ -481,21 +489,21 @@ export default class Scope {
*/
crawl() {
var block = this.block;
var block = this.block;
var i;
//
var info = block._scopeInfo;
var info = this.path.getData("scopeInfo");
if (info) {
extend(this, info);
return;
}
info = block._scopeInfo = {
info = this.path.setData("scopeInfo", {
bindings: object(),
globals: object()
};
});
extend(this, info);