示例#1
0
        internal override void AnalyzeNode()
        {
            // throw a warning discouraging the use of this statement
            Context.HandleError(JSError.WithNotRecommended, false);

            // hold onto the with-scope in case we need to do something with it
            BlockScope withScope = (m_block == null ? null : m_block.BlockScope);

            if (Parser.Settings.StripDebugStatements &&
                Parser.Settings.IsModificationAllowed(TreeModifications.StripDebugStatements) &&
                m_block != null &&
                m_block.IsDebuggerStatement)
            {
                m_block = null;
            }

            // recurse
            base.AnalyzeNode();

            // we'd have to know what the object (obj) evaluates to before we
            // can figure out what to add to the scope -- not possible without actually
            // running the code. This could throw a whole bunch of 'undefined' errors.
            if (m_block != null && m_block.Count == 0)
            {
                m_block = null;
            }

            // we got rid of the block -- tidy up the no-longer-needed scope
            if (m_block == null && withScope != null)
            {
                // because the scope is empty, we now know it (it does nothing)
                withScope.IsKnownAtCompileTime = true;
            }
        }
示例#2
0
        internal override void AnalyzeNode()
        {
            // verify the syntax
            try
            {
                // just try instantiating a Regex object with this string.
                // if it's invalid, it will throw an exception.
                // we don't need to pass the flags -- we're just interested in the pattern
                Regex re = new Regex(m_pattern, RegexOptions.ECMAScript);

                // basically we have this test here so the re variable is referenced
                // and FxCop won't throw an error. There really aren't any cases where
                // the constructor will return null (other than out-of-memory)
                if (re == null)
                {
                    Context.HandleError(JSError.RegExpSyntax, true);
                }
            }
            catch (System.ArgumentException e)
            {
                System.Diagnostics.Debug.WriteLine(e.ToString());
                Context.HandleError(JSError.RegExpSyntax, true);
            }
            // don't bother calling the base -- there are no children
        }
示例#3
0
文件: return.cs 项目: formist/LinkMe
        internal override void AnalyzeNode()
        {
            // first we want to make sure that we are indeed within a function scope.
            // it makes no sense to have a return outside of a function
            ActivationObject scope = ScopeStack.Peek();

            while (scope != null && !(scope is FunctionScope))
            {
                scope = scope.Parent;
            }
            if (scope == null)
            {
                Context.HandleError(JSError.BadReturn);
            }

            // now just do the default analyze
            base.AnalyzeNode();
        }
示例#4
0
        internal override void AnalyzeScope()
        {
            if (Context != null)
            {
                // get the parent global/function scope where variables defined within our
                // scope are REALLY defined
                ActivationObject definingScope = this;
                do
                {
                    definingScope = definingScope.Parent;
                } while (definingScope is BlockScope);

                // see if there is a variable already defined in that scope with the same name
                JSVariableField outerField = definingScope[m_name];
                if (outerField != null)
                {
                    // there is one defined already!!!
                    // but if it isn't referenced, it's safe to just use it
                    // as the outer field for our catch variable so our names
                    // stay in sync when we rename stuff
                    if (outerField.IsReferenced)
                    {
                        // but the outer field IS referenced somewhere! We have a possible ambiguous
                        // catch variable problem that behaves differently in IE and non-IE browsers.
                        Context.HandleError(JSError.AmbiguousCatchVar);
                    }
                }
                else
                {
                    // there isn't one defined -- add one and hook it to our argument
                    // field as the outer reference so the name doesn't collide with any
                    // other fields in that scope if we are renaming fields
                    outerField = definingScope.CreateField(m_name, null, 0);
                    outerField.IsPlaceholder = true;
                    definingScope.AddField(outerField);
                }

                // point our inner catch variable to the outer variable
                this[m_name].OuterField = outerField;
            }
            base.AnalyzeScope();
        }
