public void Visit(JsFunctionObject node) { if (node != null) { // it's a declaration; put the index to -1. node.Index = -1; // create a function scope, assign it to the function object, // and push it on the stack var parentScope = CurrentLexicalScope; if (node.FunctionType == JsFunctionType.Expression && !string.IsNullOrEmpty(node.Name)) { // function expressions have an intermediate scope between the parent and the // function's scope that contains just the function name so the function can // be self-referencing without the function expression polluting the parent scope. // don't add the function name field yet, because it's not a decl per se. parentScope = new JsFunctionScope(parentScope, true, m_settings, node) { IsInWithScope = m_withDepth > 0 }; // add this function object to the list of function objects the variable scope // will need to ghost later CurrentVariableScope.GhostedFunctions.Add(node); } node.FunctionScope = new JsFunctionScope(parentScope, node.FunctionType != JsFunctionType.Declaration, m_settings, node) { IsInWithScope = m_withDepth > 0 }; m_lexicalStack.Push(node.FunctionScope); m_variableStack.Push(node.FunctionScope); var savedIndex = m_orderIndex; try { // recurse into the function to handle it after saving the current index and resetting it if (node.Body != null) { m_orderIndex = 0; node.Body.Accept(this); } } finally { Debug.Assert(CurrentLexicalScope == node.FunctionScope); m_lexicalStack.Pop(); m_variableStack.Pop(); m_orderIndex = savedIndex; } // nothing to add to the var-decl list. // but add the function name to the current lex-decl list // IF it is a declaration and it has a name (and it SHOULD unless there was an error) if (node.FunctionType == JsFunctionType.Declaration && !string.IsNullOrEmpty(node.Name)) { var lexicalScope = CurrentLexicalScope; lexicalScope.LexicallyDeclaredNames.Add(node); if (lexicalScope != CurrentVariableScope) { // the current lexical scope is the variable scope. // this is ES6 syntax: a function declaration inside a block scope. Not allowed // in ES5 code, so throw a warning and ghost this function in the outer variable scope // to make sure that we don't generate any naming collisions. node.NameContext.HandleError(JsError.MisplacedFunctionDeclaration, false); CurrentVariableScope.GhostedFunctions.Add(node); } } } }