Exemple #1
0
 /// <summary>
 /// Pops the value on the stack, converts it to an object, then pushes the result onto the
 /// stack.
 /// </summary>
 /// <param name="generator"> The IL generator. </param>
 /// <param name="fromType"> The type to convert from. </param>
 public static void ToAny(ILGenerator generator, PrimitiveType fromType)
 {
     if (PrimitiveTypeUtilities.IsValueType(fromType))
     {
         generator.Box(fromType);
     }
 }
Exemple #2
0
        /// <summary>
        /// Pops the value on the stack, converts it to a primitive value, then pushes the result
        /// onto the stack.
        /// </summary>
        /// <param name="generator"> The IL generator. </param>
        /// <param name="fromType"> The type to convert from. </param>
        /// <param name="preferredType"> Specifies whether toString() or valueOf() should be
        /// preferred when converting to a primitive. </param>
        public static void ToPrimitive(ILGenerator generator, PrimitiveType fromType, PrimitiveTypeHint preferredType)
        {
            switch (fromType)
            {
            case PrimitiveType.Undefined:
            case PrimitiveType.Null:
            case PrimitiveType.Bool:
            case PrimitiveType.String:
            case PrimitiveType.ConcatenatedString:
            case PrimitiveType.Int32:
            case PrimitiveType.UInt32:
            case PrimitiveType.Number:
                // These are primitives already.
                break;

            case PrimitiveType.Any:
            case PrimitiveType.Object:
                // Otherwise, fall back to calling TypeConverter.ToPrimitive()
                if (PrimitiveTypeUtilities.IsValueType(fromType))
                {
                    generator.Box(fromType);
                }
                generator.LoadInt32((int)preferredType);
                generator.Call(ReflectionHelpers.TypeConverter_ToPrimitive);
                break;

            default:
                throw new NotImplementedException(string.Format("Unsupported primitive type: {0}", fromType));
            }
        }
Exemple #3
0
        /// <summary>
        /// Generates CIL for the logical operators.
        /// </summary>
        /// <param name="generator"> The generator to output the CIL to. </param>
        /// <param name="optimizationInfo"> Information about any optimizations that should be performed. </param>
        private void GenerateLogical(ILGenerator generator, OptimizationInfo optimizationInfo)
        {
            // Get the statically-determined types of the left and right operands.
            PrimitiveType leftType  = this.Left.ResultType;
            PrimitiveType rightType = this.Right.ResultType;

            // Load the left-hand side operand.
            this.Left.GenerateCode(generator, optimizationInfo);

            // Make sure the output type is consistant.
            if (leftType != rightType)
            {
                if (PrimitiveTypeUtilities.IsNumeric(leftType) == true && PrimitiveTypeUtilities.IsNumeric(rightType) == true)
                {
                    EmitConversion.ToNumber(generator, leftType);
                    leftType = PrimitiveType.Number;
                }
                else
                {
                    EmitConversion.ToAny(generator, leftType);
                    leftType = PrimitiveType.Any;
                }
            }

            // Duplicate and convert to a Boolean.
            generator.Duplicate();
            EmitConversion.ToBool(generator, leftType);

            // Stack contains "left, (bool)left"
            var endOfIf = generator.CreateLabel();

            if (this.OperatorType == OperatorType.LogicalAnd)
            {
                generator.BranchIfFalse(endOfIf);
            }
            else
            {
                generator.BranchIfTrue(endOfIf);
            }

            // Stack contains "left".  Load the right-hand side operand.
            generator.Pop();
            this.Right.GenerateCode(generator, optimizationInfo);

            // Make sure the output type is consistant.
            if (leftType != rightType)
            {
                if (PrimitiveTypeUtilities.IsNumeric(leftType) == true && PrimitiveTypeUtilities.IsNumeric(rightType) == true)
                {
                    EmitConversion.ToNumber(generator, rightType);
                }
                else
                {
                    EmitConversion.ToAny(generator, rightType);
                }
            }

            // Define the label used above.
            generator.DefineLabelPosition(endOfIf);
        }