示例#5
0
        internal virtual void AnalyzeScope()
        {
            // check for unused local fields or arguments
            foreach (JSVariableField variableField in m_nameTable.Values)
            {
                JSLocalField locField = variableField as JSLocalField;
                if (locField != null && !locField.IsReferenced && locField.OriginalContext != null)
                {
                    if (locField.FieldValue is FunctionObject)
                    {
                        Context ctx = ((FunctionObject)locField.FieldValue).IdContext;
                        if (ctx == null)
                        {
                            ctx = locField.OriginalContext;
                        }
                        ctx.HandleError(JSError.FunctionNotReferenced, false);
                    }
                    else if (!locField.IsGenerated)
                    {
                        JSArgumentField argumentField = locField as JSArgumentField;
                        if (argumentField != null)
                        {
                            // we only want to throw this error if it's possible to remove it
                            // from the argument list. And that will only happen if there are
                            // no REFERENCED arguments after this one in the formal parameter list.
                            // Assertion: because this is a JSArgumentField, this should be a function scope,
                            // let's walk up to the first function scope we find, just in case.
                            FunctionScope functionScope = this as FunctionScope;
                            if (functionScope == null)
                            {
                                ActivationObject scope = this.Parent;
                                while (scope != null)
                                {
                                    functionScope = scope as FunctionScope;
                                    if (scope != null)
                                    {
                                        break;
                                    }
                                }
                            }
                            if (functionScope == null || functionScope.IsArgumentTrimmable(argumentField))
                            {
                                locField.OriginalContext.HandleError(
                                    JSError.ArgumentNotReferenced,
                                    false
                                    );
                            }
                        }
                        else if (locField.OuterField == null || !locField.OuterField.IsReferenced)
                        {
                            locField.OriginalContext.HandleError(
                                JSError.VariableDefinedNotReferenced,
                                false
                                );
                        }
                    }
                }
            }

            // rename fields if we need to
            RenameFields();

            // recurse
            foreach (ActivationObject activationObject in m_childScopes)
            {
                try
                {
                    Parser.ScopeStack.Push(activationObject);
                    activationObject.AnalyzeScope();
                }
                finally
                {
                    Parser.ScopeStack.Pop();
                }
            }
        }
