public override bool Walk(FunctionObject node) { // FunctionExpressions contain FunctionObjects. // Therefore we only need to handle FunctionObjects to handle both. if (node.Body.Braces != BraceState.StartAndEnd) { return false; } TagSpan span = GetFunctionSpan(_ast, _snapshot, node); OutliningTagSpans.Add(span); return base.Walk(node); }
internal FunctionScope(Statement node, ActivationObject parent, bool isExpression, FunctionObject funcObj, ErrorSink errorSink) : base(node, parent, errorSink) { m_refScopes = new HashSet<ActivationObject>(); if (isExpression) { // parent scopes automatically reference enclosed function expressions AddReference(Parent); } FunctionObject = funcObj; }
private bool WalkFunction(FunctionObject node, bool isExpression) { var functionAnalysis = AddFunction(node, _curUnit, isExpression); if (functionAnalysis != null) { _analysisStack.Push(_curUnit); _curUnit = functionAnalysis; Debug.Assert(_scope.EnumerateTowardsGlobal.Contains(functionAnalysis.Environment.Parent)); _scope = functionAnalysis.Environment; return true; } return false; }
internal FunctionScope(Statement node, ActivationObject parent, bool isExpression, FunctionObject funcObj, ErrorSink errorSink) : base(node, parent, errorSink) { m_refScopes = new HashSet <ActivationObject>(); if (isExpression) { // parent scopes automatically reference enclosed function expressions AddReference(Parent); } FunctionObject = funcObj; }
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; }
internal FunctionAnalysisUnit AddFunction(FunctionObject node, AnalysisUnit outerUnit, bool isExpression = false) { EnvironmentRecord scope; if (!_scope.GlobalEnvironment.TryGetNodeEnvironment(node, out scope)) { if (node.Body == null) { return null; } IAnalysisSet functionObj; UserFunctionValue func = null; if (!_scope.GlobalEnvironment.TryGetNodeValue(NodeEnvironmentKind.UserFunctionValue, node, out functionObj)) { func = CreateUserFunction(node, outerUnit); } else { func = (UserFunctionValue)functionObj; } var funcScope = GetFunctionEnvironment(func); scope = funcScope; VariableDef[] parameters = new VariableDef[node.ParameterDeclarations != null ? node.ParameterDeclarations.Length : 0]; for (int i = 0; i < parameters.Length; i++) { parameters[i] = funcScope.AddLocatedVariable( node.ParameterDeclarations[i].Name, node.ParameterDeclarations[i], _curUnit.ProjectEntry ); } _scope.Children.Add(scope); _scope.GlobalEnvironment.AddNodeEnvironment(node, scope); if (!isExpression && node.Name != null) { // lambdas don't have their names published var funcVar = _scope.AddLocatedVariable(node.Name, node, funcScope.AnalysisUnit); funcVar.AddTypes(funcScope.AnalysisUnit, func.SelfSet); } funcScope.AnalysisUnit.Enqueue(); } return ((FunctionEnvironmentRecord)scope).AnalysisUnit; }
public override void PostWalk(FunctionObject node) { if (node.Body != null) { Debug.Assert(_scope is DeclarativeEnvironmentRecord && ((DeclarativeEnvironmentRecord)_scope).Node == node); Debug.Assert(!(_scope.Parent is DeclarativeEnvironmentRecord) || ((DeclarativeEnvironmentRecord)_scope.Parent).Node != node); _scope = _scope.Parent; _curUnit = _analysisStack.Pop(); Debug.Assert(_scope.EnumerateTowardsGlobal.Contains(_curUnit.Environment)); } }
public override bool Walk(FunctionObject node) { IAnalysisSet value; EnvironmentRecord record; if (_scope.GlobalEnvironment.TryGetNodeEnvironment(node, out record) && _scope.GlobalEnvironment.TryGetNodeValue(NodeEnvironmentKind.UserFunctionValue, node, out value) && node.Name != null) { if (node.IsExpression) { // Only assign if the variable wasn't defined explicitly in the // functions scope. var varDef = record.GetVariable(node.Name); if (varDef != null && varDef is LocatedVariableDef && ((LocatedVariableDef)varDef).Node == node) { varDef.AddTypes( _projectEntry, value, false ); } } else { Debug.Assert(record.Parent.ContainsVariable(node.Name)); record.Parent.GetVariable(node.Name).AddTypes( _projectEntry, value, false ); } } return true; }
public override bool IsMatch(FunctionObject node) { if (node.ParameterDeclarations != null && node.ParameterDeclarations.Length >= 1) { var visitor = new CloneVisitor(node.ParameterDeclarations[0].VariableField); node.Walk(visitor); return visitor.ReturnsClonedVar; } return false; }
public override bool IsMatch(FunctionObject node) { MatchState state = new MatchState(node); return Body.IsMatch(state, node.Body); }
public MatchState(FunctionObject curFunction) { CurrentFunction = curFunction; }
public SpecializedUserFunctionValue(CallDelegate call, FunctionObject node, AnalysisUnit declUnit, EnvironmentRecord declScope, bool callBase) : base(node, declUnit, declScope) { _call = call; _callBase = callBase; }
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; }
private UserFunctionValue CreateUserFunction(FunctionObject node, AnalysisUnit outerUnit) { UserFunctionValue func = null; BaseSpecialization[] specializations; var funcName = node.Name ?? node.NameGuess; if (funcName != null && _specializations.TryGetValue(funcName, out specializations)) { foreach (var specialization in specializations) { if (specialization.IsMatch(node)) { func = new SpecializedUserFunctionValue( specialization.Specialization, node, outerUnit, _scope, specialization.CallBase ); break; } } } if (func == null) { func = new UserFunctionValue(node, outerUnit, _scope, _isNested); } _scope.GlobalEnvironment.AddNodeValue(NodeEnvironmentKind.UserFunctionValue, node, func.Proxy); return func; }
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; }
public override bool Walk(FunctionObject node) { return WalkFunction(node, false); }
public abstract bool IsMatch(FunctionObject node);
public MatchState(FunctionObject curFunction, MatchState outerState) { OuterState = outerState; _state = outerState._state; CurrentFunction = curFunction; }
private static TagSpan GetFunctionSpan(JsAst ast, ITextSnapshot snapshot, FunctionObject functionObject) { IndexSpan indexSpan = functionObject.Body.GetSpan(ast.LocationResolver); return(GetTagSpan(snapshot, indexSpan.Start, indexSpan.End, functionObject.ParameterEnd)); }