Exemplo n.º 1
0
        /// <summary>
        /// Gets the type that results from evaluating this expression.
        /// </summary>
        public override Type GetResultType(OptimizationInfo optimizationInfo)
        {
            // The result is either the type of the second operand or the third operand.
            var a = this.GetOperand(1).GetResultType(optimizationInfo);
            var b = this.GetOperand(2).GetResultType(optimizationInfo);

            if (a == b)
            {
                return(a);
            }
            if (PrimitiveTypeUtilities.IsNumeric(a) == true && PrimitiveTypeUtilities.IsNumeric(b) == true)
            {
                return(typeof(double));
            }

            if (StaticResult != null)
            {
                // Convert it to a bool:
                bool result = TypeConverter.ToBoolean(StaticResult);

                if (result)
                {
                    return(a);
                }

                return(b);
            }

            // Don't know if it'll be a or b, and they're distinctive types.
            return(typeof(object));
        }
Exemplo n.º 2
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)
        {
            // If either evaluates statically to 0 then we also know the correct return type.
            object leftEval = Left.Evaluate();

            if (leftEval != null)
            {
                // RHS only.

                bool leftTrue = TypeConverter.ToBoolean(leftEval);

                // a && b
                // If a is false, don't do anything with b.
                // If a is true, emit b.
                // a || b
                // If a is false, emit b. If it's true, emit a.

                if (OperatorType == OperatorType.LogicalAnd && !leftTrue)
                {
                    // Don't evaluate the RHS. Just emit a 'false' if one is needed.
                    if (optimizationInfo.RootExpression != this)
                    {
                        // Emit the false:
                        generator.LoadBoolean(false);
                    }
                }
                else if (OperatorType == OperatorType.LogicalOr && leftTrue)
                {
                    // Emit the left object only.
                    if (optimizationInfo.RootExpression != this)
                    {
                        // Load it:
                        EmitHelpers.EmitValue(generator, leftEval);
                    }
                }
                else if (optimizationInfo.RootExpression == this)
                {
                    // Emitting b (no return type required).

                    // Right will be the root instead.
                    optimizationInfo.RootExpression = Right;
                    Right.GenerateCode(generator, optimizationInfo);
                    optimizationInfo.RootExpression = this;
                }
                else
                {
                    // Emitting b (return type required).

                    // Output required.
                    Right.GenerateCode(generator, optimizationInfo);
                }

                return;
            }

            // Evaluate B, just in case we're doing RHS only:
            object rightEval = Right.Evaluate();

            // Get the statically-determined types of the left and right operands.
            Type leftType  = this.Left.GetResultType(optimizationInfo);
            Type rightType = rightEval == null?this.Right.GetResultType(optimizationInfo) : rightEval.GetType();

            // 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 = typeof(double);
                }
                else
                {
                    EmitConversion.ToAny(generator, leftType);
                    leftType = typeof(object);
                }
            }

            // If this is an OR, we might be using the value currently on the stack if it's true.
            // So, duplicate:
            if (OperatorType == OperatorType.LogicalOr && optimizationInfo.RootExpression != this)
            {
                generator.Duplicate();
            }

            // Convert to a boolean:
            EmitConversion.ToBool(generator, leftType);

            // If this is an AND, we might be using the value currently on the stack if it's false.
            // So, duplicate:
            if (OperatorType == OperatorType.LogicalAnd && optimizationInfo.RootExpression != this)
            {
                generator.Duplicate();
            }

            // Stack contains:
            // OR: "left, (bool)left"
            // AND: "(bool)left, (bool)left"

            var endOfIf = generator.CreateLabel();

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

            if (optimizationInfo.RootExpression == this)
            {
                // Right hand side will now be the root (output is not in use).
                optimizationInfo.RootExpression = Right;

                Right.GenerateCode(generator, optimizationInfo);

                // Restore:
                optimizationInfo.RootExpression = this;
            }
            else
            {
                // Stack contains "left" which we don't need if we fall through here. Pop it off:
                generator.Pop();

                // Output is in use.
                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);
        }