Exemple #4
0
        /// <summary>
        /// Determines the type of member access.
        /// </summary>
        /// <param name="optimizationInfo"> Information about any optimizations that should be performed. </param>
        /// <returns></returns>
        private TypeOfMemberAccess DetermineTypeOfMemberAccess(OptimizationInfo optimizationInfo, out string propertyName)
        {
            // Right-hand-side can be a property name (a.b)
            if (this.OperatorType == OperatorType.MemberAccess)
            {
                var rhs = this.GetOperand(1) as NameExpression;
                if (rhs == null)
                {
                    throw new JavaScriptException(optimizationInfo.Engine, "SyntaxError", "Invalid member access", optimizationInfo.SourceSpan.StartLine, optimizationInfo.Source.Path, optimizationInfo.FunctionName);
                }
                propertyName = rhs.Name;
                return(TypeOfMemberAccess.Static);
            }

            // Or a constant indexer (a['b'])
            if (this.OperatorType == OperatorType.Index)
            {
                var rhs = this.GetOperand(1) as LiteralExpression;
                if (rhs != null && (PrimitiveTypeUtilities.IsNumeric(rhs.ResultType) || rhs.ResultType == PrimitiveType.String))
                {
                    propertyName = TypeConverter.ToString(rhs.Value);

                    // Or a array index (a[0])
                    if (rhs.ResultType == PrimitiveType.Int32 || (propertyName != null && Library.ArrayInstance.ParseArrayIndex(propertyName) != uint.MaxValue))
                    {
                        return(TypeOfMemberAccess.ArrayIndex);
                    }
                    return(TypeOfMemberAccess.Static);
                }
            }

            propertyName = null;
            return(TypeOfMemberAccess.Dynamic);
        }
Exemple #5
0
        /// <summary>
        /// Pops the value on the stack, converts it from one type to another, then pushes the
        /// result onto the stack.
        /// </summary>
        /// <param name="il"> The IL generator. </param>
        /// <param name="fromType"> The type to convert from. </param>
        /// <param name="toType"> The type to convert to. </param>
        private static void EmitTypeConversion(ILGenerator il, Type fromType, Type toType)
        {
            // If the source type equals the destination type, then there is nothing to do.
            if (fromType == toType)
            {
                return;
            }

            // Emit for each type of argument we support.
            if (toType == typeof(int))
            {
                EmitConversion.ToInteger(il, PrimitiveTypeUtilities.ToPrimitiveType(fromType));
            }
            else if (typeof(ObjectInstance).IsAssignableFrom(toType))
            {
                EmitConversion.Convert(il, PrimitiveTypeUtilities.ToPrimitiveType(fromType), PrimitiveType.Object);
                if (toType != typeof(ObjectInstance))
                {
                    // Convert to null if the from type isn't compatible with the to type.
                    // For example, if the target type is FunctionInstance and the from type is ArrayInstance, then pass null.
                    il.IsInstance(toType);
                }
            }
            else
            {
                EmitConversion.Convert(il, PrimitiveTypeUtilities.ToPrimitiveType(fromType), PrimitiveTypeUtilities.ToPrimitiveType(toType));
            }
        }
Exemple #6
0
        /// <summary>
        /// Pops the value on the stack, converts it to a string, then pushes the result onto the
        /// stack.
        /// </summary>
        /// <param name="generator"> The IL generator. </param>
        /// <param name="fromType"> The type to convert from. </param>
        public static void ToString(ILGenerator generator, PrimitiveType fromType)
        {
            // Check that a conversion is actually necessary.
            if (fromType == PrimitiveType.String)
            {
                return;
            }

            switch (fromType)
            {
            case PrimitiveType.Undefined:
                // Converting from undefined produces "undefined".
                generator.Pop();
                generator.LoadString("undefined");
                break;

            case PrimitiveType.Null:
                // Converting from null produces "null".
                generator.Pop();
                generator.LoadString("null");
                break;

            case PrimitiveType.Bool:
                // Converting from a boolean produces "false" if the boolean is false, or "true" if the boolean is true.
                var elseClause = generator.CreateLabel();
                var endOfIf    = generator.CreateLabel();
                generator.BranchIfFalse(elseClause);
                generator.LoadString("true");
                generator.Branch(endOfIf);
                generator.DefineLabelPosition(elseClause);
                generator.LoadString("false");
                generator.DefineLabelPosition(endOfIf);
                break;

            case PrimitiveType.ConcatenatedString:
                generator.Call(ReflectionHelpers.ConcatenatedString_ToString);
                break;

            case PrimitiveType.Int32:
            case PrimitiveType.UInt32:
            case PrimitiveType.Number:
            case PrimitiveType.Any:
            case PrimitiveType.Object:
                // Otherwise, fall back to calling TypeConverter.ToString()
                if (PrimitiveTypeUtilities.IsValueType(fromType))
                {
                    generator.Box(fromType);
                }
                generator.Call(ReflectionHelpers.TypeConverter_ToString);
                break;

            default:
                throw new NotImplementedException(string.Format("Unsupported primitive type: {0}", fromType));
            }
        }
