Beispiel #1
0
        public void DetachFromOuterField(bool leaveInnerPointingToOuter)
        {
            // we're going to change the reference from the outer variable to the inner variable
            // save the inner variable field
            JSNamedFunctionExpressionField nfeField = m_variableField.NamedFunctionExpression;

            // break the connection from the outer to the inner
            m_variableField.NamedFunctionExpression = null;

            if (!leaveInnerPointingToOuter)
            {
                // detach the inner from the outer
                nfeField.Detach();
            }

            // the outer field no longer points to the function object
            m_variableField.FieldValue = null;
            // but the inner field should
            nfeField.FieldValue = this;

            // our variable field is now the inner field
            m_variableField = nfeField;

            // and so is out identifier
            m_identifier.VariableField = nfeField;
        }
Beispiel #2
0
        // NAME [SCOPE TYPE] [crunched to CRUNCH]
        //
        // SCOPE: global, local, outer, ''
        // TYPE: var, function, argument, arguments array, possibly undefined
        private void WriteMemberReport(JSVariableField variableField, ActivationObject immediateScope)
        {
            // skip any *unreferenced* named-function-expression fields
            JSNamedFunctionExpressionField namedFuncExpr = variableField as JSNamedFunctionExpressionField;

            if (namedFuncExpr == null || namedFuncExpr.RefCount > 0 || !m_removeFunctionExpressionNames)
            {
                string scope    = string.Empty;
                string type     = string.Empty;
                string crunched = string.Empty;
                string name     = variableField.Name;
                if (variableField.IsLiteral)
                {
                    name = variableField.FieldValue.ToString();
                }

                // calculate the crunched label
                JSLocalField localField = variableField as JSLocalField;
                if (localField != null)
                {
                    if (localField.CrunchedName != null)
                    {
                        crunched = StringMgr.GetString("CrunchedTo", localField.CrunchedName, localField.RefCount);
                    }
                }

                // get the field's default scope and type
                GetFieldScopeType(variableField, immediateScope, out scope, out type);
                if (variableField is JSWithField)
                {
                    // if the field is a with field, we won't be using the crunched field (since
                    // those fields can't be crunched), so let's overload it with what the field
                    // could POSSIBLY be if the with object doesn't have a property of that name
                    string outerScope;
                    string outerType;
                    GetFieldScopeType(variableField.OuterField, immediateScope, out outerScope, out outerType);
                    crunched = StringMgr.GetString("MemberInfoWithPossibly", outerScope, outerType);
                }

                // format the entire string
                WriteProgress(StringMgr.GetString(
                                  "MemberInfoFormat",
                                  name,
                                  scope,
                                  type,
                                  crunched
                                  ));
            }
        }
