private void ResolveGhostedFunctions(ActivationObject scope, FunctionObject funcObject) { var functionField = funcObject.VariableField; // let's check on ghosted names in the outer variable scope var ghostField = scope[funcObject.Name]; if (ghostField == null) { // nothing; good to go. Add a ghosted field to keep track of it. ghostField = new JSVariableField(FieldType.GhostFunction, funcObject.Name); scope.AddField(ghostField); } else if (ghostField.FieldType == FieldType.GhostFunction) { // there is, but it's another ghosted function expression. // what if a lookup is resolved to this field later? We probably still need to // at least flag it as ambiguous. We will only need to throw an error, though, // if someone actually references the outer ghost variable. } else { // something already exists. Could be a naming collision for IE or at least a // a cross-browser behavior difference if it's not coded properly. // mark this field as a function, even if it wasn't before if (ghostField.OuterField != null) { // if the pre-existing field we are ghosting is a reference to // an OUTER field, then we actually have a problem that creates a BIG // difference between older IE browsers and everything else. // modern browsers will have the link to the outer field, but older // IE browsers will link to this function expression! // fire a cross-browser error warning _errorSink.HandleError( JSError.AmbiguousNamedFunctionExpression, funcObject.GetNameSpan(_locationResolver), _locationResolver ); } } // link them so they all keep the same name going forward // (since they are named the same in the sources) functionField.OuterField = ghostField; }
public override bool Walk(FunctionObject node) { AddNode(node, node.GetNameSpan(_tree.LocationResolver).Start, node.ParameterStart, node.ParameterEnd); return true; }
public override bool Walk(FunctionObject node) { if (node != null) { // create a function scope, assign it to the function object, // and push it on the stack var parentScope = CurrentLexicalScope; if (node.FunctionType == FunctionType.Expression && !string.IsNullOrEmpty(node.Name)) { // add this function object to the list of function objects the variable scope // will need to ghost later CurrentVariableScope.GhostedFunctions.Add(node); } SetScope( node, new FunctionScope(node, parentScope, node.FunctionType != FunctionType.Declaration, node, _errorSink) { IsInWithScope = m_withDepth > 0 } ); m_lexicalStack.Push(GetScope(node)); m_variableStack.Push(GetScope(node)); try { // recurse into the function to handle it after saving the current index and resetting it if (node.Body != null) { node.Body.Walk(this); } } finally { Debug.Assert(CurrentLexicalScope == GetScope(node)); m_lexicalStack.Pop(); m_variableStack.Pop(); } // 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 == FunctionType.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. _errorSink.HandleError(JSError.MisplacedFunctionDeclaration, node.GetNameSpan(_locationResolver), _locationResolver); CurrentVariableScope.GhostedFunctions.Add(node); } } } return(false); }
public override bool Walk(FunctionObject node) { if (node != null) { // create a function scope, assign it to the function object, // and push it on the stack var parentScope = CurrentLexicalScope; if (node.FunctionType == FunctionType.Expression && !string.IsNullOrEmpty(node.Name)) { // add this function object to the list of function objects the variable scope // will need to ghost later CurrentVariableScope.GhostedFunctions.Add(node); } SetScope( node, new FunctionScope(node, parentScope, node.FunctionType != FunctionType.Declaration, node, _errorSink) { IsInWithScope = m_withDepth > 0 } ); m_lexicalStack.Push(GetScope(node)); m_variableStack.Push(GetScope(node)); try { // recurse into the function to handle it after saving the current index and resetting it if (node.Body != null) { node.Body.Walk(this); } } finally { Debug.Assert(CurrentLexicalScope == GetScope(node)); m_lexicalStack.Pop(); m_variableStack.Pop(); } // 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 == FunctionType.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. _errorSink.HandleError(JSError.MisplacedFunctionDeclaration, node.GetNameSpan(_locationResolver), _locationResolver); CurrentVariableScope.GhostedFunctions.Add(node); } } } return false; }
public override bool Walk(FunctionObject node) { if (node.IsGenerator) { ReplaceFollowingWhiteSpace( node.GetStartIndex(_tree.LocationResolver) + "function".Length, "" ); if (node.Name != null) { ReplaceFollowingWhiteSpace( node.GeneratorIndex + "*".Length, " " ); } } else if (node.Name == null) { ReplaceFollowingWhiteSpace( node.GetStartIndex(_tree.LocationResolver) + "function".Length, _options.SpaceAfterFunctionInAnonymousFunctions ? " " : "" ); } else { ReplaceFollowingWhiteSpace( node.GetNameSpan(_tree.LocationResolver).End, "" ); } if (node.ParameterDeclarations != null && node.ParameterDeclarations.Length > 0) { ReplaceFollowingWhiteSpace( node.ParameterStart + 1, _options.SpaceAfterOpeningAndBeforeClosingNonEmptyParenthesis ? " " : "" ); for (int i = 1; i < node.ParameterDeclarations.Length; i++) { ReplacePreceedingWhiteSpace(node.ParameterDeclarations[i].GetStartIndex(_tree.LocationResolver), _options.SpaceAfterComma ? " " : "", _comma); } ReplacePreceedingWhiteSpace( node.ParameterEnd - 1, _options.SpaceAfterOpeningAndBeforeClosingNonEmptyParenthesis ? " " : "" ); } else { ReplaceFollowingWhiteSpace( node.ParameterStart + 1, "" ); } if (!_onEnter) { ReplacePreceedingIncludingNewLines( node.Body.GetStartIndex(_tree.LocationResolver), GetFlowFunctionBraceInsertion(node.ParameterEnd, false, node.Body.GetStartIndex(_tree.LocationResolver))); } WalkBlock(node.Body); return false; }