Exemple #7
0
 /// <summary>
 /// Pops the value on the stack, converts it to an object, then pushes the result onto the
 /// stack.
 /// </summary>
 /// <param name="generator"> The IL generator. </param>
 /// <param name="fromType"> The type to convert from. </param>
 public static void ToAny(ILGenerator generator, PrimitiveType fromType)
 {
     if (PrimitiveTypeUtilities.IsValueType(fromType))
     {
         generator.Box(fromType);
     }
     else
     {
         generator.ReinterpretCast(typeof(object));
     }
 }
Exemple #8
0
        /// <summary>
        /// Pops the value on the stack, converts it to a concatenated string, then pushes the result
        /// onto the stack.
        /// </summary>
        /// <param name="generator"> The IL generator. </param>
        /// <param name="fromType"> The type to convert from. </param>
        public static void ToConcatenatedString(ILGenerator generator, PrimitiveType fromType)
        {
            // Check that a conversion is actually necessary.
            if (fromType == PrimitiveType.ConcatenatedString)
            {
                return;
            }

            switch (fromType)
            {
            case PrimitiveType.Undefined:
            case PrimitiveType.Null:
            case PrimitiveType.Bool:
            case PrimitiveType.String:
                // Convert as per ToString, then create a new ConcatenatedString instance.
                ToString(generator, fromType);
                generator.NewObject(ReflectionHelpers.ConcatenatedString_Constructor_String);
                break;

            case PrimitiveType.Int32:
            case PrimitiveType.UInt32:
            case PrimitiveType.Number:
            case PrimitiveType.Any:
            case PrimitiveType.Object:
                // Otherwise, fall back to calling TypeConverter.ToConcatenatedString()
                if (PrimitiveTypeUtilities.IsValueType(fromType))
                {
                    generator.Box(fromType);
                }
                generator.Call(ReflectionHelpers.TypeConverter_ToConcatenatedString);
                break;

            default:
                throw new NotImplementedException(string.Format("Unsupported primitive type: {0}", fromType));
            }
        }
Exemple #9
0
 /// <summary>
 /// Pops the array, index and value off the stack and stores the value in the array.
 /// </summary>
 /// <param name="type"> The element type. </param>
 public void StoreArrayElement(PrimitiveType type)
 {
     StoreArrayElement(PrimitiveTypeUtilities.ToType(type));
 }
Exemple #10
0
 /// <summary>
 /// Pops the array and index off the stack and pushes the element value onto the stack.
 /// </summary>
 /// <param name="type"> The element type. </param>
 public void LoadArrayElement(PrimitiveType type)
 {
     LoadArrayElement(PrimitiveTypeUtilities.ToType(type));
 }
Exemple #11
0
 /// <summary>
 /// Pops an object reference (representing a boxed value) from the stack, extracts the value,
 /// then pushes the value onto the stack.
 /// </summary>
 /// <param name="type"> The type of the boxed value.  This should be a value type. </param>
 public void UnboxAny(PrimitiveType type)
 {
     UnboxAny(PrimitiveTypeUtilities.ToType(type));
 }
Exemple #12
0
 /// <summary>
 /// Pops a value from the stack, converts it to an object reference, then pushes it back onto
 /// the stack.
 /// </summary>
 /// <param name="type"> The type of value to box.  This should be a value type. </param>
 public void Box(PrimitiveType type)
 {
     Box(PrimitiveTypeUtilities.ToType(type));
 }
Exemple #13
0
 /// <summary>
 /// Retrieves a temporary variable with the given type, reusing a previous variable if
 /// possible.
 /// </summary>
 /// <param name="type"> The type of variable to create. </param>
 /// <returns> A temporary variable  </returns>
 public ILLocalVariable CreateTemporaryVariable(PrimitiveType type)
 {
     return(CreateTemporaryVariable(PrimitiveTypeUtilities.ToType(type)));
 }