Beispiel #3
0
        public FunctionObject(Lookup identifier, JSParser parser, FunctionType functionType, ParameterDeclaration[] parameterDeclarations, Block bodyBlock, Context functionContext, FunctionScope functionScope)
            : base(functionContext, parser)
        {
            FunctionType    = functionType;
            m_functionScope = functionScope;
            if (functionScope != null)
            {
                functionScope.FunctionObject = this;
            }

            m_name       = string.Empty;
            m_identifier = identifier;
            if (m_identifier != null)
            {
                m_identifier.Parent = this;
            }

            // make sure the parameter array is never null so we don't have to keep checking it
            m_parameterDeclarations = parameterDeclarations ?? new ParameterDeclaration[0];

            Body = bodyBlock;
            if (bodyBlock != null)
            {
                bodyBlock.Parent = this;
            }

            // now we need to make sure that the enclosing scope has the name of this function defined
            // so that any references get properly resolved once we start analyzing the parent scope
            // see if this is not anonymnous AND not a getter/setter
            bool isGetterSetter = (FunctionType == FunctionType.Getter || FunctionType == FunctionType.Setter);

            if (m_identifier != null && !isGetterSetter)
            {
                // yes -- add the function name to the current enclosing
                // check whether the function name is in use already
                // shouldn't be any duplicate names
                ActivationObject enclosingScope = m_functionScope.Parent;
                // functions aren't owned by block scopes
                while (enclosingScope is BlockScope)
                {
                    enclosingScope = enclosingScope.Parent;
                }

                // if the enclosing scope already contains this name, then we know we have a dup
                string functionName = m_identifier.Name;
                m_variableField = enclosingScope[functionName];
                if (m_variableField != null)
                {
                    // it's pointing to a function
                    m_variableField.IsFunction = true;

                    if (FunctionType == FunctionType.Expression)
                    {
                        // if the containing scope is itself a named function expression, then just
                        // continue on as if everything is fine. It will chain and be good.
                        if (!(m_variableField is JSNamedFunctionExpressionField))
                        {
                            if (m_variableField.NamedFunctionExpression != null)
                            {
                                // we have a second named function expression in the same scope
                                // with the same name. Not an error unless someone actually references
                                // it.

                                // we are now ambiguous.
                                m_variableField.IsAmbiguous = true;

                                // BUT because this field now points to multiple function object, we
                                // need to break the connection. We'll leave the inner NFEs pointing
                                // to this field as the outer field so the names all align, however.
                                DetachFromOuterField(true);

                                // create a new NFE pointing to the existing field as the outer so
                                // the names stay in sync, and with a value of our function object.
                                JSNamedFunctionExpressionField namedExpressionField =
                                    new JSNamedFunctionExpressionField(m_variableField);
                                namedExpressionField.FieldValue = this;
                                m_functionScope.AddField(namedExpressionField);

                                // hook our function object up to the named field
                                m_variableField            = namedExpressionField;
                                m_identifier.VariableField = namedExpressionField;

                                // we're done; quit.
                                return;
                            }
                            else if (m_variableField.IsAmbiguous)
                            {
                                // we're pointing to a field that is already marked as ambiguous.
                                // just create our own NFE pointing to this one, and hook us up.
                                JSNamedFunctionExpressionField namedExpressionField =
                                    new JSNamedFunctionExpressionField(m_variableField);
                                namedExpressionField.FieldValue = this;
                                m_functionScope.AddField(namedExpressionField);

                                // hook our function object up to the named field
                                m_variableField            = namedExpressionField;
                                m_identifier.VariableField = namedExpressionField;

                                // we're done; quit.
                                return;
                            }
                            else
                            {
                                // we are a named function expression in a scope that has already
                                // defined a local variable of the same name. Not good. Throw the
                                // error but keep them attached because the names have to be synced
                                // to keep the same meaning in all browsers.
                                m_identifier.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)
                                {
                                    m_variableField.CanCrunch = false;
                                }
                            }
                        }

                        /*else
                         * {
                         *  // it's okay; just chain the NFEs as normal and everything will work out
                         *  // and the names will be properly synced.
                         * }*/
                    }
                    else
                    {
                        // function declaration -- duplicate name
                        m_identifier.Context.HandleError(JSError.DuplicateName, false);
                    }
                }
                else
                {
                    // doesn't exist -- create it now
                    m_variableField = enclosingScope.DeclareField(functionName, this, 0);

                    // and it's a pointing to a function object
                    m_variableField.IsFunction = true;
                }

                // set the identifier variable field now. We *know* what the field is now, and during
                // Analyze mode we aren't going to recurse into the identifier because that would add
                // a reference to it.
                m_identifier.VariableField = m_variableField;

                // if we're here, we have a name. if this is a function expression, then we have
                // a named function expression and we need to do a little more work to prepare for
                // the ambiguities of named function expressions in various browsers.
                if (FunctionType == FunctionType.Expression)
                {
                    // now add a field within the function scope that indicates that it's okay to reference
                    // this named function expression from WITHIN the function itself.
                    // the inner field points to the outer field since we're going to want to catch ambiguous
                    // references in the future
                    JSNamedFunctionExpressionField namedExpressionField = new JSNamedFunctionExpressionField(m_variableField);
                    m_functionScope.AddField(namedExpressionField);
                    m_variableField.NamedFunctionExpression = namedExpressionField;
                }
                else
                {
                    // function declarations are declared by definition
                    m_variableField.IsDeclared = true;
                }
            }
        }