示例#6
0
文件: call.cs 项目: formist/LinkMe
        internal override void AnalyzeNode()
        {
            // see if this is a member (we'll need it for a couple checks)
            Member member = m_func as Member;

            if (Parser.Settings.StripDebugStatements && Parser.Settings.IsModificationAllowed(TreeModifications.StripDebugStatements))
            {
                // if this is a member, and it's a debugger object, and it's a constructor....
                if (member != null && member.IsDebuggerStatement && m_isConstructor)
                {
                    // we need to replace our debugger object with a generic Object
                    m_func = new Lookup("Object", m_func.Context, Parser);
                    // and make sure the node list is empty
                    if (m_args != null && m_args.Count > 0)
                    {
                        m_args = new AstNodeList(m_args.Context, Parser);
                    }
                }
            }

            // if this is a constructor and we want to collapse
            // some of them to literals...
            if (m_isConstructor && Parser.Settings.CollapseToLiteral)
            {
                // see if this is a lookup, and if so, if it's pointing to one
                // of the two constructors we want to collapse
                Lookup lookup = m_func as Lookup;
                if (lookup != null)
                {
                    if (lookup.Name == "Object" &&
                        Parser.Settings.IsModificationAllowed(TreeModifications.NewObjectToObjectLiteral))
                    {
                        // no arguments -- the Object constructor with no arguments is the exact same as an empty
                        // object literal
                        if (m_args == null || m_args.Count == 0)
                        {
                            // replace our node with an object literal
                            ObjectLiteral objLiteral = new ObjectLiteral(Context, Parser, null, null);
                            if (Parent.ReplaceChild(this, objLiteral))
                            {
                                // and bail now. No need to recurse -- it's an empty literal
                                return;
                            }
                        }
                        else if (m_args.Count == 1)
                        {
                            // one argument
                            // check to see if it's an object literal.
                            ObjectLiteral objectLiteral = m_args[0] as ObjectLiteral;
                            if (objectLiteral != null)
                            {
                                // the Object constructor with an argument that is a JavaScript object merely returns the
                                // argument. Since the argument is an object literal, it is by definition a JavaScript object
                                // and therefore we can replace the constructor call with the object literal
                                Parent.ReplaceChild(this, objectLiteral);

                                // don't forget to recurse the object now
                                objectLiteral.AnalyzeNode();

                                // and then bail -- we don't want to process this call
                                // operation any more; we've gotten rid of it
                                return;
                            }
                        }
                    }
                    else if (lookup.Name == "Array" &&
                             Parser.Settings.IsModificationAllowed(TreeModifications.NewArrayToArrayLiteral))
                    {
                        // Array is trickier.
                        // If there are no arguments, then just use [].
                        // if there are multiple arguments, then use [arg0,arg1...argN].
                        // but if there is one argument and it's numeric, we can't crunch it.
                        // also can't crunch if it's a function call or a member or something, since we won't
                        // KNOW whether or not it's numeric.
                        //
                        // so first see if it even is a single-argument constant wrapper.
                        ConstantWrapper constWrapper = (m_args != null && m_args.Count == 1 ? m_args[0] as ConstantWrapper : null);

                        // if the argument count is not one, then we crunch.
                        // if the argument count IS one, we only crunch if we have a constant wrapper,
                        // AND it's not numeric.
                        if (m_args == null ||
                            m_args.Count != 1 ||
                            (constWrapper != null && !constWrapper.IsNumericLiteral))
                        {
                            // create the new array literal object
                            ArrayLiteral arrayLiteral = new ArrayLiteral(Context, Parser, m_args);
                            // replace ourself within our parent
                            if (Parent.ReplaceChild(this, arrayLiteral))
                            {
                                // recurse
                                arrayLiteral.AnalyzeNode();
                                // and bail -- we don't want to recurse this node any more
                                return;
                            }
                        }
                    }
                }
            }

            // if we are replacing resource references with strings generated from resource files
            // and this is a brackets call: lookup[args]
            ResourceStrings resourceStrings = Parser.ResourceStrings;

            if (m_inBrackets && resourceStrings != null && resourceStrings.Count > 0)
            {
                // see if the root object is a lookup that corresponds to the
                // global value (not a local field) for our resource object
                // (same name)
                Lookup rootLookup = m_func as Lookup;
                if (rootLookup != null &&
                    rootLookup.LocalField == null &&
                    string.CompareOrdinal(rootLookup.Name, resourceStrings.Name) == 0)
                {
                    // we're going to replace this node with a string constant wrapper
                    // but first we need to make sure that this is a valid lookup.
                    // if the parameter contains anything that would vary at run-time,
                    // then we need to throw an error.
                    // the parser will always have either one or zero nodes in the arguments
                    // arg list. We're not interested in zero args, so just make sure there is one
                    if (m_args.Count == 1)
                    {
                        // must be a constant wrapper
                        ConstantWrapper argConstant = m_args[0] as ConstantWrapper;
                        if (argConstant != null)
                        {
                            string resourceName = argConstant.Value.ToString();

                            // get the localized string from the resources object
                            ConstantWrapper resourceLiteral = new ConstantWrapper(
                                resourceStrings[resourceName],
                                PrimitiveType.String,
                                Context,
                                Parser);

                            // replace this node with localized string, analyze it, and bail
                            // so we don't anaylze the tree we just replaced
                            Parent.ReplaceChild(this, resourceLiteral);
                            resourceLiteral.AnalyzeNode();
                            return;
                        }
                        else
                        {
                            // error! must be a constant
                            Context.HandleError(
                                JSError.ResourceReferenceMustBeConstant,
                                true);
                        }
                    }
                    else
                    {
                        // error! can only be a single constant argument to the string resource object.
                        // the parser will only have zero or one arguments, so this must be zero
                        // (since the parser won't pass multiple args to a [] operator)
                        Context.HandleError(
                            JSError.ResourceReferenceMustBeConstant,
                            true);
                    }
                }
            }

            // and finally, if this is a backets call and the argument is a constantwrapper that can
            // be an identifier, just change us to a member node:  obj["prop"] to obj.prop.
            // but ONLY if the string value is "safe" to be an identifier. Even though the ECMA-262
            // spec says certain Unicode categories are okay, in practice the various major browsers
            // all seem to have problems with certain characters in identifiers. Rather than risking
            // some browsers breaking when we change this syntax, don't do it for those "danger" categories.
            if (m_inBrackets && m_args != null)
            {
                // see if there is a single, constant argument
                string argText = m_args.SingleConstantArgument;
                if (argText != null)
                {
                    // see if we want to replace the name
                    string newName;
                    if (Parser.Settings.HasRenamePairs && Parser.Settings.ManualRenamesProperties &&
                        Parser.Settings.IsModificationAllowed(TreeModifications.PropertyRenaming) &&
                        !string.IsNullOrEmpty(newName = Parser.Settings.GetNewName(argText)))
                    {
                        // yes -- we are going to replace the name, either as a string literal, or by converting
                        // to a member-dot operation.
                        // See if we can't turn it into a dot-operator. If we can't, then we just want to replace the operator with
                        // a new constant wrapper. Otherwise we'll just replace the operator with a new constant wrapper.
                        if (Parser.Settings.IsModificationAllowed(TreeModifications.BracketMemberToDotMember) &&
                            JSScanner.IsSafeIdentifier(newName) &&
                            !JSScanner.IsKeyword(newName))
                        {
                            // the new name is safe to convert to a member-dot operator.
                            // but we don't want to convert the node to the NEW name, because we still need to Analyze the
                            // new member node -- and it might convert the new name to something else. So instead we're
                            // just going to convert this existing string to a member node WITH THE OLD STRING,
                            // and THEN analyze it (which will convert the old string to newName)
                            Member replacementMember = new Member(Context, Parser, m_func, argText);
                            Parent.ReplaceChild(this, replacementMember);

                            // this analyze call will convert the old-name member to the newName value
                            replacementMember.AnalyzeNode();
                            return;
                        }
                        else
                        {
                            // nope; can't convert to a dot-operator.
                            // we're just going to replace the first argument with a new string literal
                            // and continue along our merry way.
                            m_args.ReplaceChild(m_args[0], new ConstantWrapper(newName, PrimitiveType.String, m_args[0].Context, Parser));
                        }
                    }
                    else if (Parser.Settings.IsModificationAllowed(TreeModifications.BracketMemberToDotMember) &&
                             JSScanner.IsSafeIdentifier(argText) &&
                             !JSScanner.IsKeyword(argText))
                    {
                        // not a replacement, but the string literal is a safe identifier. So we will
                        // replace this call node with a Member-dot operation
                        Member replacementMember = new Member(Context, Parser, m_func, argText);
                        Parent.ReplaceChild(this, replacementMember);
                        replacementMember.AnalyzeNode();
                        return;
                    }
                }
            }

            // call the base class to recurse
            base.AnalyzeNode();

            // call this AFTER recursing to give the fields a chance to resolve, because we only
            // want to make this replacement if we are working on the global Date object.
            if (!m_inBrackets && !m_isConstructor &&
                (m_args == null || m_args.Count == 0) &&
                member != null && string.CompareOrdinal(member.Name, "getTime") == 0 &&
                Parser.Settings.IsModificationAllowed(TreeModifications.DateGetTimeToUnaryPlus))
            {
                // this is not a constructor and it's not a brackets call, and there are no arguments.
                // if the function is a member operation to "getTime" and the object of the member is a
                // constructor call to the global "Date" object (not a local), then we want to replace the call
                // with a unary plus on the Date constructor. Converting to numeric type is the same as
                // calling getTime, so it's the equivalent with much fewer bytes.
                CallNode dateConstructor = member.Root as CallNode;
                if (dateConstructor != null &&
                    dateConstructor.IsConstructor)
                {
                    // lookup for the predifined (not local) "Date" field
                    Lookup lookup = dateConstructor.Function as Lookup;
                    if (lookup != null && string.CompareOrdinal(lookup.Name, "Date") == 0 &&
                        lookup.LocalField == null)
                    {
                        // this is in the pattern: (new Date()).getTime()
                        // we want to replace it with +new Date
                        // use the same date constructor node as the operand
                        NumericUnary unary = new NumericUnary(Context, Parser, dateConstructor, JSToken.Plus);

                        // replace us (the call to the getTime method) with this unary operator
                        Parent.ReplaceChild(this, unary);

                        // don't need to AnalyzeNode on the unary operator. The operand has already
                        // been analyzed when we recursed, and the unary operator wouldn't do anything
                        // special anyway (since the operand is not a numeric constant)
                    }
                }
            }
            else if (Parser.Settings.EvalTreatment != EvalTreatment.Ignore)
            {
                // if this is a window.eval call, then we need to mark this scope as unknown just as
                // we would if this was a regular eval call.
                // (unless, of course, the parser settings say evals are safe)
                // call AFTER recursing so we know the left-hand side properties have had a chance to
                // lookup their fields to see if they are local or global
                if (member != null && string.CompareOrdinal(member.Name, "eval") == 0)
                {
                    if (member.LeftHandSide.IsWindowLookup)
                    {
                        // this is a call to window.eval()
                        // mark this scope as unknown so we don't crunch out locals
                        // we might reference in the eval at runtime
                        ScopeStack.Peek().IsKnownAtCompileTime = false;
                    }
                }
                else
                {
                    CallNode callNode = m_func as CallNode;
                    if (callNode != null &&
                        callNode.InBrackets &&
                        callNode.LeftHandSide.IsWindowLookup &&
                        callNode.Arguments.IsSingleConstantArgument("eval"))
                    {
                        // this is a call to window["eval"]
                        // mark this scope as unknown so we don't crunch out locals
                        // we might reference in the eval at runtime
                        ScopeStack.Peek().IsKnownAtCompileTime = false;
                    }
                }
            }

            /* REVIEW: may be too late. lookups may alread have been analyzed and
             * found undefined
             * // check to see if this is an assignment to a window["prop"] structure
             * BinaryOperator binaryOp = Parent as BinaryOperator;
             * if (binaryOp != null && binaryOp.IsAssign
             *  && m_inBrackets
             *  && m_func.IsWindowLookup
             *  && m_args != null)
             * {
             *  // and IF the property is a non-empty constant that isn't currently
             *  // a global field...
             *  string propertyName = m_args.SingleConstantArgument;
             *  if (!string.IsNullOrEmpty(propertyName)
             *      && Parser.GlobalScope[propertyName] == null)
             *  {
             *      // we want to also add it to the global fields so it's not undefined
             *      Parser.GlobalScope.DeclareField(propertyName, null, 0);
             *  }
             * }
             */
        }