Exemple #14
0
 /// <summary>
 /// Declares a new local variable.
 /// </summary>
 /// <param name="type"> The type of the local variable. </param>
 /// <param name="name"> The name of the local variable. Can be <c>null</c>. </param>
 /// <returns> A new local variable. </returns>
 public ILLocalVariable DeclareVariable(PrimitiveType type, string name = null)
 {
     return(DeclareVariable(PrimitiveTypeUtilities.ToType(type), name));
 }
        /// <summary>
        /// Pushes the value of the reference onto the stack.
        /// </summary>
        /// <param name="generator"> The generator to output the CIL to. </param>
        /// <param name="optimizationInfo"> Information about any optimizations that should be performed. </param>
        /// <param name="throwIfUnresolvable"> <c>true</c> to throw a ReferenceError exception if
        /// the name is unresolvable; <c>false</c> to output <c>null</c> instead. </param>
        public void GenerateGet(ILGenerator generator, OptimizationInfo optimizationInfo, bool throwIfUnresolvable)
        {
            string propertyName = null;
            bool   isArrayIndex = false;

            // Right-hand-side can be a property name (a.b)
            if (this.OperatorType == OperatorType.MemberAccess)
            {
                var rhs = this.GetOperand(1) as NameExpression;
                if (rhs == null)
                {
                    throw new JavaScriptException(optimizationInfo.Engine, "SyntaxError", "Invalid member access", optimizationInfo.SourceSpan.StartLine, optimizationInfo.Source.Path, optimizationInfo.FunctionName);
                }
                propertyName = rhs.Name;
            }

            // Or a constant indexer (a['b'])
            if (this.OperatorType == OperatorType.Index)
            {
                var rhs = this.GetOperand(1) as LiteralExpression;
                if (rhs != null && (PrimitiveTypeUtilities.IsNumeric(rhs.ResultType) || rhs.ResultType == PrimitiveType.String))
                {
                    propertyName = TypeConverter.ToString(rhs.Value);

                    // Or a array index (a[0])
                    if (rhs.ResultType == PrimitiveType.Int32 || (propertyName != null && Library.ArrayInstance.ParseArrayIndex(propertyName) != uint.MaxValue))
                    {
                        isArrayIndex = true;
                    }
                }
            }

            if (isArrayIndex == true)
            {
                // Array indexer
                // -------------
                // xxx = object[index]

                // Load the left-hand side and convert to an object instance.
                var lhs = this.GetOperand(0);
                lhs.GenerateCode(generator, optimizationInfo);
                EmitConversion.ToObject(generator, lhs.ResultType, optimizationInfo);

                // Load the right-hand side and convert to a uint32.
                var rhs = this.GetOperand(1);
                rhs.GenerateCode(generator, optimizationInfo);
                EmitConversion.ToUInt32(generator, rhs.ResultType);

                // Call the indexer.
                generator.Call(ReflectionHelpers.ObjectInstance_GetPropertyValue_Int);
            }
            else if (propertyName != null)
            {
                //// Load the left-hand side and convert to an object instance.
                //var lhs = this.GetOperand(0);
                //lhs.GenerateCode(generator, optimizationInfo);
                //EmitConversion.ToObject(generator, lhs.ResultType);

                //// Call Get(string)
                //generator.LoadString(propertyName);
                //generator.Call(ReflectionHelpers.ObjectInstance_GetPropertyValue_String);



                // Named property access (e.g. x = y.property)
                // -------------------------------------------
                // __object_cacheKey = null;
                // __object_property_cachedIndex = 0;
                // ...
                // if (__object_cacheKey != object.InlineCacheKey)
                //     xxx = object.InlineGetPropertyValue("property", out __object_property_cachedIndex, out __object_cacheKey)
                // else
                //     xxx = object.InlinePropertyValues[__object_property_cachedIndex];

                // Load the left-hand side and convert to an object instance.
                var lhs = this.GetOperand(0);
                lhs.GenerateCode(generator, optimizationInfo);
                EmitConversion.ToObject(generator, lhs.ResultType, optimizationInfo);

                // TODO: share these variables somehow.
                var cacheKey    = generator.DeclareVariable(typeof(object));
                var cachedIndex = generator.DeclareVariable(typeof(int));

                // Store the object into a temp variable.
                var objectInstance = generator.DeclareVariable(PrimitiveType.Object);
                generator.StoreVariable(objectInstance);

                // if (__object_cacheKey != object.InlineCacheKey)
                generator.LoadVariable(cacheKey);
                generator.LoadVariable(objectInstance);
                generator.Call(ReflectionHelpers.ObjectInstance_InlineCacheKey);
                var elseClause = generator.CreateLabel();
                generator.BranchIfEqual(elseClause);

                // value = object.InlineGetProperty("property", out __object_property_cachedIndex, out __object_cacheKey)
                generator.LoadVariable(objectInstance);
                generator.LoadString(propertyName);
                generator.LoadAddressOfVariable(cachedIndex);
                generator.LoadAddressOfVariable(cacheKey);
                generator.Call(ReflectionHelpers.ObjectInstance_InlineGetPropertyValue);

                var endOfIf = generator.CreateLabel();
                generator.Branch(endOfIf);

                // else
                generator.DefineLabelPosition(elseClause);

                // value = object.InlinePropertyValues[__object_property_cachedIndex];
                generator.LoadVariable(objectInstance);
                generator.Call(ReflectionHelpers.ObjectInstance_InlinePropertyValues);
                generator.LoadVariable(cachedIndex);
                generator.LoadArrayElement(typeof(object));

                // End of the if statement
                generator.DefineLabelPosition(endOfIf);
            }
            else
            {
                // Dynamic property access
                // -----------------------
                // xxx = object.Get(x)

                // Load the left-hand side and convert to an object instance.
                var lhs = this.GetOperand(0);
                lhs.GenerateCode(generator, optimizationInfo);
                EmitConversion.ToObject(generator, lhs.ResultType, optimizationInfo);

                // Load the property name and convert to a string.
                var rhs = this.GetOperand(1);
                rhs.GenerateCode(generator, optimizationInfo);
                EmitConversion.ToString(generator, rhs.ResultType);

                // Call Get(string)
                generator.Call(ReflectionHelpers.ObjectInstance_GetPropertyValue_String);
            }
        }