Beispiel #4
0
        internal virtual void ReserveFields()
        {
            // traverse through our children first to get depth-first
            foreach (ActivationObject scope in m_childScopes)
            {
                scope.ReserveFields();
            }

            // then reserve all our fields that need reserving
            // check for unused local fields or arguments
            foreach (JSVariableField variableField in m_nameTable.Values)
            {
                JSLocalField localField = variableField as JSLocalField;
                if (localField != null)
                {
                    // if this is a named-function-expression name, then we want to use the name of the
                    // outer field so we don't collide in IE
                    JSNamedFunctionExpressionField namedExprField = localField as JSNamedFunctionExpressionField;
                    if (namedExprField != null)
                    {
                        // make sure the field is in this scope's verboten list so we don't accidentally reuse
                        // an outer scope variable name
                        if (!Verboten.ContainsKey(localField))
                        {
                            Verboten.Add(localField, localField);
                        }

                        // we don't need to reserve up the scope because the named function expression's
                        // "outer" field is always in the very next scope
                    }
                    else if (localField.OuterField != null)
                    {
                        // if the outer field is not null, then this field (not the name) needs to be
                        // reserved up the scope chain until the scope where it's defined.
                        // make sure the field is in this scope's verboten list so we don't accidentally reuse
                        // the outer scope's variable name
                        if (!Verboten.ContainsKey(localField))
                        {
                            Verboten.Add(localField, localField);
                        }

                        for (ActivationObject scope = this; scope != null; scope = scope.Parent)
                        {
                            // get the local field by this name (if any)
                            JSLocalField scopeField = scope.GetLocalField(variableField.Name);
                            if (scopeField == null)
                            {
                                // it's not referenced in this scope -- if the field isn't in the verboten
                                // list, add it now
                                if (!scope.Verboten.ContainsKey(localField))
                                {
                                    scope.Verboten.Add(localField, localField);
                                }
                            }
                            else if (scopeField.OuterField == null)
                            {
                                // found the original field -- stop looking
                                break;
                            }
                        }
                    }
                    else if (m_parser.Settings.LocalRenaming == LocalRenaming.KeepLocalizationVars &&
                             localField.Name.StartsWith("L_", StringComparison.Ordinal))
                    {
                        // localization variable. don't crunch it.
                        // add it to this scope's verboten list in the extremely off-hand chance
                        // that a crunched variable might be the same pattern
                        if (!Verboten.ContainsKey(localField))
                        {
                            Verboten.Add(localField, localField);
                        }
                    }
                    else if (!localField.CanCrunch)
                    {
                        // this local field cannot be crunched for whatever reason
                        // (we probably already have a name picked out for it that we want to keep).
                        // add it to the verboten list, too.
                        if (!Verboten.ContainsKey(localField))
                        {
                            Verboten.Add(localField, localField);
                        }
                    }
                }
                else
                {
                    // must be a global of some sort
                    // reserve the name in this scope and all the way up the chain
                    for (ActivationObject scope = this; scope != null; scope = scope.Parent)
                    {
                        if (!scope.Verboten.ContainsKey(variableField))
                        {
                            scope.Verboten.Add(variableField, variableField);
                        }
                    }
                }
            }

            // finally, if this scope is not known at compile time,
            // AND we know we want to make all affected scopes safe
            // for the eval statement
            // AND we are actually referenced by the enclosing scope,
            // then our parent scope is also not known at compile time
            if (!m_isKnownAtCompileTime &&
                Parser.Settings.EvalTreatment == EvalTreatment.MakeAllSafe)
            {
                ActivationObject parentScope = (ActivationObject)Parent;
                FunctionScope    funcScope   = this as FunctionScope;
                if (funcScope == null)
                {
                    // we're not a function -- parent is unknown too
                    parentScope.IsKnownAtCompileTime = false;
                }
                else
                {
                    JSLocalField localField = parentScope.GetLocalField(funcScope.FunctionObject.Name);
                    if (localField == null || localField.IsReferenced)
                    {
                        parentScope.IsKnownAtCompileTime = false;
                    }
                }
            }
        }
