示例#1
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));
            }
        }
 /// <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);
     }
 }
示例#3
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 && conditional
                                };
                            }
                        }
                    }
                }
            }

            // Determine whether the child nodes are conditional.
            conditional = conditional ||
                          continueEncountered ||
                          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, ref continueEncountered);
            }
        }
        /// <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) && PrimitiveTypeUtilities.IsNumeric(rightType))
                {
                    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) && PrimitiveTypeUtilities.IsNumeric(rightType))
                {
                    EmitConversion.ToNumber(generator, rightType);
                }
                else
                {
                    EmitConversion.ToAny(generator, rightType);
                }
            }

            // Define the label used above.
            generator.DefineLabelPosition(endOfIf);
        }
        /// <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.Value);
                break;

            default:
                throw new NotImplementedException(string.Format("Unsupported primitive type: {0}", fromType));
            }
        }
        /// <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.Value);
                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.Value);
                break;

            default:
                throw new NotImplementedException(string.Format("Unsupported primitive type: {0}", fromType));
            }
        }
        /// <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.Value);
                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.Value);
                break;

            default:
                throw new NotImplementedException(string.Format("Unsupported primitive type: {0}", fromType));
            }
        }
示例#8
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));
 }
示例#9
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));
 }
示例#10
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));
 }
示例#11
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));
 }
示例#12
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)));
 }
示例#13
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)
 {
     return(DeclareVariable(PrimitiveTypeUtilities.ToType(type), name));
 }
示例#14
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));
 }
        /// <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.Value);
                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.Value);
                    break;

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

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

                case OperatorType.GreaterThanOrEqual:
                    generator.Call(ReflectionHelpers.TypeComparer_GreaterThanOrEqual.Value);
                    break;
                }
            }
        }
        /// <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.Value);
                }
                else if (rightType == PrimitiveType.ConcatenatedString)
                {
                    // Concatenate the two strings.
                    generator.Call(ReflectionHelpers.ConcatenatedString_Concatenate_ConcatenatedString.Value);
                }
                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.Value);
                }
            }
            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.Value);
            }
        }