Exemple #16
0
 /// <summary>
 /// Emits a dummy value of the given type.
 /// </summary>
 /// <param name="generator"> The IL generator. </param>
 /// <param name="type"> The type of value to generate. </param>
 public static void EmitDefaultValue(ILGenerator generator, PrimitiveType type)
 {
     EmitDefaultValue(generator, PrimitiveTypeUtilities.ToType(type));
 }
Exemple #17
0
        /// <summary>
        /// Finds variables that were assigned to and determines their types.
        /// </summary>
        /// <param name="root"> The root of the abstract syntax tree to search. </param>
        /// <param name="variableTypes"> A dictionary containing the variables that were assigned to. </param>
        /// <param name="conditional"> <c>true</c> if execution of the AST node <paramref name="root"/>
        /// is conditional (i.e. the node is inside an if statement or a conditional expression. </param>
        /// <param name="continueEncountered"> Keeps track of whether a continue statement has been
        /// encountered. </param>
        private static void FindTypedVariables(AstNode root, Dictionary <Scope.DeclaredVariable, InferredTypeInfo> variableTypes, bool conditional, ref bool continueEncountered)
        {
            if (root is AssignmentExpression)
            {
                // Found an assignment.
                var assignment = (AssignmentExpression)root;
                if (assignment.Target is NameExpression)
                {
                    // Found an assignment to a variable.
                    var name = (NameExpression)assignment.Target;
                    if (name.Scope is DeclarativeScope)
                    {
                        var variable = name.Scope.GetDeclaredVariable(name.Name);
                        if (variable != null)
                        {
                            // The variable is in the top-most scope.
                            // Check if the variable has been seen before.
                            InferredTypeInfo existingTypeInfo;
                            if (variableTypes.TryGetValue(variable, out existingTypeInfo) == false)
                            {
                                // This is the first time the variable has been encountered.
                                variableTypes.Add(variable, new InferredTypeInfo()
                                {
                                    Type = assignment.ResultType, Conditional = conditional
                                });
                            }
                            else
                            {
                                // The variable has been seen before.
                                variableTypes[variable] = new InferredTypeInfo()
                                {
                                    Type        = PrimitiveTypeUtilities.GetCommonType(existingTypeInfo.Type, assignment.ResultType),
                                    Conditional = existingTypeInfo.Conditional == true && conditional == true
                                };
                            }
                        }
                    }
                }
            }

            // Determine whether the child nodes are conditional.
            conditional = conditional == true ||
                          continueEncountered == true ||
                          root is IfStatement ||
                          root is TernaryExpression ||
                          root is TryCatchFinallyStatement ||
                          (root is BinaryExpression && ((BinaryExpression)root).OperatorType == OperatorType.LogicalAnd) ||
                          (root is BinaryExpression && ((BinaryExpression)root).OperatorType == OperatorType.LogicalOr);

            // If the AST node is a continue statement, all further assignments are conditional.
            if (root is ContinueStatement)
            {
                continueEncountered = true;
            }

            // Search child nodes for assignment statements.
            foreach (var node in root.ChildNodes)
            {
                FindTypedVariables(node, variableTypes, conditional: conditional, continueEncountered: ref continueEncountered);
            }
        }