Beispiel #5
0
        private static void GetFieldScopeType(JSVariableField variableField, ActivationObject immediateScope, out string scope, out string type)
        {
            JSLocalField      localField                 = variableField as JSLocalField;
            JSPredefinedField predefinedField            = variableField as JSPredefinedField;
            JSNamedFunctionExpressionField namedFuncExpr = variableField as JSNamedFunctionExpressionField;

            // default scope is blank
            scope = string.Empty;

            if (variableField is JSArgumentField)
            {
                type = StringMgr.GetString("MemberInfoTypeArgument");
            }
            else if (variableField is JSArgumentsField)
            {
                type = StringMgr.GetString("MemberInfoTypeArguments");
            }
            else if (predefinedField != null)
            {
                switch (predefinedField.GlobalObject)
                {
                case GlobalObjectInstance.GlobalObject:
                    scope = StringMgr.GetString("MemberInfoScopeGlobalObject");
                    break;

                case GlobalObjectInstance.WindowObject:
                    scope = StringMgr.GetString("MemberInfoScopeWindowObject");
                    break;

                case GlobalObjectInstance.Other:
                    scope = StringMgr.GetString("MemberInfoScopeOtherObject");
                    break;
                }
                switch (predefinedField.MemberType)
                {
                case MemberTypes.Method:
                    type = StringMgr.GetString("MemberInfoBuiltInMethod");
                    break;

                case MemberTypes.Property:
                    type = StringMgr.GetString("MemberInfoBuiltInProperty");
                    break;

                default:
                    type = StringMgr.GetString("MemberInfoBuiltInObject");
                    break;
                }
            }
            else if (variableField is JSGlobalField)
            {
                if ((variableField.Attributes & FieldAttributes.RTSpecialName) == FieldAttributes.RTSpecialName)
                {
                    // this is a special "global." It might not be a global, but something referenced
                    // in a with scope somewhere down the line.
                    type = StringMgr.GetString("MemberInfoPossiblyUndefined");
                }
                else if (variableField.FieldValue is FunctionObject)
                {
                    if (variableField.NamedFunctionExpression == null)
                    {
                        type = StringMgr.GetString("MemberInfoGlobalFunction");
                    }
                    else
                    {
                        type = StringMgr.GetString("MemberInfoFunctionExpression");
                    }
                }
                else
                {
                    type = StringMgr.GetString("MemberInfoGlobalVar");
                }
            }
            else if (variableField is JSWithField)
            {
                type = StringMgr.GetString("MemberInfoWithField");
            }
            else if (namedFuncExpr != null)
            {
                type = StringMgr.GetString("MemberInfoSelfFuncExpr");
            }
            else if (localField != null)
            {
                // type string
                if (localField.FieldValue is FunctionObject)
                {
                    if (localField.NamedFunctionExpression == null)
                    {
                        type = StringMgr.GetString("MemberInfoLocalFunction");
                    }
                    else
                    {
                        type = StringMgr.GetString("MemberInfoFunctionExpression");
                    }
                }
                else if (localField.IsLiteral)
                {
                    type = StringMgr.GetString("MemberInfoLocalLiteral");
                }
                else
                {
                    type = StringMgr.GetString("MemberInfoLocalVar");
                }

                // scope string
                // this is a local variable, so there MUST be a non-null function scope passed
                // to us. That function scope will be the scope we are expecting local variables
                // to be defined in. If the field is defined in that scope, it's local -- otherwise
                // it must be an outer variable.
                JSVariableField scopeField = immediateScope[variableField.Name];
                if (scopeField == null || scopeField.OuterField != null)
                {
                    scope = StringMgr.GetString("MemberInfoScopeOuter");
                }
                else
                {
                    scope = StringMgr.GetString("MemberInfoScopeLocal");
                }
            }
            else
            {
                type = StringMgr.GetString("MemberInfoBuiltInObject");
            }
        }
