nonlocal = (parsed) => {
const state = {in_scope: [], nonlocal: []}
walk.recursive(parsed, state, {
Identifier(node, state, c) {
if (!state.in_scope.includes(node.name)) state.nonlocal.push(node.name)
},
VariableDeclarator(node, state, c) {
state.in_scope.push(node.id.name)
c(node.id, state)
node.init && c(node.init, state)
},
FunctionDeclaration(node, state, c) {
node.id && state.in_scope.push(node.id.name)
const old_scope = [...state.in_scope]
node.params.map(p => state.in_scope.push(p.name))
c(node.id, state)
node.params.map(p => c(p, state))
c(node.body, state)
state.in_scope = old_scope
},
FunctionExpression(node, state, c) {
const old_scope = [...state.in_scope]
node.params.map(p => state.in_scope.push(p.name))
node.params.map(p => c(p, state))
c(node.body, state)
state.in_scope = old_scope
},
ArrowFunctionExpression(node, state, c) {
const old_scope = [...state.in_scope]
node.params.map(p => state.in_scope.push(p.name))
node.params.map(p => c(p, state))
c(node.body, state)
state.in_scope = old_scope
},
ForStatement(node, state, c) {
const old_scope = [...state.in_scope]
c(node.init, state)
c(node.test, state)
c(node.update, state)
c(node.body, state)
state.in_scope = old_scope
},
ForInStatement(node, state, c) {
const old_scope = [...state.in_scope]
c(node.left, state)
c(node.right, state)
c(node.body, state)
state.in_scope = old_scope
},
ForOfStatement(node, state, c) {
const old_scope = [...state.in_scope]
c(node.left, state)
c(node.right, state)
c(node.body, state)
state.in_scope = old_scope
},
BlockStatement(node, state, c) {
const old_scope = [...state.in_scope]
node.body.map(e => c(e, state))
state.in_scope = old_scope
},
})
return state.nonlocal
}