Exemple #18
0
        /// <summary>
        /// Generates CIL for the relational operators.
        /// </summary>
        /// <param name="generator"> The generator to output the CIL to. </param>
        /// <param name="optimizationInfo"> Information about any optimizations that should be performed. </param>
        private void GenerateRelational(ILGenerator generator, OptimizationInfo optimizationInfo)
        {
            // Get the statically-determined types of the left and right operands.
            PrimitiveType leftType  = this.Left.ResultType;
            PrimitiveType rightType = this.Right.ResultType;

            // The relational operators compare strings if both of the operands are strings.
            if (leftType == PrimitiveType.String && rightType == PrimitiveType.String)
            {
                // Both of the operands are strings.

                // Load the left hand side operand onto the stack.
                this.Left.GenerateCode(generator, optimizationInfo);

                // Load the right hand side operand onto the stack.
                this.Right.GenerateCode(generator, optimizationInfo);

                // Compare the two strings.
                generator.Call(ReflectionHelpers.String_CompareOrdinal);
                switch (this.OperatorType)
                {
                case OperatorType.LessThan:
                    generator.LoadInt32(0);
                    generator.CompareLessThan();
                    break;

                case OperatorType.LessThanOrEqual:
                    generator.LoadInt32(1);
                    generator.CompareLessThan();
                    break;

                case OperatorType.GreaterThan:
                    generator.LoadInt32(0);
                    generator.CompareGreaterThan();
                    break;

                case OperatorType.GreaterThanOrEqual:
                    generator.LoadInt32(-1);
                    generator.CompareGreaterThan();
                    break;
                }
            }
            else if (leftType == PrimitiveType.Int32 && rightType == PrimitiveType.Int32)
            {
                // Both of the operands are integers.

                // Load the left hand side operand onto the stack.
                this.Left.GenerateCode(generator, optimizationInfo);

                // Load the right hand side operand onto the stack.
                this.Right.GenerateCode(generator, optimizationInfo);

                // Compare the two numbers.
                switch (this.OperatorType)
                {
                case OperatorType.LessThan:
                    generator.CompareLessThan();
                    break;

                case OperatorType.GreaterThan:
                    generator.CompareGreaterThan();
                    break;

                case OperatorType.LessThanOrEqual:
                    // a <= b   <-->   (a > b) == false
                    generator.CompareGreaterThan();
                    generator.LoadBoolean(false);
                    generator.CompareEqual();
                    break;

                case OperatorType.GreaterThanOrEqual:
                    // a >= b   <-->   (a < b) == false
                    generator.CompareLessThan();
                    generator.LoadBoolean(false);
                    generator.CompareEqual();
                    break;
                }
            }
            else if (PrimitiveTypeUtilities.IsNumeric(leftType) || PrimitiveTypeUtilities.IsNumeric(rightType))
            {
                // At least one of the operands is a number.

                // Load the left hand side operand onto the stack.
                this.Left.GenerateCode(generator, optimizationInfo);

                // Convert the operand to a number.
                EmitConversion.ToNumber(generator, leftType);

                // Load the right hand side operand onto the stack.
                this.Right.GenerateCode(generator, optimizationInfo);

                // Convert the operand to a number.
                EmitConversion.ToNumber(generator, rightType);

                // Compare the two numbers.
                switch (this.OperatorType)
                {
                case OperatorType.LessThan:
                    generator.CompareLessThan();
                    break;

                case OperatorType.GreaterThan:
                    generator.CompareGreaterThan();
                    break;

                case OperatorType.LessThanOrEqual:
                    // a <= b   <-->   (a > b) == false
                    generator.CompareGreaterThanUnsigned();
                    generator.LoadBoolean(false);
                    generator.CompareEqual();
                    break;

                case OperatorType.GreaterThanOrEqual:
                    // a >= b   <-->   (a < b) == false
                    generator.CompareLessThanUnsigned();
                    generator.LoadBoolean(false);
                    generator.CompareEqual();
                    break;
                }
            }
            else
            {
                // It is unknown whether one of the operands is a string.

                // Load the left hand side operand onto the stack.
                this.Left.GenerateCode(generator, optimizationInfo);
                EmitConversion.ToAny(generator, leftType);

                // Load the right hand side operand onto the stack.
                this.Right.GenerateCode(generator, optimizationInfo);
                EmitConversion.ToAny(generator, rightType);

                switch (this.OperatorType)
                {
                case OperatorType.LessThan:
                    generator.Call(ReflectionHelpers.TypeComparer_LessThan);
                    break;

                case OperatorType.LessThanOrEqual:
                    generator.Call(ReflectionHelpers.TypeComparer_LessThanOrEqual);
                    break;

                case OperatorType.GreaterThan:
                    generator.Call(ReflectionHelpers.TypeComparer_GreaterThan);
                    break;

                case OperatorType.GreaterThanOrEqual:
                    generator.Call(ReflectionHelpers.TypeComparer_GreaterThanOrEqual);
                    break;
                }
            }
        }