Beispiel #6
0
        public FunctionObject(Lookup identifier, JSParser parser, FunctionType functionType, ParameterDeclaration[] parameterDeclarations, Block bodyBlock, Context functionContext, FunctionScope functionScope)
            : base(functionContext, parser)
        {
            FunctionType = functionType;
            m_functionScope = functionScope;
            if (functionScope != null)
            {
                functionScope.FunctionObject = this;
            }

            m_name = string.Empty;
            Identifier = identifier;
            if (Identifier != null) { Identifier.Parent = this; }

            m_parameterDeclarations = parameterDeclarations;

            Body = bodyBlock;
            if (bodyBlock != null) { bodyBlock.Parent = this; }

            // now we need to make sure that the enclosing scope has the name of this function defined
            // so that any references get properly resolved once we start analyzing the parent scope
            // see if this is not anonymnous AND not a getter/setter
            bool isGetterSetter = (FunctionType == FunctionType.Getter || FunctionType == FunctionType.Setter);
            if (Identifier != null && !isGetterSetter)
            {
                // yes -- add the function name to the current enclosing
                // check whether the function name is in use already
                // shouldn't be any duplicate names
                ActivationObject enclosingScope = m_functionScope.Parent;
                // functions aren't owned by block scopes
                while (enclosingScope is BlockScope)
                {
                    enclosingScope = enclosingScope.Parent;
                }

                // if the enclosing scope already contains this name, then we know we have a dup
                string functionName = Identifier.Name;
                m_variableField = enclosingScope[functionName];
                if (m_variableField != null)
                {
                    // it's pointing to a function
                    m_variableField.IsFunction = true;

                    if (FunctionType == FunctionType.Expression)
                    {
                        // if the containing scope is itself a named function expression, then just
                        // continue on as if everything is fine. It will chain and be good.
                        if (!(m_variableField is JSNamedFunctionExpressionField))
                        {
                            if (m_variableField.NamedFunctionExpression != null)
                            {
                                // we have a second named function expression in the same scope
                                // with the same name. Not an error unless someone actually references
                                // it.

                                // we are now ambiguous.
                                m_variableField.IsAmbiguous = true;

                                // BUT because this field now points to multiple function object, we
                                // need to break the connection. We'll leave the inner NFEs pointing
                                // to this field as the outer field so the names all align, however.
                                DetachFromOuterField(true);

                                // create a new NFE pointing to the existing field as the outer so
                                // the names stay in sync, and with a value of our function object.
                                JSNamedFunctionExpressionField namedExpressionField =
                                    new JSNamedFunctionExpressionField(m_variableField);
                                namedExpressionField.FieldValue = this;
                                m_functionScope.AddField(namedExpressionField);

                                // hook our function object up to the named field
                                m_variableField = namedExpressionField;
                                Identifier.VariableField = namedExpressionField;

                                // we're done; quit.
                                return;
                            }
                            else if (m_variableField.IsAmbiguous)
                            {
                                // we're pointing to a field that is already marked as ambiguous.
                                // just create our own NFE pointing to this one, and hook us up.
                                JSNamedFunctionExpressionField namedExpressionField =
                                    new JSNamedFunctionExpressionField(m_variableField);
                                namedExpressionField.FieldValue = this;
                                m_functionScope.AddField(namedExpressionField);

                                // hook our function object up to the named field
                                m_variableField = namedExpressionField;
                                Identifier.VariableField = namedExpressionField;

                                // we're done; quit.
                                return;
                            }
                            else
                            {
                                // we are a named function expression in a scope that has already
                                // defined a local variable of the same name. Not good. Throw the
                                // error but keep them attached because the names have to be synced
                                // to keep the same meaning in all browsers.
                                Identifier.Context.HandleError(JSError.AmbiguousNamedFunctionExpression, false);

                                // if we are preserving function names, then we need to mark this field
                                // as not crunchable
                                if (Parser.Settings.PreserveFunctionNames)
                                {
                                    m_variableField.CanCrunch = false;
                                }
                            }
                        }
                        /*else
                        {
                            // it's okay; just chain the NFEs as normal and everything will work out
                            // and the names will be properly synced.
                        }*/
                    }
                    else
                    {
                        // function declaration -- duplicate name
                        Identifier.Context.HandleError(JSError.DuplicateName, false);
                    }
                }
                else
                {
                    // doesn't exist -- create it now
                    m_variableField = enclosingScope.DeclareField(functionName, this, 0);

                    // and it's a pointing to a function object
                    m_variableField.IsFunction = true;
                }

                // set the identifier variable field now. We *know* what the field is now, and during
                // Analyze mode we aren't going to recurse into the identifier because that would add
                // a reference to it.
                Identifier.VariableField = m_variableField;

                // if we're here, we have a name. if this is a function expression, then we have
                // a named function expression and we need to do a little more work to prepare for
                // the ambiguities of named function expressions in various browsers.
                if (FunctionType == FunctionType.Expression)
                {
                    // now add a field within the function scope that indicates that it's okay to reference
                    // this named function expression from WITHIN the function itself.
                    // the inner field points to the outer field since we're going to want to catch ambiguous
                    // references in the future
                    JSNamedFunctionExpressionField namedExpressionField = new JSNamedFunctionExpressionField(m_variableField);
                    m_functionScope.AddField(namedExpressionField);
                    m_variableField.NamedFunctionExpression = namedExpressionField;
                }
                else
                {
                    // function declarations are declared by definition
                    m_variableField.IsDeclared = true;
                }
            }
        }