Exemplo n.º 3
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.
            Type leftType  = this.Left.GetResultType(optimizationInfo);
            Type rightType = this.Right.GetResultType(optimizationInfo);

            // The relational operators compare strings if both of the operands are strings.
            if (leftType == typeof(string) && rightType == typeof(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);

                if (optimizationInfo.RootExpression == this)
                {
                    generator.Pop();
                    generator.Pop();
                    return;
                }

                // 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 == typeof(int) && rightType == typeof(int))
            {
                // 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);

                if (optimizationInfo.RootExpression == this)
                {
                    generator.Pop();
                    generator.Pop();
                    return;
                }

                // 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);

                if (optimizationInfo.RootExpression == this)
                {
                    generator.Pop();
                    generator.Pop();
                    return;
                }

                // 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);

                if (optimizationInfo.RootExpression == this)
                {
                    generator.Pop();
                    generator.Pop();
                    return;
                }

                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;
                }
            }
        }
Exemplo n.º 4
0
        /// <summary>
        /// Gets the type that results from evaluating this expression.
        /// </summary>
        public override Type GetResultType(OptimizationInfo optimizationInfo)
        {
            var type = this.OperatorType;

            switch (this.OperatorType)
            {
            // Add
            case OperatorType.Add:
            {
                var lhs = this.Left.GetResultType(optimizationInfo);
                var rhs = this.Right.GetResultType(optimizationInfo);
                if (lhs == typeof(string) || rhs == typeof(string))
                {
                    return(typeof(ConcatenatedString));
                }
                if (lhs == typeof(ConcatenatedString) || rhs == typeof(ConcatenatedString))
                {
                    return(typeof(ConcatenatedString));
                }

                // If the two types are numeric integers, retain the one with the most accuracy.
                Type numeric = TypeConverter.MostAccurateInteger(lhs, rhs);

                if (numeric != null)
                {
                    return(numeric);
                }

                if (lhs == typeof(object) || lhs == typeof(Library.ObjectInstance) ||
                    rhs == typeof(object) || rhs == typeof(Library.ObjectInstance))
                {
                    return(typeof(object));
                }
                return(typeof(double));
            }

            // Arithmetic operations.
            case OperatorType.Subtract:
            case OperatorType.Multiply:
            case OperatorType.Divide:
            case OperatorType.Modulo:
                return(typeof(double));

            // Bitwise operations.
            case OperatorType.BitwiseAnd:
            case OperatorType.BitwiseOr:
            case OperatorType.BitwiseXor:
            case OperatorType.LeftShift:
            case OperatorType.SignedRightShift:
                return(typeof(int));

            case OperatorType.UnsignedRightShift:
                return(typeof(double));

            // Relational operations.
            case OperatorType.LessThan:
            case OperatorType.LessThanOrEqual:
            case OperatorType.GreaterThan:
            case OperatorType.GreaterThanOrEqual:
                return(typeof(bool));

            // Equality operations.
            case OperatorType.Equal:
            case OperatorType.StrictlyEqual:
            case OperatorType.NotEqual:
            case OperatorType.StrictlyNotEqual:
                return(typeof(bool));

            // Logical operations.
            case OperatorType.LogicalAnd:
            {
                var lhs = this.Left.GetResultType(optimizationInfo);
                var rhs = this.Right.GetResultType(optimizationInfo);

                // If lhs is true (regardless of whatever it's type is) then we respond with rhs.
                // If it's false, we respond with typeof(bool).

                // Try and eval left statically:
                object leftEval = Left.Evaluate();

                if (leftEval == null)
                {
                    // Can't statically eval it.

                    // If rhs is a bool then great, we know for sure we're returning a bool.
                    if (rhs == typeof(bool))
                    {
                        return(typeof(bool));
                    }

                    // Either a bool or rhs. For now this is an error condition.
                    optimizationInfo.TypeError(
                        "Ambiguous type && statement. It returns either a boolean or '" + rhs +
                        "'. Add ==true to the right hand side to make sure it only returns a boolean."
                        );

                    return(typeof(object));
                }

                if (leftEval != null && TypeConverter.ToBoolean(leftEval))
                {
                    // Ok! We'll be returning rhs no matter what.
                    return(rhs);
                }

                // Left eval was false so we'll be returning false.
                return(typeof(bool));
            }

            case OperatorType.LogicalOr:
            {
                // The result is either the left-hand side or the right-hand side.
                var lhs = this.Left.GetResultType(optimizationInfo);
                var rhs = this.Right.GetResultType(optimizationInfo);
                if (lhs == rhs)
                {
                    return(lhs);
                }
                if (PrimitiveTypeUtilities.IsNumeric(lhs) && PrimitiveTypeUtilities.IsNumeric(rhs))
                {
                    return(typeof(double));
                }

                // If either evaluates statically to 0 then we also know the correct return type.
                object leftEval = Left.Evaluate();

                if (leftEval != null && !TypeConverter.ToBoolean(leftEval))
                {
                    return(rhs);
                }

                object rightEval = Right.Evaluate();

                if (rightEval != null && !TypeConverter.ToBoolean(rightEval))
                {
                    return(lhs);
                }

                return(typeof(object));
            }

            // Misc
            case OperatorType.InstanceOf:
            case OperatorType.In:
                return(typeof(bool));
            }
            throw new NotImplementedException();
        }