示例#7
0
 //---------------------------------------------------------------------------------------
 // ForceReportInfo
 //
 //  Generate a parser error (info), does not change the error state in the parse
 //---------------------------------------------------------------------------------------
 private static void ForceReportInfo(Context context, JSError errorId)
 {
     Debug.Assert(context != null);
     context.HandleError(errorId);
 }
示例#8
0
        //---------------------------------------------------------------------------------------
        // ReportError
        //
        //  Generate a parser error.
        //  The function is told whether or not next call to GetToken() should return the same
        //  token or not
        //---------------------------------------------------------------------------------------
        private void ReportError(JSError errorId, Context context, bool skipToken)
        {
            Debug.Assert(context != null);
            int previousSeverity = m_severity;
            m_severity = (new JScriptException(errorId)).Severity;
            // EOF error is special and it's the last error we can possibly get
            if (JSToken.EndOfFile == context.Token)
                EOFError(errorId); // EOF context is special
            else
            {
                // report the error if not in error condition and the
                // error for this token is not worse than the one for the
                // previous token
                if (m_goodTokensProcessed > 0 || m_severity < previousSeverity)
                    context.HandleError(errorId);

                // reset proper info
                if (skipToken)
                    m_goodTokensProcessed = -1;
                else
                {
                    m_errorToken = m_currentToken;
                    m_goodTokensProcessed = 0;
                }
            }
        }
