* @param {object} node * @param {array} path * @param {object} state
(node, path, state)
| 12318 | * @param {object} state |
| 12319 | */ |
| 12320 | function traverse(node, path, state) { |
| 12321 | /*jshint -W004*/ |
| 12322 | // Create a scope stack entry if this is the first node we've encountered in |
| 12323 | // its local scope |
| 12324 | var startIndex = null; |
| 12325 | var parentNode = path[0]; |
| 12326 | if (!Array.isArray(node) && state.localScope.parentNode !== parentNode) { |
| 12327 | if (_nodeIsClosureScopeBoundary(node, parentNode)) { |
| 12328 | var scopeIsStrict = state.scopeIsStrict; |
| 12329 | if (!scopeIsStrict |
| 12330 | && (node.type === Syntax.BlockStatement |
| 12331 | || node.type === Syntax.Program)) { |
| 12332 | scopeIsStrict = |
| 12333 | node.body.length > 0 |
| 12334 | && node.body[0].type === Syntax.ExpressionStatement |
| 12335 | && node.body[0].expression.type === Syntax.Literal |
| 12336 | && node.body[0].expression.value === 'use strict'; |
| 12337 | } |
| 12338 | |
| 12339 | if (node.type === Syntax.Program) { |
| 12340 | startIndex = state.g.buffer.length; |
| 12341 | state = utils.updateState(state, { |
| 12342 | scopeIsStrict: scopeIsStrict |
| 12343 | }); |
| 12344 | } else { |
| 12345 | startIndex = state.g.buffer.length + 1; |
| 12346 | state = utils.updateState(state, { |
| 12347 | localScope: { |
| 12348 | parentNode: parentNode, |
| 12349 | parentScope: state.localScope, |
| 12350 | identifiers: {}, |
| 12351 | tempVarIndex: 0, |
| 12352 | tempVars: [] |
| 12353 | }, |
| 12354 | scopeIsStrict: scopeIsStrict |
| 12355 | }); |
| 12356 | |
| 12357 | // All functions have an implicit 'arguments' object in scope |
| 12358 | declareIdentInScope('arguments', initScopeMetadata(node), state); |
| 12359 | |
| 12360 | // Include function arg identifiers in the scope boundaries of the |
| 12361 | // function |
| 12362 | if (parentNode.params.length > 0) { |
| 12363 | var param; |
| 12364 | var metadata = initScopeMetadata(parentNode, path.slice(1), path[0]); |
| 12365 | for (var i = 0; i < parentNode.params.length; i++) { |
| 12366 | param = parentNode.params[i]; |
| 12367 | if (param.type === Syntax.Identifier) { |
| 12368 | declareIdentInScope(param.name, metadata, state); |
| 12369 | } |
| 12370 | } |
| 12371 | } |
| 12372 | |
| 12373 | // Include rest arg identifiers in the scope boundaries of their |
| 12374 | // functions |
| 12375 | if (parentNode.rest) { |
| 12376 | var metadata = initScopeMetadata( |
| 12377 | parentNode, |
no test coverage detected