Beispiel #1
0
        internal void SetOuterLocalField(ActivationObject parentScope)
        {
            // if we're trying to set the outer local field using a global scope,
            // then ignore this request. This should only do something for scopes with
            // local variables
            if (!(parentScope is GlobalScope))
            {
                // get the field reference for this lookup value
                JSVariableField variableField = parentScope.FindReference(m_name);
                if (variableField != null)
                {
                    // see if this scope already points to this name
                    if (parentScope[m_name] == null)
                    {
                        // create an inner reference so we don't keep walking up the scope chain for this name
                        variableField = parentScope.CreateInnerField(variableField);
                    }

                    // save the local field
                    VariableField = variableField as JSLocalField;
                    // add a reference
                    if (VariableField != null)
                    {
                        VariableField.AddReference(parentScope);
                    }
                }
            }
        }
Beispiel #2
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));
                    }
                }
            }
        }
Beispiel #3
0
        private string NumericToString()
        {
            // numerics are doubles in JavaScript, so force it now as a shortcut
            double doubleValue = (double)Value;

            if (double.IsNaN(doubleValue) || double.IsInfinity(doubleValue))
            {
                // weird number -- just return the uncrunched source code as-is.
                // we've should have already thrown an error alerting the developer
                // to the overflow mistake, and it might alter the code to change the value
                if (this.Context != null && !string.IsNullOrEmpty(Context.Code) &&
                    string.CompareOrdinal(Context.Code, "[generated code]") != 0)
                {
                    return(Context.Code);
                }

                // Hmmm... don't have a context source.
                // Must be generated. Just generate the proper JS literal.
                //
                // DANGER! If we just output NaN and Infinity and -Infinity blindly, that assumes
                // that there aren't any local variables in this scope chain with that
                // name, and we're pulling the GLOBAL properties. Might want to use properties
                // on the Number object -- which, of course, assumes that Number doesn't
                // resolve to a local variable...
                string objectName = double.IsNaN(doubleValue) ? "NaN" : "Infinity";

                ActivationObject enclosingScope = EnclosingScope;
                if (!(enclosingScope is GlobalScope))
                {
                    JSPredefinedField globalReference = enclosingScope.FindReference(objectName) as JSPredefinedField;
                    if (globalReference == null)
                    {
                        // the name doesn't resolve to the global object properties! Must be a local field in the way!
                        // we can't assume the local field of this name contains the proper numeric value or we
                        // could get into big trouble.
                        // try the Number object
                        globalReference = enclosingScope.FindReference("Number") as JSPredefinedField;
                        if (globalReference != null)
                        {
                            // use the properties off this object. Not very compact, but accurate.
                            // I don't think there will be any precedence problems with these constructs --
                            // the member-dot operator is pretty high on the precedence scale.
                            if (double.IsPositiveInfinity(doubleValue))
                            {
                                return("Number.POSITIVE_INFINITY");
                            }
                            if (double.IsNegativeInfinity(doubleValue))
                            {
                                return("Number.NEGATIVE_INFINITY");
                            }
                            return("Number.NaN");
                        }
                        else
                        {
                            // that doesn't resolve to the global Number object, either!
                            // well, extreme circumstances. Let's use literals to generate those values.
                            if (double.IsPositiveInfinity(doubleValue))
                            {
                                // 1 divided by zero is +Infinity
                                return("(1/0)");
                            }
                            if (double.IsNegativeInfinity(doubleValue))
                            {
                                // 1 divided by negative zero is -Infinity
                                return("(1/-0)");
                            }
                            // the unary plus converts to a number, and "x" will generate NaN
                            return("(+'x')");
                        }
                    }
                }

                // we're good to go -- just return the name because it will resolve to the
                // global properties (make a special case for negative infinity)
                return(double.IsNegativeInfinity(doubleValue) ? "-Infinity" : objectName);
            }
            else if (doubleValue == 0)
            {
                // special case zero because we don't need to go through all those
                // gyrations to get a "0" -- and because negative zero is different
                // than a positive zero
                return(IsNegativeZero ? "-0" : "0");
            }
            else
            {
                // normal string representations
                string normal = GetSmallestRep(doubleValue.ToString("R", CultureInfo.InvariantCulture));

                // if this is an integer (no decimal portion)....
                if (Math.Floor(doubleValue) == doubleValue)
                {
                    // then convert to hex and see if it's smaller.
                    // only really big numbers might be smaller in hex.
                    string hex = NormalOrHexIfSmaller(doubleValue, normal);
                    if (hex.Length < normal.Length)
                    {
                        normal = hex;
                    }
                }
                return(normal);
            }
        }