Exemplo n.º 5
0
        internal override void ResolveVariables(OptimizationInfo optimizationInfo)
        {
            if (ResolvedProperty != null || propertyName != null)
            {
                // Already resolved.
                return;
            }

            // Resolve kids:
            base.ResolveVariables(optimizationInfo);

            // 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", 1, optimizationInfo.Source.Path, optimizationInfo.FunctionName);
                }
                propertyName = rhs.Name;
            }

            // Or a constant indexer (a['b'])
            if (this.OperatorType == OperatorType.Index)
            {
                var rhs = this.GetOperand(1);
                if (rhs != null)
                {
                    Type rhsType = rhs.GetResultType(optimizationInfo);

                    if (rhsType == typeof(string))
                    {
                        // Try a literal:
                        LiteralExpression literalStr = rhs as LiteralExpression;

                        if (literalStr != null)
                        {
                            propertyName = TypeConverter.ToString(literalStr.Value);

                            // Could actually be numeric, so try that:
                            if (propertyName != null && Nitrassic.Library.Array.ParseArrayIndex(propertyName) != uint.MaxValue)
                            {
                                // Yep, it is!
                                isArrayIndex = true;
                            }
                        }
                    }
                    else if (PrimitiveTypeUtilities.IsNumeric(rhsType))
                    {
                        // array index (a[0])
                        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);

                // Get the type of the LHS (the object being read from):
                Type lhsType = lhs.GetResultType(optimizationInfo);

                // Get the proto for it:
                Nitrassic.Library.Prototype proto = optimizationInfo.Engine.Prototypes.Get(lhsType);

                // Does that type have an indexer method on it? (this[uint])
                ResolvedProperty = proto.Indexer(typeof(uint));

                if (ResolvedProperty == null)
                {
                    // Try [int] instead:
                    ResolvedProperty = proto.Indexer(typeof(int));
                }
            }

            if (ResolvedProperty == null && propertyName != null)
            {
                // Load the left-hand side and convert to an object instance.
                var lhs = this.GetOperand(0);

                Type lhsType = lhs.GetResultType(optimizationInfo);

                // Get the prototype:
                Nitrassic.Library.Prototype proto = optimizationInfo.Engine.Prototypes.Get(lhsType);

                // Get the property:
                ResolvedProperty = proto.GetProperty(propertyName);

                if (ResolvedProperty == null)
                {
                    // Add it now (as undefined):
                    ResolvedProperty = proto.AddProperty(propertyName, null, Nitrassic.Library.PropertyAttributes.FullAccess);
                }
            }
        }