Exemple #19
0
        /// <summary>
        /// Generates CIL for the addition operation.
        /// </summary>
        /// <param name="generator"> The generator to output the CIL to. </param>
        /// <param name="optimizationInfo"> Information about any optimizations that should be performed. </param>
        private void GenerateAdd(ILGenerator generator, OptimizationInfo optimizationInfo)
        {
            // Get the statically-determined types of the left and right operands.
            PrimitiveType leftType  = this.Left.ResultType;
            PrimitiveType rightType = this.Right.ResultType;

            // The add operator adds two strings together if at least one of the operands
            // is a string, otherwise it adds two numbers.
            if (PrimitiveTypeUtilities.IsString(leftType) || PrimitiveTypeUtilities.IsString(rightType))
            {
                // If at least one of the operands is a string, then the add operator concatenates.

                // Load the left-hand side onto the stack.
                this.Left.GenerateCode(generator, optimizationInfo);

                // Convert the operand to a concatenated string.
                EmitConversion.ToPrimitive(generator, leftType, PrimitiveTypeHint.None);
                EmitConversion.ToConcatenatedString(generator, leftType);

                // Load the right-hand side onto the stack.
                this.Right.GenerateCode(generator, optimizationInfo);

                if (rightType == PrimitiveType.String)
                {
                    // Concatenate the two strings.
                    generator.Call(ReflectionHelpers.ConcatenatedString_Concatenate_String);
                }
                else if (rightType == PrimitiveType.ConcatenatedString)
                {
                    // Concatenate the two strings.
                    generator.Call(ReflectionHelpers.ConcatenatedString_Concatenate_ConcatenatedString);
                }
                else
                {
                    // Convert the operand to an object.
                    EmitConversion.ToPrimitive(generator, rightType, PrimitiveTypeHint.None);
                    EmitConversion.ToAny(generator, rightType);

                    // Concatenate the two strings.
                    generator.Call(ReflectionHelpers.ConcatenatedString_Concatenate_Object);
                }
            }
            else if (leftType != PrimitiveType.Any && leftType != PrimitiveType.Object &&
                     rightType != PrimitiveType.Any && rightType != PrimitiveType.Object)
            {
                // Neither of the operands are strings.

                // Load the left hand side onto the stack.
                this.Left.GenerateCode(generator, optimizationInfo);

                // Convert the operand to a number.
                EmitConversion.ToNumber(generator, leftType);

                // Load the right hand side onto the stack.
                this.Right.GenerateCode(generator, optimizationInfo);

                // Convert the operand to a number.
                EmitConversion.ToNumber(generator, rightType);

                // Add the two numbers.
                generator.Add();
            }
            else
            {
                // It is unknown whether the operands are strings.

                // Load the left hand side onto the stack.
                this.Left.GenerateCode(generator, optimizationInfo);
                EmitConversion.ToAny(generator, leftType);

                // Load the right hand side onto the stack.
                this.Right.GenerateCode(generator, optimizationInfo);
                EmitConversion.ToAny(generator, rightType);

                // Add the two objects.
                generator.Call(ReflectionHelpers.TypeUtilities_Add);
            }
        }