public void Visit(FunctionObject node) { // recurse the function binding if (node != null && node.Binding != null) { node.Binding.Accept(this); } }
public void Visit(FunctionObject node) { // if this is an arrow function, then we're good to go. Otherwise // this shouldn't be called for anything but a function expression, // which is definitely NOT safe to start a statement off because it would // then be interpreted as a function *declaration*. m_isSafe = node.IfNotNull(n => n.FunctionType == FunctionType.ArrowFunction); }
internal FunctionScope(ActivationObject parent, bool isExpression, CodeSettings settings, FunctionObject funcObj) : base(parent, settings) { ScopeType = ScopeType.Function; m_refScopes = new HashSet <ActivationObject>(); if (isExpression) { // parent scopes automatically reference enclosed function expressions AddReference(Parent); } Owner = funcObj; }
public override void Visit(FunctionObject node) { if (node != null) { // if we are reordering ANYTHING, then we need to do the reordering on a scope level. // so if that's the case, we need to create a list of all the child functions and NOT // recurse at this point. Then we'll reorder, then we'll use the lists to recurse. // BUT if we are not reordering anything, no sense making the lists and recursing later. // if that's the case, we can just recurse now and not have to worry about anything later. if (m_moveVarStatements || m_moveFunctionDecls) { // add the node to the appropriate list: either function expression or function declaration. // assume if it's not a function declaration, it must be an expression since the other types // are not declaration (getter, setter) and we want to treat declarations special. // if the conditional comment level isn't zero, then something funky is going on with // the conditional-compilation statements, and we don't want to move the declarations, so // don't add them to the declaration list. But we still want to recurse them, so add them // to the expression list (which get recursed but not moved). if (node.FunctionType == FunctionType.Declaration && m_conditionalCommentLevel == 0) { if (m_functionDeclarations == null) { m_functionDeclarations = new List <FunctionObject>(); } m_functionDeclarations.Add(node); } else { if (m_functionExpressions == null) { m_functionExpressions = new List <FunctionObject>(); } m_functionExpressions.Add(node); } // BUT DO NOT RECURSE!!!! // we only want the functions and variables in THIS scope, not child function scopes. //base.Visit(node); } else { // we're not reordering, so just recurse now to save the hassle base.Visit(node); } } }
private void WriteScopeReport(FunctionObject funcObj, ActivationObject scope) { // output the function header if (scope is GlobalScope) { WriteProgress(StringMgr.GetString("GlobalObjectsHeader")); } else { FunctionScope functionScope = scope as FunctionScope; if (functionScope != null && funcObj != null) { WriteFunctionHeader(funcObj, scope.IsKnownAtCompileTime); } else { BlockScope blockScope = scope as BlockScope; if (blockScope is CatchScope) { WriteBlockHeader(blockScope, StringMgr.GetString("BlockTypeCatch")); } else if (blockScope is WithScope) { WriteBlockHeader(blockScope, StringMgr.GetString("BlockTypeWith")); } else { WriteProgress(); WriteProgress(StringMgr.GetString("UnknownScopeType", scope.GetType().ToString())); } } } // get all the fields in the scope JSVariableField[] scopeFields = scope.GetFields(); // sort the fields Array.Sort(scopeFields, FieldComparer.Instance); // iterate over all the fields foreach (JSVariableField variableField in scopeFields) { // don't report placeholder fields if (!variableField.IsPlaceholder) { WriteMemberReport(variableField, scope); } } }
public void Visit(FunctionObject node) { if (node != null) { // if this is an arrow function with a single statement in the block that isn't a return statement, // then we need to ask the block statement if it requires a separator. if (node.FunctionType == FunctionType.ArrowFunction && node.Body.IfNotNull(b => b.Count == 1 && !(b[0] is ReturnNode))) { node.Body[0].Accept(this); } else { DoesRequire = false; } } }
public void Visit(FunctionObject node) { // we're good }
private static int RelocateFunction(Block block, int insertAt, FunctionObject funcDecl) { if (block[insertAt] != funcDecl) { // technically function declarations can only be direct children of the program or a function block. // and since we are passing in such a block, the parent of the function declaration better be that // block. If it isn't, we don't want to move it because it's not in an allowed place, and different // browsers treat that situation differently. Some browsers would process such funcdecls as if // they were a direct child of the main block. Others will treat it like a function expression with // an external name, and only assign the function to the name if that line of code is actually // executed. So since there's a difference, just leave them as-is and only move valid funcdecls. if (funcDecl.Parent == block && !InsideConditionalComment(funcDecl)) { // remove the function from it's parent, which will take it away from where it is right now. funcDecl.Parent.ReplaceChild(funcDecl, null); // now insert it into the block at the new location, incrementing the location so the next function // will be inserted after it. It is important that they be in the same order as the source, or the semantics // will change when there are functions with the same name. block.Insert(insertAt++, funcDecl); } } else { // we're already in the right place. Just increment the pointer to move to the next position // for next time ++insertAt; } // return the new position return insertAt; }
public override void Visit(FunctionObject node) { if (node != null) { // if we are reordering ANYTHING, then we need to do the reordering on a scope level. // so if that's the case, we need to create a list of all the child functions and NOT // recurse at this point. Then we'll reorder, then we'll use the lists to recurse. // BUT if we are not reordering anything, no sense making the lists and recursing later. // if that's the case, we can just recurse now and not have to worry about anything later. if (m_moveVarStatements || m_moveFunctionDecls) { // add the node to the appropriate list: either function expression or function declaration. // assume if it's not a function declaration, it must be an expression since the other types // are not declaration (getter, setter) and we want to treat declarations special. if (node.FunctionType == FunctionType.Declaration) { if (m_functionDeclarations == null) { m_functionDeclarations = new List<FunctionObject>(); } m_functionDeclarations.Add(node); } else { if (m_functionExpressions == null) { m_functionExpressions = new List<FunctionObject>(); } m_functionExpressions.Add(node); } // BUT DO NOT RECURSE!!!! // we only want the functions and variables in THIS scope, not child function scopes. //base.Visit(node); } else { // we're not reordering, so just recurse now to save the hassle base.Visit(node); } } }
private static string GetPropertyType(FunctionObject funcObj) { // should never be a function declaration.... return funcObj == null || funcObj.FunctionType == FunctionType.Expression ? "data" : funcObj.FunctionType == FunctionType.Getter ? "get" : "set"; }
public override void Visit(FunctionObject node) { if (node != null) { // get the name of this function, calculate something if it's anonymous if (node.Identifier == null) { node.Name = GuessAtName(node); } // don't analyze the identifier or we'll add an extra reference to it. // and we don't need to analyze the parameters because they were fielded-up // back when the function object was created, too if (ScopeStack.Peek().UseStrict) { // we need to make sure the function isn't named "eval" or "arguments" if (string.CompareOrdinal(node.Name, "eval") == 0 || string.CompareOrdinal(node.Name, "arguments") == 0) { if (node.IdContext != null) { node.IdContext.HandleError(JSError.StrictModeFunctionName, true); } else if (node.Context != null) { node.Context.HandleError(JSError.StrictModeFunctionName, true); } } // we need to make sure: // 1. there are no duplicate argument names, and // 2. none of them are named "eval" or "arguments" // create map that we'll use to determine if there are any dups if (node.ParameterDeclarations != null && node.ParameterDeclarations.Count > 0) { var parameterMap = new Dictionary<string, string>(node.ParameterDeclarations.Count); foreach (var parameter in node.ParameterDeclarations) { // if it already exists in the map, then it's a dup if (parameterMap.ContainsKey(parameter.Name)) { // already exists -- throw an error parameter.Context.HandleError(JSError.StrictModeDuplicateArgument, true); } else { // not in there, add it now parameterMap.Add(parameter.Name, parameter.Name); // now check to see if it's one of the two forbidden names if (string.CompareOrdinal(parameter.Name, "eval") == 0 || string.CompareOrdinal(parameter.Name, "arguments") == 0) { parameter.Context.HandleError(JSError.StrictModeArgumentName, true); } } } } } else if (node.ParameterDeclarations != null && node.ParameterDeclarations.Count > 0) { // not strict // if there are duplicate parameter names, throw a warning var parameterMap = new Dictionary<string, string>(node.ParameterDeclarations.Count); foreach (var parameter in node.ParameterDeclarations) { // if it already exists in the map, then it's a dup if (parameterMap.ContainsKey(parameter.Name)) { // already exists -- throw an error parameter.Context.HandleError(JSError.DuplicateName, false); } else { // not in there, add it now parameterMap.Add(parameter.Name, parameter.Name); } } } // push the stack and analyze the body ScopeStack.Push(node.FunctionScope); try { // recurse the body node.Body.Accept(this); } finally { ScopeStack.Pop(); } } }
//TYPE "NAME" - Starts at line LINE, col COLUMN STATUS [crunched to CRUNCH] // //TYPE: Function, Function getter, Function setter //STATUS: '', Unknown, Unreachable private void WriteFunctionHeader(FunctionObject funcObj, bool isKnown) { // get the crunched value (if any) string crunched = string.Empty; JSLocalField localField = funcObj.LocalField as JSLocalField; if (localField != null && localField.CrunchedName != null) { crunched = StringMgr.GetString("CrunchedTo", localField.CrunchedName, localField.RefCount); } // get the status if the function StringBuilder statusBuilder = new StringBuilder(); if (!isKnown) { statusBuilder.Append('['); statusBuilder.Append(StringMgr.GetString("NotKnown")); } if (funcObj.FunctionScope.Parent is GlobalScope) { // global function. // if this is a named function expression, we still want to know if it's // referenced by anyone if (funcObj.FunctionType == FunctionType.Expression && !string.IsNullOrEmpty(funcObj.Name)) { // output a comma separator if not the first item, otherwise // open the square bracket if (statusBuilder.Length > 0) { statusBuilder.Append(", "); } else { statusBuilder.Append('['); } statusBuilder.Append(StringMgr.GetString( "FunctionInfoReferences", funcObj.RefCount )); } } else if (!funcObj.FunctionScope.IsReferenced(null)) { // local function that isn't referenced -- unreachable! // output a comma separator if not the first item, otherwise // open the square bracket if (statusBuilder.Length > 0) { statusBuilder.Append(", "); } else { statusBuilder.Append('['); } statusBuilder.Append(StringMgr.GetString("Unreachable")); } if (statusBuilder.Length > 0) { statusBuilder.Append(']'); } string status = statusBuilder.ToString(); string functionType; switch (funcObj.FunctionType) { case FunctionType.Getter: functionType = "FunctionTypePropGet"; break; case FunctionType.Setter: functionType = "FunctionTypePropSet"; break; case FunctionType.Expression: functionType = "FunctionTypeExpression"; break; default: functionType = "FunctionTypeFunction"; break; } // output WriteProgress(); WriteProgress(StringMgr.GetString( "FunctionHeader", StringMgr.GetString(functionType), funcObj.Name, funcObj.Context.StartLineNumber, funcObj.Context.StartColumn, status, crunched )); }
public void Visit(FunctionObject node) { // invalid! ignore IsValid = false; }
public VariableDeclaration(Context context, JSParser parser, string identifier, Context idContext, AstNode initializer, FieldAttributes fieldAttributes, bool ignoreDuplicates) : base(context, parser) { // identifier cannot be null m_identifier = identifier; // initializer may be null m_initializer = initializer; if (m_initializer != null) { m_initializer.Parent = this; } // we'll need to do special stuff if the initializer if a function expression, // so try the conversion now FunctionObject functionValue = m_initializer as FunctionObject; string name = m_identifier.ToString(); ActivationObject currentScope = ScopeStack.Peek(); ActivationObject definingScope = currentScope; if (definingScope is BlockScope) { // block scope -- the variable is ACTUALLY defined in the containing function/global scope, // so we need to check THERE for duplicate defines. do { definingScope = definingScope.Parent; } while (definingScope is BlockScope); } JSVariableField field = definingScope[name]; if (field != null && (functionValue == null || functionValue != field.FieldValue)) { // this is a declaration that already has a field declared. // if the field is a named function expression, we want to fire an // ambiguous named function expression error -- and we know it's an NFE // if the FieldValue is a function object OR if the field // has already been marked ambiguous if (field.IsAmbiguous || field.FieldValue is FunctionObject) { if (idContext != null) { idContext.HandleError( JSError.AmbiguousNamedFunctionExpression, true ); } else if (context != null) { // not identifier context???? Try the whole statment context. // if neither context is set, then we don't get an error! context.HandleError( JSError.AmbiguousNamedFunctionExpression, true ); } // if we are preserving function names, then we need to mark this field // as not crunchable if (Parser.Settings.PreserveFunctionNames) { field.CanCrunch = false; } } else if (!ignoreDuplicates) { if (idContext != null) { // otherwise just a normal duplicate error idContext.HandleError( JSError.DuplicateName, field.IsLiteral ); } else if (context != null) { // otherwise just a normal duplicate error context.HandleError( JSError.DuplicateName, field.IsLiteral ); } } } bool isLiteral = ((fieldAttributes & FieldAttributes.Literal) != 0); // normally the value will be null. // but if there is no initializer, we'll use Missing so we can tell the difference. // and if this is a literal, we'll set it to the actual literal astnode object val = null; if (m_initializer == null) { val = Missing.Value; } else if (isLiteral || (functionValue != null)) { val = m_initializer; } m_field = currentScope.DeclareField( m_identifier, val, fieldAttributes ); m_field.OriginalContext = idContext; // we are now declared by a var statement m_field.IsDeclared = true; // if we are declaring a variable inside a with statement, then we will be declaring // a local variable in the enclosing scope if the with object doesn't have a property // of that name. But if it does, we won't actually be creating a variable field -- we'll // just use the property. So if we use an initializer in this declaration, then we will // actually be referencing the value. // SO, if this is a with-scope and this variable declaration has an initializer, we're going // to go ahead and bump up the reference. if (currentScope is WithScope && m_initializer != null) { m_field.AddReference(currentScope); } // special case the ambiguous function expression test. If we are var-ing a variable // with the same name as the function expression, then it's okay. We won't have an ambiguous // reference and it will be okay to use the name to reference the function expression if (functionValue != null && string.CompareOrdinal(m_identifier, functionValue.Name) == 0) { // null out the link to the named function expression // and make the function object point to the PROPER variable: the local within its own scope // and the inner is not pointing to the outer. functionValue.DetachFromOuterField(false); m_field.IsFunction = false; } }
//TYPE "NAME" - Starts at line LINE, col COLUMN STATUS [crunched to CRUNCH] // //TYPE: Function, Function getter, Function setter //STATUS: '', Unknown, Unreachable private void WriteFunctionHeader(FunctionObject funcObj, bool isKnown, bool useStrict) { // get the crunched value (if any) string crunched = string.Empty; var functionField = funcObj.Binding.IfNotNull(b => b.VariableField); if (functionField != null && functionField.CrunchedName != null) { crunched = AjaxMin.CrunchedTo.FormatInvariant(functionField.CrunchedName, functionField.RefCount); } // get the status if the function string status = null; var statusBuilder = StringBuilderPool.Acquire(); try { if (!isKnown) { statusBuilder.Append('['); statusBuilder.Append(AjaxMin.NotKnown); } if (funcObj.EnclosingScope.Parent is GlobalScope) { // global function. // if this is a named function expression, we still want to know if it's // referenced by anyone if (funcObj.FunctionType == FunctionType.Expression && funcObj.Binding != null && !funcObj.Binding.Name.IsNullOrWhiteSpace()) { // output a comma separator if not the first item, otherwise // open the square bracket if (statusBuilder.Length > 0) { statusBuilder.Append(", "); } else { statusBuilder.Append('['); } statusBuilder.Append(AjaxMin.FunctionInfoReferences.FormatInvariant( funcObj.Binding.VariableField.IfNotNull(v => v.RefCount) )); } } else if (!funcObj.IsReferenced && m_useReferenceCounts) { // local function that isn't referenced -- unreachable! // output a comma separator if not the first item, otherwise // open the square bracket if (statusBuilder.Length > 0) { statusBuilder.Append(", "); } else { statusBuilder.Append('['); } statusBuilder.Append(AjaxMin.Unreachable); } if (statusBuilder.Length > 0) { statusBuilder.Append(']'); } if (useStrict) { statusBuilder.Append(AjaxMin.ScopeIsStrictFlag); } status = statusBuilder.ToString(); } finally { statusBuilder.Release(); } string functionType; switch (funcObj.FunctionType) { case FunctionType.Getter: functionType = AjaxMin.FunctionTypePropGet; break; case FunctionType.Setter: functionType = AjaxMin.FunctionTypePropSet; break; case FunctionType.Expression: functionType = AjaxMin.FunctionTypeExpression; break; case FunctionType.ArrowFunction: functionType = AjaxMin.FunctionTypeArrow; break; case FunctionType.Method: functionType = AjaxMin.FunctionTypeMethod; break; default: functionType = AjaxMin.FunctionTypeFunction; break; } var functionName = funcObj.Binding.IfNotNull(b => b.Name); if (functionName.IsNullOrWhiteSpace()) { functionName = !funcObj.NameGuess.IsNullOrWhiteSpace() ? '"' + funcObj.NameGuess + '"' : AjaxMin.AnonymousName; } // output WriteProgress(); WriteProgress(AjaxMin.FunctionHeader.FormatInvariant( functionType, functionName, funcObj.Context.StartLineNumber, funcObj.Context.StartColumn + 1, status, crunched, funcObj.IsGenerator ? AjaxMin.FunctionTypeGenerator : string.Empty)); }