|
@ -13,52 +13,52 @@ export default function attachScopes ( statement ) { |
|
|
enter ( node, parent ) { |
|
|
enter ( node, parent ) { |
|
|
let newScope; |
|
|
let newScope; |
|
|
|
|
|
|
|
|
switch ( node.type ) { |
|
|
// function foo () {...}
|
|
|
case 'FunctionDeclaration': |
|
|
// class Foo {...}
|
|
|
|
|
|
if ( /(Function|Class)Declaration/.test( node.type ) ) { |
|
|
scope.addDeclaration( node, false, false ); |
|
|
scope.addDeclaration( node, false, false ); |
|
|
break; |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// var foo = 1
|
|
|
|
|
|
// TODO can we have multiple declarations at this point? when
|
|
|
|
|
|
// do we create synthetic var nodes?
|
|
|
|
|
|
if ( node.type === 'VariableDeclaration' ) { |
|
|
|
|
|
const isBlockDeclaration = blockDeclarations[ node.kind ]; |
|
|
|
|
|
node.declarations.forEach( declarator => { |
|
|
|
|
|
scope.addDeclaration( declarator, isBlockDeclaration, true ); |
|
|
|
|
|
}); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
case 'BlockStatement': |
|
|
// create new function scope
|
|
|
if ( parent && /Function/.test( parent.type ) ) { |
|
|
if ( /Function/.test( node.type ) ) { |
|
|
newScope = new Scope({ |
|
|
newScope = new Scope({ |
|
|
parent: scope, |
|
|
parent: scope, |
|
|
block: false, |
|
|
block: false, |
|
|
params: parent.params |
|
|
params: node.params |
|
|
}); |
|
|
}); |
|
|
|
|
|
|
|
|
// named function expressions - the name is considered
|
|
|
// named function expressions - the name is considered
|
|
|
// part of the function's scope
|
|
|
// part of the function's scope
|
|
|
if ( parent.type === 'FunctionExpression' && parent.id ) { |
|
|
if ( node.type === 'FunctionExpression' && node.id ) { |
|
|
newScope.addDeclaration( parent, false, false ); |
|
|
newScope.addDeclaration( node, false, false ); |
|
|
} |
|
|
} |
|
|
} else { |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// create new block scope
|
|
|
|
|
|
if ( node.type === 'BlockStatement' && !/Function/.test( parent.type ) ) { |
|
|
newScope = new Scope({ |
|
|
newScope = new Scope({ |
|
|
parent: scope, |
|
|
parent: scope, |
|
|
block: true |
|
|
block: true |
|
|
}); |
|
|
}); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
break; |
|
|
// catch clause has its own block scope
|
|
|
|
|
|
if ( node.type === 'CatchClause' ) { |
|
|
case 'CatchClause': |
|
|
|
|
|
newScope = new Scope({ |
|
|
newScope = new Scope({ |
|
|
parent: scope, |
|
|
parent: scope, |
|
|
params: [ node.param ], |
|
|
params: [ node.param ], |
|
|
block: true |
|
|
block: true |
|
|
}); |
|
|
}); |
|
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
|
|
|
|
case 'VariableDeclaration': |
|
|
|
|
|
node.declarations.forEach( declarator => { |
|
|
|
|
|
const isBlockDeclaration = node.type === 'VariableDeclaration' && blockDeclarations[ node.kind ]; |
|
|
|
|
|
scope.addDeclaration( declarator, isBlockDeclaration, true ); |
|
|
|
|
|
}); |
|
|
|
|
|
break; |
|
|
|
|
|
|
|
|
|
|
|
case 'ClassDeclaration': |
|
|
|
|
|
scope.addDeclaration( node, false, false ); |
|
|
|
|
|
break; |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
if ( newScope ) { |
|
|
if ( newScope ) { |
|
|