示例#9
0
        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;
            }
        }
示例#10
0
        internal override void AnalyzeNode()
        {
            // figure out if our reference type is a function or a constructor
            if (Parent is CallNode)
            {
                m_refType = (
                    ((CallNode)Parent).IsConstructor
                  ? ReferenceType.Constructor
                  : ReferenceType.Function
                    );
            }

            ActivationObject scope = ScopeStack.Peek();

            VariableField = scope.FindReference(m_name);
            if (VariableField == null)
            {
                // this must be a global. if it isn't in the global space, throw an error
                // this name is not in the global space.
                // if it isn't generated, then we want to throw an error
                // we also don't want to report an undefined variable if it is the object
                // of a typeof operator
                if (!m_isGenerated && !(Parent is TypeOfNode))
                {
                    // report this undefined reference
                    Context.ReportUndefined(this);

                    // possibly undefined global (but definitely not local)
                    Context.HandleError(
                        (Parent is CallNode && ((CallNode)Parent).Function == this ? JSError.UndeclaredFunction : JSError.UndeclaredVariable),
                        null,
                        false
                        );
                }

                if (!(scope is GlobalScope))
                {
                    // add it to the scope so we know this scope references the global
                    scope.AddField(new JSGlobalField(
                                       m_name,
                                       Missing.Value,
                                       0
                                       ));
                }
            }
            else
            {
                // BUT if this field is a place-holder in the containing scope of a named
                // function expression, then we need to throw an ambiguous named function expression
                // error because this could cause problems.
                // OR if the field is already marked as ambiguous, throw the error
                if (VariableField.NamedFunctionExpression != null ||
                    VariableField.IsAmbiguous)
                {
                    // mark it as a field that's referenced ambiguously
                    VariableField.IsAmbiguous = true;
                    // throw as 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)
                    {
                        VariableField.CanCrunch = false;
                    }
                }

                // see if this scope already points to this name
                if (scope[m_name] == null)
                {
                    // create an inner reference so we don't keep walking up the scope chain for this name
                    VariableField = scope.CreateInnerField(VariableField);
                }

                // add the reference
                VariableField.AddReference(scope);

                if (VariableField is JSPredefinedField)
                {
                    // this is a predefined field. If it's Nan or Infinity, we should
                    // replace it with the numeric value in case we need to later combine
                    // some literal expressions.
                    if (string.CompareOrdinal(m_name, "NaN") == 0)
                    {
                        // don't analyze the new ConstantWrapper -- we don't want it to take part in the
                        // duplicate constant combination logic should it be turned on.
                        Parent.ReplaceChild(this, new ConstantWrapper(double.NaN, PrimitiveType.Number, Context, Parser));
                    }
                    else if (string.CompareOrdinal(m_name, "Infinity") == 0)
                    {
                        // don't analyze the new ConstantWrapper -- we don't want it to take part in the
                        // duplicate constant combination logic should it be turned on.
                        Parent.ReplaceChild(this, new ConstantWrapper(double.PositiveInfinity, PrimitiveType.Number, Context, Parser));
                    }
                }
            }
        }